Begin porting the PaneAxis element
This commit is contained in:
parent
c7e19c0bcd
commit
25df11dd26
8 changed files with 564 additions and 407 deletions
|
@ -57,8 +57,12 @@ where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
E: 'static + Debug,
|
E: 'static + Debug,
|
||||||
{
|
{
|
||||||
|
#[track_caller]
|
||||||
pub fn detach_and_log_err(self, cx: &mut AppContext) {
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,54 @@ use std::{
|
||||||
ops::{Add, Div, Mul, MulAssign, Sub},
|
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<i32> {
|
||||||
|
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.
|
/// Describes a location in a 2D cartesian coordinate space.
|
||||||
///
|
///
|
||||||
/// It holds two public fields, `x` and `y`, which represent the coordinates in the space.
|
/// It holds two public fields, `x` and `y`, which represent the coordinates in the space.
|
||||||
|
@ -94,6 +142,19 @@ impl<T: Clone + Debug + Default> Point<T> {
|
||||||
y: f(self.y.clone()),
|
y: f(self.y.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn apply_along(&self, axis: Axis, f: impl FnOnce(T) -> T) -> Point<T> {
|
||||||
|
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<Pixels> {
|
impl Point<Pixels> {
|
||||||
|
@ -373,6 +434,32 @@ impl Size<Pixels> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Size<T>
|
||||||
|
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<T> Size<T>
|
impl<T> Size<T>
|
||||||
where
|
where
|
||||||
T: PartialOrd + Clone + Default + Debug,
|
T: PartialOrd + Clone + Default + Debug,
|
||||||
|
|
|
@ -477,3 +477,12 @@ impl From<Pixels> for AvailableSpace {
|
||||||
AvailableSpace::Definite(pixels)
|
AvailableSpace::Definite(pixels)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Size<Pixels>> for Size<AvailableSpace> {
|
||||||
|
fn from(size: Size<Pixels>) -> Self {
|
||||||
|
Size {
|
||||||
|
width: AvailableSpace::Definite(size.width),
|
||||||
|
height: AvailableSpace::Definite(size.height),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -184,6 +184,11 @@ pub trait TryFutureExt {
|
||||||
fn log_err(self) -> LogErrorFuture<Self>
|
fn log_err(self) -> LogErrorFuture<Self>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
|
fn log_tracked_err(self, location: core::panic::Location<'static>) -> LogErrorFuture<Self>
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
fn warn_on_err(self) -> LogErrorFuture<Self>
|
fn warn_on_err(self) -> LogErrorFuture<Self>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
@ -197,18 +202,29 @@ where
|
||||||
F: Future<Output = Result<T, E>>,
|
F: Future<Output = Result<T, E>>,
|
||||||
E: std::fmt::Debug,
|
E: std::fmt::Debug,
|
||||||
{
|
{
|
||||||
|
#[track_caller]
|
||||||
fn log_err(self) -> LogErrorFuture<Self>
|
fn log_err(self) -> LogErrorFuture<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
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<Self>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
LogErrorFuture(self, log::Level::Error, location)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
fn warn_on_err(self) -> LogErrorFuture<Self>
|
fn warn_on_err(self) -> LogErrorFuture<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
LogErrorFuture(self, log::Level::Warn)
|
let location = Location::caller();
|
||||||
|
LogErrorFuture(self, log::Level::Warn, *location)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unwrap(self) -> UnwrapFuture<Self>
|
fn unwrap(self) -> UnwrapFuture<Self>
|
||||||
|
@ -219,7 +235,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LogErrorFuture<F>(F, log::Level);
|
pub struct LogErrorFuture<F>(F, log::Level, core::panic::Location<'static>);
|
||||||
|
|
||||||
impl<F, T, E> Future for LogErrorFuture<F>
|
impl<F, T, E> Future for LogErrorFuture<F>
|
||||||
where
|
where
|
||||||
|
@ -230,12 +246,19 @@ where
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||||
let level = self.1;
|
let level = self.1;
|
||||||
|
let location = self.2;
|
||||||
let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) };
|
let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) };
|
||||||
match inner.poll(cx) {
|
match inner.poll(cx) {
|
||||||
Poll::Ready(output) => Poll::Ready(match output {
|
Poll::Ready(output) => Poll::Ready(match output {
|
||||||
Ok(output) => Some(output),
|
Ok(output) => Some(output),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::log!(level, "{:?}", error);
|
log::log!(
|
||||||
|
level,
|
||||||
|
"{}:{}: {:?}",
|
||||||
|
location.file(),
|
||||||
|
location.line(),
|
||||||
|
error
|
||||||
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{status_bar::StatusItemView, Axis, Workspace};
|
use crate::{status_bar::StatusItemView, Workspace};
|
||||||
use gpui::{
|
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,
|
FocusHandle, FocusableView, IntoElement, ParentElement, Render, SharedString, Styled,
|
||||||
Subscription, View, ViewContext, VisualContext, WeakView, WindowContext,
|
Subscription, View, ViewContext, VisualContext, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
use crate::{AppState, FollowerState, Pane, Workspace};
|
use crate::{pane_group::element::pane_axis, AppState, FollowerState, Pane, Workspace};
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use call::{ActiveCall, ParticipantLocation};
|
use call::{ActiveCall, ParticipantLocation};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use db::sqlez::{
|
|
||||||
bindable::{Bind, Column, StaticColumnCount},
|
|
||||||
statement::Statement,
|
|
||||||
};
|
|
||||||
use gpui::{
|
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,
|
ViewContext,
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
@ -20,38 +16,6 @@ const HANDLE_HITBOX_SIZE: f32 = 4.0;
|
||||||
const HORIZONTAL_MIN_SIZE: f32 = 80.;
|
const HORIZONTAL_MIN_SIZE: f32 = 80.;
|
||||||
const VERTICAL_MIN_SIZE: f32 = 100.;
|
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<i32> {
|
|
||||||
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)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct PaneGroup {
|
pub struct PaneGroup {
|
||||||
pub(crate) root: Member,
|
pub(crate) root: Member,
|
||||||
|
@ -632,16 +596,10 @@ impl PaneAxis {
|
||||||
zoomed: Option<&AnyWeakView>,
|
zoomed: Option<&AnyWeakView>,
|
||||||
app_state: &Arc<AppState>,
|
app_state: &Arc<AppState>,
|
||||||
cx: &mut ViewContext<Workspace>,
|
cx: &mut ViewContext<Workspace>,
|
||||||
) -> Div {
|
) -> gpui::AnyElement {
|
||||||
debug_assert!(self.members.len() == self.flexes.lock().len());
|
debug_assert!(self.members.len() == self.flexes.lock().len());
|
||||||
|
|
||||||
div()
|
pane_axis(self.axis, basis, self.flexes.clone())
|
||||||
.flex()
|
|
||||||
.flex_auto()
|
|
||||||
.map(|s| match self.axis {
|
|
||||||
Axis::Vertical => s.flex_col(),
|
|
||||||
Axis::Horizontal => s.flex_row(),
|
|
||||||
})
|
|
||||||
.children(self.members.iter().enumerate().map(|(ix, member)| {
|
.children(self.members.iter().enumerate().map(|(ix, member)| {
|
||||||
match member {
|
match member {
|
||||||
Member::Axis(axis) => axis
|
Member::Axis(axis) => axis
|
||||||
|
@ -658,6 +616,7 @@ impl PaneAxis {
|
||||||
Member::Pane(pane) => pane.clone().into_any_element(),
|
Member::Pane(pane) => pane.clone().into_any_element(),
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
.into_any_element()
|
||||||
|
|
||||||
// let mut pane_axis = PaneAxisElement::new(
|
// let mut pane_axis = PaneAxisElement::new(
|
||||||
// self.axis,
|
// self.axis,
|
||||||
|
@ -767,7 +726,84 @@ impl SplitDirection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// mod element {
|
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<Mutex<Vec<f32>>>) -> PaneAxisElement {
|
||||||
|
PaneAxisElement {
|
||||||
|
axis,
|
||||||
|
basis,
|
||||||
|
flexes,
|
||||||
|
children: SmallVec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PaneAxisElement {
|
||||||
|
axis: Axis,
|
||||||
|
basis: usize,
|
||||||
|
flexes: Arc<Mutex<Vec<f32>>>,
|
||||||
|
children: SmallVec<[AnyElement; 2]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoElement for PaneAxisElement {
|
||||||
|
type Element = Self;
|
||||||
|
|
||||||
|
fn element_id(&self) -> Option<ui::prelude::ElementId> {
|
||||||
|
Some("pane axis".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_element(self) -> Self::Element {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Element for PaneAxisElement {
|
||||||
|
type State = ();
|
||||||
|
|
||||||
|
fn layout(
|
||||||
|
&mut self,
|
||||||
|
state: Option<Self::State>,
|
||||||
|
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<ui::prelude::Pixels>,
|
||||||
|
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 std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc};
|
||||||
|
|
||||||
// // use gpui::{
|
// // use gpui::{
|
||||||
|
@ -1166,4 +1202,4 @@ impl SplitDirection {
|
||||||
// })
|
// })
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
}
|
||||||
|
|
|
@ -6,12 +6,12 @@ use std::path::Path;
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
|
use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
|
||||||
use gpui::WindowBounds;
|
use gpui::{Axis, WindowBounds};
|
||||||
|
|
||||||
use util::{unzip_option, ResultExt};
|
use util::{unzip_option, ResultExt};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{Axis, WorkspaceId};
|
use crate::WorkspaceId;
|
||||||
|
|
||||||
use model::{
|
use model::{
|
||||||
GroupId, PaneId, SerializedItem, SerializedPane, SerializedPaneGroup, SerializedWorkspace,
|
GroupId, PaneId, SerializedItem, SerializedPane, SerializedPaneGroup, SerializedWorkspace,
|
||||||
|
@ -403,7 +403,7 @@ impl WorkspaceDb {
|
||||||
.map(|(group_id, axis, pane_id, active, flexes)| {
|
.map(|(group_id, axis, pane_id, active, flexes)| {
|
||||||
if let Some((group_id, axis)) = group_id.zip(axis) {
|
if let Some((group_id, axis)) = group_id.zip(axis) {
|
||||||
let flexes = flexes
|
let flexes = flexes
|
||||||
.map(|flexes| serde_json::from_str::<Vec<f32>>(&flexes))
|
.map(|flexes: String| serde_json::from_str::<Vec<f32>>(&flexes))
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
|
||||||
Ok(SerializedPaneGroup::Group {
|
Ok(SerializedPaneGroup::Group {
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
use crate::{
|
use crate::{item::ItemHandle, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId};
|
||||||
item::ItemHandle, Axis, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId,
|
|
||||||
};
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use async_recursion::async_recursion;
|
use async_recursion::async_recursion;
|
||||||
use db::sqlez::{
|
use db::sqlez::{
|
||||||
bindable::{Bind, Column, StaticColumnCount},
|
bindable::{Bind, Column, StaticColumnCount},
|
||||||
statement::Statement,
|
statement::Statement,
|
||||||
};
|
};
|
||||||
use gpui::{AsyncWindowContext, Model, Task, View, WeakView, WindowBounds};
|
use gpui::{AsyncWindowContext, Axis, Model, Task, View, WeakView, WindowBounds};
|
||||||
use project::Project;
|
use project::Project;
|
||||||
use std::{
|
use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue