Support disabling drag-and-drop in Project Panel (#36719)

Release Notes:

- Added setting for disabling drag and drop in project panel. `{
"project_panel": {"drag_and_drop": false } }`
This commit is contained in:
Peter Tripp 2025-08-26 09:35:45 -04:00 committed by GitHub
parent aa0f7a2d09
commit 76dbcde628
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 50 additions and 33 deletions

View file

@ -653,6 +653,8 @@
// "never" // "never"
"show": "always" "show": "always"
}, },
// Whether to enable drag-and-drop operations in the project panel.
"drag_and_drop": true,
// Whether to hide the root entry when only one folder is open in the window. // Whether to hide the root entry when only one folder is open in the window.
"hide_root": false "hide_root": false
}, },

View file

@ -4089,6 +4089,7 @@ impl ProjectPanel {
.when(!is_sticky, |this| { .when(!is_sticky, |this| {
this this
.when(is_highlighted && folded_directory_drag_target.is_none(), |this| this.border_color(transparent_white()).bg(item_colors.drag_over)) .when(is_highlighted && folded_directory_drag_target.is_none(), |this| this.border_color(transparent_white()).bg(item_colors.drag_over))
.when(settings.drag_and_drop, |this| this
.on_drag_move::<ExternalPaths>(cx.listener( .on_drag_move::<ExternalPaths>(cx.listener(
move |this, event: &DragMoveEvent<ExternalPaths>, _, cx| { move |this, event: &DragMoveEvent<ExternalPaths>, _, cx| {
let is_current_target = this.drag_target_entry.as_ref() let is_current_target = this.drag_target_entry.as_ref()
@ -4222,7 +4223,7 @@ impl ProjectPanel {
} }
this.drag_onto(selections, entry_id, kind.is_file(), window, cx); this.drag_onto(selections, entry_id, kind.is_file(), window, cx);
}), }),
) ))
}) })
.on_mouse_down( .on_mouse_down(
MouseButton::Left, MouseButton::Left,
@ -4433,6 +4434,7 @@ impl ProjectPanel {
div() div()
.when(!is_sticky, |div| { .when(!is_sticky, |div| {
div div
.when(settings.drag_and_drop, |div| div
.on_drop(cx.listener(move |this, selections: &DraggedSelection, window, cx| { .on_drop(cx.listener(move |this, selections: &DraggedSelection, window, cx| {
this.hover_scroll_task.take(); this.hover_scroll_task.take();
this.drag_target_entry = None; this.drag_target_entry = None;
@ -4464,7 +4466,7 @@ impl ProjectPanel {
} }
}, },
)) )))
}) })
.child( .child(
Label::new(DELIMITER.clone()) Label::new(DELIMITER.clone())
@ -4484,6 +4486,7 @@ impl ProjectPanel {
.when(index != components_len - 1, |div|{ .when(index != components_len - 1, |div|{
let target_entry_id = folded_ancestors.ancestors.get(components_len - 1 - index).cloned(); let target_entry_id = folded_ancestors.ancestors.get(components_len - 1 - index).cloned();
div div
.when(settings.drag_and_drop, |div| div
.on_drag_move(cx.listener( .on_drag_move(cx.listener(
move |this, event: &DragMoveEvent<DraggedSelection>, _, _| { move |this, event: &DragMoveEvent<DraggedSelection>, _, _| {
if event.bounds.contains(&event.event.position) { if event.bounds.contains(&event.event.position) {
@ -4521,7 +4524,7 @@ impl ProjectPanel {
target.index == index target.index == index
), |this| { ), |this| {
this.bg(item_colors.drag_over) this.bg(item_colors.drag_over)
}) }))
}) })
}) })
.on_click(cx.listener(move |this, _, _, cx| { .on_click(cx.listener(move |this, _, _, cx| {
@ -5029,7 +5032,8 @@ impl ProjectPanel {
sticky_parents.reverse(); sticky_parents.reverse();
let git_status_enabled = ProjectPanelSettings::get_global(cx).git_status; let panel_settings = ProjectPanelSettings::get_global(cx);
let git_status_enabled = panel_settings.git_status;
let root_name = OsStr::new(worktree.root_name()); let root_name = OsStr::new(worktree.root_name());
let git_summaries_by_id = if git_status_enabled { let git_summaries_by_id = if git_status_enabled {
@ -5113,11 +5117,11 @@ impl Render for ProjectPanel {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let has_worktree = !self.visible_entries.is_empty(); let has_worktree = !self.visible_entries.is_empty();
let project = self.project.read(cx); let project = self.project.read(cx);
let indent_size = ProjectPanelSettings::get_global(cx).indent_size; let panel_settings = ProjectPanelSettings::get_global(cx);
let show_indent_guides = let indent_size = panel_settings.indent_size;
ProjectPanelSettings::get_global(cx).indent_guides.show == ShowIndentGuides::Always; let show_indent_guides = panel_settings.indent_guides.show == ShowIndentGuides::Always;
let show_sticky_entries = { let show_sticky_entries = {
if ProjectPanelSettings::get_global(cx).sticky_scroll { if panel_settings.sticky_scroll {
let is_scrollable = self.scroll_handle.is_scrollable(); let is_scrollable = self.scroll_handle.is_scrollable();
let is_scrolled = self.scroll_handle.offset().y < px(0.); let is_scrolled = self.scroll_handle.offset().y < px(0.);
is_scrollable && is_scrolled is_scrollable && is_scrolled
@ -5205,8 +5209,10 @@ impl Render for ProjectPanel {
h_flex() h_flex()
.id("project-panel") .id("project-panel")
.group("project-panel") .group("project-panel")
.on_drag_move(cx.listener(handle_drag_move::<ExternalPaths>)) .when(panel_settings.drag_and_drop, |this| {
.on_drag_move(cx.listener(handle_drag_move::<DraggedSelection>)) this.on_drag_move(cx.listener(handle_drag_move::<ExternalPaths>))
.on_drag_move(cx.listener(handle_drag_move::<DraggedSelection>))
})
.size_full() .size_full()
.relative() .relative()
.on_modifiers_changed(cx.listener( .on_modifiers_changed(cx.listener(
@ -5544,30 +5550,32 @@ impl Render for ProjectPanel {
})), })),
) )
.when(is_local, |div| { .when(is_local, |div| {
div.drag_over::<ExternalPaths>(|style, _, _, cx| { div.when(panel_settings.drag_and_drop, |div| {
style.bg(cx.theme().colors().drop_target_background) div.drag_over::<ExternalPaths>(|style, _, _, cx| {
style.bg(cx.theme().colors().drop_target_background)
})
.on_drop(cx.listener(
move |this, external_paths: &ExternalPaths, window, cx| {
this.drag_target_entry = None;
this.hover_scroll_task.take();
if let Some(task) = this
.workspace
.update(cx, |workspace, cx| {
workspace.open_workspace_for_paths(
true,
external_paths.paths().to_owned(),
window,
cx,
)
})
.log_err()
{
task.detach_and_log_err(cx);
}
cx.stop_propagation();
},
))
}) })
.on_drop(cx.listener(
move |this, external_paths: &ExternalPaths, window, cx| {
this.drag_target_entry = None;
this.hover_scroll_task.take();
if let Some(task) = this
.workspace
.update(cx, |workspace, cx| {
workspace.open_workspace_for_paths(
true,
external_paths.paths().to_owned(),
window,
cx,
)
})
.log_err()
{
task.detach_and_log_err(cx);
}
cx.stop_propagation();
},
))
}) })
} }
} }

View file

@ -47,6 +47,7 @@ pub struct ProjectPanelSettings {
pub scrollbar: ScrollbarSettings, pub scrollbar: ScrollbarSettings,
pub show_diagnostics: ShowDiagnostics, pub show_diagnostics: ShowDiagnostics,
pub hide_root: bool, pub hide_root: bool,
pub drag_and_drop: bool,
} }
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
@ -160,6 +161,10 @@ pub struct ProjectPanelSettingsContent {
/// ///
/// Default: true /// Default: true
pub sticky_scroll: Option<bool>, pub sticky_scroll: Option<bool>,
/// Whether to enable drag-and-drop operations in the project panel.
///
/// Default: true
pub drag_and_drop: Option<bool>,
} }
impl Settings for ProjectPanelSettings { impl Settings for ProjectPanelSettings {

View file

@ -3243,6 +3243,7 @@ Run the `theme selector: toggle` action in the command palette to see a current
"indent_size": 20, "indent_size": 20,
"auto_reveal_entries": true, "auto_reveal_entries": true,
"auto_fold_dirs": true, "auto_fold_dirs": true,
"drag_and_drop": true,
"scrollbar": { "scrollbar": {
"show": null "show": null
}, },

View file

@ -431,6 +431,7 @@ Project panel can be shown/hidden with {#action project_panel::ToggleFocus} ({#k
"auto_reveal_entries": true, // Show file in panel when activating its buffer "auto_reveal_entries": true, // Show file in panel when activating its buffer
"auto_fold_dirs": true, // Fold dirs with single subdir "auto_fold_dirs": true, // Fold dirs with single subdir
"sticky_scroll": true, // Stick parent directories at top of the project panel. "sticky_scroll": true, // Stick parent directories at top of the project panel.
"drag_and_drop": true, // Whether drag and drop is enabled
"scrollbar": { // Project panel scrollbar settings "scrollbar": { // Project panel scrollbar settings
"show": null // Show/hide: (auto, system, always, never) "show": null // Show/hide: (auto, system, always, never)
}, },