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

textline-label-margin-x

Number of pixels between right side of textline label to the left size of the editor

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

“textedit”

A multi-line text editor

“box”

A rectangle with a given line width (not filled)

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.

Textedit nodes have the same properties as textline nodes, with the following differences:

  • The editor supports multiple lines of text

  • Pressing Enter inserts a newline instead of closing the editor

  • Home/End move to start/end of the current line

  • Ctrl+K kills to end of the current line (not entire buffer)

  • Up/Down (Ctrl+P/N) navigate between lines

See Command-line Parsing for a full list of editing keys.

Box nodes have the following additional properties:

width

type: u32, required

Specifies the line width of the box in pixels.

fill

type: bool, optional

Specifies whether to fill the box (true) or draw outline only (false). Defaults to false if not specified.

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";
        };
    };
};

Test Mode

Expo supports a test mode that can be enabled by setting the environment variable expotest to 1. When enabled, expo displays performance metrics in the top-right corner of the display. This is useful for debugging and performance analysis.

To enable test mode:

=> setenv expotest 1
=> bootflow menu

Test mode displays the following metrics:

Frame count

Shows the total number of frames rendered. This is the number of times expo_render() has been called since expo_enter_mode() was invoked. The counter resets each time expo mode is entered.

FPS (frames per second)

Shows the rendering rate averaged over the past 5 seconds. This provides a stable indication of rendering performance.

Timing information

Shows average timings (in millisecond) for the following operations, measured over the past second:

  • Render: Time taken to render the scene

  • Sync: Time taken to sync the framebuffer to the display

  • Poll: Time taken to poll for keyboard/mouse input

These metrics help identify performance bottlenecks and verify that expo is operating efficiently. The timing information is particularly useful when optimizing display drivers or debugging slow rendering issues.

Log filter

Expo supports filtering log output by object name, which is useful when debugging specific objects. Set the expo_log_filter environment variable to a substring that matches the object names you want to log.

To enable log filtering:

=> setenv expo_log_filter texted
=> log filter-add -d console -A -c expo -l debug

This shows debug logs only for objects whose name contains “texted”.

Multiple filters can be specified as a comma-separated list:

=> setenv expo_log_filter menu,text

This logs objects matching either “menu” or “text”.

Remove the filter to see all objects:

=> setenv expo_log_filter

This feature requires CONFIG_EXPO_LOG_FILTER which is enabled by default for sandbox.

Writing expo tests

Expo has extensive tests in test/boot/expo.c and test/boot/cedit.c. These can be run under sandbox like any other test (see Introduction to testing).

Test structure

Each test function follows a standard pattern:

static int expo_my_test(struct unit_test_state *uts)
{
    struct expo *exp;

    /* Create expo and perform tests */

    ut_assertok(expo_new("test", NULL, &exp));

    /* ... test code ... */

    expo_destroy(exp);

    return 0;
}
BOOTSTD_TEST(expo_my_test, UTF_DM | UTF_SCAN_FDT);

The BOOTSTD_TEST() macro registers the test with the test framework. Common flags include:

UTF_DM

Requires driver model to be enabled (most expo tests need this)

UTF_SCAN_FDT

Scans the device tree for devices (needed for video display)

UTF_CONSOLE

Test needs to record console output (needed for commands)

UTF_NO_SILENT

Don’t silence console output (needed for tests that check rendering output with user input)

Memory checking

Tests should verify that no memory is leaked:

ulong start_mem;

start_mem = ut_check_free();

/* ... create expo, test, destroy ... */

ut_assertok(ut_check_delta(start_mem));

For assertions, see Assertions.

Creating test expos

A common pattern is to create a helper function that sets up an expo with scenes and objects for testing. See create_test_expo() in test/boot/expo.c for an example:

static int create_test_expo(struct unit_test_state *uts, struct expo **expp,
                            struct scene **scnp, struct scene_obj_menu **menup,
                            ...)
{
    struct expo *exp;
    struct scene *scn;
    int id;

    ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
    ut_assertok(expo_new(EXPO_NAME, NULL, &exp));

    id = scene_new(exp, SCENE_NAME1, SCENE1, &scn);
    ut_assert(id > 0);

    ut_assertok(expo_set_display(exp, dev));

    /* Add objects to the scene */
    id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", NULL);
    ut_assert(id > 0);

    /* Return pointers */
    *expp = exp;
    *scnp = scn;

    return 0;
}

