From: Simon Glass <sjg@chromium.org> Since the scene is drawn by iterating through the list of objects, when the user clicks somewhere we should look at the top-most object under the mouse first. This is not true when a menu is popped up, since we only care about the menu in that case. Add a way to reverse the direction of the object search. For now there are no new test cases, since OBJ_OVERLAP is a text object and cannot currently be clicked on. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- boot/scene.c | 45 +++++++++++++++++++++++++++++-------------- boot/scene_internal.h | 5 ++++- test/boot/expo.c | 10 +++++----- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/boot/scene.c b/boot/scene.c index a9e0d1f1266..05a683dd1da 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -1193,20 +1193,37 @@ bool scene_obj_within(const struct scene *scn, struct scene_obj *obj, int x, return within; } -struct scene_obj *scene_find_obj_within(const struct scene *scn, int x, int y) +struct scene_obj *scene_find_obj_within(const struct scene *scn, int x, int y, + bool reverse) { struct scene_obj *obj; - log_debug("within: x %d y %d\n", x, y); - list_for_each_entry(obj, &scn->obj_head, sibling) { - log_debug(" - obj %d '%s' can_highlight %d within %d\n", - obj->id, obj->name, scene_obj_can_highlight(obj), - scene_obj_within(scn, obj, x, y)); - if (scene_obj_can_highlight(obj) && - scene_obj_within(scn, obj, x, y)) { - log_debug("- returning obj %d '%s'\n", obj->id, - obj->name); - return obj; + log_debug("within: x %d y %d reverse %d\n", x, y, reverse); + if (reverse) { + list_for_each_entry_reverse(obj, &scn->obj_head, sibling) { + log_debug(" - obj %d '%s' can_highlight %d within %d\n", + obj->id, obj->name, + scene_obj_can_highlight(obj), + scene_obj_within(scn, obj, x, y)); + if (scene_obj_can_highlight(obj) && + scene_obj_within(scn, obj, x, y)) { + log_debug("- returning obj %d '%s'\n", obj->id, + obj->name); + return obj; + } + } + } else { + list_for_each_entry(obj, &scn->obj_head, sibling) { + log_debug(" - obj %d '%s' can_highlight %d within %d\n", + obj->id, obj->name, + scene_obj_can_highlight(obj), + scene_obj_within(scn, obj, x, y)); + if (scene_obj_can_highlight(obj) && + scene_obj_within(scn, obj, x, y)) { + log_debug("- returning obj %d '%s'\n", obj->id, + obj->name); + return obj; + } } } log_debug("- no object\n"); @@ -1238,7 +1255,7 @@ static void send_click_obj(struct scene *scn, struct scene_obj *obj, int x, } log_debug("no object; finding...\n"); - obj = scene_find_obj_within(scn, x, y); + obj = scene_find_obj_within(scn, x, y, false); if (obj) { event->type = EXPOACT_POINT_OPEN; event->select.id = obj->id; @@ -1264,7 +1281,7 @@ static int scene_click_popup(struct scene *scn, int x, int y, } /* check that the click is within our object */ - chk = scene_find_obj_within(scn, x, y); + chk = scene_find_obj_within(scn, x, y, false); log_debug("chk %d '%s' (obj %d '%s')\n", chk ? chk->id : -1, chk ? chk->name : "(none)", obj->id, obj->name); if (!chk) { @@ -1323,7 +1340,7 @@ int scene_send_click(struct scene *scn, int x, int y, struct expo_action *event) return 0; } - obj = scene_find_obj_within(scn, x, y); + obj = scene_find_obj_within(scn, x, y, false); log_debug("non-popup obj %d '%s'\n", obj ? obj->id : -1, obj ? obj->name : "(none)"); if (!obj) diff --git a/boot/scene_internal.h b/boot/scene_internal.h index 8e61067d4b4..e2f4cc066d0 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -562,8 +562,11 @@ const char *scene_obj_type_name(enum scene_obj_t type); * @scn: Scene to check * @x: X coordinates of the click * @y: Y coordinate of the click + * @reverse: true to search from top to bottom (reverse order), false for + * bottom to top * Return: object that is being clicked on, NULL if none */ -struct scene_obj *scene_find_obj_within(const struct scene *scn, int x, int y); +struct scene_obj *scene_find_obj_within(const struct scene *scn, int x, int y, + bool reverse); #endif /* __SCENE_INTERNAL_H */ diff --git a/test/boot/expo.c b/test/boot/expo.c index db4a54e7cd7..e32550a6685 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -1289,19 +1289,19 @@ static int expo_find_obj_within(struct unit_test_state *uts) * Check finding a menu by 'clicking' on a menu item label - menu items * are at (50,436) for ITEM1 and (50,454) for ITEM2 */ - obj = scene_find_obj_within(scn, 60, 440); + obj = scene_find_obj_within(scn, 60, 440, false); ut_assertnonnull(obj); ut_asserteq(OBJ_MENU, obj->id); /* logo and text are not highlightable, so they should not be found */ - ut_assertnull(scene_find_obj_within(scn, 60, 30)); - ut_assertnull(scene_find_obj_within(scn, 410, 110)); + ut_assertnull(scene_find_obj_within(scn, 60, 30, false)); + ut_assertnull(scene_find_obj_within(scn, 410, 110, false)); /* empty space */ - ut_assertnull(scene_find_obj_within(scn, 10, 10)); + ut_assertnull(scene_find_obj_within(scn, 10, 10, false)); /* way outside bounds */ - ut_assertnull(scene_find_obj_within(scn, 9999, 9999)); + ut_assertnull(scene_find_obj_within(scn, 9999, 9999, false)); abuf_uninit(&buf); abuf_uninit(&logo_copy); -- 2.43.0