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:
parent
c28f5b11f8
commit
8240a52a39
2 changed files with 79 additions and 30 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue