1use crate::{
2 AnyElement, AppContext, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement,
3 IntoAnyElement, LayoutId, ParentElement, Pixels, SharedString, Style, StyleCascade, Styled,
4 ViewContext,
5};
6use collections::HashMap;
7use refineable::Refineable;
8use smallvec::SmallVec;
9
10#[derive(Default)]
11struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
12
13pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
14 cx.default_global::<GroupBounds>()
15 .0
16 .get(name)
17 .and_then(|bounds_stack| bounds_stack.last().cloned())
18}
19
20pub trait ElementKind: 'static + Send + Sync {
21 fn id(&self) -> Option<ElementId>;
22}
23
24pub struct IdentifiedElementKind(ElementId);
25pub struct AnonymousElementKind;
26
27impl ElementKind for IdentifiedElementKind {
28 fn id(&self) -> Option<ElementId> {
29 Some(self.0.clone())
30 }
31}
32
33impl ElementKind for AnonymousElementKind {
34 fn id(&self) -> Option<ElementId> {
35 None
36 }
37}
38
39pub struct LayoutNodeElement<V: 'static + Send + Sync, K: ElementKind> {
40 style_cascade: StyleCascade,
41 computed_style: Option<Style>,
42 children: SmallVec<[AnyElement<V>; 2]>,
43 kind: K,
44 group: Option<SharedString>,
45}
46
47impl<V: 'static + Send + Sync> LayoutNodeElement<V, AnonymousElementKind> {
48 pub fn new() -> LayoutNodeElement<V, AnonymousElementKind> {
49 LayoutNodeElement {
50 style_cascade: StyleCascade::default(),
51 computed_style: None,
52 children: SmallVec::new(),
53 kind: AnonymousElementKind,
54 group: None,
55 }
56 }
57
58 pub fn identify(self, id: impl Into<ElementId>) -> LayoutNodeElement<V, IdentifiedElementKind> {
59 LayoutNodeElement {
60 style_cascade: self.style_cascade,
61 computed_style: self.computed_style,
62 children: self.children,
63 kind: IdentifiedElementKind(id.into()),
64 group: self.group,
65 }
66 }
67}
68
69impl<V: 'static + Send + Sync, E: ElementKind> LayoutNodeElement<V, E> {
70 pub fn set_group(&mut self, group: impl Into<SharedString>) {
71 self.group = Some(group.into());
72 }
73
74 fn with_element_id<R>(
75 &mut self,
76 cx: &mut ViewContext<V>,
77 f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
78 ) -> R {
79 if let Some(id) = self.id() {
80 cx.with_element_id(id, |cx| f(self, cx))
81 } else {
82 f(self, cx)
83 }
84 }
85}
86
87impl<V: 'static + Send + Sync, K: ElementKind> Styled for LayoutNodeElement<V, K> {
88 fn style_cascade(&mut self) -> &mut StyleCascade {
89 &mut self.style_cascade
90 }
91
92 fn computed_style(&mut self) -> &Style {
93 self.computed_style
94 .get_or_insert_with(|| Style::default().refined(self.style_cascade.merged()))
95 }
96}
97
98impl<V: 'static + Send + Sync> IdentifiedElement for LayoutNodeElement<V, IdentifiedElementKind> {
99 fn id(&self) -> ElementId {
100 self.kind.0.clone()
101 }
102}
103
104impl<V, K> IntoAnyElement<V> for LayoutNodeElement<V, K>
105where
106 V: 'static + Send + Sync,
107 K: ElementKind,
108{
109 fn into_any(self) -> AnyElement<V> {
110 AnyElement::new(self)
111 }
112}
113
114impl<V: 'static + Send + Sync, K: ElementKind> Element for LayoutNodeElement<V, K> {
115 type ViewState = V;
116 type ElementState = ();
117
118 fn id(&self) -> Option<ElementId> {
119 self.kind.id()
120 }
121
122 fn layout(
123 &mut self,
124 state: &mut Self::ViewState,
125 _: Option<Self::ElementState>,
126 cx: &mut ViewContext<Self::ViewState>,
127 ) -> (LayoutId, Self::ElementState) {
128 self.with_element_id(cx, |this, cx| {
129 let layout_ids = this
130 .children
131 .iter_mut()
132 .map(|child| child.layout(state, cx))
133 .collect::<Vec<_>>();
134
135 let style = this.computed_style();
136 let layout_id = cx.request_layout(style, layout_ids);
137 (layout_id, ())
138 })
139 }
140
141 fn paint(
142 &mut self,
143 bounds: Bounds<Pixels>,
144 state: &mut Self::ViewState,
145 _: &mut Self::ElementState,
146 cx: &mut ViewContext<Self::ViewState>,
147 ) {
148 self.with_element_id(cx, |this, cx| {
149 if let Some(group) = this.group.clone() {
150 cx.default_global::<GroupBounds>()
151 .0
152 .entry(group)
153 .or_default()
154 .push(bounds);
155 }
156
157 let style = this.computed_style().clone();
158 let z_index = style.z_index.unwrap_or(0);
159 cx.stack(z_index, |cx| style.paint(bounds, cx));
160
161 // todo!("implement overflow")
162 // let overflow = &style.overflow;
163
164 style.apply_text_style(cx, |cx| {
165 cx.stack(z_index + 1, |cx| {
166 style.apply_overflow(bounds, cx, |cx| {
167 for child in &mut this.children {
168 child.paint(state, None, cx);
169 }
170 })
171 })
172 });
173
174 if let Some(group) = this.group.as_ref() {
175 cx.default_global::<GroupBounds>()
176 .0
177 .get_mut(group)
178 .unwrap()
179 .pop();
180 }
181 })
182 }
183}
184
185impl<V: 'static + Send + Sync, K: ElementKind> ParentElement for LayoutNodeElement<V, K> {
186 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
187 &mut self.children
188 }
189
190 fn group_mut(&mut self) -> &mut Option<SharedString> {
191 &mut self.group
192 }
193}