@@ -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) {
@@ -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
*
@@ -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)
@@ -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)
{