Testing rendering

For graphical rendering tests, use video_compress_fb() to get a checksum of the framebuffer:

ut_assertok(expo_render(exp));
ut_asserteq(expected_checksum, video_compress_fb(uts, dev, false));

For text-mode rendering, check console output lines:

expo_set_text_mode(exp, true);
ut_assertok(expo_render(exp));
ut_assert_nextline("Expected line");
ut_assert_console_end();

Testing input

To test keyboard input handling, use expo_send_key():

ut_assertok(expo_send_key(exp, BKEY_DOWN));
ut_assertok(expo_action_get(exp, &act));
ut_asserteq(EXPOACT_POINT_ITEM, act.type);
ut_asserteq(ITEM2, act.select.id);

To test mouse clicks, use scene_send_click():

ut_assertok(scene_send_click(scn, x, y, &act));
ut_asserteq(EXPOACT_SELECT, act.type);

Building from devicetree

To test building an expo from a devicetree description:

ofnode node;

node = ofnode_path("/cedit");
ut_assert(ofnode_valid(node));
ut_assertok(expo_build(node, &exp));

The test devicetree is in test/boot/files/expo_layout.dts with IDs defined in test/boot/files/expo_ids.h. See setup_cedit_file() in test/py/img/cedit.py for how this is set up.

Using IDs

Define an enum for all object IDs at the top of the test file:

enum {
    /* scenes */
    SCENE1 = 7,

    /* objects */
    OBJ_LOGO,
    OBJ_TEXT,
    OBJ_MENU,

    /* strings */
    STR_TEXT,
    STR_MENU_TITLE,

    /* menu items */
    ITEM1,
    ITEM2,
};

Starting IDs from a value higher than EXPOID_BASE_ID avoids conflicts with reserved expo IDs.

Debugging tests

Running tests directly (without pytest) makes debugging easier. See Sandbox tests for details on running sandbox tests with gdb.

For example, to run a single expo test:

./u-boot -T -c "ut bootstd expo_render_image"

To debug with gdb:

gdb --args ./u-boot -T -c "ut bootstd expo_render_image"
(gdb) break expo_render_image
(gdb) run

IDEs such as Visual Studio Code can also be used.

Sandbox provides command-line options useful for debugging expo and video tests, including -l (show LCD), -K (double LCD size), -V (video test mode with delay), --video_frames (capture frames), -f (continue after failure), and -F (skip flat-tree tests). See Sandbox for full details.

For example, to watch an expo test render with a visible display:

./u-boot -T -l -V 500 --video_frames /tmp/good -c "ut bootstd expo_render_image"

When using -V or with LOG_DEBUG enabled, some video tests call ut_check_video() to display a message at the top right corner of the screen identifying the current frame check. This helps identify which assertion is being displayed when debugging test failures. The message is automatically removed after the delay, so it does not affect the framebuffer checksums used by video tests.

The sb command grid subcommand can be used to overlay a grid on the display, to help with checking alignment of objects. The grid size defaults to 0x20 pixels but can be specified as a parameter.

This will write each asserted expo frame to /tmp/good/frame0.bmp, /tmp/good/frame1.bmp, etc.

API documentation

enum expo_id_t

standard expo IDs

Constants

EXPOID_NONE

Not used, invalid ID 0

EXPOID_SAVE

User has requested that the expo data be saved

EXPOID_DISCARD

User has requested that the expo data be discarded

EXPOID_BASE_ID

First 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_NONE

no action

EXPOACT_POINT_OBJ

object was highlighted (id indicates which object)

EXPOACT_POINT_ITEM

menu item was highlighted (id indicates which item)

EXPOACT_SELECT

menu item was selected (id indicates which)

EXPOACT_OPEN

menu was opened, so an item can be selected (id indicates which menu object)

EXPOACT_CLOSE

menu was closed (id indicates which menu object)

EXPOACT_POINT_OPEN

menu item was pointed to and menu opened (id indicates which menu object)

EXPOACT_POINT_CLOSE

menu item was pointed to and menu closed id indicates which menu item)

EXPOACT_REPOINT_OPEN

menu closed, another menu opened (prev_id indicates the menu closed, id indicates menu opened)

EXPOACT_QUIT

request to exit the menu

EXPOACT_CLICK

click on an object

EXPOACT_SETTINGS

select menu settings

struct expo_action

an action report by the expo

Definition

struct expo_action {
  enum expoact_type type;
  union {
    struct {
      int id;
      int prev_id;
      bool changed;
    } select;
  };
};

Members

type

Action type (EXPOACT_NONE if there is no action)

{unnamed_union}

anonymous

select

Used for all actions except EXPOACT_NONE and EXPOACT_QUIT

select.id

ID number of the object affected

select.prev_id

ID number of the old object that was highlighted

select.changed

true if the selection has changed since last time (only valid for EXPOACT_POINT_ITEM)

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;
  u32 textline_label_margin_x;
  bool white_on_black;
};

Members

font_size

Default font size for all text

menu_inset

Inset width (on each side and top/bottom) for menu items

menuitem_gap_y

Gap between menu items in pixels

menu_title_margin_x

Gap between right side of menu title and left size of menu label

textline_label_margin_x

Gap between right side of textline prompt and left side of editable text

white_on_black

True to use white-on-black for the expo, false for black-on-white

struct expo

information about an expo

Definition

struct expo {
  char *name;
  struct udevice *display;
  struct udevice *cons;
  struct udevice *mouse;
  uint scene_id;
  uint next_id;
  struct expo_action action;
  int req_width;
  int req_height;
  bool text_mode;
  bool popup;
  bool show_highlight;
  bool mouse_enabled;
  const void *mouse_ptr;
  struct vid_size mouse_size;
  struct vid_pos mouse_pos;
  struct vid_bbox damage;
  void *priv;
  bool done;
  bool save;
  struct expo_test_mode *test;
  struct expo_theme theme;
  struct list_head scene_head;
  struct list_head str_head;
  struct cli_ch_state cch;
  ulong last_key_ms;
};

Members

name

Name of the expo (allocated)

display

Display to use (UCLASS_VIDEO), or NULL to use text mode

cons

Console to use (UCLASS_VIDEO_CONSOLE), or NULL to use text mode

mouse

Mouse to use (UCLASS_MOUSE), or NULL if no mouse

scene_id

Current scene ID (0 if none)

next_id

Next ID number to use, for automatic allocation

action

Action selected by user. At present only one is supported, with the

req_width

Requested width of the display

req_height

Requested height of the display type set to EXPOACT_NONE if there is no action

text_mode

true to use text mode for the menu (no vidconsole)

popup

true to use popup menus, instead of showing all items

show_highlight

show a highlight bar on the selected menu item

mouse_enabled

true if the mouse is enabled

mouse_ptr

Pointer to mouse pointer image data (BMP format)

mouse_size

Size of mouse pointer (width and height in pixels)

mouse_pos

Current mouse position

damage

Bounding box of the area that needs to be redrawn

priv

Private data for the controller

done

Indicates that a cedit session is complete and the user has quit

save

Indicates that cedit data should be saved, rather than discarded

test

Pointer to test mode information, NULL if not allocated

theme

Information about fonts styles, etc.

scene_head

List of scenes

str_head

list of strings

cch

Keyboard context for input

last_key_ms

timestamp of the last key received

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

id

ID number of the string

buf

String (contains nul terminator)

sibling

Node 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 prompt_id;
  uint highlight_id;
  struct cli_line_state cls;
  struct abuf buf;
  struct list_head sibling;
  struct list_head obj_head;
};

Members

expo

Expo this scene is part of

name

Name of the scene (allocated)

id

ID number of the scene

title_id

String ID of title of the scene (allocated)

prompt_id

String ID of prompt of the scene (allocated)

highlight_id

ID of highlighted object, if any

cls

cread state to use for input

buf

Buffer for input

sibling

Node to link this scene to its siblings

obj_head

List 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_NONE

Used to indicate that the type does not matter

SCENEOBJT_IMAGE

Image data to render

SCENEOBJT_TEXT

Text line to render

SCENEOBJT_BOX

Rectangular box

SCENEOBJT_MENU

Menu containing items the user can select

