
From: Simon Glass <sjg@chromium.org> To implement mouse clicks we need a way to figure out what the user has clicked on. As a starting point, create a scene_menu_within() function which returns the item containing an x, y coordinate. Provide a helper function in scene.c for use with this. Add a simple for completeness. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- boot/scene.c | 17 +++++++++++++++ boot/scene_internal.h | 24 +++++++++++++++++++++ boot/scene_menu.c | 31 +++++++++++++++++++++++++++ test/boot/expo.c | 49 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) diff --git a/boot/scene.c b/boot/scene.c index 50a7dfb22a1..98716ef2337 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -1028,6 +1028,23 @@ int scene_send_key(struct scene *scn, int key, struct expo_action *event) return 0; } +bool scene_within(const struct scene *scn, uint id, int x, int y) +{ + struct scene_obj *obj; + + obj = scene_obj_find(scn, id, SCENEOBJT_NONE); + if (!obj) { + log_debug("Cannot find id %d\n", id); + return false; + } + log_debug("- id %d: '%s' bbox x0 %d y0 %d x1 %d y1 %d\n", id, obj->name, + obj->bbox.x0, obj->bbox.y0, obj->bbox.x1, obj->bbox.x1); + + /* Check if point (x, y) is within object's bounding box */ + return (x >= obj->bbox.x0 && x <= obj->bbox.x1 && + y >= obj->bbox.y0 && y <= obj->bbox.y1); +} + int scene_obj_calc_bbox(struct scene_obj *obj, struct vidconsole_bbox bbox[]) { switch (obj->type) { diff --git a/boot/scene_internal.h b/boot/scene_internal.h index c6f2615a2c5..15a96b1e31e 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -241,6 +241,30 @@ int scene_render(struct scene *scn); */ int scene_send_key(struct scene *scn, int key, struct expo_action *event); +/** + * scene_within() - check if a point is considered within an object ID + * + * @scn: Scene to check + * @id: ID of object to check + * @x: X coordinate of the point + * @y: Y coordinate of the point + * Return: true if the point is considered within the object, false if not + */ +bool scene_within(const struct scene *scn, uint id, int x, int y); + +/** + * scene_menu_within() - check if a point is considered within a menu + * + * @scn: Scene to check + * @menu: Menu to check + * @x: X coordinate of the point + * @y: Y coordinate of the point + * Return: item the point is within, or NULL if none + */ +struct scene_menitem *scene_menu_within(const struct scene *scn, + struct scene_obj_menu *menu, + int x, int y); + /** * scene_render_deps() - Render an object and its dependencies * diff --git a/boot/scene_menu.c b/boot/scene_menu.c index 0ed73cd12cc..758343fe909 100644 --- a/boot/scene_menu.c +++ b/boot/scene_menu.c @@ -497,6 +497,37 @@ int scene_menu_send_key(struct scene *scn, struct scene_obj_menu *menu, int key, return 0; } +struct scene_menitem *scene_menu_within(const struct scene *scn, + struct scene_obj_menu *menu, + int x, int y) +{ + struct scene_menitem *item; + + list_for_each_entry(item, &menu->item_head, sibling) { + log_debug(" item %d: label %d\n", item->id, item->label_id); + bool within; + + within = scene_within(scn, item->label_id, x, y); + log_debug("- item %d within %d\n", item->id, within); + if (!within && !scn->expo->popup) { + log_debug("- non-popup within key %d desc %d preview %d\n", + scene_within(scn, item->key_id, x, y), + scene_within(scn, item->desc_id, x, y), + scene_within(scn, item->preview_id, x, y)); + within |= scene_within(scn, item->key_id, x, y) || + scene_within(scn, item->desc_id, x, y) || + scene_within(scn, item->preview_id, x, y); + log_debug("- popup within %d\n", within); + } + + log_debug("- final within %d\n", within); + if (within) + return item; + } + + return NULL; +} + int scene_menuitem(struct scene *scn, uint menu_id, const char *name, uint id, uint key_id, uint label_id, uint desc_id, uint preview_id, uint flags, struct scene_menitem **itemp) diff --git a/test/boot/expo.c b/test/boot/expo.c index d407ad839f6..99c28cc77f6 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -962,6 +962,55 @@ static int expo_test_build(struct unit_test_state *uts) } BOOTSTD_TEST(expo_test_build, UTF_DM); +/* test scene_menu_within() function */ +static int expo_menu_within(struct unit_test_state *uts) +{ + struct scene_obj_menu *menu; + struct scene_menitem *item; + struct scene_obj *obj; + struct udevice *dev; + struct scene *scn; + struct expo *exp; + ofnode node; + + node = ofnode_path("/cedit"); + ut_assert(ofnode_valid(node)); + ut_assertok(expo_build(node, &exp)); + + scn = expo_lookup_scene_id(exp, ID_SCENE1); + ut_assertnonnull(scn); + + menu = scene_obj_find(scn, ID_CPU_SPEED, SCENEOBJT_NONE); + ut_assertnonnull(menu); + + ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev)); + ut_assertok(expo_set_display(exp, dev)); + + ut_assertok(scene_arrange(scn)); + + /* get first menu item and test with its coordinates */ + item = list_first_entry(&menu->item_head, struct scene_menitem, + sibling); + ut_assertnonnull(item); + + /* get the label object to find coordinates */ + obj = scene_obj_find(scn, item->label_id, SCENEOBJT_NONE); + ut_assertnonnull(obj); + ut_asserteq_ptr(item, scene_menu_within(scn, menu, obj->bbox.x0 + 1, + obj->bbox.y0 + 1)); + + /* test point outside menu bounds */ + ut_assertnull(scene_menu_within(scn, menu, -1, -1)); + + /* test point far outside menu bounds */ + ut_assertnull(scene_menu_within(scn, menu, 9999, 9999)); + + expo_destroy(exp); + + return 0; +} +BOOTSTD_TEST(expo_menu_within, UTF_DM | UTF_SCAN_FDT); + /* test expo_set_mouse_enable() */ static int expo_mouse_enable(struct unit_test_state *uts) { -- 2.43.0