div.rs

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