SCENEOBJT_TEXTLINE

Line of text the user can edit

SCENEOBJT_TEXTEDIT

Simple text editor

struct scene_obj_offset

Offsets for drawing the object

Definition

struct scene_obj_offset {
  int xofs;
  int yofs;
};

Members

xofs

x offset

yofs

y 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

x

x dimension

y

y 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_LEFT

Left of object is aligned with its x coordinate

SCENEOA_RIGHT

Right of object is aligned with x + w

SCENEOA_CENTRE

Centre of object is aligned with centre of bounding box

SCENEOA_TOP

Left of object is aligned with its x coordinate

SCENEOA_BOTTOM

Right 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_HIDE

object should be hidden

SCENEOF_POINT

object should be highlighted

SCENEOF_OPEN

object should be opened (e.g. menu is opened so that an option can be selected)

SCENEOF_SIZE_VALID

object’s size (width/height) is valid, so any adjustment to x0/y0 should maintain the width/height of the object

SCENEOF_SYNC_POS

object’s position has changed

SCENEOF_SYNC_SIZE

object’s size (width/height) has changed

SCENEOF_SYNC_WIDTH

object’s widget has changed

SCENEOF_SYNC_BBOX

object’s bounding box has changed

SCENEOF_MANUAL

manually arrange the items associated with this object

SCENEOF_DIRTY

object has been modified and needs to be redrawn

SCENEOF_PASSWORD

textline input should show stars instead of characters

SCENEOF_MULTILINE

textedit allows multiline input (Enter adds newline)

SCENEOF_LAST

used just as a check for the size of the flags mask

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 vid_bbox req_bbox;
  struct vid_bbox bbox;
  struct scene_obj_offset ofs;
  struct scene_obj_dims dims;
  enum scene_obj_align horiz;
  enum scene_obj_align vert;
  u16 flags;
  u16 start_bit;
  u8 bit_length;
  struct list_head sibling;
};

Members

scene

Scene that this object relates to

name

Name of the object (allocated)

id

ID number of the object

type

Type of this object

req_bbox

Requested bounding box for this object, synced to bbox when scene is arranged

bbox

Bounding box for this object (internal use only)

ofs

Offset from x0, y0 where the object is drawn (internal use only)

dims

Dimensions of the text/image; may be smaller than bbox (internal use only)

horiz

Horizonal alignment

vert

Vertical alignment

flags

Flags for this object

start_bit

Start bit to use for this object in CMOS RAM

bit_length

Number of bits used for this object in CMOS RAM

sibling

Node 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;
  const char *data;
};

Members

obj

Basic object information

data

Image 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_id

ID of the text string to display

font_name

Name of font (allocated by caller)

font_size

Nominal size of font in pixels

lines

alist 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

obj

Basic object information

gen

Generic 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;
  int pointer_xofs;
  struct list_head item_head;
};

Members

obj

Basic object information

title_id

ID of the title text object (not string ID), or 0 if none

cur_item_id

ID of the current menu item, or 0 if none

pointer_id

ID of the object pointing to the current selection

pointer_xofs

x position of pointer relative to the left side of the menu

item_head

List 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_BEFORE

Add 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

name

Name of the item (this is allocated by this call)

id

ID number of the object

key_id

ID of text object to use as the keypress to show

label_id

ID of text object to use as the label text

desc_id

ID of text object to use as the description text

preview_id

ID of the preview object, or 0 if none

flags

Flags for this item

value

Value for this item, or INT_MAX to use sequence

sibling

Node 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_txtin

generic info for text-input objects

Definition

struct scene_txtin {
  uint label_id;
  uint edit_id;
  uint line_chars;
  struct abuf buf;
  void *ctx;
  struct cli_line_state cls;
};

Members

label_id

ID of the label text object (not string ID), or 0 if none

edit_id

ID of the editable text object (not string ID)

line_chars

Nominal number of characters in a line

buf

Text buffer containing current text

ctx

Vidconsole context for this text-input object

cls

CLI line state for text editing

struct scene_obj_textline

information about a textline in a scene

Definition

struct scene_obj_textline {
  struct scene_obj obj;
  struct scene_txtin tin;
  uint pos;
};

Members

obj

Basic object information

tin

Text-input info

pos

