1use crate::{
2 AnyElement, Bounds, Element, ElementId, Interactive, LayoutId, MouseEventListeners, Overflow,
3 ParentElement, Pixels, Point, Refineable, RefinementCascade, StatefulElement, Style, Styled,
4 ViewContext,
5};
6use parking_lot::Mutex;
7use smallvec::SmallVec;
8use std::{marker::PhantomData, sync::Arc};
9
10pub enum HasId {}
11
12pub struct Div<S: 'static, I = ()> {
13 styles: RefinementCascade<Style>,
14 id: Option<ElementId>,
15 listeners: MouseEventListeners<S>,
16 children: SmallVec<[AnyElement<S>; 2]>,
17 scroll_state: Option<ScrollState>,
18 identified: PhantomData<I>,
19}
20
21pub fn div<S>() -> Div<S> {
22 Div {
23 styles: Default::default(),
24 id: None,
25 listeners: Default::default(),
26 children: Default::default(),
27 scroll_state: None,
28 identified: PhantomData,
29 }
30}
31
32impl<S: 'static + Send + Sync, Marker: 'static + Send + Sync> Element for Div<S, Marker> {
33 type ViewState = S;
34 type ElementState = ();
35
36 fn element_id(&self) -> Option<ElementId> {
37 self.id.clone()
38 }
39
40 fn layout(
41 &mut self,
42 view: &mut S,
43 _: Option<Self::ElementState>,
44 cx: &mut ViewContext<S>,
45 ) -> (LayoutId, Self::ElementState) {
46 let style = self.computed_style();
47 let child_layout_ids = style.apply_text_style(cx, |cx| self.layout_children(view, cx));
48 let layout_id = cx.request_layout(style.into(), child_layout_ids.clone());
49 (layout_id, ())
50 }
51
52 fn paint(
53 &mut self,
54 bounds: Bounds<Pixels>,
55 state: &mut S,
56 _: &mut (),
57 cx: &mut ViewContext<S>,
58 ) {
59 let style = self.computed_style();
60 cx.stack(0, |cx| style.paint(bounds, cx));
61
62 let overflow = &style.overflow;
63 style.apply_text_style(cx, |cx| {
64 cx.stack(1, |cx| {
65 style.apply_overflow(bounds, cx, |cx| {
66 self.listeners.paint(bounds, cx);
67 self.paint_children(overflow, state, cx)
68 })
69 })
70 });
71 }
72}
73
74impl<S> Div<S, ()>
75where
76 S: 'static + Send + Sync,
77{
78 pub fn id(self, id: impl Into<ElementId>) -> Div<S, HasId> {
79 Div {
80 styles: self.styles,
81 id: Some(id.into()),
82 listeners: self.listeners,
83 children: self.children,
84 scroll_state: self.scroll_state,
85 identified: PhantomData,
86 }
87 }
88}
89
90impl<S, Marker> Div<S, Marker>
91where
92 S: 'static + Send + Sync,
93 Marker: 'static + Send + Sync,
94{
95 pub fn overflow_hidden(mut self) -> Self {
96 self.declared_style().overflow.x = Some(Overflow::Hidden);
97 self.declared_style().overflow.y = Some(Overflow::Hidden);
98 self
99 }
100
101 pub fn overflow_hidden_x(mut self) -> Self {
102 self.declared_style().overflow.x = Some(Overflow::Hidden);
103 self
104 }
105
106 pub fn overflow_hidden_y(mut self) -> Self {
107 self.declared_style().overflow.y = Some(Overflow::Hidden);
108 self
109 }
110
111 pub fn overflow_scroll(mut self, scroll_state: ScrollState) -> Self {
112 self.scroll_state = Some(scroll_state);
113 self.declared_style().overflow.x = Some(Overflow::Scroll);
114 self.declared_style().overflow.y = Some(Overflow::Scroll);
115 self
116 }
117
118 pub fn overflow_x_scroll(mut self, scroll_state: ScrollState) -> Self {
119 self.scroll_state = Some(scroll_state);
120 self.declared_style().overflow.x = Some(Overflow::Scroll);
121 self
122 }
123
124 pub fn overflow_y_scroll(mut self, scroll_state: ScrollState) -> Self {
125 self.scroll_state = Some(scroll_state);
126 self.declared_style().overflow.y = Some(Overflow::Scroll);
127 self
128 }
129
130 fn scroll_offset(&self, overflow: &Point<Overflow>) -> Point<Pixels> {
131 let mut offset = Point::default();
132 if overflow.y == Overflow::Scroll {
133 offset.y = self.scroll_state.as_ref().unwrap().y();
134 }
135 if overflow.x == Overflow::Scroll {
136 offset.x = self.scroll_state.as_ref().unwrap().x();
137 }
138
139 offset
140 }
141
142 fn layout_children(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> Vec<LayoutId> {
143 self.children
144 .iter_mut()
145 .map(|child| child.layout(view, cx))
146 .collect()
147 }
148
149 fn paint_children(
150 &mut self,
151 overflow: &Point<Overflow>,
152 state: &mut S,
153 cx: &mut ViewContext<S>,
154 ) {
155 let scroll_offset = self.scroll_offset(overflow);
156 for child in &mut self.children {
157 child.paint(state, Some(scroll_offset), cx);
158 }
159 }
160}
161
162impl<V: 'static + Send + Sync, Marker: 'static + Send + Sync> Styled for Div<V, Marker> {
163 type Style = Style;
164
165 fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
166 &mut self.styles
167 }
168
169 fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
170 self.styles.base()
171 }
172}
173
174impl<V: Send + Sync + 'static> StatefulElement for Div<V, HasId> {}
175
176impl<V: Send + Sync + 'static> Interactive<V> for Div<V, HasId> {
177 fn listeners(&mut self) -> &mut MouseEventListeners<V> {
178 &mut self.listeners
179 }
180}
181
182impl<S: 'static> ParentElement for Div<S> {
183 type State = S;
184
185 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<S>; 2]> {
186 &mut self.children
187 }
188}
189
190#[derive(Default, Clone)]
191pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
192
193impl ScrollState {
194 pub fn x(&self) -> Pixels {
195 self.0.lock().x
196 }
197
198 pub fn set_x(&self, value: Pixels) {
199 self.0.lock().x = value;
200 }
201
202 pub fn y(&self) -> Pixels {
203 self.0.lock().y
204 }
205
206 pub fn set_y(&self, value: Pixels) {
207 self.0.lock().y = value;
208 }
209}