div.rs

  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}