Merge PR #2848: LRC-SS-LAYOUT: the Slideshow settings page no longer moves when the slide preview finishes rendering

docs/whats-new.md, docs/parity-checklist.md: both sides kept; header keeps the newer date.
This commit is contained in:
aiongg
2026-10-31 02:10:51 +00:00
3 changed files with 36 additions and 1 deletions
@@ -247,9 +247,14 @@ pub fn preview(app: &mut LightcraftApp, ui: &mut egui::Ui, t: &Tokens, max_h: f3
} else {
ui.ctx().request_repaint_after(std::time::Duration::from_secs_f64((DEBOUNCE - still).clamp(0.01, DEBOUNCE)));
}
let say =
|ui: &mut egui::Ui| hint(ui, t, "The selected photo as a slide. Playback fills the screen; the aspect preview only changes this preview.");
let Some(tex) = app.renderer.textures.get(&Slot::SlidePreview).filter(|tex| tex.photo == id) else {
p.rect_filled(rect, 0.0, Color32::from_rgb(s.backdrop_color[0], s.backdrop_color[1], s.backdrop_color[2]));
p.text(rect.center(), Align2::CENTER_CENTER, crate::i18n::tr("Rendering…"), t.font(11.5), Color32::from_gray(200));
// (the hint too: the render lands on a frame nobody can name, and a line that came with it would push
// the pinned preview's block, and the page under it, down while a control is being clicked)
say(ui);
return;
};
let drawn = crate::panels::detail::fit_texture_rect(rect, tex.size);
@@ -269,7 +274,7 @@ pub fn preview(app: &mut LightcraftApp, ui: &mut egui::Ui, t: &Tokens, max_h: f3
p.line_segment([pos2(drawn.left(), gy), pos2(drawn.right(), gy)], stroke);
}
}
hint(ui, t, "The selected photo as a slide. Playback fills the screen; the aspect preview only changes this preview.");
say(ui);
}
/// The preview showing title screen `title` (composed off the UI thread like the photo's slide,
+23
View File
@@ -400,6 +400,29 @@ fn playback_settings_drive_the_slideshow_and_bad_ones_are_refused() {
h.settle(SETTLE);
}
/// The slide preview's render lands on a frame nobody can name (a worker thread); the page under it must
/// not move when it does, or a click made in that frame lands beside the control aimed at (the gate went
/// red on it: `playback_settings_…` clicks "Random order" and the checkbox never changed).
#[test]
fn the_settings_page_does_not_move_when_the_slide_preview_finishes_rendering() {
let mut h = grid();
let open = std::rc::Rc::new(std::cell::Cell::new(false));
h.app.renderer.set_offload(Box::new(crate::headless::RenderGate::new(open.clone())));
run(&mut h, "view.slideshowOptions", json!({}));
// (the held render keeps the app "busy", so settle() would wait out its timeout: a second of frames instead)
for _ in 0..60 {
h.step();
}
let rect = |h: &Headless, w: &str| h.app.widgets.iter().find(|(id, _)| id == w).map(|(_, r)| *r).unwrap_or_else(|| panic!("{w} is on screen"));
let (room, check) = (rect(&h, "settings:pageRoom"), rect(&h, "check:settings.slideshowRandom"));
assert!(!h.app.renderer.textures.contains_key(&Slot::SlidePreview), "the render is held back");
open.set(true);
assert!(h.step_until(SETTLE, |h| h.app.renderer.textures.contains_key(&Slot::SlidePreview)), "the render lands");
h.settle(Duration::from_secs(5));
assert_eq!(rect(&h, "settings:pageRoom"), room, "the page's room is the same before and after the render");
assert_eq!(rect(&h, "check:settings.slideshowRandom"), check, "a control stays where it was drawn");
}
#[test]
fn a_click_on_a_control_scrolled_out_of_the_settings_page_is_refused() {
// A compact window leaves the lower controls of the Slideshow settings page outside the
+7
View File
@@ -57,8 +57,15 @@
## 2026-10-24
### Typed GPS coordinates are validated before editing metadata
- Entered coordinates must contain a complete decimal or degrees/minutes/seconds value. Unknown text, exponent notation, wrong-axis or conflicting hemispheres, and minutes or seconds outside [0,60) are rejected instead of being silently ignored and reinterpreted. A rejected GPS value also leaves the other fields in the same metadata edit unchanged.
### The Slideshow settings page stays put while the preview renders
- In Settings ▸ Slideshow, the line under the slide preview ("The selected photo as a slide…") now shows from the first
frame instead of only once the preview has finished rendering. Before, it appeared with the render, pushing the page
below it down by a line, so a click made in that moment could land beside the control you aimed at.
### Relative-date filters and smart albums follow the clock
- A current view or source count using “in the last” rules now refreshes when the session clock moves into a new
minute, even when no catalog edit occurred. This fixes stale photos remaining in the grid and stale counts for