Menu Driver - Core Data Structures
Page State Types
A page state is:
The persistent data container that represents everything a UI page needs to function between frames.
Not just data. It’s:
- memory of what the user did
- memory of what was rendered
- memory of external data (diagnostics, etc.)
List Page State
typedef struct {
uint8_t num_entries;
uint8_t selected_index;
uint8_t entry_ids[MAX_LIST_ENTRIES];
const uint8_t (*entry_icons)[MENU_DRIVER_ICON_BYTE_SIZE];
bool first_render;
} page_list_state;
Responsibilities:
- track selection
- map entries → page IDs
- hold icons
- manage first render optimization
Overview Page State
Todo :D
State Union
typedef union {
page_list_state list;
page_overview_state overview;
} menu_page_state;
Page Type
typedef enum {
MENU_PAGE_TYPE_LIST,
MENU_PAGE_TYPE_OVERVIEW,
} menu_page_type_t;
Used to interpret the union correctly.
Page Object
typedef struct {
menu_page_state *state;
menu_page_type_t type;
unsigned char id;
unsigned char parent_id;
bool needs_render;
char name[MAX_PAGE_NAME_LEN];
void (*init)(menu_page_state *);
void (*update)(menu_manager_t *);
void (*render)(menu_manager_t *);
void (*destruct)(menu_page_state *);
} menu_page_t;
This is the core abstraction.
Definition and Role
A page object represents one logical screen within the menu system. It encapsulates:
- the data required to represent the page (via its state)
- the functions required to manage its lifecycle
- metadata used for navigation and identification
This abstraction allows the menu system to treat all pages uniformly, regardless of their internal implementation or purpose.
Important Fields
Render Control
bool needs_render;
This flag indicates whether the page requires re-rendering.
It allows the system to avoid unnecessary redraw operations, which is critical in environments where display updates are expensive.
The responsibility for managing this flag lies with the page implementation.
Lifecycle Function Pointers
Each page defines its own behavior through four function pointers:
Initialization
void (*init)(menu_page_state *state);
Responsible for preparing the page state when the page becomes active.
Typical responsibilities include:
- resetting selection indices
- initializing flags
- preparing any required data structures
Update
void (*update)(struct menu_manager_t *manager);
Handles input processing and state updates.
This function is expected to:
- read input through the manager
- modify internal state accordingly
- trigger page transitions if necessary
Render
void (*render)(struct menu_manager_t *manager);
Responsible for drawing the page to the display.
This function should:
- read from the page state
- issue drawing commands via the display driver
- respect the
needs_renderflag when applicable
Destruction
void (*destruct)(menu_page_state *state);
Handles cleanup when the page is no longer active.
In embedded systems, this typically involves:
- resetting state fields
- releasing logical ownership of resources
Dynamic memory cleanup is generally not required unless explicitly used.
Menu Manager
typedef struct {
unsigned char active_page_id;
const menu_page_t *pages;
menu_input (*get_input)(void);
} menu_manager_t;
Responsibilities:
- track active page
- provide input access
- hold page table
Does NOT:
- validate anything
- own memory
- manage concurrency