From bd3b993b90747d92d904d165bc264c83e7f8ec1d Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sun, 20 Sep 2026 17:25:00 +0200 Subject: [PATCH] Split library_ui::wire into one function per section wire() registered every grid callback in one 1,214-line function behind four section comments, two of which were themselves far over 300 lines with no further markers. Each fenced section becomes its own function, called from wire() in the original order with the section's own comment kept as its doc comment: - "the keyboard cursor (FR-CULL-4)" (496 lines) splits at its own topic breaks into wire_grid_cursor_and_zoom (cursor movement, cell zoom and pinch), wire_grid_sync_and_load (explicit sync/thumbnail requests and the reloads a changed viewport, column count or scroll position trigger), wire_timeline (the capture-time sidebar) and wire_grid_routes (grid/launch/develop navigation and a manual rescan). - "ratings and flags" and "keywords" were already under 300 lines and become one function each. - "the filter bar" (447 lines) splits into wire_filter_ratings_and_people (which keeps the section's own comment), wire_filter_dates and wire_filter_scope_and_offline. The three callbacks registered before the first section comment (on_settings_xmp_reload, on_library_cell_clicked, on_library_roll_pick) and the trailing crate::recovery_ui::wire call stay directly in wire(), since neither is inside a fenced section. --- ui/dr-ui/src/library_ui.rs | 109 ++++++++++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 25 deletions(-) diff --git a/ui/dr-ui/src/library_ui.rs b/ui/dr-ui/src/library_ui.rs index 42412a8..4749b8a 100644 --- a/ui/dr-ui/src/library_ui.rs +++ b/ui/dr-ui/src/library_ui.rs @@ -5884,13 +5884,35 @@ pub fn wire( }); } - // --- the keyboard cursor (FR-CULL-4) ----------------------------------- - // - // Walking the grid with the arrows, and opening with `Return`. Together - // with the judgement keys already bound in the grid, this is what makes a - // culling pass a keyboard job: move, rate, move, open the doubtful one, - // come back. A cull is thousands of decisions, and reaching for the mouse - // between each of them is the difference between an hour and an evening. + wire_grid_cursor_and_zoom(window, &ctl, &coll_ctl, &on_open_image); + wire_grid_sync_and_load(window, &ctl); + wire_timeline(window, &ctl); + wire_grid_routes(window, &ctl, &coll_ctl, on_leave_develop); + wire_ratings_and_flags(window, &ctl, &coll_ctl); + wire_keywords(window, &ctl, &coll_ctl); + wire_filter_ratings_and_people(window, &ctl); + wire_filter_dates(window, &ctl); + wire_filter_scope_and_offline(window, &ctl, &coll_ctl); + + // Last, and in its own module: the answers to a damaged catalog have + // nothing to do with the library view except that they run before it + // exists. + crate::recovery_ui::wire(window, &ctl, &coll_ctl); +} + +/// --- the keyboard cursor (FR-CULL-4) ----------------------------------- +/// +/// Walking the grid with the arrows, and opening with `Return`. Together +/// with the judgement keys already bound in the grid, this is what makes a +/// culling pass a keyboard job: move, rate, move, open the doubtful one, +/// come back. A cull is thousands of decisions, and reaching for the mouse +/// between each of them is the difference between an hour and an evening. +fn wire_grid_cursor_and_zoom( + window: &AppWindow, + ctl: &Rc, + coll_ctl: &Rc, + on_open_image: &OpenImage, +) { { let weak = window.as_weak(); let ctl = ctl.clone(); @@ -6011,7 +6033,11 @@ pub fn wire( crate::collections_ui::cancel_press(&w, &coll, &ctl.visible_ids()); }); } +} +/// Reload triggers for the grid: an explicit sync or thumbnail sweep, and +/// the geometry and scroll changes that move which rows are loaded. +fn wire_grid_sync_and_load(window: &AppWindow, ctl: &Rc) { // Explicit sync, for when the user wants the exchange now rather than // after the next sweep. { @@ -6212,7 +6238,11 @@ pub fn wire( load_window(&w, &ctl); }); } +} +/// The capture-time sidebar: panning, zooming and scrubbing the axis that +/// the grid's loaded window follows. +fn wire_timeline(window: &AppWindow, ctl: &Rc) { // Panning the timeline slides the visible span without changing its width. { let weak = window.as_weak(); @@ -6320,7 +6350,16 @@ pub fn wire( apply_zoom(&w, &ctl, steps); }); } +} +/// Moving between the grid and the screens around it: the launch screen, +/// develop, and a manual rescan. +fn wire_grid_routes( + window: &AppWindow, + ctl: &Rc, + coll_ctl: &Rc, + on_leave_develop: Rc, +) { // Grid → launch screen. The route that was missing: once past the launch // screen there was no way back to it, so a library pointed at the wrong // folder could not be changed without clearing stored state by hand. @@ -6379,9 +6418,14 @@ pub fn wire( start_rescan(&w, &ctl, &coll_ctl); }); } +} - // --- ratings and flags (FR-CAT-5, FR-CULL-4) -------------------------- - +/// --- ratings and flags (FR-CAT-5, FR-CULL-4) -------------------------- +fn wire_ratings_and_flags( + window: &AppWindow, + ctl: &Rc, + coll_ctl: &Rc, +) { // Clicking a star rates *that cell*, not the selection. The pointer names // one photograph unambiguously, and a click that silently rated forty // others would be a trap — the keyboard is the bulk gesture. @@ -6483,13 +6527,19 @@ pub fn wire( } }); } +} - // --- keywords (FR-CAT-5, FR-CAT-6) ------------------------------------ - // - // Three callbacks and no state of their own: the sheet's open/shut is local - // to the `.slint` file, and what a keyword applies to is the grid selection - // the collections controller already owns. A second copy of either here is - // a second thing that can disagree with the first. +/// --- keywords (FR-CAT-5, FR-CAT-6) ------------------------------------ +/// +/// Three callbacks and no state of their own: the sheet's open/shut is local +/// to the `.slint` file, and what a keyword applies to is the grid selection +/// the collections controller already owns. A second copy of either here is +/// a second thing that can disagree with the first. +fn wire_keywords( + window: &AppWindow, + ctl: &Rc, + coll_ctl: &Rc, +) { { let weak = window.as_weak(); let ctl = ctl.clone(); @@ -6517,12 +6567,14 @@ pub fn wire( apply_keyword(&w, &ctl, word.as_str(), false); }); } +} - // --- the filter bar --------------------------------------------------- - // - // Each of these narrows what the grid *queries*, so all three reset the - // scroll offset: the window's position was an ordinal into a different - // set of images and means nothing once the set changes. +/// --- the filter bar --------------------------------------------------- +/// +/// Each of these narrows what the grid *queries*, so all three reset the +/// scroll offset: the window's position was an ordinal into a different +/// set of images and means nothing once the set changes. +fn wire_filter_ratings_and_people(window: &AppWindow, ctl: &Rc) { { let weak = window.as_weak(); let ctl = ctl.clone(); @@ -6691,7 +6743,11 @@ pub fn wire( refilter(&w, &ctl); }); } +} +/// The date-range filter: turned on from the timeline's own visible span, +/// dragged along the axis, or typed as two dates. +fn wire_filter_dates(window: &AppWindow, ctl: &Rc) { // Turn the range on, over the period the histogram is showing. // // The range is taken from the timeline rather than typed into two date @@ -6860,7 +6916,15 @@ pub fn wire( refilter(&w, &ctl); }); } +} +/// Whether the grid is scoped to what is available offline, and the +/// prompt those controls open. +fn wire_filter_scope_and_offline( + window: &AppWindow, + ctl: &Rc, + coll_ctl: &Rc, +) { // TRACES: FR-CAT-9 // "On this device" — the images openable without a server. Composes with // the rating terms rather than replacing them: "five-star frames I can @@ -6959,11 +7023,6 @@ pub fn wire( start_rescan(&w, &ctl, &coll_ctl); }); } - - // Last, and in its own module: the answers to a damaged catalog have - // nothing to do with the library view except that they run before it - // exists. - crate::recovery_ui::wire(window, &ctl, &coll_ctl); } /// Reload the grid after the filter changed.