Grid: selected photos whose thumbnail isn't drawn yet still show as selected (#298)
The grid and filmstrip now both ask Selection::state_of. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5b80fc6bcf
commit
6c19090fde
|
|
@ -471,7 +471,8 @@ fn cell(app: &mut LightcraftApp, ui: &mut egui::Ui, id: PhotoId, r: Rect, square
|
|||
let Some(photo) = app.session.catalog.photo(id).cloned() else { return };
|
||||
let resp = ui.interact(r, egui::Id::new(("cell", id.0)), Sense::click_and_drag());
|
||||
register(ui.ctx(), format!("thumb:{}", id.0), r);
|
||||
let selected = app.session.selection.contains(id);
|
||||
let state = app.session.selection.state_of(id);
|
||||
let selected = state != lightcraft_engine::SelectionState::NotSelected;
|
||||
// screen readers: the file, then rating / flag / label
|
||||
let mut spoken = photo.file_name.clone();
|
||||
if photo.rating > 0 {
|
||||
|
|
@ -486,7 +487,7 @@ fn cell(app: &mut LightcraftApp, ui: &mut egui::Ui, id: PhotoId, r: Rect, square
|
|||
spoken.push_str(&format!(", {} label", app.session.catalog.label_name(l)));
|
||||
}
|
||||
resp.widget_info(|| egui::WidgetInfo::selected(egui::WidgetType::SelectableLabel, true, selected, &spoken));
|
||||
let active = app.session.selection.active == Some(id);
|
||||
let active = state == lightcraft_engine::SelectionState::Active;
|
||||
let p = ui.painter();
|
||||
let img_rect = if square {
|
||||
p.rect_filled(r, 0.0, if selected { t.cell_selected } else { t.cell });
|
||||
|
|
@ -514,6 +515,12 @@ fn cell(app: &mut LightcraftApp, ui: &mut egui::Ui, id: PhotoId, r: Rect, square
|
|||
} else {
|
||||
let ph = img_rect.shrink(if square { 20.0 } else { 0.0 });
|
||||
p.rect_filled(ph, 0.0, Color32::from_gray(38));
|
||||
// not drawn yet (or unreadable): the selection is still visible
|
||||
if active {
|
||||
p.rect_stroke(ph, 0.0, Stroke::new(2.0, Color32::WHITE), StrokeKind::Outside);
|
||||
} else if selected {
|
||||
p.rect_stroke(ph, 0.0, Stroke::new(2.0, Color32::from_gray(170)), StrokeKind::Outside);
|
||||
}
|
||||
if app.renderer.failure(Slot::Thumb(id)).is_some() {
|
||||
// unreadable / missing file
|
||||
p.text(ph.center(), Align2::CENTER_CENTER, "!", t.semibold(18.0), t.text_dim);
|
||||
|
|
|
|||
|
|
@ -131,3 +131,27 @@ fn grid_headers_selection_scrolling_stacks_and_shape_changes() {
|
|||
assert!(after.height() > after.width(), "{after:?}");
|
||||
assert_cheap_frames(&mut h);
|
||||
}
|
||||
|
||||
/// Selected photos whose thumbnails have not loaded (or can't) are still marked selected in the
|
||||
/// justified grid (issue #298): the active one white, the others grey.
|
||||
#[test]
|
||||
fn unloaded_thumbnails_show_their_selection() {
|
||||
let mut h = grid(ViewMode::PhotoGrid);
|
||||
h.request("engine.execute", json!({"command": "library.selectAll"}), T);
|
||||
let img = h.snapshot(SETTLE);
|
||||
assert_eq!(h.view.ctx.pixels_per_point(), 1.0);
|
||||
let active = h.app.session.selection.active.expect("active");
|
||||
let canvas = h.app.canvas_rect.expect("grid drawn");
|
||||
let mut checked = 0;
|
||||
for (w, r) in h.app.widgets.iter().filter(|(w, _)| w.starts_with("thumb:")) {
|
||||
if !canvas.shrink(4.0).contains_rect(*r) || r.min.x < 6.0 {
|
||||
continue;
|
||||
}
|
||||
let id = w.trim_start_matches("thumb:").parse::<u64>().unwrap();
|
||||
let want = if id == active.0 { egui::Color32::WHITE } else { egui::Color32::from_gray(170) };
|
||||
let px = img[((r.min.x - 1.0) as usize, r.center().y as usize)];
|
||||
assert_eq!(px, want, "photo {id}");
|
||||
checked += 1;
|
||||
}
|
||||
assert!(checked >= 3, "checked {checked}");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue