Merge pull request #276 from marcoarnulfo/fix/filmstrip-clip-start

fix(video-universe): filmstrip thumbnails use the clip's own movie time (#225)
This commit is contained in:
Brandon Thomas authored and GitHub committed 2026-10-13 04:26:45 -04:00
commit baf102e13f
1 file changed
+37 -2
+37 -2
View File
@@ -95,6 +95,12 @@ fn video(app: &mut SoundApp, ctx: &egui::Context) {
}
}
/// Timeline position of strip coordinate `x` (the strip spans `left`..`left + width` and samples
/// 0..`end`), clamped to the start of the clip being drawn.
fn strip_position(x: f32, left: f32, width: f32, end: i64, clip_start: i64) -> i64 {
(((x - left) / width * end as f32) as i64).max(clip_start)
}
fn first_movie_aspect(s: &soundcraft_model::Session) -> Option<f32> {
s.videos.first().map(|v| v.aspect() as f32)
}
@@ -131,8 +137,7 @@ fn universe(app: &mut SoundApp, ctx: &egui::Context) {
let hpx = ((cr.height() * ppp / 16.0).ceil() * 16.0).clamp(16.0, 256.0) as u32;
let mut x = cr.min.x;
while x < cr.max.x {
let at = c.start + ((x - r.min.x) / r.width() * end as f32) as i64 - c.start.min(0);
let secs = movie_secs(&s, c.start, offset, at.max(c.start)).max(0.0);
let secs = movie_secs(&s, c.start, offset, strip_position(x, r.min.x, r.width(), end, c.start)).max(0.0);
if let Some(tex) = app.video.thumb(ctx, key, &v.path, secs, hpx) {
let tr = Rect::from_min_size(pos2(x, cr.min.y), vec2(tw, cr.height()));
let vis = tr.intersect(cr);
@@ -164,3 +169,33 @@ fn universe(app: &mut SoundApp, ctx: &egui::Context) {
app.ui.show_video_universe = false;
}
}
#[cfg(test)]
mod tests {
use super::strip_position;
// A 1024 px strip over 1_024_000 samples: 1000 samples per point, exact in f32.
const LEFT: f32 = 100.0;
const WIDTH: f32 = 1024.0;
const END: i64 = 1_024_000;
#[test]
fn strip_position_is_the_timeline_position_for_clips_after_zero() {
// A clip at 48_000 has its left edge at x = 148.
assert_eq!(strip_position(148.0, LEFT, WIDTH, END, 48_000), 48_000);
assert_eq!(strip_position(248.0, LEFT, WIDTH, END, 48_000), 148_000);
let s = soundcraft_model::Session::default();
let at = strip_position(148.0, LEFT, WIDTH, END, 48_000);
assert_eq!(crate::video_track::movie_secs(&s, 48_000, 0, at), 0.0, "the clip's left edge shows the movie's first picture");
}
#[test]
fn strip_position_is_unchanged_for_clips_at_or_before_zero() {
assert_eq!(strip_position(100.0, LEFT, WIDTH, END, 0), 0);
assert_eq!(strip_position(200.0, LEFT, WIDTH, END, 0), 100_000);
// A clip at -48_000 starts left of the strip; positions before it clamp to its start.
assert_eq!(strip_position(0.0, LEFT, WIDTH, END, -48_000), -48_000);
assert_eq!(strip_position(52.0, LEFT, WIDTH, END, -48_000), -48_000);
assert_eq!(strip_position(200.0, LEFT, WIDTH, END, -48_000), 100_000);
}
}