]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
expo: Set up the width and height of objects
authorSimon Glass <sjg@chromium.org>
Thu, 1 Jun 2023 16:22:52 +0000 (10:22 -0600)
committerTom Rini <trini@konsulko.com>
Fri, 14 Jul 2023 16:54:51 +0000 (12:54 -0400)
Provide a way to set the full dimensions of objects, i.e. including the
width and height.

For menus, calculate the bounding box of all objects in the menu. Set all
labels to be the same size, so that highlighting works correct, once
implemented.

Signed-off-by: Simon Glass <sjg@chromium.org>
boot/expo.c
boot/scene.c
boot/scene_internal.h
boot/scene_menu.c
doc/develop/expo.rst
include/expo.h
test/boot/expo.c

index be11cfd4e946597c0439d5821866828dcf05907f..67cae3c7e28da3a6c8fa9382f13f358b2ccaa8a8 100644 (file)
@@ -114,6 +114,30 @@ int expo_set_display(struct expo *exp, struct udevice *dev)
        return 0;
 }
 
+int expo_calc_dims(struct expo *exp)
+{
+       struct scene *scn;
+       int ret;
+
+       if (!exp->cons)
+               return log_msg_ret("dim", -ENOTSUPP);
+
+       list_for_each_entry(scn, &exp->scene_head, sibling) {
+               /*
+                * Do the menus last so that all the menus' text objects
+                * are dimensioned
+                */
+               ret = scene_calc_dims(scn, false);
+               if (ret)
+                       return log_msg_ret("scn", ret);
+               ret = scene_calc_dims(scn, true);
+               if (ret)
+                       return log_msg_ret("scn", ret);
+       }
+
+       return 0;
+}
+
 void expo_set_text_mode(struct expo *exp, bool text_mode)
 {
        exp->text_mode = text_mode;
index 981a18b3ba1c0dac84e876576b3932c4a0dc1fda..6d5e3c1f03dd7afd55fb7b7164994f12014a54c3 100644 (file)
@@ -207,6 +207,19 @@ int scene_obj_set_pos(struct scene *scn, uint id, int x, int y)
        return 0;
 }
 
+int scene_obj_set_size(struct scene *scn, uint id, int w, int h)
+{
+       struct scene_obj *obj;
+
+       obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
+       if (!obj)
+               return log_msg_ret("find", -ENOENT);
+       obj->dim.w = w;
+       obj->dim.h = h;
+
+       return 0;
+}
+
 int scene_obj_set_hide(struct scene *scn, uint id, bool hide)
 {
        int ret;
@@ -414,3 +427,42 @@ int scene_send_key(struct scene *scn, int key, struct expo_action *event)
 
        return 0;
 }
+
+int scene_calc_dims(struct scene *scn, bool do_menus)
+{
+       struct scene_obj *obj;
+       int ret;
+
+       list_for_each_entry(obj, &scn->obj_head, sibling) {
+               switch (obj->type) {
+               case SCENEOBJT_NONE:
+               case SCENEOBJT_TEXT:
+               case SCENEOBJT_IMAGE: {
+                       int width;
+
+                       if (!do_menus) {
+                               ret = scene_obj_get_hw(scn, obj->id, &width);
+                               if (ret < 0)
+                                       return log_msg_ret("get", ret);
+                               obj->dim.w = width;
+                               obj->dim.h = ret;
+                       }
+                       break;
+               }
+               case SCENEOBJT_MENU: {
+                       struct scene_obj_menu *menu;
+
+                       if (do_menus) {
+                               menu = (struct scene_obj_menu *)obj;
+
+                               ret = scene_menu_calc_dims(menu);
+                               if (ret)
+                                       return log_msg_ret("men", ret);
+                       }
+                       break;
+               }
+               }
+       }
+
+       return 0;
+}
index 24a2ba6a6a3df0da2d2d3cf81204a452b2564634..00085a2f55d31149c69b74e5757f12d0712a483b 100644 (file)
@@ -65,6 +65,17 @@ int scene_obj_add(struct scene *scn, const char *name, uint id,
  */
 int scene_obj_flag_clrset(struct scene *scn, uint id, uint clr, uint set);
 
+/**
+ * scene_calc_dims() - Calculate the dimensions of the scene objects
+ *
+ * Updates the width and height of all objects based on their contents
+ *
+ * @scn: Scene to update
+ * @do_menus: true to calculate only menus, false to calculate everything else
+ * Returns 0 if OK, -ENOTSUPP if there is no graphical console
+ */
+int scene_calc_dims(struct scene *scn, bool do_menus);
+
 /**
  * scene_menu_arrange() - Set the position of things in the menu
  *
@@ -133,4 +144,14 @@ int scene_render(struct scene *scn);
  */
 int scene_send_key(struct scene *scn, int key, struct expo_action *event);
 
+/**
+ * scene_menu_calc_dims() - Calculate the dimensions of a menu
+ *
+ * Updates the width and height of the menu based on its contents
+ *
+ * @menu: Menu to update
+ * Returns 0 if OK, -ENOTSUPP if there is no graphical console
+ */
+int scene_menu_calc_dims(struct scene_obj_menu *menu);
+
 #endif /* __SCENE_INTERNAL_H */
index eed7565f6a617d34e242c2144b1fc5740096c7c6..fa79cecdbd934ac3216a019f7fabf02ed7a00bd5 100644 (file)
@@ -43,6 +43,85 @@ static void menu_point_to_item(struct scene_obj_menu *menu, uint item_id)
        menu->cur_item_id = item_id;
 }
 
