nandi/jolt-nativepublic Fork 0
7703c757d45b22224a0423d7b0dc4699a8ca2f9e
Commits
Clone
git clone https://git.rickub.com/nandi/jolt-native.git
git clone ssh://git@rickub.com/nandi/jolt-native.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

README.md · 102 lines · 4.5 KBmarkdown Blame HistoryRaw
Write dvui's shape in jolt, on SDL3, with no shared object 109c7e4 Veronika Winters 9d ago1# glimmer-jvui
2
3The **jvui** backend for [glimmer](https://github.com/jolt-lang/glimmer), the
4reactive GUI toolkit for [jolt](https://github.com/jolt-lang/jolt).
5
6glimmer owns the portable half — reactive cells, the component model, the
7reconciler — and knows nothing about any toolkit. This project supplies the
8other half out of [`../../jvui`](../../jvui), which is dvui's shape written in
9jolt on SDL3. Requiring `glimmer-jvui.core` registers it, and components that
10render as GTK widgets under
11[glimmer-gtk](https://github.com/jolt-lang/glimmer-gtk), as egui under
12[glimmer-vidya](../glimmer-vidya) and as text under
13[glimmer-tui](../glimmer-tui) render here as jvui.
14
15```clojure
16(ns myapp
17 (:require [glimmer.ratom :as ra]
18 [glimmer.core :as ui]
19 [glimmer-jvui.core])) ; installs this backend
20
21(defn counter []
22 (let [n (ra/atom 0)]
23 (fn []
24 [:card {}
25 [:title {:label "Counter"}]
26 [:label {:label (str "Count: " (ra/deref n))}]
27 [:hbox {:spacing 8}
28 [:button {:label "- 1" :on-click #(ra/swap! n dec)}]
29 [:button {:label "+ 1" :kind :primary :on-click #(ra/swap! n inc)}]]])))
30
31(defn -main [& _] (ui/run counter {:title "myapp" :max-width 420}))
32```
33
34```bash
35jolt test # headless: no window, no SDL, no font, no display
36jolt counter # a window
37jolt counter --shot
38```
39
40## The smallest of the four backends
41
42A glimmer backend usually has to supply everything a toolkit would have done
43for it. [glimmer-gfx](../glimmer-gfx) writes its own measure, place, paint and
44hit test, because there is nothing underneath it. [glimmer-vidya](../glimmer-vidya)
45keeps a node arena in Rust behind a second C ABI, because egui hands a
46reconciler nothing to hold.
47
48Here none of that is needed, because jvui is a toolkit rather than an ABI. What
49is left is the one thing an immediate-mode library does not have — somewhere to
50put a widget between frames — and it is thirty lines of atoms:
51
52 src/glimmer_jvui/core.clj the tree, the walk, the loop
53
54`create!` makes an atom, `append-child!` conjes onto a vector, and once a frame
55`emit!` walks that tree and calls the jvui widget each node names. Layout,
56clipping, focus, capture and painting are jvui's.
57
58## Three things worth knowing
59
60**The walk is the closure.** glimmer-vidya's README explains why its tree lives
61in Rust: egui's `ScrollArea` and `Frame` take an `FnOnce(&mut Ui)` and keep
62their begin/end private, so a push/pop ABI cannot scroll a page. jvui's
63containers take a body function for the same reason — and here the recursion
64*is* that function. `emit!` on a container hands `emit-children!` over as the
65body and the nesting takes care of itself, which is why there is no push/pop
66anywhere in this file.
67
68**Every node carries a key.** jvui identifies a widget by its parent and its
69index among its siblings, unless it is given a `:key`, which *replaces* the
70index. A reconciler reorders children, and an identity built on the index would
71hand every widget after the moved one the caret, the scroll offset and the drag
72of whichever widget used to sit at its index. So each node takes a serial
73number at creation and passes it as its key, and identity follows the node
74rather than its position. That is the bug class
75[zvui](../../zig/jolt-zvui)'s README describes from the backend side, closed
76here at the other end — and `jolt test` reorders a list and checks it.
77
78**A re-render is queued, never inline.** A handler fires in the middle of the
79walk, and a ratom change would have the reconciler patch the tree while it is
80being walked — half the frame old, half new. `:schedule` queues the work and
81jvui's `:before` hook drains it at the top of the next frame, before anything
82is placed.
83
84## What renders
85
86Containers: `:page` `:card` `:frame` `:vbox` `:box` `:hbox` `:scroll`.
87Widgets: `:title` `:label` `:dim-label` `:button` `:checkbox` `:slider`
88`:entry`/`:text-entry` `:progress` `:separator` `:spacer`/`:gap`.
89
90Props are the vocabulary the other backends share — `:label`/`:text`,
91`:spacing`, `:padding`, `:margin`, `:orientation`, `:max-width`, `:kind`,
92`:checked`, `:value`/`:min`/`:max`, `:placeholder`, `:dim`, `:size`,
93`:on-click`, `:on-change`.
94
95An unknown tag is a container rather than an error, so a tree written against a
96richer backend still shows its contents — the same bargain jolt-zvui makes.
97
98## Not done
99
100Everything jvui has not got, and nothing else: one font style, no text
101selection, vertical scrolling only, no animation clock, no menus or dialogs.
102`:sensitive`, `:multiline` and `:fill-height` are accepted and ignored.