summaryrefslogblamecommitdiffstats
path: root/renderer/src/widget/canvas.rs
blob: 35c8fff9603f27c6034194595a9f9bfa7766cac9 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

















                                                                                
                                   















                                                                              
                                                                
































































































                                                                                
                                                                        










































                                                                                
mod cache;

pub use cache::Cache;

pub use iced_native::widget::canvas::event::{self, Event};
pub use iced_native::widget::canvas::fill::{self, Fill};
pub use iced_native::widget::canvas::gradient::{self, Gradient};
pub use iced_native::widget::canvas::path::{self, Path};
pub use iced_native::widget::canvas::stroke::{self, Stroke};
pub use iced_native::widget::canvas::{
    Canvas, Cursor, LineCap, LineDash, LineJoin, Program, Renderer, Style, Text,
};

use crate::{Backend, Point, Rectangle, Size, Vector};

pub use crate::Geometry;

pub enum Frame {
    Wgpu(iced_wgpu::canvas::Frame),
    TinySkia(iced_tiny_skia::canvas::Frame),
}

macro_rules! delegate {
    ($frame:expr, $name:ident => $body:expr) => {
        match $frame {
            Self::Wgpu($name) => $body,
            Self::TinySkia($name) => $body,
        }
    };
}

impl Frame {
    pub fn new<Theme>(renderer: &crate::Renderer<Theme>, size: Size) -> Self {
        match renderer.backend() {
            Backend::Wgpu(_) => {
                Frame::Wgpu(iced_wgpu::canvas::Frame::new(size))
            }
            Backend::TinySkia(_) => {
                Frame::TinySkia(iced_tiny_skia::canvas::Frame::new(size))
            }
        }
    }

    /// Returns the width of the [`Frame`].
    #[inline]
    pub fn width(&self) -> f32 {
        delegate!(self, frame => frame.width())
    }

    /// Returns the height of the [`Frame`].
    #[inline]
    pub fn height(&self) -> f32 {
        delegate!(self, frame => frame.height())
    }

    /// Returns the dimensions of the [`Frame`].
    #[inline]
    pub fn size(&self) -> Size {
        delegate!(self, frame => frame.size())
    }

    /// Returns the coordinate of the center of the [`Frame`].
    #[inline]
    pub fn center(&self) -> Point {
        delegate!(self, frame => frame.center())
    }

    /// Draws the given [`Path`] on the [`Frame`] by filling it with the
    /// provided style.
    pub fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {
        delegate!(self, frame => frame.fill(path, fill));
    }

    /// Draws an axis-aligned rectangle given its top-left corner coordinate and
    /// its `Size` on the [`Frame`] by filling it with the provided style.
    pub fn fill_rectangle(
        &mut self,
        top_left: Point,
        size: Size,
        fill: impl Into<Fill>,
    ) {
        delegate!(self, frame => frame.fill_rectangle(top_left, size, fill));
    }

    /// Draws the stroke of the given [`Path`] on the [`Frame`] with the
    /// provided style.
    pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {
        delegate!(self, frame => frame.stroke(path, stroke));
    }

    /// Draws the characters of the given [`Text`] on the [`Frame`], filling
    /// them with the given color.
    ///
    /// __Warning:__ Text currently does not work well with rotations and scale
    /// transforms! The position will be correctly transformed, but the
    /// resulting glyphs will not be rotated or scaled properly.
    ///
    /// Additionally, all text will be rendered on top of all the layers of
    /// a [`Canvas`]. Therefore, it is currently only meant to be used for
    /// overlays, which is the most common use case.
    ///
    /// Support for vectorial text is planned, and should address all these
    /// limitations.
    ///
    /// [`Canvas`]: crate::widget::Canvas
    pub fn fill_text(&mut self, text: impl Into<Text>) {
        delegate!(self, frame => frame.fill_text(text));
    }

    /// Stores the current transform of the [`Frame`] and executes the given
    /// drawing operations, restoring the transform afterwards.
    ///
    /// This method is useful to compose transforms and perform drawing
    /// operations in different coordinate systems.
    #[inline]
    pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) {
        delegate!(self, frame => frame.push_transform());

        f(self);

        delegate!(self, frame => frame.pop_transform());
    }

    /// Executes the given drawing operations within a [`Rectangle`] region,
    /// clipping any geometry that overflows its bounds. Any transformations
    /// performed are local to the provided closure.
    ///
    /// This method is useful to perform drawing operations that need to be
    /// clipped.
    #[inline]
    pub fn with_clip(&mut self, region: Rectangle, f: impl FnOnce(&mut Frame)) {
        let mut frame = match self {
            Self::Wgpu(_) => {
                Self::Wgpu(iced_wgpu::canvas::Frame::new(region.size()))
            }
            Self::TinySkia(_) => Self::TinySkia(
                iced_tiny_skia::canvas::Frame::new(region.size()),
            ),
        };

        f(&mut frame);

        let translation = Vector::new(region.x, region.y);

        match (self, frame) {
            (Self::Wgpu(target), Self::Wgpu(frame)) => {
                target.clip(frame, translation);
            }
            (Self::TinySkia(target), Self::TinySkia(frame)) => {
                target.clip(frame, translation);
            }
            _ => unreachable!(),
        };
    }

    /// Applies a translation to the current transform of the [`Frame`].
    #[inline]
    pub fn translate(&mut self, translation: Vector) {
        delegate!(self, frame => frame.translate(translation));
    }

    /// Applies a rotation in radians to the current transform of the [`Frame`].
    #[inline]
    pub fn rotate(&mut self, angle: f32) {
        delegate!(self, frame => frame.rotate(angle));
    }

    /// Applies a scaling to the current transform of the [`Frame`].
    #[inline]
    pub fn scale(&mut self, scale: f32) {
        delegate!(self, frame => frame.scale(scale));
    }

    pub fn into_geometry(self) -> Geometry {
        Geometry(delegate!(self, frame => frame.into_primitive()))
    }
}