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