PIPKIT · Layout Navigation

Layout helpers, регистрация экранов и основной цикл.

Страница повторяет разделы API.md про layout helpers, экраны, цикл, input model, redraw и transitions.

6. Layout helpers

Это лёгкие helper-ы для раскладки UI без тяжёлой layout-системы.

Базовые типы:

UiSize   size{120, 40};
UiRect   rect{0, 0, 240, 320};
UiInsets insets{10, 10, 10, 10};

6.1. Slicing API

UiRect root{0, 0, 240, 320};
UiRect work = inset(root, 10);

UiRect header = takeTop(work, 24, 8);
UiRect footer = takeBottom(work, 28, 8);
UiRect content = work;

Доступно:

  • inset(rect, all)
  • inset(rect, l, t, r, b)
  • inset(rect, UiInsets{...})
  • takeTop(...)
  • takeBottom(...)
  • takeLeft(...)
  • takeRight(...)
  • placeInside(...)
  • centerIn(...)

6.2. Flow API

UiSize sizes[3] = {{40, 20}, {60, 20}, {40, 20}};
UiRect out[3];

flowRow(area, sizes, out, 3, 10, Center, Center);
flowColumn(area, sizes, out, 3, 8, Center, Center);

Для распределения доступны:

  • Start
  • Center
  • End
  • layout::SpaceBetween
  • layout::SpaceEvenly

6.3. Cursor-based API

UiFlowRow<3> row(area, 10, layout::SpaceEvenly, Center);

row.next(40, 24);
row.next(60, 24);
row.next(40, 24);
row.finish();

Аналогично работает UiFlowColumn<N>.

Как этим пользоваться правильно:

  • next(w, h) резервирует следующий slot
  • после всех next(...) нужно вызвать finish()
  • итоговые прямоугольники потом берутся через row[i] или column[i]

Для позиционирования и выравнивания часто используются короткие шорткаты:

  • center для автоматического центрирования по оси
  • Left, Center, Right
  • Top, Bottom

11. Экраны и цикл

11.1. Регистрация экранов

Экраны регистрируются через макрос SCREEN(name, order):

SCREEN(ScreenHome, 0)
{
    ui.clear(ui.rgb(0, 0, 0));
}

SCREEN(ScreenSettings, 1)
{
    ui.clear(ui.rgb(8, 8, 8));
}

Что создаёт макрос:

  • callback-функцию экрана;
  • числовой id экрана;
  • автоматическую регистрацию экрана в таблице GUI.

Что важно:

  • name становится константой id, её потом можно передавать в setScreen(...), updateList(...), updateTile(...) и другие API
  • order задаёт порядок регистрации экрана
  • order должен быть уникальным для каждого экрана
  • обычно первый экран делают с order = 0

После этого экран можно активировать:

ui.setScreen(ScreenHome);

11.2. Основной цикл

Базовый вариант:

void loop()
{
    ui.loop();
}

Вспомогательный вариант, если есть две кнопки Button:

Button Next(1, Pullup);
Button Prev(2, Pullup);

void setup()
{
    Next.begin();
    Prev.begin();
}

void loop()
{
    ui.loopWithInput(Next, Prev);
}

Вариант с тремя кнопками (Next/Prev/Select):

Button Next(1, Pullup);
Button Prev(2, Pullup);
Button Select(3, Pullup);

void setup()
{
    Next.begin();
    Prev.begin();
    Select.begin();
}

void loop()
{
    ui.loopWithInput(Next, Prev, Select);
}

loopWithInput(...) обновляет объекты Button, обрабатывает ввод для built-in overlay/меню (list/tile/popup/error/notification) и затем вызывает ui.loop(). Если вам нужен свой state-machine ввода, используйте pollInput(...) и/или передавайте состояния кнопок вручную через ...Input() fluent-методы.

По умолчанию loopWithInput(...) включает авто-переходы между экранами по коротким нажатиям Next/Prev (когда не активны overlay/меню). loopWithPolledInput() обрабатывает built-in overlay/меню на основании последнего pollInput(...) и так же включает авто-переходы между экранами по коротким нажатиям Next/Prev (как loopWithInput(...)). Чтобы отключить авто-навигацию на текущем тике (если вы используете кнопки под свой сценарий), вызовите ui.consumeAutoNav() до loopWithPolledInput().

