Merge branch 'lang/foundations' into lang/nav
This commit is contained in:
commit
24c16ebee4
30 changed files with 45219 additions and 44778 deletions
|
|
@ -61,7 +61,7 @@ function el_look(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
|||
n.fg = ui_color(ui_st, s)
|
||||
n.fg_a = ui_st.cl_alpha
|
||||
} else if key == "bg" {
|
||||
if gr_is(tpl_words(s)) { nx(n).grad = gr_parse(ui_st, s) } else if len(s) > 4 and sat(s, 0, "url(") { n.bg_img = el_url(s) } else if tpl_words(s) == "transparent" {
|
||||
if gr_is(tw(ui_st, s)) { nx(n).grad = gr_parse(ui_st, s) } else if len(s) > 4 and sat(s, 0, "url(") { n.bg_img = el_url_u(ui_st, s) } else if tw(ui_st, s) == "transparent" {
|
||||
n.bg = 0
|
||||
n.bg_a = 0.0
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ function el_edge(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
|||
let parts = mm_split(ui_st, s, 32)
|
||||
if len(parts) > 0 { n.bar_c = ui_color(ui_st, parts[0]) }
|
||||
if len(parts) > 1 { n.bar_track = ui_color(ui_st, parts[1]) }
|
||||
} else if key == "background-image" and gr_is(tpl_words(s)) { nx(n).grad = gr_parse(ui_st, s) } else if key == "background-image" { n.bg_img = el_url(s) } else if key == "border-image" { el_border_image(ui_st, n, s) } else if key == "box-shadow" { el_shadow(ui_st, n, s) } else if key == "animation" { el_animation(ui_st, n, s) } else if key == "transition" { n.tr_dur = el_secs(s) } else { return false }
|
||||
} else if key == "background-image" and gr_is(tw(ui_st, s)) { nx(n).grad = gr_parse(ui_st, s) } else if key == "background-image" { n.bg_img = el_url_u(ui_st, s) } else if key == "border-image" { el_border_image(ui_st, n, s) } else if key == "box-shadow" { el_shadow(ui_st, n, s) } else if key == "animation" { el_animation(ui_st, n, s) } else if key == "transition" { n.tr_dur = el_secs(s) } else { return false }
|
||||
return true
|
||||
}
|
||||
# url(path) or url("path") -> path
|
||||
|
|
@ -21,17 +21,25 @@ function el_url(s: string) -> string {
|
|||
}
|
||||
# border-image: url(chip.png) 14 / 12px - the source's corner size, then how wide they are drawn
|
||||
function el_border_image(ui_st: mut UiState, n: UiNode, s: string) -> void {
|
||||
var close = 0
|
||||
while close < len(s) and s[close] != 41 { close += 1 }
|
||||
n.bi_src = el_url(s[0..Math.min(close + 1, len(s))])
|
||||
let rest = mm_split(ui_st, s[Math.min(close + 1, len(s))..len(s)], 47)
|
||||
n.bi_slice = el_num(tpl_words(rest[0]))
|
||||
let m = mm_of(ui_st)
|
||||
var at = mm_find(m, MM_BIMG, s)
|
||||
if at < 0 {
|
||||
var close = 0
|
||||
while close < len(s) and s[close] != 41 { close += 1 }
|
||||
at = mm_add(m, MM_BIMG, s)
|
||||
if at < 0 { return }
|
||||
m.texts[at] = el_url(s[0..Math.min(close + 1, len(s))])
|
||||
m.lists[at] = lss_split(s[Math.min(close + 1, len(s))..len(s)], 47)
|
||||
}
|
||||
n.bi_src = m.texts[at]
|
||||
let rest = m.lists[at]
|
||||
n.bi_slice = el_num(tw(ui_st, rest[0]))
|
||||
n.bi_width = el_px(ui_st, n.bi_slice)
|
||||
if len(rest) > 1 { n.bi_width = el_unit(ui_st, tpl_words(rest[1])) }
|
||||
if len(rest) > 1 { n.bi_width = el_unit(ui_st, tw(ui_st, rest[1])) }
|
||||
}
|
||||
# box-shadow: 6px 10px 0 rgba(0, 0, 0, 0.45) - x, y, a blur this renderer draws sharp, the colour
|
||||
function el_shadow(ui_st: mut UiState, n: UiNode, s: string) -> void {
|
||||
if tpl_words(s) == "none" {
|
||||
if tw(ui_st, s) == "none" {
|
||||
n.sh_c = -2
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# shorthand, flex-shrink, order, text-shadow, pointer-events, text-fit and line-height (text_fit.ludic)
|
||||
function el_more(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
|
||||
let s = vl_text_u(ui_st, v)
|
||||
if key == "shrink" { nx(n).shrink = Math.max(el_num(s), 0.0) } else if key == "order" { nx(n).order = int(el_num(s)) } else if key == "text-shadow" { el_text_shadow(ui_st, n, s) } else if key == "pointer-events" { nx(n).no_pointer = tpl_words(s) == "none" } else if key == "text-fit" { el_text_fit(ui_st, n, s) } else if key == "line-height" { el_line_h(ui_st, n, s) } else { return el_fit_props(ui_st, n, key, s) }
|
||||
if key == "shrink" { nx(n).shrink = Math.max(el_num(s), 0.0) } else if key == "order" { nx(n).order = int(el_num(s)) } else if key == "text-shadow" { el_text_shadow(ui_st, n, s) } else if key == "pointer-events" { nx(n).no_pointer = tw(ui_st, s) == "none" } else if key == "text-fit" { el_text_fit(ui_st, n, s) } else if key == "line-height" { el_line_h(ui_st, n, s) } else { return el_fit_props(ui_st, n, key, s) }
|
||||
return true
|
||||
}
|
||||
# width or height: a length (0 included), fill, a percentage, calc(), or auto/fit (none)
|
||||
|
|
@ -71,7 +71,7 @@ function el_text_shadow(ui_st: mut UiState, n: UiNode, s: string) -> void {
|
|||
let x = nx(n)
|
||||
x.tsh_set = true
|
||||
x.tsh_c = -2
|
||||
if tpl_words(s) == "none" { return }
|
||||
if tw(ui_st, s) == "none" { return }
|
||||
let parts = mm_words(ui_st, s)
|
||||
var nums = 0
|
||||
var col = ""
|
||||
|
|
|
|||
|
|
@ -39,6 +39,13 @@ export state UiState {
|
|||
mm_ivals: []Val = null
|
||||
ev_depth: int = 0 # eval.ludic: a call's arguments, in lists kept one a depth
|
||||
ev_args: []Val = new []Val
|
||||
cv_texts: []string = new []string # units_pieces.ludic: a value's var() pieces, kept
|
||||
fit_out: []float = new []float # draw_content.ludic: an image's box, kept
|
||||
r3n_cut: []float = new []float # render3d_nine.ludic: a nine-slice's edges, kept
|
||||
r3n_xs: []float = new []float
|
||||
r3n_ys: []float = new []float
|
||||
r3n_us: []float = new []float
|
||||
r3n_vs: []float = new []float
|
||||
ly_depth: int = 0 # layout_run.ludic: the lists a line lays out with, one a depth
|
||||
ly_sizes: [][]float = new [][]float
|
||||
ly_frozen: [][]bool = new [][]bool
|
||||
|
|
@ -90,6 +97,8 @@ export state UiState {
|
|||
in_now: UiInput = new UiInput
|
||||
in_was_down: bool = false
|
||||
in_last: UiInput = new UiInput
|
||||
in_rec_a: UiInput = new UiInput
|
||||
in_rec_b: UiInput = new UiInput
|
||||
in_given: bool = false
|
||||
rp_next: []float = [-1.0, -1.0, -1.0, -1.0]
|
||||
rp_a: bool = false
|
||||
|
|
@ -109,14 +118,21 @@ export state UiState {
|
|||
lc_mounts: []UiAct = new []UiAct
|
||||
lc_unmounts: []UiAct = new []UiAct
|
||||
lc_envs: []UiEnv = new []UiEnv
|
||||
lc_sp_keys: []string = new []string # life.ludic: the spare set lc_run fills and swaps in
|
||||
lc_sp_unmounts: []UiAct = new []UiAct
|
||||
lc_sp_envs: []UiEnv = new []UiEnv
|
||||
lc_prev_keys: []string = new []string
|
||||
lc_prev_unmounts: []UiAct = new []UiAct
|
||||
lc_prev_envs: []UiEnv = new []UiEnv
|
||||
nt_list: []UiNative = new []UiNative
|
||||
nt_sp_nodes: []UiNode = new []UiNode # native.ludic: the queue's spare, swapped while it runs
|
||||
nt_sp_names: []string = new []string
|
||||
nt_sp_vals: []Val = new []Val
|
||||
nt_q_nodes: []UiNode = new []UiNode
|
||||
nt_q_names: []string = new []string
|
||||
nt_q_vals: []Val = new []Val
|
||||
fr_hover: []string = new []string
|
||||
fr_hover_sp: []string = new []string
|
||||
fr_press_key: string = ""
|
||||
fr_down_now: bool = false
|
||||
fr_key_press: string = "" # the control Enter or the pad's A is holding down
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ function bd_class(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string, out: []Ui
|
|||
}
|
||||
cls.props(it.ptr, props)
|
||||
let ce = env_new(ui_st, null)
|
||||
ce.model = cls.model(it.ptr)
|
||||
if it.model == null { it.model = Value.object() }
|
||||
ce.model = cls.model(it.ptr, it.model)
|
||||
ce.inst = it
|
||||
ce.ctx = e.ctx
|
||||
ce.slot = k
|
||||
|
|
|
|||
|
|
@ -9,12 +9,14 @@ export property UiClass {
|
|||
lss: string = ""
|
||||
make: fn() -> pointer = null
|
||||
props: fn(pointer, Val) -> void = null
|
||||
model: fn(pointer) -> Val = null
|
||||
model: fn(pointer, Val) -> Val = null # fills the object it is given (the instance keeps one)
|
||||
call: fn(pointer, string, Val) -> Val = null
|
||||
root: UiTpl = null # the template, once read
|
||||
sheet: UiSheet = null
|
||||
seen_xml: string = "" # the files as a developer's build last found them on disk
|
||||
seen_lss: string = ""
|
||||
use: UiTpl = null # screen_class.ludic: the element that shows it as a screen, made once
|
||||
none: Val = null # and the empty model it is shown with
|
||||
}
|
||||
export function ui_register(ui_st: mut UiState, k: UiClass) -> int {
|
||||
push(ui_st.uc_list, k)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,24 @@
|
|||
# color.ludic - CSS colours: #rgb, #rgba, #rrggbb, #rrggbbaa, rgb(r, g, b), rgba(r, g, b, a), the
|
||||
# basic names, transparent and none. A colour is 0xRRGGBB; its alpha is left in cl_alpha.
|
||||
const CL_NAMES: string = " black=000000 white=ffffff red=ff0000 green=008000 lime=00ff00 blue=0000ff yellow=ffff00 cyan=00ffff aqua=00ffff magenta=ff00ff fuchsia=ff00ff gray=808080 grey=808080 silver=c0c0c0 maroon=800000 olive=808000 navy=000080 purple=800080 teal=008080 orange=ffa500 "
|
||||
# a colour is worked out once per text and kept with its alpha
|
||||
function ui_color(ui_st: mut UiState, name0: string) -> int {
|
||||
let name = tpl_words(name0)
|
||||
let m = mm_of(ui_st)
|
||||
let i = mm_find(m, MM_COLOR, name0)
|
||||
if i >= 0 {
|
||||
ui_st.cl_alpha = m.n2[i]
|
||||
return int(m.n1[i])
|
||||
}
|
||||
let c = ui_color_new(ui_st, name0)
|
||||
let j = mm_add(m, MM_COLOR, name0)
|
||||
if j >= 0 {
|
||||
m.n1[j] = float(c)
|
||||
m.n2[j] = ui_st.cl_alpha
|
||||
}
|
||||
return c
|
||||
}
|
||||
function ui_color_new(ui_st: mut UiState, name0: string) -> int {
|
||||
let name = tw(ui_st, name0)
|
||||
ui_st.cl_alpha = 1.0
|
||||
if name == "none" or name == "" or name == "transparent" { return UI_NONE }
|
||||
if name[0] == 35 { return cl_hex_at(ui_st, name, 1, len(name) - 1) }
|
||||
|
|
@ -38,8 +54,8 @@ function cl_rgb(ui_st: mut UiState, s: string) -> int {
|
|||
while open < len(s) and s[open] != 40 { open += 1 }
|
||||
let parts = mm_split(ui_st, s[open + 1..len(s) - 1], 44)
|
||||
var c = 0
|
||||
for i in 0 .. Math.min(3, len(parts)) { c = c * 256 + Math.clamp(int(el_num(tpl_words(parts[i]))), 0, 255) }
|
||||
if len(parts) > 3 { ui_st.cl_alpha = el_num(tpl_words(parts[3])) }
|
||||
for i in 0 .. Math.min(3, len(parts)) { c = c * 256 + Math.clamp(int(el_num(tw(ui_st, parts[i]))), 0, 255) }
|
||||
if len(parts) > 3 { ui_st.cl_alpha = el_num(tw(ui_st, parts[3])) }
|
||||
return c
|
||||
}
|
||||
# a colour as #rrggbb, for a dump or a test
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ function fr_image(ui_st: mut UiState, n: UiNode) -> void {
|
|||
nat_w = ui_st.ui_be.image_w(n.src)
|
||||
nat_h = ui_st.ui_be.image_h(n.src)
|
||||
}
|
||||
let r = ui_object_fit(n, nat_w, nat_h)
|
||||
let r = ui_object_fit_into(ui_st.fit_out, n, nat_w, nat_h)
|
||||
let clipped = ui_st.ui_be.clip != null and (r[2] > n.cw - ly_hin(n) or r[3] > n.ch - ly_vin(n))
|
||||
if clipped { fr_clip_push(ui_st, n.x + n.pl + n.bl, n.y + n.pt + n.bt, n.cw - ly_hin(n), n.ch - ly_vin(n)) }
|
||||
ui_st.ui_be.image(n.src, r[0], r[1], r[2], r[3], c, a)
|
||||
|
|
|
|||
|
|
@ -19,22 +19,22 @@ function gr_parse(ui_st: mut UiState, s0: string) -> UiGradient {
|
|||
return g
|
||||
}
|
||||
function gr_parse_new(ui_st: mut UiState, s0: string) -> UiGradient {
|
||||
let s = tpl_words(s0)
|
||||
let s = tw(ui_st, s0)
|
||||
let parts = el_commas(s[16..len(s) - 1])
|
||||
let g = new UiGradient
|
||||
g.cols = new []int
|
||||
g.alphas = new []float
|
||||
g.at = new []float
|
||||
var from = 0
|
||||
if len(parts) > 0 and gr_dir(g, tpl_words(parts[0])) { from = 1 }
|
||||
if len(parts) > 0 and gr_dir(g, tw(ui_st, parts[0])) { from = 1 }
|
||||
for i in from .. len(parts) {
|
||||
let words = mm_words(ui_st, tpl_words(parts[i]))
|
||||
var col = tpl_words(parts[i])
|
||||
let words = mm_words(ui_st, tw(ui_st, parts[i]))
|
||||
var col = tw(ui_st, parts[i])
|
||||
var at = -1.0
|
||||
let last = words[len(words) - 1]
|
||||
if len(words) > 1 and last[len(last) - 1] == 37 {
|
||||
at = el_num(last) / 100.0
|
||||
col = tpl_words(col[0..len(col) - len(last)])
|
||||
col = tw(ui_st, col[0..len(col) - len(last)])
|
||||
}
|
||||
push(g.cols, ui_color(ui_st, col))
|
||||
push(g.alphas, ui_st.cl_alpha)
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
# more than half the box across or half of it down (each direction on its own, so a small key cap
|
||||
# keeps its round ends and has no seam), on whole pixels so the nine pieces meet exactly
|
||||
# x0 x1 x2 x3 then y0 y1 y2 y3: the columns' and the rows' edges
|
||||
export function ui_nine_cuts(x: float, y: float, w: float, h: float, dst: float) -> []float {
|
||||
export function ui_nine_cuts(x: float, y: float, w: float, h: float, dst: float) -> []float { return ui_nine_cuts_into(new []float, x, y, w, h, dst) }
|
||||
# the same into a list the caller keeps, emptied first
|
||||
function ui_nine_cuts_into(out: []float, x: float, y: float, w: float, h: float, dst: float) -> []float {
|
||||
let dx = Math.max(Math.min(dst, w / 2.0), 0.0)
|
||||
let dy = Math.max(Math.min(dst, h / 2.0), 0.0)
|
||||
let out = new []float
|
||||
List.clear(out)
|
||||
push(out, nn_px(x))
|
||||
push(out, nn_px(x + dx))
|
||||
push(out, nn_px(x + w - dx))
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ function fc_move(ui_st: mut UiState, step: int) -> void {
|
|||
}
|
||||
# the keys, after the tree is laid out: moving, then acting on what has the focus
|
||||
function fc_keys(ui_st: mut UiState, root: UiNode) -> void {
|
||||
ui_st.fc_list = new []UiNode
|
||||
List.clear(ui_st.fc_list)
|
||||
let top = pp_top(root)
|
||||
if top != null { fc_collect(ui_st, top) } else { fc_collect(ui_st, root) }
|
||||
if ct_key_capture(ui_st, ui_st.fc_list) { return }
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import "pool_reset.ludic"
|
|||
import "pool_reset_more.ludic"
|
||||
import "memo.ludic"
|
||||
import "memo_join.ludic"
|
||||
import "units_pieces.ludic"
|
||||
import "expr.ludic"
|
||||
import "expr_parse.ludic"
|
||||
import "expr_prim.ludic"
|
||||
|
|
|
|||
|
|
@ -34,8 +34,10 @@ function in_read(ui_st: mut UiState) -> void {
|
|||
return
|
||||
}
|
||||
ui_st.in_was_down = ui_st.in_now.down
|
||||
var i = ui_st.in_rec_a # the package's own two records, in turn (never a host's)
|
||||
if ui_st.in_now == ui_st.in_rec_a { i = ui_st.in_rec_b }
|
||||
ui_st.in_last = ui_st.in_now
|
||||
let i = new UiInput
|
||||
in_reset(i)
|
||||
if ui_st.ui_be != null and ui_st.ui_be.input {
|
||||
let ps = in_pointer_scale(ui_st)
|
||||
i.x = float(Input.mouse_x()) * ps
|
||||
|
|
@ -81,3 +83,31 @@ export function ui_input(ui_st: mut UiState, i: UiInput) -> void {
|
|||
ui_st.in_now = i
|
||||
ui_st.in_given = true
|
||||
}
|
||||
# every field back to its default (generated from UiInput)
|
||||
function in_reset(i: UiInput) -> void {
|
||||
i.x = -1.0
|
||||
i.y = -1.0
|
||||
i.down = false
|
||||
i.wheel = 0.0
|
||||
i.tab = false
|
||||
i.shift = false
|
||||
i.up = false
|
||||
i.down_key = false
|
||||
i.left = false
|
||||
i.right = false
|
||||
i.enter = false
|
||||
i.space = false
|
||||
i.escape = false
|
||||
i.backspace = false
|
||||
i.typed = ""
|
||||
i.key = 0
|
||||
i.held_up = false
|
||||
i.held_down = false
|
||||
i.held_left = false
|
||||
i.held_right = false
|
||||
i.pad_a = false
|
||||
i.pad_b = false
|
||||
i.held_enter = false
|
||||
i.down_right = false
|
||||
i.down_middle = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ property UiInst {
|
|||
ptr: pointer = null
|
||||
seen: int = 0
|
||||
props: Val = null # its props, filled again each frame into the same object
|
||||
model: Val = null # and its model, filled in place by the class's model()
|
||||
}
|
||||
function in_get(ui_st: mut UiState, key: string, k: UiClass) -> UiInst {
|
||||
for i in 0 .. len(ui_st.in_list) {
|
||||
|
|
@ -25,10 +26,13 @@ function in_get(ui_st: mut UiState, key: string, k: UiClass) -> UiInst {
|
|||
}
|
||||
# after a build of `screen`: its instances the build did not reach are unmounted
|
||||
function in_sweep(ui_st: mut UiState, screen: string) -> void {
|
||||
let keep = new []UiInst
|
||||
var kept = 0
|
||||
for i in 0 .. len(ui_st.in_list) {
|
||||
let it = ui_st.in_list[i]
|
||||
if it.seen == ui_st.in_build or not lc_mine(it.key, screen) { push(keep, it) }
|
||||
if it.seen == ui_st.in_build or not lc_mine(it.key, screen) {
|
||||
ui_st.in_list[kept] = it
|
||||
kept += 1
|
||||
}
|
||||
}
|
||||
ui_st.in_list = keep
|
||||
while len(ui_st.in_list) > kept { List.pop(ui_st.in_list) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ function ly_ratio(n: UiNode, fixed_w: float, avail: float) -> void {
|
|||
} else if fixed_w < 0.0 and n.w != UI_FILL and n.h >= 0.0 { n.mw = n.h * r }
|
||||
}
|
||||
# x, y, w, h: a `nat_w` x `nat_h` picture in the node's content box by its object-fit
|
||||
export function ui_object_fit(n: UiNode, nat_w: float, nat_h: float) -> []float {
|
||||
export function ui_object_fit(n: UiNode, nat_w: float, nat_h: float) -> []float { return ui_object_fit_into(new []float, n, nat_w, nat_h) }
|
||||
function ui_object_fit_into(out: []float, n: UiNode, nat_w: float, nat_h: float) -> []float {
|
||||
let bx = n.x + n.pl + n.bl
|
||||
let by = n.y + n.pt + n.bt
|
||||
let bw = n.cw - ly_hin(n)
|
||||
|
|
@ -29,7 +30,7 @@ export function ui_object_fit(n: UiNode, nat_w: float, nat_h: float) -> []float
|
|||
w = nat_w * s
|
||||
h = nat_h * s
|
||||
}
|
||||
let out = new []float
|
||||
List.clear(out)
|
||||
push(out, bx + (bw - w) / 2.0)
|
||||
push(out, by + (bh - h) / 2.0)
|
||||
push(out, w)
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
# in last frame is mounted, and one that is gone is unmounted, each once, after the frame is drawn
|
||||
# a build starts its own records: a screen built twice keeps only the last build's
|
||||
function lc_begin(ui_st: mut UiState) -> void {
|
||||
ui_st.lc_keys = new []string
|
||||
ui_st.lc_mounts = new []UiAct
|
||||
ui_st.lc_unmounts = new []UiAct
|
||||
ui_st.lc_envs = new []UiEnv
|
||||
List.clear(ui_st.lc_keys)
|
||||
List.clear(ui_st.lc_mounts)
|
||||
List.clear(ui_st.lc_unmounts)
|
||||
List.clear(ui_st.lc_envs)
|
||||
}
|
||||
function lc_note(ui_st: mut UiState, key: string, names: []string, acts: []UiAct, e: UiEnv) -> void {
|
||||
var m: UiAct = null
|
||||
|
|
@ -29,9 +29,12 @@ function lc_run(ui_st: mut UiState, screen: string) -> void {
|
|||
for i in 0 .. len(ui_st.lc_keys) {
|
||||
if ui_st.lc_mounts[i] != null and not sel_has(ui_st.lc_prev_keys, ui_st.lc_keys[i]) { act_run(ui_st, ui_st.lc_mounts[i], ui_st.lc_envs[i]) }
|
||||
}
|
||||
let keys = new []string
|
||||
let unmounts = new []UiAct
|
||||
let envs = new []UiEnv
|
||||
let keys = ui_st.lc_sp_keys # the spare set, emptied: the records carried over
|
||||
let unmounts = ui_st.lc_sp_unmounts
|
||||
let envs = ui_st.lc_sp_envs
|
||||
List.clear(keys)
|
||||
List.clear(unmounts)
|
||||
List.clear(envs)
|
||||
for i in 0 .. len(ui_st.lc_prev_keys) {
|
||||
let k = ui_st.lc_prev_keys[i]
|
||||
if lc_mine(k, screen) {
|
||||
|
|
@ -47,11 +50,14 @@ function lc_run(ui_st: mut UiState, screen: string) -> void {
|
|||
push(unmounts, ui_st.lc_unmounts[i])
|
||||
push(envs, ui_st.lc_envs[i])
|
||||
}
|
||||
ui_st.lc_sp_keys = ui_st.lc_prev_keys
|
||||
ui_st.lc_sp_unmounts = ui_st.lc_prev_unmounts
|
||||
ui_st.lc_sp_envs = ui_st.lc_prev_envs
|
||||
ui_st.lc_prev_keys = keys
|
||||
ui_st.lc_prev_unmounts = unmounts
|
||||
ui_st.lc_prev_envs = envs
|
||||
ui_st.lc_keys = new []string
|
||||
ui_st.lc_mounts = new []UiAct
|
||||
ui_st.lc_unmounts = new []UiAct
|
||||
ui_st.lc_envs = new []UiEnv
|
||||
List.clear(ui_st.lc_keys)
|
||||
List.clear(ui_st.lc_mounts)
|
||||
List.clear(ui_st.lc_unmounts)
|
||||
List.clear(ui_st.lc_envs)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,21 @@ export property UiMemo {
|
|||
tags: []int = null # what kind of result: a separator, or a kind below
|
||||
lists: [][]string = null
|
||||
grads: []UiGradient = null
|
||||
texts: []string = null # a text worked out from the key: tw, el_url
|
||||
vals: []Val = null # a Value made from it: cs_vars_in's
|
||||
vtpls: []UiVarTpl = null
|
||||
n1: []float = null # numbers worked out from the key: a colour and its alpha
|
||||
n2: []float = null
|
||||
}
|
||||
const MM_WORDS: int = -1 # el_words: spaces, a bracket's own kept
|
||||
const MM_GRAD: int = -2
|
||||
const MM_JOIN: int = -3 # keys[i] is the joined text itself
|
||||
const MM_TW: int = -4 # tpl_words
|
||||
const MM_URL: int = -5 # el_url
|
||||
const MM_VARS: int = -6 # cs_vars_in: keys[i] is the text with every var() put in
|
||||
const MM_VTPL: int = -7 # a value's var()s parsed (units_pieces.ludic)
|
||||
const MM_COLOR: int = -8 # ui_color: n1 the colour, n2 its alpha
|
||||
const MM_BIMG: int = -9 # border-image: texts the picture, lists what follows its url()
|
||||
function mm_new() -> UiMemo {
|
||||
let m = new UiMemo
|
||||
m.slots = words(MM_CAP)
|
||||
|
|
@ -20,6 +31,11 @@ function mm_new() -> UiMemo {
|
|||
m.tags = new []int
|
||||
m.lists = new [][]string
|
||||
m.grads = new []UiGradient
|
||||
m.texts = new []string
|
||||
m.vals = new []Val
|
||||
m.vtpls = new []UiVarTpl
|
||||
m.n1 = new []float
|
||||
m.n2 = new []float
|
||||
return m
|
||||
}
|
||||
function mm_of(ui_st: mut UiState) -> UiMemo {
|
||||
|
|
@ -51,6 +67,11 @@ function mm_add(m: UiMemo, tag: int, s: string) -> int {
|
|||
push(m.tags, tag)
|
||||
push(m.lists, null)
|
||||
push(m.grads, null)
|
||||
push(m.texts, null)
|
||||
push(m.vals, null)
|
||||
push(m.vtpls, null)
|
||||
push(m.n1, 0.0)
|
||||
push(m.n2, 0.0)
|
||||
m.slots[at] = len(m.keys)
|
||||
return len(m.keys) - 1
|
||||
}
|
||||
|
|
@ -66,3 +87,24 @@ function mm_split(ui_st: mut UiState, s: string, c: int) -> []string {
|
|||
return parts
|
||||
}
|
||||
function mm_words(ui_st: mut UiState, s: string) -> []string { return mm_split(ui_st, s, MM_WORDS) }
|
||||
# tpl_words, made once per text (a clean one is its own answer, and nothing is kept for it)
|
||||
function tw(ui_st: mut UiState, s: string) -> string {
|
||||
if tpl_clean(s) { return s }
|
||||
let m = mm_of(ui_st)
|
||||
let i = mm_find(m, MM_TW, s)
|
||||
if i >= 0 { return m.texts[i] }
|
||||
let t = tpl_words(s)
|
||||
let j = mm_add(m, MM_TW, s)
|
||||
if j >= 0 { m.texts[j] = t }
|
||||
return t
|
||||
}
|
||||
# el_url, made once per text
|
||||
function el_url_u(ui_st: mut UiState, s: string) -> string {
|
||||
let m = mm_of(ui_st)
|
||||
let i = mm_find(m, MM_URL, s)
|
||||
if i >= 0 { return m.texts[i] }
|
||||
let t = el_url(s)
|
||||
let j = mm_add(m, MM_URL, s)
|
||||
if j >= 0 { m.texts[j] = t }
|
||||
return t
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@ function mm_join(ui_st: mut UiState, a: string, sep: string, b: string) -> strin
|
|||
push(m.tags, MM_JOIN)
|
||||
push(m.lists, null)
|
||||
push(m.grads, null)
|
||||
push(m.texts, null)
|
||||
push(m.vals, null)
|
||||
push(m.vtpls, null)
|
||||
push(m.n1, 0.0)
|
||||
push(m.n2, 0.0)
|
||||
m.slots[at] = len(m.keys)
|
||||
return k
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ function nt_find(ui_st: UiState, tag: string) -> UiNative {
|
|||
return null
|
||||
}
|
||||
function nt_fired_clear(ui_st: mut UiState) -> void {
|
||||
ui_st.nt_q_nodes = new []UiNode
|
||||
ui_st.nt_q_names = new []string
|
||||
ui_st.nt_q_vals = new []Val
|
||||
List.clear(ui_st.nt_q_nodes)
|
||||
List.clear(ui_st.nt_q_names)
|
||||
List.clear(ui_st.nt_q_vals)
|
||||
}
|
||||
export function ui_fire(ui_st: mut UiState, n: UiNode, name: string, value: Val) -> void {
|
||||
push(ui_st.nt_q_nodes, n)
|
||||
|
|
@ -49,11 +49,17 @@ export function ui_fire(ui_st: mut UiState, n: UiNode, name: string, value: Val)
|
|||
push(ui_st.nt_q_vals, value)
|
||||
}
|
||||
function nt_fired_run(ui_st: mut UiState) -> void {
|
||||
let nodes = ui_st.nt_q_nodes
|
||||
let nodes = ui_st.nt_q_nodes # run from these while what they fire goes to the spares
|
||||
let names = ui_st.nt_q_names
|
||||
let vals = ui_st.nt_q_vals
|
||||
ui_st.nt_q_nodes = ui_st.nt_sp_nodes
|
||||
ui_st.nt_q_names = ui_st.nt_sp_names
|
||||
ui_st.nt_q_vals = ui_st.nt_sp_vals
|
||||
nt_fired_clear(ui_st)
|
||||
for i in 0 .. len(nodes) { nt_run(ui_st, nodes[i], names[i], vals[i]) }
|
||||
ui_st.nt_sp_nodes = nodes
|
||||
ui_st.nt_sp_names = names
|
||||
ui_st.nt_sp_vals = vals
|
||||
}
|
||||
# the element's on-<name>, with `event` bound to what happened
|
||||
function nt_run(ui_st: mut UiState, n: UiNode, name: string, value: Val) -> void {
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ function fr_was_hovered(ui_st: UiState, key: string) -> bool { return sel_has(ui
|
|||
function fr_pointer(ui_st: mut UiState, root: UiNode) -> void {
|
||||
let i = ui_st.in_now
|
||||
ui_st.fr_down_now = i.down
|
||||
let keys = new []string
|
||||
let keys = ui_st.fr_hover_sp # the spare list, emptied; last frame's goes spare
|
||||
List.clear(keys)
|
||||
let top = pp_top(root)
|
||||
var scope = root
|
||||
if top != null { scope = top }
|
||||
fr_under(scope, i.x, i.y, keys)
|
||||
ui_st.fr_hover_sp = ui_st.fr_hover
|
||||
ui_st.fr_hover = keys
|
||||
if top != null and pp_pointer(ui_st, top) { return }
|
||||
if ui_st.sc_drag != "" or ct_key_mouse(ui_st, root) { return }
|
||||
|
|
|
|||
|
|
@ -8,29 +8,11 @@ function fr_in(n: UiNode, px: float, py: float) -> bool {
|
|||
if n.ex != null and n.ex.no_pointer { return false }
|
||||
return px >= n.x and py >= n.y and px < n.x + n.cw and py < n.y + n.ch
|
||||
}
|
||||
# the nearest element that wants `kind`, out from the topmost one under the point
|
||||
# the nearest element that wants `kind`, out from the topmost one under the point: the children are
|
||||
# walked the other way from how they are painted (positioned ones by z-index, highest first, then
|
||||
# the flow, last first; a popover is on the top layer, not here), with no list made for it
|
||||
function fr_pick(n: UiNode, px: float, py: float, kind: int) -> UiNode {
|
||||
let kids = fr_paint_rev(n)
|
||||
for i in 0 .. len(kids) {
|
||||
if fr_in(kids[i], px, py) {
|
||||
let r = fr_pick(kids[i], px, py, kind)
|
||||
if r != null { return r }
|
||||
return fr_wants(n, kind)
|
||||
}
|
||||
}
|
||||
return fr_wants(n, kind)
|
||||
}
|
||||
function fr_wants(n: UiNode, kind: int) -> UiNode {
|
||||
if kind == PK_CONTROL and (n.focusable or n.act != null) { return n }
|
||||
if kind == PK_POINTER and pe_wants(n, false) { return n }
|
||||
if kind == PK_WHEEL and pe_wants(n, true) { return n }
|
||||
return null
|
||||
}
|
||||
# the children the other way from how they are painted: positioned ones by z-index, highest first,
|
||||
# then the flow, last first; a popover is on the top layer, not here
|
||||
function fr_paint_rev(n: UiNode) -> []UiNode {
|
||||
let out = new []UiNode
|
||||
if n.children == null { return out }
|
||||
if n.children == null { return fr_wants(n, kind) }
|
||||
var lo = 1000000
|
||||
var hi = -1000000
|
||||
for i in 0 .. len(n.children) {
|
||||
|
|
@ -45,15 +27,27 @@ function fr_paint_rev(n: UiNode) -> []UiNode {
|
|||
var i = len(n.children) - 1
|
||||
while i >= 0 {
|
||||
let c = n.children[i]
|
||||
if c.pos != 0 and not c.popover and c.z == z { push(out, c) }
|
||||
if c.pos != 0 and not c.popover and c.z == z and fr_in(c, px, py) { return fr_pick_in(n, c, px, py, kind) }
|
||||
i -= 1
|
||||
}
|
||||
z -= 1
|
||||
}
|
||||
var k = len(n.children) - 1
|
||||
while k >= 0 {
|
||||
if n.children[k].pos == 0 and not n.children[k].popover { push(out, n.children[k]) }
|
||||
let c = n.children[k]
|
||||
if c.pos == 0 and not c.popover and fr_in(c, px, py) { return fr_pick_in(n, c, px, py, kind) }
|
||||
k -= 1
|
||||
}
|
||||
return out
|
||||
return fr_wants(n, kind)
|
||||
}
|
||||
function fr_pick_in(n: UiNode, c: UiNode, px: float, py: float, kind: int) -> UiNode {
|
||||
let r = fr_pick(c, px, py, kind)
|
||||
if r != null { return r }
|
||||
return fr_wants(n, kind)
|
||||
}
|
||||
function fr_wants(n: UiNode, kind: int) -> UiNode {
|
||||
if kind == PK_CONTROL and (n.focusable or n.act != null) { return n }
|
||||
if kind == PK_POINTER and pe_wants(n, false) { return n }
|
||||
if kind == PK_WHEEL and pe_wants(n, true) { return n }
|
||||
return null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ function r3u_nine(render3d_st: mut Render3dState, ui_st: mut UiState, src: strin
|
|||
if t == 0 { return }
|
||||
let su = slice / float(Math.max(tex_width(render3d_st, t), 1))
|
||||
let sv = slice / float(Math.max(tex_height(render3d_st, t), 1))
|
||||
let cut = ui_nine_cuts(x, y, w, h, dst)
|
||||
let xs = r3u_four(cut[0], cut[1], cut[2], cut[3])
|
||||
let ys = r3u_four(cut[4], cut[5], cut[6], cut[7])
|
||||
let us = r3u_four(0.0, su, 1.0 - su, 1.0)
|
||||
let vs = r3u_four(0.0, sv, 1.0 - sv, 1.0)
|
||||
let cut = ui_nine_cuts_into(ui_st.r3n_cut, x, y, w, h, dst)
|
||||
let xs = r3u_four(ui_st.r3n_xs, cut[0], cut[1], cut[2], cut[3])
|
||||
let ys = r3u_four(ui_st.r3n_ys, cut[4], cut[5], cut[6], cut[7])
|
||||
let us = r3u_four(ui_st.r3n_us, 0.0, su, 1.0 - su, 1.0)
|
||||
let vs = r3u_four(ui_st.r3n_vs, 0.0, sv, 1.0 - sv, 1.0)
|
||||
for j in 0 .. 3 {
|
||||
for i in 0 .. 3 {
|
||||
let x0 = int(xs[i])
|
||||
|
|
@ -21,8 +21,8 @@ function r3u_nine(render3d_st: mut Render3dState, ui_st: mut UiState, src: strin
|
|||
}
|
||||
}
|
||||
}
|
||||
function r3u_four(a: float, b: float, c: float, d: float) -> []float {
|
||||
let out = new []float
|
||||
function r3u_four(out: []float, a: float, b: float, c: float, d: float) -> []float {
|
||||
List.clear(out)
|
||||
push(out, a)
|
||||
push(out, b)
|
||||
push(out, c)
|
||||
|
|
|
|||
|
|
@ -7,16 +7,21 @@ function fr_class_nodes(ui_st: mut UiState, cls: UiClass) -> UiNode {
|
|||
ui_st.ui_view = null
|
||||
uc_load(ui_st, cls)
|
||||
let root = fr_root(ui_st, cls.name, cls.sheet)
|
||||
let use = new UiTpl
|
||||
use.tag = cls.name
|
||||
use.cls = cls
|
||||
use.keys = new []string
|
||||
use.vals = new []UiExpr
|
||||
use.on_keys = new []string
|
||||
use.on_acts = new []UiAct
|
||||
use.kids = new []UiTpl
|
||||
if cls.use == null {
|
||||
let use = new UiTpl
|
||||
use.tag = cls.name
|
||||
use.cls = cls
|
||||
use.keys = new []string
|
||||
use.vals = new []UiExpr
|
||||
use.on_keys = new []string
|
||||
use.on_acts = new []UiAct
|
||||
use.kids = new []UiTpl
|
||||
cls.use = use
|
||||
cls.none = Value.object()
|
||||
}
|
||||
let use = cls.use
|
||||
let e = env_new(ui_st, null)
|
||||
e.model = Value.object()
|
||||
e.model = cls.none
|
||||
root.env = e
|
||||
bd_class(ui_st, use, e, cls.name, root.children)
|
||||
in_sweep(ui_st, cls.name)
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
# size, and cuts what still does not fit with an ellipsis; line-height (a multiple of the font size,
|
||||
# px or em) spaces a text's lines. Both are inherited, as font properties are.
|
||||
function el_text_fit(ui_st: mut UiState, n: UiNode, s: string) -> void {
|
||||
let parts = mm_split(ui_st, tpl_words(s), 32)
|
||||
let parts = mm_split(ui_st, tw(ui_st, s), 32)
|
||||
nx(n).fit_min = 0.0
|
||||
if len(parts) >= 2 and parts[0] == "shrink" { nx(n).fit_min = Math.max(el_unit(ui_st, parts[1]), 1.0) }
|
||||
}
|
||||
function el_line_h(ui_st: UiState, n: UiNode, s0: string) -> void {
|
||||
let s = tpl_words(s0)
|
||||
function el_line_h(ui_st: mut UiState, n: UiNode, s0: string) -> void {
|
||||
let s = tw(ui_st, s0)
|
||||
let x = nx(n)
|
||||
x.lh_kind = 0
|
||||
if s == "normal" or s == "" { return }
|
||||
|
|
|
|||
|
|
@ -46,37 +46,31 @@ function cs_var(n: UiNode, name: string) -> string {
|
|||
}
|
||||
return null
|
||||
}
|
||||
# a value with var(--name) or var(--name, fallback) in it, with each replaced by what it names
|
||||
# a value with var(--name) or var(--name, fallback) in it, with each replaced by what it names. What
|
||||
# it becomes is found by its pieces - stretches of the value and each var's text - compared in place,
|
||||
# so a result seen before (every frame's, nearly always) is its kept Value, and nothing is built
|
||||
function cs_vars_in(ui_st: mut UiState, n: UiNode, v: Val) -> Val {
|
||||
if Value.kind(v) != 4 { return v }
|
||||
let s = Value.as_str(v)
|
||||
var at = 0
|
||||
var out = ""
|
||||
var found = false
|
||||
var i = 0
|
||||
while i + 4 <= len(s) {
|
||||
if sat(s, i, "var(") {
|
||||
found = true
|
||||
var j = i + 4
|
||||
var depth = 1
|
||||
while j < len(s) and depth > 0 {
|
||||
if s[j] == 40 { depth += 1 }
|
||||
if s[j] == 41 { depth -= 1 }
|
||||
j += 1
|
||||
}
|
||||
out = out + s[at..i] + cs_var_ref(ui_st, n, s[i + 4..j - 1])
|
||||
at = j
|
||||
i = j
|
||||
} else { i += 1 }
|
||||
if not cv_pieces(ui_st, n, s) { return v }
|
||||
let m = mm_of(ui_st)
|
||||
var at = cv_hash(ui_st) & (MM_CAP - 1)
|
||||
while m.slots[at] != 0 {
|
||||
let i = m.slots[at] - 1
|
||||
if m.tags[i] == MM_VARS and cv_same(ui_st, m.keys[i]) { return m.vals[i] }
|
||||
at = (at + 1) & (MM_CAP - 1)
|
||||
}
|
||||
if not found { return v }
|
||||
return Value.str(tpl_words(out + s[at..len(s)]))
|
||||
let raw = cv_join(ui_st)
|
||||
let r = Value.str(tpl_words(raw))
|
||||
let j = mm_add(m, MM_VARS, raw)
|
||||
if j >= 0 { m.vals[j] = r }
|
||||
return r
|
||||
}
|
||||
function cs_var_ref(ui_st: mut UiState, n: UiNode, inner: string) -> string {
|
||||
let parts = mm_split(ui_st, inner, 44)
|
||||
let v = cs_var(n, tpl_words(parts[0]))
|
||||
let v = cs_var(n, tw(ui_st, parts[0]))
|
||||
if v != null { return v }
|
||||
if len(parts) > 1 { return tpl_words(inner[len(parts[0]) + 1..len(inner)]) }
|
||||
ui_err(ui_st, `var({tpl_words(parts[0])}): no element here or above sets it`)
|
||||
if len(parts) > 1 { return tw(ui_st, inner[len(parts[0]) + 1..len(inner)]) }
|
||||
ui_err(ui_st, `var({tw(ui_st, parts[0])}): no element here or above sets it`)
|
||||
return ""
|
||||
}
|
||||
|
|
|
|||
93
packages/ludic.ui/units_pieces.ludic
Normal file
93
packages/ludic.ui/units_pieces.ludic
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# units_pieces.ludic - a value with var()s, parsed once by its text into its stretches, the names it
|
||||
# asks for and their fallbacks; each frame its pieces are those stretches and what the names hold
|
||||
# here, in a list kept on the state, hashed and compared against the memo without a copy
|
||||
export property UiVarTpl {
|
||||
lits: []string = null # the text around the var()s: one more than there are names
|
||||
names: []string = null
|
||||
falls: []string = null # a var's fallback, or null
|
||||
}
|
||||
function cv_tpl(ui_st: mut UiState, s: string) -> UiVarTpl {
|
||||
let m = mm_of(ui_st)
|
||||
let i = mm_find(m, MM_VTPL, s)
|
||||
if i >= 0 { return m.vtpls[i] }
|
||||
let t = cv_parse(ui_st, s)
|
||||
let j = mm_add(m, MM_VTPL, s)
|
||||
if j >= 0 { m.vtpls[j] = t }
|
||||
return t
|
||||
}
|
||||
function cv_parse(ui_st: mut UiState, s: string) -> UiVarTpl {
|
||||
let t = new UiVarTpl
|
||||
t.lits = new []string
|
||||
t.names = new []string
|
||||
t.falls = new []string
|
||||
var at = 0
|
||||
var i = 0
|
||||
while i + 4 <= len(s) {
|
||||
if sat(s, i, "var(") {
|
||||
var j = i + 4
|
||||
var depth = 1
|
||||
while j < len(s) and depth > 0 {
|
||||
if s[j] == 40 { depth += 1 }
|
||||
if s[j] == 41 { depth -= 1 }
|
||||
j += 1
|
||||
}
|
||||
push(t.lits, s[at..i])
|
||||
let inner = s[i + 4..j - 1]
|
||||
let parts = lss_split(inner, 44)
|
||||
push(t.names, tpl_words(parts[0]))
|
||||
if len(parts) > 1 { push(t.falls, tpl_words(inner[len(parts[0]) + 1..len(inner)])) } else { push(t.falls, null) }
|
||||
at = j
|
||||
i = j
|
||||
} else { i += 1 }
|
||||
}
|
||||
push(t.lits, s[at..len(s)])
|
||||
return t
|
||||
}
|
||||
# this element's pieces for `s` into cv_texts; false when it has no var() at all
|
||||
function cv_pieces(ui_st: mut UiState, n: UiNode, s: string) -> bool {
|
||||
if not cv_has(s) { return false }
|
||||
let t = cv_tpl(ui_st, s)
|
||||
List.clear(ui_st.cv_texts)
|
||||
for k in 0 .. len(t.names) {
|
||||
push(ui_st.cv_texts, t.lits[k])
|
||||
push(ui_st.cv_texts, cv_value(ui_st, n, t, k))
|
||||
}
|
||||
push(ui_st.cv_texts, t.lits[len(t.names)])
|
||||
return true
|
||||
}
|
||||
function cv_has(s: string) -> bool {
|
||||
for i in 0 .. len(s) - 3 {
|
||||
if s[i] == 118 and sat(s, i, "var(") { return true }
|
||||
}
|
||||
return false
|
||||
}
|
||||
function cv_value(ui_st: mut UiState, n: UiNode, t: UiVarTpl, k: int) -> string {
|
||||
let v = cs_var(n, t.names[k])
|
||||
if v != null { return v }
|
||||
if t.falls[k] != null { return t.falls[k] }
|
||||
ui_err(ui_st, `var({t.names[k]}): no element here or above sets it`)
|
||||
return ""
|
||||
}
|
||||
function cv_hash(ui_st: UiState) -> int {
|
||||
var h = 216613626 ^ (MM_VARS & 255)
|
||||
for p in 0 .. len(ui_st.cv_texts) {
|
||||
let t = ui_st.cv_texts[p]
|
||||
for i in 0 .. len(t) { h = ((h ^ t[i]) * 16777619) & 2147483647 }
|
||||
}
|
||||
return h
|
||||
}
|
||||
# the pieces, one after another, are exactly `k`
|
||||
function cv_same(ui_st: UiState, k: string) -> bool {
|
||||
var at = 0
|
||||
for p in 0 .. len(ui_st.cv_texts) {
|
||||
let t = ui_st.cv_texts[p]
|
||||
if not sat(k, at, t) { return false }
|
||||
at += len(t)
|
||||
}
|
||||
return at == len(k)
|
||||
}
|
||||
function cv_join(ui_st: UiState) -> string {
|
||||
var out = ""
|
||||
for p in 0 .. len(ui_st.cv_texts) { out = out + ui_st.cv_texts[p] }
|
||||
return out
|
||||
}
|
||||
|
|
@ -69,6 +69,42 @@ function value_put(obj: Val, key: pointer, item: Val) -> Val {
|
|||
# --- accessors --------------------------------------------------------------
|
||||
function value_kind(v: Val) -> int { return v.tag }
|
||||
function value_count(v: Val) -> int { return value_n(v) }
|
||||
# a scalar field of an object set in place: the Value under `key` is changed when it is already that
|
||||
# kind, and made only the first time (a component's model, filled into the same object every frame)
|
||||
function value_slot(o: Val, key: pointer, tag: int) -> Val {
|
||||
value_lists(o)
|
||||
var i = 0
|
||||
while i < len(o.keys) {
|
||||
if o.keys[i] == key {
|
||||
if o.kids[i].tag == tag { return o.kids[i] }
|
||||
let v = value_new(tag)
|
||||
o.kids[i] = v
|
||||
return v
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
let v = value_new(tag)
|
||||
push(o.keys, key)
|
||||
push(o.kids, v)
|
||||
return v
|
||||
}
|
||||
function value_set_int(o: Val, key: pointer, n: int) -> void {
|
||||
let v = value_slot(o, key, 1)
|
||||
v.num = n
|
||||
}
|
||||
function value_set_float(o: Val, key: pointer, x: float) -> void {
|
||||
let v = value_slot(o, key, 7)
|
||||
v.num = float_bits(x)
|
||||
}
|
||||
function value_set_str(o: Val, key: pointer, s: pointer) -> void {
|
||||
let v = value_slot(o, key, 4)
|
||||
v.txt = s
|
||||
}
|
||||
function value_set_bool(o: Val, key: pointer, b: bool) -> void {
|
||||
let v = value_slot(o, key, 3)
|
||||
v.num = 0
|
||||
if b { v.num = 1 }
|
||||
}
|
||||
# a list or an object emptied in place, its room kept - for one filled again every frame
|
||||
function value_clear(v: Val) -> void {
|
||||
if v.kids == null { return }
|
||||
|
|
|
|||
|
|
@ -23,24 +23,31 @@ function cm_from(c: int, ty: pointer, x: pointer) -> pointer {
|
|||
cm_err(c, `a prop or state is an int, a float, a bool, a string or a Val, not a {ty}`)
|
||||
return x
|
||||
}
|
||||
# the model is filled into the object the instance keeps (ludic.ui's): a scalar field updates its own
|
||||
# Value in place, so showing a component allocates nothing for it frame after frame
|
||||
function cm_model_src(c: int, px: pointer, rec: pointer, head: Node) -> pointer {
|
||||
var src = `function {px}model(p: pointer) -> Val {{\n let s: {rec} = p\n let o = value_object()\n`
|
||||
var src = `function {px}model(p: pointer, o: Val) -> Val {{\n let s: {rec} = p\n`
|
||||
var i = 0
|
||||
while i < len(g_cm_keep[c]) {
|
||||
let k = g_cm_keep[c][i]
|
||||
let put = cm_to(c, g_cm_keep_ty[c][i], "s." + k, head)
|
||||
src = src + ` value_put(o, "{k}", {put})\n`
|
||||
src = src + cm_set(c, g_cm_keep_ty[c][i], k, "s." + k, head)
|
||||
i += 1
|
||||
}
|
||||
i = 0
|
||||
while i < len(g_cm_fields[c]) {
|
||||
let g = g_cm_fields[c][i]
|
||||
let put = cm_to(c, g.ty, g.s + "(s)", head)
|
||||
src = src + ` value_put(o, "{g_cm_fnames[c][i]}", {put})\n`
|
||||
src = src + cm_set(c, g.ty, g_cm_fnames[c][i], g.s + "(s)", head)
|
||||
i += 1
|
||||
}
|
||||
return src + " return o\n}\n"
|
||||
}
|
||||
function cm_set(c: int, ty: pointer, k: pointer, x: pointer, head: Node) -> pointer {
|
||||
if (ty == "int") { return ` value_set_int(o, "{k}", {x})\n` }
|
||||
if (ty == "float") { return ` value_set_float(o, "{k}", {x})\n` }
|
||||
if (ty == "string") { return ` value_set_str(o, "{k}", {x})\n` }
|
||||
if (ty == "bool") { return ` value_set_bool(o, "{k}", {x})\n` }
|
||||
return ` value_put(o, "{k}", {cm_to(c, ty, x, head)})\n`
|
||||
}
|
||||
function cm_to(c: int, ty: pointer, x: pointer, head: Node) -> pointer {
|
||||
if (ty == "Val") { return x }
|
||||
let conv = vw_conv(0, ty, x, head)
|
||||
|
|
|
|||
44743
selfhost/ludicc.seed.ll
44743
selfhost/ludicc.seed.ll
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue