diff --git a/README.md b/README.md index 5e707e1..76468ad 100644 --- a/README.md +++ b/README.md @@ -31,23 +31,51 @@ graph LR ``` -## 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) -- 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 +### Supported (v0.2.0) -**Intentional non-goals (deferred):** -- Multi-widget z-order / stacking panels -- Always-on HUD widgets (non-modal overlays) -- Keyboard navigation within widgets -- Panel animation (fade in / out) -- Screen-size from engine (no Lua-accessible get_screen_size; v0.1 falls back to 1280x720 constants matching default Sporel window config) +- Multi-active panels: multiple windows open simultaneously, each + rendered + hit-tested independently. +- 11 layout-slot templates (center, left, right, top, bottom, four + corners, left-half, right-half) for common positioning. +- Custom layout-fn hook `function(sw, sh) -> {x,y,w,h}` for bespoke + 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 @@ -85,8 +113,9 @@ string. Loud-error on duplicate `widget_id` or missing required fields. **Syntax:** `panel.unregister(widget_id: string) -> void` -Removes the widget from the registry. If the widget is currently active, -closes the panel (sets active to nil, clears any open context-menu). +Removes the widget from the registry. If the widget is currently open, +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 `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?)` @@ -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, 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). --- @@ -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 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 `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. Both receive a `ctx` table: @@ -347,7 +380,7 @@ ctx = { h = number, -- content area height }, 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) } ```