// Copyright © 2015 Abhishek Banthia import Cocoa import CoreLoggerKit protocol PanelTableViewDelegate: NSTableViewDelegate { func tableView(_ table: NSTableView, didHoverOver row: NSInteger) } class PanelTableView: NSTableView { weak var panelDelegate: PanelTableViewDelegate? private var enableHover: Bool = false private var trackingArea: NSTrackingArea? private(set) var hoverRow: Int = -1 override func awakeFromNib() { super.awakeFromNib() enableHover = true } override func updateTrackingAreas() { if let tracker = trackingArea { removeTrackingArea(tracker) } createTrackingArea() super.updateTrackingAreas() } private func createTrackingArea() { let options: NSTrackingArea.Options = [ .mouseMoved, .mouseEnteredAndExited, .activeAlways, ] let clipRect = enclosingScrollView?.contentView.bounds ?? .zero trackingArea = NSTrackingArea(rect: clipRect, options: options, owner: self, userInfo: nil) if let tracker = trackingArea { addTrackingArea(tracker) } } override func mouseEntered(with event: NSEvent) { let mousePointInWindow = event.locationInWindow let mousePoint = convert(mousePointInWindow, from: nil) var currentHoverRow = row(at: mousePoint) if currentHoverRow != hoverRow { // We've scrolled off the end of the table if currentHoverRow < 0 || currentHoverRow >= numberOfRows { currentHoverRow = -1 } setHoverRow(currentHoverRow) } } private func setHoverRow(_ row: Int) { if row != hoverRow { hoverRow = row panelDelegate?.tableView(self, didHoverOver: hoverRow) setNeedsDisplay() } } override func reloadData() { super.reloadData() setHoverRow(-1) evaluateForHighlight() } private func evaluateForHighlight() { if enableHover == false { return } guard let mousePointInWindow = window?.mouseLocationOutsideOfEventStream else { return } let mousePoint = convert(mousePointInWindow, from: nil) evaluateForHighlight(at: mousePoint) } private func evaluateForHighlight(at point: NSPoint) { if enableHover == false { Logger.info("Unable to show hover button because window is occluded!") return } var hover = row(at: point) if hover != hoverRow { if hover < 0 || hover >= numberOfRows { hover = -1 } } setHoverRow(hover) } override func mouseMoved(with event: NSEvent) { let mousePointInWindow = event.locationInWindow let mousePoint = convert(mousePointInWindow, from: nil) evaluateForHighlight(at: mousePoint) } private func setEnableHover(_ enable: Bool) { if enable != enableHover { if enableHover == false { setHoverRow(-1) } enableHover = enable evaluateForHighlight() } } }