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}