- 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>
55 lines
2.1 KiB
Text
55 lines
2.1 KiB
Text
# ui_select_disabled.ludic - <option disabled="{...}">: a value on a disabled option is set to the
|
|
# nearest enabled one, the arrow toward disabled options is drawn disabled, and the arrows step past
|
|
# them (a host's cap on the fog): clamped 2 next-on 0 next 0 prev 2
|
|
import "ludic.ui"
|
|
program UiSelectDisabled {
|
|
numbers float
|
|
state SelState { v: int = 4 }
|
|
view V (sel_st: mut SelState) {
|
|
v = sel_st.v
|
|
on set(x: int) { sel_st.v = x }
|
|
}
|
|
const PAGE: string = "<ui><screen name='s'><select label='Fog' value='{v}' on-change='set(event.value)'><option value='{0}'>0</option><option value='{1}'>1</option><option value='{2}'>2</option><option value='{3}' disabled='{v >= 0}'>3</option><option value='{4}' disabled='{true}'>4</option></select></screen></ui>"
|
|
function frame(ui_st: mut UiState, x: float, y: float, down: bool) -> UiNode {
|
|
let i = new UiInput
|
|
i.x = x
|
|
i.y = y
|
|
i.down = down
|
|
ui_input(ui_st, i)
|
|
ui_show(ui_st, "s", view_v(), 0.0, 0.0, 400.0, 400.0)
|
|
let root: UiNode = ui_nodes(ui_st, "s", view_v())
|
|
ui_place(ui_st, root, 0.0, 0.0, 400.0, 400.0)
|
|
return root
|
|
}
|
|
function part(n: UiNode, cls: string) -> UiNode {
|
|
for i in 0 .. len(n.children) {
|
|
if List.contains(n.children[i].classes, cls) { return n.children[i] }
|
|
let f = part(n.children[i], cls)
|
|
if f != null { return f }
|
|
}
|
|
return null
|
|
}
|
|
function click(ui_st: mut UiState, cls: string) -> void {
|
|
let root = frame(ui_st, -1.0, -1.0, false)
|
|
let p = part(root, cls)
|
|
let x = p.x + p.cw / 2.0
|
|
let y = p.y + p.ch / 2.0
|
|
frame(ui_st, x, y, false)
|
|
frame(ui_st, x, y, true)
|
|
frame(ui_st, x, y, false)
|
|
frame(ui_st, x, y, false)
|
|
}
|
|
entry (ui_st: mut UiState, sel_st: SelState) {
|
|
ui_backend(ui_st, new UiBackend)
|
|
ui_load_text(ui_st, PAGE, "s.xml")
|
|
frame(ui_st, -1.0, -1.0, false)
|
|
let root = frame(ui_st, -1.0, -1.0, false)
|
|
let clamped = sel_st.v
|
|
let nx = part(root, "ui-next")
|
|
let at_cap = `{nx.enabled}`
|
|
click(ui_st, "ui-next")
|
|
let wrapped = sel_st.v
|
|
click(ui_st, "ui-prev")
|
|
print(`clamped {clamped} next-on {at_cap} next {wrapped} prev {sel_st.v}`)
|
|
}
|
|
}
|