Cursor 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;
  bool fill;
};

Members

obj

Basic object information

width

Line-width in pixels

fill

true to fill the box, false to draw outline only

Description

A box surrounds a part of the screen with a border

struct scene_obj_txtedit

information about a textedit in a scene

Definition

struct scene_obj_txtedit {
  struct scene_obj obj;
  struct scene_txtin tin;
};

Members

obj

Basic object information

tin

Text-input info

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_width

Maximum width of labels in scene

int expo_new(const char *name, void *priv, struct expo **expp)

create a new expo

Parameters

const char *name

Name of expo (this is allocated by this call)

void *priv

Private data for the controller

struct expo **expp

Returns a pointer to the new expo on success

Description

Allocates a new expo

Return

0 if OK, -ENOMEM if out of memory

void expo_destroy(struct expo *exp)

Destroy an expo and free all its memory

Parameters

struct expo *exp

Expo to destroy

void expo_set_dynamic_start(struct expo *exp, uint dyn_start)

Set the start of the ‘dynamic’ IDs

Parameters

struct expo *exp

Expo to update

uint dyn_start

Start 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 *exp

Expo to update

const char *name

Name to use (this is allocated by this call)

uint id

ID to use for the new object (0 to allocate one)

const char *str

Pointer to text to display (allocated by caller)

Return

ID number for the object (typically id), or -ve on error

const char *expo_get_str(struct expo *exp, uint id)

Get a string by ID

Parameters

struct expo *exp

Expo to use

uint id

String 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 *exp

Expo to use

uint id

String ID to look up

struct abuf *orig

If 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 **copyp

Returns 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

int expo_set_display(struct expo *exp, struct udevice *dev)

set the display to use for a expo

Parameters

struct expo *exp

Expo to update

struct udevice *dev

Display to use (UCLASS_VIDEO), NULL to use text mode

Return

0 (always)

int expo_calc_dims(struct expo *exp)

Calculate the dimensions of the objects

Parameters

struct expo *exp

Expo 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

int expo_set_scene_id(struct expo *exp, uint scene_id)

Set the current scene ID

Parameters

struct expo *exp

Expo to update

uint scene_id

New scene ID to use (0 to select no scene)

Return

0 if OK, -ENOENT if there is no scene with that ID

int expo_first_scene_id(struct expo *exp)

Get the ID of the first scene

Parameters

struct expo *exp

Expo to check

Return

Scene ID of first scene, or -ENOENT if there are no scenes

int expo_render(struct expo *exp)

render the expo on the display / console

Parameters

struct expo *exp

Expo 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

int expo_render_dirty(struct expo *exp)

render the dirty portion of expo on the display

Parameters

struct expo *exp

Expo to render

Description

Only the objects within the damage bbox are rendered. The others are assumed to be up-to-date.

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

int expo_arrange(struct expo *exp)

Arrange the current scene to deal with object sizes

Parameters

struct expo *exp

Expo to arrange

Description

Updates any menus in the current scene so that their objects are in the right place. Does nothing if there is no scene

Return

0 if OK, -ve on error

void expo_set_text_mode(struct expo *exp, bool text_mode)

Controls whether the expo renders in text mode

Parameters

struct expo *exp

Expo to update

bool text_mode

true to use text mode, false to use the console

int expo_set_mouse_enable(struct expo *exp, bool enable)

Controls whether the expo enables mouse input

Parameters

struct expo *exp

Expo to update

bool enable

true to enable mouse input, false to disable

Return

0 if OK, or -ve error if no mouse found

int scene_new(struct expo *exp, const char *name, uint id, struct scene **scnp)

create a new scene in a expo

Parameters

struct expo *exp

Expo to update

const char *name

Name to use (this is allocated by this call)

uint id

ID to use for the new scene (0 to allocate one)

struct scene **scnp

Returns 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

struct scene *expo_lookup_scene_id(struct expo *exp, uint scene_id)

Look up a scene by ID

Parameters

struct expo *exp

Expo to check

uint scene_id

Scene ID to look up returns pointer to scene if found, else NULL

void scene_highlight_first(struct scene *scn)

Highlight the first item in a scene

Parameters

struct scene *scn

Scene to update

Description

This highlights the first item, so that the user can see that it is pointed to

