Skip to main content

max / makeover-immediate

Reframe the focus refusal as the general rule It read as a local exception to a describable state. It is the rule: egui owns reach, focus and the ring, and a description states none of them. The argument was already right and only its framing changed. Takes makeover-layout 0.19.0.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-13 13:54 UTC
Signed with PGP, not checked
Commit: eaf9a49bbdf99c8aab163a7dc1d5d4fdffb53ce2
Parent: 2a37e80
2 files changed, +21 insertions, -21 deletions
M Cargo.toml +2 -2
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "makeover-immediate"
3 - version = "0.16.0"
3 + version = "0.17.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.18.0"
15 + makeover-layout = "0.19.0"
16 16
17 17 [lints.rust]
18 18 unused = "warn"
M src/lib.rs +19 -19
@@ -117,11 +117,16 @@
117 117 //! holds that a well is for anything the user looks *into*, and a text field
118 118 //! is its own example; a select and a checkbox are pressed rather than looked
119 119 //! into, so they keep egui's own control painting.
120 - //! - **[`makeover_layout::State::Focus`] is not drawn here.** egui already
121 - //! paints exactly one focus stroke, and the description's rule is one ring
122 - //! rather than a ring per primitive, so adding a second would break the rule
123 - //! it came from. [`makeover_layout::State::Disabled`] *is* drawn, because egui
124 - //! has no opinion about it until told.
120 + //! - **Focus is not describable, and egui owns all of it here.** **Reach**,
121 + //! **focus** and the **focus ring** are this renderer's three answers and
122 + //! egui already has all three: its own id stack decides what is reachable,
123 + //! its own state decides what holds the keyboard, and it paints exactly one
124 + //! ring. A description states none of them — `makeover_layout` removed the
125 + //! member that used to try in 0.19.0 — and drawing a second ring on top of
126 + //! egui's would break the one-ring rule it would have come from. The terms
127 + //! are defined once in `makeover_layout`'s crate header, "Reach, focus and
128 + //! the focus ring". [`makeover_layout::State::Disabled`] *is* drawn, because
129 + //! egui has no opinion about it until told.
125 130
126 131 #![forbid(unsafe_code)]
127 132
@@ -643,9 +648,9 @@
643 648 /// `state` is the description's interaction axis.
644 649 /// [`State::Disabled`] greys the field and stops it answering, through
645 650 /// [`State::suppresses_interaction`] rather than through a second reading of
646 - /// what disabled means. [`State::Focus`] is deliberately not acted on: egui
647 - /// paints its own focus stroke and the description asks for one ring, not one
648 - /// per renderer that happens to have opinions.
651 + /// what disabled means. Focus is not on that axis and never reaches here: egui
652 + /// owns reach, focus and the ring for this renderer, and one ring means not a
653 + /// second one per renderer that happens to have opinions.
649 654 pub fn field(
650 655 ui: &mut Ui,
651 656 field: &Field<'_>,
@@ -916,7 +921,7 @@
916 921 }
917 922
918 923 #[test]
919 - fn a_disabled_field_stops_answering_and_a_focused_one_does_not() {
924 + fn a_disabled_field_stops_answering_and_an_unstated_one_does_not() {
920 925 let f = Field::new(FieldKind::Text, "title", "Title");
921 926 let p = palette(Color32::from_rgb(9, 9, 9));
922 927 let style = FieldStyle::default();
@@ -933,17 +938,12 @@
933 938 .unwrap();
934 939 assert!(!disabled.enabled());
935 940
941 + // Stating no state is the ordinary case and answers. Focus used to
942 + // be the counter-example here; it is egui's now and a description
943 + // cannot state it at all.
936 944 let mut text = String::from("x");
937 - let focused = field(
938 - ui,
939 - &f,
940 - Filling::Text(&mut text),
941 - Some(State::Focus),
942 - &p,
943 - &style,
944 - )
945 - .unwrap();
946 - assert!(focused.enabled(), "focus is a thing you can still click");
945 + let plain = field(ui, &f, Filling::Text(&mut text), None, &p, &style).unwrap();
946 + assert!(plain.enabled(), "an unstated field still answers");
947 947 });
948 948 }
949 949