Если loopWithInput(...) не используется, вызывайте btn.update() сами в начале каждого loop(). После этого wasPressed() и isDown() читают уже обновлённое состояние кнопки.

Если нужен готовый snapshot ввода для собственного state-machine:

InputState input = ui.pollInput(Next, Prev);

или (если есть кнопка выбора):

InputState input = ui.pollInput(Next, Prev, Select);

pollInput(...) сам обновляет кнопки и возвращает готовый снимок их состояния на текущий тик.

Поля InputState:

  • nextDown - кнопка Next сейчас удерживается
  • prevDown - кнопка Prev сейчас удерживается
  • nextPressed - кнопка Next была нажата именно в этом тике
  • prevPressed - кнопка Prev была нажата именно в этом тике
  • selectDown - кнопка Select сейчас удерживается (если включен 3-button режим)
  • selectPressed - кнопка Select была нажата именно в этом тике (если включен 3-button режим)
  • comboDown - обе кнопки сейчас зажаты одновременно
  • hasSelect - true, если pollInput/loopWithInput вызваны в 3-button режиме

Разница простая:

  • Down - состояние удержания
  • Pressed - одноразовое событие нажатия

11.2.1. Где библиотека использует кнопки (шорткаты и встроенные сценарии)

Если вы используете loopWithInput(...) или вручную прокидываете ...Input() fluent-методы, то кнопки обрабатываются в этих местах:

  • Скриншоты (built-in shortcut): удержание Next + Prev (если включены screenshots) — захват скриншота.
  • List menu (updateList):
  • Next/Prev коротко — перемещение по пунктам.
  • 2-button режим: удержание Next — открыть targetScreen.
  • 3-button режим: короткое нажатие Select — открыть targetScreen.
  • удержание PrevbackScreen() (назад по history).
  • Tile menu (updateTile): то же самое, что и list (перемещение Next/Prev, открыть Next-hold или Select-press, назад Prev-hold).
  • Popup menu: Next/Prev — перемещение; 2-button ?????: Next-hold подтверждает; 3-button ?????: Select-press подтверждает; Prev-hold закрывает.
  • Notification overlay: закрывается через встроенную обработку ввода:
  • 2-button режим: Prev подтверждает/закрывает.
  • 3-button режим: Select подтверждает/закрывает (и Prev тоже принимается для совместимости).
  • Error overlay: Next/Prev переключают ошибки; комбинация (comboDown) используется для подтверждения/закрытия (зависит от типа ошибки).
  • Slider: Next/Prev двигают значение (берётся из последнего pollInput(...)).
  • Graph pause (только 3-button режим): Select на экранах с графиком переключает паузу (см. раздел 15.4).
  • Auto screen-nav: при использовании loopWithInput(...) короткие Next/Prev переключают экраны через nextScreen()/prevScreen() когда не активны overlay/меню.

Если вы используете Next/Prev под кастомную логику на каком-то экране (и не хотите авто-переключения экранов), после своей обработки вызовите:

ui.consumeAutoNav();

11.3. Управление экранами

Эти методы управляют активным экраном и переходами между экранами.

ui.setScreen(ScreenHome);      // сразу переключает на указанный экран
ui.currentScreen();            // возвращает id текущего активного экрана
ui.nextScreen();               // переходит на следующий экран по порядку регистрации
ui.prevScreen();               // переходит на предыдущий экран по порядку регистрации (циклически)
ui.backScreen();               // возвращает назад по navigation-history
ui.screenTransitionActive();   // показывает, что переход между экранами сейчас ещё идёт

Что важно:

  • библиотека сама ведёт history переходов между экранами (для backScreen())
  • если экран меняется через setScreen(...), текущий экран добавляется в history автоматически

11.4. Принудительная перерисовка

ui.requestRedraw();

Нужно, когда данные экрана изменились вне обычного render-flow, и вы хотите гарантированно перерисовать следующий кадр.

11.5. Анимация переходов

ui.setScreenAnim(SlideX, 250);

setScreenAnim(mode, durationMs) задаёт стиль и длительность перехода между экранами.

Доступные режимы:

  • None - переход без анимации
  • SlideX - горизонтальный слайд
  • SlideY - вертикальный слайд

Code copied