A small hierarchical menu renderer on top of LVGL.
Data model: a static const tree of TreeMenuNode. A node is either a leaf
(on_activate set, children NULL) or a branch (children set,
on_activate ignored). Every non-root level automatically gets a "back"
row injected at position 0 — you never declare it yourself.
Input-agnostic: this library never reads any button/input device. The host
app wires its own input (physical buttons, touch, ...) to
treemenu_next()/treemenu_prev()/treemenu_activate().
#include <TreeMenu.h>
static void onWifiSelected(const TreeMenuNode *self, void *userdata) {
// ...
}
static const TreeMenuNode settingsMenu[] = {
{"Wifi", onWifiSelected, NULL, 0},
};
static const TreeMenuNode rootMenu[] = {
{"Settings", NULL, settingsMenu, 1},
};
void setup() {
// ... after the LVGL display driver is registered ...
TreeMenuConfig cfg = {0};
cfg.parent = lv_scr_act();
cfg.row_height = 18;
cfg.color_active = 0x2266ff;
cfg.color_text = 0xffffff;
cfg.color_text_active = 0xffffff;
cfg.color_separator = 0x333333;
cfg.color_chevron = 0xffffff;
cfg.bg_color = 0x000000;
treemenu_init(&cfg, rootMenu, 1);
}
// Wire your own buttons/touch to these:
// treemenu_next(); // move selection down, wraps around
// treemenu_prev(); // move selection up, wraps around
// treemenu_activate(); // enter a branch / back out / fire a leaf's on_activateSee src/TreeMenu.h for the full TreeMenuConfig (colors,
sizing, an optional breadcrumb strip, ...).
TreeMenu is pure C on top of LVGL — no hardware, no Arduino dependency — so its tests run entirely on the host against a real (headless) LVGL instance (a dummy display driver, no actual rendering):
pio test -e nativeCI runs this on every push/PR — see .github/workflows/tests.yml.
src/TreeMenu.h/.c Public API + implementation
test/test_native/ Unit tests, run on the host against headless LVGL