tiles: To support close panel. (#674)

- Add `remove_panel` method to DockArea.
This commit is contained in:
Jason Lee 2025-02-28 18:36:58 +08:00 committed by GitHub
parent 5cf11ffe1b
commit 9732c3b7e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 121 additions and 7 deletions

View file

@ -276,6 +276,17 @@ impl Dock {
cx.notify();
}
/// Remove item from the Dock.
pub fn remove_panel(
&mut self,
panel: Arc<dyn PanelView>,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.panel.remove_panel(panel, window, cx);
cx.notify();
}
fn render_resize_handle(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let axis = self.placement.axis();
let view = cx.entity().clone();

View file

@ -368,6 +368,32 @@ impl DockItem {
}
}
/// Remove a panel from the dock item.
pub fn remove_panel(&self, panel: Arc<dyn PanelView>, window: &mut Window, cx: &mut App) {
match self {
DockItem::Tabs { view, .. } => {
view.update(cx, |tab_panel, cx| {
tab_panel.remove_panel(panel, window, cx);
});
}
DockItem::Split { items, view, .. } => {
// For each child item, set collapsed state
for item in items {
item.remove_panel(panel.clone(), window, cx);
}
view.update(cx, |split, cx| {
split.remove_panel(panel, window, cx);
});
}
DockItem::Tiles { view, .. } => {
view.update(cx, |tiles, cx| {
tiles.remove(panel, window, cx);
});
}
DockItem::Panel { .. } => {}
}
}
pub fn set_collapsed(&self, collapsed: bool, window: &mut Window, cx: &mut App) {
match self {
DockItem::Tabs { view, .. } => {
@ -567,6 +593,7 @@ impl DockArea {
}
/// Determine if the dock area is locked.
#[inline]
pub fn is_locked(&self) -> bool {
self.locked
}
@ -674,8 +701,6 @@ impl DockArea {
}
/// Add a panel item to the dock area at the given placement.
///
/// If the left, bottom, right dock is not present, it will set the dock at the placement.
pub fn add_panel(
&mut self,
panel: Arc<dyn PanelView>,
@ -732,6 +757,56 @@ impl DockArea {
}
}
/// Remove panel from the DockArea at the given placement.
pub fn remove_panel(
&mut self,
panel: Arc<dyn PanelView>,
placement: DockPlacement,
window: &mut Window,
cx: &mut Context<Self>,
) {
match placement {
DockPlacement::Left => {
if let Some(dock) = self.left_dock.as_mut() {
dock.update(cx, |dock, cx| {
dock.remove_panel(panel, window, cx);
});
}
}
DockPlacement::Right => {
if let Some(dock) = self.right_dock.as_mut() {
dock.update(cx, |dock, cx| {
dock.remove_panel(panel, window, cx);
});
}
}
DockPlacement::Bottom => {
if let Some(dock) = self.bottom_dock.as_mut() {
dock.update(cx, |dock, cx| {
dock.remove_panel(panel, window, cx);
});
}
}
DockPlacement::Center => {
self.items.remove_panel(panel, window, cx);
}
}
cx.notify();
}
/// Remove a panel from all docks.
pub fn remove_panel_from_all_docks(
&mut self,
panel: Arc<dyn PanelView>,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.remove_panel(panel.clone(), DockPlacement::Center, window, cx);
self.remove_panel(panel.clone(), DockPlacement::Left, window, cx);
self.remove_panel(panel.clone(), DockPlacement::Right, window, cx);
self.remove_panel(panel.clone(), DockPlacement::Bottom, window, cx);
}
/// Load the state of the DockArea from the DockAreaState.
///
/// See also [DockeArea::dump].

View file

@ -81,6 +81,8 @@ pub struct TabPanel {
collapsed: bool,
/// When drag move, will get the placement of the panel to be split
will_split_placement: Option<Placement>,
/// Is TabPanel used in Tiles.
in_tiles: bool,
}
impl Panel for TabPanel {
@ -158,9 +160,15 @@ impl TabPanel {
zoomed: false,
collapsed: false,
closable: true,
in_tiles: false,
}
}
/// Mark the TabPanel as being used in Tiles.
pub(super) fn set_in_tiles(&mut self, in_tiles: bool) {
self.in_tiles = in_tiles;
}
pub(super) fn set_parent(&mut self, view: WeakEntity<StackPanel>) {
self.stack_panel = Some(view);
}
@ -1063,6 +1071,20 @@ impl TabPanel {
if let Some(panel) = self.active_panel(cx) {
self.remove_panel(panel, window, cx);
}
// Remove self from the parent DockArea.
// This is ensure to remove from Tiles
if self.panels.is_empty() && self.in_tiles {
let tab_panel = Arc::new(cx.entity());
window.defer(cx, {
let dock_area = self.dock_area.clone();
move |window, cx| {
_ = dock_area.update(cx, |this, cx| {
this.remove_panel_from_all_docks(tab_panel, window, cx);
});
}
});
}
}
}
@ -1088,7 +1110,10 @@ impl Render for TabPanel {
zoomable: self.zoomable(cx),
active_panel,
};
if !state.draggable {
// 1. When is the final panel in the dock, it will not able to close.
// 2. When is in the Tiles, it will always able to close (by active panel state).
if !state.draggable && !self.in_tiles {
state.closable = false;
}

View file

@ -361,10 +361,13 @@ impl Tiles {
window: &mut Window,
cx: &mut Context<Self>,
) {
assert!(
item.panel.view().downcast::<TabPanel>().is_ok(),
"only allows to add TabPanel type"
);
let Ok(tab_panel) = item.panel.view().downcast::<TabPanel>() else {
panic!("only allows to add TabPanel type")
};
tab_panel.update(cx, |tab_panel, _| {
tab_panel.set_in_tiles(true);
});
self.panels.push(item.clone());
window.defer(cx, {