Merge pull request #189 from Luna161/fix/168-project-select-all

Engine: project.selectAll and project.deselectAll for the Project panel (#168)
This commit is contained in:
Brandon Thomas
2026-10-07 17:46:19 -04:00
3 changed files with 33 additions and 1 deletions
+9
View File
@@ -17,6 +17,7 @@
//! | `project.freeform.saveArrangement` / `.restoreArrangement` / `.arrangements` / `.deleteArrangement` | saved arrangements |
//! | `project.freeform.options` | Freeform View Options… (grid, snap, names, durations) |
//! | `project.renameBin` | rename a bin (inline rename, undoable) |
//! | `project.selectAll` / `project.deselectAll` | select every item in the project / clear the Project panel selection (Cmd+A / Cmd+Shift+A with the panel focused) |
use std::collections::BTreeMap;
@@ -1222,5 +1223,13 @@ pub(crate) fn commands() -> Vec<CommandSpec> {
freeform_options,
),
c("project.renameBin", "Rename Bin", r#"{"bin":binId,"name":str}"#, always, rename_bin),
c("project.selectAll", "Select All Project Items", "{}", always, |s, _| {
s.state.project_selection = s.project.items.keys().copied().collect();
Ok(json!({"selected": s.state.project_selection.len()}))
}),
c("project.deselectAll", "Deselect All Project Items", "{}", always, |s, _| {
s.state.project_selection.clear();
Ok(Value::Null)
}),
]
}
+19
View File
@@ -286,3 +286,22 @@ fn usage_counts_sequence_uses() {
assert_eq!(text, (if v > 0 { v } else { a }).to_string());
assert!(!matches!(it.kind, ItemKind::Graphic { .. }));
}
#[test]
fn select_all_selects_every_project_item() {
let mut s = demo();
assert!(s.project.items.len() >= 3);
s.state.project_selection.clear();
let r = s.execute("project.selectAll", json!({})).unwrap();
assert_eq!(r["selected"].as_u64(), Some(s.project.items.len() as u64));
assert_eq!(s.state.project_selection.len(), s.project.items.len());
assert!(s.project.items.keys().all(|i| s.state.project_selection.contains(i)));
s.execute("project.deselectAll", json!({})).unwrap();
assert!(s.state.project_selection.is_empty());
// the timeline Select All still selects timeline clips and leaves the Project panel alone
s.execute("project.selectAll", json!({})).unwrap();
let before = s.state.project_selection.clone();
s.execute("edit.selectAll", json!({})).unwrap();
assert!(!s.state.selection.is_empty());
assert_eq!(s.state.project_selection, before);
}
+5 -1
View File
@@ -1001,7 +1001,11 @@ impl FilmcraftApp {
}
}
});
for id in fire {
for mut id in fire {
// Select All / Deselect All act on the Project panel's items when it has focus (#168).
if self.ui.focused == PanelKind::Project && matches!(id.as_str(), "edit.selectAll" | "edit.deselectAll") {
id = id.replacen("edit.", "project.", 1);
}
// Mark In/Out in the Source monitor when it has focus.
let params = if self.ui.focused == PanelKind::Source
&& (matches!(id.as_str(), "markers.markIn" | "markers.markOut") || id.starts_with("markers.markSplit") || id.starts_with("markers.goToSplit"))