From 25df11dd2629814de2be9fcc9e7160fda32cc88f Mon Sep 17 00:00:00 2001 From: Mikayla Date: Thu, 7 Dec 2023 17:16:19 -0800 Subject: [PATCH 1/5] Begin porting the PaneAxis element --- crates/gpui2/src/executor.rs | 6 +- crates/gpui2/src/geometry.rs | 87 +++ crates/gpui2/src/taffy.rs | 9 + crates/util/src/util.rs | 31 +- crates/workspace2/src/dock.rs | 4 +- crates/workspace2/src/pane_group.rs | 822 +++++++++++---------- crates/workspace2/src/persistence.rs | 6 +- crates/workspace2/src/persistence/model.rs | 6 +- 8 files changed, 564 insertions(+), 407 deletions(-) diff --git a/crates/gpui2/src/executor.rs b/crates/gpui2/src/executor.rs index e01846c404..81fa6e64ca 100644 --- a/crates/gpui2/src/executor.rs +++ b/crates/gpui2/src/executor.rs @@ -57,8 +57,12 @@ where T: 'static, E: 'static + Debug, { + #[track_caller] pub fn detach_and_log_err(self, cx: &mut AppContext) { - cx.foreground_executor().spawn(self.log_err()).detach(); + let location = core::panic::Location::caller(); + cx.foreground_executor() + .spawn(self.log_tracked_err(*location)) + .detach(); } } diff --git a/crates/gpui2/src/geometry.rs b/crates/gpui2/src/geometry.rs index 50f680f493..4a13fa83f6 100644 --- a/crates/gpui2/src/geometry.rs +++ b/crates/gpui2/src/geometry.rs @@ -8,6 +8,54 @@ use std::{ ops::{Add, Div, Mul, MulAssign, Sub}, }; +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Axis { + Vertical, + Horizontal, +} + +impl Axis { + pub fn invert(&self) -> Self { + match self { + Axis::Vertical => Axis::Horizontal, + Axis::Horizontal => Axis::Vertical, + } + } +} + +impl sqlez::bindable::StaticColumnCount for Axis {} +impl sqlez::bindable::Bind for Axis { + fn bind( + &self, + statement: &sqlez::statement::Statement, + start_index: i32, + ) -> anyhow::Result { + match self { + Axis::Horizontal => "Horizontal", + Axis::Vertical => "Vertical", + } + .bind(statement, start_index) + } +} + +impl sqlez::bindable::Column for Axis { + fn column( + statement: &mut sqlez::statement::Statement, + start_index: i32, + ) -> anyhow::Result<(Self, i32)> { + String::column(statement, start_index).and_then(|(axis_text, next_index)| { + Ok(( + match axis_text.as_str() { + "Horizontal" => Axis::Horizontal, + "Vertical" => Axis::Vertical, + _ => anyhow::bail!("Stored serialized item kind is incorrect"), + }, + next_index, + )) + }) + } +} + /// Describes a location in a 2D cartesian coordinate space. /// /// It holds two public fields, `x` and `y`, which represent the coordinates in the space. @@ -94,6 +142,19 @@ impl Point { y: f(self.y.clone()), } } + + pub fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Point { + match axis { + Axis::Horizontal => Point { + x: f(self.x.clone()), + y: self.y.clone(), + }, + Axis::Vertical => Point { + x: self.x.clone(), + y: f(self.y.clone()), + }, + } + } } impl Point { @@ -373,6 +434,32 @@ impl Size { } } +impl Size +where + T: Clone + Default + Debug, +{ + pub fn along(&self, axis: Axis) -> T { + match axis { + Axis::Horizontal => self.width.clone(), + Axis::Vertical => self.height.clone(), + } + } + + /// Returns the value of this size along the given axis. + pub fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Self { + match axis { + Axis::Horizontal => Size { + width: f(self.width.clone()), + height: self.height.clone(), + }, + Axis::Vertical => Size { + width: self.width.clone(), + height: f(self.height.clone()), + }, + } + } +} + impl Size where T: PartialOrd + Clone + Default + Debug, diff --git a/crates/gpui2/src/taffy.rs b/crates/gpui2/src/taffy.rs index 2bceb1bc13..b4fc6c3abe 100644 --- a/crates/gpui2/src/taffy.rs +++ b/crates/gpui2/src/taffy.rs @@ -477,3 +477,12 @@ impl From for AvailableSpace { AvailableSpace::Definite(pixels) } } + +impl From> for Size { + fn from(size: Size) -> Self { + Size { + width: AvailableSpace::Definite(size.width), + height: AvailableSpace::Definite(size.height), + } + } +} diff --git a/crates/util/src/util.rs b/crates/util/src/util.rs index aacec422fe..3f2371121c 100644 --- a/crates/util/src/util.rs +++ b/crates/util/src/util.rs @@ -184,6 +184,11 @@ pub trait TryFutureExt { fn log_err(self) -> LogErrorFuture where Self: Sized; + + fn log_tracked_err(self, location: core::panic::Location<'static>) -> LogErrorFuture + where + Self: Sized; + fn warn_on_err(self) -> LogErrorFuture where Self: Sized; @@ -197,18 +202,29 @@ where F: Future>, E: std::fmt::Debug, { + #[track_caller] fn log_err(self) -> LogErrorFuture where Self: Sized, { - LogErrorFuture(self, log::Level::Error) + let location = Location::caller(); + LogErrorFuture(self, log::Level::Error, *location) } + fn log_tracked_err(self, location: core::panic::Location<'static>) -> LogErrorFuture + where + Self: Sized, + { + LogErrorFuture(self, log::Level::Error, location) + } + + #[track_caller] fn warn_on_err(self) -> LogErrorFuture where Self: Sized, { - LogErrorFuture(self, log::Level::Warn) + let location = Location::caller(); + LogErrorFuture(self, log::Level::Warn, *location) } fn unwrap(self) -> UnwrapFuture @@ -219,7 +235,7 @@ where } } -pub struct LogErrorFuture(F, log::Level); +pub struct LogErrorFuture(F, log::Level, core::panic::Location<'static>); impl Future for LogErrorFuture where @@ -230,12 +246,19 @@ where fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { let level = self.1; + let location = self.2; let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) }; match inner.poll(cx) { Poll::Ready(output) => Poll::Ready(match output { Ok(output) => Some(output), Err(error) => { - log::log!(level, "{:?}", error); + log::log!( + level, + "{}:{}: {:?}", + location.file(), + location.line(), + error + ); None } }), diff --git a/crates/workspace2/src/dock.rs b/crates/workspace2/src/dock.rs index 7bae7bc419..0640389189 100644 --- a/crates/workspace2/src/dock.rs +++ b/crates/workspace2/src/dock.rs @@ -1,6 +1,6 @@ -use crate::{status_bar::StatusItemView, Axis, Workspace}; +use crate::{status_bar::StatusItemView, Workspace}; use gpui::{ - div, px, Action, AnchorCorner, AnyView, AppContext, Div, Entity, EntityId, EventEmitter, + div, px, Action, AnchorCorner, AnyView, AppContext, Axis, Div, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, IntoElement, ParentElement, Render, SharedString, Styled, Subscription, View, ViewContext, VisualContext, WeakView, WindowContext, }; diff --git a/crates/workspace2/src/pane_group.rs b/crates/workspace2/src/pane_group.rs index 66465a4982..398f57bf6f 100644 --- a/crates/workspace2/src/pane_group.rs +++ b/crates/workspace2/src/pane_group.rs @@ -1,13 +1,9 @@ -use crate::{AppState, FollowerState, Pane, Workspace}; -use anyhow::{anyhow, bail, Result}; +use crate::{pane_group::element::pane_axis, AppState, FollowerState, Pane, Workspace}; +use anyhow::{anyhow, Result}; use call::{ActiveCall, ParticipantLocation}; use collections::HashMap; -use db::sqlez::{ - bindable::{Bind, Column, StaticColumnCount}, - statement::Statement, -}; use gpui::{ - point, size, AnyWeakView, Bounds, Div, Entity as _, IntoElement, Model, Pixels, Point, View, + point, size, AnyWeakView, Axis, Bounds, Entity as _, IntoElement, Model, Pixels, Point, View, ViewContext, }; use parking_lot::Mutex; @@ -20,38 +16,6 @@ const HANDLE_HITBOX_SIZE: f32 = 4.0; const HORIZONTAL_MIN_SIZE: f32 = 80.; const VERTICAL_MIN_SIZE: f32 = 100.; -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum Axis { - Vertical, - Horizontal, -} - -impl StaticColumnCount for Axis {} -impl Bind for Axis { - fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result { - match self { - Axis::Horizontal => "Horizontal", - Axis::Vertical => "Vertical", - } - .bind(statement, start_index) - } -} - -impl Column for Axis { - fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> { - String::column(statement, start_index).and_then(|(axis_text, next_index)| { - Ok(( - match axis_text.as_str() { - "Horizontal" => Axis::Horizontal, - "Vertical" => Axis::Vertical, - _ => bail!("Stored serialized item kind is incorrect"), - }, - next_index, - )) - }) - } -} - #[derive(Clone, PartialEq)] pub struct PaneGroup { pub(crate) root: Member, @@ -632,16 +596,10 @@ impl PaneAxis { zoomed: Option<&AnyWeakView>, app_state: &Arc, cx: &mut ViewContext, - ) -> Div { + ) -> gpui::AnyElement { debug_assert!(self.members.len() == self.flexes.lock().len()); - div() - .flex() - .flex_auto() - .map(|s| match self.axis { - Axis::Vertical => s.flex_col(), - Axis::Horizontal => s.flex_row(), - }) + pane_axis(self.axis, basis, self.flexes.clone()) .children(self.members.iter().enumerate().map(|(ix, member)| { match member { Member::Axis(axis) => axis @@ -658,6 +616,7 @@ impl PaneAxis { Member::Pane(pane) => pane.clone().into_any_element(), } })) + .into_any_element() // let mut pane_axis = PaneAxisElement::new( // self.axis, @@ -767,403 +726,480 @@ impl SplitDirection { } } -// mod element { -// // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc}; +mod element { + use std::sync::Arc; -// // use gpui::{ -// // geometry::{ -// // rect::Bounds, -// // vector::{vec2f, Vector2F}, -// // }, -// // json::{self, ToJson}, -// // platform::{CursorStyle, MouseButton}, -// // scene::MouseDrag, -// // AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, BoundsExt, -// // SizeConstraint, Vector2FExt, ViewContext, -// // }; + use gpui::{relative, AnyElement, Axis, Element, IntoElement, ParentElement, Style}; + use parking_lot::Mutex; + use smallvec::SmallVec; -// use crate::{ -// pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE}, -// Workspace, WorkspaceSettings, -// }; + pub fn pane_axis(axis: Axis, basis: usize, flexes: Arc>>) -> PaneAxisElement { + PaneAxisElement { + axis, + basis, + flexes, + children: SmallVec::new(), + } + } -// pub struct PaneAxisElement { -// axis: Axis, -// basis: usize, -// active_pane_ix: Option, -// flexes: Rc>>, -// children: Vec>, -// bounding_boxes: Rc>>>>, -// } + pub struct PaneAxisElement { + axis: Axis, + basis: usize, + flexes: Arc>>, + children: SmallVec<[AnyElement; 2]>, + } -// impl PaneAxisElement { -// pub fn new( -// axis: Axis, -// basis: usize, -// flexes: Rc>>, -// bounding_boxes: Rc>>>>, -// ) -> Self { -// Self { -// axis, -// basis, -// flexes, -// bounding_boxes, -// active_pane_ix: None, -// children: Default::default(), -// } -// } + impl IntoElement for PaneAxisElement { + type Element = Self; -// pub fn set_active_pane(&mut self, active_pane_ix: Option) { -// self.active_pane_ix = active_pane_ix; -// } + fn element_id(&self) -> Option { + Some("pane axis".into()) + } -// fn layout_children( -// &mut self, -// active_pane_magnification: f32, -// constraint: SizeConstraint, -// remaining_space: &mut f32, -// remaining_flex: &mut f32, -// cross_axis_max: &mut f32, -// view: &mut Workspace, -// cx: &mut ViewContext, -// ) { -// let flexes = self.flexes.borrow(); -// let cross_axis = self.axis.invert(); -// for (ix, child) in self.children.iter_mut().enumerate() { -// 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] -// }; + fn into_element(self) -> Self::Element { + self + } + } -// let child_size = if *remaining_flex == 0.0 { -// *remaining_space -// } else { -// let space_per_flex = *remaining_space / *remaining_flex; -// space_per_flex * flex -// }; + impl Element for PaneAxisElement { + type State = (); -// 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); -// *remaining_flex -= flex; -// *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis)); -// } -// } + fn layout( + &mut self, + state: Option, + cx: &mut ui::prelude::WindowContext, + ) -> (gpui::LayoutId, Self::State) { + let mut style = Style::default(); + style.size.width = relative(1.).into(); + style.size.height = relative(1.).into(); + let layout_id = cx.request_layout(&style, None); -// fn handle_resize( -// flexes: Rc>>, -// axis: Axis, -// preceding_ix: usize, -// child_start: Vector2F, -// drag_bounds: Bounds, -// ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext) { -// let size = move |ix, flexes: &[f32]| { -// drag_bounds.length_along(axis) * (flexes[ix] / flexes.len() as f32) -// }; + (layout_id, ()) + } -// move |drag, workspace: &mut Workspace, cx| { -// if drag.end { -// // TODO: Clear cascading resize state -// return; -// } -// let min_size = match axis { -// Axis::Horizontal => HORIZONTAL_MIN_SIZE, -// Axis::Vertical => VERTICAL_MIN_SIZE, -// }; -// let mut flexes = flexes.borrow_mut(); + fn paint( + self, + bounds: gpui::Bounds, + state: &mut Self::State, + cx: &mut ui::prelude::WindowContext, + ) { + let flexes = self.flexes.lock().clone(); + debug_assert!(flexes.len() == self.children.len()); -// // Don't allow resizing to less than the minimum size, if elements are already too small -// if min_size - 1. > size(preceding_ix, flexes.as_slice()) { -// return; -// } + let origin = bounds.origin; + let size = bounds.size; + let len = self.children.len(); + let child_size = size.apply_along(self.axis, |val| val / len as f32); + for (ix, child) in self.children.into_iter().enumerate() { + let origin = + origin.apply_along(self.axis, |val| val + child_size.along(self.axis) * ix); + child.draw(origin, child_size.into(), cx); + } + } + } -// let mut proposed_current_pixel_change = (drag.position - child_start).along(axis) -// - size(preceding_ix, flexes.as_slice()); + impl ParentElement for PaneAxisElement { + fn children_mut(&mut self) -> &mut smallvec::SmallVec<[AnyElement; 2]> { + &mut self.children + } + } -// let flex_changes = |pixel_dx, target_ix, next: isize, 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 as isize + next) as usize] - flex_change; -// (current_target_flex, next_target_flex) -// }; + // // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc}; -// let mut successors = from_fn({ -// let forward = proposed_current_pixel_change > 0.; -// let mut ix_offset = 0; -// let len = flexes.len(); -// move || { -// let result = if forward { -// (preceding_ix + 1 + ix_offset < len).then(|| preceding_ix + ix_offset) -// } else { -// (preceding_ix as isize - ix_offset as isize >= 0) -// .then(|| preceding_ix - ix_offset) -// }; + // // use gpui::{ + // // geometry::{ + // // rect::Bounds, + // // vector::{vec2f, Vector2F}, + // // }, + // // json::{self, ToJson}, + // // platform::{CursorStyle, MouseButton}, + // // scene::MouseDrag, + // // AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, BoundsExt, + // // SizeConstraint, Vector2FExt, ViewContext, + // // }; -// ix_offset += 1; + // use crate::{ + // pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE}, + // Workspace, WorkspaceSettings, + // }; -// result -// } -// }); + // pub struct PaneAxisElement { + // axis: Axis, + // basis: usize, + // active_pane_ix: Option, + // flexes: Rc>>, + // children: Vec>, + // bounding_boxes: Rc>>>>, + // } -// while proposed_current_pixel_change.abs() > 0. { -// let Some(current_ix) = successors.next() else { -// break; -// }; + // impl PaneAxisElement { + // pub fn new( + // axis: Axis, + // basis: usize, + // flexes: Rc>>, + // bounding_boxes: Rc>>>>, + // ) -> Self { + // Self { + // axis, + // basis, + // flexes, + // bounding_boxes, + // active_pane_ix: None, + // children: Default::default(), + // } + // } -// let next_target_size = f32::max( -// size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change, -// min_size, -// ); + // pub fn set_active_pane(&mut self, active_pane_ix: Option) { + // self.active_pane_ix = active_pane_ix; + // } -// let current_target_size = f32::max( -// size(current_ix, flexes.as_slice()) -// + size(current_ix + 1, flexes.as_slice()) -// - next_target_size, -// min_size, -// ); + // fn layout_children( + // &mut self, + // active_pane_magnification: f32, + // constraint: SizeConstraint, + // remaining_space: &mut f32, + // remaining_flex: &mut f32, + // cross_axis_max: &mut f32, + // view: &mut Workspace, + // cx: &mut ViewContext, + // ) { + // let flexes = self.flexes.borrow(); + // let cross_axis = self.axis.invert(); + // for (ix, child) in self.children.iter_mut().enumerate() { + // 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 current_pixel_change = -// current_target_size - size(current_ix, flexes.as_slice()); + // let child_size = if *remaining_flex == 0.0 { + // *remaining_space + // } else { + // let space_per_flex = *remaining_space / *remaining_flex; + // space_per_flex * flex + // }; -// let (current_target_flex, next_target_flex) = -// flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice()); + // 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); + // *remaining_flex -= flex; + // *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis)); + // } + // } -// flexes[current_ix] = current_target_flex; -// flexes[current_ix + 1] = next_target_flex; + // fn handle_resize( + // flexes: Rc>>, + // axis: Axis, + // preceding_ix: usize, + // child_start: Vector2F, + // drag_bounds: Bounds, + // ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext) { + // let size = move |ix, flexes: &[f32]| { + // drag_bounds.length_along(axis) * (flexes[ix] / flexes.len() as f32) + // }; -// proposed_current_pixel_change -= current_pixel_change; -// } + // move |drag, workspace: &mut Workspace, cx| { + // if drag.end { + // // TODO: Clear cascading resize state + // return; + // } + // let min_size = match axis { + // Axis::Horizontal => HORIZONTAL_MIN_SIZE, + // Axis::Vertical => VERTICAL_MIN_SIZE, + // }; + // let mut flexes = flexes.borrow_mut(); -// workspace.schedule_serialize(cx); -// cx.notify(); -// } -// } -// } + // // Don't allow resizing to less than the minimum size, if elements are already too small + // if min_size - 1. > size(preceding_ix, flexes.as_slice()) { + // return; + // } -// impl Extend> for PaneAxisElement { -// fn extend>>(&mut self, children: T) { -// self.children.extend(children); -// } -// } + // let mut proposed_current_pixel_change = (drag.position - child_start).along(axis) + // - size(preceding_ix, flexes.as_slice()); -// impl Element for PaneAxisElement { -// type LayoutState = f32; -// type PaintState = (); + // let flex_changes = |pixel_dx, target_ix, next: isize, 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 as isize + next) as usize] - flex_change; + // (current_target_flex, next_target_flex) + // }; -// fn layout( -// &mut self, -// constraint: SizeConstraint, -// view: &mut Workspace, -// cx: &mut ViewContext, -// ) -> (Vector2F, Self::LayoutState) { -// debug_assert!(self.children.len() == self.flexes.borrow().len()); + // let mut successors = from_fn({ + // let forward = proposed_current_pixel_change > 0.; + // let mut ix_offset = 0; + // let len = flexes.len(); + // move || { + // let result = if forward { + // (preceding_ix + 1 + ix_offset < len).then(|| preceding_ix + ix_offset) + // } else { + // (preceding_ix as isize - ix_offset as isize >= 0) + // .then(|| preceding_ix - ix_offset) + // }; -// let active_pane_magnification = -// settings::get::(cx).active_pane_magnification; + // ix_offset += 1; -// let mut remaining_flex = 0.; + // result + // } + // }); -// 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; -// } -// } + // while proposed_current_pixel_change.abs() > 0. { + // let Some(current_ix) = successors.next() else { + // break; + // }; -// let mut cross_axis_max: f32 = 0.0; -// let mut remaining_space = constraint.max_along(self.axis); + // let next_target_size = f32::max( + // size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change, + // min_size, + // ); -// if remaining_space.is_infinite() { -// panic!("flex contains flexible children but has an infinite constraint along the flex axis"); -// } + // let current_target_size = f32::max( + // size(current_ix, flexes.as_slice()) + // + size(current_ix + 1, flexes.as_slice()) + // - next_target_size, + // min_size, + // ); -// self.layout_children( -// active_pane_magnification, -// constraint, -// &mut remaining_space, -// &mut remaining_flex, -// &mut cross_axis_max, -// view, -// cx, -// ); + // let current_pixel_change = + // current_target_size - size(current_ix, flexes.as_slice()); -// 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), -// }; + // let (current_target_flex, next_target_flex) = + // flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice()); -// 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())); -// } + // flexes[current_ix] = current_target_flex; + // flexes[current_ix + 1] = next_target_flex; -// if size.x() > constraint.max.x() { -// size.set_x(constraint.max.x()); -// } -// if size.y() > constraint.max.y() { -// size.set_y(constraint.max.y()); -// } + // proposed_current_pixel_change -= current_pixel_change; + // } -// (size, remaining_space) -// } + // workspace.schedule_serialize(cx); + // cx.notify(); + // } + // } + // } -// fn paint( -// &mut self, -// bounds: Bounds, -// visible_bounds: Bounds, -// remaining_space: &mut Self::LayoutState, -// 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(); + // impl Extend> for PaneAxisElement { + // fn extend>>(&mut self, children: T) { + // self.children.extend(children); + // } + // } -// let overflowing = *remaining_space < 0.; -// if overflowing { -// cx.scene().push_layer(Some(visible_bounds)); -// } + // impl Element for PaneAxisElement { + // type LayoutState = f32; + // type PaintState = (); -// let mut child_origin = bounds.origin(); + // fn layout( + // &mut self, + // constraint: SizeConstraint, + // view: &mut Workspace, + // cx: &mut ViewContext, + // ) -> (Vector2F, Self::LayoutState) { + // debug_assert!(self.children.len() == self.flexes.borrow().len()); -// let mut bounding_boxes = self.bounding_boxes.borrow_mut(); -// bounding_boxes.clear(); + // let active_pane_magnification = + // settings::get::(cx).active_pane_magnification; -// 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(child_origin, visible_bounds, view, cx); + // let mut remaining_flex = 0.; -// bounding_boxes.push(Some(Bounds::new(child_origin, child.size()))); + // 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; + // } + // } -// match self.axis { -// Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0), -// Axis::Vertical => child_origin += vec2f(0.0, child.size().y()), -// } + // let mut cross_axis_max: f32 = 0.0; + // let mut remaining_space = constraint.max_along(self.axis); -// if can_resize && children_iter.peek().is_some() { -// cx.scene().push_stacking_context(None, None); + // if remaining_space.is_infinite() { + // panic!("flex contains flexible children but has an infinite constraint along the flex axis"); + // } -// 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.), -// }; + // self.layout_children( + // active_pane_magnification, + // constraint, + // &mut remaining_space, + // &mut remaining_flex, + // &mut cross_axis_max, + // view, + // cx, + // ); -// let handle_bounds = match self.axis { -// Axis::Horizontal => Bounds::new( -// handle_origin, -// vec2f(HANDLE_HITBOX_SIZE, visible_bounds.height()), -// ), -// Axis::Vertical => Bounds::new( -// handle_origin, -// vec2f(visible_bounds.width(), HANDLE_HITBOX_SIZE), -// ), -// }; + // 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), + // }; -// let style = match self.axis { -// Axis::Horizontal => CursorStyle::ResizeLeftRight, -// Axis::Vertical => CursorStyle::ResizeUpDown, -// }; + // 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())); + // } -// cx.scene().push_cursor_region(CursorRegion { -// bounds: handle_bounds, -// style, -// }); + // if size.x() > constraint.max.x() { + // size.set_x(constraint.max.x()); + // } + // if size.y() > constraint.max.y() { + // size.set_y(constraint.max.y()); + // } -// enum ResizeHandle {} -// let mut mouse_region = MouseRegion::new::( -// cx.view_id(), -// self.basis + ix, -// handle_bounds, -// ); -// mouse_region = mouse_region -// .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| { -// if e.click_count >= 2 { -// let mut borrow = flexes.borrow_mut(); -// *borrow = vec![1.; borrow.len()]; -// v.schedule_serialize(cx); -// cx.notify(); -// } -// } -// }); -// cx.scene().push_mouse_region(mouse_region); + // (size, remaining_space) + // } -// cx.scene().pop_stacking_context(); -// } -// } + // fn paint( + // &mut self, + // bounds: Bounds, + // visible_bounds: Bounds, + // remaining_space: &mut Self::LayoutState, + // 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(); -// if overflowing { -// cx.scene().pop_layer(); -// } -// } + // let overflowing = *remaining_space < 0.; + // if overflowing { + // cx.scene().push_layer(Some(visible_bounds)); + // } -// fn rect_for_text_range( -// &self, -// range_utf16: Range, -// _: Bounds, -// _: Bounds, -// _: &Self::LayoutState, -// _: &Self::PaintState, -// view: &Workspace, -// cx: &ViewContext, -// ) -> Option> { -// self.children -// .iter() -// .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx)) -// } + // let mut child_origin = bounds.origin(); -// fn debug( -// &self, -// bounds: Bounds, -// _: &Self::LayoutState, -// _: &Self::PaintState, -// view: &Workspace, -// cx: &ViewContext, -// ) -> json::Value { -// serde_json::json!({ -// "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::>() -// }) -// } -// } -// } + // let mut bounding_boxes = self.bounding_boxes.borrow_mut(); + // bounding_boxes.clear(); + + // 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(child_origin, visible_bounds, view, cx); + + // bounding_boxes.push(Some(Bounds::new(child_origin, child.size()))); + + // match self.axis { + // Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0), + // Axis::Vertical => child_origin += vec2f(0.0, child.size().y()), + // } + + // if can_resize && children_iter.peek().is_some() { + // cx.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 => Bounds::new( + // handle_origin, + // vec2f(HANDLE_HITBOX_SIZE, visible_bounds.height()), + // ), + // Axis::Vertical => Bounds::new( + // handle_origin, + // vec2f(visible_bounds.width(), HANDLE_HITBOX_SIZE), + // ), + // }; + + // let style = match self.axis { + // Axis::Horizontal => CursorStyle::ResizeLeftRight, + // Axis::Vertical => CursorStyle::ResizeUpDown, + // }; + + // cx.scene().push_cursor_region(CursorRegion { + // bounds: handle_bounds, + // style, + // }); + + // enum ResizeHandle {} + // let mut mouse_region = MouseRegion::new::( + // cx.view_id(), + // self.basis + ix, + // handle_bounds, + // ); + // mouse_region = mouse_region + // .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| { + // if e.click_count >= 2 { + // let mut borrow = flexes.borrow_mut(); + // *borrow = vec![1.; borrow.len()]; + // v.schedule_serialize(cx); + // cx.notify(); + // } + // } + // }); + // cx.scene().push_mouse_region(mouse_region); + + // cx.scene().pop_stacking_context(); + // } + // } + + // if overflowing { + // cx.scene().pop_layer(); + // } + // } + + // fn rect_for_text_range( + // &self, + // range_utf16: Range, + // _: Bounds, + // _: Bounds, + // _: &Self::LayoutState, + // _: &Self::PaintState, + // view: &Workspace, + // cx: &ViewContext, + // ) -> Option> { + // self.children + // .iter() + // .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx)) + // } + + // fn debug( + // &self, + // bounds: Bounds, + // _: &Self::LayoutState, + // _: &Self::PaintState, + // view: &Workspace, + // cx: &ViewContext, + // ) -> json::Value { + // serde_json::json!({ + // "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::>() + // }) + // } + // } +} diff --git a/crates/workspace2/src/persistence.rs b/crates/workspace2/src/persistence.rs index b842355991..1abb06dccf 100644 --- a/crates/workspace2/src/persistence.rs +++ b/crates/workspace2/src/persistence.rs @@ -6,12 +6,12 @@ use std::path::Path; use anyhow::{anyhow, bail, Context, Result}; use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql}; -use gpui::WindowBounds; +use gpui::{Axis, WindowBounds}; use util::{unzip_option, ResultExt}; use uuid::Uuid; -use crate::{Axis, WorkspaceId}; +use crate::WorkspaceId; use model::{ GroupId, PaneId, SerializedItem, SerializedPane, SerializedPaneGroup, SerializedWorkspace, @@ -403,7 +403,7 @@ impl WorkspaceDb { .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)) + .map(|flexes: String| serde_json::from_str::>(&flexes)) .transpose()?; Ok(SerializedPaneGroup::Group { diff --git a/crates/workspace2/src/persistence/model.rs b/crates/workspace2/src/persistence/model.rs index 74304d3c8e..f204e5152c 100644 --- a/crates/workspace2/src/persistence/model.rs +++ b/crates/workspace2/src/persistence/model.rs @@ -1,13 +1,11 @@ -use crate::{ - item::ItemHandle, Axis, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId, -}; +use crate::{item::ItemHandle, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId}; use anyhow::{Context, Result}; use async_recursion::async_recursion; use db::sqlez::{ bindable::{Bind, Column, StaticColumnCount}, statement::Statement, }; -use gpui::{AsyncWindowContext, Model, Task, View, WeakView, WindowBounds}; +use gpui::{AsyncWindowContext, Axis, Model, Task, View, WeakView, WindowBounds}; use project::Project; use std::{ path::{Path, PathBuf}, From fd34d1da31c94becafb87fcc3eebe18b82f6c011 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 8 Dec 2023 16:29:42 -0800 Subject: [PATCH 2/5] Add back semi-funcitonal pane resizing code --- crates/editor2/src/element.rs | 16 +- crates/gpui2/src/elements/div.rs | 22 +- crates/gpui2/src/elements/text.rs | 2 +- crates/gpui2/src/geometry.rs | 31 +- crates/gpui2/src/interactive.rs | 6 + crates/gpui2/src/window.rs | 12 +- crates/ui2/src/components/right_click_menu.rs | 2 +- crates/workspace2/src/pane.rs | 5 +- crates/workspace2/src/pane_group.rs | 309 +++++++++++++----- crates/workspace2/src/workspace2.rs | 2 +- 10 files changed, 299 insertions(+), 108 deletions(-) diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index ad66ed8090..7219e90665 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -389,9 +389,9 @@ impl EditorElement { let mut click_count = event.click_count; let modifiers = event.modifiers; - if gutter_bounds.contains_point(&event.position) { + if gutter_bounds.contains(&event.position) { click_count = 3; // Simulate triple-click when clicking the gutter to select lines - } else if !text_bounds.contains_point(&event.position) { + } else if !text_bounds.contains(&event.position) { return false; } if !cx.was_top_layer(&event.position, stacking_order) { @@ -437,7 +437,7 @@ impl EditorElement { text_bounds: Bounds, cx: &mut ViewContext, ) -> bool { - if !text_bounds.contains_point(&event.position) { + if !text_bounds.contains(&event.position) { return false; } let point_for_position = position_map.point_for_position(text_bounds, event.position); @@ -467,7 +467,7 @@ impl EditorElement { if !pending_nonempty_selections && event.modifiers.command - && text_bounds.contains_point(&event.position) + && text_bounds.contains(&event.position) && cx.was_top_layer(&event.position, stacking_order) { let point = position_map.point_for_position(text_bounds, event.position); @@ -529,8 +529,8 @@ impl EditorElement { ); } - let text_hovered = text_bounds.contains_point(&event.position); - let gutter_hovered = gutter_bounds.contains_point(&event.position); + let text_hovered = text_bounds.contains(&event.position); + let gutter_hovered = gutter_bounds.contains(&event.position); let was_top = cx.was_top_layer(&event.position, stacking_order); editor.set_gutter_hovered(gutter_hovered, cx); @@ -894,7 +894,7 @@ impl EditorElement { bounds: text_bounds, }), |cx| { - if text_bounds.contains_point(&cx.mouse_position()) { + if text_bounds.contains(&cx.mouse_position()) { if self .editor .read(cx) @@ -960,7 +960,7 @@ impl EditorElement { |fold_element_state, cx| { if fold_element_state.is_active() { gpui::blue() - } else if fold_bounds.contains_point(&cx.mouse_position()) { + } else if fold_bounds.contains(&cx.mouse_position()) { gpui::black() } else { gpui::red() diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index 10fd7dda0a..479ef262d3 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -761,7 +761,7 @@ pub struct InteractiveBounds { impl InteractiveBounds { pub fn visibly_contains(&self, point: &Point, cx: &WindowContext) -> bool { - self.bounds.contains_point(point) && cx.was_top_layer(&point, &self.stacking_order) + self.bounds.contains(point) && cx.was_top_layer(&point, &self.stacking_order) } } @@ -860,10 +860,10 @@ impl Interactivity { .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx)); if let Some(group_bounds) = hover_group_bounds { - let hovered = group_bounds.contains_point(&cx.mouse_position()); + let hovered = group_bounds.contains(&cx.mouse_position()); cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { if phase == DispatchPhase::Capture { - if group_bounds.contains_point(&event.position) != hovered { + if group_bounds.contains(&event.position) != hovered { cx.notify(); } } @@ -875,10 +875,10 @@ impl Interactivity { || cx.active_drag.is_some() && !self.drag_over_styles.is_empty() { let bounds = bounds.intersect(&cx.content_mask().bounds); - let hovered = bounds.contains_point(&cx.mouse_position()); + let hovered = bounds.contains(&cx.mouse_position()); cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { if phase == DispatchPhase::Capture { - if bounds.contains_point(&event.position) != hovered { + if bounds.contains(&event.position) != hovered { cx.notify(); } } @@ -1067,8 +1067,8 @@ impl Interactivity { let interactive_bounds = interactive_bounds.clone(); cx.on_mouse_event(move |down: &MouseDownEvent, phase, cx| { if phase == DispatchPhase::Bubble { - let group = active_group_bounds - .map_or(false, |bounds| bounds.contains_point(&down.position)); + let group = + active_group_bounds.map_or(false, |bounds| bounds.contains(&down.position)); let element = interactive_bounds.visibly_contains(&down.position, cx); if group || element { *active_state.borrow_mut() = ElementClickedState { group, element }; @@ -1182,7 +1182,7 @@ impl Interactivity { let mouse_position = cx.mouse_position(); if let Some(group_hover) = self.group_hover_style.as_ref() { if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) { - if group_bounds.contains_point(&mouse_position) + if group_bounds.contains(&mouse_position) && cx.was_top_layer(&mouse_position, cx.stacking_order()) { style.refine(&group_hover.style); @@ -1192,7 +1192,7 @@ impl Interactivity { if self.hover_style.is_some() { if bounds .intersect(&cx.content_mask().bounds) - .contains_point(&mouse_position) + .contains(&mouse_position) && cx.was_top_layer(&mouse_position, cx.stacking_order()) { style.refine(&self.hover_style); @@ -1203,7 +1203,7 @@ impl Interactivity { for (state_type, group_drag_style) in &self.group_drag_over_styles { if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) { if *state_type == drag.view.entity_type() - && group_bounds.contains_point(&mouse_position) + && group_bounds.contains(&mouse_position) { style.refine(&group_drag_style.style); } @@ -1214,7 +1214,7 @@ impl Interactivity { if *state_type == drag.view.entity_type() && bounds .intersect(&cx.content_mask().bounds) - .contains_point(&mouse_position) + .contains(&mouse_position) { style.refine(drag_over_style); } diff --git a/crates/gpui2/src/elements/text.rs b/crates/gpui2/src/elements/text.rs index d398b1f8fe..b8fe5e6866 100644 --- a/crates/gpui2/src/elements/text.rs +++ b/crates/gpui2/src/elements/text.rs @@ -253,7 +253,7 @@ impl TextState { } fn index_for_position(&self, bounds: Bounds, position: Point) -> Option { - if !bounds.contains_point(&position) { + if !bounds.contains(&position) { return None; } diff --git a/crates/gpui2/src/geometry.rs b/crates/gpui2/src/geometry.rs index 4a13fa83f6..ee2f42d2a2 100644 --- a/crates/gpui2/src/geometry.rs +++ b/crates/gpui2/src/geometry.rs @@ -23,6 +23,14 @@ impl Axis { } } +pub trait Along { + type Unit; + + fn along(&self, axis: Axis) -> Self::Unit; + + fn apply_along(&self, axis: Axis, f: impl FnOnce(Self::Unit) -> Self::Unit) -> Self; +} + impl sqlez::bindable::StaticColumnCount for Axis {} impl sqlez::bindable::Bind for Axis { fn bind( @@ -142,8 +150,19 @@ impl Point { y: f(self.y.clone()), } } +} - pub fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Point { +impl Along for Point { + type Unit = T; + + fn along(&self, axis: Axis) -> T { + match axis { + Axis::Horizontal => self.x.clone(), + Axis::Vertical => self.y.clone(), + } + } + + fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Point { match axis { Axis::Horizontal => Point { x: f(self.x.clone()), @@ -434,11 +453,13 @@ impl Size { } } -impl Size +impl Along for Size where T: Clone + Default + Debug, { - pub fn along(&self, axis: Axis) -> T { + type Unit = T; + + fn along(&self, axis: Axis) -> T { match axis { Axis::Horizontal => self.width.clone(), Axis::Vertical => self.height.clone(), @@ -446,7 +467,7 @@ where } /// Returns the value of this size along the given axis. - pub fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Self { + fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Self { match axis { Axis::Horizontal => Size { width: f(self.width.clone()), @@ -1079,7 +1100,7 @@ where /// assert!(bounds.contains_point(&inside_point)); /// assert!(!bounds.contains_point(&outside_point)); /// ``` - pub fn contains_point(&self, point: &Point) -> bool { + pub fn contains(&self, point: &Point) -> bool { point.x >= self.origin.x && point.x <= self.origin.x.clone() + self.size.width.clone() && point.y >= self.origin.y diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index 84636630f3..3aff57ed34 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -131,6 +131,12 @@ pub struct MouseMoveEvent { pub modifiers: Modifiers, } +impl MouseMoveEvent { + pub fn dragging(&self) -> bool { + self.pressed_button == Some(MouseButton::Left) + } +} + #[derive(Clone, Debug)] pub struct ScrollWheelEvent { pub position: Point, diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index f98d9820c2..33d6a111c1 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -60,6 +60,16 @@ pub enum DispatchPhase { Capture, } +impl DispatchPhase { + pub fn bubble(self) -> bool { + self == DispatchPhase::Bubble + } + + pub fn capture(self) -> bool { + self == DispatchPhase::Capture + } +} + type AnyObserver = Box bool + 'static>; type AnyMouseListener = Box; type AnyFocusListener = Box; @@ -859,7 +869,7 @@ impl<'a> WindowContext<'a> { /// same layer as the given stacking order. pub fn was_top_layer(&self, point: &Point, level: &StackingOrder) -> bool { for (stack, bounds) in self.window.rendered_frame.depth_map.iter() { - if bounds.contains_point(point) { + if bounds.contains(point) { return level.starts_with(stack) || stack.starts_with(level); } } diff --git a/crates/ui2/src/components/right_click_menu.rs b/crates/ui2/src/components/right_click_menu.rs index 27c4fdab96..19031b2be7 100644 --- a/crates/ui2/src/components/right_click_menu.rs +++ b/crates/ui2/src/components/right_click_menu.rs @@ -137,7 +137,7 @@ impl Element for RightClickMenu { cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| { if phase == DispatchPhase::Bubble && event.button == MouseButton::Right - && bounds.contains_point(&event.position) + && bounds.contains(&event.position) { cx.stop_propagation(); cx.prevent_default(); diff --git a/crates/workspace2/src/pane.rs b/crates/workspace2/src/pane.rs index 3b1c00994f..f1e9649e10 100644 --- a/crates/workspace2/src/pane.rs +++ b/crates/workspace2/src/pane.rs @@ -1040,10 +1040,11 @@ impl Pane { { pane.remove_item(item_ix, false, cx); } - })?; + }) + .ok(); } - pane.update(&mut cx, |_, cx| cx.notify())?; + pane.update(&mut cx, |_, cx| cx.notify()).ok(); Ok(()) }) } diff --git a/crates/workspace2/src/pane_group.rs b/crates/workspace2/src/pane_group.rs index 398f57bf6f..4865a40a57 100644 --- a/crates/workspace2/src/pane_group.rs +++ b/crates/workspace2/src/pane_group.rs @@ -12,7 +12,7 @@ use serde::Deserialize; use std::sync::Arc; use ui::{prelude::*, Button}; -const HANDLE_HITBOX_SIZE: f32 = 4.0; +const HANDLE_HITBOX_SIZE: f32 = 10.0; //todo!(change this back to 4) const HORIZONTAL_MIN_SIZE: f32 = 80.; const VERTICAL_MIN_SIZE: f32 = 100.; @@ -576,7 +576,7 @@ impl PaneAxis { for (idx, member) in self.members.iter().enumerate() { if let Some(coordinates) = bounding_boxes[idx] { - if coordinates.contains_point(&coordinate) { + if coordinates.contains(&coordinate) { return match member { Member::Pane(found) => Some(found), Member::Axis(axis) => axis.pane_at_pixel_position(coordinate), @@ -598,73 +598,41 @@ impl PaneAxis { cx: &mut ViewContext, ) -> gpui::AnyElement { debug_assert!(self.members.len() == self.flexes.lock().len()); + let mut active_pane_ix = None; - pane_axis(self.axis, basis, self.flexes.clone()) - .children(self.members.iter().enumerate().map(|(ix, member)| { - match member { - Member::Axis(axis) => axis - .render( - project, - basis, - follower_states, - active_pane, - zoomed, - app_state, - cx, - ) - .into_any_element(), - Member::Pane(pane) => pane.clone().into_any_element(), - } - })) - .into_any_element() + pane_axis( + self.axis, + basis, + self.flexes.clone(), + self.bounding_boxes.clone(), + ) + .children(self.members.iter().enumerate().map(|(ix, member)| { + if member.contains(active_pane) { + active_pane_ix = Some(ix); + } - // let mut pane_axis = PaneAxisElement::new( - // self.axis, - // basis, - // self.flexes.clone(), - // self.bounding_boxes.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(); - - // if member.contains(active_pane) { - // active_pane_ix = Some(ix); - // } - - // let mut member = member.render( - // project, - // (basis + ix) * 10, - // theme, - // follower_states, - // 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, - // } - - // member = member.contained().with_border(border).into_any(); - // } - - // pane_axis = pane_axis.with_child(member.into_any()); - // } - // pane_axis.set_active_pane(active_pane_ix); - // pane_axis.into_any() + match member { + Member::Axis(axis) => axis + .render( + project, + (basis + ix) * 10, + follower_states, + active_pane, + zoomed, + app_state, + cx, + ) + .into_any_element(), + Member::Pane(pane) => div() + .size_full() + .border() + .border_color(gpui::green()) + .child(pane.clone()) + .into_any_element(), + } + })) + .with_active_pane(active_pane_ix) + .into_any_element() } } @@ -727,18 +695,31 @@ impl SplitDirection { } mod element { - use std::sync::Arc; - use gpui::{relative, AnyElement, Axis, Element, IntoElement, ParentElement, Style}; + use std::{iter, sync::Arc}; + + use gpui::{ + px, relative, Along, AnyElement, Axis, Bounds, CursorStyle, Element, IntoElement, + MouseMoveEvent, ParentElement, Pixels, Style, WindowContext, + }; use parking_lot::Mutex; use smallvec::SmallVec; - pub fn pane_axis(axis: Axis, basis: usize, flexes: Arc>>) -> PaneAxisElement { + use super::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE}; + + pub fn pane_axis( + axis: Axis, + basis: usize, + flexes: Arc>>, + bounding_boxes: Arc>>>>, + ) -> PaneAxisElement { PaneAxisElement { axis, basis, flexes, + bounding_boxes, children: SmallVec::new(), + active_pane_ix: None, } } @@ -746,7 +727,145 @@ mod element { axis: Axis, basis: usize, flexes: Arc>>, + bounding_boxes: Arc>>>>, children: SmallVec<[AnyElement; 2]>, + active_pane_ix: Option, + } + + impl PaneAxisElement { + pub fn with_active_pane(mut self, active_pane_ix: Option) -> Self { + self.active_pane_ix = active_pane_ix; + self + } + + fn compute_resize( + flexes: &Arc>>, + e: &MouseMoveEvent, + ix: usize, + axis: Axis, + axis_bounds: Bounds, + cx: &mut WindowContext, + ) { + let min_size = match axis { + Axis::Horizontal => px(HORIZONTAL_MIN_SIZE), + Axis::Vertical => px(VERTICAL_MIN_SIZE), + }; + let mut flexes = flexes.lock(); + debug_assert!(flex_values_in_bounds(flexes.as_slice())); + + let size = move |ix, flexes: &[f32]| { + axis_bounds.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; + } + + let mut proposed_current_pixel_change = + (e.position - axis_bounds.origin).along(axis) - size(ix, flexes.as_slice()); + + let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| { + let flex_change = pixel_dx / axis_bounds.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 mut successors = iter::from_fn({ + let forward = proposed_current_pixel_change > px(0.); + let mut ix_offset = 0; + let len = flexes.len(); + move || { + let result = if forward { + (ix + 1 + ix_offset < len).then(|| ix + ix_offset) + } else { + (ix as isize - ix_offset as isize >= 0).then(|| ix - ix_offset) + }; + + ix_offset += 1; + + result + } + }); + + while dbg!(proposed_current_pixel_change).abs() > px(0.) { + let Some(current_ix) = successors.next() else { + break; + }; + + dbg!(current_ix); + + let next_target_size = Pixels::max( + size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change, + min_size, + ); + + let current_target_size = Pixels::max( + size(current_ix, flexes.as_slice()) + size(current_ix + 1, flexes.as_slice()) + - next_target_size, + min_size, + ); + + let current_pixel_change = + current_target_size - size(current_ix, flexes.as_slice()); + + let (current_target_flex, next_target_flex) = + flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice()); + + flexes[current_ix] = current_target_flex; + flexes[current_ix + 1] = next_target_flex; + + proposed_current_pixel_change -= current_pixel_change; + } + + // todo!(reserialize workspace) + // workspace.schedule_serialize(cx); + cx.notify(); + } + + fn push_handle( + flexes: Arc>>, + axis: Axis, + ix: usize, + pane_bounds: Bounds, + axis_bounds: Bounds, + cx: &mut WindowContext, + ) { + let handle_bounds = Bounds { + origin: pane_bounds.origin.apply_along(axis, |o| { + o + pane_bounds.size.along(axis) - Pixels(HANDLE_HITBOX_SIZE / 2.) + }), + size: pane_bounds + .size + .apply_along(axis, |_| Pixels(HANDLE_HITBOX_SIZE)), + }; + + cx.with_z_index(3, |cx| { + if handle_bounds.contains(&cx.mouse_position()) { + cx.set_cursor_style(match axis { + Axis::Vertical => CursorStyle::ResizeUpDown, + Axis::Horizontal => CursorStyle::ResizeLeftRight, + }) + } + + cx.add_opaque_layer(handle_bounds); + + cx.paint_quad( + handle_bounds, + Default::default(), + gpui::red(), + Default::default(), + gpui::red(), + ); + + cx.on_mouse_event(move |e: &MouseMoveEvent, phase, cx| { + if phase.bubble() && e.dragging() && handle_bounds.contains(&e.position) { + Self::compute_resize(&flexes, e, ix, axis, axis_bounds, cx) + } + }); + }); + } } impl IntoElement for PaneAxisElement { @@ -784,16 +903,47 @@ mod element { cx: &mut ui::prelude::WindowContext, ) { let flexes = self.flexes.lock().clone(); - debug_assert!(flexes.len() == self.children.len()); - - let origin = bounds.origin; - let size = bounds.size; let len = self.children.len(); - let child_size = size.apply_along(self.axis, |val| val / len as f32); + debug_assert!(flexes.len() == len); + debug_assert!(flex_values_in_bounds(flexes.as_slice())); + + let mut origin = bounds.origin; + let space_per_flex = bounds.size.along(self.axis) / len as f32; + + let mut bounding_boxes = self.bounding_boxes.lock(); + bounding_boxes.clear(); + for (ix, child) in self.children.into_iter().enumerate() { - let origin = - origin.apply_along(self.axis, |val| val + child_size.along(self.axis) * ix); - child.draw(origin, child_size.into(), cx); + //todo!(active_pane_magnification) + // If usign active pane magnification, need to switch to using + // 1 for all non-active panes, and then the magnification for the + // active pane. + let child_size = bounds + .size + .apply_along(self.axis, |_| space_per_flex * flexes[ix]); + + let child_bounds = Bounds { + origin, + size: child_size, + }; + bounding_boxes.push(Some(child_bounds)); + cx.with_z_index(0, |cx| { + child.draw(origin, child_size.into(), cx); + }); + cx.with_z_index(1, |cx| { + if ix < len - 1 { + Self::push_handle( + self.flexes.clone(), + self.axis, + ix, + child_bounds, + bounds, + cx, + ); + } + }); + + origin = origin.apply_along(self.axis, |val| val + child_size.along(self.axis)); } } } @@ -804,6 +954,9 @@ mod element { } } + fn flex_values_in_bounds(flexes: &[f32]) -> bool { + (flexes.iter().copied().sum::() - flexes.len() as f32).abs() < 0.001 + } // // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc}; // // use gpui::{ diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index 251f0685b0..72c9fb8aa2 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -2015,7 +2015,7 @@ impl Workspace { }; let cursor = self.active_pane.read(cx).pixel_position_of_cursor(cx); let center = match cursor { - Some(cursor) if bounding_box.contains_point(&cursor) => cursor, + Some(cursor) if bounding_box.contains(&cursor) => cursor, _ => bounding_box.center(), }; From 0ee61e214de67b53216ffd2b9a4022883220188a Mon Sep 17 00:00:00 2001 From: Mikayla Date: Fri, 8 Dec 2023 17:02:25 -0800 Subject: [PATCH 3/5] Fix drag events --- crates/workspace2/src/pane_group.rs | 40 +++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/crates/workspace2/src/pane_group.rs b/crates/workspace2/src/pane_group.rs index 4865a40a57..9dc4e84c00 100644 --- a/crates/workspace2/src/pane_group.rs +++ b/crates/workspace2/src/pane_group.rs @@ -696,11 +696,11 @@ impl SplitDirection { mod element { - use std::{iter, sync::Arc}; + use std::{cell::RefCell, iter, rc::Rc, sync::Arc}; use gpui::{ px, relative, Along, AnyElement, Axis, Bounds, CursorStyle, Element, IntoElement, - MouseMoveEvent, ParentElement, Pixels, Style, WindowContext, + MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Style, WindowContext, }; use parking_lot::Mutex; use smallvec::SmallVec; @@ -789,13 +789,11 @@ mod element { } }); - while dbg!(proposed_current_pixel_change).abs() > px(0.) { + while proposed_current_pixel_change.abs() > px(0.) { let Some(current_ix) = successors.next() else { break; }; - dbg!(current_ix); - let next_target_size = Pixels::max( size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change, min_size, @@ -826,6 +824,7 @@ mod element { fn push_handle( flexes: Arc>>, + dragged_handle: Rc>>, axis: Axis, ix: usize, pane_bounds: Bounds, @@ -859,8 +858,17 @@ mod element { gpui::red(), ); + cx.on_mouse_event({ + let dragged_handle = dragged_handle.clone(); + move |e: &MouseDownEvent, phase, cx| { + if phase.bubble() && handle_bounds.contains(&e.position) { + dragged_handle.replace(Some(ix)); + } + } + }); cx.on_mouse_event(move |e: &MouseMoveEvent, phase, cx| { - if phase.bubble() && e.dragging() && handle_bounds.contains(&e.position) { + let dragged_handle = dragged_handle.borrow(); + if *dragged_handle == Some(ix) { Self::compute_resize(&flexes, e, ix, axis, axis_bounds, cx) } }); @@ -872,7 +880,7 @@ mod element { type Element = Self; fn element_id(&self) -> Option { - Some("pane axis".into()) + Some(self.basis.into()) } fn into_element(self) -> Self::Element { @@ -881,7 +889,7 @@ mod element { } impl Element for PaneAxisElement { - type State = (); + type State = Rc>>; fn layout( &mut self, @@ -892,8 +900,8 @@ mod element { style.size.width = relative(1.).into(); style.size.height = relative(1.).into(); let layout_id = cx.request_layout(&style, None); - - (layout_id, ()) + let dragged_pane = state.unwrap_or_else(|| Rc::new(RefCell::new(None))); + (layout_id, dragged_pane) } fn paint( @@ -934,6 +942,7 @@ mod element { if ix < len - 1 { Self::push_handle( self.flexes.clone(), + state.clone(), self.axis, ix, child_bounds, @@ -945,6 +954,17 @@ mod element { origin = origin.apply_along(self.axis, |val| val + child_size.along(self.axis)); } + + cx.with_z_index(1, |cx| { + cx.on_mouse_event({ + let state = state.clone(); + move |e: &MouseUpEvent, phase, cx| { + if phase.bubble() { + state.replace(None); + } + } + }); + }) } } From f03c0f6e6386c6aeff9b94c699c44205b328c448 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Mon, 11 Dec 2023 13:17:42 -0800 Subject: [PATCH 4/5] Add double click handling --- crates/gpui2/src/app.rs | 4 ++ crates/gpui2/src/platform.rs | 1 + crates/gpui2/src/platform/mac/platform.rs | 8 ++++ crates/gpui2/src/platform/test/platform.rs | 5 ++ crates/workspace2/src/dock.rs | 53 +++++++++++++++++++-- crates/workspace2/src/workspace2.rs | 54 +++++++++++++++++++--- 6 files changed, 115 insertions(+), 10 deletions(-) diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 842ac0b704..0d70458d37 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -514,6 +514,10 @@ impl AppContext { self.platform.path_for_auxiliary_executable(name) } + pub fn double_click_interval(&self) -> Duration { + self.platform.double_click_interval() + } + pub fn prompt_for_paths( &self, options: PathPromptOptions, diff --git a/crates/gpui2/src/platform.rs b/crates/gpui2/src/platform.rs index 006640af4f..2442841f05 100644 --- a/crates/gpui2/src/platform.rs +++ b/crates/gpui2/src/platform.rs @@ -102,6 +102,7 @@ pub(crate) trait Platform: 'static { fn app_version(&self) -> Result; fn app_path(&self) -> Result; fn local_timezone(&self) -> UtcOffset; + fn double_click_interval(&self) -> Duration; fn path_for_auxiliary_executable(&self, name: &str) -> Result; fn set_cursor_style(&self, style: CursorStyle); diff --git a/crates/gpui2/src/platform/mac/platform.rs b/crates/gpui2/src/platform/mac/platform.rs index 2deea545e1..6b6c023752 100644 --- a/crates/gpui2/src/platform/mac/platform.rs +++ b/crates/gpui2/src/platform/mac/platform.rs @@ -48,6 +48,7 @@ use std::{ rc::Rc, slice, str, sync::Arc, + time::Duration, }; use time::UtcOffset; @@ -650,6 +651,13 @@ impl Platform for MacPlatform { "macOS" } + fn double_click_interval(&self) -> Duration { + unsafe { + let double_click_interval: f64 = msg_send![class!(NSEvent), doubleClickInterval]; + Duration::from_secs_f64(double_click_interval) + } + } + fn os_version(&self) -> Result { unsafe { let process_info = NSProcessInfo::processInfo(nil); diff --git a/crates/gpui2/src/platform/test/platform.rs b/crates/gpui2/src/platform/test/platform.rs index 876120b626..751cc4f753 100644 --- a/crates/gpui2/src/platform/test/platform.rs +++ b/crates/gpui2/src/platform/test/platform.rs @@ -11,6 +11,7 @@ use std::{ path::PathBuf, rc::{Rc, Weak}, sync::Arc, + time::Duration, }; pub struct TestPlatform { @@ -272,4 +273,8 @@ impl Platform for TestPlatform { fn delete_credentials(&self, _url: &str) -> Result<()> { Ok(()) } + + fn double_click_interval(&self) -> std::time::Duration { + Duration::from_millis(500) + } } diff --git a/crates/workspace2/src/dock.rs b/crates/workspace2/src/dock.rs index 817a89df9e..672484d3b5 100644 --- a/crates/workspace2/src/dock.rs +++ b/crates/workspace2/src/dock.rs @@ -1,8 +1,9 @@ use crate::{status_bar::StatusItemView, Workspace}; +use crate::{DockClickReset, DockDragState}; use gpui::{ - div, px, Action, AnchorCorner, AnyView, AppContext, Axis, Div, Entity, EntityId, EventEmitter, - FocusHandle, FocusableView, IntoElement, ParentElement, Render, SharedString, Styled, - Subscription, View, ViewContext, VisualContext, WeakView, WindowContext, + div, px, Action, AnchorCorner, AnyView, AppContext, Axis, ClickEvent, Div, Entity, EntityId, + EventEmitter, FocusHandle, FocusableView, IntoElement, MouseButton, ParentElement, Render, + SharedString, Styled, Subscription, View, ViewContext, VisualContext, WeakView, WindowContext, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -364,7 +365,7 @@ impl Dock { this.set_open(false, cx); } } - PanelEvent::Focus => todo!(), + PanelEvent::Focus => {} }), ]; @@ -485,6 +486,48 @@ impl Render for Dock { if let Some(entry) = self.visible_entry() { let size = entry.panel.size(cx); + let mut pre_resize_handle = None; + let mut post_resize_handle = None; + let position = self.position; + let handler = div() + .id("resize-handle") + .bg(gpui::red()) + .on_mouse_down(gpui::MouseButton::Left, move |_, cx| { + cx.update_global(|drag: &mut DockDragState, cx| drag.0 = Some(position)) + }) + .on_click(cx.listener(|v, e: &ClickEvent, cx| { + if e.down.button == MouseButton::Left { + cx.update_global(|state: &mut DockClickReset, cx| { + if state.0.is_some() { + state.0 = None; + v.resize_active_panel(None, cx) + } else { + let double_click = cx.double_click_interval(); + let timer = cx.background_executor().timer(double_click); + state.0 = Some(cx.spawn(|_, mut cx| async move { + timer.await; + cx.update_global(|state: &mut DockClickReset, cx| { + state.0 = None; + }) + .ok(); + })); + } + }) + } + })); + + match self.position() { + DockPosition::Left => { + post_resize_handle = Some(handler.w_2().h_full().cursor_col_resize()) + } + DockPosition::Bottom => { + pre_resize_handle = Some(handler.w_full().h_2().cursor_row_resize()) + } + DockPosition::Right => { + pre_resize_handle = Some(handler.w_full().h_1().cursor_col_resize()) + } + } + div() .border_color(cx.theme().colors().border) .map(|this| match self.position().axis() { @@ -496,7 +539,9 @@ impl Render for Dock { DockPosition::Right => this.border_l(), DockPosition::Bottom => this.border_t(), }) + .children(pre_resize_handle) .child(entry.panel.to_any()) + .children(post_resize_handle) } else { div() } diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index 409798573e..43aa13847d 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -29,12 +29,12 @@ use futures::{ Future, FutureExt, StreamExt, }; use gpui::{ - actions, div, impl_actions, point, size, Action, AnyModel, AnyView, AnyWeakView, + actions, canvas, div, impl_actions, point, size, Action, AnyModel, AnyView, AnyWeakView, AnyWindowHandle, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Context, Div, Entity, EntityId, EventEmitter, FocusHandle, FocusableView, GlobalPixels, InteractiveElement, - KeyContext, ManagedView, Model, ModelContext, ParentElement, PathPromptOptions, Point, - PromptLevel, Render, Size, Styled, Subscription, Task, View, ViewContext, VisualContext, - WeakView, WindowBounds, WindowContext, WindowHandle, WindowOptions, + KeyContext, ManagedView, Model, ModelContext, MouseMoveEvent, ParentElement, PathPromptOptions, + Pixels, Point, PromptLevel, Render, Size, Styled, Subscription, Task, View, ViewContext, + VisualContext, WeakView, WindowBounds, WindowContext, WindowHandle, WindowOptions, }; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem}; use itertools::Itertools; @@ -227,6 +227,9 @@ pub fn init_settings(cx: &mut AppContext) { } pub fn init(app_state: Arc, cx: &mut AppContext) { + cx.default_global::(); + cx.default_global::(); + init_settings(cx); notifications::init(cx); @@ -480,8 +483,6 @@ struct FollowerState { items_by_leader_view_id: HashMap>, } -enum WorkspaceBounds {} - impl Workspace { pub fn new( workspace_id: WorkspaceId, @@ -3571,6 +3572,16 @@ impl FocusableView for Workspace { } } +struct WorkspaceBounds(Bounds); + +//todo!("remove this when better drag APIs are in GPUI2") +#[derive(Default)] +struct DockDragState(Option); + +//todo!("remove this when better double APIs are in GPUI2") +#[derive(Default)] +struct DockClickReset(Option>); + impl Render for Workspace { type Element = Div; @@ -3614,6 +3625,37 @@ impl Render for Workspace { .border_t() .border_b() .border_color(cx.theme().colors().border) + .on_mouse_up(gpui::MouseButton::Left, |_, cx| { + cx.update_global(|drag: &mut DockDragState, cx| { + drag.0 = None; + }) + }) + .on_mouse_move(cx.listener(|workspace, e: &MouseMoveEvent, cx| { + if let Some(types) = &cx.global::().0 { + let workspace_bounds = cx.global::().0; + match types { + DockPosition::Left => { + let size = e.position.x; + workspace.left_dock.update(cx, |left_dock, cx| { + left_dock.resize_active_panel(Some(size.0), cx); + }); + } + DockPosition::Right => { + let size = workspace_bounds.size.width - e.position.x; + workspace.right_dock.update(cx, |right_dock, cx| { + right_dock.resize_active_panel(Some(size.0), cx); + }); + } + DockPosition::Bottom => { + let size = workspace_bounds.size.height - e.position.y; + workspace.bottom_dock.update(cx, |bottom_dock, cx| { + bottom_dock.resize_active_panel(Some(size.0), cx); + }); + } + } + } + })) + .child(canvas(|bounds, cx| cx.set_global(WorkspaceBounds(bounds)))) .child(self.modal_layer.clone()) .child( div() From cb8109ab98c654d557fc648947f426b8ae4f5247 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Mon, 11 Dec 2023 13:23:07 -0800 Subject: [PATCH 5/5] Remove some debug styles --- crates/workspace2/src/dock.rs | 6 +++--- crates/workspace2/src/pane_group.rs | 9 --------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/crates/workspace2/src/dock.rs b/crates/workspace2/src/dock.rs index 672484d3b5..e8840fb172 100644 --- a/crates/workspace2/src/dock.rs +++ b/crates/workspace2/src/dock.rs @@ -491,7 +491,7 @@ impl Render for Dock { let position = self.position; let handler = div() .id("resize-handle") - .bg(gpui::red()) + .bg(cx.theme().colors().border) .on_mouse_down(gpui::MouseButton::Left, move |_, cx| { cx.update_global(|drag: &mut DockDragState, cx| drag.0 = Some(position)) }) @@ -518,10 +518,10 @@ impl Render for Dock { match self.position() { DockPosition::Left => { - post_resize_handle = Some(handler.w_2().h_full().cursor_col_resize()) + post_resize_handle = Some(handler.w_1().h_full().cursor_col_resize()) } DockPosition::Bottom => { - pre_resize_handle = Some(handler.w_full().h_2().cursor_row_resize()) + pre_resize_handle = Some(handler.w_full().h_1().cursor_row_resize()) } DockPosition::Right => { pre_resize_handle = Some(handler.w_full().h_1().cursor_col_resize()) diff --git a/crates/workspace2/src/pane_group.rs b/crates/workspace2/src/pane_group.rs index 9dc4e84c00..5f14df833d 100644 --- a/crates/workspace2/src/pane_group.rs +++ b/crates/workspace2/src/pane_group.rs @@ -626,7 +626,6 @@ impl PaneAxis { Member::Pane(pane) => div() .size_full() .border() - .border_color(gpui::green()) .child(pane.clone()) .into_any_element(), } @@ -850,14 +849,6 @@ mod element { cx.add_opaque_layer(handle_bounds); - cx.paint_quad( - handle_bounds, - Default::default(), - gpui::red(), - Default::default(), - gpui::red(), - ); - cx.on_mouse_event({ let dragged_handle = dragged_handle.clone(); move |e: &MouseDownEvent, phase, cx| {