diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index 19b34209a3e82fcf2c8bdcc78110a70b6baa357b..ddc53537b75e5c575992cdd85c8477216c0995ea 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -2,7 +2,7 @@ use gpui::{elements::*, Entity, ModelHandle, View, ViewContext, ViewHandle, Weak use project::Project; use settings::{Settings, WorkingDirectory}; use util::ResultExt; -use workspace::{dock::Panel, Pane, Workspace}; +use workspace::{dock::Panel, DraggedItem, Pane, Workspace}; use crate::TerminalView; @@ -17,11 +17,20 @@ impl TerminalPanel { Self { project: workspace.project().clone(), pane: cx.add_view(|cx| { - Pane::new( + let window_id = cx.window_id(); + let mut pane = Pane::new( workspace.weak_handle(), workspace.app_state().background_actions, cx, - ) + ); + pane.on_can_drop(move |drag_and_drop, cx| { + drag_and_drop + .currently_dragged::(window_id) + .map_or(false, |(_, item)| { + item.handle.act_as::(cx).is_some() + }) + }); + pane }), workspace: workspace.weak_handle(), } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 2597b4af811b09ab83bac94d562ea2f8bd2eb7c9..fc3fda8e6a7fe1de348b49fbff37443d26f117ab 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -7,8 +7,8 @@ use crate::{ use anyhow::{anyhow, Result}; use collections::{HashMap, HashSet, VecDeque}; use context_menu::{ContextMenu, ContextMenuItem}; -use drag_and_drop::Draggable; -pub use dragged_item_receiver::{dragged_item_receiver, handle_dropped_item}; +use drag_and_drop::{DragAndDrop, Draggable}; +use dragged_item_receiver::dragged_item_receiver; use futures::StreamExt; use gpui::{ actions, @@ -148,6 +148,7 @@ pub struct Pane { _background_actions: BackgroundActions, workspace: WeakViewHandle, has_focus: bool, + can_drop: Rc, &WindowContext) -> bool>, } pub struct ItemNavHistory { @@ -185,9 +186,9 @@ pub struct NavigationEntry { pub data: Option>, } -struct DraggedItem { - item: Box, - pane: WeakViewHandle, +pub struct DraggedItem { + pub handle: Box, + pub pane: WeakViewHandle, } pub enum ReorderBehavior { @@ -253,6 +254,7 @@ impl Pane { _background_actions: background_actions, workspace, has_focus: false, + can_drop: Rc::new(|_, _| true), } } @@ -273,6 +275,13 @@ impl Pane { self.has_focus } + pub fn on_can_drop(&mut self, can_drop: F) + where + F: 'static + Fn(&DragAndDrop, &WindowContext) -> bool, + { + self.can_drop = Rc::new(can_drop); + } + pub fn nav_history_for_item(&self, item: &ViewHandle) -> ItemNavHistory { ItemNavHistory { history: self.nav_history.clone(), @@ -1293,7 +1302,7 @@ impl Pane { row.add_child({ enum TabDragReceiver {} let mut receiver = - dragged_item_receiver::(ix, ix, true, None, cx, { + dragged_item_receiver::(self, ix, ix, true, None, cx, { let item = item.clone(); let pane = pane.clone(); let detail = detail.clone(); @@ -1372,7 +1381,7 @@ impl Pane { receiver.as_draggable( DraggedItem { - item, + handle: item, pane: pane.clone(), }, { @@ -1382,7 +1391,7 @@ impl Pane { move |dragged_item: &DraggedItem, cx: &mut ViewContext| { let tab_style = &theme.workspace.tab_bar.dragged_tab; Self::render_dragged_tab( - &dragged_item.item, + &dragged_item.handle, dragged_item.pane.clone(), false, detail, @@ -1402,7 +1411,7 @@ impl Pane { let filler_style = theme.workspace.tab_bar.tab_style(pane_active, false); enum Filler {} row.add_child( - dragged_item_receiver::(0, filler_index, true, None, cx, |_, _| { + dragged_item_receiver::(self, 0, filler_index, true, None, cx, |_, _| { Empty::new() .contained() .with_style(filler_style.container) @@ -1601,11 +1610,7 @@ impl Pane { .into_any() } - fn render_blank_pane( - &mut self, - theme: &Theme, - _cx: &mut ViewContext, - ) -> AnyElement { + fn render_blank_pane(&self, theme: &Theme, _cx: &mut ViewContext) -> AnyElement { let background = theme.workspace.background; Empty::new() .contained() @@ -1668,6 +1673,7 @@ impl View for Pane { .with_child({ enum PaneContentTabDropTarget {} dragged_item_receiver::( + self, 0, self.active_item_index + 1, false, @@ -1696,7 +1702,7 @@ impl View for Pane { enum EmptyPane {} let theme = cx.global::().theme.clone(); - dragged_item_receiver::(0, 0, false, None, cx, |_, cx| { + dragged_item_receiver::(self, 0, 0, false, None, cx, |_, cx| { self.render_blank_pane(&theme, cx) }) .on_down(MouseButton::Left, |_, _, cx| { diff --git a/crates/workspace/src/pane/dragged_item_receiver.rs b/crates/workspace/src/pane/dragged_item_receiver.rs index 961205b9ee72e67a32e152bb18cbad58a7c7a64f..003cf1e4efc54ed7ae54526b5e62b03bef0515e1 100644 --- a/crates/workspace/src/pane/dragged_item_receiver.rs +++ b/crates/workspace/src/pane/dragged_item_receiver.rs @@ -15,6 +15,7 @@ use crate::{Pane, SplitDirection, Workspace}; use super::DraggedItem; pub fn dragged_item_receiver( + pane: &Pane, region_id: usize, drop_index: usize, allow_same_pane: bool, @@ -27,22 +28,24 @@ where D: Element, F: FnOnce(&mut MouseState, &mut ViewContext) -> D, { - MouseEventHandler::::above(region_id, cx, |state, cx| { + let drag_and_drop = cx.global::>(); + let drag_position = if (pane.can_drop)(drag_and_drop, cx) { + drag_and_drop + .currently_dragged::(cx.window_id()) + .map(|(drag_position, _)| drag_position) + .or_else(|| { + drag_and_drop + .currently_dragged::(cx.window_id()) + .map(|(drag_position, _)| drag_position) + }) + } else { + None + }; + + let mut handler = MouseEventHandler::::above(region_id, cx, |state, cx| { // Observing hovered will cause a render when the mouse enters regardless // of if mouse position was accessed before - let drag_position = if state.hovered() { - cx.global::>() - .currently_dragged::(cx.window_id()) - .map(|(drag_position, _)| drag_position) - .or_else(|| { - cx.global::>() - .currently_dragged::(cx.window_id()) - .map(|(drag_position, _)| drag_position) - }) - } else { - None - }; - + let drag_position = if state.hovered() { drag_position } else { None }; Stack::new() .with_child(render_child(state, cx)) .with_children(drag_position.map(|drag_position| { @@ -67,38 +70,44 @@ where } }) })) - }) - .on_up(MouseButton::Left, { - move |event, pane, cx| { - let workspace = pane.workspace.clone(); - let pane = cx.weak_handle(); - handle_dropped_item( - event, - workspace, - &pane, - drop_index, - allow_same_pane, - split_margin, - cx, - ); - cx.notify(); - } - }) - .on_move(|_, _, cx| { - let drag_and_drop = cx.global::>(); + }); - if drag_and_drop - .currently_dragged::(cx.window_id()) - .is_some() - || drag_and_drop - .currently_dragged::(cx.window_id()) - .is_some() - { - cx.notify(); - } else { - cx.propagate_event(); - } - }) + if drag_position.is_some() { + handler = handler + .on_up(MouseButton::Left, { + move |event, pane, cx| { + let workspace = pane.workspace.clone(); + let pane = cx.weak_handle(); + handle_dropped_item( + event, + workspace, + &pane, + drop_index, + allow_same_pane, + split_margin, + cx, + ); + cx.notify(); + } + }) + .on_move(|_, _, cx| { + let drag_and_drop = cx.global::>(); + + if drag_and_drop + .currently_dragged::(cx.window_id()) + .is_some() + || drag_and_drop + .currently_dragged::(cx.window_id()) + .is_some() + { + cx.notify(); + } else { + cx.propagate_event(); + } + }) + } + + handler } pub fn handle_dropped_item( @@ -118,7 +127,7 @@ pub fn handle_dropped_item( let action = if let Some((_, dragged_item)) = drag_and_drop.currently_dragged::(cx.window_id()) { - Action::Move(dragged_item.pane.clone(), dragged_item.item.id()) + Action::Move(dragged_item.pane.clone(), dragged_item.handle.id()) } else if let Some((_, project_entry)) = drag_and_drop.currently_dragged::(cx.window_id()) {