Timeline: the marker bin's double-click needs both clicks on the bin (#1826)

egui takes any click within a few points of the last one for the first
click of a double-click, so a click on the ruler right beside the bin and
then one on the bin added a marker. The bin now remembers when it was
last clicked and adds one only when the first click was on it too (or
both came in one frame over it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Zinadin ZidanandClaude Opus 5.5 committed 2026-11-05 18:05:43 +06:00
1 parent 5cb2658e38
commit 5e96b2a385
2 files changed
+47 -2

No files matched your search

+35 -2
View File
@@ -435,8 +435,9 @@ pub(crate) fn marker_bin(app: &mut EffectcraftApp, ui: &mut egui::Ui, comp: &Com
// The bin senses drags only, so a drag starts as soon as it is pressed: sensing clicks too
// would hold that back until the pointer moved, and a drag out released within that frame
// would add nothing. The double-click is read from the pointer instead.
let double_clicked = resp.contains_pointer() && ui.input(|i| i.pointer.button_double_clicked(egui::PointerButton::Primary));
if double_clicked && let Err(e) = app.session.execute("comp.addMarker", json!({})) {
if bin_double_clicked(ui, resp.id, bin, resp.contains_pointer())
&& let Err(e) = app.session.execute("comp.addMarker", json!({}))
{
app.ui.status = e.to_string();
}
app.auto.add("timeline.markerBin", bin, "Composition marker bin");
@@ -463,6 +464,38 @@ pub(crate) fn marker_bin(app: &mut EffectcraftApp, ui: &mut egui::Ui, comp: &Com
}
}
/// Whether the marker bin `bin` (widget `id`, under the pointer when `here`) was double-clicked
/// this frame: egui's double-click, with its first click on the bin too. egui takes any click
/// within a few points of the last for the first one, so a click on the ruler right beside the
/// bin and then one on the bin would count. The bin remembers when it was last clicked; two
/// clicks on it within one frame need no memory.
fn bin_double_clicked(ui: &egui::Ui, id: egui::Id, bin: Rect, here: bool) -> bool {
use egui::{Event, PointerButton};
if !here {
return false;
}
let (time, clicked, double, releases) = ui.input(|i| {
let releases = i
.events
.iter()
.filter(|e| matches!(e, Event::PointerButton { button: PointerButton::Primary, pressed: false, pos, .. } if bin.contains(*pos)))
.count();
(i.time, i.pointer.button_clicked(PointerButton::Primary), i.pointer.button_double_clicked(PointerButton::Primary), releases)
});
if !clicked {
return false;
}
let delay = ui.ctx().options(|o| o.input_options.max_double_click_delay);
let id = id.with("last click");
let last = ui.data_mut(|d| {
let last = d.get_temp::<f64>(id);
d.insert_temp(id, time);
last
});
let last = last.unwrap_or(f64::NEG_INFINITY);
double && (releases >= 2 || time - last < delay)
}
/// Layer markers on a layer's row `r`; on a precomp layer, its comp's markers too (read-only,
/// outlined: hover names them, a double-click opens the nested comp at the marker).
pub(crate) fn layer_markers(app: &mut EffectcraftApp, ui: &mut egui::Ui, clip: Rect, comp: &Comp, layer: &Layer, tm: TMap, r: Rect) {
@@ -431,6 +431,18 @@ fn double_clicking_the_marker_bin_adds_a_comp_marker_at_the_current_time() {
h.step();
h.run_steps(3);
assert_eq!(markers(&h), vec![21.5, 22.0], "a double-click released while the bin is dragged");
// A click on the ruler right beside the bin and then one on the bin, in one frame: egui
// takes them for a double-click (they are a few points apart), but only one was on the bin.
let (beside, on) = (pos2(bin.min.x - 2.0, bin.center().y), pos2(bin.min.x + 2.0, bin.center().y));
assert!(ruler.contains(beside) && !bin.contains(beside) && bin.contains(on));
h.event(Event::PointerMoved(beside));
h.step();
for (pos, pressed) in [(beside, true), (beside, false), (on, true), (on, false)] {
h.input_mut().events.push(Event::PointerButton { pos, button: egui::PointerButton::Primary, pressed, modifiers: Modifiers::NONE });
}
h.step();
h.run_steps(3);
assert_eq!(markers(&h), vec![21.5, 22.0], "one click beside the bin and one on it");
// Dragged out 3 s into the visible span (from 10 s at 200 px/s): a marker at 13 s too.
drag(&mut h, bin.center(), pos2(ruler.min.x + 6.0 + 600.0, ruler.center().y));
assert_eq!(markers(&h), vec![13.0, 21.5, 22.0]);