Перенесён из KONOR_ds18b20/lib/menu; в OpticalTester лежала такая же копия. Содержимое экрана движок запрашивает обратными вызовами, поэтому один экран описывает и статический список, и перечень датчиков переменной длины. Рисует через Menu_Painter: от драйвера дисплея не зависит, цвет передаётся как есть — подходит и RGB565, и монохром.
72 lines
3.3 KiB
Markdown
72 lines
3.3 KiB
Markdown
# menu
|
||
|
||
Экранное меню для дисплея и шести кнопок навигации.
|
||
|
||
Движок хранит стек открытых экранов, курсор и окно прокрутки, а содержимое
|
||
запрашивает у приложения обратными вызовами: так один и тот же экран описывает
|
||
и статический список, и перечень датчиков, число которых меняется на ходу.
|
||
|
||
Рисует движок через таблицу `Menu_Painter`, поэтому от драйвера дисплея он не
|
||
зависит: для ST7789V адаптер занимает несколько строк, для знакосинтезирующего
|
||
ЖКИ или SSD1306 — столько же.
|
||
|
||
```
|
||
приложение
|
||
count/text/enter/adjust ← чем наполнен экран
|
||
│
|
||
menu.c стек экранов, курсор, прокрутка, перерисовка
|
||
│
|
||
Menu_Painter fill_rect, draw_text
|
||
│
|
||
драйвер дисплея
|
||
```
|
||
|
||
## Состав
|
||
|
||
| Файл | Что делает | Зависимости |
|
||
|---|---|---|
|
||
| `menu.h`, `menu.c` | стек экранов до 4 уровней, курсор, прокрутка, тема оформления, строка состояния | `stdint.h` |
|
||
|
||
Вспомогательное: `Menu_TextCopy()` и `Menu_TextInt()` — форматирование строк
|
||
пунктов без `snprintf`. `Menu_GetSnapshot()` отдаёт состояние без отрисовки,
|
||
что удобно для хостовых тестов.
|
||
|
||
## Что нужно от платформы
|
||
|
||
Только два вызова отрисовки — цвет передаётся как есть, поэтому в него
|
||
укладывается и RGB565, и палитра монохромного индикатора:
|
||
|
||
```c
|
||
void fill_rect(void *ctx, int16_t x, int16_t y, uint16_t w, uint16_t h, uint32_t color);
|
||
void draw_text(void *ctx, int16_t x, int16_t y, const char *text,
|
||
uint32_t color, uint32_t background, uint8_t scale);
|
||
```
|
||
|
||
## Быстрый старт
|
||
|
||
```c
|
||
static const Menu_Screen screen_root = {
|
||
.title = "Главное меню",
|
||
.count = root_count, /* сколько пунктов сейчас */
|
||
.text = root_text, /* текст пункта по индексу */
|
||
.enter = root_enter, /* вернуть вложенный экран или 0 */
|
||
.context = &app,
|
||
};
|
||
|
||
Menu menu;
|
||
Menu_Theme theme;
|
||
Menu_ThemeDefault(&theme);
|
||
Menu_Init(&menu, &painter, &theme, &screen_root);
|
||
|
||
Menu_HandleKey(&menu, MENU_KEY_DOWN);
|
||
Menu_Render(&menu, 0); /* перерисует только если что-то изменилось */
|
||
```
|
||
|
||
Данные, меняющиеся сами по себе (температура, состояние связи), обновляются
|
||
вызовом `Menu_Invalidate()` — движок перерисует экран на ближайшем `Menu_Render()`.
|
||
|
||
## Проверено в проектах
|
||
|
||
`KONOR_ds18b20`, `OpticalTester` — поверх [`st7789`](../st7789) и [`keypad`](../keypad).
|
||
Меню от них не зависит: связывает всё адаптер в приложении.
|