In some cases it is useful to obtain more than just two bounding boxes
from a menu, e.g. to line up all descriptions vertically.

Use an array to obtain bounding-box information and calculate it
separately for each item.

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

 boot/scene.c          | 61 +++++++++++++++++++++++++++----------------
 boot/scene_internal.h | 46 ++++++++++++++++++++++++++------
 boot/scene_menu.c     | 58 ++++++++++++++++++++++++++--------------
 3 files changed, 115 insertions(+), 50 deletions(-)

diff --git a/boot/scene.c b/boot/scene.c
index ff6712a0db6..6142d2b736d 100644
--- a/boot/scene.c
+++ b/boot/scene.c
@@ -326,9 +326,9 @@ int scene_obj_get_hw(struct scene *scn, uint id, int 
*widthp)
  */
 static void scene_render_background(struct scene_obj *obj, bool box_only)
 {
+       struct vidconsole_bbox bbox[SCENEBB_count], *sel;
        struct expo *exp = obj->scene->expo;
        const struct expo_theme *theme = &exp->theme;
-       struct vidconsole_bbox bbox, label_bbox;
        struct udevice *dev = exp->display;
        struct video_priv *vid_priv;
        struct udevice *cons = exp->cons;
@@ -347,17 +347,20 @@ static void scene_render_background(struct scene_obj 
*obj, bool box_only)
        }
 
        /* see if this object wants to render a background */
-       if (scene_obj_calc_bbox(obj, &bbox, &label_bbox))
+       if (scene_obj_calc_bbox(obj, bbox))
+               return;
+
+       sel = &bbox[SCENEBB_label];
+       if (!sel->valid)
                return;
 
        vidconsole_push_colour(cons, fore, back, &old);
-       video_fill_part(dev, label_bbox.x0 - inset, label_bbox.y0 - inset,
-                       label_bbox.x1 + inset, label_bbox.y1 + inset,
+       video_fill_part(dev, sel->x0 - inset, sel->y0 - inset,
+                       sel->x1 + inset, sel->y1 + inset,
                        vid_priv->colour_fg);
        vidconsole_pop_colour(cons, &old);
        if (box_only) {
-               video_fill_part(dev, label_bbox.x0, label_bbox.y0,
-                               label_bbox.x1, label_bbox.y1,
+               video_fill_part(dev, sel->x0, sel->y0, sel->x1, sel->y1,
                                vid_priv->colour_bg);
        }
 }
@@ -730,8 +733,7 @@ int scene_send_key(struct scene *scn, int key, struct 
expo_action *event)
        return 0;
 }
 
-int scene_obj_calc_bbox(struct scene_obj *obj, struct vidconsole_bbox *bbox,
-                       struct vidconsole_bbox *label_bbox)
+int scene_obj_calc_bbox(struct scene_obj *obj, struct vidconsole_bbox bbox[])
 {
        switch (obj->type) {
        case SCENEOBJT_NONE:
@@ -741,14 +743,15 @@ int scene_obj_calc_bbox(struct scene_obj *obj, struct 
vidconsole_bbox *bbox,
        case SCENEOBJT_MENU: {
                struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
 
-               scene_menu_calc_bbox(menu, bbox, label_bbox);
+               scene_menu_calc_bbox(menu, bbox);
                break;
        }
        case SCENEOBJT_TEXTLINE: {
                struct scene_obj_textline *tline;
 
                tline = (struct scene_obj_textline *)obj;
-               scene_textline_calc_bbox(tline, bbox, label_bbox);
+               scene_textline_calc_bbox(tline, &bbox[SCENEBB_all],
+                                        &bbox[SCENEBB_label]);
                break;
        }
        }
@@ -916,28 +919,42 @@ int scene_iter_objs(struct scene *scn, 
expo_scene_obj_iterator iter,
        return 0;
 }
 
+int scene_bbox_join(const struct vidconsole_bbox *src, int inset,
+                   struct vidconsole_bbox *dst)
+{
+       if (dst->valid) {
+               dst->x0 = min(dst->x0, src->x0 - inset);
+               dst->y0 = min(dst->y0, src->y0);
+               dst->x1 = max(dst->x1, src->x1 + inset);
+               dst->y1 = max(dst->y1, src->y1);
+       } else {
+               dst->x0 = src->x0 - inset;
+               dst->y0 = src->y0;
+               dst->x1 = src->x1 + inset;
+               dst->y1 = src->y1;
+               dst->valid = true;
+       }
+
+       return 0;
+}
+
 int scene_bbox_union(struct scene *scn, uint id, int inset,
                     struct vidconsole_bbox *bbox)
 {
        struct scene_obj *obj;
+       struct vidconsole_bbox local;
 
        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->bbox.x0 - inset);
-               bbox->y0 = min(bbox->y0, obj->bbox.y0);
-               bbox->x1 = max(bbox->x1, obj->bbox.x1 + inset);
-               bbox->y1 = max(bbox->y1, obj->bbox.y1);
-       } else {
-               bbox->x0 = obj->bbox.x0 - inset;
-               bbox->y0 = obj->bbox.y0;
-               bbox->x1 = obj->bbox.x1 + inset;
-               bbox->y1 = obj->bbox.y1;
-               bbox->valid = true;
-       }
+       local.x0 = obj->bbox.x0;
+       local.y0 = obj->bbox.y0;
+       local.x1 = obj->bbox.x1;
+       local.y1 = obj->bbox.y1;
+       local.valid = true;
+       scene_bbox_join(&local, inset, bbox);
 
        return 0;
 }
