Merge pull request #1280 from TheGalitube/fix/1252-tracks-nested-in-a-folder-are-no

Indent tracks nested in folders
This commit is contained in:
Brandon Thomas authored and GitHub committed 2026-11-03 10:05:11 -05:00
commit b11ffe73ae
2 files changed
+66 -4

No files matched your search

+24 -4
View File
@@ -46,9 +46,28 @@ pub fn tracks_and_groups(app: &mut SoundApp, ui: &mut Ui) {
if crate::widgets::icon_button(&mut ui.new_child(egui::UiBuilder::new().max_rect(plus)), plus.size(), "plus", false, &tip).clicked() {
let _ = app.dialogs.open_for_command(&app.engine, "track.new");
}
let tracks: Vec<(u64, String, bool, [u8; 3], bool)> = {
let tracks: Vec<(u64, String, bool, [u8; 3], bool, usize)> = {
let s = app.engine.session();
s.tracks.iter().map(|x| (x.id.0, x.name.clone(), !x.hidden, x.color, s.edit.selected_tracks.contains(&x.id))).collect()
s.tracks
.iter()
.map(|x| {
let mut current = x.folder;
let mut depth = 0;
let mut seen = Vec::new();
while let Some(folder_id) = current {
if seen.contains(&folder_id) {
break;
}
seen.push(folder_id);
let Some(folder) = s.track(folder_id) else {
break;
};
depth += 1;
current = folder.folder;
}
(x.id.0, x.name.clone(), !x.hidden, x.color, s.edit.selected_tracks.contains(&x.id), depth)
})
.collect()
};
let hidden = egui::scroll_area::ScrollBarVisibility::AlwaysHidden;
let lists = with_pending_offset(egui::ScrollArea::vertical().id_salt("tracks_scroll"), ui, "tracks_scroll")
@@ -56,7 +75,7 @@ pub fn tracks_and_groups(app: &mut SoundApp, ui: &mut Ui) {
.auto_shrink([false, false])
.scroll_bar_visibility(hidden);
let out = lists.show(ui, |ui| {
for (id, name, shown, color, sel) in tracks {
for (id, name, shown, color, sel, depth) in tracks {
let (r, resp) = ui.allocate_exact_size(vec2(ui.available_width(), 17.0), Sense::click_and_drag());
resp.widget_info(|| egui::WidgetInfo::selected(egui::Role::Button, true, sel, &name));
if sel {
@@ -70,7 +89,8 @@ pub fn tracks_and_groups(app: &mut SoundApp, ui: &mut Ui) {
}
ui.painter().rect_filled(Rect::from_min_size(pos2(r.min.x + 20.0, r.min.y + 3.0), vec2(4.0, 11.0)), 0.0, rgb(color));
ui.painter().with_clip_rect(r).text(
pos2(r.min.x + 30.0, r.center().y),
// Indent stops growing at eight levels so a deep name keeps room in the column.
pos2(r.min.x + 30.0 + depth.min(8) as f32 * 10.0, r.center().y),
Align2::LEFT_CENTER,
&name,
regular(11.5),
+42
View File
@@ -50,6 +50,16 @@ impl Rig {
.expect("row not in the Tracks list")
}
fn text_x(&self, name: &str) -> f32 {
self.shapes
.iter()
.find_map(|c| match &c.shape {
Shape::Text(t) if t.galley.text() == name && t.pos.x < 150.0 => Some(t.pos.x),
_ => None,
})
.expect("text not in the Tracks list")
}
fn press(&mut self, at: Pos2, pressed: bool) {
self.frame(vec![
Event::PointerMoved(at),
@@ -90,3 +100,35 @@ fn clicking_a_track_list_row_still_selects_the_track() {
r.press(at, false);
assert_eq!(r.app.engine.session().edit.selected_tracks, vec![r.order()[2]]);
}
#[test]
fn a_track_inside_a_folder_is_indented_in_the_track_list() {
let mut r = Rig::new();
let child = r.order()[1];
let child_name = r.app.engine.session().track(child).unwrap().name.clone();
r.app.run("track.move_to_new_folder", json!({"tracks": [child.0], "name": "Folder"})).unwrap();
r.frame(vec![]);
let folder = r.app.engine.session().tracks.iter().find(|track| track.is_folder()).unwrap();
assert!(r.text_x(&child_name) > r.text_x(&folder.name), "child is not indented under the folder");
}
#[test]
fn deeply_nested_tracks_keep_indenting_past_six_folders() {
let mut r = Rig::new();
let child = r.order()[1];
let child_name = r.app.engine.session().track(child).unwrap().name.clone();
r.app.run("track.move_to_new_folder", json!({"tracks": [child.0], "name": "Folder 1"})).unwrap();
let mut parent = r.app.engine.session().tracks.iter().find(|track| track.name == "Folder 1").unwrap().id;
for depth in 2..=7 {
r.app.run("track.move_to_new_folder", json!({"tracks": [parent.0], "name": format!("Folder {depth}")})).unwrap();
parent = r.app.engine.session().tracks.iter().find(|track| track.name == format!("Folder {depth}")).unwrap().id;
}
r.frame(vec![]);
// "Folder 1" is the child's own folder and the seventh level; "Folder 7" is the outermost.
assert_eq!(r.app.engine.session().track(parent).unwrap().name, "Folder 7");
assert!(r.text_x(&child_name) > r.text_x("Folder 1"), "deeply nested child is not indented under its own folder");
assert!(r.text_x("Folder 1") > r.text_x("Folder 2"), "each level indents further");
}