Fix Resizable drag move position. #28 (#41)

This commit is contained in:
Jason Lee 2024-07-18 00:02:59 +08:00 committed by GitHub
parent 0fdf7be40d
commit 683b22c4a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 77 additions and 53 deletions

View file

@ -1,12 +1,12 @@
use std::rc::Rc; use std::rc::Rc;
use gpui::{ use gpui::{
canvas, deferred, div, prelude::FluentBuilder as _, px, AnyElement, AnyView, Axis, Bounds, canvas, div, prelude::FluentBuilder as _, px, AnyElement, AnyView, Axis, Bounds, DragMoveEvent,
DragMoveEvent, EntityId, InteractiveElement as _, IntoElement, ParentElement, Pixels, Render, EntityId, InteractiveElement as _, IntoElement, ParentElement, Pixels, Render,
StatefulInteractiveElement, Styled, View, ViewContext, VisualContext as _, WindowContext, StatefulInteractiveElement, Styled, View, ViewContext, VisualContext as _, WindowContext,
}; };
use crate::{h_flex, theme::ActiveTheme, v_flex}; use crate::{h_flex, styled_ext::AxisExt, theme::ActiveTheme, v_flex};
#[derive(Clone, Render)] #[derive(Clone, Render)]
pub struct DragPanel(pub (EntityId, usize, Axis)); pub struct DragPanel(pub (EntityId, usize, Axis));
@ -78,68 +78,79 @@ impl ResizablePanelGroup {
let axis = self.axis; let axis = self.axis;
let handle_size = self.handle_size; let handle_size = self.handle_size;
deferred( div()
div() .id(("resizable-handle", ix))
.id(("resizable-handle", ix)) .occlude()
.occlude() .hover(|this| this.bg(cx.theme().drag_border))
.hover(|this| this.bg(cx.theme().drag_border)) .on_drag_move(cx.listener(
.on_drag_move(cx.listener(move |view, e: &DragMoveEvent<DragPanel>, cx| { move |view, e: &DragMoveEvent<DragPanel>, cx| match e.drag(cx) {
match e.drag(cx) { DragPanel((entity_id, ix, axis)) => {
DragPanel((entity_id, ix, axis)) => { if cx.entity_id() != *entity_id {
let ix = *ix; return;
if cx.entity_id() != *entity_id { }
return;
let ix = *ix;
let panel = view
.panels
.get(ix)
.expect("BUG: invalid panel index")
.read(cx);
view.sync_real_panel_sizes(cx);
match axis {
Axis::Horizontal => {
view.resize_panels(ix, e.event.position.x - panel.bounds.left(), cx)
} }
Axis::Vertical => {
let panel = view view.resize_panels(ix, e.event.position.y - panel.bounds.top(), cx);
.panels
.get(ix)
.expect("BUG: invalid panel index")
.read(cx);
match axis {
Axis::Horizontal => {
let size = e.event.position.x - panel.bounds.left();
view.resize_panels(ix, size, cx)
}
Axis::Vertical => {
let size = e.event.position.y - panel.bounds.top();
view.resize_panels(ix, size, cx);
}
} }
} }
} }
})) },
.when(self.axis == Axis::Horizontal, |this| { ))
this.cursor_col_resize().top_0().w(handle_size).h_full() .when(self.axis.is_horizontal(), |this| {
}) this.cursor_col_resize().top_0().h_full().w(handle_size)
.when(self.axis == Axis::Vertical, |this| { })
this.cursor_row_resize().left_0().w_full().h(handle_size) .when(self.axis.is_vertical(), |this| {
}) this.cursor_row_resize().left_0().w_full().h(handle_size)
.on_drag(DragPanel((cx.entity_id(), ix, axis)), |drag_panel, cx| { })
cx.stop_propagation(); .on_drag(DragPanel((cx.entity_id(), ix, axis)), |drag_panel, cx| {
cx.new_view(|_| drag_panel.clone()) cx.stop_propagation();
}), cx.new_view(|_| drag_panel.clone())
) })
}
fn sync_real_panel_sizes(&mut self, cx: &WindowContext) {
for (i, panel) in self.panels.iter_mut().enumerate() {
if self.axis.is_horizontal() {
self.sizes[i] = panel.read(cx).bounds.size.width;
} else {
self.sizes[i] = panel.read(cx).bounds.size.height;
}
}
} }
/// The `ix`` is the index of the panel to resize, /// The `ix`` is the index of the panel to resize,
/// and the `size` is the new size for the panel. /// and the `size` is the new size for the panel.
fn resize_panels(&mut self, ix: usize, size: Pixels, cx: &mut ViewContext<Self>) { fn resize_panels(&mut self, ix: usize, size: Pixels, cx: &mut ViewContext<Self>) {
// Only resize the middle panels. // Only resize the left panels.
if ix == self.panels.len() - 1 { if ix == self.panels.len() - 1 {
return; return;
} }
let size = size.floor();
let old_size = self.sizes[ix]; let old_size = self.sizes[ix];
let size = self.panels[ix].read(cx).limit_size(size); let new_size = self.panels[ix].read(cx).limit_size(size);
let changed_size = size - old_size; if new_size < size {
return;
}
let changed_size = new_size - old_size;
// If change size is less than 1px, do nothing. // If change size is less than 1px, do nothing.
if changed_size > px(-1.0) && changed_size < px(1.0) { if changed_size > px(-1.0) && changed_size < px(1.0) {
return; return;
} }
self.sizes[ix] = size; self.sizes[ix] = new_size;
let next_size = self.sizes[ix + 1]; let next_size = self.sizes[ix + 1];
self.sizes[ix + 1] = self.panels[ix + 1] self.sizes[ix + 1] = self.panels[ix + 1]
@ -150,7 +161,6 @@ impl ResizablePanelGroup {
let size = self.sizes[i]; let size = self.sizes[i];
panel.update(cx, |this, _| this.size = size); panel.update(cx, |this, _| this.size = size);
} }
cx.notify();
} }
} }
@ -164,7 +174,7 @@ impl Render for ResizablePanelGroup {
} }
} }
let container = if self.axis == Axis::Horizontal { let container = if self.axis.is_horizontal() {
h_flex() h_flex()
} else { } else {
v_flex() v_flex()
@ -254,17 +264,16 @@ impl ResizablePanel {
impl Render for ResizablePanel { impl Render for ResizablePanel {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement { fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let view = cx.view().clone();
let size = self.limit_size(self.size); let size = self.limit_size(self.size);
div() div()
.size_full() .size_full()
.relative() .relative()
.when(self.grow, |this| this.flex_grow()) .when(self.grow, |this| this.flex_grow())
.when(self.axis == Axis::Vertical, |this| this.h(size)) .when(self.axis.is_vertical(), |this| this.h(size))
.when(self.axis == Axis::Horizontal, |this| this.w(size)) .when(self.axis.is_horizontal(), |this| this.w(size))
.overflow_hidden()
.child({ .child({
let view = cx.view().clone();
canvas( canvas(
move |bounds, cx| view.update(cx, |r, _| r.bounds = bounds), move |bounds, cx| view.update(cx, |r, _| r.bounds = bounds),
|_, _, _| {}, |_, _, _| {},

View file

@ -1,5 +1,5 @@
use crate::theme::ActiveTheme; use crate::theme::ActiveTheme;
use gpui::{hsla, point, px, rems, BoxShadow, FocusHandle, Pixels, Styled, WindowContext}; use gpui::{hsla, point, px, rems, Axis, BoxShadow, FocusHandle, Pixels, Styled, WindowContext};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
pub enum ElevationIndex { pub enum ElevationIndex {
@ -187,3 +187,18 @@ impl<T: Styled> Sizeful<T> for T {
} }
} }
} }
pub trait AxisExt {
fn is_horizontal(self) -> bool;
fn is_vertical(self) -> bool;
}
impl AxisExt for Axis {
fn is_horizontal(self) -> bool {
self == Axis::Horizontal
}
fn is_vertical(self) -> bool {
self == Axis::Vertical
}
}