[PATCH 18/34] expo: Place menu items to the right of all labels

Simon Glass sjg at chromium.org
Mon Oct 2 03:15:28 CEST 2023


At present a fixed position is used for menu items, 200 pixels to the
right of the left side of the labels. This means that a menu item with
a very long label may overlap the items.

It seems better to calculate the maximum label width and then place the
items to the right of all of them.

To implement this, add a new struct to containing arrangement
information. Calculate it before doing the actual arrangement. Add a
new style item which sets the amount of space from the right side of
the labels to left side of the items.

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

 boot/cedit.c          | 13 ++++++++---
 boot/expo.c           |  2 ++
 boot/scene.c          | 52 +++++++++++++++++++++++++++++++++++++++++--
 boot/scene_internal.h | 20 +++++++++++++++--
 boot/scene_menu.c     |  9 +++++---
 boot/scene_textline.c |  3 ++-
 doc/develop/expo.rst  |  4 ++++
 include/expo.h        | 12 ++++++++++
 8 files changed, 104 insertions(+), 11 deletions(-)

diff --git a/boot/cedit.c b/boot/cedit.c
index 8c654dba6dc3..b5f89e945bce 100644
--- a/boot/cedit.c
+++ b/boot/cedit.c
@@ -52,10 +52,11 @@ struct cedit_iter_priv {
 
 int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
 {
+	struct expo_arrange_info arr;
 	struct scene_obj_txt *txt;
 	struct scene_obj *obj;
 	struct scene *scn;
-	int y;
+	int y, ret;
 
 	scn = expo_lookup_scene_id(exp, scene_id);
 	if (!scn)
@@ -69,6 +70,11 @@ int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
 	if (txt)
 		scene_obj_set_pos(scn, txt->obj.id, 200, 10);
 
+	memset(&arr, '\0', sizeof(arr));
+	ret = scene_calc_arrange(scn, &arr);
+	if (ret < 0)
+		return log_msg_ret("arr", ret);
+
 	y = 100;
 	list_for_each_entry(obj, &scn->obj_head, sibling) {
 		switch (obj->type) {
@@ -78,12 +84,13 @@ int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
 			break;
 		case SCENEOBJT_MENU:
 			scene_obj_set_pos(scn, obj->id, 50, y);
-			scene_menu_arrange(scn, (struct scene_obj_menu *)obj);
+			scene_menu_arrange(scn, &arr,
+					   (struct scene_obj_menu *)obj);
 			y += 50;
 			break;
 		case SCENEOBJT_TEXTLINE:
 			scene_obj_set_pos(scn, obj->id, 50, y);
-			scene_textline_arrange(scn,
+			scene_textline_arrange(scn, &arr,
 					(struct scene_obj_textline *)obj);
 			y += 50;
 			break;
diff --git a/boot/expo.c b/boot/expo.c
index cadb6a0ad6e3..d030820e77ca 100644
--- a/boot/expo.c
+++ b/boot/expo.c
@@ -259,6 +259,8 @@ int expo_apply_theme(struct expo *exp, ofnode node)
 	ofnode_read_u32(node, "font-size", &theme->font_size);
 	ofnode_read_u32(node, "menu-inset", &theme->menu_inset);
 	ofnode_read_u32(node, "menuitem-gap-y", &theme->menuitem_gap_y);
+	ofnode_read_u32(node, "menu-title-margin-x",
+			&theme->menu_title_margin_x);
 
 	list_for_each_entry(scn, &exp->scene_head, sibling) {
 		ret = scene_apply_theme(scn, theme);
diff --git a/boot/scene.c b/boot/scene.c
index 0b37971b1ff4..56569e76e9f2 100644
--- a/boot/scene.c
+++ b/boot/scene.c
@@ -478,11 +478,59 @@ static int scene_obj_render(struct scene_obj *obj, bool text_mode)
 	return 0;
 }
 
+int scene_calc_arrange(struct scene *scn, struct expo_arrange_info *arr)
+{
+	struct scene_obj *obj;
+
+	arr->label_width = 0;
+	list_for_each_entry(obj, &scn->obj_head, sibling) {
+		uint label_id = 0;
+		int width;
+
+		switch (obj->type) {
+		case SCENEOBJT_NONE:
+		case SCENEOBJT_IMAGE:
+		case SCENEOBJT_TEXT:
+			break;
+		case SCENEOBJT_MENU: {
+			struct scene_obj_menu *menu;
+
+			menu = (struct scene_obj_menu *)obj,
+			label_id = menu->title_id;
+			break;
+		}
+		case SCENEOBJT_TEXTLINE: {
+			struct scene_obj_textline *tline;
+
+			tline = (struct scene_obj_textline *)obj,
+			label_id = tline->label_id;
+			break;
+		}
+		}
+
+		if (label_id) {
+			int ret;
+
+			ret = scene_obj_get_hw(scn, label_id, &width);
+			if (ret < 0)
+				return log_msg_ret("hei", ret);
+			arr->label_width = max(arr->label_width, width);
+		}
+	}
+
+	return 0;
+}
+
 int scene_arrange(struct scene *scn)
 {
+	struct expo_arrange_info arr;
 	struct scene_obj *obj;
 	int ret;
 
+	ret = scene_calc_arrange(scn, &arr);
+	if (ret < 0)
+		return log_msg_ret("arr", ret);
+
 	list_for_each_entry(obj, &scn->obj_head, sibling) {
 		switch (obj->type) {
 		case SCENEOBJT_NONE:
@@ -493,7 +541,7 @@ int scene_arrange(struct scene *scn)
 			struct scene_obj_menu *menu;
 
 			menu = (struct scene_obj_menu *)obj,
-			ret = scene_menu_arrange(scn, menu);
+			ret = scene_menu_arrange(scn, &arr, menu);
 			if (ret)
 				return log_msg_ret("arr", ret);
 			break;
@@ -502,7 +550,7 @@ int scene_arrange(struct scene *scn)
 			struct scene_obj_textline *tline;
 
 			tline = (struct scene_obj_textline *)obj,
-			ret = scene_textline_arrange(scn, tline);
+			ret = scene_textline_arrange(scn, &arr, tline);
 			if (ret)
 				return log_msg_ret("arr", ret);
 			break;
diff --git a/boot/scene_internal.h b/boot/scene_internal.h
index e72202c98213..be25f6a8b967 100644
--- a/boot/scene_internal.h
+++ b/boot/scene_internal.h
@@ -96,10 +96,12 @@ int scene_calc_dims(struct scene *scn, bool do_menus);
  * if not already done
  *
  * @scn: Scene to update
+ * @arr: Arrangement information
  * @menu: Menu to process
  * Returns: 0 if OK, -ve on error
  */
-int scene_menu_arrange(struct scene *scn, struct scene_obj_menu *menu);
+int scene_menu_arrange(struct scene *scn, struct expo_arrange_info *arr,
+		       struct scene_obj_menu *menu);
 
 /**
  * scene_textline_arrange() - Set the position of things in a textline
@@ -108,10 +110,12 @@ int scene_menu_arrange(struct scene *scn, struct scene_obj_menu *menu);
  * positioned correctly relative to the textline.
  *
  * @scn: Scene to update
+ * @arr: Arrangement information
  * @tline: textline to process
  * Returns: 0 if OK, -ve on error
  */
-int scene_textline_arrange(struct scene *scn, struct scene_obj_textline *tline);
+int scene_textline_arrange(struct scene *scn, struct expo_arrange_info *arr,
+			   struct scene_obj_textline *tline);
 
 /**
  * scene_apply_theme() - Apply a theme to a scene
@@ -358,4 +362,16 @@ int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline);
  */
 int scene_textline_close(struct scene *scn, struct scene_obj_textline *tline);
 
+/**
+ * scene_calc_arrange() - Calculate sizes needed to arrange a scene
+ *
+ * Checks the size of some objects and stores this info to help with a later
+ * scene arrangement
+ *
+ * @scn: Scene to check
+ * @arr: Place to put scene-arrangement info
+ * Returns: 0 if OK, -ve on error
+ */
+int scene_calc_arrange(struct scene *scn, struct expo_arrange_info *arr);
+
 #endif /* __SCENE_INTERNAL_H */
diff --git a/boot/scene_menu.c b/boot/scene_menu.c
index 63994165efba..dbf6eacb2983 100644
--- a/boot/scene_menu.c
+++ b/boot/scene_menu.c
@@ -169,7 +169,8 @@ int scene_menu_calc_dims(struct scene_obj_menu *menu)
 	return 0;
 }
 
-int scene_menu_arrange(struct scene *scn, struct scene_obj_menu *menu)
+int scene_menu_arrange(struct scene *scn, struct expo_arrange_info *arr,
+		       struct scene_obj_menu *menu)
 {
 	const bool open = menu->obj.flags & SCENEOF_OPEN;
 	struct expo *exp = scn->expo;
@@ -183,16 +184,18 @@ int scene_menu_arrange(struct scene *scn, struct scene_obj_menu *menu)
 	x = menu->obj.dim.x;
 	y = menu->obj.dim.y;
 	if (menu->title_id) {
+		int width;
+
 		ret = scene_obj_set_pos(scn, menu->title_id, menu->obj.dim.x, y);
 		if (ret < 0)
 			return log_msg_ret("tit", ret);
 
-		ret = scene_obj_get_hw(scn, menu->title_id, NULL);
+		ret = scene_obj_get_hw(scn, menu->title_id, &width);
 		if (ret < 0)
 			return log_msg_ret("hei", ret);
 
 		if (stack)
-			x += 200;
+			x += arr->label_width + theme->menu_title_margin_x;
 		else
 			y += ret * 2;
 	}
diff --git a/boot/scene_textline.c b/boot/scene_textline.c
index 6ea072a1c268..576a402a688d 100644
--- a/boot/scene_textline.c
+++ b/boot/scene_textline.c
@@ -85,7 +85,8 @@ int scene_textline_calc_dims(struct scene_obj_textline *tline)
 	return 0;
 }
 
-int scene_textline_arrange(struct scene *scn, struct scene_obj_textline *tline)
+int scene_textline_arrange(struct scene *scn, struct expo_arrange_info *arr,
+			   struct scene_obj_textline *tline)
 {
 	const bool open = tline->obj.flags & SCENEOF_OPEN;
 	bool point;
diff --git a/doc/develop/expo.rst b/doc/develop/expo.rst
index c87b6ec81285..f7b636e5fc62 100644
--- a/doc/develop/expo.rst
+++ b/doc/develop/expo.rst
@@ -176,6 +176,10 @@ menu-inset
 menuitem-gap-y
     Number of pixels between menu items
 
+menu-title-margin-x
+    Number of pixels between right side of menu title to the left size of the
+    menu labels
+
 Pop-up mode
 -----------
 
diff --git a/include/expo.h b/include/expo.h
index 3260703a7a01..4f62ee077e1f 100644
--- a/include/expo.h
+++ b/include/expo.h
@@ -59,11 +59,14 @@ struct expo_action {
  * @font_size: Default font size for all text
  * @menu_inset: Inset width (on each side and top/bottom) for menu items
  * @menuitem_gap_y: Gap between menu items in pixels
+ * @menu_title_margin_x: Gap between right side of menu title and left size of
+ *	menu label
  */
 struct expo_theme {
 	u32 font_size;
 	u32 menu_inset;
 	u32 menuitem_gap_y;
+	u32 menu_title_margin_x;
 };
 
 /**
@@ -341,6 +344,15 @@ struct scene_obj_textline {
 	uint pos;
 };
 
+/**
+ * struct expo_arrange_info - Information used when arranging a scene
+ *
+ * @label_width: Maximum width of labels in scene
+ */
+struct expo_arrange_info {
+	int label_width;
+};
+
 /**
  * expo_new() - create a new expo
  *
-- 
2.42.0.582.g8ccd20d70d-goog



More information about the U-Boot mailing list