anathema_widgets/nodes/
element.rs1use std::ops::ControlFlow;
2
3use anathema_geometry::{Pos, Region, Size};
4use anathema_value_resolver::AttributeStorage;
5
6use crate::container::Container;
7use crate::error::Result;
8use crate::layout::{Constraints, LayoutCtx, PositionFilter, Viewport};
9use crate::paint::{PaintCtx, PaintFilter, Unsized};
10use crate::widget::ForEach;
11use crate::{LayoutForEach, WidgetId};
12
13pub enum Layout {
14 Changed(Size),
15 Unchanged(Size),
16 Floating(Size),
17}
18
19impl From<Layout> for Size {
20 fn from(value: Layout) -> Self {
21 match value {
22 Layout::Changed(size) | Layout::Unchanged(size) | Layout::Floating(size) => size,
23 }
24 }
25}
26
27#[derive(Debug)]
30pub struct Element<'bp> {
31 pub ident: &'bp str,
32 pub(crate) container: Container,
33}
34
35impl<'bp> Element<'bp> {
36 pub fn id(&self) -> WidgetId {
37 self.container.id
38 }
39
40 pub(crate) fn new(ident: &'bp str, container: Container) -> Self {
41 Self { ident, container }
42 }
43
44 pub fn layout(
45 &mut self,
46 mut children: LayoutForEach<'_, 'bp>,
47 constraints: Constraints,
48 ctx: &mut LayoutCtx<'_, 'bp>,
49 ) -> Result<Layout> {
50 let count = children.len();
57 let mut rebuild = self.container.cache.count_check(count);
58
59 if let Some(size) = self.cached_size() {
60 _ = children.each(ctx, |ctx, node, children| {
61 let constraints = match node.container.cache.constraints() {
75 None => constraints,
76 Some(constraints) => constraints,
77 };
78
79 match node.layout(children, constraints, ctx)? {
80 Layout::Changed(_) => {
81 rebuild = true;
82 Ok(ControlFlow::Break(()))
83 }
84 Layout::Floating(_) | Layout::Unchanged(_) => Ok(ControlFlow::Continue(())),
85 }
86 })?;
87
88 if !self.container.cache.count_check(count) {
89 rebuild = true;
90 }
91
92 if !rebuild {
93 return Ok(Layout::Unchanged(size));
94 }
95 }
96
97 self.container.layout(children, constraints, ctx)
98 }
99
100 pub fn invalidate_cache(&mut self) {
101 self.container.cache.invalidate();
102 }
103
104 pub fn position(
106 &mut self,
107 children: ForEach<'_, 'bp, PositionFilter>,
108 pos: Pos,
109 attribute_storage: &AttributeStorage<'bp>,
110 viewport: Viewport,
111 ) {
112 self.container.position(children, pos, attribute_storage, viewport)
113 }
114
115 pub fn paint(
117 &mut self,
118 children: ForEach<'_, 'bp, PaintFilter>,
119 ctx: PaintCtx<'_, Unsized>,
120 attribute_storage: &AttributeStorage<'bp>,
121 ) {
122 self.container.paint(children, ctx, attribute_storage);
123 }
124
125 pub fn cached_size(&self) -> Option<Size> {
128 self.container.cache.size()
129 }
130
131 pub fn size(&self) -> Size {
132 self.container.cache.size
133 }
134
135 pub fn inner_bounds(&self) -> Region {
137 self.container.inner_bounds
138 }
139
140 pub fn bounds(&self) -> Region {
142 let pos = self.get_pos();
143 let size = self.size();
144 Region::from((pos, size))
145 }
146
147 pub fn to<T: 'static>(&mut self) -> &mut T {
153 self.try_to().expect("wrong element type")
154 }
155
156 pub fn try_to<T: 'static>(&mut self) -> Option<&mut T> {
158 self.container.inner.to_any_mut().downcast_mut::<T>()
159 }
160
161 pub fn to_ref<T: 'static>(&self) -> &T {
167 self.try_to_ref().expect("wrong element type")
168 }
169
170 pub fn try_to_ref<T: 'static>(&self) -> Option<&T> {
172 self.container.inner.to_any_ref().downcast_ref::<T>()
173 }
174
175 pub fn get_pos(&self) -> Pos {
177 self.container.cache.pos.unwrap_or(Pos::ZERO)
178 }
179
180 pub(crate) fn is_floating(&self) -> bool {
182 self.container.inner.any_floats()
183 }
184}