Skip to main content

vizia_core/
model.rs

1//! Models are used to store application data and can be bound to by views to visually display the data.
2
3use crate::prelude::*;
4use hashbrown::HashMap;
5use std::any::{Any, TypeId};
6
7/// A trait implemented by application data in order to respond to events and mutate state.
8///
9/// # Examples
10///
11/// ```
12/// # use vizia_core::prelude::*;
13/// #
14/// pub struct AppData {
15///     count: i32,
16/// }
17///
18/// enum AppEvent {
19///     Increment,
20///     Decrement,
21/// }
22///
23/// impl Model for AppData {
24///     fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
25///         event.map(|app_event, _| match app_event {
26///             AppEvent::Increment => {
27///                 self.count += 1;
28///             }
29///
30///             AppEvent::Decrement => {
31///                 self.count -= 1;
32///             }
33///         });
34///     }
35/// }
36/// ```
37pub trait Model: 'static + Sized {
38    /// Build the model data into the application tree.
39    ///
40    /// # Examples
41    ///
42    /// ```no_run
43    /// # use vizia_core::prelude::*;
44    /// # use vizia_winit::application::Application;
45    /// #
46    /// # #[derive(Default)]
47    /// # pub struct AppData {
48    /// #     count: i32,
49    /// # }
50    /// #
51    /// # impl Model for AppData {}
52    /// #
53    /// fn main() {
54    ///     Application::new(|cx|{
55    ///         AppData::default().build(cx);
56    ///     }).run();  
57    /// }
58    /// ```
59    fn build(self, cx: &mut Context) -> &Self {
60        let current = if cx.tree.is_ignored(cx.current) {
61            cx.tree.get_layout_parent(cx.current).unwrap()
62        } else {
63            cx.current
64        };
65
66        if let Some(models) = cx.models.get_mut(&current) {
67            models.insert(TypeId::of::<Self>(), Box::new(self));
68        } else {
69            let mut models: HashMap<TypeId, Box<dyn ModelData>> = HashMap::new();
70            models.insert(TypeId::of::<Self>(), Box::new(self));
71            cx.models.insert(current, models);
72        }
73
74        cx.models
75            .get(&current)
76            .unwrap()
77            .get(&TypeId::of::<Self>())
78            .unwrap()
79            .as_any_ref()
80            .downcast_ref::<Self>()
81            .unwrap()
82    }
83
84    /// Respond to events in order to mutate the model data.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// # use vizia_core::prelude::*;
90    ///
91    /// # use vizia_winit::application::Application;
92    /// #
93    /// # #[derive(Default)]
94    /// # pub struct AppData {
95    /// #     count: i32,
96    /// # }
97    /// #
98    /// # enum AppEvent {
99    /// #     Increment,
100    /// #     Decrement,
101    /// # }
102    /// #
103    /// impl Model for AppData {
104    ///     fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
105    ///         event.map(|app_event, _| match app_event {
106    ///             AppEvent::Increment => {
107    ///                 self.count += 1;
108    ///             }
109    ///
110    ///             AppEvent::Decrement => {
111    ///                 self.count -= 1;
112    ///             }
113    ///         });
114    ///     }
115    /// }
116    /// ```
117    #[allow(unused_variables)]
118    fn event(&mut self, cx: &mut EventContext, event: &mut Event) {}
119
120    /// Returns the name of the [Model] if it has one.
121    #[cfg(debug_assertions)]
122    fn name(&self) -> Option<&'static str> {
123        None
124    }
125}
126
127pub(crate) trait ModelData: Any {
128    #[allow(unused_variables)]
129    fn event(&mut self, cx: &mut EventContext, event: &mut Event) {}
130
131    fn as_any_ref(&self) -> &dyn Any;
132    #[cfg(debug_assertions)]
133    fn name(&self) -> Option<&'static str>;
134}
135
136impl dyn ModelData {
137    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
138        self.as_any_ref().downcast_ref()
139    }
140}
141
142impl<T: Model> ModelData for T {
143    fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
144        <T as Model>::event(self, cx, event);
145    }
146
147    fn as_any_ref(&self) -> &dyn Any {
148        self
149    }
150
151    #[cfg(debug_assertions)]
152    fn name(&self) -> Option<&'static str> {
153        <T as Model>::name(self)
154    }
155}
156
157impl Model for () {}