workspace: Fix drag&dropping project panel entries into editor area (#12767)
Fixes #12733 Release Notes: - Fixed drag&dropping project panel entries into editor area & tab bar
This commit is contained in:
parent
07dbd2bce8
commit
5f5e6b8616
2 changed files with 40 additions and 33 deletions
|
@ -36,7 +36,7 @@ use util::{maybe, NumericPrefixWithSuffix, ResultExt, TryFutureExt};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
dock::{DockPosition, Panel, PanelEvent},
|
dock::{DockPosition, Panel, PanelEvent},
|
||||||
notifications::{DetachAndPromptErr, NotifyTaskExt},
|
notifications::{DetachAndPromptErr, NotifyTaskExt},
|
||||||
OpenInTerminal, Workspace,
|
DraggedSelection, OpenInTerminal, SelectedEntry, Workspace,
|
||||||
};
|
};
|
||||||
use worktree::CreatedEntry;
|
use worktree::CreatedEntry;
|
||||||
|
|
||||||
|
@ -65,26 +65,6 @@ pub struct ProjectPanel {
|
||||||
pending_serialization: Task<Option<()>>,
|
pending_serialization: Task<Option<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
struct SelectedEntry {
|
|
||||||
worktree_id: WorktreeId,
|
|
||||||
entry_id: ProjectEntryId,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DraggedSelection {
|
|
||||||
active_selection: SelectedEntry,
|
|
||||||
marked_selections: Arc<BTreeSet<SelectedEntry>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DraggedSelection {
|
|
||||||
fn items<'a>(&'a self) -> Box<dyn Iterator<Item = &'a SelectedEntry> + 'a> {
|
|
||||||
if self.marked_selections.contains(&self.active_selection) {
|
|
||||||
Box::new(self.marked_selections.iter())
|
|
||||||
} else {
|
|
||||||
Box::new(std::iter::once(&self.active_selection))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct EditState {
|
struct EditState {
|
||||||
worktree_id: WorktreeId,
|
worktree_id: WorktreeId,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
||||||
SplitDirection, ToggleZoom, Workspace,
|
SplitDirection, ToggleZoom, Workspace,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use collections::{HashMap, HashSet, VecDeque};
|
use collections::{BTreeSet, HashMap, HashSet, VecDeque};
|
||||||
use futures::{stream::FuturesUnordered, StreamExt};
|
use futures::{stream::FuturesUnordered, StreamExt};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, anchored, deferred, impl_actions, prelude::*, Action, AnchorCorner, AnyElement,
|
actions, anchored, deferred, impl_actions, prelude::*, Action, AnchorCorner, AnyElement,
|
||||||
|
@ -20,7 +20,7 @@ use gpui::{
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use project::{Project, ProjectEntryId, ProjectPath};
|
use project::{Project, ProjectEntryId, ProjectPath, WorktreeId};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -43,6 +43,30 @@ use ui::{
|
||||||
use ui::{v_flex, ContextMenu};
|
use ui::{v_flex, ContextMenu};
|
||||||
use util::{debug_panic, maybe, truncate_and_remove_front, ResultExt};
|
use util::{debug_panic, maybe, truncate_and_remove_front, ResultExt};
|
||||||
|
|
||||||
|
/// A selected entry in e.g. project panel.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct SelectedEntry {
|
||||||
|
pub worktree_id: WorktreeId,
|
||||||
|
pub entry_id: ProjectEntryId,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A group of selected entries from project panel.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DraggedSelection {
|
||||||
|
pub active_selection: SelectedEntry,
|
||||||
|
pub marked_selections: Arc<BTreeSet<SelectedEntry>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DraggedSelection {
|
||||||
|
pub fn items<'a>(&'a self) -> Box<dyn Iterator<Item = &'a SelectedEntry> + 'a> {
|
||||||
|
if self.marked_selections.contains(&self.active_selection) {
|
||||||
|
Box::new(self.marked_selections.iter())
|
||||||
|
} else {
|
||||||
|
Box::new(std::iter::once(&self.active_selection))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Copy, Deserialize, Debug)]
|
#[derive(PartialEq, Clone, Copy, Deserialize, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum SaveIntent {
|
pub enum SaveIntent {
|
||||||
|
@ -1602,7 +1626,7 @@ impl Pane {
|
||||||
.drag_over::<DraggedTab>(|tab, _, cx| {
|
.drag_over::<DraggedTab>(|tab, _, cx| {
|
||||||
tab.bg(cx.theme().colors().drop_target_background)
|
tab.bg(cx.theme().colors().drop_target_background)
|
||||||
})
|
})
|
||||||
.drag_over::<ProjectEntryId>(|tab, _, cx| {
|
.drag_over::<DraggedSelection>(|tab, _, cx| {
|
||||||
tab.bg(cx.theme().colors().drop_target_background)
|
tab.bg(cx.theme().colors().drop_target_background)
|
||||||
})
|
})
|
||||||
.when_some(self.can_drop_predicate.clone(), |this, p| {
|
.when_some(self.can_drop_predicate.clone(), |this, p| {
|
||||||
|
@ -1612,9 +1636,9 @@ impl Pane {
|
||||||
this.drag_split_direction = None;
|
this.drag_split_direction = None;
|
||||||
this.handle_tab_drop(dragged_tab, ix, cx)
|
this.handle_tab_drop(dragged_tab, ix, cx)
|
||||||
}))
|
}))
|
||||||
.on_drop(cx.listener(move |this, entry_id: &ProjectEntryId, cx| {
|
.on_drop(cx.listener(move |this, selection: &DraggedSelection, cx| {
|
||||||
this.drag_split_direction = None;
|
this.drag_split_direction = None;
|
||||||
this.handle_project_entry_drop(entry_id, cx)
|
this.handle_project_entry_drop(&selection.active_selection.entry_id, cx)
|
||||||
}))
|
}))
|
||||||
.on_drop(cx.listener(move |this, paths, cx| {
|
.on_drop(cx.listener(move |this, paths, cx| {
|
||||||
this.drag_split_direction = None;
|
this.drag_split_direction = None;
|
||||||
|
@ -1820,16 +1844,16 @@ impl Pane {
|
||||||
.drag_over::<DraggedTab>(|bar, _, cx| {
|
.drag_over::<DraggedTab>(|bar, _, cx| {
|
||||||
bar.bg(cx.theme().colors().drop_target_background)
|
bar.bg(cx.theme().colors().drop_target_background)
|
||||||
})
|
})
|
||||||
.drag_over::<ProjectEntryId>(|bar, _, cx| {
|
.drag_over::<DraggedSelection>(|bar, _, cx| {
|
||||||
bar.bg(cx.theme().colors().drop_target_background)
|
bar.bg(cx.theme().colors().drop_target_background)
|
||||||
})
|
})
|
||||||
.on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| {
|
.on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| {
|
||||||
this.drag_split_direction = None;
|
this.drag_split_direction = None;
|
||||||
this.handle_tab_drop(dragged_tab, this.items.len(), cx)
|
this.handle_tab_drop(dragged_tab, this.items.len(), cx)
|
||||||
}))
|
}))
|
||||||
.on_drop(cx.listener(move |this, entry_id: &ProjectEntryId, cx| {
|
.on_drop(cx.listener(move |this, selection: &DraggedSelection, cx| {
|
||||||
this.drag_split_direction = None;
|
this.drag_split_direction = None;
|
||||||
this.handle_project_entry_drop(entry_id, cx)
|
this.handle_project_entry_drop(&selection.active_selection.entry_id, cx)
|
||||||
}))
|
}))
|
||||||
.on_drop(cx.listener(move |this, paths, cx| {
|
.on_drop(cx.listener(move |this, paths, cx| {
|
||||||
this.drag_split_direction = None;
|
this.drag_split_direction = None;
|
||||||
|
@ -2179,7 +2203,7 @@ impl Render for Pane {
|
||||||
.relative()
|
.relative()
|
||||||
.group("")
|
.group("")
|
||||||
.on_drag_move::<DraggedTab>(cx.listener(Self::handle_drag_move))
|
.on_drag_move::<DraggedTab>(cx.listener(Self::handle_drag_move))
|
||||||
.on_drag_move::<ProjectEntryId>(cx.listener(Self::handle_drag_move))
|
.on_drag_move::<DraggedSelection>(cx.listener(Self::handle_drag_move))
|
||||||
.on_drag_move::<ExternalPaths>(cx.listener(Self::handle_drag_move))
|
.on_drag_move::<ExternalPaths>(cx.listener(Self::handle_drag_move))
|
||||||
.map(|div| {
|
.map(|div| {
|
||||||
if let Some(item) = self.active_item() {
|
if let Some(item) = self.active_item() {
|
||||||
|
@ -2205,7 +2229,7 @@ impl Render for Pane {
|
||||||
.absolute()
|
.absolute()
|
||||||
.bg(cx.theme().colors().drop_target_background)
|
.bg(cx.theme().colors().drop_target_background)
|
||||||
.group_drag_over::<DraggedTab>("", |style| style.visible())
|
.group_drag_over::<DraggedTab>("", |style| style.visible())
|
||||||
.group_drag_over::<ProjectEntryId>("", |style| style.visible())
|
.group_drag_over::<DraggedSelection>("", |style| style.visible())
|
||||||
.group_drag_over::<ExternalPaths>("", |style| style.visible())
|
.group_drag_over::<ExternalPaths>("", |style| style.visible())
|
||||||
.when_some(self.can_drop_predicate.clone(), |this, p| {
|
.when_some(self.can_drop_predicate.clone(), |this, p| {
|
||||||
this.can_drop(move |a, cx| p(a, cx))
|
this.can_drop(move |a, cx| p(a, cx))
|
||||||
|
@ -2213,8 +2237,11 @@ impl Render for Pane {
|
||||||
.on_drop(cx.listener(move |this, dragged_tab, cx| {
|
.on_drop(cx.listener(move |this, dragged_tab, cx| {
|
||||||
this.handle_tab_drop(dragged_tab, this.active_item_index(), cx)
|
this.handle_tab_drop(dragged_tab, this.active_item_index(), cx)
|
||||||
}))
|
}))
|
||||||
.on_drop(cx.listener(move |this, entry_id, cx| {
|
.on_drop(cx.listener(move |this, selection: &DraggedSelection, cx| {
|
||||||
this.handle_project_entry_drop(entry_id, cx)
|
this.handle_project_entry_drop(
|
||||||
|
&selection.active_selection.entry_id,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
}))
|
}))
|
||||||
.on_drop(cx.listener(move |this, paths, cx| {
|
.on_drop(cx.listener(move |this, paths, cx| {
|
||||||
this.handle_external_paths_drop(paths, cx)
|
this.handle_external_paths_drop(paths, cx)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue