dock: Fix zoom support for side dock panel. (#327)
- Fix emit `PanelEvent::LayoutChanged` when panel resized.
This commit is contained in:
parent
2198134832
commit
5915618928
5 changed files with 72 additions and 32 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue