Merge pull request #397 from grovebit/mix-narrow-headers

Fit the section names in narrow Mix strips
This commit is contained in:
Brandon Thomas authored and GitHub committed 2026-10-13 04:42:33 -04:00
commit e5ca24cc3e
2 files changed
+80 -3

No files matched your search

+23 -3
View File
@@ -75,8 +75,26 @@ fn channel_levels(ui: &Ui, key: (&str, u64), peaks: &[f32], n: usize) -> Vec<f32
lv
}
/// Pro Tools' names for sections in strips too narrow for the full ones.
fn short_label(text: &str) -> &str {
match text {
"INSERTS A-E" => "I A-E",
"INSERTS F-J" => "I F-J",
"SENDS A-E" => "S A-E",
"SENDS F-J" => "S F-J",
"INSTRUMENT" => "INST",
_ => text,
}
}
fn section_label(ui: &Ui, r: Rect, text: &str) {
ui.painter().text(pos2(r.center().x, r.min.y + 7.0), Align2::CENTER_CENTER, text, bold(10.0), Tokens::current().section_label);
let p = ui.painter();
let color = Tokens::current().section_label;
let mut galley = p.layout_no_wrap(text.to_owned(), bold(10.0), color);
if galley.size().x > r.width() - 8.0 {
galley = p.layout_no_wrap(short_label(text).to_owned(), bold(10.0), color);
}
p.galley(Align2::CENTER_CENTER.anchor_size(pos2(r.center().x, r.min.y + 7.0), galley.size()).min, galley, color);
}
pub(crate) fn route_name(app: &SoundApp, r: &Route) -> String {
@@ -220,7 +238,8 @@ fn strip(app: &mut SoundApp, ui: &mut Ui, id: TrackId, snap: Option<&MeterSnapsh
let sec = Rect::from_min_size(pos2(x0, y), vec2(inner_w, 44.0));
let mut c = track.comments.clone();
let mut child = ui.new_child(egui::UiBuilder::new().max_rect(sec));
if child.add(egui::TextEdit::multiline(&mut c).desired_width(inner_w).desired_rows(2).hint_text("comments").font(regular(10.0))).changed() {
let hint = if narrow { "" } else { "comments" };
if child.add(egui::TextEdit::multiline(&mut c).desired_width(inner_w).desired_rows(2).hint_text(hint).font(regular(10.0))).changed() {
let _ = app.engine.execute_merged("track.comments", &json!({"track": id.0, "comments": c}), &format!("comments:{}", id.0));
}
y = sec.max.y + 4.0;
@@ -268,7 +287,8 @@ fn strip(app: &mut SoundApp, ui: &mut Ui, id: TrackId, snap: Option<&MeterSnapsh
y = sec.max.y + 4.0;
}
// Group selector.
let gname = app.engine.session().groups.iter().find(|g| g.members.contains(&id)).map_or("no group".to_string(), |g| g.name.clone());
let no_group = if narrow { "nogrp" } else { "no group" };
let gname = app.engine.session().groups.iter().find(|g| g.members.contains(&id)).map_or(no_group.to_string(), |g| g.name.clone());
let gr = Rect::from_min_size(pos2(x0 + 2.0, y), vec2(inner_w - 4.0, 16.0));
let mut c = ui.new_child(egui::UiBuilder::new().max_rect(gr));
let _ = selector_box(&mut c, gr.width(), gr.height(), &gname, t.text_dim);
@@ -0,0 +1,57 @@
use egui::{Shape, vec2};
use serde_json::json;
use soundcraft_ui_egui::mix_window::strip_width;
use soundcraft_ui_egui::{Services, SoundApp};
const FULL: [&str; 7] = ["INSERTS A-E", "INSERTS F-J", "SENDS A-E", "SENDS F-J", "INSTRUMENT", "comments", "no group"];
const SHORT: [&str; 6] = ["I A-E", "I F-J", "S A-E", "S F-J", "INST", "nogrp"];
fn painted_labels(narrow: bool) -> Vec<(String, f32, bool)> {
let mut app = SoundApp::new(soundcraft_engine::demo::demo_engine(), None, Services::default());
app.run("window.mix", json!({})).unwrap();
app.run("view.mix_section", json!({"section": "all"})).unwrap();
app.run("view.mix_section", json!({"section": "instruments"})).unwrap();
app.ui.narrow_mix = narrow;
let mut harness = egui_kittest::Harness::builder().with_size(vec2(1600.0, 1000.0)).build_ui_state(
|ui, app: &mut SoundApp| {
app.logic(ui.ctx());
app.ui(ui);
},
app,
);
for _ in 0..4 {
harness.step();
}
harness
.output()
.shapes
.iter()
.filter_map(|s| match &s.shape {
Shape::Text(t) if FULL.contains(&t.galley.job.text.as_str()) || SHORT.contains(&t.galley.job.text.as_str()) => {
Some((t.galley.job.text.clone(), t.visual_bounding_rect().width(), t.galley.elided))
}
_ => None,
})
.collect()
}
#[test]
fn narrow_strips_use_short_section_names_that_fit() {
let labels = painted_labels(true);
for name in SHORT {
assert!(labels.iter().any(|(text, ..)| text == name), "{name} missing in {labels:?}");
}
for (text, width, elided) in &labels {
assert!(SHORT.contains(&text.as_str()), "{text} painted in a narrow strip, where it doesn't fit");
assert!(*width <= strip_width(true) - 16.0 && !elided, "{text} is {width} pt wide, elided: {elided}");
}
}
#[test]
fn normal_strips_keep_the_full_section_names() {
let labels = painted_labels(false);
for name in FULL {
assert!(labels.iter().any(|(text, ..)| text == name), "{name} missing in {labels:?}");
}
assert!(labels.iter().all(|(text, ..)| FULL.contains(&text.as_str())), "{labels:?}");
}