From 21b018c8a9440751e75cddcaa39f52488b1ac334 Mon Sep 17 00:00:00 2001 From: Dan Hiorns Date: Mon, 12 Oct 2026 18:54:11 -0600 Subject: [PATCH] Brush Settings: Brush Tip Shape lines up with the other section names (#4282) (#4294) The section list indented every row without an enable box by the box's width, except the first, so Brush Tip Shape started in the checkbox column while Smoothing, the other box-less row, lined up with the names. Photoshop indents Brush Tip Shape too. Every name now starts in the same column. Test: section_names_line_up_whether_or_not_they_have_a_box checks the painted x of every section name (Brush Tip Shape was 20 px left before). Co-authored-by: Claude Opus 5.5 --- crates/ui-egui/src/brush_panel.rs | 4 +++- crates/ui-egui/src/brush_panel_tests.rs | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/brush_panel.rs b/crates/ui-egui/src/brush_panel.rs index d018219238..8f51ca8572 100644 --- a/crates/ui-egui/src/brush_panel.rs +++ b/crates/ui-egui/src/brush_panel.rs @@ -295,7 +295,9 @@ fn section_list(app: &mut PhotocraftApp, ui: &mut egui::Ui, b: &mut BrushSetting *flag = true; } x += 20.0; - } else if i > 0 { + } else { + // No box (Brush Tip Shape): the name still starts in the names' column, + // as in Photoshop (#4282). x += 20.0; } let color = if sel { t.text } else { t.text_dim }; diff --git a/crates/ui-egui/src/brush_panel_tests.rs b/crates/ui-egui/src/brush_panel_tests.rs index 34dc0d9d4d..49ddc0063c 100644 --- a/crates/ui-egui/src/brush_panel_tests.rs +++ b/crates/ui-egui/src/brush_panel_tests.rs @@ -599,6 +599,31 @@ fn editing_the_options_bar_amount_reenables_smoothing() { assert_eq!(last_journal(h.state()).unwrap().1["brush"]["smoothing"]["enabled"], true); } +/// #4282: every name in the section list starts in the same column, Brush Tip Shape included, +/// whether or not its row has an enable box (Photoshop indents the rows without one). +#[test] +fn section_names_line_up_whether_or_not_they_have_a_box() { + fn text_x(shape: &egui::Shape, out: &mut Vec<(String, f32)>) { + match shape { + egui::Shape::Text(text) => out.push((text.galley.job.text.clone(), text.pos.x)), + egui::Shape::Vec(shapes) => shapes.iter().for_each(|s| text_x(s, out)), + _ => {} + } + } + // Shape Dynamics is shown, so its heading paints too; the list's copy is the leftmost. + let h = harness(0, 1); + let mut painted = Vec::new(); + for shape in &h.output().shapes { + text_x(&shape.shape, &mut painted); + } + let left = |name: &str| painted.iter().filter(|(t, _)| t == name).map(|(_, x)| *x).reduce(f32::min); + let columns: Vec<(&str, f32)> = SECTIONS.iter().map(|(name, _)| (*name, left(name).unwrap_or_else(|| panic!("{name} painted")))).collect(); + let (_, boxed) = columns[1]; + for (name, x) in &columns { + assert!((x - boxed).abs() < 0.5, "{name} starts at {x}, the boxed names at {boxed}: {columns:?}"); + } +} + #[test] fn preview_strip_re_renders_only_when_the_brush_changes() { let mut h = harness(0, 0);