1use gpui2::{hsla, red, AnyElement, ElementId, ExternalPaths, Hsla, Length, Size, View};
2use smallvec::SmallVec;
3
4use crate::prelude::*;
5
6#[derive(Default, PartialEq)]
7pub enum SplitDirection {
8 #[default]
9 Horizontal,
10 Vertical,
11}
12
13#[derive(Component)]
14pub struct Pane<V: 'static> {
15 id: ElementId,
16 size: Size<Length>,
17 fill: Hsla,
18 children: SmallVec<[AnyElement<V>; 2]>,
19}
20
21impl<V: 'static> Pane<V> {
22 pub fn new(id: impl Into<ElementId>, size: Size<Length>) -> Self {
23 // Fill is only here for debugging purposes, remove before release
24
25 Self {
26 id: id.into(),
27 size,
28 fill: hsla(0.3, 0.3, 0.3, 1.),
29 children: SmallVec::new(),
30 }
31 }
32
33 pub fn fill(mut self, fill: Hsla) -> Self {
34 self.fill = fill;
35 self
36 }
37
38 fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
39 div()
40 .id(self.id.clone())
41 .flex()
42 .flex_initial()
43 .bg(self.fill)
44 .w(self.size.width)
45 .h(self.size.height)
46 .relative()
47 .child(div().z_index(0).size_full().children(self.children))
48 .child(
49 div()
50 .z_index(1)
51 .id("drag-target")
52 .drag_over::<ExternalPaths>(|d| d.bg(red()))
53 .on_drop(|_, files: View<ExternalPaths>, cx| {
54 dbg!("dropped files!", files.read(cx));
55 })
56 .absolute()
57 .inset_0(),
58 )
59 }
60}
61
62impl<V: 'static> ParentElement<V> for Pane<V> {
63 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
64 &mut self.children
65 }
66}
67
68#[derive(Component)]
69pub struct PaneGroup<V: 'static> {
70 groups: Vec<PaneGroup<V>>,
71 panes: Vec<Pane<V>>,
72 split_direction: SplitDirection,
73}
74
75impl<V: 'static> PaneGroup<V> {
76 pub fn new_groups(groups: Vec<PaneGroup<V>>, split_direction: SplitDirection) -> Self {
77 Self {
78 groups,
79 panes: Vec::new(),
80 split_direction,
81 }
82 }
83
84 pub fn new_panes(panes: Vec<Pane<V>>, split_direction: SplitDirection) -> Self {
85 Self {
86 groups: Vec::new(),
87 panes,
88 split_direction,
89 }
90 }
91
92 fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
93 if !self.panes.is_empty() {
94 let el = div()
95 .flex()
96 .flex_1()
97 .gap_px()
98 .w_full()
99 .h_full()
100 .children(self.panes.into_iter().map(|pane| pane.render(view, cx)));
101
102 if self.split_direction == SplitDirection::Horizontal {
103 return el;
104 } else {
105 return el.flex_col();
106 }
107 }
108
109 if !self.groups.is_empty() {
110 let el = div()
111 .flex()
112 .flex_1()
113 .gap_px()
114 .w_full()
115 .h_full()
116 .bg(cx.theme().colors().editor)
117 .children(self.groups.into_iter().map(|group| group.render(view, cx)));
118
119 if self.split_direction == SplitDirection::Horizontal {
120 return el;
121 } else {
122 return el.flex_col();
123 }
124 }
125
126 unreachable!()
127 }
128}