+static int scene_bbox_union(struct scene *scn, uint id,
+                           struct vidconsole_bbox *bbox)
+{
+       struct scene_obj *obj;
+
+       if (!id)
+               return 0;
+       obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
+       if (!obj)
+               return log_msg_ret("obj", -ENOENT);
+       if (bbox->valid) {
+               bbox->x0 = min(bbox->x0, obj->dim.x);
+               bbox->y0 = min(bbox->y0, obj->dim.y);
+               bbox->x1 = max(bbox->x1, obj->dim.x + obj->dim.w);
+               bbox->y1 = max(bbox->y1, obj->dim.y + obj->dim.h);
+       } else {
+               bbox->x0 = obj->dim.x;
+               bbox->y0 = obj->dim.y;
+               bbox->x1 = obj->dim.x + obj->dim.w;
+               bbox->y1 = obj->dim.y + obj->dim.h;
+               bbox->valid = true;
+       }
+
+       return 0;
+}
+
+/**
+ * scene_menu_calc_bbox() - Calculate bounding boxes for the menu
+ *
+ * @menu: Menu to process
+ * @bbox: Returns bounding box of menu including prompts
+ * @label_bbox: Returns bounding box of labels
+ */
+static void scene_menu_calc_bbox(struct scene_obj_menu *menu,
+                                struct vidconsole_bbox *bbox,
+                                struct vidconsole_bbox *label_bbox)
+{
+       const struct scene_menitem *item;
+
+       bbox->valid = false;
+       scene_bbox_union(menu->obj.scene, menu->title_id, bbox);
+
+       label_bbox->valid = false;
+
+       list_for_each_entry(item, &menu->item_head, sibling) {
+               scene_bbox_union(menu->obj.scene, item->label_id, bbox);
+               scene_bbox_union(menu->obj.scene, item->key_id, bbox);
+               scene_bbox_union(menu->obj.scene, item->desc_id, bbox);
+               scene_bbox_union(menu->obj.scene, item->preview_id, bbox);
+
+               /* Get the bounding box of all labels */
+               scene_bbox_union(menu->obj.scene, item->label_id, label_bbox);
+       }
+}
+
+int scene_menu_calc_dims(struct scene_obj_menu *menu)
+{
+       struct vidconsole_bbox bbox, label_bbox;
+       const struct scene_menitem *item;
+
+       scene_menu_calc_bbox(menu, &bbox, &label_bbox);
+
+       /* Make all labels the same size */
+       if (label_bbox.valid) {
+               list_for_each_entry(item, &menu->item_head, sibling) {
+                       scene_obj_set_size(menu->obj.scene, item->label_id,
+                                          label_bbox.x1 - label_bbox.x0,
+                                          label_bbox.y1 - label_bbox.y0);
+               }
+       }
+
+       if (bbox.valid) {
+               menu->obj.dim.w = bbox.x1 - bbox.x0;
+               menu->obj.dim.h = bbox.y1 - bbox.y0;
+       }
+
+       return 0;
+}
+
 int scene_menu_arrange(struct scene *scn, struct scene_obj_menu *menu)
 {
        struct scene_menitem *item;
index 9565974a28e9d2a6909e0fb53c574a035d5723d2..54861b93acf842ee394537e66a03b2d491a7bf14 100644 (file)
@@ -182,8 +182,6 @@ Some ideas for future work:
 - Add a Kconfig option to drop the names to save code / data space
 - Add a Kconfig option to disable vidconsole support to save code / data space
 - Support both graphical and text menus at the same time on different devices
-- Implement proper measurement of object bounding boxes, to permit more exact
-  layout. This would tidy up the layout when Truetype is not used
 - Support unicode
 - Support curses for proper serial-terminal menus
 
index b6777cebcbec51c7684e41888e5b3d9f04b06d52..6c45c403cf79410ecd4132db77e125d235bbb878 100644 (file)
@@ -327,6 +327,16 @@ const char *expo_get_str(struct expo *exp, uint id);
  */
 int expo_set_display(struct expo *exp, struct udevice *dev);
 
+/**
+ * expo_calc_dims() - Calculate the dimensions of the objects
+ *
+ * Updates the width and height of all objects based on their contents
+ *
+ * @exp: Expo to update
+ * Returns 0 if OK, -ENOTSUPP if there is no graphical console
+ */
+int expo_calc_dims(struct expo *exp);
+
 /**
  * expo_set_scene_id() - Set the current scene ID
  *
@@ -468,6 +478,17 @@ int scene_txt_set_font(struct scene *scn, uint id, const char *font_name,
  */
 int scene_obj_set_pos(struct scene *scn, uint id, int x, int y);
 
+/**
+ * scene_obj_set_size() - Set the size of an object
+ *
+ * @scn: Scene to update
+ * @id: ID of object to update
+ * @w: width in pixels
+ * @h: height in pixels
+ * Returns: 0 if OK, -ENOENT if @id is invalid
+ */
+int scene_obj_set_size(struct scene *scn, uint id, int w, int h);
+
 /**
  * scene_obj_set_hide() - Set whether an object is hidden
  *
index 5088776f7bd5d4d29339fdb3347a0c42a4bd321b..493d050baf872780cb7b62a1eaf8226d509c1f9b 100644 (file)
@@ -473,6 +473,48 @@ static int expo_render_image(struct unit_test_state *uts)
        /* render without a scene */
        ut_asserteq(-ECHILD, expo_render(exp));
 
+       ut_assertok(expo_calc_dims(exp));
+       ut_assertok(scene_arrange(scn));
+
+       /* check dimensions of text */
+       obj = scene_obj_find(scn, OBJ_TEXT, SCENEOBJT_NONE);
+       ut_assertnonnull(obj);
+       ut_asserteq(400, obj->dim.x);
+       ut_asserteq(100, obj->dim.y);
+       ut_asserteq(126, obj->dim.w);
+       ut_asserteq(40, obj->dim.h);
+
+       /* check dimensions of image */
+       obj = scene_obj_find(scn, OBJ_LOGO, SCENEOBJT_NONE);
+       ut_assertnonnull(obj);
+       ut_asserteq(50, obj->dim.x);
+       ut_asserteq(20, obj->dim.y);
+       ut_asserteq(160, obj->dim.w);
+       ut_asserteq(160, obj->dim.h);
+
+       /* check dimensions of menu labels - both should be the same width */
+       obj = scene_obj_find(scn, ITEM1_LABEL, SCENEOBJT_NONE);
+       ut_assertnonnull(obj);
+       ut_asserteq(50, obj->dim.x);
+       ut_asserteq(436, obj->dim.y);
+       ut_asserteq(29, obj->dim.w);
+       ut_asserteq(18, obj->dim.h);
+
+       obj = scene_obj_find(scn, ITEM2_LABEL, SCENEOBJT_NONE);
+       ut_assertnonnull(obj);
+       ut_asserteq(50, obj->dim.x);
+       ut_asserteq(454, obj->dim.y);
+       ut_asserteq(29, obj->dim.w);
+       ut_asserteq(18, obj->dim.h);
+
+       /* check dimensions of menu */
+       obj = scene_obj_find(scn, OBJ_MENU, SCENEOBJT_NONE);
+       ut_assertnonnull(obj);
+       ut_asserteq(50, obj->dim.x);
+       ut_asserteq(400, obj->dim.y);
+       ut_asserteq(160, obj->dim.w);
+       ut_asserteq(160, obj->dim.h);
+
        /* render it */
        expo_set_scene_id(exp, SCENE1);
        ut_assertok(expo_render(exp));