Maintain panel visibility when changing its position

Antonio Scandurra created

Change summary

crates/workspace/src/dock.rs      | 18 ++++++++++++++++--
crates/workspace/src/workspace.rs | 23 +++++++++++++++++++----
2 files changed, 35 insertions(+), 6 deletions(-)

Detailed changes

crates/workspace/src/dock.rs 🔗

@@ -187,8 +187,22 @@ impl Dock {
     }
 
     pub fn remove_panel<T: Panel>(&mut self, panel: &ViewHandle<T>, cx: &mut ViewContext<Self>) {
-        self.panels.retain(|entry| entry.panel.id() != panel.id());
-        cx.notify();
+        if let Some(panel_ix) = self
+            .panels
+            .iter()
+            .position(|item| item.panel.id() == panel.id())
+        {
+            if panel_ix == self.active_item_ix {
+                self.active_item_ix = 0;
+                cx.emit(Event::Close);
+            }
+            self.panels.remove(panel_ix);
+            cx.notify();
+        }
+    }
+
+    pub fn panels_len(&self) -> usize {
+        self.panels.len()
     }
 
     pub fn activate_item(&mut self, item_ix: usize, cx: &mut ViewContext<Self>) {

crates/workspace/src/workspace.rs 🔗

@@ -845,16 +845,31 @@ impl Workspace {
             let mut dock = dock.clone();
             move |this, panel, event, cx| {
                 if T::should_change_position_on_event(event) {
-                    dock.update(cx, |dock, cx| dock.remove_panel(&panel, cx));
+                    let mut was_visible = false;
+                    dock.update(cx, |dock, cx| {
+                        was_visible = dock.is_open()
+                            && dock
+                                .active_item()
+                                .map_or(false, |item| item.as_any().is::<T>());
+                        dock.remove_panel(&panel, cx);
+                    });
                     dock = match panel.read(cx).position(cx) {
                         DockPosition::Left => &this.left_dock,
                         DockPosition::Bottom => &this.bottom_dock,
                         DockPosition::Right => &this.right_dock,
-                    }.clone();
-                    dock.update(cx, |dock, cx| dock.add_panel(panel, cx));
+                    }
+                    .clone();
+                    dock.update(cx, |dock, cx| {
+                        dock.add_panel(panel, cx);
+                        if was_visible {
+                            dock.set_open(true, cx);
+                            dock.activate_item(dock.panels_len() - 1, cx);
+                        }
+                    });
                 }
             }
-        }).detach();
+        })
+        .detach();
 
         dock.update(cx, |dock, cx| dock.add_panel(panel, cx));
     }