CPDFDigtalView.m 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. //
  2. // CPDFDigtalView.m
  3. // PDF Reader Pro Edition
  4. //
  5. // Created by Niehaoyu on 2023/10/10.
  6. //
  7. #import "CPDFDigtalView.h"
  8. #import "CPDFAnnotation+PDFListView.h"
  9. #import "NSGeometry+PDFListView.h"
  10. #import "CPDFListViewConfig.h"
  11. #define HANDLE_SIZE 4.0
  12. #define MIN_NOTE_SIZE 8.0
  13. @implementation CPDFDigtalView
  14. - (void)drawRect:(NSRect)dirtyRect {
  15. [super drawRect:dirtyRect];
  16. // Drawing code here.
  17. }
  18. - (id)initWithFrame:(NSRect)frameRect {
  19. self = [super initWithFrame:frameRect];
  20. if (self) {
  21. [self setUp];
  22. }
  23. return self;
  24. }
  25. - (id)initWithCoder:(NSCoder *)decoder {
  26. self = [super initWithCoder:decoder];
  27. if (self) {
  28. [self setUp];
  29. }
  30. return self;
  31. }
  32. - (void)setUp {
  33. self.annotationType = CAnnotationTypeSignature;
  34. self.activeAnnotations = [NSMutableArray array];
  35. }
  36. - (void)setDocument:(CPDFDocument *)document {
  37. [super setDocument:document];
  38. NSArray *signatures = document.signatures;
  39. NSMutableArray *tempArr = [NSMutableArray array];
  40. for (CPDFSignature *signature in signatures) {
  41. if(signature.signers.count > 0) {
  42. [signature verifySignatureWithDocument:document];
  43. [tempArr addObject:signature];
  44. }
  45. }
  46. self.signatures = tempArr;
  47. }
  48. - (CPDFPage *)pageAndPoint:(NSPoint *)point forEvent:(NSEvent *)event nearest:(BOOL)nearest {
  49. NSPoint p = [self convertPoint:[event locationInWindow] fromView:nil];
  50. CPDFPage *page = [self pageForPoint:p nearest:nearest];
  51. if (page && point)
  52. *point = [self convertPoint:p toPage:page];
  53. return page;
  54. }
  55. - (void)setCursorForMouse:(NSEvent *)theEvent {
  56. if (theEvent == nil)
  57. theEvent = [NSEvent mouseEventWithType:NSEventTypeMouseMoved
  58. location:[[self window] mouseLocationOutsideOfEventStream]
  59. modifierFlags:[NSEvent standardPDFListViewModifierFlags]
  60. timestamp:0
  61. windowNumber:[[self window] windowNumber]
  62. context:nil
  63. eventNumber:0
  64. clickCount:1
  65. pressure:0.0];
  66. [self setCursorForAreaOfInterest:[self areaOfInterestForMouse:theEvent]];
  67. }
  68. - (CPDFAnnotation *)activeAnnotation {
  69. return self.activeAnnotations.lastObject;
  70. }
  71. - (void)mouseDown:(NSEvent *)theEvent {
  72. [self setCursorForMouse:theEvent];
  73. NSPoint point = NSZeroPoint;
  74. CPDFAreaOfInterest area = [self areaOfInterestForMouse:theEvent];
  75. NSPoint newpoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
  76. area = [self areaOfInterestForPoint:newpoint];
  77. CPDFAnnotation *newActiveAnnotation = nil;
  78. if ([[self document] isLocked]) {
  79. [super mouseDown:theEvent];
  80. } else if ([self doClickAnnotationWithEvent:theEvent forAnnotation:&newActiveAnnotation]) {
  81. [self doDragAnnotationWithEvent:theEvent forAnnotation:newActiveAnnotation];
  82. } else {
  83. [self doDragAddAnnotationWithEvent:theEvent];
  84. }
  85. }
  86. - (BOOL)doClickAnnotationWithEvent:(NSEvent *)theEvent forAnnotation:(CPDFAnnotation **)annotation{
  87. CPDFAnnotation *newActiveAnnotation = nil;
  88. NSPoint point = NSZeroPoint;
  89. CPDFPage *page = [self pageAndPoint:&point forEvent:theEvent nearest:YES];
  90. NSMutableArray *currentActiveAnnotations = [NSMutableArray array];
  91. for (CPDFAnnotation *an in self.activeAnnotations) {
  92. if([an.page isEqual:page]) {
  93. if(!([an isKindOfClass:[CPDFMarkupAnnotation class]] || [an isKindOfClass:[CPDFTextAnnotation class]])) {
  94. [currentActiveAnnotations addObject:an];
  95. }
  96. }
  97. }
  98. newActiveAnnotation = [self doSelectAnnotationWithEvent:theEvent];
  99. *annotation = newActiveAnnotation;
  100. return !!newActiveAnnotation;
  101. }
  102. - (CPDFAnnotation *)doSelectAnnotationWithEvent:(NSEvent *)theEvent {
  103. CPDFAnnotation *newActiveAnnotation = nil;
  104. NSPoint point = NSZeroPoint;
  105. CPDFPage *page = [self pageAndPoint:&point forEvent:theEvent nearest:YES];
  106. id annotations = [page annotations];
  107. for (CPDFAnnotation *annotation in annotations) {
  108. if ([annotation hitTest:point] && [annotation annotationShouldDisplay] ) {
  109. newActiveAnnotation = annotation;
  110. break;
  111. }
  112. }
  113. return newActiveAnnotation;
  114. }
  115. - (void)doDragAnnotationWithEvent:(NSEvent *)theEvent forAnnotation:(CPDFAnnotation *)newActiveAnnotation {
  116. BOOL isContains = YES;
  117. if (self.activeAnnotations.count == 0 || ![self.activeAnnotations containsObject:newActiveAnnotation]) {
  118. isContains = NO;
  119. }
  120. NSRect originalBounds = [newActiveAnnotation bounds];
  121. BOOL isLine = [newActiveAnnotation isKindOfClass:[CPDFLineAnnotation class]];
  122. NSPoint pagePoint = NSZeroPoint;
  123. CPDFPage *page = [self pageAndPoint:&pagePoint forEvent:theEvent nearest:YES];
  124. NSPoint originalStartPoint = NSZeroPoint;
  125. NSPoint originalEndPoint = NSZeroPoint;
  126. BOOL draggedAnnotation = NO;
  127. NSEvent *lastMouseEvent = theEvent;
  128. NSPoint offset = CPDFListViewSubstractPoints(pagePoint, originalBounds.origin);
  129. NSUInteger eventMask = NSEventMaskLeftMouseUp | NSEventMaskLeftMouseDragged;
  130. CGFloat mouseOffset = [self unitWidthOnPage:page];
  131. while (YES) {
  132. theEvent = [[self window] nextEventMatchingMask:eventMask];
  133. if ([theEvent type] == NSEventTypeLeftMouseUp) {
  134. if(draggedAnnotation) {
  135. if (!isContains)
  136. [self.selectAnnotations removeAllObjects];
  137. } else {
  138. if(self.activeAnnotations.count == 1 &&
  139. self.activeAnnotation == newActiveAnnotation &&
  140. ([newActiveAnnotation isKindOfClass:[CPDFTextAnnotation class]] || [newActiveAnnotation isKindOfClass:[CPDFFreeTextAnnotation class]])) {
  141. [self editAnnotation:newActiveAnnotation];
  142. break;
  143. }
  144. if(!isContains) {
  145. [self updateActiveAnnotations:@[newActiveAnnotation]];
  146. }
  147. [self editAnnotation:newActiveAnnotation];
  148. }
  149. [self setNeedsDisplayAnnotationViewForPage:page];
  150. break;
  151. } else if ([theEvent type] == NSEventTypeLeftMouseDragged) {
  152. NSPoint point = NSZeroPoint;
  153. [self pageAndPoint:&point forEvent:theEvent nearest:YES];
  154. CGRect zRect = CGRectMake(pagePoint.x-2*mouseOffset, pagePoint.y-2*mouseOffset, 4*mouseOffset, 4*mouseOffset);
  155. if (CGRectContainsPoint(zRect, point)) {continue;}
  156. lastMouseEvent = theEvent;
  157. draggedAnnotation = YES;
  158. if(!isContains) {
  159. [self dragAnnotationReferenceLine:newActiveAnnotation];
  160. [self.selectAnnotations removeAllObjects];
  161. [self.selectAnnotations addObject:newActiveAnnotation];
  162. [self doMoveAnnotation:newActiveAnnotation withEvent:lastMouseEvent offset:offset];
  163. } else {
  164. if ([newActiveAnnotation isKindOfClass:[CPDFStampAnnotation class]] ||
  165. [newActiveAnnotation isKindOfClass:[CPDFFreeTextAnnotation class]] ||
  166. [newActiveAnnotation isKindOfClass:[CPDFSignatureAnnotation class]] ||
  167. [newActiveAnnotation isKindOfClass:[CPDFWidgetAnnotation class]]) {
  168. [newActiveAnnotation updateAppearanceStream];
  169. }
  170. }
  171. [self dragAnnotationReferenceLine:newActiveAnnotation];
  172. [self setNeedsDisplayAnnotationViewForPage:page];
  173. }
  174. }
  175. [self performSelector:@selector(setCursorForMouse:) withObject:theEvent afterDelay:0];
  176. }
  177. - (void)doMoveAnnotation:(CPDFAnnotation *)activeAnnotation withEvent:(NSEvent *)theEvent offset:(NSPoint)offset {
  178. // Move annotation.
  179. [[[self documentView] contentView] autoscroll:theEvent];
  180. NSPoint point = NSZeroPoint;
  181. CPDFPage *newActivePage = [self pageAndPoint:&point forEvent:theEvent nearest:YES];
  182. if (newActivePage) { // newActivePage should never be nil, but just to be sure
  183. if (newActivePage != [activeAnnotation page]) {
  184. return;
  185. }
  186. NSRect newBounds = [activeAnnotation bounds];
  187. newBounds.origin = CPDFListViewIntegralPoint(CPDFListViewSubstractPoints(point, offset));
  188. // constrain bounds inside page bounds
  189. }
  190. }
  191. - (void)dragAnnotationReferenceLine:(CPDFAnnotation *)annotation {
  192. // if ([self isAlignedWithOtherForms:annotation] && annotation) {
  193. // CGRect bounds = annotation.bounds;
  194. // NSRect rect = [self convertRect:bounds fromPage:self.currentPage];
  195. // [self drawLineOfDashByCAShapeLayer:rect];
  196. // }
  197. }
  198. - (void)editAnnotation:(CPDFAnnotation *)annotation {
  199. if ([annotation isKindOfClass:[CPDFFreeTextAnnotation class]]) {
  200. [self editAnnotationFreeText:(CPDFFreeTextAnnotation *)annotation];
  201. [[self window] makeFirstResponder:self];
  202. [self setNeedsDisplayAnnotation:annotation];
  203. } else {
  204. if([annotation isKindOfClass:[CPDFSignatureWidgetAnnotation class]]) {
  205. if([self.pdfListViewDelegate respondsToSelector:@selector(PDFListViewEditAnnotation:forAnnotation:)]) {
  206. [self.pdfListViewDelegate PDFListViewEditAnnotation:self forAnnotation:annotation];
  207. }
  208. }
  209. }
  210. }
  211. - (void)doDragAddAnnotationWithEvent:(NSEvent *)theEvent {
  212. NSPoint pagePoint = NSZeroPoint;
  213. CPDFPage *page = [self pageAndPoint:&pagePoint forEvent:theEvent nearest:YES];
  214. NSRect originalBounds = CGRectZero;
  215. CGFloat mouseOffset = [self unitWidthOnPage:page];
  216. // [self setCursorForAreaOfInterest:CAreaOfInterestForResizeHandle(CMaxXEdgeMask | CMinYEdgeMask, page)];
  217. CPDFAnnotation *annotation = nil;
  218. originalBounds = CPDFListViewRectFromCenterAndSquareSize(CPDFListViewIntegralPoint(pagePoint), 0.0);
  219. CRectEdges resizeHandle = CMaxXEdgeMask | CMinYEdgeMask;
  220. BOOL draggedAnnotation = NO;
  221. NSEvent *lastMouseEvent = theEvent;
  222. NSUInteger eventMask = NSEventMaskLeftMouseUp | NSEventMaskLeftMouseDragged;
  223. while (YES) {
  224. theEvent = [[self window] nextEventMatchingMask:eventMask];
  225. if ([theEvent type] == NSEventTypeLeftMouseUp) {
  226. if (!draggedAnnotation) {
  227. if (annotation) {
  228. break;
  229. }
  230. if(CAnnotationTypeLine == self.annotationType ||
  231. CAnnotationTypeArrow == self.annotationType) {
  232. } else {
  233. CGFloat defaultWidth = 72;
  234. CGFloat defaultHeight = 32;
  235. NSSize defaultSize = ([page rotation] % 180 == 0) ? NSMakeSize(defaultWidth, defaultHeight) : NSMakeSize(defaultHeight, defaultWidth);
  236. CGRect bounds = CGRectZero;
  237. bounds = CPDFListViewRectFromCenterAndSize(CPDFListViewIntegralPoint(pagePoint), defaultSize);
  238. bounds = CPDFListViewConstrainRect(bounds, page.bounds,[CPDFListViewConfig defaultManager].annotationBorderOffset.floatValue);
  239. annotation = [self addAnnotationWithType:self.annotationType selection:nil page:page bounds:bounds];
  240. originalBounds = [annotation bounds];
  241. if(annotation) {
  242. [self updateActiveAnnotations:@[annotation]];
  243. [self setNeedsDisplayAnnotation:annotation];
  244. } else if(self.activeAnnotations.count >0) {
  245. [self updateActiveAnnotations:@[]];
  246. [self setNeedsDisplayAnnotationViewForPage:page];
  247. }
  248. }
  249. } else {
  250. }
  251. break;
  252. } else if ([theEvent type] == NSEventTypeLeftMouseDragged) {
  253. CGPoint zPoint = pagePoint;
  254. [self pageAndPoint:&zPoint forEvent:theEvent nearest:YES];
  255. CGRect zRect = CGRectMake(pagePoint.x-2*mouseOffset, pagePoint.y-2*mouseOffset, 4*mouseOffset, 4*mouseOffset);
  256. if (CGRectContainsPoint(zRect, zPoint)) {continue;}
  257. if (annotation == nil)
  258. annotation = [self addAnnotationWithType:self.annotationType selection:nil page:page bounds:CPDFListViewRectFromCenterAndSquareSize(originalBounds.origin, 0.0)];
  259. if(annotation) {
  260. [self updateActiveAnnotations:@[annotation]];
  261. } else if(self.activeAnnotations.count >0) {
  262. [self updateActiveAnnotations:@[]];
  263. [self setNeedsDisplayAnnotationViewForPage:page];
  264. }
  265. lastMouseEvent = theEvent;
  266. draggedAnnotation = YES;
  267. [self setNeedsDisplayAnnotationViewForPage:page];
  268. }
  269. [self doResizeAnnotationWithEvent:lastMouseEvent fromPoint:pagePoint originalBounds:originalBounds resizeHandle:&resizeHandle];
  270. }
  271. if (annotation) {
  272. [self setNeedsDisplayAnnotation:annotation];
  273. if ([self.pdfListViewDelegate respondsToSelector:@selector(PDFListViewAddAnnotation:forAddAnnotation:inPage:)]) {
  274. [self.pdfListViewDelegate PDFListViewAddAnnotation:self forAddAnnotation:annotation inPage:page];
  275. }
  276. }
  277. [self performSelector:@selector(setCursorForMouse:) withObject:theEvent afterDelay:0];
  278. }
  279. - (void)setNeedsDisplayAnnotation:(CPDFAnnotation *)annotation {
  280. if (annotation) {
  281. [self setNeedsDisplayAnnotationViewForPage:annotation.page];
  282. } else {
  283. [self setNeedsDisplayAnnotationViewForVisiblePages];
  284. }
  285. }
  286. - (CGFloat)unitWidthOnPage:(CPDFPage *)page {
  287. return NSWidth([self convertRect:NSMakeRect(0.0, 0.0, 1.0, 1.0) toPage:page]);
  288. }
  289. - (CPDFAnnotation *)addAnnotationWithType:(CAnnotationType)annotationType selection:(CPDFSelection *)selection page:(CPDFPage *)page bounds:(NSRect)bounds {
  290. CPDFAnnotation *annotation = nil;
  291. NSString *text = [selection PDFListViewCleanedString];
  292. BOOL isInitial = NO;
  293. if(selection) {
  294. CGRect noteRect = selection.bounds;
  295. isInitial = NSEqualSizes(noteRect.size, NSZeroSize);
  296. } else {
  297. isInitial = NSEqualSizes(bounds.size, NSZeroSize);
  298. }
  299. if (isInitial)
  300. bounds = CPDFListViewRectFromCenterAndSquareSize(bounds.origin, 8.0);
  301. switch (annotationType) {
  302. case CAnnotationTypeSignature:
  303. annotation = [[CPDFSignatureWidgetAnnotation alloc] initPDFListViewNoteWithDocument:self.document];
  304. annotation.bounds = bounds;
  305. break;
  306. default:
  307. break;
  308. }
  309. if (annotation) {
  310. if (annotationType != CAnnotationTypeLine && annotationType != CAnnotationTypeArrow && annotationType != CAnnotationTypeInk && [text length] > 0)
  311. [annotation setString:text];
  312. [self addAnnotation:annotation toPage:page];
  313. }
  314. return annotation;
  315. }
  316. - (void)updateActiveAnnotations:(NSArray<CPDFAnnotation *> *)activeAnnotations {
  317. [self refreshActiveAnnotations:activeAnnotations isRight:NO];
  318. }
  319. - (void)addAnnotation:(CPDFAnnotation *)annotation toPage:(CPDFPage *)page {
  320. // [[[self undoManager] prepareWithInvocationTarget:self] removeAnnotation:annotation];
  321. [annotation setModificationDate:[NSDate date]];
  322. //widget设置作者与fieldName冲突
  323. if (![annotation isKindOfClass:[CPDFWidgetAnnotation class]]) {
  324. [annotation setUserName:CPDFKitShareConfig.annotationAuthor?:NSFullUserName()];
  325. }
  326. [page addAnnotation:annotation];
  327. [self setNeedsDisplayAnnotation:annotation];
  328. [[self undoManager] setActionName:NSLocalizedString(@"Add Note", @"Undo action name")];
  329. }
  330. - (void)refreshActiveAnnotations:(NSArray<CPDFAnnotation *> *)activeAnnotations isRight:(BOOL)isRight {
  331. if(activeAnnotations) {
  332. NSArray *selectTure = [activeAnnotations filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF in %@", self.activeAnnotations]];
  333. BOOL isSame = NO;
  334. if(self.activeAnnotations.count == activeAnnotations.count && self.activeAnnotations.count == selectTure.count) isSame = YES;
  335. if(!isSame) {
  336. self.activeAnnotations = [NSMutableArray arrayWithArray:activeAnnotations];
  337. }
  338. } else if (!activeAnnotations && self.activeAnnotations.count > 0) {
  339. [self.activeAnnotations removeAllObjects];
  340. }
  341. }
  342. - (void)doResizeAnnotationWithEvent:(NSEvent *)theEvent fromPoint:(NSPoint)originalPagePoint originalBounds:(NSRect)originalBounds resizeHandle:(CRectEdges *)resizeHandlePtr {
  343. CPDFAnnotation *activeAnnotation = self.activeAnnotation;
  344. NSPoint pagePoint = NSZeroPoint;
  345. CPDFPage *page = activeAnnotation?activeAnnotation.page:[self pageAndPoint:&pagePoint forEvent:theEvent nearest:YES];
  346. NSRect newBounds = originalBounds;
  347. NSRect pageBounds = [page boundsForBox:[self displayBox]];
  348. NSPoint currentPagePoint = [self convertPoint:[theEvent locationInPDFListView:self] toPage:page];
  349. NSPoint relPoint = CPDFListViewSubstractPoints(currentPagePoint, originalPagePoint);
  350. CRectEdges resizeHandle = *resizeHandlePtr;
  351. if (NSEqualSizes(originalBounds.size, NSZeroSize)) {
  352. CRectEdges currentResizeHandle = (relPoint.x < 0.0 ? CMinXEdgeMask : CMaxXEdgeMask) | (relPoint.y <= 0.0 ? CMinYEdgeMask : CMaxYEdgeMask);
  353. if (currentResizeHandle != resizeHandle) {
  354. *resizeHandlePtr = resizeHandle = currentResizeHandle;
  355. // [self setCursorForAreaOfInterest:CAreaOfInterestForResizeHandle(resizeHandle, page)];
  356. }
  357. }
  358. BOOL isRadioOrCheckButton = NO;
  359. if ([activeAnnotation isKindOfClass:[CPDFButtonWidgetAnnotation class]]) {
  360. CPDFButtonWidgetAnnotation *annotation = (CPDFButtonWidgetAnnotation *)activeAnnotation;
  361. if (CPDFWidgetRadioButtonControl == annotation.controlType ||
  362. CPDFWidgetCheckBoxControl == annotation.controlType) {
  363. isRadioOrCheckButton = YES;
  364. }
  365. }
  366. CGFloat minWidth = MIN_NOTE_SIZE;
  367. CGFloat minHeight = MIN_NOTE_SIZE;
  368. CGFloat offsetPageSet = 2;
  369. if ((resizeHandle & CMaxXEdgeMask)) {
  370. newBounds.size.width += relPoint.x;
  371. if (NSMaxX(newBounds)+offsetPageSet > NSMaxX(pageBounds))
  372. newBounds.size.width = NSMaxX(pageBounds) - NSMinX(newBounds)-offsetPageSet;
  373. if (NSWidth(newBounds) < minWidth) {
  374. newBounds.size.width = minWidth;
  375. }
  376. } else if ((resizeHandle & CMinXEdgeMask)) {
  377. newBounds.origin.x += relPoint.x;
  378. newBounds.size.width -= relPoint.x;
  379. if (NSMinX(newBounds)-offsetPageSet < NSMinX(pageBounds)) {
  380. newBounds.size.width = NSMaxX(newBounds) - NSMinX(pageBounds)-offsetPageSet;
  381. newBounds.origin.x = NSMinX(pageBounds)+offsetPageSet;
  382. }
  383. if (NSWidth(newBounds) < minWidth) {
  384. newBounds.origin.x = NSMaxX(newBounds) - minWidth;
  385. newBounds.size.width = minWidth;
  386. }
  387. }
  388. if ((resizeHandle & CMaxYEdgeMask)) {
  389. newBounds.size.height += relPoint.y;
  390. if (NSMaxY(newBounds)+ offsetPageSet > NSMaxY(pageBounds)) {
  391. newBounds.size.height = NSMaxY(pageBounds) - NSMinY(newBounds)- offsetPageSet;
  392. }
  393. if (NSHeight(newBounds) < minHeight) {
  394. newBounds.size.height = minHeight;
  395. }
  396. } else if ((resizeHandle & CMinYEdgeMask)) {
  397. newBounds.origin.y += relPoint.y;
  398. newBounds.size.height -= relPoint.y;
  399. if (NSMinY(newBounds)-offsetPageSet < NSMinY(pageBounds)) {
  400. newBounds.size.height = NSMaxY(newBounds) - NSMinY(pageBounds)-offsetPageSet;
  401. newBounds.origin.y = NSMinY(pageBounds)+offsetPageSet;
  402. }
  403. if (NSHeight(newBounds) < minHeight) {
  404. newBounds.origin.y = NSMaxY(newBounds) - minHeight;
  405. newBounds.size.height = minHeight;
  406. }
  407. }
  408. [activeAnnotation setBounds:NSIntegralRect(newBounds)];
  409. if ([activeAnnotation isKindOfClass:[CPDFFreeTextAnnotation class]]) {
  410. [self updateAnnotationFreeTextBounds:(CPDFFreeTextAnnotation *)activeAnnotation];
  411. }
  412. }
  413. #pragma mark - NSMenu
  414. - (NSMenu *)menuForEvent:(NSEvent *)event {
  415. if (self.annotationType == CAnnotationTypeInk || self.annotationType == CAnnotationTypeEraser) {
  416. return nil;
  417. }
  418. NSMenu *menu = [super menuForEvent:event];
  419. if(!menu)
  420. menu = [[NSMenu alloc] init];
  421. NSPoint pagePoint = NSZeroPoint;
  422. CPDFPage *page = [self pageAndPoint:&pagePoint forEvent:event nearest:YES];
  423. NSMenuItem * copyItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Copy", @"PDFListView") action:@selector(copy:) keyEquivalent:@"c"];
  424. NSMenuItem * pasteItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Paste", @"PDFListView") action:@selector(menuItemClick_Paste:) keyEquivalent:@"v"];
  425. pasteItem.representedObject = event;
  426. NSMenuItem * cutItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Cut", @"PDFListView") action:@selector(cut:) keyEquivalent:@"x"];
  427. NSMenuItem * deleteItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Delete", @"PDFListView") action:@selector(delete:) keyEquivalent:@""];
  428. NSMenu *subMenu = nil;
  429. NSMenuItem * arrangementItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Arrangement", @"PDFListView") action:nil keyEquivalent:@""];
  430. subMenu = [[NSMenu alloc] init];
  431. NSMenuItem * bringForwardItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Bring Forward", @"PDFListView") action:@selector(menuItemClick_BringForward:) keyEquivalent:@""];
  432. NSMenuItem * sendBackForwardItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Send Backward", @"PDFListView") action:@selector(menuItemClick_SendBackward:) keyEquivalent:@""];
  433. NSMenuItem * bringFrontItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Bring to Front", @"PDFListView") action:@selector(menuItemClick_BringFront:) keyEquivalent:@""];
  434. NSMenuItem * sendBackItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Send to Back", @"PDFListView") action:@selector(menuItemClick_SendBack:) keyEquivalent:@""];
  435. [subMenu addItem:bringForwardItem];
  436. [subMenu addItem:sendBackForwardItem];
  437. [subMenu addItem:bringFrontItem];
  438. [subMenu addItem:sendBackItem];
  439. arrangementItem.submenu = subMenu;
  440. NSMenuItem * editNoteItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Edit Note", @"PDFListView") action:@selector(menuItemClick_EditNote:) keyEquivalent:@""];
  441. if(0) {
  442. } else {
  443. CPDFAnnotation *annotation = nil;
  444. for (CPDFAnnotation *tAnnotation in page.annotations) {
  445. if ([tAnnotation hitTest:pagePoint]) {
  446. annotation = tAnnotation;
  447. break;
  448. }
  449. }
  450. if (annotation && [annotation isKindOfClass:[CPDFWidgetAnnotation class]] ){
  451. }
  452. if(annotation) {
  453. if(![self.activeAnnotations containsObject:annotation]) {
  454. [self updateIsRightActiveAnnotations:@[annotation]];
  455. [self setNeedsDisplayAnnotation:annotation];
  456. }
  457. }
  458. if(annotation && [annotation isKindOfClass:[CPDFWidgetAnnotation class]]) {
  459. annotation = nil;
  460. } else if(annotation && [annotation isKindOfClass:[CPDFRedactAnnotation class]]) {
  461. annotation = nil;
  462. } else if (annotation && [annotation isKindOfClass:[CPDFInkAnnotation class]] && [self annotationType] == CAnnotationTypeInk) {
  463. annotation = nil;
  464. }
  465. CPDFSelection *selection = [self creatImageCurrentSelectionForPoint:[event locationInPDFListView:self]];
  466. if(selection && CPDFSelectionTypeImage == [selection selectionType] && !self.activeAnnotation){
  467. self.currentSelection = selection;
  468. }
  469. NSMenu *subMenu = [[NSMenu alloc] init];
  470. if(self.activeAnnotations.count == 1) {
  471. // NSMenuItem * lineStyleItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Line Style", @"PDFListView") action:@selector(menuItemClick_LineStyle:) keyEquivalent:@""];
  472. //
  473. // subMenu = [[NSMenu alloc] init];
  474. // NSMenuItem * lineSolidItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Solid", @"PDFListView") action:@selector(menuItemClick_LineStyle:) keyEquivalent:@""];
  475. // lineSolidItem.tag = CPDFBorderStyleSolid;
  476. // NSMenuItem * lineDashedItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Dashed", @"PDFListView") action:@selector(menuItemClick_LineStyle:) keyEquivalent:@""];
  477. // lineDashedItem.tag = CPDFBorderStyleDashed;
  478. //
  479. // [subMenu addItem:lineSolidItem];
  480. // [subMenu addItem:lineDashedItem];
  481. // lineStyleItem.submenu = subMenu;
  482. //
  483. // NSMenuItem * changeColorItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Color...", @"PDFListView") action:@selector(menuItemClick_ChangeColor:) keyEquivalent:@""];
  484. // [menu insertItem:arrangementItem atIndex:0];
  485. // [menu insertItem:[NSMenuItem separatorItem] atIndex:0];
  486. // if([self.activeAnnotation isKindOfClass:[CPDFMarkupAnnotation class]] ||
  487. // [self.activeAnnotation isKindOfClass:[CPDFStampAnnotation class]] ||
  488. // [self.activeAnnotation isKindOfClass:[CPDFSignatureAnnotation class]]) {
  489. // [menu insertItem:editNoteItem atIndex:0];
  490. // } else if ([self.activeAnnotation isKindOfClass:[CPDFInkAnnotation class]]) {
  491. // [menu insertItem:editNoteItem atIndex:0];
  492. // [menu insertItem:lineStyleItem atIndex:0];
  493. // [menu insertItem:changeColorItem atIndex:0];
  494. // } else if ([self.activeAnnotation isKindOfClass:[CPDFTextAnnotation class]]) {
  495. // [menu insertItem:editNoteItem atIndex:0];
  496. // [menu insertItem:changeColorItem atIndex:0];
  497. // } else if ([self.activeAnnotation isKindOfClass:[CPDFSquareAnnotation class]] ||
  498. // [self.activeAnnotation isKindOfClass:[CPDFCircleAnnotation class]] ||
  499. // [self.activeAnnotation isKindOfClass:[CPDFLineAnnotation class]]) {
  500. // [menu insertItem:editNoteItem atIndex:0];
  501. // if([self.activeAnnotation isKindOfClass:[CPDFLineAnnotation class]]) {
  502. // NSMenuItem * directionItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Direction", @"PDFListView") action:nil keyEquivalent:@""];
  503. // subMenu = [[NSMenu alloc]init];
  504. //
  505. // NSMenuItem * lineHorizontalItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Horizontal", @"PDFListView") action:@selector(menuItemClick_LineHorizontal:) keyEquivalent:@""];
  506. // NSMenuItem * lineVerticalItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Vertical", @"PDFListView") action:@selector(menuItemClick_LineVertical:) keyEquivalent:@""];
  507. // [subMenu addItem:lineHorizontalItem];
  508. // [subMenu addItem:lineVerticalItem];
  509. // directionItem.submenu = subMenu;
  510. //
  511. // [menu insertItem:directionItem atIndex:0];
  512. // }
  513. // [menu insertItem:lineStyleItem atIndex:0];
  514. // [menu insertItem:changeColorItem atIndex:0];
  515. // }
  516. if ([self.activeAnnotation isKindOfClass:[CPDFSignatureWidgetAnnotation class]]) {
  517. CPDFSignatureWidgetAnnotation *aa = (CPDFSignatureWidgetAnnotation *)self.activeAnnotation;
  518. CPDFSignature *aaa = aa.signature;
  519. [menu insertItem:[NSMenuItem separatorItem] atIndex:0];
  520. [menu insertItem:deleteItem atIndex:0];
  521. }
  522. // if(![self.activeAnnotation isKindOfClass:[CPDFMarkupAnnotation class]]) {
  523. // if ([[NSPasteboard generalPasteboard] canReadObjectForClasses:[NSArray arrayWithObjects:[CPDFAnnotation class], [NSString class],[NSImage class], nil] options:[NSDictionary dictionary]]) {
  524. // [menu insertItem:pasteItem atIndex:0];
  525. // }
  526. // [menu insertItem:cutItem atIndex:0];
  527. // }
  528. // [menu insertItem:copyItem atIndex:0];
  529. __block typeof(self) blockSelf = self;
  530. } else if (self.activeAnnotations.count > 1) {
  531. BOOL isMarkupAn = NO;
  532. for (CPDFAnnotation *annotation in self.activeAnnotations) {
  533. if([annotation isKindOfClass:[CPDFMarkupAnnotation class]]) {
  534. isMarkupAn = YES;
  535. break;
  536. }
  537. }
  538. // [menu insertItem:arrangementItem atIndex:0];
  539. [menu insertItem:[NSMenuItem separatorItem] atIndex:0];
  540. [menu insertItem:deleteItem atIndex:0];
  541. if(!isMarkupAn) {
  542. [menu insertItem:cutItem atIndex:0];
  543. [menu insertItem:copyItem atIndex:0];
  544. }
  545. } else if (self.currentSelection) {
  546. if(CPDFSelectionTypeImage == [self.currentSelection selectionType]) {
  547. NSMenuItem * exportImageItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Export…", nil) action:@selector(menuItemClick_ExportImage:) keyEquivalent:@""];
  548. [menu insertItem:exportImageItem atIndex:0];
  549. [menu insertItem:[NSMenuItem separatorItem] atIndex:0];
  550. }
  551. if ([[NSPasteboard generalPasteboard] canReadObjectForClasses:[NSArray arrayWithObjects:[CPDFAnnotation class], [NSString class],[NSImage class], nil] options:[NSDictionary dictionary]]) {
  552. [menu insertItem:pasteItem atIndex:0];
  553. }
  554. [menu insertItem:copyItem atIndex:0];
  555. } else if (!self.activeAnnotation) {
  556. // NSMenuItem * pageDisplayItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Page Display", @"PDFListView") action:nil keyEquivalent:@""];
  557. // subMenu = [[NSMenu alloc] init];
  558. //
  559. // NSMenuItem * twoPagesContinuousItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Two Pages Continuous", @"PDFListView") action:@selector(menuItemClick_TwoPagesContinuous:) keyEquivalent:@""];
  560. // NSMenuItem * twoPagesItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Two Pages", @"PDFListView") action:@selector(menuItemClick_TwoPages:) keyEquivalent:@""];
  561. // NSMenuItem * singlePageContinuousItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Single Page Continuous", @"PDFListView") action:@selector(menuItemClick_SinglePagesContinuous:) keyEquivalent:@""];
  562. // NSMenuItem * singlePageItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Single Page", @"PDFListView") action:@selector(menuItemClick_SinglePage:) keyEquivalent:@""];
  563. // NSMenuItem * bookModeItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Book Mode", @"PDFListView") action:@selector(menuItemClick_BookMode:) keyEquivalent:@""];
  564. // switch (self.displayViewMode) {
  565. // case CPDFDisplayViewSinglePageContinuous:
  566. // singlePageContinuousItem.state = NSControlStateValueOn;
  567. // break;
  568. // case CPDFDisplayViewTwoUp:
  569. // if (self.displaysAsBook)
  570. // bookModeItem.state = NSControlStateValueOn;
  571. // else
  572. // twoPagesItem.state = NSControlStateValueOn;
  573. // break;
  574. // case CPDFDisplayViewTwoUpContinuous:
  575. // if (self.displaysAsBook)
  576. // bookModeItem.state = NSControlStateValueOn;
  577. // else
  578. // twoPagesContinuousItem.state = NSControlStateValueOn;
  579. // break;
  580. // default:
  581. // case CPDFDisplayViewSinglePage:
  582. // singlePageItem.state = NSControlStateValueOn;
  583. // break;
  584. // }
  585. //
  586. // [subMenu addItem:singlePageItem];
  587. // [subMenu addItem:singlePageContinuousItem];
  588. // [subMenu addItem:twoPagesItem];
  589. // [subMenu addItem:twoPagesContinuousItem];
  590. // [subMenu addItem:bookModeItem];
  591. // pageDisplayItem.submenu = subMenu;
  592. //
  593. // [menu insertItem:pageDisplayItem atIndex:0];
  594. //
  595. // NSMenuItem *zoomItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Zoom", @"PDFListView") action:nil keyEquivalent:@""];
  596. // subMenu = [[NSMenu alloc]init];
  597. //
  598. // NSMenuItem * fitWidthItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Fit Width", @"PDFListView") action:@selector(menuItemClick_FitWidth:) keyEquivalent:@""];
  599. // NSMenuItem * automaticallyItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Automatically Resize", @"PDFListView") action:@selector(menuItemClick_AutomaticallyResize:) keyEquivalent:@""];
  600. // NSMenuItem * actualSizeItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Actual Size", @"PDFListView") action:@selector(menuItemClick_ActualSize:) keyEquivalent:@""];
  601. // NSMenuItem * zoomInItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Zoom In", @"PDFListView") action:@selector(menuItemClick_ZoomIn:) keyEquivalent:@""];
  602. // NSMenuItem * zoomOutItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Zoom Out", @"PDFListView") action:@selector(menuItemClick_ZoomOut:) keyEquivalent:@""];
  603. //
  604. // NSMenuItem * hidenShowNoteItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Hide Notes", @"PDFListView") action:@selector(menuItemClick_HidenorShowNote:) keyEquivalent:@""];
  605. //
  606. // if (self.autoScales) {
  607. // automaticallyItem.state = NSControlStateValueOn;
  608. // } else if (self.scaleFactor == 1.0) {
  609. // actualSizeItem.state = NSControlStateValueOn;
  610. // }
  611. //
  612. //
  613. //
  614. // [subMenu addItem:fitWidthItem];
  615. // [subMenu addItem:automaticallyItem];
  616. // [subMenu addItem:actualSizeItem];
  617. // [subMenu addItem:zoomInItem];
  618. // [subMenu addItem:zoomOutItem];
  619. // zoomItem.submenu = subMenu;
  620. // [menu insertItem:zoomItem atIndex:0];
  621. //
  622. // [menu insertItem:[NSMenuItem separatorItem] atIndex:0];
  623. // [menu insertItem:hidenShowNoteItem atIndex:0];
  624. // [menu insertItem:[NSMenuItem separatorItem] atIndex:0];
  625. // [menu insertItem:pasteItem atIndex:0];
  626. }
  627. }
  628. // if ([self.pdfListViewDelegate respondsToSelector:@selector(PDFListViewMenuForEvent:forEvent:clickMenu:)]) {
  629. // [self.pdfListViewDelegate PDFListViewMenuForEvent:self forEvent:event clickMenu:&menu];
  630. // }
  631. return menu;
  632. }
  633. - (void)updateIsRightActiveAnnotations:(NSArray<CPDFAnnotation *> *)activeAnnotations {
  634. [self refreshActiveAnnotations:activeAnnotations isRight:YES];
  635. }
  636. - (IBAction)delete:(id)sender {
  637. if (self.activeAnnotations.count > 0 ) {
  638. NSMutableArray *tarr = [NSMutableArray arrayWithArray:self.activeAnnotations];
  639. for (CPDFAnnotation * an in tarr) {
  640. // if(self.hoverAnnotation == an) {
  641. // self.hoverAnnotation = nil;
  642. // }
  643. [self removeAnnotation:an];
  644. [[self undoManager] setActionName:NSLocalizedString(@"Remove Note", @"Undo action name")];
  645. if([an isKindOfClass:[CPDFFreeTextAnnotation class]]) {
  646. CPDFFreeTextAnnotation *freeTextAn = (CPDFFreeTextAnnotation *)an;
  647. if ([self isEditWithCurrentFreeText:freeTextAn]) {
  648. [self commitEditAnnotationFreeText:freeTextAn];
  649. }
  650. }
  651. }
  652. [self removeActiveAnnotations:tarr];
  653. } else {
  654. NSBeep();
  655. }
  656. }
  657. - (void)removeAnnotation:(CPDFAnnotation *)annotation {
  658. CPDFAnnotation *wasAnnotation = annotation;
  659. CPDFPage *page = wasAnnotation.page;
  660. [[[self undoManager] prepareWithInvocationTarget:self] addAnnotation:wasAnnotation toPage:page];
  661. [page removeAnnotation:wasAnnotation];
  662. [self annotationsChangedOnPage:page];
  663. [self setNeedsDisplayAnnotation:wasAnnotation];
  664. // dispatch_async(dispatch_get_main_queue(), ^{
  665. // [[NSNotificationCenter defaultCenter] postNotificationName:CPDFListViewDidRemoveAnnotationNotification object:self
  666. // userInfo:[NSDictionary dictionaryWithObjectsAndKeys:wasAnnotation, CPDFListViewAnnotationKey, page, CPDFListViewPageKey, nil]];
  667. // });
  668. //
  669. // if([self.pdfListViewDelegate respondsToSelector:@selector(PDFListViewRemoveAnnotations:forRemoveAnnotations:inPage:)])
  670. // [self.pdfListViewDelegate PDFListViewRemoveAnnotations:self forRemoveAnnotations:@[annotation] inPage:page];
  671. }
  672. - (void)removeActiveAnnotations:(NSArray<CPDFAnnotation *> *)removeAnnotations {
  673. BOOL isContains = NO;
  674. NSMutableArray *tarr = [NSMutableArray arrayWithArray:self.activeAnnotations];
  675. [tarr removeObjectsInArray:removeAnnotations];
  676. self.activeAnnotations = tarr;
  677. isContains = YES;
  678. if(isContains) {
  679. if([self.pdfListViewDelegate respondsToSelector:@selector(PDFListViewDeleteAnnotation:forAnnotation:)])
  680. [self.pdfListViewDelegate PDFListViewDeleteAnnotation:self forAnnotation:removeAnnotations.firstObject];
  681. dispatch_async(dispatch_get_main_queue(), ^{
  682. [[NSNotificationCenter defaultCenter] postNotificationName:CPDFListViewActiveAnnotationsChangeNotification object:self];
  683. });
  684. }
  685. // if(isContains) {
  686. // if([self.pdfListViewDelegate respondsToSelector:@selector(PDFListViewChangeatioActiveAnnotations:forActiveAnnotations:isRightMenu:)])
  687. // [self.pdfListViewDelegate PDFListViewChangeatioActiveAnnotations:self forActiveAnnotations:self.activeAnnotations isRightMenu:NO];
  688. //
  689. // dispatch_async(dispatch_get_main_queue(), ^{
  690. // [[NSNotificationCenter defaultCenter] postNotificationName:CPDFListViewActiveAnnotationsChangeNotification object:self];
  691. // });
  692. // }
  693. }
  694. @end