Add support for resizing panes using vim motions (#21038)
Closes #8628 Release Notes: - Added support for resizing the current pane using vim keybinds with the intention to follow the functionality of vim - "ctrl-w +" to make a pane taller - "ctrl-w -" to make the pane shorter - "ctrl-w >" to make a pane wider - "ctrl-w <" to make the pane narrower - Changed vim pre_count and post_count to globals to allow for other crates to use the vim count. In this case, it allows for resizing by more than one unit. For example, "10 ctrl-w -" will decrease the height of the pane 10 times more than "ctrl-w -" - This pr does **not** add keybinds for making all panes in an axis equal size and does **not** add support for resizing docks. This is mentioned because these could be implied by the original issue --------- Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
parent
d75d34576a
commit
f702575255
25 changed files with 251 additions and 68 deletions
|
@ -8,8 +8,8 @@ use call::{ActiveCall, ParticipantLocation};
|
|||
use client::proto::PeerId;
|
||||
use collections::HashMap;
|
||||
use gpui::{
|
||||
point, size, AnyView, AnyWeakView, Axis, Bounds, IntoElement, Model, MouseButton, Pixels,
|
||||
Point, StyleRefinement, View, ViewContext,
|
||||
point, size, Along, AnyView, AnyWeakView, Axis, Bounds, IntoElement, Model, MouseButton,
|
||||
Pixels, Point, StyleRefinement, View, ViewContext,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use project::Project;
|
||||
|
@ -90,6 +90,21 @@ impl PaneGroup {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resize(
|
||||
&mut self,
|
||||
pane: &View<Pane>,
|
||||
direction: Axis,
|
||||
amount: Pixels,
|
||||
bounds: &Bounds<Pixels>,
|
||||
) {
|
||||
match &mut self.root {
|
||||
Member::Pane(_) => {}
|
||||
Member::Axis(axis) => {
|
||||
let _ = axis.resize(pane, direction, amount, bounds);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn swap(&mut self, from: &View<Pane>, to: &View<Pane>) {
|
||||
match &mut self.root {
|
||||
Member::Pane(_) => {}
|
||||
|
@ -445,6 +460,116 @@ impl PaneAxis {
|
|||
}
|
||||
}
|
||||
|
||||
fn resize(
|
||||
&mut self,
|
||||
pane: &View<Pane>,
|
||||
axis: Axis,
|
||||
amount: Pixels,
|
||||
bounds: &Bounds<Pixels>,
|
||||
) -> Option<bool> {
|
||||
let container_size = self
|
||||
.bounding_boxes
|
||||
.lock()
|
||||
.iter()
|
||||
.filter_map(|e| *e)
|
||||
.reduce(|acc, e| acc.union(&e))
|
||||
.unwrap_or(*bounds)
|
||||
.size;
|
||||
|
||||
let found_pane = self
|
||||
.members
|
||||
.iter()
|
||||
.any(|member| matches!(member, Member::Pane(p) if p == pane));
|
||||
|
||||
if found_pane && self.axis != axis {
|
||||
return Some(false); // pane found but this is not the correct axis direction
|
||||
}
|
||||
let mut found_axis_index: Option<usize> = None;
|
||||
if !found_pane {
|
||||
for (i, pa) in self.members.iter_mut().enumerate() {
|
||||
if let Member::Axis(pa) = pa {
|
||||
if let Some(done) = pa.resize(pane, axis, amount, bounds) {
|
||||
if done {
|
||||
return Some(true); // pane found and operations already done
|
||||
} else if self.axis != axis {
|
||||
return Some(false); // pane found but this is not the correct axis direction
|
||||
} else {
|
||||
found_axis_index = Some(i); // pane found and this is correct direction
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
found_axis_index?; // no pane found
|
||||
}
|
||||
|
||||
let min_size = match axis {
|
||||
Axis::Horizontal => px(HORIZONTAL_MIN_SIZE),
|
||||
Axis::Vertical => px(VERTICAL_MIN_SIZE),
|
||||
};
|
||||
let mut flexes = self.flexes.lock();
|
||||
|
||||
let ix = if found_pane {
|
||||
self.members.iter().position(|m| {
|
||||
if let Member::Pane(p) = m {
|
||||
p == pane
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
found_axis_index
|
||||
};
|
||||
|
||||
if ix.is_none() {
|
||||
return Some(true);
|
||||
}
|
||||
|
||||
let ix = ix.unwrap_or(0);
|
||||
|
||||
let size = move |ix, flexes: &[f32]| {
|
||||
container_size.along(axis) * (flexes[ix] / flexes.len() as f32)
|
||||
};
|
||||
|
||||
// Don't allow resizing to less than the minimum size, if elements are already too small
|
||||
if min_size - px(1.) > size(ix, flexes.as_slice()) {
|
||||
return Some(true);
|
||||
}
|
||||
|
||||
let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| {
|
||||
let flex_change = flexes.len() as f32 * pixel_dx / container_size.along(axis);
|
||||
let current_target_flex = flexes[target_ix] + flex_change;
|
||||
let next_target_flex = flexes[(target_ix as isize + next) as usize] - flex_change;
|
||||
(current_target_flex, next_target_flex)
|
||||
};
|
||||
|
||||
let apply_changes =
|
||||
|current_ix: usize, proposed_current_pixel_change: Pixels, flexes: &mut [f32]| {
|
||||
let next_target_size = Pixels::max(
|
||||
size(current_ix + 1, flexes) - proposed_current_pixel_change,
|
||||
min_size,
|
||||
);
|
||||
let current_target_size = Pixels::max(
|
||||
size(current_ix, flexes) + size(current_ix + 1, flexes) - next_target_size,
|
||||
min_size,
|
||||
);
|
||||
|
||||
let current_pixel_change = current_target_size - size(current_ix, flexes);
|
||||
|
||||
let (current_target_flex, next_target_flex) =
|
||||
flex_changes(current_pixel_change, current_ix, 1, flexes);
|
||||
|
||||
flexes[current_ix] = current_target_flex;
|
||||
flexes[current_ix + 1] = next_target_flex;
|
||||
};
|
||||
|
||||
if ix + 1 == flexes.len() {
|
||||
apply_changes(ix - 1, -1.0 * amount, flexes.as_mut_slice());
|
||||
} else {
|
||||
apply_changes(ix, amount, flexes.as_mut_slice());
|
||||
}
|
||||
Some(true)
|
||||
}
|
||||
|
||||
fn swap(&mut self, from: &View<Pane>, to: &View<Pane>) {
|
||||
for member in self.members.iter_mut() {
|
||||
match member {
|
||||
|
@ -625,6 +750,14 @@ impl SplitDirection {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
|
||||
pub enum ResizeIntent {
|
||||
Lengthen,
|
||||
Shorten,
|
||||
Widen,
|
||||
Narrow,
|
||||
}
|
||||
|
||||
mod element {
|
||||
|
||||
use std::mem;
|
||||
|
|
|
@ -2988,6 +2988,12 @@ impl Workspace {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resize_pane(&mut self, axis: gpui::Axis, amount: Pixels, cx: &mut ViewContext<Self>) {
|
||||
self.center
|
||||
.resize(&self.active_pane.clone(), axis, amount, &self.bounds);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn handle_pane_focused(&mut self, pane: View<Pane>, cx: &mut ViewContext<Self>) {
|
||||
// This is explicitly hoisted out of the following check for pane identity as
|
||||
// terminal panel panes are not registered as a center panes.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue