Skip to main content

anathema_widgets/tree/
mod.rs

1// -----------------------------------------------------------------------------
2//   - Here be dragons -
3//   This code needs cleaning up.
4//
5//   At some point this should be better documented and broken
6//   into smaller pieces.
7//
8//   TODO: clean this blessed mess
9// -----------------------------------------------------------------------------
10use std::ops::ControlFlow;
11
12use anathema_state::Value as StateValue;
13use anathema_templates::blueprints::Blueprint;
14use anathema_value_resolver::{AttributeStorage, Scope};
15
16use crate::error::Result;
17use crate::layout::{LayoutCtx, LayoutFilter};
18use crate::nodes::loops::Iteration;
19use crate::nodes::{controlflow, eval_blueprint};
20use crate::widget::WidgetTreeView;
21use crate::{Element, WidgetContainer, WidgetId, WidgetKind};
22
23pub mod debug;
24
25// TODO:
26// Add the option to "skip" values with an offset for `inner_each` (this is for overflow widgets)
27// Note that this might not be possible, depending on how widget generation goes
28
29/// Determine what kind of widgets that should be laid out:
30/// Fixed or floating.
31#[derive(Debug, Copy, Clone)]
32pub enum WidgetPositionFilter {
33    Floating,
34    Fixed,
35    All,
36    None,
37}
38
39#[derive(Debug, Copy, Clone)]
40pub enum Generator<'widget, 'bp> {
41    Single {
42        ident: &'bp str,
43        body: &'bp [Blueprint],
44    },
45    Loop {
46        len: usize,
47        binding: &'bp str,
48        body: &'bp [Blueprint],
49    },
50    Iteration {
51        binding: &'bp str,
52        body: &'bp [Blueprint],
53    },
54    With {
55        binding: &'bp str,
56        body: &'bp [Blueprint],
57    },
58    ControlFlow(&'widget controlflow::ControlFlow<'bp>),
59    ControlFlowContainer(&'bp [Blueprint]),
60    Slot(&'bp [Blueprint]),
61}
62
63impl<'widget, 'bp> Generator<'widget, 'bp> {
64    fn from_loop(body: &'bp [Blueprint], binding: &'bp str, len: usize) -> Self {
65        Self::Loop { binding, body, len }
66    }
67
68    fn from_with(body: &'bp [Blueprint], binding: &'bp str) -> Self {
69        Self::With { binding, body }
70    }
71}
72
73impl<'widget, 'bp> From<&'widget WidgetContainer<'bp>> for Generator<'widget, 'bp> {
74    fn from(widget: &'widget WidgetContainer<'bp>) -> Self {
75        match &widget.kind {
76            WidgetKind::Element(_) => panic!("use Self::Single directly"),
77            WidgetKind::For(_) => panic!("use Self::Loop directly"),
78            WidgetKind::With(_) => panic!("use Self::With directly"),
79            WidgetKind::ControlFlowContainer(_) => Self::ControlFlowContainer(widget.children),
80            WidgetKind::Component(comp) => Self::Single {
81                ident: comp.name,
82                body: widget.children,
83            },
84            WidgetKind::Iteration(iter) => Self::Iteration {
85                binding: iter.binding,
86                body: widget.children,
87            },
88            WidgetKind::ControlFlow(controlflow) => Self::ControlFlow(controlflow),
89            WidgetKind::Slot => Self::Slot(widget.children),
90        }
91    }
92}
93
94// -----------------------------------------------------------------------------
95//   - Layout -
96// -----------------------------------------------------------------------------
97#[derive(Debug)]
98pub struct LayoutForEach<'a, 'bp> {
99    tree: WidgetTreeView<'a, 'bp>,
100    scope: &'a Scope<'a, 'bp>,
101    generator: Option<Generator<'a, 'bp>>,
102    parent_component: Option<WidgetId>,
103    filter: LayoutFilter,
104}
105
106impl<'a, 'bp> LayoutForEach<'a, 'bp> {
107    pub fn new(
108        tree: WidgetTreeView<'a, 'bp>,
109        scope: &'a Scope<'a, 'bp>,
110        filter: LayoutFilter,
111        parent_component: Option<WidgetId>,
112    ) -> Self {
113        Self {
114            tree,
115            scope,
116            generator: None,
117            parent_component,
118            filter,
119        }
120    }
121
122    fn with_generator(
123        tree: WidgetTreeView<'a, 'bp>,
124        scope: &'a Scope<'a, 'bp>,
125        generator: Generator<'a, 'bp>,
126        filter: LayoutFilter,
127        parent_component: Option<WidgetId>,
128    ) -> Self {
129        Self {
130            tree,
131            scope,
132            generator: Some(generator),
133            filter,
134            parent_component,
135        }
136    }
137
138    // pub fn first<F>(&mut self, ctx: &mut LayoutCtx<'_, 'bp>, mut f: F) -> Result<ControlFlow<()>>
139    // where
140    //     F: FnMut(&mut LayoutCtx<'_, 'bp>, &mut Element<'bp>, LayoutForEach<'_, 'bp>) -> Result<ControlFlow<()>>,
141    // {
142    //     self.inner_each(ctx, &mut f)
143    // }
144
145    pub fn each<F>(&mut self, ctx: &mut LayoutCtx<'_, 'bp>, mut f: F) -> Result<ControlFlow<()>>
146    where
147        F: FnMut(&mut LayoutCtx<'_, 'bp>, &mut Element<'bp>, LayoutForEach<'_, 'bp>) -> Result<ControlFlow<()>>,
148    {
149        self.inner_each(ctx, &mut f)
150    }
151
152    fn inner_each<F>(&mut self, ctx: &mut LayoutCtx<'_, 'bp>, f: &mut F) -> Result<ControlFlow<()>>
153    where
154        F: FnMut(&mut LayoutCtx<'_, 'bp>, &mut Element<'bp>, LayoutForEach<'_, 'bp>) -> Result<ControlFlow<()>>,
155    {
156        for index in 0..self.tree.layout_len() {
157            match self.process(index, ctx, f)? {
158                ControlFlow::Continue(_) => continue,
159                ControlFlow::Break(_) => return Ok(ControlFlow::Break(())),
160            }
161        }
162
163        // If there is no parent then there can be no children generated
164        let Some(parent) = self.generator else { return Ok(ControlFlow::Continue(())) };
165
166        // NOTE: Generate will never happen unless the preceding iteration returns `Continue(())`.
167        //       Therefore there is no need to worry about excessive creation of `Iter`s for loops.
168        loop {
169            let index = self.tree.layout_len();
170            if !generate(parent, &mut self.tree, ctx, self.scope, self.parent_component)? {
171                break;
172            }
173            match self.process(index, ctx, f)? {
174                ControlFlow::Continue(_) => continue,
175                ControlFlow::Break(_) => return Ok(ControlFlow::Break(())),
176            }
177        }
178
179        Ok(ControlFlow::Continue(()))
180    }
181
182    // TODO: this function is gross and large
183    fn process<F>(&mut self, index: usize, ctx: &mut LayoutCtx<'_, 'bp>, f: &mut F) -> Result<ControlFlow<()>>
184    where
185        F: FnMut(&mut LayoutCtx<'_, 'bp>, &mut Element<'bp>, LayoutForEach<'_, 'bp>) -> Result<ControlFlow<()>>,
186    {
187        let node = self
188            .tree
189            .layout
190            .get(index)
191            .expect("widgets are always generated before processed");
192
193        let widget_id = node.value();
194
195        self.tree
196            .with_value_mut(widget_id, |_, widget, children| {
197                let output = self.filter.filter(widget, ctx.attribute_storage);
198                if let FilterOutput::Exclude = output {
199                    return Ok(ControlFlow::Continue(()));
200                }
201
202                match &mut widget.kind {
203                    WidgetKind::Element(el) => {
204                        let children = LayoutForEach::with_generator(
205                            children,
206                            self.scope,
207                            Generator::Single {
208                                ident: el.ident,
209                                body: widget.children,
210                            },
211                            self.filter,
212                            self.parent_component,
213                        );
214                        f(ctx, el, children)
215                    }
216                    WidgetKind::ControlFlow(_) => {
217                        let generator = Generator::from(&*widget);
218                        let mut children = LayoutForEach::with_generator(
219                            children,
220                            self.scope,
221                            generator,
222                            self.filter,
223                            self.parent_component,
224                        );
225                        children.inner_each(ctx, f)
226                    }
227                    WidgetKind::For(for_loop) => {
228                        let len = for_loop.collection.len();
229                        if len == 0 {
230                            return Ok(ControlFlow::Break(()));
231                        }
232
233                        let scope = Scope::with_collection(&for_loop.collection, self.scope);
234                        let mut children = LayoutForEach::with_generator(
235                            children,
236                            &scope,
237                            Generator::from_loop(widget.children, for_loop.binding, len),
238                            self.filter,
239                            self.parent_component,
240                        );
241
242                        children.inner_each(ctx, f)
243                    }
244                    WidgetKind::Iteration(iteration) => {
245                        let loop_index = *iteration.loop_index.to_ref() as usize;
246                        let scope = Scope::with_index(
247                            iteration.binding,
248                            loop_index,
249                            self.scope,
250                            iteration.loop_index.reference(),
251                        );
252                        let mut children = LayoutForEach::with_generator(
253                            children,
254                            &scope,
255                            Generator::from(&*widget),
256                            self.filter,
257                            self.parent_component,
258                        );
259                        children.inner_each(ctx, f)
260                    }
261                    WidgetKind::With(with) => {
262                        let scope = Scope::with_value(with.binding, &with.data, self.scope);
263                        let mut children = LayoutForEach::with_generator(
264                            children,
265                            &scope,
266                            Generator::from_with(widget.children, with.binding),
267                            self.filter,
268                            self.parent_component,
269                        );
270
271                        children.inner_each(ctx, f)
272                    }
273                    WidgetKind::Component(component) => {
274                        let parent_component = component.widget_id;
275                        let state_id = component.state_id();
276                        let scope = Scope::with_component(state_id, component.widget_id, Some(self.scope));
277                        let mut children = LayoutForEach::with_generator(
278                            children,
279                            &scope,
280                            Generator::from(&*widget),
281                            self.filter,
282                            Some(parent_component),
283                        );
284                        children.inner_each(ctx, f)
285                    }
286                    WidgetKind::ControlFlowContainer(_) => {
287                        let mut children = LayoutForEach::with_generator(
288                            children,
289                            self.scope,
290                            Generator::from(&*widget),
291                            self.filter,
292                            self.parent_component,
293                        );
294                        children.inner_each(ctx, f)
295                    }
296                    WidgetKind::Slot => {
297                        let mut children = LayoutForEach::with_generator(
298                            children,
299                            self.scope.outer(),
300                            Generator::from(&*widget),
301                            self.filter,
302                            self.parent_component,
303                        );
304                        children.inner_each(ctx, f)
305                    }
306                }
307            })
308            .unwrap_or(Ok(ControlFlow::Continue(())))
309    }
310
311    pub(crate) fn len(&self) -> usize {
312        self.tree.layout_len()
313    }
314}
315
316// Generate the next available widget into the tree
317// TODO: break this down into more manageable code.
318//       this is a hot mess
319fn generate<'bp>(
320    parent: Generator<'_, 'bp>,
321    tree: &mut WidgetTreeView<'_, 'bp>,
322    ctx: &mut LayoutCtx<'_, 'bp>,
323    scope: &Scope<'_, 'bp>,
324    parent_component: Option<WidgetId>,
325) -> Result<bool> {
326    match parent {
327        Generator::Single { body: blueprints, .. }
328        | Generator::Iteration { body: blueprints, .. }
329        | Generator::With { body: blueprints, .. }
330        | Generator::ControlFlowContainer(blueprints) => {
331            if blueprints.is_empty() {
332                return Ok(false);
333            }
334
335            let index = tree.layout_len();
336            if index >= blueprints.len() {
337                return Ok(false);
338            }
339
340            let mut ctx = ctx.eval_ctx(parent_component);
341            // TODO: unwrap.
342            // this should propagate somewhere useful
343            eval_blueprint(&blueprints[index], &mut ctx, scope, tree.offset, tree)?;
344            Ok(true)
345        }
346
347        Generator::Slot(blueprints) => {
348            if blueprints.is_empty() {
349                return Ok(false);
350            }
351
352            let index = tree.layout_len();
353            if index >= blueprints.len() {
354                return Ok(false);
355            }
356
357            let mut ctx = ctx.eval_ctx(parent_component);
358            eval_blueprint(&blueprints[index], &mut ctx, scope, tree.offset, tree).unwrap();
359            Ok(true)
360        }
361        Generator::Loop { len, .. } if len == tree.layout_len() => Ok(false),
362        Generator::Loop { binding, body, .. } => {
363            let loop_index = tree.layout_len();
364
365            let transaction = tree.insert(tree.offset);
366            let widget = WidgetKind::Iteration(Iteration {
367                loop_index: StateValue::new(loop_index as i64),
368                binding,
369            });
370            let widget = WidgetContainer::new(widget, body);
371            // NOTE: for this to fail one of the values along the path would have to
372            // have been removed
373            transaction.commit_child(widget).unwrap();
374            Ok(true)
375        }
376        Generator::ControlFlow(controlflow) => {
377            let child_count = tree.layout_len();
378            assert_eq!(child_count.saturating_sub(1), 0, "too many branches have been created");
379
380            // TODO: this could probably be replaced with the functionality in
381            // ControlFlow::has_changed
382
383            let should_create = {
384                if child_count == 0 {
385                    true
386                } else {
387                    let node_id = tree.layout[0].value();
388                    let (_, widget) = tree
389                        .values
390                        .get(node_id)
391                        .expect("because the node exists, the value exist");
392
393                    let is_true = match &widget.kind {
394                        WidgetKind::ControlFlowContainer(id) => controlflow.elses[*id as usize].is_true(),
395                        _ => unreachable!("the child of `ControlFlow` can only be `Else`"),
396                    };
397
398                    // The condition no longer holds so the branch has to be trimmed
399                    if is_true {
400                        return Ok(false);
401                    }
402
403                    is_true
404                }
405            };
406
407            if !should_create {
408                return Ok(false);
409            }
410
411            let thing = controlflow
412                .elses
413                .iter()
414                .enumerate()
415                .filter_map(|(id, node)| {
416                    // If there is a condition but it's not a bool, then it's false
417                    // If there is no condition then it's true (a conditionless else)
418                    // Everything else is down to the value
419                    let cond = match node.cond.as_ref() {
420                        Some(val) => val.truthiness(),
421                        None => true,
422                    };
423                    match cond {
424                        true => Some((id, node.body)),
425                        false => None,
426                    }
427                })
428                .next();
429
430            match thing {
431                Some((id, body)) => {
432                    let kind = WidgetKind::ControlFlowContainer(id as u16);
433                    let widget = WidgetContainer::new(kind, body);
434                    let transaction = tree.insert(tree.offset);
435                    transaction.commit_child(widget);
436                }
437                None => return Ok(false),
438            }
439
440            Ok(true)
441        }
442    }
443}
444
445#[derive(Debug)]
446pub enum FilterOutput<T, F> {
447    Include(T, F),
448    Exclude,
449    Continue,
450}
451
452pub trait Filter<'bp>: std::fmt::Debug + Copy {
453    type Output: std::fmt::Debug;
454
455    fn filter<'a>(
456        &mut self,
457        widget: &'a mut WidgetContainer<'bp>,
458        attribute_storage: &AttributeStorage<'_>,
459    ) -> FilterOutput<&'a mut Self::Output, Self>;
460}
461
462// -----------------------------------------------------------------------------
463//   - Position / Paint -
464// -----------------------------------------------------------------------------
465#[derive(Debug)]
466pub struct ForEach<'a, 'bp, Fltr> {
467    tree: WidgetTreeView<'a, 'bp>,
468    attribute_storage: &'a AttributeStorage<'bp>,
469    pub filter: Fltr,
470}
471
472impl<'a, 'bp, Fltr: Filter<'bp>> ForEach<'a, 'bp, Fltr> {
473    pub fn new(tree: WidgetTreeView<'a, 'bp>, attribute_storage: &'a AttributeStorage<'bp>, filter: Fltr) -> Self {
474        Self {
475            tree,
476            attribute_storage,
477            filter,
478        }
479    }
480
481    pub fn each<F>(&mut self, mut f: F) -> ControlFlow<()>
482    where
483        F: FnMut(&mut Fltr::Output, ForEach<'_, 'bp, Fltr>) -> ControlFlow<()>,
484    {
485        self.inner_each(&mut f)
486    }
487
488    fn inner_each<F>(&mut self, f: &mut F) -> ControlFlow<()>
489    where
490        F: FnMut(&mut Fltr::Output, ForEach<'_, 'bp, Fltr>) -> ControlFlow<()>,
491    {
492        for index in 0..self.tree.layout_len() {
493            _ = self.process(index, f);
494        }
495
496        ControlFlow::Continue(())
497    }
498
499    fn process<F>(&mut self, index: usize, f: &mut F) -> ControlFlow<()>
500    where
501        F: FnMut(&mut Fltr::Output, ForEach<'_, 'bp, Fltr>) -> ControlFlow<()>,
502    {
503        let Some(node) = self.tree.layout.get(index) else { panic!() };
504        self.tree
505            .with_value_mut(node.value(), |_, widget, children| {
506                match self.filter.filter(widget, self.attribute_storage) {
507                    FilterOutput::Include(el, filter) => f(el, ForEach::new(children, self.attribute_storage, filter)),
508                    FilterOutput::Exclude => ControlFlow::Break(()),
509                    FilterOutput::Continue => ForEach::new(children, self.attribute_storage, self.filter).inner_each(f),
510                }
511            })
512            .unwrap() // TODO: unwrap...
513    }
514}