Skip to main content

anathema_backend/
lib.rs

1use std::ops::ControlFlow;
2use std::time::Duration;
3
4use anathema_geometry::{Pos, Size};
5use anathema_value_resolver::{AttributeStorage, Scope};
6use anathema_widgets::components::events::Event;
7use anathema_widgets::error::Result;
8use anathema_widgets::layout::{Constraints, LayoutCtx, LayoutFilter, PositionFilter, Viewport};
9use anathema_widgets::paint::PaintFilter;
10use anathema_widgets::{GlyphMap, LayoutForEach, PaintChildren, PositionChildren, WidgetTreeView};
11
12pub mod testing;
13pub mod tui;
14
15pub trait Backend {
16    fn size(&self) -> Size;
17
18    fn next_event(&mut self, timeout: Duration) -> Option<Event>;
19
20    fn resize(&mut self, new_size: Size, glyph_map: &mut GlyphMap);
21
22    /// Paint the widgets
23    fn paint<'bp>(
24        &mut self,
25        glyph_map: &mut GlyphMap,
26        widgets: PaintChildren<'_, 'bp>,
27        attribute_storage: &AttributeStorage<'bp>,
28    );
29
30    /// Called by the runtime at the end of the frame.
31    fn render(&mut self, glyph_map: &mut GlyphMap);
32
33    /// Clear is called immediately after `render` is called.
34    fn clear(&mut self);
35
36    /// Finalizes the backend. This is called when the runtime starts.
37    fn finalize(&mut self) {}
38}
39
40// TODO: rename this.
41// This does layout, position and paint and should have
42// a less silly name
43pub struct WidgetCycle<'rt, 'bp, T> {
44    backend: &'rt mut T,
45    tree: WidgetTreeView<'rt, 'bp>,
46    constraints: Constraints,
47}
48
49impl<'rt, 'bp, T: Backend> WidgetCycle<'rt, 'bp, T> {
50    pub fn new(backend: &'rt mut T, tree: WidgetTreeView<'rt, 'bp>, constraints: Constraints) -> Self {
51        Self {
52            backend,
53            tree,
54            constraints,
55        }
56    }
57
58    fn fixed(&mut self, ctx: &mut LayoutCtx<'_, 'bp>, needs_layout: bool) -> Result<()> {
59        // -----------------------------------------------------------------------------
60        //   - Layout -
61        // -----------------------------------------------------------------------------
62        if needs_layout {
63            self.layout(ctx, LayoutFilter)?;
64        }
65
66        // -----------------------------------------------------------------------------
67        //   - Position -
68        // -----------------------------------------------------------------------------
69        self.position(ctx.attribute_storage, *ctx.viewport, PositionFilter::fixed());
70
71        // -----------------------------------------------------------------------------
72        //   - Paint -
73        // -----------------------------------------------------------------------------
74        self.paint(ctx, PaintFilter::fixed());
75
76        Ok(())
77    }
78
79    fn floating(&mut self, ctx: &mut LayoutCtx<'_, 'bp>) -> Result<()> {
80        // -----------------------------------------------------------------------------
81        //   - Position -
82        // -----------------------------------------------------------------------------
83        self.position(ctx.attribute_storage, *ctx.viewport, PositionFilter::floating());
84
85        // -----------------------------------------------------------------------------
86        //   - Paint -
87        // -----------------------------------------------------------------------------
88        self.paint(ctx, PaintFilter::floating());
89
90        Ok(())
91    }
92
93    pub fn run(&mut self, ctx: &mut LayoutCtx<'_, 'bp>, needs_layout: bool) -> Result<()> {
94        self.fixed(ctx, needs_layout)?;
95        self.floating(ctx)?;
96        Ok(())
97    }
98
99    fn layout(&mut self, ctx: &mut LayoutCtx<'_, 'bp>, filter: LayoutFilter) -> Result<()> {
100        #[cfg(feature = "profile")]
101        puffin::profile_function!();
102        let tree = self.tree.view();
103
104        let scope = Scope::root();
105        let mut for_each = LayoutForEach::new(tree, &scope, filter, None);
106        let constraints = self.constraints;
107        _ = for_each.each(ctx, |ctx, widget, children| {
108            _ = widget.layout(children, constraints, ctx)?;
109            Ok(ControlFlow::Break(()))
110        })?;
111        Ok(())
112    }
113
114    fn position(&mut self, attributes: &AttributeStorage<'bp>, viewport: Viewport, filter: PositionFilter) {
115        #[cfg(feature = "profile")]
116        puffin::profile_function!();
117
118        let mut for_each = PositionChildren::new(self.tree.view(), attributes, filter);
119        _ = for_each.each(|widget, children| {
120            widget.position(children, Pos::ZERO, attributes, viewport);
121            ControlFlow::Break(())
122        });
123    }
124
125    fn paint(&mut self, ctx: &mut LayoutCtx<'_, 'bp>, filter: PaintFilter) {
126        #[cfg(feature = "profile")]
127        puffin::profile_function!();
128
129        let for_each = PaintChildren::new(self.tree.view(), ctx.attribute_storage, filter);
130        self.backend.paint(ctx.glyph_map, for_each, ctx.attribute_storage);
131    }
132}