1use std::cell::Cell;
2
3use crate::{
4 element::{AnyElement, Element, IntoElement, Layout, ParentElement},
5 hsla,
6 layout_context::LayoutContext,
7 paint_context::PaintContext,
8 style::{CornerRadii, Style, StyleHelpers, Styleable},
9 InteractionHandlers, Interactive,
10};
11use anyhow::Result;
12use gpui::{
13 platform::{MouseButton, MouseButtonEvent, MouseMovedEvent},
14 scene::{self},
15 LayoutId,
16};
17use refineable::{Refineable, RefinementCascade};
18use smallvec::SmallVec;
19use util::ResultExt;
20
21pub struct Div<V: 'static> {
22 styles: RefinementCascade<Style>,
23 handlers: InteractionHandlers<V>,
24 children: SmallVec<[AnyElement<V>; 2]>,
25}
26
27pub fn div<V>() -> Div<V> {
28 Div {
29 styles: Default::default(),
30 handlers: Default::default(),
31 children: Default::default(),
32 }
33}
34
35impl<V: 'static> Element<V> for Div<V> {
36 type PaintState = ();
37
38 fn layout(
39 &mut self,
40 view: &mut V,
41 cx: &mut LayoutContext<V>,
42 ) -> Result<(LayoutId, Self::PaintState)>
43 where
44 Self: Sized,
45 {
46 let style = self.computed_style();
47 let pop_text_style = style.text_style(cx).map_or(false, |style| {
48 cx.push_text_style(&style).log_err().is_some()
49 });
50
51 let children = self
52 .children
53 .iter_mut()
54 .map(|child| child.layout(view, cx))
55 .collect::<Result<Vec<LayoutId>>>()?;
56
57 if pop_text_style {
58 cx.pop_text_style();
59 }
60
61 Ok((cx.add_layout_node(style, children)?, ()))
62 }
63
64 fn paint(
65 &mut self,
66 view: &mut V,
67 layout: &Layout,
68 _: &mut Self::PaintState,
69 cx: &mut PaintContext<V>,
70 ) where
71 Self: Sized,
72 {
73 let style = self.computed_style();
74 let pop_text_style = style.text_style(cx).map_or(false, |style| {
75 cx.push_text_style(&style).log_err().is_some()
76 });
77 style.paint_background(layout.bounds, cx);
78 self.interaction_handlers()
79 .paint(layout.order, layout.bounds, cx);
80 for child in &mut self.children {
81 child.paint(view, layout.bounds.origin(), cx);
82 }
83 style.paint_foreground(layout.bounds, cx);
84 if pop_text_style {
85 cx.pop_text_style();
86 }
87
88 if cx.is_inspector_enabled() {
89 self.paint_inspector(layout, cx);
90 }
91 }
92}
93
94impl<V: 'static> Div<V> {
95 fn paint_inspector(&self, layout: &Layout, cx: &mut PaintContext<V>) {
96 let style = self.styles.merged();
97
98 let hovered = layout.bounds.contains_point(cx.mouse_position());
99 if hovered {
100 let rem_size = cx.rem_size();
101 cx.scene.push_quad(scene::Quad {
102 bounds: layout.bounds,
103 background: Some(hsla(0., 0., 1., 0.05).into()),
104 border: gpui::Border {
105 color: hsla(0., 0., 1., 0.2).into(),
106 top: 1.,
107 right: 1.,
108 bottom: 1.,
109 left: 1.,
110 },
111 corner_radii: CornerRadii::default()
112 .refined(&style.corner_radii)
113 .to_gpui(layout.bounds.size(), rem_size),
114 })
115 }
116
117 let bounds = layout.bounds;
118 let pressed = Cell::new(hovered && cx.is_mouse_down(MouseButton::Left));
119 cx.on_event(layout.order, move |_, event: &MouseButtonEvent, _| {
120 if bounds.contains_point(event.position) {
121 if event.is_down {
122 pressed.set(true);
123 } else if pressed.get() {
124 pressed.set(false);
125 eprintln!("clicked div {:?} {:#?}", bounds, style);
126 }
127 }
128 });
129
130 let hovered = Cell::new(hovered);
131 cx.on_event(layout.order, move |_, event: &MouseMovedEvent, cx| {
132 cx.bubble_event();
133 let hovered_now = bounds.contains_point(event.position);
134 if hovered.get() != hovered_now {
135 hovered.set(hovered_now);
136 cx.repaint();
137 }
138 });
139 }
140}
141
142impl<V> Styleable for Div<V> {
143 type Style = Style;
144
145 fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
146 &mut self.styles
147 }
148
149 fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {
150 self.styles.base()
151 }
152}
153
154impl<V> StyleHelpers for Div<V> {}
155
156impl<V> Interactive<V> for Div<V> {
157 fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
158 &mut self.handlers
159 }
160}
161
162impl<V: 'static> ParentElement<V> for Div<V> {
163 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
164 &mut self.children
165 }
166}
167
168impl<V: 'static> IntoElement<V> for Div<V> {
169 type Element = Self;
170
171 fn into_element(self) -> Self::Element {
172 self
173 }
174}