@@ -1,7 +1,7 @@
use crate::{
CloseWindow, NewFile, NewTerminal, OpenInTerminal, OpenOptions, OpenTerminal, OpenVisible,
SplitDirection, ToggleFileFinder, ToggleProjectSymbols, ToggleZoom, Workspace,
- WorkspaceItemBuilder,
+ WorkspaceItemBuilder, ZoomIn, ZoomOut,
invalid_item_view::InvalidItemView,
item::{
ActivateOnClose, ClosePosition, Item, ItemBufferKind, ItemHandle, ItemSettings,
@@ -1306,6 +1306,25 @@ impl Pane {
}
}
+ pub fn zoom_in(&mut self, _: &ZoomIn, window: &mut Window, cx: &mut Context<Self>) {
+ if !self.can_toggle_zoom {
+ cx.propagate();
+ } else if !self.zoomed && !self.items.is_empty() {
+ if !self.focus_handle.contains_focused(window, cx) {
+ cx.focus_self(window);
+ }
+ cx.emit(Event::ZoomIn);
+ }
+ }
+
+ pub fn zoom_out(&mut self, _: &ZoomOut, _window: &mut Window, cx: &mut Context<Self>) {
+ if !self.can_toggle_zoom {
+ cx.propagate();
+ } else if self.zoomed {
+ cx.emit(Event::ZoomOut);
+ }
+ }
+
pub fn activate_item(
&mut self,
index: usize,
@@ -3900,6 +3919,8 @@ impl Render for Pane {
cx.emit(Event::JoinAll);
}))
.on_action(cx.listener(Pane::toggle_zoom))
+ .on_action(cx.listener(Pane::zoom_in))
+ .on_action(cx.listener(Pane::zoom_out))
.on_action(cx.listener(Self::navigate_backward))
.on_action(cx.listener(Self::navigate_forward))
.on_action(
@@ -272,6 +272,10 @@ actions!(
ToggleRightDock,
/// Toggles zoom on the active pane.
ToggleZoom,
+ /// Zooms in on the active pane.
+ ZoomIn,
+ /// Zooms out of the active pane.
+ ZoomOut,
/// Stops following a collaborator.
Unfollow,
/// Restores the banner.
@@ -9594,6 +9598,105 @@ mod tests {
});
}
+ #[gpui::test]
+ async fn test_pane_zoom_in_out(cx: &mut TestAppContext) {
+ init_test(cx);
+ let fs = FakeFs::new(cx.executor());
+
+ let project = Project::test(fs, [], cx).await;
+ let (workspace, cx) =
+ cx.add_window_view(|window, cx| Workspace::test_new(project, window, cx));
+
+ let pane = workspace.update_in(cx, |workspace, _window, _cx| {
+ workspace.active_pane().clone()
+ });
+
+ // Add an item to the pane so it can be zoomed
+ workspace.update_in(cx, |workspace, window, cx| {
+ let item = cx.new(TestItem::new);
+ workspace.add_item(pane.clone(), Box::new(item), None, true, true, window, cx);
+ });
+
+ // Initially not zoomed
+ workspace.update_in(cx, |workspace, _window, cx| {
+ assert!(!pane.read(cx).is_zoomed(), "Pane starts unzoomed");
+ assert!(
+ workspace.zoomed.is_none(),
+ "Workspace should track no zoomed pane"
+ );
+ assert!(pane.read(cx).items_len() > 0, "Pane should have items");
+ });
+
+ // Zoom In
+ pane.update_in(cx, |pane, window, cx| {
+ pane.zoom_in(&crate::ZoomIn, window, cx);
+ });
+
+ workspace.update_in(cx, |workspace, window, cx| {
+ assert!(
+ pane.read(cx).is_zoomed(),
+ "Pane should be zoomed after ZoomIn"
+ );
+ assert!(
+ workspace.zoomed.is_some(),
+ "Workspace should track the zoomed pane"
+ );
+ assert!(
+ pane.read(cx).focus_handle(cx).contains_focused(window, cx),
+ "ZoomIn should focus the pane"
+ );
+ });
+
+ // Zoom In again is a no-op
+ pane.update_in(cx, |pane, window, cx| {
+ pane.zoom_in(&crate::ZoomIn, window, cx);
+ });
+
+ workspace.update_in(cx, |workspace, window, cx| {
+ assert!(pane.read(cx).is_zoomed(), "Second ZoomIn keeps pane zoomed");
+ assert!(
+ workspace.zoomed.is_some(),
+ "Workspace still tracks zoomed pane"
+ );
+ assert!(
+ pane.read(cx).focus_handle(cx).contains_focused(window, cx),
+ "Pane remains focused after repeated ZoomIn"
+ );
+ });
+
+ // Zoom Out
+ pane.update_in(cx, |pane, window, cx| {
+ pane.zoom_out(&crate::ZoomOut, window, cx);
+ });
+
+ workspace.update_in(cx, |workspace, _window, cx| {
+ assert!(
+ !pane.read(cx).is_zoomed(),
+ "Pane should unzoom after ZoomOut"
+ );
+ assert!(
+ workspace.zoomed.is_none(),
+ "Workspace clears zoom tracking after ZoomOut"
+ );
+ });
+
+ // Zoom Out again is a no-op
+ pane.update_in(cx, |pane, window, cx| {
+ pane.zoom_out(&crate::ZoomOut, window, cx);
+ });
+
+ workspace.update_in(cx, |workspace, _window, cx| {
+ assert!(
+ !pane.read(cx).is_zoomed(),
+ "Second ZoomOut keeps pane unzoomed"
+ );
+ assert!(
+ workspace.zoomed.is_none(),
+ "Workspace remains without zoomed pane"
+ );
+ });
+ }
+
#[gpui::test]
async fn test_toggle_all_docks(cx: &mut gpui::TestAppContext) {
init_test(cx);