1use crate::{
2 color::ColorU,
3 fonts::{FontId, GlyphId},
4 geometry::{rect::RectF, vector::Vector2F},
5};
6
7pub struct Scene {
8 scale_factor: f32,
9 layers: Vec<Layer>,
10 active_layer_stack: Vec<usize>,
11}
12
13#[derive(Default)]
14pub struct Layer {
15 clip_bounds: Option<RectF>,
16 quads: Vec<Quad>,
17 shadows: Vec<Shadow>,
18 glyphs: Vec<Glyph>,
19 icons: Vec<Icon>,
20 paths: Vec<Path>,
21}
22
23#[derive(Default, Debug)]
24pub struct Quad {
25 pub bounds: RectF,
26 pub background: Option<ColorU>,
27 pub border: Border,
28 pub corner_radius: f32,
29}
30
31#[derive(Debug)]
32pub struct Shadow {
33 pub bounds: RectF,
34 pub corner_radius: f32,
35 pub sigma: f32,
36 pub color: ColorU,
37}
38
39#[derive(Debug)]
40pub struct Glyph {
41 pub font_id: FontId,
42 pub font_size: f32,
43 pub id: GlyphId,
44 pub origin: Vector2F,
45 pub color: ColorU,
46}
47
48pub struct Icon {
49 pub bounds: RectF,
50 pub svg: usvg::Tree,
51 pub path: String,
52 pub color: ColorU,
53}
54
55#[derive(Clone, Copy, Default, Debug)]
56pub struct Border {
57 pub width: f32,
58 pub color: Option<ColorU>,
59 pub top: bool,
60 pub right: bool,
61 pub bottom: bool,
62 pub left: bool,
63}
64
65#[derive(Debug)]
66pub struct Path {
67 pub bounds: RectF,
68 pub color: ColorU,
69 pub vertices: Vec<PathVertex>,
70}
71
72#[derive(Debug)]
73pub struct PathVertex {
74 pub xy_position: Vector2F,
75 pub st_position: Vector2F,
76}
77
78impl Scene {
79 pub fn new(scale_factor: f32) -> Self {
80 Scene {
81 scale_factor,
82 layers: vec![Layer::new(None)],
83 active_layer_stack: vec![0],
84 }
85 }
86
87 pub fn scale_factor(&self) -> f32 {
88 self.scale_factor
89 }
90
91 pub fn layers(&self) -> &[Layer] {
92 self.layers.as_slice()
93 }
94
95 pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
96 let ix = self.layers.len();
97 self.layers.push(Layer::new(clip_bounds));
98 self.active_layer_stack.push(ix);
99 }
100
101 pub fn pop_layer(&mut self) {
102 assert!(self.active_layer_stack.len() > 1);
103 self.active_layer_stack.pop();
104 }
105
106 pub fn push_quad(&mut self, quad: Quad) {
107 self.active_layer().push_quad(quad)
108 }
109
110 pub fn push_shadow(&mut self, shadow: Shadow) {
111 self.active_layer().push_shadow(shadow)
112 }
113
114 pub fn push_glyph(&mut self, glyph: Glyph) {
115 self.active_layer().push_glyph(glyph)
116 }
117
118 pub fn push_icon(&mut self, icon: Icon) {
119 self.active_layer().push_icon(icon)
120 }
121
122 pub fn push_path(&mut self, path: Path) {
123 self.active_layer().push_path(path);
124 }
125
126 fn active_layer(&mut self) -> &mut Layer {
127 &mut self.layers[*self.active_layer_stack.last().unwrap()]
128 }
129}
130
131impl Layer {
132 pub fn new(clip_bounds: Option<RectF>) -> Self {
133 Self {
134 clip_bounds,
135 quads: Vec::new(),
136 shadows: Vec::new(),
137 glyphs: Vec::new(),
138 icons: Vec::new(),
139 paths: Vec::new(),
140 }
141 }
142
143 pub fn clip_bounds(&self) -> Option<RectF> {
144 self.clip_bounds
145 }
146
147 fn push_quad(&mut self, quad: Quad) {
148 self.quads.push(quad);
149 }
150
151 pub fn quads(&self) -> &[Quad] {
152 self.quads.as_slice()
153 }
154
155 fn push_shadow(&mut self, shadow: Shadow) {
156 self.shadows.push(shadow);
157 }
158
159 pub fn shadows(&self) -> &[Shadow] {
160 self.shadows.as_slice()
161 }
162
163 fn push_glyph(&mut self, glyph: Glyph) {
164 self.glyphs.push(glyph);
165 }
166
167 pub fn glyphs(&self) -> &[Glyph] {
168 self.glyphs.as_slice()
169 }
170
171 pub fn push_icon(&mut self, icon: Icon) {
172 self.icons.push(icon);
173 }
174
175 pub fn icons(&self) -> &[Icon] {
176 self.icons.as_slice()
177 }
178
179 fn push_path(&mut self, path: Path) {
180 if !path.bounds.is_empty() {
181 self.paths.push(path);
182 }
183 }
184
185 pub fn paths(&self) -> &[Path] {
186 self.paths.as_slice()
187 }
188}
189
190impl Border {
191 pub fn new(width: f32, color: impl Into<ColorU>) -> Self {
192 Self {
193 width,
194 color: Some(color.into()),
195 top: false,
196 left: false,
197 bottom: false,
198 right: false,
199 }
200 }
201
202 pub fn all(width: f32, color: impl Into<ColorU>) -> Self {
203 Self {
204 width,
205 color: Some(color.into()),
206 top: true,
207 left: true,
208 bottom: true,
209 right: true,
210 }
211 }
212
213 pub fn top(width: f32, color: impl Into<ColorU>) -> Self {
214 let mut border = Self::new(width, color);
215 border.top = true;
216 border
217 }
218
219 pub fn left(width: f32, color: impl Into<ColorU>) -> Self {
220 let mut border = Self::new(width, color);
221 border.left = true;
222 border
223 }
224
225 pub fn bottom(width: f32, color: impl Into<ColorU>) -> Self {
226 let mut border = Self::new(width, color);
227 border.bottom = true;
228 border
229 }
230
231 pub fn right(width: f32, color: impl Into<ColorU>) -> Self {
232 let mut border = Self::new(width, color);
233 border.right = true;
234 border
235 }
236
237 pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
238 self.top = top;
239 self.left = left;
240 self.bottom = bottom;
241 self.right = right;
242 self
243 }
244
245 pub fn top_width(&self) -> f32 {
246 if self.top {
247 self.width
248 } else {
249 0.0
250 }
251 }
252
253 pub fn left_width(&self) -> f32 {
254 if self.left {
255 self.width
256 } else {
257 0.0
258 }
259 }
260}