Skip to main content

max / makeover-immediate

Draw the slider's track along its curve makeover-layout 0.32.0: a slider's data is a fraction and a function taking numbers to numbers, so `min` and `max` are f(0) and f(1) rather than the control's extent. This host has the easiest job of the three, since egui already owns the control -- `Slider::logarithmic` is a constant-ratio track, so the mapping is a builder call and not arithmetic of its own. The granularity moved onto the curve, so a range reads `curve.step()` and every other kind still reads `Field::step`. It is in the value's own units under either curve, so the display precision is derived exactly as before. The ratio fallback is asked of `Curve::is_ratio` rather than matched on the variant, so this renderer and a terminal cannot disagree about when a logarithmic request is honoured -- an envelope's sustain is a 0-to-1 level and a constant ratio is undefined there. 45 tests pass, clippy clean, fmt clean.
Author: Max Johnson <me@maxj.phd> · 2026-08-21 17:37 UTC
Signed with PGP, not checked
Commit: 21f701edd240b528a1fbb49815b661801ac237f9
Parent: afeb399
2 files changed, +35 insertions, -6 deletions
M Cargo.toml +2 -2
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "makeover-immediate"
3 - version = "0.30.0"
3 + version = "0.31.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"
@@ -12,7 +12,7 @@
12 12 # Exact patch rather than the minor, as the rest of the suite pins: a
13 13 # minor-only requirement is satisfied by a consumer lock holding an earlier
14 14 # patch, which then fails to compile against an API added in a later one.
15 - makeover-layout = "0.31.0"
15 + makeover-layout = "0.32.0"
16 16
17 17 [lints.rust]
18 18 unused = "warn"
M src/lib.rs +33 -4
@@ -154,6 +154,23 @@
154 154 //! looks for it, and because the silent version reads as "egui does not need
155 155 //! a palette" rather than "nobody has built the renderer yet".
156 156
157 + //! # 0.31.0: the slider's track is a curve
158 + //!
159 + //! `makeover-layout` 0.32.0 says what a slider is: a fraction and a function
160 + //! taking numbers to numbers, with `min` and `max` being `f(0)` and `f(1)`
161 + //! rather than the control's extent. This host has the easiest job of the
162 + //! three, because egui already has the control -- `Slider::logarithmic` is a
163 + //! constant-ratio track, so the mapping is a builder call rather than an
164 + //! arithmetic of its own.
165 + //!
166 + //! Two things worth knowing. The granularity moved onto the curve, so a range
167 + //! reads `Field::curve.step()` and every other kind still reads `Field::step`;
168 + //! the step is in the value's own units under either curve, so the display
169 + //! precision is derived exactly as before. And the fallback for a ratio curve
170 + //! across zero is asked of `Curve::is_ratio` rather than matched on the
171 + //! variant, so this renderer and a terminal cannot disagree about when a
172 + //! logarithmic request is honoured.
173 + //!
157 174 //! # 0.28.0: the slider, the unanswered chooser, and the option that is not
158 175 //! offered yet
159 176 //!
@@ -780,16 +797,28 @@
780 797 // written back until the user drags, so an unreadable value the app
781 798 // put there survives being looked at.
782 799 let mut number = value.parse::<f64>().unwrap_or(*extent.start());
783 - let mut slider = Slider::new(&mut number, extent).text("");
784 - if let Some(places) = decimals(field.step) {
800 + // The granularity is the curve's as of makeover-layout 0.32.0. It
801 + // is still in the value's own units, so the display precision is
802 + // read off it exactly as before.
803 + let step = field.curve.step();
804 + let mut slider = Slider::new(&mut number, extent.clone()).text("");
805 + if let Some(places) = decimals(step) {
785 806 slider = slider.max_decimals(places);
786 807 }
787 - if let Some(step) = field.step.and_then(|s| s.parse::<f64>().ok()) {
808 + if let Some(step) = step.and_then(|s| s.parse::<f64>().ok()) {
788 809 slider = slider.step_by(step);
789 810 }
811 + // egui's own constant-ratio track, which is this host's answer to
812 + // `Curve::Logarithmic`. `is_ratio` rather than a match on the
813 + // variant, because a ratio across zero is not one: makeover-layout
814 + // decides the fallback so that four renderers cannot disagree about
815 + // when it applies.
816 + if field.curve.is_ratio(*extent.start(), *extent.end()) {
817 + slider = slider.logarithmic(true);
818 + }
790 819 let response = ui.add(slider);
791 820 if response.changed() {
792 - *value = match decimals(field.step) {
821 + *value = match decimals(step) {
793 822 Some(places) => format!("{number:.places$}"),
794 823 None => number.to_string(),
795 824 };