1use crate::{Brush, Color, Modifier, Rect, TextSpan, Transform};
2use std::{cell::Cell, 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 struct OverlayEntry {
20 pub id: u64,
21 pub view: Box<View>,
22}
23
24#[derive(Clone)]
25pub enum ViewKind {
26 Surface,
27 Box,
28 Row,
29 Column,
30 Stack,
31 OverlayHost,
32 ScrollV {
33 on_scroll: Option<ScrollCallback>,
34 set_viewport_height: Option<Rc<dyn Fn(f32)>>,
35 set_content_height: Option<Rc<dyn Fn(f32)>>,
36 get_scroll_offset: Option<Rc<dyn Fn() -> f32>>,
37 set_scroll_offset: Option<Rc<dyn Fn(f32)>>,
38 show_scrollbar: bool,
39 },
40 ScrollXY {
41 on_scroll: Option<ScrollCallback>,
42 set_viewport_width: Option<Rc<dyn Fn(f32)>>,
43 set_viewport_height: Option<Rc<dyn Fn(f32)>>,
44 set_content_width: Option<Rc<dyn Fn(f32)>>,
45 set_content_height: Option<Rc<dyn Fn(f32)>>,
46 get_scroll_offset_xy: Option<Rc<dyn Fn() -> (f32, f32)>>,
47 set_scroll_offset_xy: Option<Rc<dyn Fn(f32, f32)>>,
48 show_scrollbar: bool,
49 },
50 Text {
51 text: String,
52 color: Color,
53 font_size: f32,
54 soft_wrap: bool,
55 max_lines: Option<usize>,
56 overflow: TextOverflow,
57 font_family: Option<&'static str>,
58 annotations: Option<Arc<[TextSpan]>>,
59 },
60 Button {
61 on_click: Option<Callback>,
62 },
63 TextField {
64 state_key: ViewId,
65 hint: String,
66 multiline: bool,
67 on_change: Option<Rc<dyn Fn(String)>>,
68 on_submit: Option<Rc<dyn Fn(String)>>,
69 focus_tracker: Option<Rc<Cell<bool>>>,
72 },
73 Slider {
74 value: f32,
75 min: f32,
76 max: f32,
77 step: Option<f32>,
78 on_change: Option<CallbackF32>,
79 },
80 RangeSlider {
81 start: f32,
82 end: f32,
83 min: f32,
84 max: f32,
85 step: Option<f32>,
86 on_change: Option<CallbackRange>,
87 },
88 ProgressBar {
89 value: f32,
90 min: f32,
91 max: f32,
92 circular: bool,
93 },
94 Image {
95 handle: ImageHandle,
96 tint: Color, fit: ImageFit,
98 },
99 Ellipse {
100 rect: Rect,
101 color: Color,
102 },
103 EllipseBorder {
104 rect: Rect,
105 color: Color,
106 width: f32, },
108}
109
110impl std::fmt::Debug for ViewKind {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 match self {
113 Self::Surface => f.write_str("Surface"),
114 Self::Box => f.write_str("Box"),
115 Self::Row => f.write_str("Row"),
116 Self::Column => f.write_str("Column"),
117 Self::Stack => f.write_str("Stack"),
118 Self::OverlayHost => f.write_str("OverlayHost"),
119 Self::ScrollV { .. } => f.write_str("ScrollV"),
120 Self::ScrollXY { .. } => f.write_str("ScrollXY"),
121 Self::Button { .. } => f.write_str("Button"),
122 Self::Image { .. } => f.write_str("Image"),
123 Self::Ellipse { .. } => f.write_str("Ellipse"),
124 Self::EllipseBorder { .. } => f.write_str("EllipseBorder"),
125 Self::Text { text, .. } => write!(f, "Text({:?})", text),
126 Self::TextField { hint, .. } => write!(f, "TextField({:?})", hint),
127 Self::Slider { value, .. } => write!(f, "Slider({})", value),
128 Self::RangeSlider { start, end, .. } => write!(f, "Range({}..{})", start, end),
129 Self::ProgressBar { value, .. } => write!(f, "Progress({})", value),
130 }
131 }
132}
133
134#[derive(Clone, Debug)]
135pub struct View {
136 pub id: ViewId,
137 pub kind: ViewKind,
138 pub modifier: Modifier,
139 pub children: Vec<View>,
140 pub semantics: Option<crate::semantics::Semantics>,
141}
142
143impl View {
144 pub fn new(id: ViewId, kind: ViewKind) -> Self {
145 View {
146 id,
147 kind,
148 modifier: Modifier::default(),
149 children: vec![],
150 semantics: None,
151 }
152 }
153 pub fn modifier(mut self, m: Modifier) -> Self {
154 self.modifier = m;
155 self
156 }
157 pub fn disabled(mut self) -> Self {
159 self.modifier.disabled = true;
160 self
161 }
162 pub fn with_children(mut self, kids: Vec<View>) -> Self {
163 self.children = kids;
164 self
165 }
166 pub fn semantics(mut self, s: crate::semantics::Semantics) -> Self {
167 self.semantics = Some(s);
168 self
169 }
170}
171
172#[derive(Clone, Debug, Default)]
174pub struct Scene {
175 pub clear_color: Color,
176 pub nodes: Vec<SceneNode>,
177}
178
179#[derive(Clone, Debug)]
180pub enum SceneNode {
181 Rect {
182 rect: Rect,
183 brush: Brush,
184 radius: f32,
185 },
186 Border {
187 rect: Rect,
188 color: Color,
189 width: f32,
190 radius: f32,
191 },
192 Text {
193 rect: Rect,
194 text: Arc<str>,
195 color: Color,
196 size: f32,
197 font_family: Option<&'static str>,
198 },
199 Ellipse {
200 rect: Rect,
201 brush: Brush,
202 },
203 EllipseBorder {
204 rect: Rect,
205 color: Color,
206 width: f32, },
208 PushClip {
209 rect: Rect,
210 radius: f32,
211 },
212 PopClip,
213 PushTransform {
214 transform: Transform,
215 },
216 PopTransform,
217 Image {
218 rect: Rect,
219 handle: ImageHandle,
220 tint: Color,
221 fit: ImageFit,
222 },
223 Shadow {
226 rect: Rect,
227 radius: f32,
228 elevation: f32,
229 color: Color,
230 },
231}
232
233pub type CallbackF32 = Rc<dyn Fn(f32)>;
234pub type CallbackRange = Rc<dyn Fn(f32, f32)>;
235
236#[derive(Clone, Copy, Debug, PartialEq, Eq)]
237pub enum TextOverflow {
238 Visible,
239 Clip,
240 Ellipsis,
241}