Fix cursor shape flickering and dead-zone on 1px border around list items in project and outline panels (#20202)
Some checks are pending
CI / Check Postgres and Protobuf migrations, mergability (push) Waiting to run
CI / Check formatting and spelling (push) Waiting to run
CI / (macOS) Run Clippy and tests (push) Waiting to run
CI / (Linux) Run Clippy and tests (push) Waiting to run
CI / (Linux) Build Remote Server (push) Waiting to run
CI / (Windows) Run Clippy and tests (push) Waiting to run
CI / Create a macOS bundle (push) Blocked by required conditions
CI / Create a Linux bundle (push) Blocked by required conditions
CI / Create arm64 Linux bundle (push) Blocked by required conditions
Deploy Docs / Deploy Docs (push) Waiting to run
Docs / Check formatting (push) Waiting to run

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 <stephan.assmus@sap.com>
This commit is contained in:
Stephan Aßmus 2024-11-05 13:26:20 +01:00 committed by GitHub
parent 02b1e3a3c1
commit f8bd6c66f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 79 additions and 80 deletions

View file

@ -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

View file

@ -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