ui-preview: hold <id or key> <pseudo> - hover, active, focus, focus-visible, checked or disabled held on from the next frame on top of the real input, by the element's key (so through model and load), let go with "" or reset; ludic.ui's held.ludic keeps them and the matcher asks it first; protocol-v1.md and smoke.txt
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3d5aaa6f6e
commit
aac58ec6fa
10 changed files with 122 additions and 1 deletions
21
tools/ui-preview/cmd_hold.ludic
Normal file
21
tools/ui-preview/cmd_hold.ludic
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# cmd_hold.ludic - `hold <id or key> <pseudo>`: a pseudo-class held on for an element from the next frame,
|
||||
# on top of the real input (ludic.ui's held.ludic); "" as the pseudo lets that element's holds go, and
|
||||
# "" "" every hold. Holds are by the element's key, so they survive `model` and `load`; `reset` clears.
|
||||
function pv_hold(ui_st: mut UiState, w: []string) -> string {
|
||||
if len(w) < 3 { return "hold: <id or key> <hover|active|focus|focus-visible|checked|disabled>, \"\" to let go" }
|
||||
let id = pv_text(w[1])
|
||||
let pseudo = pv_text(w[2])
|
||||
if id == "" {
|
||||
if pseudo != "" { return "hold: a pseudo-class needs an element" }
|
||||
ui_hold_clear(ui_st, "")
|
||||
return ""
|
||||
}
|
||||
let n = ui_find(ui_st, id)
|
||||
if n == null { return `no element {id}` }
|
||||
if pseudo == "" {
|
||||
ui_hold_clear(ui_st, n.key)
|
||||
return ""
|
||||
}
|
||||
if not ui_hold(ui_st, n.key, pseudo) { return `hold: {pseudo} cannot be held (hover, active, focus, focus-visible, checked, disabled)` }
|
||||
return ""
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ function pv_run(pv: mut PvState, ui_st: mut UiState, i18n_st: mut I18nState, w:
|
|||
if c == "hello" { pv.ok_more = pv_hello(pv) } else if c == "quit" {
|
||||
pv_end(pv, "")
|
||||
return false
|
||||
} else if c == "frame" { why = pv_frame(pv, ui_st, w) } else if c == "load" { why = pv_load(pv, ui_st, w) } else if c == "model" { why = pv_story_cmd(pv, w, false) } else if c == "calls" { why = pv_story_cmd(pv, w, true) } else if c == "show" { why = pv_show(pv, ui_st, w) } else if c == "native" { why = pv_native(pv, ui_st, w) } else if c == "input" { why = pv_input(pv, w) } else if c == "viewport" { why = pv_viewport(pv, w) } else if c == "font" { why = pv_font_cmd(pv, w) } else if c == "locale" { why = pv_locale(pv, i18n_st, w) } else if c == "atlas" { why = pv_atlas(pv, w) } else if c == "image" { why = pv_image_cmd(pv, w) } else if c == "file" { why = pv_file(pv, ui_st, w) } else if c == "tree" { why = pv_tree(pv, ui_st) } else if c == "box" { why = pv_id_cmd(pv, ui_st, w, false) } else if c == "rules" { why = pv_id_cmd(pv, ui_st, w, true) } else if c == "reset" { why = pv_reset(pv, ui_st) } else { why = `unknown request {c}` }
|
||||
} else if c == "frame" { why = pv_frame(pv, ui_st, w) } else if c == "load" { why = pv_load(pv, ui_st, w) } else if c == "model" { why = pv_story_cmd(pv, w, false) } else if c == "calls" { why = pv_story_cmd(pv, w, true) } else if c == "show" { why = pv_show(pv, ui_st, w) } else if c == "native" { why = pv_native(pv, ui_st, w) } else if c == "input" { why = pv_input(pv, w) } else if c == "viewport" { why = pv_viewport(pv, w) } else if c == "font" { why = pv_font_cmd(pv, w) } else if c == "locale" { why = pv_locale(pv, i18n_st, w) } else if c == "atlas" { why = pv_atlas(pv, w) } else if c == "image" { why = pv_image_cmd(pv, w) } else if c == "file" { why = pv_file(pv, ui_st, w) } else if c == "tree" { why = pv_tree(pv, ui_st) } else if c == "box" { why = pv_id_cmd(pv, ui_st, w, false) } else if c == "rules" { why = pv_id_cmd(pv, ui_st, w, true) } else if c == "reset" { why = pv_reset(pv, ui_st) } else if c == "hold" { why = pv_hold(ui_st, w) } else { why = `unknown request {c}` }
|
||||
pv_end(pv, why)
|
||||
return true
|
||||
}
|
||||
|
|
@ -67,6 +67,7 @@ function pv_frame(pv: mut PvState, ui_st: mut UiState, w: []string) -> string {
|
|||
}
|
||||
# `reset`: the root's template state and instances forgotten, as a screen shown for the first time
|
||||
function pv_reset(pv: mut PvState, ui_st: mut UiState) -> string {
|
||||
ui_hold_clear(ui_st, "")
|
||||
if pv.root != "" { ui_forget(ui_st, pv.root) }
|
||||
return ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ program UiPreview {
|
|||
import "input.ludic"
|
||||
import "input_keys.ludic"
|
||||
import "inspect.ludic"
|
||||
import "cmd_hold.ludic"
|
||||
import "computed.ludic"
|
||||
import "cmd_load.ludic"
|
||||
import "cmd_world.ludic"
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ A template error is NOT a `fail`: the request succeeded and the error is reporte
|
|||
| `native <text tag> [<num w> <num h>]` | none. `<tag>` becomes an element the game draws itself: laid out with that content size in design pixels (default 0 0), drawn as a `native` line. Declare natives before the templates that use them are loaded |
|
||||
| `atlas <text prefix> <text name> <int cols> <int rows> [<json list of names>]` | none. `<img src="prefix:cell">` is a cell of atlas `name`: a `cols` x `rows` grid, cells numbered row by row from 0, named by the list (a cell is also reachable by its number) |
|
||||
| `image <text path> <num w> <num h>` | none. A picture's natural size in pixels, for `object-fit`; an undeclared picture has none (it fills its box) |
|
||||
| `hold <text id or key> <text pseudo>` | none, or `fail "no element …"`. Holds a pseudo-class on for that element from the next frame, on top of the real input: `hover`, `active`, `focus`, `focus-visible` (which is `focus` too), `checked`, `disabled`. `""` as the pseudo lets go of that element's holds; `hold "" ""` lets go of every hold. Holds are by the element's key, so they survive `model` and `load`; `reset` clears them. `tree`, `box` and `rules` answer as if the pseudo-class were real: `rules` lists the `:hover` / `:focus` rules it makes match. Added in v1 (a host without it answers `fail "unknown request hold"`) |
|
||||
| `file <text path> <text contents>` | none. Reading `path` gives these contents (an imported stylesheet, a `.po`) instead of the disk's, until replaced; every class re-reads its styles at its next show |
|
||||
| `input pointer <num x> <num y> <int buttons>` | none. Held until changed. Screen pixels; buttons is a mask: 1 left, 2 right, 4 middle |
|
||||
| `input wheel <num d>` | none. Added to the next frame's wheel only |
|
||||
|
|
|
|||
|
|
@ -168,6 +168,45 @@
|
|||
< "dem Nordbecken"
|
||||
<= ok
|
||||
|
||||
# hold: a pseudo-class held on without input - the :hover rule draws from the next frame, rules lists
|
||||
# it, and letting go puts the plain background back
|
||||
> load "Hov" "<row><button id=\"b\" class=\"b\">Go</button></row>" ".b { background: #0000ff; }\n.b:hover { background: #00ff00; }"
|
||||
<= ok
|
||||
|
||||
> show "Hov"
|
||||
<= ok
|
||||
|
||||
> frame 0
|
||||
< #0000ff
|
||||
<! #00ff00
|
||||
<= ok
|
||||
|
||||
> hold "b" "hover"
|
||||
<= ok
|
||||
|
||||
> frame 1
|
||||
< #00ff00
|
||||
<= ok
|
||||
|
||||
> rules "b"
|
||||
< ".b:hover"
|
||||
<= ok
|
||||
|
||||
> hold "nothing" "hover"
|
||||
<= fail "no element nothing"
|
||||
|
||||
> hold "b" "wobble"
|
||||
< fail
|
||||
<= fail "hold: wobble cannot be held (hover, active, focus, focus-visible, checked, disabled)"
|
||||
|
||||
> hold "" ""
|
||||
<= ok
|
||||
|
||||
> frame 2
|
||||
< #0000ff
|
||||
<! #00ff00
|
||||
<= ok
|
||||
|
||||
> frobnicate
|
||||
<= fail "unknown request frobnicate"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue