1use crate::{
2 AnyElement, Bounds, Element, Interactive, LayoutId, MouseEventListeners, Overflow,
3 ParentElement, Pixels, Point, Refineable, RefinementCascade, Result, Style, Styled,
4 ViewContext,
5};
6use parking_lot::Mutex;
7use smallvec::SmallVec;
8use std::sync::Arc;
9use util::ResultExt;
10
11pub struct Div<S: 'static> {
12 styles: RefinementCascade<Style>,
13 listeners: MouseEventListeners<S>,
14 children: SmallVec<[AnyElement<S>; 2]>,
15 scroll_state: Option<ScrollState>,
16}
17
18pub fn div<S>() -> Div<S> {
19 Div {
20 styles: Default::default(),
21 listeners: Default::default(),
22 children: Default::default(),
23 scroll_state: None,
24 }
25}
26
27impl<S: 'static + Send + Sync> Element for Div<S> {
28 type State = S;
29 type FrameState = Vec<LayoutId>;
30
31 fn layout(
32 &mut self,
33 view: &mut S,
34 cx: &mut ViewContext<S>,
35 ) -> Result<(LayoutId, Self::FrameState)> {
36 let style = self.computed_style();
37 let child_layout_ids = style.apply_text_style(cx, |cx| self.layout_children(view, cx))?;
38 let layout_id = cx.request_layout(style.into(), child_layout_ids.clone())?;
39 Ok((layout_id, child_layout_ids))
40 }
41
42 fn paint(
43 &mut self,
44 bounds: Bounds<Pixels>,
45 state: &mut S,
46 child_layout_ids: &mut Self::FrameState,
47 cx: &mut ViewContext<S>,
48 ) -> Result<()> {
49 let style = self.computed_style();
50 let z_index = style.z_index.unwrap_or(0);
51 cx.stack(z_index, |cx| style.paint(bounds, cx));
52
53 let overflow = &style.overflow;
54 style.apply_text_style(cx, |cx| {
55 cx.stack(z_index + 1, |cx| {
56 style.apply_overflow(bounds, cx, |cx| {
57 self.listeners.paint(bounds, cx);
58 self.paint_children(overflow, state, cx)
59 })
60 })
61 })?;
62 self.handle_scroll(bounds, style.overflow.clone(), child_layout_ids, cx);
63
64 // todo!("enable inspector")
65 // if cx.is_inspector_enabled() {
66 // self.paint_inspector(parent_origin, layout, cx);
67 // }
68 //
69
70 Ok(())
71 }
72}
73
74impl<S: 'static> Div<S> {
75 pub fn z_index(mut self, z_index: u32) -> Self {
76 self.declared_style().z_index = Some(z_index);
77 self
78 }
79
80 pub fn overflow_hidden(mut self) -> Self {
81 self.declared_style().overflow.x = Some(Overflow::Hidden);
82 self.declared_style().overflow.y = Some(Overflow::Hidden);
83 self
84 }
85
86 pub fn overflow_hidden_x(mut self) -> Self {
87 self.declared_style().overflow.x = Some(Overflow::Hidden);
88 self
89 }
90
91 pub fn overflow_hidden_y(mut self) -> Self {
92 self.declared_style().overflow.y = Some(Overflow::Hidden);
93 self
94 }
95
96 pub fn overflow_scroll(mut self, scroll_state: ScrollState) -> Self {
97 self.scroll_state = Some(scroll_state);
98 self.declared_style().overflow.x = Some(Overflow::Scroll);
99 self.declared_style().overflow.y = Some(Overflow::Scroll);
100 self
101 }
102
103 pub fn overflow_x_scroll(mut self, scroll_state: ScrollState) -> Self {
104 self.scroll_state = Some(scroll_state);
105 self.declared_style().overflow.x = Some(Overflow::Scroll);
106 self
107 }
108
109 pub fn overflow_y_scroll(mut self, scroll_state: ScrollState) -> Self {
110 self.scroll_state = Some(scroll_state);
111 self.declared_style().overflow.y = Some(Overflow::Scroll);
112 self
113 }
114
115 fn scroll_offset(&self, overflow: &Point<Overflow>) -> Point<Pixels> {
116 let mut offset = Point::default();
117 if overflow.y == Overflow::Scroll {
118 offset.y = self.scroll_state.as_ref().unwrap().y();
119 }
120 if overflow.x == Overflow::Scroll {
121 offset.x = self.scroll_state.as_ref().unwrap().x();
122 }
123
124 offset
125 }
126
127 fn layout_children(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> Result<Vec<LayoutId>> {
128 self.children
129 .iter_mut()
130 .map(|child| child.layout(view, cx))
131 .collect::<Result<Vec<LayoutId>>>()
132 }
133
134 fn paint_children(
135 &mut self,
136 overflow: &Point<Overflow>,
137 state: &mut S,
138 cx: &mut ViewContext<S>,
139 ) -> Result<()> {
140 let scroll_offset = self.scroll_offset(overflow);
141 for child in &mut self.children {
142 child.paint(state, Some(scroll_offset), cx)?;
143 }
144 Ok(())
145 }
146
147 fn handle_scroll(
148 &mut self,
149 bounds: Bounds<Pixels>,
150 overflow: Point<Overflow>,
151 child_layout_ids: &[LayoutId],
152 cx: &mut ViewContext<S>,
153 ) {
154 if overflow.y == Overflow::Scroll || overflow.x == Overflow::Scroll {
155 let mut scroll_max = Point::default();
156 for child_layout_id in child_layout_ids {
157 if let Some(child_bounds) = cx.layout_bounds(*child_layout_id).log_err() {
158 scroll_max = scroll_max.max(&child_bounds.lower_right());
159 }
160 }
161 scroll_max -= bounds.size;
162
163 // todo!("handle scroll")
164 // let scroll_state = self.scroll_state.as_ref().unwrap().clone();
165 // cx.on_event(order, move |_, event: &ScrollWheelEvent, cx| {
166 // if bounds.contains_point(event.position) {
167 // let scroll_delta = match event.delta {
168 // ScrollDelta::Pixels(delta) => delta,
169 // ScrollDelta::Lines(delta) => cx.text_style().font_size * delta,
170 // };
171 // if overflow.x == Overflow::Scroll {
172 // scroll_state.set_x(
173 // (scroll_state.x() - scroll_delta.x())
174 // .max(px(0.))
175 // .min(scroll_max.x),
176 // );
177 // }
178 // if overflow.y == Overflow::Scroll {
179 // scroll_state.set_y(
180 // (scroll_state.y() - scroll_delta.y())
181 // .max(px(0.))
182 // .min(scroll_max.y),
183 // );
184 // }
185 // cx.repaint();
186 // } else {
187 // cx.bubble_event();
188 // }
189 // })
190 }
191 }
192
193 // fn paint_inspector(
194 // &self,
195 // parent_origin: Point<Pixels>,
196 // layout: &Layout,
197 // cx: &mut ViewContext<V>,
198 // ) {
199 // let style = self.styles.merged();
200 // let bounds = layout.bounds;
201
202 // let hovered = bounds.contains_point(cx.mouse_position());
203 // if hovered {
204 // let rem_size = cx.rem_size();
205 // // cx.scene().push_quad(scene::Quad {
206 // // bounds,
207 // // background: Some(hsla(0., 0., 1., 0.05).into()),
208 // // border: gpui::Border {
209 // // color: hsla(0., 0., 1., 0.2).into(),
210 // // top: 1.,
211 // // right: 1.,
212 // // bottom: 1.,
213 // // left: 1.,
214 // // },
215 // // corner_radii: CornerRadii::default()
216 // // .refined(&style.corner_radii)
217 // // .to_gpui(bounds.size(), rem_size),
218 // // })
219 // }
220
221 // // let pressed = Cell::new(hovered && cx.is_mouse_down(MouseButton::Left));
222 // // cx.on_event(layout.order, move |_, event: &MouseButtonEvent, _| {
223 // // if bounds.contains_point(event.position) {
224 // // if event.is_down {
225 // // pressed.set(true);
226 // // } else if pressed.get() {
227 // // pressed.set(false);
228 // // eprintln!("clicked div {:?} {:#?}", bounds, style);
229 // // }
230 // // }
231 // // });
232
233 // // let hovered = Cell::new(hovered);
234 // // cx.on_event(layout.order, move |_, event: &MouseMovedEvent, cx| {
235 // // cx.bubble_event();
236 // // let hovered_now = bounds.contains_point(event.position);
237 // // if hovered.get() != hovered_now {
238 // // hovered.set(hovered_now);
239 // // cx.repaint();
240 // // }
241 // // });
242 // }
243 //
244}
245
246impl<V> Styled for Div<V> {
247 type Style = Style;
248
249 fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
250 &mut self.styles
251 }
252
253 fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
254 self.styles.base()
255 }
256}
257
258impl<V: Send + Sync + 'static> Interactive<V> for Div<V> {
259 fn listeners(&mut self) -> &mut MouseEventListeners<V> {
260 &mut self.listeners
261 }
262}
263
264impl<S: 'static> ParentElement for Div<S> {
265 type State = S;
266
267 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<S>; 2]> {
268 &mut self.children
269 }
270}
271
272#[derive(Default, Clone)]
273pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
274
275impl ScrollState {
276 pub fn x(&self) -> Pixels {
277 self.0.lock().x
278 }
279
280 pub fn set_x(&self, value: Pixels) {
281 self.0.lock().x = value;
282 }
283
284 pub fn y(&self) -> Pixels {
285 self.0.lock().y
286 }
287
288 pub fn set_y(&self, value: Pixels) {
289 self.0.lock().y = value;
290 }
291}