// // KMImageToolTipWindow.swift // PDF Reader Pro // // Created by tangchao on 2023/11/23. // import Cocoa class KMImageToolTipWindow: KMAnimatedBorderlessWindow { var context: KMImageToolTipContext? var point: NSPoint = .zero private let WINDOW_OFFSET = 18.0 private let ALPHA_VALUE = 0.95 private let CRITICAL_ALPHA_VALUE = 0.9 private let AUTO_HIDE_TIME_INTERVAL = 10.0 private let DEFAULT_SHOW_DELAY = 1.5 private let ALT_SHOW_DELAY = 0.2 static let shared = KMImageToolTipWindow() deinit { KMPrint("KMImageToolTipWindow deinit.") NotificationCenter.default.removeObserver(self) } convenience init() { self.init(contentRect: .zero) self.hidesOnDeactivate = false self.ignoresMouseEvents = true self.isOpaque = true self.backgroundColor = .white self.hasShadow = true self.level = NSWindow.Level(104) self.defaultAlphaValue = ALPHA_VALUE self.autoHideTimeInterval = AUTO_HIDE_TIME_INTERVAL self.context = nil self.point = .zero NotificationCenter.default.addObserver(self, selector: #selector(orderOut), name: NSApplication.willResignActiveNotification, object: NSApp) } override func orderOut(_ sender: Any?) { self.point = .zero super.orderOut(sender) } override func fadeOut() { self.context = nil self.point = .zero super.fadeOut() } override func stopAnimation() { super.stopAnimation() Self.cancelPreviousPerformRequests(withTarget: self, selector: #selector(_showDelayed), object: nil) } // MARK: - Public Methods public func showForImageContext(_ aContext: KMImageToolTipContext, at aPoint: NSPoint) { if aContext != nil { if aContext.isEqual(self.context) == false { self.point = aPoint if aContext.isEqual(self.context) == false { self.stopAnimation() self.context = aContext self.perform(#selector(_showDelayed), with: nil, afterDelay: self.isVisible ? ALT_SHOW_DELAY: DEFAULT_SHOW_DELAY) } } } } @objc func newShowForImageContext(_ aContext: KMImageToolTipContext, at aPoint: NSPoint) { self.point = aPoint if aContext.isEqual(self.context) == false { self.stopAnimation() self.context = aContext self.perform(#selector(_showDelayed), with: nil, afterDelay: self.isVisible ? ALT_SHOW_DELAY: DEFAULT_SHOW_DELAY) } } } // MARK: - Private Methods extension KMImageToolTipWindow { @objc private func _showDelayed() { let thePoint = self.point == .zero ? NSEvent.mouseLocation : self.point var contentRect: NSRect = .zero let screenRect = NSScreen.screen(for: thePoint)?.frame ?? .zero let image = self.context?.toolTipImage() if (image != nil) { self.backgroundImage = image contentRect.size = image!.size contentRect.origin.x = fmin(thePoint.x, NSMaxX(screenRect) - NSWidth(contentRect)) contentRect.origin.y = thePoint.y - WINDOW_OFFSET - NSHeight(contentRect) contentRect = self.frameRect(forContentRect: contentRect) if (NSMinY(contentRect) < NSMinX(screenRect)) { contentRect.origin.y = thePoint.y + WINDOW_OFFSET } self.setFrame(contentRect, display: false) if self.isVisible && self.alphaValue > CRITICAL_ALPHA_VALUE { self.orderFront(self) } else { self.fadeIn() } } else { self.fadeOut() } } }