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 = self.width.unwrap_or(self.initial_width);
109
110 match self.current_side {
111 PanelSide::Left => {
112 panel_base = v_stack()
113 .flex_initial()
114 .h_full()
115 .w(current_width)
116 .fill(theme.middle.base.default.background)
117 .border_r()
118 .border_color(theme.middle.base.default.border);
119 }
120 PanelSide::Right => {
121 panel_base = v_stack()
122 .flex_initial()
123 .h_full()
124 .w(current_width)
125 .fill(theme.middle.base.default.background)
126 .border_l()
127 .border_color(theme.middle.base.default.border);
128 }
129 PanelSide::Bottom => {
130 panel_base = v_stack()
131 .flex_initial()
132 .w_full()
133 .h(current_width)
134 .fill(theme.middle.base.default.background)
135 .border_t()
136 .border_color(theme.middle.base.default.border);
137 }
138 }
139
140 panel_base.children_any((self.children)(cx, self.payload.as_ref()))
141 }
142}