123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- //
- // KMTocOutlineView.swift
- // PDF Reader Pro
- //
- // Created by tangchao on 2023/11/17.
- //
- import Cocoa
- @objc protocol KMTocOutlineViewDelegate: KMCustomOutlineViewDelegate {
- @objc optional func outlineView(_ anOutlineView: NSOutlineView, highlightLevelForRow row: Int) -> Int
- @objc optional func outlineView(_ anOutlineView: NSOutlineView, imageContextForItem item: Any?) -> AnyObject?
- }
- class KMTocOutlineView: KMCustomOutlineView {
- weak var tocDelegate: KMTocOutlineViewDelegate? {
- didSet {
- self._rebuildTrackingAreas()
- }
- }
-
- var hasImageToolTips: Bool {
- get {
- return self._kmTrackingAreas != nil
- }
- set {
- if (newValue && self._kmTrackingAreas == nil) {
- self._kmTrackingAreas = []
- if (self.window != nil) {
- self._rebuildTrackingAreas()
- }
- } else if (newValue == false && self._kmTrackingAreas != nil) {
- if self.window != nil {
- self._removeTrackingAreas()
- }
- }
- }
- }
-
- private var _kmTrackingAreas: [NSTrackingArea]?
-
- private let MAX_HIGHLIGHTS = 5
-
- deinit {
- KMPrint("KMTocOutlineView deinit.")
-
- NotificationCenter.default.removeObserver(self)
- }
- override func draw(_ dirtyRect: NSRect) {
- super.draw(dirtyRect)
- }
-
- override func drawRow(_ row: Int, clipRect: NSRect) {
- // if (RUNNING_BEFORE(10_10) && [[self delegate] respondsToSelector:@selector(outlineView:highlightLevelForRow:)] &&
- // [self isRowSelected:row] == NO) {
- if let level = self.tocDelegate?.outlineView?(self, highlightLevelForRow: row), self.isRowSelected(row) == false {
- if (level < MAX_HIGHLIGHTS) {
- var color = NSColor(red: 0.556, green: 0.615, blue: 0.748, alpha: 1.0)
-
- let rect = self.rect(ofRow: row)
- if (NSIntersectsRect(rect, clipRect)) {
- NSGraphicsContext.saveGraphicsState()
- color.withAlphaComponent(0.1 * (CGFloat(MAX_HIGHLIGHTS) - level.cgFloat)).setFill()
- NSBezierPath.fill(rect)
- NSGraphicsContext.restoreGraphicsState()
- }
- }
- }
-
- super.drawRow(row, clipRect: clipRect)
- }
-
- override func highlightSelection(inClipRect clipRect: NSRect) {
- if self.selectionHighlightStyle == .regular {
- NSGraphicsContext.saveGraphicsState()
- NSColor(red: 0.556, green: 0.615, blue: 0.748, alpha: 1.0).setFill()
- for i in self.selectedRowIndexes {
- __NSRectFill(self.rect(ofRow: i))
- }
- NSGraphicsContext.restoreGraphicsState()
- } else {
- super.highlightSelection(inClipRect: clipRect)
- }
- }
-
- override func preparedCell(atColumn column: Int, row: Int) -> NSCell? {
- let cell = super.preparedCell(atColumn: column, row: row)
- if self.selectionHighlightStyle == .regular && self.isRowSelected(row) && cell?.type == .textCellType {
- if var attrString = cell?.attributedStringValue.mutableCopy() as? NSMutableAttributedString {
- let font = NSFontManager.shared.convert(cell?.font ?? .systemFont(ofSize: 12), toHaveTrait: .boldFontMask)
- attrString.addAttributes([.font : font], range: NSMakeRange(0, attrString.length))
- cell?.attributedStringValue = attrString
- }
- }
- return cell
- }
-
- override func selectRowIndexes(_ indexes: IndexSet, byExtendingSelection extend: Bool) {
- super.selectRowIndexes(indexes, byExtendingSelection: extend)
-
- self._handleHighlightsChanged()
- }
-
- override func deselectRow(_ row: Int) {
- super.deselectRow(row)
-
- self._handleHighlightsChanged()
- }
-
- override func becomeFirstResponder() -> Bool {
- if super.becomeFirstResponder() {
- self._handleHighlightsChanged()
- return true
- }
- return false
- }
-
- override func resignFirstResponder() -> Bool {
- if super.resignFirstResponder() {
- self._handleHighlightsChanged()
- return true
- }
- return false
- }
-
-
- override func updateTrackingAreas() {
- super.updateTrackingAreas()
-
- self._rebuildTrackingAreas()
- }
-
- override func noteNumberOfRowsChanged() {
- super.noteNumberOfRowsChanged()
-
- self._rebuildTrackingAreas()
- }
-
- override func viewDidMoveToWindow() {
- super.viewDidMoveToWindow()
-
- if self.window != nil {
- self._handleKeyOrMainStateChanged(nil)
- }
- }
-
- override func viewWillMove(toWindow newWindow: NSWindow?) {
- let oldWindow = self.window
- let names = [NSWindow.didBecomeMainNotification, NSWindow.didResignMainNotification, NSWindow.didBecomeKeyNotification, NSWindow.didResignKeyNotification]
- if oldWindow != nil {
- for name in names {
- NotificationCenter.default.removeObserver(self, name: name, object: oldWindow)
- }
- }
- if newWindow != nil {
- for name in names {
- NotificationCenter.default.addObserver(self, selector: #selector(_handleKeyOrMainStateChanged), name: name, object: newWindow)
- }
- }
- super.viewWillMove(toWindow: newWindow)
- }
-
- override func keyDown(with event: NSEvent) {
- let eventChar = event.firstCharacter()
- let modifiers = event.standardPDFListViewModifierFlags()
-
- if (eventChar == NSLeftArrowFunctionKey && modifiers == (NSEvent.ModifierFlags.command.rawValue + NSEvent.ModifierFlags.option.rawValue)) {
- self.collapseItem(nil, collapseChildren: true)
- } else if (eventChar == NSRightArrowFunctionKey && modifiers == (NSEvent.ModifierFlags.command.rawValue + NSEvent.ModifierFlags.option.rawValue)) {
- self.expandItem(nil, expandChildren: true)
- } else {
- super.keyDown(with: event)
- }
- }
-
- override func mouseEntered(with event: NSEvent) {
- if (self._kmTrackingAreas == nil) {
- return
- }
-
- let userInfo = event.trackingArea?.userInfo
- if let rowNumber = userInfo?["row"] as? Int {
- var item = self.item(atRow: rowNumber)
- if let context = self.tocDelegate?.outlineView?(self, imageContextForItem: item) as? KMImageToolTipContext {
- KMImageToolTipWindow.shared.showForImageContext(context, at: .zero)
- }
- }
- }
-
- override func mouseExited(with event: NSEvent) {
- let userInfo = event.trackingArea?.userInfo
- if let row = userInfo?["row"] {
- KMImageToolTipWindow.shared.fadeOut()
- }
- }
-
- }
- // MARK: - Private Methods
- extension KMTocOutlineView {
- private func _handleHighlightsChanged() {
- // if (RUNNING_BEFORE(10_10) && [[self delegate] respondsToSelector:@selector(outlineView:highlightLevelForRow:)])
- if let _ = self.tocDelegate?.outlineView?(self, highlightLevelForRow: -1) {
- self.needsDisplay = true
- }
- }
-
- @objc private func _handleKeyOrMainStateChanged(_ note: NSNotification?) {
- if self.selectionHighlightStyle == .sourceList {
- self._handleHighlightsChanged()
- } else {
- if let win = self.window, win.isMainWindow || win.isKeyWindow {
- // self.backgroundColor = NSColor(calibratedRed: 0.839216, green: 0.866667, blue: 0.898039, alpha: 1)
- } else {
- // self.backgroundColor = .controlColor
- }
- self.needsDisplay = true
- }
- }
-
- private func _rebuildTrackingAreas() {
- if self._kmTrackingAreas == nil || self.tocDelegate?.outlineView?(self, imageContextForItem: nil) == nil {
- return
- }
-
- self._removeTrackingAreas()
-
- if (self.window != nil) {
- let visibleRect = self.visibleRect
- let rowRange = self.rows(in: visibleRect)
- // NSUInteger row;
-
- for row in rowRange.location ..< NSMaxRange(rowRange) {
- self._addTrackingAreaForRow(row)
- }
- }
- }
-
- private func _removeTrackingAreas() {
- if (self._kmTrackingAreas == nil) {
- return
- }
-
- for area in self._kmTrackingAreas! {
- self.removeTrackingArea(area)
- }
- self._kmTrackingAreas?.removeAll()
- }
-
- private func _addTrackingAreaForRow(_ row: Int) {
- if (self._kmTrackingAreas == nil) {
- return
- }
-
- let userInfo = ["row" : row]
- let area = NSTrackingArea(rect: self.rect(ofRow: row), options: [.mouseEnteredAndExited, .activeInActiveApp], owner: self, userInfo: userInfo)
- self.addTrackingArea(area)
- self._kmTrackingAreas?.append(area)
- }
- }
|