mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-14 19:27:05 -04:00
M5.14: J / K stop at the work area; the Info panel shows a selected keyframe
- Go to Next / Previous Keyframe (K / J) also stops at the work area's start and end, as in After Effects. - With one keyframe selected, the Info panel shows its property, time and value instead of "1 keyframes selected". Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
43bf2906d3
commit
dfb0227468
3 files changed
+39
-8
No files matched your search
@@ -79,7 +79,7 @@ fn go(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
"layerIn" => sel_layer.map(|l| l.in_point).unwrap_or(t),
|
||||
"layerOut" => sel_layer.map(|l| l.out_point - comp.frame_duration()).unwrap_or(t),
|
||||
"nextKey" | "prevKey" => {
|
||||
// Keyframes (of visible/selected layers) and markers, in comp time.
|
||||
// Keyframes (of visible/selected layers), markers and the work area, in comp time.
|
||||
let mut times: Vec<Tick> = comp.markers.iter().map(|m| m.time).collect();
|
||||
let layers: Vec<_> = if s.state.selected_layers.is_empty() {
|
||||
comp.layers.iter().collect()
|
||||
@@ -90,6 +90,9 @@ fn go(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let only = p.get("prop").and_then(Value::as_u64);
|
||||
if only.is_some() {
|
||||
times.clear();
|
||||
} else {
|
||||
// The work area's start and end too, as in After Effects.
|
||||
times.extend([comp.work_area.0, comp.work_area.1 - comp.frame_duration()]);
|
||||
}
|
||||
for l in layers {
|
||||
l.props.walk("", &mut |_, pr| {
|
||||
|
||||
@@ -1014,3 +1014,19 @@ fn keys_from_several_layers_paste_in_order_and_paste_reversed_respects_stretch()
|
||||
assert!(ct.len() == 2 && (ct[1] - ct[0] - 1.0).abs() < 1e-6, "keys 1 s apart in comp time: {ct:?}");
|
||||
assert_eq!(vals, vec![10.0, 0.0], "reversed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn j_and_k_stop_at_keys_markers_and_the_work_area() {
|
||||
let mut s = comp();
|
||||
let a = solid(&mut s, "#ff0000");
|
||||
opacity_keys(&mut s, a, &[2.0]);
|
||||
s.execute("comp.workArea", json!({"start": 1.0, "end": 3.0})).unwrap();
|
||||
s.execute("layer.select", json!({"layers": [a]})).unwrap();
|
||||
let mut stops = vec![];
|
||||
for _ in 0..4 {
|
||||
s.execute("time.nextKey", json!({})).unwrap();
|
||||
stops.push((s.time().seconds() * 30.0).round() / 30.0);
|
||||
}
|
||||
let last = (3.0 * 30.0 - 1.0) / 30.0;
|
||||
assert_eq!(stops, vec![1.0, 2.0, (last * 30.0f64).round() / 30.0, (last * 30.0f64).round() / 30.0]);
|
||||
}
|
||||
@@ -101,13 +101,25 @@ pub fn show(app: &mut EffectcraftApp, ui: &mut egui::Ui, rect: Rect) {
|
||||
p.text(pos2(x0, ly), Align2::LEFT_CENTER, format!("Render: {ms:.0} ms • UI {:.0} fps{rq}", app.fps), Tokens::ui(11.5), t.text_faint);
|
||||
}
|
||||
if !app.session.state.selected_keys.is_empty() {
|
||||
p.text(
|
||||
pos2(x0, ly + 18.0),
|
||||
Align2::LEFT_CENTER,
|
||||
format!("{} keyframes selected", app.session.state.selected_keys.len()),
|
||||
Tokens::ui(11.5),
|
||||
t.text_dim,
|
||||
);
|
||||
// One key: its property, time and value (as After Effects' Info panel shows them).
|
||||
let sel = &app.session.state.selected_keys;
|
||||
let one = match sel.as_slice() {
|
||||
[k] => c.layer(k.layer).and_then(|l| {
|
||||
let pr = l.props.find(k.prop)?;
|
||||
let key = pr.keys.iter().find(|x| x.time == k.time)?;
|
||||
let tc = crate::panels::timecode(&app.session, &c, l.comp_time(k.time));
|
||||
let v = match &key.value {
|
||||
effectcraft_engine::keyframe::Value::Scalar(v) => format!("{v:.2}"),
|
||||
effectcraft_engine::keyframe::Value::Vec2(v) => format!("{:.1}, {:.1}", v[0], v[1]),
|
||||
effectcraft_engine::keyframe::Value::Vec3(v) => format!("{:.1}, {:.1}, {:.1}", v[0], v[1], v[2]),
|
||||
_ => String::new(),
|
||||
};
|
||||
Some(format!("{} {tc} {v}", pr.name).trim_end().to_string())
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
let line = one.unwrap_or_else(|| format!("{} keyframes selected", sel.len()));
|
||||
p.text(pos2(x0, ly + 18.0), Align2::LEFT_CENTER, line, Tokens::ui(11.5), t.text_dim);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user