tiles: Fix back panels flick when hover on top panel in tiles. (#708)

- Move resize handle out of the panel to avoid conflict with scrollbar.
This commit is contained in:
Jason Lee 2025-03-11 19:56:50 +08:00 committed by GitHub
parent d8ec1ee516
commit df94217999
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -28,7 +28,7 @@ actions!(tiles, [Undo, Redo,]);
const MINIMUM_SIZE: Size<Pixels> = size(px(100.), px(100.));
const DRAG_BAR_HEIGHT: Pixels = px(30.);
const HANDLE_SIZE: Pixels = px(12.0);
const HANDLE_SIZE: Pixels = px(5.0);
#[derive(Clone, PartialEq, Debug)]
struct TileChange {
@ -133,7 +133,6 @@ pub struct Tiles {
dragging_initial_mouse: Point<Pixels>,
dragging_initial_bounds: Bounds<Pixels>,
resizing_index: Option<usize>,
active_index: Option<usize>,
resizing_drag_data: Option<ResizeDrag>,
bounds: Bounds<Pixels>,
history: History<TileChange>,
@ -193,7 +192,6 @@ impl Tiles {
history: History::new().group_interval(std::time::Duration::from_millis(100)),
scroll_state: Rc::new(Cell::new(ScrollbarState::default())),
scroll_handle: ScrollHandle::default(),
active_index: None,
}
}
@ -498,11 +496,7 @@ impl Tiles {
/// Returns the active panel, if any.
pub fn active_panel(&self, cx: &App) -> Option<Arc<dyn PanelView>> {
let Some(active_index) = self.active_index else {
return None;
};
self.panels.get(active_index).and_then(|item| {
self.panels.last().and_then(|item| {
if let Ok(tab_panel) = item.panel.view().downcast::<TabPanel>() {
tab_panel.read(cx).active_panel(cx)
} else if let Ok(_) = item.panel.view().downcast::<StackPanel>() {
@ -513,15 +507,6 @@ impl Tiles {
})
}
fn set_active_index(&mut self, index: Option<usize>, cx: &mut Context<Self>) {
if self.active_index == index {
return;
}
self.active_index = index;
cx.notify();
}
/// Produce a vector of AnyElement representing the three possible resize handles
fn render_resize_handles(
&mut self,
@ -533,8 +518,8 @@ impl Tiles {
) -> Vec<AnyElement> {
let panel_bounds = item.bounds;
let right_handle_bounds = Bounds::new(
panel_bounds.origin + point(panel_bounds.size.width - HANDLE_SIZE.half(), px(0.0)),
size(HANDLE_SIZE.half(), panel_bounds.size.height),
panel_bounds.origin + point(panel_bounds.size.width - HANDLE_SIZE, px(0.0)),
size(HANDLE_SIZE, panel_bounds.size.height),
);
let bottom_handle_bounds = Bounds::new(
@ -550,6 +535,7 @@ impl Tiles {
),
size(HANDLE_SIZE.half(), HANDLE_SIZE.half()),
);
let handle_offset = -HANDLE_SIZE + px(1.);
let mut elements = Vec::new();
@ -557,10 +543,10 @@ impl Tiles {
elements.push(if !is_occluded(&right_handle_bounds) {
div()
.id("right-resize-handle")
.cursor_col_resize()
.cursor_ew_resize()
.absolute()
.top(px(0.0))
.right(-HANDLE_SIZE.half())
.top_0()
.right(handle_offset)
.w(HANDLE_SIZE)
.h(panel_bounds.size.height)
.on_mouse_down(
@ -614,10 +600,10 @@ impl Tiles {
elements.push(if !is_occluded(&bottom_handle_bounds) {
div()
.id("bottom-resize-handle")
.cursor_row_resize()
.cursor_ns_resize()
.absolute()
.left(px(0.0))
.bottom(-HANDLE_SIZE.half())
.bottom(handle_offset)
.w(panel_bounds.size.width)
.h(HANDLE_SIZE)
.on_mouse_down(
@ -667,64 +653,74 @@ impl Tiles {
// Corner resize handle
elements.push(if !is_occluded(&corner_handle_bounds) {
div()
.id("corner-resize-handle")
.cursor_nwse_resize()
.absolute()
.right(px(3.))
.bottom(px(3.))
.size_3()
.child(
Icon::new(IconName::ResizeCorner)
.size_3()
.absolute()
.right(px(1.))
.bottom(px(1.))
.text_color(cx.theme().muted_foreground.opacity(0.5)),
)
.rounded(cx.theme().radius)
.on_mouse_down(
MouseButton::Left,
cx.listener({
move |this, event: &MouseDownEvent, window, cx| {
let last_position = event.position;
let drag_data = ResizeDrag {
axis: ResizeAxis::Both,
last_position,
last_bounds: panel_bounds,
};
this.update_resizing_drag(drag_data, window, cx);
if let Some((_, new_ix)) = this.bring_to_front(this.resizing_index, cx)
{
this.resizing_index = Some(new_ix);
}
}
}),
)
.on_drag(DragResizing(entity_id), |drag, _, _, cx| {
cx.stop_propagation();
cx.new(|_| drag.clone())
})
.on_drag_move(cx.listener(
move |this, e: &DragMoveEvent<DragResizing>, window, cx| match e.drag(cx) {
DragResizing(id) => {
if *id != entity_id {
return;
}
if let Some(ref drag_data) = this.resizing_drag_data {
if drag_data.axis != ResizeAxis::Both {
return;
.child(
div()
.id("corner-resize-handle")
.cursor_nwse_resize()
.absolute()
.right(handle_offset)
.bottom(handle_offset)
.size_3()
.on_mouse_down(
MouseButton::Left,
cx.listener({
move |this, event: &MouseDownEvent, window, cx| {
let last_position = event.position;
let drag_data = ResizeDrag {
axis: ResizeAxis::Both,
last_position,
last_bounds: panel_bounds,
};
this.update_resizing_drag(drag_data, window, cx);
if let Some((_, new_ix)) =
this.bring_to_front(this.resizing_index, cx)
{
this.resizing_index = Some(new_ix);
}
}
let pos = e.event.position;
let delta_x = pos.x - drag_data.last_position.x;
let delta_y = pos.y - drag_data.last_position.y;
let new_width = (drag_data.last_bounds.size.width + delta_x)
.max(MINIMUM_SIZE.width);
let new_height = (drag_data.last_bounds.size.height + delta_y)
.max(MINIMUM_SIZE.height);
this.resize_height(new_height, window, cx);
this.resize_width(new_width, window, cx);
}
}
},
))
}),
)
.on_drag(DragResizing(entity_id), |drag, _, _, cx| {
cx.stop_propagation();
cx.new(|_| drag.clone())
})
.on_drag_move(cx.listener(
move |this, e: &DragMoveEvent<DragResizing>, window, cx| {
match e.drag(cx) {
DragResizing(id) => {
if *id != entity_id {
return;
}
if let Some(ref drag_data) = this.resizing_drag_data {
if drag_data.axis != ResizeAxis::Both {
return;
}
let pos = e.event.position;
let delta_x = pos.x - drag_data.last_position.x;
let delta_y = pos.y - drag_data.last_position.y;
let new_width = (drag_data.last_bounds.size.width
+ delta_x)
.max(MINIMUM_SIZE.width);
let new_height = (drag_data.last_bounds.size.height
+ delta_y)
.max(MINIMUM_SIZE.height);
this.resize_height(new_height, window, cx);
this.resize_width(new_width, window, cx);
}
}
}
},
)),
)
.into_any_element()
} else {
div().into_any_element()
@ -814,6 +810,7 @@ impl Tiles {
};
v_flex()
.occlude()
.bg(cx.theme().background)
.border_1()
.border_color(cx.theme().border)
@ -823,15 +820,15 @@ impl Tiles {
// More 1px to account for the border width when 2 panels are too close
.w(item.bounds.size.width + px(1.))
.h(item.bounds.size.height + px(1.))
.overflow_hidden()
.rounded(cx.theme().radius)
.child(h_flex().size_full().child(panel_view))
.child(h_flex().overflow_hidden().size_full().child(panel_view))
.children(self.render_resize_handles(window, cx, entity_id, &item, &is_occluded))
.child(self.render_drag_bar(window, cx, entity_id, &item, &is_occluded))
// Here must be mouse up for avoid conflict with Drag event
.on_mouse_up(
MouseButton::Left,
cx.listener(move |this, _, _, cx| {
this.set_active_index(Some(ix), cx);
this.bring_to_front(Some(ix), cx);
}),
)
}