makepad_widgets/
data_binding.rs

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