panes.rs

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