Skip to main content

widgetkit_render/
model.rs

1use crate::{Stroke, TextStyle};
2use widgetkit_core::{Color, Point, Rect, Size};
3
4// Unstable render command model used behind `Canvas`.
5//
6// These types are implementation details for the current software renderer and future backend
7// experiments. They are exposed through `widgetkit_render::unstable` only and should not be
8// treated as a stable WidgetKit application API.
9
10/// Unstable render frame consumed by renderer backends.
11#[derive(Clone, Debug, PartialEq)]
12pub struct RenderFrame {
13    size: Size,
14    commands: Vec<RenderCommand>,
15}
16
17impl RenderFrame {
18    pub fn new(size: Size, commands: Vec<RenderCommand>) -> Self {
19        Self { size, commands }
20    }
21
22    pub fn size(&self) -> Size {
23        self.size
24    }
25
26    pub fn commands(&self) -> &[RenderCommand] {
27        &self.commands
28    }
29
30    pub fn into_commands(self) -> Vec<RenderCommand> {
31        self.commands
32    }
33
34    pub(crate) fn from_list(size: Size, commands: CommandList) -> Self {
35        Self::new(size, commands.into_commands())
36    }
37
38    pub(crate) fn into_parts(self) -> (Size, Vec<RenderCommand>) {
39        (self.size, self.commands)
40    }
41}
42
43#[derive(Clone, Debug, Default, PartialEq)]
44pub(crate) struct CommandList {
45    commands: Vec<RenderCommand>,
46}
47
48impl CommandList {
49    pub(crate) fn new() -> Self {
50        Self::default()
51    }
52
53    pub(crate) fn push(&mut self, command: RenderCommand) {
54        self.commands.push(command);
55    }
56
57    pub(crate) fn into_commands(self) -> Vec<RenderCommand> {
58        self.commands
59    }
60}
61
62/// Unstable low-level drawing command.
63#[derive(Clone, Debug, PartialEq)]
64pub enum RenderCommand {
65    Clear(ClearCommand),
66    Fill(FillCommand),
67    Stroke(StrokeCommand),
68    Text(TextCommand),
69    Image(ImageCommand),
70    Clip(ClipCommand),
71    Transform(TransformCommand),
72    State(StateCommand),
73}
74
75#[derive(Clone, Copy, Debug, PartialEq)]
76pub struct Paint {
77    pub color: Color,
78}
79
80impl Paint {
81    pub const fn solid(color: Color) -> Self {
82        Self { color }
83    }
84}
85
86#[derive(Clone, Copy, Debug, PartialEq)]
87pub struct ClearCommand {
88    pub paint: Paint,
89}
90
91#[derive(Clone, Copy, Debug, PartialEq)]
92pub struct Fill {
93    pub paint: Paint,
94}
95
96impl Fill {
97    pub const fn solid(color: Color) -> Self {
98        Self {
99            paint: Paint::solid(color),
100        }
101    }
102}
103
104#[derive(Clone, Copy, Debug, PartialEq)]
105pub struct FillCommand {
106    pub shape: FillShape,
107    pub fill: Fill,
108}
109
110#[derive(Clone, Copy, Debug, PartialEq)]
111pub enum FillShape {
112    Rect(Rect),
113    RoundRect {
114        rect: Rect,
115        radius: f32,
116    },
117    Circle {
118        center: Point,
119        radius: f32,
120    },
121    Ellipse {
122        center: Point,
123        radius_x: f32,
124        radius_y: f32,
125    },
126}
127
128#[derive(Clone, Copy, Debug, PartialEq)]
129pub struct StrokeCommand {
130    pub shape: StrokeShape,
131    pub stroke: Stroke,
132    pub paint: Paint,
133}
134
135#[derive(Clone, Copy, Debug, PartialEq)]
136pub enum StrokeShape {
137    Line { start: Point, end: Point },
138}
139
140#[derive(Clone, Debug, PartialEq)]
141pub struct TextCommand {
142    pub position: Point,
143    pub text: String,
144    pub style: TextStyle,
145    pub paint: Paint,
146}
147
148#[derive(Clone, Copy, Debug, PartialEq)]
149pub struct ImageCommand {
150    pub rect: Rect,
151    pub source: ImageSource,
152    pub paint: Paint,
153}
154
155#[derive(Clone, Copy, Debug, PartialEq)]
156pub enum ImageSource {
157    Placeholder,
158}
159
160#[derive(Clone, Copy, Debug, PartialEq)]
161pub struct ClipCommand {
162    pub primitive: ClipPrimitive,
163}
164
165#[derive(Clone, Copy, Debug, PartialEq)]
166pub enum ClipPrimitive {
167    Rect(Rect),
168}
169
170#[derive(Clone, Copy, Debug, Default, PartialEq)]
171pub struct Transform {
172    pub translate_x: f32,
173    pub translate_y: f32,
174}
175
176impl Transform {
177    pub const fn translation(x: f32, y: f32) -> Self {
178        Self {
179            translate_x: x,
180            translate_y: y,
181        }
182    }
183
184    pub(crate) fn then(self, next: Self) -> Self {
185        Self {
186            translate_x: self.translate_x + next.translate_x,
187            translate_y: self.translate_y + next.translate_y,
188        }
189    }
190
191    pub(crate) fn map_point(self, point: Point) -> Point {
192        Point::new(point.x + self.translate_x, point.y + self.translate_y)
193    }
194
195    pub(crate) fn map_rect(self, rect: Rect) -> Rect {
196        Rect::xywh(
197            rect.x() + self.translate_x,
198            rect.y() + self.translate_y,
199            rect.width(),
200            rect.height(),
201        )
202    }
203}
204
205#[derive(Clone, Copy, Debug, PartialEq)]
206pub struct TransformCommand {
207    pub transform: Transform,
208}
209
210#[derive(Clone, Copy, Debug, PartialEq, Eq)]
211pub enum StateCommand {
212    Save,
213    Restore,
214}
215
216// TODO(v0.3): layout-aware text measurement hooks
217// TODO(v0.3): keep raw render internals unstable until post-v0.3 review
218// TODO(v0.4): input-related hit-test helpers for shapes
219// TODO(v0.5): ensure command model is sufficient for declarative layer