diff --git a/crates/ui-egui/src/edit_window/header.rs b/crates/ui-egui/src/edit_window/header.rs index 447671d8..5b3d4400 100644 --- a/crates/ui-egui/src/edit_window/header.rs +++ b/crates/ui-egui/src/edit_window/header.rs @@ -1,3 +1,4 @@ +use super::layout::STRIP_W; use super::tracks::{click_track, folder_depth, height_targets, in_edit_window, track_context_menu, view_label, view_menu}; use super::{ Align2, AutoParam, Color32, Pos2, Rect, Sense, Shape, SoundApp, Stroke, Tokens, Track, TrackHeight, TrackId, TrackKind, Ui, bold, groove, json, @@ -14,6 +15,7 @@ pub(super) fn track_header(app: &mut SoundApp, ui: &mut Ui, track: &Track, head: click_track(app, id, ui.input(|i| i.modifiers), in_edit_window); } bg.context_menu(|ui| track_context_menu(app, ui, id)); + color_strip(app, ui, id, head); resize_edge(app, ui, track, head); strip_buttons(app, ui, track, head); name_plate(app, ui, track, head, selected); @@ -26,6 +28,28 @@ pub(super) fn track_header(app: &mut SoundApp, ui: &mut Ui, track: &Track, head: header_meter(ui, Rect::from_min_max(pos2(head.max.x - 8.0, head.min.y + 1.0), pos2(head.max.x, head.max.y - 1.5)), &md, track.channels() >= 2); } +/// The colour strip: a click selects the track as the header does, a double click opens the Color +/// Palette for the selected tracks. A plain click on a track that is already selected keeps the +/// selection, so double-clicking one of several selected tracks colours them all. Registered after +/// the header background, so it sits on top of it, and before the strip's own buttons and the +/// resize edge, which stay on top of it. +fn color_strip(app: &mut SoundApp, ui: &mut Ui, id: TrackId, head: Rect) { + let strip = Rect::from_min_size(head.min, vec2(STRIP_W, head.height())); + let resp = ui.interact(strip, ui.scope_id().with(("color_strip", id.0)), Sense::click()); + let mods = ui.input(|i| i.modifiers); + let selected = app.engine.session().edit.selected_tracks.contains(&id); + if resp.double_clicked() { + // A Cmd click toggles, so a Cmd double click's first click deselected the track: add it back. + if !selected { + click_track(app, id, mods, in_edit_window); + } + app.ui.show_color_palette = true; + } else if resp.clicked() && !(selected && mods.is_none()) { + click_track(app, id, mods, in_edit_window); + } + resp.context_menu(|ui| track_context_menu(app, ui, id)); +} + /// Drag the bottom edge of the header to resize the track (snaps to the height presets). fn resize_edge(app: &mut SoundApp, ui: &mut Ui, track: &Track, head: Rect) { let id = track.id; diff --git a/crates/ui-egui/src/edit_window/tests.rs b/crates/ui-egui/src/edit_window/tests.rs index 37dd3be9..ea7e7082 100644 --- a/crates/ui-egui/src/edit_window/tests.rs +++ b/crates/ui-egui/src/edit_window/tests.rs @@ -534,6 +534,53 @@ fn shift_and_cmd_click_on_track_names_extend_the_selection() { } } +/// #1254: double-clicking a track's colour strip selects the track and opens the Color Palette; +/// a single click only selects it. +#[test] +fn double_clicking_the_color_strip_opens_the_color_palette() { + let mut h = harness(3); + let ids = row_ids(&h); + let strip = |h: &Harness, i: usize| pos2(row(h, i).min.x + layout::STRIP_W / 2.0, row(h, i).center().y); + h.state_mut().engine.execute("edit.select", &json!({"tracks": [ids[0].0]})).unwrap(); + h.run_steps(2); + let at = strip(&h, 1); + click(&mut h, at); + assert_eq!(h.state().engine.session().edit.selected_tracks, [ids[1]]); + assert!(!h.state().ui.show_color_palette, "a single click on the strip doesn't open the palette"); + h.run_steps(30); + let at = strip(&h, 2); + click(&mut h, at); + click(&mut h, at); + assert_eq!(h.state().engine.session().edit.selected_tracks, [ids[2]]); + assert!(h.state().ui.show_color_palette, "a double click on the strip opens the palette"); +} + +/// #1254: a double click on the strip of one of several selected tracks keeps them all selected, +/// so the palette colours every one; with Cmd held the double-clicked track ends selected too. +#[test] +fn double_clicking_a_selected_tracks_strip_keeps_the_selection() { + let mut h = harness(3); + let ids = row_ids(&h); + let strip = |h: &Harness, i: usize| pos2(row(h, i).min.x + layout::STRIP_W / 2.0, row(h, i).center().y); + h.state_mut().engine.execute("edit.select", &json!({"tracks": [ids[0].0, ids[2].0]})).unwrap(); + h.run_steps(2); + let at = strip(&h, 2); + click(&mut h, at); + assert_eq!(h.state().engine.session().edit.selected_tracks, [ids[0], ids[2]], "a plain click on a selected strip keeps the selection"); + assert!(!h.state().ui.show_color_palette); + click(&mut h, at); + assert_eq!(h.state().engine.session().edit.selected_tracks, [ids[0], ids[2]], "both tracks stay selected"); + assert!(h.state().ui.show_color_palette, "a double click on the strip opens the palette"); + + h.state_mut().ui.show_color_palette = false; + h.run_steps(30); + let at = strip(&h, 0); + click_with(&mut h, at, egui::Modifiers::COMMAND); + click_with(&mut h, at, egui::Modifiers::COMMAND); + assert!(h.state().engine.session().edit.selected_tracks.contains(&ids[0]), "a Cmd double click leaves its track selected"); + assert!(h.state().ui.show_color_palette, "a Cmd double click on the strip opens the palette"); +} + #[test] fn a_quick_drag_from_a_clip_edge_trims_it() { let mut h = smart_demo();