PR #1226: keep editor playback on the media bar

This commit is contained in:
kinower
2026-10-26 11:18:32 +01:00
parent 811758f791
commit 1956b6b491
2 changed files with 1 additions and 115 deletions
-26
View File
@@ -258,16 +258,11 @@ pub fn show(app: &mut SlideApp, ui: &mut Ui) {
ruler(&painter, avail, slide_rect, scale, &t);
ruler_markers(app, ui, &painter, avail, xf, &t);
}
// A click the Eyedropper takes is not also a click on a video.
let sampling = app.eyedropper.is_some();
pointer(app, ui, &resp, xf);
if !app.anim_preview_active() {
overlays(app, ui, &painter, xf, &t);
ime_output(app, ui, xf);
media_bar(app, ui, xf);
if !sampling {
media_click(app, ui, &resp, xf);
}
gif_buttons(app, ui, xf, &gifs);
if resp.secondary_clicked()
&& let Some(p) = resp.interact_pointer_pos()
@@ -414,27 +409,6 @@ fn media_bar(app: &mut SlideApp, ui: &mut Ui, xf: Xf) {
}
}
/// A click on a video plays or pauses it, as its bar's Play button does. The click selects it as
/// usual; dragging it moves it without playing, and a modifier key leaves it to the selection.
fn media_click(app: &mut SlideApp, ui: &Ui, resp: &egui::Response, xf: Xf) {
// The second and third clicks of a double or triple click leave the first one's choice.
if !resp.clicked() || resp.double_clicked() || resp.triple_clicked() || !ui.input(|i| i.modifiers.is_none()) {
return;
}
let Some(p) = resp.interact_pointer_pos() else { return };
let Some(d) = app.session.active() else { return };
if d.selection.target != Target::Slides || d.selection.text.is_some() || d.selection.shapes.len() != 1 {
return;
}
let only = d.selection.shapes[0];
let hit = crate::media::slide_media(&d.doc, d.selection.slide)
.into_iter()
.find(|(id, x, clip)| clip.video && *id == only && screen_rect(xf, x).contains(p));
let Some((id, _, clip)) = hit else { return };
let (uid, doc) = (d.uid, d.doc.clone());
app.media.toggle(uid, &doc, id, &clip, crate::media::Owner::Editor);
}
fn master_tex(
ctx: &egui::Context,
doc: &deckcraft_model::Presentation,
+1 -89
View File
@@ -2,10 +2,8 @@
//! mouse: a press on it used to reach the canvas, start a selection marquee there and hide the bar
//! before the click landed, so Play only worked in the slide show.
use std::sync::Arc;
use deckcraft_engine::Session;
use deckcraft_model::{Shape, ShapeId, ShapeKind};
use deckcraft_model::ShapeId;
use egui::{Modifiers, PointerButton, Pos2, pos2, vec2};
use egui_kittest::Harness;
use serde_json::json;
@@ -72,89 +70,3 @@ fn play_on_the_editor_media_bar_plays_the_selected_clip() {
click(&mut h, bar + vec2(w - 30.0, 13.0));
assert_eq!(h.state().session.active().unwrap().selection.shapes, vec![id]);
}
/// A click on a video plays it and the next one pauses it; dragging it only moves it.
#[test]
fn a_click_on_a_video_plays_or_pauses_it() {
let mut s = Session::with_new();
s.execute("slide.new", &json!({"layout": "blank"})).unwrap();
let r = s.execute("insert.audio", &json!({"name": "tone.wav", "data": deckcraft_engine::cmd::base64_encode(&wav(10.0))})).unwrap();
let id = ShapeId(r["id"].as_u64().unwrap() as u32);
// Only videos play on a click; the clip's sound stands in for a film. It is long enough to
// still be playing when the last click lands.
{
let d = s.active_mut().unwrap();
let slide = Arc::make_mut(&mut Arc::make_mut(&mut d.doc).slides[d.selection.slide]);
if let Some(Shape { kind: ShapeKind::Media(clip), .. }) = deckcraft_model::find_shape_mut(&mut slide.shapes, id) {
clip.video = true;
}
}
s.execute("edit.deselect", &json!({})).unwrap();
let app = SlideApp::new(s, Services::default());
let mut h = Harness::builder().with_size(vec2(1400.0, 900.0)).with_step_dt(1.0 / 60.0).build_ui_state(
|ui, app: &mut SlideApp| {
app.logic(ui.ctx());
app.ui(ui);
},
app,
);
h.run_steps(3);
let d = h.state().session.active().unwrap();
let x = d.doc.slides[d.selection.slide].shape(id).unwrap().xfrm.unwrap();
// Where the clip's centre is on screen (a double click opens the Format pane, which moves it).
let centre_of = |h: &Harness<'_, SlideApp>| {
let (slide, k) = (h.state().slide_rect.unwrap(), h.state().canvas_scale);
slide.min + vec2((x.x + x.w / 2.0) as f32 * k, (x.y + x.h / 2.0) as f32 * k)
};
let mut centre = centre_of(&h);
click(&mut h, centre);
assert_eq!(h.state().session.active().unwrap().selection.shapes, vec![id], "the click selects it");
assert!(h.state().media.is_playing(id), "and plays it");
// Far enough apart not to make a double click.
h.run_steps(40);
click(&mut h, centre);
assert!(!h.state().media.is_playing(id), "the next click pauses it");
// A double or triple click plays it once: only the first click counts.
for clicks in [2, 3] {
h.run_steps(40);
assert!(!h.state().media.is_playing(id));
for _ in 0..clicks {
h.event(egui::Event::PointerButton { pos: centre, button: PointerButton::Primary, pressed: true, modifiers: Modifiers::NONE });
h.run_steps(1);
h.event(egui::Event::PointerButton { pos: centre, button: PointerButton::Primary, pressed: false, modifiers: Modifiers::NONE });
h.run_steps(1);
}
assert!(h.state().media.is_playing(id), "{clicks} quick clicks leave it playing");
h.run_steps(40);
centre = centre_of(&h);
click(&mut h, centre);
assert!(!h.state().media.is_playing(id));
}
// A click the Eyedropper takes does not play the video.
h.run_steps(40);
crate::eyedropper::note_open_menu(&h.ctx, egui::Id::new("fill-colour"));
crate::eyedropper::request(&h.ctx);
h.run_steps(2);
assert!(h.state().eyedropper.is_some(), "the Eyedropper waits for a click");
click(&mut h, centre);
assert!(h.state().eyedropper.is_none(), "the Eyedropper took the click");
assert!(!h.state().media.is_playing(id), "the video did not start");
// A drag moves it without playing.
h.run_steps(40);
h.event(egui::Event::PointerButton { pos: centre, button: PointerButton::Primary, pressed: true, modifiers: Modifiers::NONE });
h.run_steps(1);
for i in 1..=6 {
h.event(egui::Event::PointerMoved(centre + vec2(8.0 * i as f32, 0.0)));
h.run_steps(1);
}
h.event(egui::Event::PointerButton { pos: centre + vec2(48.0, 0.0), button: PointerButton::Primary, pressed: false, modifiers: Modifiers::NONE });
h.run_steps(2);
assert!(!h.state().media.is_playing(id), "dragging does not play it");
let d = h.state().session.active().unwrap();
let moved = d.doc.slides[d.selection.slide].shape(id).unwrap().xfrm.unwrap();
assert!(moved.x > x.x, "the drag moved it");
}