repose_core/
view.rs

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, // multiplicative (WHITE = no tint)
101        fit: ImageFit,
102    },
103}
104
105impl std::fmt::Debug for ViewKind {
106    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107        match self {
108            ViewKind::Checkbox { checked, label, .. } => f
109                .debug_struct("Checkbox")
110                .field("checked", checked)
111                .field("label", label)
112                .finish(),
113            ViewKind::RadioButton {
114                selected, label, ..
115            } => f
116                .debug_struct("RadioButton")
117                .field("selected", selected)
118                .field("label", label)
119                .finish(),
120            ViewKind::Switch { checked, label, .. } => f
121                .debug_struct("Switch")
122                .field("checked", checked)
123                .field("label", label)
124                .finish(),
125            ViewKind::Surface => write!(f, "Surface"),
126            ViewKind::Box => write!(f, "Box"),
127            ViewKind::Row => write!(f, "Row"),
128            ViewKind::Column => write!(f, "Column"),
129            ViewKind::Stack => write!(f, "Stack"),
130            ViewKind::ScrollV { .. } => write!(f, "ScrollV"),
131            ViewKind::ScrollXY { .. } => write!(f, "ScrollXY"),
132            ViewKind::Text {
133                text,
134                color,
135                font_size,
136                soft_wrap,
137                max_lines,
138                overflow,
139            } => f
140                .debug_struct("Text")
141                .field("text", text)
142                .field("color", color)
143                .field("font_size", font_size)
144                .field("soft_wrap", soft_wrap)
145                .field("max_lines", max_lines)
146                .field("overflow", overflow)
147                .finish(),
148            ViewKind::Image { handle, tint, fit } => f
149                .debug_struct("Image")
150                .field("handle", handle)
151                .field("tint", tint)
152                .field("fit", fit)
153                .finish(),
154            ViewKind::Button { text, .. } => f
155                .debug_struct("Button")
156                .field("text", text)
157                .field("on_click", &"<callback>")
158                .finish(),
159            ViewKind::TextField {
160                state_key,
161                hint,
162                on_change,
163                on_submit,
164            } => f
165                .debug_struct("TextField")
166                .field("state_key", state_key)
167                .field("hint", hint)
168                .finish(),
169            ViewKind::Slider {
170                value,
171                min,
172                max,
173                step,
174                label,
175                ..
176            } => f
177                .debug_struct("Slider")
178                .field("value", value)
179                .field("min", min)
180                .field("max", max)
181                .field("step", step)
182                .field("label", label)
183                .finish(),
184            ViewKind::RangeSlider {
185                start,
186                end,
187                min,
188                max,
189                step,
190                label,
191                ..
192            } => f
193                .debug_struct("RangeSlider")
194                .field("start", start)
195                .field("end", end)
196                .field("min", min)
197                .field("max", max)
198                .field("step", step)
199                .field("label", label)
200                .finish(),
201            ViewKind::ProgressBar {
202                value,
203                min,
204                max,
205                label,
206                circular,
207            } => f
208                .debug_struct("ProgressBar")
209                .field("value", value)
210                .field("min", min)
211                .field("max", max)
212                .field("label", label)
213                .field("circular", circular)
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/// Renderable scene
253#[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        color: Color,
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: String,
275        color: Color,
276        size: f32,
277    },
278    PushClip {
279        rect: Rect,
280        radius: f32,
281    },
282    PopClip,
283    PushTransform {
284        transform: Transform,
285    },
286    PopTransform,
287    Image {
288        rect: Rect,
289        handle: ImageHandle,
290        tint: Color,
291        fit: ImageFit,
292    },
293}
294
295pub type CallbackF32 = Rc<dyn Fn(f32)>;
296pub type CallbackRange = Rc<dyn Fn(f32, f32)>;
297
298#[derive(Clone, Copy, Debug, PartialEq, Eq)]
299pub enum TextOverflow {
300    Visible,
301    Clip,
302    Ellipsis,
303}