Skip to main content

repose_core/
view.rs

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        /// Set by the component (e.g. OutlinedTextField) to receive focus-change
70        /// signals from the layout/paint phase.
71        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, // multiplicative (WHITE = no tint)
97        fit: ImageFit,
98    },
99    Ellipse {
100        rect: Rect,
101        color: Color,
102    },
103    EllipseBorder {
104        rect: Rect,
105        color: Color,
106        width: f32, // screen-space width (px)
107    },
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    /// Mark this view as disabled - ignores pointer events.
158    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/// Renderable scene
173#[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, // screen-space width (px)
207    },
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 behind a rounded rect, typically driven by `StateElevation`.
224    /// The `elevation` field controls offset and alpha.
225    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}