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::widget::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::widget::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::widget::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()))
}
}