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