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