227 lines
5.2 KiB
Markdown
227 lines
5.2 KiB
Markdown
# UI System
|
|
|
|
Source: `src/dusk/ui/`
|
|
|
|
See also: `.claude/display-spritebatch.md`, `.claude/display-text.md`,
|
|
`.claude/display-color.md`
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
The UI system renders overlaid interface elements on top of the scene
|
|
each frame. It is called by the engine after the scene render pipeline
|
|
and before the screen unbind -- game code does not drive it directly.
|
|
|
|
All UI elements render through the global SpriteBatch.
|
|
|
|
---
|
|
|
|
## Lifecycle
|
|
|
|
```c
|
|
extern ui_t UI;
|
|
|
|
errorret_t uiInit(void);
|
|
void uiUpdate(void);
|
|
errorret_t uiRender(void);
|
|
void uiDispose(void);
|
|
```
|
|
|
|
`uiUpdate` is called each game tick; `uiRender` is called each render
|
|
tick. The engine calls both automatically -- do not call them from
|
|
game scripts.
|
|
|
|
---
|
|
|
|
## Element registration (`uielement.h`)
|
|
|
|
```c
|
|
typedef struct {
|
|
uielementtype_t type; // UI_ELEMENT_TYPE_NULL or UI_ELEMENT_TYPE_NATIVE
|
|
errorret_t (*draw)(); // draw callback
|
|
} uielement_t;
|
|
|
|
extern uielement_t UI_ELEMENTS[]; // registered element array
|
|
```
|
|
|
|
`uiRender` iterates `UI_ELEMENTS` and calls each element's `draw`
|
|
callback. Elements register themselves during `uiInit`.
|
|
|
|
---
|
|
|
|
## Elements
|
|
|
|
### uiframe_t -- 9-slice border (`uiframe.h`)
|
|
|
|
A resizable bordered panel rendered using 9-slice (9-patch) technique
|
|
from a 3x3 tileset.
|
|
|
|
```c
|
|
typedef struct {
|
|
tileset_t tileset;
|
|
texture_t *texture;
|
|
} uiframe_t;
|
|
|
|
errorret_t uiFrameInit(uiframe_t *frame);
|
|
|
|
errorret_t uiFrameDraw(
|
|
const uiframe_t *frame,
|
|
const float_t x,
|
|
const float_t y,
|
|
const float_t width,
|
|
const float_t height
|
|
);
|
|
|
|
void uiFrameDispose(uiframe_t *frame); // does not dispose texture
|
|
```
|
|
|
|
`uiFrameDraw` pushes 9 quads (corners + edges + centre) to the
|
|
SpriteBatch without flushing. The caller must call `spriteBatchFlush()`
|
|
after all sprites for a draw pass are buffered.
|
|
|
|
---
|
|
|
|
### uitextbox_t -- typewriter dialogue box (`uitextbox.h`)
|
|
|
|
A global single-instance dialogue box that displays text one character
|
|
at a time with word-wrap and multi-page support.
|
|
|
|
```c
|
|
extern uitextbox_t UI_TEXTBOX;
|
|
|
|
errorret_t uiTextboxInit(void);
|
|
void uiTextboxDispose(void);
|
|
```
|
|
|
|
**Setting text:**
|
|
|
|
```c
|
|
uiTextboxSetText("Hello, world!");
|
|
// Automatically word-wraps and paginates.
|
|
// Resets currentPage and scroll to 0.
|
|
```
|
|
|
|
**Tick update (called from script `update` or uiUpdate):**
|
|
|
|
```c
|
|
uiTextboxUpdate();
|
|
// Advances typewriter by UI_TEXTBOX_SCROLL_CHARS_PER_TICK (1) each
|
|
// fixed tick. Skipped on dynamic sub-ticks.
|
|
```
|
|
|
|
**Page control:**
|
|
|
|
```c
|
|
bool_t uiTextboxPageIsComplete(void); // scroll revealed full page
|
|
bool_t uiTextboxHasNextPage(void); // more pages remain
|
|
void uiTextboxNextPage(void); // advance; no-op on last page
|
|
int32_t uiTextboxGetPageCharCount(void);
|
|
```
|
|
|
|
**Events:**
|
|
|
|
```c
|
|
// Fires when the current page is fully scrolled into view:
|
|
UI_TEXTBOX.onPageComplete
|
|
|
|
// Fires when the last page has been fully scrolled:
|
|
UI_TEXTBOX.onLastPage
|
|
```
|
|
|
|
Subscribe via the event system (see `.claude/events.md`).
|
|
|
|
**Limits:**
|
|
|
|
| Constant | Value |
|
|
|----------|-------|
|
|
| `UI_TEXTBOX_TEXT_MAX` | 1024 chars |
|
|
| `UI_TEXTBOX_LINES_MAX` | 64 lines |
|
|
| `UI_TEXTBOX_LINES_PER_PAGE_MAX` | 3 lines per page |
|
|
| `UI_TEXTBOX_SCROLL_CHARS_PER_TICK` | 1 char per tick |
|
|
|
|
---
|
|
|
|
### uifullbox_t -- full-screen colour overlay (`uifullbox.h`)
|
|
|
|
An animated solid-colour overlay that covers the entire screen. Used
|
|
for fade-to-black, scene transitions, and flash effects.
|
|
|
|
Two global instances are provided:
|
|
|
|
```c
|
|
extern uifullbox_t UI_FULLBOX_UNDER; // draws below scene content
|
|
extern uifullbox_t UI_FULLBOX_OVER; // draws above all content
|
|
```
|
|
|
|
```c
|
|
void uiFullboxInit(uifullbox_t *fullbox);
|
|
|
|
// Start a colour-to-colour transition:
|
|
void uiFullboxTransition(
|
|
uifullbox_t *fullbox,
|
|
color_t from,
|
|
color_t to,
|
|
float_t duration,
|
|
easingtype_t easing
|
|
);
|
|
|
|
void uiFullboxUpdate(uifullbox_t *fullbox, float_t delta);
|
|
errorret_t uiFullboxDraw(uifullbox_t *fullbox);
|
|
// Draw is skipped entirely when alpha == 0.
|
|
```
|
|
|
|
`fullbox.onTransitionEnd` event fires once when the transition
|
|
completes. Subscribe to it to chain scene transitions:
|
|
|
|
```c
|
|
// Typical fade-out before a scene change:
|
|
uiFullboxTransition(
|
|
&UI_FULLBOX_OVER,
|
|
COLOR_TRANSPARENT, COLOR_BLACK,
|
|
0.5f, EASING_OUT_QUAD
|
|
);
|
|
eventSubscribe(&UI_FULLBOX_OVER.onTransitionEnd, onFadeComplete, NULL);
|
|
```
|
|
|
|
---
|
|
|
|
### uiloading_t -- loading indicator (`uiloading.h`)
|
|
|
|
An animated loading indicator with fade-in / fade-out transitions.
|
|
Shown while asset batches are loading.
|
|
|
|
```c
|
|
extern uiloading_t UI_LOADING;
|
|
|
|
void uiLoadingInit(void);
|
|
void uiLoadingUpdate(float_t delta);
|
|
errorret_t uiLoadingDraw(void);
|
|
|
|
// Fade in; callback fires when fully visible:
|
|
void uiLoadingShow(eventcallback_t callback, void *user);
|
|
|
|
// Fade out; callback fires when fully hidden:
|
|
void uiLoadingHide(eventcallback_t callback, void *user);
|
|
```
|
|
|
|
`UI_LOADING_FADE_DURATION` is 0.5 seconds. `UI_LOADING_MARGIN` is 8px.
|
|
`uiLoadingDraw` is a no-op when the indicator is fully transparent.
|
|
|
|
---
|
|
|
|
### uifps_t -- FPS counter (`uifps.h`)
|
|
|
|
Debug FPS display. Measures real elapsed time between ticks and draws
|
|
the average frame rate as text in the corner of the screen.
|
|
|
|
```c
|
|
extern uifps_t UIFPS;
|
|
|
|
errorret_t uiFPSDraw(); // also performs the measurement update
|
|
```
|
|
|
|
Intended for debug builds only. Draw it explicitly from a JS `render`
|
|
hook or from a UI element -- it is not registered in `UI_ELEMENTS` by
|
|
default.
|