mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-26 02:59:17 -06:00
LR-BEHAV-BG-TASKS: name the failed filmstrip thumbnail, firmer light placeholders, paper print cells
A failed thumbnail in the detail view's filmstrip is announced with the file name and "This photo can't be opened" (the painted ! had no name). The skeleton placeholder is set further off the surfaces in Silver and Paper (1.3 / 1.2 : 1 on the grid before, about 1.7 / 1.6 after) and the test floor for the light themes is 1.15. The print preview's empty and loading cells go back to fixed greys: its page is paper in every theme. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
3de9654e39
commit
316f82dbd2
@@ -2836,7 +2836,8 @@ pub(crate) fn filmstrip(app: &mut LightcraftApp, ui: &mut egui::Ui, r: Rect) {
|
||||
continue;
|
||||
}
|
||||
let resp = ui.interact(cr, egui::Id::new(("film", id.0)), Sense::click());
|
||||
crate::widgets::announce(&resp, app.session.catalog.photo(*id).map(|p| p.file_name.clone()).unwrap_or_default());
|
||||
let failed = app.renderer.thumb(*id).is_none() && app.renderer.failure(Slot::Thumb(*id)).is_some();
|
||||
crate::widgets::announce(&resp, film_spoken(app.session.catalog.photo(*id).map_or("", |p| p.file_name.as_str()), failed));
|
||||
register(ui.ctx(), format!("film:{}", id.0), cr);
|
||||
let state = app.session.selection.state_of(*id);
|
||||
let sel = state == lightcraft_engine::SelectionState::Active;
|
||||
@@ -2862,8 +2863,8 @@ pub(crate) fn filmstrip(app: &mut LightcraftApp, ui: &mut egui::Ui, r: Rect) {
|
||||
let thumb = app.renderer.thumb(*id);
|
||||
if thumb.is_none() {
|
||||
p.rect_filled(img_area, 0.0, t.skeleton);
|
||||
if app.renderer.failure(Slot::Thumb(*id)).is_some() {
|
||||
p.text(img_area.center(), Align2::CENTER_CENTER, "!", t.semibold(14.0), t.text_dim);
|
||||
if failed {
|
||||
p.text(img_area.center(), Align2::CENTER_CENTER, "!", t.semibold(14.0), t.text);
|
||||
}
|
||||
}
|
||||
if let Some(tex) = thumb {
|
||||
@@ -2934,6 +2935,12 @@ pub(crate) fn filmstrip(app: &mut LightcraftApp, ui: &mut egui::Ui, r: Rect) {
|
||||
});
|
||||
}
|
||||
|
||||
/// What a screen reader says for a filmstrip thumbnail: the file, and why there is no picture
|
||||
/// when the thumbnail failed (the painted `!` has no name of its own).
|
||||
pub(crate) fn film_spoken(file_name: &str, failed: bool) -> String {
|
||||
if failed { format!("{file_name}, {}", crate::i18n::tr("This photo can't be opened")) } else { file_name.to_string() }
|
||||
}
|
||||
|
||||
/// Rating, flag and edited badges along a filmstrip thumbnail's bottom edge (Settings → Interface).
|
||||
fn film_badges(p: &egui::Painter, t: &Tokens, fr: Rect, ph: &lightcraft_catalog::Photo) {
|
||||
use crate::icons::{Icon, paint};
|
||||
|
||||
@@ -805,11 +805,13 @@ fn cell(app: &mut LightcraftApp, ui: &mut egui::Ui, id: PhotoId, r: Rect, square
|
||||
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);
|
||||
// a light theme's skeleton is itself mid-grey: the ring takes the dim text colour
|
||||
let ring = if t.skeleton.r() > 0x80 { t.text_dim } else { Color32::from_gray(170) };
|
||||
p.rect_stroke(ph, 0.0, Stroke::new(2.0, ring), 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);
|
||||
p.text(ph.center(), Align2::CENTER_CENTER, "!", t.semibold(18.0), t.text);
|
||||
}
|
||||
}
|
||||
// labels and badges
|
||||
|
||||
@@ -856,8 +856,9 @@ fn paint_cell(
|
||||
clip.add(egui::Shape::mesh(mesh));
|
||||
}
|
||||
None => {
|
||||
let t = Tokens::get(painter.ctx());
|
||||
clip.rect_filled(shown, 0.0, if photo.is_some() { t.skeleton } else { t.track });
|
||||
// the page is paper in every theme (its colour is the print's, not the theme's), so
|
||||
// these stay fixed greys: a photo still to come, and an empty cell
|
||||
clip.rect_filled(shown, 0.0, if photo.is_some() { Color32::from_gray(52) } else { Color32::from_gray(200) });
|
||||
}
|
||||
}
|
||||
if im.stroke_enabled && im.stroke_width_pt > 0.0 {
|
||||
|
||||
@@ -175,7 +175,25 @@ fn the_thumbnail_placeholder_stands_apart_in_every_theme() {
|
||||
let t = Tokens::for_kind(kind);
|
||||
for (name, behind) in [("grid", t.grid_bg), ("cell", t.cell), ("selected cell", t.cell_selected), ("canvas", t.canvas)] {
|
||||
let c = contrast(t.skeleton, behind);
|
||||
assert!(c >= 1.1, "{kind:?}: the placeholder on the {name} is {c:.2}:1");
|
||||
// the light themes' surfaces are close together, so the placeholder has to be set
|
||||
// further off them to read at all
|
||||
let floor = if matches!(kind, ThemeKind::Silver | ThemeKind::Paper) { 1.15 } else { 1.1 };
|
||||
assert!(c >= floor, "{kind:?}: the placeholder on the {name} is {c:.2}:1");
|
||||
}
|
||||
let mark = contrast(t.text, t.skeleton);
|
||||
assert!(mark >= 3.0, "{kind:?}: the failure mark on the placeholder is {mark:.2}:1");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_failed_filmstrip_thumbnail_is_announced_with_its_reason() {
|
||||
let spoken = |failed: bool| {
|
||||
let (nodes, _, _) = frames(Vec::new(), |ui| {
|
||||
let resp = ui.interact(Rect::from_min_size(pos2(10.0, 10.0), vec2(120.0, 80.0)), egui::Id::new("film-test"), egui::Sense::click());
|
||||
crate::widgets::announce(&resp, crate::panels::detail::film_spoken("IMG_0001.jpg", failed));
|
||||
});
|
||||
nodes.into_iter().find(|n| n.role == "Button").map(|n| n.label)
|
||||
};
|
||||
assert_eq!(spoken(false).as_deref(), Some("IMG_0001.jpg"));
|
||||
assert_eq!(spoken(true).as_deref(), Some("IMG_0001.jpg, This photo can't be opened"));
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ impl Tokens {
|
||||
grid_bg: rgb(0xd9d9d9),
|
||||
cell: rgb(0xcbcbcb),
|
||||
cell_selected: rgb(0xb4b4b4),
|
||||
skeleton: rgb(0xbfbfbf),
|
||||
skeleton: rgb(0xa6a6a6),
|
||||
divider: rgb(0xc4c4c4),
|
||||
inset: rgb(0xdcdcdc),
|
||||
field: rgb(0xf6f6f6),
|
||||
@@ -225,7 +225,7 @@ impl Tokens {
|
||||
grid_bg: rgb(0xf2f2f2),
|
||||
cell: rgb(0xe8e8e8),
|
||||
cell_selected: rgb(0xd2d2d2),
|
||||
skeleton: rgb(0xdddddd),
|
||||
skeleton: rgb(0xbcbcbc),
|
||||
divider: rgb(0xe0e0e0),
|
||||
inset: rgb(0xf0f0f0),
|
||||
field: rgb(0xffffff),
|
||||
|
||||
Reference in New Issue
Block a user