[Concept,12/23] expo: Allow checking if a position is within a textline

Message ID 20250915122905.1217249-13-sjg@u-boot.org
State New
Headers
Series expo: Support interactions with a mouse or touchpad |

Commit Message

Simon Glass Sept. 15, 2025, 12:28 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

For a textline it is possible to click into the edit field. Provide a
function to check whether a position is within this field.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 boot/scene.c          | 33 +++++++++++++++++++++++++++++++++
 boot/scene_internal.h | 12 ++++++++++++
 boot/scene_textline.c |  6 ++++++
 test/boot/expo.c      | 24 +++++++++++++++++++++---
 4 files changed, 72 insertions(+), 3 deletions(-)
  

Patch

diff --git a/boot/scene.c b/boot/scene.c
index 98716ef2337..e25596366cc 100644
--- a/boot/scene.c
+++ b/boot/scene.c
@@ -1045,6 +1045,39 @@  bool scene_within(const struct scene *scn, uint id, int x, int y)
 		y >= obj->bbox.y0 && y <= obj->bbox.y1);
 }
 
+bool scene_obj_within(const struct scene *scn, struct scene_obj *obj, int x,
+		      int y)
+{
+	bool within = false;
+
+	switch (obj->type) {
+	case SCENEOBJT_NONE:
+	case SCENEOBJT_IMAGE:
+	case SCENEOBJT_TEXT:
+	case SCENEOBJT_BOX:
+		break;
+	case SCENEOBJT_MENU: {
+		struct scene_obj_menu *menu;
+
+		menu = (struct scene_obj_menu *)obj,
+		within = scene_menu_within(scn, menu, x, y);
+		break;
+	}
+	case SCENEOBJT_TEXTLINE: {
+		struct scene_obj_textline *tline;
+
+		tline = (struct scene_obj_textline *)obj,
+		within = scene_textline_within(scn, tline, x, y);
+		break;
+	}
+	case SCENEOBJT_TEXTEDIT:
+		/* TODO(sjg@chromium.org): Implement this */
+		break;
+	}
+
+	return within;
+}
+
 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 15a96b1e31e..03bc925edfe 100644
--- a/boot/scene_internal.h
+++ b/boot/scene_internal.h
@@ -265,6 +265,18 @@  struct scene_menitem *scene_menu_within(const struct scene *scn,
 					struct scene_obj_menu *menu,
 					int x, int y);
 
+/**
+ * scene_textline_within() - check if a point is considered within a textline
+ *
+ * @scn: Scene to check
+ * @tline: Txtline 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_textline_within(const struct scene *scn,
+			   struct scene_obj_textline *tline, int x, int y);
+
 /**
  * scene_render_deps() - Render an object and its dependencies
  *
diff --git a/boot/scene_textline.c b/boot/scene_textline.c
index 4a77cc652a8..b595d3477e4 100644
--- a/boot/scene_textline.c
+++ b/boot/scene_textline.c
@@ -175,6 +175,12 @@  int scene_textline_send_key(struct scene *scn, struct scene_obj_textline *tline,
 	return 0;
 }
 
+bool scene_textline_within(const struct scene *scn,
+			   struct scene_obj_textline *tline, int x, int y)
+{
+	return scene_within(scn, tline->edit_id, x, y);
+}
+
 int scene_textline_render_deps(struct scene *scn,
 			       struct scene_obj_textline *tline)
 {
diff --git a/test/boot/expo.c b/test/boot/expo.c
index 99c28cc77f6..e8674d359d7 100644
--- a/test/boot/expo.c
+++ b/test/boot/expo.c
@@ -962,9 +962,10 @@  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)
+/* test scene object within functions */
+static int expo_within_funcs(struct unit_test_state *uts)
 {
+	struct scene_obj_textline *tline;
 	struct scene_obj_menu *menu;
 	struct scene_menitem *item;
 	struct scene_obj *obj;
@@ -980,6 +981,7 @@  static int expo_menu_within(struct unit_test_state *uts)
 	scn = expo_lookup_scene_id(exp, ID_SCENE1);
 	ut_assertnonnull(scn);
 
+	/* test scene_menu_within() */
 	menu = scene_obj_find(scn, ID_CPU_SPEED, SCENEOBJT_NONE);
 	ut_assertnonnull(menu);
 
@@ -1005,11 +1007,27 @@  static int expo_menu_within(struct unit_test_state *uts)
 	/* test point far outside menu bounds */
 	ut_assertnull(scene_menu_within(scn, menu, 9999, 9999));
 
+	/* test scene_textline_within() */
+	tline = scene_obj_find(scn, ID_MACHINE_NAME, SCENEOBJT_NONE);
+	ut_assertnonnull(tline);
+	obj = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
+	ut_assertnonnull(obj);
+
+	/* positive test: point within textline bounds */
+	ut_assert(scene_textline_within(scn, tline, obj->bbox.x0 + 1,
+					obj->bbox.y0 + 1));
+
+	/* test point outside textline bounds */
+	ut_assert(!scene_textline_within(scn, tline, -1, -1));
+
+	/* test point far outside textline bounds */
+	ut_assert(!scene_textline_within(scn, tline, 9999, 9999));
+
 	expo_destroy(exp);
 
 	return 0;
 }
-BOOTSTD_TEST(expo_menu_within, UTF_DM | UTF_SCAN_FDT);
+BOOTSTD_TEST(expo_within_funcs, UTF_DM | UTF_SCAN_FDT);
 
 /* test expo_set_mouse_enable() */
 static int expo_mouse_enable(struct unit_test_state *uts)