/** * @file lv_obj_pos.c * */ /********************* * INCLUDES *********************/ #include "lv_obj.h" /********************* * DEFINES *********************/ #define LV_OBJX_NAME "lv_obj" /********************** * TYPEDEFS **********************/ /********************** * STATIC PROTOTYPES **********************/ static bool refr_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h); /********************** * STATIC VARIABLES **********************/ /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ /** * Set relative the position of an object (relative to the parent) * @param obj pointer to an object * @param x new distance from the left side of the parent plus the parent's left padding or a grid cell * @param y new distance from the top side of the parent plus the parent's right padding or a grid cell * @note Zero value value means place the object is on the left padding of the parent, and not on the left edge. * @note A grid cell can be and explicit placement with cell position and span: * `LV_GRID_CELL_START/END/CENTER/STRETCH(pos, span)` * or "auto" to place the object on the grid in the creation order of other children * `LV_GRID_AUTO_START/END/CENTER/STRETCH` * @note to use grid placement the parent needs have a defined grid with `lv_obj_set_grid` */ void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); obj->x_set = x; obj->y_set = y; bool gi = _lv_obj_is_grid_item(obj); bool fi = _lv_obj_is_flex_item(obj); /*For consistency set the size to stretched if the objects is stretched on the grid*/ if(gi) { if(LV_GRID_GET_CELL_PLACE(obj->x_set) == LV_GRID_STRETCH) obj->w_set = LV_SIZE_STRETCH; if(LV_GRID_GET_CELL_PLACE(obj->y_set) == LV_GRID_STRETCH) obj->h_set = LV_SIZE_STRETCH; } /*If not grid or flex item but has grid or flex position set the position to 0*/ if(!gi) { if(LV_COORD_IS_GRID(x)) x = 0; if(LV_COORD_IS_GRID(y)) y = 0; } if(!fi) { if(LV_COORD_IS_FLEX(x)) x = 0; if(LV_COORD_IS_FLEX(y)) y = 0; } /*If the object is on a grid item let the grid to position it. */ if(gi) { lv_grid_item_refr_pos(obj); } else if(fi) { _lv_flex_refresh(lv_obj_get_parent(obj)); } else { _lv_obj_move_to(obj, x, y, true); } } /** * Set the x coordinate of a object * @param obj pointer to an object * @param x new distance from the left side from the parent plus the parent's left padding or a grid cell */ void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_obj_set_pos(obj, x, obj->y_set); } /** * Set the y coordinate of a object * @param obj pointer to an object * @param y new distance from the top of the parent plus the parent's top padding or a grid cell */ void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_obj_set_pos(obj, obj->x_set, y); } /** * Set the size of an object. * @param obj pointer to an object * @param w new width in pixels or `LV_SIZE_AUTO` to set the size to involve all children * @param h new height in pixels or `LV_SIZE_AUTO` to set the size to involve all children */ void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); bool gi = _lv_obj_is_grid_item(obj); bool fi = _lv_obj_is_flex_item(obj); bool x_stretch = false; bool y_stretch = false; if(gi) { x_stretch = LV_GRID_GET_CELL_PLACE(obj->x_set) == LV_GRID_STRETCH ? true : false; y_stretch = LV_GRID_GET_CELL_PLACE(obj->y_set) == LV_GRID_STRETCH ? true : false; if(x_stretch) w = LV_SIZE_STRETCH; if(y_stretch) h = LV_SIZE_STRETCH; } obj->w_set = w; obj->h_set = h; /*If both stretched the size is managed by the grid*/ if(x_stretch && y_stretch) return; if(x_stretch) w = lv_obj_get_width(obj); if(y_stretch) h = lv_obj_get_height(obj); /*Calculate the required auto sizes*/ 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); if(x_auto && y_auto) _lv_obj_calc_auto_size(obj, &w, &h); else if(x_auto) _lv_obj_calc_auto_size(obj, &w, NULL); else if(y_auto) _lv_obj_calc_auto_size(obj, NULL, &h); /*Calculate the required auto sizes*/ bool pct_w = LV_COORD_IS_PCT(obj->w_set) ? true : false; bool pct_h = LV_COORD_IS_PCT(obj->h_set) ? true : false; lv_obj_t * parent = lv_obj_get_parent(obj); if(parent) { lv_coord_t cont_w = lv_obj_get_width_fit(parent); lv_coord_t cont_h = lv_obj_get_height_fit(parent); if(pct_w) w = (_LV_COORD_GET_PCT(obj->w_set) * cont_w) / 100; if(pct_h) h = (_LV_COORD_GET_PCT(obj->h_set) * cont_h) / 100; } refr_size(obj, w, h); } /** * Set the width of an object * @param obj pointer to an object * @param w new width in pixels or `LV_SIZE_AUTO` to set the size to involve all children */ void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_obj_set_size(obj, w, obj->h_set); } /** * Set the height of an object * @param obj pointer to an object * @param h new height in pixels or `LV_SIZE_AUTO` to set the size to involve all children */ void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_obj_set_size(obj, obj->w_set, h); } /** * Set the width reduced by the left and right padding. * @param obj pointer to an object * @param w the width without paddings in pixels */ void lv_obj_set_content_width(lv_obj_t * obj, lv_coord_t w) { lv_style_int_t pleft = lv_obj_get_style_pad_left(obj, LV_OBJ_PART_MAIN); lv_style_int_t pright = lv_obj_get_style_pad_right(obj, LV_OBJ_PART_MAIN); lv_obj_set_width(obj, w + pleft + pright); } /** * Set the height reduced by the top and bottom padding. * @param obj pointer to an object * @param h the height without paddings in pixels */ void lv_obj_set_content_height(lv_obj_t * obj, lv_coord_t h) { lv_style_int_t ptop = lv_obj_get_style_pad_top(obj, LV_OBJ_PART_MAIN); lv_style_int_t pbottom = lv_obj_get_style_pad_bottom(obj, LV_OBJ_PART_MAIN); lv_obj_set_height(obj, h + ptop + pbottom); } /** * Set the width of an object by taking the left and right margin into account. * The object width will be `obj_w = w - margin_left - margin_right` * @param obj pointer to an object * @param w new height including margins in pixels */ void lv_obj_set_width_margin(lv_obj_t * obj, lv_coord_t w) { lv_style_int_t mleft = lv_obj_get_style_margin_left(obj, LV_OBJ_PART_MAIN); lv_style_int_t mright = lv_obj_get_style_margin_right(obj, LV_OBJ_PART_MAIN); lv_obj_set_width(obj, w - mleft - mright); } /** * Set the height of an object by taking the top and bottom margin into account. * The object height will be `obj_h = h - margin_top - margin_bottom` * @param obj pointer to an object * @param h new height including margins in pixels */ void lv_obj_set_height_margin(lv_obj_t * obj, lv_coord_t h) { lv_style_int_t mtop = lv_obj_get_style_margin_top(obj, LV_OBJ_PART_MAIN); lv_style_int_t mbottom = lv_obj_get_style_margin_bottom(obj, LV_OBJ_PART_MAIN); lv_obj_set_height(obj, h - mtop - mbottom); } /** * Align an object to an other object. * @param obj pointer to an object to align * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. * @param align type of alignment (see 'lv_align_t' enum) * @param x_ofs x coordinate offset after alignment * @param y_ofs y coordinate offset after alignment */ void lv_obj_align(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); if(base == NULL) base = lv_obj_get_parent(obj); LV_ASSERT_OBJ(base, LV_OBJX_NAME); lv_coord_t x; lv_coord_t y; switch(align) { case LV_ALIGN_CENTER: x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; break; case LV_ALIGN_IN_TOP_LEFT: x = 0; y = 0; break; case LV_ALIGN_IN_TOP_MID: x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; y = 0; break; case LV_ALIGN_IN_TOP_RIGHT: x = lv_obj_get_width(base) - lv_obj_get_width(obj); y = 0; break; case LV_ALIGN_IN_BOTTOM_LEFT: x = 0; y = lv_obj_get_height(base) - lv_obj_get_height(obj); break; case LV_ALIGN_IN_BOTTOM_MID: x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; y = lv_obj_get_height(base) - lv_obj_get_height(obj); break; case LV_ALIGN_IN_BOTTOM_RIGHT: x = lv_obj_get_width(base) - lv_obj_get_width(obj); y = lv_obj_get_height(base) - lv_obj_get_height(obj); break; case LV_ALIGN_IN_LEFT_MID: x = 0; y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; break; case LV_ALIGN_IN_RIGHT_MID: x = lv_obj_get_width(base) - lv_obj_get_width(obj); y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; break; case LV_ALIGN_OUT_TOP_LEFT: x = 0; y = -lv_obj_get_height(obj); break; case LV_ALIGN_OUT_TOP_MID: x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; y = -lv_obj_get_height(obj); break; case LV_ALIGN_OUT_TOP_RIGHT: x = lv_obj_get_width(base) - lv_obj_get_width(obj); y = -lv_obj_get_height(obj); break; case LV_ALIGN_OUT_BOTTOM_LEFT: x = 0; y = lv_obj_get_height(base); break; case LV_ALIGN_OUT_BOTTOM_MID: x = lv_obj_get_width(base) / 2 - lv_obj_get_width(obj) / 2; y = lv_obj_get_height(base); break; case LV_ALIGN_OUT_BOTTOM_RIGHT: x = lv_obj_get_width(base) - lv_obj_get_width(obj); y = lv_obj_get_height(base); break; case LV_ALIGN_OUT_LEFT_TOP: x = -lv_obj_get_width(obj); y = 0; break; case LV_ALIGN_OUT_LEFT_MID: x = -lv_obj_get_width(obj); y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; break; case LV_ALIGN_OUT_LEFT_BOTTOM: x = -lv_obj_get_width(obj); y = lv_obj_get_height(base) - lv_obj_get_height(obj); break; case LV_ALIGN_OUT_RIGHT_TOP: x = lv_obj_get_width(base); y = 0; break; case LV_ALIGN_OUT_RIGHT_MID: x = lv_obj_get_width(base); y = lv_obj_get_height(base) / 2 - lv_obj_get_height(obj) / 2; break; case LV_ALIGN_OUT_RIGHT_BOTTOM: x = lv_obj_get_width(base); y = lv_obj_get_height(base) - lv_obj_get_height(obj); break; } lv_obj_t * parent = lv_obj_get_parent(obj); x += x_ofs + base->coords.x1 - parent->coords.x1 - lv_obj_get_style_pad_left(parent, LV_OBJ_PART_MAIN); y += y_ofs + base->coords.y1 - parent->coords.y1 - lv_obj_get_style_pad_top(parent, LV_OBJ_PART_MAIN); lv_obj_set_pos(obj, x, y); } /** * Copy the coordinates of an object to an area * @param obj pointer to an object * @param coords_out pointer to an area to store the coordinates */ void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * coords_out) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_area_copy(coords_out, &obj->coords); } /** * Reduce area retried by `lv_obj_get_coords()` the get graphically usable area of an object. * (Without the size of the border or other extra graphical elements) * @param coords_out store the result area here */ void lv_obj_get_inner_coords(const lv_obj_t * obj, lv_area_t * coords_out) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_border_side_t part = lv_obj_get_style_border_side(obj, LV_OBJ_PART_MAIN); lv_coord_t w = lv_obj_get_style_border_width(obj, LV_OBJ_PART_MAIN); if(part & LV_BORDER_SIDE_LEFT) coords_out->x1 += w; if(part & LV_BORDER_SIDE_RIGHT) coords_out->x2 -= w; if(part & LV_BORDER_SIDE_TOP) coords_out->y1 += w; if(part & LV_BORDER_SIDE_BOTTOM) coords_out->y2 -= w; } /** * Get the x coordinate of object. * @param obj pointer to an object * @return distance of 'obj' from the left side of its parent plus the parent's left padding * @note Zero return value means the object is on the left padding of the parent, and not on the left edge. * @note Scrolling of the parent doesn't change the returned value. * @note The returned value is always the distance from the parent even if the position is grid cell or other special value. */ lv_coord_t lv_obj_get_x(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_coord_t rel_x; lv_obj_t * parent = lv_obj_get_parent(obj); if(parent) { rel_x = obj->coords.x1 - parent->coords.x1; rel_x += lv_obj_get_scroll_left(parent); rel_x -= lv_obj_get_style_pad_left(parent, LV_OBJ_PART_MAIN); } else { rel_x = obj->coords.x1; } return rel_x; } /** * Get the y coordinate of object. * @param obj pointer to an object * @return distance of 'obj' from the top side of its parent plus the parent's top padding * @note Zero return value means the object is on the top padding of the parent, and not on the top edge. * @note Scrolling of the parent doesn't change the returned value. * @note The returned value is always the distance from the parent even if the position is grid cell or other special value. */ lv_coord_t lv_obj_get_y(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_coord_t rel_y; lv_obj_t * parent = lv_obj_get_parent(obj); if(parent) { rel_y = obj->coords.y1 - parent->coords.y1; rel_y += lv_obj_get_scroll_top(parent); rel_y -= lv_obj_get_style_pad_top(parent, LV_OBJ_PART_MAIN); } else { rel_y = obj->coords.y1; } return rel_y; } /** * Get the width of an object * @param obj pointer to an object * @return the width in pixels * @note The returned value is always the width in pixels even if the width is set to `LV_SIZE_AUTO` or other special value. */ lv_coord_t lv_obj_get_width(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); return lv_area_get_width(&obj->coords); } /** * Get the height of an object * @param obj pointer to an object * @return the height in pixels * @note The returned value is always the width in pixels even if the width is set to `LV_SIZE_AUTO` or other special value. */ lv_coord_t lv_obj_get_height(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); return lv_area_get_height(&obj->coords); } /** * Get that width reduced by the left and right padding. * @param obj pointer to an object * @return the width which still fits into the container without causing overflow */ lv_coord_t lv_obj_get_width_fit(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_style_int_t left = lv_obj_get_style_pad_left(obj, LV_OBJ_PART_MAIN); lv_style_int_t right = lv_obj_get_style_pad_right(obj, LV_OBJ_PART_MAIN); return lv_obj_get_width(obj) - left - right; } /** * Get that height reduced by the top an bottom padding. * @param obj pointer to an object * @return the height which still fits into the container without causing overflow */ lv_coord_t lv_obj_get_height_fit(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_style_int_t top = lv_obj_get_style_pad_top((lv_obj_t *)obj, LV_OBJ_PART_MAIN); lv_style_int_t bottom = lv_obj_get_style_pad_bottom((lv_obj_t *)obj, LV_OBJ_PART_MAIN); return lv_obj_get_height(obj) - top - bottom; } /** * Get the height of an object by taking the top and bottom margin into account. * The returned height will be `obj_h + margin_top + margin_bottom` * @param obj pointer to an object * @return the height including the margins */ lv_coord_t lv_obj_get_height_margin(const lv_obj_t * obj) { lv_style_int_t mtop = lv_obj_get_style_margin_top(obj, LV_OBJ_PART_MAIN); lv_style_int_t mbottom = lv_obj_get_style_margin_bottom(obj, LV_OBJ_PART_MAIN); return lv_obj_get_height(obj) + mtop + mbottom; } /** * Get the width of an object by taking the left and right margin into account. * The returned width will be `obj_w + margin_left + margin_right` * @param obj pointer to an object * @return the height including the margins */ lv_coord_t lv_obj_get_width_margin(const lv_obj_t * obj) { lv_style_int_t mleft = lv_obj_get_style_margin_left(obj, LV_OBJ_PART_MAIN); lv_style_int_t mright = lv_obj_get_style_margin_right(obj, LV_OBJ_PART_MAIN); 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(struct _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(struct _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(struct _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 * @param w_out store the width here. NULL to not calculate width * @param h_out store the height here. NULL to not calculate height */ void _lv_obj_calc_auto_size(lv_obj_t * obj, lv_coord_t * w_out, lv_coord_t * h_out) { if(!w_out && !h_out) return; // printf("auto size\n"); /*If no other effect the auto-size of zero by default*/ if(w_out) *w_out = 0; if(h_out) *h_out = 0; /*Get the grid size of the object has a defined grid*/ lv_coord_t grid_w = 0; lv_coord_t grid_h = 0; if(obj->grid) { _lv_grid_calc_t calc; _lv_grid_calc(obj, &calc); grid_w = calc.grid_w + lv_obj_get_style_pad_left(obj, LV_OBJ_PART_MAIN) + lv_obj_get_style_pad_right(obj, LV_OBJ_PART_MAIN); grid_h = calc.grid_h + lv_obj_get_style_pad_top(obj, LV_OBJ_PART_MAIN) + lv_obj_get_style_pad_bottom(obj, LV_OBJ_PART_MAIN); _lv_grid_calc_free(&calc); } /*Get the children's most right and bottom position*/ lv_coord_t children_w = 0; lv_coord_t children_h = 0; if(w_out) { 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_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; } /*auto_size = max(gird_size, children_size)*/ if(w_out) *w_out = LV_MATH_MAX(children_w, grid_w); if(h_out) *h_out = LV_MATH_MAX(children_h, grid_h); } /** * Move an object to a given x and y coordinate. * It's the core function to move objects but user should use `lv_obj_set_pos/x/y/..` etc. * @param obj pointer to an object to move * @param x the new x coordinate in pixels * @param y the new y coordinate in pixels * @param notify_parent true: send `LV_SIGNAL_CHILD_CHG` to the parent if `obj` moved; false: do not notify the parent */ void _lv_obj_move_to(lv_obj_t * obj, lv_coord_t x, lv_coord_t y, bool notify_parent) { /*Convert x and y to absolute coordinates*/ lv_obj_t * parent = obj->parent; if(parent) { lv_coord_t pad_left = lv_obj_get_style_pad_left(parent, LV_OBJ_PART_MAIN); lv_coord_t pad_top = lv_obj_get_style_pad_top(parent, LV_OBJ_PART_MAIN); x += pad_left + parent->coords.x1 - lv_obj_get_scroll_left(parent); y += pad_top + parent->coords.y1 - lv_obj_get_scroll_top(parent); } else { /*If no parent then it's screen but screen can't be on a grid*/ if(LV_COORD_IS_GRID(obj->x_set) || LV_COORD_IS_GRID(obj->x_set)) { obj->x_set = 0; obj->y_set = 0; x = 0; y = 0; } } /*Calculate and set the movement*/ lv_point_t diff; diff.x = x - obj->coords.x1; diff.y = y - obj->coords.y1; /* Do nothing if the position is not changed */ /* It is very important else recursive positioning can * occur without position change*/ if(diff.x == 0 && diff.y == 0) return; /*Invalidate the original area*/ lv_obj_invalidate(obj); /*Save the original coordinates*/ lv_area_t ori; lv_obj_get_coords(obj, &ori); obj->coords.x1 += diff.x; obj->coords.y1 += diff.y; obj->coords.x2 += diff.x; obj->coords.y2 += diff.y; _lv_obj_move_children_by(obj, diff.x, diff.y); /*Inform the object about its new coordinates*/ obj->signal_cb(obj, LV_SIGNAL_COORD_CHG, &ori); /*Send a signal to the parent too*/ if(parent && notify_parent) parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj); /*Invalidate the new area*/ lv_obj_invalidate(obj); } /** * Reposition the children of an object. (Called recursively) * @param obj pointer to an object which children will be repositioned * @param x_diff x coordinate shift * @param y_diff y coordinate shift */ void _lv_obj_move_children_by(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff) { lv_obj_t * i; _LV_LL_READ(obj->child_ll, i) { i->coords.x1 += x_diff; i->coords.y1 += y_diff; i->coords.x2 += x_diff; i->coords.y2 += y_diff; _lv_obj_move_children_by(i, x_diff, y_diff); } } /** * Check if an object is valid grid item or not. * @param obj pointer to an object to check * @return true: grid item; false: not grid item */ bool _lv_obj_is_grid_item(lv_obj_t * obj) { lv_obj_t * cont = lv_obj_get_parent(obj); if(cont == NULL) return false; if(cont->grid == NULL) return false; if(cont->grid->col_dsc == NULL) return false; if(cont->grid->row_dsc == NULL) return false; if(cont->grid->row_dsc_len == 0) return false; if(cont->grid->col_dsc_len == 0) return false; if(LV_COORD_IS_GRID(obj->x_set) == false || LV_COORD_IS_GRID(obj->y_set) == false) return false; return true; } /** * Check if an object is valid grid item or not. * @param obj pointer to an object to check * @return true: grid item; false: not grid item */ bool _lv_obj_is_flex_item(struct _lv_obj_t * obj) { lv_obj_t * cont = lv_obj_get_parent(obj); if(cont == NULL) return false; if(cont->flex_dir == LV_FLEX_DIR_NONE) return false; if(LV_COORD_IS_FLEX(obj->x_set) == false || LV_COORD_IS_FLEX(obj->y_set) == false) return false; return true; } /********************** * STATIC FUNCTIONS **********************/ /** * Set the size of an object. * It's the core function to set the size of objects but user should use `lv_obj_set_size/width/height/..` etc. * @param obj pointer to an object * @param w the new width in pixels * @param h the new height in pixels * @return true: the size was changed; false: `w` and `h` was equal to the current width and height so nothing happened. */ static bool refr_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h) { /* Do nothing if the size is not changed */ /* It is very important else recursive resizing can * occur without size change*/ if(lv_obj_get_width(obj) == w && lv_obj_get_height(obj) == h) { return false; } /*Invalidate the original area*/ lv_obj_invalidate(obj); /*Save the original coordinates*/ lv_area_t ori; lv_obj_get_coords(obj, &ori); /* Grow size is managed by the flexbox in `LV_SIGNAL_CHILD_CHG` * So the real current value now. * w or h has `LV_FLEX_GROW(x)` value which is a very large special value * so it should be avoided to use such a special value as width*/ if(_LV_FLEX_GET_GROW(obj->w_set)) w = lv_obj_get_width(obj); if(_LV_FLEX_GET_GROW(obj->h_set)) h = lv_obj_get_height(obj); /* Set the length and height * Be sure the content is not scrolled in an invalid position on the new size*/ obj->coords.y2 = obj->coords.y1 + h - 1; if(lv_obj_get_base_dir(obj) == LV_BIDI_DIR_RTL) { obj->coords.x1 = obj->coords.x2 - w + 1; } else { obj->coords.x2 = obj->coords.x1 + w - 1; } /*Send a signal to the object with its new coordinates*/ obj->signal_cb(obj, LV_SIGNAL_COORD_CHG, &ori); /*Send a signal to the parent too*/ lv_obj_t * par = lv_obj_get_parent(obj); if(par != NULL) par->signal_cb(par, LV_SIGNAL_CHILD_CHG, obj); /*Invalidate the new area*/ lv_obj_invalidate(obj); return true; }