# 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). Меню от них не зависит: связывает всё адаптер в приложении.