Skip to content

Commit 4489593

Browse files
author
Iakov Senatov
committed
Implement AppKit multi-file drag via DragOverlayView
1 parent 612c9dc commit 4489593

File tree

2 files changed

+246
-192
lines changed

2 files changed

+246
-192
lines changed

GUI/Sources/Features/Panels/FileTable/DragOverlayView.swift

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@
2929
}
3030

3131
func updateNSView(_ nsView: DragNSView, context: Context) {
32+
nsView.panelSide = panelSide
3233
nsView.files = files
34+
nsView.dragDropManager = dragDropManager
35+
nsView.appState = appState
3336
}
3437
}
3538

@@ -40,27 +43,54 @@
4043
weak var dragDropManager: DragDropManager?
4144
weak var appState: AppState?
4245

43-
override func mouseDragged(with event: NSEvent) {
46+
private var mouseDownPoint: NSPoint = .zero
47+
private let dragThreshold: CGFloat = 4.0
48+
private var didStartDragging = false
4449

45-
guard let appState else { return }
50+
override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
51+
true
52+
}
4653

47-
let selectedFiles = appState.markedFiles(for: panelSide)
54+
override func mouseDown(with event: NSEvent) {
55+
mouseDownPoint = convert(event.locationInWindow, from: nil)
56+
didStartDragging = false
57+
super.mouseDown(with: event)
58+
}
4859

49-
guard !selectedFiles.isEmpty else { return }
60+
override func mouseUp(with event: NSEvent) {
61+
didStartDragging = false
62+
super.mouseUp(with: event)
63+
}
5064

51-
log.debug("[DragOverlay] starting AppKit drag with \(selectedFiles.count) file(s)")
65+
override func mouseDragged(with event: NSEvent) {
66+
67+
guard !didStartDragging else { return }
68+
guard let appState, let panelSide else { return }
5269

53-
let draggingItems: [NSDraggingItem] = selectedFiles.map { file in
70+
let currentPoint = convert(event.locationInWindow, from: nil)
71+
let deltaX = currentPoint.x - mouseDownPoint.x
72+
let deltaY = currentPoint.y - mouseDownPoint.y
73+
let dragDistance = hypot(deltaX, deltaY)
5474

55-
let pasteboardItem = NSPasteboardItem()
56-
let fileURL = URL(fileURLWithPath: file)
57-
pasteboardItem.setString(fileURL.absoluteString, forType: .fileURL)
75+
guard dragDistance >= dragThreshold else {
76+
super.mouseDragged(with: event)
77+
return
78+
}
5879

59-
let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem)
80+
let selectedPaths = appState.markedFiles(for: panelSide)
81+
let selectedURLs = selectedPaths.map { URL(fileURLWithPath: $0) }
6082

61-
let frame = self.bounds
62-
draggingItem.setDraggingFrame(frame, contents: nil)
83+
guard !selectedURLs.isEmpty else { return }
6384

85+
didStartDragging = true
86+
log.debug("[DragOverlay] starting AppKit drag with \(selectedURLs.count) file(s)")
87+
88+
let draggingItems: [NSDraggingItem] = selectedURLs.map { fileURL in
89+
let draggingItem = NSDraggingItem(pasteboardWriter: fileURL as NSURL)
90+
let icon = NSWorkspace.shared.icon(forFile: fileURL.path)
91+
icon.size = NSSize(width: 32, height: 32)
92+
let draggingFrame = NSRect(origin: .zero, size: icon.size)
93+
draggingItem.setDraggingFrame(draggingFrame, contents: icon)
6494
return draggingItem
6595
}
6696

@@ -71,6 +101,22 @@
71101
_ session: NSDraggingSession,
72102
sourceOperationMaskFor context: NSDraggingContext
73103
) -> NSDragOperation {
74-
return .copy
104+
switch context {
105+
case .outsideApplication:
106+
return [.copy, .move]
107+
case .withinApplication:
108+
return [.move]
109+
@unknown default:
110+
return [.copy]
111+
}
112+
}
113+
114+
func ignoreModifierKeys(for session: NSDraggingSession) -> Bool {
115+
false
116+
}
117+
118+
func draggingSession(_ session: NSDraggingSession, endedAt screenPoint: NSPoint, operation: NSDragOperation) {
119+
didStartDragging = false
120+
log.debug("[DragOverlay] drag ended operation=\(String(describing: operation.rawValue))")
75121
}
76122
}

0 commit comments

Comments
 (0)