Add support for resizing splits and docks, as well as utilities (#3595)
Making this PR to upstream changes to util and GPUI2, resizing exists but isn't working yet. Release Notes: - N/A
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
use crate::{status_bar::StatusItemView, Axis, Workspace};
|
||||
use crate::{status_bar::StatusItemView, Workspace};
|
||||
use crate::{DockClickReset, DockDragState};
|
||||
use gpui::{
|
||||
div, px, Action, AnchorCorner, AnyView, AppContext, 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(cx.theme().colors().border)
|
||||
.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_1().h_full().cursor_col_resize())
|
||||
}
|
||||
DockPosition::Bottom => {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -1046,10 +1046,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(())
|
||||
})
|
||||
}
|
||||
|
||||
+658
-458
File diff suppressed because it is too large
Load Diff
@@ -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::<Vec<f32>>(&flexes))
|
||||
.map(|flexes: String| serde_json::from_str::<Vec<f32>>(&flexes))
|
||||
.transpose()?;
|
||||
|
||||
Ok(SerializedPaneGroup::Group {
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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<AppState>, cx: &mut AppContext) {
|
||||
cx.default_global::<DockDragState>();
|
||||
cx.default_global::<DockClickReset>();
|
||||
|
||||
init_settings(cx);
|
||||
notifications::init(cx);
|
||||
|
||||
@@ -480,8 +483,6 @@ struct FollowerState {
|
||||
items_by_leader_view_id: HashMap<ViewId, Box<dyn FollowableItemHandle>>,
|
||||
}
|
||||
|
||||
enum WorkspaceBounds {}
|
||||
|
||||
impl Workspace {
|
||||
pub fn new(
|
||||
workspace_id: WorkspaceId,
|
||||
@@ -2032,7 +2033,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(),
|
||||
};
|
||||
|
||||
@@ -3571,6 +3572,16 @@ impl FocusableView for Workspace {
|
||||
}
|
||||
}
|
||||
|
||||
struct WorkspaceBounds(Bounds<Pixels>);
|
||||
|
||||
//todo!("remove this when better drag APIs are in GPUI2")
|
||||
#[derive(Default)]
|
||||
struct DockDragState(Option<DockPosition>);
|
||||
|
||||
//todo!("remove this when better double APIs are in GPUI2")
|
||||
#[derive(Default)]
|
||||
struct DockClickReset(Option<Task<()>>);
|
||||
|
||||
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::<DockDragState>().0 {
|
||||
let workspace_bounds = cx.global::<WorkspaceBounds>().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()
|
||||
|
||||
Reference in New Issue
Block a user