ludic/examples/library/ui_react.ludic

61 lines
3.1 KiB
Text

# ui_react.ludic — ludic.ui's React side without a renderer: keyed lists keep each item's state when
# the list is reordered, <let> names a value, context reaches through a component, named slots,
# on-mount and on-unmount, and a native element of the program's own firing on-change with a value.
import "ludic.ui"
program UiReact {
numbers float
state UireactState {
names: []string = new []string
volume: int = 3
mounted: int = 0
unmounted: int = 0
show_extra: bool = true
}
view Mixer (uireact_st: mut UireactState) {
names = uireact_st.names
volume = uireact_st.volume
extra = uireact_st.show_extra
on set_volume(v: int) { uireact_st.volume = v }
on mount() { uireact_st.mounted += 1 }
on unmount() { uireact_st.unmounted += 1 }
}
# a dial the program draws itself: it measures 40 square and, pressed, turns up by one
function dial_measure(n: UiNode, avail: float) -> void {
n.mw = 40.0
n.mh = 40.0
}
function dial_draw(n: UiNode) -> void { }
const PAGE: string = "<ui>\n<component name='Card'>\n <div class='card'><h3><slot name='title'/></h3><slot/><p>{theme}</p></div>\n</component>\n<component name='Item'>\n <state taps='{0}'/>\n <button on-click='set taps = taps + 1'>{label} {taps}</button>\n</component>\n<screen name='mix'>\n <let loud='{volume > 5}'/>\n <provide theme='dark'>\n <Card>\n <template slot='title'>Mixer</template>\n <fragment><p>{loud ? 'loud' : 'quiet'}</p></fragment>\n </Card>\n </provide>\n <each in='{names}' as='n' key='{n}'><Item label='{n}'/></each>\n <dial value='{volume}' on-change='set_volume(event.value)'/>\n <input type='checkbox' checked='{extra}' on-change='set on = event.value'/>\n <if test='{extra}'><p on-mount='mount()' on-unmount='unmount()'>extra</p></if>\n <state on='{false}'/>\n <p>checkbox {on}</p>\n</screen>\n</ui>\n"
function texts(n: UiNode, out: []string) -> void {
if n.text != "" { push(out, n.text) }
for i in 0 .. len(n.children) { texts(n.children[i], out) }
}
function frame(ui_st: mut UiState) -> UiNode {
ui_show(ui_st, "mix", view_mixer(), 0.0, 0.0, 400.0, 400.0)
let root: UiNode = ui_nodes(ui_st, "mix", view_mixer())
ui_place(ui_st, root, 0.0, 0.0, 400.0, 400.0)
return root
}
entry (ui_st: mut UiState, uireact_st: mut UireactState) {
ui_native(ui_st, "dial", fn dial_measure, fn dial_draw)
push(uireact_st.names, "bass")
push(uireact_st.names, "drums")
ui_load_text(ui_st, PAGE, "ui/mix.xml")
var root = frame(ui_st)
ui_press(ui_st, root.children[2])
uireact_st.names[0] = "drums"
uireact_st.names[1] = "bass"
root = frame(ui_st)
let dial = root.children[3]
ui_event(ui_st, dial, "change", Value.int(uireact_st.volume + 4))
ui_event(ui_st, root.children[4], "change", Value.bool(1))
uireact_st.show_extra = false
root = frame(ui_st)
let out = new []string
texts(root, out)
var joined = ""
for i in 0 .. len(out) { joined = joined + out[i] + "|" }
print(joined)
print(`volume {uireact_st.volume}; dial {int(dial.cw)}x{int(dial.ch)}; mounted {uireact_st.mounted}, unmounted {uireact_st.unmounted}`)
}
}