diff --git a/boot/scene_internal.h b/boot/scene_internal.h
index ec9008ea593..ac2a36d6e4d 100644
--- a/boot/scene_internal.h
+++ b/boot/scene_internal.h
@@ -13,6 +13,27 @@ struct vidconsole_bbox;
 
 typedef int (*expo_scene_obj_iterator)(struct scene_obj *obj, void *priv);
 
+/**
+ * enum scene_bbox_t - Parts of an object which can have a bounding box
+ *
+ * Objects can provide any or all of these bounding boxes
+ *
+ * @SCENEBB_label: Menu-item label
+ * @SCENEBB_key: Menu-item key label
+ * @SCENEBB_desc: Menu-item Description
+ * @SCENEBB_curitem: Current item (pointed to)
+ * @SCENEBB_all: All the above objects combined
+ */
+enum scene_bbox_t {
+       SCENEBB_label,
+       SCENEBB_key,
+       SCENEBB_desc,
+       SCENEBB_curitem,
+       SCENEBB_all,
+
+       SCENEBB_count,
+};
+
 /**
  * expo_lookup_scene_id() - Look up a scene ID
  *
@@ -291,6 +312,19 @@ struct scene_menitem *scene_menuitem_find_seq(const struct 
scene_obj_menu *menu,
 struct scene_menitem *scene_menuitem_find_val(const struct scene_obj_menu 
*menu,
                                              int val);
 
+/**
+ * scene_bbox_join() - update bouding box with a given src box
+ *
+ * Updates @dst so that it encompasses the bounding box @src
+ *
+ * @src: Input bounding box
+ * @inset: Amount of inset to use for width
+ * @dst: Bounding box to update
+ * Return: 0 if OK, -ve on error
+ */
+int scene_bbox_join(const struct vidconsole_bbox *src, int inset,
+                   struct vidconsole_bbox *dst);
+
 /**
  * scene_bbox_union() - update bouding box with the demensions of an object
  *
@@ -319,13 +353,11 @@ int scene_textline_calc_dims(struct scene_obj_textline 
*tline);
  * 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
+ * @bbox: List of bounding box to fill in
  * Return: 0 if OK, -ve on error
  */
 void scene_menu_calc_bbox(struct scene_obj_menu *menu,
-                         struct vidconsole_bbox *bbox,
-                         struct vidconsole_bbox *label_bbox);
+                         struct vidconsole_bbox *bbox);
 
 /**
  * scene_textline_calc_bbox() - Calculate bounding box for the textline
@@ -343,12 +375,10 @@ void scene_textline_calc_bbox(struct scene_obj_textline 
*menu,
  * scene_obj_calc_bbox() - Calculate bounding boxes for an object
  *
  * @obj: Object to process
- * @bbox: Returns bounding box of object including prompts
- * @label_bbox: Returns bounding box of labels (active area)
+ * @bbox: Returns bounding boxes for object
  * Return: 0 if OK, -ve on error
  */
