tuix_core/state/
mod.rs

1#![allow(dead_code)]
2
3pub mod entity;
4pub use entity::*;
5
6pub mod tree;
7pub use tree::*;
8
9pub mod storage;
10pub use storage::*;
11
12pub mod style;
13pub use style::*;
14
15pub mod data;
16pub use data::*;
17
18pub mod animation;
19pub use animation::*;
20
21pub mod mouse;
22pub use mouse::*;
23
24pub mod resource;
25pub use resource::*;
26
27
28pub use crate::events::{Builder, Event, Propagation, Widget, EventHandler};
29pub use crate::window_event::WindowEvent;
30
31use femtovg::FontId;
32
33use std::collections::VecDeque;
34
35use fnv::FnvHashMap;
36
37#[derive(Clone)]
38pub struct Fonts {
39    pub regular: Option<FontId>,
40    pub bold: Option<FontId>,
41    pub icons: Option<FontId>,
42    pub emoji: Option<FontId>,
43    pub arabic: Option<FontId>,
44}
45
46pub struct State {
47    // Creates and destroys entities
48    pub(crate) entity_manager: EntityManager, 
49    // The widget tree
50    pub tree: Tree,
51    // The style properties for every widget
52    pub style: Style,
53    // Computed data for every widget
54    pub data: CachedData,
55    // Mouse state
56    pub mouse: MouseState,
57    // Modifiers state
58    pub modifiers: ModifiersState,
59
60    // Hovered entity
61    pub hovered: Entity,
62    // Active entity
63    pub active: Entity,
64    // Captured entity
65    pub captured: Entity,
66    // Focused entity
67    pub focused: Entity,
68
69
70    pub(crate) callbacks: FnvHashMap<Entity, Box<dyn FnMut(&mut Box<dyn EventHandler>, &mut Self, Entity)>>,
71
72    // Map of widgets
73    pub event_handlers: FnvHashMap<Entity, Box<dyn EventHandler>>,
74
75    // List of removed entities
76    pub(crate) removed_entities: Vec<Entity>,
77
78    // Queue of events
79    pub event_queue: VecDeque<Event>,
80
81    pub fonts: Fonts, //TODO - Replace with resource manager
82
83    pub(crate) resource_manager: ResourceManager, //TODO
84
85    // Flag which signifies that a restyle is required
86    pub needs_restyle: bool,
87    pub needs_relayout: bool,
88    pub needs_redraw: bool,
89
90    pub listeners: FnvHashMap<Entity, Box<dyn Fn(&mut dyn EventHandler, &mut State, Entity, &mut Event)>>,
91}
92
93impl State {
94    pub fn new() -> Self {
95        let mut entity_manager = EntityManager::new();
96        let _root = entity_manager.create_entity();
97        let tree = Tree::new();
98        let mut style = Style::default();
99        let mut data = CachedData::default();
100        let mouse = MouseState::default();
101        let modifiers = ModifiersState::default();
102
103        let root = Entity::root();
104
105        data.add(root);
106        style.add(root);
107
108        style.clip_widget.set(root, root);
109
110        style.background_color.insert(root, Color::rgb(80, 80, 80)).expect("");
111
112        
113
114        State {
115            entity_manager,
116            tree,
117            style,
118            data,
119            mouse,
120            modifiers,
121            hovered: Entity::root(),
122            active: Entity::null(),
123            captured: Entity::null(),
124            focused: Entity::root(),
125            callbacks: FnvHashMap::default(),
126            event_handlers: FnvHashMap::default(),
127            event_queue: VecDeque::new(),
128            removed_entities: Vec::new(),
129            fonts: Fonts {
130                regular: None,
131                bold: None,
132                icons: None,
133                emoji: None,
134                arabic: None,
135            },
136            resource_manager: ResourceManager::new(),
137            needs_restyle: false,
138            needs_relayout: false,
139            needs_redraw: false,
140
141            listeners: FnvHashMap::default(),
142        }
143    }
144
145    pub(crate) fn build<'a, T>(&'a mut self, entity: Entity, event_handler: T) -> Builder<'a,T>
146    where
147        T: EventHandler + 'static,
148    {
149        self.event_handlers.insert(entity, Box::new(event_handler));
150
151        Builder::new(self, entity)
152    }
153
154    pub fn query<E: EventHandler>(&mut self, entity: Entity) -> Option<&mut E> {
155        if let Some(event_handler) = self.event_handlers.get_mut(&entity) {
156            event_handler.downcast::<E>()
157        } else {
158            None
159        }
160    }
161
162    /// Adds a stylesheet to the application
163    ///
164    /// This function adds the stylesheet path to the application allowing for hot reloading of syles
165    /// while the application is running.
166    ///
167    /// # Examples
168    ///
169    /// ```
170    /// state.add_stylesheet("path_to_stylesheet.css");
171    /// ```
172    pub fn add_stylesheet(&mut self, path: &str) -> Result<(), std::io::Error> {
173        let style_string = std::fs::read_to_string(path.clone())?;
174        self.resource_manager.stylesheets.push(path.to_owned());
175        self.style.parse_theme(&style_string);
176
177        Ok(())
178    }
179
180    pub fn add_theme(&mut self, theme: &str) {
181        self.resource_manager.themes.push(theme.to_owned());
182
183        self.reload_styles().expect("Failed to reload styles");
184    }
185
186    /// Adds a style rule to the application
187    ///
188    /// This function adds a style rule to the application allowing for multiple entites to share the same style properties based on the rule selector.
189    ///
190    /// # Examples
191    /// Adds a style rule which sets the flex-grow properties of all 'button' elements to 1.0:
192    /// ```
193    /// state.add_style_rule(StyleRule::new(Selector::element("button")).property(Property::FlexGrow(1.0)))
194    /// ```
195    pub fn add_style_rule(&mut self, style_rule: StyleRule) {
196        self.style.add_rule(style_rule);
197        self.insert_event(Event::new(WindowEvent::Restyle).target(Entity::root()));
198        self.insert_event(Event::new(WindowEvent::Relayout).target(Entity::root()));
199        self.insert_event(Event::new(WindowEvent::Redraw).target(Entity::root()));
200    }
201
202    //TODO
203    // pub fn add_image(&mut self, image: image::DynamicImage) -> Rc<()> {
204    //     self.resource_manager.add_image(image)
205    // }
206
207    //TODO
208    pub fn add_font(&mut self, _name: &str, _path: &str) {
209        println!("Add an font to resource manager");
210    }
211
212    // Removes all style data and then reloads the stylesheets
213    // TODO change the error type to allow for parsing errors
214    pub fn reload_styles(&mut self) -> Result<(), std::io::Error> {
215        if self.resource_manager.themes.is_empty() && self.resource_manager.stylesheets.is_empty() {
216            return Ok(());
217        }
218
219        self.style.remove_all();
220
221        let mut overall_theme = String::new();
222
223        // Reload the stored themes
224        for theme in self.resource_manager.themes.iter() {
225            //self.style.parse_theme(theme);
226            overall_theme += theme;
227        }
228
229        // Reload the stored stylesheets
230        for stylesheet in self.resource_manager.stylesheets.iter() {
231            let theme = std::fs::read_to_string(stylesheet)?;
232            overall_theme += &theme;
233        }
234
235        self.style.parse_theme(&overall_theme);
236
237        self.insert_event(Event::new(WindowEvent::Restyle).target(Entity::root()));
238        self.insert_event(Event::new(WindowEvent::Relayout).target(Entity::root()));
239        self.insert_event(Event::new(WindowEvent::Redraw).target(Entity::root()));
240
241        Ok(())
242    }
243
244    /// Insert a new event into the application event queue
245    ///
246    /// Inserts a new event into the application event queue that will be processed on the next event loop.
247    /// If the event unique flag is set to true, only the most recent event of the same type will exist in the queue.
248    ///
249    /// # Examples
250    /// ```
251    /// state.insert_event(Event::new(WindowEvent::WindowClose));
252    /// ```
253    pub fn insert_event(&mut self, event: Event) {
254        if event.unique {
255            self.event_queue.retain(|e| e != &event);
256        }
257
258        self.event_queue.push_back(event);
259    }
260
261    // This should probably be moved to state.mouse
262    pub fn capture(&mut self, entity: Entity) {
263        //println!("CAPTURE: {}", entity);
264        if entity != Entity::null() && self.captured != entity {
265            self.insert_event(
266                Event::new(WindowEvent::MouseCaptureEvent)
267                    .target(entity)
268                    .propagate(Propagation::Direct),
269            );
270        }
271
272        if self.captured != Entity::null() && self.captured != entity {
273            self.insert_event(
274                Event::new(WindowEvent::MouseCaptureOutEvent)
275                    .target(self.captured)
276                    .propagate(Propagation::Direct),
277            );
278        }
279
280        self.captured = entity;
281        self.active = entity;
282    }
283
284    // This should probably be moved to state.mouse
285    pub fn release(&mut self, id: Entity) {
286        
287        if self.captured == id {
288            self.insert_event(
289                Event::new(WindowEvent::MouseCaptureOutEvent)
290                    .target(self.captured)
291                    .propagate(Propagation::Direct),
292            );
293
294            //println!("RELEASE: {}", id);
295            
296            self.captured = Entity::null();
297            self.active = Entity::null();
298        }
299        
300    }
301
302    pub fn set_focus(&mut self, entity: Entity) {
303        if self.focused != entity {
304            if self.focused != Entity::null() {
305                self.focused.set_focus(self, false);
306                self.insert_event(Event::new(WindowEvent::FocusOut).target(self.focused));
307            }
308            
309            if entity != Entity::null() {
310                self.focused = entity;
311                entity.set_focus(self, true);
312                self.insert_event(Event::new(WindowEvent::FocusIn).target(self.focused));
313            }
314        }  
315    }
316
317    // Adds a new entity with a specified parent
318    pub(crate) fn add(&mut self, parent: Entity) -> Entity {
319        let entity = self
320            .entity_manager
321            .create_entity()
322            .expect("Failed to create entity");
323        self.tree.add(entity, parent).expect("");
324        self.data.add(entity);
325        self.style.add(entity);
326
327        self.insert_event(Event::new(WindowEvent::Restyle).target(Entity::root()));
328        self.insert_event(Event::new(WindowEvent::Relayout).target(Entity::root()));
329        self.insert_event(Event::new(WindowEvent::Redraw).target(Entity::root()));
330
331        entity
332    }
333
334    //  TODO
335    pub fn remove(&mut self, entity: Entity) {
336        // Collect all entities below the removed entity on the same branch of the tree
337        let delete_list = entity.branch_iter(&self.tree).collect::<Vec<_>>();
338
339        for entity in delete_list.iter().rev() {
340            self.tree.remove(*entity).expect("");
341            //self.tree.remove(*entity);
342            self.data.remove(*entity);
343            self.style.remove(*entity);
344            self.removed_entities.push(*entity);
345            self.entity_manager.destroy_entity(*entity);
346        }
347
348        self.insert_event(Event::new(WindowEvent::Restyle).target(Entity::root()));
349        self.insert_event(Event::new(WindowEvent::Relayout).target(Entity::root()));
350        self.insert_event(Event::new(WindowEvent::Redraw).target(Entity::root()));
351    }
352
353    // Run all pending animations
354    // TODO - This should probably be moved to style or an animation handling system
355    pub fn apply_animations(&mut self) -> bool {
356
357        let time = std::time::Instant::now();
358
359        self.style.background_color.animate(time);
360        
361        // Spacing
362        self.style.left.animate(time);
363        self.style.right.animate(time);
364        self.style.top.animate(time);
365        self.style.bottom.animate(time);
366
367        // Spacing Constraints
368        self.style.min_left.animate(time);
369        self.style.max_left.animate(time);
370        self.style.min_right.animate(time);
371        self.style.max_right.animate(time);
372        self.style.min_top.animate(time);
373        self.style.max_top.animate(time);
374        self.style.min_bottom.animate(time);
375        self.style.max_bottom.animate(time);
376
377        // Size
378        self.style.width.animate(time);
379        self.style.height.animate(time);
380
381        // Size Constraints
382        self.style.min_width.animate(time);
383        self.style.max_width.animate(time);
384        self.style.min_height.animate(time);
385        self.style.max_height.animate(time);
386
387        // Child Spacing
388        self.style.child_left.animate(time);
389        self.style.child_right.animate(time);
390        self.style.child_top.animate(time);
391        self.style.child_bottom.animate(time);
392        self.style.row_between.animate(time);
393        self.style.col_between.animate(time);
394
395        self.style.opacity.animate(time);
396        self.style.rotate.animate(time);
397
398        // Border Radius
399        self.style.border_radius_top_left.animate(time);
400        self.style.border_radius_top_right.animate(time);
401        self.style.border_radius_bottom_left.animate(time);
402        self.style.border_radius_bottom_right.animate(time);
403        
404        // Border
405        self.style.border_width.animate(time);
406        self.style.border_color.animate(time);
407
408        // Font
409        self.style.font_size.animate(time);
410        self.style.font_color.animate(time);
411        
412
413        self.style.background_color.has_animations()
414            || self.style.font_color.has_animations()
415            // Spacing
416            || self.style.left.has_animations()
417            || self.style.right.has_animations()
418            || self.style.top.has_animations()
419            || self.style.bottom.has_animations()
420            // Spacing Constraints
421            || self.style.min_left.has_animations()
422            || self.style.max_left.has_animations()
423            || self.style.min_right.has_animations()
424            || self.style.max_right.has_animations()
425            || self.style.min_top.has_animations()
426            || self.style.max_top.has_animations()
427            || self.style.min_bottom.has_animations()
428            || self.style.max_bottom.has_animations()
429            // Size
430            || self.style.width.has_animations()
431            || self.style.height.has_animations()
432            // Size Constraints
433            || self.style.min_width.has_animations()
434            || self.style.max_width.has_animations()
435            || self.style.min_height.has_animations()
436            || self.style.max_height.has_animations()
437            // Child Spacing
438            || self.style.child_left.has_animations()
439            || self.style.child_right.has_animations()
440            || self.style.child_top.has_animations()
441            || self.style.child_bottom.has_animations()
442            || self.style.row_between.has_animations()
443            || self.style.col_between.has_animations()
444            //
445            || self.style.opacity.has_animations()
446            || self.style.rotate.has_animations()
447            // Border Radius
448            || self.style.border_radius_top_left.has_animations()
449            || self.style.border_radius_top_right.has_animations()
450            || self.style.border_radius_bottom_left.has_animations()
451            || self.style.border_radius_bottom_right.has_animations()
452            // Border
453            || self.style.border_width.has_animations()
454            || self.style.border_color.has_animations()
455
456    }
457}