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;