mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-30 21:47:00 -06:00
PR #1226: keep editor playback on the media bar
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user