1use zng_layout::unit::PxSize;
2use zng_var::Var;
3
4use crate::{
5 update::{EventUpdate, WidgetUpdates},
6 widget::{
7 WIDGET, WidgetHandlesCtx,
8 node::{IntoUiNode, UiNodeImpl},
9 },
10};
11
12use super::{UiNode, UiNodeListObserver};
13
14pub struct WhenUiNodeBuilder {
20 default: UiNode,
21 conditions: Vec<(Var<bool>, UiNode)>,
22}
23impl WhenUiNodeBuilder {
24 pub fn new(default: impl IntoUiNode) -> Self {
26 Self {
27 default: default.into_node(),
28 conditions: vec![],
29 }
30 }
31
32 pub fn push(&mut self, condition: Var<bool>, node: impl IntoUiNode) {
36 self.conditions.push((condition, node.into_node()));
37 }
38
39 pub fn build(self) -> UiNode {
41 UiNode::new(WhenUiNode {
42 default: self.default,
43 conditions: self.conditions,
44 current: usize::MAX,
45 wgt_handles: WidgetHandlesCtx::new(),
46 })
47 }
48}
49
50struct WhenUiNode {
51 default: UiNode,
52 conditions: Vec<(Var<bool>, UiNode)>,
53 current: usize,
54 wgt_handles: WidgetHandlesCtx,
55}
56impl WhenUiNode {
57 fn child_mut_with_handles(&mut self) -> (&mut UiNode, &mut WidgetHandlesCtx) {
58 let child = if self.current == usize::MAX {
59 &mut self.default
60 } else {
61 &mut self.conditions[self.current].1
62 };
63 (child, &mut self.wgt_handles)
64 }
65
66 fn child_ref(&self) -> &UiNode {
67 if self.current == usize::MAX {
68 &self.default
69 } else {
70 &self.conditions[self.current].1
71 }
72 }
73
74 fn change_child(&mut self, new: usize) {
75 {
76 let (child, wgt_handles) = self.child_mut_with_handles();
77 WIDGET.with_handles(wgt_handles, || child.deinit());
78 wgt_handles.clear();
79 }
80
81 self.current = new;
82
83 {
84 let (child, wgt_handles) = self.child_mut_with_handles();
85 WIDGET.with_handles(wgt_handles, || child.init());
86 }
87
88 WIDGET.update_info().layout().render();
89 }
90
91 fn with<R>(&mut self, f: impl FnOnce(&mut UiNode) -> R) -> R {
92 let (child, wgt_handles) = self.child_mut_with_handles();
93 WIDGET.with_handles(wgt_handles, || f(child))
94 }
95
96 fn update_when(&mut self) -> bool {
97 let mut any = false;
98 for (i, (c, _)) in self.conditions.iter().enumerate() {
99 if i < self.current {
100 if c.get() {
101 self.change_child(i);
103 return true;
104 }
105 } else if i == self.current {
106 if c.get() {
107 any = true;
109 break;
110 }
111 } else if c.get() {
112 self.change_child(i);
114 return true;
115 }
116 }
117
118 if !any && self.current != usize::MAX {
119 self.change_child(usize::MAX);
121 return true;
122 }
123 false
124 }
125}
126impl UiNodeImpl for WhenUiNode {
127 fn children_len(&self) -> usize {
128 self.child_ref().0.children_len()
129 }
130
131 fn with_child(&mut self, index: usize, visitor: &mut dyn FnMut(&mut UiNode)) {
132 self.child_mut_with_handles().0.0.with_child(index, visitor);
133 }
134
135 fn init(&mut self) {
136 self.current = usize::MAX;
137 for (i, (c, _)) in self.conditions.iter().enumerate() {
138 if self.current == usize::MAX && c.get() {
139 self.current = i;
140 }
141 WIDGET.sub_var(c);
142 }
143 self.with(|c| c.0.init());
144 }
145
146 fn deinit(&mut self) {
147 self.with(|c| c.0.deinit());
148 self.wgt_handles.clear();
149 }
150
151 fn info(&mut self, info: &mut crate::widget::info::WidgetInfoBuilder) {
152 self.with(|c| c.0.info(info));
153 }
154
155 fn event(&mut self, update: &EventUpdate) {
156 self.with(|c| c.0.event(update));
157 }
158
159 fn update(&mut self, updates: &WidgetUpdates) {
160 if !self.update_when() {
161 self.with(|c| c.0.update(updates));
164 }
165 }
166 fn update_list(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
167 if self.update_when() {
168 observer.reset();
169 } else {
170 self.with(|c| c.0.update_list(updates, observer));
171 }
172 }
173
174 fn measure(&mut self, wm: &mut crate::widget::info::WidgetMeasure) -> PxSize {
175 self.with(|c| c.0.measure(wm))
176 }
177
178 fn layout(&mut self, wl: &mut crate::widget::info::WidgetLayout) -> PxSize {
179 self.with(|c| c.0.layout(wl))
180 }
181
182 fn render(&mut self, frame: &mut crate::render::FrameBuilder) {
183 self.with(|c| c.0.render(frame))
184 }
185
186 fn render_update(&mut self, update: &mut crate::render::FrameUpdate) {
187 self.with(|c| c.0.render_update(update))
188 }
189
190 fn is_list(&self) -> bool {
191 self.child_ref().0.is_list()
192 }
193
194 fn for_each_child(&mut self, visitor: &mut dyn FnMut(usize, &mut UiNode)) {
195 self.child_mut_with_handles().0.0.for_each_child(visitor);
196 }
197
198 fn try_for_each_child(
199 &mut self,
200 visitor: &mut dyn FnMut(usize, &mut UiNode) -> std::ops::ControlFlow<zng_var::BoxAnyVarValue>,
201 ) -> std::ops::ControlFlow<zng_var::BoxAnyVarValue> {
202 self.child_mut_with_handles().0.0.try_for_each_child(visitor)
203 }
204
205 fn par_each_child(&mut self, visitor: &(dyn Fn(usize, &mut UiNode) + Sync)) {
206 self.child_mut_with_handles().0.0.par_each_child(visitor);
207 }
208
209 fn par_fold_reduce(
210 &mut self,
211 identity: zng_var::BoxAnyVarValue,
212 fold: &(dyn Fn(zng_var::BoxAnyVarValue, usize, &mut UiNode) -> zng_var::BoxAnyVarValue + Sync),
213 reduce: &(dyn Fn(zng_var::BoxAnyVarValue, zng_var::BoxAnyVarValue) -> zng_var::BoxAnyVarValue + Sync),
214 ) -> zng_var::BoxAnyVarValue {
215 self.child_mut_with_handles().0.0.par_fold_reduce(identity, fold, reduce)
216 }
217
218 fn measure_list(
219 &mut self,
220 wm: &mut crate::widget::info::WidgetMeasure,
221 measure: &(dyn Fn(usize, &mut UiNode, &mut crate::widget::info::WidgetMeasure) -> PxSize + Sync),
222 fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
223 ) -> PxSize {
224 self.with(|c| c.0.measure_list(wm, measure, fold_size))
225 }
226
227 fn layout_list(
228 &mut self,
229 wl: &mut crate::widget::info::WidgetLayout,
230 layout: &(dyn Fn(usize, &mut UiNode, &mut crate::widget::info::WidgetLayout) -> PxSize + Sync),
231 fold_size: &(dyn Fn(PxSize, PxSize) -> PxSize + Sync),
232 ) -> PxSize {
233 self.with(|c| c.0.layout_list(wl, layout, fold_size))
234 }
235
236 fn render_list(
237 &mut self,
238 frame: &mut crate::render::FrameBuilder,
239 render: &(dyn Fn(usize, &mut UiNode, &mut crate::render::FrameBuilder) + Sync),
240 ) {
241 self.with(|c| c.0.render_list(frame, render))
242 }
243
244 fn render_update_list(
245 &mut self,
246 update: &mut crate::render::FrameUpdate,
247 render_update: &(dyn Fn(usize, &mut UiNode, &mut crate::render::FrameUpdate) + Sync),
248 ) {
249 self.with(|c| c.0.render_update_list(update, render_update))
250 }
251
252 fn as_widget(&mut self) -> Option<&mut dyn super::WidgetUiNodeImpl> {
253 self.child_mut_with_handles().0.0.as_widget()
254 }
255}