panes.rs

  1use std::marker::PhantomData;
  2
  3use gpui3::{hsla, AnyElement, Hsla, Length, Size};
  4use smallvec::SmallVec;
  5
  6use crate::prelude::*;
  7use crate::theme;
  8
  9#[derive(Default, PartialEq)]
 10pub enum SplitDirection {
 11    #[default]
 12    Horizontal,
 13    Vertical,
 14}
 15
 16#[derive(Element)]
 17pub struct Pane<S: 'static + Send + Sync> {
 18    state_type: PhantomData<S>,
 19    scroll_state: ScrollState,
 20    size: Size<Length>,
 21    fill: Hsla,
 22    children: SmallVec<[AnyElement<S>; 2]>,
 23}
 24
 25impl<S: 'static + Send + Sync> Pane<S> {
 26    pub fn new(scroll_state: ScrollState, size: Size<Length>) -> Self {
 27        // Fill is only here for debugging purposes, remove before release
 28        let system_color = SystemColor::new();
 29
 30        Self {
 31            state_type: PhantomData,
 32            scroll_state,
 33            size,
 34            fill: hsla(0.3, 0.3, 0.3, 1.),
 35            // fill: system_color.transparent,
 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(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
 46        let theme = theme(cx);
 47
 48        div()
 49            .flex()
 50            .flex_initial()
 51            .bg(self.fill)
 52            .w(self.size.width)
 53            .h(self.size.height)
 54            .overflow_y_scroll(self.scroll_state.clone())
 55            .children(self.children.drain(..))
 56    }
 57}
 58
 59impl<S: 'static + Send + Sync> ParentElement for Pane<S> {
 60    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]> {
 61        &mut self.children
 62    }
 63}
 64
 65#[derive(Element)]
 66pub struct PaneGroup<S: 'static + Send + Sync> {
 67    state_type: PhantomData<S>,
 68    groups: Vec<PaneGroup<S>>,
 69    panes: Vec<Pane<S>>,
 70    split_direction: SplitDirection,
 71}
 72
 73impl<S: 'static + Send + Sync> PaneGroup<S> {
 74    pub fn new_groups(groups: Vec<PaneGroup<S>>, split_direction: SplitDirection) -> Self {
 75        Self {
 76            state_type: PhantomData,
 77            groups,
 78            panes: Vec::new(),
 79            split_direction,
 80        }
 81    }
 82
 83    pub fn new_panes(panes: Vec<Pane<S>>, split_direction: SplitDirection) -> Self {
 84        Self {
 85            state_type: PhantomData,
 86            groups: Vec::new(),
 87            panes,
 88            split_direction,
 89        }
 90    }
 91
 92    fn render(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
 93        let theme = theme(cx);
 94
 95        if !self.panes.is_empty() {
 96            let el = div()
 97                .flex()
 98                .flex_1()
 99                .gap_px()
100                .w_full()
101                .h_full()
102                .bg(theme.lowest.base.default.background)
103                .children(self.panes.iter_mut().map(|pane| pane.render(view, cx)));
104
105            if self.split_direction == SplitDirection::Horizontal {
106                return el;
107            } else {
108                return el.flex_col();
109            }
110        }
111
112        if !self.groups.is_empty() {
113            let el = div()
114                .flex()
115                .flex_1()
116                .gap_px()
117                .w_full()
118                .h_full()
119                .bg(theme.lowest.base.default.background)
120                .children(self.groups.iter_mut().map(|group| group.render(view, cx)));
121
122            if self.split_direction == SplitDirection::Horizontal {
123                return el;
124            } else {
125                return el.flex_col();
126            }
127        }
128
129        unreachable!()
130    }
131}