From c474d6d3a664ee889141edaae2b094fb30aa66f4 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 28 Sep 2020 10:42:36 +0200 Subject: [PATCH] add self-size support --- src/lv_core/lv_grid.c | 10 ++- src/lv_core/lv_obj.h | 1 + src/lv_core/lv_obj_pos.c | 8 +- src/lv_core/lv_obj_scroll.c | 11 ++- src/lv_widgets/lv_roller.c | 143 +++++++++++++++++++----------------- 5 files changed, 100 insertions(+), 73 deletions(-) diff --git a/src/lv_core/lv_grid.c b/src/lv_core/lv_grid.c index d8e8d3c8a..cd0170d1a 100644 --- a/src/lv_core/lv_grid.c +++ b/src/lv_core/lv_grid.c @@ -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++; diff --git a/src/lv_core/lv_obj.h b/src/lv_core/lv_obj.h index 23d6f4f9b..a6ed06d50 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -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 */ diff --git a/src/lv_core/lv_obj_pos.c b/src/lv_core/lv_obj_pos.c index 42272e48d..d3fefad13 100644 --- a/src/lv_core/lv_obj_pos.c +++ b/src/lv_core/lv_obj_pos.c @@ -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)*/ diff --git a/src/lv_core/lv_obj_scroll.c b/src/lv_core/lv_obj_scroll.c index ef0c9e8c0..0954d62e0 100644 --- a/src/lv_core/lv_obj_scroll.c +++ b/src/lv_core/lv_obj_scroll.c @@ -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); } /********************** diff --git a/src/lv_widgets/lv_roller.c b/src/lv_widgets/lv_roller.c index c0f35174a..8fc8eb575 100644 --- a/src/lv_widgets/lv_roller.c +++ b/src/lv_widgets/lv_roller.c @@ -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, ©_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) {