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 bootmenu command. 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.
A textline object contains a label and an editable string.
A box object is a rectangle with a given line width. It is not filled.
All components have a name. This is mostly for debugging, so it is easy to see what object is referred to, although the name is also used for saving values. 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.
Some standard IDs are reserved for certain purposes. These are defined by enum expo_id_t and start at 1. EXPOID_BASE_ID defines the first ID which can be used for an expo.
An ID of 0 is invalid. If this is specified in an expo call then a valid ‘dynamic IDs is allocated. Use expo_set_dynamic_start() to set the start value, so that they are allocated above the starting (enum) 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.
Position and alignment
Objects are typically positioned automatically, when scene_arrange() is called. However it is possible to position objects manually. The scene_obj_set_pos() sets the coordinates of the top left of the object.
All objects have a bounding box. Typically this is calculated by looking at the object contents, in scene_calc_arrange(). The calculated dimensions of each object are stored in the object’s dims field.
It is possible to adjust the size of an object with scene_obj_set_size() or even set the bounding box, with scene_obj_set_bbox(). The SCENEOF_SIZE_VALID flag tracks whether the width/height should be maintained when the position changes.
If the bounding box is larger than the object needs, the object can be aligned to different edges within the box. Objects can be left- or right-aligned, or centred. For text objects this applies to each line of text. Normally objects are drawn starting at the top of their bounding box, but they can be aligned vertically to the bottom, or centred vertically within the box.
Where the width of a text object’s bounding box is smaller than the space needed to show the next, the text is word-wrapped onto multiple lines, assuming there is enough vertical space. Newline characters in the next cause a new line to be started. The measurement information is created by the Truetype console driver and stored in an alist in struct scene_txt_generic.
When the object is drawn the ofs field indicates the x and y offset to use, from the top left of the bounding box. These values are affected by alignment.
Creating an expo
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 Expo Format below.
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, but if it returns a value >= BKEY_FIRST_EXTRA then you should pass the unmodified ASCII key to the expo, since it may be used by textline objects.
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 supports simple themes, for setting the font size, for example. Use the expo_apply_theme() function to load a theme, passing a node with the required properties:
- font-size
Font size to use for all text (type: u32)
- menu-inset
Number of pixels to inset the menu on the sides and top (type: u32)
- menuitem-gap-y
Number of pixels between menu items
- menu-title-margin-x
Number of pixels between right side of menu title to the left size of the menu labels
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. The cedit command can be used to load a configuration and create an expo from it.
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
- “textline”
A line of text which can be edited
- id
type: u32, required
Specifies the ID of the object. This is used when referring to the object.
Where CMOS RAM is used for reading and writing settings, the following additional properties are required:
- start-bit
Specifies the first bit in the CMOS RAM to use for this setting. For a RAM with 0x100 bytes, there are 0x800 bit locations. For example, register 0x80 holds bits 0x400 to 0x407.
- bit-length
Specifies the number of CMOS RAM bits to use for this setting. The bits extend from start-bit to start-bit + bit-length - 1. Note that the bits must be contiguous.
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-value
type: u32 list, optional
Specifies the value for each menu item. These are used for saving and loading. If this is omitted the value is its position in the menu (0..n-1). Valid values are positive and negative integers INT_MIN…(INT_MAX - 1).
- 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.
Textline nodes have the following additional properties:
- label / label-id
type: string / u32, required
Specifies the label of the textline. This is shown to the left of the area for this textline.
- edit-id
type: u32, required
Specifies the ID of the of the editable text object. This can be used to obtain the text from the textline
- max-chars:
type: u32, required
Specifies the maximum number of characters permitted to be in the textline. The user will be prevented from adding more.
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.
/* this comment is parsed by the expo.py tool to insert the values below
enum {
ID_PROMPT = EXPOID_BASE_ID,
ID_SCENE1,
ID_SCENE1_TITLE,
ID_CPU_SPEED,
ID_CPU_SPEED_TITLE,
ID_CPU_SPEED_1,
ID_CPU_SPEED_2,
ID_CPU_SPEED_3,
ID_POWER_LOSS,
ID_AC_OFF,
ID_AC_ON,
ID_AC_MEMORY,
ID_MACHINE_NAME,
ID_MACHINE_NAME_EDIT,
ID_DYNAMIC_START,
*/
&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>;
/* values for the menu items */
item-value = <(-1) 3 6>;
};
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>;
};
machine-name {
id = <ID_MACHINE_NAME>;
type = "textline";
max-chars = <20>;
title = "Machine name";
edit-id = <ID_MACHINE_NAME_EDIT>;
};
};
strings {
title {
id = <ID_SCENE1_TITLE>;
value = "Test Configuration";
value-es = "configuración de prueba";
};
};
};
API documentation
-
enum expo_id_t
standard expo IDs
Constants
EXPOID_NONENot used, invalid ID 0
EXPOID_SAVEUser has requested that the expo data be saved
EXPOID_DISCARDUser has requested that the expo data be discarded
EXPOID_BASE_IDFirst ID which can be used for expo objects
Description
These are assumed to be in use at all times. Expos should use IDs starting from EXPOID_BASE_ID,
-
enum expoact_type
types of actions reported by the expo
Constants
EXPOACT_NONEno action
EXPOACT_POINT_OBJobject was highlighted (id indicates which)
EXPOACT_POINT_ITEMmenu item was highlighted (id indicates which)
EXPOACT_SELECTmenu item was selected (id indicates which)
EXPOACT_OPENmenu was opened, so an item can be selected (id indicates which menu object)
EXPOACT_CLOSEmenu was closed (id indicates which menu object)
EXPOACT_QUITrequest to exit the menu
-
struct expo_action
an action report by the expo
Definition
struct expo_action {
enum expoact_type type;
union {
struct {
int id;
} select;
};
};
Members
typeAction type (EXPOACT_NONE if there is no action)
{unnamed_union}anonymous
selectUsed for EXPOACT_POINT_ITEM and EXPOACT_SELECT
select.idID number of the object affected.
-
struct expo_theme
theme for the expo
Definition
struct expo_theme {
u32 font_size;
u32 menu_inset;
u32 menuitem_gap_y;
u32 menu_title_margin_x;
};
Members
font_sizeDefault font size for all text
menu_insetInset width (on each side and top/bottom) for menu items
menuitem_gap_yGap between menu items in pixels
menu_title_margin_xGap between right side of menu title and left size of menu label
-
struct expo
information about an expo
Definition
struct expo {
char *name;
struct udevice *display;
struct udevice *cons;
uint scene_id;
uint next_id;
struct expo_action action;
bool text_mode;
bool popup;
bool show_highlight;
void *priv;
bool done;
bool save;
struct expo_theme theme;
struct list_head scene_head;
struct list_head str_head;
struct cli_ch_state cch;
};
Members
nameName of the expo (allocated)
displayDisplay to use (UCLASS_VIDEO), or NULL to use text mode
consConsole to use (UCLASS_VIDEO_CONSOLE), or NULL to use text mode
scene_idCurrent scene ID (0 if none)
next_idNext ID number to use, for automatic allocation
actionAction selected by user. At present only one is supported, with the type set to EXPOACT_NONE if there is no action
text_modetrue to use text mode for the menu (no vidconsole)
popuptrue to use popup menus, instead of showing all items
show_highlightshow a highlight bar on the selected menu item
privPrivate data for the controller
doneIndicates that a cedit session is complete and the user has quit
saveIndicates that cedit data should be saved, rather than discarded
themeInformation about fonts styles, etc.
scene_headList of scenes
str_headlist of strings
cchKeyboard context for input
Description
A group of scenes which can be presented to the user, typically to obtain input or to make a selection.
-
struct expo_string
a string that can be used in an expo
Definition
struct expo_string {
uint id;
struct abuf buf;
struct list_head sibling;
};
Members
idID number of the string
bufString (contains nul terminator)
siblingNode to link this object to its siblings
-
struct scene
information about a scene in an expo
Definition
struct scene {
struct expo *expo;
char *name;
uint id;
uint title_id;
uint highlight_id;
struct cli_line_state cls;
struct abuf buf;
struct abuf entry_save;
struct list_head sibling;
struct list_head obj_head;
};
Members
expoExpo this scene is part of
nameName of the scene (allocated)
idID number of the scene
title_idString ID of title of the scene (allocated)
highlight_idID of highlighted object, if any
clscread state to use for input
bufBuffer for input
entry_saveBuffer to hold vidconsole text-entry information
siblingNode to link this scene to its siblings
obj_headList of objects in the scene
Description
A collection of text/image/menu items in an expo
-
enum scene_obj_t
type of a scene object
Constants
SCENEOBJT_NONEUsed to indicate that the type does not matter
SCENEOBJT_IMAGEImage data to render
SCENEOBJT_TEXTText line to render
SCENEOBJT_BOXRectangular box
SCENEOBJT_TEXTEDITSimple text editor
SCENEOBJT_MENUMenu containing items the user can select
SCENEOBJT_TEXTLINELine of text the user can edit
-
struct scene_obj_bbox
Dimensions of an object
Definition
struct scene_obj_bbox {
int x0;
int y0;
int x1;
int y1;
};
Members
x0x position, in pixels from left side
y0y position, in pixels from top
x1x position of right size
y1y position of bottom
-
struct scene_obj_offset
Offsets for drawing the object
Definition
struct scene_obj_offset {
int xofs;
int yofs;
};
Members
xofsx offset
yofsy offset
Description
Stores the offset from x0, x1 at which objects are drawn
-
struct scene_obj_dims
Dimensions of the object being drawn
Definition
struct scene_obj_dims {
int x;
int y;
};
Members
xx dimension
yy dimension
Description
Image and text objects have a dimension which can change depending on what they contain. For images this stores the size. For text it stores the size as rendered on the display
-
enum scene_obj_align
Horizontal alignment of objects
Constants
SCENEOA_LEFTLeft of object is aligned with its x coordinate
SCENEOA_RIGHTRight of object is aligned with x + w
SCENEOA_CENTRECentre of object is aligned with centre of bounding box
SCENEOA_TOPLeft of object is aligned with its x coordinate
SCENEOA_BOTTOMRight of object is aligned with x + w
Description
Objects are normally drawn on the left size of their bounding box. This properly allows aligning on the right or having the object centred.
Note
It would be nice to make this a char type but Sphinx riddles: ./include/expo.h:258: error: Cannot parse enum! enum scene_obj_align : char {
-
enum scene_obj_flags_t
flags for objects
Constants
SCENEOF_HIDEobject should be hidden
SCENEOF_POINTobject should be highlighted
SCENEOF_OPENobject should be opened (e.g. menu is opened so that an option can be selected)
SCENEOF_SIZE_VALIDobject’s size (width/height) is valid, so any adjustment to x0/y0 should maintain the width/height of the object
-
struct scene_obj
information about an object in a scene
Definition
struct scene_obj {
struct scene *scene;
char *name;
uint id;
enum scene_obj_t type;
struct scene_obj_bbox bbox;
struct scene_obj_offset ofs;
struct scene_obj_dims dims;
enum scene_obj_align horiz;
enum scene_obj_align vert;
u8 flags;
u8 bit_length;
u16 start_bit;
struct list_head sibling;
};
Members
sceneScene that this object relates to
nameName of the object (allocated)
idID number of the object
typeType of this object
bboxBounding box for this object
ofsOffset from x0, y0 where the object is drawn
dimsDimensions of the text/image (may be smaller than bbox)
horizHorizonal alignment
vertVertical alignment
flagsFlags for this object
bit_lengthNumber of bits used for this object in CMOS RAM
start_bitStart bit to use for this object in CMOS RAM
siblingNode to link this object to its siblings
-
struct scene_obj_img
information about an image object in a scene
Definition
struct scene_obj_img {
struct scene_obj obj;
char *data;
};
Members
objBasic object information
dataImage data in BMP format
Description
This is a rectangular image which is blitted onto the display
-
struct scene_txt_generic
Generic information common to text objects
Definition
struct scene_txt_generic {
uint str_id;
const char *font_name;
uint font_size;
struct alist lines;
};
Members
str_idID of the text string to display
font_nameName of font (allocated by caller)
font_sizeNominal size of font in pixels
linesalist of struct vidconsole_mline with a separate record for each line of text
-
struct scene_obj_txt
information about a text object in a scene
Definition
struct scene_obj_txt {
struct scene_obj obj;
struct scene_txt_generic gen;
};
Members
objBasic object information
genGeneric information common to all objects which show text
Description
This is a single-line text object
-
struct scene_obj_menu
information about a menu object in a scene
Definition
struct scene_obj_menu {
struct scene_obj obj;
uint title_id;
uint cur_item_id;
uint pointer_id;
struct list_head item_head;
};
Members
objBasic object information
title_idID of the title text, or 0 if none
cur_item_idID of the current menu item, or 0 if none
pointer_idID of the object pointing to the current selection
item_headList of items in the menu
Description
A menu has a number of items which can be selected by the user
It also has:
a text/image object (pointer_id) which points to the current item (cur_item_id)
a preview object which shows an image related to the current item
-
enum scene_menuitem_flags_t
flags for menu items
Constants
SCENEMIF_GAP_BEFOREAdd a gap before this item
-
struct scene_menitem
a menu item in a menu
Definition
struct scene_menitem {
char *name;
uint id;
uint key_id;
uint label_id;
uint desc_id;
uint preview_id;
uint flags;
int value;
struct list_head sibling;
};
Members
nameName of the item (this is allocated by this call)
idID number of the object
key_idID of text object to use as the keypress to show
label_idID of text object to use as the label text
desc_idID of text object to use as the description text
preview_idID of the preview object, or 0 if none
flagsFlags for this item
valueValue for this item, or INT_MAX to use sequence
siblingNode to link this item to its siblings
Description
A menu item has:
text object holding the name (short) and description (can be longer)
a text object holding the keypress
-
struct scene_obj_textline
information about a textline in a scene
Definition
struct scene_obj_textline {
struct scene_obj obj;
uint label_id;
uint edit_id;
uint max_chars;
struct abuf buf;
uint pos;
};
Members
objBasic object information
label_idID of the label text, or 0 if none
edit_idID of the editable text
max_charsMaximum number of characters allowed
bufText buffer containing current text
posCursor position
Description
A textline has a prompt and a line of editable text
-
struct scene_obj_box
information about a box in a scene
Definition
struct scene_obj_box {
struct scene_obj obj;
uint width;
};
Members
objBasic object information
widthLine-width in pixels
Description
A box surrounds a part of the screen with a border
-
struct scene_obj_txtedit
information about a box in a scene
Definition
struct scene_obj_txtedit {
struct scene_obj obj;
struct scene_txt_generic gen;
struct abuf buf;
};
Members
objBasic object information
genGeneric information common to all objects which show text
bufText buffer containing current text
Description
A text editor which allows users to edit a small text file
-
struct expo_arrange_info
Information used when arranging a scene
Definition
struct expo_arrange_info {
int label_width;
};
Members
label_widthMaximum width of labels in scene
Parameters
const char *nameName of expo (this is allocated by this call)
void *privPrivate data for the controller
struct expo **exppReturns a pointer to the new expo on success
Description
Allocates a new expo
Return
0 if OK, -ENOMEM if out of memory
Parameters
struct expo *expExpo to destroy
Parameters
struct expo *expExpo to update
uint dyn_startStart ID that expo should use for dynamic allocation
Description
It is common for a set of ‘static’ IDs to be used to refer to objects in the expo. These typically use an enum so that they are defined in sequential order.
Dynamic IDs (for objects not in the enum) are intended to be used for objects to which the code does not need to refer. These are ideally located above the static IDs.
Use this function to set the start of the dynamic range, making sure that the value is higher than all the statically allocated IDs.
-
int expo_str(struct expo *exp, const char *name, uint id, const char *str)
add a new string to an expo
Parameters
struct expo *expExpo to update
const char *nameName to use (this is allocated by this call)
uint idID to use for the new object (0 to allocate one)
const char *strPointer to text to display (allocated by caller)
Return
ID number for the object (typically id), or -ve on error
Parameters
struct expo *expExpo to use
uint idString ID to look up returns string, or NULL if not found
-
int expo_edit_str(struct expo *exp, uint id, struct abuf *orig, struct abuf **copyp)
Make a string writeable
Parameters
struct expo *expExpo to use
uint idString ID to look up
struct abuf *origIf non-NULL, returns the original buffer, which can be used by the caller. It is no-longer used by expo so must be uninited by the caller. It contains a snapshot of the string contents
struct abuf **copypReturns a pointer to the new, writeable buffer
Description
This allows a string to be updated under the control of the caller. The buffer must remain valid while the expo is active.
Return
0 if OK, -ENOENT if the id was not found, -ENOMEM if out of memory
Parameters
struct expo *expExpo to update
struct udevice *devDisplay to use (UCLASS_VIDEO), NULL to use text mode
Return
0 (always)
Parameters
struct expo *expExpo to update Returns 0 if OK, -ENOTSUPP if there is no graphical console
Description
Updates the width and height of all objects based on their contents
Parameters
struct expo *expExpo to update
uint scene_idNew scene ID to use (0 to select no scene)
Return
0 if OK, -ENOENT if there is no scene with that ID
Parameters
struct expo *expExpo to check
Return
Scene ID of first scene, or -ENOENT if there are no scenes
Parameters
struct expo *expExpo to render
Return
0 if OK, -ECHILD if there is no current scene, -ENOENT if the current scene is not found, other error if something else goes wrong
-
void expo_set_text_mode(struct expo *exp, bool text_mode)
Controls whether the expo renders in text mode
Parameters
struct expo *expExpo to update
bool text_modetrue to use text mode, false to use the console
-
int scene_new(struct expo *exp, const char *name, uint id, struct scene **scnp)
create a new scene in a expo
Parameters
struct expo *expExpo to update
const char *nameName to use (this is allocated by this call)
uint idID to use for the new scene (0 to allocate one)
struct scene **scnpReturns a pointer to the new scene on success
Description
The scene is given the ID id which must be unique across all scenes, objects and items. The expo’s next_id is updated to at least id + 1
Return
ID number for the scene (typically id), or -ve on error
Parameters
struct expo *expExpo to check
uint scene_idScene ID to look up returns pointer to scene if found, else NULL
Parameters
struct scene *scnScene to update
Description
This highlights the first item, so that the user can see that it is pointed to
Parameters
struct scene *scnScene to update
uint idID of object to highlight
Description
Sets a new object to highlight in the scene
Parameters
struct scene *scnScene to update
uint idID of object to update
bool opentrue to open the object, false to close it
Return
0 if OK, -ENOENT if id is invalid
Parameters
struct scene *scnScene to check
Return
number of objects in the scene, 0 if none
-
int scene_img(struct scene *scn, const char *name, uint id, char *data, struct scene_obj_img **imgp)
add a new image to a scene
Parameters
struct scene *scnScene to update
const char *nameName to use (this is allocated by this call)
uint idID to use for the new object (0 to allocate one)
char *dataPointer to image data
struct scene_obj_img **imgpIf non-NULL, returns the new object
Return
ID number for the object (typically id), or -ve on error
-
int scene_txt(struct scene *scn, const char *name, uint id, uint str_id, struct scene_obj_txt **txtp)
add a new text object to a scene
Parameters
struct scene *scnScene to update
const char *nameName to use (this is allocated by this call)
uint idID to use for the new object (0 to allocate one)
uint str_idID of the string to use
struct scene_obj_txt **txtpIf non-NULL, returns the new object
Return
ID number for the object (typically id), or -ve on error
-
int scene_txt_str(struct scene *scn, const char *name, uint id, uint str_id, const char *str, struct scene_obj_txt **txtp)
add a new string to expo and text object to a scene
Parameters
struct scene *scnScene to update
const char *nameName to use (this is allocated by this call)
uint idID to use for the new object (0 to allocate one)
uint str_idID of the string to use
const char *strPointer to text to display (allocated by caller)
struct scene_obj_txt **txtpIf non-NULL, returns the new object
Return
ID number for the object (typically id), or -ve on error
-
int scene_menu(struct scene *scn, const char *name, uint id, struct scene_obj_menu **menup)
create a menu
Parameters
struct scene *scnScene to update
const char *nameName to use (this is allocated by this call)
uint idID to use for the new object (0 to allocate one)
struct scene_obj_menu **menupIf non-NULL, returns the new object
Return
ID number for the object (typically id), or -ve on error
-
int scene_textline(struct scene *scn, const char *name, uint id, uint max_chars, struct scene_obj_textline **tlinep)
create a textline
Parameters
struct scene *scnScene to update
const char *nameName to use (this is allocated by this call)
uint idID to use for the new object (0 to allocate one)
uint max_charsMaximum length of the textline in characters
struct scene_obj_textline **tlinepIf non-NULL, returns the new object
Return
ID number for the object (typically id), or -ve on error
-
int scene_box(struct scene *scn, const char *name, uint id, uint width, struct scene_obj_box **boxp)
create a box
Parameters
struct scene *scnScene to update
const char *nameName to use (this is allocated by this call)
uint idID to use for the new object (0 to allocate one)
uint widthLine-width in pixels
struct scene_obj_box **boxpIf non-NULL, returns the new object
Return
ID number for the object (typically id), or -ve on error
-
int scene_texted(struct scene *scn, const char *name, uint id, uint strid, struct scene_obj_txtedit **teditp)
create a text editor
Parameters
struct scene *scnScene to update
const char *nameName to use (this is allocated by this call)
uint idID to use for the new object (0 to allocate one)
uint stridID of the string to edit
struct scene_obj_txtedit **teditpIf non-NULL, returns the new object
Return
ID number for the object (typically id), or -ve on error
-
int scene_txt_set_font(struct scene *scn, uint id, const char *font_name, uint font_size)
Set the font for an object
Parameters
struct scene *scnScene to update
uint idID of object to update
const char *font_nameFont name to use (allocated by caller)
uint font_sizeFont size to use (nominal height in pixels)
-
int scene_txted_set_font(struct scene *scn, uint id, const char *font_name, uint font_size)
Set the font for an object
Parameters
struct scene *scnScene to update
uint idID of object to update
const char *font_nameFont name to use (allocated by caller)
uint font_sizeFont size to use (nominal height in pixels)
Parameters
struct scene *scnScene to update
uint idID of object to update
int xx position, in pixels from left side
int yy position, in pixels from top
Return
0 if OK, -ENOENT if id is invalid
Parameters
struct scene *scnScene to update
uint idID of object to update
int wwidth in pixels
int hheight in pixels
Return
0 if OK, -ENOENT if id is invalid
Parameters
struct scene *scnScene to update
uint idID of object to update
int wwidth in pixels
Return
0 if OK, -ENOENT if id is invalid
-
int scene_obj_set_bbox(struct scene *scn, uint id, int x0, int y0, int x1, int y1)
Set the bounding box of an object
Parameters
struct scene *scnScene to update
uint idID of object to update
int x0x position, in pixels from left side
int y0y position, in pixels from top
int x1ending x position (right side)
int y1ending y position (botton side)
Return
0 if OK, -ENOENT if id is invalid
-
int scene_obj_set_halign(struct scene *scn, uint id, enum scene_obj_align aln)
Set the horizontal alignment of an object
Parameters
struct scene *scnScene to update
uint idID of object to update
enum scene_obj_align alnHorizontal alignment to use
Return
0 if OK, -ENOENT if id is invalid
-
int scene_obj_set_valign(struct scene *scn, uint id, enum scene_obj_align aln)
Set the vertical alignment of an object
Parameters
struct scene *scnScene to update
uint idID of object to update
enum scene_obj_align alnVertical alignment to use
Return
0 if OK, -ENOENT if id is invalid
Parameters
struct scene *scnScene to update
uint idID of object to update
bool hidetrue to hide the object, false to show it
Description
The update happens when the expo is next rendered.
Return
0 if OK, -ENOENT if id is invalid
Parameters
struct scene *scnScene to update
uint idID of menu object to update
uint title_idID of text object to use as the title
Return
0 if OK, -ENOENT if id is invalid, -EINVAL if title_id is invalid
-
int scene_menu_set_pointer(struct scene *scn, uint id, uint cur_item_id)
Set the item pointer for a menu
Parameters
struct scene *scnScene to update
uint idID of menu object to update
uint cur_item_idID of text or image object to use as a pointer to the current item
Description
This is a visual indicator of the current item, typically a “>” character which sits next to the current item and moves when the user presses the up/down arrow keys
Return
0 if OK, -ENOENT if id is invalid, -EINVAL if cur_item_id is invalid
-
int scene_menu_select_item(struct scene *scn, uint id, uint sel_id)
move the pointer/highlight to an item
Parameters
struct scene *scnScene to update
uint idID of menu object to update
uint sel_idID of the menuitem to select Return 0 on success, -ENOENT if there was no such item
Parameters
struct scene *scnScene to update
uint idID of menu object to update Return ID of the current item the menu is pointing to, -ENOENT if id is not valid, 0 if no item is pointed to
-
int scene_obj_get_hw(struct scene *scn, uint id, int *widthp)
Get width and height of an object in a scene
Parameters
struct scene *scnScene to check
uint idID of menu object to check
int *widthpIf non-NULL, returns width of object in pixels
Return
Height of object in pixels
-
int scene_menuitem(struct scene *scn, uint menu_id, const char *name, uint id, uint key_id, uint label_id, uint desc_id, uint preview_id, uint flags, struct scene_menitem **itemp)
Add an item to a menu
Parameters
struct scene *scnScene to update
uint menu_idID of menu object to update
const char *nameName to use (this is allocated by this call)
uint idID to use for the new object (0 to allocate one)
uint key_idID of text object to use as the keypress to show
uint label_idID of text object to use as the label text
uint desc_idID of text object to use as the description text
uint preview_idID of object to use as the preview (text or image)
uint flagsFlags for this item (enum scene_menuitem_flags_t)
struct scene_menitem **itempIf non-NULL, returns the new object
Return
ID number for the item (typically id), or -ve on error
Parameters
struct scene *scnScene to arrange
Description
Updates any menus in the scene so that their objects are in the right place.
Return
0 if OK, -ve on error
Parameters
struct expo *expExpo to receive the key
int keyKey to send (ASCII or enum bootmenu_key)
Return
0 if OK, -ECHILD if there is no current scene
-
int expo_action_get(struct expo *exp, struct expo_action *act)
read user input from the expo
Parameters
struct expo *expExpo to check
struct expo_action *actReturns action
Return
0 if OK, -EAGAIN if there was no action to return
Parameters
struct expo *expExpo to update
ofnode nodeNode containing the theme
Parameters
ofnode rootRoot node for expo description
struct expo **exppReturns the new expo
Description
Build a complete expo from a description in the provided devicetree.
See doc/develop/expo.rst for a description of the format
Return
0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format error, -ENOENT if there is a references to a non-existent string
Parameters
struct expo **exppReturns the expo created
Return
0 if OK, -ve on error
-
int expo_poll(struct expo *exp, struct expo_action *act)
see if the user takes an action
Parameters
struct expo *expExpo to poll
struct expo_action *actReturns action on success
Description
This checks for a keypress. If there is one, it is processed and the resulting action returned, if any.
Note that expo_render() should normally be called immediately before this function so that the user can see the latest state.
Return
- 0 if an action was obtained, -EAGAIN if not, other error if something
went wrong
Future ideas
Some ideas for future work:
Default menu item and a timeout
Complete the text editor
Image formats other than BMP
Use of ANSI sequences to control a serial terminal
Colour selection
Support for more widgets, e.g. 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
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
Support unicode
Support curses for proper serial-terminal menus
Add support for large menus which need to scroll
Update expo.py tool to check for overlapping names and CMOS locations