Fixes: https://github.com/longbridge/gpui-component/issues/994 1. When SVG is rotated, incorrect graphics are drawn. For example: the original aspect ratio of the SVG is 1:1, if the bounds used to render the SVG are 400x200 (aspect ratio 2:1), [here](https://github.com/zed-industries/zed/blob/21f985a018f7cca9c0fb7f5b7a87555486ab9db5/crates/gpui/src/svg_renderer.rs#L91) the width is used as the scaling factor, causing the rendered SVG to only have half the height. This PR ensures the complete SVG image is always rendered. 2. The clipping region has no transformation applied, I added a function called `distance_from_clip_rect_transformed` in the shader. 3. Fixed `monochrome_sprite_fragment` in `shader.metal` not applying clipping region. ### Before: https://github.com/user-attachments/assets/8f93ac36-281e-4837-96cd-c308bfbf92d1 ### After: https://github.com/user-attachments/assets/f52b67a6-4cb9-4d6c-b759-bbb91b59c1cf Release Notes: - N/A --------- Co-authored-by: Jason Lee <huacnlee@gmail.com>
122 lines
4.1 KiB
Rust
122 lines
4.1 KiB
Rust
use std::time::Duration;
|
|
|
|
use anyhow::Result;
|
|
use gpui::{
|
|
Animation, AnimationExt as _, App, Application, AssetSource, Bounds, Context, SharedString,
|
|
Transformation, Window, WindowBounds, WindowOptions, bounce, div, ease_in_out, percentage,
|
|
prelude::*, px, size, svg,
|
|
};
|
|
|
|
struct Assets {}
|
|
|
|
impl AssetSource for Assets {
|
|
fn load(&self, path: &str) -> Result<Option<std::borrow::Cow<'static, [u8]>>> {
|
|
std::fs::read(path)
|
|
.map(Into::into)
|
|
.map_err(Into::into)
|
|
.map(Some)
|
|
}
|
|
|
|
fn list(&self, path: &str) -> Result<Vec<SharedString>> {
|
|
Ok(std::fs::read_dir(path)?
|
|
.filter_map(|entry| {
|
|
Some(SharedString::from(
|
|
entry.ok()?.path().to_string_lossy().into_owned(),
|
|
))
|
|
})
|
|
.collect::<Vec<_>>())
|
|
}
|
|
}
|
|
|
|
const ARROW_CIRCLE_SVG: &str = concat!(
|
|
env!("CARGO_MANIFEST_DIR"),
|
|
"/examples/image/arrow_circle.svg"
|
|
);
|
|
|
|
struct AnimationExample {}
|
|
|
|
impl Render for AnimationExample {
|
|
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
|
div()
|
|
.flex()
|
|
.flex_col()
|
|
.size_full()
|
|
.bg(gpui::white())
|
|
.text_color(gpui::black())
|
|
.justify_around()
|
|
.child(
|
|
div()
|
|
.flex()
|
|
.flex_col()
|
|
.size_full()
|
|
.justify_around()
|
|
.child(
|
|
div()
|
|
.id("content")
|
|
.flex()
|
|
.flex_col()
|
|
.h(px(150.))
|
|
.overflow_y_scroll()
|
|
.w_full()
|
|
.flex_1()
|
|
.justify_center()
|
|
.items_center()
|
|
.text_xl()
|
|
.gap_4()
|
|
.child("Hello Animation")
|
|
.child(
|
|
svg()
|
|
.size_20()
|
|
.overflow_hidden()
|
|
.path(ARROW_CIRCLE_SVG)
|
|
.text_color(gpui::black())
|
|
.with_animation(
|
|
"image_circle",
|
|
Animation::new(Duration::from_secs(2))
|
|
.repeat()
|
|
.with_easing(bounce(ease_in_out)),
|
|
|svg, delta| {
|
|
svg.with_transformation(Transformation::rotate(
|
|
percentage(delta),
|
|
))
|
|
},
|
|
),
|
|
),
|
|
)
|
|
.child(
|
|
div()
|
|
.flex()
|
|
.h(px(64.))
|
|
.w_full()
|
|
.p_2()
|
|
.justify_center()
|
|
.items_center()
|
|
.border_t_1()
|
|
.border_color(gpui::black().opacity(0.1))
|
|
.bg(gpui::black().opacity(0.05))
|
|
.child("Other Panel"),
|
|
),
|
|
)
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
Application::new()
|
|
.with_assets(Assets {})
|
|
.run(|cx: &mut App| {
|
|
let options = WindowOptions {
|
|
window_bounds: Some(WindowBounds::Windowed(Bounds::centered(
|
|
None,
|
|
size(px(300.), px(300.)),
|
|
cx,
|
|
))),
|
|
..Default::default()
|
|
};
|
|
cx.open_window(options, |_, cx| {
|
|
cx.activate(false);
|
|
cx.new(|_| AnimationExample {})
|
|
})
|
|
.unwrap();
|
|
});
|
|
}
|