Skip to main content

max / makeover-immediate

0.2.0: drop the well substitution Palette::well is a required Color32, not an Option, and fill() is a plain lookup. The substitution existed only while surface-well was underived; makeover derives it from 2.3.0 and audiofiles now reads it, so the condition its own doc comment set for deletion is met. makeover-tui keeps an Option for a different reason and should not be made to match: a terminal can have the colour and still be unable to show it, which is a fact about the surface rather than about the theme. Breaking for anyone building a Palette literal, which is audiofiles and nobody else.
Author: Max Johnson <me@maxj.phd> · 2026-07-28 22:51 UTC
Signed with PGP, not checked
Commit: b2c0f6399e980f68b4bdb550b1a4ff7c7b4c624d
Parent: ea2d0dd
3 files changed, +37 insertions, -31 deletions
M Cargo.toml +1 -1
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "makeover-immediate"
3 - version = "0.1.0"
3 + version = "0.2.0"
4 4 edition = "2024"
5 5 description = "The immediate-mode renderer for makeover-layout. Immediate mode is the constraint that matters, not the library: no cascade, no retained tree, one stroke per widget. Backed by egui."
6 6 license = "MIT"
M README.md +7 -3
@@ -15,9 +15,13 @@
15 15
16 16 ## What it owns
17 17
18 - The expression, and nothing else. Two mitred polylines for a bevel, a `Frame`
19 - for a filled region, and the decision of what to do when an intent has no colour
20 - yet.
18 + The expression, and nothing else. Two mitred polylines for a bevel and a
19 + `Frame` for a filled region.
20 +
21 + It no longer owns a substitution. This renderer briefly supplied the page where
22 + a theme had no `surface-well`, which was a stand-in for a token that did not
23 + exist yet; makeover derives it from 2.3.0 and every consumer reads it, so
24 + `Palette::well` is a required `Color32` rather than an `Option`.
21 25
22 26 It owns no colours and no sizes. `Palette` is handed in already resolved, and
23 27 every radius, margin and stroke width arrives in `FrameStyle`. That is why there
M src/lib.rs +29 -27
@@ -15,9 +15,11 @@
15 15 //!
16 16 //! # What this crate does and does not own
17 17 //!
18 - //! It owns the *expression*: two mitred polylines for a bevel, a `Frame` for a
19 - //! filled region, and the decision of what to do when an intent has no colour
20 - //! yet. It owns no colours and no sizes. [`Palette`] is supplied by the caller,
18 + //! It owns the *expression*: two mitred polylines for a bevel and a `Frame`
19 + //! for a filled region. It owns no colours and no sizes, and no longer owns a
20 + //! substitution: it briefly supplied the page for a well, which was a stand-in
21 + //! for `surface-well` before makeover derived it, and every consumer reads the
22 + //! real token now. [`Palette`] is supplied by the caller,
21 23 //! already resolved, and every radius, margin and stroke width arrives in
22 24 //! [`FrameStyle`].
23 25 //!
@@ -51,8 +53,14 @@
51 53 pub raised: Color32,
52 54 /// `surface-overlay`.
53 55 pub overlay: Color32,
54 - /// `surface-well`, absent on makeover before 2.3.0.
55 - pub well: Option<Color32>,
56 + /// `surface-well`.
57 + ///
58 + /// Required, not optional. makeover derives it for every theme from 2.3.0,
59 + /// so a resolved palette without a well is not a thing that exists here.
60 + /// It was an `Option` while that was untrue, and this renderer substituted
61 + /// the page; `makeover-tui` keeps its own `Option` for a different reason,
62 + /// since a terminal can have the colour and still be unable to show it.
63 + pub well: Color32,
56 64 /// `bevel-light`.
57 65 pub bevel_light: Color32,
58 66 /// `bevel-dark`.
@@ -62,21 +70,16 @@
62 70 impl Palette {
63 71 /// Resolve a surface intent.
64 72 ///
65 - /// `Fill::Well` substitutes the page when the theme has no `surface-well`,
66 - /// which is every theme on makeover before 2.3.0. That substitution lives
67 - /// here rather than in the description because it is only right for a
68 - /// renderer that can always paint an exact colour: makeover-tui had to
69 - /// reject it, since on a terminal the page is often the very surface the
70 - /// well is cut into and the two quantise together.
71 - ///
72 - /// Delete it once 2.3.0 is published and the consumers adopt it.
73 + /// A plain lookup. There is no substitution here any more: it existed only
74 + /// while `surface-well` was underived, and every consumer now reads the
75 + /// real token.
73 76 #[must_use]
74 - pub fn fill(&self, fill: Fill) -> Color32 {
77 + pub const fn fill(&self, fill: Fill) -> Color32 {
75 78 match fill {
76 79 Fill::Page => self.page,
77 80 Fill::Raised => self.raised,
78 81 Fill::Overlay => self.overlay,
79 - Fill::Well => self.well.unwrap_or(self.page),
82 + Fill::Well => self.well,
80 83 }
81 84 }
82 85
@@ -178,7 +181,7 @@
178 181 mod tests {
179 182 use super::*;
180 183
181 - fn palette(well: Option<Color32>) -> Palette {
184 + fn palette(well: Color32) -> Palette {
182 185 Palette {
183 186 page: Color32::from_rgb(1, 1, 1),
184 187 raised: Color32::from_rgb(2, 2, 2),
@@ -190,19 +193,18 @@
190 193 }
191 194
192 195 #[test]
193 - fn a_well_falls_back_to_the_page_before_makeover_2_3() {
194 - // This renderer's policy, not the description's. See makeover-tui,
195 - // which reaches the opposite conclusion for the same intent.
196 - let p = palette(None);
197 - assert_eq!(p.fill(Fill::Well), p.page);
198 - // and uses the real token once the theme carries one
196 + fn a_well_resolves_to_its_own_token() {
197 + // No substitution left. The page-filled well was a stand-in for a
198 + // token that did not exist yet; it exists now.
199 199 let w = Color32::from_rgb(9, 9, 9);
200 - assert_eq!(palette(Some(w)).fill(Fill::Well), w);
200 + let p = palette(w);
201 + assert_eq!(p.fill(Fill::Well), w);
202 + assert_ne!(p.fill(Fill::Well), p.page);
201 203 }
202 204
203 205 #[test]
204 - fn every_other_intent_resolves_without_a_fallback() {
205 - let p = palette(None);
206 + fn every_intent_is_a_plain_lookup() {
207 + let p = palette(Color32::from_rgb(9, 9, 9));
206 208 assert_eq!(p.fill(Fill::Page), p.page);
207 209 assert_eq!(p.fill(Fill::Raised), p.raised);
208 210 assert_eq!(p.fill(Fill::Overlay), p.overlay);
@@ -211,7 +213,7 @@
211 213 #[test]
212 214 fn a_raised_region_never_resolves_to_the_well_fill() {
213 215 // The cross-app bug, asserted at the renderer boundary this time.
214 - let p = palette(Some(Color32::from_rgb(9, 9, 9)));
216 + let p = palette(Color32::from_rgb(9, 9, 9));
215 217 let raised = Depth::Raised.fill().map(|f| p.fill(f));
216 218 let well = Depth::Well.fill().map(|f| p.fill(f));
217 219 assert_eq!(raised, Some(p.raised));
@@ -220,7 +222,7 @@
220 222
221 223 #[test]
222 224 fn the_lit_edge_swaps_when_a_card_is_pressed() {
223 - let p = palette(None);
225 + let p = palette(Color32::from_rgb(9, 9, 9));
224 226 let (tl, _) = Depth::Raised.bevel().unwrap().edges();
225 227 let (ptl, _) = Depth::Raised.pressed().bevel().unwrap().edges();
226 228 assert_eq!(p.edge(tl), p.bevel_light);