Skip to main content

repose_core/
view.rs

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