From b29f4fb0e6d86cb54feb40ad97e8b4b4d66ce7b8 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 14 Nov 2024 15:47:26 +0800 Subject: [PATCH] dock: Add `set_locked` to lock dock area to limit split, move panels. (#417) But still allow to resize panels. --- crates/ui/src/dock/mod.rs | 14 ++++++++++++++ crates/ui/src/dock/tab_panel.rs | 28 +++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/crates/ui/src/dock/mod.rs b/crates/ui/src/dock/mod.rs index 14b59de5..b4205337 100644 --- a/crates/ui/src/dock/mod.rs +++ b/crates/ui/src/dock/mod.rs @@ -54,6 +54,9 @@ pub struct DockArea { /// The top zoom view of the dockarea, if any. zoom_view: Option, + /// Lock panels layout, but allow to resize. + is_locked: bool, + _subscriptions: Vec, } @@ -238,6 +241,7 @@ impl DockArea { left_dock: None, right_dock: None, bottom_dock: None, + is_locked: false, _subscriptions: vec![], }; @@ -316,6 +320,16 @@ impl DockArea { })); } + /// Set locked state of the dock area, if locked, the dock area cannot be split or move, but allows to resize panels. + pub fn set_locked(&mut self, locked: bool, _: &mut WindowContext) { + self.is_locked = locked; + } + + /// Determine if the dock area is locked. + pub fn is_locked(&self) -> bool { + self.is_locked + } + /// Determine if the dock area has a dock at the given placement. pub fn has_dock(&self, placement: DockPlacement) -> bool { match placement { diff --git a/crates/ui/src/dock/tab_panel.rs b/crates/ui/src/dock/tab_panel.rs index 745e7865..d036fe1d 100644 --- a/crates/ui/src/dock/tab_panel.rs +++ b/crates/ui/src/dock/tab_panel.rs @@ -265,9 +265,20 @@ impl TabPanel { } } - /// Return true if the panel can be split or move - fn can_split(&self) -> bool { - self.stack_panel.is_some() && !self.is_zoomed + fn is_locked(&self, cx: &AppContext) -> bool { + let Some(dock_area) = self.dock_area.upgrade() else { + return false; + }; + + if dock_area.read(cx).is_locked() { + return true; + } + + if self.is_zoomed { + return true; + } + + self.stack_panel.is_none() } pub(super) fn set_collapsed(&mut self, collapsed: bool, cx: &mut ViewContext) { @@ -332,6 +343,7 @@ impl TabPanel { fn render_title_bar(&self, cx: &mut ViewContext) -> impl IntoElement { let view = cx.view().clone(); + let is_locked = self.is_locked(cx); if self.panels.len() == 1 { let panel = self.panels.get(0).unwrap(); @@ -356,7 +368,7 @@ impl TabPanel { .text_ellipsis() .whitespace_nowrap() .child(panel.title(cx)) - .when(self.can_split(), |this| { + .when(!is_locked, |this| { this.on_drag( DragPanel { panel: panel.clone(), @@ -397,7 +409,7 @@ impl TabPanel { .on_click(cx.listener(move |view, _, cx| { view.set_active_ix(ix, cx); })) - .when(self.can_split(), |this| { + .when(!is_locked, |this| { this.on_drag(DragPanel::new(panel.clone(), view.clone()), |drag, cx| { cx.stop_propagation(); cx.new_view(|_| drag.clone()) @@ -423,7 +435,7 @@ impl TabPanel { .h_full() .flex_grow() .min_w_16() - .when(self.can_split(), |this| { + .when(!is_locked, |this| { this.drag_over::(|this, _, cx| this.bg(cx.theme().drop_target)) .on_drop(cx.listener(move |this, drag: &DragPanel, cx| { this.will_split_placement = None; @@ -456,6 +468,8 @@ impl TabPanel { } fn render_active_panel(&self, cx: &mut ViewContext) -> impl IntoElement { + let is_locked = self.is_locked(cx); + self.active_panel() .map(|panel| { div() @@ -465,7 +479,7 @@ impl TabPanel { .overflow_x_hidden() .flex_1() .child(panel.view()) - .when(self.can_split(), |this| { + .when(!is_locked, |this| { this.on_drag_move(cx.listener(Self::on_panel_drag_move)) .child( div()