add self-size support

This commit is contained in:
Gabor Kiss-Vamosi
2020-09-28 10:42:36 +02:00
parent f5dc2e4248
commit c474d6d3a6
5 changed files with 100 additions and 73 deletions

View File

@@ -385,7 +385,10 @@ static void calc_implicit_cols(lv_obj_t * cont, _lv_grid_calc_t * calc)
while(child) {
if(_GRID_IS_CELL(child->x_set) && _GRID_IS_CELL(child->y_set)) {
lv_coord_t w;
if(_GRID_GET_CELL_FLAG(child->x_set) == LV_GRID_STRETCH) _lv_obj_calc_auto_size(child, &w, NULL);
if(_GRID_GET_CELL_FLAG(child->x_set) == LV_GRID_STRETCH) {
lv_obj_scroll_to_x(child, 0, LV_ANIM_OFF);
_lv_obj_calc_auto_size(child, &w, NULL);
}
else w = lv_obj_get_width(child);
calc->w[col_i] = LV_MATH_MAX(calc->w[col_i], w);
row_i++;
@@ -416,7 +419,10 @@ static void calc_implicit_rows(lv_obj_t * cont, _lv_grid_calc_t * calc)
while(child) {
if(_GRID_IS_CELL(child->x_set) && _GRID_IS_CELL(child->y_set)) {
lv_coord_t h;
if(_GRID_GET_CELL_FLAG(child->y_set) == LV_GRID_STRETCH) _lv_obj_calc_auto_size(child, NULL, &h);
if(_GRID_GET_CELL_FLAG(child->y_set) == LV_GRID_STRETCH) {
lv_obj_scroll_to_y(child, 0, LV_ANIM_OFF);
_lv_obj_calc_auto_size(child, NULL, &h);
}
else h = lv_obj_get_height(child);
calc->h[row_i] = LV_MATH_MAX(calc->h[row_i], h);
col_i++;

View File

@@ -129,6 +129,7 @@ enum {
LV_SIGNAL_REFR_EXT_DRAW_PAD, /**< Object's extra padding has changed */
LV_SIGNAL_GET_TYPE, /**< LVGL needs to retrieve the object's type */
LV_SIGNAL_GET_STYLE, /**< Get the style of an object*/
LV_SIGNAL_GET_SELF_SIZE, /**< Get the internal size of a widget*/
/*Input device related*/
LV_SIGNAL_HIT_TEST, /**< Advanced hit-testing */

View File

@@ -147,6 +147,10 @@ void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h)
bool x_auto = obj->w_set == LV_SIZE_AUTO ? true : false;
bool y_auto = obj->h_set == LV_SIZE_AUTO ? true : false;
/*Be sure the object is not scrolled when it has auto size*/
if(x_auto) lv_obj_scroll_to_x(obj, 0, LV_ANIM_OFF);
if(y_auto) lv_obj_scroll_to_y(obj, 0, LV_ANIM_OFF);
lv_coord_t auto_w;
lv_coord_t auto_h;
if(x_auto && y_auto) {
@@ -471,17 +475,15 @@ void _lv_obj_calc_auto_size(lv_obj_t * obj, lv_coord_t * w_out, lv_coord_t * h_o
lv_coord_t children_w = 0;
lv_coord_t children_h = 0;
if(w_out) {
lv_obj_scroll_to_x(obj, 0, LV_ANIM_OFF);
lv_coord_t scroll_right = lv_obj_get_scroll_right(obj);
lv_coord_t scroll_left = lv_obj_get_scroll_left(obj);
children_w = lv_obj_get_width(obj) + scroll_right + scroll_left;
}
if(h_out) {
lv_obj_scroll_to_y(obj, 0, LV_ANIM_OFF);
lv_coord_t scroll_bottom = lv_obj_get_scroll_bottom(obj);
lv_coord_t scroll_top = lv_obj_get_scroll_top(obj);
children_h = lv_obj_get_height(obj) + scroll_bottom + scroll_top ;
children_h = lv_obj_get_height(obj) + scroll_bottom + scroll_top;
}
/*auto_size = max(gird_size, children_size)*/

View File

@@ -234,7 +234,16 @@ lv_coord_t lv_obj_get_scroll_right(const lv_obj_t * obj)
}
return child_res - obj->coords.x2 + lv_obj_get_style_pad_right(obj, LV_OBJ_PART_MAIN);
lv_coord_t pad_right = lv_obj_get_style_pad_right(obj, LV_OBJ_PART_MAIN);
lv_coord_t pad_left = lv_obj_get_style_pad_left(obj, LV_OBJ_PART_MAIN);
child_res -= (obj->coords.x2 - pad_right);
lv_point_t p = {0, 0};
lv_signal_send(obj, LV_SIGNAL_GET_SELF_SIZE, &p);
p.x = p.x - (lv_obj_get_width(obj) - pad_right - pad_left);
p.x += obj->scroll.x;
return LV_MATH_MAX(child_res, p.x);
}
/**********************

View File

@@ -38,20 +38,22 @@ static lv_design_res_t lv_roller_design(lv_obj_t * roller, const lv_area_t * cli
static lv_design_res_t lv_roller_label_design(lv_obj_t * label, const lv_area_t * clip_area, lv_design_mode_t mode);
static lv_style_list_t * lv_roller_get_style(lv_obj_t * roller, uint8_t part);
static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * param);
static lv_res_t lv_roller_label_signal(lv_obj_t * label, lv_signal_t sign, void * param);
static void refr_position(lv_obj_t * roller, lv_anim_enable_t animen);
static lv_res_t release_handler(lv_obj_t * roller);
static void inf_normalize(lv_obj_t * roller_scrl);
static lv_obj_t * get_label(const lv_obj_t * roller);
static lv_coord_t get_selected_label_width(const lv_obj_t * roller);
#if LV_USE_ANIMATION
static void scroll_anim_ready_cb(lv_anim_t * a);
#endif
static void draw_bg(lv_obj_t * roller, const lv_area_t * clip_area);
/**********************
* STATIC VARIABLES
**********************/
static lv_signal_cb_t ancestor_signal;
static lv_design_cb_t ancestor_design;
static lv_signal_cb_t ancestor_label_signal;
static lv_design_cb_t ancestor_label_design;
/**********************
@@ -95,8 +97,6 @@ lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy)
lv_style_list_init(&ext->style_sel);
/*The signal and design functions are not copied so set them here*/
lv_obj_set_signal_cb(roller, lv_roller_signal);
lv_obj_set_design_cb(roller, lv_roller_design);
/*Init the new roller roller*/
if(copy == NULL) {
@@ -106,8 +106,14 @@ lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy)
lv_obj_t * label = lv_label_create(roller, NULL);
lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);
if(ancestor_label_design == NULL) ancestor_label_design = lv_obj_get_design_cb(label);
if(ancestor_label_signal == NULL) ancestor_label_signal = lv_obj_get_signal_cb(label);
lv_obj_set_design_cb(label, lv_roller_label_design);
lv_obj_set_signal_cb(label, lv_roller_label_signal);
lv_obj_set_signal_cb(roller, lv_roller_signal);
lv_obj_set_design_cb(roller, lv_roller_design);
lv_roller_set_options(roller, "Option 1\nOption 2\nOption 3\nOption 4\nOption 5", LV_ROLLER_MODE_NORMAL);
@@ -117,7 +123,7 @@ lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy)
}
/*Copy an existing roller*/
else {
lv_label_create(roller, get_label(copy));
lv_obj_t * label = lv_label_create(roller, get_label(copy));
lv_roller_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
ext->mode = copy_ext->mode;
@@ -125,6 +131,12 @@ lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy)
ext->sel_opt_id = copy_ext->sel_opt_id;
ext->sel_opt_id_ori = copy_ext->sel_opt_id;
lv_obj_set_design_cb(label, lv_roller_label_design);
lv_obj_set_signal_cb(label, lv_roller_label_signal);
lv_obj_set_signal_cb(roller, lv_roller_signal);
lv_obj_set_design_cb(roller, lv_roller_design);
lv_style_list_copy(&ext->style_sel, &copy_ext->style_sel);
_lv_obj_refresh_style(roller, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
}
@@ -189,6 +201,10 @@ void lv_roller_set_options(lv_obj_t * roller, const char * options, lv_roller_mo
}
ext->sel_opt_id_ori = ext->sel_opt_id;
/*If the selected text has larger font the label needs some extra draw padding to draw it.*/
_lv_obj_refresh_ext_draw_pad(label);
}
/**
@@ -204,6 +220,7 @@ void lv_roller_set_align(lv_obj_t * roller, lv_label_align_t align)
if(label == NULL) return; /*Probably the roller is being deleted if the label is NULL.*/
lv_label_set_align(label, align);
refr_position(roller, LV_ANIM_OFF);
}
/**
@@ -562,13 +579,8 @@ static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * par
res = ancestor_signal(roller, sign, param);
if(res != LV_RES_OK) return res;
int32_t id = -1;
lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);
const lv_font_t * font = lv_obj_get_style_text_font(roller, LV_ROLLER_PART_BG);
lv_style_int_t line_space = lv_obj_get_style_text_line_space(roller, LV_ROLLER_PART_BG);
lv_coord_t font_h = lv_font_get_line_height(font);
/* Include the ancient signal function */
if(sign == LV_SIGNAL_GET_STYLE) {
lv_get_style_info_t * info = param;
@@ -578,10 +590,15 @@ static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * par
else if(sign == LV_SIGNAL_GET_TYPE) {
return _lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
}
else if(sign == LV_SIGNAL_GET_SELF_SIZE) {
lv_point_t * p = param;
p->x = get_selected_label_width(roller);
}
else if(sign == LV_SIGNAL_STYLE_CHG) {
lv_obj_t * label = get_label(roller);
/*Be sure the label's style is updated before processing the roller*/
if(label) lv_signal_send(label, LV_SIGNAL_STYLE_CHG, NULL);
lv_obj_set_width(roller, roller->w_set);
refr_position(roller, false);
}
else if(sign == LV_SIGNAL_COORD_CHG) {
@@ -667,13 +684,32 @@ static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * par
_lv_obj_reset_style_list_no_refr(roller, LV_ROLLER_PART_SELECTED);
}
return res;
}
/*Position the scrollable according to the new selected option*/
if(id != -1) {
refr_position(roller, LV_ANIM_ON);
/**
* Signal function of the roller's label
* @param label pointer to a roller's label object
* @param sign a signal type from lv_signal_t enum
* @param param pointer to a signal specific variable
* @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
*/
static lv_res_t lv_roller_label_signal(lv_obj_t * label, lv_signal_t sign, void * param)
{
lv_res_t res;
/* Include the ancient signal function */
res = ancestor_label_signal(label, sign, param);
if(res != LV_RES_OK) return res;
if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) {
/*If the selected text has a larger font it needs some extra space to draw it*/
lv_obj_t * roller = lv_obj_get_parent(label);
lv_coord_t sel_w = get_selected_label_width(roller);
lv_coord_t label_w = lv_obj_get_width(label);
label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, sel_w - label_w);
}
return res;
}
@@ -704,60 +740,6 @@ static lv_style_list_t * lv_roller_get_style(lv_obj_t * roller, uint8_t part)
return style_dsc_p;
}
/**
* Draw a rectangle which has gradient on its top and bottom
* @param roller pointer to a roller object
* @param clip_area pointer to the current mask (from the design function)
*/
static void draw_bg(lv_obj_t * roller, const lv_area_t * clip_area)
{
lv_draw_rect_dsc_t bg_dsc;
lv_draw_rect_dsc_init(&bg_dsc);
lv_obj_init_draw_rect_dsc(roller, LV_ROLLER_PART_BG, &bg_dsc);
/*With non-vertical gradient simply draw the background*/
if(bg_dsc.bg_grad_dir == LV_GRAD_DIR_NONE) {
lv_draw_rect(&roller->coords, clip_area, &bg_dsc);
return;
}
/*With vertical gradient mirror it*/
lv_area_t half_mask;
lv_coord_t h = lv_obj_get_height(roller);
bool union_ok;
lv_area_copy(&half_mask, &roller->coords);
half_mask.x1 -= roller->ext_draw_pad; /*Add ext size too (e.g. because of shadow draw) */
half_mask.x2 += roller->ext_draw_pad;
half_mask.y1 -= roller->ext_draw_pad;
half_mask.y2 = roller->coords.y1 + h / 2;
union_ok = _lv_area_intersect(&half_mask, &half_mask, clip_area);
bg_dsc.bg_main_color_stop = bg_dsc.bg_main_color_stop / 2;
bg_dsc.bg_grad_color_stop = 128 - (255 - bg_dsc.bg_grad_color_stop) / 2;
if(union_ok) {
lv_draw_rect(&roller->coords, &half_mask, &bg_dsc);
}
lv_area_copy(&half_mask, &roller->coords);
half_mask.x1 -= roller->ext_draw_pad; /*Revert ext. size adding*/
half_mask.x2 += roller->ext_draw_pad;
half_mask.y1 = roller->coords.y1 + h / 2;
half_mask.y2 += roller->ext_draw_pad;
union_ok = _lv_area_intersect(&half_mask, &half_mask, clip_area);
if(union_ok) {
lv_color_t c = bg_dsc.bg_color;
bg_dsc.bg_color = bg_dsc.bg_grad_color;
bg_dsc.bg_grad_color = c;
bg_dsc.bg_main_color_stop += 127;
bg_dsc.bg_grad_color_stop += 127;
lv_draw_rect(&roller->coords, &half_mask, &bg_dsc);
}
}
/**
* Refresh the position of the roller. It uses the id stored in: ext->ddlist.selected_option_id
* @param roller pointer to a roller object
@@ -772,6 +754,19 @@ static void refr_position(lv_obj_t * roller, lv_anim_enable_t anim_en)
anim_en = LV_ANIM_OFF;
#endif
lv_label_align_t align = lv_label_get_align(label);
switch(align) {
case LV_LABEL_ALIGN_CENTER:
lv_obj_set_x(label, (lv_obj_get_width_fit(roller) - lv_obj_get_width(label)) / 2);
break;
case LV_LABEL_ALIGN_RIGHT:
lv_obj_set_x(label, lv_obj_get_width_fit(roller) - lv_obj_get_width(label));
break;
case LV_LABEL_ALIGN_LEFT:
lv_obj_set_x(label, 0);
break;
}
lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);
const lv_font_t * font = lv_obj_get_style_text_font(roller, LV_ROLLER_PART_BG);
lv_style_int_t line_space = lv_obj_get_style_text_line_space(roller, LV_ROLLER_PART_BG);
@@ -929,6 +924,20 @@ static lv_obj_t * get_label(const lv_obj_t * roller)
return lv_obj_get_child(roller, NULL);
}
static lv_coord_t get_selected_label_width(const lv_obj_t * roller)
{
lv_obj_t * label = get_label(roller);
if(label == NULL) return 0;
const lv_font_t * font = lv_obj_get_style_text_font(roller, LV_ROLLER_PART_SELECTED);
lv_style_int_t letter_space = lv_obj_get_style_text_letter_space(roller, LV_ROLLER_PART_SELECTED);
const char * txt = lv_label_get_text(label);
lv_point_t size;
_lv_txt_get_size(&size, txt, font, letter_space, 0, LV_COORD_MAX, LV_TXT_FLAG_NONE);
return size.x;
}
#if LV_USE_ANIMATION
static void scroll_anim_ready_cb(lv_anim_t * a)
{