mirror of
https://github.com/storytold/filmcraft.git
synced 2026-11-02 18:09:21 +00:00
Effect Controls: double-clicking a property's name resets it (#3735)
* Effect Controls: double-clicking a property's name resets it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VkpGcKfWyCudfSsQNiWAaG * Effect Controls: the property-name automation ID carries the effect index and is clipped to the view Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VkpGcKfWyCudfSsQNiWAaG * test: the name double-click is one undo step and leaves the row in place Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VkpGcKfWyCudfSsQNiWAaG --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -648,6 +648,20 @@ pub(crate) fn param_row(
|
||||
x += 14.0;
|
||||
let vx = r.min.x + (r.width() * 0.5).max(150.0);
|
||||
row_label(ui, pos2(x, r.center().y), crate::i18n::t(pd.label), vx - 6.0 - x, Tokens::ui(12.0), t.text);
|
||||
// double-clicking a property's name resets it, as the reset button at the row's end does (a
|
||||
// click on the value itself starts typing, so the name is the double-click target)
|
||||
if mask.is_none() {
|
||||
let name = Rect::from_min_max(pos2(x, r.min.y), pos2(vx - 6.0, r.max.y));
|
||||
// the instance index tells two copies of one effect apart; only the visible part of a row
|
||||
// scrolled partly out of view is registered
|
||||
let shown = name.intersect(ui.clip_rect());
|
||||
if shown.is_positive() {
|
||||
app.auto.add(&format!("effectControls.{}.{idx}.{}.name", e.effect, pkey), shown, crate::i18n::t(pd.label));
|
||||
}
|
||||
if row.double_clicked() && row.interact_pointer_pos().is_some_and(|p| name.contains(p)) {
|
||||
actions.push(("effects.resetParam".into(), json!({"clip": clip.0, "effect": idx, "param": pd.id})));
|
||||
}
|
||||
}
|
||||
let value = param.value_at(mt);
|
||||
let mut vui = ui.new_child(
|
||||
egui::UiBuilder::new()
|
||||
|
||||
@@ -30,7 +30,8 @@ impl Driver {
|
||||
let (tx, rx) = channel();
|
||||
let app = FilmcraftApp::new(session).with_control(rx);
|
||||
let shots = std::env::var_os("FILMCRAFT_UI_SHOTS").map(std::path::PathBuf::from);
|
||||
let mut b = Harness::builder().with_size(egui::vec2(1600.0, 980.0)).with_max_steps(10_000);
|
||||
// frames 1/60 s apart, so that two clicks make a double-click
|
||||
let mut b = Harness::builder().with_size(egui::vec2(1600.0, 980.0)).with_step_dt(1.0 / 60.0).with_max_steps(10_000);
|
||||
if shots.is_some() {
|
||||
b = b.wgpu().with_pixels_per_point(1.0);
|
||||
}
|
||||
@@ -237,6 +238,32 @@ fn effect_controls_reset_button_keeps_keyframes() {
|
||||
assert_eq!(value, 100.0);
|
||||
}
|
||||
|
||||
/// Double-clicking a property's name resets it, as its reset button does; a single click doesn't.
|
||||
#[test]
|
||||
fn effect_controls_double_clicking_a_property_name_resets_it() {
|
||||
let (mut d, clip) = Driver::demo();
|
||||
d.exec("effects.setParam", json!({"clip": clip.id, "effect": "motion", "param": "scale", "value": 150.0}));
|
||||
d.frames(2);
|
||||
let [x, y, w, h] = d.rect("effectControls.motion.0.scale.name");
|
||||
let (x, y) = (x + w * 0.3, y + h * 0.5);
|
||||
d.ok("ui.click", json!({"x": x, "y": y}));
|
||||
d.frames(3);
|
||||
assert_eq!(d.scale(&clip).1, 150.0, "a single click leaves the value");
|
||||
// half a second later, or egui counts the next clicks as a triple click
|
||||
d.frames(30);
|
||||
d.ok("ui.click", json!({"x": x, "y": y, "count": 2}));
|
||||
d.frames(3);
|
||||
let (keys, value) = d.scale(&clip);
|
||||
assert!(keys.is_empty(), "{keys:?}");
|
||||
assert_eq!(value, 100.0);
|
||||
// the double-click neither folds nor renames anything: the row is still there
|
||||
d.rect("effectControls.motion.0.scale.name");
|
||||
// and the reset is one undo step
|
||||
d.exec("edit.undo", json!({}));
|
||||
d.frames(2);
|
||||
assert_eq!(d.scale(&clip).1, 150.0, "one undo brings the value back");
|
||||
}
|
||||
|
||||
/// Crop is not on a clip until it is used: its diamond applies the effect, then adds the keyframe.
|
||||
#[test]
|
||||
fn properties_diamond_applies_crop_first() {
|
||||
|
||||
Reference in New Issue
Block a user