diff --git a/crates/ui/src/dock/dock.rs b/crates/ui/src/dock/dock.rs index cec31c94..6ff4eef6 100644 --- a/crates/ui/src/dock/dock.rs +++ b/crates/ui/src/dock/dock.rs @@ -6,7 +6,7 @@ use gpui::{ div, prelude::FluentBuilder as _, px, Axis, Element, InteractiveElement as _, IntoElement, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Render, StatefulInteractiveElement, Style, Styled as _, View, ViewContext, VisualContext as _, - WeakView, + WeakView, WindowContext, }; use serde::{Deserialize, Serialize}; @@ -74,10 +74,11 @@ impl Dock { let panel = cx.new_view(|cx| { let mut tab = TabPanel::new(None, dock_area.clone(), cx); tab.closeable = false; - tab.zoomable = false; tab }); + Self::subscribe_panel_events(dock_area.clone(), panel.clone(), cx); + Self { placement, dock_area, @@ -106,7 +107,10 @@ impl Dock { size: Pixels, panel: View, open: bool, + cx: &mut WindowContext, ) -> Self { + Self::subscribe_panel_events(dock_area.clone(), panel.clone(), cx); + Self { placement, dock_area, @@ -117,6 +121,21 @@ impl Dock { } } + fn subscribe_panel_events( + dock_area: WeakView, + panel: View, + cx: &mut WindowContext, + ) { + // Subscribe the panel to the dock area. + cx.defer({ + move |cx| { + _ = dock_area.update(cx, |this, cx| { + this.subscribe_panel(&panel, cx); + }); + } + }); + } + pub fn set_panels(&mut self, panels: Vec>, cx: &mut ViewContext) { self.panel.update(cx, |tab_panel, _| { tab_panel.panels = panels; diff --git a/crates/ui/src/dock/mod.rs b/crates/ui/src/dock/mod.rs index 5f378026..b13279e9 100644 --- a/crates/ui/src/dock/mod.rs +++ b/crates/ui/src/dock/mod.rs @@ -10,7 +10,7 @@ pub use dock::*; use gpui::{ actions, canvas, div, prelude::FluentBuilder, AnyElement, AnyView, AppContext, Axis, Bounds, EventEmitter, InteractiveElement as _, IntoElement, ParentElement as _, Pixels, Render, - SharedString, Styled, View, ViewContext, VisualContext, WeakView, WindowContext, + SharedString, Styled, Subscription, View, ViewContext, VisualContext, WeakView, WindowContext, }; pub use panel::*; pub use stack_panel::*; @@ -50,6 +50,8 @@ pub struct DockArea { right_dock: Option>, /// The top zoom view of the dockarea, if any. zoom_view: Option, + + _subscriptions: Vec, } /// DockItem is a tree structure that represents the layout of the dock. @@ -108,6 +110,17 @@ impl DockItem { stack_panel }); + + cx.defer({ + let stack_panel = stack_panel.clone(); + let dock_area = dock_area.clone(); + move |cx| { + _ = dock_area.update(cx, |this, cx| { + this.subscribe_panel(&stack_panel, cx); + }); + } + }); + Self::Split { axis, items, @@ -189,6 +202,7 @@ impl DockArea { cx: &mut ViewContext, ) -> Self { let stack_panel = cx.new_view(|cx| StackPanel::new(Axis::Horizontal, cx)); + let dock_item = DockItem::Split { axis: Axis::Horizontal, items: vec![], @@ -196,7 +210,7 @@ impl DockArea { view: stack_panel.clone(), }; - Self { + let mut this = Self { id: id.into(), version, bounds: Bounds::default(), @@ -205,7 +219,12 @@ impl DockArea { left_dock: None, right_dock: None, bottom_dock: None, - } + _subscriptions: vec![], + }; + + this.subscribe_panel(&stack_panel, cx); + + this } /// Set version of the dock area. @@ -372,18 +391,18 @@ impl DockArea { /// Subscribe event on the panels #[allow(clippy::only_used_in_recursion)] - fn subscribe_item(&self, item: &DockItem, cx: &mut ViewContext) { + fn subscribe_item(&mut self, item: &DockItem, cx: &mut ViewContext) { match item { DockItem::Split { items, view, .. } => { for item in items { self.subscribe_item(item, cx); } - cx.subscribe(view, move |_, _, event, cx| match event { - PanelEvent::LayoutChanged => cx.emit(DockEvent::LayoutChanged), - _ => {} - }) - .detach(); + self._subscriptions + .push(cx.subscribe(view, move |_, _, event, cx| match event { + PanelEvent::LayoutChanged => cx.emit(DockEvent::LayoutChanged), + _ => {} + })); } DockItem::Tabs { .. } => { // We subscribe the tab panel event is in StackPanel insert_panel @@ -392,8 +411,12 @@ impl DockArea { } /// Subscribe zoom event on the panel - pub(crate) fn subscribe_panel(view: &View

, cx: &mut ViewContext) { - cx.subscribe(view, move |_, panel, event, cx| match event { + pub(crate) fn subscribe_panel( + &mut self, + view: &View

, + cx: &mut ViewContext, + ) { + let subscription = cx.subscribe(view, move |_, panel, event, cx| match event { PanelEvent::ZoomIn => { let dock_area = cx.view().clone(); let panel = panel.clone(); @@ -417,8 +440,9 @@ impl DockArea { .detach() } PanelEvent::LayoutChanged => cx.emit(DockEvent::LayoutChanged), - }) - .detach(); + }); + + self._subscriptions.push(subscription); } /// Returns the ID of the dock area. diff --git a/crates/ui/src/dock/stack_panel.rs b/crates/ui/src/dock/stack_panel.rs index 2f39086a..a9f20cb7 100644 --- a/crates/ui/src/dock/stack_panel.rs +++ b/crates/ui/src/dock/stack_panel.rs @@ -14,8 +14,8 @@ use crate::{ use super::{DockArea, DockItemState, Panel, PanelEvent, PanelView, TabPanel}; use gpui::{ prelude::FluentBuilder as _, AppContext, Axis, DismissEvent, Entity, EventEmitter, FocusHandle, - FocusableView, IntoElement, ParentElement, Pixels, Render, Styled, View, ViewContext, - VisualContext, WeakView, + FocusableView, IntoElement, ParentElement, Pixels, Render, Styled, Subscription, View, + ViewContext, VisualContext, WeakView, }; use smallvec::SmallVec; @@ -25,6 +25,7 @@ pub struct StackPanel { focus_handle: FocusHandle, pub(crate) panels: SmallVec<[Arc; 2]>, panel_group: View, + _subscriptions: Vec, } impl Panel for StackPanel { @@ -59,10 +60,10 @@ impl StackPanel { }); // Bubble up the resize event. - cx.subscribe(&panel_group, |_, _, _: &ResizablePanelEvent, cx| { - cx.emit(PanelEvent::LayoutChanged) - }) - .detach(); + let _subscriptions = vec![cx + .subscribe(&panel_group, |_, _, _: &ResizablePanelEvent, cx| { + cx.emit(PanelEvent::LayoutChanged) + })]; Self { axis, @@ -70,6 +71,7 @@ impl StackPanel { focus_handle: cx.focus_handle(), panels: SmallVec::new(), panel_group, + _subscriptions, } } @@ -184,9 +186,11 @@ impl StackPanel { } // Subscribe to the panel's layout change event. - _ = dock_area.update(cx, |_, cx| { + _ = dock_area.update(cx, |this, cx| { if let Ok(tab_panel) = panel.view().downcast::() { - DockArea::subscribe_panel(&tab_panel, cx); + this.subscribe_panel(&tab_panel, cx); + } else if let Ok(stack_panel) = panel.view().downcast::() { + this.subscribe_panel(&stack_panel, cx); } }); } diff --git a/crates/ui/src/dock/state.rs b/crates/ui/src/dock/state.rs index 5f217ac7..76c7f3d1 100644 --- a/crates/ui/src/dock/state.rs +++ b/crates/ui/src/dock/state.rs @@ -51,13 +51,14 @@ impl DockState { ) -> Result> { let view = self.panel.to_item(dock_area.clone(), cx).view(); if let Ok(tab_panel) = view.view().downcast::() { - let dock = cx.new_view(|_| { + let dock = cx.new_view(|cx| { Dock::from_state( dock_area.clone(), self.placement, self.size, tab_panel, self.open, + cx, ) }); diff --git a/crates/ui/src/dock/tab_panel.rs b/crates/ui/src/dock/tab_panel.rs index 4a9d2778..349109da 100644 --- a/crates/ui/src/dock/tab_panel.rs +++ b/crates/ui/src/dock/tab_panel.rs @@ -68,9 +68,6 @@ pub struct TabPanel { /// If this is true, the Panel closeable will follow the active panel's closeable, /// otherwise this TabPanel will not able to close pub(crate) closeable: bool, - /// If this is true, the Panel zoomable will follow the active panel's zoomable, - /// otherwise this TabPanel will not able to zoom - pub(crate) zoomable: bool, /// When drag move, will get the placement of the panel to be split will_split_placement: Option, @@ -98,10 +95,6 @@ impl Panel for TabPanel { } fn zoomable(&self, cx: &WindowContext) -> bool { - if !self.zoomable { - return false; - } - self.active_panel() .map(|panel| panel.zoomable(cx)) .unwrap_or(false) @@ -147,7 +140,6 @@ impl TabPanel { will_split_placement: None, is_zoomed: false, closeable: true, - zoomable: true, } }