Detailed changes
@@ -297,6 +297,10 @@ impl Interactivity {
));
}
+ pub fn can_drop(&mut self, predicate: impl Fn(&dyn Any, &mut WindowContext) -> bool + 'static) {
+ self.can_drop_predicate = Some(Box::new(predicate));
+ }
+
pub fn on_click(&mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static)
where
Self: Sized,
@@ -569,6 +573,14 @@ pub trait InteractiveElement: Sized {
self
}
+ fn can_drop(
+ mut self,
+ predicate: impl Fn(&dyn Any, &mut WindowContext) -> bool + 'static,
+ ) -> Self {
+ self.interactivity().can_drop(predicate);
+ self
+ }
+
fn block_mouse(mut self) -> Self {
self.interactivity().block_mouse();
self
@@ -699,6 +711,8 @@ pub type DragListener = Box<dyn Fn(&dyn Any, &mut WindowContext) -> AnyView + 's
type DropListener = Box<dyn Fn(&dyn Any, &mut WindowContext) + 'static>;
+type CanDropPredicate = Box<dyn Fn(&dyn Any, &mut WindowContext) -> bool + 'static>;
+
pub type TooltipBuilder = Rc<dyn Fn(&mut WindowContext) -> AnyView + 'static>;
pub type KeyDownListener = Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + 'static>;
@@ -887,6 +901,7 @@ pub struct Interactivity {
pub key_up_listeners: Vec<KeyUpListener>,
pub action_listeners: Vec<(TypeId, ActionListener)>,
pub drop_listeners: Vec<(TypeId, DropListener)>,
+ pub can_drop_predicate: Option<CanDropPredicate>,
pub click_listeners: Vec<ClickListener>,
pub drag_listener: Option<(Box<dyn Any>, DragListener)>,
pub hover_listener: Option<Box<dyn Fn(&bool, &mut WindowContext)>>,
@@ -1198,6 +1213,7 @@ impl Interactivity {
let mut drag_listener = mem::take(&mut self.drag_listener);
let drop_listeners = mem::take(&mut self.drop_listeners);
let click_listeners = mem::take(&mut self.click_listeners);
+ let can_drop_predicate = mem::take(&mut self.can_drop_predicate);
if !drop_listeners.is_empty() {
cx.on_mouse_event({
@@ -1215,9 +1231,17 @@ impl Interactivity {
"checked for type drag state type above",
);
- listener(drag.value.as_ref(), cx);
- cx.notify();
- cx.stop_propagation();
+ let mut can_drop = true;
+ if let Some(predicate) = &can_drop_predicate {
+ can_drop =
+ predicate(drag.value.as_ref(), cx);
+ }
+
+ if can_drop {
+ listener(drag.value.as_ref(), cx);
+ cx.notify();
+ cx.stop_propagation();
+ }
}
}
}
@@ -1596,27 +1620,36 @@ impl Interactivity {
}
if let Some(drag) = cx.active_drag.take() {
- for (state_type, group_drag_style) in &self.group_drag_over_styles {
- if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
- if *state_type == drag.value.as_ref().type_id()
- && group_bounds.contains(&mouse_position)
+ let mut can_drop = true;
+ if let Some(can_drop_predicate) = &self.can_drop_predicate {
+ can_drop = can_drop_predicate(drag.value.as_ref(), cx);
+ }
+
+ if can_drop {
+ for (state_type, group_drag_style) in &self.group_drag_over_styles {
+ if let Some(group_bounds) =
+ GroupBounds::get(&group_drag_style.group, cx)
{
- style.refine(&group_drag_style.style);
+ if *state_type == drag.value.as_ref().type_id()
+ && group_bounds.contains(&mouse_position)
+ {
+ style.refine(&group_drag_style.style);
+ }
}
}
- }
- for (state_type, drag_over_style) in &self.drag_over_styles {
- if *state_type == drag.value.as_ref().type_id()
- && bounds
- .intersect(&cx.content_mask().bounds)
- .contains(&mouse_position)
- && cx.was_top_layer_under_active_drag(
- &mouse_position,
- cx.stacking_order(),
- )
- {
- style.refine(drag_over_style);
+ for (state_type, drag_over_style) in &self.drag_over_styles {
+ if *state_type == drag.value.as_ref().type_id()
+ && bounds
+ .intersect(&cx.content_mask().bounds)
+ .contains(&mouse_position)
+ && cx.was_top_layer_under_active_drag(
+ &mouse_position,
+ cx.stacking_order(),
+ )
+ {
+ style.refine(drag_over_style);
+ }
}
}
@@ -1672,6 +1705,7 @@ impl Default for Interactivity {
key_up_listeners: Vec::new(),
action_listeners: Vec::new(),
drop_listeners: Vec::new(),
+ can_drop_predicate: None,
click_listeners: Vec::new(),
drag_listener: None,
hover_listener: None,
@@ -58,6 +58,15 @@ impl TerminalPanel {
workspace.weak_handle(),
workspace.project().clone(),
Default::default(),
+ Some(Arc::new(|a, cx| {
+ if let Some(tab) = a.downcast_ref::<workspace::pane::DraggedTab>() {
+ if let Some(item) = tab.pane.read(cx).item_for_index(tab.ix) {
+ return item.downcast::<TerminalView>().is_some();
+ }
+ }
+
+ false
+ })),
cx,
);
pane.set_can_split(false, cx);
@@ -181,7 +181,7 @@ pub struct Pane {
workspace: WeakView<Workspace>,
project: Model<Project>,
drag_split_direction: Option<SplitDirection>,
- // can_drop: Rc<dyn Fn(&DragAndDrop<Workspace>, &WindowContext) -> bool>,
+ can_drop_predicate: Option<Arc<dyn Fn(&dyn Any, &mut WindowContext) -> bool>>,
can_split: bool,
// render_tab_bar_buttons: Rc<dyn Fn(&mut Pane, &mut ViewContext<Pane>) -> AnyElement<Pane>>,
_subscriptions: Vec<Subscription>,
@@ -229,7 +229,7 @@ pub struct NavigationEntry {
}
#[derive(Clone)]
-struct DraggedTab {
+pub struct DraggedTab {
pub pane: View<Pane>,
pub ix: usize,
pub item_id: EntityId,
@@ -325,6 +325,7 @@ impl Pane {
workspace: WeakView<Workspace>,
project: Model<Project>,
next_timestamp: Arc<AtomicUsize>,
+ can_drop_predicate: Option<Arc<dyn Fn(&dyn Any, &mut WindowContext) -> bool + 'static>>,
cx: &mut ViewContext<Self>,
) -> Self {
// todo!("context menu")
@@ -371,7 +372,7 @@ impl Pane {
// tab_context_menu: cx.build_view(|_| ContextMenu::new(pane_view_id, cx)),
workspace,
project,
- // can_drop: Rc::new(|_, _| true),
+ can_drop_predicate,
can_split: true,
// render_tab_bar_buttons: Rc::new(move |pane, cx| {
// Flex::row()
@@ -746,6 +747,10 @@ impl Pane {
.position(|i| i.item_id() == item.item_id())
}
+ pub fn item_for_index(&self, ix: usize) -> Option<&dyn ItemHandle> {
+ self.items.get(ix).map(|i| i.as_ref())
+ }
+
pub fn toggle_zoom(&mut self, _: &ToggleZoom, cx: &mut ViewContext<Self>) {
if self.zoomed {
cx.emit(Event::ZoomOut);
@@ -1530,6 +1535,9 @@ impl Pane {
)
.drag_over::<DraggedTab>(|tab| tab.bg(cx.theme().colors().drop_target_background))
.drag_over::<ProjectEntryId>(|tab| tab.bg(cx.theme().colors().drop_target_background))
+ .when_some(self.can_drop_predicate.clone(), |this, p| {
+ this.can_drop(move |a, cx| p(a, cx))
+ })
.on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| {
this.drag_split_direction = None;
this.handle_tab_drop(dragged_tab, ix, cx)
@@ -1947,6 +1955,9 @@ impl Render for Pane {
))
.group_drag_over::<DraggedTab>("", |style| style.visible())
.group_drag_over::<ProjectEntryId>("", |style| style.visible())
+ .when_some(self.can_drop_predicate.clone(), |this, p| {
+ this.can_drop(move |a, cx| p(a, cx))
+ })
.on_drop(cx.listener(move |this, dragged_tab, cx| {
this.handle_tab_drop(dragged_tab, this.active_item_index(), cx)
}))
@@ -542,6 +542,7 @@ impl Workspace {
weak_handle.clone(),
project.clone(),
pane_history_timestamp.clone(),
+ None,
cx,
)
});
@@ -1724,6 +1725,7 @@ impl Workspace {
self.weak_handle(),
self.project.clone(),
self.pane_history_timestamp.clone(),
+ None,
cx,
)
});