Add the akgl_ui subsystem: clay-backed menus, HUDs and dialogs #3
@@ -28,6 +28,15 @@ declarative blocks yourself between the same two frame calls, with the whole DSL
|
||||
available. The demo this chapter quotes, [`examples/uidemo`](../examples/uidemo), does
|
||||
both: its title menu and HUD are widgets, its options screen is raw `CLAY()`.
|
||||
|
||||
**What this chapter assumes.** A program that already brings libakgl up — the
|
||||
`akgl_game_init` startup order from [Chapter 7](07-the-game-and-the-frame.md) (or
|
||||
[Chapter 3](03-getting-started.md)'s smallest window), plus one loaded font from
|
||||
[Chapter 17](17-text-and-fonts.md). None of that is restated here, and the UI adds only
|
||||
three calls to it, shown below. When something in *your* bring-up fights you, the demo's
|
||||
`startup()` in [`examples/uidemo/uidemo.c`](../examples/uidemo/uidemo.c) is the complete
|
||||
working sequence to diff against — including the `main()` shape, which the runnable
|
||||
snippets in this manual deliberately hide.
|
||||
|
||||
Like collision, the subsystem is optional at runtime rather than at build time: it is
|
||||
always compiled in, costs static storage until `akgl_ui_init` runs, and a game that
|
||||
never calls that pays nothing else.
|
||||
@@ -242,8 +251,13 @@ static akgl_UiMenu title_menu = {
|
||||
Declaring it each frame is `akgl_ui_menu(&title_menu)`. Input reaches it two ways, and
|
||||
they meet in the same struct: `akgl_ui_menu_handle_event` moves `selected` from the
|
||||
arrow keys and D-pad (wrapping at both ends) and sets `activated` on Return or gamepad
|
||||
South; the mouse selects by *moving onto* a row and activates by clicking one, during
|
||||
the declaration itself. A stationary pointer claims nothing — parking the mouse over the
|
||||
South — exactly `SDLK_UP`, `SDLK_DOWN` and `SDLK_RETURN` against `SDL_Event.key.key`,
|
||||
and `SDL_GAMEPAD_BUTTON_DPAD_UP`, `_DPAD_DOWN` and `_SOUTH` against
|
||||
`SDL_Event.gbutton.button`. Keycodes, not scancodes — which only matters when you
|
||||
*synthesize* events, as the demo's `--demo` script does: a hand-built key event must
|
||||
fill in `key.key`, or it matches nothing and the menu silently ignores it. The mouse
|
||||
selects by *moving onto* a row and activates by clicking one, during the declaration
|
||||
itself. A stationary pointer claims nothing — parking the mouse over the
|
||||
menu must not pin the selection against the keyboard, which would otherwise fight it
|
||||
sixty times a second and lose.
|
||||
|
||||
|
||||
@@ -391,6 +391,13 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_ui_frame_end(akgl_RenderBackend *self);
|
||||
* -- clay keeps the pointer, not a copy. May be empty, which
|
||||
* draws an empty panel.
|
||||
* @param style Look to draw with, or `NULL` for the textbox palette.
|
||||
*
|
||||
* @note The panel's height is fixed at #AKGL_UI_DIALOG_HEIGHT and the text is
|
||||
* not clipped to it: a message that wraps to more lines than fit runs
|
||||
* past the bottom border, visibly. That is the same behaviour as the
|
||||
* hand-rolled panel this widget mirrors, and it is deliberate --
|
||||
* overflow you can see beats truncation you cannot. Size the height for
|
||||
* your longest message, or raise the override.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER If @p id or @p text is `NULL`.
|
||||
* @throws AKGL_ERR_UI If the subsystem is not initialized or no frame is
|
||||
|
||||
Reference in New Issue
Block a user