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

@ -31,9 +31,9 @@ function ct_activate(ui_st: mut UiState, n: UiNode) -> void {
function ct_step(ui_st: mut UiState, n: UiNode, d: int) -> void {
let t = ct_type(n)
if t == "select" and n.opts != null and len(n.opts) > 0 {
let at = (ct_option_at(n, n.opts) + d + len(n.opts)) % len(n.opts)
let ov = ui_attr(n.opts[at], "value")
if Value.kind(ov) == 0 { ct_change(ui_st, n, Value.int(at)) } else { ct_change(ui_st, n, ov) }
let from = ct_option_at(n, n.opts)
let at = ct_opt_step(n.opts, from, d) # past a disabled option
if at != from { ct_opt_pick(ui_st, n, n.opts, at) }
}
if t == "number" { ct_num_step(ui_st, n, d) }
if t == "range" {