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