panes.rs

  1use gpui2::{hsla, red, AnyElement, ElementId, ExternalPaths, Hsla, Length, Size};
  2use smallvec::SmallVec;
  3
  4use crate::prelude::*;
  5
  6#[derive(Default, PartialEq)]
  7pub enum SplitDirection {
  8    #[default]
  9    Horizontal,
 10    Vertical,
 11}
 12
 13#[derive(Component)]
 14pub struct Pane<V: 'static> {
 15    id: ElementId,
 16    size: Size<Length>,
 17    fill: Hsla,
 18    children: SmallVec<[AnyElement<V>; 2]>,
 19}
 20
 21// impl<V: 'static> IntoAnyElement<V> for Pane<V> {
 22//     fn into_any(self) -> AnyElement<V> {
 23//         (move |view_state: &mut V, cx: &mut ViewContext<'_, '_, V>| self.render(view_state, cx))
 24//             .into_any()
 25//     }
 26// }
 27
 28impl<V: 'static> Pane<V> {
 29    pub fn new(id: impl Into<ElementId>, size: Size<Length>) -> Self {
 30        // Fill is only here for debugging purposes, remove before release
 31
 32        Self {
 33            id: id.into(),
 34            size,
 35            fill: hsla(0.3, 0.3, 0.3, 1.),
 36            children: SmallVec::new(),
 37        }
 38    }
 39
 40    pub fn fill(mut self, fill: Hsla) -> Self {
 41        self.fill = fill;
 42        self
 43    }
 44
 45    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
 46        div()
 47            .id(self.id.clone())
 48            .flex()
 49            .flex_initial()
 50            .bg(self.fill)
 51            .w(self.size.width)
 52            .h(self.size.height)
 53            .relative()
 54            .child(div().z_index(0).size_full().children(self.children))
 55            .child(
 56                div()
 57                    .z_index(1)
 58                    .id("drag-target")
 59                    .drag_over::<ExternalPaths>(|d| d.bg(red()))
 60                    .on_drop(|_, files: ExternalPaths, _| {
 61                        dbg!("dropped files!", files);
 62                    })
 63                    .absolute()
 64                    .inset_0(),
 65            )
 66    }
 67}
 68
 69impl<V: 'static> ParentElement<V> for Pane<V> {
 70    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
 71        &mut self.children
 72    }
 73}
 74
 75#[derive(Component)]
 76pub struct PaneGroup<V: 'static> {
 77    groups: Vec<PaneGroup<V>>,
 78    panes: Vec<Pane<V>>,
 79    split_direction: SplitDirection,
 80}
 81
 82impl<V: 'static> PaneGroup<V> {
 83    pub fn new_groups(groups: Vec<PaneGroup<V>>, split_direction: SplitDirection) -> Self {
 84        Self {
 85            groups,
 86            panes: Vec::new(),
 87            split_direction,
 88        }
 89    }
 90
 91    pub fn new_panes(panes: Vec<Pane<V>>, split_direction: SplitDirection) -> Self {
 92        Self {
 93            groups: Vec::new(),
 94            panes,
 95            split_direction,
 96        }
 97    }
 98
 99    fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
100        let theme = theme(cx);
101
102        if !self.panes.is_empty() {
103            let el = div()
104                .flex()
105                .flex_1()
106                .gap_px()
107                .w_full()
108                .h_full()
109                .children(self.panes.into_iter().map(|pane| pane.render(view, cx)));
110
111            if self.split_direction == SplitDirection::Horizontal {
112                return el;
113            } else {
114                return el.flex_col();
115            }
116        }
117
118        if !self.groups.is_empty() {
119            let el = div()
120                .flex()
121                .flex_1()
122                .gap_px()
123                .w_full()
124                .h_full()
125                .bg(theme.editor)
126                .children(self.groups.into_iter().map(|group| group.render(view, cx)));
127
128            if self.split_direction == SplitDirection::Horizontal {
129                return el;
130            } else {
131                return el.flex_col();
132            }
133        }
134
135        unreachable!()
136    }
137}