-int scene_obj_calc_bbox(struct scene_obj *obj, struct vidconsole_bbox *bbox,
-                       struct vidconsole_bbox *label_bbox);
+int scene_obj_calc_bbox(struct scene_obj *obj, struct vidconsole_bbox *bbox);
 
 /**
  * scene_textline_open() - Open a textline object
diff --git a/boot/scene_menu.c b/boot/scene_menu.c
index 490fb42995c..6d945cfa62d 100644
--- a/boot/scene_menu.c
+++ b/boot/scene_menu.c
@@ -132,55 +132,73 @@ static int menu_point_to_item(struct scene_obj_menu 
*menu, uint item_id)
 }
 
 void scene_menu_calc_bbox(struct scene_obj_menu *menu,
-                         struct vidconsole_bbox *bbox,
-                         struct vidconsole_bbox *label_bbox)
+                         struct vidconsole_bbox *bbox)
 {
        const struct expo_theme *theme = &menu->obj.scene->expo->theme;
        const struct scene_menitem *item;
+       int i;
 
-       bbox->valid = false;
-       scene_bbox_union(menu->obj.scene, menu->title_id, 0, bbox);
+       for (i = 0; i < SCENEBB_count; i++)
+               bbox[i].valid = false;
 
-       label_bbox->valid = false;
+       scene_bbox_union(menu->obj.scene, menu->title_id, 0,
+                        &bbox[SCENEBB_all]);
 
        list_for_each_entry(item, &menu->item_head, sibling) {
+               struct vidconsole_bbox local;
+
+               local.valid = false;
                scene_bbox_union(menu->obj.scene, item->label_id,
-                                theme->menu_inset, bbox);
-               scene_bbox_union(menu->obj.scene, item->key_id, 0, bbox);
-               scene_bbox_union(menu->obj.scene, item->desc_id, 0, bbox);
-               scene_bbox_union(menu->obj.scene, item->preview_id, 0, bbox);
+                                theme->menu_inset, &local);
+               scene_bbox_union(menu->obj.scene, item->key_id, 0, &local);
+               scene_bbox_union(menu->obj.scene, item->desc_id, 0, &local);
+               scene_bbox_union(menu->obj.scene, item->preview_id, 0, &local);
+
+               scene_bbox_join(&local, 0, &bbox[SCENEBB_all]);
 
-               /* Get the bounding box of all labels */
+               /* Get the bounding box of all individual fields */
                scene_bbox_union(menu->obj.scene, item->label_id,
-                                theme->menu_inset, label_bbox);
+                                theme->menu_inset, &bbox[SCENEBB_label]);
+               scene_bbox_union(menu->obj.scene, item->key_id,
+                                theme->menu_inset, &bbox[SCENEBB_key]);
+               scene_bbox_union(menu->obj.scene, item->desc_id,
+                                theme->menu_inset, &bbox[SCENEBB_desc]);
+
+               if (menu->cur_item_id == item->id)
+                       scene_bbox_join(&local, 0, &bbox[SCENEBB_curitem]);
        }
 
        /*
         * subtract the final menuitem's gap to keep the insert the same top
         * and bottom
         */
-       label_bbox->y1 -= theme->menuitem_gap_y;
+       bbox[SCENEBB_label].y1 -= theme->menuitem_gap_y;
 }
 
 int scene_menu_calc_dims(struct scene_obj_menu *menu)
 {
-       struct vidconsole_bbox bbox, label_bbox;
+       struct vidconsole_bbox bbox[SCENEBB_count], *cur;
        const struct scene_menitem *item;
 
-       scene_menu_calc_bbox(menu, &bbox, &label_bbox);
+       scene_menu_calc_bbox(menu, bbox);
 
        /* Make all labels the same size */
-       if (label_bbox.valid) {
+       cur = &bbox[SCENEBB_label];
+       if (cur->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);
+                                          cur->x1 - cur->x0,
+                                          cur->y1 - cur->y0);
                }
        }
 
-       if (bbox.valid) {
-               menu->obj.dims.x = bbox.x1 - bbox.x0;
-               menu->obj.dims.y = bbox.y1 - bbox.y0;
+       cur = &bbox[SCENEBB_all];
+       if (cur->valid) {
+               menu->obj.dims.x = cur->x1 - cur->x0;
+               menu->obj.dims.y = cur->y1 - cur->y0;
+
+               menu->obj.bbox.x1 = cur->x1;
+               menu->obj.bbox.y1 = cur->y1;
        }
 
        return 0;
-- 
2.43.0

Reply via email to