1use crate::{Brush, Color, Modifier, Rect, Transform};
2use std::{rc::Rc, sync::Arc};
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 on_click: Option<Callback>,
51 },
52 TextField {
53 state_key: ViewId,
54 hint: String,
55 on_change: Option<Rc<dyn Fn(String)>>,
56 on_submit: Option<Rc<dyn Fn(String)>>,
57 },
58 Checkbox {
59 checked: bool,
60 on_change: Option<Rc<dyn Fn(bool)>>,
61 },
62 RadioButton {
63 selected: bool,
64 on_select: Option<Callback>,
65 },
66 Switch {
67 checked: bool,
68 on_change: Option<Rc<dyn Fn(bool)>>,
69 },
70 Slider {
71 value: f32,
72 min: f32,
73 max: f32,
74 step: Option<f32>,
75 on_change: Option<CallbackF32>,
76 },
77 RangeSlider {
78 start: f32,
79 end: f32,
80 min: f32,
81 max: f32,
82 step: Option<f32>,
83 on_change: Option<CallbackRange>,
84 },
85 ProgressBar {
86 value: f32,
87 min: f32,
88 max: f32,
89 circular: bool,
90 },
91 Image {
92 handle: ImageHandle,
93 tint: Color, fit: ImageFit,
95 },
96 Ellipse {
97 rect: Rect,
98 color: Color,
99 },
100 EllipseBorder {
101 rect: Rect,
102 color: Color,
103 width: f32, },
105}
106
107impl std::fmt::Debug for ViewKind {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109 match self {
110 ViewKind::Checkbox { checked, .. } => f
111 .debug_struct("Checkbox")
112 .field("checked", checked)
113 .finish(),
114 ViewKind::RadioButton { selected, .. } => f
115 .debug_struct("RadioButton")
116 .field("selected", selected)
117 .finish(),
118 ViewKind::Switch { checked, .. } => {
119 f.debug_struct("Switch").field("checked", checked).finish()
120 }
121 ViewKind::Surface => write!(f, "Surface"),
122 ViewKind::Box => write!(f, "Box"),
123 ViewKind::Row => write!(f, "Row"),
124 ViewKind::Column => write!(f, "Column"),
125 ViewKind::Stack => write!(f, "Stack"),
126 ViewKind::ScrollV { .. } => write!(f, "ScrollV"),
127 ViewKind::ScrollXY { .. } => write!(f, "ScrollXY"),
128 ViewKind::Text {
129 text,
130 color,
131 font_size,
132 soft_wrap,
133 max_lines,
134 overflow,
135 } => f
136 .debug_struct("Text")
137 .field("text", text)
138 .field("color", color)
139 .field("font_size", font_size)
140 .field("soft_wrap", soft_wrap)
141 .field("max_lines", max_lines)
142 .field("overflow", overflow)
143 .finish(),
144 ViewKind::Image { handle, tint, fit } => f
145 .debug_struct("Image")
146 .field("handle", handle)
147 .field("tint", tint)
148 .field("fit", fit)
149 .finish(),
150 ViewKind::Button { .. } => f
151 .debug_struct("Button")
152 .field("on_click", &"<callback>")
153 .finish(),
154 ViewKind::TextField {
155 state_key,
156 hint,
157 on_change,
158 on_submit,
159 } => f
160 .debug_struct("TextField")
161 .field("state_key", state_key)
162 .field("hint", hint)
163 .finish(),
164 ViewKind::Slider {
165 value,
166 min,
167 max,
168 step,
169 ..
170 } => f
171 .debug_struct("Slider")
172 .field("value", value)
173 .field("min", min)
174 .field("max", max)
175 .field("step", step)
176 .finish(),
177 ViewKind::RangeSlider {
178 start,
179 end,
180 min,
181 max,
182 step,
183 ..
184 } => f
185 .debug_struct("RangeSlider")
186 .field("start", start)
187 .field("end", end)
188 .field("min", min)
189 .field("max", max)
190 .field("step", step)
191 .finish(),
192 ViewKind::ProgressBar {
193 value,
194 min,
195 max,
196 circular,
197 } => f
198 .debug_struct("ProgressBar")
199 .field("value", value)
200 .field("min", min)
201 .field("max", max)
202 .field("circular", circular)
203 .finish(),
204 ViewKind::Ellipse { rect, color } => f
205 .debug_struct("Ellipse")
206 .field("rect", rect)
207 .field("color", color)
208 .finish(),
209 ViewKind::EllipseBorder { rect, color, width } => f
210 .debug_struct("EllipseBorder")
211 .field("rect", rect)
212 .field("color", color)
213 .field("width", width)
214 .finish(),
215 }
216 }
217}
218
219#[derive(Clone, Debug)]
220pub struct View {
221 pub id: ViewId,
222 pub kind: ViewKind,
223 pub modifier: Modifier,
224 pub children: Vec<View>,
225 pub semantics: Option<crate::semantics::Semantics>,
226}
227
228impl View {
229 pub fn new(id: ViewId, kind: ViewKind) -> Self {
230 View {
231 id,
232 kind,
233 modifier: Modifier::default(),
234 children: vec![],
235 semantics: None,
236 }
237 }
238 pub fn modifier(mut self, m: Modifier) -> Self {
239 self.modifier = m;
240 self
241 }
242 pub fn with_children(mut self, kids: Vec<View>) -> Self {
243 self.children = kids;
244 self
245 }
246 pub fn semantics(mut self, s: crate::semantics::Semantics) -> Self {
247 self.semantics = Some(s);
248 self
249 }
250}
251
252#[derive(Clone, Debug, Default)]
254pub struct Scene {
255 pub clear_color: Color,
256 pub nodes: Vec<SceneNode>,
257}
258
259#[derive(Clone, Debug)]
260pub enum SceneNode {
261 Rect {
262 rect: Rect,
263 brush: Brush,
264 radius: f32,
265 },
266 Border {
267 rect: Rect,
268 color: Color,
269 width: f32,
270 radius: f32,
271 },
272 Text {
273 rect: Rect,
274 text: Arc<str>,
275 color: Color,
276 size: f32,
277 },
278 Ellipse {
279 rect: Rect,
280 brush: Brush,
281 },
282 EllipseBorder {
283 rect: Rect,
284 color: Color,
285 width: f32, },
287 PushClip {
288 rect: Rect,
289 radius: f32,
290 },
291 PopClip,
292 PushTransform {
293 transform: Transform,
294 },
295 PopTransform,
296 Image {
297 rect: Rect,
298 handle: ImageHandle,
299 tint: Color,
300 fit: ImageFit,
301 },
302}
303
304pub type CallbackF32 = Rc<dyn Fn(f32)>;
305pub type CallbackRange = Rc<dyn Fn(f32, f32)>;
306
307#[derive(Clone, Copy, Debug, PartialEq, Eq)]
308pub enum TextOverflow {
309 Visible,
310 Clip,
311 Ellipsis,
312}