div.rs

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