panes.rs

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