1use zng_layout::unit::PxSize;
2use zng_var::{BoxedVar, Var};
3
4use crate::{
5 update::{EventUpdate, WidgetUpdates},
6 widget::{WIDGET, WidgetHandlesCtx},
7};
8
9use super::{BoxedUiNode, BoxedUiNodeList, UiNode, UiNodeList, UiNodeListObserver};
10
11pub struct WhenUiNodeBuilder {
15 default: BoxedUiNode,
16 conditions: Vec<(BoxedVar<bool>, BoxedUiNode)>,
17}
18impl WhenUiNodeBuilder {
19 pub fn new(default: impl UiNode) -> Self {
21 Self {
22 default: default.boxed(),
23 conditions: vec![],
24 }
25 }
26
27 pub fn push(&mut self, condition: impl Var<bool>, node: impl UiNode) {
31 self.conditions.push((condition.boxed(), node.boxed()));
32 }
33
34 pub fn build(self) -> impl UiNode {
36 WhenUiNode {
37 default: self.default,
38 conditions: self.conditions,
39 current: usize::MAX,
40 wgt_handles: WidgetHandlesCtx::new(),
41 }
42 }
43}
44
45pub struct WhenUiNodeListBuilder {
49 default: BoxedUiNodeList,
50 conditions: Vec<(BoxedVar<bool>, BoxedUiNodeList)>,
51}
52impl WhenUiNodeListBuilder {
53 pub fn new(default: impl UiNodeList) -> Self {
55 Self {
56 default: default.boxed(),
57 conditions: vec![],
58 }
59 }
60
61 pub fn push(&mut self, condition: impl Var<bool>, list: impl UiNodeList) {
65 self.conditions.push((condition.boxed(), list.boxed()));
66 }
67
68 pub fn build(self) -> impl UiNodeList {
70 WhenUiNodeList {
71 default: self.default,
72 conditions: self.conditions,
73 current: usize::MAX,
74 wgt_handles: WidgetHandlesCtx::new(),
75 }
76 }
77}
78
79struct WhenUiNode {
80 default: BoxedUiNode,
81 conditions: Vec<(BoxedVar<bool>, BoxedUiNode)>,
82 current: usize,
83 wgt_handles: WidgetHandlesCtx,
84}
85impl WhenUiNode {
86 fn child_mut_with_handles(&mut self) -> (&mut BoxedUiNode, &mut WidgetHandlesCtx) {
87 let child = if self.current == usize::MAX {
88 &mut self.default
89 } else {
90 &mut self.conditions[self.current].1
91 };
92 (child, &mut self.wgt_handles)
93 }
94
95 fn change_child(&mut self, new: usize) {
96 {
97 let (child, wgt_handles) = self.child_mut_with_handles();
98 WIDGET.with_handles(wgt_handles, || child.deinit());
99 wgt_handles.clear();
100 }
101
102 self.current = new;
103
104 {
105 let (child, wgt_handles) = self.child_mut_with_handles();
106 WIDGET.with_handles(wgt_handles, || child.init());
107 }
108
109 WIDGET.update_info().layout().render();
110 }
111
112 fn with<R>(&mut self, f: impl FnOnce(&mut BoxedUiNode) -> R) -> R {
113 let (child, wgt_handles) = self.child_mut_with_handles();
114 WIDGET.with_handles(wgt_handles, || f(child))
115 }
116}
117impl UiNode for WhenUiNode {
118 fn init(&mut self) {
119 self.current = usize::MAX;
120 for (i, (c, _)) in self.conditions.iter().enumerate() {
121 if self.current == usize::MAX && c.get() {
122 self.current = i;
123 }
124 WIDGET.sub_var(c);
125 }
126 self.with(|c| c.init());
127 }
128
129 fn deinit(&mut self) {
130 self.with(|c| c.deinit());
131 self.wgt_handles.clear();
132 }
133
134 fn info(&mut self, info: &mut crate::widget::info::WidgetInfoBuilder) {
135 self.with(|c| c.info(info));
136 }
137
138 fn event(&mut self, update: &EventUpdate) {
139 self.with(|c| c.event(update));
140 }
141
142 fn update(&mut self, updates: &WidgetUpdates) {
143 let mut any = false;
144 for (i, (c, _)) in self.conditions.iter().enumerate() {
145 if i < self.current {
146 if c.get() {
147 self.change_child(i);
149 return;
150 }
151 } else if i == self.current {
152 if c.get() {
153 any = true;
155 break;
156 }
157 } else if c.get() {
158 self.change_child(i);
160 return;
161 }
162 }
163
164 if !any && self.current != usize::MAX {
165 self.change_child(usize::MAX);
167 return;
168 }
169
170 self.with(|c| c.update(updates));
173 }
174
175 fn measure(&mut self, wm: &mut crate::widget::info::WidgetMeasure) -> PxSize {
176 self.with(|c| c.measure(wm))
177 }
178
179 fn layout(&mut self, wl: &mut crate::widget::info::WidgetLayout) -> PxSize {
180 self.with(|c| c.layout(wl))
181 }
182
183 fn render(&mut self, frame: &mut crate::render::FrameBuilder) {
184 self.with(|c| c.render(frame))
185 }
186
187 fn render_update(&mut self, update: &mut crate::render::FrameUpdate) {
188 self.with(|c| c.render_update(update))
189 }
190}
191
192struct WhenUiNodeList {
193 default: BoxedUiNodeList,
194 conditions: Vec<(BoxedVar<bool>, BoxedUiNodeList)>,
195 current: usize,
196 wgt_handles: WidgetHandlesCtx,
197}
198impl WhenUiNodeList {
199 fn children(&self) -> &BoxedUiNodeList {
200 if self.current == usize::MAX {
201 &self.default
202 } else {
203 &self.conditions[self.current].1
204 }
205 }
206
207 fn children_mut_with_handles(&mut self) -> (&mut BoxedUiNodeList, &mut WidgetHandlesCtx) {
208 let child = if self.current == usize::MAX {
209 &mut self.default
210 } else {
211 &mut self.conditions[self.current].1
212 };
213 (child, &mut self.wgt_handles)
214 }
215
216 fn change_children(&mut self, observer: &mut dyn UiNodeListObserver, new: usize) {
217 {
218 let (child, wgt_handles) = self.children_mut_with_handles();
219 WIDGET.with_handles(wgt_handles, || child.deinit_all());
220 wgt_handles.clear();
221 }
222
223 self.current = new;
224
225 {
226 let (child, wgt_handles) = self.children_mut_with_handles();
227 WIDGET.with_handles(wgt_handles, || child.init_all());
228 }
229
230 observer.reset();
231 WIDGET.update_info().layout().render();
232 }
233}
234
235impl UiNodeList for WhenUiNodeList {
236 fn with_node<R, F>(&mut self, index: usize, f: F) -> R
237 where
238 F: FnOnce(&mut BoxedUiNode) -> R,
239 {
240 self.children_mut_with_handles().0.with_node(index, f)
241 }
242
243 fn for_each<F>(&mut self, f: F)
244 where
245 F: FnMut(usize, &mut BoxedUiNode),
246 {
247 self.children_mut_with_handles().0.for_each(f)
248 }
249
250 fn par_each<F>(&mut self, f: F)
251 where
252 F: Fn(usize, &mut BoxedUiNode) + Send + Sync,
253 {
254 self.children_mut_with_handles().0.par_each(f)
255 }
256
257 fn par_fold_reduce<T, I, F, R>(&mut self, identity: I, fold: F, reduce: R) -> T
258 where
259 T: Send + 'static,
260 I: Fn() -> T + Send + Sync,
261 F: Fn(T, usize, &mut BoxedUiNode) -> T + Send + Sync,
262 R: Fn(T, T) -> T + Send + Sync,
263 {
264 self.children_mut_with_handles().0.par_fold_reduce(identity, fold, reduce)
265 }
266
267 fn len(&self) -> usize {
268 self.children().len()
269 }
270
271 fn boxed(self) -> BoxedUiNodeList {
272 Box::new(self)
273 }
274
275 fn drain_into(&mut self, vec: &mut Vec<BoxedUiNode>) {
276 self.children_mut_with_handles().0.drain_into(vec)
277 }
278
279 fn init_all(&mut self) {
280 self.current = usize::MAX;
281 for (i, (c, _)) in self.conditions.iter().enumerate() {
282 if self.current == usize::MAX && c.get() {
283 self.current = i;
284 }
285 WIDGET.sub_var(c);
286 }
287
288 let (children, wgt_handles) = self.children_mut_with_handles();
289 WIDGET.with_handles(wgt_handles, || children.init_all());
290 }
291
292 fn deinit_all(&mut self) {
293 let (children, wgt_handles) = self.children_mut_with_handles();
294 WIDGET.with_handles(wgt_handles, || children.deinit_all());
295 wgt_handles.clear();
296 }
297
298 fn update_all(&mut self, updates: &WidgetUpdates, observer: &mut dyn UiNodeListObserver) {
299 let mut any = false;
300 for (i, (c, _)) in self.conditions.iter().enumerate() {
301 if i < self.current {
302 if c.get() {
304 any = true;
305 self.change_children(observer, i);
306
307 break;
308 }
309 } else if i == self.current {
310 if c.get() {
312 any = true;
313 break;
314 }
315 } else if c.get() {
316 any = true;
318 self.change_children(observer, i);
319
320 break;
321 }
322 }
323
324 if !any && self.current != usize::MAX {
325 self.change_children(observer, usize::MAX);
327 }
328
329 let (children, wgt_handles) = self.children_mut_with_handles();
330 WIDGET.with_handles(wgt_handles, || children.update_all(updates, observer));
331 }
332
333 fn info_all(&mut self, info: &mut crate::widget::info::WidgetInfoBuilder) {
334 let (children, wgt_handles) = self.children_mut_with_handles();
335 WIDGET.with_handles(wgt_handles, || {
336 children.info_all(info);
337 })
338 }
339
340 fn event_all(&mut self, update: &EventUpdate) {
341 let (children, wgt_handles) = self.children_mut_with_handles();
342 WIDGET.with_handles(wgt_handles, || {
343 children.event_all(update);
344 })
345 }
346}