pierro/core/ui/
mod.rs

1
2pub mod layout;
3use std::any::Any;
4
5pub use layout::*;
6
7pub mod memory;
8pub use memory::*;
9
10pub mod style;
11use style::*;
12
13pub mod input;
14pub use input::*;
15
16mod paint;
17
18mod tree;
19pub use tree::*;
20
21mod cursor;
22pub use cursor::*;
23
24mod clipboard;
25
26use crate::{Color, Rect, Vec2};
27
28use super::{text::FontId, Margin, Painter, PerAxis, RenderResources, Stroke, TSTransform};
29
30pub struct UI<'a, 'b> {
31    input: &'a Input,
32    memory: &'a mut Memory,
33    style: Style,
34
35    render_resources: &'a mut RenderResources<'b>,
36    clipboard: Option<&'a mut arboard::Clipboard>,
37
38    window_size: Vec2,
39
40    // tree-building
41    tree: UITree,
42    parent_stack: Vec<UIRef>,
43    curr_sibling: UIRef,
44
45    // communication
46    pub(crate) request_redraw: bool,
47    pub(crate) cursor: CursorIcon,
48    pub(crate) request_ime: Option<UIRef>
49}
50
51impl<'a, 'b> UI<'a, 'b> {
52
53    pub(crate) fn new(input: &'a Input, memory: &'a mut Memory, render_resources: &'a mut RenderResources<'b>, clipboard: Option<&'a mut arboard::Clipboard>, window_size: Vec2, tree: UITree, layer: UIRef) -> Self {
54        Self {
55            input,
56            memory,
57            style: Style::new(),
58            render_resources,
59            clipboard,
60            window_size,
61            tree,
62            parent_stack: vec![layer],
63            curr_sibling: UIRef::Null,
64            request_redraw: false,
65            cursor: CursorIcon::default(),
66            request_ime: None
67        }
68    }
69
70    pub(crate) fn tree(self) -> UITree {
71        self.tree
72    }
73
74    pub fn curr_parent(&self) -> UIRef {
75        let Some(parent) = self.parent_stack.last() else { panic!("no parents in parent stack. ui in an invalid state.") };
76        *parent
77    }
78
79    pub fn node(&mut self, params: UINodeParams) -> Response {
80        let parent_ref = self.curr_parent();
81        let parent = self.tree.get(parent_ref);
82
83        let mut new_node = UINode::new(parent.id, parent.n_children, params);
84        new_node.prev = self.curr_sibling;
85        new_node.parent = parent_ref;
86
87        let new_node = self.tree.add_node(new_node);
88
89        match self.curr_sibling {
90            UIRef::Null => {
91                self.tree.get_mut(parent_ref).first_child = new_node;
92            },
93            UIRef::Some(_) => {
94                self.tree.get_mut(self.curr_sibling).next = new_node;
95            },
96        }
97
98        self.curr_sibling = new_node;
99        self.tree.get_mut(parent_ref).last_child = new_node;
100        self.tree.get_mut(parent_ref).n_children += 1; 
101
102        let id = self.tree.get(new_node).id;
103        let interaction = self.memory.get::<Interaction>(id);
104        
105        Response {
106            id,
107            node_ref: new_node,
108            hovered: interaction.hovered,
109            through_hovered: interaction.through_hovered,
110            l_mouse: interaction.l_mouse,
111            r_mouse: interaction.r_mouse,
112            scroll: interaction.scroll
113        }
114    }
115
116    pub(crate) fn push_parent(&mut self, parent: UIRef) {
117        self.parent_stack.push(parent);
118        self.curr_sibling = self.tree.get(parent).last_child;
119    }
120
121    pub(crate) fn pop_parent(&mut self) {
122        self.parent_stack.pop();
123        if self.parent_stack.is_empty() {
124            panic!("ui parent stack underflow!");
125        }
126        self.curr_sibling = self.tree.get(self.curr_parent()).last_child;
127    }
128
129    pub fn with_parent<R, F: FnOnce(&mut Self) -> R>(&mut self, parent: UIRef, body: F) -> R {
130        self.push_parent(parent);
131        let body_result = body(self);
132        self.pop_parent();
133        body_result
134    }
135
136    pub fn with_node<R, F: FnOnce(&mut UI) -> R>(&mut self, params: UINodeParams, body: F) -> (Response, R) {
137        let resp = self.node(params);
138        (resp, self.with_parent(resp.node_ref, body))
139    }
140
141    pub fn layer<R, F: FnOnce(&mut Self) -> R>(&mut self, body: F) -> (UIRef, R) {
142        let layer = self.tree.add_layer(self.window_size);
143        (layer, self.with_parent(layer, body))
144    }
145
146    pub fn get_parent_ref(&self, node: UIRef) -> UIRef {
147        self.tree.get(node).parent
148    } 
149
150    pub fn get_parent_id(&self, node: UIRef) -> Id {
151        let parent_ref = self.get_parent_ref(node);
152        self.tree.get(parent_ref).id
153    }
154
155    pub fn input(&self) -> &Input {
156        &self.input
157    }
158
159    pub fn window_size(&self) -> Vec2 {
160        self.window_size
161    }
162
163    pub fn memory(&mut self) -> &mut Memory {
164        &mut self.memory
165    }
166
167    pub fn style<T: Default + Any>(&mut self) -> &T {
168        self.style.get()
169    }
170
171    pub fn with_style<T: Default + Any, F: FnOnce(&mut Self)>(&mut self, style: T, body: F) {
172        self.style.push(style);
173        body(self);
174        self.style.pop();
175    }
176
177    pub fn set_size(&mut self, node: UIRef, width: Size, height: Size) {
178        self.tree.get_mut(node).params.size = PerAxis::new(width, height);
179    }
180    
181    pub fn set_margin(&mut self, node: UIRef, margin: Margin) {
182        self.tree.get_mut(node).params.margin = margin; 
183    }
184
185    pub fn set_fill(&mut self, node: UIRef, fill: Color) {
186        self.tree.get_mut(node).params.fill = fill;
187    }
188
189    pub fn set_stroke(&mut self, node: UIRef, stroke: Stroke) {
190        self.tree.get_mut(node).params.stroke = stroke;
191    }
192
193    pub fn set_transform(&mut self, node: UIRef, transform: TSTransform) {
194        self.tree.get_mut(node).params.transform = transform;
195    }
196
197    pub fn set_text<S: Into<String>>(&mut self, node: UIRef, text: S) {
198        self.tree.get_mut(node).params.text = Some(text.into());
199    }
200
201    pub fn set_sense_mouse(&mut self, node: UIRef, mouse: bool) {
202        self.tree.get_mut(node).params.mouse = mouse;
203    }
204    
205    pub fn set_on_paint<F: FnOnce(&mut Painter, Rect) + 'static>(&mut self, node: UIRef, on_paint: F) {
206        self.tree.get_mut(node).params.on_paint = Some(Box::new(on_paint));
207    }
208
209    pub fn request_redraw(&mut self) {
210        self.request_redraw = true;
211    }
212
213    pub fn set_cursor(&mut self, cursor: CursorIcon) {
214        self.cursor = cursor;
215    }
216
217    pub fn request_ime(&mut self, node: UIRef) {
218        self.request_ime = Some(node);
219    }
220
221    /// Get the WebGPU render device
222    pub fn wgpu_device(&mut self) -> &wgpu::Device {
223        &self.render_resources.device
224    } 
225
226    /// Get the WebGPU render queue
227    pub fn wgpu_queue(&mut self) -> &wgpu::Queue {
228        &self.render_resources.queue
229    }
230
231    /// Get the COSMIC Text font system
232    pub fn font_system(&mut self, font_id: FontId) -> Option<&mut cosmic_text::FontSystem> {
233        let font = self.render_resources.text_resources.fonts.get_mut(&font_id)?;
234        Some(&mut font.font_system)
235    }
236
237    pub fn text_font(&self) -> FontId {
238        self.render_resources.text_resources.text_font
239    }
240    
241    pub fn icon_font(&self) -> FontId {
242        self.render_resources.text_resources.icon_font
243    }
244
245}