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
|
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()`.
|
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
|
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
|
always compiled in, costs static storage until `akgl_ui_init` runs, and a game that
|
||||||
never calls that pays nothing else.
|
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
|
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
|
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
|
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
|
South — exactly `SDLK_UP`, `SDLK_DOWN` and `SDLK_RETURN` against `SDL_Event.key.key`,
|
||||||
the declaration itself. A stationary pointer claims nothing — parking the mouse over the
|
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
|
menu must not pin the selection against the keyboard, which would otherwise fight it
|
||||||
sixty times a second and lose.
|
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
|
* -- clay keeps the pointer, not a copy. May be empty, which
|
||||||
* draws an empty panel.
|
* draws an empty panel.
|
||||||
* @param style Look to draw with, or `NULL` for the textbox palette.
|
* @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.
|
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||||
* @throws AKERR_NULLPOINTER If @p id or @p text is `NULL`.
|
* @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
|
* @throws AKGL_ERR_UI If the subsystem is not initialized or no frame is
|
||||||
|
|||||||
Reference in New Issue
Block a user