123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- //
- // CDSDrawView.m
- // PDFViewer-Mac
- //
- // Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
- //
- // THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
- // AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
- // UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
- // This notice may not be removed from this file.
- //
- #import "CDSDrawView.h"
- static NSInteger _index;
- static CGPoint _points[5];
- @interface CDSDrawView ()
- @property (nonatomic,assign) BOOL cursorIsHidden;
- @property (nonatomic,assign) BOOL mouseIsInView;
- @property (nonatomic,retain) NSTouch *activeTouch;
- @property (nonatomic,retain) NSBezierPath *bezierPath;
- @property (nonatomic,assign) BOOL isInView;
- @end
- @implementation CDSDrawView
- - (void)dealloc {
-
- }
- - (id)initWithFrame:(NSRect)frameRect {
- if (self = [super initWithFrame:frameRect]) {
- self.drawImage = [[NSImage alloc] initWithSize:self.frame.size];
- self.drawColor = [NSColor colorWithDeviceRed:0 green:0 blue:0 alpha:1];
- self.strokeRadius = 0.3;
-
- _bezierPath = [[NSBezierPath alloc] init];
-
- self.wantsLayer = YES;
- self.layer.borderWidth = 1.0;
- self.layer.borderColor =[NSColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.05].CGColor;
- }
- return self;
- }
- - (id)initWithCoder:(NSCoder *)coder {
- if (self = [super initWithCoder:coder]) {
- self.drawImage = [[NSImage alloc] initWithSize:self.frame.size];
- self.drawColor = [NSColor colorWithDeviceRed:0 green:0 blue:0 alpha:1];
- self.strokeRadius = 0.3;
-
- _bezierPath = [[NSBezierPath alloc] init];
-
- self.wantsLayer = YES;
- self.layer.borderWidth = 1.0;
- self.layer.borderColor =[NSColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.05].CGColor;
- }
- return self;
- }
- - (NSBezierPath *)drawBezierPath {
- _drawBezierPath = [_bezierPath copy];
-
- CGRect rect = self.bezierPath.bounds;
- NSAffineTransform *transform = [NSAffineTransform transform];
- [transform translateXBy:- rect.origin.x + +self.bezierPath.lineWidth/2.0 yBy:-rect.origin.y + self.bezierPath.lineWidth/2.0];
- [_drawBezierPath transformUsingAffineTransform:transform];
-
- return _drawBezierPath;
- }
- /*
- ** - (BOOL) acceptsFirstResponder
- **
- ** Make sure the view will receive
- ** events.
- **
- ** Input: none
- **
- ** Output: YES to accept, NO to reject
- */
- - (BOOL)acceptsFirstResponder {
- return YES;
- }
- - (void)setIsAcceptsTouch:(BOOL)isAcceptsTouch {
- _isAcceptsTouch = isAcceptsTouch;
-
- // Accept trackpad events
- [self setAcceptsTouchEvents:isAcceptsTouch];
-
- size_t screenHeight = CGDisplayPixelsHigh(CGMainDisplayID());
- NSRect frameToWindow = [self convertRect:self.bounds toView:nil];
- NSRect frameToScreen = [self.window convertRectToScreen:frameToWindow];
- if (isAcceptsTouch) {
- // If the mouse cursor is not already hidden,
- if (!self.cursorIsHidden) {
- frameToScreen.origin.x = frameToScreen.origin.x+5;
- frameToScreen.origin.y = 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(false);
-
- // Hide the mouse cursor
- [NSCursor hide];
-
- // Remember that we detached and hid the
- // mouse cursor
- self.cursorIsHidden = YES;
- }
- } else {
- frameToScreen.origin.y = 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(true);
-
- // 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 = NO;
- }
- }
- - (void)clearImage {
- self.drawImage = nil;
- [self.bezierPath removeAllPoints];
- [self setNeedsDisplay:YES];
- }
- - (void)setDrawColor:(NSColor *)drawColor {
- if (_drawColor != drawColor) {
- _drawColor = drawColor;
- }
- [self setNeedsDisplay:YES];
- }
- - (void)setStrokeRadius:(float)strokeRadius {
- _strokeRadius = strokeRadius;
- [self setNeedsDisplay:YES];
- }
- - (NSImage *)signatureImage {
- CGRect rect = CGRectZero;
- if (self.bezierPath.empty) {
- return nil;
- } else {
- rect = self.bezierPath.bounds;
- }
-
- CGSize size = CGSizeMake(rect.size.width+self.bezierPath.lineWidth,
- rect.size.height+self.bezierPath.lineWidth);
- NSImage *image = [[NSImage alloc] initWithSize:size];
- [image lockFocus];
-
- [self.drawColor set];
- [self.drawBezierPath setLineWidth:self.strokeRadius * 2];
- [self.drawBezierPath setLineCapStyle:kCGLineCapRound];
- [self.drawBezierPath setLineJoinStyle:kCGLineJoinRound];
- [self.drawBezierPath stroke];
- [image unlockFocus];
- return image;
- }
- #pragma mark Draw
- - (void)drawRect:(NSRect)dirtyRect {
- [super drawRect:dirtyRect];
-
- [NSGraphicsContext saveGraphicsState];
- [[NSColor clearColor] set];
- if (([[self window] firstResponder] == self) && self.mouseIsInView) {
- NSSetFocusRingStyle(NSFocusRingAbove);
- }
- [[NSBezierPath bezierPathWithRect:[self bounds]] fill];
-
- [NSGraphicsContext restoreGraphicsState];
- if (self.drawImage) {
- CGRect imageFrame = [self imageFrameInRect:self.bounds];
- [self.drawImage drawInRect:imageFrame];
- }
-
- [self.drawColor set];
- [self.bezierPath setLineWidth:self.strokeRadius * 2];
- [self.bezierPath setLineCapStyle:kCGLineCapRound];
- [self.bezierPath setLineJoinStyle:kCGLineJoinRound];
- [self.bezierPath stroke];
- }
- - (CGRect)imageFrameInRect:(CGRect)rect {
- CGRect imageRect;
- if (self.drawImage.size.width < rect.size.width &&
- self.drawImage.size.height < rect.size.height) {
- imageRect.origin.x = (rect.size.width-self.drawImage.size.width)/2.0;
- imageRect.origin.y = (rect.size.height-self.drawImage.size.height)/2.0;
- imageRect.size = self.drawImage.size;
- } else {
- if (self.drawImage.size.width/self.drawImage.size.height >
- rect.size.width/rect.size.height) {
- imageRect.size.width = rect.size.width;
- imageRect.size.height = rect.size.width*self.drawImage.size.height/self.drawImage.size.width;
- } else {
- imageRect.size.height = rect.size.height;
- imageRect.size.width = rect.size.height*self.drawImage.size.width/self.drawImage.size.height;
- }
- imageRect.origin.x = (rect.size.width-imageRect.size.width)/2.0;
- imageRect.origin.y = (rect.size.height-imageRect.size.height)/2.0;
- }
- return imageRect;
- }
- #pragma mark Touch
- - (void)touchesBeganWithEvent:(NSEvent *)event {
- [super touchesBeganWithEvent:event];
-
- NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:self];
- self.activeTouch = [touches anyObject];
-
- CGPoint point = [self.activeTouch normalizedPosition];
- point.x = point.x * self.bounds.size.width;
- point.y = point.y * self.bounds.size.height;
- _index = 0;
- _points[0] = point;
- [self setNeedsDisplay:YES];
-
- if (!self.cursorIsHidden) {
- CGAssociateMouseAndMouseCursorPosition(false);
-
- [NSCursor hide];
- self.cursorIsHidden = YES;
- }
- }
- - (void)touchesMovedWithEvent:(NSEvent *)event {
- [super touchesMovedWithEvent:event];
-
- NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:self];
-
- BOOL isTouch = NO;
- for (NSTouch *touch in touches) {
- if (touch.identity == self.activeTouch.identity) {
- isTouch = YES;
- self.activeTouch = touch;
- }
- }
-
- if (!isTouch) {
- return;
- }
-
- NSPoint point = [self.activeTouch normalizedPosition];
- point.x = point.x * self.bounds.size.width;
- point.y = point.y * self.bounds.size.height;
-
- _index++;
- _points[_index] = point;
-
- if (_index == 4) {
- _points[3] = CGPointMake((_points[2].x + _points[4].x)/2.0,
- (_points[2].y + _points[4].y)/2.0);
- [self.bezierPath moveToPoint:_points[0]];
-
- [self.bezierPath curveToPoint:_points[3]
- controlPoint1:_points[1]
- controlPoint2:_points[2] ];
- _points[0] = _points[3];
- _points[1] = _points[4];
- _index = 1;
- [self setNeedsDisplay:YES];
- }
- }
- - (void)touchesEndedWithEvent:(NSEvent *)event {
- [super touchesEndedWithEvent:event];
-
- NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:self];
-
- for (NSTouch *touch in touches) {
- if (touch.identity == self.activeTouch.identity) {
- self.activeTouch = nil;
- }
- }
-
- if (_index < 4) {
- for (int i=0; i<_index; i++) {
- [self.bezierPath moveToPoint:_points[i]];
- }
- [self setNeedsDisplay:YES];
- }
- }
- - (void)touchesCancelledWithEvent:(NSEvent *)event {
- [super touchesCancelledWithEvent:event];
-
- for (int i=0; i<_index; i++) {
- [self.bezierPath moveToPoint:_points[i]];
- }
- self.activeTouch = nil;
- [self setNeedsDisplay:YES];
- }
- #pragma mark - Mouse
- - (void)viewDidMoveToWindow {
- if ([self window] != nil) {
- [self addTrackingRect:[self bounds]
- owner:self
- userData:NULL
- assumeInside:NO];
- }
- }
- - (void)mouseEntered:(NSEvent *)theEvent {
- [[self window] makeFirstResponder:self];
- self.mouseIsInView = YES;
- [self setNeedsDisplay:YES];
- }
- - (void)mouseExited:(NSEvent *)theEvent {
- self.mouseIsInView = NO;
-
- [self setNeedsDisplay:YES];
- }
- - (void)mouseDown:(NSEvent *)theEvent {
- if ([self acceptsTouchEvents]) {
- return;
- }
-
- CGPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
- if (CGRectContainsPoint(self.bounds, point)) {
- self.isInView = YES;
- _index = 0;
- _points[0] = point;
- }
- }
- - (void)mouseDragged:(NSEvent *)theEvent {
- if ([self acceptsTouchEvents]) {
- return;
- }
-
- NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
- if (CGRectContainsPoint(self.bounds, point)) {
- _index++;
- _points[_index] = point;
-
- if (_index == 4) {
- if (!self.isInView) {
- _points[3] = CGPointMake((_points[2].x + _points[4].x)/2.0,
- (_points[2].y + _points[4].y)/2.0);
- [self.bezierPath moveToPoint:_points[0]];
-
- [self.bezierPath curveToPoint:_points[3]
- controlPoint1:_points[1]
- controlPoint2:_points[2] ];
- }
- self.isInView = NO;
- _points[0] = _points[3];
- _points[1] = _points[4];
- _index = 1;
- [self setNeedsDisplay:YES];
- }
- } else {
- self.isInView = YES;
-
- _points[0] = _points[3];
- _points[1] = _points[4];
- _index = 1;
- [self setNeedsDisplay:YES];
- }
- }
- - (void)mouseUp:(NSEvent *)theEvent {
- if ([self acceptsTouchEvents]) {
- return;
- }
-
- if (_index < 4) {
- for (int i=0; i<_index; i++) {
- [self.bezierPath moveToPoint:_points[i]];
- }
- [self setNeedsDisplay:YES];
- }
- }
- - (void)keyDown:(NSEvent *)theEvent {
- NSString *chars = [theEvent characters];
- unichar character = [chars characterAtIndex: 0];
-
- if (character == 27) {
- if (self.isAcceptsTouch) {
- self.isAcceptsTouch = NO;
- if ([self.delegate respondsToSelector:@selector(drawViewDidFinishTouchMode:)]) {
- [self.delegate drawViewDidFinishTouchMode:self];
- }
- return;
- }
- }
-
- [super keyDown:theEvent];
- }
- @end
|