diff options
| author | 2019-12-16 21:38:33 +0100 | |
|---|---|---|
| committer | 2019-12-16 21:38:33 +0100 | |
| commit | 3702b109977a249247a0f1be40e57bec2cbaa4e3 (patch) | |
| tree | 9919f2ee30ab29c83a2455f838313ab5bfb2f146 /native/src/widget | |
| parent | c1b9f6652517dcbf5ffd83b5db4a624f9a5b0da4 (diff) | |
| parent | 514ccf8a72d660d77f26e085b545e5104389c138 (diff) | |
| download | iced-3702b109977a249247a0f1be40e57bec2cbaa4e3.tar.gz iced-3702b109977a249247a0f1be40e57bec2cbaa4e3.tar.bz2 iced-3702b109977a249247a0f1be40e57bec2cbaa4e3.zip  | |
Merge pull request #111 from Maldela/svg
Svg and icon support
Diffstat (limited to 'native/src/widget')
| -rw-r--r-- | native/src/widget/svg.rs | 187 | 
1 files changed, 187 insertions, 0 deletions
diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs new file mode 100644 index 00000000..9580f195 --- /dev/null +++ b/native/src/widget/svg.rs @@ -0,0 +1,187 @@ +//! Display vector graphics in your application. +use crate::{layout, Element, Hasher, Layout, Length, Point, Size, Widget}; + +use std::{ +    hash::Hash, +    path::{Path, PathBuf}, +}; + +/// 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, +    width: Length, +    height: Length, +} + +impl Svg { +    /// Creates a new [`Svg`] from the given [`Handle`]. +    /// +    /// [`Svg`]: struct.Svg.html +    /// [`Handle`]: struct.Handle.html +    pub fn new(handle: impl Into<Handle>) -> Self { +        Svg { +            handle: handle.into(), +            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<Message, Renderer> Widget<Message, Renderer> for Svg +where +    Renderer: self::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) +            .resolve(Size::new(width as f32, height as f32)); + +        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); +    } +} + +/// 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<T: Into<PathBuf>>(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<String> 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<Svg> for Element<'a, Message, Renderer> +where +    Renderer: self::Renderer, +{ +    fn from(icon: Svg) -> Element<'a, Message, Renderer> { +        Element::new(icon) +    } +}  | 
