oficina / sheets Public

Clone
git clone https://amadan.net/oficina/sheets

Plain git — no account needed to clone.

Download

Download this file

1#if os(macOS)
2import AppKit
3import SwiftUI
4
5struct SheetResizeHandle: NSViewRepresentable {
6 let vertical: Bool
7 let canBegin: () -> Bool
8 let change: (Double) -> Void
9 let finish: () -> Void
10 let cancel: () -> Void
11 var fit: (() -> Void)? = nil
12 func makeNSView(context: Context) -> Handle { Handle() }
13 func updateNSView(_ view: Handle, context: Context) { view.actions = self }
14 final class Handle: NSControl {
15 override func draw(_ dirtyRect: NSRect) {
16 NSColor.secondaryLabelColor.withAlphaComponent(0.15).setFill()
17 // Keep the 8-point mouse target, but paint only the grid boundary.
18 let pixel = 1 / (window?.backingScaleFactor ?? 2)
19 let rule = actions?.vertical == true
20 ? NSRect(x: bounds.minX, y: bounds.minY, width: bounds.width, height: pixel)
21 : NSRect(x: bounds.maxX - pixel, y: bounds.minY, width: pixel, height: bounds.height)
22 rule.fill()
23 }
24 var actions: SheetResizeHandle?
25 private var start: NSPoint?
26 private var moved = false
27 private weak var previousResponder: NSResponder?
28 override var acceptsFirstResponder: Bool { true }
29 override func acceptsFirstMouse(for event: NSEvent?) -> Bool { true }
30 override func resetCursorRects() {
31 addCursorRect(bounds, cursor: actions?.vertical == true ? .resizeUpDown : .resizeLeftRight)
32 }
33 override func mouseDown(with event: NSEvent) {
34 guard actions?.canBegin() == true else { return }
35 if event.clickCount == 2, let fit = actions?.fit { fit(); return }
36 previousResponder = window?.firstResponder
37 window?.makeFirstResponder(self)
38 start = event.locationInWindow; moved = false
39 }
40 override func mouseDragged(with event: NSEvent) {
41 guard let start else { return }
42 let amount = actions?.vertical == true ? start.y - event.locationInWindow.y : event.locationInWindow.x - start.x
43 guard moved || abs(amount) >= 2 else { return }
44 moved = true; actions?.change(amount)
45 }
46 override func mouseUp(with event: NSEvent) {
47 guard start != nil else { return }
48 if moved { actions?.finish() }
49 reset()
50 }
51 override func keyDown(with event: NSEvent) {
52 if event.keyCode == 53 { actions?.cancel(); reset() } else { super.keyDown(with: event) }
53 }
54 override func viewWillMove(toWindow newWindow: NSWindow?) {
55 if newWindow == nil, start != nil { actions?.cancel(); reset() }
56 super.viewWillMove(toWindow: newWindow)
57 }
58 private func reset() {
59 start = nil; moved = false
60 if window?.firstResponder === self { window?.makeFirstResponder(previousResponder) }
61 previousResponder = nil
62 }
63 }
64}
65#endif
66