# emit_ui.ludic — a `ui` block is data: the compiler flattens the widget tree # and emits @ui_build(), which hands every property to the Ludic UI runtime via # rt_ui_set(index, key, value). Mirrors compiler/back/ir_ui.c. Layout/drawing/ # focus all live in runtime/native/ui.ludic. var uiw: []Node # flattened widgets, pre-order var uiw_parent: []int var ui_roots: []int # first-widget index of each ui block function ui_wtype(w: Node) -> int { let s = w.s if (s == "panel") { return 0 }; if (s == "col") { return 1 }; if (s == "row") { return 2 } if (s == "label") { return 3 }; if (s == "button") { return 4 } if (s == "image") { return 5 }; if (s == "spacer") { return 6 } return 0 } function ui_prop(w: Node, key: pointer) -> Node { var i = 0 while i < len(w.b.kids) { if (w.b.kids[i].s == key) { return w.b.kids[i].a }; i = i + 1 } return null } function ui_flatten(w: Node, parent: int) -> void { let idx = len(uiw) push(uiw, w); push(uiw_parent, parent) var i = 0 while i < len(w.kids) { ui_flatten(w.kids[i], idx); i = i + 1 } } function ui_flatten_all() -> void { uiw = new []Node; uiw_parent = new []int; ui_roots = new []int var i = 0 while i < len(prog) { if prog[i].kind == N_UI and prog[i].ival == 1 { push(ui_roots, len(uiw)); ui_flatten(prog[i].a, 0 - 1) } i = i + 1 } } function has_ui() -> bool { var i = 0 while i < len(prog) { if prog[i].kind == N_UI and prog[i].ival == 1 { return true }; i = i + 1 } return false } # index of a UI_: a ui block's root, or a widget's id= function ui_index_of(nm: pointer) -> int { let s = nm[3..len(nm)] # strip "UI_" let u = 0; var bi = 0 var i = 0 while i < len(prog) { if prog[i].kind == N_UI and prog[i].ival == 1 { if (prog[i].s == s) { return ui_roots[bi] }; bi = bi + 1 } i = i + 1 } i = 0 while i < len(uiw) { let idp = ui_prop(uiw[i], "id") if (idp != null) { if idp.kind == E_ID and (idp.s == s) { return i } } i = i + 1 } return 0 } function is_ui_ident(nm: pointer) -> bool { return len(nm) > 3 and nm[0] == 85 and nm[1] == 73 and nm[2] == 95 # "UI_" } function ll_ui_set(idx: int, key: int, val: pointer) -> void { emit(" call void @fn_rt_ui_set(i32 "); emit(itoa(idx)); emit(", i32 "); emit(itoa(key)); emit(", i32 "); emit(val); emit(")\n") } function ui_prop_key(k: pointer) -> int { if (k == "w") { return 2 }; if (k == "h") { return 3 }; if (k == "x") { return 4 }; if (k == "y") { return 5 } if (k == "pad") { return 7 }; if (k == "gap") { return 8 }; if (k == "bg") { return 9 }; if (k == "fg") { return 10 } if (k == "border") { return 11 }; if (k == "grow") { return 13 }; if (k == "font") { return 14 }; if (k == "size") { return 15 } if (k == "inset") { return 16 }; if (k == "focus") { return 17 } return 0 - 1 } function emit_ui_build() -> void { ui_flatten_all() ll_t = 0; ll_lbl = 0; g_term = false; loc_reset(); nloop = 0 let fbody = buf_new() falloc = buf_new() let saved = code code = fbody emit(" call void @fn_rt_ui_reset(i32 "); emit(itoa(len(uiw))); emit(")\n") var i = 0 while i < len(uiw) { let w = uiw[i] let t = ui_wtype(w) ll_ui_set(i, 0, itoa(t)) ll_ui_set(i, 1, itoa(uiw_parent[i])) if t == 4 { ll_ui_set(i, 17, "1") } var p = 0 while p < len(w.b.kids) { let pr = w.b.kids[p] let k = pr.s let v = pr.a if (k == "id") { p = p + 1; continue } if (k == "text") { let sv = emit_expr(v) emit(" call void @fn_rt_ui_static_text(i32 "); emit(itoa(i)); emit(", ptr "); emit(sv.code); emit(")\n") } else { if (k == "skin") or (k == "image") { let sv = emit_expr(v) let r = emit_bind(`call i32 @fn_rt_image_load(ptr {sv.code})`) if (k == "skin") { ll_ui_set(i, 20, r) } else { ll_ui_set(i, 19, r) } } else { if (k == "align") { if v.kind == E_ID { var a = 0 if (v.s == "center") { a = 1 }; if (v.s == "end") { a = 2 } ll_ui_set(i, 12, itoa(a)) } else { let vv = emit_expr(v); ll_ui_set(i, 12, vv.code) } } else { let key = ui_prop_key(k) if key >= 0 { let vv = emit_expr(v) ll_ui_set(i, key, vv.code) if key == 4 or key == 5 { ll_ui_set(i, 6, "1") } } } } } p = p + 1 } i = i + 1 } code = saved emit("define void @ui_build() {\nentry:\n") emit(buf_str(falloc)) emit(buf_str(fbody)) emit(" ret void\n}\n\n") }