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