1use std::marker::PhantomData;
2
3use gpui2::{hsla, AnyElement, ElementId, Hsla, Length, Size};
4use smallvec::SmallVec;
5
6use crate::prelude::*;
7
8#[derive(Default, PartialEq)]
9pub enum SplitDirection {
10 #[default]
11 Horizontal,
12 Vertical,
13}
14
15#[derive(Element)]
16pub struct Pane<S: 'static + Send + Sync> {
17 id: ElementId,
18 state_type: PhantomData<S>,
19 size: Size<Length>,
20 fill: Hsla,
21 children: SmallVec<[AnyElement<S>; 2]>,
22}
23
24impl<S: 'static + Send + Sync> Pane<S> {
25 pub fn new(id: impl Into<ElementId>, size: Size<Length>) -> Self {
26 // Fill is only here for debugging purposes, remove before release
27 let system_color = SystemColor::new();
28
29 Self {
30 id: id.into(),
31 state_type: PhantomData,
32 size,
33 fill: hsla(0.3, 0.3, 0.3, 1.),
34 // fill: system_color.transparent,
35 children: SmallVec::new(),
36 }
37 }
38
39 pub fn fill(mut self, fill: Hsla) -> Self {
40 self.fill = fill;
41 self
42 }
43
44 fn render(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
45 let color = ThemeColor::new(cx);
46
47 div()
48 .id(self.id.clone())
49 .flex()
50 .flex_initial()
51 .bg(self.fill)
52 .w(self.size.width)
53 .h(self.size.height)
54 .overflow_y_scroll()
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 color = ThemeColor::new(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 .children(self.panes.iter_mut().map(|pane| pane.render(view, cx)));
103
104 if self.split_direction == SplitDirection::Horizontal {
105 return el;
106 } else {
107 return el.flex_col();
108 }
109 }
110
111 if !self.groups.is_empty() {
112 let el = div()
113 .flex()
114 .flex_1()
115 .gap_px()
116 .w_full()
117 .h_full()
118 .bg(color.editor)
119 .children(self.groups.iter_mut().map(|group| group.render(view, cx)));
120
121 if self.split_direction == SplitDirection::Horizontal {
122 return el;
123 } else {
124 return el.flex_col();
125 }
126 }
127
128 unreachable!()
129 }
130}