diff --git a/docs/overview/object.md b/docs/overview/object.md index 109303381..0eca957e0 100644 --- a/docs/overview/object.md +++ b/docs/overview/object.md @@ -91,6 +91,9 @@ If a child is partially or fully outside of its parent then the parts outside wi lv_obj_set_x(obj1, -30); /*Move the child a little bit off the parent*/ ``` +This behavior can be overwritten with `lv_obj_add_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE);` which allow the children to be drawn out of the parent. + + ### Create and delete objects In LVGL, objects can be created and deleted dynamically at run time. It means only the currently created (existing) objects consume RAM. diff --git a/docs/widgets/obj.md b/docs/widgets/obj.md index 240015fd0..a885f6130 100644 --- a/docs/widgets/obj.md +++ b/docs/widgets/obj.md @@ -124,6 +124,7 @@ There are some attributes which can be enabled/disabled by `lv_obj_add/clear_fla - `LV_OBJ_FLAG_ADV_HITTEST` Allow performing more accurate hit (click) test. E.g. accounting for rounded corners - `LV_OBJ_FLAG_IGNORE_LAYOUT` Make the object positionable by the layouts - `LV_OBJ_FLAG_FLOATING` Do not scroll the object when the parent scrolls and ignore layout +- `LV_OBJ_FLAG_OVERFLOW_VISIBLE` Do not clip the children's content to the parent's boundary - `LV_OBJ_FLAG_LAYOUT_1` Custom flag, free to use by layouts - `LV_OBJ_FLAG_LAYOUT_2` Custom flag, free to use by layouts diff --git a/src/core/lv_indev.c b/src/core/lv_indev.c index 106b13f38..86796c1ba 100644 --- a/src/core/lv_indev.c +++ b/src/core/lv_indev.c @@ -290,32 +290,27 @@ lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point) { lv_obj_t * found_p = NULL; - /*If the point is on this object check its children too*/ - if(lv_obj_hit_test(obj, point)) { + /*If this obj is hidden the children are hidden too so return immediately*/ + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return NULL; + + bool hit_test_ok = lv_obj_hit_test(obj, point); + + /*If the point is on this object or has overflow visible check its children too*/ + if(_lv_area_is_point_on(&obj->coords, point, 0) || lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) { int32_t i; uint32_t child_cnt = lv_obj_get_child_cnt(obj); + /*If a child matches use it*/ for(i = child_cnt - 1; i >= 0; i--) { lv_obj_t * child = obj->spec_attr->children[i]; found_p = lv_indev_search_obj(child, point); - - /*If a child was found then break*/ - if(found_p != NULL) break; - } - - /*If then the children was not ok, and this obj is clickable - * and it or its parent is not hidden then save this object*/ - if(found_p == NULL && lv_obj_has_flag(obj, LV_OBJ_FLAG_CLICKABLE)) { - lv_obj_t * hidden_i = obj; - while(hidden_i != NULL) { - if(lv_obj_has_flag(hidden_i, LV_OBJ_FLAG_HIDDEN) == true) break; - hidden_i = lv_obj_get_parent(hidden_i); - } - /*No parent found with hidden == true*/ - if(hidden_i == NULL && (lv_obj_get_state(obj) & LV_STATE_DISABLED) == false) found_p = obj; + if(found_p) return found_p; } } - return found_p; + /*If not return earlier for a clicked child and this obj's hittest was ok use it + *else return NULL*/ + if(hit_test_ok) return obj; + else return NULL; } /********************** diff --git a/src/core/lv_obj.h b/src/core/lv_obj.h index 416b958b4..a35ee0728 100644 --- a/src/core/lv_obj.h +++ b/src/core/lv_obj.h @@ -106,6 +106,7 @@ enum { LV_OBJ_FLAG_ADV_HITTEST = (1L << 16), /**< Allow performing more accurate hit (click) test. E.g. consider rounded corners.*/ LV_OBJ_FLAG_IGNORE_LAYOUT = (1L << 17), /**< Make the object position-able by the layouts*/ LV_OBJ_FLAG_FLOATING = (1L << 18), /**< Do not scroll the object when the parent scrolls and ignore layout*/ + LV_OBJ_FLAG_OVERFLOW_VISIBLE = (1L << 19), /**< Do not clip the children's content to the parent's boundary*/ LV_OBJ_FLAG_LAYOUT_1 = (1L << 23), /**< Custom flag, free to use by layouts*/ LV_OBJ_FLAG_LAYOUT_2 = (1L << 24), /**< Custom flag, free to use by layouts*/ diff --git a/src/core/lv_obj_pos.c b/src/core/lv_obj_pos.c index 74d194bd2..67dfd03bf 100644 --- a/src/core/lv_obj_pos.c +++ b/src/core/lv_obj_pos.c @@ -807,6 +807,12 @@ void lv_obj_invalidate(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, MY_CLASS); + /*If the object has overflow visible it can be drawn anywhere on its parent + *It needs to be checked recursively*/ + while(lv_obj_get_parent(obj) && lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) { + obj = lv_obj_get_parent(obj); + } + /*Truncate the area to the object*/ lv_area_t obj_coords; lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj); @@ -824,7 +830,7 @@ bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area) { if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return false; - /*Invalidate the object only if it belongs to the current or previous'*/ + /*Invalidate the object only if it belongs to the current or previous or one of the layers'*/ lv_obj_t * obj_scr = lv_obj_get_screen(obj); lv_disp_t * disp = lv_obj_get_disp(obj_scr); if(obj_scr != lv_disp_get_scr_act(disp) && @@ -835,26 +841,29 @@ bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area) } /*Truncate the area to the object*/ - lv_area_t obj_coords; - lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj); - lv_area_copy(&obj_coords, &obj->coords); - obj_coords.x1 -= ext_size; - obj_coords.y1 -= ext_size; - obj_coords.x2 += ext_size; - obj_coords.y2 += ext_size; + if(!lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) { + lv_area_t obj_coords; + lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj); + lv_area_copy(&obj_coords, &obj->coords); + obj_coords.x1 -= ext_size; + obj_coords.y1 -= ext_size; + obj_coords.x2 += ext_size; + obj_coords.y2 += ext_size; - bool is_common; - - is_common = _lv_area_intersect(area, area, &obj_coords); - if(is_common == false) return false; /*The area is not on the object*/ + /*The area is not on the object*/ + if(!_lv_area_intersect(area, area, &obj_coords)) return false; + } /*Truncate recursively to the parents*/ lv_obj_t * par = lv_obj_get_parent(obj); while(par != NULL) { - is_common = _lv_area_intersect(area, area, &par->coords); - if(is_common == false) return false; /*If no common parts with parent break;*/ - if(lv_obj_has_flag(par, LV_OBJ_FLAG_HIDDEN)) return - false; /*If the parent is hidden then the child is hidden and won't be drawn*/ + /*If the parent is hidden then the child is hidden and won't be drawn*/ + if(lv_obj_has_flag(par, LV_OBJ_FLAG_HIDDEN)) return false; + + /*Truncate to the parent and if no common parts break*/ + if(!lv_obj_has_flag(par, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) { + if(!_lv_area_intersect(area, area, &par->coords)) return false; + } par = lv_obj_get_parent(par); } @@ -899,6 +908,9 @@ void lv_obj_get_click_area(const lv_obj_t * obj, lv_area_t * area) bool lv_obj_hit_test(lv_obj_t * obj, const lv_point_t * point) { + if(!lv_obj_has_flag(obj, LV_OBJ_FLAG_CLICKABLE)) return false; + if(lv_obj_has_state(obj, LV_STATE_DISABLED)) return false; + lv_area_t a; lv_obj_get_click_area(obj, &a); bool res = _lv_area_is_point_on(&a, point, 0); diff --git a/src/core/lv_refr.c b/src/core/lv_refr.c index 0a002f3da..66517e237 100644 --- a/src/core/lv_refr.c +++ b/src/core/lv_refr.c @@ -130,16 +130,18 @@ void lv_refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj) if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return; const lv_area_t * clip_area_ori = draw_ctx->clip_area; + lv_area_t clip_coords_for_obj; + + /*Truncate the clip area to `obj size + ext size` area*/ lv_area_t obj_coords_ext; - lv_area_t obj_ext_clip_coords; lv_obj_get_coords(obj, &obj_coords_ext); lv_coord_t ext_draw_size = _lv_obj_get_ext_draw_size(obj); lv_area_increase(&obj_coords_ext, ext_draw_size, ext_draw_size); - if(!_lv_area_intersect(&obj_ext_clip_coords, clip_area_ori, &obj_coords_ext)) return; + if(!_lv_area_intersect(&clip_coords_for_obj, clip_area_ori, &obj_coords_ext)) return; - draw_ctx->clip_area = &obj_ext_clip_coords; + draw_ctx->clip_area = &clip_coords_for_obj; - /*Redraw the object*/ + /*Draw the object*/ lv_event_send(obj, LV_EVENT_DRAW_MAIN_BEGIN, draw_ctx); lv_event_send(obj, LV_EVENT_DRAW_MAIN, draw_ctx); lv_event_send(obj, LV_EVENT_DRAW_MAIN_END, draw_ctx); @@ -156,27 +158,29 @@ void lv_refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj) lv_draw_rect(&obj_ext_mask, &obj_ext_mask, &draw_dsc); #endif - /*Create a new 'obj_clip' without 'ext_size' because the children can't be visible there*/ - lv_area_t obj_clip_coords; - if(_lv_area_intersect(&obj_clip_coords, clip_area_ori, &obj->coords)) { + /*With overflow visible keep the previous clip area to let the children visible out of this object too + *With not overflow visible limit the clip are to the object's coordinates to clip the children*/ + bool refr_children = true; + lv_area_t clip_coords_for_children; + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) { + clip_coords_for_children = *clip_area_ori; + } + else { + if(!_lv_area_intersect(&clip_coords_for_children, clip_area_ori, &obj->coords)) { + refr_children = false; + } + } + + if(refr_children) { uint32_t i; uint32_t child_cnt = lv_obj_get_child_cnt(obj); for(i = 0; i < child_cnt; i++) { lv_obj_t * child = obj->spec_attr->children[i]; - lv_area_t child_coords; - lv_obj_get_coords(child, &child_coords); - ext_draw_size = _lv_obj_get_ext_draw_size(child); - lv_area_increase(&child_coords, ext_draw_size, ext_draw_size); - lv_area_t child_clip; - if(_lv_area_intersect(&child_clip, &obj_clip_coords, &child_coords)) { - /*Refresh the next child*/ - draw_ctx->clip_area = &child_clip; - lv_refr_obj(draw_ctx, child); - } + lv_refr_obj(draw_ctx, child); } } - draw_ctx->clip_area = &obj_ext_clip_coords; + draw_ctx->clip_area = &clip_coords_for_obj; /*If all the children are redrawn make 'post draw' draw*/ lv_event_send(obj, LV_EVENT_DRAW_POST_BEGIN, draw_ctx); @@ -664,7 +668,7 @@ static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj) { lv_obj_t * found_p = NULL; - /*If this object is fully cover the draw area check the children too*/ + /*If this object is fully cover the draw area then check the children too*/ if(_lv_area_is_in(area_p, &obj->coords, 0) && lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN) == false) { lv_cover_check_info_t info; info.res = LV_COVER_RES_COVER; diff --git a/src/extra/widgets/tileview/lv_tileview.c b/src/extra/widgets/tileview/lv_tileview.c index 8f8f3c4d2..4f98b552a 100644 --- a/src/extra/widgets/tileview/lv_tileview.c +++ b/src/extra/widgets/tileview/lv_tileview.c @@ -89,6 +89,8 @@ void lv_obj_set_tile(lv_obj_t * obj, lv_obj_t * tile_obj, lv_anim_enable_t anim_ void lv_obj_set_tile_id(lv_obj_t * tv, uint32_t col_id, uint32_t row_id, lv_anim_enable_t anim_en) { + lv_obj_update_layout(tv); + lv_coord_t w = lv_obj_get_content_width(tv); lv_coord_t h = lv_obj_get_content_height(tv);