123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- //
- // KMDrawSignatureView.swift
- // PDF Reader Pro
- //
- // Created by lizhe on 2023/10/9.
- //
- import Cocoa
- private var _index: Int = 0
- private var _points: [CGPoint] = [CGPoint](repeating: .zero, count: 5)
- @objc protocol KMDrawViewSignatureDelegate: NSObjectProtocol {
- func drawViewDidFinishTouchMode(_ drawView: KMDrawSignatureView)
- }
- @objcMembers class KMDrawSignatureView: NSView {
- private var drawImage: NSImage?
- var drawColor: NSColor = NSColor(red: 0, green: 0, blue: 0, alpha: 1) {
- didSet {
- self.needsDisplay = true
- }
- }
- var strokeRadius: CGFloat = 0.3 {
- didSet {
- self.needsDisplay = true
- }
- }
- private var bezierPath: NSBezierPath = NSBezierPath()
- var isAcceptsTouch: Bool = false {
- willSet{
-
- }
- didSet{
- self.acceptsTouchEvents = isAcceptsTouch
- let screenHeight = CGDisplayPixelsHigh(CGMainDisplayID())
- let frameToWindow = self.convert(self.bounds, to: nil)
- var frameToScreen = self.window!.convertToScreen(frameToWindow)
- if isAcceptsTouch {
- // If the mouse cursor is not already hidden,
- if !self.cursorIsHidden {
- frameToScreen.origin.x += 5
- frameToScreen.origin.y = CGFloat(screenHeight) - frameToScreen.origin.y - 5
- CGWarpMouseCursorPosition(frameToScreen.origin)
-
- // Detach the mouse cursor from the mouse
- // hardware so that moving the mouse (or a
- // single finger) will not move the cursor
- CGAssociateMouseAndMouseCursorPosition(0)
-
- // Hide the mouse cursor
- NSCursor.hide()
-
- // Remember that we detached and hid the
- // mouse cursor
- self.cursorIsHidden = true
- }
- } else {
- frameToScreen.origin.y = CGFloat(screenHeight) - frameToScreen.origin.y
- CGWarpMouseCursorPosition(frameToScreen.origin)
-
- // Attach the mouse cursor to the mouse
- // hardware so that moving the mouse (or a
- // single finger) will move the cursor
- CGAssociateMouseAndMouseCursorPosition(1)
-
- // Show the mouse cursor
- NSCursor.unhide()
-
- // Remember that we attached and unhid the
- // mouse cursor so that the next touch that
- // begins will detach and hide it
- self.cursorIsHidden = false
- }
- }
- }
- private var cursorIsHidden: Bool = false
- private var mouseIsInView: Bool = false
- private var activeTouch: NSTouch?
-
- weak var delegate: KMDrawViewSignatureDelegate?
-
- var drawBezierPath: NSBezierPath {
- return bezierPath
- }
-
- var touchEndCallback: ((Bool) -> Void)?
- var changeDrawCallback: ((Bool) -> Void)?
-
- // override func acceptsFirstResponder() -> Bool {
- // return true
- // }
-
- override init(frame frameRect: NSRect) {
- super.init(frame: frameRect)
-
- self.drawImage = NSImage(size: self.frame.size)
- self.drawColor = NSColor(red: 0, green: 0, blue: 0, alpha: 1)
- self.strokeRadius = 0.3
-
- self.wantsLayer = true
- self.layer?.borderWidth = 1.0
- self.layer?.borderColor = NSColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.05).cgColor
- }
-
- required init?(coder: NSCoder) {
- super.init(coder: coder)
- }
-
- func clearImage() {
- self.drawImage = nil
- self.bezierPath.removeAllPoints()
- self.needsDisplay = true
- if let touchEndCallback = self.touchEndCallback {
- touchEndCallback(true)
- }
- }
-
- func signatureImage() -> NSImage? {
- var rect = CGRect.zero
-
- if bezierPath.isEmpty {
- return nil
- } else {
- rect = bezierPath.bounds
- }
-
- let size = CGSize(width: rect.size.width + bezierPath.lineWidth,
- height: rect.size.height + bezierPath.lineWidth)
-
- if size.width <= 0 && size.height <= 0 {
- return nil
- }
-
- let image = NSImage(size: self.bounds.size)
- image.lockFocus()
-
- drawColor.set()
- drawBezierPath.lineWidth = strokeRadius * 2
- drawBezierPath.lineCapStyle = .round
- drawBezierPath.lineJoinStyle = .round
- drawBezierPath.stroke()
-
- image.unlockFocus()
-
- return image
- }
-
- override func draw(_ dirtyRect: NSRect) {
- super.draw(dirtyRect)
- NSGraphicsContext.saveGraphicsState()
- NSColor.clear.set()
- if window?.firstResponder == self && mouseIsInView {
- focusRingType = .`default`
- }
-
- NSBezierPath(rect: bounds).fill()
-
- NSGraphicsContext.restoreGraphicsState()
- if let drawImage = self.drawImage {
- let imageFrame = imageFrameInRect(rect: dirtyRect)
- drawImage.draw(in: imageFrame)
- }
- drawColor.set()
- bezierPath.lineWidth = strokeRadius * 2
- bezierPath.lineCapStyle = .round
- bezierPath.lineJoinStyle = .round
- bezierPath.stroke()
- }
-
- private func imageFrameInRect(rect: CGRect) -> CGRect {
- var originX: CGFloat
- var originY: CGFloat
- var width: CGFloat
- var height: CGFloat
-
- if drawImage?.size.width ?? 0 < rect.size.width &&
- drawImage?.size.height ?? 0 < rect.size.height {
- originX = (rect.size.width - (drawImage?.size.width ?? 0)) / 2.0
- originY = (rect.size.height - (drawImage?.size.height ?? 0)) / 2.0
- width = drawImage?.size.width ?? 0
- height = drawImage?.size.height ?? 0
- } else {
- if (drawImage?.size.width ?? 0) / (drawImage?.size.height ?? 0) >
- rect.size.width / rect.size.height {
- width = rect.size.width
- height = (rect.size.width * (drawImage?.size.height ?? 0)) / (drawImage?.size.width ?? 0)
- } else {
- height = rect.size.height
- width = (rect.size.height * (drawImage?.size.width ?? 0)) / (drawImage?.size.height ?? 0)
- }
- originX = (rect.size.width - width) / 2.0
- originY = (rect.size.height - height) / 2.0
- }
-
- let rect = NSMakeRect(originX, originY, width, height)
-
- return rect
- }
-
- override func viewDidMoveToWindow() {
- if window != nil {
- addTrackingRect(bounds, owner: self, userData: nil, assumeInside: false)
- }
- }
-
- override func touchesBegan(with event: NSEvent) {
- super.touchesBegan(with: event)
- let touches = event.touches(matching: .began, in: self)
- self.activeTouch = touches.first
-
- guard let activeTouch = self.activeTouch else { return }
-
- var point = activeTouch.normalizedPosition
- point.x *= self.bounds.size.width
- point.y *= self.bounds.size.height
- _index = 0
- _points[0] = point
- self.needsDisplay = true
-
- if !self.cursorIsHidden {
- CGAssociateMouseAndMouseCursorPosition(0)
- NSCursor.hide()
- self.cursorIsHidden = true
- }
-
- if let changeDrawCallback = changeDrawCallback {
- changeDrawCallback(true)
- }
- }
-
- override func touchesMoved(with event: NSEvent) {
- super.touchesMoved(with: event)
-
- let touches = event.touches(matching: .moved, in: self)
-
- var isTouch = false
- for touch in touches {
- if touch.identity.isEqual(self.activeTouch?.identity) {
- isTouch = true
- self.activeTouch = touch
- }
- }
-
- guard isTouch else { return }
-
- var point = self.activeTouch!.normalizedPosition
- point.x *= self.bounds.size.width
- point.y *= self.bounds.size.height
-
- _index += 1
- _points[_index] = point
-
- if _index == 4 {
- _points[3] = CGPoint(x: (_points[2].x + _points[4].x)/2.0,
- y: (_points[2].y + _points[4].y)/2.0)
-
- bezierPath.move(to: _points[0])
- bezierPath.curve(to: _points[3], controlPoint1: _points[1], controlPoint2: _points[2])
-
- _points[0] = _points[3]
- _points[1] = _points[4]
- _index = 1
- self.needsDisplay = true
- }
- }
-
- override func touchesEnded(with event: NSEvent) {
- super.touchesEnded(with: event)
-
- let touches = event.touches(matching: .moved, in: self)
-
- for touch in touches {
- if touch.identity.isEqual(self.activeTouch?.identity) {
- self.activeTouch = nil
- }
- }
-
- if _index < 4 {
- for i in 0..<_index {
- bezierPath.move(to: _points[i])
- }
- self.needsDisplay = true
- }
-
- // var image = signatureImage()
- // if let changeDrawCallback = changeDrawCallback {
- // changeDrawCallback(image)
- // }
- }
-
- override func touchesCancelled(with event: NSEvent) {
- super.touchesCancelled(with: event)
-
- for i in 0..<_index {
- bezierPath.move(to: _points[i])
- }
- activeTouch = nil
- self.needsDisplay = true
- }
-
- override func mouseEntered(with event: NSEvent) {
- window?.makeFirstResponder(self)
- // self.mouseIsInView = true
- needsDisplay = true
- }
-
- override func mouseExited(with event: NSEvent) {
- // self.mouseIsInView = false
- needsDisplay = true
- }
-
- override func mouseDown(with event: NSEvent) {
- if acceptsTouchEvents {
- return
- }
-
- let point = convert(event.locationInWindow, from: nil)
- _index = 0
- _points[0] = point
- }
-
- override func mouseDragged(with event: NSEvent) {
- if acceptsTouchEvents {
- return
- }
-
- let point = convert(event.locationInWindow, from: nil)
- _index += 1
- _points[_index] = point
-
- if _index == 4 {
- _points[3] = CGPoint(x: (_points[2].x + _points[4].x) / 2.0,
- y: (_points[2].y + _points[4].y) / 2.0)
- bezierPath.move(to: _points[0])
- bezierPath.curve(to: _points[3], controlPoint1: _points[1], controlPoint2: _points[2])
- _points[0] = _points[3]
- _points[1] = _points[4]
- _index = 1
- needsDisplay = true
-
- if let changeDrawCallback = self.changeDrawCallback {
- changeDrawCallback(true)
- }
- }
- }
-
- override func mouseUp(with event: NSEvent) {
- if acceptsTouchEvents {
- return
- }
-
- if _index < 4 {
- for i in 0..<_index {
- bezierPath.move(to: _points[i])
- }
- needsDisplay = true
- }
-
- if let touchEndCallback = self.touchEndCallback {
- touchEndCallback(false)
- }
- }
-
- override func keyDown(with event: NSEvent) {
- if let characters = event.characters, characters.count > 0 {
- let character = characters.first!
- // if character == "\u{1B}" { // Check for the Escape key
- if isAcceptsTouch {
- isAcceptsTouch = false
- if let delegate = self.delegate {
- delegate.drawViewDidFinishTouchMode(self)
- }
- return
- }
- // }
- }
-
- super.keyDown(with: event)
- }
- }
|