From 26b9be628ebaf238c683bb925ca155518126e5ca Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 12 Jul 2023 22:34:33 -0700 Subject: [PATCH] Add the math for pane resizing --- crates/gpui/src/app/window.rs | 13 +++ crates/gpui/src/gpui.rs | 2 +- crates/workspace/src/dock.rs | 3 - crates/workspace/src/pane_group.rs | 120 ++++++++++++++++------ crates/workspace/src/persistence/model.rs | 6 +- 5 files changed, 103 insertions(+), 41 deletions(-) diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 58d7bb4c4035f03083482d4a83e3c5b7b6e855f1..49b12d823e69832eb42ae382c3d6b37c39fd1957 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -1268,6 +1268,19 @@ impl Vector2FExt for Vector2F { } } +pub trait RectFExt { + fn length_along(self, axis: Axis) -> f32; +} + +impl RectFExt for RectF { + fn length_along(self, axis: Axis) -> f32 { + match axis { + Axis::Horizontal => self.width(), + Axis::Vertical => self.height(), + } + } +} + #[derive(Copy, Clone, Debug)] pub struct SizeConstraint { pub min: Vector2F, diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index 3442934b3a9520ecca113433f420c63a15140489..c79c793ddaf87c201b448f568f9fc12b11f8b9f0 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -27,7 +27,7 @@ pub mod json; pub mod keymap_matcher; pub mod platform; pub use gpui_macros::{test, Element}; -pub use window::{Axis, SizeConstraint, Vector2FExt, WindowContext}; +pub use window::{Axis, RectFExt, SizeConstraint, Vector2FExt, WindowContext}; pub use anyhow; pub use serde_json; diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 259e343248508790b673133f9f46c983c7532a2f..ebaf399e22b3ecfa51b217327f5912a34dc7b542 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -408,9 +408,6 @@ impl View for Dock { } fn render(&mut self, cx: &mut ViewContext) -> AnyElement { - - - if let Some(active_entry) = self.visible_entry() { let style = self.style(cx); ChildView::new(active_entry.panel.as_any(), cx) diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index 7198dff3bfe9362ad0c172cdc982044cea12d88a..fdda67ad22e470777eb5d245051eef72c7318d9d 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -308,10 +308,19 @@ impl Member { pub(crate) struct PaneAxis { pub axis: Axis, pub members: Vec, - pub ratios: Rc>>, + ratios: Rc>>, } impl PaneAxis { + pub fn new(axis: Axis, members: Vec) -> Self { + let ratios = Rc::new(RefCell::new(vec![1.; members.len()])); + Self { + axis, + members, + ratios, + } + } + fn split( &mut self, old_pane: &ViewHandle, @@ -397,20 +406,24 @@ impl PaneAxis { cx: &mut ViewContext, ) -> AnyElement { let ratios = self.ratios.clone(); - let mut flex_container = AdjustableGroupElement::new(self.axis, 2., basis, move |new_flexes| { - let mut borrow = ratios.borrow_mut(); - borrow.extend(new_flexes); - borrow.truncate(10); - dbg!(borrow); - }); + let mut flex_container = + AdjustableGroupElement::new(self.axis, 2., basis, move |new_flexes, _, cx| { + let mut borrow = ratios.borrow_mut(); + for (ix, flex) in new_flexes { + if let Some(el) = borrow.get_mut(ix) { + *el = flex; + } + } + + cx.notify(); + }); + let ratios_borrow = self.ratios.borrow(); let next_basis = basis + self.members.len(); - let mut members = self.members.iter().enumerate().peekable(); - while let Some((_ix, member)) = members.next() { + let mut members = self.members.iter().zip(ratios_borrow.iter()).peekable(); + while let Some((member, flex)) = members.next() { let last = members.peek().is_none(); - let mut flex = 1.0; - // TODO: Include minimum sizes // TODO: Restore this // if member.contains(active_pane) { // flex = settings::get::(cx).active_pane_magnification; @@ -439,16 +452,11 @@ impl PaneAxis { Axis::Horizontal => border.right = true, } - let side = match self.axis { - Axis::Horizontal => HandleSide::Right, - Axis::Vertical => HandleSide::Bottom, - }; - member = member.contained().with_border(border).into_any(); } flex_container = - flex_container.with_child(AdjustableGroupItem::new(member, flex).into_any()); + flex_container.with_child(AdjustableGroupItem::new(member, *flex).into_any()); } flex_container.into_any() @@ -520,10 +528,11 @@ mod adjustable_group { }, json::{self, ToJson}, platform::{CursorStyle, MouseButton}, - AnyElement, Axis, CursorRegion, Element, LayoutContext, MouseRegion, Quad, SceneBuilder, - SizeConstraint, Vector2FExt, View, ViewContext, + AnyElement, Axis, CursorRegion, Element, EventContext, LayoutContext, MouseRegion, Quad, + RectFExt, SceneBuilder, SizeConstraint, Vector2FExt, View, ViewContext, }; use serde_json::Value; + use smallvec::SmallVec; struct AdjustableFlexData { flex: f32, @@ -533,7 +542,7 @@ mod adjustable_group { axis: Axis, handle_size: f32, basis: usize, - callback: Rc)>, + callback: Rc, &mut V, &mut EventContext)>, children: Vec>, } @@ -542,7 +551,7 @@ mod adjustable_group { axis: Axis, handle_size: f32, basis: usize, - callback: impl Fn(Vec) + 'static, + callback: impl Fn(SmallVec<[(usize, f32); 2]>, &mut V, &mut EventContext) + 'static, ) -> Self { Self { axis, @@ -676,8 +685,9 @@ mod adjustable_group { let mut child_origin = bounds.origin(); - let last_ix = self.children.len() - 1; - for (ix, child) in self.children.iter_mut().enumerate() { + let mut children_iter = self.children.iter_mut().enumerate().peekable(); + while let Some((ix, child)) = children_iter.next() { + let child_start = child_origin.clone(); child.paint(scene, child_origin, visible_bounds, view, cx); match self.axis { @@ -685,7 +695,7 @@ mod adjustable_group { Axis::Vertical => child_origin += vec2f(0.0, child.size().y()), } - if ix != last_ix { + if let Some((next_ix, next_child)) = children_iter.peek() { let bounds = match self.axis { Axis::Horizontal => RectF::new( child_origin, @@ -710,20 +720,66 @@ mod adjustable_group { scene.push_cursor_region(CursorRegion { bounds, style }); - enum ResizeHandle {} let callback = self.callback.clone(); let axis = self.axis; + let child_size = child.size(); + let next_child_size = next_child.size(); + let mut drag_bounds = visible_bounds.clone(); + // Unsure why this should be needed.... + drag_bounds.set_origin_y(0.); + let current_flex = child.metadata::().unwrap().flex; + let next_flex = next_child.metadata::().unwrap().flex; + let next_ix = *next_ix; + const HORIZONTAL_MIN_SIZE: f32 = 80.; + const VERTICAL_MIN_SIZE: f32 = 100.; + enum ResizeHandle {} let mut mouse_region = MouseRegion::new::(cx.view_id(), self.basis + ix, bounds); mouse_region = mouse_region.on_drag(MouseButton::Left, move |drag, v: &mut V, cx| { - dbg!(drag); - callback({ - match axis { - Axis::Horizontal => vec![0., 1., 2.], - Axis::Vertical => vec![3., 2., 1.], - } - }) + let min_size = match axis { + Axis::Horizontal => HORIZONTAL_MIN_SIZE, + Axis::Vertical => VERTICAL_MIN_SIZE, + }; + // Don't allow resizing to less than the minimum size, if elements are already too small + if min_size - 1. > child_size.along(axis) + || min_size - 1. > next_child_size.along(axis) + { + return; + } + + let flex_position = drag.position - drag_bounds.origin(); + let mut current_target_size = (flex_position - child_start).along(axis); + let proposed_current_pixel_change = + current_target_size - child_size.along(axis); + + if proposed_current_pixel_change < 0. { + current_target_size = current_target_size.max(min_size); + } else if proposed_current_pixel_change > 0. { + // TODO: cascade this size change down, collect into a vec + let next_target_size = (next_child_size.along(axis) + - proposed_current_pixel_change) + .max(min_size); + current_target_size = current_target_size.min( + child_size.along(axis) + next_child_size.along(axis) + - next_target_size, + ); + } + + let current_pixel_change = current_target_size - child_size.along(axis); + let flex_change = current_pixel_change / drag_bounds.length_along(axis); + + let current_target_flex = current_flex + flex_change; + let next_target_flex = next_flex - flex_change; + + callback( + smallvec::smallvec![ + (ix, current_target_flex), + (next_ix, next_target_flex), + ], + v, + cx, + ) }); scene.push_mouse_region(mouse_region); diff --git a/crates/workspace/src/persistence/model.rs b/crates/workspace/src/persistence/model.rs index c159ff0f427c573ca83733ea582cd60f62b84854..762d7171deeea6c3cf9dad87a9f623007aad46e5 100644 --- a/crates/workspace/src/persistence/model.rs +++ b/crates/workspace/src/persistence/model.rs @@ -184,11 +184,7 @@ impl SerializedPaneGroup { } Some(( - Member::Axis(PaneAxis { - axis: *axis, - members, - ratios: Default::default() - }), + Member::Axis(PaneAxis::new(*axis, members)), current_active_pane, items, ))