void scene_set_highlight_id(struct scene *scn, uint id)

Set the object which is highlighted

Parameters

struct scene *scn

Scene to update

uint id

ID of object to highlight

Description

Sets a new object to highlight in the scene

int scene_img_set_data(struct scene *scn, uint id, const void *data, int size)

Set the image data for an image object

Parameters

struct scene *scn

Scene to update

uint id

ID of existing image obejct

const void *data

Image data to use

int size

Size of image data

Return

0 if OK, -ENOENT if id is invalid

int scene_set_open(struct scene *scn, uint id, bool open)

Set whether an item is open or not

Parameters

struct scene *scn

Scene to update

uint id

ID of object to update

bool open

true to open the object, false to close it

Return

0 if OK, -ENOENT if id is invalid

int scene_obj_count(struct scene *scn)

Count the number of objects in a scene

Parameters

struct scene *scn

Scene 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 *scn

Scene to update

const char *name

Name to use (this is allocated by this call)

uint id

ID to use for the new object (0 to allocate one)

char *data

Pointer to image data

struct scene_obj_img **imgp

If 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 *scn

Scene to update

const char *name

Name to use (this is allocated by this call)

uint id

ID to use for the new object (0 to allocate one)

uint str_id

ID of the string to use

struct scene_obj_txt **txtp

If 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 *scn

Scene to update

const char *name

Name to use (this is allocated by this call)

uint id

ID to use for the new object (0 to allocate one)

uint str_id

ID of the string to use

const char *str

Pointer to text to display (allocated by caller)

struct scene_obj_txt **txtp

If 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 *scn

Scene to update

const char *name

Name to use (this is allocated by this call)

uint id

ID to use for the new object (0 to allocate one)

struct scene_obj_menu **menup

If 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 line_chars, struct scene_obj_textline **tlinep)

create a textline

Parameters

struct scene *scn

Scene to update

const char *name

Name to use (this is allocated by this call)

uint id

ID to use for the new object (0 to allocate one)

uint line_chars

Number of characters in a line (also a hard limit)

struct scene_obj_textline **tlinep

If 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, bool fill, struct scene_obj_box **boxp)

create a box

Parameters

struct scene *scn

Scene to update

const char *name

Name to use (this is allocated by this call)

uint id

ID to use for the new object (0 to allocate one)

uint width

Line-width in pixels

bool fill

true to fill the box, false to draw outline only

struct scene_obj_box **boxp

If non-NULL, returns the new object

Return

ID number for the object (typically id), or -ve on error

int scene_box_set_fill(struct scene *scn, uint id, bool fill)

Set the fill property of a box object

Parameters

struct scene *scn

Scene containing the box

uint id

ID of the box object to update

bool fill

true to fill the box, false to draw outline only

Return

0 if OK, -ENOENT if the object is not found or is not a box

int scene_texted(struct scene *scn, const char *name, uint id, uint line_chars, struct scene_obj_txtedit **teditp)

create a text editor

Parameters

struct scene *scn

Scene to update

const char *name

Name to use (this is allocated by this call)

uint id

ID to use for the new object (0 to allocate one)

uint line_chars

Nominal number of characters in a line

struct scene_obj_txtedit **teditp

If 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 *scn

Scene to update

uint id

ID of object to update

const char *font_name

Font name to use (allocated by caller)

uint font_size

Font 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 *scn

Scene to update

uint id

ID of object to update

const char *font_name

Font name to use (allocated by caller)

uint font_size

Font size to use (nominal height in pixels)

int scene_obj_set_pos(struct scene *scn, uint id, int x, int y)

Set the postion of an object

Parameters

struct scene *scn

Scene to update

uint id

ID of object to update

int x

x position, in pixels from left side

int y

y position, in pixels from top

Description

The given position is marked as ‘requested’ and will be applied when the scene is next arranged

Return

0 if OK, -ENOENT if id is invalid

int scene_obj_set_size(struct scene *scn, uint id, int w, int h)

Set the size of an object

Parameters

struct scene *scn

Scene to update

uint id

ID of object to update

int w

width in pixels

int h

height in pixels

Description

The given size is marked as ‘requested’ and will be applied when the scene is next arranged

Return

0 if OK, -ENOENT if id is invalid

