dock: Fix to active prev tab, when current tab is invisible. (#517)

This commit is contained in:
Jason Lee 2024-12-27 11:58:19 +08:00 committed by GitHub
parent 9eba97ddf6
commit 6851e53183
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -24,12 +24,13 @@ use super::{
StackPanel, ToggleZoom, StackPanel, ToggleZoom,
}; };
#[derive(Clone, Copy)] #[derive(Clone)]
struct TabState { struct TabState {
closable: bool, closable: bool,
zoomable: bool, zoomable: bool,
draggable: bool, draggable: bool,
droppable: bool, droppable: bool,
active_panel: Option<Arc<dyn PanelView>>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -378,7 +379,7 @@ impl TabPanel {
!self.is_locked(cx) !self.is_locked(cx)
} }
fn render_toolbar(&self, state: TabState, cx: &mut ViewContext<Self>) -> impl IntoElement { fn render_toolbar(&self, state: &TabState, cx: &mut ViewContext<Self>) -> impl IntoElement {
let is_zoomed = self.is_zoomed && state.zoomable; let is_zoomed = self.is_zoomed && state.zoomable;
let view = cx.view().clone(); let view = cx.view().clone();
let build_popup_menu = move |this, cx: &WindowContext| view.read(cx).popup_menu(this, cx); let build_popup_menu = move |this, cx: &WindowContext| view.read(cx).popup_menu(this, cx);
@ -411,20 +412,25 @@ impl TabPanel {
.icon(IconName::Ellipsis) .icon(IconName::Ellipsis)
.xsmall() .xsmall()
.ghost() .ghost()
.popup_menu(move |this, cx| { .popup_menu({
build_popup_menu(this, cx) let zoomable = state.zoomable;
.when(state.zoomable, |this| { let closable = state.closable;
let name = if is_zoomed {
t!("Dock.Zoom Out") move |this, cx| {
} else { build_popup_menu(this, cx)
t!("Dock.Zoom In") .when(zoomable, |this| {
}; let name = if is_zoomed {
this.separator().menu(name, Box::new(ToggleZoom)) t!("Dock.Zoom Out")
}) } else {
.when(state.closable, |this| { t!("Dock.Zoom In")
this.separator() };
.menu(t!("Dock.Close"), Box::new(ClosePanel)) this.separator().menu(name, Box::new(ToggleZoom))
}) })
.when(closable, |this| {
this.separator()
.menu(t!("Dock.Close"), Box::new(ClosePanel))
})
}
}) })
.anchor(Corner::TopRight), .anchor(Corner::TopRight),
) )
@ -511,7 +517,7 @@ impl TabPanel {
) )
} }
fn render_title_bar(&self, state: TabState, cx: &mut ViewContext<Self>) -> impl IntoElement { fn render_title_bar(&self, state: &TabState, cx: &mut ViewContext<Self>) -> impl IntoElement {
let view = cx.view().clone(); let view = cx.view().clone();
let Some(dock_area) = self.dock_area.upgrade() else { let Some(dock_area) = self.dock_area.upgrade() else {
@ -584,7 +590,7 @@ impl TabPanel {
.flex_shrink_0() .flex_shrink_0()
.ml_1() .ml_1()
.gap_1() .gap_1()
.child(self.render_toolbar(state, cx)) .child(self.render_toolbar(&state, cx))
.children(right_dock_button), .children(right_dock_button),
) )
.into_any_element(); .into_any_element();
@ -615,7 +621,7 @@ impl TabPanel {
}, },
) )
.children(self.panels.iter().enumerate().filter_map(|(ix, panel)| { .children(self.panels.iter().enumerate().filter_map(|(ix, panel)| {
let mut active = ix == self.active_ix; let mut active = state.active_panel.as_ref() == Some(panel);
let disabled = self.is_collapsed; let disabled = self.is_collapsed;
if !panel.visible(cx) { if !panel.visible(cx) {
@ -702,56 +708,56 @@ impl TabPanel {
.into_any_element() .into_any_element()
} }
fn render_active_panel(&self, state: TabState, cx: &mut ViewContext<Self>) -> impl IntoElement { fn render_active_panel(
&self,
state: &TabState,
cx: &mut ViewContext<Self>,
) -> impl IntoElement {
if self.is_collapsed { if self.is_collapsed {
return Empty {}.into_any_element(); return Empty {}.into_any_element();
} }
self.active_panel(cx) let Some(active_panel) = state.active_panel.as_ref() else {
.map(|panel| { return Empty {}.into_any_element();
div() };
.id("tab-content")
.group("") div()
.overflow_y_scroll() .id("tab-content")
.overflow_x_hidden() .group("")
.flex_1() .overflow_y_scroll()
.child(panel.view()) .overflow_x_hidden()
.when(state.droppable, |this| { .flex_1()
this.on_drag_move(cx.listener(Self::on_panel_drag_move)) .child(active_panel.view())
.child( .when(state.droppable, |this| {
div() this.on_drag_move(cx.listener(Self::on_panel_drag_move))
.invisible() .child(
.absolute() div()
.bg(cx.theme().drop_target) .invisible()
.map(|this| match self.will_split_placement { .absolute()
Some(placement) => { .bg(cx.theme().drop_target)
let size = DefiniteLength::Fraction(0.35); .map(|this| match self.will_split_placement {
match placement { Some(placement) => {
Placement::Left => { let size = DefiniteLength::Fraction(0.35);
this.left_0().top_0().bottom_0().w(size) match placement {
} Placement::Left => this.left_0().top_0().bottom_0().w(size),
Placement::Right => { Placement::Right => {
this.right_0().top_0().bottom_0().w(size) this.right_0().top_0().bottom_0().w(size)
}
Placement::Top => {
this.top_0().left_0().right_0().h(size)
}
Placement::Bottom => {
this.bottom_0().left_0().right_0().h(size)
}
}
} }
None => this.top_0().left_0().size_full(), Placement::Top => this.top_0().left_0().right_0().h(size),
}) Placement::Bottom => {
.group_drag_over::<DragPanel>("", |this| this.visible()) this.bottom_0().left_0().right_0().h(size)
.on_drop(cx.listener(|this, drag: &DragPanel, cx| { }
this.on_drop(drag, None, true, cx) }
})), }
) None => this.top_0().left_0().size_full(),
}) })
.into_any_element() .group_drag_over::<DragPanel>("", |this| this.visible())
.on_drop(cx.listener(|this, drag: &DragPanel, cx| {
this.on_drop(drag, None, true, cx)
})),
)
}) })
.unwrap_or(Empty {}.into_any_element()) .into_any_element()
} }
/// Calculate the split direction based on the current mouse position /// Calculate the split direction based on the current mouse position
@ -976,11 +982,13 @@ impl EventEmitter<PanelEvent> for TabPanel {}
impl Render for TabPanel { impl Render for TabPanel {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl gpui::IntoElement { fn render(&mut self, cx: &mut ViewContext<Self>) -> impl gpui::IntoElement {
let focus_handle = self.focus_handle(cx); let focus_handle = self.focus_handle(cx);
let active_panel = self.active_panel(cx);
let mut state = TabState { let mut state = TabState {
closable: self.closable(cx), closable: self.closable(cx),
draggable: self.draggable(cx), draggable: self.draggable(cx),
droppable: self.droppable(cx), droppable: self.droppable(cx),
zoomable: self.zoomable(cx), zoomable: self.zoomable(cx),
active_panel,
}; };
if !state.draggable { if !state.draggable {
state.closable = false; state.closable = false;
@ -994,7 +1002,7 @@ impl Render for TabPanel {
.size_full() .size_full()
.overflow_hidden() .overflow_hidden()
.bg(cx.theme().background) .bg(cx.theme().background)
.child(self.render_title_bar(state, cx)) .child(self.render_title_bar(&state, cx))
.child(self.render_active_panel(state, cx)) .child(self.render_active_panel(&state, cx))
} }
} }