WIP: cascade split resizes

Mikayla Maki created

Change summary

crates/workspace/src/pane_group.rs | 176 +++++++++++++++++--------------
1 file changed, 98 insertions(+), 78 deletions(-)

Detailed changes

crates/workspace/src/pane_group.rs 🔗

@@ -587,14 +587,16 @@ mod element {
     use std::{cell::RefCell, ops::Range, rc::Rc};
 
     use gpui::{
+        elements::MouseEventHandler,
         geometry::{
             rect::RectF,
             vector::{vec2f, Vector2F},
         },
         json::{self, ToJson},
         platform::{CursorStyle, MouseButton},
-        AnyElement, Axis, CursorRegion, Element, LayoutContext, MouseRegion, RectFExt,
-        SceneBuilder, SizeConstraint, Vector2FExt, ViewContext,
+        scene::MouseDrag,
+        AnyElement, Axis, CursorRegion, Element, EventContext, LayoutContext, MouseRegion,
+        RectFExt, SceneBuilder, SizeConstraint, Vector2FExt, ViewContext,
     };
 
     use crate::{
@@ -682,6 +684,90 @@ mod element {
                 *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis));
             }
         }
+
+        fn handle_resize(
+            flexes: Rc<RefCell<Vec<f32>>>,
+            axis: Axis,
+            ix: usize,
+            child_start: Vector2F,
+            drag_bounds: RectF,
+        ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext<Workspace>) {
+            let size = move |ix, flexes: &[f32]| {
+                drag_bounds.length_along(axis) * (flexes[ix] / flexes.len() as f32)
+            };
+
+            move |drag, workspace: &mut Workspace, cx| {
+                let min_size = match axis {
+                    Axis::Horizontal => HORIZONTAL_MIN_SIZE,
+                    Axis::Vertical => VERTICAL_MIN_SIZE,
+                };
+                let mut flexes = flexes.borrow_mut();
+
+                // Don't allow resizing to less than the minimum size, if elements are already too small
+                if min_size - 1. > size(ix, flexes.as_slice()) {
+                    return;
+                }
+
+                let mut current_target_size = (drag.position - child_start).along(axis);
+
+                let mut proposed_current_pixel_change =
+                    current_target_size - size(ix, flexes.as_slice());
+
+                let flex_changes = |pixel_dx, target_ix, flexes: &[f32]| {
+                    let flex_change = pixel_dx / drag_bounds.length_along(axis);
+                    let current_target_flex = flexes[target_ix] + flex_change;
+                    let next_target_flex = flexes[target_ix + 1] - flex_change;
+                    (current_target_flex, next_target_flex)
+                };
+
+                if proposed_current_pixel_change < 0. {
+                    current_target_size = f32::max(current_target_size, min_size);
+                    let current_pixel_change = current_target_size - size(ix, flexes.as_slice());
+
+                    let (current_target_flex, next_target_flex) =
+                        flex_changes(current_pixel_change, ix, flexes.as_slice());
+
+                    flexes[ix] = current_target_flex;
+                    flexes[ix + 1] = next_target_flex;
+                } else if proposed_current_pixel_change > 0. {
+                    let mut ix_offset = 0;
+                    while proposed_current_pixel_change > 0.01 && ix + 1 + ix_offset < flexes.len()
+                    {
+                        let next_target_size = f32::max(
+                            size(ix + 1, flexes.as_slice()) - proposed_current_pixel_change,
+                            min_size,
+                        );
+
+                        current_target_size = f32::min(
+                            current_target_size,
+                            size(ix, flexes.as_slice()) + size(ix + 1, flexes.as_slice())
+                                - next_target_size,
+                        );
+
+                        let current_pixel_change =
+                            current_target_size - size(ix, flexes.as_slice());
+
+                        let (current_target_flex, next_target_flex) =
+                            flex_changes(current_pixel_change, ix, flexes.as_slice());
+
+                        flexes[ix_offset + ix] = current_target_flex;
+                        flexes[ix_offset + ix + 1] = next_target_flex;
+
+                        dbg!(
+                            current_pixel_change,
+                            proposed_current_pixel_change,
+                            proposed_current_pixel_change - current_pixel_change
+                        );
+                        proposed_current_pixel_change -= current_pixel_change;
+                        ix_offset += 1;
+                    }
+                    dbg!("done");
+                }
+
+                workspace.schedule_serialize(cx);
+                cx.notify();
+            }
+        }
     }
 
     impl Extend<AnyElement<Workspace>> for PaneAxisElement {
@@ -780,11 +866,6 @@ mod element {
             let mut bounding_boxes = self.bounding_boxes.borrow_mut();
             bounding_boxes.clear();
 
-            let sizes = self
-                .children
-                .iter()
-                .map(|child| child.size())
-                .collect::<Vec<_>>();
             let mut children_iter = self.children.iter_mut().enumerate().peekable();
             while let Some((ix, child)) = children_iter.next() {
                 let child_start = child_origin.clone();
@@ -826,8 +907,6 @@ mod element {
                         style,
                     });
 
-                    let axis = self.axis;
-                    let drag_bounds = visible_bounds.clone();
                     enum ResizeHandle {}
                     let mut mouse_region = MouseRegion::new::<ResizeHandle>(
                         cx.view_id(),
@@ -835,75 +914,16 @@ mod element {
                         handle_bounds,
                     );
                     mouse_region = mouse_region
-                        .on_drag(MouseButton::Left, {
-                            let flexes = self.flexes.clone();
-                            let sizes = sizes.clone();
-                            move |drag, workspace: &mut Workspace, cx| {
-                                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. > sizes[ix].along(axis) {
-                                    return;
-                                }
-
-                                let mut flexes = flexes.borrow_mut();
-
-                                let mut current_target_size =
-                                    (drag.position - child_start).along(axis);
-
-                                let mut proposed_current_pixel_change =
-                                    current_target_size - sizes[ix].along(axis);
-
-                                let flex_changes = |target_size, target_ix| {
-                                    let current_pixel_change = target_size - sizes[ix].along(axis);
-                                    let flex_change =
-                                        current_pixel_change / drag_bounds.length_along(axis);
-                                    let current_target_flex = flexes[target_ix] + flex_change;
-                                    let next_target_flex = flexes[target_ix + 1] - flex_change;
-                                    (current_target_flex, next_target_flex)
-                                };
-
-                                if proposed_current_pixel_change < 0. {
-                                    current_target_size = f32::max(current_target_size, min_size);
-                                    let (current_target_flex, next_target_flex) =
-                                        flex_changes(current_target_size, ix);
-
-                                    *flexes.get_mut(ix).unwrap() = current_target_flex;
-                                    *flexes.get_mut(ix + 1).unwrap() = next_target_flex;
-                                } else if proposed_current_pixel_change > 0. {
-                                    let mut next_target_size = f32::max(
-                                        sizes[ix + 1].along(axis) - proposed_current_pixel_change,
-                                        min_size,
-                                    );
-
-                                    current_target_size = f32::min(
-                                        current_target_size,
-                                        sizes[ix].along(axis) + sizes[ix + 1].along(axis)
-                                            - next_target_size,
-                                    );
-
-                                    let (current_target_flex, next_target_flex) =
-                                        flex_changes(current_target_size, ix);
-
-                                    // TODO: make this into a loop
-                                    *flexes.get_mut(ix).unwrap() = current_target_flex;
-                                    *flexes.get_mut(ix + 1).unwrap() = next_target_flex;
-
-                                    // let mut ix_offset = 0;
-
-                                    // while proposed_current_pixel_change > 0.
-                                    //     && ix + 1 + ix_offset < flexes.len()
-                                    // {
-
-                                    // }
-                                }
-
-                                workspace.schedule_serialize(cx);
-                                cx.notify();
-                            }
-                        })
+                        .on_drag(
+                            MouseButton::Left,
+                            Self::handle_resize(
+                                self.flexes.clone(),
+                                self.axis,
+                                ix,
+                                child_start,
+                                visible_bounds.clone(),
+                            ),
+                        )
                         .on_click(MouseButton::Left, {
                             let flexes = self.flexes.clone();
                             move |e, v: &mut Workspace, cx| {