ludic.ui: <option disabled="{...}"> - a select steps past it, clamps off it and greys the arrow toward it

- The arrows, a press on the select and the pad step past a disabled option (ct_opt_step), wrapping
  as before.
- A value naming a disabled option is shown as the nearest enabled one (the lower of two as near) and
  set to it once the build is done: an event fired while the tree is built is cleared with the frame's,
  so the clamp is queued (ct_clamp_n / _i) and fired after nt_fired_clear.
- The < or > whose next option is disabled is drawn disabled (its part's :disabled), so a cycler shows
  where the options stop being on; it still steps past them.
- ct_build_select moves to controls_opts.ludic with the rest (controls_build.ludic 119 -> 104 lines).

Golden ui_select_disabled: options 3 and 4 disabled, a value of 4 clamps to 2, > is drawn disabled
there, > wraps to 0 and < from 0 steps back to 2. The 38 ui examples pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-29 16:01:43 +03:00
parent 6af48afdda
commit 181d317d20
8 changed files with 140 additions and 18 deletions

View file

@ -67,21 +67,6 @@ function ct_build_range(ui_st: mut UiState, n: UiNode) -> void {
ui_kept(n.children, track)
ui_kept(n.children, ct_part(ui_st, n, "ui-value", ct_value_shown(ui_st, n)))
}
function ct_build_select(ui_st: mut UiState, n: UiNode) -> void {
@alloc_ok("once per pooled node: its list is kept and cleared")
if n.opts == null { n.opts = new []UiNode } # its options moved to a list the node keeps, not a new one
let opts = n.opts
List.clear(opts)
for i in 0 .. len(n.children) { ui_kept(opts, n.children[i]) }
List.clear(n.children)
ct_label(ui_st, n)
var shown = ""
let at = ct_option_at(n, opts)
if at >= 0 { shown = opts[at].text }
ui_kept(n.children, ct_part(ui_st, n, "ui-prev", "<"))
ui_kept(n.children, ct_part(ui_st, n, "ui-value", shown))
ui_kept(n.children, ct_part(ui_st, n, "ui-next", ">"))
}
# which option the select's value names: an option's value="...", else its place
function ct_option_at(n: UiNode, opts: []UiNode) -> int {
let nv = ui_attr(n, "value")