Interactive GUI API — prototype
GUI 0.3 preparation adds separate auto-checkpointed gui.json state plus optional
Tabs, CheckboxGroup, HsvPicker, Theme, BoxLayout and ScrollPanel helpers,
plus native ui.theme and preview-only ui.keybind. See GUI_03_RU.md; existing primitives
and event/geometry limits below still apply.
Six controls are now supported in the script-owned portion of the own preview
window. This is not the planned package manager or editor. Layout uses explicit
logical coordinates and the default dark/orange or explicit frame-local palette.
bool ui::button(const string &in id, const string &in label,
float x, float y, float width, float height);
bool ui::checkbox(const string &in id, const string &in label, bool value,
float x, float y, float width, float height);
Both require render permission and are allowed only inside on_frame.
IDs must be nonempty, unique in a frame, ≤64 bytes, and contain lowercase ASCII
letters, digits, - or _. Labels: ≤128 bytes; width: 24–2048; height: 24–128.
Coordinates use the normal finite ±100000 limit.
Button returns true on an activation in the current snapshot, otherwise false.
Checkbox returns the supplied value, toggled on an activation. The script owns
state: assign the returned value to a script variable. Reload resets ordinary
script globals; configuration persistence remains an explicit separate API.
bool enabled = true;
void on_frame() {
if (ui::button("save", "Save", 24, 64, 180, 36)) runtime::log("pressed");
enabled = ui::checkbox("enabled", "Enabled", enabled, 24, 112, 220, 36);
}
Host input is restricted to its own preview window. A click is generated after
left-button down/up on the same widget. Last drawn overlapping widget wins.
Release outside, lost mouse capture or lost focus cancels the pending press.
Input is DPI-adjusted. The pending queue is limited to 12 activations; excess
are dropped. Events enter the next host snapshot as ui.click:<id> strings,
also visible to on_event. Duplicates for one ID coalesce to one activation
per snapshot. IDs unknown to the script have no effect and are not retained.
RC11 adds ui::slider and ui::cycle using the same render permission, stable
IDs, explicit layout and script-owned state. Full signatures and range/step
semantics: EXTENSIONS_RU.md. Cycle is not a dropdown. Slider updates while
dragging, coalescing events for one ID into ui.value:<id>:<0..10000> in the
next snapshot. The normalized integer is mapped to its declared range/step by
the worker, not by arbitrary code executed in the UI thread. Values expire
after their snapshot; malformed/unknown values are ignored. Pending values
are cancelled on lost focus/capture. Controls remain preview-local.
RC17 adds a single-line UTF-8 text field:
string ui::textbox(const string &in id,const string &in label,
const string &in value,uint max_bytes,
float x,float y,float width,float height);
Assign the returned string to your script variable. Requires render/on_frame,
the same ID/geometry rules and a byte limit of 1–128. Existing values outside
the declared limit fail rather than silently truncate. Invalid UTF-8, control
characters and line breaks are rejected. Height >=44 shows the label above
the value; a smaller field shows only the value. Text is clipped to its bounds.
Click the field in the own preview, then type; Backspace removes the last
Unicode code point. Enter blurs and keeps queued edits. Escape cancels pending
edits and blurs; another Escape closes the preview. Switching widgets commits
already queued edits. Focus loss, hiding/removing/changing the field limit or
Reload cancels undelivered input. Already delivered edits are not rolled back.
Input drafts survive older in-flight frames. UTF-16 surrogate pairs become
UTF-8; isolated surrogates are ignored. Changes coalesce as ui.text:<id>:<text>
with the full current value; only the first separator after the ID is structural.
Text events expire after their snapshot, including when the widget is hidden.
The shared 12-event queue may drop new edits if full; it never grows unbounded.
This is append-at-end text entry, not a full editor: no caret navigation,
selection, clipboard paste, IME composition or password masking. Do not enter
secrets; event content is visible to the script's on_event callback. While a
field is focused its local draft drives subsequent keystrokes; external script
changes should blur/hide it before setting a new value. A click-through game
overlay does not accept text input. No global hooks or game input are added.
Example: sdk/templates/text-form, usable without storage consent.
Prototype limits: no full keyboard navigation, hover/pressed styling,
disabled states, automatic layout or accessibility API.
RC18 adds explicit wheel scroll regions and nested clipping (drawing and hit
testing), plus cancellation for fully clipped textbox/slider input. See SCROLL_RU.md.
Automatic layout, scrollbar dragging and full keyboard navigation remain absent.
The preview session now stays open until closed, unless a frame/time limit is
specified. run has no input; stream accepts
input only from its trusted native host. No global/game input API was added.
Demo: examples/interactive/main.as. Launch:
./bin/EasyUniversal.exe preview ./examples/interactive --capture ./build/interactive.png
./tests/gui.ps1