From 488b41826b90102180a3c60c3a088ff1195e0749 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 12 Jul 2023 12:46:56 -0700 Subject: [PATCH 1/9] WIP --- crates/workspace/src/adjustable_flex.rs | 83 ++++++++++++++++++++++++ crates/workspace/src/dock.rs | 3 + crates/workspace/src/pane_group.rs | 84 ++++++++++++++++--------- crates/workspace/src/workspace.rs | 5 +- 4 files changed, 140 insertions(+), 35 deletions(-) create mode 100644 crates/workspace/src/adjustable_flex.rs diff --git a/crates/workspace/src/adjustable_flex.rs b/crates/workspace/src/adjustable_flex.rs new file mode 100644 index 0000000000..4ea1b719f1 --- /dev/null +++ b/crates/workspace/src/adjustable_flex.rs @@ -0,0 +1,83 @@ +use gpui::{Element, View, Axis, AnyElement}; + +// Model for the center group: AdjustableGroup of AdjustableGroups +// Implementation notes +// - These have two representations: Exact pixel widths and ratios of elements compared to whole space +// - We have a constraint of minimum sizes for things. +// - If The space is smaller than allowed, things run off the edge +// - When doing Drag resize, we update the pixel width representation, causing a recalc of the ratios +// - If dragging past minimum, take space from next item, until out of space +// - When doing a reflow (e.g. layout) we read off the ratios and calculate pixels from that +// - When adding / removing items in an Adjustable flex, reset to default ratios (1:1) +// - By default, every item takes up as much space as possible +// + + +struct AdjustableFlex { + axis: Axis, + handle_size: f32, + items: Vec<(AnyElement, f32)> +} + +impl AdjustableFlex { + fn new(axis: Axis) -> Self { + AdjustableFlex { + axis, + handle_size: 2., + items: Vec::new(), + } + } + + fn add_item() +} + +impl Element for AdjustableFlex { + type LayoutState = (); + + type PaintState = (); + + fn layout( + &mut self, + constraint: gpui::SizeConstraint, + view: &mut V, + cx: &mut gpui::LayoutContext, + ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { + todo!() + } + + fn paint( + &mut self, + scene: &mut gpui::SceneBuilder, + bounds: gpui::geometry::rect::RectF, + visible_bounds: gpui::geometry::rect::RectF, + layout: &mut Self::LayoutState, + view: &mut V, + cx: &mut gpui::ViewContext, + ) -> Self::PaintState { + todo!() + } + + fn rect_for_text_range( + &self, + range_utf16: std::ops::Range, + bounds: gpui::geometry::rect::RectF, + visible_bounds: gpui::geometry::rect::RectF, + layout: &Self::LayoutState, + paint: &Self::PaintState, + view: &V, + cx: &gpui::ViewContext, + ) -> Option { + todo!() + } + + fn debug( + &self, + bounds: gpui::geometry::rect::RectF, + layout: &Self::LayoutState, + paint: &Self::PaintState, + view: &V, + cx: &gpui::ViewContext, + ) -> serde_json::Value { + todo!() + } +} diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index ebaf399e22..259e343248 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -408,6 +408,9 @@ 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 5e5a5a98ba..8160a770a3 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -9,6 +9,7 @@ use gpui::{ platform::{CursorStyle, MouseButton}, AnyViewHandle, Axis, Border, ModelHandle, ViewContext, ViewHandle, }; +use itertools::Itertools; use project::Project; use serde::Deserialize; use theme::Theme; @@ -385,40 +386,61 @@ impl PaneAxis { app_state: &Arc, cx: &mut ViewContext, ) -> AnyElement { - let last_member_ix = self.members.len() - 1; - Flex::new(self.axis) - .with_children(self.members.iter().enumerate().map(|(ix, member)| { - let mut flex = 1.0; - if member.contains(active_pane) { - flex = settings::get::(cx).active_pane_magnification; + let mut flex_container = Flex::new(self.axis); + + let mut members = self.members.iter().enumerate().peekable(); + while let Some((ix, member)) = members.next() { + let last = members.peek().is_none(); + + let mut flex = 1.0; + if member.contains(active_pane) { + flex = settings::get::(cx).active_pane_magnification; + } + + let mut member = member.render( + project, + theme, + follower_state, + active_call, + active_pane, + zoomed, + app_state, + cx, + ); + if !last { + let mut border = theme.workspace.pane_divider; + border.left = false; + border.right = false; + border.top = false; + border.bottom = false; + + match self.axis { + Axis::Vertical => border.bottom = true, + Axis::Horizontal => border.right = true, } - let mut member = member.render( - project, - theme, - follower_state, - active_call, - active_pane, - zoomed, - app_state, - cx, - ); - if ix < last_member_ix { - let mut border = theme.workspace.pane_divider; - border.left = false; - border.right = false; - border.top = false; - border.bottom = false; - match self.axis { - Axis::Vertical => border.bottom = true, - Axis::Horizontal => border.right = true, - } - member = member.contained().with_border(border).into_any(); - } + let side = match self.axis { + Axis::Horizontal => HandleSide::Right, + Axis::Vertical => HandleSide::Bottom, + }; - FlexItem::new(member).flex(flex, true) - })) - .into_any() + member = member.contained().with_border(border) + .resizable(side, 1., |workspace, size, cx| { + dbg!("resize", size); + }) + .into_any(); + + + } + + flex_container = flex_container.with_child( + FlexItem::new(member) + .flex(flex, true) + .into_any() + ); + } + + flex_container.into_any() } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 01d80d141c..cafcd191a3 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1,13 +1,10 @@ pub mod dock; -/// NOTE: Focus only 'takes' after an update has flushed_effects. -/// -/// This may cause issues when you're trying to write tests that use workspace focus to add items at -/// specific locations. pub mod item; pub mod notifications; pub mod pane; pub mod pane_group; mod persistence; +mod adjustable_flex; pub mod searchable; pub mod shared_screen; mod status_bar; From 5385ca411bc3b6392df023562b3ec28e492f0368 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 12 Jul 2023 17:53:01 -0700 Subject: [PATCH 2/9] Added the new elements and wired through the pointers to update the pane axis ratios --- crates/workspace/src/adjustable_flex.rs | 83 ----- crates/workspace/src/pane_group.rs | 397 ++++++++++++++++++++-- crates/workspace/src/persistence/model.rs | 1 + crates/workspace/src/workspace.rs | 3 +- 4 files changed, 375 insertions(+), 109 deletions(-) delete mode 100644 crates/workspace/src/adjustable_flex.rs diff --git a/crates/workspace/src/adjustable_flex.rs b/crates/workspace/src/adjustable_flex.rs deleted file mode 100644 index 4ea1b719f1..0000000000 --- a/crates/workspace/src/adjustable_flex.rs +++ /dev/null @@ -1,83 +0,0 @@ -use gpui::{Element, View, Axis, AnyElement}; - -// Model for the center group: AdjustableGroup of AdjustableGroups -// Implementation notes -// - These have two representations: Exact pixel widths and ratios of elements compared to whole space -// - We have a constraint of minimum sizes for things. -// - If The space is smaller than allowed, things run off the edge -// - When doing Drag resize, we update the pixel width representation, causing a recalc of the ratios -// - If dragging past minimum, take space from next item, until out of space -// - When doing a reflow (e.g. layout) we read off the ratios and calculate pixels from that -// - When adding / removing items in an Adjustable flex, reset to default ratios (1:1) -// - By default, every item takes up as much space as possible -// - - -struct AdjustableFlex { - axis: Axis, - handle_size: f32, - items: Vec<(AnyElement, f32)> -} - -impl AdjustableFlex { - fn new(axis: Axis) -> Self { - AdjustableFlex { - axis, - handle_size: 2., - items: Vec::new(), - } - } - - fn add_item() -} - -impl Element for AdjustableFlex { - type LayoutState = (); - - type PaintState = (); - - fn layout( - &mut self, - constraint: gpui::SizeConstraint, - view: &mut V, - cx: &mut gpui::LayoutContext, - ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { - todo!() - } - - fn paint( - &mut self, - scene: &mut gpui::SceneBuilder, - bounds: gpui::geometry::rect::RectF, - visible_bounds: gpui::geometry::rect::RectF, - layout: &mut Self::LayoutState, - view: &mut V, - cx: &mut gpui::ViewContext, - ) -> Self::PaintState { - todo!() - } - - fn rect_for_text_range( - &self, - range_utf16: std::ops::Range, - bounds: gpui::geometry::rect::RectF, - visible_bounds: gpui::geometry::rect::RectF, - layout: &Self::LayoutState, - paint: &Self::PaintState, - view: &V, - cx: &gpui::ViewContext, - ) -> Option { - todo!() - } - - fn debug( - &self, - bounds: gpui::geometry::rect::RectF, - layout: &Self::LayoutState, - paint: &Self::PaintState, - view: &V, - cx: &gpui::ViewContext, - ) -> serde_json::Value { - todo!() - } -} diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index 8160a770a3..7198dff3bf 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -1,6 +1,6 @@ -use std::sync::Arc; +use std::{cell::RefCell, rc::Rc, sync::Arc}; -use crate::{AppState, FollowerStatesByLeader, Pane, Workspace, WorkspaceSettings}; +use crate::{AppState, FollowerStatesByLeader, Pane, Workspace}; use anyhow::{anyhow, Result}; use call::{ActiveCall, ParticipantLocation}; use gpui::{ @@ -9,12 +9,13 @@ use gpui::{ platform::{CursorStyle, MouseButton}, AnyViewHandle, Axis, Border, ModelHandle, ViewContext, ViewHandle, }; -use itertools::Itertools; use project::Project; use serde::Deserialize; use theme::Theme; -#[derive(Clone, Debug, Eq, PartialEq)] +use self::adjustable_group::{AdjustableGroupElement, AdjustableGroupItem}; + +#[derive(Clone, Debug, PartialEq)] pub struct PaneGroup { pub(crate) root: Member, } @@ -78,6 +79,7 @@ impl PaneGroup { ) -> AnyElement { self.root.render( project, + 0, theme, follower_states, active_call, @@ -95,7 +97,7 @@ impl PaneGroup { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub(crate) enum Member { Axis(PaneAxis), Pane(ViewHandle), @@ -120,7 +122,11 @@ impl Member { Down | Right => vec![Member::Pane(old_pane), Member::Pane(new_pane)], }; - Member::Axis(PaneAxis { axis, members }) + Member::Axis(PaneAxis { + axis, + members, + ratios: Default::default(), + }) } fn contains(&self, needle: &ViewHandle) -> bool { @@ -133,6 +139,7 @@ impl Member { pub fn render( &self, project: &ModelHandle, + basis: usize, theme: &Theme, follower_states: &FollowerStatesByLeader, active_call: Option<&ModelHandle>, @@ -273,6 +280,7 @@ impl Member { } Member::Axis(axis) => axis.render( project, + basis + 1, theme, follower_states, active_call, @@ -296,10 +304,11 @@ impl Member { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub(crate) struct PaneAxis { pub axis: Axis, pub members: Vec, + pub ratios: Rc>>, } impl PaneAxis { @@ -378,6 +387,7 @@ impl PaneAxis { fn render( &self, project: &ModelHandle, + basis: usize, theme: &Theme, follower_state: &FollowerStatesByLeader, active_call: Option<&ModelHandle>, @@ -386,19 +396,29 @@ impl PaneAxis { app_state: &Arc, cx: &mut ViewContext, ) -> AnyElement { - let mut flex_container = Flex::new(self.axis); + 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 next_basis = basis + self.members.len(); let mut members = self.members.iter().enumerate().peekable(); - while let Some((ix, member)) = members.next() { + while let Some((_ix, member)) = members.next() { let last = members.peek().is_none(); let mut flex = 1.0; - if member.contains(active_pane) { - flex = settings::get::(cx).active_pane_magnification; - } + // TODO: Include minimum sizes + // TODO: Restore this + // if member.contains(active_pane) { + // flex = settings::get::(cx).active_pane_magnification; + // } let mut member = member.render( project, + next_basis, theme, follower_state, active_call, @@ -424,20 +444,11 @@ impl PaneAxis { Axis::Vertical => HandleSide::Bottom, }; - member = member.contained().with_border(border) - .resizable(side, 1., |workspace, size, cx| { - dbg!("resize", size); - }) - .into_any(); - - + member = member.contained().with_border(border).into_any(); } - flex_container = flex_container.with_child( - FlexItem::new(member) - .flex(flex, true) - .into_any() - ); + flex_container = + flex_container.with_child(AdjustableGroupItem::new(member, flex).into_any()); } flex_container.into_any() @@ -496,3 +507,341 @@ impl SplitDirection { } } } + +mod adjustable_group { + + use std::{any::Any, ops::Range, rc::Rc}; + + use gpui::{ + color::Color, + geometry::{ + rect::RectF, + vector::{vec2f, Vector2F}, + }, + json::{self, ToJson}, + platform::{CursorStyle, MouseButton}, + AnyElement, Axis, CursorRegion, Element, LayoutContext, MouseRegion, Quad, SceneBuilder, + SizeConstraint, Vector2FExt, View, ViewContext, + }; + use serde_json::Value; + + struct AdjustableFlexData { + flex: f32, + } + + pub struct AdjustableGroupElement { + axis: Axis, + handle_size: f32, + basis: usize, + callback: Rc)>, + children: Vec>, + } + + impl AdjustableGroupElement { + pub fn new( + axis: Axis, + handle_size: f32, + basis: usize, + callback: impl Fn(Vec) + 'static, + ) -> Self { + Self { + axis, + handle_size, + basis, + callback: Rc::new(callback), + children: Default::default(), + } + } + + fn layout_flex_children( + &mut self, + constraint: SizeConstraint, + remaining_space: &mut f32, + remaining_flex: &mut f32, + cross_axis_max: &mut f32, + view: &mut V, + cx: &mut LayoutContext, + ) { + let cross_axis = self.axis.invert(); + let last_ix = self.children.len() - 1; + for (ix, child) in self.children.iter_mut().enumerate() { + let flex = child.metadata::().unwrap().flex; + + let handle_size = if ix == last_ix { 0. } else { self.handle_size }; + + let child_size = if *remaining_flex == 0.0 { + *remaining_space + } else { + let space_per_flex = *remaining_space / *remaining_flex; + space_per_flex * flex + } - handle_size; + + let child_constraint = match self.axis { + Axis::Horizontal => SizeConstraint::new( + vec2f(child_size, constraint.min.y()), + vec2f(child_size, constraint.max.y()), + ), + Axis::Vertical => SizeConstraint::new( + vec2f(constraint.min.x(), child_size), + vec2f(constraint.max.x(), child_size), + ), + }; + let child_size = child.layout(child_constraint, view, cx); + *remaining_space -= child_size.along(self.axis) + handle_size; + *remaining_flex -= flex; + *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis)); + } + } + } + + impl Extend> for AdjustableGroupElement { + fn extend>>(&mut self, children: T) { + self.children.extend(children); + } + } + + impl Element for AdjustableGroupElement { + type LayoutState = f32; + type PaintState = (); + + fn layout( + &mut self, + constraint: SizeConstraint, + view: &mut V, + cx: &mut LayoutContext, + ) -> (Vector2F, Self::LayoutState) { + let mut remaining_flex = 0.; + + let mut cross_axis_max: f32 = 0.0; + for child in &mut self.children { + let metadata = child.metadata::(); + let flex = metadata + .map(|metadata| metadata.flex) + .expect("All children of an adjustable flex must be AdjustableFlexItems"); + remaining_flex += flex; + } + + let mut remaining_space = constraint.max_along(self.axis); + + if remaining_space.is_infinite() { + panic!("flex contains flexible children but has an infinite constraint along the flex axis"); + } + + self.layout_flex_children( + constraint, + &mut remaining_space, + &mut remaining_flex, + &mut cross_axis_max, + view, + cx, + ); + + let mut size = match self.axis { + Axis::Horizontal => vec2f(constraint.max.x() - remaining_space, cross_axis_max), + Axis::Vertical => vec2f(cross_axis_max, constraint.max.y() - remaining_space), + }; + + if constraint.min.x().is_finite() { + size.set_x(size.x().max(constraint.min.x())); + } + if constraint.min.y().is_finite() { + size.set_y(size.y().max(constraint.min.y())); + } + + if size.x() > constraint.max.x() { + size.set_x(constraint.max.x()); + } + if size.y() > constraint.max.y() { + size.set_y(constraint.max.y()); + } + + (size, remaining_space) + } + + fn paint( + &mut self, + scene: &mut SceneBuilder, + bounds: RectF, + visible_bounds: RectF, + remaining_space: &mut Self::LayoutState, + view: &mut V, + cx: &mut ViewContext, + ) -> Self::PaintState { + let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); + + let overflowing = *remaining_space < 0.; + if overflowing { + scene.push_layer(Some(visible_bounds)); + } + + let mut child_origin = bounds.origin(); + + let last_ix = self.children.len() - 1; + for (ix, child) in self.children.iter_mut().enumerate() { + child.paint(scene, child_origin, visible_bounds, view, cx); + + match self.axis { + Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0), + Axis::Vertical => child_origin += vec2f(0.0, child.size().y()), + } + + if ix != last_ix { + let bounds = match self.axis { + Axis::Horizontal => RectF::new( + child_origin, + vec2f(self.handle_size, visible_bounds.height()), + ), + Axis::Vertical => RectF::new( + child_origin, + vec2f(visible_bounds.width(), self.handle_size), + ), + }; + + scene.push_quad(Quad { + bounds, + background: Some(Color::red()), + ..Default::default() + }); + + let style = match self.axis { + Axis::Horizontal => CursorStyle::ResizeLeftRight, + Axis::Vertical => CursorStyle::ResizeUpDown, + }; + + scene.push_cursor_region(CursorRegion { bounds, style }); + + enum ResizeHandle {} + let callback = self.callback.clone(); + let axis = self.axis; + 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.], + } + }) + }); + scene.push_mouse_region(mouse_region); + + match self.axis { + Axis::Horizontal => child_origin += vec2f(self.handle_size, 0.0), + Axis::Vertical => child_origin += vec2f(0.0, self.handle_size), + } + } + } + + if overflowing { + scene.pop_layer(); + } + } + + fn rect_for_text_range( + &self, + range_utf16: Range, + _: RectF, + _: RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + view: &V, + cx: &ViewContext, + ) -> Option { + self.children + .iter() + .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx)) + } + + fn debug( + &self, + bounds: RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + view: &V, + cx: &ViewContext, + ) -> json::Value { + serde_json::json!({ + "type": "Flex", + "bounds": bounds.to_json(), + "axis": self.axis.to_json(), + "children": self.children.iter().map(|child| child.debug(view, cx)).collect::>() + }) + } + } + + pub struct AdjustableGroupItem { + metadata: AdjustableFlexData, + child: AnyElement, + } + + impl AdjustableGroupItem { + pub fn new(child: impl Element, flex: f32) -> Self { + Self { + metadata: AdjustableFlexData { flex }, + child: child.into_any(), + } + } + } + + impl Element for AdjustableGroupItem { + type LayoutState = (); + type PaintState = (); + + fn layout( + &mut self, + constraint: SizeConstraint, + view: &mut V, + cx: &mut LayoutContext, + ) -> (Vector2F, Self::LayoutState) { + let size = self.child.layout(constraint, view, cx); + (size, ()) + } + + fn paint( + &mut self, + scene: &mut SceneBuilder, + bounds: RectF, + visible_bounds: RectF, + _: &mut Self::LayoutState, + view: &mut V, + cx: &mut ViewContext, + ) -> Self::PaintState { + self.child + .paint(scene, bounds.origin(), visible_bounds, view, cx) + } + + fn rect_for_text_range( + &self, + range_utf16: Range, + _: RectF, + _: RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + view: &V, + cx: &ViewContext, + ) -> Option { + self.child.rect_for_text_range(range_utf16, view, cx) + } + + fn metadata(&self) -> Option<&dyn Any> { + Some(&self.metadata) + } + + fn debug( + &self, + _: RectF, + _: &Self::LayoutState, + _: &Self::PaintState, + view: &V, + cx: &ViewContext, + ) -> Value { + serde_json::json!({ + "type": "Flexible", + "flex": self.metadata.flex, + "child": self.child.debug(view, cx) + }) + } + } +} diff --git a/crates/workspace/src/persistence/model.rs b/crates/workspace/src/persistence/model.rs index 1075061853..c159ff0f42 100644 --- a/crates/workspace/src/persistence/model.rs +++ b/crates/workspace/src/persistence/model.rs @@ -187,6 +187,7 @@ impl SerializedPaneGroup { Member::Axis(PaneAxis { axis: *axis, members, + ratios: Default::default() }), current_active_pane, items, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index cafcd191a3..f91204c51a 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -4,7 +4,6 @@ pub mod notifications; pub mod pane; pub mod pane_group; mod persistence; -mod adjustable_flex; pub mod searchable; pub mod shared_screen; mod status_bar; @@ -2924,7 +2923,7 @@ impl Workspace { cx: &AppContext, ) -> SerializedPaneGroup { match pane_group { - Member::Axis(PaneAxis { axis, members }) => SerializedPaneGroup::Group { + Member::Axis(PaneAxis { axis, members, .. }) => SerializedPaneGroup::Group { axis: *axis, children: members .iter() From 26b9be628ebaf238c683bb925ca155518126e5ca Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 12 Jul 2023 22:34:33 -0700 Subject: [PATCH 3/9] 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 58d7bb4c40..49b12d823e 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 3442934b3a..c79c793dda 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 259e343248..ebaf399e22 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 7198dff3bf..fdda67ad22 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 c159ff0f42..762d7171de 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, )) From d5f7ad08fa48cd4997de64b3f98522970a2b9f9a Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 13 Jul 2023 11:28:21 -0700 Subject: [PATCH 4/9] Styled and refined behavior for split resizing --- crates/editor/src/element.rs | 6 +- crates/workspace/src/pane_group.rs | 259 +++++++++-------------------- 2 files changed, 86 insertions(+), 179 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index f0bae9533b..074a96dfc1 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1182,8 +1182,10 @@ impl EditorElement { }); scene.push_mouse_region( MouseRegion::new::(cx.view_id(), cx.view_id(), track_bounds) - .on_move(move |_, editor: &mut Editor, cx| { - editor.scroll_manager.show_scrollbar(cx); + .on_move(move |event, editor: &mut Editor, cx| { + if event.pressed_button.is_none() { + editor.scroll_manager.show_scrollbar(cx); + } }) .on_down(MouseButton::Left, { let row_range = row_range.clone(); diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index fdda67ad22..372bfd8ef4 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -1,6 +1,8 @@ use std::{cell::RefCell, rc::Rc, sync::Arc}; -use crate::{AppState, FollowerStatesByLeader, Pane, Workspace}; +use crate::{ + pane_group::element::PaneAxisElement, AppState, FollowerStatesByLeader, Pane, Workspace, +}; use anyhow::{anyhow, Result}; use call::{ActiveCall, ParticipantLocation}; use gpui::{ @@ -13,8 +15,6 @@ use project::Project; use serde::Deserialize; use theme::Theme; -use self::adjustable_group::{AdjustableGroupElement, AdjustableGroupItem}; - #[derive(Clone, Debug, PartialEq)] pub struct PaneGroup { pub(crate) root: Member, @@ -122,11 +122,7 @@ impl Member { Down | Right => vec![Member::Pane(old_pane), Member::Pane(new_pane)], }; - Member::Axis(PaneAxis { - axis, - members, - ratios: Default::default(), - }) + Member::Axis(PaneAxis::new(axis, members)) } fn contains(&self, needle: &ViewHandle) -> bool { @@ -308,16 +304,16 @@ impl Member { pub(crate) struct PaneAxis { pub axis: Axis, pub members: Vec, - ratios: Rc>>, + flexes: Rc>>, } impl PaneAxis { pub fn new(axis: Axis, members: Vec) -> Self { - let ratios = Rc::new(RefCell::new(vec![1.; members.len()])); + let flexes = Rc::new(RefCell::new(vec![1.; members.len()])); Self { axis, members, - ratios, + flexes, } } @@ -342,6 +338,7 @@ impl PaneAxis { } self.members.insert(idx, Member::Pane(new_pane.clone())); + *self.flexes.borrow_mut() = vec![1.; self.members.len()]; } else { *member = Member::new_axis(old_pane.clone(), new_pane.clone(), direction); @@ -381,6 +378,7 @@ impl PaneAxis { if found_pane { if let Some(idx) = remove_member { self.members.remove(idx); + *self.flexes.borrow_mut() = vec![1.; self.members.len()]; } if self.members.len() == 1 { @@ -405,23 +403,17 @@ impl PaneAxis { app_state: &Arc, cx: &mut ViewContext, ) -> AnyElement { - let ratios = self.ratios.clone(); - 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; - } - } + debug_assert!(self.members.len() == self.flexes.borrow().len()); - cx.notify(); - }); + // TODO: SImplify further by just passing in the flexes pointer directly, no need to generify! + let mut flex_container = PaneAxisElement::new(self.axis, basis, self.flexes.clone()); - let ratios_borrow = self.ratios.borrow(); - let next_basis = basis + self.members.len(); - let mut members = self.members.iter().zip(ratios_borrow.iter()).peekable(); - while let Some((member, flex)) = members.next() { + let mut members = self + .members + .iter() + .enumerate() + .peekable(); + while let Some((ix, member)) = members.next() { let last = members.peek().is_none(); // TODO: Restore this @@ -431,7 +423,7 @@ impl PaneAxis { let mut member = member.render( project, - next_basis, + (basis + ix) * 10, theme, follower_state, active_call, @@ -440,6 +432,7 @@ impl PaneAxis { app_state, cx, ); + if !last { let mut border = theme.workspace.pane_divider; border.left = false; @@ -455,8 +448,7 @@ impl PaneAxis { member = member.contained().with_border(border).into_any(); } - flex_container = - flex_container.with_child(AdjustableGroupItem::new(member, *flex).into_any()); + flex_container = flex_container.with_child(member.into_any()); } flex_container.into_any() @@ -516,48 +508,34 @@ impl SplitDirection { } } -mod adjustable_group { - - use std::{any::Any, ops::Range, rc::Rc}; +// TODO: PaneAxis element here +mod element { + use std::{cell::RefCell, ops::Range, rc::Rc}; use gpui::{ - color::Color, geometry::{ rect::RectF, vector::{vec2f, Vector2F}, }, json::{self, ToJson}, platform::{CursorStyle, MouseButton}, - AnyElement, Axis, CursorRegion, Element, EventContext, LayoutContext, MouseRegion, Quad, - RectFExt, SceneBuilder, SizeConstraint, Vector2FExt, View, ViewContext, + AnyElement, Axis, CursorRegion, Element, LayoutContext, MouseRegion, RectFExt, + SceneBuilder, SizeConstraint, Vector2FExt, View, ViewContext, }; - use serde_json::Value; - use smallvec::SmallVec; - struct AdjustableFlexData { - flex: f32, - } - - pub struct AdjustableGroupElement { + pub struct PaneAxisElement { axis: Axis, - handle_size: f32, basis: usize, - callback: Rc, &mut V, &mut EventContext)>, + flexes: Rc>>, children: Vec>, } - impl AdjustableGroupElement { - pub fn new( - axis: Axis, - handle_size: f32, - basis: usize, - callback: impl Fn(SmallVec<[(usize, f32); 2]>, &mut V, &mut EventContext) + 'static, - ) -> Self { + impl PaneAxisElement { + pub fn new(axis: Axis, basis: usize, flexes: Rc>>) -> Self { Self { axis, - handle_size, basis, - callback: Rc::new(callback), + flexes, children: Default::default(), } } @@ -571,19 +549,17 @@ mod adjustable_group { view: &mut V, cx: &mut LayoutContext, ) { + let flexes = self.flexes.borrow(); let cross_axis = self.axis.invert(); - let last_ix = self.children.len() - 1; for (ix, child) in self.children.iter_mut().enumerate() { - let flex = child.metadata::().unwrap().flex; - - let handle_size = if ix == last_ix { 0. } else { self.handle_size }; + let flex = flexes[ix]; let child_size = if *remaining_flex == 0.0 { *remaining_space } else { let space_per_flex = *remaining_space / *remaining_flex; space_per_flex * flex - } - handle_size; + }; let child_constraint = match self.axis { Axis::Horizontal => SizeConstraint::new( @@ -596,20 +572,20 @@ mod adjustable_group { ), }; let child_size = child.layout(child_constraint, view, cx); - *remaining_space -= child_size.along(self.axis) + handle_size; + *remaining_space -= child_size.along(self.axis); *remaining_flex -= flex; *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis)); } } } - impl Extend> for AdjustableGroupElement { + impl Extend> for PaneAxisElement { fn extend>>(&mut self, children: T) { self.children.extend(children); } } - impl Element for AdjustableGroupElement { + impl Element for PaneAxisElement { type LayoutState = f32; type PaintState = (); @@ -619,14 +595,11 @@ mod adjustable_group { view: &mut V, cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { + debug_assert!(self.children.len() == self.flexes.borrow().len()); let mut remaining_flex = 0.; let mut cross_axis_max: f32 = 0.0; - for child in &mut self.children { - let metadata = child.metadata::(); - let flex = metadata - .map(|metadata| metadata.flex) - .expect("All children of an adjustable flex must be AdjustableFlexItems"); + for flex in self.flexes.borrow().iter() { remaining_flex += flex; } @@ -695,48 +668,61 @@ mod adjustable_group { Axis::Vertical => child_origin += vec2f(0.0, child.size().y()), } + const HANDLE_HITBOX_SIZE: f32 = 4.0; if let Some((next_ix, next_child)) = children_iter.peek() { - let bounds = match self.axis { + scene.push_stacking_context(None, None); + + let handle_origin = match self.axis { + Axis::Horizontal => child_origin - vec2f(HANDLE_HITBOX_SIZE / 2., 0.0), + Axis::Vertical => child_origin - vec2f(0.0, HANDLE_HITBOX_SIZE / 2.), + }; + + let handle_bounds = match self.axis { Axis::Horizontal => RectF::new( - child_origin, - vec2f(self.handle_size, visible_bounds.height()), + handle_origin, + vec2f(HANDLE_HITBOX_SIZE, visible_bounds.height()), ), Axis::Vertical => RectF::new( - child_origin, - vec2f(visible_bounds.width(), self.handle_size), + handle_origin, + vec2f(visible_bounds.width(), HANDLE_HITBOX_SIZE), ), }; - scene.push_quad(Quad { - bounds, - background: Some(Color::red()), - ..Default::default() - }); + // use gpui::color::Color, + // scene.push_quad(Quad { + // bounds: handle_bounds, + // background: Some(Color::red()), + // ..Default::default() + // }); let style = match self.axis { Axis::Horizontal => CursorStyle::ResizeLeftRight, Axis::Vertical => CursorStyle::ResizeUpDown, }; - scene.push_cursor_region(CursorRegion { bounds, style }); + scene.push_cursor_region(CursorRegion { + bounds: handle_bounds, + style, + }); - 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 drag_bounds = visible_bounds.clone(); + let flexes = self.flexes.clone(); + let current_flex = flexes.borrow()[ix]; let next_ix = *next_ix; + let next_flex = flexes.borrow()[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); + let mut mouse_region = MouseRegion::new::( + cx.view_id(), + self.basis + ix, + handle_bounds, + ); mouse_region = - mouse_region.on_drag(MouseButton::Left, move |drag, v: &mut V, cx| { + mouse_region.on_drag(MouseButton::Left, move |drag, _: &mut V, cx| { let min_size = match axis { Axis::Horizontal => HORIZONTAL_MIN_SIZE, Axis::Vertical => VERTICAL_MIN_SIZE, @@ -748,15 +734,15 @@ mod adjustable_group { return; } - let flex_position = drag.position - drag_bounds.origin(); - let mut current_target_size = (flex_position - child_start).along(axis); + let mut current_target_size = (drag.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 + // TODO: cascade this size change down, collect all changes into a vec let next_target_size = (next_child_size.along(axis) - proposed_current_pixel_change) .max(min_size); @@ -768,25 +754,18 @@ mod adjustable_group { 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, - ) + let mut borrow = flexes.borrow_mut(); + *borrow.get_mut(ix).unwrap() = current_target_flex; + *borrow.get_mut(next_ix).unwrap() = next_target_flex; + + cx.notify(); }); scene.push_mouse_region(mouse_region); - match self.axis { - Axis::Horizontal => child_origin += vec2f(self.handle_size, 0.0), - Axis::Vertical => child_origin += vec2f(0.0, self.handle_size), - } + scene.pop_stacking_context(); } } @@ -819,85 +798,11 @@ mod adjustable_group { cx: &ViewContext, ) -> json::Value { serde_json::json!({ - "type": "Flex", + "type": "PaneAxis", "bounds": bounds.to_json(), "axis": self.axis.to_json(), "children": self.children.iter().map(|child| child.debug(view, cx)).collect::>() }) } } - - pub struct AdjustableGroupItem { - metadata: AdjustableFlexData, - child: AnyElement, - } - - impl AdjustableGroupItem { - pub fn new(child: impl Element, flex: f32) -> Self { - Self { - metadata: AdjustableFlexData { flex }, - child: child.into_any(), - } - } - } - - impl Element for AdjustableGroupItem { - type LayoutState = (); - type PaintState = (); - - fn layout( - &mut self, - constraint: SizeConstraint, - view: &mut V, - cx: &mut LayoutContext, - ) -> (Vector2F, Self::LayoutState) { - let size = self.child.layout(constraint, view, cx); - (size, ()) - } - - fn paint( - &mut self, - scene: &mut SceneBuilder, - bounds: RectF, - visible_bounds: RectF, - _: &mut Self::LayoutState, - view: &mut V, - cx: &mut ViewContext, - ) -> Self::PaintState { - self.child - .paint(scene, bounds.origin(), visible_bounds, view, cx) - } - - fn rect_for_text_range( - &self, - range_utf16: Range, - _: RectF, - _: RectF, - _: &Self::LayoutState, - _: &Self::PaintState, - view: &V, - cx: &ViewContext, - ) -> Option { - self.child.rect_for_text_range(range_utf16, view, cx) - } - - fn metadata(&self) -> Option<&dyn Any> { - Some(&self.metadata) - } - - fn debug( - &self, - _: RectF, - _: &Self::LayoutState, - _: &Self::PaintState, - view: &V, - cx: &ViewContext, - ) -> Value { - serde_json::json!({ - "type": "Flexible", - "flex": self.metadata.flex, - "child": self.child.debug(view, cx) - }) - } - } } From 00b04f1c85301c17592deed99b08e539106931e4 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 13 Jul 2023 13:10:36 -0700 Subject: [PATCH 5/9] Restore active pane magnification --- crates/workspace/src/pane_group.rs | 80 ++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index 372bfd8ef4..3e4ce21694 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -15,6 +15,10 @@ use project::Project; use serde::Deserialize; use theme::Theme; +const HANDLE_HITBOX_SIZE: f32 = 4.0; +const HORIZONTAL_MIN_SIZE: f32 = 80.; +const VERTICAL_MIN_SIZE: f32 = 100.; + #[derive(Clone, Debug, PartialEq)] pub struct PaneGroup { pub(crate) root: Member, @@ -405,21 +409,17 @@ impl PaneAxis { ) -> AnyElement { debug_assert!(self.members.len() == self.flexes.borrow().len()); - // TODO: SImplify further by just passing in the flexes pointer directly, no need to generify! let mut flex_container = PaneAxisElement::new(self.axis, basis, self.flexes.clone()); + let mut active_pane_ix = None; - let mut members = self - .members - .iter() - .enumerate() - .peekable(); + let mut members = self.members.iter().enumerate().peekable(); while let Some((ix, member)) = members.next() { let last = members.peek().is_none(); // TODO: Restore this - // if member.contains(active_pane) { - // flex = settings::get::(cx).active_pane_magnification; - // } + if member.contains(active_pane) { + active_pane_ix = Some(ix); + } let mut member = member.render( project, @@ -450,7 +450,7 @@ impl PaneAxis { flex_container = flex_container.with_child(member.into_any()); } - + flex_container.set_active_pane(active_pane_ix); flex_container.into_any() } } @@ -508,7 +508,6 @@ impl SplitDirection { } } -// TODO: PaneAxis element here mod element { use std::{cell::RefCell, ops::Range, rc::Rc}; @@ -523,9 +522,15 @@ mod element { SceneBuilder, SizeConstraint, Vector2FExt, View, ViewContext, }; + use crate::{ + pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE}, + WorkspaceSettings, + }; + pub struct PaneAxisElement { axis: Axis, basis: usize, + active_pane_ix: Option, flexes: Rc>>, children: Vec>, } @@ -536,12 +541,18 @@ mod element { axis, basis, flexes, + active_pane_ix: None, children: Default::default(), } } + pub fn set_active_pane(&mut self, active_pane_ix: Option) { + self.active_pane_ix = active_pane_ix; + } + fn layout_flex_children( &mut self, + active_pane_magnification: f32, constraint: SizeConstraint, remaining_space: &mut f32, remaining_flex: &mut f32, @@ -552,7 +563,19 @@ mod element { let flexes = self.flexes.borrow(); let cross_axis = self.axis.invert(); for (ix, child) in self.children.iter_mut().enumerate() { - let flex = flexes[ix]; + let flex = if active_pane_magnification != 1. { + if let Some(active_pane_ix) = self.active_pane_ix { + if ix == active_pane_ix { + active_pane_magnification + } else { + 1. + } + } else { + 1. + } + } else { + flexes[ix] + }; let child_size = if *remaining_flex == 0.0 { *remaining_space @@ -596,13 +619,25 @@ mod element { cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { debug_assert!(self.children.len() == self.flexes.borrow().len()); + + let active_pane_magnification = + settings::get::(cx).active_pane_magnification; + let mut remaining_flex = 0.; - let mut cross_axis_max: f32 = 0.0; - for flex in self.flexes.borrow().iter() { - remaining_flex += flex; + if active_pane_magnification != 1. { + let active_pane_flex = self + .active_pane_ix + .map(|_| active_pane_magnification) + .unwrap_or(1.); + remaining_flex += self.children.len() as f32 - 1. + active_pane_flex; + } else { + for flex in self.flexes.borrow().iter() { + remaining_flex += flex; + } } + let mut cross_axis_max: f32 = 0.0; let mut remaining_space = constraint.max_along(self.axis); if remaining_space.is_infinite() { @@ -610,6 +645,7 @@ mod element { } self.layout_flex_children( + active_pane_magnification, constraint, &mut remaining_space, &mut remaining_flex, @@ -649,6 +685,7 @@ mod element { view: &mut V, cx: &mut ViewContext, ) -> Self::PaintState { + let can_resize = settings::get::(cx).active_pane_magnification == 1.; let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); let overflowing = *remaining_space < 0.; @@ -668,8 +705,8 @@ mod element { Axis::Vertical => child_origin += vec2f(0.0, child.size().y()), } - const HANDLE_HITBOX_SIZE: f32 = 4.0; - if let Some((next_ix, next_child)) = children_iter.peek() { + if let Some(Some((next_ix, next_child))) = can_resize.then(|| children_iter.peek()) + { scene.push_stacking_context(None, None); let handle_origin = match self.axis { @@ -688,13 +725,6 @@ mod element { ), }; - // use gpui::color::Color, - // scene.push_quad(Quad { - // bounds: handle_bounds, - // background: Some(Color::red()), - // ..Default::default() - // }); - let style = match self.axis { Axis::Horizontal => CursorStyle::ResizeLeftRight, Axis::Vertical => CursorStyle::ResizeUpDown, @@ -713,8 +743,6 @@ mod element { let current_flex = flexes.borrow()[ix]; let next_ix = *next_ix; let next_flex = flexes.borrow()[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(), From 5797282b981ddc8b527f03ef70793d1b6a534457 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 13 Jul 2023 14:21:14 -0700 Subject: [PATCH 6/9] Add resising serialization --- crates/workspace/src/pane_group.rs | 67 ++++++---- crates/workspace/src/persistence.rs | 152 ++++++++++++++-------- crates/workspace/src/persistence/model.rs | 9 +- crates/workspace/src/workspace.rs | 16 ++- 4 files changed, 159 insertions(+), 85 deletions(-) diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index 3e4ce21694..e58b95d6b3 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -308,7 +308,7 @@ impl Member { pub(crate) struct PaneAxis { pub axis: Axis, pub members: Vec, - flexes: Rc>>, + pub flexes: Rc>>, } impl PaneAxis { @@ -321,6 +321,18 @@ impl PaneAxis { } } + pub fn load(axis: Axis, members: Vec, flexes: Option>) -> Self { + let flexes = flexes.unwrap_or_else(|| vec![1.; members.len()]); + debug_assert!(members.len() == flexes.len()); + + let flexes = Rc::new(RefCell::new(flexes)); + Self { + axis, + members, + flexes, + } + } + fn split( &mut self, old_pane: &ViewHandle, @@ -519,23 +531,23 @@ mod element { json::{self, ToJson}, platform::{CursorStyle, MouseButton}, AnyElement, Axis, CursorRegion, Element, LayoutContext, MouseRegion, RectFExt, - SceneBuilder, SizeConstraint, Vector2FExt, View, ViewContext, + SceneBuilder, SizeConstraint, Vector2FExt, ViewContext, }; use crate::{ pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE}, - WorkspaceSettings, + WorkspaceSettings, Workspace, }; - pub struct PaneAxisElement { + pub struct PaneAxisElement { axis: Axis, basis: usize, active_pane_ix: Option, flexes: Rc>>, - children: Vec>, + children: Vec>, } - impl PaneAxisElement { + impl PaneAxisElement { pub fn new(axis: Axis, basis: usize, flexes: Rc>>) -> Self { Self { axis, @@ -557,8 +569,8 @@ mod element { remaining_space: &mut f32, remaining_flex: &mut f32, cross_axis_max: &mut f32, - view: &mut V, - cx: &mut LayoutContext, + view: &mut Workspace, + cx: &mut LayoutContext, ) { let flexes = self.flexes.borrow(); let cross_axis = self.axis.invert(); @@ -602,21 +614,21 @@ mod element { } } - impl Extend> for PaneAxisElement { - fn extend>>(&mut self, children: T) { + impl Extend> for PaneAxisElement { + fn extend>>(&mut self, children: T) { self.children.extend(children); } } - impl Element for PaneAxisElement { + impl Element for PaneAxisElement { type LayoutState = f32; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - view: &mut V, - cx: &mut LayoutContext, + view: &mut Workspace, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { debug_assert!(self.children.len() == self.flexes.borrow().len()); @@ -682,8 +694,8 @@ mod element { bounds: RectF, visible_bounds: RectF, remaining_space: &mut Self::LayoutState, - view: &mut V, - cx: &mut ViewContext, + view: &mut Workspace, + cx: &mut ViewContext, ) -> Self::PaintState { let can_resize = settings::get::(cx).active_pane_magnification == 1.; let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); @@ -750,7 +762,7 @@ mod element { handle_bounds, ); mouse_region = - mouse_region.on_drag(MouseButton::Left, move |drag, _: &mut V, cx| { + mouse_region.on_drag(MouseButton::Left, move |drag, workspace: &mut Workspace, cx| { let min_size = match axis { Axis::Horizontal => HORIZONTAL_MIN_SIZE, Axis::Vertical => VERTICAL_MIN_SIZE, @@ -768,13 +780,15 @@ mod element { current_target_size - child_size.along(axis); if proposed_current_pixel_change < 0. { - current_target_size = current_target_size.max(min_size); + current_target_size = f32::max(current_target_size, min_size); } else if proposed_current_pixel_change > 0. { - // TODO: cascade this size change down, collect all changes 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( + // TODO: cascade this change to other children if current item is at min size + let next_target_size = f32::max( + next_child_size.along(axis) - proposed_current_pixel_change, + min_size, + ); + current_target_size = f32::min( + current_target_size, child_size.along(axis) + next_child_size.along(axis) - next_target_size, ); @@ -789,6 +803,7 @@ mod element { *borrow.get_mut(ix).unwrap() = current_target_flex; *borrow.get_mut(next_ix).unwrap() = next_target_flex; + workspace.schedule_serialize(cx); cx.notify(); }); scene.push_mouse_region(mouse_region); @@ -809,8 +824,8 @@ mod element { _: RectF, _: &Self::LayoutState, _: &Self::PaintState, - view: &V, - cx: &ViewContext, + view: &Workspace, + cx: &ViewContext, ) -> Option { self.children .iter() @@ -822,8 +837,8 @@ mod element { bounds: RectF, _: &Self::LayoutState, _: &Self::PaintState, - view: &V, - cx: &ViewContext, + view: &Workspace, + cx: &ViewContext, ) -> json::Value { serde_json::json!({ "type": "PaneAxis", diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index dd2aa5a818..0d7784093a 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -45,6 +45,7 @@ define_connection! { // parent_group_id: Option, // None indicates that this is the root node // position: Optiopn, // None indicates that this is the root node // axis: Option, // 'Vertical', 'Horizontal' + // flexes: Option>, // A JSON array of floats // ) // // panes( @@ -168,7 +169,12 @@ define_connection! { ALTER TABLE workspaces ADD COLUMN left_dock_zoom INTEGER; //bool ALTER TABLE workspaces ADD COLUMN right_dock_zoom INTEGER; //bool ALTER TABLE workspaces ADD COLUMN bottom_dock_zoom INTEGER; //bool - )]; + ), + // Add pane group flex data + sql!( + ALTER TABLE pane_groups ADD COLUMN flexes TEXT; + ) + ]; } impl WorkspaceDb { @@ -359,38 +365,51 @@ impl WorkspaceDb { group_id: Option, ) -> Result> { type GroupKey = (Option, WorkspaceId); - type GroupOrPane = (Option, Option, Option, Option); + type GroupOrPane = ( + Option, + Option, + Option, + Option, + Option, + ); self.select_bound::(sql!( - SELECT group_id, axis, pane_id, active + SELECT group_id, axis, pane_id, active, flexes FROM (SELECT - group_id, - axis, - NULL as pane_id, - NULL as active, - position, - parent_group_id, - workspace_id - FROM pane_groups + group_id, + axis, + NULL as pane_id, + NULL as active, + position, + parent_group_id, + workspace_id, + flexes + FROM pane_groups UNION - SELECT - NULL, - NULL, - center_panes.pane_id, - panes.active as active, - position, - parent_group_id, - panes.workspace_id as workspace_id - FROM center_panes - JOIN panes ON center_panes.pane_id = panes.pane_id) + SELECT + NULL, + NULL, + center_panes.pane_id, + panes.active as active, + position, + parent_group_id, + panes.workspace_id as workspace_id, + NULL + FROM center_panes + JOIN panes ON center_panes.pane_id = panes.pane_id) WHERE parent_group_id IS ? AND workspace_id = ? ORDER BY position ))?((group_id, workspace_id))? .into_iter() - .map(|(group_id, axis, pane_id, active)| { + .map(|(group_id, axis, pane_id, active, flexes)| { if let Some((group_id, axis)) = group_id.zip(axis) { + let flexes = flexes + .map(|flexes| serde_json::from_str::>(&flexes)) + .transpose()?; + Ok(SerializedPaneGroup::Group { axis, children: self.get_pane_group(workspace_id, Some(group_id))?, + flexes, }) } else if let Some((pane_id, active)) = pane_id.zip(active) { Ok(SerializedPaneGroup::Pane(SerializedPane::new( @@ -417,14 +436,31 @@ impl WorkspaceDb { parent: Option<(GroupId, usize)>, ) -> Result<()> { match pane_group { - SerializedPaneGroup::Group { axis, children } => { + SerializedPaneGroup::Group { + axis, + children, + flexes, + } => { let (parent_id, position) = unzip_option(parent); + let flex_string = serde_json::json!(flexes).to_string(); let group_id = conn.select_row_bound::<_, i64>(sql!( - INSERT INTO pane_groups(workspace_id, parent_group_id, position, axis) - VALUES (?, ?, ?, ?) + INSERT INTO pane_groups( + workspace_id, + parent_group_id, + position, + axis, + flexes + ) + VALUES (?, ?, ?, ?, ?) RETURNING group_id - ))?((workspace_id, parent_id, position, *axis))? + ))?(( + workspace_id, + parent_id, + position, + *axis, + flex_string, + ))? .ok_or_else(|| anyhow!("Couldn't retrieve group_id from inserted pane_group"))?; for (position, group) in children.iter().enumerate() { @@ -641,6 +677,14 @@ mod tests { assert_eq!(test_text_1, "test-text-1"); } + fn group(axis: gpui::Axis, children: Vec) -> SerializedPaneGroup { + SerializedPaneGroup::Group { + axis, + flexes: None, + children, + } + } + #[gpui::test] async fn test_full_workspace_serialization() { env_logger::try_init().ok(); @@ -652,12 +696,12 @@ mod tests { // | - - - | | // | 3,4 | | // ----------------- - let center_group = SerializedPaneGroup::Group { - axis: gpui::Axis::Horizontal, - children: vec![ - SerializedPaneGroup::Group { - axis: gpui::Axis::Vertical, - children: vec![ + let center_group = group( + gpui::Axis::Horizontal, + vec![ + group( + gpui::Axis::Vertical, + vec![ SerializedPaneGroup::Pane(SerializedPane::new( vec![ SerializedItem::new("Terminal", 5, false), @@ -673,7 +717,7 @@ mod tests { false, )), ], - }, + ), SerializedPaneGroup::Pane(SerializedPane::new( vec![ SerializedItem::new("Terminal", 9, false), @@ -682,7 +726,7 @@ mod tests { false, )), ], - }; + ); let workspace = SerializedWorkspace { id: 5, @@ -811,12 +855,12 @@ mod tests { // | - - - | | // | 3,4 | | // ----------------- - let center_pane = SerializedPaneGroup::Group { - axis: gpui::Axis::Horizontal, - children: vec![ - SerializedPaneGroup::Group { - axis: gpui::Axis::Vertical, - children: vec![ + let center_pane = group( + gpui::Axis::Horizontal, + vec![ + group( + gpui::Axis::Vertical, + vec![ SerializedPaneGroup::Pane(SerializedPane::new( vec![ SerializedItem::new("Terminal", 1, false), @@ -832,7 +876,7 @@ mod tests { true, )), ], - }, + ), SerializedPaneGroup::Pane(SerializedPane::new( vec![ SerializedItem::new("Terminal", 5, true), @@ -841,7 +885,7 @@ mod tests { false, )), ], - }; + ); let workspace = default_workspace(&["/tmp"], ¢er_pane); @@ -858,12 +902,12 @@ mod tests { let db = WorkspaceDb(open_test_db("test_cleanup_panes").await); - let center_pane = SerializedPaneGroup::Group { - axis: gpui::Axis::Horizontal, - children: vec![ - SerializedPaneGroup::Group { - axis: gpui::Axis::Vertical, - children: vec![ + let center_pane = group( + gpui::Axis::Horizontal, + vec![ + group( + gpui::Axis::Vertical, + vec![ SerializedPaneGroup::Pane(SerializedPane::new( vec![ SerializedItem::new("Terminal", 1, false), @@ -879,7 +923,7 @@ mod tests { true, )), ], - }, + ), SerializedPaneGroup::Pane(SerializedPane::new( vec![ SerializedItem::new("Terminal", 5, false), @@ -888,7 +932,7 @@ mod tests { false, )), ], - }; + ); let id = &["/tmp"]; @@ -896,9 +940,9 @@ mod tests { db.save_workspace(workspace.clone()).await; - workspace.center_group = SerializedPaneGroup::Group { - axis: gpui::Axis::Vertical, - children: vec![ + workspace.center_group = group( + gpui::Axis::Vertical, + vec![ SerializedPaneGroup::Pane(SerializedPane::new( vec![ SerializedItem::new("Terminal", 1, false), @@ -914,7 +958,7 @@ mod tests { true, )), ], - }; + ); db.save_workspace(workspace.clone()).await; diff --git a/crates/workspace/src/persistence/model.rs b/crates/workspace/src/persistence/model.rs index 762d7171de..aa184dbb56 100644 --- a/crates/workspace/src/persistence/model.rs +++ b/crates/workspace/src/persistence/model.rs @@ -127,10 +127,11 @@ impl Bind for DockData { } } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Clone)] pub enum SerializedPaneGroup { Group { axis: Axis, + flexes: Option>, children: Vec, }, Pane(SerializedPane), @@ -149,7 +150,7 @@ impl Default for SerializedPaneGroup { impl SerializedPaneGroup { #[async_recursion(?Send)] pub(crate) async fn deserialize( - &self, + self, project: &ModelHandle, workspace_id: WorkspaceId, workspace: &WeakViewHandle, @@ -160,7 +161,7 @@ impl SerializedPaneGroup { Vec>>, )> { match self { - SerializedPaneGroup::Group { axis, children } => { + SerializedPaneGroup::Group { axis, children, flexes } => { let mut current_active_pane = None; let mut members = Vec::new(); let mut items = Vec::new(); @@ -184,7 +185,7 @@ impl SerializedPaneGroup { } Some(( - Member::Axis(PaneAxis::new(*axis, members)), + Member::Axis(PaneAxis::load(axis, members, flexes)), current_active_pane, items, )) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index f91204c51a..e31e0d924f 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -504,6 +504,7 @@ pub struct Workspace { subscriptions: Vec, _apply_leader_updates: Task>, _observe_current_user: Task>, + _schedule_serialize: Option>, pane_history_timestamp: Arc, } @@ -718,6 +719,7 @@ impl Workspace { app_state, _observe_current_user, _apply_leader_updates, + _schedule_serialize: None, leader_updates_tx, subscriptions, pane_history_timestamp, @@ -2893,6 +2895,13 @@ impl Workspace { cx.notify(); } + fn schedule_serialize(&mut self, cx: &mut ViewContext) { + self._schedule_serialize = Some(cx.spawn(|this, cx| async move { + cx.background().timer(Duration::from_millis(100)).await; + this.read_with(&cx, |this, cx| this.serialize_workspace(cx)).ok(); + })); + } + fn serialize_workspace(&self, cx: &ViewContext) { fn serialize_pane_handle( pane_handle: &ViewHandle, @@ -2923,12 +2932,17 @@ impl Workspace { cx: &AppContext, ) -> SerializedPaneGroup { match pane_group { - Member::Axis(PaneAxis { axis, members, .. }) => SerializedPaneGroup::Group { + Member::Axis(PaneAxis { + axis, + members, + flexes, + }) => SerializedPaneGroup::Group { axis: *axis, children: members .iter() .map(|member| build_serialized_pane_group(member, cx)) .collect::>(), + flexes: Some(flexes.borrow().clone()), }, Member::Pane(pane_handle) => { SerializedPaneGroup::Pane(serialize_pane_handle(&pane_handle, cx)) From 331fd896b56e90f27c7c3296633303b0ba3685fa Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 13 Jul 2023 14:21:30 -0700 Subject: [PATCH 7/9] fmt --- crates/workspace/src/pane_group.rs | 12 +++++++----- crates/workspace/src/persistence/model.rs | 6 +++++- crates/workspace/src/workspace.rs | 3 ++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index e58b95d6b3..1edee1bc42 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -536,7 +536,7 @@ mod element { use crate::{ pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE}, - WorkspaceSettings, Workspace, + Workspace, WorkspaceSettings, }; pub struct PaneAxisElement { @@ -547,7 +547,7 @@ mod element { children: Vec>, } - impl PaneAxisElement { + impl PaneAxisElement { pub fn new(axis: Axis, basis: usize, flexes: Rc>>) -> Self { Self { axis, @@ -761,8 +761,9 @@ mod element { self.basis + ix, handle_bounds, ); - mouse_region = - mouse_region.on_drag(MouseButton::Left, move |drag, workspace: &mut Workspace, cx| { + mouse_region = mouse_region.on_drag( + MouseButton::Left, + move |drag, workspace: &mut Workspace, cx| { let min_size = match axis { Axis::Horizontal => HORIZONTAL_MIN_SIZE, Axis::Vertical => VERTICAL_MIN_SIZE, @@ -805,7 +806,8 @@ mod element { workspace.schedule_serialize(cx); cx.notify(); - }); + }, + ); scene.push_mouse_region(mouse_region); scene.pop_stacking_context(); diff --git a/crates/workspace/src/persistence/model.rs b/crates/workspace/src/persistence/model.rs index aa184dbb56..5f4c29cd5b 100644 --- a/crates/workspace/src/persistence/model.rs +++ b/crates/workspace/src/persistence/model.rs @@ -161,7 +161,11 @@ impl SerializedPaneGroup { Vec>>, )> { match self { - SerializedPaneGroup::Group { axis, children, flexes } => { + SerializedPaneGroup::Group { + axis, + children, + flexes, + } => { let mut current_active_pane = None; let mut members = Vec::new(); let mut items = Vec::new(); diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index e31e0d924f..885c686ddc 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -2898,7 +2898,8 @@ impl Workspace { fn schedule_serialize(&mut self, cx: &mut ViewContext) { self._schedule_serialize = Some(cx.spawn(|this, cx| async move { cx.background().timer(Duration::from_millis(100)).await; - this.read_with(&cx, |this, cx| this.serialize_workspace(cx)).ok(); + this.read_with(&cx, |this, cx| this.serialize_workspace(cx)) + .ok(); })); } From 9da8f609cf71d9bc0ee9e5686d5b6caef0d50465 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 13 Jul 2023 14:34:32 -0700 Subject: [PATCH 8/9] tidy up names --- crates/workspace/src/pane_group.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/workspace/src/pane_group.rs b/crates/workspace/src/pane_group.rs index 1edee1bc42..2ece5030f3 100644 --- a/crates/workspace/src/pane_group.rs +++ b/crates/workspace/src/pane_group.rs @@ -421,14 +421,13 @@ impl PaneAxis { ) -> AnyElement { debug_assert!(self.members.len() == self.flexes.borrow().len()); - let mut flex_container = PaneAxisElement::new(self.axis, basis, self.flexes.clone()); + let mut pane_axis = PaneAxisElement::new(self.axis, basis, self.flexes.clone()); let mut active_pane_ix = None; let mut members = self.members.iter().enumerate().peekable(); while let Some((ix, member)) = members.next() { let last = members.peek().is_none(); - // TODO: Restore this if member.contains(active_pane) { active_pane_ix = Some(ix); } @@ -460,10 +459,10 @@ impl PaneAxis { member = member.contained().with_border(border).into_any(); } - flex_container = flex_container.with_child(member.into_any()); + pane_axis = pane_axis.with_child(member.into_any()); } - flex_container.set_active_pane(active_pane_ix); - flex_container.into_any() + pane_axis.set_active_pane(active_pane_ix); + pane_axis.into_any() } } @@ -562,7 +561,7 @@ mod element { self.active_pane_ix = active_pane_ix; } - fn layout_flex_children( + fn layout_children( &mut self, active_pane_magnification: f32, constraint: SizeConstraint, @@ -656,7 +655,7 @@ mod element { panic!("flex contains flexible children but has an infinite constraint along the flex axis"); } - self.layout_flex_children( + self.layout_children( active_pane_magnification, constraint, &mut remaining_space, @@ -846,6 +845,7 @@ mod element { "type": "PaneAxis", "bounds": bounds.to_json(), "axis": self.axis.to_json(), + "flexes": *self.flexes.borrow(), "children": self.children.iter().map(|child| child.debug(view, cx)).collect::>() }) } From 50623c018cb04b1080025f074b8bf45c1a8e7af2 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 13 Jul 2023 14:47:37 -0700 Subject: [PATCH 9/9] Fix serialization error --- crates/workspace/src/persistence.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 0d7784093a..2a4062c079 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -443,7 +443,10 @@ impl WorkspaceDb { } => { let (parent_id, position) = unzip_option(parent); - let flex_string = serde_json::json!(flexes).to_string(); + let flex_string = flexes + .as_ref() + .map(|flexes| serde_json::json!(flexes).to_string()); + let group_id = conn.select_row_bound::<_, i64>(sql!( INSERT INTO pane_groups( workspace_id,