From 132e79fa428f0f428a1015b0272dce94a6e4a442 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Tue, 29 Sep 2020 14:26:35 +0200 Subject: [PATCH] rework checkbox and add LV_SIGNAL_SELF_SIZE --- src/lv_core/lv_obj_pos.c | 37 ++++++++ src/lv_core/lv_obj_pos.h | 21 +++++ src/lv_core/lv_obj_scroll.c | 26 ++++-- src/lv_core/lv_obj_scroll.h | 4 +- src/lv_themes/lv_theme_material.c | 3 - src/lv_widgets/lv_canvas.c | 7 +- src/lv_widgets/lv_checkbox.c | 147 ++++++++++++++++++++++++++++-- src/lv_widgets/lv_checkbox.h | 58 ++---------- 8 files changed, 226 insertions(+), 77 deletions(-) diff --git a/src/lv_core/lv_obj_pos.c b/src/lv_core/lv_obj_pos.c index d3fefad13..e1a719fe9 100644 --- a/src/lv_core/lv_obj_pos.c +++ b/src/lv_core/lv_obj_pos.c @@ -444,6 +444,43 @@ lv_coord_t lv_obj_get_width_margin(lv_obj_t * obj) return lv_obj_get_width(obj) + mleft + mright; } +/** + * Get the width of the virtual content of an object + * @param obj pointer to an objects + * @return the width of the virtually drawn content + */ +lv_coord_t _lv_obj_get_self_width(lv_obj_t * obj) +{ + lv_point_t p = {0, LV_COORD_MIN}; + lv_signal_send((lv_obj_t * )obj, LV_SIGNAL_GET_SELF_SIZE, &p); + return p.x; +} + +/** + * Get the height of the virtual content of an object + * @param obj pointer to an objects + * @return the width of the virtually drawn content + */ +lv_coord_t _lv_obj_get_self_height(lv_obj_t * obj) +{ + lv_point_t p = {LV_COORD_MIN, 0}; + lv_signal_send((lv_obj_t * )obj, LV_SIGNAL_GET_SELF_SIZE, &p); + return p.y; +} + +/** + * Handle if the size of the internal (virtual) content of an object has changed. + * @param obj pointer to an object + * @return false: nothing happened; true: refresh happened + */ +bool _lv_obj_handle_self_size_chg(lv_obj_t * obj) +{ + if(obj->w_set != LV_SIZE_AUTO && obj->h_set == LV_SIZE_AUTO) return false; + + lv_obj_set_size(obj, obj->w_set, obj->h_set); + return true; +} + /** * Calculate the "auto size". It's `auto_size = max(gird_size, children_size, self_size)` * @param obj pointer to an object diff --git a/src/lv_core/lv_obj_pos.h b/src/lv_core/lv_obj_pos.h index fa763d5bc..0f440f496 100644 --- a/src/lv_core/lv_obj_pos.h +++ b/src/lv_core/lv_obj_pos.h @@ -198,6 +198,27 @@ lv_coord_t lv_obj_get_height_margin(struct _lv_obj_t * obj); */ lv_coord_t lv_obj_get_width_margin(struct _lv_obj_t * obj); +/** + * Get the width of the virtual content of an object + * @param obj pointer to an objects + * @return the width of the virtually drawn content + */ +lv_coord_t _lv_obj_get_self_width(lv_obj_t * obj); + +/** + * Get the height of the virtual content of an object + * @param obj pointer to an objects + * @return the width of the virtually drawn content + */ +lv_coord_t _lv_obj_get_self_height(lv_obj_t * obj); + +/** + * Handle if the size of the internal (virtual) content of an object has changed. + * @param obj pointer to an object + * @return false: nothing happened; true: refresh happened + */ +bool _lv_obj_handle_self_size_chg(lv_obj_t * obj); + /** * Calculate the "auto size". It's `auto_size = max(gird_size, children_size)` * @param obj pointer to an object diff --git a/src/lv_core/lv_obj_scroll.c b/src/lv_core/lv_obj_scroll.c index 0954d62e0..1e6547ad9 100644 --- a/src/lv_core/lv_obj_scroll.c +++ b/src/lv_core/lv_obj_scroll.c @@ -179,7 +179,7 @@ lv_coord_t lv_obj_get_scroll_top(const lv_obj_t * obj) * @param obj * @return */ -lv_coord_t lv_obj_get_scroll_bottom(const lv_obj_t * obj) +lv_coord_t lv_obj_get_scroll_bottom(lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); @@ -196,6 +196,18 @@ lv_coord_t lv_obj_get_scroll_bottom(const lv_obj_t * obj) child_res = y2; } + + lv_coord_t pad_top = lv_obj_get_style_pad_top(obj, LV_OBJ_PART_MAIN); + lv_coord_t pad_bottom = lv_obj_get_style_pad_bottom(obj, LV_OBJ_PART_MAIN); + + child_res -= (obj->coords.y2 - pad_bottom); + + lv_coord_t self_h = _lv_obj_get_self_height(obj); + self_h = self_h - (lv_obj_get_height(obj) - pad_top - pad_bottom); + self_h += obj->scroll.y; + return LV_MATH_MAX(child_res, self_h); + + return child_res - obj->coords.y2 + lv_obj_get_style_pad_bottom(obj, LV_OBJ_PART_MAIN); } @@ -218,7 +230,7 @@ lv_coord_t lv_obj_get_scroll_left(const lv_obj_t * obj) * @param obj * @return */ -lv_coord_t lv_obj_get_scroll_right(const lv_obj_t * obj) +lv_coord_t lv_obj_get_scroll_right(lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); @@ -239,11 +251,11 @@ lv_coord_t lv_obj_get_scroll_right(const lv_obj_t * obj) 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); + lv_coord_t self_w = _lv_obj_get_self_width(obj); + self_w = self_w - (lv_obj_get_width(obj) - pad_right - pad_left); + self_w += obj->scroll.x; + + return LV_MATH_MAX(child_res, self_w); } /********************** diff --git a/src/lv_core/lv_obj_scroll.h b/src/lv_core/lv_obj_scroll.h index bb7987132..191d7c94e 100644 --- a/src/lv_core/lv_obj_scroll.h +++ b/src/lv_core/lv_obj_scroll.h @@ -119,7 +119,7 @@ lv_coord_t lv_obj_get_scroll_top(const struct _lv_obj_t * obj); * @param obj * @return */ -lv_coord_t lv_obj_get_scroll_bottom(const struct _lv_obj_t * obj); +lv_coord_t lv_obj_get_scroll_bottom(struct _lv_obj_t * obj); /** @@ -138,7 +138,7 @@ lv_coord_t lv_obj_get_scroll_left(const struct _lv_obj_t * obj); * @param obj * @return */ -lv_coord_t lv_obj_get_scroll_right(const struct _lv_obj_t * obj); +lv_coord_t lv_obj_get_scroll_right(struct _lv_obj_t * obj); /********************** diff --git a/src/lv_themes/lv_theme_material.c b/src/lv_themes/lv_theme_material.c index 0bda77ec6..1dd0b110c 100644 --- a/src/lv_themes/lv_theme_material.c +++ b/src/lv_themes/lv_theme_material.c @@ -626,9 +626,6 @@ static void checkbox_init(void) #if LV_USE_CHECKBOX != 0 style_init_reset(&styles->cb_bg); lv_style_set_radius(&styles->cb_bg, LV_STATE_DEFAULT, LV_DPX(4)); - lv_style_set_pad_left(&styles->cb_bg, LV_STATE_DEFAULT, LV_DPX(30)); - lv_style_set_pad_top(&styles->cb_bg, LV_STATE_DEFAULT, LV_DPX(3)); - lv_style_set_pad_bottom(&styles->cb_bg, LV_STATE_DEFAULT, LV_DPX(3)); lv_style_set_outline_color(&styles->cb_bg, LV_STATE_DEFAULT, theme.color_primary); lv_style_set_outline_opa(&styles->cb_bg, LV_STATE_DEFAULT, LV_OPA_TRANSP); lv_style_set_outline_opa(&styles->cb_bg, LV_STATE_FOCUSED, LV_OPA_50); diff --git a/src/lv_widgets/lv_canvas.c b/src/lv_widgets/lv_canvas.c index 14fb5e023..1c3c8784a 100644 --- a/src/lv_widgets/lv_canvas.c +++ b/src/lv_widgets/lv_canvas.c @@ -1108,9 +1108,10 @@ static lv_res_t lv_canvas_signal(lv_obj_t * canvas, lv_signal_t sign, void * par /* Include the ancient signal function */ res = ancestor_signal(canvas, sign, param); if(res != LV_RES_OK) return res; - if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME); - - if(sign == LV_SIGNAL_CLEANUP) { + if(sign == LV_SIGNAL_GET_TYPE) { + return _lv_obj_handle_get_type_signal(param, LV_OBJX_NAME); + } + else if(sign == LV_SIGNAL_CLEANUP) { /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ } diff --git a/src/lv_widgets/lv_checkbox.c b/src/lv_widgets/lv_checkbox.c index a8258d159..0da9ab5f5 100644 --- a/src/lv_widgets/lv_checkbox.c +++ b/src/lv_widgets/lv_checkbox.c @@ -12,6 +12,7 @@ #include "../lv_misc/lv_debug.h" #include "../lv_core/lv_group.h" #include "../lv_themes/lv_theme.h" +#include "lv_label.h" /********************* * DEFINES @@ -54,7 +55,7 @@ lv_obj_t * lv_checkbox_create(lv_obj_t * par, const lv_obj_t * copy) LV_LOG_TRACE("check box create started"); /*Create the ancestor basic object*/ - lv_obj_t * cb = lv_label_create(par, copy); + lv_obj_t * cb = lv_obj_create(par, copy); LV_ASSERT_MEM(cb); if(cb == NULL) return NULL; @@ -75,11 +76,12 @@ lv_obj_t * lv_checkbox_create(lv_obj_t * par, const lv_obj_t * copy) /*Init the new checkbox object*/ if(copy == NULL) { - lv_label_set_text_static(cb, "Check box"); + ext->txt = "Check box"; + ext->static_txt = 1; lv_theme_apply(cb, LV_THEME_CHECKBOX); lv_obj_add_flag(cb, LV_OBJ_FLAG_CLICKABLE); lv_obj_add_flag(cb, LV_OBJ_FLAG_CHECKABLE); - + lv_obj_set_size(cb, LV_SIZE_AUTO, LV_SIZE_AUTO); } else { @@ -99,10 +101,87 @@ lv_obj_t * lv_checkbox_create(lv_obj_t * par, const lv_obj_t * copy) * Setter functions *====================*/ +/** + * Set the text of a check box. `txt` will be copied and may be deallocated + * after this function returns. + * @param cb pointer to a check box + * @param txt the text of the check box. NULL to refresh with the current text. + */ +void lv_checkbox_set_text(lv_obj_t * cb, const char * txt) +{ + lv_checkbox_ext_t * ext = lv_obj_get_ext_attr(cb); + size_t len = strlen(txt); + + if(!ext->static_txt) ext->txt = lv_mem_realloc(ext->txt, len + 1); + else ext->txt = lv_mem_alloc(len + 1); + + strcpy(ext->txt, txt); + ext->static_txt = 0; + + if(cb->w_set == LV_SIZE_AUTO || cb->h_set == LV_SIZE_AUTO) { + lv_obj_set_size(cb, cb->w_set, cb->h_set); + } +} + +/** + * Set the text of a check box. `txt` must not be deallocated during the life + * of this checkbox. + * @param cb pointer to a check box + * @param txt the text of the check box. NULL to refresh with the current text. + */ +void lv_checkbox_set_text_static(lv_obj_t * cb, const char * txt) +{ + lv_checkbox_ext_t * ext = lv_obj_get_ext_attr(cb); + + if(!ext->static_txt) lv_mem_free(ext->txt); + + ext->txt = txt; + ext->static_txt = 1; + + if(cb->w_set == LV_SIZE_AUTO || cb->h_set == LV_SIZE_AUTO) { + lv_obj_set_size(cb, cb->w_set, cb->h_set); + } +} + +/** + * Set the state of the check box + * @param cb pointer to a check box object + * @param checked true: make the check box checked; false: make it unchecked + */ +void lv_checkbox_set_checked(lv_obj_t * cb, bool checked) +{ + if(checked) lv_obj_set_state(cb, LV_STATE_CHECKED); + else lv_obj_clear_state(cb, LV_STATE_CHECKED); + _lv_obj_remove_style_trans(cb); +} + +/** + * Make the check box inactive (disabled) + * @param cb pointer to a check box object + * @param dis true; make the checkbox disabled; false: make the chackbox active + */ +void lv_checkbox_set_disabled(lv_obj_t * cb, bool dis) +{ + if(dis) lv_obj_set_state(cb, LV_STATE_DISABLED); + else lv_obj_clear_state(cb, LV_STATE_DISABLED); + _lv_obj_remove_style_trans(cb); +} + /*===================== * Getter functions *====================*/ +/** + * Get the text of a check box + * @param cb pointer to check box object + * @return pointer to the text of the check box + */ +const char * lv_checkbox_get_text(const lv_obj_t * cb) +{ + lv_checkbox_ext_t * ext = lv_obj_get_ext_attr(cb); + return ext->txt; +} + /********************** * STATIC FUNCTIONS **********************/ @@ -129,12 +208,14 @@ static lv_design_res_t lv_checkbox_design(lv_obj_t * cb, const lv_area_t * clip_ lv_checkbox_ext_t * ext = lv_obj_get_ext_attr(cb); const lv_font_t * font = lv_obj_get_style_text_font(cb, LV_CHECKBOX_PART_MAIN); - lv_coord_t line_height = lv_font_get_line_height(font); + lv_coord_t font_h = lv_font_get_line_height(font); lv_coord_t bg_topp = lv_obj_get_style_pad_top(cb, LV_CHECKBOX_PART_MAIN); + lv_coord_t bg_leftp = lv_obj_get_style_pad_left(cb, LV_CHECKBOX_PART_MAIN); lv_coord_t bullet_leftm = lv_obj_get_style_margin_left(cb, LV_CHECKBOX_PART_BULLET); lv_coord_t bullet_topm = lv_obj_get_style_margin_top(cb, LV_CHECKBOX_PART_BULLET); + lv_coord_t bullet_rightm = lv_obj_get_style_margin_right(cb, LV_CHECKBOX_PART_BULLET); lv_coord_t bullet_leftp = lv_obj_get_style_pad_left(cb, LV_CHECKBOX_PART_BULLET); lv_coord_t bullet_rightp = lv_obj_get_style_pad_right(cb, LV_CHECKBOX_PART_BULLET); @@ -145,12 +226,32 @@ static lv_design_res_t lv_checkbox_design(lv_obj_t * cb, const lv_area_t * clip_ lv_draw_rect_dsc_init(&bullet_dsc); lv_obj_init_draw_rect_dsc(cb, LV_CHECKBOX_PART_BULLET, &bullet_dsc); lv_area_t bullet_area; - bullet_area.x1 = cb->coords.x1 + bullet_leftm; - bullet_area.x2 = bullet_area.x1 + line_height + bullet_leftp + bullet_rightp - 1; - bullet_area.y1 = cb->coords.y1 + bg_topp - bullet_topp + bullet_topm; - bullet_area.y2 = bullet_area.y1 + line_height + bullet_topp + bullet_bottomp - 1; + bullet_area.x1 = cb->coords.x1 + bg_leftp + bullet_leftm; + bullet_area.x2 = bullet_area.x1 + font_h + bullet_leftp + bullet_rightp - 1; + bullet_area.y1 = cb->coords.y1 + bg_topp + bullet_topm; + bullet_area.y2 = bullet_area.y1 + font_h + bullet_topp + bullet_bottomp - 1; lv_draw_rect(&bullet_area, clip_area, &bullet_dsc); + + lv_coord_t line_space = lv_obj_get_style_text_line_space(cb, LV_CHECKBOX_PART_MAIN); + lv_coord_t letter_space = lv_obj_get_style_text_letter_space(cb, LV_CHECKBOX_PART_MAIN); + + lv_point_t txt_size; + _lv_txt_get_size(&txt_size, ext->txt, font, letter_space, line_space, LV_COORD_MAX, LV_TXT_FLAG_NONE); + + lv_draw_label_dsc_t txt_dsc; + lv_draw_label_dsc_init(&txt_dsc); + lv_obj_init_draw_label_dsc(cb, LV_CHECKBOX_PART_MAIN, &txt_dsc); + + lv_coord_t y_ofs = (lv_area_get_height(&bullet_area) - font_h) / 2; + lv_area_t txt_area; + txt_area.x1 = bullet_area.x2 + bullet_rightm; + txt_area.x2 = txt_area.x1 + txt_size.x; + txt_area.y1 = cb->coords.y1 + bg_topp + y_ofs; + txt_area.y2 = txt_area.y1 + txt_size.y; + + lv_draw_label(&txt_area, clip_area, &txt_dsc, ext->txt, NULL); + } else { ancestor_design(cb, clip_area, mode); } @@ -166,8 +267,6 @@ static lv_design_res_t lv_checkbox_design(lv_obj_t * cb, const lv_area_t * clip_ */ static lv_res_t lv_checkbox_signal(lv_obj_t * cb, lv_signal_t sign, void * param) { - lv_checkbox_ext_t * ext = lv_obj_get_ext_attr(cb); - lv_res_t res; /* Include the ancient signal function */ res = ancestor_signal(cb, sign, param); @@ -182,6 +281,34 @@ static lv_res_t lv_checkbox_signal(lv_obj_t * cb, lv_signal_t sign, void * param 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; + lv_checkbox_ext_t * ext = lv_obj_get_ext_attr(cb); + + const lv_font_t * font = lv_obj_get_style_text_font(cb, LV_CHECKBOX_PART_MAIN); + lv_coord_t font_h = lv_font_get_line_height(font); + lv_coord_t line_space = lv_obj_get_style_text_line_space(cb, LV_CHECKBOX_PART_MAIN); + lv_coord_t letter_space = lv_obj_get_style_text_letter_space(cb, LV_CHECKBOX_PART_MAIN); + + lv_point_t txt_size; + _lv_txt_get_size(&txt_size, ext->txt, font, letter_space, line_space, LV_COORD_MAX, LV_TXT_FLAG_NONE); + + lv_coord_t bullet_leftm = lv_obj_get_style_margin_left(cb, LV_CHECKBOX_PART_BULLET); + lv_coord_t bullet_topm = lv_obj_get_style_margin_top(cb, LV_CHECKBOX_PART_BULLET); + lv_coord_t bullet_rightm = lv_obj_get_style_margin_right(cb, LV_CHECKBOX_PART_BULLET); + lv_coord_t bullet_bottomm = lv_obj_get_style_margin_bottom(cb, LV_CHECKBOX_PART_BULLET); + lv_coord_t bullet_leftp = lv_obj_get_style_pad_left(cb, LV_CHECKBOX_PART_BULLET); + lv_coord_t bullet_rightp = lv_obj_get_style_pad_right(cb, LV_CHECKBOX_PART_BULLET); + lv_coord_t bullet_topp = lv_obj_get_style_pad_top(cb, LV_CHECKBOX_PART_BULLET); + lv_coord_t bullet_bottomp = lv_obj_get_style_pad_bottom(cb, LV_CHECKBOX_PART_BULLET); + lv_point_t bullet_size; + bullet_size.x = font_h + bullet_leftm + bullet_rightm + bullet_leftp + bullet_rightp; + bullet_size.y = font_h + bullet_topm + bullet_bottomm + bullet_topp + bullet_bottomp; + + p->x = bullet_size.x + txt_size.x; + p->y = LV_MATH_MAX(bullet_size.y, txt_size.y); + + } return res; } diff --git a/src/lv_widgets/lv_checkbox.h b/src/lv_widgets/lv_checkbox.h index 43753b845..a635dbf0d 100644 --- a/src/lv_widgets/lv_checkbox.h +++ b/src/lv_widgets/lv_checkbox.h @@ -14,20 +14,15 @@ extern "C" { * INCLUDES *********************/ #include "../lv_conf_internal.h" +#include "../lv_core/lv_obj.h" #if LV_USE_CHECKBOX != 0 /*Testing of dependencies*/ -#if LV_USE_BTN == 0 -#error "lv_cb: lv_btn is required. Enable it in lv_conf.h (LV_USE_BTN 1) " -#endif - #if LV_USE_LABEL == 0 #error "lv_cb: lv_label is required. Enable it in lv_conf.h (LV_USE_LABEL 1) " #endif -#include "lv_label.h" - /********************* * DEFINES *********************/ @@ -38,10 +33,10 @@ extern "C" { /*Data of check box*/ typedef struct { - lv_label_ext_t label_ext; - /*New data for this widget */ lv_style_list_t style_bullet; + char * txt; + uint32_t static_txt :1; } lv_checkbox_ext_t; /** Checkbox styles. */ @@ -68,65 +63,24 @@ lv_obj_t * lv_checkbox_create(lv_obj_t * par, const lv_obj_t * copy); * Setter functions *====================*/ - -/** - * Set the text of a check box. `txt` will be copied and may be deallocated - * after this function returns. - * @param cb pointer to a check box - * @param txt the text of the check box. NULL to refresh with the current text. - */ -static inline void lv_checkbox_set_text(lv_obj_t * cb, const char * txt) -{ - lv_label_set_text(cb, txt); -} - -/** - * Set the text of a check box. `txt` must not be deallocated during the life - * of this checkbox. - * @param cb pointer to a check box - * @param txt the text of the check box. NULL to refresh with the current text. - */ -static inline void lv_checkbox_set_text_static(lv_obj_t * cb, const char * txt) -{ - lv_label_set_text_static(cb, txt); -} - /** * Set the state of the check box * @param cb pointer to a check box object * @param checked true: make the check box checked; false: make it unchecked */ -static inline void lv_checkbox_set_checked(lv_obj_t * cb, bool checked) -{ - if(checked) lv_obj_set_state(cb, LV_STATE_CHECKED); - else lv_obj_clear_state(cb, LV_STATE_CHECKED); -} +void lv_checkbox_set_checked(lv_obj_t * cb, bool checked); /** * Make the check box inactive (disabled) * @param cb pointer to a check box object - * @param dis true; make the checkbox disabled; false: make the chackbox active + * @param dis true; make the checkbox disabled; false: make the checkbox active */ -static inline void lv_checkbox_set_disabled(lv_obj_t * cb, bool dis) -{ - if(dis) lv_obj_set_state(cb, LV_STATE_DISABLED); - else lv_obj_clear_state(cb, LV_STATE_DISABLED); -} +void lv_checkbox_set_disabled(lv_obj_t * cb, bool dis); /*===================== * Getter functions *====================*/ -/** - * Get the text of a check box - * @param cb pointer to check box object - * @return pointer to the text of the check box - */ -static inline const char * lv_checkbox_get_text(const lv_obj_t * cb) -{ - return lv_label_get_text(cb); -} - /** * Get the current state of the check box * @param cb pointer to a check box object