ludic/packages/ludic.ui/cascade.ludic

75 lines
3 KiB
Text

# cascade.ludic - once the frame's tree is built, every element is styled as a browser would:
# the default sheet, then the file's rules from least to most specific, then its style="...", then
# its own attributes. Then what is display: none leaves the tree.
function cs_tree(ui_st: mut UiState, n: UiNode) -> void {
for i in 0 .. len(n.children) {
let c = n.children[i]
c.parent = n
c.index = i
}
if n.tag != "" { cs_node(ui_st, n) }
for i in 0 .. len(n.children) { cs_tree(ui_st, n.children[i]) }
var kept = 0
for i in 0 .. len(n.children) {
if not n.children[i].hidden {
n.children[kept] = n.children[i]
kept += 1
}
}
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
# element ends with (again when it zooms, so its own lengths are zoomed)
function cs_node(ui_st: mut UiState, n: UiNode) -> void {
ui_st.cs_pass = 1
cs_styles(ui_st, n)
if zm_own(n) != 1.0 { cs_styles(ui_st, n) }
ui_st.cs_pass = 0
cs_styles(ui_st, n)
an_apply(ui_st, n)
tr_apply(ui_st, n)
}
function cs_styles(ui_st: mut UiState, n: UiNode) -> void {
cs_sheet(ui_st, n, ua_sheet(ui_st))
if n.ups != null { cs_merged(ui_st, n) } else if n.sheet != null { cs_sheet(ui_st, n, n.sheet) }
if n.style != null { cs_rule(ui_st, n, n.style) }
if n.ups != null {
for i in 0 .. len(n.ups) {
if n.ups[i].style != null { cs_rule_in(ui_st, n, n.ups[i].style, n.ups[i].env) }
}
}
for i in 0 .. len(n.akeys) {
if cs_pass_ok(ui_st, n.akeys[i]) { el_apply(ui_st, n, n.akeys[i], n.vals[i]) }
}
}
function cs_pass_ok(ui_st: UiState, key: string) -> bool { return ui_st.cs_pass == 0 or at_alias(key) == "size" or key == "zoom" }
function cs_sheet(ui_st: mut UiState, n: UiNode, sh: UiSheet) -> void {
for i in 0 .. len(sh.rules) {
let r = sh.rules[i]
if md_ok(ui_st, r) and sel_match(ui_st, r.sel, n) { cs_rule(ui_st, n, r) }
}
}
function cs_rule(ui_st: mut UiState, n: UiNode, r: UiRule) -> void { cs_rule_in(ui_st, n, r, n.env) }
# a rule's custom properties first, so its other declarations can read them; values read in `e`
function cs_rule_in(ui_st: mut UiState, n: UiNode, r: UiRule, e: UiEnv) -> void {
for j in 0 .. len(r.keys) {
if len(r.keys[j]) > 2 and sat(r.keys[j], 0, "--") { el_attr(ui_st, n, r.keys[j], ui_eval(ui_st, r.vals[j], e)) }
}
for j in 0 .. len(r.keys) {
if not (len(r.keys[j]) > 2 and sat(r.keys[j], 0, "--")) and cs_pass_ok(ui_st, r.keys[j]) { el_attr(ui_st, n, r.keys[j], ui_eval(ui_st, r.vals[j], e)) }
}
}
function ua_sheet(ui_st: mut UiState) -> UiSheet {
if ui_st.ua_sh == null { ua_sheet_make(ui_st) }
return ui_st.ua_sh
}
@alloc_ok("once: the default sheet is read the first time a style is asked for")
function ua_sheet_make(ui_st: mut UiState) -> void {
let f = new UiFile
f.path = "the default sheet"
f.imp = new []UiFile
f.own = new []UiRule
lss_text(ui_st, f, UA_LSS)
ui_st.ua_sh = sheet_of(f)
}