KMDrawView.swift 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. //
  2. // KMDrawView.swift
  3. // PDF Master
  4. //
  5. // Created by lizhe on 2023/10/9.
  6. //
  7. import Cocoa
  8. private var _index: Int = 0
  9. private var _points: [CGPoint] = [CGPoint](repeating: .zero, count: 5)
  10. @objc protocol KMDrawViewDelegate: NSObjectProtocol {
  11. func drawViewDidFinishTouchMode(_ drawView: KMDrawView)
  12. }
  13. @objcMembers class KMDrawView: NSView {
  14. private var drawImage: NSImage?
  15. var drawColor: NSColor = NSColor(red: 0, green: 0, blue: 0, alpha: 1) {
  16. didSet {
  17. self.needsDisplay = true
  18. }
  19. }
  20. var strokeRadius: CGFloat = 0.3 {
  21. didSet {
  22. self.needsDisplay = true
  23. }
  24. }
  25. private var bezierPath: NSBezierPath = NSBezierPath()
  26. var isAcceptsTouch: Bool = false
  27. private var cursorIsHidden: Bool = false
  28. private var mouseIsInView: Bool = false
  29. private var activeTouch: NSTouch?
  30. weak var delegate: KMDrawViewDelegate?
  31. var drawBezierPath: NSBezierPath {
  32. return bezierPath
  33. }
  34. var touchEndCallback: ((Bool) -> Void)?
  35. var changeDrawCallback: ((Bool) -> Void)?
  36. // override func acceptsFirstResponder() -> Bool {
  37. // return true
  38. // }
  39. override init(frame frameRect: NSRect) {
  40. super.init(frame: frameRect)
  41. self.drawImage = NSImage(size: self.frame.size)
  42. self.drawColor = NSColor(red: 0, green: 0, blue: 0, alpha: 1)
  43. self.strokeRadius = 0.3
  44. self.wantsLayer = true
  45. self.layer?.borderWidth = 1.0
  46. self.layer?.borderColor = NSColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.05).cgColor
  47. }
  48. required init?(coder: NSCoder) {
  49. super.init(coder: coder)
  50. }
  51. func clearImage() {
  52. self.drawImage = nil
  53. self.bezierPath.removeAllPoints()
  54. self.needsDisplay = true
  55. if let touchEndCallback = self.touchEndCallback {
  56. touchEndCallback(true)
  57. }
  58. }
  59. func signatureImage() -> NSImage? {
  60. var rect = CGRect.zero
  61. if bezierPath.isEmpty {
  62. return nil
  63. } else {
  64. rect = bezierPath.bounds
  65. }
  66. let size = CGSize(width: rect.size.width + bezierPath.lineWidth,
  67. height: rect.size.height + bezierPath.lineWidth)
  68. if size.width <= 0 && size.height <= 0 {
  69. return nil
  70. }
  71. let image = NSImage(size: self.bounds.size)
  72. image.lockFocus()
  73. drawColor.set()
  74. drawBezierPath.lineWidth = strokeRadius * 2
  75. drawBezierPath.lineCapStyle = .round
  76. drawBezierPath.lineJoinStyle = .round
  77. drawBezierPath.stroke()
  78. image.unlockFocus()
  79. return image
  80. }
  81. override func draw(_ dirtyRect: NSRect) {
  82. super.draw(dirtyRect)
  83. NSGraphicsContext.saveGraphicsState()
  84. NSColor.clear.set()
  85. if window?.firstResponder == self && mouseIsInView {
  86. focusRingType = .`default`
  87. }
  88. NSBezierPath(rect: bounds).fill()
  89. NSGraphicsContext.restoreGraphicsState()
  90. if let drawImage = self.drawImage {
  91. let imageFrame = imageFrameInRect(rect: dirtyRect)
  92. drawImage.draw(in: imageFrame)
  93. }
  94. drawColor.set()
  95. bezierPath.lineWidth = strokeRadius * 2
  96. bezierPath.lineCapStyle = .round
  97. bezierPath.lineJoinStyle = .round
  98. bezierPath.stroke()
  99. }
  100. private func imageFrameInRect(rect: CGRect) -> CGRect {
  101. var originX: CGFloat
  102. var originY: CGFloat
  103. var width: CGFloat
  104. var height: CGFloat
  105. if drawImage?.size.width ?? 0 < rect.size.width &&
  106. drawImage?.size.height ?? 0 < rect.size.height {
  107. originX = (rect.size.width - (drawImage?.size.width ?? 0)) / 2.0
  108. originY = (rect.size.height - (drawImage?.size.height ?? 0)) / 2.0
  109. width = drawImage?.size.width ?? 0
  110. height = drawImage?.size.height ?? 0
  111. } else {
  112. if (drawImage?.size.width ?? 0) / (drawImage?.size.height ?? 0) >
  113. rect.size.width / rect.size.height {
  114. width = rect.size.width
  115. height = (rect.size.width * (drawImage?.size.height ?? 0)) / (drawImage?.size.width ?? 0)
  116. } else {
  117. height = rect.size.height
  118. width = (rect.size.height * (drawImage?.size.width ?? 0)) / (drawImage?.size.height ?? 0)
  119. }
  120. originX = (rect.size.width - width) / 2.0
  121. originY = (rect.size.height - height) / 2.0
  122. }
  123. let rect = CGRectMake(originX, originY, width, height)
  124. return rect
  125. }
  126. override func viewDidMoveToWindow() {
  127. if window != nil {
  128. addTrackingRect(bounds, owner: self, userData: nil, assumeInside: false)
  129. }
  130. }
  131. override func mouseEntered(with event: NSEvent) {
  132. window?.makeFirstResponder(self)
  133. // self.mouseIsInView = true
  134. needsDisplay = true
  135. }
  136. override func mouseExited(with event: NSEvent) {
  137. // self.mouseIsInView = false
  138. needsDisplay = true
  139. }
  140. override func mouseDown(with event: NSEvent) {
  141. if acceptsTouchEvents {
  142. return
  143. }
  144. let point = convert(event.locationInWindow, from: nil)
  145. _index = 0
  146. _points[0] = point
  147. }
  148. override func mouseDragged(with event: NSEvent) {
  149. if acceptsTouchEvents {
  150. return
  151. }
  152. let point = convert(event.locationInWindow, from: nil)
  153. _index += 1
  154. _points[_index] = point
  155. if _index == 4 {
  156. _points[3] = CGPoint(x: (_points[2].x + _points[4].x) / 2.0,
  157. y: (_points[2].y + _points[4].y) / 2.0)
  158. bezierPath.move(to: _points[0])
  159. bezierPath.curve(to: _points[3], controlPoint1: _points[1], controlPoint2: _points[2])
  160. _points[0] = _points[3]
  161. _points[1] = _points[4]
  162. _index = 1
  163. needsDisplay = true
  164. if let changeDrawCallback = self.changeDrawCallback {
  165. changeDrawCallback(true)
  166. }
  167. }
  168. }
  169. override func mouseUp(with event: NSEvent) {
  170. if acceptsTouchEvents {
  171. return
  172. }
  173. if _index < 4 {
  174. for i in 0..<_index {
  175. bezierPath.move(to: _points[i])
  176. }
  177. needsDisplay = true
  178. }
  179. if let touchEndCallback = self.touchEndCallback {
  180. touchEndCallback(false)
  181. }
  182. }
  183. override func keyDown(with event: NSEvent) {
  184. if let characters = event.characters, characters.count > 0 {
  185. let character = characters.first!
  186. // if character == "\u{1B}" { // Check for the Escape key
  187. if isAcceptsTouch {
  188. isAcceptsTouch = false
  189. if let delegate = self.delegate {
  190. delegate.drawViewDidFinishTouchMode(self)
  191. }
  192. return
  193. }
  194. // }
  195. }
  196. super.keyDown(with: event)
  197. }
  198. }