Dismiss zoomed panels by closing their dock, not zooming them out

Max Brunsfeld created

Change summary

crates/workspace/src/dock.rs      |   4 +
crates/workspace/src/workspace.rs | 110 ++++++++++++++++++---------------
2 files changed, 64 insertions(+), 50 deletions(-)

Detailed changes

crates/workspace/src/dock.rs 🔗

@@ -175,6 +175,10 @@ impl Dock {
         }
     }
 
+    pub fn position(&self) -> DockPosition {
+        self.position
+    }
+
     pub fn is_open(&self) -> bool {
         self.is_open
     }

crates/workspace/src/workspace.rs 🔗

@@ -908,18 +908,24 @@ impl Workspace {
                         }
                     });
                 } else if T::should_zoom_in_on_event(event) {
-                    this.zoom_out(cx);
                     dock.update(cx, |dock, cx| dock.set_panel_zoomed(&panel, true, cx));
                     if panel.has_focus(cx) {
                         this.zoomed = Some(panel.downgrade().into_any());
                         this.zoomed_position = Some(panel.read(cx).position(cx));
                     }
                 } else if T::should_zoom_out_on_event(event) {
-                    this.zoom_out(cx);
+                    dock.update(cx, |dock, cx| dock.set_panel_zoomed(&panel, false, cx));
+                    if this.zoomed_position == Some(prev_position) {
+                        this.zoomed = None;
+                        this.zoomed_position = None;
+                    }
+                    cx.notify();
                 } else if T::is_focus_event(event) {
+                    let position = panel.read(cx).position(cx);
+                    this.dismiss_zoomed_items_to_reveal(Some(position), cx);
                     if panel.is_zoomed(cx) {
                         this.zoomed = Some(panel.downgrade().into_any());
-                        this.zoomed_position = Some(panel.read(cx).position(cx));
+                        this.zoomed_position = Some(position);
                     } else {
                         this.zoomed = None;
                         this.zoomed_position = None;
@@ -1592,7 +1598,7 @@ impl Workspace {
             DockPosition::Right => &self.right_dock,
         };
         let mut focus_center = false;
-        let mut zoom_out = false;
+        let mut reveal_dock = false;
         dock.update(cx, |dock, cx| {
             let other_is_zoomed = self.zoomed.is_some() && self.zoomed_position != Some(dock_side);
             let was_visible = dock.is_open() && !other_is_zoomed;
@@ -1607,14 +1613,15 @@ impl Workspace {
                     if active_panel.is_zoomed(cx) {
                         cx.focus(active_panel.as_any());
                     }
-                    zoom_out = true;
+                    reveal_dock = true;
                 }
             }
         });
 
-        if zoom_out {
-            self.zoom_out_everything_except(dock_side, cx);
+        if reveal_dock {
+            self.dismiss_zoomed_items_to_reveal(Some(dock_side), cx);
         }
+
         if focus_center {
             cx.focus_self();
         }
@@ -1623,62 +1630,49 @@ impl Workspace {
         self.serialize_workspace(cx);
     }
 
+    /// Transfer focus to the panel of the given type.
     pub fn focus_panel<T: Panel>(&mut self, cx: &mut ViewContext<Self>) -> Option<ViewHandle<T>> {
-        self.show_or_hide_panel::<T>(cx, |_, _| true)?
+        self.focus_or_unfocus_panel::<T>(cx, |_, _| true)?
             .as_any()
             .clone()
             .downcast()
     }
 
+    /// Focus the panel of the given type if it isn't already focused. If it is
+    /// already focused, then transfer focus back to the workspace center.
     pub fn toggle_panel_focus<T: Panel>(&mut self, cx: &mut ViewContext<Self>) {
-        self.show_or_hide_panel::<T>(cx, |panel, cx| !panel.has_focus(cx));
+        self.focus_or_unfocus_panel::<T>(cx, |panel, cx| !panel.has_focus(cx));
     }
 
-    fn show_or_hide_panel<T: Panel>(
+    /// Focus or unfocus the given panel type, depending on the given callback.
+    fn focus_or_unfocus_panel<T: Panel>(
         &mut self,
         cx: &mut ViewContext<Self>,
-        show: impl Fn(&dyn PanelHandle, &mut ViewContext<Dock>) -> bool,
+        should_focus: impl Fn(&dyn PanelHandle, &mut ViewContext<Dock>) -> bool,
     ) -> Option<Rc<dyn PanelHandle>> {
-        for (dock, position) in [
-            self.left_dock.clone(),
-            self.bottom_dock.clone(),
-            self.right_dock.clone(),
-        ]
-        .into_iter()
-        .zip(
-            [
-                DockPosition::Left,
-                DockPosition::Bottom,
-                DockPosition::Right,
-            ]
-            .into_iter(),
-        ) {
+        for dock in [&self.left_dock, &self.bottom_dock, &self.right_dock] {
             if let Some(panel_index) = dock.read(cx).panel_index_for_type::<T>() {
                 let mut focus_center = false;
-                let mut zoom_out = false;
+                let mut reveal_dock = false;
                 let panel = dock.update(cx, |dock, cx| {
                     dock.activate_panel(panel_index, cx);
 
                     let panel = dock.active_panel().cloned();
                     if let Some(panel) = panel.as_ref() {
-                        let should_show = show(&**panel, cx);
-                        if should_show {
+                        if should_focus(&**panel, cx) {
                             dock.set_open(true, cx);
                             cx.focus(panel.as_any());
-                            zoom_out = true;
+                            reveal_dock = true;
                         } else {
-                            if panel.is_zoomed(cx) {
-                                dock.set_open(false, cx);
-                            }
+                            // if panel.is_zoomed(cx) {
+                            //     dock.set_open(false, cx);
+                            // }
                             focus_center = true;
                         }
                     }
                     panel
                 });
 
-                if zoom_out {
-                    self.zoom_out_everything_except(position, cx);
-                }
                 if focus_center {
                     cx.focus_self();
                 }
@@ -1705,28 +1699,38 @@ impl Workspace {
         cx.notify();
     }
 
-    fn zoom_out_everything_except(
+    fn dismiss_zoomed_items_to_reveal(
         &mut self,
-        except_position: DockPosition,
+        except_position: Option<DockPosition>,
         cx: &mut ViewContext<Self>,
     ) {
-        for pane in &self.panes {
-            pane.update(cx, |pane, cx| pane.set_zoomed(false, cx));
-        }
-
-        if except_position != DockPosition::Left {
-            self.left_dock.update(cx, |dock, cx| dock.zoom_out(cx));
+        // If a center pane is zoomed, unzoom it.
+        if except_position.is_some() {
+            for pane in &self.panes {
+                pane.update(cx, |pane, cx| pane.set_zoomed(false, cx));
+            }
         }
 
-        if except_position != DockPosition::Bottom {
-            self.bottom_dock.update(cx, |dock, cx| dock.zoom_out(cx));
+        // If another dock is zoomed, hide it.
+        let mut focus_center = false;
+        for dock in [&self.left_dock, &self.right_dock, &self.bottom_dock] {
+            dock.update(cx, |dock, cx| {
+                if Some(dock.position()) != except_position {
+                    if let Some(panel) = dock.active_panel() {
+                        if panel.is_zoomed(cx) {
+                            focus_center |= panel.has_focus(cx);
+                            dock.set_open(false, cx);
+                        }
+                    }
+                }
+            });
         }
 
-        if except_position != DockPosition::Right {
-            self.right_dock.update(cx, |dock, cx| dock.zoom_out(cx));
+        if focus_center {
+            cx.focus_self();
         }
 
-        if self.zoomed_position != Some(except_position) {
+        if self.zoomed_position != except_position {
             self.zoomed = None;
             self.zoomed_position = None;
         }
@@ -1937,6 +1941,7 @@ impl Workspace {
             self.last_active_center_pane = Some(pane.downgrade());
         }
 
+        self.dismiss_zoomed_items_to_reveal(None, cx);
         if pane.read(cx).is_zoomed() {
             self.zoomed = Some(pane.downgrade().into_any());
         } else {
@@ -1998,7 +2003,6 @@ impl Workspace {
             }
             pane::Event::ZoomIn => {
                 if pane == self.active_pane {
-                    self.zoom_out(cx);
                     pane.update(cx, |pane, cx| pane.set_zoomed(true, cx));
                     if pane.read(cx).has_focus() {
                         self.zoomed = Some(pane.downgrade().into_any());
@@ -2007,7 +2011,13 @@ impl Workspace {
                     cx.notify();
                 }
             }
-            pane::Event::ZoomOut => self.zoom_out(cx),
+            pane::Event::ZoomOut => {
+                pane.update(cx, |pane, cx| pane.set_zoomed(false, cx));
+                if self.zoomed_position.is_none() {
+                    self.zoomed = None;
+                }
+                cx.notify();
+            }
         }
 
         self.serialize_workspace(cx);