int scene_obj_set_width_flags(struct scene *scn, uint id, int w, uint flags)

Set the width of an object, with flags

Parameters

struct scene *scn

Scene to update

uint id

ID of object to update

int w

width in pixels

uint flags

Flags to OR with the current flags

Description

The given width is marked as ‘requested’ and will be applied when the scene is next arranged. The object flags are ORed with flags

Return

0 if OK, -ENOENT if id is invalid

int scene_obj_set_width(struct scene *scn, uint id, int w)

Set the width of an object

Parameters

struct scene *scn

Scene to update

uint id

ID of object to update

int w

width in pixels

Description

The given width is marked as ‘requested’ and will be applied when the scene is next arranged

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 *scn

Scene to update

uint id

ID of object to update

int x0

x position, in pixels from left side

int y0

y position, in pixels from top

int x1

ending x position (right side)

int y1

ending y position (botton side)

Description

The given bounding box is marked as ‘requested’ and will be applied when the scene is next arranged

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 *scn

Scene to update

uint id

ID of object to update

enum scene_obj_align aln

Horizontal 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 *scn

Scene to update

uint id

ID of object to update

enum scene_obj_align aln

Vertical alignment to use

Return

0 if OK, -ENOENT if id is invalid

int scene_obj_set_hide(struct scene *scn, uint id, bool hide)

Set whether an object is hidden

Parameters

struct scene *scn

Scene to update

uint id

ID of object to update

bool hide

true 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

int scene_obj_set_manual(struct scene *scn, uint id, bool manual)

Set whether an object arranges its dependents

Parameters

struct scene *scn

Scene to update

uint id

ID of object to update

bool manual

true to disable arrange dependents when this object is updated

Description

When this is enabled, scene_arrange() will refrain from moving objects attached to this one. E.g. for a menu, normally it moves text objects associated with the menu.

Return

0 if OK, -ENOENT if id is invalid

int scene_menu_set_title(struct scene *scn, uint id, uint title_id)

Set the title of a menu

Parameters

struct scene *scn

Scene to update

uint id

ID of menu object to update

uint title_id

ID 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 *scn

Scene to update

uint id

ID of menu object to update

uint cur_item_id

ID 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 *scn

Scene to update

uint id

ID of menu object to update

uint sel_id

ID of the menuitem to select Return 0 on success, -ENOENT if there was no such item

int scene_menu_get_cur_item(struct scene *scn, uint id)

get the currently pointed-to item

Parameters

struct scene *scn

Scene to update

uint id

ID 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 *scn

Scene to check

uint id

ID of menu object to check

int *widthp

If 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 *scn

Scene to update

uint menu_id

ID of menu object to update

const char *name

Name to use (this is allocated by this call)

uint id

ID to use for the new object (0 to allocate one)

uint key_id

ID of text object to use as the keypress to show

uint label_id

ID of text object to use as the label text

uint desc_id

ID of text object to use as the description text

uint preview_id

ID of object to use as the preview (text or image)

uint flags

Flags for this item (enum scene_menuitem_flags_t)

struct scene_menitem **itemp

If non-NULL, returns the new object

Return

ID number for the item (typically id), or -ve on error

int scene_arrange(struct scene *scn)

Arrange the scene to deal with object sizes

Parameters

struct scene *scn

Scene 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

int expo_send_key(struct expo *exp, int key)

set a keypress to the expo

Parameters

struct expo *exp

Expo to receive the key

int key

Key to send (ASCII or enum bootmenu_key)

Description

This processes the key, taking any action that is needed, such as moving between menu items or editing the text in a textline

Return

0 if OK, -ECHILD if there is no current scene

int expo_send_click(struct expo *exp, int x, int y)

send a mouse click to the expo

Parameters

struct expo *exp

Expo to receive the click

int x

X coordinate of click

int y

Y coordinate of click

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 *exp

Expo to check

struct expo_action *act

Returns action

Return

0 if OK, -EAGAIN if there was no action to return

int expo_setup_theme(struct expo *exp, ofnode node)

Read a theme from a node and apply it to an expo

Parameters

struct expo *exp

Expo to update

ofnode node

Node containing the theme

Return

0 if OK, -ve on error

int expo_apply_theme(struct expo *exp, bool do_objs)

