gpui_base/dock/
dock_placement.rs1use gpui::{Bounds, Pixels, Point, px};
9
10use crate::PANEL_MIN_SIZE;
11
12use super::state::DockPlacement;
13
14#[derive(Clone, Copy, Debug)]
20pub struct DockSizing {
21 placement: DockPlacement,
22 area: Bounds<Pixels>,
23 opposite_dock_size: Pixels,
24}
25
26impl DockSizing {
27 pub fn new(placement: DockPlacement) -> Self {
28 Self {
29 placement,
30 area: Bounds::default(),
31 opposite_dock_size: px(0.),
32 }
33 }
34
35 pub fn with_area_bounds(mut self, area: Bounds<Pixels>) -> Self {
39 self.area = area;
40 self
41 }
42
43 pub fn with_area_width(mut self, width: Pixels) -> Self {
47 self.area.size.width = width;
48 self
49 }
50
51 pub fn with_area_height(mut self, height: Pixels) -> Self {
55 self.area.size.height = height;
56 self
57 }
58
59 pub fn with_opposite_dock_size(mut self, size: Pixels) -> Self {
62 self.opposite_dock_size = size;
63 self
64 }
65
66 pub fn size_from_pointer(&self, pointer: Point<Pixels>) -> Pixels {
75 match self.placement {
76 DockPlacement::Left => pointer.x - self.area.left(),
77 DockPlacement::Right => self.area.right() - pointer.x,
78 DockPlacement::Bottom => self.area.bottom() - pointer.y,
79 DockPlacement::Center => px(0.),
80 }
81 }
82
83 pub fn clamp(&self, size: Pixels) -> Pixels {
93 let max_size = match self.placement {
94 DockPlacement::Left | DockPlacement::Right => {
95 (self.area.size.width - PANEL_MIN_SIZE - self.opposite_dock_size)
96 .max(PANEL_MIN_SIZE)
97 }
98 DockPlacement::Bottom => (self.area.size.height - PANEL_MIN_SIZE).max(PANEL_MIN_SIZE),
99 DockPlacement::Center => return size,
100 };
101 size.clamp(PANEL_MIN_SIZE, max_size)
102 }
103}
104
105#[derive(Clone, Copy, Debug)]
113pub struct Dock {
114 open: bool,
115 collapsible: bool,
116 size: Pixels,
117 resizing: bool,
118}
119
120impl Dock {
121 pub fn new(size: Pixels) -> Self {
122 Self {
123 open: true,
124 collapsible: true,
125 size,
126 resizing: false,
127 }
128 }
129
130 pub fn is_open(&self) -> bool {
131 self.open
132 }
133
134 pub fn set_open(&mut self, open: bool) {
135 self.open = open;
136 }
137
138 pub fn is_collapsible(&self) -> bool {
139 self.collapsible
140 }
141
142 pub fn set_collapsible(&mut self, collapsible: bool) {
143 self.collapsible = collapsible;
144 }
145
146 pub fn size(&self) -> Pixels {
147 self.size
148 }
149
150 pub fn set_size(&mut self, size: Pixels) {
157 self.size = size.max(PANEL_MIN_SIZE);
158 }
159
160 pub fn is_resizing(&self) -> bool {
161 self.resizing
162 }
163
164 pub fn set_resizing(&mut self, resizing: bool) {
165 self.resizing = resizing;
166 }
167}
168
169#[cfg(test)]
170mod dock_tests {
171 use super::*;
172 use gpui::{point, size};
173
174 #[test]
175 fn a_left_dock_cannot_squeeze_past_the_right_dock() {
176 let sizing = DockSizing::new(DockPlacement::Left)
177 .with_area_width(px(1000.))
178 .with_opposite_dock_size(px(300.));
179
180 assert_eq!(
181 sizing.clamp(px(900.)),
182 px(1000.) - PANEL_MIN_SIZE - px(300.)
183 );
184 }
185
186 #[test]
187 fn a_dock_never_clamps_below_the_minimum() {
188 let sizing = DockSizing::new(DockPlacement::Bottom).with_area_height(px(120.));
189 assert_eq!(sizing.clamp(px(1.)), PANEL_MIN_SIZE);
190 }
191
192 #[test]
193 fn a_bottom_dock_measures_from_the_area_bottom() {
194 let sizing = DockSizing::new(DockPlacement::Bottom).with_area_bounds(Bounds {
195 origin: point(px(0.), px(0.)),
196 size: size(px(800.), px(600.)),
197 });
198
199 assert_eq!(
200 sizing.size_from_pointer(point(px(400.), px(400.))),
201 px(200.)
202 );
203 }
204
205 #[test]
206 fn a_right_dock_measures_from_the_area_right_edge() {
207 let sizing = DockSizing::new(DockPlacement::Right).with_area_bounds(Bounds {
208 origin: point(px(0.), px(0.)),
209 size: size(px(800.), px(600.)),
210 });
211
212 assert_eq!(sizing.size_from_pointer(point(px(500.), px(0.))), px(300.));
213 }
214
215 #[test]
219 fn a_dock_never_shrinks_below_the_minimum() {
220 let mut dock = Dock::new(px(240.));
221 dock.set_size(px(1.));
222 assert_eq!(dock.size(), PANEL_MIN_SIZE);
223
224 dock.set_size(px(400.));
225 assert_eq!(dock.size(), px(400.), "a size above the floor is kept");
226 }
227
228 #[test]
232 fn the_center_placement_is_answered_rather_than_panicking() {
233 let sizing = DockSizing::new(DockPlacement::Center).with_area_bounds(Bounds {
234 origin: point(px(0.), px(0.)),
235 size: size(px(800.), px(600.)),
236 });
237
238 assert_eq!(sizing.clamp(px(7.)), px(7.), "the center clamps nothing");
239 assert_eq!(sizing.size_from_pointer(point(px(400.), px(300.))), px(0.));
240 }
241
242 #[test]
243 fn dock_state_defaults_to_open_and_collapsible() {
244 let dock = Dock::new(px(240.));
245 assert!(dock.is_open());
246 assert!(dock.is_collapsible());
247 assert_eq!(dock.size(), px(240.));
248 assert!(!dock.is_resizing());
249 }
250}