iced_graphics/geometry/
frame.rs

1//! Draw and generate geometry.
2use crate::core::{Point, Radians, Rectangle, Size, Vector};
3use crate::geometry::{self, Fill, Image, Path, Stroke, Svg, Text};
4
5/// The region of a surface that can be used to draw geometry.
6pub struct Frame<Renderer>
7where
8    Renderer: geometry::Renderer,
9{
10    raw: Renderer::Frame,
11}
12
13impl<Renderer> Frame<Renderer>
14where
15    Renderer: geometry::Renderer,
16{
17    /// Creates a new [`Frame`] with the given dimensions.
18    ///
19    /// Any geometry drawn outside of the dimensions will be clipped.
20    /// If you need further control, use [`with_bounds`](Self::with_bounds).
21    pub fn new(renderer: &Renderer, size: Size) -> Self {
22        Self::with_bounds(renderer, Rectangle::with_size(size))
23    }
24
25    /// Creates a new [`Frame`] with the given clip bounds.
26    pub fn with_bounds(renderer: &Renderer, bounds: Rectangle) -> Self {
27        Self {
28            raw: renderer.new_frame(bounds),
29        }
30    }
31
32    /// Returns the width of the [`Frame`].
33    pub fn width(&self) -> f32 {
34        self.raw.width()
35    }
36
37    /// Returns the height of the [`Frame`].
38    pub fn height(&self) -> f32 {
39        self.raw.height()
40    }
41
42    /// Returns the dimensions of the [`Frame`].
43    pub fn size(&self) -> Size {
44        self.raw.size()
45    }
46
47    /// Returns the coordinate of the center of the [`Frame`].
48    pub fn center(&self) -> Point {
49        self.raw.center()
50    }
51
52    /// Draws the given [`Path`] on the [`Frame`] by filling it with the
53    /// provided style.
54    pub fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {
55        self.raw.fill(path, fill);
56    }
57
58    /// Draws an axis-aligned rectangle given its top-left corner coordinate and
59    /// its `Size` on the [`Frame`] by filling it with the provided style.
60    pub fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: impl Into<Fill>) {
61        self.raw.fill_rectangle(top_left, size, fill);
62    }
63
64    /// Draws the stroke of the given [`Path`] on the [`Frame`] with the
65    /// provided style.
66    pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {
67        self.raw.stroke(path, stroke);
68    }
69
70    /// Draws the stroke of an axis-aligned rectangle with the provided style
71    /// given its top-left corner coordinate and its `Size` on the [`Frame`] .
72    pub fn stroke_rectangle<'a>(
73        &mut self,
74        top_left: Point,
75        size: Size,
76        stroke: impl Into<Stroke<'a>>,
77    ) {
78        self.raw.stroke_rectangle(top_left, size, stroke);
79    }
80
81    /// Draws the characters of the given [`Text`] on the [`Frame`], filling
82    /// them with the given color.
83    ///
84    /// __Warning:__ All text will be rendered on top of all the layers of
85    /// a `Canvas`. Therefore, it is currently only meant to be used for
86    /// overlays, which is the most common use case.
87    pub fn fill_text(&mut self, text: impl Into<Text>) {
88        self.raw.fill_text(text);
89    }
90
91    /// Draws the given [`Image`] on the [`Frame`] inside the given bounds.
92    #[cfg(feature = "image")]
93    pub fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>) {
94        self.raw.draw_image(bounds, image);
95    }
96
97    /// Draws the given [`Svg`] on the [`Frame`] inside the given bounds.
98    #[cfg(feature = "svg")]
99    pub fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>) {
100        self.raw.draw_svg(bounds, svg);
101    }
102
103    /// Stores the current transform of the [`Frame`] and executes the given
104    /// drawing operations, restoring the transform afterwards.
105    ///
106    /// This method is useful to compose transforms and perform drawing
107    /// operations in different coordinate systems.
108    #[inline]
109    pub fn with_save<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
110        self.push_transform();
111
112        let result = f(self);
113
114        self.pop_transform();
115
116        result
117    }
118
119    /// Pushes the current transform in the transform stack.
120    pub fn push_transform(&mut self) {
121        self.raw.push_transform();
122    }
123
124    /// Pops a transform from the transform stack and sets it as the current transform.
125    pub fn pop_transform(&mut self) {
126        self.raw.pop_transform();
127    }
128
129    /// Executes the given drawing operations within a [`Rectangle`] region,
130    /// clipping any geometry that overflows its bounds. Any transformations
131    /// performed are local to the provided closure.
132    ///
133    /// This method is useful to perform drawing operations that need to be
134    /// clipped.
135    #[inline]
136    pub fn with_clip<R>(&mut self, region: Rectangle, f: impl FnOnce(&mut Self) -> R) -> R {
137        let mut frame = self.draft(region);
138
139        let result = f(&mut frame);
140        self.paste(frame);
141
142        result
143    }
144
145    /// Creates a new [`Frame`] with the given [`Size`].
146    ///
147    /// Draw its contents back to this [`Frame`] with [`paste`].
148    ///
149    /// [`paste`]: Self::paste
150    fn draft(&mut self, clip_bounds: Rectangle) -> Self {
151        Self {
152            raw: self.raw.draft(clip_bounds),
153        }
154    }
155
156    /// Draws the contents of the given [`Frame`] with origin at the given [`Point`].
157    fn paste(&mut self, frame: Self) {
158        self.raw.paste(frame.raw);
159    }
160
161    /// Applies a translation to the current transform of the [`Frame`].
162    pub fn translate(&mut self, translation: Vector) {
163        self.raw.translate(translation);
164    }
165
166    /// Applies a rotation in radians to the current transform of the [`Frame`].
167    pub fn rotate(&mut self, angle: impl Into<Radians>) {
168        self.raw.rotate(angle);
169    }
170
171    /// Applies a uniform scaling to the current transform of the [`Frame`].
172    pub fn scale(&mut self, scale: impl Into<f32>) {
173        self.raw.scale(scale);
174    }
175
176    /// Applies a non-uniform scaling to the current transform of the [`Frame`].
177    pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {
178        self.raw.scale_nonuniform(scale);
179    }
180
181    /// Turns the [`Frame`] into its underlying geometry.
182    pub fn into_geometry(self) -> Renderer::Geometry {
183        self.raw.into_geometry()
184    }
185}
186
187/// The internal implementation of a [`Frame`].
188///
189/// Analogous to [`Frame`]. See [`Frame`] for the documentation
190/// of each method.
191#[allow(missing_docs)]
192pub trait Backend: Sized {
193    type Geometry;
194
195    fn width(&self) -> f32;
196    fn height(&self) -> f32;
197    fn size(&self) -> Size;
198    fn center(&self) -> Point;
199
200    fn push_transform(&mut self);
201    fn pop_transform(&mut self);
202
203    fn translate(&mut self, translation: Vector);
204    fn rotate(&mut self, angle: impl Into<Radians>);
205    fn scale(&mut self, scale: impl Into<f32>);
206    fn scale_nonuniform(&mut self, scale: impl Into<Vector>);
207
208    fn draft(&mut self, clip_bounds: Rectangle) -> Self;
209    fn paste(&mut self, frame: Self);
210
211    fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>);
212    fn stroke_rectangle<'a>(&mut self, top_left: Point, size: Size, stroke: impl Into<Stroke<'a>>);
213    fn stroke_text<'a>(&mut self, text: impl Into<Text>, stroke: impl Into<Stroke<'a>>);
214
215    fn fill(&mut self, path: &Path, fill: impl Into<Fill>);
216    fn fill_text(&mut self, text: impl Into<Text>);
217    fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: impl Into<Fill>);
218
219    fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>);
220    fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>);
221
222    fn into_geometry(self) -> Self::Geometry;
223}
224
225#[cfg(debug_assertions)]
226impl Backend for () {
227    type Geometry = ();
228
229    fn width(&self) -> f32 {
230        0.0
231    }
232
233    fn height(&self) -> f32 {
234        0.0
235    }
236
237    fn size(&self) -> Size {
238        Size::ZERO
239    }
240
241    fn center(&self) -> Point {
242        Point::ORIGIN
243    }
244
245    fn push_transform(&mut self) {}
246    fn pop_transform(&mut self) {}
247
248    fn translate(&mut self, _translation: Vector) {}
249    fn rotate(&mut self, _angle: impl Into<Radians>) {}
250    fn scale(&mut self, _scale: impl Into<f32>) {}
251    fn scale_nonuniform(&mut self, _scale: impl Into<Vector>) {}
252
253    fn draft(&mut self, _clip_bounds: Rectangle) -> Self {}
254    fn paste(&mut self, _frame: Self) {}
255
256    fn stroke<'a>(&mut self, _path: &Path, _stroke: impl Into<Stroke<'a>>) {}
257    fn stroke_rectangle<'a>(
258        &mut self,
259        _top_left: Point,
260        _size: Size,
261        _stroke: impl Into<Stroke<'a>>,
262    ) {
263    }
264    fn stroke_text<'a>(&mut self, _text: impl Into<Text>, _stroke: impl Into<Stroke<'a>>) {}
265
266    fn fill(&mut self, _path: &Path, _fill: impl Into<Fill>) {}
267    fn fill_text(&mut self, _text: impl Into<Text>) {}
268    fn fill_rectangle(&mut self, _top_left: Point, _size: Size, _fill: impl Into<Fill>) {}
269
270    fn draw_image(&mut self, _bounds: Rectangle, _image: impl Into<Image>) {}
271    fn draw_svg(&mut self, _bounds: Rectangle, _svg: impl Into<Svg>) {}
272
273    fn into_geometry(self) -> Self::Geometry {}
274}