Skip to main content

repose_core/
view.rs

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