summaryrefslogtreecommitdiffstats
path: root/renderer/src/geometry
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--renderer/src/geometry.rs174
-rw-r--r--renderer/src/geometry/cache.rs (renamed from graphics/src/widget/canvas/cache.rs)56
2 files changed, 197 insertions, 33 deletions
diff --git a/renderer/src/geometry.rs b/renderer/src/geometry.rs
new file mode 100644
index 00000000..26e2fed0
--- /dev/null
+++ b/renderer/src/geometry.rs
@@ -0,0 +1,174 @@
+mod cache;
+
+pub use cache::Cache;
+
+use crate::core::{Point, Rectangle, Size, Vector};
+use crate::graphics::geometry::{Fill, Geometry, Path, Stroke, Text};
+use crate::Backend;
+
+pub enum Frame {
+ TinySkia(iced_tiny_skia::geometry::Frame),
+ #[cfg(feature = "wgpu")]
+ Wgpu(iced_wgpu::geometry::Frame),
+}
+
+macro_rules! delegate {
+ ($frame:expr, $name:ident, $body:expr) => {
+ match $frame {
+ Self::TinySkia($name) => $body,
+ #[cfg(feature = "wgpu")]
+ Self::Wgpu($name) => $body,
+ }
+ };
+}
+
+impl Frame {
+ pub fn new<Theme>(renderer: &crate::Renderer<Theme>, size: Size) -> Self {
+ match renderer.backend() {
+ Backend::TinySkia(_) => {
+ Frame::TinySkia(iced_tiny_skia::geometry::Frame::new(size))
+ }
+ #[cfg(feature = "wgpu")]
+ Backend::Wgpu(_) => {
+ Frame::Wgpu(iced_wgpu::geometry::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::TinySkia(_) => Self::TinySkia(
+ iced_tiny_skia::geometry::Frame::new(region.size()),
+ ),
+ #[cfg(feature = "wgpu")]
+ Self::Wgpu(_) => {
+ Self::Wgpu(iced_wgpu::geometry::Frame::new(region.size()))
+ }
+ };
+
+ f(&mut frame);
+
+ let origin = Point::new(region.x, region.y);
+
+ match (self, frame) {
+ (Self::TinySkia(target), Self::TinySkia(frame)) => {
+ target.clip(frame, origin);
+ }
+ #[cfg(feature = "wgpu")]
+ (Self::Wgpu(target), Self::Wgpu(frame)) => {
+ target.clip(frame, origin);
+ }
+ #[allow(unreachable_patterns)]
+ _ => 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()))
+ }
+}
diff --git a/graphics/src/widget/canvas/cache.rs b/renderer/src/geometry/cache.rs
index 678b0f92..2a3534d0 100644
--- a/graphics/src/widget/canvas/cache.rs
+++ b/renderer/src/geometry/cache.rs
@@ -1,18 +1,10 @@
-use crate::widget::canvas::{Frame, Geometry};
-use crate::Primitive;
+use crate::core::Size;
+use crate::geometry::{Frame, Geometry};
+use crate::graphics::Primitive;
+use crate::Renderer;
-use iced_native::Size;
-use std::{cell::RefCell, sync::Arc};
-
-#[derive(Default)]
-enum State {
- #[default]
- Empty,
- Filled {
- bounds: Size,
- primitive: Arc<Primitive>,
- },
-}
+use std::cell::RefCell;
+use std::sync::Arc;
/// A simple cache that stores generated [`Geometry`] to avoid recomputation.
///
@@ -23,6 +15,16 @@ pub struct Cache {
state: RefCell<State>,
}
+#[derive(Debug, Default)]
+enum State {
+ #[default]
+ Empty,
+ Filled {
+ bounds: Size,
+ primitive: Arc<Primitive>,
+ },
+}
+
impl Cache {
/// Creates a new empty [`Cache`].
pub fn new() -> Self {
@@ -46,8 +48,9 @@ impl Cache {
/// Otherwise, the previously stored [`Geometry`] will be returned. The
/// [`Cache`] is not cleared in this case. In other words, it will keep
/// returning the stored [`Geometry`] if needed.
- pub fn draw(
+ pub fn draw<Theme>(
&self,
+ renderer: &Renderer<Theme>,
bounds: Size,
draw_fn: impl FnOnce(&mut Frame),
) -> Geometry {
@@ -59,19 +62,19 @@ impl Cache {
} = self.state.borrow().deref()
{
if *cached_bounds == bounds {
- return Geometry::from_primitive(Primitive::Cached {
- cache: primitive.clone(),
+ return Geometry(Primitive::Cache {
+ content: primitive.clone(),
});
}
}
- let mut frame = Frame::new(bounds);
+ let mut frame = Frame::new(renderer, bounds);
draw_fn(&mut frame);
let primitive = {
let geometry = frame.into_geometry();
- Arc::new(geometry.into_primitive())
+ Arc::new(geometry.0)
};
*self.state.borrow_mut() = State::Filled {
@@ -79,19 +82,6 @@ impl Cache {
primitive: primitive.clone(),
};
- Geometry::from_primitive(Primitive::Cached { cache: primitive })
- }
-}
-
-impl std::fmt::Debug for State {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- State::Empty => write!(f, "Empty"),
- State::Filled { primitive, bounds } => f
- .debug_struct("Filled")
- .field("primitive", primitive)
- .field("bounds", bounds)
- .finish(),
- }
+ Geometry(Primitive::Cache { content: primitive })
}
}