Skip to main content

anathema_widgets/widget/
mod.rs

1use std::any::Any;
2use std::fmt::{self, Debug};
3use std::ops::ControlFlow;
4
5use anathema_geometry::{Pos, Region, Size};
6use anathema_state::StateId;
7use anathema_store::slab::SecondaryMap;
8use anathema_store::tree::{Tree, TreeView};
9use anathema_templates::ComponentBlueprintId;
10use anathema_value_resolver::AttributeStorage;
11
12pub use self::factory::Factory;
13pub use self::style::{Attributes, Style};
14use crate::WidgetContainer;
15use crate::error::Result;
16use crate::layout::{Constraints, LayoutCtx, PositionCtx, PositionFilter};
17use crate::paint::{PaintCtx, PaintFilter, SizePos};
18pub use crate::tree::{Filter, ForEach, LayoutForEach};
19
20mod factory;
21mod style;
22
23pub type WidgetTreeView<'a, 'bp> = TreeView<'a, WidgetContainer<'bp>>;
24pub type WidgetTree<'a> = Tree<WidgetContainer<'a>>;
25pub type LayoutChildren<'a, 'bp> = LayoutForEach<'a, 'bp>;
26pub type PositionChildren<'a, 'bp> = ForEach<'a, 'bp, PositionFilter>;
27pub type PaintChildren<'a, 'bp> = ForEach<'a, 'bp, PaintFilter>;
28pub type WidgetId = anathema_store::slab::Key;
29
30#[derive(Debug)]
31pub struct CompEntry {
32    /// The state owned by this component
33    pub state_id: StateId,
34    /// The components id in the widget tree
35    pub widget_id: WidgetId,
36
37    /// Does the component accept tick events
38    pub accept_ticks: bool,
39
40    component_id: ComponentBlueprintId,
41}
42
43/// Store a list of components currently in the tree
44pub struct Components {
45    inner: Vec<CompEntry>,
46}
47
48impl Components {
49    pub fn new() -> Self {
50        Self { inner: vec![] }
51    }
52
53    pub fn push(
54        &mut self,
55        component_id: ComponentBlueprintId,
56        widget_id: WidgetId,
57        state_id: StateId,
58        accept_ticks: bool,
59    ) {
60        let entry = CompEntry {
61            component_id,
62            widget_id,
63            state_id,
64            accept_ticks,
65        };
66
67        self.inner.push(entry)
68    }
69
70    pub fn try_remove(&mut self, widget_id: WidgetId) {
71        self.inner.retain(|entry| entry.widget_id != widget_id);
72    }
73
74    /// Get the component by its index
75    pub fn get(&mut self, index: usize) -> Option<(WidgetId, StateId)> {
76        self.inner.get(index).map(|e| (e.widget_id, e.state_id))
77    }
78
79    /// This is used to send messages to components.
80    /// The `ComponentBlueprintId` is only available to components that were added
81    /// as a singular component, not prototypes
82    pub fn get_by_component_id(&mut self, id: ComponentBlueprintId) -> Option<&CompEntry> {
83        self.inner.iter().find(|e| e.component_id == id)
84    }
85
86    /// Get the component by its widget id
87    pub fn get_by_widget_id(&mut self, id: WidgetId) -> Option<(WidgetId, StateId)> {
88        self.inner
89            .iter()
90            .find(|entry| entry.widget_id == id)
91            .map(|e| (e.widget_id, e.state_id))
92    }
93
94    /// Get widget id and state id for a component that accepts tick events
95    pub fn get_ticking(&self, index: usize) -> Option<(WidgetId, StateId)> {
96        self.inner
97            .get(index)
98            .and_then(|e| e.accept_ticks.then_some((e.widget_id, e.state_id)))
99    }
100
101    pub fn iter(&self) -> impl Iterator<Item = &CompEntry> {
102        self.inner.iter()
103    }
104
105    pub fn len(&self) -> usize {
106        self.inner.len()
107    }
108}
109
110#[derive(Debug)]
111pub struct FloatingWidgets(SecondaryMap<WidgetId, WidgetId>);
112
113impl FloatingWidgets {
114    pub fn empty() -> Self {
115        Self(SecondaryMap::empty())
116    }
117
118    pub fn try_remove(&mut self, key: WidgetId) {
119        self.0.try_remove(key);
120    }
121
122    pub(crate) fn insert(&mut self, widget_id: WidgetId) {
123        self.0.insert(widget_id, widget_id);
124    }
125
126    pub fn iter(&self) -> impl Iterator<Item = &WidgetId> {
127        self.0.iter()
128    }
129}
130
131/// Parent in a component relationship
132#[derive(Debug, Copy, Clone)]
133pub struct Parent(pub WidgetId);
134
135impl From<Parent> for WidgetId {
136    fn from(value: Parent) -> Self {
137        value.0
138    }
139}
140
141impl From<WidgetId> for Parent {
142    fn from(value: WidgetId) -> Self {
143        Self(value)
144    }
145}
146
147/// Component relationships, tracking the parent component of each component
148pub struct ComponentParents(SecondaryMap<ComponentBlueprintId, Parent>);
149
150impl ComponentParents {
151    pub fn empty() -> Self {
152        Self(SecondaryMap::empty())
153    }
154
155    pub fn try_remove(&mut self, key: ComponentBlueprintId) {
156        self.0.try_remove(key);
157    }
158
159    pub fn get_parent(&self, child: ComponentBlueprintId) -> Option<Parent> {
160        self.0.get(child).copied()
161    }
162}
163
164/// Any widget should never be implemented directly
165/// as it's implemented for any type that implements `Widget`
166pub trait AnyWidget {
167    fn to_any_ref(&self) -> &dyn Any;
168    fn to_any_mut(&mut self) -> &mut dyn Any;
169
170    fn any_layout<'bp>(
171        &mut self,
172        children: LayoutForEach<'_, 'bp>,
173        constraints: Constraints,
174        id: WidgetId,
175        ctx: &mut LayoutCtx<'_, 'bp>,
176    ) -> Result<Size>;
177
178    fn any_position<'bp>(
179        &mut self,
180        children: ForEach<'_, 'bp, PositionFilter>,
181        id: WidgetId,
182        attribute_storage: &AttributeStorage<'bp>,
183        ctx: PositionCtx,
184    );
185
186    fn any_paint<'bp>(
187        &mut self,
188        children: ForEach<'_, 'bp, PaintFilter>,
189        id: WidgetId,
190        attribute_storage: &AttributeStorage<'bp>,
191        ctx: PaintCtx<'_, SizePos>,
192    );
193
194    fn any_floats(&self) -> bool;
195
196    fn any_inner_bounds(&self, pos: Pos, size: Size) -> Region;
197
198    fn any_needs_reflow(&mut self) -> bool;
199}
200
201impl<T: 'static + Widget> AnyWidget for T {
202    fn to_any_ref(&self) -> &dyn Any {
203        self
204    }
205
206    fn to_any_mut(&mut self) -> &mut dyn Any {
207        self
208    }
209
210    fn any_layout<'bp>(
211        &mut self,
212        children: LayoutForEach<'_, 'bp>,
213        constraints: Constraints,
214        id: WidgetId,
215        ctx: &mut LayoutCtx<'_, 'bp>,
216    ) -> Result<Size> {
217        self.layout(children, constraints, id, ctx)
218    }
219
220    fn any_position<'bp>(
221        &mut self,
222        children: ForEach<'_, 'bp, PositionFilter>,
223        id: WidgetId,
224        attribute_storage: &AttributeStorage<'bp>,
225        ctx: PositionCtx,
226    ) {
227        self.position(children, id, attribute_storage, ctx)
228    }
229
230    fn any_paint<'bp>(
231        &mut self,
232        children: ForEach<'_, 'bp, PaintFilter>,
233        id: WidgetId,
234        attribute_storage: &AttributeStorage<'bp>,
235        ctx: PaintCtx<'_, SizePos>,
236    ) {
237        self.paint(children, id, attribute_storage, ctx)
238    }
239
240    fn any_inner_bounds(&self, pos: Pos, size: Size) -> Region {
241        self.inner_bounds(pos, size)
242    }
243
244    fn any_floats(&self) -> bool {
245        self.floats()
246    }
247
248    fn any_needs_reflow(&mut self) -> bool {
249        self.needs_reflow()
250    }
251}
252
253impl Debug for dyn AnyWidget {
254    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255        write!(f, "<dyn AnyWidget>")
256    }
257}
258
259pub trait Widget {
260    fn layout<'bp>(
261        &mut self,
262        children: LayoutForEach<'_, 'bp>,
263        constraints: Constraints,
264        id: WidgetId,
265        ctx: &mut LayoutCtx<'_, 'bp>,
266    ) -> Result<Size>;
267
268    fn paint<'bp>(
269        &mut self,
270        mut children: ForEach<'_, 'bp, PaintFilter>,
271        _id: WidgetId,
272        attribute_storage: &AttributeStorage<'bp>,
273        mut ctx: PaintCtx<'_, SizePos>,
274    ) {
275        _ = children.each(|child, children| {
276            let ctx = ctx.to_unsized();
277            child.paint(children, ctx, attribute_storage);
278            ControlFlow::Continue(())
279        });
280    }
281
282    fn position<'bp>(
283        &mut self,
284        children: ForEach<'_, 'bp, PositionFilter>,
285        id: WidgetId,
286        attribute_storage: &AttributeStorage<'bp>,
287        ctx: PositionCtx,
288    );
289
290    fn floats(&self) -> bool {
291        false
292    }
293
294    fn inner_bounds(&self, pos: Pos, size: Size) -> Region {
295        Region::from((pos, size))
296    }
297
298    fn needs_reflow(&mut self) -> bool {
299        false
300    }
301}
302
303impl Debug for dyn Widget {
304    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        write!(f, "<dyn Widget>")
306    }
307}