Skip to main content

max / quasi

0.20.1: this renderer can press what it draws, and three things could not be pressed The blocker was fonts, not the harness. With `default-features = false` every string measures zero points wide, so a `Response` covers no pixel, is never hovered, and no injected click reaches it however faithfully it is sent. A dev-dependency turning `default_fonts` on applies to this crate's own tests and to nothing a consumer builds, so the dependency keeps the flag it had and no font is committed. With that, `Host` drives a real `Context` a frame at a time and aims the pointer at the shapes the previous frame painted, rather than at arithmetic over the layout. Six tests: a row opens, each row answers for itself, a right-click raises the menu and the item fires its route with the confirmation it was described with, and the same two over a table. They found three defects, all of which the suite could not previously see: A list row's interact id was ("row", value.unwrap_or("")), and `Row::value` is only set by `ticking`, so every row of a list without checkboxes shared one id. egui answers a repeated id with an error label and one shared interaction, so the second row onwards could not be clicked at all. Falls back to the row's position, which is the only thing distinguishing rows that carry no value; the value still wins where there is one, because it survives a reorder. A table row hung both gestures on `ui.response()`, which carries the sense the `Ui` was built with -- `Sense::hover()` -- so `clicked()` and the secondary click `context_menu` reads were permanently false. Neither opening a table row nor raising its menu did anything, in the one consumer whose file list is a `Node::Table`. Now interacts for the sense it needs, as `list_row` already did. `Row::menu` drawing nothing, fixed in 40c7977 by reading. Now asserted. Each was verified by putting it back and watching the intended test fail.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-17 22:43 UTC
Signed with PGP, not checked
Commit: 44bf892d0b14d1f727f800a9b2115504764d6d4c
Parent: 40c7977
13 files changed, +388 insertions, -62 deletions
M Cargo.lock +29 -22
@@ -1052,6 +1052,7 @@
1052 1052 "ahash",
1053 1053 "ecolor",
1054 1054 "emath",
1055 + "epaint_default_fonts",
1055 1056 "font-types",
1056 1057 "harfrust",
1057 1058 "log",
@@ -1066,6 +1067,12 @@
1066 1067 "vello_cpu",
1067 1068 ]
1068 1069
1070 + [[package]]
1071 + name = "epaint_default_fonts"
1072 + version = "0.35.0"
1073 + source = "registry+https://github.com/rust-lang/crates.io-index"
1074 + checksum = "13ee4e1f553a3584c301f3a56ff1a775f1384781396cea301c8d952e9b93f560"
1075 +
1069 1076 [[package]]
1070 1077 name = "equivalent"
1071 1078 version = "1.0.2"
@@ -3093,11 +3100,11 @@
3093 3100
3094 3101 [[package]]
3095 3102 name = "quasi"
3096 - version = "0.20.0"
3103 + version = "0.20.1"
3097 3104
3098 3105 [[package]]
3099 3106 name = "quasi-axum"
3100 - version = "0.20.0"
3107 + version = "0.20.1"
3101 3108 dependencies = [
3102 3109 "axum",
3103 3110 "http",
@@ -3111,7 +3118,7 @@
3111 3118
3112 3119 [[package]]
3113 3120 name = "quasi-basics"
3114 - version = "0.20.0"
3121 + version = "0.20.1"
3115 3122 dependencies = [
3116 3123 "makeover-layout",
3117 3124 "quasi-http",
@@ -3121,7 +3128,7 @@
3121 3128
3122 3129 [[package]]
3123 3130 name = "quasi-bench"
3124 - version = "0.20.0"
3131 + version = "0.20.1"
3125 3132 dependencies = [
3126 3133 "dhat",
3127 3134 "makeover",
@@ -3136,7 +3143,7 @@
3136 3143
3137 3144 [[package]]
3138 3145 name = "quasi-http"
3139 - version = "0.20.0"
3146 + version = "0.20.1"
3140 3147 dependencies = [
3141 3148 "form_urlencoded",
3142 3149 "http",
@@ -3145,7 +3152,7 @@
3145 3152
3146 3153 [[package]]
3147 3154 name = "quasi-immediate"
3148 - version = "0.20.0"
3155 + version = "0.20.1"
3149 3156 dependencies = [
3150 3157 "docengine",
3151 3158 "egui",
@@ -3155,7 +3162,7 @@
3155 3162
3156 3163 [[package]]
3157 3164 name = "quasi-router"
3158 - version = "0.20.0"
3165 + version = "0.20.1"
3159 3166 dependencies = [
3160 3167 "makeover-layout",
3161 3168 ]
@@ -3172,7 +3179,7 @@
3172 3179
3173 3180 [[package]]
3174 3181 name = "quasi-tauri"
3175 - version = "0.20.0"
3182 + version = "0.20.1"
3176 3183 dependencies = [
3177 3184 "http",
3178 3185 "quasi-http",
@@ -3183,7 +3190,7 @@
3183 3190
3184 3191 [[package]]
3185 3192 name = "quasi-tui"
3186 - version = "0.20.0"
3193 + version = "0.20.1"
3187 3194 dependencies = [
3188 3195 "docengine",
3189 3196 "makeover",
@@ -3195,7 +3202,7 @@
3195 3202
3196 3203 [[package]]
3197 3204 name = "quasi-webview"
3198 - version = "0.20.0"
3205 + version = "0.20.1"
3199 3206 dependencies = [
3200 3207 "docengine",
3201 3208 "makeover-layout",
@@ -5625,6 +5632,18 @@
5625 5632 source = "registry+https://github.com/rust-lang/crates.io-index"
5626 5633 checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
5627 5634
5635 + [[patch.unused]]
5636 + name = "synckit-client"
5637 + version = "0.8.0"
5638 +
5639 + [[patch.unused]]
5640 + name = "synckit-config"
5641 + version = "0.2.0"
5642 +
5643 + [[patch.unused]]
5644 + name = "quasi-type"
5645 + version = "0.1.0"
5646 +
5628 5647 [[patch.unused]]
5629 5648 name = "kberg"
5630 5649 version = "0.1.0"
@@ -5640,15 +5659,3 @@
5640 5659 [[patch.unused]]
5641 5660 name = "tagtree"
5642 5661 version = "0.4.0"
5643 -
5644 - [[patch.unused]]
5645 - name = "synckit-client"
5646 - version = "0.8.0"
5647 -
5648 - [[patch.unused]]
5649 - name = "synckit-config"
5650 - version = "0.2.0"
5651 -
5652 - [[patch.unused]]
5653 - name = "quasi-type"
5654 - version = "0.1.0"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-axum"
3 - version = "0.20.0"
3 + version = "0.20.1"
4 4 description = "The axum host adapter for quasi-router: an HTTP request in, a rendered description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,14 +13,14 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.20.0" }
17 - quasi-http = { path = "../quasi-http", version = "0.20.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.20.1" }
17 + quasi-http = { path = "../quasi-http", version = "0.20.1" }
18 18 axum = "0.8.8"
19 19 http = "1.3.1"
20 20 tokio = { version = "1.50.0", features = ["rt"] }
21 21
22 22 [dev-dependencies]
23 - quasi-webview = { path = "../quasi-webview", version = "0.20.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.20.1" }
24 24 tokio = { version = "1.50.0", features = ["macros", "rt-multi-thread"] }
25 25 tower = { version = "0.5.3", features = ["util"] }
26 26 http-body-util = "0.1.3"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-basics"
3 - version = "0.20.0"
3 + version = "0.20.1"
4 4 description = "The first-party widget set: named assemblies of primitives, shared across our apps"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,12 +13,12 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.20.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.20.1" }
17 17 makeover-layout = "0.28.0"
18 18
19 19 [dev-dependencies]
20 20 # A widget's guarantees are claims about what a renderer draws, so they are
21 21 # tested against a real one rather than by walking the tree the assembly just
22 22 # built. The webview is the renderer that recognises names today.
23 - quasi-webview = { path = "../quasi-webview", version = "0.20.0" }
24 - quasi-http = { path = "../quasi-http", version = "0.20.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.20.1" }
24 + quasi-http = { path = "../quasi-http", version = "0.20.1" }
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-bench"
3 - version = "0.20.0"
3 + version = "0.20.1"
4 4 description = "What a described screen costs to render, in time and in allocations"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -22,13 +22,13 @@
22 22 count = ["dep:dhat"]
23 23
24 24 [dependencies]
25 - quasi-router = { path = "../quasi-router", version = "0.20.0" }
26 - quasi-webview = { path = "../quasi-webview", version = "0.20.0" }
27 - quasi-tui = { path = "../quasi-tui", version = "0.20.0" }
25 + quasi-router = { path = "../quasi-router", version = "0.20.1" }
26 + quasi-webview = { path = "../quasi-webview", version = "0.20.1" }
27 + quasi-tui = { path = "../quasi-tui", version = "0.20.1" }
28 28 # `Serves` is the trait carrying `screen` and `fragment`, which is what the
29 29 # webview is measured through. Taken directly rather than through quasi-webview
30 30 # because a bench calling a trait method should name the trait it calls.
31 - quasi-http = { path = "../quasi-http", version = "0.20.0" }
31 + quasi-http = { path = "../quasi-http", version = "0.20.1" }
32 32 makeover-layout = "0.28.0"
33 33 makeover-tui = { version = "0.27.0", features = ["theme"] }
34 34 # Only to load a bundled theme file. `makeover_tui::Theme` is `#[non_exhaustive]`,
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-http"
3 - version = "0.20.0"
3 + version = "0.20.1"
4 4 description = "The http-shaped seam quasi's webview host adapters share: decoding in, a rendered description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,6 +13,6 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.20.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.20.1" }
17 17 http = "1.3.1"
18 18 form_urlencoded = "1.2.2"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-immediate"
3 - version = "0.20.0"
3 + version = "0.20.1"
4 4 edition = "2024"
5 5 description = "The immediate-mode renderer for quasi-router: a described screen in, an egui frame out. Immediate mode is the constraint that matters, not the library."
6 6 license = "MIT"
@@ -12,7 +12,7 @@
12 12 categories = ["gui"]
13 13
14 14 [dependencies]
15 - quasi-router = { path = "../quasi-router", version = "0.20.0" }
15 + quasi-router = { path = "../quasi-router", version = "0.20.1" }
16 16 # The node drawing, which is the makeover layer's and not this crate's. Every
17 17 # widget here that is not a container comes from it: a screen walk that painted
18 18 # its own meter would be the divergence the suite exists to end, one copy per
@@ -24,6 +24,21 @@
24 24 # cannot, so this asks for the plain rendering.
25 25 docengine = { git = "https://makenot.work/git/max/docengine.git", version = "0.7" }
26 26
27 + [dev-dependencies]
28 + # Fonts, for tests only.
29 + #
30 + # The dependency above keeps `default-features = false` on purpose: a consumer
31 + # supplies its own faces (audiofiles does), and the harness wanting one is no
32 + # reason to push the Ubuntu/Emoji set into every consumer's build. A
33 + # dev-dependency's features apply when this crate's own tests are built and
34 + # nowhere else, so this is the dev-only form the alternative (committing a test
35 + # face) would not be -- and the tree's rule is not to store what rebuilds.
36 + #
37 + # Without it every string measures zero points wide, so a `Response` covers no
38 + # pixel, is never hovered, and no injected click can reach it. That is why this
39 + # renderer could assert only that drawing fires nothing.
40 + egui = { version = "0.35", features = ["default_fonts"] }
41 +
27 42 [lints.rust]
28 43 unused = "warn"
29 44 unreachable_pub = "warn"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-router"
3 - version = "0.20.0"
3 + version = "0.20.1"
4 4 description = "Host-agnostic router: a request in, a renderer-agnostic description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-tauri"
3 - version = "0.20.0"
3 + version = "0.20.1"
4 4 description = "The Tauri custom-protocol host adapter for quasi-router: a webview request in, a rendered description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,8 +13,8 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.20.0" }
17 - quasi-http = { path = "../quasi-http", version = "0.20.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.20.1" }
17 + quasi-http = { path = "../quasi-http", version = "0.20.1" }
18 18 http = "1.3.1"
19 19 # Default features off: this crate uses tauri's protocol registration and its
20 20 # blocking pool, and nothing else. An app brings the features it wants, and the
@@ -22,7 +22,7 @@
22 22 tauri = { version = "2.11.5", default-features = false }
23 23
24 24 [dev-dependencies]
25 - quasi-webview = { path = "../quasi-webview", version = "0.20.0" }
25 + quasi-webview = { path = "../quasi-webview", version = "0.20.1" }
26 26 # The doctest names a concrete `Runtime`, and `Wry` is behind a default feature
27 27 # this crate does not otherwise ask for. Only the example needs it: nothing in
28 28 # the test module builds a window, which is what keeps them runnable with no