feat(lang): L11 views and templates - the UI is markup, not code
A `view Name { field = x; function q(..); on e(..) }` declaration is the one bridge between a
program and its UI: it writes view_<name>() -> UiView, whose model is a Value of every field and
whose call runs a query or an event by name.
ludic.ui is a template runtime:
- HTML-shaped XML screens and components, loaded at run time;
- {expression} bindings, if/else/each, props, slots, per-instance state;
- on-press / onclick actions (event, set, emit);
- component libraries (export="true", <import src as>).
Styling:
- stylesheets in <style> or importable .lss files (@import);
- CSS selectors (#id, .class, [attr=v], descendant and > combinators, :hover, :disabled,
:first-child, :last-child, :nth-child, :not) weighed by specificity;
- the box model and flex under CSS's property names.
Also:
- default parameters, and positional-then-named calls;
- Value gains a float kind;
- a function shadowing a runtime one is refused;
- an index is evaluated before the slice is read;
- runtime errors name the right file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
334469ef61
commit
66a2bc2214
64 changed files with 74806 additions and 63975 deletions
66
packages/ludic.ui/draw.ludic
Normal file
66
packages/ludic.ui/draw.ludic
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# draw.ludic - the laid-out nodes through the renderer: background, border, then content
|
||||
function fr_draw(n: UiNode) -> void {
|
||||
if n.kind == UI_BUTTON {
|
||||
fr_button(n)
|
||||
return
|
||||
}
|
||||
if n.bg >= 0 and ui_be.rect != null { ui_be.rect(n.x, n.y, n.cw, n.ch, n.bg, n.alpha) }
|
||||
fr_border(n)
|
||||
if n.kind == UI_TEXT { ui_be.text(fr_text_x(n), n.y + n.pt + n.border, n.text, n.rsize, n.rfg) }
|
||||
if n.kind == UI_IMAGE and ui_be.image != null { ui_be.image(n.src, n.x + n.pl + n.border, n.y + n.pt + n.border, n.cw - ly_hin(n), n.ch - ly_vin(n), n.rfg, n.alpha) }
|
||||
var off = 0.0
|
||||
if n.kind == UI_SCROLL and ui_be.scroll_begin != null { off = ui_be.scroll_begin(n.key, n.x, n.y, n.cw, n.ch, n.mh) }
|
||||
if off != 0.0 {
|
||||
for i in 0 .. len(n.children) { fr_shift(n.children[i], off) }
|
||||
}
|
||||
if n.children != null {
|
||||
for i in 0 .. len(n.children) { fr_draw(n.children[i]) }
|
||||
}
|
||||
if n.kind == UI_SCROLL and ui_be.scroll_end != null { ui_be.scroll_end() }
|
||||
}
|
||||
# where a text starts: text-align within the room the box gives it
|
||||
function fr_text_x(n: UiNode) -> float {
|
||||
let x = n.x + n.pl + n.border
|
||||
if n.talign == UI_START { return x }
|
||||
let spare = n.cw - ly_hin(n) - ly_text_w(n.text, n.rsize)
|
||||
if n.talign == UI_CENTER { return x + spare / 2.0 }
|
||||
return x + spare
|
||||
}
|
||||
function fr_border(n: UiNode) -> void {
|
||||
if n.border <= 0.0 or ui_be.rect == null { return }
|
||||
var c = n.border_c
|
||||
if c < 0 { c = n.rfg }
|
||||
let b = n.border
|
||||
ui_be.rect(n.x, n.y, n.cw, b, c, n.alpha)
|
||||
ui_be.rect(n.x, n.y + n.ch - b, n.cw, b, c, n.alpha)
|
||||
ui_be.rect(n.x, n.y, b, n.ch, c, n.alpha)
|
||||
ui_be.rect(n.x + n.cw - b, n.y, b, n.ch, c, n.alpha)
|
||||
}
|
||||
# the renderer's own button when it has one: it draws, focuses and answers the press
|
||||
function fr_button(n: UiNode) -> void {
|
||||
if ui_be.button != null {
|
||||
if ui_be.button(n.x, n.y, n.cw, n.ch, n.text, n.enabled) and n.enabled { push(fr_pressed, n) }
|
||||
return
|
||||
}
|
||||
var bg = n.bg
|
||||
if bg < 0 { bg = 4210752 }
|
||||
if ui_be.rect != null { ui_be.rect(n.x, n.y, n.cw, n.ch, bg, n.alpha) }
|
||||
fr_border(n)
|
||||
ui_be.text(fr_text_x(n), n.y + n.pt + n.border, n.text, n.rsize, n.rfg)
|
||||
}
|
||||
function fr_shift(n: UiNode, off: float) -> void {
|
||||
n.y = n.y - off
|
||||
if n.children != null {
|
||||
for i in 0 .. len(n.children) { fr_shift(n.children[i], off) }
|
||||
}
|
||||
}
|
||||
# every node and where it went, one line each - for a test, or a look at a layout
|
||||
export function ui_dump(n: UiNode, depth: int) -> string {
|
||||
var pad = ""
|
||||
for d in 0 .. depth { pad = pad + " " }
|
||||
var out = `{pad}{n.kind} {int(n.x)},{int(n.y)} {int(n.cw)}x{int(n.ch)} {n.text}\n`
|
||||
if n.children != null {
|
||||
for i in 0 .. len(n.children) { out = out + ui_dump(n.children[i], depth + 1) }
|
||||
}
|
||||
return out
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue