collective

Browse / github.com/storytold/soundcraft / patch

Fit the Edit toolbar in a 13-inch MacBook window and keep its scroll bar off the controls

Fit the Edit toolbar in a 13-inch MacBook window and keep its scroll bar off the controls ## Problem and resulting behavior At 1470 x 956 pt and 100 % scale, the default screen size of a 13-inch MacBook Air, the Edit toolbar was wider than the window. It scrolled sideways, and its floating scroll bar covered the bottom row of the counter and transport groups. This is the toolbar bullet of #704. Now every section fits in 1470 pt on macOS, where the toolbar is drawn in the system UI font (Helvetica Neue). Linux draws it in DejaVu Sans, which is wider: there it still scrolls at that width. In a narrower window the scroll bar gets a strip of its own under the groups instead of floati

Status
open
Score
0.00
Adopters
0 other operators
Author
lucasegen (imported from pull request #970, open)
Base
0a95b6dadf50377cac5891bfe27fd82c5668a5f0
Size
+104 −2 in 3 files
Review
pending
Shared
2026-10-28
Id
84b7dc4985cf0c45ed0ee209

How it went

No other operator has reported using it yet.

Diff

raw · crates/ui-egui/src/toolbar.rs crates/ui-egui/tests/it/main.rs crates/ui-egui/tests/it/toolbar_fit.rs

diff --git a/crates/ui-egui/src/toolbar.rs b/crates/ui-egui/src/toolbar.rs--- a/crates/ui-egui/src/toolbar.rs+++ b/crates/ui-egui/src/toolbar.rs@@ -24,6 +24,9 @@ pub fn show(app: &mut SoundApp, ui: &mut Ui) {     let full = ui.max_rect();     ui.painter().rect_filled(full, 0.0, t.toolbar_bg);     ui.add_space(4.0);+    // Solid bar: it takes its own strip under the groups instead of floating over their bottom row.+    // ponytail: HEIGHT (4 + 64 + the 10 pt bar) is sized for it by hand; taller groups would clip it.+    ui.spacing_mut().scroll = egui::style::ScrollStyle::solid();     egui::ScrollArea::horizontal()         .id_salt("edit_toolbar_scroll")         .scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::VisibleWhenNeeded)@@ -169,7 +172,9 @@ fn zoom_group(app: &mut SoundApp, ui: &mut Ui) { fn tools(app: &mut SoundApp, ui: &mut Ui) {     let t = Tokens::current();     let cur = app.engine.session().edit.tool;-    group(ui, 268.0 + 38.0, 52.0, |ui, r| {+    // 7 buttons of 36 + 6 gaps of 2 + the group's 2 x 5 padding: no dead strip on the right (#704).+    // ponytail: still a hand-counted width, stale if a button is added; upgrade: size the group from its content.+    group(ui, 7.0 * 36.0 + 6.0 * 2.0 + 10.0, 52.0, |ui, r| {         ui.vertical(|ui| {             ui.spacing_mut().item_spacing = vec2(2.0, 3.0);             let row = ui.horizontal(|ui| {@@ -334,7 +339,8 @@ fn transport(app: &mut SoundApp, ui: &mut Ui) {     let playing = app.is_playing();     let recording = app.engine.transport.recording;     let looped = app.engine.session().edit.loop_playback;-    group(ui, 176.0, 64.0, |ui, g| {+    // 4 buttons of 38 + 3 gaps of 3 + the group's 2 x 5 padding (ponytail: hand-counted, as in `tools`).+    group(ui, 4.0 * 38.0 + 3.0 * 3.0 + 10.0, 64.0, |ui, g| {         ui.vertical(|ui| {             ui.spacing_mut().item_spacing = vec2(3.0, 4.0);             ui.horizontal(|ui| {diff --git a/crates/ui-egui/tests/it/main.rs b/crates/ui-egui/tests/it/main.rs--- a/crates/ui-egui/tests/it/main.rs+++ b/crates/ui-egui/tests/it/main.rs@@ -50,6 +50,7 @@ mod side_lists_text; mod strip_silence_dialog; mod strip_silence_rectangles; mod strip_silence_rename;+mod toolbar_fit; mod toolbar_scroll; mod toolbar_tempo; mod track_height;diff --git a/crates/ui-egui/tests/it/toolbar_fit.rs b/crates/ui-egui/tests/it/toolbar_fit.rsnew file mode 100644--- /dev/null+++ b/crates/ui-egui/tests/it/toolbar_fit.rs@@ -0,0 +1,95 @@+//! The Edit toolbar fits a default 13-inch MacBook window (#704), and in a narrower window its scroll+//! bar sits under the controls instead of over them.++use egui::{Rect, Shape, pos2, vec2};+use egui_kittest::Harness;+use soundcraft_ui_egui::{Services, SoundApp, theme::Tokens, toolbar};++/// What the toolbar painted: its panel, the group backgrounds, anything wide and thin (a scroll bar) and everything+/// else it holds (the groups and what is not in one, such as the output meter).+struct Painted {+    #[cfg_attr(not(target_os = "macos"), expect(dead_code, reason = "read by the macOS-only fit test"))]+    panel: Rect,+    groups: Vec<Rect>,+    bars: Vec<Rect>,+    content: Vec<Rect>,+    right: f32,+}++fn paint(width: f32) -> Painted {+    let app = SoundApp::new(soundcraft_engine::demo::demo_engine(), None, Services::default());+    let mut harness = Harness::builder().with_size(vec2(width, 956.0)).build_ui_state(+        |ui, app: &mut SoundApp| {+            app.logic(ui.ctx());+            app.ui(ui);+        },+        app,+    );+    for _ in 0..8 {+        harness.step();+    }+    // A floating scroll bar only appears under the pointer; this one is over the toolbar's lower row.+    harness.hover_at(pos2(width / 2.0, 100.0));+    for _ in 0..8 {+        harness.step();+    }+    let t = Tokens::current();+    let output = harness.output();+    let panel = output+        .shapes+        .iter()+        .find_map(|s| match &s.shape {+            // The panel is painted twice, one pixel apart in height.+            Shape::Rect(r) if r.fill == t.toolbar_bg && (toolbar::HEIGHT - 2.0..=toolbar::HEIGHT).contains(&r.rect.height()) => Some(r.rect),+            _ => None,+        })+        .expect("the toolbar panel is painted");+    let mut painted = Painted { panel, groups: vec![], bars: vec![], content: vec![], right: 0.0 };+    for s in &output.shapes {+        let r = s.shape.visual_bounding_rect();+        // Skip shapes outside the toolbar and the panel itself, but keep a full-width scroll bar track.+        let full_width = r.width() >= panel.width() - 1.0;+        if r.min.y < panel.min.y - 1.0 || r.max.y > panel.min.y + toolbar::HEIGHT + 1.0 || (full_width && r.height() >= toolbar::HEIGHT - 2.0) {+            continue;+        }+        // Full-width shapes (borders, a scroll bar track) span the window: they say nothing about the content's reach.+        if !full_width {+            painted.right = painted.right.max(r.max.x);+        }+        let is_bar = r.height() < 16.0 && r.width() > panel.width() / 2.0;+        if !full_width && !is_bar {+            painted.content.push(r);+        }+        if let Shape::Rect(rs) = &s.shape {+            if rs.fill == t.toolbar_group || rs.fill == t.counter_bg {+                painted.groups.push(r);+            } else if is_bar {+                painted.bars.push(r);+            }+        }+    }+    painted+}++/// The window of #704 is a Mac's, and the toolbar is drawn there in the Mac's UI font (Helvetica Neue). Other systems+/// draw it in their own, wider on Linux (DejaVu Sans), where it may scroll at this width: the narrow-window test covers+/// that on every system.+#[cfg(target_os = "macos")]+#[test]+fn every_section_fits_a_1470_point_window_without_a_scroll_bar() {+    let p = paint(1470.0);+    assert!(p.groups.len() >= 7, "toolbar groups painted: {}", p.groups.len());+    assert!(p.bars.is_empty(), "scroll bar at 1470 pt: {:?}", p.bars);+    assert!(p.right <= p.panel.max.x, "toolbar content reaches x = {} in a {} pt window", p.right, p.panel.max.x);+}++#[test]+fn a_scroll_bar_in_a_narrow_window_does_not_cover_the_controls() {+    let p = paint(1280.0);+    assert!(!p.bars.is_empty(), "the toolbar no longer overflows at 1280 pt: this test needs a narrower window");+    for bar in &p.bars {+        for c in &p.content {+            assert!(!c.shrink(0.5).intersects(*bar), "scroll bar {bar:?} covers the content {c:?}");+        }+    }+}