From fb725ce33fa92764861d93c42937479339a9c90c Mon Sep 17 00:00:00 2001 From: Vikram Bhaskaran Date: Tue, 13 Oct 2026 01:23:51 +1100 Subject: [PATCH] Scroll the filmstrip when the same photo is shown from another source. --- crates/ui-egui/src/panels/detail.rs | 2 +- crates/ui-egui/src/panels/grid.rs | 32 ++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/crates/ui-egui/src/panels/detail.rs b/crates/ui-egui/src/panels/detail.rs index 23447616..53f8df73 100644 --- a/crates/ui-egui/src/panels/detail.rs +++ b/crates/ui-egui/src/panels/detail.rs @@ -2145,7 +2145,7 @@ pub(crate) fn filmstrip(app: &mut LightcraftApp, ui: &mut egui::Ui, r: Rect) { // a vertical mouse wheel scrolls the strip sideways (horizontal trackpad scrolls still work) child.style_mut().always_scroll_the_only_direction = true; // only a new active photo (or the strip appearing) scrolls it; see `grid::follow_active` - let follow = super::grid::follow_active(child.ctx(), egui::Id::new("film-follow-active"), active); + let follow = super::grid::follow_active(child.ctx(), egui::Id::new("film-follow-active"), active, app.session.source); egui::ScrollArea::horizontal().id_salt("filmstrip").auto_shrink([false, false]).show_viewport(&mut child, |ui, vp| { let (area, _) = ui.allocate_exact_size(vec2(ids.len() as f32 * cell_w, r.height() - 16.0), Sense::hover()); app.film_scroll = Some(vp.left()); diff --git a/crates/ui-egui/src/panels/grid.rs b/crates/ui-egui/src/panels/grid.rs index 7b6d5cf6..2d620725 100644 --- a/crates/ui-egui/src/panels/grid.rs +++ b/crates/ui-egui/src/panels/grid.rs @@ -229,7 +229,7 @@ fn show_inner(app: &mut LightcraftApp, ui: &mut egui::Ui) { let active = app.session.selection.active; // bring the active photo into view when it changes (keyboard, click, command) or the grid // comes back on screen; otherwise the scroll position is the user's - let scroll_to: Option = if follow_active(ui.ctx(), egui::Id::new("grid-follow-active"), active) { + let scroll_to: Option = if follow_active(ui.ctx(), egui::Id::new("grid-follow-active"), active, app.session.source) { active.and_then(|a| ids.iter().position(|x| *x == a)).and_then(|i| lay.cells.get(i).copied()) } else { None @@ -295,16 +295,29 @@ fn show_inner(app: &mut LightcraftApp, ui: &mut egui::Ui) { /// the strip was not drawn on the previous pass (view switch, panel shown again). Otherwise the /// scroll position is the user's: time passing, finished renders, edits to the photo or a released /// scroll bar never move it (issue #11). -pub(crate) fn follow_active(ctx: &egui::Context, key: egui::Id, active: Option) -> bool { +pub(crate) fn follow_active(ctx: &egui::Context, key: egui::Id, active: Option, source: lightcraft_engine::LibrarySource) -> bool { let pass = ctx.cumulative_pass_nr(); - let last: Option<(Option, u64)> = ctx.data(|d| d.get_temp(key)); - ctx.data_mut(|d| d.insert_temp(key, (active, pass))); + let last: Option<(Option, lightcraft_engine::LibrarySource, u64)> = ctx.data(|d| d.get_temp(key)); + ctx.data_mut(|d| d.insert_temp(key, (active, source, pass))); match last { - Some((was, drawn)) => was != active || drawn + 1 < pass, + Some((was, where_, drawn)) => follow_changed(was, where_, drawn, active, source, pass), None => true, } } +/// Scroll when the active photo changes, the strip was not drawn last pass, or the same photo +/// sits in a different library source (another album) (#1142). +pub(crate) fn follow_changed( + was: Option, + where_was: lightcraft_engine::LibrarySource, + drawn: u64, + active: Option, + source: lightcraft_engine::LibrarySource, + pass: u64, +) -> bool { + was != active || where_was != source || drawn + 1 < pass +} + /// Height of a date header row (points). pub const HEADER_H: f32 = 40.0; @@ -1146,6 +1159,15 @@ pub fn context_menu(app: &mut LightcraftApp, ui: &mut egui::Ui, id: PhotoId) { mod tests { use super::*; + #[test] + fn the_same_photo_in_another_source_scrolls_into_view() { + let id = PhotoId(3); + let all = lightcraft_engine::LibrarySource::All; + let album = lightcraft_engine::LibrarySource::Album(lightcraft_catalog::AlbumId(9)); + assert!(!follow_changed(Some(id), all, 4, Some(id), all, 5)); + assert!(follow_changed(Some(id), all, 4, Some(id), album, 5)); + } + #[test] fn ungrouped_justified_rows_fill_the_width() { let aspects = [1.5f32, 1.5, 0.66, 1.0, 1.5, 1.5, 1.5];