project panel: scroll when drag-hovering over the edge of a list (#20207)
Closes [19554](https://github.com/zed-industries/zed/issues/19554) Release Notes: - Added auto-scrolling to project panel when a vertical edge of a panel is hovered with a dragged entry.
This commit is contained in:
parent
258cf6c746
commit
2965119201
1 changed files with 65 additions and 0 deletions
|
@ -63,6 +63,9 @@ pub struct ProjectPanel {
|
|||
fs: Arc<dyn Fs>,
|
||||
focus_handle: FocusHandle,
|
||||
scroll_handle: UniformListScrollHandle,
|
||||
// An update loop that keeps incrementing/decrementing scroll offset while there is a dragged entry that's
|
||||
// hovered over the start/end of a list.
|
||||
hover_scroll_task: Option<Task<()>>,
|
||||
visible_entries: Vec<(WorktreeId, Vec<Entry>, OnceCell<HashSet<Arc<Path>>>)>,
|
||||
/// Maps from leaf project entry ID to the currently selected ancestor.
|
||||
/// Relevant only for auto-fold dirs, where a single project panel entry may actually consist of several
|
||||
|
@ -307,6 +310,7 @@ impl ProjectPanel {
|
|||
let scroll_handle = UniformListScrollHandle::new();
|
||||
let mut this = Self {
|
||||
project: project.clone(),
|
||||
hover_scroll_task: None,
|
||||
fs: workspace.app_state().fs.clone(),
|
||||
focus_handle,
|
||||
visible_entries: Default::default(),
|
||||
|
@ -2544,6 +2548,7 @@ impl ProjectPanel {
|
|||
))
|
||||
.on_drop(cx.listener(
|
||||
move |this, external_paths: &ExternalPaths, cx| {
|
||||
this.hover_scroll_task.take();
|
||||
this.last_external_paths_drag_over_entry = None;
|
||||
this.marked_entries.clear();
|
||||
this.drop_external_files(external_paths.paths(), entry_id, cx);
|
||||
|
@ -2563,6 +2568,7 @@ impl ProjectPanel {
|
|||
style.bg(cx.theme().colors().drop_target_background)
|
||||
})
|
||||
.on_drop(cx.listener(move |this, selections: &DraggedSelection, cx| {
|
||||
this.hover_scroll_task.take();
|
||||
this.drag_onto(selections, entry_id, kind.is_file(), cx);
|
||||
}))
|
||||
.child(
|
||||
|
@ -3057,9 +3063,67 @@ impl Render for ProjectPanel {
|
|||
.map(|(_, worktree_entries, _)| worktree_entries.len())
|
||||
.sum();
|
||||
|
||||
fn handle_drag_move_scroll<T: 'static>(
|
||||
this: &mut ProjectPanel,
|
||||
e: &DragMoveEvent<T>,
|
||||
cx: &mut ViewContext<ProjectPanel>,
|
||||
) {
|
||||
if !e.bounds.contains(&e.event.position) {
|
||||
return;
|
||||
}
|
||||
this.hover_scroll_task.take();
|
||||
let panel_height = e.bounds.size.height;
|
||||
if panel_height <= px(0.) {
|
||||
return;
|
||||
}
|
||||
|
||||
let event_offset = e.event.position.y - e.bounds.origin.y;
|
||||
// How far along in the project panel is our cursor? (0. is the top of a list, 1. is the bottom)
|
||||
let hovered_region_offset = event_offset / panel_height;
|
||||
|
||||
// We want the scrolling to be a bit faster when the cursor is closer to the edge of a list.
|
||||
// These pixels offsets were picked arbitrarily.
|
||||
let vertical_scroll_offset = if hovered_region_offset <= 0.05 {
|
||||
8.
|
||||
} else if hovered_region_offset <= 0.15 {
|
||||
5.
|
||||
} else if hovered_region_offset >= 0.95 {
|
||||
-8.
|
||||
} else if hovered_region_offset >= 0.85 {
|
||||
-5.
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
let adjustment = point(px(0.), px(vertical_scroll_offset));
|
||||
this.hover_scroll_task = Some(cx.spawn(move |this, mut cx| async move {
|
||||
loop {
|
||||
let should_stop_scrolling = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.hover_scroll_task.as_ref()?;
|
||||
let handle = this.scroll_handle.0.borrow_mut();
|
||||
let offset = handle.base_handle.offset();
|
||||
|
||||
handle.base_handle.set_offset(offset + adjustment);
|
||||
cx.notify();
|
||||
Some(())
|
||||
})
|
||||
.ok()
|
||||
.flatten()
|
||||
.is_some();
|
||||
if should_stop_scrolling {
|
||||
return;
|
||||
}
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(16))
|
||||
.await;
|
||||
}
|
||||
}));
|
||||
}
|
||||
h_flex()
|
||||
.id("project-panel")
|
||||
.group("project-panel")
|
||||
.on_drag_move(cx.listener(handle_drag_move_scroll::<ExternalPaths>))
|
||||
.on_drag_move(cx.listener(handle_drag_move_scroll::<DraggedSelection>))
|
||||
.size_full()
|
||||
.relative()
|
||||
.on_hover(cx.listener(|this, hovered, cx| {
|
||||
|
@ -3291,6 +3355,7 @@ impl Render for ProjectPanel {
|
|||
move |this, external_paths: &ExternalPaths, cx| {
|
||||
this.last_external_paths_drag_over_entry = None;
|
||||
this.marked_entries.clear();
|
||||
this.hover_scroll_task.take();
|
||||
if let Some(task) = this
|
||||
.workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue