vizia_core/binding/
mod.rs

1//! Data binding provides a way to link views to model data so that view properties update when data changes.
2//!
3//! # Example
4//! Fist we declare some data for our application. The [Lens] trait has been derived for the data, which allows us to bind to fields of the struct:
5//! ```
6//! # use vizia_core::prelude::*;
7//! # use vizia_derive::*;
8//! #[derive(Lens)]
9//! struct AppData {
10//!     count: i32,
11//! }
12//!
13//! ```
14//! Next we'll declare some events which will be sent by views to modify the data. Data binding in vizia is one-way, events are sent up the tree
15//! to the app data to mutate it and updated values are sent to observers, such as a [`Binding`] view.
16//! ```
17//! enum AppEvent {
18//!     Increment,
19//!     Decrement,
20//! }
21//! ```
22//! Then we implement the [`Model`](crate::model::Model) trait on our data, which allows us to modify the it in response to an [`Event`](crate::events::Event):
23//! ```
24//! # use vizia_core::prelude::*;
25//! # use vizia_derive::*;
26//! #[derive(Lens)]
27//! struct AppData {
28//!     count: i32,
29//! }
30//!
31//! enum AppEvent {
32//!     Increment,
33//!     Decrement,
34//! }
35//!
36//! impl Model for AppData {
37//!     fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
38//!         event.map(|app_event, _| match app_event {
39//!             AppEvent::Increment => {
40//!                 self.count += 1;
41//!             }
42//!
43//!             AppEvent::Decrement => {
44//!                 self.count -= 1;
45//!             }
46//!         });
47//!     }
48//! }
49//! ```
50//! This trait also allows data to be built into the application [Tree](crate::prelude::Tree):
51//! ```no_run
52//! # use vizia_core::prelude::*;
53//! # use vizia_derive::*;
54//! # use vizia_winit::application::Application;
55//! #[derive(Lens)]
56//! struct AppData {
57//!     count: i32,
58//! }
59//!
60//! impl Model for AppData {}
61//!
62//! fn main() {
63//!     Application::new(|cx|{
64//!         AppData {
65//!             count: 0,
66//!         }.build(cx);
67//!     }).run();  
68//! }
69//! ```
70//! A [`Binding`] view is one way in which data can be used by views. A [`Lens`] is used to determine what data the binding should react to:
71//! ```no_run
72//! # use vizia_core::prelude::*;
73//! # use vizia_derive::*;
74//! # use vizia_winit::application::Application;
75//! #[derive(Lens)]
76//! struct AppData {
77//!     count: i32,
78//! }
79//!
80//! impl Model for AppData {}
81//!
82//! fn main() {
83//!     Application::new(|cx|{
84//!         AppData {
85//!             count: 0,
86//!         }.build(cx);
87//!
88//!         Binding::new(cx, AppData::count, |cx, count|{
89//!             Label::new(cx, &count.get(cx).to_string());
90//!         });
91//!     }).run();
92//! }
93//! ```
94//! The second parameter to the [Binding] view is a [Lens], allowing us to bind to some field of the application data.
95//! The third parameter is a closure which provides the context and the lens, which can be used to retrieve the bound data using the `.get()`
96//! method, which takes the [Context](crate::prelude::Context) as an argument.
97//!
98//! Now when the data is modified, the binding will rebuild its contents and the label will update, for example:
99//! ```no_run
100//! # use vizia_core::prelude::*;
101//! # use vizia_derive::*;
102//! # use vizia_winit::application::Application;
103//! #[derive(Lens)]
104//! struct AppData {
105//!     count: i32,
106//! }
107//!
108//! impl Model for AppData {
109//!     fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
110//!         event.map(|app_event, _| match app_event {
111//!             AppEvent::Increment => {
112//!                 self.count += 1;
113//!             }
114//!
115//!             AppEvent::Decrement => {
116//!                 self.count -= 1;
117//!             }
118//!         });
119//!     }
120//! }
121//!
122//! enum AppEvent {
123//!     Increment,
124//!     Decrement,
125//! }
126//!
127//! fn main() {
128//!     Application::new(|cx|{
129//!         AppData {
130//!             count: 0,
131//!         }.build(cx);
132//!
133//!         Binding::new(cx, AppData::count, |cx, count|{
134//!             Label::new(cx, &count.get(cx).to_string());
135//!         });
136//!
137//!         Button::new(cx, |cx| cx.emit(AppEvent::Increment), |cx|{
138//!             Label::new(cx, "Increment")
139//!         });
140//!
141//!         Button::new(cx, |cx| cx.emit(AppEvent::Increment), |cx|{
142//!             Label::new(cx, "Decrement")
143//!         });
144//!     }).run();
145//! }
146//! ```
147//! Note, the checkbox does not need to be bound to the data to send an event to it. By default events will propagate up the tree.
148//!
149//! Completely rebuilding the `Label` when the data changes is unnecessary in this case. Instead we can update just the text of the label
150//! by binding the `text()` property modifier to the application data. This is called a property binding.
151//! ```no_run
152//! # use vizia_core::prelude::*;
153//! # use vizia_winit::application::Application;
154//!
155//! # #[derive(Lens)]
156//! # struct AppData {
157//! #     count: i32,
158//! # }
159//! # impl Model for AppData {
160//! #     fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
161//! #         event.map(|app_event, _| match app_event {
162//! #             AppEvent::Increment => {
163//! #                 self.count += 1;
164//! #             }
165//! #             AppEvent::Decrement => {
166//! #                 self.count -= 1;
167//! #             }
168//! #         });
169//! #     }
170//! # }
171//! # enum AppEvent {
172//! #     Increment,
173//! #     Decrement,
174//! # }
175//! fn main() {
176//!     Application::new(|cx|{
177//!         AppData {
178//!             count: 0,
179//!         }.build(cx);
180//!
181//!         Label::new(cx, AppData::count);
182//!
183//!         Button::new(cx, |cx|{
184//!             Label::new(cx, "Increment")
185//!         })
186//!         .on_press(|cx| cx.emit(AppEvent::Increment));
187//!
188//!         Button::new(cx, |cx|{
189//!             Label::new(cx, "Decrement")
190//!         })
191//!         .on_press(|cx| cx.emit(AppEvent::Increment));
192//!     }).run();
193//! }
194//! ```
195//!
196//! Note that even though the `count` value is `i32`, the label accepts a lens to this data because it implements `ToString` and is converted internally.
197//! If the data is the wrong type and cannot be converted internally, use the [`map()`](crate::binding::LensExt::map) method on the lens.
198mod lens;
199pub use lens::*;
200
201mod store;
202pub(crate) use store::*;
203
204mod binding_view;
205pub use binding_view::*;
206
207mod data;
208pub use data::*;
209
210mod res;
211pub use res::*;
212
213mod map;
214pub(crate) use map::MapId;