gardesk/garfield / a7977df

Browse files

ui: add resizable sidebar width via drag

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
a7977dff44a3aa431213e4e34dede5c901f0d0ec
Parents
af05392
Tree
b5ac75a

2 changed files

StatusFile+-
M garfield/src/app.rs 28 3
M garfield/src/ui/sidebar.rs 25 0
garfield/src/app.rsmodified
@@ -51,6 +51,8 @@ pub struct App {
5151
     should_quit: bool,
5252
     /// Pane divider resize in progress (split pane pointer path).
5353
     pane_resize_path: Option<Vec<bool>>,
54
+    /// Sidebar resize in progress.
55
+    sidebar_resizing: bool,
5456
     /// Last click time for double-click detection.
5557
     last_click_time: Option<Instant>,
5658
     /// Last click position for double-click detection.
@@ -190,6 +192,7 @@ impl App {
190192
             help_modal,
191193
             should_quit: false,
192194
             pane_resize_path: None,
195
+            sidebar_resizing: false,
193196
             last_click_time: None,
194197
             last_click_pos: None,
195198
             drag_source_path: None,
@@ -326,6 +329,12 @@ impl App {
326329
             return;
327330
         }
328331
 
332
+        // Check for sidebar resize handle
333
+        if self.sidebar.is_resize_handle(pos) {
334
+            self.sidebar_resizing = true;
335
+            return;
336
+        }
337
+
329338
         // Check for pane split divider resize start
330339
         if let Some(path) = self.root_pane.split_divider_at(pos) {
331340
             self.pane_resize_path = Some(path);
@@ -416,8 +425,9 @@ impl App {
416425
         self.drag_active = false;
417426
         self.sidebar.set_drop_highlight(false);
418427
 
419
-        // Clear pane resize
428
+        // Clear resize states
420429
         self.pane_resize_path = None;
430
+        self.sidebar_resizing = false;
421431
 
422432
         if let Some(pane) = self.focused_pane_mut() {
423433
             if pane.is_resizing() {
@@ -431,6 +441,15 @@ impl App {
431441
 
432442
     /// Handle mouse move.
433443
     fn handle_mouse_move(&mut self, pos: Point) {
444
+        // Handle sidebar resize in progress
445
+        if self.sidebar_resizing {
446
+            let new_width = (pos.x - self.sidebar.bounds().x).max(0) as u32;
447
+            self.sidebar.set_width(new_width);
448
+            let size = self.renderer.size();
449
+            self.update_layout(size.width, size.height);
450
+            return;
451
+        }
452
+
434453
         // Handle pane divider resize in progress
435454
         if let Some(path) = &self.pane_resize_path {
436455
             let path_clone = path.clone();
@@ -1072,10 +1091,16 @@ impl App {
10721091
 
10731092
     /// Update layout.
10741093
     fn update_layout(&mut self, width: u32, height: u32) {
1075
-        let sidebar_w = self.sidebar.width();
1094
+        // Preserve current sidebar width (or use default if sidebar is hidden)
1095
+        let current_sidebar_width = if self.sidebar.is_visible() {
1096
+            self.sidebar.bounds().width
1097
+        } else {
1098
+            SIDEBAR_WIDTH
1099
+        };
1100
+        let sidebar_w = if self.sidebar.is_visible() { current_sidebar_width } else { 0 };
10761101
         let header_height = TAB_BAR_HEIGHT + TOOLBAR_HEIGHT + BREADCRUMB_HEIGHT;
10771102
 
1078
-        self.sidebar.set_bounds(Rect::new(0, 0, SIDEBAR_WIDTH, height));
1103
+        self.sidebar.set_bounds(Rect::new(0, 0, current_sidebar_width, height));
10791104
 
10801105
         self.tab_bar.set_bounds(Rect::new(
10811106
             sidebar_w as i32,
garfield/src/ui/sidebar.rsmodified
@@ -296,6 +296,11 @@ impl Sidebar {
296296
         self.bounds = bounds;
297297
     }
298298
 
299
+    /// Get current bounds.
300
+    pub fn bounds(&self) -> Rect {
301
+        self.bounds
302
+    }
303
+
299304
     /// Get sidebar width.
300305
     pub fn width(&self) -> u32 {
301306
         if self.visible {
@@ -305,6 +310,26 @@ impl Sidebar {
305310
         }
306311
     }
307312
 
313
+    /// Set sidebar width (clamped to min/max).
314
+    pub fn set_width(&mut self, width: u32) {
315
+        let min_width = 120;
316
+        let max_width = 400;
317
+        self.bounds.width = width.clamp(min_width, max_width);
318
+    }
319
+
320
+    /// Check if position is on the resize handle (right edge).
321
+    pub fn is_resize_handle(&self, pos: Point) -> bool {
322
+        if !self.visible {
323
+            return false;
324
+        }
325
+        let handle_x = self.bounds.x + self.bounds.width as i32;
326
+        let tolerance = 4;
327
+        pos.x >= handle_x - tolerance
328
+            && pos.x <= handle_x + tolerance
329
+            && pos.y >= self.bounds.y
330
+            && pos.y <= self.bounds.y + self.bounds.height as i32
331
+    }
332
+
308333
     /// Toggle visibility.
309334
     pub fn toggle(&mut self) {
310335
         self.visible = !self.visible;