1use anathema_geometry::{Pos, Region, Size};
2use anathema_state::{State, StateId, States};
3use anathema_store::tree::TreeView;
4use anathema_templates::{ComponentBlueprintId, Variables};
5use anathema_value_resolver::{AttributeStorage, Attributes, FunctionTable};
6use display::DISPLAY;
7
8pub use self::constraints::Constraints;
9pub use self::display::Display;
10use crate::components::{AnyComponent, ComponentKind, ComponentRegistry};
11use crate::error::{Error, ErrorKind};
12use crate::nodes::element::Element;
13use crate::tree::{FilterOutput, WidgetPositionFilter};
14use crate::{Components, Factory, FloatingWidgets, GlyphMap, WidgetContainer, WidgetId, WidgetKind};
15
16mod constraints;
17pub mod display;
18pub mod text;
19
20pub struct LayoutCtx<'frame, 'bp> {
21 pub states: &'frame mut States,
22 pub(super) globals: &'bp Variables,
23 factory: &'frame Factory,
24 pub attribute_storage: &'frame mut AttributeStorage<'bp>,
25 pub components: &'frame mut Components,
26 pub glyph_map: &'frame mut GlyphMap,
27 pub viewport: &'frame mut Viewport,
28
29 pub floating_widgets: &'frame mut FloatingWidgets,
31 pub component_registry: &'frame mut ComponentRegistry,
32 pub new_components: Vec<(WidgetId, StateId)>,
33 pub stop_runtime: bool,
34 pub(super) function_table: &'bp FunctionTable,
35}
36
37impl<'frame, 'bp> LayoutCtx<'frame, 'bp> {
38 pub fn new(
39 globals: &'bp Variables,
40 factory: &'frame Factory,
41 states: &'frame mut States,
42 attribute_storage: &'frame mut AttributeStorage<'bp>,
43 components: &'frame mut Components,
44 component_registry: &'frame mut ComponentRegistry,
45 floating_widgets: &'frame mut FloatingWidgets,
46 glyph_map: &'frame mut GlyphMap,
47 viewport: &'frame mut Viewport,
48 function_table: &'bp FunctionTable,
49 ) -> Self {
50 Self {
51 states,
52 attribute_storage,
53 components,
54 component_registry,
55 globals,
56 factory,
57 floating_widgets,
58 glyph_map,
59 viewport,
60 new_components: vec![],
61 stop_runtime: false,
62 function_table,
63 }
64 }
65
66 pub fn attributes(&self, node_id: WidgetId) -> &Attributes<'bp> {
67 self.attribute_storage.get(node_id)
68 }
69
70 pub fn eval_ctx(&mut self, parent_component: Option<WidgetId>) -> EvalCtx<'_, 'bp> {
71 EvalCtx {
72 floating_widgets: self.floating_widgets,
73 attribute_storage: self.attribute_storage,
74 states: self.states,
75 component_registry: self.component_registry,
76 components: self.components,
77 globals: self.globals,
78 factory: self.factory,
79 parent_component,
80 new_components: &mut self.new_components,
81 function_table: self.function_table,
82 }
83 }
84
85 pub(crate) fn truncate_children(&mut self, tree: &mut TreeView<'_, WidgetContainer<'bp>>) {
86 tree.truncate_children(&mut |widget| {
87 self.return_component(widget);
88 });
89 }
90
91 pub(crate) fn relative_remove(&mut self, path: &[u16], mut tree: TreeView<'_, WidgetContainer<'bp>>) {
92 tree.relative_remove(path, &mut |widget| {
93 self.return_component(widget);
94 });
95 }
96
97 fn return_component(&mut self, widget: WidgetContainer<'_>) {
98 let WidgetKind::Component(comp) = widget.kind else { return };
99 self.components.try_remove(comp.widget_id);
100 let id = comp.component_id;
101 let state = self.states.remove(comp.state_id).take();
102 self.component_registry.return_component(id, comp.dyn_component, state);
103 }
104}
105
106pub struct EvalCtx<'frame, 'bp> {
107 pub(super) new_components: &'frame mut Vec<(WidgetId, StateId)>,
108 pub(super) floating_widgets: &'frame mut FloatingWidgets,
109 pub(super) attribute_storage: &'frame mut AttributeStorage<'bp>,
110 pub(super) states: &'frame mut States,
111 component_registry: &'frame mut ComponentRegistry,
112 pub(super) components: &'frame mut Components,
113 pub(super) globals: &'bp Variables,
114 pub(super) factory: &'frame Factory,
115 pub(super) function_table: &'bp FunctionTable,
116 pub(super) parent_component: Option<WidgetId>,
117}
118
119impl<'frame, 'bp> EvalCtx<'frame, 'bp> {
120 pub(super) fn get_component(
121 &mut self,
122 component_id: ComponentBlueprintId,
123 ) -> Option<(ComponentKind, Box<dyn AnyComponent>, Box<dyn State>)> {
124 self.component_registry.get(component_id)
125 }
126
127 pub(crate) fn error(&self, kind: ErrorKind) -> Error {
128 Error { kind, path: None }
129 }
130}
131
132#[derive(Debug, Copy, Clone)]
133pub struct Viewport {
135 size: Size,
136}
137
138impl Viewport {
139 pub fn new(size: impl Into<Size>) -> Self {
140 let size = size.into();
141 Self { size }
142 }
143
144 pub fn size(&self) -> Size {
145 self.size
146 }
147
148 pub fn constraints(&self) -> Constraints {
149 Constraints::new(self.size.width, self.size.height)
150 }
151
152 pub fn resize(&mut self, size: Size) {
153 self.size = size;
154 }
155}
156
157#[derive(Debug, Copy, Clone)]
158pub struct LayoutFilter;
159
160impl<'bp> crate::widget::Filter<'bp> for LayoutFilter {
161 type Output = WidgetContainer<'bp>;
162
163 fn filter<'a>(
164 &mut self,
165 widget: &'a mut WidgetContainer<'bp>,
166 attribute_storage: &AttributeStorage<'_>,
167 ) -> FilterOutput<&'a mut Self::Output, Self> {
168 match &mut widget.kind {
169 WidgetKind::Element(element) => {
170 let attributes = attribute_storage.get(element.id());
171 match attributes.get_as::<Display>(DISPLAY).unwrap_or_default() {
172 Display::Show | Display::Hide => FilterOutput::Include(widget, *self),
173 Display::Exclude => FilterOutput::Exclude,
174 }
175 }
176 _ => FilterOutput::Continue,
177 }
178 }
179}
180
181#[derive(Debug, Copy, Clone)]
182pub struct PositionCtx {
183 pub inner_size: Size,
184 pub pos: Pos,
185 pub viewport: Viewport,
186}
187
188impl PositionCtx {
189 pub fn region(&self) -> Region {
190 Region::from((self.pos, self.inner_size))
191 }
192}
193
194#[derive(Debug, Copy, Clone)]
195pub struct PositionFilter(WidgetPositionFilter);
196
197impl PositionFilter {
198 pub fn fixed() -> Self {
199 Self(WidgetPositionFilter::Fixed)
200 }
201
202 pub fn floating() -> Self {
203 Self(WidgetPositionFilter::Floating)
204 }
205
206 pub fn all() -> Self {
207 Self(WidgetPositionFilter::All)
208 }
209
210 pub fn none() -> Self {
211 Self(WidgetPositionFilter::None)
212 }
213}
214
215impl<'bp> crate::widget::Filter<'bp> for PositionFilter {
216 type Output = Element<'bp>;
217
218 fn filter<'a>(
219 &mut self,
220 widget: &'a mut WidgetContainer<'bp>,
221 attribute_storage: &AttributeStorage<'_>,
222 ) -> FilterOutput<&'a mut Self::Output, Self> {
223 match &mut widget.kind {
224 WidgetKind::Element(element) => {
225 let attributes = attribute_storage.get(element.id());
226 match attributes.get_as::<Display>(DISPLAY).unwrap_or_default() {
227 Display::Show => match self.0 {
228 WidgetPositionFilter::Floating => match element.is_floating() {
229 true => FilterOutput::Include(element, Self::all()),
230 false => FilterOutput::Continue,
231 },
232 WidgetPositionFilter::Fixed => match element.is_floating() {
233 false => FilterOutput::Include(element, *self),
234 true => FilterOutput::Include(element, Self::none()),
235 },
236 WidgetPositionFilter::All => FilterOutput::Include(element, *self),
237 WidgetPositionFilter::None => FilterOutput::Exclude,
238 },
239 Display::Hide | Display::Exclude => FilterOutput::Exclude,
240 }
241 }
242 _ => FilterOutput::Continue,
243 }
244 }
245}
246
247#[cfg(test)]
248mod test {
249 use std::ops::ControlFlow;
250
251 use super::*;
252 use crate::widget::ForEach;
253
254 #[test]
255 fn filter_floating_positioning() {
256 let tpl = "
257 many
258 many
259 many
260 // --------------------
261 float //
262 text // <- only these
263 text // <------------
264 float //
265 text //
266 // --------------------
267 many
268 many
269 many
270 many
271 ";
272
273 let mut expected = vec!["float", "text", "text", "float", "text"];
274 crate::testing::with_template(tpl, move |tree, attributes| {
275 let filter = PositionFilter::floating();
276 let children = ForEach::new(tree, attributes, filter);
277 recur(children, &mut expected);
278 });
279
280 fn recur(mut f: ForEach<'_, '_, PositionFilter>, expected: &mut Vec<&'static str>) {
281 _ = f.each(|el, nodes| {
282 assert_eq!(expected.remove(0), el.ident);
283 recur(nodes, expected);
284 ControlFlow::Continue(())
285 });
286 }
287 }
288}