Prevent panels from being resized past the edge of the workspace (#20637)

Closes #20593

Release Notes:

- Fixed a bug where it is possible to get in near-unrecoverable panel
state by resizing the panel past the edge of the workspace.

Co-authored-by: Trace <violet.white.batt@gmail.com>
This commit is contained in:
Mikayla Maki 2024-11-22 14:59:40 -08:00 committed by GitHub
parent c28f5b11f8
commit 8240a52a39
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 79 additions and 30 deletions

View file

@ -15,7 +15,7 @@ use std::sync::Arc;
use ui::{h_flex, ContextMenu, IconButton, Tooltip}; use ui::{h_flex, ContextMenu, IconButton, Tooltip};
use ui::{prelude::*, right_click_menu}; use ui::{prelude::*, right_click_menu};
const RESIZE_HANDLE_SIZE: Pixels = Pixels(6.); pub(crate) const RESIZE_HANDLE_SIZE: Pixels = Pixels(6.);
pub enum PanelEvent { pub enum PanelEvent {
ZoomIn, ZoomIn,
@ -574,6 +574,7 @@ impl Dock {
pub fn resize_active_panel(&mut self, size: Option<Pixels>, cx: &mut ViewContext<Self>) { pub fn resize_active_panel(&mut self, size: Option<Pixels>, cx: &mut ViewContext<Self>) {
if let Some(entry) = self.panel_entries.get_mut(self.active_panel_index) { if let Some(entry) = self.panel_entries.get_mut(self.active_panel_index) {
let size = size.map(|size| size.max(RESIZE_HANDLE_SIZE).round()); let size = size.map(|size| size.max(RESIZE_HANDLE_SIZE).round());
entry.panel.set_size(size, cx); entry.panel.set_size(size, cx);
cx.notify(); cx.notify();
} }
@ -593,6 +594,15 @@ impl Dock {
dispatch_context dispatch_context
} }
pub fn clamp_panel_size(&mut self, max_size: Pixels, cx: &mut WindowContext) {
let max_size = px((max_size.0 - RESIZE_HANDLE_SIZE.0).abs());
for panel in self.panel_entries.iter().map(|entry| &entry.panel) {
if panel.size(cx) > max_size {
panel.set_size(Some(max_size.max(RESIZE_HANDLE_SIZE)), cx);
}
}
}
} }
impl Render for Dock { impl Render for Dock {

View file

@ -21,7 +21,7 @@ use client::{
}; };
use collections::{hash_map, HashMap, HashSet}; use collections::{hash_map, HashMap, HashSet};
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use dock::{Dock, DockPosition, Panel, PanelButtons, PanelHandle}; use dock::{Dock, DockPosition, Panel, PanelButtons, PanelHandle, RESIZE_HANDLE_SIZE};
use futures::{ use futures::{
channel::{ channel::{
mpsc::{self, UnboundedReceiver, UnboundedSender}, mpsc::{self, UnboundedReceiver, UnboundedSender},
@ -4824,7 +4824,27 @@ impl Render for Workspace {
let this = cx.view().clone(); let this = cx.view().clone();
canvas( canvas(
move |bounds, cx| { move |bounds, cx| {
this.update(cx, |this, _cx| this.bounds = bounds) this.update(cx, |this, cx| {
let bounds_changed = this.bounds != bounds;
this.bounds = bounds;
if bounds_changed {
this.left_dock.update(cx, |dock, cx| {
dock.clamp_panel_size(bounds.size.width, cx)
});
this.right_dock.update(cx, |dock, cx| {
dock.clamp_panel_size(bounds.size.width, cx)
});
this.bottom_dock.update(cx, |dock, cx| {
dock.clamp_panel_size(
bounds.size.height,
cx,
)
});
}
})
}, },
|_, _, _| {}, |_, _, _| {},
) )
@ -4836,42 +4856,27 @@ impl Render for Workspace {
|workspace, e: &DragMoveEvent<DraggedDock>, cx| { |workspace, e: &DragMoveEvent<DraggedDock>, cx| {
match e.drag(cx).0 { match e.drag(cx).0 {
DockPosition::Left => { DockPosition::Left => {
let size = e.event.position.x resize_left_dock(
- workspace.bounds.left(); e.event.position.x
workspace.left_dock.update( - workspace.bounds.left(),
workspace,
cx, cx,
|left_dock, cx| {
left_dock.resize_active_panel(
Some(size),
cx,
);
},
); );
} }
DockPosition::Right => { DockPosition::Right => {
let size = workspace.bounds.right() resize_right_dock(
- e.event.position.x; workspace.bounds.right()
workspace.right_dock.update( - e.event.position.x,
workspace,
cx, cx,
|right_dock, cx| {
right_dock.resize_active_panel(
Some(size),
cx,
);
},
); );
} }
DockPosition::Bottom => { DockPosition::Bottom => {
let size = workspace.bounds.bottom() resize_bottom_dock(
- e.event.position.y; workspace.bounds.bottom()
workspace.bottom_dock.update( - e.event.position.y,
workspace,
cx, cx,
|bottom_dock, cx| {
bottom_dock.resize_active_panel(
Some(size),
cx,
);
},
); );
} }
} }
@ -4959,6 +4964,40 @@ impl Render for Workspace {
} }
} }
fn resize_bottom_dock(
new_size: Pixels,
workspace: &mut Workspace,
cx: &mut ViewContext<'_, Workspace>,
) {
let size = new_size.min(workspace.bounds.bottom() - RESIZE_HANDLE_SIZE);
workspace.bottom_dock.update(cx, |bottom_dock, cx| {
bottom_dock.resize_active_panel(Some(size), cx);
});
}
fn resize_right_dock(
new_size: Pixels,
workspace: &mut Workspace,
cx: &mut ViewContext<'_, Workspace>,
) {
let size = new_size.max(workspace.bounds.left() - RESIZE_HANDLE_SIZE);
workspace.right_dock.update(cx, |right_dock, cx| {
right_dock.resize_active_panel(Some(size), cx);
});
}
fn resize_left_dock(
new_size: Pixels,
workspace: &mut Workspace,
cx: &mut ViewContext<'_, Workspace>,
) {
let size = new_size.min(workspace.bounds.right() - RESIZE_HANDLE_SIZE);
workspace.left_dock.update(cx, |left_dock, cx| {
left_dock.resize_active_panel(Some(size), cx);
});
}
impl WorkspaceStore { impl WorkspaceStore {
pub fn new(client: Arc<Client>, cx: &mut ModelContext<Self>) -> Self { pub fn new(client: Arc<Client>, cx: &mut ModelContext<Self>) -> Self {
Self { Self {