dock: Fix zoom support for side dock panel. (#327)

- Fix emit `PanelEvent::LayoutChanged` when panel resized.
This commit is contained in:
Jason Lee 2024-10-10 15:16:16 +08:00 committed by GitHub
parent 2198134832
commit 5915618928
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 72 additions and 32 deletions

View file

@ -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<TabPanel>,
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<DockArea>,
panel: View<TabPanel>,
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<Arc<dyn PanelView>>, cx: &mut ViewContext<Self>) {
self.panel.update(cx, |tab_panel, _| {
tab_panel.panels = panels;

View file

@ -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<View<Dock>>,
/// The top zoom view of the dockarea, if any.
zoom_view: Option<AnyView>,
_subscriptions: Vec<Subscription>,
}
/// 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>,
) -> 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<Self>) {
fn subscribe_item(&mut self, item: &DockItem, cx: &mut ViewContext<Self>) {
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<P: Panel>(view: &View<P>, cx: &mut ViewContext<DockArea>) {
cx.subscribe(view, move |_, panel, event, cx| match event {
pub(crate) fn subscribe_panel<P: Panel>(
&mut self,
view: &View<P>,
cx: &mut ViewContext<DockArea>,
) {
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.

View file

@ -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<dyn PanelView>; 2]>,
panel_group: View<ResizablePanelGroup>,
_subscriptions: Vec<Subscription>,
}
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::<TabPanel>() {
DockArea::subscribe_panel(&tab_panel, cx);
this.subscribe_panel(&tab_panel, cx);
} else if let Ok(stack_panel) = panel.view().downcast::<Self>() {
this.subscribe_panel(&stack_panel, cx);
}
});
}

View file

@ -51,13 +51,14 @@ impl DockState {
) -> Result<View<Dock>> {
let view = self.panel.to_item(dock_area.clone(), cx).view();
if let Ok(tab_panel) = view.view().downcast::<TabPanel>() {
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,
)
});

View file

@ -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<Placement>,
@ -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,
}
}