|
29 | 29 | } |
30 | 30 |
|
31 | 31 | func updateNSView(_ nsView: DragNSView, context: Context) { |
| 32 | + nsView.panelSide = panelSide |
32 | 33 | nsView.files = files |
| 34 | + nsView.dragDropManager = dragDropManager |
| 35 | + nsView.appState = appState |
33 | 36 | } |
34 | 37 | } |
35 | 38 |
|
|
40 | 43 | weak var dragDropManager: DragDropManager? |
41 | 44 | weak var appState: AppState? |
42 | 45 |
|
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 |
44 | 49 |
|
45 | | - guard let appState else { return } |
| 50 | + override func acceptsFirstMouse(for event: NSEvent?) -> Bool { |
| 51 | + true |
| 52 | + } |
46 | 53 |
|
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 | + } |
48 | 59 |
|
49 | | - guard !selectedFiles.isEmpty else { return } |
| 60 | + override func mouseUp(with event: NSEvent) { |
| 61 | + didStartDragging = false |
| 62 | + super.mouseUp(with: event) |
| 63 | + } |
50 | 64 |
|
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 } |
52 | 69 |
|
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) |
54 | 74 |
|
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 | + } |
58 | 79 |
|
59 | | - let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem) |
| 80 | + let selectedPaths = appState.markedFiles(for: panelSide) |
| 81 | + let selectedURLs = selectedPaths.map { URL(fileURLWithPath: $0) } |
60 | 82 |
|
61 | | - let frame = self.bounds |
62 | | - draggingItem.setDraggingFrame(frame, contents: nil) |
| 83 | + guard !selectedURLs.isEmpty else { return } |
63 | 84 |
|
| 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) |
64 | 94 | return draggingItem |
65 | 95 | } |
66 | 96 |
|
|
71 | 101 | _ session: NSDraggingSession, |
72 | 102 | sourceOperationMaskFor context: NSDraggingContext |
73 | 103 | ) -> 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))") |
75 | 121 | } |
76 | 122 | } |
0 commit comments