From c2f3ac24a4f3bd83b14262899c48980ea15c6148 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 25 May 2023 12:11:11 +0200 Subject: [PATCH] Prevent zoom from being restored when focusing a modal --- crates/workspace/src/workspace.rs | 158 ++++++++++++++++-------------- 1 file changed, 82 insertions(+), 76 deletions(-) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index da23d23285..52dd7193c2 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -40,9 +40,9 @@ use gpui::{ CursorStyle, MouseButton, PathPromptOptions, Platform, PromptLevel, WindowBounds, WindowOptions, }, - AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, - SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, - WindowContext, + AnyModelHandle, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, + ModelContext, ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, + WeakViewHandle, WindowContext, }; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem}; use itertools::Itertools; @@ -484,6 +484,7 @@ pub struct Workspace { weak_self: WeakViewHandle, remote_entity_subscription: Option, modal: Option, + zoomed: Option, center: PaneGroup, left_dock: ViewHandle, bottom_dock: ViewHandle, @@ -687,6 +688,7 @@ impl Workspace { let mut this = Workspace { weak_self: weak_handle.clone(), modal: None, + zoomed: None, center: PaneGroup::new(center_pane.clone()), panes: vec![center_pane.clone()], panes_by_item: Default::default(), @@ -905,9 +907,17 @@ 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()); + } } else if T::should_zoom_out_on_event(event) { this.zoom_out(cx); } else if T::is_focus_event(event) { + if panel.is_zoomed(cx) { + this.zoomed = Some(panel.downgrade().into_any()); + } else { + this.zoomed = None; + } cx.notify(); } } @@ -1359,44 +1369,6 @@ impl Workspace { } } - fn zoomed(&self, cx: &WindowContext) -> Option { - self.zoomed_panel_for_dock(DockPosition::Left, cx) - .or_else(|| self.zoomed_panel_for_dock(DockPosition::Bottom, cx)) - .or_else(|| self.zoomed_panel_for_dock(DockPosition::Right, cx)) - .or_else(|| self.zoomed_pane(cx)) - } - - fn zoomed_panel_for_dock( - &self, - position: DockPosition, - cx: &WindowContext, - ) -> Option { - let (dock, other_docks) = match position { - DockPosition::Left => (&self.left_dock, [&self.bottom_dock, &self.right_dock]), - DockPosition::Bottom => (&self.bottom_dock, [&self.left_dock, &self.right_dock]), - DockPosition::Right => (&self.right_dock, [&self.left_dock, &self.bottom_dock]), - }; - - let zoomed_panel = dock.read(&cx).zoomed_panel(cx)?; - if other_docks.iter().all(|dock| !dock.read(cx).has_focus(cx)) - && !self.active_pane.read(cx).has_focus() - { - Some(zoomed_panel.as_any().clone()) - } else { - None - } - } - - fn zoomed_pane(&self, cx: &WindowContext) -> Option { - let active_pane = self.active_pane.read(cx); - let docks = [&self.left_dock, &self.bottom_dock, &self.right_dock]; - if active_pane.is_zoomed() && docks.iter().all(|dock| !dock.read(cx).has_focus(cx)) { - Some(self.active_pane.clone().into_any()) - } else { - None - } - } - pub fn items<'a>( &'a self, cx: &'a AppContext, @@ -1567,6 +1539,7 @@ impl Workspace { self.left_dock.update(cx, |dock, cx| dock.zoom_out(cx)); self.bottom_dock.update(cx, |dock, cx| dock.zoom_out(cx)); self.right_dock.update(cx, |dock, cx| dock.zoom_out(cx)); + self.zoomed = None; cx.notify(); } @@ -1749,6 +1722,12 @@ impl Workspace { self.last_active_center_pane = Some(pane.downgrade()); } + if pane.read(cx).is_zoomed() { + self.zoomed = Some(pane.downgrade().into_any()); + } else { + self.zoomed = None; + } + self.update_followers( proto::update_followers::Variant::UpdateActiveView(proto::UpdateActiveView { id: self.active_item(cx).and_then(|item| { @@ -1804,6 +1783,9 @@ impl Workspace { 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()); + } cx.notify(); } } @@ -2840,7 +2822,7 @@ impl Workspace { DockPosition::Bottom => &self.bottom_dock, }; let active_panel = dock.read(cx).active_panel()?; - let element = if Some(active_panel.as_any()) == self.zoomed(cx).as_ref() { + let element = if Some(active_panel.id()) == self.zoomed.as_ref().map(|zoomed| zoomed.id()) { dock.read(cx).render_placeholder(cx) } else { ChildView::new(dock, cx).into_any() @@ -3008,16 +2990,21 @@ impl View for Workspace { .with_child( Flex::column() .with_child( - FlexItem::new(self.center.render( - &project, - &theme, - &self.follower_states_by_leader, - self.active_call(), - self.active_pane(), - self.zoomed(cx).as_ref(), - &self.app_state, - cx, - )) + FlexItem::new( + self.center.render( + &project, + &theme, + &self.follower_states_by_leader, + self.active_call(), + self.active_pane(), + self.zoomed + .as_ref() + .and_then(|zoomed| zoomed.upgrade(cx)) + .as_ref(), + &self.app_state, + cx, + ), + ) .flex(1., true), ) .with_children( @@ -3029,20 +3016,25 @@ impl View for Workspace { }) .with_child(Overlay::new( Stack::new() - .with_children(self.zoomed(cx).map(|zoomed| { + .with_children(self.zoomed.as_ref().and_then(|zoomed| { enum ZoomBackground {} - - ChildView::new(&zoomed, cx) - .contained() - .with_style(theme.workspace.zoomed_foreground) - .aligned() - .contained() - .with_style(theme.workspace.zoomed_background) - .mouse::(0) - .capture_all() - .on_down(MouseButton::Left, |_, this: &mut Self, cx| { - this.zoom_out(cx); - }) + let zoomed = zoomed.upgrade(cx)?; + Some( + ChildView::new(&zoomed, cx) + .contained() + .with_style(theme.workspace.zoomed_foreground) + .aligned() + .contained() + .with_style(theme.workspace.zoomed_background) + .mouse::(0) + .capture_all() + .on_down( + MouseButton::Left, + |_, this: &mut Self, cx| { + this.zoom_out(cx); + }, + ), + ) })) .with_children(self.modal.as_ref().map(|modal| { ChildView::new(modal, cx) @@ -3068,7 +3060,6 @@ impl View for Workspace { if cx.is_self_focused() { cx.focus(&self.active_pane); } - cx.notify(); } } @@ -3393,7 +3384,7 @@ mod tests { item::test::{TestItem, TestItemEvent, TestProjectItem}, }; use fs::FakeFs; - use gpui::{executor::Deterministic, TestAppContext}; + use gpui::{executor::Deterministic, test::EmptyView, TestAppContext}; use project::{Project, ProjectEntryId}; use serde_json::json; use settings::SettingsStore; @@ -3971,7 +3962,7 @@ mod tests { let fs = FakeFs::new(cx.background()); let project = Project::test(fs, [], cx).await; - let (_window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); + let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); let (panel_1, panel_2) = workspace.update(cx, |workspace, cx| { // Add panel_1 on the left, panel_2 on the right. @@ -4102,26 +4093,41 @@ mod tests { // Emitting a ZoomIn event shows the panel as zoomed. panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::ZoomIn)); - workspace.read_with(cx, |workspace, cx| { - assert_eq!(workspace.zoomed(cx), Some(panel_1.clone().into_any())); + workspace.read_with(cx, |workspace, _| { + assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any())); + }); + + // If focus is transferred to another view that's not a panel or another pane, we still show + // the panel as zoomed. + let focus_receiver = cx.add_view(window_id, |_| EmptyView); + focus_receiver.update(cx, |_, cx| cx.focus_self()); + workspace.read_with(cx, |workspace, _| { + assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any())); }); // If focus is transferred elsewhere in the workspace, the panel is no longer zoomed. workspace.update(cx, |_, cx| cx.focus_self()); - workspace.read_with(cx, |workspace, cx| { - assert_eq!(workspace.zoomed(cx), None); + workspace.read_with(cx, |workspace, _| { + assert_eq!(workspace.zoomed, None); + }); + + // If focus is transferred again to another view that's not a panel or a pane, we won't + // show the panel as zoomed because it wasn't zoomed before. + focus_receiver.update(cx, |_, cx| cx.focus_self()); + workspace.read_with(cx, |workspace, _| { + assert_eq!(workspace.zoomed, None); }); // When focus is transferred back to the panel, it is zoomed again. panel_1.update(cx, |_, cx| cx.focus_self()); - workspace.read_with(cx, |workspace, cx| { - assert_eq!(workspace.zoomed(cx), Some(panel_1.clone().into_any())); + workspace.read_with(cx, |workspace, _| { + assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any())); }); // Emitting a ZoomOut event unzooms the panel. panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::ZoomOut)); - workspace.read_with(cx, |workspace, cx| { - assert_eq!(workspace.zoomed(cx), None); + workspace.read_with(cx, |workspace, _| { + assert_eq!(workspace.zoomed, None); }); // Emit closed event on panel 1, which is active