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 live_size: Option<Pixels>,
118 resizing: bool,
119}
120
121impl Dock {
122 pub fn new(size: Pixels) -> Self {
123 Self {
124 open: true,
125 collapsible: true,
126 size,
127 live_size: None,
128 resizing: false,
129 }
130 }
131
132 pub fn is_open(&self) -> bool {
133 self.open
134 }
135
136 pub fn set_open(&mut self, open: bool) {
137 self.open = open;
138 }
139
140 pub fn is_collapsible(&self) -> bool {
141 self.collapsible
142 }
143
144 pub fn set_collapsible(&mut self, collapsible: bool) {
145 self.collapsible = collapsible;
146 }
147
148 pub fn size(&self) -> Pixels {
149 self.size
150 }
151
152 pub fn set_size(&mut self, size: Pixels) {
159 self.size = size.max(PANEL_MIN_SIZE);
160 }
161
162 pub(crate) fn live_size(&self) -> Option<Pixels> {
166 self.live_size
167 }
168
169 pub(crate) fn set_live_size(&mut self, size: Option<Pixels>) {
170 self.live_size = size;
171 }
172
173 pub fn is_resizing(&self) -> bool {
174 self.resizing
175 }
176
177 pub fn set_resizing(&mut self, resizing: bool) {
178 self.resizing = resizing;
179 }
180}
181
182#[cfg(test)]
183mod dock_tests {
184 use super::*;
185 use gpui::{point, size};
186
187 #[test]
188 fn a_left_dock_cannot_squeeze_past_the_right_dock() {
189 let sizing = DockSizing::new(DockPlacement::Left)
190 .with_area_width(px(1000.))
191 .with_opposite_dock_size(px(300.));
192
193 assert_eq!(
194 sizing.clamp(px(900.)),
195 px(1000.) - PANEL_MIN_SIZE - px(300.)
196 );
197 }
198
199 #[test]
200 fn a_dock_never_clamps_below_the_minimum() {
201 let sizing = DockSizing::new(DockPlacement::Bottom).with_area_height(px(120.));
202 assert_eq!(sizing.clamp(px(1.)), PANEL_MIN_SIZE);
203 }
204
205 #[test]
206 fn a_bottom_dock_measures_from_the_area_bottom() {
207 let sizing = DockSizing::new(DockPlacement::Bottom).with_area_bounds(Bounds {
208 origin: point(px(0.), px(0.)),
209 size: size(px(800.), px(600.)),
210 });
211
212 assert_eq!(
213 sizing.size_from_pointer(point(px(400.), px(400.))),
214 px(200.)
215 );
216 }
217
218 #[test]
219 fn a_right_dock_measures_from_the_area_right_edge() {
220 let sizing = DockSizing::new(DockPlacement::Right).with_area_bounds(Bounds {
221 origin: point(px(0.), px(0.)),
222 size: size(px(800.), px(600.)),
223 });
224
225 assert_eq!(sizing.size_from_pointer(point(px(500.), px(0.))), px(300.));
226 }
227
228 #[test]
232 fn a_dock_never_shrinks_below_the_minimum() {
233 let mut dock = Dock::new(px(240.));
234 dock.set_size(px(1.));
235 assert_eq!(dock.size(), PANEL_MIN_SIZE);
236
237 dock.set_size(px(400.));
238 assert_eq!(dock.size(), px(400.), "a size above the floor is kept");
239 }
240
241 #[test]
245 fn the_center_placement_is_answered_rather_than_panicking() {
246 let sizing = DockSizing::new(DockPlacement::Center).with_area_bounds(Bounds {
247 origin: point(px(0.), px(0.)),
248 size: size(px(800.), px(600.)),
249 });
250
251 assert_eq!(sizing.clamp(px(7.)), px(7.), "the center clamps nothing");
252 assert_eq!(sizing.size_from_pointer(point(px(400.), px(300.))), px(0.));
253 }
254
255 #[test]
256 fn dock_state_defaults_to_open_and_collapsible() {
257 let dock = Dock::new(px(240.));
258 assert!(dock.is_open());
259 assert!(dock.is_collapsible());
260 assert_eq!(dock.size(), px(240.));
261 assert!(!dock.is_resizing());
262 }
263}