Prevent dragging items that aren't terminals to the terminal panel
This commit is contained in:
@@ -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::<DraggedItem>(window_id)
|
||||
.map_or(false, |(_, item)| {
|
||||
item.handle.act_as::<TerminalView>(cx).is_some()
|
||||
})
|
||||
});
|
||||
pane
|
||||
}),
|
||||
workspace: workspace.weak_handle(),
|
||||
}
|
||||
|
||||
@@ -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<Workspace>,
|
||||
has_focus: bool,
|
||||
can_drop: Rc<dyn Fn(&DragAndDrop<Workspace>, &WindowContext) -> bool>,
|
||||
}
|
||||
|
||||
pub struct ItemNavHistory {
|
||||
@@ -185,9 +186,9 @@ pub struct NavigationEntry {
|
||||
pub data: Option<Box<dyn Any>>,
|
||||
}
|
||||
|
||||
struct DraggedItem {
|
||||
item: Box<dyn ItemHandle>,
|
||||
pane: WeakViewHandle<Pane>,
|
||||
pub struct DraggedItem {
|
||||
pub handle: Box<dyn ItemHandle>,
|
||||
pub pane: WeakViewHandle<Pane>,
|
||||
}
|
||||
|
||||
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<F>(&mut self, can_drop: F)
|
||||
where
|
||||
F: 'static + Fn(&DragAndDrop<Workspace>, &WindowContext) -> bool,
|
||||
{
|
||||
self.can_drop = Rc::new(can_drop);
|
||||
}
|
||||
|
||||
pub fn nav_history_for_item<T: Item>(&self, item: &ViewHandle<T>) -> ItemNavHistory {
|
||||
ItemNavHistory {
|
||||
history: self.nav_history.clone(),
|
||||
@@ -1293,7 +1302,7 @@ impl Pane {
|
||||
row.add_child({
|
||||
enum TabDragReceiver {}
|
||||
let mut receiver =
|
||||
dragged_item_receiver::<TabDragReceiver, _, _>(ix, ix, true, None, cx, {
|
||||
dragged_item_receiver::<TabDragReceiver, _, _>(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<Workspace>| {
|
||||
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::<Filler, _, _>(0, filler_index, true, None, cx, |_, _| {
|
||||
dragged_item_receiver::<Filler, _, _>(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<Self>,
|
||||
) -> AnyElement<Self> {
|
||||
fn render_blank_pane(&self, theme: &Theme, _cx: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||
let background = theme.workspace.background;
|
||||
Empty::new()
|
||||
.contained()
|
||||
@@ -1668,6 +1673,7 @@ impl View for Pane {
|
||||
.with_child({
|
||||
enum PaneContentTabDropTarget {}
|
||||
dragged_item_receiver::<PaneContentTabDropTarget, _, _>(
|
||||
self,
|
||||
0,
|
||||
self.active_item_index + 1,
|
||||
false,
|
||||
@@ -1696,7 +1702,7 @@ impl View for Pane {
|
||||
enum EmptyPane {}
|
||||
let theme = cx.global::<Settings>().theme.clone();
|
||||
|
||||
dragged_item_receiver::<EmptyPane, _, _>(0, 0, false, None, cx, |_, cx| {
|
||||
dragged_item_receiver::<EmptyPane, _, _>(self, 0, 0, false, None, cx, |_, cx| {
|
||||
self.render_blank_pane(&theme, cx)
|
||||
})
|
||||
.on_down(MouseButton::Left, |_, _, cx| {
|
||||
|
||||
@@ -15,6 +15,7 @@ use crate::{Pane, SplitDirection, Workspace};
|
||||
use super::DraggedItem;
|
||||
|
||||
pub fn dragged_item_receiver<Tag, D, F>(
|
||||
pane: &Pane,
|
||||
region_id: usize,
|
||||
drop_index: usize,
|
||||
allow_same_pane: bool,
|
||||
@@ -27,22 +28,24 @@ where
|
||||
D: Element<Pane>,
|
||||
F: FnOnce(&mut MouseState, &mut ViewContext<Pane>) -> D,
|
||||
{
|
||||
MouseEventHandler::<Tag, _>::above(region_id, cx, |state, cx| {
|
||||
let drag_and_drop = cx.global::<DragAndDrop<Workspace>>();
|
||||
let drag_position = if (pane.can_drop)(drag_and_drop, cx) {
|
||||
drag_and_drop
|
||||
.currently_dragged::<DraggedItem>(cx.window_id())
|
||||
.map(|(drag_position, _)| drag_position)
|
||||
.or_else(|| {
|
||||
drag_and_drop
|
||||
.currently_dragged::<ProjectEntryId>(cx.window_id())
|
||||
.map(|(drag_position, _)| drag_position)
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut handler = MouseEventHandler::<Tag, _>::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::<DragAndDrop<Workspace>>()
|
||||
.currently_dragged::<DraggedItem>(cx.window_id())
|
||||
.map(|(drag_position, _)| drag_position)
|
||||
.or_else(|| {
|
||||
cx.global::<DragAndDrop<Workspace>>()
|
||||
.currently_dragged::<ProjectEntryId>(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::<DragAndDrop<Workspace>>();
|
||||
});
|
||||
|
||||
if drag_and_drop
|
||||
.currently_dragged::<DraggedItem>(cx.window_id())
|
||||
.is_some()
|
||||
|| drag_and_drop
|
||||
.currently_dragged::<ProjectEntryId>(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::<DragAndDrop<Workspace>>();
|
||||
|
||||
if drag_and_drop
|
||||
.currently_dragged::<DraggedItem>(cx.window_id())
|
||||
.is_some()
|
||||
|| drag_and_drop
|
||||
.currently_dragged::<ProjectEntryId>(cx.window_id())
|
||||
.is_some()
|
||||
{
|
||||
cx.notify();
|
||||
} else {
|
||||
cx.propagate_event();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
handler
|
||||
}
|
||||
|
||||
pub fn handle_dropped_item<V: View>(
|
||||
@@ -118,7 +127,7 @@ pub fn handle_dropped_item<V: View>(
|
||||
let action = if let Some((_, dragged_item)) =
|
||||
drag_and_drop.currently_dragged::<DraggedItem>(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::<ProjectEntryId>(cx.window_id())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user