div.rs

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