PixelUI provides Popups for short messages, progress editing, text entry, and fixed-width integer input. Applications open them through the PixelUI::showPopup...() functions.
Information Popup
1 | if (!ui.showPopupInfo("Saved", "Settings", 80, 30, 1500)) { |
Multi-tap keyboard Popup
The keyboard Popup uses phone-style multi-tap input and stores its draft in a caller-provided character buffer. The buffer remains valid throughout queueing and display, and its capacity includes the terminating \0.
1 | // name_ is an App member that covers the complete pending and active lifetime. |
Repeated presses of one numeric key cycle through its candidate characters. A pause of about 800 ms starts a new character. DELETE removes the last character, OK commits the draft and invokes the callback, and BACK or timeout cancels the edit. The default layout requires at least 100x58 pixels and must fit within the display.
Progress Popup
The int32_t& overload uses step 1, percentage formatting, and CommitOnConfirm editing:
1 | int32_t progress_ = 0; // persistent App member |
Select percentage, raw, scaled, or unit-bearing text through NumericFormatter.
For a configurable step or live editing, keep the range and formatter configuration as persistent members:
1 | NumericRange progressRange_{}; |
Progress input follows the edit policy explicitly:
| Input | CommitOnConfirm |
Live |
|---|---|---|
| LEFT/RIGHT | Change only the draft by range.step() |
Write and notify after each successful step |
| SELECT | Write and notify if changed, then close | Close without an extra notification |
| BACK | Discard the draft and close | Restore and notify the original value if changed, then close |
If a binding write fails, the Popup stays open and keeps a consistent draft. See Numeric values for the session contract.
Fixed-width integer input
1 | int32_t setpoint = 25; |
Construction and queueing leave setpoint unchanged. The digit count may range from 1 to PIXELUI_MAX_INT_FIXED_WIDTH.
The editor has two levels of interaction. Focus moves among every digit, OK, and CANCEL. Selecting a digit enters that digit’s local edit mode; selecting it again leaves only that local mode and keeps the Popup open.
| State and input | Result |
|---|---|
| Focused digit + SELECT | Enter local digit editing |
| Active digit + LEFT/RIGHT | Change only that digit |
| Active digit + SELECT | Finish that digit and keep the Popup open |
| OK + SELECT | Commit the combined value and close |
| CANCEL + SELECT, or BACK anywhere | Cancel the whole session and close |
Timeout, clearPopups(), or destruction |
Cancel an unfinished session |
The int32_t& overload uses CommitOnConfirm: its callback runs once when OK commits a changed combined value. CANCEL and BACK finish without invoking the callback. With the ValueEditorBinding overload and ValueEditPolicy::Live, each successful digit change writes and notifies immediately; every cancellation path restores and notifies the original value if it changed.
The default layout is 100x56. The minimum height is 56; the minimum width is computed from the wider of the digit row and the OK/CANCEL action row. Layout validation rejects requests below those limits or beyond the actual display before enqueueing. A 96x40 display therefore requires a different input design.
Always check the return value. false means the binding, digit count, requested layout, display bounds, queue capacity, or protected-dispatch state rejected the request. true means only that the request was accepted; non-owning data must still survive its pending and active lifetime.
Queue and capacity
PopupManager is a fixed-capacity FIFO:
1 | active Popup -> pending request 1 -> pending request 2 |
- Only the active Popup is constructed, drawn, and receives input.
- Pending entries are validated type-specific
etl::variant<InfoRequest, ProgressRequest, ValueDigitsRequest>descriptors, processed in arrival order. PIXELUI_MAX_POPUP_NUMincludes the active and pending Popups.- Requests use arrival order without priority or preemption. A full queue returns
falsefor a new request. - The active Popup lives in a single-slot
etl::variant_pool. It is destroyed before the next Popup is constructed in the same stable slot. - A request callback moves through the queue and into the active Popup.
- Destroying a Popup stops its own animations and preserves unrelated App animations.
Lifetime and reentrancy
Text/title/font pointers, binding contexts, formatter contexts and referenced suffix/range objects, injected sessions, and references captured by callbacks are non-owning. Their required lifetime covers both pending and active use.
Popping an App clears its active and pending Popups. Call clearPopups() earlier when data belongs to a shorter-lived owner.
PopupManager rejects enqueue and clear operations while constructing, destroying, updating, drawing, or dispatching input. Callbacks can record a pending action and perform it after the current dispatch returns. Ordinary consecutive calls outside protected dispatch remain FIFO while capacity is available.



