|
@@ -31,26 +31,17 @@ class KMSnapshotWindowController: NSWindowController {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ var animating = false
|
|
|
+ var thumbnail: NSImage?
|
|
|
+ var windowImage: NSImage?
|
|
|
+
|
|
|
/*
|
|
|
extern NSString *SKSnapshotCurrentSetupKey;
|
|
|
|
|
|
- @interface SKSnapshotWindowController : NSWindowController <NSWindowDelegate> {
|
|
|
- SKSnapshotPDFView* pdfView;
|
|
|
- NSImage *thumbnail;
|
|
|
- NSImage *windowImage;
|
|
|
- NSString *string;
|
|
|
- BOOL ;
|
|
|
- BOOL forceOnTop;
|
|
|
- BOOL animating;
|
|
|
- }
|
|
|
-
|
|
|
- @property (nonatomic, retain) NSImage *thumbnail;
|
|
|
@property (nonatomic, readonly) NSUInteger pageIndex;
|
|
|
- @property (nonatomic, copy) NSString *string;
|
|
|
@property (nonatomic, readonly) BOOL hasWindow;
|
|
|
@property (nonatomic, readonly) NSDictionary *pageAndWindow;
|
|
|
@property (nonatomic, readonly) NSDictionary *currentSetup;
|
|
|
- @property (nonatomic) BOOL forceOnTop;
|
|
|
|
|
|
@property (nonatomic, readonly) NSAttributedString *thumbnailAttachment, *thumbnail512Attachment, *thumbnail256Attachment, *thumbnail128Attachment, *thumbnail64Attachment, *thumbnail32Attachment;
|
|
|
|
|
@@ -85,7 +76,7 @@ class KMSnapshotWindowController: NSWindowController {
|
|
|
#define EM_DASH_CHARACTER (unichar)0x2014
|
|
|
|
|
|
|
|
|
- #define RESIZE_TIME_FACTOR 0.6
|
|
|
+
|
|
|
|
|
|
NSString *SKSnapshotCurrentSetupKey = @"currentSetup";
|
|
|
|
|
@@ -99,7 +90,8 @@ class KMSnapshotWindowController: NSWindowController {
|
|
|
@end
|
|
|
*/
|
|
|
|
|
|
- private let SMALL_DELAY = 0.1
|
|
|
+ private let SMALL_DELAY = 0.1
|
|
|
+ private let RESIZE_TIME_FACTOR = 0.6
|
|
|
|
|
|
private let PAGE_KEY = "page"
|
|
|
private let RECT_KEY = "rect"
|
|
@@ -229,6 +221,10 @@ class KMSnapshotWindowController: NSWindowController {
|
|
|
// if ([[page document] isEqual:[pdfView document]] && [self isPageVisible:page])
|
|
|
// [self setNeedsDisplayForAnnotation:annotation onPage:page];
|
|
|
}
|
|
|
+
|
|
|
+ @objc func notifiyDidFinishSetup() {
|
|
|
+ self.delegate?.snapshotControllerDidFinishSetup?(self)
|
|
|
+ }
|
|
|
/*
|
|
|
|
|
|
- (void)handleDidMoveAnnotationNotification:(NSNotification *)notification {
|
|
@@ -244,11 +240,6 @@ class KMSnapshotWindowController: NSWindowController {
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
- - (void)notifiyDidFinishSetup {
|
|
|
- [[self delegate] snapshotControllerDidFinishSetup:self];
|
|
|
- }
|
|
|
-
|
|
|
- (void)setPdfDocument:(PDFDocument *)pdfDocument setup:(NSDictionary *)setup {
|
|
|
[self setPdfDocument:pdfDocument
|
|
|
goToPageNumber:[[setup objectForKey:PAGE_KEY] unsignedIntegerValue]
|
|
@@ -371,60 +362,65 @@ class KMSnapshotWindowController: NSWindowController {
|
|
|
return YES;
|
|
|
}
|
|
|
|
|
|
- #pragma mark Thumbnails
|
|
|
+ */
|
|
|
+ // MARK: - Thumbnails
|
|
|
|
|
|
- - (NSImage *)thumbnailWithSize:(CGFloat)size {
|
|
|
- NSView *clipView = [[[pdfView documentView] enclosingScrollView] contentView];
|
|
|
- NSRect bounds = [pdfView convertRect:[clipView bounds] fromView:clipView];
|
|
|
+ func thumbnailWithSize(_ size: CGFloat) -> NSImage? {
|
|
|
+ let clipView = self.pdfView.documentView().contentView
|
|
|
+ var bounds = self.pdfView.convert(clipView.bounds, from: clipView)
|
|
|
if (CGRectEqualToRect(CGRectZero, bounds) || CGRectIsNull(bounds)) {
|
|
|
- return nil;
|
|
|
+ return nil
|
|
|
}
|
|
|
- NSBitmapImageRep *imageRep = [pdfView bitmapImageRepForCachingDisplayInRect:bounds];
|
|
|
- NSAffineTransform *transform = nil;
|
|
|
- NSSize thumbnailSize = bounds.size;
|
|
|
- CGFloat shadowBlurRadius = 0.0;
|
|
|
- CGFloat shadowOffset = 0.0;
|
|
|
- NSImage *image;
|
|
|
-
|
|
|
- [pdfView cacheDisplayInRect:bounds toBitmapImageRep:imageRep];
|
|
|
+ let imageRep = self.pdfView.bitmapImageRepForCachingDisplay(in: bounds)
|
|
|
+ var transform: NSAffineTransform?
|
|
|
+ var thumbnailSize = bounds.size
|
|
|
+ var shadowBlurRadius: CGFloat = 0.0
|
|
|
+ var shadowOffset: CGFloat = 0.0
|
|
|
+ var image: NSImage?
|
|
|
+ if let data = imageRep {
|
|
|
+ self.pdfView.cacheDisplay(in: bounds, to: data)
|
|
|
+ }
|
|
|
|
|
|
- bounds.origin = NSZeroPoint;
|
|
|
+ bounds.origin = NSZeroPoint
|
|
|
|
|
|
if (size > 0.0) {
|
|
|
- shadowBlurRadius = round(size / 32.0);
|
|
|
- shadowOffset = -ceil(shadowBlurRadius * 0.75);
|
|
|
- if (NSHeight(bounds) > NSWidth(bounds))
|
|
|
+ shadowBlurRadius = round(size / 32.0)
|
|
|
+ shadowOffset = -ceil(shadowBlurRadius * 0.75)
|
|
|
+ if (NSHeight(bounds) > NSWidth(bounds)) {
|
|
|
thumbnailSize = NSMakeSize(round((size - 2.0 * shadowBlurRadius) * NSWidth(bounds) / NSHeight(bounds) + 2.0 * shadowBlurRadius), size);
|
|
|
- else
|
|
|
+ } else {
|
|
|
thumbnailSize = NSMakeSize(size, round((size - 2.0 * shadowBlurRadius) * NSHeight(bounds) / NSWidth(bounds) + 2.0 * shadowBlurRadius));
|
|
|
- transform = [NSAffineTransform transform];
|
|
|
- [transform translateXBy:shadowBlurRadius yBy:shadowBlurRadius - shadowOffset];
|
|
|
- [transform scaleXBy:(thumbnailSize.width - 2.0 * shadowBlurRadius) / NSWidth(bounds) yBy:(thumbnailSize.height - 2.0 * shadowBlurRadius) / NSHeight(bounds)];
|
|
|
+ }
|
|
|
+ transform = NSAffineTransform()
|
|
|
+ transform?.translateX(by: shadowBlurRadius, yBy: shadowBlurRadius - shadowOffset)
|
|
|
+ transform?.scaleX(by: (thumbnailSize.width - 2.0 * shadowBlurRadius) / NSWidth(bounds), yBy: (thumbnailSize.height - 2.0 * shadowBlurRadius) / NSHeight(bounds))
|
|
|
}
|
|
|
|
|
|
if (CGSizeEqualToSize(CGSizeZero, thumbnailSize)) {
|
|
|
- return nil;
|
|
|
+ return nil
|
|
|
}
|
|
|
- image = [[[NSImage alloc] initWithSize:thumbnailSize] autorelease];
|
|
|
+ image = NSImage(size: thumbnailSize)
|
|
|
|
|
|
- if (CGSizeEqualToSize(CGSizeZero, image.size)) {
|
|
|
- return nil;
|
|
|
+ if (CGSizeEqualToSize(CGSizeZero, image!.size)) {
|
|
|
+ return nil
|
|
|
}
|
|
|
- [image lockFocus];
|
|
|
- [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
|
|
|
- [transform concat];
|
|
|
- [NSGraphicsContext saveGraphicsState];
|
|
|
- [[PDFView defaultPageBackgroundColor] set];
|
|
|
- if (shadowBlurRadius > 0.0)
|
|
|
- [NSShadow setShadowWithColor:[NSColor colorWithCalibratedWhite:0.0 alpha:0.5] blurRadius:shadowBlurRadius yOffset:shadowOffset];
|
|
|
- NSRectFill(bounds);
|
|
|
- [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationDefault];
|
|
|
- [NSGraphicsContext restoreGraphicsState];
|
|
|
- [imageRep drawInRect:bounds];
|
|
|
- [image unlockFocus];
|
|
|
+ image?.lockFocus()
|
|
|
+ NSGraphicsContext.current?.imageInterpolation = .high
|
|
|
+ transform?.concat()
|
|
|
+ NSGraphicsContext.saveGraphicsState()
|
|
|
+// [[PDFView defaultPageBackgroundColor] set];
|
|
|
+ if (shadowBlurRadius > 0.0) {
|
|
|
+// [NSShadow setShadowWithColor:[NSColor colorWithCalibratedWhite:0.0 alpha:0.5] blurRadius:shadowBlurRadius yOffset:shadowOffset];
|
|
|
+ }
|
|
|
+ __NSRectFill(bounds)
|
|
|
+ NSGraphicsContext.current?.imageInterpolation = .default
|
|
|
+ NSGraphicsContext.restoreGraphicsState()
|
|
|
+ imageRep?.draw(in: bounds)
|
|
|
+ image?.unlockFocus()
|
|
|
|
|
|
- return image;
|
|
|
+ return image
|
|
|
}
|
|
|
+ /*
|
|
|
|
|
|
- (NSAttributedString *)thumbnailAttachmentWithSize:(CGFloat)size {
|
|
|
NSImage *image = [self thumbnailWithSize:size];
|
|
@@ -466,86 +462,104 @@ class KMSnapshotWindowController: NSWindowController {
|
|
|
return [self thumbnailAttachmentWithSize:32.0];
|
|
|
}
|
|
|
|
|
|
- #pragma mark Miniaturize / Deminiaturize
|
|
|
+ */
|
|
|
+ // MARK: - Miniaturize / Deminiaturize
|
|
|
|
|
|
- - (NSRect)miniaturizedRectForDockingRect:(NSRect)dockRect {
|
|
|
- NSView *clipView = [[[pdfView documentView] enclosingScrollView] contentView];
|
|
|
- NSRect sourceRect = [clipView convertRect:[clipView bounds] toView:nil];
|
|
|
- NSRect targetRect;
|
|
|
- NSSize windowSize = [[self window] frame].size;
|
|
|
- NSSize thumbSize = [thumbnail size];
|
|
|
- CGFloat thumbRatio = thumbSize.height / thumbSize.width;
|
|
|
- CGFloat dockRatio = NSHeight(dockRect) / NSWidth(dockRect);
|
|
|
- CGFloat scaleFactor;
|
|
|
- CGFloat shadowRadius = round(fmax(thumbSize.width, thumbSize.height) / 32.0);
|
|
|
- CGFloat shadowOffset = ceil(0.75 * shadowRadius);
|
|
|
+ func miniaturizedRectForDockingRect(_ dockRect: NSRect) -> NSRect {
|
|
|
+ let clipView = self.pdfView.documentView().enclosingScrollView?.contentView
|
|
|
+ let sourceRect = clipView?.convert(clipView?.bounds ?? .zero, to: nil) ?? .zero
|
|
|
+ var targetRect: NSRect = .zero
|
|
|
+ let windowSize = self.window?.frame.size ?? .zero
|
|
|
+ let thumbSize = self.thumbnail?.size ?? .zero
|
|
|
+ var thumbRatio: CGFloat = 0
|
|
|
+ if thumbSize.width > 0 {
|
|
|
+ thumbRatio = thumbSize.height / thumbSize.width
|
|
|
+ }
|
|
|
+ var dockRatio: CGFloat = 0
|
|
|
+ if NSWidth(dockRect) > 0 {
|
|
|
+ dockRatio = NSHeight(dockRect) / NSWidth(dockRect)
|
|
|
+ }
|
|
|
+ var scaleFactor: CGFloat = 0
|
|
|
+ var shadowRadius = round(fmax(thumbSize.width, thumbSize.height) / 32.0)
|
|
|
+ var shadowOffset = ceil(0.75 * shadowRadius)
|
|
|
|
|
|
if (thumbRatio > dockRatio) {
|
|
|
- targetRect = NSInsetRect(dockRect, 0.5 * NSWidth(dockRect) * (1.0 - dockRatio / thumbRatio), 0.0);
|
|
|
- scaleFactor = NSHeight(targetRect) / thumbSize.height;
|
|
|
+ targetRect = NSInsetRect(dockRect, 0.5 * NSWidth(dockRect) * (1.0 - dockRatio / thumbRatio), 0.0)
|
|
|
+ scaleFactor = NSHeight(targetRect) / thumbSize.height
|
|
|
} else {
|
|
|
- targetRect = NSInsetRect(dockRect, 0.0, 0.5 * NSHeight(dockRect) * (1.0 - thumbRatio / dockRatio));
|
|
|
- scaleFactor = NSWidth(targetRect) / thumbSize.width;
|
|
|
+ targetRect = NSInsetRect(dockRect, 0.0, 0.5 * NSHeight(dockRect) * (1.0 - thumbRatio / dockRatio))
|
|
|
+ scaleFactor = NSWidth(targetRect) / thumbSize.width
|
|
|
}
|
|
|
- shadowRadius *= scaleFactor;
|
|
|
- shadowOffset *= scaleFactor;
|
|
|
- targetRect = NSOffsetRect(NSInsetRect(targetRect, shadowRadius, shadowRadius), 0.0, shadowOffset);
|
|
|
- scaleFactor = thumbRatio > dockRatio ? NSHeight(targetRect) / NSHeight(sourceRect) : NSWidth(targetRect) / NSWidth(sourceRect);
|
|
|
+ shadowRadius *= scaleFactor
|
|
|
+ shadowOffset *= scaleFactor
|
|
|
+ targetRect = NSOffsetRect(NSInsetRect(targetRect, shadowRadius, shadowRadius), 0.0, shadowOffset)
|
|
|
+ if thumbRatio > dockRatio {
|
|
|
+ if NSHeight(sourceRect) != 0 {
|
|
|
+ scaleFactor = NSHeight(targetRect) / NSHeight(sourceRect)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if NSWidth(sourceRect) != 0 {
|
|
|
+ scaleFactor = NSWidth(targetRect) / NSWidth(sourceRect)
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
return NSMakeRect(NSMinX(targetRect) - scaleFactor * NSMinX(sourceRect), NSMinY(targetRect) - scaleFactor * NSMinY(sourceRect), scaleFactor * windowSize.width, scaleFactor * windowSize.height);
|
|
|
}
|
|
|
|
|
|
- - (void)miniaturizeWindowFromRect:(NSRect)startRect toRect:(NSRect)endRect {
|
|
|
- if (windowImage == nil)
|
|
|
- windowImage = [[(SKSnapshotWindow *)[self window] windowImage] retain];
|
|
|
-
|
|
|
- SKAnimatedBorderlessWindow *miniaturizeWindow = [[SKAnimatedBorderlessWindow alloc] initWithContentRect:startRect];
|
|
|
- [miniaturizeWindow setLevel:NSFloatingWindowLevel];
|
|
|
- [miniaturizeWindow setBackgroundImage:windowImage];
|
|
|
+ func miniaturizeWindowFromRect(_ startRect: NSRect, toRect endRect: NSRect) {
|
|
|
+ if (self.windowImage == nil) {
|
|
|
+ self.windowImage = (self.window as? KMSnapshotWindow)?.windowImage
|
|
|
+ }
|
|
|
|
|
|
- [miniaturizeWindow orderFront:nil];
|
|
|
+ let miniaturizeWindow = KMAnimatedBorderlessWindow(contentRect: startRect)
|
|
|
+ miniaturizeWindow.level = .floating
|
|
|
+ miniaturizeWindow.backgroundImage = self.windowImage
|
|
|
+ miniaturizeWindow.orderFront(nil)
|
|
|
|
|
|
- animating = YES;
|
|
|
|
|
|
- [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
|
|
|
- [context setDuration:RESIZE_TIME_FACTOR * [miniaturizeWindow animationResizeTime:endRect]];
|
|
|
- [[miniaturizeWindow animator] setFrame:endRect display:YES];
|
|
|
- }
|
|
|
- completionHandler:^{
|
|
|
- if ([self hasWindow]) {
|
|
|
- if ([[self window] respondsToSelector:@selector(setAnimationBehavior:)])
|
|
|
- [[self window] setAnimationBehavior:NSWindowAnimationBehaviorNone];
|
|
|
- [[self window] orderFront:nil];
|
|
|
- [self updateWindowLevel];
|
|
|
- if ([[self window] respondsToSelector:@selector(setAnimationBehavior:)])
|
|
|
- [[self window] setAnimationBehavior:NSWindowAnimationBehaviorDefault];
|
|
|
- }
|
|
|
- [miniaturizeWindow orderOut:nil];
|
|
|
- animating = NO;
|
|
|
- }];
|
|
|
+ self.animating = true
|
|
|
|
|
|
- [miniaturizeWindow release];
|
|
|
+ NSAnimationContext.runAnimationGroup { context in
|
|
|
+ context.duration = RESIZE_TIME_FACTOR * miniaturizeWindow.animationResizeTime(endRect)
|
|
|
+ miniaturizeWindow.animator().setFrame(endRect, display: true)
|
|
|
+ } completionHandler: {
|
|
|
+ if self.hasWindow {
|
|
|
+ if let data = self.window?.responds(to: NSSelectorFromString("setAnimationBehavior:")), data {
|
|
|
+ self.window?.animationBehavior = .none
|
|
|
+ }
|
|
|
+ self.window?.orderFront(nil)
|
|
|
+ self._updateWindowLevel()
|
|
|
+ if let data = self.window?.responds(to: NSSelectorFromString("setAnimationBehavior:")), data {
|
|
|
+ self.window?.animationBehavior = .default
|
|
|
+ }
|
|
|
+ miniaturizeWindow.orderOut(nil)
|
|
|
+ self.animating = false
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- - (void)miniaturize {
|
|
|
- if (animating)
|
|
|
- return;
|
|
|
- if ([[self delegate] respondsToSelector:@selector(snapshotController:miniaturizedRect:)]) {
|
|
|
- NSRect dockRect = [[self delegate] snapshotController:self miniaturizedRect:YES];
|
|
|
- NSRect startRect = [[self window] frame];
|
|
|
- NSRect endRect = [self miniaturizedRectForDockingRect:dockRect];
|
|
|
+
|
|
|
+ func miniaturize() {
|
|
|
+ if (self.animating) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if let dockRect = self.delegate?.snapshotController?(self, miniaturizedRect: true) {
|
|
|
+ let startRect = self.window?.frame ?? .zero
|
|
|
+ let endRect = self.miniaturizedRectForDockingRect(dockRect)
|
|
|
|
|
|
- [self miniaturizeWindowFromRect:startRect toRect:endRect];
|
|
|
+ self.miniaturizeWindowFromRect(startRect, toRect: endRect)
|
|
|
|
|
|
- if ([[self window] respondsToSelector:@selector(setAnimationBehavior:)])
|
|
|
- [[self window] setAnimationBehavior:NSWindowAnimationBehaviorNone];
|
|
|
+ if let data = self.window?.responds(to: NSSelectorFromString("setAnimationBehavior:")), data {
|
|
|
+ self.window?.animationBehavior = .none
|
|
|
+ }
|
|
|
}
|
|
|
- [[self window] orderOut:nil];
|
|
|
- if ([[self window] respondsToSelector:@selector(setAnimationBehavior:)])
|
|
|
- [[self window] setAnimationBehavior:NSWindowAnimationBehaviorDefault];
|
|
|
- [self setHasWindow:NO];
|
|
|
+ self.window?.orderOut(nil)
|
|
|
+
|
|
|
+ if let data = self.window?.responds(to: NSSelectorFromString("setAnimationBehavior:")), data {
|
|
|
+ self.window?.animationBehavior = .default
|
|
|
+ }
|
|
|
+ self.hasWindow = false
|
|
|
}
|
|
|
-
|
|
|
+/*
|
|
|
- (void)deminiaturize {
|
|
|
if (animating)
|
|
|
return;
|
|
@@ -636,8 +650,7 @@ class KMSnapshotWindowController: NSWindowController {
|
|
|
// name:SKPDFViewDidRemoveAnnotationNotification object:nil];
|
|
|
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDidMoveAnnotationNotification:)
|
|
|
// name:SKPDFViewDidMoveAnnotationNotification object:nil];
|
|
|
-// if ([[self delegate] respondsToSelector:@selector(snapshotControllerDidFinishSetup:)])
|
|
|
-// [self performSelector:@selector(notifiyDidFinishSetup) withObject:nil afterDelay:SMALL_DELAY];
|
|
|
+ self.perform(#selector(notifiyDidFinishSetup), with: nil, afterDelay: SMALL_DELAY)
|
|
|
//
|
|
|
if self.hasWindow {
|
|
|
self.showWindow(nil)
|