1use crate::{Color, Modifier, Rect, Transform};
2use std::rc::Rc;
3
4pub type ViewId = u64;
5
6pub type ImageHandle = u64;
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub enum ImageFit {
9 Contain,
10 Cover,
11 FitWidth,
12 FitHeight,
13}
14
15pub type Callback = Rc<dyn Fn()>;
16pub type ScrollCallback = Rc<dyn Fn(crate::Vec2) -> crate::Vec2>;
17
18#[derive(Clone)]
19pub enum ViewKind {
20 Surface,
21 Box,
22 Row,
23 Column,
24 Stack,
25 ScrollV {
26 on_scroll: Option<ScrollCallback>,
27 set_viewport_height: Option<Rc<dyn Fn(f32)>>,
28 set_content_height: Option<Rc<dyn Fn(f32)>>,
29 get_scroll_offset: Option<Rc<dyn Fn() -> f32>>,
30 set_scroll_offset: Option<Rc<dyn Fn(f32)>>,
31 },
32 ScrollXY {
33 on_scroll: Option<ScrollCallback>,
34 set_viewport_width: Option<Rc<dyn Fn(f32)>>,
35 set_viewport_height: Option<Rc<dyn Fn(f32)>>,
36 set_content_width: Option<Rc<dyn Fn(f32)>>,
37 set_content_height: Option<Rc<dyn Fn(f32)>>,
38 get_scroll_offset_xy: Option<Rc<dyn Fn() -> (f32, f32)>>,
39 set_scroll_offset_xy: Option<Rc<dyn Fn(f32, f32)>>,
40 },
41 Text {
42 text: String,
43 color: Color,
44 font_size: f32,
45 soft_wrap: bool,
46 max_lines: Option<usize>,
47 overflow: TextOverflow,
48 },
49 Button {
50 text: String,
51 on_click: Option<Callback>,
52 },
53 TextField {
54 state_key: ViewId,
55 hint: String,
56 on_change: Option<Rc<dyn Fn(String)>>,
57 on_submit: Option<Rc<dyn Fn(String)>>,
58 },
59 Checkbox {
60 checked: bool,
61 label: String,
62 on_change: Option<Rc<dyn Fn(bool)>>,
63 },
64 RadioButton {
65 selected: bool,
66 label: String,
67 on_select: Option<Callback>,
68 },
69 Switch {
70 checked: bool,
71 label: String,
72 on_change: Option<Rc<dyn Fn(bool)>>,
73 },
74 Slider {
75 value: f32,
76 min: f32,
77 max: f32,
78 step: Option<f32>,
79 label: String,
80 on_change: Option<CallbackF32>,
81 },
82 RangeSlider {
83 start: f32,
84 end: f32,
85 min: f32,
86 max: f32,
87 step: Option<f32>,
88 label: String,
89 on_change: Option<CallbackRange>,
90 },
91 ProgressBar {
92 value: f32,
93 min: f32,
94 max: f32,
95 label: String,
96 circular: bool,
97 },
98 Image {
99 handle: ImageHandle,
100 tint: Color, fit: ImageFit,
102 },
103 Ellipse {
104 rect: Rect,
105 color: Color,
106 },
107 EllipseBorder {
108 rect: Rect,
109 color: Color,
110 width: f32, },
112}
113
114impl std::fmt::Debug for ViewKind {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 match self {
117 ViewKind::Checkbox { checked, label, .. } => f
118 .debug_struct("Checkbox")
119 .field("checked", checked)
120 .field("label", label)
121 .finish(),
122 ViewKind::RadioButton {
123 selected, label, ..
124 } => f
125 .debug_struct("RadioButton")
126 .field("selected", selected)
127 .field("label", label)
128 .finish(),
129 ViewKind::Switch { checked, label, .. } => f
130 .debug_struct("Switch")
131 .field("checked", checked)
132 .field("label", label)
133 .finish(),
134 ViewKind::Surface => write!(f, "Surface"),
135 ViewKind::Box => write!(f, "Box"),
136 ViewKind::Row => write!(f, "Row"),
137 ViewKind::Column => write!(f, "Column"),
138 ViewKind::Stack => write!(f, "Stack"),
139 ViewKind::ScrollV { .. } => write!(f, "ScrollV"),
140 ViewKind::ScrollXY { .. } => write!(f, "ScrollXY"),
141 ViewKind::Text {
142 text,
143 color,
144 font_size,
145 soft_wrap,
146 max_lines,
147 overflow,
148 } => f
149 .debug_struct("Text")
150 .field("text", text)
151 .field("color", color)
152 .field("font_size", font_size)
153 .field("soft_wrap", soft_wrap)
154 .field("max_lines", max_lines)
155 .field("overflow", overflow)
156 .finish(),
157 ViewKind::Image { handle, tint, fit } => f
158 .debug_struct("Image")
159 .field("handle", handle)
160 .field("tint", tint)
161 .field("fit", fit)
162 .finish(),
163 ViewKind::Button { text, .. } => f
164 .debug_struct("Button")
165 .field("text", text)
166 .field("on_click", &"<callback>")
167 .finish(),
168 ViewKind::TextField {
169 state_key,
170 hint,
171 on_change,
172 on_submit,
173 } => f
174 .debug_struct("TextField")
175 .field("state_key", state_key)
176 .field("hint", hint)
177 .finish(),
178 ViewKind::Slider {
179 value,
180 min,
181 max,
182 step,
183 label,
184 ..
185 } => f
186 .debug_struct("Slider")
187 .field("value", value)
188 .field("min", min)
189 .field("max", max)
190 .field("step", step)
191 .field("label", label)
192 .finish(),
193 ViewKind::RangeSlider {
194 start,
195 end,
196 min,
197 max,
198 step,
199 label,
200 ..
201 } => f
202 .debug_struct("RangeSlider")
203 .field("start", start)
204 .field("end", end)
205 .field("min", min)
206 .field("max", max)
207 .field("step", step)
208 .field("label", label)
209 .finish(),
210 ViewKind::ProgressBar {
211 value,
212 min,
213 max,
214 label,
215 circular,
216 } => f
217 .debug_struct("ProgressBar")
218 .field("value", value)
219 .field("min", min)
220 .field("max", max)
221 .field("label", label)
222 .field("circular", circular)
223 .finish(),
224 ViewKind::Ellipse { rect, color } => f
225 .debug_struct("Ellipse")
226 .field("rect", rect)
227 .field("color", color)
228 .finish(),
229 ViewKind::EllipseBorder { rect, color, width } => f
230 .debug_struct("EllipseBorder")
231 .field("rect", rect)
232 .field("color", color)
233 .field("width", width)
234 .finish(),
235 }
236 }
237}
238
239#[derive(Clone, Debug)]
240pub struct View {
241 pub id: ViewId,
242 pub kind: ViewKind,
243 pub modifier: Modifier,
244 pub children: Vec<View>,
245 pub semantics: Option<crate::semantics::Semantics>,
246}
247
248impl View {
249 pub fn new(id: ViewId, kind: ViewKind) -> Self {
250 View {
251 id,
252 kind,
253 modifier: Modifier::default(),
254 children: vec![],
255 semantics: None,
256 }
257 }
258 pub fn modifier(mut self, m: Modifier) -> Self {
259 self.modifier = m;
260 self
261 }
262 pub fn with_children(mut self, kids: Vec<View>) -> Self {
263 self.children = kids;
264 self
265 }
266 pub fn semantics(mut self, s: crate::semantics::Semantics) -> Self {
267 self.semantics = Some(s);
268 self
269 }
270}
271
272#[derive(Clone, Debug, Default)]
274pub struct Scene {
275 pub clear_color: Color,
276 pub nodes: Vec<SceneNode>,
277}
278
279#[derive(Clone, Debug)]
280pub enum SceneNode {
281 Rect {
282 rect: Rect,
283 color: Color,
284 radius: f32,
285 },
286 Border {
287 rect: Rect,
288 color: Color,
289 width: f32,
290 radius: f32,
291 },
292 Text {
293 rect: Rect,
294 text: String,
295 color: Color,
296 size: f32,
297 },
298 Ellipse {
299 rect: Rect,
300 color: Color,
301 },
302 EllipseBorder {
303 rect: Rect,
304 color: Color,
305 width: f32, },
307 PushClip {
308 rect: Rect,
309 radius: f32,
310 },
311 PopClip,
312 PushTransform {
313 transform: Transform,
314 },
315 PopTransform,
316 Image {
317 rect: Rect,
318 handle: ImageHandle,
319 tint: Color,
320 fit: ImageFit,
321 },
322}
323
324pub type CallbackF32 = Rc<dyn Fn(f32)>;
325pub type CallbackRange = Rc<dyn Fn(f32, f32)>;
326
327#[derive(Clone, Copy, Debug, PartialEq, Eq)]
328pub enum TextOverflow {
329 Visible,
330 Clip,
331 Ellipsis,
332}