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(
61        &mut self,
62        top_left: Point,
63        size: Size,
64        fill: impl Into<Fill>,
65    ) {
66        self.raw.fill_rectangle(top_left, size, fill);
67    }
68
69    /// Draws the stroke of the given [`Path`] on the [`Frame`] with the
70    /// provided style.
71    pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {
72        self.raw.stroke(path, stroke);
73    }
74
75    /// Draws the stroke of an axis-aligned rectangle with the provided style
76    /// given its top-left corner coordinate and its `Size` on the [`Frame`] .
77    pub fn stroke_rectangle<'a>(
78        &mut self,
79        top_left: Point,
80        size: Size,
81        stroke: impl Into<Stroke<'a>>,
82    ) {
83        self.raw.stroke_rectangle(top_left, size, stroke);
84    }
85
86    /// Draws the characters of the given [`Text`] on the [`Frame`], filling
87    /// them with the given color.
88    ///
89    /// __Warning:__ All text will be rendered on top of all the layers of
90    /// a `Canvas`. Therefore, it is currently only meant to be used for
91    /// overlays, which is the most common use case.
92    pub fn fill_text(&mut self, text: impl Into<Text>) {
93        self.raw.fill_text(text);
94    }
95
96    /// Draws the given [`Image`] on the [`Frame`] inside the given bounds.
97    #[cfg(feature = "image")]
98    pub fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>) {
99        self.raw.draw_image(bounds, image);
100    }
101
102    /// Draws the given [`Svg`] on the [`Frame`] inside the given bounds.
103    #[cfg(feature = "svg")]
104    pub fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>) {
105        self.raw.draw_svg(bounds, svg);
106    }
107
108    /// Stores the current transform of the [`Frame`] and executes the given
109    /// drawing operations, restoring the transform afterwards.
110    ///
111    /// This method is useful to compose transforms and perform drawing
112    /// operations in different coordinate systems.
113    #[inline]
114    pub fn with_save<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
115        self.push_transform();
116
117        let result = f(self);
118
119        self.pop_transform();
120
121        result
122    }
123
124    /// Pushes the current transform in the transform stack.
125    pub fn push_transform(&mut self) {
126        self.raw.push_transform();
127    }
128
129    /// Pops a transform from the transform stack and sets it as the current transform.
130    pub fn pop_transform(&mut self) {
131        self.raw.pop_transform();
132    }
133
134    /// Executes the given drawing operations within a [`Rectangle`] region,
135    /// clipping any geometry that overflows its bounds. Any transformations
136    /// performed are local to the provided closure.
137    ///
138    /// This method is useful to perform drawing operations that need to be
139    /// clipped.
140    #[inline]
141    pub fn with_clip<R>(
142        &mut self,
143        region: Rectangle,
144        f: impl FnOnce(&mut Self) -> R,
145    ) -> R {
146        let mut frame = self.draft(region);
147
148        let result = f(&mut frame);
149        self.paste(frame);
150
151        result
152    }
153
154    /// Creates a new [`Frame`] with the given [`Size`].
155    ///
156    /// Draw its contents back to this [`Frame`] with [`paste`].
157    ///
158    /// [`paste`]: Self::paste
159    fn draft(&mut self, clip_bounds: Rectangle) -> Self {
160        Self {
161            raw: self.raw.draft(clip_bounds),
162        }
163    }
164
165    /// Draws the contents of the given [`Frame`] with origin at the given [`Point`].
166    fn paste(&mut self, frame: Self) {
167        self.raw.paste(frame.raw);
168    }
169
170    /// Applies a translation to the current transform of the [`Frame`].
171    pub fn translate(&mut self, translation: Vector) {
172        self.raw.translate(translation);
173    }
174
175    /// Applies a rotation in radians to the current transform of the [`Frame`].
176    pub fn rotate(&mut self, angle: impl Into<Radians>) {
177        self.raw.rotate(angle);
178    }
179
180    /// Applies a uniform scaling to the current transform of the [`Frame`].
181    pub fn scale(&mut self, scale: impl Into<f32>) {
182        self.raw.scale(scale);
183    }
184
185    /// Applies a non-uniform scaling to the current transform of the [`Frame`].
186    pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {
187        self.raw.scale_nonuniform(scale);
188    }
189
190    /// Turns the [`Frame`] into its underlying geometry.
191    pub fn into_geometry(self) -> Renderer::Geometry {
192        self.raw.into_geometry()
193    }
194}
195
196/// The internal implementation of a [`Frame`].
197///
198/// Analogous to [`Frame`]. See [`Frame`] for the documentation
199/// of each method.
200#[allow(missing_docs)]
201pub trait Backend: Sized {
202    type Geometry;
203
204    fn width(&self) -> f32;
205    fn height(&self) -> f32;
206    fn size(&self) -> Size;
207    fn center(&self) -> Point;
208
209    fn push_transform(&mut self);
210    fn pop_transform(&mut self);
211
212    fn translate(&mut self, translation: Vector);
213    fn rotate(&mut self, angle: impl Into<Radians>);
214    fn scale(&mut self, scale: impl Into<f32>);
215    fn scale_nonuniform(&mut self, scale: impl Into<Vector>);
216
217    fn draft(&mut self, clip_bounds: Rectangle) -> Self;
218    fn paste(&mut self, frame: Self);
219
220    fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>);
221    fn stroke_rectangle<'a>(
222        &mut self,
223        top_left: Point,
224        size: Size,
225        stroke: impl Into<Stroke<'a>>,
226    );
227    fn stroke_text<'a>(
228        &mut self,
229        text: impl Into<Text>,
230        stroke: impl Into<Stroke<'a>>,
231    );
232
233    fn fill(&mut self, path: &Path, fill: impl Into<Fill>);
234    fn fill_text(&mut self, text: impl Into<Text>);
235    fn fill_rectangle(
236        &mut self,
237        top_left: Point,
238        size: Size,
239        fill: impl Into<Fill>,
240    );
241
242    fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>);
243    fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>);
244
245    fn into_geometry(self) -> Self::Geometry;
246}
247
248#[cfg(debug_assertions)]
249impl Backend for () {
250    type Geometry = ();
251
252    fn width(&self) -> f32 {
253        0.0
254    }
255
256    fn height(&self) -> f32 {
257        0.0
258    }
259
260    fn size(&self) -> Size {
261        Size::ZERO
262    }
263
264    fn center(&self) -> Point {
265        Point::ORIGIN
266    }
267
268    fn push_transform(&mut self) {}
269    fn pop_transform(&mut self) {}
270
271    fn translate(&mut self, _translation: Vector) {}
272    fn rotate(&mut self, _angle: impl Into<Radians>) {}
273    fn scale(&mut self, _scale: impl Into<f32>) {}
274    fn scale_nonuniform(&mut self, _scale: impl Into<Vector>) {}
275
276    fn draft(&mut self, _clip_bounds: Rectangle) -> Self {}
277    fn paste(&mut self, _frame: Self) {}
278
279    fn stroke<'a>(&mut self, _path: &Path, _stroke: impl Into<Stroke<'a>>) {}
280    fn stroke_rectangle<'a>(
281        &mut self,
282        _top_left: Point,
283        _size: Size,
284        _stroke: impl Into<Stroke<'a>>,
285    ) {
286    }
287    fn stroke_text<'a>(
288        &mut self,
289        _text: impl Into<Text>,
290        _stroke: impl Into<Stroke<'a>>,
291    ) {
292    }
293
294    fn fill(&mut self, _path: &Path, _fill: impl Into<Fill>) {}
295    fn fill_text(&mut self, _text: impl Into<Text>) {}
296    fn fill_rectangle(
297        &mut self,
298        _top_left: Point,
299        _size: Size,
300        _fill: impl Into<Fill>,
301    ) {
302    }
303
304    fn draw_image(&mut self, _bounds: Rectangle, _image: impl Into<Image>) {}
305    fn draw_svg(&mut self, _bounds: Rectangle, _svg: impl Into<Svg>) {}
306
307    fn into_geometry(self) -> Self::Geometry {}
308}