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            .fill(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    type State = S;
 61
 62    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
 63        &mut self.children
 64    }
 65}
 66
 67#[derive(Element)]
 68pub struct PaneGroup<S: 'static + Send + Sync> {
 69    state_type: PhantomData<S>,
 70    groups: Vec<PaneGroup<S>>,
 71    panes: Vec<Pane<S>>,
 72    split_direction: SplitDirection,
 73}
 74
 75impl<S: 'static + Send + Sync> PaneGroup<S> {
 76    pub fn new_groups(groups: Vec<PaneGroup<S>>, split_direction: SplitDirection) -> Self {
 77        Self {
 78            state_type: PhantomData,
 79            groups,
 80            panes: Vec::new(),
 81            split_direction,
 82        }
 83    }
 84
 85    pub fn new_panes(panes: Vec<Pane<S>>, split_direction: SplitDirection) -> Self {
 86        Self {
 87            state_type: PhantomData,
 88            groups: Vec::new(),
 89            panes,
 90            split_direction,
 91        }
 92    }
 93
 94    fn render(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
 95        let theme = theme(cx);
 96
 97        if !self.panes.is_empty() {
 98            let el = div()
 99                .flex()
100                .flex_1()
101                .gap_px()
102                .w_full()
103                .h_full()
104                .fill(theme.lowest.base.default.background)
105                .children(self.panes.iter_mut().map(|pane| pane.render(view, cx)));
106
107            if self.split_direction == SplitDirection::Horizontal {
108                return el;
109            } else {
110                return el.flex_col();
111            }
112        }
113
114        if !self.groups.is_empty() {
115            let el = div()
116                .flex()
117                .flex_1()
118                .gap_px()
119                .w_full()
120                .h_full()
121                .fill(theme.lowest.base.default.background)
122                .children(self.groups.iter_mut().map(|group| group.render(view, cx)));
123
124            if self.split_direction == SplitDirection::Horizontal {
125                return el;
126            } else {
127                return el.flex_col();
128            }
129        }
130
131        unreachable!()
132    }
133}