expo: Support building an expo from a description file
The only way to create an expo at present is by calling the functions to create each object. It is useful to have more data-driven approach, where the objects can be specified in a suitable file format and created from that. This makes testing easier as well. Add support for describing an expo in a devicetree node. This allows more complex tests to be set up, as well as providing an easier format for users. It also provides a better basis for the upcoming configuration editor. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
@@ -100,10 +100,13 @@ 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.
|
||||
To create an expo programmatically, 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.
|
||||
|
||||
To create an expo using a description file, see :ref:`expo_format` below.
|
||||
|
||||
Layout
|
||||
------
|
||||
@@ -168,6 +171,273 @@ menu-inset
|
||||
menuitem-gap-y
|
||||
Number of pixels between menu items
|
||||
|
||||
.. _expo_format:
|
||||
|
||||
Pop-up mode
|
||||
-----------
|
||||
|
||||
Expos support two modes. The simple mode is used for selecting from a single
|
||||
menu, e.g. when choosing with OS to boot. In this mode the menu items are shown
|
||||
in a list (label, > pointer, key and description) and can be chosen using arrow
|
||||
keys and enter::
|
||||
|
||||
U-Boot Boot Menu
|
||||
|
||||
UP and DOWN to choose, ENTER to select
|
||||
|
||||
mmc1 > 0 Fedora-Workstation-armhfp-31-1.9
|
||||
mmc3 1 Armbian
|
||||
|
||||
The popup mode allows multiple menus to be present in a scene. Each is shown
|
||||
just as its title and label, as with the `CPU Speed` and `AC Power` menus here::
|
||||
|
||||
Test Configuration
|
||||
|
||||
|
||||
CPU Speed <2 GHz> (highlighted)
|
||||
|
||||
AC Power Always Off
|
||||
|
||||
|
||||
UP and DOWN to choose, ENTER to select
|
||||
|
||||
|
||||
Expo Format
|
||||
-----------
|
||||
|
||||
It can be tedious to create a complex expo using code. Expo supports a
|
||||
data-driven approach, where the expo description is in a devicetree file. This
|
||||
makes it easier and faster to create and edit the description. An expo builder
|
||||
is provided to convert this format into an expo structure.
|
||||
|
||||
Layout of the expo scenes is handled automatically, based on a set of simple
|
||||
rules.
|
||||
|
||||
Top-level node
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
The top-level node has the following properties:
|
||||
|
||||
dynamic-start
|
||||
type: u32, optional
|
||||
|
||||
Specifies the start of the dynamically allocated objects. This results in
|
||||
a call to expo_set_dynamic_start().
|
||||
|
||||
The top-level node has the following subnodes:
|
||||
|
||||
scenes
|
||||
Specifies the scenes in the expo, each one being a subnode
|
||||
|
||||
strings
|
||||
Specifies the strings in the expo, each one being a subnode
|
||||
|
||||
`scenes` node
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Contains a list of scene subnodes. The name of each subnode is passed as the
|
||||
name to `scene_new()`.
|
||||
|
||||
`strings` node
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Contains a list of string subnodes. The name of each subnode is ignored.
|
||||
|
||||
`strings` subnodes
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Each subnode defines a string which can be used by scenes and objects. Each
|
||||
string has an ID number which is used to refer to it.
|
||||
|
||||
The `strings` subnodes have the following properties:
|
||||
|
||||
id
|
||||
type: u32, required
|
||||
|
||||
Specifies the ID number for the string.
|
||||
|
||||
value:
|
||||
type: string, required
|
||||
|
||||
Specifies the string text. For now only a single value is supported. Future
|
||||
work may add support for multiple languages by using a value for each
|
||||
language.
|
||||
|
||||
Scene nodes (`scenes` subnodes)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Each subnode of the `scenes` node contains a scene description.
|
||||
|
||||
Most properties can use either a string or a string ID. For example, a `title`
|
||||
property can be used to provide the title for a menu; alternatively a `title-id`
|
||||
property can provide the string ID of the title. If both are present, the
|
||||
ID takes preference, except that if a string with that ID does not exist, it
|
||||
falls back to using the string from the property (`title` in this example). The
|
||||
description below shows these are alternative properties with the same
|
||||
description.
|
||||
|
||||
The scene nodes have the following properties:
|
||||
|
||||
id
|
||||
type: u32, required
|
||||
|
||||
Specifies the ID number for the string.
|
||||
|
||||
title / title-id
|
||||
type: string / u32, required
|
||||
|
||||
Specifies the title of the scene. This is shown at the top of the scene.
|
||||
|
||||
prompt / prompt-id
|
||||
type: string / u32, required
|
||||
|
||||
Specifies a prompt for the scene. This is shown at the bottom of the scene.
|
||||
|
||||
The scene nodes have a subnode for each object in the scene.
|
||||
|
||||
Object nodes
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The object-node name is used as the name of the object, e.g. when calling
|
||||
`scene_menu()` to create a menu.
|
||||
|
||||
Object nodes have the following common properties:
|
||||
|
||||
type
|
||||
type: string, required
|
||||
|
||||
Specifies the type of the object. Valid types are:
|
||||
|
||||
"menu"
|
||||
Menu containing items which can be selected by the user
|
||||
|
||||
id
|
||||
type: u32, required
|
||||
|
||||
Specifies the ID of the object. This is used when referring to the object.
|
||||
|
||||
|
||||
Menu nodes have the following additional properties:
|
||||
|
||||
title / title-id
|
||||
type: string / u32, required
|
||||
|
||||
Specifies the title of the menu. This is shown to the left of the area for
|
||||
this menu.
|
||||
|
||||
item-id
|
||||
type: u32 list, required
|
||||
|
||||
Specifies the ID for each menu item. These are used for checking which item
|
||||
has been selected.
|
||||
|
||||
item-label / item-label-id
|
||||
type: string list / u32 list, required
|
||||
|
||||
Specifies the label for each item in the menu. These are shown to the user.
|
||||
In 'popup' mode these form the items in the menu.
|
||||
|
||||
key-label / key-label-id
|
||||
type: string list / u32 list, optional
|
||||
|
||||
Specifies the key for each item in the menu. These are currently only
|
||||
intended for use in simple mode.
|
||||
|
||||
desc-label / desc-label-id
|
||||
type: string list / u32 list, optional
|
||||
|
||||
Specifies the description for each item in the menu. These are currently
|
||||
only intended for use in simple mode.
|
||||
|
||||
|
||||
Expo layout
|
||||
~~~~~~~~~~~
|
||||
|
||||
The `expo_arrange()` function can be called to arrange the expo objects in a
|
||||
suitable manner. For each scene it puts the title at the top, the prompt at the
|
||||
bottom and the objects in order from top to bottom.
|
||||
|
||||
Expo format example
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This example shows an expo with a single scene consisting of two menus. The
|
||||
scene title is specified using a string from the strings table, but all other
|
||||
strings are provided inline in the nodes where they are used.
|
||||
|
||||
::
|
||||
|
||||
#define ID_PROMPT 1
|
||||
#define ID_SCENE1 2
|
||||
#define ID_SCENE1_TITLE 3
|
||||
|
||||
#define ID_CPU_SPEED 4
|
||||
#define ID_CPU_SPEED_TITLE 5
|
||||
#define ID_CPU_SPEED_1 6
|
||||
#define ID_CPU_SPEED_2 7
|
||||
#define ID_CPU_SPEED_3 8
|
||||
|
||||
#define ID_POWER_LOSS 9
|
||||
#define ID_AC_OFF 10
|
||||
#define ID_AC_ON 11
|
||||
#define ID_AC_MEMORY 12
|
||||
|
||||
#define ID_DYNAMIC_START 13
|
||||
|
||||
&cedit {
|
||||
dynamic-start = <ID_DYNAMIC_START>;
|
||||
|
||||
scenes {
|
||||
main {
|
||||
id = <ID_SCENE1>;
|
||||
|
||||
/* value refers to the matching id in /strings */
|
||||
title-id = <ID_SCENE1_TITLE>;
|
||||
|
||||
/* simple string is used as it is */
|
||||
prompt = "UP and DOWN to choose, ENTER to select";
|
||||
|
||||
/* defines a menu within the scene */
|
||||
cpu-speed {
|
||||
type = "menu";
|
||||
id = <ID_CPU_SPEED>;
|
||||
|
||||
/*
|
||||
* has both string and ID. The string is ignored
|
||||
* if the ID is present and points to a string
|
||||
*/
|
||||
title = "CPU speed";
|
||||
title-id = <ID_CPU_SPEED_TITLE>;
|
||||
|
||||
/* menu items as simple strings */
|
||||
item-label = "2 GHz", "2.5 GHz", "3 GHz";
|
||||
|
||||
/* IDs for the menu items */
|
||||
item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2
|
||||
ID_CPU_SPEED_3>;
|
||||
};
|
||||
|
||||
power-loss {
|
||||
type = "menu";
|
||||
id = <ID_POWER_LOSS>;
|
||||
|
||||
title = "AC Power";
|
||||
item-label = "Always Off", "Always On",
|
||||
"Memory";
|
||||
|
||||
item-id = <ID_AC_OFF ID_AC_ON ID_AC_MEMORY>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
strings {
|
||||
title {
|
||||
id = <ID_SCENE1_TITLE>;
|
||||
value = "Test Configuration";
|
||||
value-es = "configuración de prueba";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
API documentation
|
||||
-----------------
|
||||
@@ -180,11 +450,10 @@ 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 radio/option widgets
|
||||
- Support for more widgets, e.g. text, numeric, radio/option
|
||||
- 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
|
||||
@@ -194,6 +463,7 @@ Some ideas for future work:
|
||||
- Support both graphical and text menus at the same time on different devices
|
||||
- Support unicode
|
||||
- Support curses for proper serial-terminal menus
|
||||
- Add support for large menus which need to scroll
|
||||
|
||||
.. Simon Glass <sjg@chromium.org>
|
||||
.. 7-Oct-22
|
||||
|
||||
Reference in New Issue
Block a user