Merge pull request #1271 from n-delic/fix-1241-select-all-keyframes
#1241: Select All in Effect Controls selects its keyframes
This commit is contained in:
commit
ade0f36544
|
|
@ -78,6 +78,10 @@ real_name = "Valentin Klein"
|
|||
display_name = "Valentin Klein"
|
||||
sync_github_name = false
|
||||
|
||||
[people.n-delic]
|
||||
display_name = "n-delic"
|
||||
sync_github_name = false
|
||||
|
||||
[people.Silvertree2010]
|
||||
display_name = "Netter"
|
||||
sync_github_name = false
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ pub fn targets_source(app: &FilmcraftApp, params: &Value) -> bool {
|
|||
|
||||
/// Execute a UI or engine command by id.
|
||||
pub fn invoke(app: &mut FilmcraftApp, ctx: &egui::Context, id: &str, mut params: Value) -> Result<Value, String> {
|
||||
if id == "edit.selectAll" && crate::panels::graphics::select_all_edited_text(app) {
|
||||
if id == "edit.selectAll" && (crate::panels::graphics::select_all_edited_text(app) || crate::panels::effect_controls::select_all_keyframes(app)) {
|
||||
return Ok(Value::Null);
|
||||
}
|
||||
if filmcraft_engine::source_monitor::source_command(id) && targets_source(app, ¶ms) && params.get("target").is_none() {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,33 @@ fn keyframe_exists(it: &TrackItem, k: &KeyframeRef) -> bool {
|
|||
param.is_some_and(|p| p.keyframes.iter().any(|kf| kf.time == k.time))
|
||||
}
|
||||
|
||||
/// Edit ▸ Select All (⌘A) with Effect Controls focused selects every keyframe the panel shows
|
||||
/// instead of the Timeline's clips (#1241). False when the panel is not focused or shows none.
|
||||
pub(crate) fn select_all_keyframes(app: &mut FilmcraftApp) -> bool {
|
||||
if app.ui.focused != crate::dock::PanelKind::EffectControls {
|
||||
return false;
|
||||
}
|
||||
let mut keys = Vec::new();
|
||||
for (clip, it, _) in selected_clips(app) {
|
||||
for (effect, e) in it.effects.iter().enumerate() {
|
||||
let key = |param: &str, mask, time| KeyframeRef { clip: clip.0, effect, param: param.to_string(), mask, time };
|
||||
for (param, p) in &e.params {
|
||||
keys.extend(p.keyframes.iter().map(|kf| key(param, None, kf.time)));
|
||||
}
|
||||
for (m, mask) in e.masks.iter().enumerate() {
|
||||
for param in filmcraft_project::mask::MASK_PARAMS {
|
||||
keys.extend(mask.param(param).into_iter().flat_map(|p| &p.keyframes).map(|kf| key(param, Some(m), kf.time)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if keys.is_empty() {
|
||||
return false;
|
||||
}
|
||||
app.ui.keyframe_selection = keys;
|
||||
true
|
||||
}
|
||||
|
||||
fn selected_clip(app: &FilmcraftApp) -> Option<(ClipId, TrackItem, TrackKind)> {
|
||||
selected_clips(app).into_iter().next()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -311,6 +311,32 @@ fn clicking_a_lane_keyframe_selects_only_that_keyframe() {
|
|||
assert_eq!(selection(&mut d), json!([]), "a deleted keyframe is not selected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_all_in_effect_controls_selects_its_keyframes_not_the_clips() {
|
||||
// #1241
|
||||
let (mut d, clip) = Driver::demo();
|
||||
d.seek(1.0);
|
||||
for param in ["scale", "position"] {
|
||||
d.exec("effects.addKeyframe", json!({"clip": clip.id, "effect": "motion", "param": param}));
|
||||
}
|
||||
d.seek(2.0);
|
||||
d.exec("effects.addKeyframe", json!({"clip": clip.id, "effect": "motion", "param": "scale"}));
|
||||
let clips = d.ok("ui.inspect", json!({}))["selection"].clone();
|
||||
d.ok("ui.set", json!({"focused": "EffectControls"}));
|
||||
d.ok("ui.key", json!({"key": "Cmd+A"}));
|
||||
d.frames(2);
|
||||
let inspect = d.ok("ui.inspect", json!({}));
|
||||
let keys = inspect["ui"]["keyframe_selection"].as_array().cloned().unwrap_or_default();
|
||||
assert_eq!(keys.len(), 3, "{keys:?}");
|
||||
assert!(keys.iter().all(|k| k["clip"] == clip.id));
|
||||
assert_eq!(inspect["selection"], clips, "the Timeline selection is unchanged");
|
||||
// with the Timeline focused, Select All still selects the clips
|
||||
d.ok("ui.set", json!({"focused": "Timeline"}));
|
||||
d.ok("ui.key", json!({"key": "Cmd+A"}));
|
||||
d.frames(2);
|
||||
assert!(d.ok("ui.inspect", json!({}))["selection"].as_array().map_or(0, Vec::len) > clips.as_array().map_or(0, Vec::len));
|
||||
}
|
||||
|
||||
/// Effect Controls' divider (#643): dragging it widens the effect list or the keyframe area, each
|
||||
/// keeping a minimum width, and the width stays. The mouse wheel scrolls the rows over the
|
||||
/// keyframe area too, not only over the effect list.
|
||||
|
|
|
|||
Loading…
Reference in New Issue