diff --git a/ui/dr-ui/src/library_ui.rs b/ui/dr-ui/src/library_ui.rs index f7265ea..89fa881 100644 --- a/ui/dr-ui/src/library_ui.rs +++ b/ui/dr-ui/src/library_ui.rs @@ -121,6 +121,14 @@ pub struct LibraryController { /// A `Cell` because it is a `bool` read inside callbacks that already hold /// other borrows. viewing_trash: std::cell::Cell, + /// The selection's owner, so a rebuilt window can restore the `selected` + /// flags it just cleared. + /// + /// `Weak` because the two controllers outlive each other only through the + /// window, and an `Rc` both ways would leak both. Set once at wiring; a + /// `None` here means the grid simply draws nothing selected, which is the + /// old behaviour rather than a crash. + coll_ctl: RefCell>>, /// Timeline view state: how far zoomed in, and around what instant. /// /// Zoom is a level rather than a span so the axis halves and doubles in @@ -255,6 +263,7 @@ impl LibraryController { session: RefCell::new(None), scope: RefCell::new(None), viewing_trash: std::cell::Cell::new(false), + coll_ctl: RefCell::new(None), timeline_zoom: RefCell::new(0), timeline_centre: RefCell::new(None), pinch_accum: RefCell::new(1.0), @@ -1730,6 +1739,14 @@ fn load_window(window: &AppWindow, ctl: &Rc) { .collect(); crate::collections_ui::sync_badges(window, catalog, &ids); sync_ratings(window, catalog, &ids); + // The rebuilt cells all carry `selected: false`, but the selection itself + // is a set of image ids and survives untouched. Without this the ticks + // vanished on every scroll — the selection was still there and still acted + // on, which is worse than losing it, because the user cannot see what the + // buttons are about to do. + if let Some(coll) = ctl.coll_ctl.borrow().as_ref().and_then(|w| w.upgrade()) { + crate::collections_ui::sync_selection(window, &coll, &ids); + } // The filter chips' counts describe the whole library, not this window, so // they are refreshed here rather than per cell. refresh_rating_counts(window, catalog); @@ -3117,6 +3134,10 @@ pub fn wire( ) where F: Fn(String) + 'static, { + // So a rebuilt window can put the selection ticks back. Weak, or the two + // controllers would hold each other alive for the life of the process. + *ctl.coll_ctl.borrow_mut() = Some(Rc::downgrade(&coll_ctl)); + // Shared rather than moved: a click and `Return` both open an image, and // they are two callbacks. let on_open_image = Rc::new(on_open_image);