aboutsummaryrefslogtreecommitdiff
path: root/doc/develop/expo.rst
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2023-01-17 08:55:40 -0500
committerTom Rini <trini@konsulko.com>2023-01-17 08:55:40 -0500
commit5b958dea5c678dbdb2aeb6ac3c0c8cc8dfea065c (patch)
tree172424111d1a39640cf5245eefd080fae3b5fb27 /doc/develop/expo.rst
parent6d03688e75041a7bae4d33815de28da781c37dd6 (diff)
parentb5c8fea7b830c0304051237ad1501431a958b0e6 (diff)
Merge branch '2022-01-16-bootstd-updates'HEADmaster
To quote the author: So far standard boot lacks a boot menu, although it is possible to create a rudimentary one using the existing 'bootmenu' command. Even then, this text-based menu offer only basic functionality and does not take full advantage of the displays which are common on many devices. This series provides a 'bootflow menu' command which allows the user to select from the available bootflows. An attempt is made to show the name of the available operating systems, by reading more information into the bootflow. A logo can be read also, where supported, so that this can be presented to the user when an option is highlighted. Full use is made of TrueType fonts, if enabled. For cases where only a serial console is available, it falls back to a simple text-based menu. All of this is implementing using a new 'expo' construct, a collection of scenes (like menu screens) which can be navigated by the user to view information and select options. This is fairly general and should be able to cope with a wider array of use cases, with less hacking of the menu code, such as is currently needed for CMD_BOOTEFI_BOOTMGR. Of course it would be possible to enhance the existing menu rather than creating a new setup. Instead it seems better to make the existing menu use expo, if code space permits. It avoids the event-loop problem and should be more extensible, given its loosely coupled components and use of IDs instead of pointers. Further motivation is provided in the documentation. For now the CLI keypress-decoding code is split out to be used by the new menu. The key codes defined by menu.h are reused also. This is of course just a starting point. Some ideas for future work are included in the documentation.
Diffstat (limited to 'doc/develop/expo.rst')
-rw-r--r--doc/develop/expo.rst188
1 files changed, 188 insertions, 0 deletions
diff --git a/doc/develop/expo.rst b/doc/develop/expo.rst
new file mode 100644
index 000000000000..32dd7f090307
--- /dev/null
+++ b/doc/develop/expo.rst
@@ -0,0 +1,188 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Expo menu
+=========
+
+U-Boot provides a menu implementation for use with selecting bootflows and
+changing U-Boot settings. This is in early stages of development.
+
+Motivation
+----------
+
+U-Boot already has a text-based menu system accessed via the
+:doc:`../usage/cmd/bootmenu`. This works using environment variables, or via
+some EFI-specific hacks.
+
+The command makes use of a lower-level `menu` implementation, which is quite
+flexible and can be used to make menu hierarchies.
+
+However this system is not flexible enough for use with standard boot. It does
+not support a graphical user interface and cannot currently support anything
+more than a very simple list of items. While it does support multiple menus in
+hierarchies, these are implemented by the caller. See for example `eficonfig.c`.
+
+Another challenge with the current menu implementation is that it controls
+the event loop, such that bootmenu_loop() does not return until a key is
+pressed. This makes it difficult to implement dynamic displays or to do other
+things while the menu is running, such as searching for more bootflows.
+
+For these reasons an attempt has been made to develop a more flexible system
+which can handle menus as well as other elements. This is called 'expo', short
+for exposition, in an attempt to avoid common words like display, screen, menu
+and the like. The primary goal is to support Verified Boot for Embedded (VBE),
+although it is available to any boot method, using the 'bootflow menu' command.
+
+Efforts have been made to use common code with the existing menu, including
+key processing in particular.
+
+Previous work looked at integrating Nuklear into U-Boot. This works fine and
+could provide a way to provide a more flexible UI, perhaps with expo dealing
+with the interface to Nuklear. But this is quite a big step and it may be years
+before this becomes desirable, if at all. For now, U-Boot only needs a fairly
+simple set of menus and options, so rendering them directly is fairly
+straightforward.
+
+Concepts
+--------
+
+The creator of the expo is here called a `controller` and it controls most
+aspects of the expo. This is the code that you must write to use expo.
+
+An `expo` is a set of scenes which can be presented to the user one at a time,
+to show information and obtain input from the user.
+
+A `scene` is a collection of objects which are displayed together on the screen.
+Only one scene is visible at a time and scenes do not share objects.
+
+A `scene object` is something that appears in the scene, such as some text, an
+image or a menu. Objects can be positioned and hidden.
+
+A `menu object` contains a title, a set of `menu items` and a pointer to the
+current item. Menu items consist of a keypress (indicating what to press to
+select the item), label and description. All three are shown in a single line
+within the menu. Items can also have a preview image, which is shown when the
+item is highlighted.
+
+All components have a name. This is purely for debugging, so it is easy to see
+what object is referred to. Of course the ID numbers can help as well, but they
+are less easy to distinguish.
+
+While the expo implementation provides support for handling keypresses and
+rendering on the display or serial port, it does not actually deal with reading
+input from the user, nor what should be done when a particular menu item is
+selected. This is deliberate since having the event loop outside the expo is
+more flexible, particularly in a single-threaded environment like U-Boot.
+
+Everything within an expo has a unique ID number. This is done so that it is
+easy to refer to things after the expo has been created. The expectation is that
+the controller declares an enum containing all of the elements in the expo,
+passing the ID of each object as it is created. When a menu item is selected,
+its ID is returned. When a object's font or position needs to change, the ID is
+passed to expo functions to indicate which object it is. It is possible for expo
+to auto-allocate IDs, but this is not recommended. The use of IDs is a
+convenience, removing the need for the controller to store pointers to objects,
+or even the IDs of objects. Programmatic creation of many items in a loop can be
+handled by allocating space in the enum for a maximum number of items, then
+adding the loop count to the enum values to obtain unique IDs.
+
+All text strings are stored in a structure attached to the expo, referenced by
+a text ID. This makes it easier at some point to implement multiple languages or
+to support Unicode strings.
+
+Menu objects do not have their own text and image objects. Instead they simply
+refer to objects which have been created. So a menu item is just a collection
+of IDs of text and image objects. When adding a menu item you must create these
+objects first, then create the menu item, passing in the relevant IDs.
+
+Creating an expo
+----------------
+
+To create an expo, use `expo_new()` followed by `scene_new()` to create a scene.
+Then add objects to the scene, using functions like `scene_txt_str()` and
+`scene_menu()`. For every menu item, add text and image objects, then create
+the menu item with `scene_menuitem()`, referring to those objects.
+
+Layout
+------
+
+Individual objects can be positioned using `scene_obj_set_pos()`. Menu items
+cannot be positioned manually: this is done by `scene_arrange()` which is called
+automatically when something changes. The menu itself determines the position of
+its items.
+
+Rendering
+---------
+
+Rendering is performed by calling `expo_render()`. This uses either the
+vidconsole, if present, or the serial console in `text mode`. Expo handles
+presentation automatically in either case, without any change in how the expo is
+created.
+
+For the vidconsole, Truetype fonts can be used if enabled, to enhance the
+quality of the display. For text mode, each menu item is shown in a single line,
+allowing easy selection using arrow keys.
+
+Input
+-----
+
+The controller is responsible for collecting keyboard input. A good way to do
+this is to use `cli_ch_process()`, since it handles conversion of escape
+sequences into keys. However, expo has some special menu-key codes for
+navigating the interface. These are defined in `enum bootmenu_key` and include
+`BKEY_UP` for moving up and `BKEY_SELECT` for selecting an item. You can use
+`bootmenu_conv_key()` to convert an ASCII key into one of these.
+
+Once a keypress is decoded, call `expo_send_key()` to send it to the expo. This
+may cause an update to the expo state and may produce an action.
+
+Actions
+-------
+
+Call `expo_action_get()` in the event loop to check for any actions that the
+expo wants to report. These can include selecting a particular menu item, or
+quitting the menu. Processing of these is the responsibility of your controller.
+
+Event loop
+----------
+
+Expo is intended to be used in an event loop. For an example loop, see
+`bootflow_menu_run()`. It is possible to perform other work in your event loop,
+such as scanning devices for more bootflows.
+
+Themes
+------
+
+Expo does not itself support themes. The bootflow_menu implement supposed a
+basic theme, applying font sizes to the various text objects in the expo.
+
+API documentation
+-----------------
+
+.. kernel-doc:: include/expo.h
+
+Future ideas
+------------
+
+Some ideas for future work:
+
+- Default menu item and a timeout
+- Higher-level / automatic / more flexible layout of objects
+- Image formats other than BMP
+- Use of ANSI sequences to control a serial terminal
+- Colour selection
+- Better support for handling lots of settings, e.g. with multiple menus and
+ radio/option widgets
+- Mouse support
+- Integrate Nuklear, NxWidgets or some other library for a richer UI
+- Optimise rendering by only updating the display with changes since last render
+- Use expo to replace the existing menu implementation
+- 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
+
+.. Simon Glass <sjg@chromium.org>
+.. 7-Oct-22