makepad_widgets/
data_binding.rs

1use crate::{
2    makepad_platform::*,
3    widget::*,
4};
5
6pub struct DataBindingStore {
7    pub nodes: Vec<LiveNode>,
8    mutated_by: Vec<WidgetUid>,
9}
10
11impl DataBindingStore {
12    pub fn new() -> Self {
13        let mut nodes = Vec::new();
14        nodes.open_object(LiveId(0));
15        nodes.close();
16        Self {
17            nodes,
18            mutated_by: Vec::new(),
19        }
20    }
21    
22    pub fn set_mutated_by(&mut self, uid: WidgetUid) {
23        if !self.mutated_by.contains(&uid) {
24            self.mutated_by.push(uid);
25        }
26    }
27}
28
29enum Direction {
30    DataToWidgets,
31    WidgetsToData
32}
33
34pub struct DataBindingMap<'a> {
35    pub store: &'a mut DataBindingStore,
36    pub debug_missing: bool,
37    pub cx: &'a mut Cx,
38    direction: Direction,
39    pub actions: &'a WidgetActions,
40    pub ui: &'a WidgetRef,
41}
42
43impl DataBindingStore {
44    pub fn data_to_widgets<'a>(&'a mut self, cx: &'a mut Cx, actions: &'a WidgetActions, ui: &'a WidgetRef) -> DataBindingMap {
45        DataBindingMap {
46            debug_missing: false,
47            direction: Direction::DataToWidgets,
48            store: self,
49            cx,
50            ui,
51            actions
52        }
53    }
54    
55    pub fn widgets_to_data<'a>(&'a mut self, cx: &'a mut Cx, actions: &'a WidgetActions, ui: &'a WidgetRef) -> DataBindingMap {
56        DataBindingMap {
57            debug_missing: false,
58            direction: Direction::WidgetsToData,
59            store: self,
60            cx,
61            ui,
62            actions
63        }
64    }
65}
66
67impl<'a> DataBindingMap<'a> {
68    pub fn with_debug_missing(mut self) -> Self {
69        self.debug_missing = true;
70        self
71    }
72    
73    pub fn is_data_to_widgets(&self) -> bool {
74        if let Direction::DataToWidgets = self.direction {true}else {false}
75    }
76    
77    pub fn is_widgets_to_data(&self) -> bool {
78        if let Direction::WidgetsToData = self.direction {true}else {false}
79    }
80    
81    pub fn bind(&mut self, data_id: &[LiveId], widgets: &[&[LiveId]]) {
82        // alright so. we have a direction.
83        if self.is_data_to_widgets() {
84            let mut any_found = false;
85            for widget in self.ui.widgets(widgets).iter() {
86                any_found = true;
87                let uid = widget.widget_uid();
88                if !self.store.mutated_by.contains(&uid) {
89                    widget.data_to_widget(self.cx, &self.store.nodes, data_id);
90                }
91            }
92            if !any_found && self.debug_missing {
93                log!("No widgets found for databinding {:?}", widgets);
94            }
95        }
96        else {
97            if self.actions.len() == 0 {
98                return
99            }
100            for widget in self.ui.widgets(widgets).iter() {
101                if widget.widget_to_data(self.cx, self.actions, &mut self.store.nodes, data_id) {
102                    self.store.set_mutated_by(widget.widget_uid());
103                }
104            }
105        }
106    }
107    
108    pub fn apply<F>(&mut self, data: &[LiveId], widget_val: &[&[LiveId]; 2], map: F)
109    where F: FnOnce(LiveValue) -> LiveValue {
110        if self.is_data_to_widgets() {
111            if let Some(v) = self.store.nodes.read_field_value(data) {
112                let mut ui_nodes = LiveNodeVec::new();
113                ui_nodes.write_field_value(widget_val[1], map(v.clone()));
114                let widgets = self.ui.widgets(&[widget_val[0]]);
115                for widget in widgets.iter(){
116                    widget.apply_over(self.cx, &ui_nodes)
117                }
118                /*else if self.debug_missing {
119                    log!("Databinding apply cannot find widget {:?}", widget_val[0]);
120                }*/
121            }
122        }
123    }
124}
125