From f8bd6c66f447d7bfc015dc5261dfe96b82963ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Tue, 5 Nov 2024 13:26:20 +0100 Subject: [PATCH] Fix cursor shape flickering and dead-zone on 1px border around list items in project and outline panels (#20202) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move click listener to outer div - Avoids dead area when clicking the 1px border around a list item - Avoids flickering cursor shape when moving the cursor above the list, and especially when scrolling the list with a stationary cursor. Closes #15614 Release Notes: - Fixed mouse cursor shape flickering in project and outline panels when crossing items ([#15614](https://github.com/zed-industries/zed/issues/15614)) --------- Co-authored-by: Stephan Aßmus --- crates/outline_panel/src/outline_panel.rs | 21 ++-- crates/project_panel/src/project_panel.rs | 138 +++++++++++----------- 2 files changed, 79 insertions(+), 80 deletions(-) diff --git a/crates/outline_panel/src/outline_panel.rs b/crates/outline_panel/src/outline_panel.rs index 26043836f9..a5e5a215e4 100644 --- a/crates/outline_panel/src/outline_panel.rs +++ b/crates/outline_panel/src/outline_panel.rs @@ -1996,6 +1996,17 @@ impl OutlinePanel { div() .text_ui(cx) .id(item_id.clone()) + .on_click({ + let clicked_entry = rendered_entry.clone(); + cx.listener(move |outline_panel, event: &gpui::ClickEvent, cx| { + if event.down.button == MouseButton::Right || event.down.first_mouse { + return; + } + let change_selection = event.down.click_count > 1; + outline_panel.open_entry(&clicked_entry, change_selection, cx); + }) + }) + .cursor_pointer() .child( ListItem::new(item_id) .indent_level(depth) @@ -2005,16 +2016,6 @@ impl OutlinePanel { list_item.child(h_flex().child(icon_element)) }) .child(h_flex().h_6().child(label_element).ml_1()) - .on_click({ - let clicked_entry = rendered_entry.clone(); - cx.listener(move |outline_panel, event: &gpui::ClickEvent, cx| { - if event.down.button == MouseButton::Right || event.down.first_mouse { - return; - } - let change_selection = event.down.click_count > 1; - outline_panel.open_entry(&clicked_entry, change_selection, cx); - }) - }) .on_secondary_mouse_down(cx.listener( move |outline_panel, event: &MouseDownEvent, cx| { // Stop propagation to prevent the catch-all context menu for the project diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 72388187f4..5073616e9a 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -2571,6 +2571,74 @@ impl ProjectPanel { this.hover_scroll_task.take(); this.drag_onto(selections, entry_id, kind.is_file(), cx); })) + .on_click(cx.listener(move |this, event: &gpui::ClickEvent, cx| { + if event.down.button == MouseButton::Right || event.down.first_mouse { + return; + } + if !show_editor { + cx.stop_propagation(); + + if let Some(selection) = this.selection.filter(|_| event.down.modifiers.shift) { + let current_selection = this.index_for_selection(selection); + let target_selection = this.index_for_selection(SelectedEntry { + entry_id, + worktree_id, + }); + if let Some(((_, _, source_index), (_, _, target_index))) = + current_selection.zip(target_selection) + { + let range_start = source_index.min(target_index); + let range_end = source_index.max(target_index) + 1; // Make the range inclusive. + let mut new_selections = BTreeSet::new(); + this.for_each_visible_entry( + range_start..range_end, + cx, + |entry_id, details, _| { + new_selections.insert(SelectedEntry { + entry_id, + worktree_id: details.worktree_id, + }); + }, + ); + + this.marked_entries = this + .marked_entries + .union(&new_selections) + .cloned() + .collect(); + + this.selection = Some(SelectedEntry { + entry_id, + worktree_id, + }); + // Ensure that the current entry is selected. + this.marked_entries.insert(SelectedEntry { + entry_id, + worktree_id, + }); + } + } else if event.down.modifiers.secondary() { + if event.down.click_count > 1 { + this.split_entry(entry_id, cx); + } else if !this.marked_entries.insert(selection) { + this.marked_entries.remove(&selection); + } + } else if kind.is_dir() { + this.toggle_expanded(entry_id, cx); + } else { + let preview_tabs_enabled = PreviewTabsSettings::get_global(cx).enabled; + let click_count = event.up.click_count; + this.open_entry( + entry_id, + cx.modifiers().secondary(), + !preview_tabs_enabled || click_count > 1, + !preview_tabs_enabled && click_count == 1, + cx, + ); + } + } + })) + .cursor_pointer() .child( ListItem::new(entry_id.to_proto() as usize) .indent_level(depth) @@ -2671,76 +2739,6 @@ impl ProjectPanel { } .ml_1(), ) - .on_click(cx.listener(move |this, event: &gpui::ClickEvent, cx| { - if event.down.button == MouseButton::Right || event.down.first_mouse { - return; - } - if !show_editor { - cx.stop_propagation(); - - if let Some(selection) = - this.selection.filter(|_| event.down.modifiers.shift) - { - let current_selection = this.index_for_selection(selection); - let target_selection = this.index_for_selection(SelectedEntry { - entry_id, - worktree_id, - }); - if let Some(((_, _, source_index), (_, _, target_index))) = - current_selection.zip(target_selection) - { - let range_start = source_index.min(target_index); - let range_end = source_index.max(target_index) + 1; // Make the range inclusive. - let mut new_selections = BTreeSet::new(); - this.for_each_visible_entry( - range_start..range_end, - cx, - |entry_id, details, _| { - new_selections.insert(SelectedEntry { - entry_id, - worktree_id: details.worktree_id, - }); - }, - ); - - this.marked_entries = this - .marked_entries - .union(&new_selections) - .cloned() - .collect(); - - this.selection = Some(SelectedEntry { - entry_id, - worktree_id, - }); - // Ensure that the current entry is selected. - this.marked_entries.insert(SelectedEntry { - entry_id, - worktree_id, - }); - } - } else if event.down.modifiers.secondary() { - if event.down.click_count > 1 { - this.split_entry(entry_id, cx); - } else if !this.marked_entries.insert(selection) { - this.marked_entries.remove(&selection); - } - } else if kind.is_dir() { - this.toggle_expanded(entry_id, cx); - } else { - let preview_tabs_enabled = - PreviewTabsSettings::get_global(cx).enabled; - let click_count = event.up.click_count; - this.open_entry( - entry_id, - cx.modifiers().secondary(), - !preview_tabs_enabled || click_count > 1, - !preview_tabs_enabled && click_count == 1, - cx, - ); - } - } - })) .on_secondary_mouse_down(cx.listener( move |this, event: &MouseDownEvent, cx| { // Stop propagation to prevent the catch-all context menu for the project