diff --git a/src/core/lv_obj.h b/src/core/lv_obj.h index ce06e0a4a3..04b9e381c4 100644 --- a/src/core/lv_obj.h +++ b/src/core/lv_obj.h @@ -116,8 +116,9 @@ typedef enum { 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_SEND_DRAW_TASK_EVENTS = (1L << 19), /**< Send `LV_EVENT_DRAW_TASK_ADDED` events*/ + LV_OBJ_FLAG_OVERFLOW_VISIBLE = (1L << 20),/**< Do not clip the children to the parent's ext draw size*/ #if LV_USE_FLEX - LV_OBJ_FLAG_FLEX_IN_NEW_TRACK = (1L << 20), /**< Start a new flex track on this item*/ + LV_OBJ_FLAG_FLEX_IN_NEW_TRACK = (1L << 21), /**< Start a new flex track on this item*/ #endif LV_OBJ_FLAG_LAYOUT_1 = (1L << 23), /**< Custom flag, free to use by layouts*/ diff --git a/src/core/lv_obj_pos.c b/src/core/lv_obj_pos.c index 09c4f62541..da501289cb 100644 --- a/src/core/lv_obj_pos.c +++ b/src/core/lv_obj_pos.c @@ -844,29 +844,30 @@ bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area) 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; + lv_area_increase(&obj_coords, ext_size, ext_size); /*The area is not on the object*/ if(!_lv_area_intersect(area, area, &obj_coords)) return false; lv_obj_get_transformed_area(obj, area, true, false); - /*Truncate recursively to the parents*/ - lv_obj_t * par = lv_obj_get_parent(obj); - while(par != NULL) { + lv_obj_t * parent = lv_obj_get_parent(obj); + while(parent != NULL) { /*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; + if(lv_obj_has_flag(parent, LV_OBJ_FLAG_HIDDEN)) return false; /*Truncate to the parent and if no common parts break*/ - lv_area_t par_area = par->coords; - lv_obj_get_transformed_area(par, &par_area, true, false); - if(!_lv_area_intersect(area, area, &par_area)) return false; + lv_area_t parent_coords = parent->coords; + if(lv_obj_has_flag(parent, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) { + lv_coord_t parent_ext_size = _lv_obj_get_ext_draw_size(parent); + lv_area_increase(&parent_coords, parent_ext_size, parent_ext_size); + } - par = lv_obj_get_parent(par); + lv_obj_get_transformed_area(parent, &parent_coords, true, false); + if(!_lv_area_intersect(area, area, &parent_coords)) return false; + + parent = lv_obj_get_parent(parent); } return true; diff --git a/src/core/lv_refr.c b/src/core/lv_refr.c index 745fff9b9f..83ade47f5c 100644 --- a/src/core/lv_refr.c +++ b/src/core/lv_refr.c @@ -115,9 +115,16 @@ void lv_obj_redraw(lv_layer_t * layer, lv_obj_t * obj) lv_draw_rect(layer, &draw_dsc, &obj_coords_ext); #endif + const lv_area_t * obj_coords; + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) { + obj_coords = &obj_coords_ext; + } + else { + obj_coords = &obj->coords; + } lv_area_t clip_coords_for_children; bool refr_children = true; - if(!_lv_area_intersect(&clip_coords_for_children, &clip_area_ori, &obj->coords)) { + if(!_lv_area_intersect(&clip_coords_for_children, &clip_area_ori, obj_coords)) { refr_children = false; } diff --git a/src/indev/lv_indev.c b/src/indev/lv_indev.c index 036b2ffb8e..81a0abd520 100644 --- a/src/indev/lv_indev.c +++ b/src/indev/lv_indev.c @@ -488,7 +488,12 @@ lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point) bool hit_test_ok = lv_obj_hit_test(obj, &p_trans); /*If the point is on this object check its children too*/ - if(_lv_area_is_point_on(&obj->coords, &p_trans, 0)) { + lv_area_t obj_coords = obj->coords; + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_OVERFLOW_VISIBLE)) { + lv_coord_t ext_draw_size = _lv_obj_get_ext_draw_size(obj); + lv_area_increase(&obj_coords, ext_draw_size, ext_draw_size); + } + if(_lv_area_is_point_on(&obj_coords, &p_trans, 0)) { int32_t i; uint32_t child_cnt = lv_obj_get_child_cnt(obj); diff --git a/tests/ref_imgs/obj_flag_overflow_visible_1_1.png b/tests/ref_imgs/obj_flag_overflow_visible_1_1.png new file mode 100644 index 0000000000..a35919122f Binary files /dev/null and b/tests/ref_imgs/obj_flag_overflow_visible_1_1.png differ diff --git a/tests/ref_imgs/obj_flag_overflow_visible_1_2.png b/tests/ref_imgs/obj_flag_overflow_visible_1_2.png new file mode 100644 index 0000000000..2c762f4476 Binary files /dev/null and b/tests/ref_imgs/obj_flag_overflow_visible_1_2.png differ diff --git a/tests/ref_imgs/obj_flag_overflow_visible_1_3.png b/tests/ref_imgs/obj_flag_overflow_visible_1_3.png new file mode 100644 index 0000000000..c3cf2d1cb9 Binary files /dev/null and b/tests/ref_imgs/obj_flag_overflow_visible_1_3.png differ diff --git a/tests/src/test_cases/test_obj_flags.c b/tests/src/test_cases/test_obj_flags.c new file mode 100644 index 0000000000..5580f26626 --- /dev/null +++ b/tests/src/test_cases/test_obj_flags.c @@ -0,0 +1,95 @@ +#if LV_BUILD_TEST +#include "../lvgl.h" + +#include "unity/unity.h" +#include "lv_test_indev.h" + +void setUp(void) +{ + /* Function run before every test */ +} + +void tearDown(void) +{ + /* Function run after every test */ + lv_obj_clean(lv_scr_act()); +} + +static void ext_draw_size_event_cb(lv_event_t * e) +{ + lv_event_set_ext_draw_size(e, 100); +} + +static void btn_clicked_event_cb(lv_event_t * e) +{ + uint32_t * cnt = lv_event_get_user_data(e); + (*cnt)++; +} + +void test_obj_flag_overflow_visible_1(void) +{ + lv_obj_t * obj_main = lv_obj_create(lv_scr_act()); + lv_obj_set_size(obj_main, 400, 300); + lv_obj_set_style_bg_color(obj_main, lv_palette_main(LV_PALETTE_RED), 0); + lv_obj_add_flag(obj_main, LV_OBJ_FLAG_OVERFLOW_VISIBLE); + lv_obj_center(obj_main); + lv_obj_add_event(obj_main, ext_draw_size_event_cb, LV_EVENT_REFR_EXT_DRAW_SIZE, NULL); + + lv_obj_t * obj_child_1 = lv_obj_create(obj_main); + lv_obj_set_size(obj_child_1, 200, 200); + lv_obj_set_style_bg_color(obj_child_1, lv_palette_main(LV_PALETTE_PURPLE), 0); + lv_obj_add_flag(obj_child_1, LV_OBJ_FLAG_OVERFLOW_VISIBLE); + lv_obj_align(obj_child_1, LV_ALIGN_LEFT_MID, -100, 0); + + lv_obj_t * btn_1 = lv_btn_create(obj_child_1); + lv_obj_set_size(btn_1, 100, 100); + lv_obj_align(btn_1, LV_ALIGN_LEFT_MID, -75, 0); + lv_obj_clear_flag(btn_1, LV_OBJ_FLAG_SCROLL_ON_FOCUS); + uint32_t cnt_1 = 0; + lv_obj_add_event(btn_1, btn_clicked_event_cb, LV_EVENT_CLICKED, &cnt_1); + + lv_obj_t * obj_child_2 = lv_obj_create(obj_main); + lv_obj_set_size(obj_child_2, 200, 200); + lv_obj_set_style_bg_color(obj_child_2, lv_palette_main(LV_PALETTE_ORANGE), 0); + lv_obj_add_flag(obj_child_2, LV_OBJ_FLAG_OVERFLOW_VISIBLE); + lv_obj_align(obj_child_2, LV_ALIGN_RIGHT_MID, 100, 0); + lv_obj_add_flag(obj_child_2, LV_OBJ_FLAG_OVERFLOW_VISIBLE); + lv_obj_add_event(obj_child_2, ext_draw_size_event_cb, LV_EVENT_REFR_EXT_DRAW_SIZE, NULL); + + lv_obj_t * btn_2 = lv_btn_create(obj_child_2); + lv_obj_set_size(btn_2, 100, 100); + lv_obj_align(btn_2, LV_ALIGN_RIGHT_MID, 75, 0); + lv_obj_clear_flag(btn_2, LV_OBJ_FLAG_SCROLL_ON_FOCUS); + uint32_t cnt_2 = 0; + lv_obj_add_event(btn_2, btn_clicked_event_cb, LV_EVENT_CLICKED, &cnt_2); + + /*The clipped part of the left button (shouldn't trigger click event)*/ + lv_test_mouse_click_at(100, 220); + + /*The non clipped part of the left button (should trigger click event)*/ + lv_test_mouse_click_at(140, 220); + + /*The left part of the right button (should trigger click event)*/ + lv_test_mouse_click_at(650, 220); + + /*The outter part of the right button (should trigger click event as obj_child_2 has LV_OBJ_FLAG_OVERFLOW_VISIBLE)*/ + lv_test_mouse_click_at(690, 220); + + TEST_ASSERT_EQUAL_UINT32(1, cnt_1); + TEST_ASSERT_EQUAL_UINT32(2, cnt_2); + + TEST_ASSERT_EQUAL_SCREENSHOT("obj_flag_overflow_visible_1_1.png"); + + /*Test if the overflowing parts are rendered correctly after scrolling too*/ + lv_obj_scroll_by_bounded(obj_main, -20, 0, LV_ANIM_OFF); + TEST_ASSERT_EQUAL_SCREENSHOT("obj_flag_overflow_visible_1_2.png"); + + lv_obj_scroll_by_bounded(obj_child_2, -30, 0, LV_ANIM_OFF); + TEST_ASSERT_EQUAL_SCREENSHOT("obj_flag_overflow_visible_1_3.png"); + + + +} + + +#endif