Apply an expo’s theme

Parameters

struct expo *exp

Expo to update

bool do_objs

Apply theme to objects as well (normally this should be true)

Description

The theme to be applied must be set up exp->theme

Return

0 if OK, -ve on error

struct editenv_info

Context for environment-variable editing

Definition

struct editenv_info {
  struct expo *exp;
  struct scene *scn;
  struct scene_obj_txtedit *ted;
};

Members

exp

Expo being used

scn

Scene in the expo

ted

Textedit object for editing

int expo_editenv_init(const char *varname, const char *value, struct editenv_info *info)

Set up a new editenv expo

Parameters

const char *varname

Name of the variable to edit

const char *value

Initial value (may be NULL)

struct editenv_info *info

Returns info about the editenv state

Return

0 if OK, -ve on error

int expo_editenv_poll(struct editenv_info *info)

Poll for user input

Parameters

struct editenv_info *info

Editenv info

Return

0 if editing is complete, -EAGAIN if more polling is needed,

-ECANCELED if user quit, other -ve on error

void expo_editenv_uninit(struct editenv_info *info)

Free resources used by editenv

Parameters

struct editenv_info *info

Editenv info

const char *expo_editenv_result(struct editenv_info *info)

Get the result string from editenv

Parameters

struct editenv_info *info

Editenv info

Return

Pointer to the edited string

int expo_editenv(const char *varname, const char *value, char *buf, int size)

Edit an environment variable using expo

Parameters

const char *varname

Name of the variable to edit

const char *value

Initial value (may be NULL)

char *buf

Buffer to receive the edited text

int size

Size of buf

Description

Creates a simple expo with a textedit object to edit the variable. This is a convenience function that calls expo_editenv_init(), expo_editenv_poll() in a loop, and expo_editenv_uninit().

Return

0 if OK and text was edited, -ECANCELED if cancelled, other -ve on

error

int expo_build(ofnode root, struct expo **expp)

Build an expo from an FDT description

Parameters

ofnode root

Root node for expo description

struct expo **expp

Returns 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

int cb_expo_build(struct expo **expp)

Build an expo for coreboot CMOS RAM

Parameters

struct expo **expp

Returns 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 *exp

Expo to poll

struct expo_action *act

Returns 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

void expo_req_size(struct expo *exp, int width, int height)

Request a size for the expo display

Parameters

struct expo *exp

Expo to update

int width

Requested display width

int height

Requested display height

Description

Set the width and height of the display, so far as requested positions and size are concerned. The actual display may be larger or smaller, in which case expo scales the objects to fit

void expo_enter_mode(struct expo *exp)

Enter expo mode for the video subsystem

Parameters

struct expo *exp

Expo to update

Description

This suppresses automatic video sync operations to allow expo to control rendering timing. Should be called before starting the expo loop.

void expo_exit_mode(struct expo *exp)

Exit expo mode for the video subsystem

Parameters

struct expo *exp

Expo to update

Description

This restores normal video sync operations. Should be called after finishing the expo loop.

void expo_damage_reset(struct expo *exp)

Reset the damage tracking area

Parameters

struct expo *exp

Expo to reset damage tracking for

Description

Clears the damage area, indicating that no part of the display needs to be redrawn.

void expo_damage_add(struct expo *exp, const struct vid_bbox *bbox)

Add a damaged area to the expo damage tracking

Parameters

struct expo *exp

Expo to add damage to

const struct vid_bbox *bbox

Bounding box of the damaged area to add

Description

Expands the current damage area to include the new damaged region. If there is no existing damage, the damage area is set to the new region.

void expo_dump(struct expo *exp, struct membuf *mb)

Dump expo structure to a membuf

Parameters

struct expo *exp

Expo to dump

struct membuf *mb

membuf to write to

int expo_dump_file(struct expo *exp, const char *fname)

Dump expo structure to a file (sandbox only)

Parameters

struct expo *exp

Expo to dump

const char *fname

Filename to write to

Return

0 if OK, -ve on error

void scene_dump(struct membuf *mb, struct scene *scn, int indent)

Dump scene structure to a membuf

Parameters

struct membuf *mb

membuf to write to

struct scene *scn

Scene to dump

int indent

Indentation level

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