diff --git a/crates/gpui2/src/executor.rs b/crates/gpui2/src/executor.rs index e01846c404f0781ebe01d4657f624fe2d00b343b..81fa6e64caa16daa14f76c50458771f641717f32 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 50f680f493cae5ee2c2d634c982ad30b357f5880..4a13fa83f63186dbe6ff381090272a20b702adde 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 2bceb1bc139be7af1aedc67827da582f319bfc87..b4fc6c3abef84857a13d2cf47009ae5b175a1f5e 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 aacec422feb7569d6d7f48e53c6c98a4fb8f1117..3f2371121ccb2c8de641d0d7f4c8b7175ac6ba72 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 7bae7bc4199631f0b538a99d45ecb6e1d7a4aaa5..0640389189232a921738160c205e0e9bab5424ce 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 66465a4982895e3ed22b8b76d288464b1e54e100..398f57bf6f8f198cc9f67ac748e3cee8f8887b7d 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}; - -// // 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 crate::{ -// pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE}, -// Workspace, WorkspaceSettings, -// }; - -// pub struct PaneAxisElement { -// axis: Axis, -// basis: usize, -// active_pane_ix: Option, -// flexes: Rc>>, -// children: Vec>, -// bounding_boxes: Rc>>>>, -// } - -// 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(), -// } -// } - -// pub fn set_active_pane(&mut self, active_pane_ix: Option) { -// self.active_pane_ix = active_pane_ix; -// } - -// 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 child_size = if *remaining_flex == 0.0 { -// *remaining_space -// } else { -// let space_per_flex = *remaining_space / *remaining_flex; -// space_per_flex * flex -// }; - -// 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 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) -// }; - -// 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(); - -// // 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 mut proposed_current_pixel_change = (drag.position - child_start).along(axis) -// - size(preceding_ix, flexes.as_slice()); - -// 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) -// }; - -// 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) -// }; - -// ix_offset += 1; - -// result -// } -// }); - -// while proposed_current_pixel_change.abs() > 0. { -// let Some(current_ix) = successors.next() else { -// break; -// }; - -// let next_target_size = f32::max( -// size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change, -// min_size, -// ); - -// let current_target_size = f32::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; -// } - -// workspace.schedule_serialize(cx); -// cx.notify(); -// } -// } -// } - -// impl Extend> for PaneAxisElement { -// fn extend>>(&mut self, children: T) { -// self.children.extend(children); -// } -// } - -// impl Element for PaneAxisElement { -// type LayoutState = f32; -// type PaintState = (); - -// 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 active_pane_magnification = -// settings::get::(cx).active_pane_magnification; - -// let mut remaining_flex = 0.; - -// 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() { -// panic!("flex contains flexible children but has an infinite constraint along the flex axis"); -// } - -// self.layout_children( -// active_pane_magnification, -// 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, -// 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(); - -// let overflowing = *remaining_space < 0.; -// if overflowing { -// cx.scene().push_layer(Some(visible_bounds)); -// } - -// let mut child_origin = bounds.origin(); - -// 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::>() -// }) -// } -// } -// } +mod element { + use std::sync::Arc; + + use gpui::{relative, AnyElement, Axis, Element, IntoElement, ParentElement, Style}; + use parking_lot::Mutex; + use smallvec::SmallVec; + + 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, + flexes: Arc>>, + children: SmallVec<[AnyElement; 2]>, + } + + impl IntoElement for PaneAxisElement { + type Element = Self; + + fn element_id(&self) -> Option { + Some("pane axis".into()) + } + + fn into_element(self) -> Self::Element { + self + } + } + + impl Element for PaneAxisElement { + type State = (); + + 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); + + (layout_id, ()) + } + + 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()); + + 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); + } + } + } + + impl ParentElement for PaneAxisElement { + fn children_mut(&mut self) -> &mut smallvec::SmallVec<[AnyElement; 2]> { + &mut self.children + } + } + + // // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc}; + + // // 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 crate::{ + // pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE}, + // Workspace, WorkspaceSettings, + // }; + + // pub struct PaneAxisElement { + // axis: Axis, + // basis: usize, + // active_pane_ix: Option, + // flexes: Rc>>, + // children: Vec>, + // bounding_boxes: Rc>>>>, + // } + + // 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(), + // } + // } + + // pub fn set_active_pane(&mut self, active_pane_ix: Option) { + // self.active_pane_ix = active_pane_ix; + // } + + // 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 child_size = if *remaining_flex == 0.0 { + // *remaining_space + // } else { + // let space_per_flex = *remaining_space / *remaining_flex; + // space_per_flex * flex + // }; + + // 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 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) + // }; + + // 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(); + + // // 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 mut proposed_current_pixel_change = (drag.position - child_start).along(axis) + // - size(preceding_ix, flexes.as_slice()); + + // 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) + // }; + + // 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) + // }; + + // ix_offset += 1; + + // result + // } + // }); + + // while proposed_current_pixel_change.abs() > 0. { + // let Some(current_ix) = successors.next() else { + // break; + // }; + + // let next_target_size = f32::max( + // size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change, + // min_size, + // ); + + // let current_target_size = f32::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; + // } + + // workspace.schedule_serialize(cx); + // cx.notify(); + // } + // } + // } + + // impl Extend> for PaneAxisElement { + // fn extend>>(&mut self, children: T) { + // self.children.extend(children); + // } + // } + + // impl Element for PaneAxisElement { + // type LayoutState = f32; + // type PaintState = (); + + // 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 active_pane_magnification = + // settings::get::(cx).active_pane_magnification; + + // let mut remaining_flex = 0.; + + // 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() { + // panic!("flex contains flexible children but has an infinite constraint along the flex axis"); + // } + + // self.layout_children( + // active_pane_magnification, + // 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, + // 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(); + + // let overflowing = *remaining_space < 0.; + // if overflowing { + // cx.scene().push_layer(Some(visible_bounds)); + // } + + // let mut child_origin = bounds.origin(); + + // 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 b84235599192b7d9040b1b1706694d43173f1554..1abb06dccfa712c97b626dafd1e8c1feb251ddb6 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 74304d3c8e43b80f6ee35735bae449ad883ff3a4..f204e5152c30fbcf0dc2a6ab9594d1c5a8af4d57 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},