From a88aae5e04e0a92457e5dd617a86af823e90af6c Mon Sep 17 00:00:00 2001 From: Malte Veerman Date: Fri, 6 Dec 2019 19:37:56 +0100 Subject: Added an `Icon` widget to native. --- native/src/widget.rs | 3 ++ native/src/widget/icon.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 native/src/widget/icon.rs (limited to 'native') diff --git a/native/src/widget.rs b/native/src/widget.rs index 71dcdc0d..0cf6a639 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -24,6 +24,7 @@ pub mod button; pub mod checkbox; pub mod column; pub mod container; +pub mod icon; pub mod image; pub mod radio; pub mod row; @@ -41,6 +42,8 @@ pub use column::Column; #[doc(no_inline)] pub use container::Container; #[doc(no_inline)] +pub use icon::Icon; +#[doc(no_inline)] pub use image::Image; #[doc(no_inline)] pub use radio::Radio; diff --git a/native/src/widget/icon.rs b/native/src/widget/icon.rs new file mode 100644 index 00000000..4687d7e6 --- /dev/null +++ b/native/src/widget/icon.rs @@ -0,0 +1,103 @@ +//! Display an icon. +use crate::{layout, Element, Hasher, Layout, Length, Point, Rectangle, Widget}; + +use std::hash::Hash; +use std::path::{Path, PathBuf}; + +/// A simple icon_loader widget. +#[derive(Debug, Clone)] +pub struct Icon { + path: PathBuf, + size: Length, +} + +impl Icon { + /// Create a new [`Icon`] from the file at `path`. + /// + /// [`Icon`]: struct.Icon.html + pub fn new(path: impl Into) -> Self { + Icon { + path: path.into(), + size: Length::Fill, + } + } + + /// Sets the size of the [`Icon`]. + /// + /// [`Icon`]: struct.Icon.html + pub fn size(mut self, size: Length) -> Self { + self.size = size; + self + } +} + +impl Widget for Icon +where + Renderer: self::Renderer, +{ + fn width(&self) -> Length { + self.size + } + + fn height(&self) -> Length { + self.size + } + + fn layout(&self, _: &Renderer, limits: &layout::Limits) -> layout::Node { + let mut size = limits.width(self.size).height(self.size).max(); + + if size.width > size.height { + size.width = size.height; + } else if size.width < size.height { + size.height = size.width; + } + + layout::Node::new(size) + } + + fn draw( + &self, + renderer: &mut Renderer, + layout: Layout<'_>, + _cursor_position: Point, + ) -> Renderer::Output { + let bounds = layout.bounds(); + + renderer.draw( + bounds, + self.path.as_path(), + ) + } + + fn hash_layout(&self, state: &mut Hasher) { + self.size.hash(state); + } +} + +/// The renderer of an [`Icon`]. +/// +/// Your [renderer] will need to implement this trait before being +/// able to use [`Icon`] in your [`UserInterface`]. +/// +/// [`Icon`]: struct.Icon.html +/// [renderer]: ../../renderer/index.html +/// [`UserInterface`]: ../../struct.UserInterface.html +pub trait Renderer: crate::Renderer { + /// Draws an [`Icon`]. + /// + /// [`Icon`]: struct.Icon.html + fn draw( + &mut self, + bounds: Rectangle, + path: &Path, + ) -> Self::Output; +} + +impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> +where + Renderer: self::Renderer, +{ + fn from(icon: Icon) -> Element<'a, Message, Renderer> { + Element::new(icon) + } +} -- cgit From 5696afcadd5b3b89a532f4205efac30d8a24d558 Mon Sep 17 00:00:00 2001 From: Malte Veerman Date: Wed, 11 Dec 2019 22:13:29 +0100 Subject: Ran cargo_fmt over changed files. --- native/src/widget/icon.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'native') diff --git a/native/src/widget/icon.rs b/native/src/widget/icon.rs index 4687d7e6..b3906ccf 100644 --- a/native/src/widget/icon.rs +++ b/native/src/widget/icon.rs @@ -1,8 +1,12 @@ //! Display an icon. -use crate::{layout, Element, Hasher, Layout, Length, Point, Rectangle, Widget}; +use crate::{ + layout, Element, Hasher, Layout, Length, Point, Rectangle, Widget, +}; -use std::hash::Hash; -use std::path::{Path, PathBuf}; +use std::{ + hash::Hash, + path::{Path, PathBuf}, +}; /// A simple icon_loader widget. #[derive(Debug, Clone)] @@ -63,10 +67,7 @@ where ) -> Renderer::Output { let bounds = layout.bounds(); - renderer.draw( - bounds, - self.path.as_path(), - ) + renderer.draw(bounds, self.path.as_path()) } fn hash_layout(&self, state: &mut Hasher) { @@ -86,11 +87,7 @@ pub trait Renderer: crate::Renderer { /// Draws an [`Icon`]. /// /// [`Icon`]: struct.Icon.html - fn draw( - &mut self, - bounds: Rectangle, - path: &Path, - ) -> Self::Output; + fn draw(&mut self, bounds: Rectangle, path: &Path) -> Self::Output; } impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> -- cgit From 895eaef99b52c24e6f3d804897ad850c1f1de960 Mon Sep 17 00:00:00 2001 From: Malte Veerman Date: Thu, 12 Dec 2019 01:14:54 +0100 Subject: Merged svg pipeline into image --- native/src/widget/icon.rs | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) (limited to 'native') diff --git a/native/src/widget/icon.rs b/native/src/widget/icon.rs index b3906ccf..c324e786 100644 --- a/native/src/widget/icon.rs +++ b/native/src/widget/icon.rs @@ -1,6 +1,6 @@ //! Display an icon. use crate::{ - layout, Element, Hasher, Layout, Length, Point, Rectangle, Widget, + image, layout, Element, Hasher, Layout, Length, Point, Rectangle, Widget, }; use std::{ @@ -11,7 +11,7 @@ use std::{ /// A simple icon_loader widget. #[derive(Debug, Clone)] pub struct Icon { - path: PathBuf, + handle: image::Handle, size: Length, } @@ -21,7 +21,7 @@ impl Icon { /// [`Icon`]: struct.Icon.html pub fn new(path: impl Into) -> Self { Icon { - path: path.into(), + handle: image::Handle::from_path(path), size: Length::Fill, } } @@ -37,7 +37,7 @@ impl Icon { impl Widget for Icon where - Renderer: self::Renderer, + Renderer: image::Renderer, { fn width(&self) -> Length { self.size @@ -65,9 +65,7 @@ where layout: Layout<'_>, _cursor_position: Point, ) -> Renderer::Output { - let bounds = layout.bounds(); - - renderer.draw(bounds, self.path.as_path()) + renderer.draw(self.handle.clone(), layout) } fn hash_layout(&self, state: &mut Hasher) { @@ -75,24 +73,9 @@ where } } -/// The renderer of an [`Icon`]. -/// -/// Your [renderer] will need to implement this trait before being -/// able to use [`Icon`] in your [`UserInterface`]. -/// -/// [`Icon`]: struct.Icon.html -/// [renderer]: ../../renderer/index.html -/// [`UserInterface`]: ../../struct.UserInterface.html -pub trait Renderer: crate::Renderer { - /// Draws an [`Icon`]. - /// - /// [`Icon`]: struct.Icon.html - fn draw(&mut self, bounds: Rectangle, path: &Path) -> Self::Output; -} - impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> where - Renderer: self::Renderer, + Renderer: image::Renderer, { fn from(icon: Icon) -> Element<'a, Message, Renderer> { Element::new(icon) -- cgit From 27717bc70c3947f553a8b75da9789fe967994a31 Mon Sep 17 00:00:00 2001 From: Malte Veerman Date: Thu, 12 Dec 2019 01:25:18 +0100 Subject: Renamed `Icon` widget to `Svg` and gave it separate width and height. The aspect ratio is now preserved like in the `Image` widget. --- native/src/widget.rs | 6 +-- native/src/widget/icon.rs | 83 ------------------------------------- native/src/widget/svg.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 86 deletions(-) delete mode 100644 native/src/widget/icon.rs create mode 100644 native/src/widget/svg.rs (limited to 'native') diff --git a/native/src/widget.rs b/native/src/widget.rs index 0cf6a639..ee7232cb 100644 --- a/native/src/widget.rs +++ b/native/src/widget.rs @@ -24,7 +24,7 @@ pub mod button; pub mod checkbox; pub mod column; pub mod container; -pub mod icon; +pub mod svg; pub mod image; pub mod radio; pub mod row; @@ -42,8 +42,6 @@ pub use column::Column; #[doc(no_inline)] pub use container::Container; #[doc(no_inline)] -pub use icon::Icon; -#[doc(no_inline)] pub use image::Image; #[doc(no_inline)] pub use radio::Radio; @@ -54,6 +52,8 @@ pub use scrollable::Scrollable; #[doc(no_inline)] pub use slider::Slider; #[doc(no_inline)] +pub use svg::Svg; +#[doc(no_inline)] pub use text::Text; #[doc(no_inline)] pub use text_input::TextInput; diff --git a/native/src/widget/icon.rs b/native/src/widget/icon.rs deleted file mode 100644 index c324e786..00000000 --- a/native/src/widget/icon.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Display an icon. -use crate::{ - image, layout, Element, Hasher, Layout, Length, Point, Rectangle, Widget, -}; - -use std::{ - hash::Hash, - path::{Path, PathBuf}, -}; - -/// A simple icon_loader widget. -#[derive(Debug, Clone)] -pub struct Icon { - handle: image::Handle, - size: Length, -} - -impl Icon { - /// Create a new [`Icon`] from the file at `path`. - /// - /// [`Icon`]: struct.Icon.html - pub fn new(path: impl Into) -> Self { - Icon { - handle: image::Handle::from_path(path), - size: Length::Fill, - } - } - - /// Sets the size of the [`Icon`]. - /// - /// [`Icon`]: struct.Icon.html - pub fn size(mut self, size: Length) -> Self { - self.size = size; - self - } -} - -impl Widget for Icon -where - Renderer: image::Renderer, -{ - fn width(&self) -> Length { - self.size - } - - fn height(&self) -> Length { - self.size - } - - fn layout(&self, _: &Renderer, limits: &layout::Limits) -> layout::Node { - let mut size = limits.width(self.size).height(self.size).max(); - - if size.width > size.height { - size.width = size.height; - } else if size.width < size.height { - size.height = size.width; - } - - layout::Node::new(size) - } - - fn draw( - &self, - renderer: &mut Renderer, - layout: Layout<'_>, - _cursor_position: Point, - ) -> Renderer::Output { - renderer.draw(self.handle.clone(), layout) - } - - fn hash_layout(&self, state: &mut Hasher) { - self.size.hash(state); - } -} - -impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> -where - Renderer: image::Renderer, -{ - fn from(icon: Icon) -> Element<'a, Message, Renderer> { - Element::new(icon) - } -} diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs new file mode 100644 index 00000000..097c1d86 --- /dev/null +++ b/native/src/widget/svg.rs @@ -0,0 +1,103 @@ +//! Display an icon. +use crate::{ + image, layout, Element, Hasher, Layout, Length, Point, Size, Widget, +}; + +use std::{ + hash::Hash, + path::PathBuf, +}; + +/// A simple icon_loader widget. +#[derive(Debug, Clone)] +pub struct Svg { + handle: image::Handle, + width: Length, + height: Length, +} + +impl Svg { + /// Create a new [`Svg`] from the file at `path`. + /// + /// [`Svg`]: struct.Svg.html + pub fn new(path: impl Into) -> Self { + Svg { + handle: image::Handle::from_path(path), + width: Length::Fill, + height: Length::Fill, + } + } + + /// Sets the width of the [`Svg`]. + /// + /// [`Svg`]: struct.Svg.html + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + /// Sets the height of the [`Svg`]. + /// + /// [`Svg`]: struct.Svg.html + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } +} + +impl Widget for Svg +where + Renderer: image::Renderer, +{ + fn width(&self) -> Length { + self.width + } + + fn height(&self) -> Length { + self.height + } + + fn layout(&self, renderer: &Renderer, limits: &layout::Limits) -> layout::Node { + let (width, height) = renderer.dimensions(&self.handle); + + let aspect_ratio = width as f32 / height as f32; + + let mut size = limits + .width(self.width) + .height(self.height) + .max(); + + let viewport_aspect_ratio = size.width / size.height; + + if viewport_aspect_ratio > aspect_ratio { + size.width = width as f32 * size.height / height as f32; + } else { + size.height = height as f32 * size.width / width as f32; + } + + layout::Node::new(size) + } + + fn draw( + &self, + renderer: &mut Renderer, + layout: Layout<'_>, + _cursor_position: Point, + ) -> Renderer::Output { + renderer.draw(self.handle.clone(), layout) + } + + fn hash_layout(&self, state: &mut Hasher) { + self.width.hash(state); + self.height.hash(state); + } +} + +impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> +where + Renderer: image::Renderer, +{ + fn from(icon: Svg) -> Element<'a, Message, Renderer> { + Element::new(icon) + } +} -- cgit From 09707f29fcf7fbd71570a43db214921043427c3f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 15 Dec 2019 06:19:07 +0100 Subject: Rerasterize SVGs when resized and refactor a bit --- native/src/widget/svg.rs | 101 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 12 deletions(-) (limited to 'native') diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs index 097c1d86..42f2ebdf 100644 --- a/native/src/widget/svg.rs +++ b/native/src/widget/svg.rs @@ -1,28 +1,27 @@ //! Display an icon. -use crate::{ - image, layout, Element, Hasher, Layout, Length, Point, Size, Widget, -}; +use crate::{layout, Element, Hasher, Layout, Length, Point, Size, Widget}; use std::{ hash::Hash, - path::PathBuf, + path::{Path, PathBuf}, }; /// A simple icon_loader widget. #[derive(Debug, Clone)] pub struct Svg { - handle: image::Handle, + handle: Handle, width: Length, height: Length, } impl Svg { - /// Create a new [`Svg`] from the file at `path`. + /// Creates a new [`Svg`] from the given [`Handle`]. /// /// [`Svg`]: struct.Svg.html - pub fn new(path: impl Into) -> Self { + /// [`Handle`]: struct.Handle.html + pub fn new(handle: impl Into) -> Self { Svg { - handle: image::Handle::from_path(path), + handle: handle.into(), width: Length::Fill, height: Length::Fill, } @@ -47,7 +46,7 @@ impl Svg { impl Widget for Svg where - Renderer: image::Renderer, + Renderer: self::Renderer, { fn width(&self) -> Length { self.width @@ -57,7 +56,11 @@ where self.height } - fn layout(&self, renderer: &Renderer, limits: &layout::Limits) -> layout::Node { + fn layout( + &self, + renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { let (width, height) = renderer.dimensions(&self.handle); let aspect_ratio = width as f32 / height as f32; @@ -65,7 +68,7 @@ where let mut size = limits .width(self.width) .height(self.height) - .max(); + .resolve(Size::new(width as f32, height as f32)); let viewport_aspect_ratio = size.width / size.height; @@ -93,9 +96,83 @@ where } } +/// An [`Svg`] handle. +/// +/// [`Svg`]: struct.Svg.html +#[derive(Debug, Clone)] +pub struct Handle { + id: u64, + path: PathBuf, +} + +impl Handle { + /// Creates an SVG [`Handle`] pointing to the vector image of the given + /// path. + /// + /// [`Handle`]: struct.Handle.html + pub fn from_path>(path: T) -> Handle { + use std::hash::Hasher as _; + + let path = path.into(); + + let mut hasher = Hasher::default(); + path.hash(&mut hasher); + + Handle { + id: hasher.finish(), + path, + } + } + + /// Returns the unique identifier of the [`Handle`]. + /// + /// [`Handle`]: struct.Handle.html + pub fn id(&self) -> u64 { + self.id + } + + /// Returns a reference to the path of the [`Handle`]. + /// + /// [`Handle`]: enum.Handle.html + pub fn path(&self) -> &Path { + &self.path + } +} + +impl From for Handle { + fn from(path: String) -> Handle { + Handle::from_path(path) + } +} + +impl From<&str> for Handle { + fn from(path: &str) -> Handle { + Handle::from_path(path) + } +} + +/// The renderer of an [`Svg`]. +/// +/// Your [renderer] will need to implement this trait before being able to use +/// an [`Svg`] in your user interface. +/// +/// [`Svg`]: struct.Svg.html +/// [renderer]: ../../renderer/index.html +pub trait Renderer: crate::Renderer { + /// Returns the default dimensions of an [`Svg`] located on the given path. + /// + /// [`Svg`]: struct.Svg.html + fn dimensions(&self, handle: &Handle) -> (u32, u32); + + /// Draws an [`Svg`]. + /// + /// [`Svg`]: struct.Svg.html + fn draw(&mut self, handle: Handle, layout: Layout<'_>) -> Self::Output; +} + impl<'a, Message, Renderer> From for Element<'a, Message, Renderer> where - Renderer: image::Renderer, + Renderer: self::Renderer, { fn from(icon: Svg) -> Element<'a, Message, Renderer> { Element::new(icon) -- cgit From 6ba2461445e68127ef686d2b9d79eb7a09f42a86 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 15 Dec 2019 06:28:44 +0100 Subject: Update `Svg` documentation --- native/src/widget/svg.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'native') diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs index 42f2ebdf..9580f195 100644 --- a/native/src/widget/svg.rs +++ b/native/src/widget/svg.rs @@ -1,4 +1,4 @@ -//! Display an icon. +//! Display vector graphics in your application. use crate::{layout, Element, Hasher, Layout, Length, Point, Size, Widget}; use std::{ @@ -6,7 +6,14 @@ use std::{ path::{Path, PathBuf}, }; -/// A simple icon_loader widget. +/// A vector graphics image. +/// +/// An [`Svg`] image resizes smoothly without losing any quality. +/// +/// [`Svg`] images can have a considerable rendering cost when resized, +/// specially when they are complex. +/// +/// [`Svg`]: struct.Svg.html #[derive(Debug, Clone)] pub struct Svg { handle: Handle, -- cgit