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(¤t) {
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(¤t)
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 () {}