dock: Fix panel zoom sometimes is not work. #197 (#211)

This is because the `PanelEvent::ZoomIn` is called 2 times when we click
the menu (I don't why, not found the source).

So just split Zoom in, Zoom out as two difference methods to avoid this.
This commit is contained in:
Jason Lee 2024-09-03 23:15:44 +08:00 committed by GitHub
parent 0834ac0394
commit 0158083599
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 46 additions and 33 deletions

View file

@ -3,7 +3,7 @@ mod stack_panel;
mod tab_panel;
use gpui::{
actions, div, prelude::FluentBuilder, AnyWeakView, InteractiveElement as _, IntoElement,
actions, div, prelude::FluentBuilder, AnyView, InteractiveElement as _, IntoElement,
ParentElement as _, Render, SharedString, Styled, View, ViewContext,
};
pub use panel::*;
@ -16,7 +16,7 @@ actions!(dock, [ToggleZoom, ClosePanel]);
pub struct DockArea {
id: SharedString,
root: View<StackPanel>,
zoom_view: Option<AnyWeakView>,
zoom_view: Option<AnyView>,
}
impl DockArea {
@ -37,13 +37,13 @@ impl DockArea {
self.id.clone()
}
/// Toggles the zoom view.
pub fn toggle_zoom<P: Panel>(&mut self, panel: View<P>, cx: &mut ViewContext<Self>) {
if self.zoom_view.is_some() {
self.zoom_view = None;
} else {
self.zoom_view = Some(panel.downgrade().into());
}
pub fn set_zoomed_in<P: Panel>(&mut self, panel: View<P>, cx: &mut ViewContext<Self>) {
self.zoom_view = Some(panel.into());
cx.notify();
}
pub fn set_zoomed_out(&mut self, cx: &mut ViewContext<Self>) {
self.zoom_view = None;
cx.notify();
}
@ -55,12 +55,13 @@ impl DockArea {
impl Render for DockArea {
fn render(&mut self, _: &mut ViewContext<Self>) -> impl IntoElement {
// println!("Rendering dock area");
div()
.id("dock-area")
.size_full()
.overflow_hidden()
.map(|this| {
if let Some(zoom_view) = self.zoom_view.as_ref().and_then(|view| view.upgrade()) {
if let Some(zoom_view) = self.zoom_view.clone() {
this.child(zoom_view)
} else {
this.child(self.root.clone())

View file

@ -24,9 +24,7 @@ pub trait Panel: EventEmitter<PanelEvent> + FocusableView {
pub trait PanelView: 'static + Send + Sync {
/// The title of the panel, default is `None`.
fn title(&self, _cx: &WindowContext) -> SharedString {
t!("Dock.Unnamed").into()
}
fn title(&self, _cx: &WindowContext) -> SharedString;
fn closeable(&self, cx: &WindowContext) -> bool;

View file

@ -23,7 +23,11 @@ pub struct StackPanel {
panel_group: View<ResizablePanelGroup>,
}
impl Panel for StackPanel {}
impl Panel for StackPanel {
fn title(&self, _cx: &gpui::WindowContext) -> gpui::SharedString {
"StackPanel".into()
}
}
impl StackPanel {
pub fn new(axis: Axis, cx: &mut ViewContext<Self>) -> Self {
@ -52,7 +56,7 @@ impl StackPanel {
}
/// Return the index of the panel.
pub fn index_of_panel<P>(&self, panel: View<P>) -> Option<usize>
pub(crate) fn index_of_panel<P>(&self, panel: &View<P>) -> Option<usize>
where
P: Panel,
{
@ -157,30 +161,33 @@ impl StackPanel {
P: Panel,
{
// If the panel is already in the stack, return.
if let Some(_) = self.index_of_panel(panel.clone()) {
if let Some(_) = self.index_of_panel(&panel) {
return;
}
let dock_area = dock_area.clone();
cx.subscribe(&panel, move |_, panel, event, cx| match event {
PanelEvent::ZoomIn | PanelEvent::ZoomOut => {
if let Some(dock) = dock_area.upgrade() {
dock.update(cx, |dock, cx| {
dock.toggle_zoom(panel.clone(), cx);
});
}
PanelEvent::ZoomIn => {
let _ = dock_area.update(cx, |dock, cx| {
dock.set_zoomed_in(panel.clone(), cx);
});
}
PanelEvent::ZoomOut => {
let _ = dock_area.update(cx, |dock, cx| dock.set_zoomed_out(cx));
}
})
.detach();
let view = cx.view().clone();
let panel1 = panel.clone();
cx.window_context().defer(move |cx| {
// If the panel is a TabPanel, set its parent to this.
if let Ok(tab_panel) = panel1.view().downcast::<TabPanel>() {
tab_panel.update(cx, |tab_panel, _| tab_panel.set_parent(view));
} else if let Ok(stack_panel) = panel1.view().downcast::<Self>() {
stack_panel.update(cx, |stack_panel, _| stack_panel.parent = Some(view));
cx.window_context().defer({
let panel = panel.clone();
move |cx| {
// If the panel is a TabPanel, set its parent to this.
if let Ok(tab_panel) = panel.view().downcast::<TabPanel>() {
tab_panel.update(cx, |tab_panel, _| tab_panel.set_parent(view));
} else if let Ok(stack_panel) = panel.view().downcast::<Self>() {
stack_panel.update(cx, |stack_panel, _| stack_panel.parent = Some(view));
}
}
});
@ -203,7 +210,7 @@ impl StackPanel {
where
P: Panel,
{
if let Some(ix) = self.index_of_panel(panel) {
if let Some(ix) = self.index_of_panel(&panel) {
self.panels.remove(ix);
self.panel_group.update(cx, |view, cx| {
view.remove_child(ix, cx);
@ -224,7 +231,7 @@ impl StackPanel {
) where
P: Panel,
{
if let Some(ix) = self.index_of_panel(old_panel) {
if let Some(ix) = self.index_of_panel(&old_panel) {
self.panels[ix] = Arc::new(new_panel.clone());
self.panel_group.update(cx, |view, cx| {
view.replace_child(Self::new_resizable_panel(new_panel.clone(), None), ix, cx);

View file

@ -20,6 +20,7 @@ use crate::{
use super::{ClosePanel, DockArea, Panel, PanelView, StackPanel, ToggleZoom};
#[derive(Debug)]
pub enum PanelEvent {
ZoomIn,
ZoomOut,
@ -449,7 +450,7 @@ impl TabPanel {
let parent_axis = stack_panel.read(cx).axis;
let ix = stack_panel
.read(cx)
.index_of_panel(cx.view().clone())
.index_of_panel(&cx.view())
.unwrap_or_default();
if parent_axis.is_vertical() && placement.is_vertical() {
@ -523,6 +524,12 @@ impl TabPanel {
}
impl Panel for TabPanel {
fn title(&self, cx: &WindowContext) -> gpui::SharedString {
self.active_panel()
.map(|panel| panel.title(cx))
.unwrap_or("Empty Tab".into())
}
fn closeable(&self, cx: &WindowContext) -> bool {
self.active_panel()
.map(|panel| panel.closeable(cx))