ludic.ui: a screen's nodes and envs are pooled and used again - two generations a screen, reset in place, their own lists emptied not replaced; a tree is good until its screen is built twice more (benchmark 256 -> 110 KB a frame)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
83200a453b
commit
d1c9359e96
19 changed files with 307 additions and 83 deletions
|
|
@ -53,10 +53,10 @@ program UiPointer {
|
|||
let active = down.children[2].bg
|
||||
let mid = said(down)
|
||||
frame(ui_st, hold.x + 5.0, hold.y + 90.0, false, 0.0, false)
|
||||
let off = frame(ui_st, -1.0, -1.0, false, 0.0, false)
|
||||
let off = said(frame(ui_st, -1.0, -1.0, false, 0.0, false))
|
||||
frame(ui_st, -1.0, -1.0, false, 0.0, true)
|
||||
let keyed = said(frame(ui_st, -1.0, -1.0, false, 0.0, true))
|
||||
let up = frame(ui_st, -1.0, -1.0, false, 0.0, false)
|
||||
print(`{ui_pointer_st.log}dragged {int(ui_pointer_st.dragged)} | {mid} active {active} | {said(off)} | {keyed} | {said(up)} {up.children[2].bg}`)
|
||||
print(`{ui_pointer_st.log}dragged {int(ui_pointer_st.dragged)} | {mid} active {active} | {off} | {keyed} | {said(up)} {up.children[2].bg}`)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ function ui_default_backend() -> UiBackend {
|
|||
return UiRenderers[0].make()
|
||||
}
|
||||
export state UiState {
|
||||
pl_pools: []UiPool = new []UiPool # pool.ludic: each screen's nodes and envs, used again
|
||||
pl_cur: UiPool = null
|
||||
an_frames: []UiKeyframes = new []UiKeyframes
|
||||
an_keys: []string = new []string
|
||||
an_start: []float = new []float
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ function bd_each(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string, out: []UiN
|
|||
let at_name = bd_name(k, "index", "index")
|
||||
let by = tpl_attr(k, "key")
|
||||
for j in 0 .. Value.count(list) {
|
||||
let le = env_new(e)
|
||||
let le = env_new(ui_st, e)
|
||||
env_bind(le, as_name, Value.at(list, j))
|
||||
env_bind(le, at_name, Value.int(j))
|
||||
var id = string(j)
|
||||
|
|
@ -77,7 +77,7 @@ function bd_comp(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string, out: []UiN
|
|||
}
|
||||
if k.comp == null { return false }
|
||||
let c = k.comp
|
||||
let ce = env_new(null)
|
||||
let ce = env_new(ui_st, null)
|
||||
ce.model = e.model
|
||||
ce.ctx = e.ctx
|
||||
for i in 0 .. len(c.keys) {
|
||||
|
|
@ -86,7 +86,6 @@ function bd_comp(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string, out: []UiN
|
|||
for i in 0 .. len(k.keys) { env_bind(ce, k.keys[i], ui_eval(ui_st, k.vals[i], e)) }
|
||||
ce.on_names = k.on_keys
|
||||
ce.on_acts = k.on_acts
|
||||
ce.on_envs = new []UiEnv
|
||||
for i in 0 .. len(k.on_keys) { push(ce.on_envs, e) }
|
||||
ce.slot = k
|
||||
ce.slot_env = e
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ function bd_class(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string, out: []Ui
|
|||
if a != "class" and a != "style" and a != "id" { Value.put(props, a, ui_eval(ui_st, k.vals[i], e)) }
|
||||
}
|
||||
cls.props(it.ptr, props)
|
||||
let ce = env_new(null)
|
||||
let ce = env_new(ui_st, null)
|
||||
ce.model = cls.model(it.ptr)
|
||||
ce.inst = it
|
||||
ce.ctx = e.ctx
|
||||
|
|
@ -19,7 +19,6 @@ function bd_class(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string, out: []Ui
|
|||
ce.slot_env = e
|
||||
ce.on_names = k.on_keys
|
||||
ce.on_acts = k.on_acts
|
||||
ce.on_envs = new []UiEnv
|
||||
for i in 0 .. len(k.on_keys) { push(ce.on_envs, e) }
|
||||
lc_note(ui_st, key, k.on_keys, k.on_acts, e)
|
||||
let at = len(out)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
# build_more.ludic - <let name="{value}"/> names a value for the siblings after it, and
|
||||
# <provide name="{value}"> gives it to everything inside, components included (React's context)
|
||||
function bd_let(ui_st: mut UiState, k: UiTpl, e: UiEnv) -> UiEnv {
|
||||
let le = env_new(e)
|
||||
let le = env_new(ui_st, e)
|
||||
for i in 0 .. len(k.keys) { env_bind(le, k.keys[i], ui_eval(ui_st, k.vals[i], e)) }
|
||||
return le
|
||||
}
|
||||
function bd_provide(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string, out: []UiNode) -> void {
|
||||
let cx = env_new(e.ctx)
|
||||
let cx = env_new(ui_st, e.ctx)
|
||||
for i in 0 .. len(k.keys) { env_bind(cx, k.keys[i], ui_eval(ui_st, k.vals[i], e)) }
|
||||
let pe = env_new(e)
|
||||
let pe = env_new(ui_st, e)
|
||||
pe.ctx = cx
|
||||
bd_kids(ui_st, k.kids, pe, key, out)
|
||||
}
|
||||
|
|
@ -18,12 +18,11 @@ function bd_group(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string, out: []Ui
|
|||
bd_kids(ui_st, k.kids, e, key, out)
|
||||
return
|
||||
}
|
||||
let t = new UiNode
|
||||
let t = nd_take(ui_st)
|
||||
t.kind = UI_TEXT
|
||||
t.key = key
|
||||
t.text = ui_tr(ui_st, ui_eval_text(ui_st, k.text, e))
|
||||
t.env = e
|
||||
t.children = new []UiNode
|
||||
push(out, t)
|
||||
}
|
||||
# text inside text - <p>Hi <b>there</b></p>, <h3><slot/></h3> - reads as one line of it
|
||||
|
|
@ -37,5 +36,5 @@ function el_inline(n: UiNode) -> void {
|
|||
s = s + c.text
|
||||
}
|
||||
n.text = s
|
||||
n.children = new []UiNode
|
||||
List.clear(n.children)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,14 @@ function cs_tree(ui_st: mut UiState, n: UiNode) -> void {
|
|||
}
|
||||
if n.tag != "" { cs_node(ui_st, n) }
|
||||
for i in 0 .. len(n.children) { cs_tree(ui_st, n.children[i]) }
|
||||
var shown = new []UiNode
|
||||
var kept = 0
|
||||
for i in 0 .. len(n.children) {
|
||||
if not n.children[i].hidden { push(shown, n.children[i]) }
|
||||
if not n.children[i].hidden {
|
||||
n.children[kept] = n.children[i]
|
||||
kept += 1
|
||||
}
|
||||
}
|
||||
n.children = shown
|
||||
while len(n.children) > kept { List.pop(n.children) }
|
||||
cs_order(n)
|
||||
}
|
||||
# twice: the font size (and zoom) first, from every rule, so an em anywhere reads the size the
|
||||
|
|
|
|||
|
|
@ -4,18 +4,13 @@
|
|||
# input[type=text|number|key] .ui-label .ui-field > .ui-value (+ .ui-caret while focused)
|
||||
# select .ui-label .ui-prev .ui-value .ui-next (its <option>s hidden)
|
||||
# with a note="...", the label is .ui-labels > .ui-label + .ui-note
|
||||
function ct_part(n: UiNode, cls: string, text: string) -> UiNode {
|
||||
let p = new UiNode
|
||||
function ct_part(ui_st: mut UiState, n: UiNode, cls: string, text: string) -> UiNode {
|
||||
let p = nd_take(ui_st)
|
||||
p.key = `{n.key}/{cls}`
|
||||
p.tag = "span"
|
||||
p.env = n.env
|
||||
p.sheet = n.sheet
|
||||
p.children = new []UiNode
|
||||
p.classes = new []string
|
||||
push(p.classes, cls)
|
||||
p.akeys = new []string
|
||||
p.avals = new []string
|
||||
p.vals = new []Val
|
||||
if text != "" {
|
||||
p.kind = UI_TEXT
|
||||
p.text = text
|
||||
|
|
@ -23,18 +18,18 @@ function ct_part(n: UiNode, cls: string, text: string) -> UiNode {
|
|||
return p
|
||||
}
|
||||
# <progress value max> and <meter value min max>: a track with a fill as far as the value
|
||||
function ct_build_bar(n: UiNode) -> void {
|
||||
function ct_build_bar(ui_st: mut UiState, n: UiNode) -> void {
|
||||
n.dir = UI_ROW
|
||||
let lo = Value.as_float(ui_attr(n, "min"))
|
||||
var hi = Value.as_float(ui_attr(n, "max"))
|
||||
if hi <= lo { hi = lo + 1.0 }
|
||||
let fill = ct_part(n, "ui-fill", "")
|
||||
let fill = ct_part(ui_st, n, "ui-fill", "")
|
||||
fill.w_pct = Math.clamp((Value.as_float(ui_attr(n, "value")) - lo) / (hi - lo), 0.0, 1.0) * 100.0
|
||||
push(n.children, fill)
|
||||
}
|
||||
function ct_build(ui_st: UiState, n: UiNode) -> void {
|
||||
function ct_build(ui_st: mut UiState, n: UiNode) -> void {
|
||||
if n.tag == "progress" or n.tag == "meter" {
|
||||
ct_build_bar(n)
|
||||
ct_build_bar(ui_st, n)
|
||||
return
|
||||
}
|
||||
n.dir = UI_ROW
|
||||
|
|
@ -46,41 +41,41 @@ function ct_build(ui_st: UiState, n: UiNode) -> void {
|
|||
}
|
||||
ct_label(ui_st, n)
|
||||
if t == "checkbox" or t == "radio" {
|
||||
let track = ct_part(n, "ui-track", "")
|
||||
push(track.children, ct_part(n, "ui-knob", ""))
|
||||
let track = ct_part(ui_st, n, "ui-track", "")
|
||||
push(track.children, ct_part(ui_st, n, "ui-knob", ""))
|
||||
push(n.children, track)
|
||||
} else if t == "range" {
|
||||
ct_build_range(n)
|
||||
ct_build_range(ui_st, n)
|
||||
} else {
|
||||
let field = ct_part(n, "ui-field", "")
|
||||
push(field.children, ct_part(n, "ui-value", ct_field_text(ui_st, n)))
|
||||
if ui_st.fc_key == n.key and t != "key" { push(field.children, ct_part(n, "ui-caret", "")) }
|
||||
let field = ct_part(ui_st, n, "ui-field", "")
|
||||
push(field.children, ct_part(ui_st, n, "ui-value", ct_field_text(ui_st, n)))
|
||||
if ui_st.fc_key == n.key and t != "key" { push(field.children, ct_part(ui_st, n, "ui-caret", "")) }
|
||||
push(n.children, field)
|
||||
}
|
||||
}
|
||||
function ct_build_range(n: UiNode) -> void {
|
||||
function ct_build_range(ui_st: mut UiState, n: UiNode) -> void {
|
||||
let lo = Value.as_float(ui_attr(n, "min"))
|
||||
var hi = Value.as_float(ui_attr(n, "max"))
|
||||
if hi <= lo { hi = lo + 1.0 }
|
||||
let v = Value.as_float(ui_attr(n, "value"))
|
||||
let track = ct_part(n, "ui-track", "")
|
||||
let fill = ct_part(n, "ui-fill", "")
|
||||
let track = ct_part(ui_st, n, "ui-track", "")
|
||||
let fill = ct_part(ui_st, n, "ui-fill", "")
|
||||
fill.w_pct = Math.clamp((v - lo) / (hi - lo), 0.0, 1.0) * 100.0
|
||||
push(track.children, fill)
|
||||
push(track.children, ct_part(n, "ui-thumb", ""))
|
||||
push(track.children, ct_part(ui_st, n, "ui-thumb", ""))
|
||||
push(n.children, track)
|
||||
push(n.children, ct_part(n, "ui-value", ct_value_text(n)))
|
||||
push(n.children, ct_part(ui_st, n, "ui-value", ct_value_text(n)))
|
||||
}
|
||||
function ct_build_select(ui_st: UiState, n: UiNode) -> void {
|
||||
function ct_build_select(ui_st: mut UiState, n: UiNode) -> void {
|
||||
let opts = n.children
|
||||
n.children = new []UiNode
|
||||
ct_label(ui_st, n)
|
||||
var shown = ""
|
||||
let at = ct_option_at(n, opts)
|
||||
if at >= 0 { shown = opts[at].text }
|
||||
push(n.children, ct_part(n, "ui-prev", "<"))
|
||||
push(n.children, ct_part(n, "ui-value", shown))
|
||||
push(n.children, ct_part(n, "ui-next", ">"))
|
||||
push(n.children, ct_part(ui_st, n, "ui-prev", "<"))
|
||||
push(n.children, ct_part(ui_st, n, "ui-value", shown))
|
||||
push(n.children, ct_part(ui_st, n, "ui-next", ">"))
|
||||
n.opts = opts
|
||||
}
|
||||
# which option the select's value names: an option's value="...", else its place
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
# controls_parts.ludic - what a control shows besides its own parts: its label, with a `note` (a line
|
||||
# of help under it) in .ui-labels > .ui-label + .ui-note, and a range's or a number's value as text:
|
||||
# `decimals="1"` places, `format="percent"` its place between min and max, and a `unit` after it
|
||||
function ct_label(ui_st: UiState, n: UiNode) -> void {
|
||||
function ct_label(ui_st: mut UiState, n: UiNode) -> void {
|
||||
let label = ui_attr_text(n, "label")
|
||||
let note = ui_attr_text(n, "note")
|
||||
if note == "" {
|
||||
if label != "" { push(n.children, ct_part(n, "ui-label", ui_tr(ui_st, label))) }
|
||||
if label != "" { push(n.children, ct_part(ui_st, n, "ui-label", ui_tr(ui_st, label))) }
|
||||
return
|
||||
}
|
||||
let both = ct_part(n, "ui-labels", "")
|
||||
if label != "" { push(both.children, ct_part(n, "ui-label", ui_tr(ui_st, label))) }
|
||||
push(both.children, ct_part(n, "ui-note", ui_tr(ui_st, note)))
|
||||
let both = ct_part(ui_st, n, "ui-labels", "")
|
||||
if label != "" { push(both.children, ct_part(ui_st, n, "ui-label", ui_tr(ui_st, label))) }
|
||||
push(both.children, ct_part(ui_st, n, "ui-note", ui_tr(ui_st, note)))
|
||||
push(n.children, both)
|
||||
}
|
||||
function ct_value_text(n: UiNode) -> string {
|
||||
|
|
|
|||
|
|
@ -4,17 +4,12 @@ const EL_BOXES: string = " col div progress meter section header footer nav main
|
|||
const EL_TEXTS: string = " text span p label h1 h2 h3 h4 h5 h6 strong em small b i a option "
|
||||
function bd_elem(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string) -> UiNode {
|
||||
ui_st.ui_at = k.where
|
||||
let n = new UiNode
|
||||
let n = nd_take(ui_st)
|
||||
n.key = key
|
||||
n.tag = k.tag
|
||||
n.env = e
|
||||
n.sheet = k.sheet
|
||||
n.style = k.style
|
||||
n.children = new []UiNode
|
||||
n.classes = new []string
|
||||
n.akeys = new []string
|
||||
n.avals = new []string
|
||||
n.vals = new []Val
|
||||
el_kind(ui_st, n, k.tag)
|
||||
for i in 0 .. len(k.keys) { el_keep(n, k.keys[i], ui_eval(ui_st, k.vals[i], e)) }
|
||||
n.hovered = fr_was_hovered(ui_st, key)
|
||||
|
|
@ -28,7 +23,7 @@ function bd_elem(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string) -> UiNode
|
|||
let say = ui_attr_text(n, "translate")
|
||||
if say == "no" { ui_st.tr_no = true } else if say == "yes" { ui_st.tr_no = false }
|
||||
bd_kids(ui_st, k.kids, e, key, n.children)
|
||||
if k.text != null { el_text(n, ui_tr(ui_st, ui_eval_text(ui_st, k.text, e))) }
|
||||
if k.text != null { el_text(ui_st, n, ui_tr(ui_st, ui_eval_text(ui_st, k.text, e))) }
|
||||
el_inline(n)
|
||||
if k.tag == "input" or k.tag == "select" or k.tag == "progress" or k.tag == "meter" { ct_build(ui_st, n) }
|
||||
ui_st.tr_no = was_no
|
||||
|
|
@ -45,16 +40,15 @@ function el_kind(ui_st: mut UiState, n: UiNode, tag: string) -> void {
|
|||
} else if tag == "input" or tag == "select" { n.focusable = true } else if tag == "spacer" { n.kind = UI_SPACER } else if tag == "scroll" { n.kind = UI_SCROLL } else if tag == "img" { n.kind = UI_IMAGE } else if tag == "hr" { n.kind = UI_RULE } else if not lk_in(EL_BOXES, tag) { ui_err(ui_st, `<{tag}>: there is no such element`) }
|
||||
}
|
||||
# a box with words in it holds them as a text of its own, as <div>words</div> does
|
||||
function el_text(n: UiNode, s: string) -> void {
|
||||
function el_text(ui_st: mut UiState, n: UiNode, s: string) -> void {
|
||||
if n.kind != UI_BOX and n.kind != UI_SCROLL {
|
||||
n.text = s
|
||||
return
|
||||
}
|
||||
let t = new UiNode
|
||||
let t = nd_take(ui_st)
|
||||
t.kind = UI_TEXT
|
||||
t.text = s
|
||||
t.env = n.env
|
||||
t.children = new []UiNode
|
||||
push(n.children, t)
|
||||
}
|
||||
# id, class, hidden, disabled and src say what the element is; the rest are applied after the rules
|
||||
|
|
|
|||
|
|
@ -16,10 +16,8 @@ export property UiEnv {
|
|||
inst: UiInst = null # the Ludic component whose template this is
|
||||
}
|
||||
|
||||
function env_new(parent: UiEnv) -> UiEnv {
|
||||
let e = new UiEnv
|
||||
e.names = new []string
|
||||
e.vals = new []Val
|
||||
function env_new(ui_st: mut UiState, parent: UiEnv) -> UiEnv {
|
||||
let e = env_take(ui_st)
|
||||
e.parent = parent
|
||||
if parent != null {
|
||||
e.model = parent.model
|
||||
|
|
|
|||
|
|
@ -39,20 +39,16 @@ export function ui_nodes(ui_st: mut UiState, screen: string, view: UiView) -> Ui
|
|||
return null
|
||||
}
|
||||
let t = ui_st.lib_screens[si]
|
||||
pl_begin(ui_st, screen)
|
||||
lc_begin(ui_st)
|
||||
ui_st.ui_view = view
|
||||
let e = env_new(null)
|
||||
let e = env_new(ui_st, null)
|
||||
if view != null and view.model != null { e.model = view.model() } else { e.model = Value.object() }
|
||||
e.state = st_for(ui_st, screen, t, e)
|
||||
let root = new UiNode
|
||||
let root = nd_take(ui_st)
|
||||
root.key = screen
|
||||
root.children = new []UiNode
|
||||
root.env = e
|
||||
root.sheet = t.sheet
|
||||
root.classes = new []string
|
||||
root.akeys = new []string
|
||||
root.avals = new []string
|
||||
root.vals = new []Val
|
||||
root.tag = "screen"
|
||||
for i in 0 .. len(t.keys) {
|
||||
if t.keys[i] != "name" { el_keep(root, t.keys[i], ui_eval(ui_st, t.vals[i], e)) }
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ import "node.ludic"
|
|||
import "node_more.ludic"
|
||||
import "view.ludic"
|
||||
import "backend.ludic"
|
||||
import "pool.ludic"
|
||||
import "pool_reset.ludic"
|
||||
import "pool_reset_more.ludic"
|
||||
import "expr.ludic"
|
||||
import "expr_parse.ludic"
|
||||
import "expr_prim.ludic"
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ function nt_run(ui_st: mut UiState, n: UiNode, name: string, value: Val) -> void
|
|||
if (lk_in(PE_NAMES, name) or name == "hold") and Value.kind(value) == 6 { ev = value }
|
||||
Value.put(ev, "name", Value.str(name))
|
||||
Value.put(ev, "value", value)
|
||||
let e = env_new(n.env)
|
||||
let e = env_new(ui_st, n.env)
|
||||
env_bind(e, "event", ev)
|
||||
act_run(ui_st, n.on_acts[i], e)
|
||||
}
|
||||
|
|
|
|||
84
packages/ludic.ui/pool.ludic
Normal file
84
packages/ludic.ui/pool.ludic
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# pool.ludic - what a frame is built of is kept and used again: ludic.ui builds a screen's tree anew
|
||||
# every frame, and Ludic frees nothing, so a node or an env made per element per frame was a leak
|
||||
# (the valley's HUD: ~100 MB/s). Each screen keeps two generations and alternates, so last frame's
|
||||
# tree - which an unmount's env, a hover or ui_box still reads - stays whole while this one is built.
|
||||
# So a host may read a tree until the same screen has been built twice more, and never keep it longer.
|
||||
export property UiPool {
|
||||
key: string = ""
|
||||
gen: int = 0
|
||||
nodes0: []UiNode = null
|
||||
nodes1: []UiNode = null
|
||||
envs0: []UiEnv = null
|
||||
envs1: []UiEnv = null
|
||||
un: int = 0
|
||||
ue: int = 0
|
||||
}
|
||||
# a build of `screen` begins: its other generation is handed out again from the start
|
||||
function pl_begin(ui_st: mut UiState, screen: string) -> void {
|
||||
var p: UiPool = null
|
||||
for i in 0 .. len(ui_st.pl_pools) {
|
||||
if ui_st.pl_pools[i].key == screen { p = ui_st.pl_pools[i] }
|
||||
}
|
||||
if p == null {
|
||||
p = new UiPool
|
||||
p.key = screen
|
||||
p.nodes0 = new []UiNode
|
||||
p.nodes1 = new []UiNode
|
||||
p.envs0 = new []UiEnv
|
||||
p.envs1 = new []UiEnv
|
||||
push(ui_st.pl_pools, p)
|
||||
}
|
||||
p.gen = 1 - p.gen
|
||||
p.un = 0
|
||||
p.ue = 0
|
||||
ui_st.pl_cur = p
|
||||
}
|
||||
# a node, blank, with its own lists (empty) - from the pool when a build is under way
|
||||
function nd_take(ui_st: mut UiState) -> UiNode {
|
||||
let p = ui_st.pl_cur
|
||||
if p == null { return nd_fresh() }
|
||||
var list = p.nodes0
|
||||
if p.gen == 1 { list = p.nodes1 }
|
||||
if p.un < len(list) {
|
||||
let n = list[p.un]
|
||||
p.un += 1
|
||||
nd_reset(n)
|
||||
return n
|
||||
}
|
||||
let n = nd_fresh()
|
||||
push(list, n)
|
||||
p.un += 1
|
||||
return n
|
||||
}
|
||||
function nd_fresh() -> UiNode {
|
||||
let n = new UiNode
|
||||
n.children = new []UiNode
|
||||
n.classes = new []string
|
||||
n.akeys = new []string
|
||||
n.avals = new []string
|
||||
n.vals = new []Val
|
||||
return n
|
||||
}
|
||||
function env_take(ui_st: mut UiState) -> UiEnv {
|
||||
let p = ui_st.pl_cur
|
||||
if p == null { return env_fresh() }
|
||||
var list = p.envs0
|
||||
if p.gen == 1 { list = p.envs1 }
|
||||
if p.ue < len(list) {
|
||||
let e = list[p.ue]
|
||||
p.ue += 1
|
||||
env_reset(e)
|
||||
return e
|
||||
}
|
||||
let e = env_fresh()
|
||||
push(list, e)
|
||||
p.ue += 1
|
||||
return e
|
||||
}
|
||||
function env_fresh() -> UiEnv {
|
||||
let e = new UiEnv
|
||||
e.names = new []string
|
||||
e.vals = new []Val
|
||||
e.on_envs = new []UiEnv
|
||||
return e
|
||||
}
|
||||
61
packages/ludic.ui/pool_reset.ludic
Normal file
61
packages/ludic.ui/pool_reset.ludic
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# pool_reset.ludic - a pooled node put back to its defaults: every field, and the lists it owns
|
||||
# emptied and kept (generated from node.ludic - a field added there is added here)
|
||||
function nd_reset(n: UiNode) -> void {
|
||||
nd_reset_a(n)
|
||||
nd_reset_b(n)
|
||||
}
|
||||
function nd_reset_a(n: UiNode) -> void {
|
||||
n.kind = 0
|
||||
n.dir = 0
|
||||
n.text = ""
|
||||
n.key = ""
|
||||
n.tag = ""
|
||||
n.id = ""
|
||||
if n.classes != null { List.clear(n.classes) }
|
||||
if n.akeys != null { List.clear(n.akeys) }
|
||||
if n.avals != null { List.clear(n.avals) }
|
||||
if n.vals != null { List.clear(n.vals) }
|
||||
n.style = null
|
||||
n.sheet = null
|
||||
if n.ups != null { List.clear(n.ups) }
|
||||
n.parent = null
|
||||
n.index = 0
|
||||
n.src = ""
|
||||
n.size = 0.0
|
||||
n.w = -1000000.0
|
||||
n.h = -1000000.0
|
||||
n.w_pct = 0.0
|
||||
n.h_pct = 0.0
|
||||
n.pt = 0.0
|
||||
n.pr = 0.0
|
||||
n.pb = 0.0
|
||||
n.pl = 0.0
|
||||
n.mt = 0.0
|
||||
n.mr = 0.0
|
||||
n.mb = 0.0
|
||||
n.ml = 0.0
|
||||
n.border = 0.0
|
||||
n.bt = 0.0
|
||||
n.br = 0.0
|
||||
n.bb = 0.0
|
||||
n.bl = 0.0
|
||||
n.border_c = -2
|
||||
n.gap = 0.0
|
||||
n.align = 0
|
||||
n.justify = 0
|
||||
n.talign = 0
|
||||
n.self = -1
|
||||
n.grow = 0.0
|
||||
n.wrap = false
|
||||
n.min_w = 0.0
|
||||
n.max_w = 0.0
|
||||
n.min_h = 0.0
|
||||
n.max_h = 0.0
|
||||
n.hidden = false
|
||||
n.pos = 0
|
||||
n.top = -1000000.0
|
||||
n.right = -1000000.0
|
||||
n.bottom = -1000000.0
|
||||
n.left = -1000000.0
|
||||
n.z = 0
|
||||
}
|
||||
96
packages/ludic.ui/pool_reset_more.ludic
Normal file
96
packages/ludic.ui/pool_reset_more.ludic
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# pool_reset_more.ludic - the rest of a pooled node's fields, its extras and an env, to their defaults
|
||||
function nd_reset_b(n: UiNode) -> void {
|
||||
n.nowrap = false
|
||||
n.ellipsis = false
|
||||
if n.lines != null { List.clear(n.lines) }
|
||||
if n.var_names != null { List.clear(n.var_names) }
|
||||
if n.var_vals != null { List.clear(n.var_vals) }
|
||||
n.fg = -1
|
||||
n.fg_a = 1.0
|
||||
n.bg = -2
|
||||
n.bg_a = 1.0
|
||||
n.border_a = 1.0
|
||||
n.rfg_a = 1.0
|
||||
n.alpha = 1.0
|
||||
n.enabled = true
|
||||
n.act = null
|
||||
n.on_names = null
|
||||
n.on_acts = null
|
||||
n.native = null
|
||||
n.env = null
|
||||
if n.children != null { List.clear(n.children) }
|
||||
n.mw = 0.0
|
||||
n.mh = 0.0
|
||||
n.content_h = 0.0
|
||||
n.x = 0.0
|
||||
n.y = 0.0
|
||||
n.cw = 0.0
|
||||
n.ch = 0.0
|
||||
n.rsize = 0.0
|
||||
n.rfg = 0
|
||||
n.hovered = false
|
||||
n.focusable = false
|
||||
n.radius = 0.0
|
||||
n.outline_w = 0.0
|
||||
n.outline_c = -1
|
||||
n.outline_a = 1.0
|
||||
n.outline_off = 0.0
|
||||
n.scroll_y = 0.0
|
||||
n.bar_c = -1
|
||||
n.bar_track = -2
|
||||
n.opts = null
|
||||
n.bg_img = ""
|
||||
n.bi_src = ""
|
||||
n.bi_slice = 0.0
|
||||
n.bi_width = 0.0
|
||||
n.sh_x = 0.0
|
||||
n.sh_y = 0.0
|
||||
n.sh_c = -2
|
||||
n.sh_a = 1.0
|
||||
n.anim = ""
|
||||
n.anim_dur = 0.0
|
||||
n.anim_loop = false
|
||||
n.anim_alt = false
|
||||
n.tr_dur = 0.0
|
||||
n.popover = false
|
||||
if n.ex != null { nx_reset(n.ex) }
|
||||
}
|
||||
function nx_reset(x: UiNodeX) -> void {
|
||||
x.shrink = -1.0
|
||||
x.order = 0
|
||||
x.w_off = 0.0
|
||||
x.h_off = 0.0
|
||||
x.mh_min = 0.0
|
||||
x.has_min = false
|
||||
x.tsh_set = false
|
||||
x.tsh_x = 0.0
|
||||
x.tsh_y = 0.0
|
||||
x.tsh_c = -2
|
||||
x.tsh_a = 1.0
|
||||
x.no_pointer = false
|
||||
x.fit_min = 0.0
|
||||
x.lh_kind = 0
|
||||
x.lh_v = 0.0
|
||||
x.ip_t = 0.0
|
||||
x.ip_r = 0.0
|
||||
x.ip_b = 0.0
|
||||
x.ip_l = 0.0
|
||||
x.grad = null
|
||||
x.ratio = 0.0
|
||||
x.fit_obj = 0
|
||||
x.zoom = 1.0
|
||||
}
|
||||
function env_reset(e: UiEnv) -> void {
|
||||
if e.names != null { List.clear(e.names) }
|
||||
if e.vals != null { List.clear(e.vals) }
|
||||
e.state = null
|
||||
e.parent = null
|
||||
e.model = null
|
||||
e.slot = null
|
||||
e.slot_env = null
|
||||
e.on_names = null
|
||||
e.on_acts = null
|
||||
if e.on_envs != null { List.clear(e.on_envs) }
|
||||
e.ctx = null
|
||||
e.inst = null
|
||||
}
|
||||
|
|
@ -1,11 +1,12 @@
|
|||
# screen_class.ludic - a Ludic component shown as a whole screen
|
||||
# a Ludic component shown as a screen: an instance at the top, keyed by its name
|
||||
function fr_class_nodes(ui_st: mut UiState, cls: UiClass) -> UiNode {
|
||||
pl_begin(ui_st, cls.name)
|
||||
lc_begin(ui_st)
|
||||
ui_st.in_build += 1
|
||||
ui_st.ui_view = null
|
||||
uc_load(ui_st, cls)
|
||||
let root = fr_root(cls.name, cls.sheet)
|
||||
let root = fr_root(ui_st, cls.name, cls.sheet)
|
||||
let use = new UiTpl
|
||||
use.tag = cls.name
|
||||
use.cls = cls
|
||||
|
|
@ -14,7 +15,7 @@ function fr_class_nodes(ui_st: mut UiState, cls: UiClass) -> UiNode {
|
|||
use.on_keys = new []string
|
||||
use.on_acts = new []UiAct
|
||||
use.kids = new []UiTpl
|
||||
let e = env_new(null)
|
||||
let e = env_new(ui_st, null)
|
||||
e.model = Value.object()
|
||||
root.env = e
|
||||
bd_class(ui_st, use, e, cls.name, root.children)
|
||||
|
|
@ -22,15 +23,10 @@ function fr_class_nodes(ui_st: mut UiState, cls: UiClass) -> UiNode {
|
|||
cs_tree(ui_st, root)
|
||||
return root
|
||||
}
|
||||
function fr_root(key: string, sheet: UiSheet) -> UiNode {
|
||||
let root = new UiNode
|
||||
function fr_root(ui_st: mut UiState, key: string, sheet: UiSheet) -> UiNode {
|
||||
let root = nd_take(ui_st)
|
||||
root.key = key
|
||||
root.tag = "screen"
|
||||
root.sheet = sheet
|
||||
root.children = new []UiNode
|
||||
root.classes = new []string
|
||||
root.akeys = new []string
|
||||
root.avals = new []string
|
||||
root.vals = new []Val
|
||||
return root
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
# it where it was taken; a press on the track jumps the thumb's middle to the pointer and holds it there.
|
||||
# the bar's parts, styled as descendants of the box, and where they are at this offset
|
||||
function sb_geo(ui_st: mut UiState, n: UiNode, off: float, room: float, most: float) -> void {
|
||||
let bar = ct_part(n, "ui-scrollbar", "")
|
||||
let bar = ct_part(ui_st, n, "ui-scrollbar", "")
|
||||
bar.tag = "div"
|
||||
bar.parent = n
|
||||
push(bar.children, ct_part(n, "ui-thumb", ""))
|
||||
push(bar.children, ct_part(ui_st, n, "ui-thumb", ""))
|
||||
cs_tree(ui_st, bar)
|
||||
ui_st.sb_bar = bar
|
||||
ui_st.sb_w = ui_px(ui_st, 6.0)
|
||||
|
|
|
|||
|
|
@ -39,12 +39,11 @@ function tt_under(n: UiNode, x: float, y: float) -> UiNode {
|
|||
}
|
||||
function tt_draw(ui_st: mut UiState, root: UiNode) -> void {
|
||||
if ui_st.tt_key == "" or ui_st.tt_text == "" or an_now(ui_st) - ui_st.tt_since < 0.5 { return }
|
||||
let n = ct_part(root, "ui-tooltip", "")
|
||||
let n = ct_part(ui_st, root, "ui-tooltip", "")
|
||||
n.tag = "div"
|
||||
n.parent = root
|
||||
n.children = new []UiNode
|
||||
let lines = tt_lines(ui_st.tt_text)
|
||||
for i in 0 .. len(lines) { push(n.children, ct_part(root, "ui-tooltip-text", lines[i])) }
|
||||
for i in 0 .. len(lines) { push(n.children, ct_part(ui_st, root, "ui-tooltip-text", lines[i])) }
|
||||
cs_tree(ui_st, n)
|
||||
ly_measure(ui_st, n, ui_st.ly_vp_w * 0.4, ui_px(ui_st, 16.0), root.rfg)
|
||||
let x = Math.min(ui_st.tt_x + ui_px(ui_st, 16.0), ui_st.ly_vp_x + ui_st.ly_vp_w - n.mw)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue