1use crate::model::{
2 ClearCommand, ClipCommand, ClipPrimitive, CommandList, Fill, FillCommand, FillShape,
3 ImageCommand, ImageSource, Paint, RenderCommand, RenderFrame, StateCommand, StrokeCommand,
4 StrokeShape, TextCommand, Transform, TransformCommand,
5};
6use crate::text::measure_text;
7use crate::{Stroke, TextMetrics, TextStyle};
8use widgetkit_core::{Color, Point, Rect, Size};
9
10#[derive(Debug)]
11pub struct Canvas {
12 size: Size,
13 commands: CommandList,
14}
15
16pub struct RawCanvas<'a> {
21 commands: &'a mut CommandList,
22}
23
24impl Canvas {
25 pub fn new(size: Size) -> Self {
26 Self {
27 size,
28 commands: CommandList::new(),
29 }
30 }
31
32 pub fn size(&self) -> Size {
33 self.size
34 }
35
36 pub fn measure_text(&self, text: impl AsRef<str>, style: &TextStyle) -> TextMetrics {
37 measure_text(text.as_ref(), style)
38 }
39
40 pub fn clear(&mut self, color: Color) {
41 self.raw().clear(color);
42 }
43
44 pub fn rect(&mut self, rect: Rect, color: Color) {
45 self.raw().fill_rect(rect, color);
46 }
47
48 pub fn round_rect(&mut self, rect: Rect, radius: f32, color: Color) {
49 self.raw().fill_round_rect(rect, radius, color);
50 }
51
52 pub fn line(&mut self, start: Point, end: Point, stroke: Stroke, color: Color) {
53 self.raw().stroke_line(start, end, stroke, color);
54 }
55
56 pub fn circle(&mut self, center: Point, radius: f32, color: Color) {
57 self.raw().fill_circle(center, radius, color);
58 }
59
60 pub fn ellipse(&mut self, center: Point, radius_x: f32, radius_y: f32, color: Color) {
61 self.raw().fill_ellipse(center, radius_x, radius_y, color);
62 }
63
64 pub fn text(
65 &mut self,
66 position: Point,
67 text: impl Into<String>,
68 style: TextStyle,
69 color: Color,
70 ) {
71 self.raw().draw_text(position, text, style, color);
72 }
73
74 pub fn image_placeholder(&mut self, rect: Rect, color: Color) {
75 self.raw().image_placeholder(rect, color);
76 }
77
78 pub fn clip_rect(&mut self, rect: Rect) {
79 self.raw().clip_rect(rect);
80 }
81
82 pub fn save(&mut self) {
83 self.raw().save();
84 }
85
86 pub fn restore(&mut self) {
87 self.raw().restore();
88 }
89
90 pub fn translate(&mut self, dx: f32, dy: f32) {
91 self.raw().translate(dx, dy);
92 }
93
94 pub fn experimental_raw(&mut self, f: impl FnOnce(&mut RawCanvas<'_>)) {
100 let mut raw = self.raw();
101 f(&mut raw);
102 }
103
104 fn raw(&mut self) -> RawCanvas<'_> {
105 RawCanvas {
106 commands: &mut self.commands,
107 }
108 }
109
110 #[doc(hidden)]
111 pub fn into_frame(self) -> RenderFrame {
112 RenderFrame::from_list(self.size, self.commands)
113 }
114}
115
116impl RawCanvas<'_> {
117 pub fn push(&mut self, command: RenderCommand) {
118 self.commands.push(command);
119 }
120
121 pub fn clear(&mut self, color: Color) {
122 self.push(RenderCommand::Clear(ClearCommand {
123 paint: Paint::solid(color),
124 }));
125 }
126
127 pub fn fill_rect(&mut self, rect: Rect, color: Color) {
128 self.push(RenderCommand::Fill(FillCommand {
129 shape: FillShape::Rect(rect),
130 fill: Fill::solid(color),
131 }));
132 }
133
134 pub fn fill_round_rect(&mut self, rect: Rect, radius: f32, color: Color) {
135 self.push(RenderCommand::Fill(FillCommand {
136 shape: FillShape::RoundRect {
137 rect,
138 radius: radius.max(0.0),
139 },
140 fill: Fill::solid(color),
141 }));
142 }
143
144 pub fn fill_circle(&mut self, center: Point, radius: f32, color: Color) {
145 self.push(RenderCommand::Fill(FillCommand {
146 shape: FillShape::Circle {
147 center,
148 radius: radius.max(0.0),
149 },
150 fill: Fill::solid(color),
151 }));
152 }
153
154 pub fn fill_ellipse(&mut self, center: Point, radius_x: f32, radius_y: f32, color: Color) {
155 self.push(RenderCommand::Fill(FillCommand {
156 shape: FillShape::Ellipse {
157 center,
158 radius_x: radius_x.max(0.0),
159 radius_y: radius_y.max(0.0),
160 },
161 fill: Fill::solid(color),
162 }));
163 }
164
165 pub fn stroke_line(&mut self, start: Point, end: Point, stroke: Stroke, color: Color) {
166 self.push(RenderCommand::Stroke(StrokeCommand {
167 shape: StrokeShape::Line { start, end },
168 stroke,
169 paint: Paint::solid(color),
170 }));
171 }
172
173 pub fn draw_text(
174 &mut self,
175 position: Point,
176 text: impl Into<String>,
177 style: TextStyle,
178 color: Color,
179 ) {
180 self.push(RenderCommand::Text(TextCommand {
181 position,
182 text: text.into(),
183 style,
184 paint: Paint::solid(color),
185 }));
186 }
187
188 pub fn image_placeholder(&mut self, rect: Rect, color: Color) {
189 self.push(RenderCommand::Image(ImageCommand {
190 rect,
191 source: ImageSource::Placeholder,
192 paint: Paint::solid(color),
193 }));
194 }
195
196 pub fn clip_rect(&mut self, rect: Rect) {
197 self.push(RenderCommand::Clip(ClipCommand {
198 primitive: ClipPrimitive::Rect(rect),
199 }));
200 }
201
202 pub fn save(&mut self) {
203 self.push(RenderCommand::State(StateCommand::Save));
204 }
205
206 pub fn restore(&mut self) {
207 self.push(RenderCommand::State(StateCommand::Restore));
208 }
209
210 pub fn translate(&mut self, dx: f32, dy: f32) {
211 self.push(RenderCommand::Transform(TransformCommand {
212 transform: Transform::translation(dx, dy),
213 }));
214 }
215}
216
217