Fill the gaps the chapter 22 weaker-model reader found
The AGENTS.md "Testing a Tutorial" pass: chapter 22 was handed to a reader on a weaker model with the library tree stripped of examples/ and docs/, and they had to build a menu/HUD/dialog program from the chapter alone. They built one that compiled and ran -- and reported success their own screenshots disproved, which is why the protocol says to verify: their synthesized key events set only the scancode, akgl_ui_menu_handle_event matches keycodes, and their program never actually left the title screen. With that one line fixed, everything they had built from the chapter worked. Three findings survived verification against eight reported: - The chapter never stated its prerequisites, so the reader burned most of the session on library bring-up it does not cover and invented goto error handling for main(). A new "What this chapter assumes" paragraph points at chapters 3, 7 and 17, and at the demo's startup() and main() as the complete reference. - Nothing named the menu's exact keys, or that they are keycodes rather than scancodes -- invisible with a real keyboard, fatal for synthesized events, which the demo's own --demo script teaches. The menus section now names SDLK_UP/DOWN/RETURN, the gamepad buttons, and the key.key trap. - Verifying their dialog screenshot showed a message wrapping past the fixed AKGL_UI_DIALOG_HEIGHT runs visibly out of the panel. Deliberate -- same as the hand-rolled textbox, and visible overflow beats silent truncation -- but undocumented; akgl_ui_dialog's header note now says so. Rejected for the record, per protocol: akgl_game_init already initializes the property registry (src/game.c:219), and the font they "found" in a different directory was the build tree's file(COPY) of tests/assets. Co-Authored-By: Claude Code (Claude Fable 5, claude-fable-5) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KzBDV2fqgnUAcqCKqKvc71
This commit is contained in:
@@ -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