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 active = down.children[2].bg
|
||||||
let mid = said(down)
|
let mid = said(down)
|
||||||
frame(ui_st, hold.x + 5.0, hold.y + 90.0, false, 0.0, false)
|
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)
|
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 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)
|
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()
|
return UiRenderers[0].make()
|
||||||
}
|
}
|
||||||
export state UiState {
|
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_frames: []UiKeyframes = new []UiKeyframes
|
||||||
an_keys: []string = new []string
|
an_keys: []string = new []string
|
||||||
an_start: []float = new []float
|
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 at_name = bd_name(k, "index", "index")
|
||||||
let by = tpl_attr(k, "key")
|
let by = tpl_attr(k, "key")
|
||||||
for j in 0 .. Value.count(list) {
|
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, as_name, Value.at(list, j))
|
||||||
env_bind(le, at_name, Value.int(j))
|
env_bind(le, at_name, Value.int(j))
|
||||||
var id = string(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 }
|
if k.comp == null { return false }
|
||||||
let c = k.comp
|
let c = k.comp
|
||||||
let ce = env_new(null)
|
let ce = env_new(ui_st, null)
|
||||||
ce.model = e.model
|
ce.model = e.model
|
||||||
ce.ctx = e.ctx
|
ce.ctx = e.ctx
|
||||||
for i in 0 .. len(c.keys) {
|
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)) }
|
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_names = k.on_keys
|
||||||
ce.on_acts = k.on_acts
|
ce.on_acts = k.on_acts
|
||||||
ce.on_envs = new []UiEnv
|
|
||||||
for i in 0 .. len(k.on_keys) { push(ce.on_envs, e) }
|
for i in 0 .. len(k.on_keys) { push(ce.on_envs, e) }
|
||||||
ce.slot = k
|
ce.slot = k
|
||||||
ce.slot_env = e
|
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)) }
|
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)
|
cls.props(it.ptr, props)
|
||||||
let ce = env_new(null)
|
let ce = env_new(ui_st, null)
|
||||||
ce.model = cls.model(it.ptr)
|
ce.model = cls.model(it.ptr)
|
||||||
ce.inst = it
|
ce.inst = it
|
||||||
ce.ctx = e.ctx
|
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.slot_env = e
|
||||||
ce.on_names = k.on_keys
|
ce.on_names = k.on_keys
|
||||||
ce.on_acts = k.on_acts
|
ce.on_acts = k.on_acts
|
||||||
ce.on_envs = new []UiEnv
|
|
||||||
for i in 0 .. len(k.on_keys) { push(ce.on_envs, e) }
|
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)
|
lc_note(ui_st, key, k.on_keys, k.on_acts, e)
|
||||||
let at = len(out)
|
let at = len(out)
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
# build_more.ludic - <let name="{value}"/> names a value for the siblings after it, and
|
# 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)
|
# <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 {
|
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)) }
|
for i in 0 .. len(k.keys) { env_bind(le, k.keys[i], ui_eval(ui_st, k.vals[i], e)) }
|
||||||
return le
|
return le
|
||||||
}
|
}
|
||||||
function bd_provide(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string, out: []UiNode) -> void {
|
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)) }
|
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
|
pe.ctx = cx
|
||||||
bd_kids(ui_st, k.kids, pe, key, out)
|
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)
|
bd_kids(ui_st, k.kids, e, key, out)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let t = new UiNode
|
let t = nd_take(ui_st)
|
||||||
t.kind = UI_TEXT
|
t.kind = UI_TEXT
|
||||||
t.key = key
|
t.key = key
|
||||||
t.text = ui_tr(ui_st, ui_eval_text(ui_st, k.text, e))
|
t.text = ui_tr(ui_st, ui_eval_text(ui_st, k.text, e))
|
||||||
t.env = e
|
t.env = e
|
||||||
t.children = new []UiNode
|
|
||||||
push(out, t)
|
push(out, t)
|
||||||
}
|
}
|
||||||
# text inside text - <p>Hi <b>there</b></p>, <h3><slot/></h3> - reads as one line of it
|
# 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
|
s = s + c.text
|
||||||
}
|
}
|
||||||
n.text = s
|
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) }
|
if n.tag != "" { cs_node(ui_st, n) }
|
||||||
for i in 0 .. len(n.children) { cs_tree(ui_st, n.children[i]) }
|
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) {
|
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)
|
cs_order(n)
|
||||||
}
|
}
|
||||||
# twice: the font size (and zoom) first, from every rule, so an em anywhere reads the size the
|
# 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)
|
# 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)
|
# 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
|
# with a note="...", the label is .ui-labels > .ui-label + .ui-note
|
||||||
function ct_part(n: UiNode, cls: string, text: string) -> UiNode {
|
function ct_part(ui_st: mut UiState, n: UiNode, cls: string, text: string) -> UiNode {
|
||||||
let p = new UiNode
|
let p = nd_take(ui_st)
|
||||||
p.key = `{n.key}/{cls}`
|
p.key = `{n.key}/{cls}`
|
||||||
p.tag = "span"
|
p.tag = "span"
|
||||||
p.env = n.env
|
p.env = n.env
|
||||||
p.sheet = n.sheet
|
p.sheet = n.sheet
|
||||||
p.children = new []UiNode
|
|
||||||
p.classes = new []string
|
|
||||||
push(p.classes, cls)
|
push(p.classes, cls)
|
||||||
p.akeys = new []string
|
|
||||||
p.avals = new []string
|
|
||||||
p.vals = new []Val
|
|
||||||
if text != "" {
|
if text != "" {
|
||||||
p.kind = UI_TEXT
|
p.kind = UI_TEXT
|
||||||
p.text = text
|
p.text = text
|
||||||
|
|
@ -23,18 +18,18 @@ function ct_part(n: UiNode, cls: string, text: string) -> UiNode {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
# <progress value max> and <meter value min max>: a track with a fill as far as the value
|
# <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
|
n.dir = UI_ROW
|
||||||
let lo = Value.as_float(ui_attr(n, "min"))
|
let lo = Value.as_float(ui_attr(n, "min"))
|
||||||
var hi = Value.as_float(ui_attr(n, "max"))
|
var hi = Value.as_float(ui_attr(n, "max"))
|
||||||
if hi <= lo { hi = lo + 1.0 }
|
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
|
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)
|
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" {
|
if n.tag == "progress" or n.tag == "meter" {
|
||||||
ct_build_bar(n)
|
ct_build_bar(ui_st, n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n.dir = UI_ROW
|
n.dir = UI_ROW
|
||||||
|
|
@ -46,41 +41,41 @@ function ct_build(ui_st: UiState, n: UiNode) -> void {
|
||||||
}
|
}
|
||||||
ct_label(ui_st, n)
|
ct_label(ui_st, n)
|
||||||
if t == "checkbox" or t == "radio" {
|
if t == "checkbox" or t == "radio" {
|
||||||
let track = ct_part(n, "ui-track", "")
|
let track = ct_part(ui_st, n, "ui-track", "")
|
||||||
push(track.children, ct_part(n, "ui-knob", ""))
|
push(track.children, ct_part(ui_st, n, "ui-knob", ""))
|
||||||
push(n.children, track)
|
push(n.children, track)
|
||||||
} else if t == "range" {
|
} else if t == "range" {
|
||||||
ct_build_range(n)
|
ct_build_range(ui_st, n)
|
||||||
} else {
|
} else {
|
||||||
let field = ct_part(n, "ui-field", "")
|
let field = ct_part(ui_st, n, "ui-field", "")
|
||||||
push(field.children, ct_part(n, "ui-value", ct_field_text(ui_st, n)))
|
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(n, "ui-caret", "")) }
|
if ui_st.fc_key == n.key and t != "key" { push(field.children, ct_part(ui_st, n, "ui-caret", "")) }
|
||||||
push(n.children, field)
|
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"))
|
let lo = Value.as_float(ui_attr(n, "min"))
|
||||||
var hi = Value.as_float(ui_attr(n, "max"))
|
var hi = Value.as_float(ui_attr(n, "max"))
|
||||||
if hi <= lo { hi = lo + 1.0 }
|
if hi <= lo { hi = lo + 1.0 }
|
||||||
let v = Value.as_float(ui_attr(n, "value"))
|
let v = Value.as_float(ui_attr(n, "value"))
|
||||||
let track = ct_part(n, "ui-track", "")
|
let track = ct_part(ui_st, n, "ui-track", "")
|
||||||
let fill = ct_part(n, "ui-fill", "")
|
let fill = ct_part(ui_st, n, "ui-fill", "")
|
||||||
fill.w_pct = Math.clamp((v - lo) / (hi - lo), 0.0, 1.0) * 100.0
|
fill.w_pct = Math.clamp((v - lo) / (hi - lo), 0.0, 1.0) * 100.0
|
||||||
push(track.children, fill)
|
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, 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
|
let opts = n.children
|
||||||
n.children = new []UiNode
|
n.children = new []UiNode
|
||||||
ct_label(ui_st, n)
|
ct_label(ui_st, n)
|
||||||
var shown = ""
|
var shown = ""
|
||||||
let at = ct_option_at(n, opts)
|
let at = ct_option_at(n, opts)
|
||||||
if at >= 0 { shown = opts[at].text }
|
if at >= 0 { shown = opts[at].text }
|
||||||
push(n.children, ct_part(n, "ui-prev", "<"))
|
push(n.children, ct_part(ui_st, n, "ui-prev", "<"))
|
||||||
push(n.children, ct_part(n, "ui-value", shown))
|
push(n.children, ct_part(ui_st, n, "ui-value", shown))
|
||||||
push(n.children, ct_part(n, "ui-next", ">"))
|
push(n.children, ct_part(ui_st, n, "ui-next", ">"))
|
||||||
n.opts = opts
|
n.opts = opts
|
||||||
}
|
}
|
||||||
# which option the select's value names: an option's value="...", else its place
|
# 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
|
# 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:
|
# 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
|
# `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 label = ui_attr_text(n, "label")
|
||||||
let note = ui_attr_text(n, "note")
|
let note = ui_attr_text(n, "note")
|
||||||
if 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
|
return
|
||||||
}
|
}
|
||||||
let both = ct_part(n, "ui-labels", "")
|
let both = ct_part(ui_st, n, "ui-labels", "")
|
||||||
if label != "" { push(both.children, ct_part(n, "ui-label", ui_tr(ui_st, label))) }
|
if label != "" { push(both.children, ct_part(ui_st, n, "ui-label", ui_tr(ui_st, label))) }
|
||||||
push(both.children, ct_part(n, "ui-note", ui_tr(ui_st, note)))
|
push(both.children, ct_part(ui_st, n, "ui-note", ui_tr(ui_st, note)))
|
||||||
push(n.children, both)
|
push(n.children, both)
|
||||||
}
|
}
|
||||||
function ct_value_text(n: UiNode) -> string {
|
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 "
|
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 {
|
function bd_elem(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string) -> UiNode {
|
||||||
ui_st.ui_at = k.where
|
ui_st.ui_at = k.where
|
||||||
let n = new UiNode
|
let n = nd_take(ui_st)
|
||||||
n.key = key
|
n.key = key
|
||||||
n.tag = k.tag
|
n.tag = k.tag
|
||||||
n.env = e
|
n.env = e
|
||||||
n.sheet = k.sheet
|
n.sheet = k.sheet
|
||||||
n.style = k.style
|
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)
|
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)) }
|
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)
|
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")
|
let say = ui_attr_text(n, "translate")
|
||||||
if say == "no" { ui_st.tr_no = true } else if say == "yes" { ui_st.tr_no = false }
|
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)
|
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)
|
el_inline(n)
|
||||||
if k.tag == "input" or k.tag == "select" or k.tag == "progress" or k.tag == "meter" { ct_build(ui_st, 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
|
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`) }
|
} 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
|
# 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 {
|
if n.kind != UI_BOX and n.kind != UI_SCROLL {
|
||||||
n.text = s
|
n.text = s
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let t = new UiNode
|
let t = nd_take(ui_st)
|
||||||
t.kind = UI_TEXT
|
t.kind = UI_TEXT
|
||||||
t.text = s
|
t.text = s
|
||||||
t.env = n.env
|
t.env = n.env
|
||||||
t.children = new []UiNode
|
|
||||||
push(n.children, t)
|
push(n.children, t)
|
||||||
}
|
}
|
||||||
# id, class, hidden, disabled and src say what the element is; the rest are applied after the rules
|
# 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
|
inst: UiInst = null # the Ludic component whose template this is
|
||||||
}
|
}
|
||||||
|
|
||||||
function env_new(parent: UiEnv) -> UiEnv {
|
function env_new(ui_st: mut UiState, parent: UiEnv) -> UiEnv {
|
||||||
let e = new UiEnv
|
let e = env_take(ui_st)
|
||||||
e.names = new []string
|
|
||||||
e.vals = new []Val
|
|
||||||
e.parent = parent
|
e.parent = parent
|
||||||
if parent != null {
|
if parent != null {
|
||||||
e.model = parent.model
|
e.model = parent.model
|
||||||
|
|
|
||||||
|
|
@ -39,20 +39,16 @@ export function ui_nodes(ui_st: mut UiState, screen: string, view: UiView) -> Ui
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
let t = ui_st.lib_screens[si]
|
let t = ui_st.lib_screens[si]
|
||||||
|
pl_begin(ui_st, screen)
|
||||||
lc_begin(ui_st)
|
lc_begin(ui_st)
|
||||||
ui_st.ui_view = view
|
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() }
|
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)
|
e.state = st_for(ui_st, screen, t, e)
|
||||||
let root = new UiNode
|
let root = nd_take(ui_st)
|
||||||
root.key = screen
|
root.key = screen
|
||||||
root.children = new []UiNode
|
|
||||||
root.env = e
|
root.env = e
|
||||||
root.sheet = t.sheet
|
root.sheet = t.sheet
|
||||||
root.classes = new []string
|
|
||||||
root.akeys = new []string
|
|
||||||
root.avals = new []string
|
|
||||||
root.vals = new []Val
|
|
||||||
root.tag = "screen"
|
root.tag = "screen"
|
||||||
for i in 0 .. len(t.keys) {
|
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)) }
|
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 "node_more.ludic"
|
||||||
import "view.ludic"
|
import "view.ludic"
|
||||||
import "backend.ludic"
|
import "backend.ludic"
|
||||||
|
import "pool.ludic"
|
||||||
|
import "pool_reset.ludic"
|
||||||
|
import "pool_reset_more.ludic"
|
||||||
import "expr.ludic"
|
import "expr.ludic"
|
||||||
import "expr_parse.ludic"
|
import "expr_parse.ludic"
|
||||||
import "expr_prim.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 }
|
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, "name", Value.str(name))
|
||||||
Value.put(ev, "value", value)
|
Value.put(ev, "value", value)
|
||||||
let e = env_new(n.env)
|
let e = env_new(ui_st, n.env)
|
||||||
env_bind(e, "event", ev)
|
env_bind(e, "event", ev)
|
||||||
act_run(ui_st, n.on_acts[i], e)
|
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
|
# 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
|
# 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 {
|
function fr_class_nodes(ui_st: mut UiState, cls: UiClass) -> UiNode {
|
||||||
|
pl_begin(ui_st, cls.name)
|
||||||
lc_begin(ui_st)
|
lc_begin(ui_st)
|
||||||
ui_st.in_build += 1
|
ui_st.in_build += 1
|
||||||
ui_st.ui_view = null
|
ui_st.ui_view = null
|
||||||
uc_load(ui_st, cls)
|
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
|
let use = new UiTpl
|
||||||
use.tag = cls.name
|
use.tag = cls.name
|
||||||
use.cls = cls
|
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_keys = new []string
|
||||||
use.on_acts = new []UiAct
|
use.on_acts = new []UiAct
|
||||||
use.kids = new []UiTpl
|
use.kids = new []UiTpl
|
||||||
let e = env_new(null)
|
let e = env_new(ui_st, null)
|
||||||
e.model = Value.object()
|
e.model = Value.object()
|
||||||
root.env = e
|
root.env = e
|
||||||
bd_class(ui_st, use, e, cls.name, root.children)
|
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)
|
cs_tree(ui_st, root)
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
function fr_root(key: string, sheet: UiSheet) -> UiNode {
|
function fr_root(ui_st: mut UiState, key: string, sheet: UiSheet) -> UiNode {
|
||||||
let root = new UiNode
|
let root = nd_take(ui_st)
|
||||||
root.key = key
|
root.key = key
|
||||||
root.tag = "screen"
|
root.tag = "screen"
|
||||||
root.sheet = sheet
|
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
|
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.
|
# 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
|
# 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 {
|
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.tag = "div"
|
||||||
bar.parent = n
|
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)
|
cs_tree(ui_st, bar)
|
||||||
ui_st.sb_bar = bar
|
ui_st.sb_bar = bar
|
||||||
ui_st.sb_w = ui_px(ui_st, 6.0)
|
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 {
|
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 }
|
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.tag = "div"
|
||||||
n.parent = root
|
n.parent = root
|
||||||
n.children = new []UiNode
|
|
||||||
let lines = tt_lines(ui_st.tt_text)
|
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)
|
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)
|
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)
|
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