1use std::marker::PhantomData;
2
3use gpui2::geometry::AbsoluteLength;
4
5use crate::prelude::*;
6use crate::{theme, token, v_stack};
7
8#[derive(Default, Debug, PartialEq, Eq, Hash, Clone, Copy)]
9pub enum PanelAllowedSides {
10 LeftOnly,
11 RightOnly,
12 BottomOnly,
13 #[default]
14 LeftAndRight,
15 All,
16}
17
18impl PanelAllowedSides {
19 /// Return a `HashSet` that contains the allowable `PanelSide`s.
20 pub fn allowed_sides(&self) -> HashSet<PanelSide> {
21 match self {
22 Self::LeftOnly => HashSet::from_iter([PanelSide::Left]),
23 Self::RightOnly => HashSet::from_iter([PanelSide::Right]),
24 Self::BottomOnly => HashSet::from_iter([PanelSide::Bottom]),
25 Self::LeftAndRight => HashSet::from_iter([PanelSide::Left, PanelSide::Right]),
26 Self::All => HashSet::from_iter([PanelSide::Left, PanelSide::Right, PanelSide::Bottom]),
27 }
28 }
29}
30
31#[derive(Default, Debug, PartialEq, Eq, Hash, Clone, Copy)]
32pub enum PanelSide {
33 #[default]
34 Left,
35 Right,
36 Bottom,
37}
38
39use std::collections::HashSet;
40
41#[derive(Element)]
42pub struct Panel<V: 'static> {
43 view_type: PhantomData<V>,
44 scroll_state: ScrollState,
45 current_side: PanelSide,
46 /// Defaults to PanelAllowedSides::LeftAndRight
47 allowed_sides: PanelAllowedSides,
48 initial_width: AbsoluteLength,
49 width: Option<AbsoluteLength>,
50 children: HackyChildren<V>,
51 payload: HackyChildrenPayload,
52}
53
54impl<V: 'static> Panel<V> {
55 pub fn new(
56 scroll_state: ScrollState,
57 children: HackyChildren<V>,
58 payload: HackyChildrenPayload,
59 ) -> Self {
60 let token = token();
61
62 Self {
63 view_type: PhantomData,
64 scroll_state,
65 current_side: PanelSide::default(),
66 allowed_sides: PanelAllowedSides::default(),
67 initial_width: token.default_panel_size,
68 width: None,
69 children,
70 payload,
71 }
72 }
73
74 pub fn initial_width(mut self, initial_width: AbsoluteLength) -> Self {
75 self.initial_width = initial_width;
76 self
77 }
78
79 pub fn width(mut self, width: AbsoluteLength) -> Self {
80 self.width = Some(width);
81 self
82 }
83
84 pub fn allowed_sides(mut self, allowed_sides: PanelAllowedSides) -> Self {
85 self.allowed_sides = allowed_sides;
86 self
87 }
88
89 pub fn side(mut self, side: PanelSide) -> Self {
90 let allowed_sides = self.allowed_sides.allowed_sides();
91
92 if allowed_sides.contains(&side) {
93 self.current_side = side;
94 } else {
95 panic!(
96 "The panel side {:?} was not added as allowed before it was set.",
97 side
98 );
99 }
100 self
101 }
102
103 fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
104 let token = token();
105 let theme = theme(cx);
106
107 let panel_base;
108 let current_width = if let Some(width) = self.width {
109 width
110 } else {
111 self.initial_width
112 };
113
114 match self.current_side {
115 PanelSide::Left => {
116 panel_base = v_stack()
117 .overflow_y_scroll(self.scroll_state.clone())
118 .h_full()
119 .w(current_width)
120 .fill(theme.middle.base.default.background)
121 .border_r()
122 .border_color(theme.middle.base.default.border);
123 }
124 PanelSide::Right => {
125 panel_base = v_stack()
126 .overflow_y_scroll(self.scroll_state.clone())
127 .h_full()
128 .w(current_width)
129 .fill(theme.middle.base.default.background)
130 .border_r()
131 .border_color(theme.middle.base.default.border);
132 }
133 PanelSide::Bottom => {
134 panel_base = v_stack()
135 .overflow_y_scroll(self.scroll_state.clone())
136 .w_full()
137 .h(current_width)
138 .fill(theme.middle.base.default.background)
139 .border_r()
140 .border_color(theme.middle.base.default.border);
141 }
142 }
143
144 panel_base.children_any((self.children)(cx, self.payload.as_ref()))
145 }
146}