diff options
-rw-r--r-- | examples/svg_style/src/main.rs | 8 | ||||
-rw-r--r-- | glow/src/image.rs | 7 | ||||
-rw-r--r-- | graphics/src/image/vector.rs | 22 | ||||
-rw-r--r-- | graphics/src/layer.rs | 7 | ||||
-rw-r--r-- | graphics/src/layer/image.rs | 6 | ||||
-rw-r--r-- | graphics/src/primitive.rs | 3 | ||||
-rw-r--r-- | graphics/src/renderer.rs | 15 | ||||
-rw-r--r-- | native/src/svg.rs | 20 | ||||
-rw-r--r-- | native/src/widget/helpers.rs | 2 | ||||
-rw-r--r-- | native/src/widget/svg.rs | 15 | ||||
-rw-r--r-- | src/widget.rs | 2 | ||||
-rw-r--r-- | style/src/svg.rs | 12 | ||||
-rw-r--r-- | style/src/theme.rs | 61 | ||||
-rw-r--r-- | wgpu/src/image.rs | 7 |
14 files changed, 112 insertions, 75 deletions
diff --git a/examples/svg_style/src/main.rs b/examples/svg_style/src/main.rs index 905e1d86..0a1fa039 100644 --- a/examples/svg_style/src/main.rs +++ b/examples/svg_style/src/main.rs @@ -39,8 +39,8 @@ impl Sandbox for SvgStyleExample { "{}/resources/go-next-symbolic.svg", env!("CARGO_MANIFEST_DIR") ))) - .style(theme::Svg::Custom(|_theme| Appearance { - fill: Some(Color { + .style(theme::Svg::custom_fn(|_theme| Appearance { + color: Some(Color { r: 0.0, g: 0.28627452, b: 0.42745098, @@ -55,8 +55,8 @@ impl Sandbox for SvgStyleExample { "{}/resources/go-next-symbolic.svg", env!("CARGO_MANIFEST_DIR") ))) - .style(theme::Svg::Custom(|_theme| Appearance { - fill: Some(Color { + .style(theme::Svg::custom_fn(|_theme| Appearance { + color: Some(Color { r: 0.5803922, g: 0.92156863, b: 0.92156863, diff --git a/glow/src/image.rs b/glow/src/image.rs index 955fd1ab..c32b2162 100644 --- a/glow/src/image.rs +++ b/glow/src/image.rs @@ -172,11 +172,16 @@ impl Pipeline { layer::Image::Raster { handle: _, bounds } => (None, bounds), #[cfg(feature = "svg")] - layer::Image::Vector { handle, bounds } => { + layer::Image::Vector { + handle, + color, + bounds, + } => { let size = [bounds.width, bounds.height]; ( vector_cache.upload( handle, + *color, size, _scale_factor, &mut gl, diff --git a/graphics/src/image/vector.rs b/graphics/src/image/vector.rs index 5be5d3c7..0af5be01 100644 --- a/graphics/src/image/vector.rs +++ b/graphics/src/image/vector.rs @@ -1,5 +1,6 @@ //! Vector image loading and caching use crate::image::Storage; +use crate::Color; use iced_native::svg; use iced_native::Size; @@ -78,6 +79,7 @@ impl<T: Storage> Cache<T> { pub fn upload( &mut self, handle: &svg::Handle, + color: Option<Color>, [width, height]: [f32; 2], scale: f32, state: &mut T::State<'_>, @@ -90,18 +92,18 @@ impl<T: Storage> Cache<T> { (scale * height).ceil() as u32, ); - let appearance = handle.appearance(); - let fill = appearance.fill.map(crate::Color::into_rgba8); + let color = color.map(Color::into_rgba8); + let key = (id, width, height, color); // TODO: Optimize! // We currently rerasterize the SVG when its size changes. This is slow // as heck. A GPU rasterizer like `pathfinder` may perform better. // It would be cool to be able to smooth resize the `svg` example. - if self.rasterized.contains_key(&(id, width, height, fill)) { + if self.rasterized.contains_key(&key) { let _ = self.svg_hits.insert(id); - let _ = self.rasterized_hits.insert((id, width, height, fill)); + let _ = self.rasterized_hits.insert(key); - return self.rasterized.get(&(id, width, height, fill)); + return self.rasterized.get(&key); } match self.load(handle) { @@ -128,7 +130,7 @@ impl<T: Storage> Cache<T> { let mut rgba = img.take(); - if let Some(color) = fill { + if let Some(color) = color { rgba.chunks_exact_mut(4).for_each(|rgba| { if rgba[3] > 0 { rgba[0] = color[0]; @@ -142,12 +144,10 @@ impl<T: Storage> Cache<T> { log::debug!("allocating {} {}x{}", id, width, height); let _ = self.svg_hits.insert(id); - let _ = self.rasterized_hits.insert((id, width, height, fill)); - let _ = self - .rasterized - .insert((id, width, height, fill), allocation); + let _ = self.rasterized_hits.insert(key); + let _ = self.rasterized.insert(key, allocation); - self.rasterized.get(&(id, width, height, fill)) + self.rasterized.get(&key) } Svg::NotFound => None, } diff --git a/graphics/src/layer.rs b/graphics/src/layer.rs index fd670f48..1d453caa 100644 --- a/graphics/src/layer.rs +++ b/graphics/src/layer.rs @@ -251,11 +251,16 @@ impl<'a> Layer<'a> { bounds: *bounds + translation, }); } - Primitive::Svg { handle, bounds } => { + Primitive::Svg { + handle, + color, + bounds, + } => { let layer = &mut layers[current_layer]; layer.images.push(Image::Vector { handle: handle.clone(), + color: *color, bounds: *bounds + translation, }); } diff --git a/graphics/src/layer/image.rs b/graphics/src/layer/image.rs index 045ec665..3eff2397 100644 --- a/graphics/src/layer/image.rs +++ b/graphics/src/layer/image.rs @@ -1,4 +1,5 @@ -use crate::Rectangle; +use crate::{Color, Rectangle}; + use iced_native::{image, svg}; /// A raster or vector image. @@ -17,6 +18,9 @@ pub enum Image { /// The handle of a vector image. handle: svg::Handle, + /// The [`Color`] filter + color: Option<Color>, + /// The bounds of the image. bounds: Rectangle, }, diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index 6f1b6f26..5a163a2f 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -60,6 +60,9 @@ pub enum Primitive { /// The path of the SVG file handle: svg::Handle, + /// The [`Color`] filter + color: Option<Color>, + /// The bounds of the viewport bounds: Rectangle, }, diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs index 65350037..aabdf7fc 100644 --- a/graphics/src/renderer.rs +++ b/graphics/src/renderer.rs @@ -6,7 +6,7 @@ use iced_native::layout; use iced_native::renderer; use iced_native::svg; use iced_native::text::{self, Text}; -use iced_native::{Background, Element, Font, Point, Rectangle, Size}; +use iced_native::{Background, Color, Element, Font, Point, Rectangle, Size}; pub use iced_native::renderer::Style; @@ -200,7 +200,16 @@ where self.backend().viewport_dimensions(handle) } - fn draw(&mut self, handle: svg::Handle, bounds: Rectangle) { - self.draw_primitive(Primitive::Svg { handle, bounds }) + fn draw( + &mut self, + handle: svg::Handle, + color: Option<Color>, + bounds: Rectangle, + ) { + self.draw_primitive(Primitive::Svg { + handle, + color, + bounds, + }) } } diff --git a/native/src/svg.rs b/native/src/svg.rs index 08b0984a..2168e409 100644 --- a/native/src/svg.rs +++ b/native/src/svg.rs @@ -1,19 +1,16 @@ //! Load and draw vector graphics. -use crate::{Hasher, Rectangle, Size}; +use crate::{Color, Hasher, Rectangle, Size}; use std::borrow::Cow; use std::hash::{Hash, Hasher as _}; use std::path::PathBuf; use std::sync::Arc; -pub use iced_style::svg::{Appearance, StyleSheet}; - /// A handle of Svg data. #[derive(Debug, Clone)] pub struct Handle { id: u64, data: Arc<Data>, - appearance: Appearance, } impl Handle { @@ -39,7 +36,6 @@ impl Handle { Handle { id: hasher.finish(), data: Arc::new(data), - appearance: Appearance::default(), } } @@ -52,16 +48,6 @@ impl Handle { pub fn data(&self) -> &Data { &self.data } - - /// Returns the styling [`Appearance`] for the SVG. - pub fn appearance(&self) -> Appearance { - self.appearance - } - - /// Set the [`Appearance`] for the SVG. - pub fn set_appearance(&mut self, appearance: Appearance) { - self.appearance = appearance; - } } impl Hash for Handle { @@ -98,6 +84,6 @@ pub trait Renderer: crate::Renderer { /// Returns the default dimensions of an SVG for the given [`Handle`]. fn dimensions(&self, handle: &Handle) -> Size<u32>; - /// Draws an SVG with the given [`Handle`] and inside the provided `bounds`. - fn draw(&mut self, handle: Handle, bounds: Rectangle); + /// Draws an SVG with the given [`Handle`], an optional [`Color`] filter, and inside the provided `bounds`. + fn draw(&mut self, handle: Handle, color: Option<Color>, bounds: Rectangle); } diff --git a/native/src/widget/helpers.rs b/native/src/widget/helpers.rs index e802f629..0bde288f 100644 --- a/native/src/widget/helpers.rs +++ b/native/src/widget/helpers.rs @@ -290,7 +290,7 @@ pub fn svg<Renderer>( ) -> widget::Svg<Renderer> where Renderer: crate::svg::Renderer, - Renderer::Theme: crate::svg::StyleSheet, + Renderer::Theme: widget::svg::StyleSheet, { widget::Svg::new(handle) } diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs index c7eb4f6d..f83f5acf 100644 --- a/native/src/widget/svg.rs +++ b/native/src/widget/svg.rs @@ -9,7 +9,8 @@ use crate::{ use std::path::PathBuf; -pub use svg::{Handle, StyleSheet}; +pub use iced_style::svg::{Appearance, StyleSheet}; +pub use svg::Handle; /// A vector graphics image. /// @@ -17,7 +18,6 @@ pub use svg::{Handle, StyleSheet}; /// /// [`Svg`] images can have a considerable rendering cost when resized, /// specially when they are complex. -#[derive(Clone)] #[allow(missing_debug_implementations)] pub struct Svg<Renderer> where @@ -146,9 +146,6 @@ where _cursor_position: Point, _viewport: &Rectangle, ) { - let mut handle = self.handle.clone(); - handle.set_appearance(theme.appearance(self.style)); - let Size { width, height } = renderer.dimensions(&self.handle); let image_size = Size::new(width as f32, height as f32); @@ -167,7 +164,13 @@ where ..bounds }; - renderer.draw(handle, drawing_bounds + offset); + let appearance = theme.appearance(&self.style); + + renderer.draw( + self.handle.clone(), + appearance.color, + drawing_bounds + offset, + ); }; if adjusted_fit.width > bounds.width diff --git a/src/widget.rs b/src/widget.rs index 7c67a599..e7df6e4e 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -194,7 +194,7 @@ pub use iced_graphics::widget::qr_code; pub mod svg { //! Display vector graphics in your application. pub use iced_native::svg::Handle; - pub use iced_native::widget::Svg; + pub use iced_native::widget::svg::{Appearance, StyleSheet, Svg}; } #[cfg(feature = "canvas")] diff --git a/style/src/svg.rs b/style/src/svg.rs index 66791d04..9378c1a7 100644 --- a/style/src/svg.rs +++ b/style/src/svg.rs @@ -2,20 +2,22 @@ use iced_core::Color; -/// The appearance of a svg. +/// The appearance of an SVG. #[derive(Debug, Default, Clone, Copy)] pub struct Appearance { - /// Changes the fill color + /// The [`Color`] filter of an SVG. /// /// Useful for coloring a symbolic icon. - pub fill: Option<Color>, + /// + /// `None` keeps the original color. + pub color: Option<Color>, } /// The stylesheet of a svg. pub trait StyleSheet { /// The supported style of the [`StyleSheet`]. - type Style: Default + Copy; + type Style: Default; /// Produces the [`Appearance`] of the svg. - fn appearance(&self, style: Self::Style) -> Appearance; + fn appearance(&self, style: &Self::Style) -> Appearance; } diff --git a/style/src/theme.rs b/style/src/theme.rs index d825b086..d2b583ed 100644 --- a/style/src/theme.rs +++ b/style/src/theme.rs @@ -798,29 +798,6 @@ impl From<fn(&Theme) -> rule::Appearance> for Rule { } } -/** - * SVG - */ -#[derive(Default, Clone, Copy)] -pub enum Svg { - /// No filtering to the rendered SVG. - #[default] - Default, - /// Apply custom filtering to the SVG. - Custom(fn(&Theme) -> svg::Appearance), -} - -impl svg::StyleSheet for Theme { - type Style = Svg; - - fn appearance(&self, style: Self::Style) -> svg::Appearance { - match style { - Svg::Default => Default::default(), - Svg::Custom(appearance) => appearance(self), - } - } -} - impl rule::StyleSheet for Theme { type Style = Rule; @@ -847,6 +824,44 @@ impl rule::StyleSheet for fn(&Theme) -> rule::Appearance { } } +/** + * SVG + */ +#[derive(Default)] +pub enum Svg { + /// No filtering to the rendered SVG. + #[default] + Default, + /// A custom style. + Custom(Box<dyn svg::StyleSheet<Style = Theme>>), +} + +impl Svg { + /// Creates a custom [`Svg`] style. + pub fn custom_fn(f: fn(&Theme) -> svg::Appearance) -> Self { + Self::Custom(Box::new(f)) + } +} + +impl svg::StyleSheet for Theme { + type Style = Svg; + + fn appearance(&self, style: &Self::Style) -> svg::Appearance { + match style { + Svg::Default => Default::default(), + Svg::Custom(custom) => custom.appearance(self), + } + } +} + +impl svg::StyleSheet for fn(&Theme) -> svg::Appearance { + type Style = Theme; + + fn appearance(&self, style: &Self::Style) -> svg::Appearance { + (self)(style) + } +} + /// The style of a scrollable. #[derive(Default)] pub enum Scrollable { diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index d06815bb..390bad90 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -318,11 +318,16 @@ impl Pipeline { layer::Image::Raster { .. } => {} #[cfg(feature = "svg")] - layer::Image::Vector { handle, bounds } => { + layer::Image::Vector { + handle, + color, + bounds, + } => { let size = [bounds.width, bounds.height]; if let Some(atlas_entry) = vector_cache.upload( handle, + *color, size, _scale, &mut (device, encoder), |