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