layout_node.rs

  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}