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