makepad_widgets/
data_binding.rs1use 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 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 }
136 }
137 }
138}
139