1use crate::core::{Point, Radians, Rectangle, Size, Vector};
3use crate::geometry::{self, Fill, Image, Path, Stroke, Svg, Text};
4
5pub 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 pub fn new(renderer: &Renderer, size: Size) -> Self {
22 Self::with_bounds(renderer, Rectangle::with_size(size))
23 }
24
25 pub fn with_bounds(renderer: &Renderer, bounds: Rectangle) -> Self {
27 Self {
28 raw: renderer.new_frame(bounds),
29 }
30 }
31
32 pub fn width(&self) -> f32 {
34 self.raw.width()
35 }
36
37 pub fn height(&self) -> f32 {
39 self.raw.height()
40 }
41
42 pub fn size(&self) -> Size {
44 self.raw.size()
45 }
46
47 pub fn center(&self) -> Point {
49 self.raw.center()
50 }
51
52 pub fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {
55 self.raw.fill(path, fill);
56 }
57
58 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 pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {
72 self.raw.stroke(path, stroke);
73 }
74
75 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 pub fn fill_text(&mut self, text: impl Into<Text>) {
93 self.raw.fill_text(text);
94 }
95
96 #[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 #[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 #[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 pub fn push_transform(&mut self) {
126 self.raw.push_transform();
127 }
128
129 pub fn pop_transform(&mut self) {
131 self.raw.pop_transform();
132 }
133
134 #[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 fn draft(&mut self, clip_bounds: Rectangle) -> Self {
160 Self {
161 raw: self.raw.draft(clip_bounds),
162 }
163 }
164
165 fn paste(&mut self, frame: Self) {
167 self.raw.paste(frame.raw);
168 }
169
170 pub fn translate(&mut self, translation: Vector) {
172 self.raw.translate(translation);
173 }
174
175 pub fn rotate(&mut self, angle: impl Into<Radians>) {
177 self.raw.rotate(angle);
178 }
179
180 pub fn scale(&mut self, scale: impl Into<f32>) {
182 self.raw.scale(scale);
183 }
184
185 pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {
187 self.raw.scale_nonuniform(scale);
188 }
189
190 pub fn into_geometry(self) -> Renderer::Geometry {
192 self.raw.into_geometry()
193 }
194}
195
196#[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}