1use std::marker::PhantomData;
2
3use gpui2::{hsla, red, AnyElement, ElementId, ExternalPaths, 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
28 Self {
29 id: id.into(),
30 state_type: PhantomData,
31 size,
32 fill: hsla(0.3, 0.3, 0.3, 1.),
33 // fill: system_color.transparent,
34 children: SmallVec::new(),
35 }
36 }
37
38 pub fn fill(mut self, fill: Hsla) -> Self {
39 self.fill = fill;
40 self
41 }
42
43 fn render(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
44 div()
45 .id(self.id.clone())
46 .flex()
47 .flex_initial()
48 .bg(self.fill)
49 .w(self.size.width)
50 .h(self.size.height)
51 .relative()
52 .child(
53 div()
54 .z_index(0)
55 .size_full()
56 .children(self.children.drain(..)),
57 )
58 .child(
59 // TODO kb! Figure out why we can't we see the red background when we drag a file over this div.
60 div()
61 .z_index(1)
62 .id("drag-target")
63 .drag_over::<ExternalPaths>(|d| d.bg(red()))
64 .on_drop(|_, files: ExternalPaths, _| {
65 dbg!("dropped files!", files);
66 })
67 .absolute()
68 .inset_0(),
69 )
70 }
71}
72
73impl<S: 'static + Send + Sync> ParentElement for Pane<S> {
74 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]> {
75 &mut self.children
76 }
77}
78
79#[derive(Element)]
80pub struct PaneGroup<S: 'static + Send + Sync> {
81 state_type: PhantomData<S>,
82 groups: Vec<PaneGroup<S>>,
83 panes: Vec<Pane<S>>,
84 split_direction: SplitDirection,
85}
86
87impl<S: 'static + Send + Sync> PaneGroup<S> {
88 pub fn new_groups(groups: Vec<PaneGroup<S>>, split_direction: SplitDirection) -> Self {
89 Self {
90 state_type: PhantomData,
91 groups,
92 panes: Vec::new(),
93 split_direction,
94 }
95 }
96
97 pub fn new_panes(panes: Vec<Pane<S>>, split_direction: SplitDirection) -> Self {
98 Self {
99 state_type: PhantomData,
100 groups: Vec::new(),
101 panes,
102 split_direction,
103 }
104 }
105
106 fn render(&mut self, view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
107 let theme = theme(cx);
108
109 if !self.panes.is_empty() {
110 let el = div()
111 .flex()
112 .flex_1()
113 .gap_px()
114 .w_full()
115 .h_full()
116 .children(self.panes.iter_mut().map(|pane| pane.render(view, cx)));
117
118 if self.split_direction == SplitDirection::Horizontal {
119 return el;
120 } else {
121 return el.flex_col();
122 }
123 }
124
125 if !self.groups.is_empty() {
126 let el = div()
127 .flex()
128 .flex_1()
129 .gap_px()
130 .w_full()
131 .h_full()
132 .bg(theme.editor)
133 .children(self.groups.iter_mut().map(|group| group.render(view, cx)));
134
135 if self.split_direction == SplitDirection::Horizontal {
136 return el;
137 } else {
138 return el.flex_col();
139 }
140 }
141
142 unreachable!()
143 }
144}