docs: README cleanup for v0.2.0 multi-active model

- Rewrite §Scope from v0.1.0 to v0.2.0: lists multi-active +
  layout-slots as supported; restages deferred items per phase.
- Replace "active" with "open"/"focused" in API prose for
  unregister + update + render (no scalar `active` exists in
  v0.2.0).
- Add cross-ref under panel.open noting the v0.2.0 behavioral
  change (open does not auto-close other panels).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Calic
2026-06-15 01:57:02 +02:00
parent 0d21d8abec
commit cdf1f63895

View File

@@ -31,23 +31,51 @@ graph LR
``` ```
<!-- topology:end --> <!-- topology:end -->
## Scope (v0.1.0) ## Scope (v0.2.0)
v0.1 ships a minimal single-active-widget panel system: v0.2.0 ships multi-active panels with layout-slot positioning,
preserving full backward-compatibility with v0.1.1's single-active
callers via shim semantics. The lib is the generic UI-Framework
substrate — domain-free per ADR-0001/ADR-0049, consumed by Display-
Libs (inventory-list-display, crafting-display, notify-display) and
modules (vagrant-skeleton).
- Widget registry (register / unregister / open / close / toggle) ### Supported (v0.2.0)
- Theme system (13 configurable keys, capability-by-declaration guard)
- Per-frame update with edge-detected mouse click + wheel dispatch
- Context-menu (show, auto-reposition to screen bounds, hit-test, auto-close)
- Default-trigger key binding via lib-core.input (lazy-required)
- pause_on_open flag for game-pause gating
**Intentional non-goals (deferred):** - Multi-active panels: multiple windows open simultaneously, each
- Multi-widget z-order / stacking panels rendered + hit-tested independently.
- Always-on HUD widgets (non-modal overlays) - 11 layout-slot templates (center, left, right, top, bottom, four
- Keyboard navigation within widgets corners, left-half, right-half) for common positioning.
- Panel animation (fade in / out) - Custom layout-fn hook `function(sw, sh) -> {x,y,w,h}` for bespoke
- Screen-size from engine (no Lua-accessible get_screen_size; v0.1 falls back to 1280x720 constants matching default Sporel window config) positioning (HUD elements, status displays, custom tool UIs).
- Bw-Compat-Shim: v0.1.1 `register(id, widget)` ohne opts works
unchanged; `close()`/`is_open()` ohne arg map to focused = last-
opened.
- Theme system: shared theme via `set_theme`/`get_theme` (unchanged).
- Context-menu via `show_context_menu` (unchanged).
- Default-trigger key-binding via `bind_default_trigger` (unchanged).
### Deferred (v0.3.0+)
- Z-order tiers (hud / normal / top) for layered rendering.
- Persistent windows (always-open, exempt from ESC-close).
- Input-block modes (none/self/all) for pass-through vs modal capture.
- Map-editor-style multi-region UI as first-class persistent widgets.
### Deferred (v0.4.0+)
- Click-to-focus and explicit focus()/raise()/lower() API.
- Drag-by-title-bar (draggable opt).
- Resize-by-corner (resizable opt).
- min/max-size constraints + screen-clamp.
### Deferred (post-v0.4.0)
- Window-decoration themes (per-window title-bar styles).
- Touch/mobile input adaptation.
- Window animations (slide-in, fade-in).
- Window groups / tabbed-windows / MDI parent-child hierarchies.
- Save/load of window-bounds across sessions.
## API ## API
@@ -85,8 +113,9 @@ string. Loud-error on duplicate `widget_id` or missing required fields.
**Syntax:** `panel.unregister(widget_id: string) -> void` **Syntax:** `panel.unregister(widget_id: string) -> void`
Removes the widget from the registry. If the widget is currently active, Removes the widget from the registry. If the widget is currently open,
closes the panel (sets active to nil, clears any open context-menu). closes it first (removes from open_order; clears any open context-menu
if it was the last open window).
--- ---
@@ -99,6 +128,10 @@ Opens `widget_id`. The window is pushed onto the top of `open_order`
already open, it is brought to the front (re-focused). Loud-error if already open, it is brought to the front (re-focused). Loud-error if
`widget_id` has not been registered. `widget_id` has not been registered.
**v0.2.0 change:** `open(id)` no longer closes other open panels.
Multiple panels can be visible simultaneously. See §Bw-Compat Guarantee
below for the migration recipe.
--- ---
### `panel.close(widget_id?)` ### `panel.close(widget_id?)`
@@ -191,7 +224,7 @@ module-load-time cycles. Loud-error if `widget_id` is not registered.
Must be called each game-update frame. Checks the default trigger key, Must be called each game-update frame. Checks the default trigger key,
reads mouse state, emits edge-detected click events (left and right reads mouse state, emits edge-detected click events (left and right
independently), and dispatches wheel events. No-ops if no widget is active independently), and dispatches wheel events. No-ops if no panels are open
(but still tracks mouse state to avoid spurious edges on next open). (but still tracks mouse state to avoid spurious edges on next open).
--- ---
@@ -202,7 +235,7 @@ independently), and dispatches wheel events. No-ops if no widget is active
Must be called each render frame (inside the engine render phase). Draws Must be called each render frame (inside the engine render phase). Draws
the panel background, border, and title, then invokes `widget_def.render(ctx)`. the panel background, border, and title, then invokes `widget_def.render(ctx)`.
If a context-menu is open, renders it on top. No-op if no widget is active. If a context-menu is open, renders it on top. No-op if no panels are open.
--- ---
@@ -333,7 +366,7 @@ If you relied on the v0.1.1 "open(B) closes A" behavior, call
## Widget-Lifecycle-Contract ## Widget-Lifecycle-Contract
Widget `render(ctx)` is called each render frame while the widget is active. Widget `render(ctx)` is called each render frame while the widget is open.
Widget `handle_input(ctx, event)` is called for each dispatched input event. Widget `handle_input(ctx, event)` is called for each dispatched input event.
Both receive a `ctx` table: Both receive a `ctx` table:
@@ -347,7 +380,7 @@ ctx = {
h = number, -- content area height h = number, -- content area height
}, },
theme = table, -- current merged theme (read-only by convention) theme = table, -- current merged theme (read-only by convention)
is_focused = bool, -- true when this widget is the active one is_focused = bool, -- true when this widget is the focused one (last-opened)
} }
``` ```