blob: de433ece6eec04452f3753304ed3340d89dfdfb6 [file] [log] [blame]
Simon Glass9f513932023-01-06 08:52:38 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Implementation of a menu in a scene
4 *
5 * Copyright 2022 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
Simon Glassfe4c1e22023-06-01 10:22:43 -06009#define LOG_CATEGORY LOGC_EXPO
Simon Glass9f513932023-01-06 08:52:38 -060010
Simon Glass9f513932023-01-06 08:52:38 -060011#include <dm.h>
12#include <expo.h>
13#include <malloc.h>
14#include <mapmem.h>
15#include <menu.h>
16#include <video.h>
17#include <video_console.h>
18#include <linux/input.h>
19#include "scene_internal.h"
20
21static void scene_menuitem_destroy(struct scene_menitem *item)
22{
23 free(item->name);
24 free(item);
25}
26
27void scene_menu_destroy(struct scene_obj_menu *menu)
28{
29 struct scene_menitem *item, *next;
30
31 list_for_each_entry_safe(item, next, &menu->item_head, sibling)
32 scene_menuitem_destroy(item);
33}
34
Simon Glass5fd4f782023-08-14 16:40:32 -060035struct scene_menitem *scene_menuitem_find(const struct scene_obj_menu *menu,
36 int id)
Simon Glassc55eeba2023-06-01 10:22:54 -060037{
38 struct scene_menitem *item;
39
40 list_for_each_entry(item, &menu->item_head, sibling) {
41 if (item->id == id)
42 return item;
43 }
44
45 return NULL;
46}
47
Simon Glass4462fa32023-08-14 16:40:38 -060048struct scene_menitem *scene_menuitem_find_seq(const struct scene_obj_menu *menu,
49 uint seq)
50{
51 struct scene_menitem *item;
52 uint i;
53
54 i = 0;
55 list_for_each_entry(item, &menu->item_head, sibling) {
56 if (i == seq)
57 return item;
58 i++;
59 }
60
61 return NULL;
62}
63
Simon Glass100389f2024-10-14 16:31:58 -060064struct scene_menitem *scene_menuitem_find_val(const struct scene_obj_menu *menu,
65 int val)
66{
67 struct scene_menitem *item;
68 uint i;
69
70 i = 0;
71 list_for_each_entry(item, &menu->item_head, sibling) {
Simon Glass6f3e87a2024-10-14 16:32:00 -060072 if (item->value == INT_MAX ? val == i : item->value == val)
Simon Glass100389f2024-10-14 16:31:58 -060073 return item;
74 i++;
75 }
76
77 return NULL;
78}
79
Simon Glassc55eeba2023-06-01 10:22:54 -060080/**
81 * update_pointers() - Update the pointer object and handle highlights
82 *
83 * @menu: Menu to update
84 * @id: ID of menu item to select/deselect
85 * @point: true if @id is being selected, false if it is being deselected
86 */
87static int update_pointers(struct scene_obj_menu *menu, uint id, bool point)
88{
89 struct scene *scn = menu->obj.scene;
Simon Glassd353b752023-06-01 10:22:55 -060090 const bool stack = scn->expo->popup;
Simon Glassc55eeba2023-06-01 10:22:54 -060091 const struct scene_menitem *item;
92 int ret;
93
94 item = scene_menuitem_find(menu, id);
95 if (!item)
96 return log_msg_ret("itm", -ENOENT);
97
98 /* adjust the pointer object to point to the selected item */
99 if (menu->pointer_id && item && point) {
100 struct scene_obj *label;
101
102 label = scene_obj_find(scn, item->label_id, SCENEOBJT_NONE);
103
104 ret = scene_obj_set_pos(scn, menu->pointer_id,
Simon Glassbc3a15f2025-05-02 08:46:31 -0600105 menu->obj.bbox.x0 + 200, label->bbox.y0);
Simon Glassc55eeba2023-06-01 10:22:54 -0600106 if (ret < 0)
107 return log_msg_ret("ptr", ret);
108 }
109
Simon Glassd353b752023-06-01 10:22:55 -0600110 if (stack) {
111 point &= scn->highlight_id == menu->obj.id;
112 scene_obj_flag_clrset(scn, item->label_id, SCENEOF_POINT,
113 point ? SCENEOF_POINT : 0);
114 }
115
Simon Glassc55eeba2023-06-01 10:22:54 -0600116 return 0;
117}
118
Simon Glass9f513932023-01-06 08:52:38 -0600119/**
120 * menu_point_to_item() - Point to a particular menu item
121 *
122 * Sets the currently pointed-to / highlighted menu item
123 */
Simon Glassbe04b962025-05-02 08:46:24 -0600124static int menu_point_to_item(struct scene_obj_menu *menu, uint item_id)
Simon Glass9f513932023-01-06 08:52:38 -0600125{
Simon Glassbe04b962025-05-02 08:46:24 -0600126 int ret;
127
128 if (menu->cur_item_id) {
129 ret = update_pointers(menu, menu->cur_item_id, false);
130 if (ret)
131 return log_msg_ret("mpi", ret);
132 }
Simon Glass9f513932023-01-06 08:52:38 -0600133 menu->cur_item_id = item_id;
Simon Glassbe04b962025-05-02 08:46:24 -0600134 ret = update_pointers(menu, item_id, true);
135 if (ret)
136 return log_msg_ret("mpu", ret);
137
138 return 0;
Simon Glass9f513932023-01-06 08:52:38 -0600139}
140
Simon Glassf0994692023-10-01 19:13:29 -0600141void scene_menu_calc_bbox(struct scene_obj_menu *menu,
Simon Glass96910ef2025-05-02 08:46:34 -0600142 struct vidconsole_bbox *bbox)
Simon Glass7a960052023-06-01 10:22:52 -0600143{
Simon Glass86f1ac52023-06-01 10:23:00 -0600144 const struct expo_theme *theme = &menu->obj.scene->expo->theme;
Simon Glass7a960052023-06-01 10:22:52 -0600145 const struct scene_menitem *item;
Simon Glass96910ef2025-05-02 08:46:34 -0600146 int inset = theme->menu_inset;
147 int i;
Simon Glass7a960052023-06-01 10:22:52 -0600148
Simon Glass96910ef2025-05-02 08:46:34 -0600149 for (i = 0; i < SCENEBB_count; i++)
150 bbox[i].valid = false;
Simon Glass7a960052023-06-01 10:22:52 -0600151
Simon Glass96910ef2025-05-02 08:46:34 -0600152 scene_bbox_union(menu->obj.scene, menu->title_id, 0,
153 &bbox[SCENEBB_all]);
Simon Glass7a960052023-06-01 10:22:52 -0600154
155 list_for_each_entry(item, &menu->item_head, sibling) {
Simon Glass96910ef2025-05-02 08:46:34 -0600156 struct vidconsole_bbox local;
Simon Glass7a960052023-06-01 10:22:52 -0600157
Simon Glass96910ef2025-05-02 08:46:34 -0600158 local.valid = false;
159 scene_bbox_union(menu->obj.scene, item->label_id, inset,
160 &local);
161 scene_bbox_union(menu->obj.scene, item->key_id, 0, &local);
162 scene_bbox_union(menu->obj.scene, item->desc_id, 0, &local);
163 scene_bbox_union(menu->obj.scene, item->preview_id, 0, &local);
164
165 scene_bbox_join(&local, 0, &bbox[SCENEBB_all]);
166
167 /* Get the bounding box of all individual fields */
168 scene_bbox_union(menu->obj.scene, item->label_id, inset,
169 &bbox[SCENEBB_label]);
170 scene_bbox_union(menu->obj.scene, item->key_id, inset,
171 &bbox[SCENEBB_key]);
172 scene_bbox_union(menu->obj.scene, item->desc_id, inset,
173 &bbox[SCENEBB_desc]);
174
175 if (menu->cur_item_id == item->id)
176 scene_bbox_join(&local, 0, &bbox[SCENEBB_curitem]);
Simon Glass7a960052023-06-01 10:22:52 -0600177 }
Simon Glass86f1ac52023-06-01 10:23:00 -0600178
179 /*
Simon Glass96910ef2025-05-02 08:46:34 -0600180 * subtract the final menuitem's gap to keep the inset the same top and
181 * bottom
Simon Glass86f1ac52023-06-01 10:23:00 -0600182 */
Simon Glass96910ef2025-05-02 08:46:34 -0600183 bbox[SCENEBB_label].y1 -= theme->menuitem_gap_y;
Simon Glass7a960052023-06-01 10:22:52 -0600184}
185
186int scene_menu_calc_dims(struct scene_obj_menu *menu)
187{
Simon Glass96910ef2025-05-02 08:46:34 -0600188 struct vidconsole_bbox bbox[SCENEBB_count], *cur;
Simon Glass7a960052023-06-01 10:22:52 -0600189 const struct scene_menitem *item;
190
Simon Glass96910ef2025-05-02 08:46:34 -0600191 scene_menu_calc_bbox(menu, bbox);
Simon Glass7a960052023-06-01 10:22:52 -0600192
Simon Glass43bfbb22025-05-02 08:46:36 -0600193 /* Make all field types the same width */
194 list_for_each_entry(item, &menu->item_head, sibling) {
195 cur = &bbox[SCENEBB_label];
196 if (cur->valid)
197 scene_obj_set_width(menu->obj.scene, item->label_id,
198 cur->x1 - cur->x0);
199 cur = &bbox[SCENEBB_key];
200 if (cur->valid)
201 scene_obj_set_width(menu->obj.scene, item->key_id,
202 cur->x1 - cur->x0);
203 cur = &bbox[SCENEBB_desc];
204 if (cur->valid)
205 scene_obj_set_width(menu->obj.scene, item->desc_id,
206 cur->x1 - cur->x0);
Simon Glass7a960052023-06-01 10:22:52 -0600207 }
208
Simon Glass96910ef2025-05-02 08:46:34 -0600209 cur = &bbox[SCENEBB_all];
210 if (cur->valid) {
211 menu->obj.dims.x = cur->x1 - cur->x0;
212 menu->obj.dims.y = cur->y1 - cur->y0;
213
214 menu->obj.bbox.x1 = cur->x1;
215 menu->obj.bbox.y1 = cur->y1;
Simon Glass7a960052023-06-01 10:22:52 -0600216 }
217
218 return 0;
219}
220
Simon Glass377f18e2024-10-14 16:31:55 -0600221int scene_menu_arrange(struct scene *scn, struct expo_arrange_info *arr,
222 struct scene_obj_menu *menu)
Simon Glass9f513932023-01-06 08:52:38 -0600223{
Simon Glassd353b752023-06-01 10:22:55 -0600224 const bool open = menu->obj.flags & SCENEOF_OPEN;
225 struct expo *exp = scn->expo;
226 const bool stack = exp->popup;
Simon Glass86f1ac52023-06-01 10:23:00 -0600227 const struct expo_theme *theme = &exp->theme;
Simon Glass9f513932023-01-06 08:52:38 -0600228 struct scene_menitem *item;
Simon Glassc55eeba2023-06-01 10:22:54 -0600229 uint sel_id;
Simon Glassd353b752023-06-01 10:22:55 -0600230 int x, y;
Simon Glass9f513932023-01-06 08:52:38 -0600231 int ret;
232
Simon Glassbc3a15f2025-05-02 08:46:31 -0600233 x = menu->obj.bbox.x0;
234 y = menu->obj.bbox.y0;
Simon Glass9f513932023-01-06 08:52:38 -0600235 if (menu->title_id) {
Simon Glass377f18e2024-10-14 16:31:55 -0600236 int width;
237
Simon Glassbc3a15f2025-05-02 08:46:31 -0600238 ret = scene_obj_set_pos(scn, menu->title_id, menu->obj.bbox.x0, y);
Simon Glass9f513932023-01-06 08:52:38 -0600239 if (ret < 0)
240 return log_msg_ret("tit", ret);
241
Simon Glass377f18e2024-10-14 16:31:55 -0600242 ret = scene_obj_get_hw(scn, menu->title_id, &width);
Simon Glass9f513932023-01-06 08:52:38 -0600243 if (ret < 0)
244 return log_msg_ret("hei", ret);
245
Simon Glassd353b752023-06-01 10:22:55 -0600246 if (stack)
Simon Glass377f18e2024-10-14 16:31:55 -0600247 x += arr->label_width + theme->menu_title_margin_x;
Simon Glassd353b752023-06-01 10:22:55 -0600248 else
249 y += ret * 2;
Simon Glass9f513932023-01-06 08:52:38 -0600250 }
251
252 /*
253 * Currently everything is hard-coded to particular columns so this
254 * won't work on small displays and looks strange if the font size is
255 * small. This can be updated once text measuring is supported in
256 * vidconsole
257 */
Simon Glassc55eeba2023-06-01 10:22:54 -0600258 sel_id = menu->cur_item_id;
Simon Glass9f513932023-01-06 08:52:38 -0600259 list_for_each_entry(item, &menu->item_head, sibling) {
Simon Glassd353b752023-06-01 10:22:55 -0600260 bool selected;
Simon Glass9f513932023-01-06 08:52:38 -0600261 int height;
262
Simon Glassd353b752023-06-01 10:22:55 -0600263 ret = scene_obj_get_hw(scn, item->label_id, NULL);
Simon Glass9f513932023-01-06 08:52:38 -0600264 if (ret < 0)
265 return log_msg_ret("get", ret);
266 height = ret;
267
268 if (item->flags & SCENEMIF_GAP_BEFORE)
269 y += height;
270
271 /* select an item if not done already */
Simon Glassc55eeba2023-06-01 10:22:54 -0600272 if (!sel_id)
273 sel_id = item->id;
Simon Glass9f513932023-01-06 08:52:38 -0600274
Simon Glassd353b752023-06-01 10:22:55 -0600275 selected = sel_id == item->id;
276
Simon Glass9f513932023-01-06 08:52:38 -0600277 /*
278 * Put the label on the left, then leave a space for the
279 * pointer, then the key and the description
280 */
Simon Glass86f1ac52023-06-01 10:23:00 -0600281 ret = scene_obj_set_pos(scn, item->label_id,
282 x + theme->menu_inset, y);
Simon Glass9f513932023-01-06 08:52:38 -0600283 if (ret < 0)
Simon Glassd353b752023-06-01 10:22:55 -0600284 return log_msg_ret("nam", ret);
285 scene_obj_set_hide(scn, item->label_id,
286 stack && !open && !selected);
Simon Glass9f513932023-01-06 08:52:38 -0600287
Simon Glassd353b752023-06-01 10:22:55 -0600288 if (item->key_id) {
289 ret = scene_obj_set_pos(scn, item->key_id, x + 230, y);
290 if (ret < 0)
291 return log_msg_ret("key", ret);
292 }
Simon Glass9f513932023-01-06 08:52:38 -0600293
Simon Glassd353b752023-06-01 10:22:55 -0600294 if (item->desc_id) {
295 ret = scene_obj_set_pos(scn, item->desc_id, x + 280, y);
296 if (ret < 0)
297 return log_msg_ret("des", ret);
298 }
Simon Glass9f513932023-01-06 08:52:38 -0600299
300 if (item->preview_id) {
301 bool hide;
302
303 /*
304 * put all previews on top of each other, on the right
305 * size of the display
306 */
307 ret = scene_obj_set_pos(scn, item->preview_id, -4, y);
308 if (ret < 0)
309 return log_msg_ret("prev", ret);
310
311 hide = menu->cur_item_id != item->id;
312 ret = scene_obj_set_hide(scn, item->preview_id, hide);
313 if (ret < 0)
314 return log_msg_ret("hid", ret);
315 }
316
Simon Glassd353b752023-06-01 10:22:55 -0600317 if (!stack || open)
Simon Glass86f1ac52023-06-01 10:23:00 -0600318 y += height + theme->menuitem_gap_y;
Simon Glass9f513932023-01-06 08:52:38 -0600319 }
320
Simon Glassc55eeba2023-06-01 10:22:54 -0600321 if (sel_id)
322 menu_point_to_item(menu, sel_id);
Simon Glassebec4972025-05-02 08:46:33 -0600323 menu->obj.bbox.x1 = menu->obj.bbox.x0 + menu->obj.dims.x;
324 menu->obj.bbox.y1 = menu->obj.bbox.y0 + menu->obj.dims.y;
325 menu->obj.flags |= SCENEOF_SIZE_VALID;
Simon Glass9f513932023-01-06 08:52:38 -0600326
327 return 0;
328}
329
330int scene_menu(struct scene *scn, const char *name, uint id,
331 struct scene_obj_menu **menup)
332{
333 struct scene_obj_menu *menu;
334 int ret;
335
336 ret = scene_obj_add(scn, name, id, SCENEOBJT_MENU,
337 sizeof(struct scene_obj_menu),
338 (struct scene_obj **)&menu);
339 if (ret < 0)
340 return log_msg_ret("obj", -ENOMEM);
341
342 if (menup)
343 *menup = menu;
344 INIT_LIST_HEAD(&menu->item_head);
345
Simon Glass9f513932023-01-06 08:52:38 -0600346 return menu->obj.id;
347}
348
349static struct scene_menitem *scene_menu_find_key(struct scene *scn,
350 struct scene_obj_menu *menu,
351 int key)
352{
353 struct scene_menitem *item;
354
355 list_for_each_entry(item, &menu->item_head, sibling) {
356 if (item->key_id) {
357 struct scene_obj_txt *txt;
358 const char *str;
359
360 txt = scene_obj_find(scn, item->key_id, SCENEOBJT_TEXT);
361 if (txt) {
Simon Glass9ef02aa2025-05-02 08:46:37 -0600362 str = expo_get_str(scn->expo, txt->gen.str_id);
Simon Glass9f513932023-01-06 08:52:38 -0600363 if (str && *str == key)
364 return item;
365 }
366 }
367 }
368
369 return NULL;
370}
371
372int scene_menu_send_key(struct scene *scn, struct scene_obj_menu *menu, int key,
373 struct expo_action *event)
374{
Simon Glassf0e1e8c2023-06-01 10:22:59 -0600375 const bool open = menu->obj.flags & SCENEOF_OPEN;
Simon Glass9f513932023-01-06 08:52:38 -0600376 struct scene_menitem *item, *cur, *key_item;
377
378 cur = NULL;
379 key_item = NULL;
380
381 if (!list_empty(&menu->item_head)) {
382 list_for_each_entry(item, &menu->item_head, sibling) {
383 /* select an item if not done already */
384 if (menu->cur_item_id == item->id) {
385 cur = item;
386 break;
387 }
388 }
389 }
390
391 if (!cur)
392 return -ENOTTY;
393
394 switch (key) {
395 case BKEY_UP:
396 if (item != list_first_entry(&menu->item_head,
397 struct scene_menitem, sibling)) {
398 item = list_entry(item->sibling.prev,
399 struct scene_menitem, sibling);
Simon Glass719a3c62023-06-01 10:22:56 -0600400 event->type = EXPOACT_POINT_ITEM;
Simon Glass9f513932023-01-06 08:52:38 -0600401 event->select.id = item->id;
402 log_debug("up to item %d\n", event->select.id);
403 }
404 break;
405 case BKEY_DOWN:
406 if (!list_is_last(&item->sibling, &menu->item_head)) {
407 item = list_entry(item->sibling.next,
408 struct scene_menitem, sibling);
Simon Glass719a3c62023-06-01 10:22:56 -0600409 event->type = EXPOACT_POINT_ITEM;
Simon Glass9f513932023-01-06 08:52:38 -0600410 event->select.id = item->id;
411 log_debug("down to item %d\n", event->select.id);
412 }
413 break;
414 case BKEY_SELECT:
415 event->type = EXPOACT_SELECT;
416 event->select.id = item->id;
417 log_debug("select item %d\n", event->select.id);
418 break;
419 case BKEY_QUIT:
Simon Glassf0e1e8c2023-06-01 10:22:59 -0600420 if (scn->expo->popup && open) {
421 event->type = EXPOACT_CLOSE;
422 event->select.id = menu->obj.id;
423 } else {
424 event->type = EXPOACT_QUIT;
425 log_debug("menu quit\n");
426 }
Simon Glass9f513932023-01-06 08:52:38 -0600427 break;
428 case '0'...'9':
429 key_item = scene_menu_find_key(scn, menu, key);
430 if (key_item) {
431 event->type = EXPOACT_SELECT;
432 event->select.id = key_item->id;
433 }
434 break;
435 }
436
Simon Glass9f513932023-01-06 08:52:38 -0600437 return 0;
438}
439
440int scene_menuitem(struct scene *scn, uint menu_id, const char *name, uint id,
441 uint key_id, uint label_id, uint desc_id, uint preview_id,
442 uint flags, struct scene_menitem **itemp)
443{
444 struct scene_obj_menu *menu;
445 struct scene_menitem *item;
Simon Glass9f513932023-01-06 08:52:38 -0600446
447 menu = scene_obj_find(scn, menu_id, SCENEOBJT_MENU);
448 if (!menu)
449 return log_msg_ret("find", -ENOENT);
450
451 /* Check that the text ID is valid */
Simon Glassd353b752023-06-01 10:22:55 -0600452 if (!scene_obj_find(scn, label_id, SCENEOBJT_TEXT))
Simon Glass9f513932023-01-06 08:52:38 -0600453 return log_msg_ret("txt", -EINVAL);
454
Dan Carpenter463be542023-07-31 17:08:29 +0300455 item = calloc(1, sizeof(struct scene_menitem));
Simon Glass9f513932023-01-06 08:52:38 -0600456 if (!item)
457 return log_msg_ret("item", -ENOMEM);
458 item->name = strdup(name);
459 if (!item->name) {
460 free(item);
461 return log_msg_ret("name", -ENOMEM);
462 }
463
464 item->id = resolve_id(scn->expo, id);
465 item->key_id = key_id;
466 item->label_id = label_id;
467 item->desc_id = desc_id;
468 item->preview_id = preview_id;
469 item->flags = flags;
Simon Glass100389f2024-10-14 16:31:58 -0600470 item->value = INT_MAX;
Simon Glass9f513932023-01-06 08:52:38 -0600471 list_add_tail(&item->sibling, &menu->item_head);
472
Simon Glass9f513932023-01-06 08:52:38 -0600473 if (itemp)
474 *itemp = item;
475
476 return item->id;
477}
478
479int scene_menu_set_title(struct scene *scn, uint id, uint title_id)
480{
481 struct scene_obj_menu *menu;
482 struct scene_obj_txt *txt;
483
484 menu = scene_obj_find(scn, id, SCENEOBJT_MENU);
485 if (!menu)
486 return log_msg_ret("menu", -ENOENT);
487
488 /* Check that the ID is valid */
489 if (title_id) {
490 txt = scene_obj_find(scn, title_id, SCENEOBJT_TEXT);
491 if (!txt)
492 return log_msg_ret("txt", -EINVAL);
493 }
494
495 menu->title_id = title_id;
496
497 return 0;
498}
499
500int scene_menu_set_pointer(struct scene *scn, uint id, uint pointer_id)
501{
502 struct scene_obj_menu *menu;
503 struct scene_obj *obj;
504
505 menu = scene_obj_find(scn, id, SCENEOBJT_MENU);
506 if (!menu)
507 return log_msg_ret("menu", -ENOENT);
508
509 /* Check that the ID is valid */
510 if (pointer_id) {
511 obj = scene_obj_find(scn, pointer_id, SCENEOBJT_NONE);
512 if (!obj)
513 return log_msg_ret("obj", -EINVAL);
514 }
515
516 menu->pointer_id = pointer_id;
517
518 return 0;
519}
520
Simon Glassbe04b962025-05-02 08:46:24 -0600521int scene_menu_select_item(struct scene *scn, uint id, uint cur_item_id)
522{
523 struct scene_obj_menu *menu;
524 int ret;
525
526 menu = scene_obj_find(scn, id, SCENEOBJT_MENU);
527 if (!menu)
528 return log_msg_ret("menu", -ENOENT);
529
530 ret = menu_point_to_item(menu, cur_item_id);
531 if (ret)
532 return log_msg_ret("msi", ret);
533
534 return 0;
535}
536
537int scene_menu_get_cur_item(struct scene *scn, uint id)
538{
539 struct scene_obj_menu *menu;
540
541 menu = scene_obj_find(scn, id, SCENEOBJT_MENU);
542 if (!menu)
543 return log_msg_ret("menu", -ENOENT);
544
545 return menu->cur_item_id;
546}
547
Simon Glass9f513932023-01-06 08:52:38 -0600548int scene_menu_display(struct scene_obj_menu *menu)
549{
550 struct scene *scn = menu->obj.scene;
551 struct scene_obj_txt *pointer;
552 struct expo *exp = scn->expo;
553 struct scene_menitem *item;
554 const char *pstr;
555
556 printf("U-Boot : Boot Menu\n\n");
557 if (menu->title_id) {
558 struct scene_obj_txt *txt;
559 const char *str;
560
561 txt = scene_obj_find(scn, menu->title_id, SCENEOBJT_TEXT);
562 if (!txt)
563 return log_msg_ret("txt", -EINVAL);
564
Simon Glass9ef02aa2025-05-02 08:46:37 -0600565 str = expo_get_str(exp, txt->gen.str_id);
Simon Glass9f513932023-01-06 08:52:38 -0600566 printf("%s\n\n", str);
567 }
568
569 if (list_empty(&menu->item_head))
570 return 0;
571
572 pointer = scene_obj_find(scn, menu->pointer_id, SCENEOBJT_TEXT);
Simon Glass9ef02aa2025-05-02 08:46:37 -0600573 pstr = expo_get_str(scn->expo, pointer->gen.str_id);
Simon Glass9f513932023-01-06 08:52:38 -0600574
575 list_for_each_entry(item, &menu->item_head, sibling) {
576 struct scene_obj_txt *key = NULL, *label = NULL;
577 struct scene_obj_txt *desc = NULL;
578 const char *kstr = NULL, *lstr = NULL, *dstr = NULL;
579
580 key = scene_obj_find(scn, item->key_id, SCENEOBJT_TEXT);
581 if (key)
Simon Glass9ef02aa2025-05-02 08:46:37 -0600582 kstr = expo_get_str(exp, key->gen.str_id);
Simon Glass9f513932023-01-06 08:52:38 -0600583
584 label = scene_obj_find(scn, item->label_id, SCENEOBJT_TEXT);
585 if (label)
Simon Glass9ef02aa2025-05-02 08:46:37 -0600586 lstr = expo_get_str(exp, label->gen.str_id);
Simon Glass9f513932023-01-06 08:52:38 -0600587
588 desc = scene_obj_find(scn, item->desc_id, SCENEOBJT_TEXT);
589 if (desc)
Simon Glass9ef02aa2025-05-02 08:46:37 -0600590 dstr = expo_get_str(exp, desc->gen.str_id);
Simon Glass9f513932023-01-06 08:52:38 -0600591
592 printf("%3s %3s %-10s %s\n",
593 pointer && menu->cur_item_id == item->id ? pstr : "",
594 kstr, lstr, dstr);
595 }
596
597 return -ENOTSUPP;
598}
Simon Glass01922ec2023-06-01 10:22:57 -0600599
Simon Glass12f57732023-06-01 10:22:58 -0600600int scene_menu_render_deps(struct scene *scn, struct scene_obj_menu *menu)
601{
602 struct scene_menitem *item;
603
604 scene_render_deps(scn, menu->title_id);
605 scene_render_deps(scn, menu->cur_item_id);
606 scene_render_deps(scn, menu->pointer_id);
607
608 list_for_each_entry(item, &menu->item_head, sibling) {
609 scene_render_deps(scn, item->key_id);
610 scene_render_deps(scn, item->label_id);
611 scene_render_deps(scn, item->desc_id);
612 }
613
614 return 0;
615}