mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
Merge pull request #1572 from zed-industries/drag-and-drop-fixes
Misc drag and drop issue fixes
This commit is contained in:
commit
d59911df26
@ -4,7 +4,7 @@ use gpui::{
|
||||
elements::{Container, MouseEventHandler},
|
||||
geometry::vector::Vector2F,
|
||||
scene::DragRegionEvent,
|
||||
Element, ElementBox, EventContext, MouseButton, RenderContext, View, ViewContext,
|
||||
CursorStyle, Element, ElementBox, EventContext, MouseButton, RenderContext, View, ViewContext,
|
||||
WeakViewHandle,
|
||||
};
|
||||
|
||||
@ -33,7 +33,6 @@ pub struct DragAndDrop<V: View> {
|
||||
|
||||
impl<V: View> DragAndDrop<V> {
|
||||
pub fn new(parent: WeakViewHandle<V>, cx: &mut ViewContext<V>) -> Self {
|
||||
// TODO: Figure out if detaching here would result in a memory leak
|
||||
cx.observe_global::<Self, _>(|cx| {
|
||||
if let Some(parent) = cx.global::<Self>().parent.upgrade(cx) {
|
||||
parent.update(cx, |_, cx| cx.notify())
|
||||
@ -110,6 +109,7 @@ impl<V: View> DragAndDrop<V> {
|
||||
.left()
|
||||
.boxed()
|
||||
})
|
||||
.with_cursor_style(CursorStyle::Arrow)
|
||||
.on_up(MouseButton::Left, |_, cx| {
|
||||
cx.defer(|cx| {
|
||||
cx.update_global::<Self, _, _>(|this, _| this.currently_dragged.take());
|
||||
|
@ -5103,6 +5103,7 @@ impl<T: Entity> From<WeakModelHandle<T>> for AnyWeakModelHandle {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WeakViewHandle<T> {
|
||||
window_id: usize,
|
||||
view_id: usize,
|
||||
|
@ -381,7 +381,12 @@ impl Presenter {
|
||||
}
|
||||
}
|
||||
MouseRegionEvent::Click(e) => {
|
||||
if e.button == self.clicked_button.unwrap() {
|
||||
// Only raise click events if the released button is the same as the one stored
|
||||
if self
|
||||
.clicked_button
|
||||
.map(|clicked_button| clicked_button == e.button)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
// Clear clicked regions and clicked button
|
||||
let clicked_regions =
|
||||
std::mem::replace(&mut self.clicked_regions, Vec::new());
|
||||
|
@ -169,7 +169,7 @@ impl MouseRegionEvent {
|
||||
match self {
|
||||
MouseRegionEvent::Move(_) => true,
|
||||
MouseRegionEvent::Drag(_) => false,
|
||||
MouseRegionEvent::Hover(_) => true,
|
||||
MouseRegionEvent::Hover(_) => false,
|
||||
MouseRegionEvent::Down(_) => true,
|
||||
MouseRegionEvent::Up(_) => true,
|
||||
MouseRegionEvent::Click(_) => true,
|
||||
|
@ -172,7 +172,7 @@ pub enum Event {
|
||||
Focused,
|
||||
ActivateItem { local: bool },
|
||||
Remove,
|
||||
RemoveItem,
|
||||
RemoveItem { item_id: usize },
|
||||
Split(SplitDirection),
|
||||
ChangeItemTitle,
|
||||
}
|
||||
@ -453,7 +453,7 @@ impl Pane {
|
||||
item
|
||||
}
|
||||
|
||||
pub fn add_item(
|
||||
pub(crate) fn add_item(
|
||||
workspace: &mut Workspace,
|
||||
pane: &ViewHandle<Pane>,
|
||||
item: Box<dyn ItemHandle>,
|
||||
@ -475,6 +475,8 @@ impl Pane {
|
||||
)
|
||||
};
|
||||
|
||||
item.added_to_pane(workspace, pane.clone(), cx);
|
||||
|
||||
// Does the item already exist?
|
||||
if let Some(existing_item_index) = pane.read(cx).items.iter().position(|existing_item| {
|
||||
let existing_item_entry_ids = existing_item.project_entry_ids(cx);
|
||||
@ -516,8 +518,6 @@ impl Pane {
|
||||
pane.activate_item(insertion_index, activate_pane, focus_item, cx);
|
||||
});
|
||||
} else {
|
||||
// If the item doesn't already exist, add it and activate it
|
||||
item.added_to_pane(workspace, pane.clone(), cx);
|
||||
pane.update(cx, |pane, cx| {
|
||||
cx.reparent(&item);
|
||||
pane.items.insert(insertion_index, item);
|
||||
@ -762,7 +762,7 @@ impl Pane {
|
||||
}
|
||||
|
||||
let item = self.items.remove(item_ix);
|
||||
cx.emit(Event::RemoveItem);
|
||||
cx.emit(Event::RemoveItem { item_id: item.id() });
|
||||
if self.items.is_empty() {
|
||||
item.deactivated(cx);
|
||||
self.update_toolbar(cx);
|
||||
@ -1069,7 +1069,7 @@ impl Pane {
|
||||
let detail = detail.clone();
|
||||
move |dragged_item, cx: &mut RenderContext<Workspace>| {
|
||||
let tab_style = &theme.workspace.tab_bar.dragged_tab;
|
||||
Pane::render_tab(
|
||||
Self::render_tab(
|
||||
&dragged_item.item,
|
||||
dragged_item.pane.clone(),
|
||||
detail,
|
||||
|
@ -535,97 +535,123 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
|
||||
}
|
||||
}
|
||||
|
||||
let mut pending_autosave = None;
|
||||
let mut cancel_pending_autosave = oneshot::channel::<()>().0;
|
||||
let pending_update = Rc::new(RefCell::new(None));
|
||||
let pending_update_scheduled = Rc::new(AtomicBool::new(false));
|
||||
let pane = pane.downgrade();
|
||||
cx.subscribe(self, move |workspace, item, event, cx| {
|
||||
let pane = if let Some(pane) = pane.upgrade(cx) {
|
||||
pane
|
||||
} else {
|
||||
log::error!("unexpected item event after pane was dropped");
|
||||
return;
|
||||
};
|
||||
if workspace
|
||||
.panes_by_item
|
||||
.insert(self.id(), pane.downgrade())
|
||||
.is_none()
|
||||
{
|
||||
let mut pending_autosave = None;
|
||||
let mut cancel_pending_autosave = oneshot::channel::<()>().0;
|
||||
let pending_update = Rc::new(RefCell::new(None));
|
||||
let pending_update_scheduled = Rc::new(AtomicBool::new(false));
|
||||
|
||||
if let Some(item) = item.to_followable_item_handle(cx) {
|
||||
let leader_id = workspace.leader_for_pane(&pane);
|
||||
let mut event_subscription =
|
||||
Some(cx.subscribe(self, move |workspace, item, event, cx| {
|
||||
let pane = if let Some(pane) = workspace
|
||||
.panes_by_item
|
||||
.get(&item.id())
|
||||
.and_then(|pane| pane.upgrade(cx))
|
||||
{
|
||||
pane
|
||||
} else {
|
||||
log::error!("unexpected item event after pane was dropped");
|
||||
return;
|
||||
};
|
||||
|
||||
if leader_id.is_some() && item.should_unfollow_on_event(event, cx) {
|
||||
workspace.unfollow(&pane, cx);
|
||||
}
|
||||
if let Some(item) = item.to_followable_item_handle(cx) {
|
||||
let leader_id = workspace.leader_for_pane(&pane);
|
||||
|
||||
if item.add_event_to_update_proto(event, &mut *pending_update.borrow_mut(), cx)
|
||||
&& !pending_update_scheduled.load(SeqCst)
|
||||
{
|
||||
pending_update_scheduled.store(true, SeqCst);
|
||||
cx.after_window_update({
|
||||
let pending_update = pending_update.clone();
|
||||
let pending_update_scheduled = pending_update_scheduled.clone();
|
||||
move |this, cx| {
|
||||
pending_update_scheduled.store(false, SeqCst);
|
||||
this.update_followers(
|
||||
proto::update_followers::Variant::UpdateView(proto::UpdateView {
|
||||
id: item.id() as u64,
|
||||
variant: pending_update.borrow_mut().take(),
|
||||
leader_id: leader_id.map(|id| id.0),
|
||||
}),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if T::should_close_item_on_event(event) {
|
||||
Pane::close_item(workspace, pane, item.id(), cx).detach_and_log_err(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
if T::should_update_tab_on_event(event) {
|
||||
pane.update(cx, |_, cx| {
|
||||
cx.emit(pane::Event::ChangeItemTitle);
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
|
||||
if T::is_edit_event(event) {
|
||||
if let Autosave::AfterDelay { milliseconds } = cx.global::<Settings>().autosave {
|
||||
let prev_autosave = pending_autosave
|
||||
.take()
|
||||
.unwrap_or_else(|| Task::ready(Some(())));
|
||||
let (cancel_tx, mut cancel_rx) = oneshot::channel::<()>();
|
||||
let prev_cancel_tx = mem::replace(&mut cancel_pending_autosave, cancel_tx);
|
||||
let project = workspace.project.downgrade();
|
||||
let _ = prev_cancel_tx.send(());
|
||||
pending_autosave = Some(cx.spawn_weak(|_, mut cx| async move {
|
||||
let mut timer = cx
|
||||
.background()
|
||||
.timer(Duration::from_millis(milliseconds))
|
||||
.fuse();
|
||||
prev_autosave.await;
|
||||
futures::select_biased! {
|
||||
_ = cancel_rx => return None,
|
||||
_ = timer => {}
|
||||
if leader_id.is_some() && item.should_unfollow_on_event(event, cx) {
|
||||
workspace.unfollow(&pane, cx);
|
||||
}
|
||||
|
||||
let project = project.upgrade(&cx)?;
|
||||
cx.update(|cx| Pane::autosave_item(&item, project, cx))
|
||||
.await
|
||||
.log_err();
|
||||
None
|
||||
}));
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
if item.add_event_to_update_proto(
|
||||
event,
|
||||
&mut *pending_update.borrow_mut(),
|
||||
cx,
|
||||
) && !pending_update_scheduled.load(SeqCst)
|
||||
{
|
||||
pending_update_scheduled.store(true, SeqCst);
|
||||
cx.after_window_update({
|
||||
let pending_update = pending_update.clone();
|
||||
let pending_update_scheduled = pending_update_scheduled.clone();
|
||||
move |this, cx| {
|
||||
pending_update_scheduled.store(false, SeqCst);
|
||||
this.update_followers(
|
||||
proto::update_followers::Variant::UpdateView(
|
||||
proto::UpdateView {
|
||||
id: item.id() as u64,
|
||||
variant: pending_update.borrow_mut().take(),
|
||||
leader_id: leader_id.map(|id| id.0),
|
||||
},
|
||||
),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cx.observe_focus(self, move |workspace, item, focused, cx| {
|
||||
if !focused && cx.global::<Settings>().autosave == Autosave::OnFocusChange {
|
||||
Pane::autosave_item(&item, workspace.project.clone(), cx).detach_and_log_err(cx);
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
if T::should_close_item_on_event(event) {
|
||||
Pane::close_item(workspace, pane, item.id(), cx).detach_and_log_err(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
if T::should_update_tab_on_event(event) {
|
||||
pane.update(cx, |_, cx| {
|
||||
cx.emit(pane::Event::ChangeItemTitle);
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
|
||||
if T::is_edit_event(event) {
|
||||
if let Autosave::AfterDelay { milliseconds } =
|
||||
cx.global::<Settings>().autosave
|
||||
{
|
||||
let prev_autosave = pending_autosave
|
||||
.take()
|
||||
.unwrap_or_else(|| Task::ready(Some(())));
|
||||
let (cancel_tx, mut cancel_rx) = oneshot::channel::<()>();
|
||||
let prev_cancel_tx =
|
||||
mem::replace(&mut cancel_pending_autosave, cancel_tx);
|
||||
let project = workspace.project.downgrade();
|
||||
let _ = prev_cancel_tx.send(());
|
||||
pending_autosave = Some(cx.spawn_weak(|_, mut cx| async move {
|
||||
let mut timer = cx
|
||||
.background()
|
||||
.timer(Duration::from_millis(milliseconds))
|
||||
.fuse();
|
||||
prev_autosave.await;
|
||||
futures::select_biased! {
|
||||
_ = cancel_rx => return None,
|
||||
_ = timer => {}
|
||||
}
|
||||
|
||||
let project = project.upgrade(&cx)?;
|
||||
cx.update(|cx| Pane::autosave_item(&item, project, cx))
|
||||
.await
|
||||
.log_err();
|
||||
None
|
||||
}));
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
cx.observe_focus(self, move |workspace, item, focused, cx| {
|
||||
if !focused && cx.global::<Settings>().autosave == Autosave::OnFocusChange {
|
||||
Pane::autosave_item(&item, workspace.project.clone(), cx)
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
let item_id = self.id();
|
||||
cx.observe_release(self, move |workspace, _, _| {
|
||||
workspace.panes_by_item.remove(&item_id);
|
||||
event_subscription.take();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
||||
fn deactivated(&self, cx: &mut MutableAppContext) {
|
||||
@ -799,6 +825,7 @@ pub struct Workspace {
|
||||
left_sidebar: ViewHandle<Sidebar>,
|
||||
right_sidebar: ViewHandle<Sidebar>,
|
||||
panes: Vec<ViewHandle<Pane>>,
|
||||
panes_by_item: HashMap<usize, WeakViewHandle<Pane>>,
|
||||
active_pane: ViewHandle<Pane>,
|
||||
status_bar: ViewHandle<StatusBar>,
|
||||
notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
|
||||
@ -910,6 +937,7 @@ impl Workspace {
|
||||
weak_self,
|
||||
center: PaneGroup::new(pane.clone()),
|
||||
panes: vec![pane.clone()],
|
||||
panes_by_item: Default::default(),
|
||||
active_pane: pane.clone(),
|
||||
status_bar,
|
||||
notifications: Default::default(),
|
||||
@ -1631,8 +1659,13 @@ impl Workspace {
|
||||
}
|
||||
self.update_window_edited(cx);
|
||||
}
|
||||
pane::Event::RemoveItem => {
|
||||
pane::Event::RemoveItem { item_id } => {
|
||||
self.update_window_edited(cx);
|
||||
if let hash_map::Entry::Occupied(entry) = self.panes_by_item.entry(*item_id) {
|
||||
if entry.get().id() == pane.id() {
|
||||
entry.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1663,6 +1696,9 @@ impl Workspace {
|
||||
cx.focus(self.panes.last().unwrap().clone());
|
||||
self.unfollow(&pane, cx);
|
||||
self.last_leaders_by_pane.remove(&pane.downgrade());
|
||||
for removed_item in pane.read(cx).items() {
|
||||
self.panes_by_item.remove(&removed_item.id());
|
||||
}
|
||||
cx.notify();
|
||||
} else {
|
||||
self.active_item_path_changed(cx);
|
||||
|
@ -72,7 +72,7 @@ export default function tabBar(theme: Theme) {
|
||||
return {
|
||||
height,
|
||||
background: backgroundColor(theme, 300),
|
||||
dropTargetOverlayColor: withOpacity(theme.textColor.muted, 0.8),
|
||||
dropTargetOverlayColor: withOpacity(theme.textColor.muted, 0.6),
|
||||
border: border(theme, "primary", {
|
||||
left: true,
|
||||
bottom: true,
|
||||
|
Loading…
Reference in New Issue
Block a user