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::{events::ViewHandler, 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, Lens)]
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) {
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
75 /// Respond to events in order to mutate the model data.
76 ///
77 /// # Examples
78 ///
79 /// ```
80 /// # use vizia_core::prelude::*;
81 /// # use vizia_derive::*;
82 /// # use vizia_winit::application::Application;
83 /// #
84 /// # #[derive(Default, Lens)]
85 /// # pub struct AppData {
86 /// # count: i32,
87 /// # }
88 /// #
89 /// # enum AppEvent {
90 /// # Increment,
91 /// # Decrement,
92 /// # }
93 /// #
94 /// impl Model for AppData {
95 /// fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
96 /// event.map(|app_event, _| match app_event {
97 /// AppEvent::Increment => {
98 /// self.count += 1;
99 /// }
100 ///
101 /// AppEvent::Decrement => {
102 /// self.count -= 1;
103 /// }
104 /// });
105 /// }
106 /// }
107 /// ```
108 #[allow(unused_variables)]
109 fn event(&mut self, cx: &mut EventContext, event: &mut Event) {}
110
111 /// Returns the name of the [Model] if it has one.
112 #[cfg(debug_assertions)]
113 fn name(&self) -> Option<&'static str> {
114 None
115 }
116}
117
118pub(crate) trait ModelData: Any {
119 #[allow(unused_variables)]
120 fn event(&mut self, cx: &mut EventContext, event: &mut Event) {}
121
122 fn as_any_ref(&self) -> &dyn Any;
123 #[cfg(debug_assertions)]
124 fn name(&self) -> Option<&'static str>;
125}
126
127impl dyn ModelData {
128 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
129 self.as_any_ref().downcast_ref()
130 }
131}
132
133impl<T: Model> ModelData for T {
134 fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
135 <T as Model>::event(self, cx, event);
136 }
137
138 fn as_any_ref(&self) -> &dyn Any {
139 self
140 }
141
142 #[cfg(debug_assertions)]
143 fn name(&self) -> Option<&'static str> {
144 <T as Model>::name(self)
145 }
146}
147
148impl Model for () {}
149
150#[derive(Copy, Clone)]
151pub(crate) enum ModelOrView<'a> {
152 Model(&'a dyn ModelData),
153 View(&'a dyn ViewHandler),
154}
155
156impl<'a> ModelOrView<'a> {
157 pub fn downcast_ref<T: 'static>(self) -> Option<&'a T> {
158 match self {
159 ModelOrView::Model(m) => m.downcast_ref(),
160 ModelOrView::View(v) => v.downcast_ref(),
161 }
162 }
163}