blob: d6fc487e030b6b2ddbe758f40d86939b42ffe0dd [file] [log] [blame]
Simon Glass311bd352023-01-06 08:52:43 -06001.. SPDX-License-Identifier: GPL-2.0+
2
3Expo menu
4=========
5
6U-Boot provides a menu implementation for use with selecting bootflows and
7changing U-Boot settings. This is in early stages of development.
8
9Motivation
10----------
11
12U-Boot already has a text-based menu system accessed via the
13:doc:`../usage/cmd/bootmenu`. This works using environment variables, or via
14some EFI-specific hacks.
15
16The command makes use of a lower-level `menu` implementation, which is quite
17flexible and can be used to make menu hierarchies.
18
19However this system is not flexible enough for use with standard boot. It does
20not support a graphical user interface and cannot currently support anything
21more than a very simple list of items. While it does support multiple menus in
22hierarchies, these are implemented by the caller. See for example `eficonfig.c`.
23
24Another challenge with the current menu implementation is that it controls
25the event loop, such that bootmenu_loop() does not return until a key is
26pressed. This makes it difficult to implement dynamic displays or to do other
27things while the menu is running, such as searching for more bootflows.
28
29For these reasons an attempt has been made to develop a more flexible system
30which can handle menus as well as other elements. This is called 'expo', short
31for exposition, in an attempt to avoid common words like display, screen, menu
32and the like. The primary goal is to support Verified Boot for Embedded (VBE),
33although it is available to any boot method, using the 'bootflow menu' command.
34
35Efforts have been made to use common code with the existing menu, including
36key processing in particular.
37
38Previous work looked at integrating Nuklear into U-Boot. This works fine and
39could provide a way to provide a more flexible UI, perhaps with expo dealing
40with the interface to Nuklear. But this is quite a big step and it may be years
41before this becomes desirable, if at all. For now, U-Boot only needs a fairly
42simple set of menus and options, so rendering them directly is fairly
43straightforward.
44
45Concepts
46--------
47
48The creator of the expo is here called a `controller` and it controls most
49aspects of the expo. This is the code that you must write to use expo.
50
51An `expo` is a set of scenes which can be presented to the user one at a time,
52to show information and obtain input from the user.
53
54A `scene` is a collection of objects which are displayed together on the screen.
55Only one scene is visible at a time and scenes do not share objects.
56
57A `scene object` is something that appears in the scene, such as some text, an
58image or a menu. Objects can be positioned and hidden.
59
60A `menu object` contains a title, a set of `menu items` and a pointer to the
61current item. Menu items consist of a keypress (indicating what to press to
62select the item), label and description. All three are shown in a single line
63within the menu. Items can also have a preview image, which is shown when the
64item is highlighted.
65
Simon Glass00f6c402023-10-01 19:13:40 -060066A `textline object` contains a label and an editable string.
67
Simon Glass138a3972025-05-02 08:46:44 -060068A `box object` is a rectangle with a given line width. It is not filled.
69
Simon Glass00f6c402023-10-01 19:13:40 -060070All components have a name. This is mostly for debugging, so it is easy to see
71what object is referred to, although the name is also used for saving values.
72Of course the ID numbers can help as well, but they are less easy to
73distinguish.
Simon Glass311bd352023-01-06 08:52:43 -060074
75While the expo implementation provides support for handling keypresses and
76rendering on the display or serial port, it does not actually deal with reading
77input from the user, nor what should be done when a particular menu item is
78selected. This is deliberate since having the event loop outside the expo is
79more flexible, particularly in a single-threaded environment like U-Boot.
80
81Everything within an expo has a unique ID number. This is done so that it is
82easy to refer to things after the expo has been created. The expectation is that
83the controller declares an enum containing all of the elements in the expo,
84passing the ID of each object as it is created. When a menu item is selected,
85its ID is returned. When a object's font or position needs to change, the ID is
86passed to expo functions to indicate which object it is. It is possible for expo
87to auto-allocate IDs, but this is not recommended. The use of IDs is a
88convenience, removing the need for the controller to store pointers to objects,
89or even the IDs of objects. Programmatic creation of many items in a loop can be
90handled by allocating space in the enum for a maximum number of items, then
91adding the loop count to the enum values to obtain unique IDs.
92
Simon Glass53a0a2f2024-10-14 16:31:57 -060093Some standard IDs are reserved for certain purposes. These are defined by
94`enum expo_id_t` and start at 1. `EXPOID_BASE_ID` defines the first ID which
95can be used for an expo.
96
97An ID of 0 is invalid. If this is specified in an expo call then a valid
98'dynamic IDs is allocated. Use expo_set_dynamic_start() to set the start
99value, so that they are allocated above the starting (enum) IDs.
Simon Glass6e9e4152023-06-01 10:22:47 -0600100
Simon Glass311bd352023-01-06 08:52:43 -0600101All text strings are stored in a structure attached to the expo, referenced by
102a text ID. This makes it easier at some point to implement multiple languages or
103to support Unicode strings.
104
105Menu objects do not have their own text and image objects. Instead they simply
106refer to objects which have been created. So a menu item is just a collection
107of IDs of text and image objects. When adding a menu item you must create these
108objects first, then create the menu item, passing in the relevant IDs.
109
Simon Glass5beb0572025-05-02 08:46:45 -0600110Position and alignment
111~~~~~~~~~~~~~~~~~~~~~~
112
113Objects are typically positioned automatically, when scene_arrange() is called.
114However it is possible to position objects manually. The scene_obj_set_pos()
115sets the coordinates of the top left of the object.
116
117All objects have a bounding box. Typically this is calculated by looking at the
118object contents, in `scene_calc_arrange()`. The calculated dimensions of each
119object are stored in the object's `dims` field.
120
121It is possible to adjust the size of an object with `scene_obj_set_size()` or
122even set the bounding box, with `scene_obj_set_bbox()`. The `SCENEOF_SIZE_VALID`
123flag tracks whether the width/height should be maintained when the position
124changes.
125
126If the bounding box is larger than the object needs, the object can be aligned
127to different edges within the box. Objects can be left- or right-aligned,
128or centred. For text objects this applies to each line of text. Normally objects
129are drawn starting at the top of their bounding box, but they can be aligned
130vertically to the bottom, or centred vertically within the box.
131
132Where the width of a text object's bounding box is smaller than the space needed
133to show the next, the text is word-wrapped onto multiple lines, assuming there
134is enough vertical space. Newline characters in the next cause a new line to be
135started. The measurement information is created by the Truetype console driver
136and stored in an alist in `struct scene_txt_generic`.
137
138When the object is drawn the `ofs` field indicates the x and y offset to use,
139from the top left of the bounding box. These values are affected by alignment.
140
Simon Glass311bd352023-01-06 08:52:43 -0600141Creating an expo
142----------------
143
Simon Glass61300722023-06-01 10:23:01 -0600144To create an expo programmatically, use `expo_new()` followed by `scene_new()`
145to create a scene. Then add objects to the scene, using functions like
146`scene_txt_str()` and `scene_menu()`. For every menu item, add text and image
147objects, then create the menu item with `scene_menuitem()`, referring to those
148objects.
149
150To create an expo using a description file, see :ref:`expo_format` below.
Simon Glass311bd352023-01-06 08:52:43 -0600151
152Layout
153------
154
155Individual objects can be positioned using `scene_obj_set_pos()`. Menu items
156cannot be positioned manually: this is done by `scene_arrange()` which is called
157automatically when something changes. The menu itself determines the position of
158its items.
159
160Rendering
161---------
162
163Rendering is performed by calling `expo_render()`. This uses either the
164vidconsole, if present, or the serial console in `text mode`. Expo handles
165presentation automatically in either case, without any change in how the expo is
166created.
167
168For the vidconsole, Truetype fonts can be used if enabled, to enhance the
169quality of the display. For text mode, each menu item is shown in a single line,
170allowing easy selection using arrow keys.
171
172Input
173-----
174
175The controller is responsible for collecting keyboard input. A good way to do
176this is to use `cli_ch_process()`, since it handles conversion of escape
177sequences into keys. However, expo has some special menu-key codes for
178navigating the interface. These are defined in `enum bootmenu_key` and include
179`BKEY_UP` for moving up and `BKEY_SELECT` for selecting an item. You can use
Simon Glass00f6c402023-10-01 19:13:40 -0600180`bootmenu_conv_key()` to convert an ASCII key into one of these, but if it
181returns a value >= `BKEY_FIRST_EXTRA` then you should pass the unmodified ASCII
182key to the expo, since it may be used by textline objects.
Simon Glass311bd352023-01-06 08:52:43 -0600183
184Once a keypress is decoded, call `expo_send_key()` to send it to the expo. This
185may cause an update to the expo state and may produce an action.
186
187Actions
188-------
189
190Call `expo_action_get()` in the event loop to check for any actions that the
191expo wants to report. These can include selecting a particular menu item, or
192quitting the menu. Processing of these is the responsibility of your controller.
193
194Event loop
195----------
196
197Expo is intended to be used in an event loop. For an example loop, see
198`bootflow_menu_run()`. It is possible to perform other work in your event loop,
199such as scanning devices for more bootflows.
200
201Themes
202------
203
Simon Glassc999e172023-06-01 10:22:53 -0600204Expo supports simple themes, for setting the font size, for example. Use the
205expo_apply_theme() function to load a theme, passing a node with the required
206properties:
207
208font-size
209 Font size to use for all text (type: u32)
210
Simon Glass86f1ac52023-06-01 10:23:00 -0600211menu-inset
212 Number of pixels to inset the menu on the sides and top (type: u32)
213
214menuitem-gap-y
215 Number of pixels between menu items
216
Simon Glass377f18e2024-10-14 16:31:55 -0600217menu-title-margin-x
218 Number of pixels between right side of menu title to the left size of the
219 menu labels
220
Simon Glass61300722023-06-01 10:23:01 -0600221Pop-up mode
222-----------
223
224Expos support two modes. The simple mode is used for selecting from a single
225menu, e.g. when choosing with OS to boot. In this mode the menu items are shown
226in a list (label, > pointer, key and description) and can be chosen using arrow
227keys and enter::
228
229 U-Boot Boot Menu
230
231 UP and DOWN to choose, ENTER to select
232
233 mmc1 > 0 Fedora-Workstation-armhfp-31-1.9
234 mmc3 1 Armbian
235
236The popup mode allows multiple menus to be present in a scene. Each is shown
237just as its title and label, as with the `CPU Speed` and `AC Power` menus here::
238
239 Test Configuration
240
241
242 CPU Speed <2 GHz> (highlighted)
243
244 AC Power Always Off
245
246
247 UP and DOWN to choose, ENTER to select
248
249
Simon Glassc8925112023-06-01 10:23:02 -0600250.. _expo_format:
251
Simon Glass61300722023-06-01 10:23:01 -0600252Expo Format
253-----------
254
255It can be tedious to create a complex expo using code. Expo supports a
256data-driven approach, where the expo description is in a devicetree file. This
257makes it easier and faster to create and edit the description. An expo builder
258is provided to convert this format into an expo structure.
259
260Layout of the expo scenes is handled automatically, based on a set of simple
Simon Glassc8925112023-06-01 10:23:02 -0600261rules. The :doc:`../usage/cmd/cedit` can be used to load a configuration
262and create an expo from it.
Simon Glass61300722023-06-01 10:23:01 -0600263
264Top-level node
265~~~~~~~~~~~~~~
266
267The top-level node has the following properties:
268
269dynamic-start
270 type: u32, optional
271
272 Specifies the start of the dynamically allocated objects. This results in
273 a call to expo_set_dynamic_start().
274
275The top-level node has the following subnodes:
276
277scenes
278 Specifies the scenes in the expo, each one being a subnode
279
280strings
281 Specifies the strings in the expo, each one being a subnode
282
283`scenes` node
284~~~~~~~~~~~~~
285
286Contains a list of scene subnodes. The name of each subnode is passed as the
287name to `scene_new()`.
288
289`strings` node
290~~~~~~~~~~~~~~
291
292Contains a list of string subnodes. The name of each subnode is ignored.
293
294`strings` subnodes
295~~~~~~~~~~~~~~~~~~
296
297Each subnode defines a string which can be used by scenes and objects. Each
298string has an ID number which is used to refer to it.
299
300The `strings` subnodes have the following properties:
301
302id
303 type: u32, required
304
305 Specifies the ID number for the string.
306
307value:
308 type: string, required
309
310 Specifies the string text. For now only a single value is supported. Future
311 work may add support for multiple languages by using a value for each
312 language.
313
314Scene nodes (`scenes` subnodes)
315~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
316
317Each subnode of the `scenes` node contains a scene description.
318
319Most properties can use either a string or a string ID. For example, a `title`
320property can be used to provide the title for a menu; alternatively a `title-id`
321property can provide the string ID of the title. If both are present, the
322ID takes preference, except that if a string with that ID does not exist, it
323falls back to using the string from the property (`title` in this example). The
324description below shows these are alternative properties with the same
325description.
326
327The scene nodes have the following properties:
328
329id
330 type: u32, required
331
332 Specifies the ID number for the string.
333
334title / title-id
335 type: string / u32, required
336
337 Specifies the title of the scene. This is shown at the top of the scene.
338
339prompt / prompt-id
340 type: string / u32, required
341
342 Specifies a prompt for the scene. This is shown at the bottom of the scene.
343
344The scene nodes have a subnode for each object in the scene.
345
346Object nodes
347~~~~~~~~~~~~
348
349The object-node name is used as the name of the object, e.g. when calling
350`scene_menu()` to create a menu.
351
352Object nodes have the following common properties:
353
354type
355 type: string, required
356
357 Specifies the type of the object. Valid types are:
358
359 "menu"
360 Menu containing items which can be selected by the user
361
Simon Glass00f6c402023-10-01 19:13:40 -0600362 "textline"
363 A line of text which can be edited
364
Simon Glass61300722023-06-01 10:23:01 -0600365id
366 type: u32, required
367
368 Specifies the ID of the object. This is used when referring to the object.
369
Simon Glass2b91ca62023-08-14 16:40:37 -0600370Where CMOS RAM is used for reading and writing settings, the following
371additional properties are required:
372
373start-bit
374 Specifies the first bit in the CMOS RAM to use for this setting. For a RAM
375 with 0x100 bytes, there are 0x800 bit locations. For example, register 0x80
376 holds bits 0x400 to 0x407.
377
378bit-length
379 Specifies the number of CMOS RAM bits to use for this setting. The bits
380 extend from `start-bit` to `start-bit + bit-length - 1`. Note that the bits
381 must be contiguous.
Simon Glass61300722023-06-01 10:23:01 -0600382
383Menu nodes have the following additional properties:
384
385title / title-id
386 type: string / u32, required
387
388 Specifies the title of the menu. This is shown to the left of the area for
389 this menu.
390
391item-id
392 type: u32 list, required
393
394 Specifies the ID for each menu item. These are used for checking which item
395 has been selected.
396
Simon Glass100389f2024-10-14 16:31:58 -0600397item-value
398 type: u32 list, optional
399
400 Specifies the value for each menu item. These are used for saving and
401 loading. If this is omitted the value is its position in the menu (0..n-1).
402 Valid values are positive and negative integers INT_MIN...(INT_MAX - 1).
403
Simon Glass61300722023-06-01 10:23:01 -0600404item-label / item-label-id
405 type: string list / u32 list, required
406
407 Specifies the label for each item in the menu. These are shown to the user.
408 In 'popup' mode these form the items in the menu.
409
410key-label / key-label-id
411 type: string list / u32 list, optional
412
413 Specifies the key for each item in the menu. These are currently only
414 intended for use in simple mode.
415
416desc-label / desc-label-id
417 type: string list / u32 list, optional
418
419 Specifies the description for each item in the menu. These are currently
420 only intended for use in simple mode.
421
Simon Glass00f6c402023-10-01 19:13:40 -0600422Textline nodes have the following additional properties:
423
424label / label-id
425 type: string / u32, required
426
427 Specifies the label of the textline. This is shown to the left of the area
428 for this textline.
429
430edit-id
431 type: u32, required
432
433 Specifies the ID of the of the editable text object. This can be used to
434 obtain the text from the textline
435
436max-chars:
437 type: u32, required
438
439 Specifies the maximum number of characters permitted to be in the textline.
440 The user will be prevented from adding more.
441
Simon Glass61300722023-06-01 10:23:01 -0600442
443Expo layout
444~~~~~~~~~~~
445
446The `expo_arrange()` function can be called to arrange the expo objects in a
447suitable manner. For each scene it puts the title at the top, the prompt at the
448bottom and the objects in order from top to bottom.
449
Simon Glass40eb3c32023-08-14 16:40:29 -0600450
451.. _expo_example:
452
Simon Glass61300722023-06-01 10:23:01 -0600453Expo format example
454~~~~~~~~~~~~~~~~~~~
455
456This example shows an expo with a single scene consisting of two menus. The
457scene title is specified using a string from the strings table, but all other
458strings are provided inline in the nodes where they are used.
459
460::
461
Simon Glassb1263bc2023-08-14 16:40:28 -0600462 /* this comment is parsed by the expo.py tool to insert the values below
Simon Glass61300722023-06-01 10:23:01 -0600463
Simon Glassb1263bc2023-08-14 16:40:28 -0600464 enum {
Simon Glass53a0a2f2024-10-14 16:31:57 -0600465 ID_PROMPT = EXPOID_BASE_ID,
Simon Glassb1263bc2023-08-14 16:40:28 -0600466 ID_SCENE1,
467 ID_SCENE1_TITLE,
Simon Glass61300722023-06-01 10:23:01 -0600468
Simon Glassb1263bc2023-08-14 16:40:28 -0600469 ID_CPU_SPEED,
470 ID_CPU_SPEED_TITLE,
471 ID_CPU_SPEED_1,
472 ID_CPU_SPEED_2,
473 ID_CPU_SPEED_3,
474
475 ID_POWER_LOSS,
476 ID_AC_OFF,
477 ID_AC_ON,
478 ID_AC_MEMORY,
Simon Glass61300722023-06-01 10:23:01 -0600479
Simon Glass00f6c402023-10-01 19:13:40 -0600480 ID_MACHINE_NAME,
481 ID_MACHINE_NAME_EDIT,
482
Simon Glassb1263bc2023-08-14 16:40:28 -0600483 ID_DYNAMIC_START,
484 */
Simon Glass61300722023-06-01 10:23:01 -0600485
486 &cedit {
487 dynamic-start = <ID_DYNAMIC_START>;
488
489 scenes {
490 main {
491 id = <ID_SCENE1>;
492
493 /* value refers to the matching id in /strings */
494 title-id = <ID_SCENE1_TITLE>;
495
496 /* simple string is used as it is */
497 prompt = "UP and DOWN to choose, ENTER to select";
498
499 /* defines a menu within the scene */
500 cpu-speed {
501 type = "menu";
502 id = <ID_CPU_SPEED>;
503
504 /*
505 * has both string and ID. The string is ignored
506 * if the ID is present and points to a string
507 */
508 title = "CPU speed";
509 title-id = <ID_CPU_SPEED_TITLE>;
510
511 /* menu items as simple strings */
512 item-label = "2 GHz", "2.5 GHz", "3 GHz";
513
514 /* IDs for the menu items */
515 item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2
516 ID_CPU_SPEED_3>;
Simon Glass100389f2024-10-14 16:31:58 -0600517
518 /* values for the menu items */
519 item-value = <(-1) 3 6>;
Simon Glass61300722023-06-01 10:23:01 -0600520 };
521
522 power-loss {
523 type = "menu";
524 id = <ID_POWER_LOSS>;
525
526 title = "AC Power";
527 item-label = "Always Off", "Always On",
528 "Memory";
529
530 item-id = <ID_AC_OFF ID_AC_ON ID_AC_MEMORY>;
531 };
Simon Glass00f6c402023-10-01 19:13:40 -0600532
533 machine-name {
534 id = <ID_MACHINE_NAME>;
535 type = "textline";
536 max-chars = <20>;
537 title = "Machine name";
538 edit-id = <ID_MACHINE_NAME_EDIT>;
Simon Glass61300722023-06-01 10:23:01 -0600539 };
540 };
541
542 strings {
543 title {
544 id = <ID_SCENE1_TITLE>;
545 value = "Test Configuration";
546 value-es = "configuración de prueba";
547 };
548 };
549 };
550
Simon Glass311bd352023-01-06 08:52:43 -0600551
552API documentation
553-----------------
554
555.. kernel-doc:: include/expo.h
556
557Future ideas
558------------
559
560Some ideas for future work:
561
562- Default menu item and a timeout
Simon Glass311bd352023-01-06 08:52:43 -0600563- Image formats other than BMP
564- Use of ANSI sequences to control a serial terminal
565- Colour selection
Simon Glass00f6c402023-10-01 19:13:40 -0600566- Support for more widgets, e.g. numeric, radio/option
Simon Glass311bd352023-01-06 08:52:43 -0600567- Mouse support
568- Integrate Nuklear, NxWidgets or some other library for a richer UI
569- Optimise rendering by only updating the display with changes since last render
570- Use expo to replace the existing menu implementation
571- Add a Kconfig option to drop the names to save code / data space
572- Add a Kconfig option to disable vidconsole support to save code / data space
573- Support both graphical and text menus at the same time on different devices
Simon Glass311bd352023-01-06 08:52:43 -0600574- Support unicode
575- Support curses for proper serial-terminal menus
Simon Glass61300722023-06-01 10:23:01 -0600576- Add support for large menus which need to scroll
Simon Glass2b91ca62023-08-14 16:40:37 -0600577- Update expo.py tool to check for overlapping names and CMOS locations
Simon Glass311bd352023-01-06 08:52:43 -0600578
579.. Simon Glass <sjg@chromium.org>
580.. 7-Oct-22