KMDrawView.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. //
  2. // KMDrawView.m
  3. // PDF Reader
  4. //
  5. // Created by lxy on 2023/1/10.
  6. //
  7. #import "KMDrawView.h"
  8. static NSInteger _index;
  9. static CGPoint _points[5];
  10. @interface KMDrawView ()
  11. @property (nonatomic,assign) BOOL cursorIsHidden;
  12. @property (nonatomic,assign) BOOL mouseIsInView;
  13. @property (nonatomic,retain) NSTouch *activeTouch;
  14. @property (nonatomic,retain) NSBezierPath *bezierPath;
  15. @end
  16. @implementation KMDrawView
  17. - (void)dealloc
  18. {
  19. _delegate = nil;
  20. }
  21. - (id)initWithFrame:(NSRect)frameRect
  22. {
  23. if (self = [super initWithFrame:frameRect]) {
  24. self.drawImage = [[NSImage alloc] initWithSize:self.frame.size];
  25. self.drawColor = [NSColor colorWithDeviceRed:0 green:0 blue:0 alpha:1];
  26. self.strokeRadius = 0.3;
  27. _bezierPath = [[NSBezierPath alloc] init];
  28. self.wantsLayer = YES;
  29. self.layer.borderWidth = 1.0;
  30. self.layer.borderColor =[NSColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.05].CGColor;
  31. }
  32. return self;
  33. }
  34. - (NSBezierPath *)drawBezierPath {
  35. _drawBezierPath = _bezierPath;
  36. CGRect rect = self.bezierPath.bounds;
  37. NSAffineTransform *transform = [NSAffineTransform transform];
  38. [transform translateXBy:- rect.origin.x + +self.bezierPath.lineWidth/2.0 yBy:-rect.origin.y + self.bezierPath.lineWidth/2.0];
  39. [_drawBezierPath transformUsingAffineTransform:transform];
  40. return _drawBezierPath;
  41. }
  42. /*
  43. ** - (BOOL) acceptsFirstResponder
  44. **
  45. ** Make sure the view will receive
  46. ** events.
  47. **
  48. ** Input: none
  49. **
  50. ** Output: YES to accept, NO to reject
  51. */
  52. - (BOOL)acceptsFirstResponder
  53. {
  54. return YES;
  55. }
  56. - (void)setIsAcceptsTouch:(BOOL)isAcceptsTouch
  57. {
  58. _isAcceptsTouch = isAcceptsTouch;
  59. // Accept trackpad events
  60. [self setAcceptsTouchEvents:isAcceptsTouch];
  61. size_t screenHeight = CGDisplayPixelsHigh(CGMainDisplayID());
  62. NSRect frameToWindow = [self convertRect:self.bounds toView:nil];
  63. NSRect frameToScreen = [self.window convertRectToScreen:frameToWindow];
  64. if (isAcceptsTouch) {
  65. // If the mouse cursor is not already hidden,
  66. if (!self.cursorIsHidden) {
  67. frameToScreen.origin.x = frameToScreen.origin.x+5;
  68. frameToScreen.origin.y = screenHeight-frameToScreen.origin.y-5;
  69. CGWarpMouseCursorPosition(frameToScreen.origin);
  70. // Detach the mouse cursor from the mouse
  71. // hardware so that moving the mouse (or a
  72. // single finger) will not move the cursor
  73. CGAssociateMouseAndMouseCursorPosition(false);
  74. // Hide the mouse cursor
  75. [NSCursor hide];
  76. // Remember that we detached and hid the
  77. // mouse cursor
  78. self.cursorIsHidden = YES;
  79. }
  80. } else {
  81. frameToScreen.origin.y = screenHeight-frameToScreen.origin.y;
  82. CGWarpMouseCursorPosition(frameToScreen.origin);
  83. // Attach the mouse cursor to the mouse
  84. // hardware so that moving the mouse (or a
  85. // single finger) will move the cursor
  86. CGAssociateMouseAndMouseCursorPosition(true);
  87. // Show the mouse cursor
  88. [NSCursor unhide];
  89. // Remember that we attached and unhid the
  90. // mouse cursor so that the next touch that
  91. // begins will detach and hide it
  92. self.cursorIsHidden = NO;
  93. }
  94. }
  95. - (void)clearImage
  96. {
  97. self.drawImage = nil;
  98. [self.bezierPath removeAllPoints];
  99. [self setNeedsDisplay:YES];
  100. if (self.touchEndCallback) {
  101. self.touchEndCallback(YES);
  102. }
  103. }
  104. - (void)setDrawColor:(NSColor *)drawColor
  105. {
  106. _drawColor = drawColor;
  107. [self setNeedsDisplay:YES];
  108. }
  109. - (void)setStrokeRadius:(float)strokeRadius
  110. {
  111. _strokeRadius = strokeRadius;
  112. [self setNeedsDisplay:YES];
  113. }
  114. - (NSImage *)signatureImage {
  115. CGRect rect = CGRectZero;
  116. if (self.bezierPath.empty) {
  117. return nil;
  118. } else {
  119. rect = self.bezierPath.bounds;
  120. }
  121. CGSize size = CGSizeMake(rect.size.width+self.bezierPath.lineWidth,
  122. rect.size.height+self.bezierPath.lineWidth);
  123. //修改崩溃 “签名,触摸板,再选中左下角触摸板,崩溃了”
  124. if (size.width <= 0 && size.height <= 0) {
  125. return nil;
  126. }
  127. NSImage *image = [[NSImage alloc] initWithSize:size];
  128. [image lockFocus];
  129. [self.drawColor set];
  130. [self.drawBezierPath setLineWidth:self.strokeRadius * 2];
  131. [self.drawBezierPath setLineCapStyle:kCGLineCapRound];
  132. [self.drawBezierPath setLineJoinStyle:kCGLineJoinRound];
  133. [self.drawBezierPath stroke];
  134. [image unlockFocus];
  135. return image;
  136. }
  137. #pragma mark Draw
  138. - (void)drawRect:(NSRect)dirtyRect {
  139. [super drawRect:dirtyRect];
  140. [NSGraphicsContext saveGraphicsState];
  141. [[NSColor clearColor] set];
  142. if (([[self window] firstResponder] == self) && self.mouseIsInView) {
  143. NSSetFocusRingStyle(NSFocusRingAbove);
  144. }
  145. [[NSBezierPath bezierPathWithRect:[self bounds]] fill];
  146. [NSGraphicsContext restoreGraphicsState];
  147. if (self.drawImage) {
  148. CGRect imageFrame = [self imageFrameInRect:dirtyRect];
  149. [self.drawImage drawInRect:imageFrame];
  150. }
  151. [self.drawColor set];
  152. [self.bezierPath setLineWidth:self.strokeRadius * 2];
  153. [self.bezierPath setLineCapStyle:kCGLineCapRound];
  154. [self.bezierPath setLineJoinStyle:kCGLineJoinRound];
  155. [self.bezierPath stroke];
  156. }
  157. - (CGRect)imageFrameInRect:(CGRect)rect {
  158. CGRect imageRect;
  159. if (self.drawImage.size.width < rect.size.width &&
  160. self.drawImage.size.height < rect.size.height) {
  161. imageRect.origin.x = (rect.size.width-self.drawImage.size.width)/2.0;
  162. imageRect.origin.y = (rect.size.height-self.drawImage.size.height)/2.0;
  163. imageRect.size = self.drawImage.size;
  164. } else {
  165. if (self.drawImage.size.width/self.drawImage.size.height >
  166. rect.size.width/rect.size.height) {
  167. imageRect.size.width = rect.size.width;
  168. imageRect.size.height = rect.size.width*self.drawImage.size.height/self.drawImage.size.width;
  169. } else {
  170. imageRect.size.height = rect.size.height;
  171. imageRect.size.width = rect.size.height*self.drawImage.size.width/self.drawImage.size.height;
  172. }
  173. imageRect.origin.x = (rect.size.width-imageRect.size.width)/2.0;
  174. imageRect.origin.y = (rect.size.height-imageRect.size.height)/2.0;
  175. }
  176. return imageRect;
  177. }
  178. #pragma mark Touch
  179. - (void)touchesBeganWithEvent:(NSEvent *)event
  180. {
  181. [super touchesBeganWithEvent:event];
  182. NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:self];
  183. self.activeTouch = [touches anyObject];
  184. CGPoint point = [self.activeTouch normalizedPosition];
  185. point.x = point.x * self.bounds.size.width;
  186. point.y = point.y * self.bounds.size.height;
  187. _index = 0;
  188. _points[0] = point;
  189. [self setNeedsDisplay:YES];
  190. if (!self.cursorIsHidden) {
  191. CGAssociateMouseAndMouseCursorPosition(false);
  192. [NSCursor hide];
  193. self.cursorIsHidden = YES;
  194. }
  195. if (self.changeDrawCallback) {
  196. self.changeDrawCallback(YES);
  197. }
  198. }
  199. - (void)touchesMovedWithEvent:(NSEvent *)event
  200. {
  201. [super touchesMovedWithEvent:event];
  202. NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:self];
  203. BOOL isTouch = NO;
  204. for (NSTouch *touch in touches) {
  205. if (touch.identity == self.activeTouch.identity) {
  206. isTouch = YES;
  207. self.activeTouch = touch;
  208. }
  209. }
  210. if (!isTouch) {
  211. return;
  212. }
  213. NSPoint point = [self.activeTouch normalizedPosition];
  214. point.x = point.x * self.bounds.size.width;
  215. point.y = point.y * self.bounds.size.height;
  216. _index++;
  217. _points[_index] = point;
  218. if (_index == 4) {
  219. _points[3] = CGPointMake((_points[2].x + _points[4].x)/2.0,
  220. (_points[2].y + _points[4].y)/2.0);
  221. [self.bezierPath moveToPoint:_points[0]];
  222. [self.bezierPath curveToPoint:_points[3]
  223. controlPoint1:_points[1]
  224. controlPoint2:_points[2] ];
  225. _points[0] = _points[3];
  226. _points[1] = _points[4];
  227. _index = 1;
  228. [self setNeedsDisplay:YES];
  229. }
  230. }
  231. - (void)touchesEndedWithEvent:(NSEvent *)event
  232. {
  233. [super touchesEndedWithEvent:event];
  234. NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:self];
  235. for (NSTouch *touch in touches) {
  236. if (touch.identity == self.activeTouch.identity) {
  237. self.activeTouch = nil;
  238. }
  239. }
  240. if (_index < 4) {
  241. for (int i=0; i<_index; i++) {
  242. [self.bezierPath moveToPoint:_points[i]];
  243. }
  244. [self setNeedsDisplay:YES];
  245. }
  246. // NSImage *image = [self signatureImage];
  247. // if (self.changeDrawCallback) {
  248. // self.changeDrawCallback(image);
  249. // }
  250. if (self.touchEndCallback) {
  251. self.touchEndCallback(NO);
  252. }
  253. }
  254. - (void)touchesCancelledWithEvent:(NSEvent *)event
  255. {
  256. [super touchesCancelledWithEvent:event];
  257. for (int i=0; i<_index; i++) {
  258. [self.bezierPath moveToPoint:_points[i]];
  259. }
  260. self.activeTouch = nil;
  261. [self setNeedsDisplay:YES];
  262. }
  263. #pragma mark Mouse
  264. - (void)viewDidMoveToWindow
  265. {
  266. if ([self window] != nil) {
  267. [self addTrackingRect:[self bounds]
  268. owner:self
  269. userData:NULL
  270. assumeInside:NO];
  271. }
  272. }
  273. - (void)mouseEntered:(NSEvent *)theEvent
  274. {
  275. [[self window] makeFirstResponder:self];
  276. // self.mouseIsInView = YES;
  277. [self setNeedsDisplay:YES];
  278. }
  279. - (void)mouseExited:(NSEvent *)theEvent
  280. {
  281. // self.mouseIsInView = NO;
  282. [self setNeedsDisplay:YES];
  283. }
  284. - (void)mouseDown:(NSEvent *)theEvent
  285. {
  286. if ([self acceptsTouchEvents]) {
  287. return;
  288. }
  289. CGPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
  290. _index = 0;
  291. _points[0] = point;
  292. }
  293. - (void)mouseDragged:(NSEvent *)theEvent
  294. {
  295. if ([self acceptsTouchEvents]) {
  296. return;
  297. }
  298. NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
  299. _index++;
  300. _points[_index] = point;
  301. if (_index == 4) {
  302. _points[3] = CGPointMake((_points[2].x + _points[4].x)/2.0,
  303. (_points[2].y + _points[4].y)/2.0);
  304. [self.bezierPath moveToPoint:_points[0]];
  305. [self.bezierPath curveToPoint:_points[3]
  306. controlPoint1:_points[1]
  307. controlPoint2:_points[2] ];
  308. _points[0] = _points[3];
  309. _points[1] = _points[4];
  310. _index = 1;
  311. [self setNeedsDisplay:YES];
  312. if (self.changeDrawCallback) {
  313. self.changeDrawCallback(YES);
  314. }
  315. }
  316. }
  317. - (void)mouseUp:(NSEvent *)theEvent
  318. {
  319. if ([self acceptsTouchEvents]) {
  320. return;
  321. }
  322. if (_index < 4) {
  323. for (int i=0; i<_index; i++) {
  324. [self.bezierPath moveToPoint:_points[i]];
  325. }
  326. [self setNeedsDisplay:YES];
  327. }
  328. if (self.touchEndCallback) {
  329. self.touchEndCallback(NO);
  330. }
  331. }
  332. - (void)keyDown:(NSEvent *)theEvent
  333. {
  334. NSString *chars = [theEvent characters];
  335. if(chars.length > 0) {
  336. unichar character = [chars characterAtIndex:0];
  337. // if (character == 27) {
  338. if (self.isAcceptsTouch) {
  339. self.isAcceptsTouch = NO;
  340. if ([self.delegate respondsToSelector:@selector(drawViewDidFinishTouchMode:)]) {
  341. [self.delegate drawViewDidFinishTouchMode:self];
  342. }
  343. return;
  344. }
  345. // }
  346. }
  347. [super keyDown:theEvent];
  348. }
  349. @end