Media: the viewer's picture moves; a viewer with no picture takes no Tab
The stage's picture carries an id, so gpui keeps its frame and asks for the next: an animated picture plays, turned or not. A viewer whose picture has not loaded or cannot open is no Tab stop. AGENTS.md: img() moves an animated picture's frames only with an id. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f8a51a5352
commit
12f0baab15
4 files changed
+15
-4
No files matched your search
@@ -109,7 +109,7 @@ Ely GPUI Component. A component library for GPUI, in light and dark.
|
|||||||
- Set an explicit line height on any box that clips text. gpui's default leading is taller than a tight box, and the clip eats descenders.
|
- Set an explicit line height on any box that clips text. gpui's default leading is taller than a tight box, and the clip eats descenders.
|
||||||
- gpui's `img` takes its picture's pixel size for any `Auto` side, and its aspect ratio beats percent heights in flow. `Image` pins it absolute at full size, so an `Image` needs a sized box.
|
- gpui's `img` takes its picture's pixel size for any `Auto` side, and its aspect ratio beats percent heights in flow. `Image` pins it absolute at full size, so an `Image` needs a sized box.
|
||||||
- Badges, tags and avatars live in `data_display`; forms and shell draw theirs from there, and `data_display` imports neither. Avatars take square pictures.
|
- Badges, tags and avatars live in `data_display`; forms and shell draw theirs from there, and `data_display` imports neither. Avatars take square pictures.
|
||||||
- `img()` keeps loading state only with an id. Content masks are rectangles, so rounded corners survive only when the image fills its box without cropping.
|
- `img()` keeps loading state, and moves an animated picture's frames, only with an id. Content masks are rectangles, so rounded corners survive only when the image fills its box without cropping.
|
||||||
- gpui reads a `&str` picture source as a web address. A file goes through `Path` (`documents::source` in the crate, `Path::new` in the gallery).
|
- gpui reads a `&str` picture source as a web address. A file goes through `Path` (`documents::source` in the crate, `Path::new` in the gallery).
|
||||||
- Taffy 0.9's grid rows overgrow tiles that keep a ratio. Tiles in a picture's shape sit in flex rows of `flex_1` cells (`generative::GenerationGrid`).
|
- Taffy 0.9's grid rows overgrow tiles that keep a ratio. Tiles in a picture's shape sit in flex rows of `flex_1` cells (`generative::GenerationGrid`).
|
||||||
- Rise reads green and fall red unless a component's `red_up` swaps them, as markets in East Asia read. `finance::quotes::moves` picks the pair.
|
- Rise reads green and fall red unless a component's `red_up` swaps them, as markets in East Asia read. `finance::quotes::moves` picks the pair.
|
||||||
|
|||||||
@@ -307,3 +307,4 @@ Per-component lines live in `tasks/`. Tags there:
|
|||||||
| T25e | 2 | PASS | |
|
| T25e | 2 | PASS | |
|
||||||
| T25f | 1 | FAIL | a drag on the turned embedding froze past the plot's edge; which version a diff sets against, and its heading, had no test |
|
| T25f | 1 | FAIL | a drag on the turned embedding froze past the plot's edge; which version a diff sets against, and its heading, had no test |
|
||||||
| T25f | 2 | PASS | |
|
| T25f | 2 | PASS | |
|
||||||
|
| T26a | 1 | FAIL | the viewer's picture had no id, so an animated picture never left its first frame |
|
||||||
@@ -282,6 +282,9 @@ fn a_picture_that_cannot_open_says_so(cx: &mut TestAppContext) {
|
|||||||
let cx = viewing(std::env::temp_dir().join("ely-media-missing.png"), cx);
|
let cx = viewing(std::env::temp_dir().join("ely-media-missing.png"), cx);
|
||||||
assert!(cx.debug_bounds("image-viewer-failed").is_some());
|
assert!(cx.debug_bounds("image-viewer-failed").is_some());
|
||||||
assert!(cx.debug_bounds("image-viewer-picture").is_none());
|
assert!(cx.debug_bounds("image-viewer-picture").is_none());
|
||||||
|
cx.update(|window, _| window.focus_next());
|
||||||
|
let focused = cx.update(|window, cx| window.focused(cx));
|
||||||
|
assert!(focused.is_none(), "with nothing to show, nothing takes Tab");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Two thumbnails, the second with no handler; the opens the first heard.
|
/// Two thumbnails, the second with no handler; the opens the first heard.
|
||||||
|
|||||||
+10
-3
@@ -119,7 +119,6 @@ impl RenderOnce for ImageViewer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let focus = tab_stop((self.id.clone(), "focus").into(), true, window, cx);
|
|
||||||
let decoded = window.use_asset::<ImageAssetLoader>(&self.source, cx);
|
let decoded = window.use_asset::<ImageAssetLoader>(&self.source, cx);
|
||||||
let turns = view.read(cx).turns;
|
let turns = view.read(cx).turns;
|
||||||
let picture: Option<Arc<RenderImage>> = match decoded {
|
let picture: Option<Arc<RenderImage>> = match decoded {
|
||||||
@@ -143,6 +142,12 @@ impl RenderOnce for ImageViewer {
|
|||||||
let size = image.size(0);
|
let size = image.size(0);
|
||||||
(size.width.0 as f32, size.height.0 as f32)
|
(size.width.0 as f32, size.height.0 as f32)
|
||||||
});
|
});
|
||||||
|
let focus = tab_stop(
|
||||||
|
(self.id.clone(), "focus").into(),
|
||||||
|
pixels.is_some(),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
let theme = cx.theme();
|
let theme = cx.theme();
|
||||||
let colors = theme.colors.clone();
|
let colors = theme.colors.clone();
|
||||||
let (zoom, offset, stage) = {
|
let (zoom, offset, stage) = {
|
||||||
@@ -252,6 +257,7 @@ impl RenderOnce for ImageViewer {
|
|||||||
});
|
});
|
||||||
let body = match (picture, shown) {
|
let body = match (picture, shown) {
|
||||||
(Some(image), Some((size, left, top))) => img(ImageSource::Render(image))
|
(Some(image), Some((size, left, top))) => img(ImageSource::Render(image))
|
||||||
|
.id((self.id.clone(), "picture"))
|
||||||
.debug_selector(|| "image-viewer-picture".into())
|
.debug_selector(|| "image-viewer-picture".into())
|
||||||
.absolute()
|
.absolute()
|
||||||
.left(Pixels::from(left))
|
.left(Pixels::from(left))
|
||||||
@@ -305,8 +311,9 @@ impl RenderOnce for ImageViewer {
|
|||||||
.bg(colors.sunken)
|
.bg(colors.sunken)
|
||||||
.border_1()
|
.border_1()
|
||||||
.border_color(transparent_black())
|
.border_color(transparent_black())
|
||||||
.track_focus(&focus)
|
.when(pixels.is_some(), |stage| {
|
||||||
.focus_ring(cx)
|
stage.track_focus(&focus).focus_ring(cx)
|
||||||
|
})
|
||||||
.when(overhangs, |stage| stage.cursor_grab())
|
.when(overhangs, |stage| stage.cursor_grab())
|
||||||
.child(
|
.child(
|
||||||
canvas(
|
canvas(
|
||||||
|
|||||||
Reference in new issue
Block a user