ludic/packages/ludic.ui/attr.ludic

101 lines
5.6 KiB
Text

# attr.ludic - what a property sets, by its CSS name or the short one (width or w, background or
# bg, font-size or size, ...). An attribute on an element is the same property, applied last.
const AT_UNDRAWN: string = " font-weight font-family font-style box-shadow cursor transition animation letter-spacing text-decoration "
# a stylesheet's property: one that means nothing is said
function el_attr(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> void {
if el_apply(ui_st, n, key, v) { return }
@alloc_ok("only when a template is wrong: a broken screen, never a working one")
if lk_in(AT_UNDRAWN, at_alias(key)) { ui_err(ui_st, `{key}: this renderer does not draw it`) } else { ui_err(ui_st, `{key}: there is no such property`) }
}
# an element's attribute: a property when it names one, otherwise only there for [selectors]
function el_apply(ui_st: mut UiState, n: UiNode, key: string, v0: Val) -> bool {
let k = at_alias(key)
ui_st.el_cur = n
ui_st.el_key = k
if len(k) > 2 and sat(k, 0, "--") {
cs_var_set(n, k, vl_text_u(ui_st, v0))
return true
}
let v = cs_vars_in(ui_st, n, v0)
return el_size(ui_st, n, k, v) or el_box(ui_st, n, k, v) or el_flex(ui_st, n, k, v) or el_look(ui_st, n, k, v) or el_place_prop(ui_st, n, k, v) or el_edge(ui_st, n, k, v) or el_more(ui_st, n, k, v)
}
function at_alias(key: string) -> string {
# the CSS name to the short one; literals, so asking allocates nothing (asked per rule per element)
if key == "width" { return "w" }
if key == "height" { return "h" }
if key == "min-width" { return "min-w" }
if key == "max-width" { return "max-w" }
if key == "min-height" { return "min-h" }
if key == "max-height" { return "max-h" }
if key == "padding" { return "pad" }
if key == "background" { return "bg" }
if key == "background-color" { return "bg" }
if key == "font-size" { return "size" }
if key == "opacity" { return "alpha" }
if key == "flex-grow" { return "grow" }
if key == "flex-shrink" { return "shrink" }
if key == "flex-direction" { return "dir" }
if key == "flex-wrap" { return "wrap" }
if key == "justify-content" { return "justify" }
if key == "align-items" { return "align" }
if key == "align-self" { return "self" }
if key == "row-gap" { return "gap" }
if key == "column-gap" { return "gap" }
if key == "text-align" { return "talign" }
return key
}
function el_size(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
if key == "w" or key == "h" { el_dim(ui_st, n, key == "w", v) } else if key == "min-w" { n.min_w = el_len(ui_st, v) } else if key == "max-w" { n.max_w = el_len(ui_st, v) } else if key == "min-h" { n.min_h = el_len(ui_st, v) } else if key == "max-h" { n.max_h = el_len(ui_st, v) } else if key == "gap" { n.gap = el_len(ui_st, v) } else { return false }
return true
}
const EL_KEYS_FLEX: string = " align dir display flex grow justify self talign wrap "
function el_flex(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
if not lk_in(EL_KEYS_FLEX, key) { return false } # not one of its keys: no text made for it
if key == "grow" {
n.grow = el_numv(ui_st, v)
return true
}
let s = vl_text_u(ui_st, v)
if key == "dir" {
n.dir = UI_COL
if s == "row" { n.dir = UI_ROW }
} else if key == "grow" { n.grow = el_num(s) } else if key == "flex" { el_flex_short(ui_st, n, s) } else if key == "wrap" { n.wrap = s == "wrap" or (vl_truthy(v) and s != "false" and s != "nowrap") } else if key == "align" { n.align = el_place(v) } else if key == "self" { n.self = el_place(v) } else if key == "justify" { n.justify = el_place(v) } else if key == "talign" { n.talign = el_place(v) } else if key == "display" { n.hidden = s == "none" } else { return false }
return true
}
const EL_KEYS_LOOK: string = " alpha bg border border-bottom border-color border-left border-right border-top border-width color enabled size "
function el_look(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> bool {
if not lk_in(EL_KEYS_LOOK, key) { return false } # not one of its keys: no text made for it
if key == "alpha" {
n.alpha = el_numv(ui_st, v)
return true
}
let s = vl_text_u(ui_st, v)
if key == "size" { n.size = el_len(ui_st, v) } else if key == "color" {
n.fg = ui_color(ui_st, s)
n.fg_a = ui_st.cl_alpha
} else if key == "bg" {
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 {
n.bg = ui_color(ui_st, s)
n.bg_a = ui_st.cl_alpha
}
} else if key == "alpha" { n.alpha = el_num(s) } else if key == "enabled" { n.enabled = vl_truthy(v) and s != "false" } else if key == "border-color" {
n.border_c = ui_color(ui_st, s)
n.border_a = ui_st.cl_alpha
} else if key == "border-width" { el_sides_border(n, el_len(ui_st, v)) } else if key == "border" { el_border(ui_st, n, s) } else if key == "border-top" or key == "border-right" or key == "border-bottom" or key == "border-left" { el_border_side(ui_st, n, key, s) } else { return false }
return true
}
# border: 1 #ffcc00, or 1px solid accent
function el_border(ui_st: mut UiState, n: UiNode, s: string) -> void {
let parts = mm_split(ui_st, s, 32)
for i in 0 .. len(parts) {
let p = parts[i]
if len(p) > 0 and ((p[0] >= 48 and p[0] <= 57) or p[0] == 46) { el_sides_border(n, el_unit(ui_st, p)) } else if p == "none" { el_sides_border(n, 0.0) } else if len(p) > 0 and p != "solid" {
n.border_c = ui_color(ui_st, p)
n.border_a = ui_st.cl_alpha
}
}
if n.border_c == UI_NONE { n.border_c = n.rfg }
}