From d987f08be97ba2348aaae78dc14afe155ce70887 Mon Sep 17 00:00:00 2001 From: Gabor Date: Mon, 20 Jun 2016 18:18:36 +0200 Subject: [PATCH] Layouts: COL_R/M/L and ROW_T/M/B implemented. --- lv_misc/anim.c | 1 + lv_obj/lv_obj.c | 219 ++++++++++++++++++++++++++++++++++++++++++++- lv_obj/lv_obj.h | 70 +++++++-------- lv_objx/lv_btn.c | 22 ++--- lv_objx/lv_label.c | 9 +- lv_objx/lv_rect.c | 56 +++++++++--- 6 files changed, 311 insertions(+), 66 deletions(-) diff --git a/lv_misc/anim.c b/lv_misc/anim.c index 5d6417123..ab415d68c 100644 --- a/lv_misc/anim.c +++ b/lv_misc/anim.c @@ -8,6 +8,7 @@ *********************/ #include #include +#include "lvgl/lvgl.h" /********************* * DEFINES diff --git a/lv_obj/lv_obj.c b/lv_obj/lv_obj.c index 3ad0ed2a4..a7c1cffaa 100644 --- a/lv_obj/lv_obj.c +++ b/lv_obj/lv_obj.c @@ -11,6 +11,7 @@ #include "../lv_draw/lv_draw_vbasic.h" #include "lv_dispi.h" #include "lv_refr.h" +#include "misc/math/math_base.h" /********************* * DEFINES @@ -26,6 +27,9 @@ static void lv_obj_pos_child_refr(lv_obj_t* obj_dp, cord_t x_diff, cord_t y_diff); static void lv_style_refr_core(void * style_p, lv_obj_t* obj_dp); static bool lv_obj_design(lv_obj_t* obj_dp, const area_t * mask_p, lv_design_mode_t mode); +static void lv_obj_refr_layout(lv_obj_t * obj_dp); +static void lv_layout_col(lv_obj_t * obj_dp); +static void lv_layout_row(lv_obj_t * obj_dp); /********************** * STATIC VARIABLES @@ -303,6 +307,20 @@ bool lv_obj_signal(lv_obj_t* obj_dp, lv_signal_t sign, void * param) bool valid = true; switch(sign) { + case LV_SIGNAL_CHILD_CHG: + lv_obj_refr_layout(obj_dp); + break; + case LV_SIGNAL_CORD_CHG: + if(param == NULL) + { + break; + } + + if(lv_obj_get_width(obj_dp) != area_get_width(param) || + lv_obj_get_height(obj_dp) != area_get_height(param)) { + lv_obj_refr_layout(obj_dp); + } + break; default: break; } @@ -417,6 +435,9 @@ void lv_obj_set_pos(lv_obj_t* obj_dp, cord_t x, cord_t y) point_t diff; diff.x = x - obj_dp->cords.x1; diff.y = y - obj_dp->cords.y1; + + /*Do nothing if the position is not changed*/ + if(diff.x == 0 && diff.y == 0) return; obj_dp->cords.x1 += diff.x; obj_dp->cords.y1 += diff.y; @@ -570,6 +591,40 @@ void lv_obj_set_height_us(lv_obj_t* obj_dp, cord_t h) lv_obj_set_size(obj_dp, lv_obj_get_width(obj_dp), h * LV_DOWNSCALE); } + +/** + * Set a layout for an object. + * @param obj_dp pointer to an object + * @param layout type of the layout (an element from lv_layout_t) + */ +void lv_obj_set_layout(lv_obj_t* obj_dp, lv_layout_t layout) +{ + obj_dp->layout_type = layout; + obj_dp->signal_f(obj_dp, LV_SIGNAL_CHILD_CHG, NULL); +} + +/** + * Set the layout spacing for an object. + * @param obj_dp pointer to an object + * @param space space between object on the layout (space / 2 on edges) + */ +void lv_obj_set_layout_space(lv_obj_t * obj_dp, cord_t space) +{ + obj_dp->layout_space = space; + obj_dp->signal_f(obj_dp, LV_SIGNAL_CHILD_CHG, NULL); +} + +/** + * Set the layout spacing for an object. + * The space will be upscaled to compensate LV_DOWNSCALE + * @param obj_dp pointer to an object + * @param space space between object on the layout (space / 2 on edges) + */ +void lv_obj_set_layout_space_us(lv_obj_t * obj_dp, cord_t space) +{ + lv_obj_set_layout_space(obj_dp, space * LV_DOWNSCALE); +} + /** * Align an object to an other object. * @param obj_dp pointer to an object to align @@ -699,11 +754,16 @@ void lv_obj_align(lv_obj_t* obj_dp,lv_obj_t* base_dp, lv_align_t align, cord_t x cord_t base_abs_y = base_dp->cords.y1; cord_t par_abs_x = par_dp->cords.x1; cord_t par_abs_y = par_dp->cords.y1; + new_x += x_mod + base_abs_x; + new_y += y_mod + base_abs_y; - new_x -= par_abs_x - base_abs_x; - new_y -= par_abs_y - base_abs_y; - - lv_obj_set_pos(obj_dp, new_x + x_mod, new_y + y_mod); + if(new_x != obj_dp->cords.x1 || new_y != obj_dp->cords.y1) { + + new_x -= par_abs_x; + new_y -= par_abs_y; + + lv_obj_set_pos(obj_dp, new_x, new_y); + } } @@ -1056,6 +1116,26 @@ cord_t lv_obj_get_height(lv_obj_t* obj_dp) return area_get_height(&obj_dp->cords); } +/** + * Get the layout type of an object + * @param obj_dp pointer to an object + * @return type of the layout (from lv_layout_t) + */ +lv_layout_t lv_obj_get_layout(lv_obj_t * obj_dp) +{ + return obj_dp->layout_type; +} + +/** + * Get the layout space of an object + * @param obj_dp pointer to an object + * @return the layout space + */ +cord_t lv_obj_get_layout_space(lv_obj_t * obj_dp) +{ + return obj_dp->layout_space; +} + /*----------------- * Appearance get *---------------*/ @@ -1275,3 +1355,134 @@ static void lv_style_refr_core(void * style_p, lv_obj_t* obj_dp) lv_style_refr_core(style_p, i); } } + + +/** + * Refresh the layout of an object + * @param obj_dp pointer to an object which layout should be refreshed + */ +static void lv_obj_refr_layout(lv_obj_t * obj_dp) +{ + lv_layout_t type = obj_dp->layout_type; + + if(type == LV_LAYOUT_OFF) return; + + if(type == LV_LAYOUT_COL_L || type == LV_LAYOUT_COL_M || type == LV_LAYOUT_COL_R) { + lv_layout_col(obj_dp); + } else if(type == LV_LAYOUT_ROW_T || type == LV_LAYOUT_ROW_M || type == LV_LAYOUT_ROW_B) { + lv_layout_row(obj_dp); + } +} + + +/** + * Handle column type layouts + * @param obj_dp pointer to an object which layout should be handled + */ +static void lv_layout_col(lv_obj_t * obj_dp) +{ + lv_layout_t type = lv_obj_get_layout(obj_dp); + cord_t space = lv_obj_get_layout_space(obj_dp); /*Space between objects*/ + cord_t margin = abs(space); /*Margin by the parent*/ + + lv_obj_t * child; + /*Recalculate space in justified mode*/ + if(space < 0) { + uint32_t h_tot = 0; + uint32_t obj_cnt = 0; + LL_READ(obj_dp->child_ll, child) { + h_tot += lv_obj_get_height(child); + obj_cnt ++; + } + + if(obj_cnt == 0) return; + space = lv_obj_get_height(parent_dp) - h_tot; + + if(obj_cnt == 5) { + obj_cnt = 5; + } + + space = space / (cord_t)obj_cnt; + } + + /*Adjust margin and get the alignment type*/ + lv_align_t align; + switch(type) { + case LV_LAYOUT_COL_L: + align = LV_ALIGN_IN_TOP_LEFT; + margin = margin / 2; + break; + case LV_LAYOUT_COL_M: + align = LV_ALIGN_IN_TOP_MID; + margin = 0; + break; + case LV_LAYOUT_COL_R: + align = LV_ALIGN_IN_TOP_RIGHT; + margin = -(margin / 2); + break; + default: + align = LV_ALIGN_IN_TOP_LEFT; + margin = 0; + break; + } + + cord_t last_cord = space / 2; + LL_READ_BACK(obj_dp->child_ll, child) { + lv_obj_align(child, parent_dp, align, margin , last_cord); + last_cord += lv_obj_get_height(child) + space; + } +} + +/** + * Handle row type layouts + * @param obj_dp pointer to an object which layout should be handled + */ +static void lv_layout_row(lv_obj_t * obj_dp) +{ + lv_layout_t type = lv_obj_get_layout(obj_dp); + cord_t space = lv_obj_get_layout_space(obj_dp); /*Space between objects*/ + cord_t margin = abs(space); /*Margin by the parent*/ + + lv_obj_t * child; + /*Recalculate space in justified mode*/ + if(space < 0) { + uint32_t w_tot = 0; + uint32_t obj_cnt = 0; + LL_READ(obj_dp->child_ll, child) { + w_tot += lv_obj_get_width(child); + obj_cnt ++; + } + + if(obj_cnt == 0) return; + space = lv_obj_get_width(obj_dp) - w_tot; + space = space / (cord_t)obj_cnt; + } + + /*Adjust margin and get the alignment type*/ + lv_align_t align; + switch(type) { + case LV_LAYOUT_ROW_T: + align = LV_ALIGN_IN_TOP_LEFT; + margin = margin / 2; + break; + case LV_LAYOUT_ROW_M: + align = LV_ALIGN_IN_LEFT_MID; + margin = 0; + break; + case LV_LAYOUT_ROW_B: + align = LV_ALIGN_IN_BOTTOM_LEFT; + margin = -(margin / 2); + break; + default: + align = LV_ALIGN_IN_TOP_LEFT; + margin = 0; + break; + } + + cord_t last_cord = space / 2; + LL_READ_BACK(obj_dp->child_ll, child) { + lv_obj_align(child, obj_dp, align, last_cord, margin); + last_cord += lv_obj_get_width(child) + space; + } +} + diff --git a/lv_obj/lv_obj.h b/lv_obj/lv_obj.h index e0ed4e631..fe33d35e6 100644 --- a/lv_obj/lv_obj.h +++ b/lv_obj/lv_obj.h @@ -70,6 +70,18 @@ typedef enum LV_SIGNAL_STYLE_CHG, }lv_signal_t; + +typedef enum +{ + LV_LAYOUT_OFF = 0, + LV_LAYOUT_COL_L, + LV_LAYOUT_COL_M, + LV_LAYOUT_COL_R, + LV_LAYOUT_ROW_T, + LV_LAYOUT_ROW_M, + LV_LAYOUT_ROW_B, +}lv_layout_t; + typedef bool (* lv_signal_f_t) (struct __LV_OBJ_T* obj_dp, lv_signal_t sign, void * param); typedef struct __LV_OBJ_T @@ -78,9 +90,20 @@ typedef struct __LV_OBJ_T ll_dsc_t child_ll; area_t cords; + + lv_signal_f_t signal_f; + lv_design_f_t design_f; - /*Basic appearance*/ - opa_t opa; + void * ext_dp; /*The object attributes can be extended here*/ + void * style_p; /*Object specific style*/ + +#if LV_OBJ_FREE_P != 0 + void * free_p; /*Application specific pointer (set it freely)*/ +#endif + + /*Layout settings*/ + cord_t layout_space; + uint8_t layout_type; /*Attributes and states*/ uint8_t click_en :1; /*1: can be pressed by a display input device*/ @@ -91,18 +114,11 @@ typedef struct __LV_OBJ_T uint8_t hidden :1; /*1: Object is hidden*/ uint8_t top_en :1; /*1: If the object or its children is clicked it goes to the foreground*/ uint8_t res :1; - + + opa_t opa; + uint8_t free_num; /*Application specific identifier (set it freely)*/ - lv_signal_f_t signal_f; - lv_design_f_t design_f; - - void * ext_dp; /*The object attributes can be extended here*/ - void * style_p; /*Object specific style*/ - -#if LV_OBJ_FREE_P != 0 - void * free_p; /*Application specific pointer (set it freely)*/ -#endif }lv_obj_t; typedef enum @@ -131,31 +147,6 @@ typedef enum }lv_align_t; -/*Layout type. Use the OR connection of the bits*/ -typedef enum -{ - /*[0] bit*/ - LV_LAYOUT_COL = 0 << 0, - LV_LAYOUT_ROW = 1 << 0, - /*[1..2] bit: horizontal alignment*/ - LV_LAYOUT_H_LEFT = 0 << 1, - LV_LAYOUT_H_MID = 1 << 1, - LV_LAYOUT_H_RIGHT = 2 << 1, - LV_LAYOUT_H_JUSTIFY = 3 << 1, - /*[3..4] bit: vertical alignment*/ - LV_LAYOUT_V_TOP = 0 << 3, - LV_LAYOUT_V_MID = 1 << 3, - LV_LAYOUT_V_BOTTOM = 2 << 3, - LV_LAYOUT_V_JUSTIFY = 3 << 3, - /*[5] bit don't exceed the parent width (in ROW) or height (in COL)*/ - LV_LAYOUT_KEEP_SIZE = 1 << 5, - /*[6] bit put more object in a row/col if possible*/ - LV_LAYOUT_FILL = 1 << 6, - /*[7] bit: don't use layout*/ - LV_LAYOUT_OFF = 1 << 7, -}lv_layout_t; - - typedef struct { color_t color; @@ -198,6 +189,9 @@ void lv_obj_set_width(lv_obj_t* obj_dp, cord_t w); void lv_obj_set_width_us(lv_obj_t* obj_dp, cord_t w); void lv_obj_set_height(lv_obj_t* obj_dp, cord_t h); void lv_obj_set_height_us(lv_obj_t* obj_dp, cord_t h); +void lv_obj_set_layout(lv_obj_t* obj_dp, lv_layout_t layout); +void lv_obj_set_layout_space(lv_obj_t * obj_dp, cord_t space); +void lv_obj_set_layout_space_us(lv_obj_t * obj_dp, cord_t space); void lv_obj_align(lv_obj_t* obj_dp,lv_obj_t* base_dp, lv_align_t align, cord_t x_mod, cord_t y_mod); void lv_obj_align_us(lv_obj_t* obj_dp,lv_obj_t* base_dp, lv_align_t align, cord_t x_mod, cord_t y_mod); /*Appearance set*/ @@ -234,6 +228,8 @@ cord_t lv_obj_get_x(lv_obj_t* obj_dp); cord_t lv_obj_get_y(lv_obj_t* obj_dp); cord_t lv_obj_get_width(lv_obj_t* obj_dp); cord_t lv_obj_get_height(lv_obj_t* obj_dp); +lv_layout_t lv_obj_get_layout(lv_obj_t * obj_dp); +cord_t lv_obj_get_layout_space(lv_obj_t * obj_dp); /*Appearance get*/ bool lv_obj_get_hidden(lv_obj_t* obj_dp); opa_t lv_obj_get_opa(lv_obj_t* obj_dp); diff --git a/lv_objx/lv_btn.c b/lv_objx/lv_btn.c index f8b296816..1d25f442f 100644 --- a/lv_objx/lv_btn.c +++ b/lv_objx/lv_btn.c @@ -60,8 +60,8 @@ static lv_btns_t lv_btns_def = .rects.bopa = 50, .rects.empty = 0, .rects.round = 4 * LV_STYLE_MULT, - .rects.hpad = 10 * LV_STYLE_MULT, - .rects.vpad = 15 * LV_STYLE_MULT, + .rects.hpad = 14 * LV_STYLE_MULT, + .rects.vpad = 10 * LV_STYLE_MULT, }; static lv_btns_t lv_btns_transp = { @@ -102,15 +102,15 @@ static lv_btns_t lv_btns_border = */ lv_obj_t* lv_btn_create(lv_obj_t* par_dp, lv_obj_t * copy_dp) { - lv_obj_t* new_obj; + lv_obj_t* new_obj_dp; - new_obj = lv_rect_create(par_dp, copy_dp); + new_obj_dp = lv_rect_create(par_dp, copy_dp); /*Allocate the extended data*/ - lv_obj_alloc_ext(new_obj, sizeof(lv_btn_ext_t)); - lv_obj_set_signal_f(new_obj, lv_btn_signal); - lv_obj_set_design_f(new_obj, lv_btn_design); + lv_obj_alloc_ext(new_obj_dp, sizeof(lv_btn_ext_t)); + lv_obj_set_signal_f(new_obj_dp, lv_btn_signal); + lv_obj_set_design_f(new_obj_dp, lv_btn_design); - lv_btn_ext_t * btn_ext_dp = lv_obj_get_ext(new_obj); + lv_btn_ext_t * btn_ext_dp = lv_obj_get_ext(new_obj_dp); btn_ext_dp->lpr_exec = 0; /*If no copy do the basic initialization*/ @@ -121,7 +121,9 @@ lv_obj_t* lv_btn_create(lv_obj_t* par_dp, lv_obj_t * copy_dp) btn_ext_dp->rel_action = NULL; btn_ext_dp->lpr_action = NULL; btn_ext_dp->tgl = 0; - lv_obj_set_style(new_obj, &lv_btns_def); + lv_obj_set_style(new_obj_dp, &lv_btns_def); + lv_obj_set_layout(new_obj_dp, LV_LAYOUT_ROW_M); + lv_obj_set_layout_space_us(new_obj_dp, 10); /*Justified align*/ } /*Copy 'copy_dp'*/ else{ @@ -133,7 +135,7 @@ lv_obj_t* lv_btn_create(lv_obj_t* par_dp, lv_obj_t * copy_dp) btn_ext_dp->tgl = ori_btn_ext->tgl; } - return new_obj; + return new_obj_dp; } /** diff --git a/lv_objx/lv_label.c b/lv_objx/lv_label.c index aff574326..34a4e1151 100644 --- a/lv_objx/lv_label.c +++ b/lv_objx/lv_label.c @@ -199,11 +199,12 @@ void lv_label_set_text(lv_obj_t * obj_dp, const char * text) /*Correction with the last line space*/ new_height -= labels_p->line_space; - lv_obj_set_height(obj_dp, new_height); - - /*Refresh the length if no fix width*/ if(ext_p->fixw == 0) { - lv_obj_set_width(obj_dp, longest_line); + /*Refresh the full size */ + lv_obj_set_size(obj_dp, longest_line, new_height); + } else { + /*With fix width only the height can change*/ + lv_obj_set_height(obj_dp, new_height); } lv_obj_t * parent_dp = lv_obj_get_parent(obj_dp); diff --git a/lv_objx/lv_rect.c b/lv_objx/lv_rect.c index 0e3e6c6fc..16716b893 100644 --- a/lv_objx/lv_rect.c +++ b/lv_objx/lv_rect.c @@ -103,6 +103,8 @@ bool lv_rect_signal(lv_obj_t* obj_dp, lv_signal_t sign, void * param) lv_rects_t * rects_p = lv_obj_get_style(obj_dp); lv_rect_ext_t * ext_p = lv_obj_get_ext(obj_dp); lv_obj_t * i; + cord_t hpad = rects_p->hpad; + cord_t vpad = rects_p->vpad; /* The object can be deleted so check its validity and then * make the object specific signal handling */ @@ -114,6 +116,39 @@ bool lv_rect_signal(lv_obj_t* obj_dp, lv_signal_t sign, void * param) ext_p->vpad_en == 0) { break; } + + /*Override the padding values according to the layout settings*/ + cord_t layout_space = lv_obj_get_layout_space(obj_dp); + lv_layout_t layout_type = lv_obj_get_layout(obj_dp); + + if(lv_obj_get_layout(obj_dp) != LV_LAYOUT_OFF) { + /* Non-justified case: use the half layout space because + * the layout use this as well on the edges. + * Else padding and layout makes an infinite loop */ + if(layout_space >= 0) { + hpad = layout_space / 2; + vpad = hpad; + } else { /*Justified cases*/ + /*The rectangle can increase infinitely with wrong settings*/ + /*COL layouts: set vpad to 0 */ + /*ROW layouts: set hpad to 0 */ + if(layout_type == LV_LAYOUT_COL_L || + layout_type == LV_LAYOUT_COL_M || + layout_type == LV_LAYOUT_COL_R) { + vpad = 0; + hpad = (-layout_space) / 2; + } else if(layout_type == LV_LAYOUT_ROW_T || + layout_type == LV_LAYOUT_ROW_M || + layout_type == LV_LAYOUT_ROW_B) { + hpad = 0; + vpad = (-layout_space) / 2; + } else { + /*Never happens*/ + break; + } + } + } + /*Search the side coordinates of the children*/ lv_obj_get_cords(obj_dp, &rect_cords); rect_cords.x1 = LV_CORD_MAX; @@ -131,15 +166,15 @@ bool lv_rect_signal(lv_obj_t* obj_dp, lv_signal_t sign, void * param) /*If the value is not the init value then the page has >=1 child.*/ if(rect_cords.x1 != LV_CORD_MAX) { if(ext_p->hpad_en != 0) { - rect_cords.x1 -= rects_p->hpad; - rect_cords.x2 += rects_p->hpad; + rect_cords.x1 -= hpad; + rect_cords.x2 += hpad; } else { rect_cords.x1 = obj_dp->cords.x1; rect_cords.x2 = obj_dp->cords.x2; } if(ext_p->vpad_en != 0) { - rect_cords.y1 -= rects_p->vpad; - rect_cords.y2 += rects_p->vpad; + rect_cords.y1 -= vpad; + rect_cords.y2 += vpad; } else { rect_cords.y1 = obj_dp->cords.y1; rect_cords.y2 = obj_dp->cords.y2; @@ -148,6 +183,9 @@ bool lv_rect_signal(lv_obj_t* obj_dp, lv_signal_t sign, void * param) lv_obj_set_pos(obj_dp, lv_obj_get_x(obj_dp), lv_obj_get_y(obj_dp)); + + lv_obj_t * par_dp = lv_obj_get_parent(obj_dp); + par_dp->signal_f(par_dp, LV_SIGNAL_CHILD_CHG, obj_dp); } else { lv_obj_set_size(obj_dp, LV_OBJ_DEF_WIDTH, LV_OBJ_DEF_HEIGHT); } @@ -180,6 +218,9 @@ void lv_rect_set_pad_en(lv_obj_t * obj_dp, bool hor_en, bool ver_en) ext_p->vpad_en = ver_en == false ? 0 : 1; obj_dp->signal_f(obj_dp, LV_SIGNAL_STYLE_CHG, obj_dp); + + lv_obj_t * par_dp = lv_obj_get_parent(obj_dp); + par_dp->signal_f(par_dp, LV_SIGNAL_CHILD_CHG, obj_dp); } /*===================== @@ -240,15 +281,8 @@ lv_rects_t * lv_rects_get(lv_rects_builtin_t style, lv_rects_t * copy_p) return style_p; } -/*===================== - * Setter functions - *====================*/ -/*===================== - * Getter functions - *====================*/ - /********************** * STATIC FUNCTIONS **********************/