diff --git a/alt-tab-macos/ui/Application.swift b/alt-tab-macos/ui/Application.swift index 3c411afc..78da8e48 100644 --- a/alt-tab-macos/ui/Application.swift +++ b/alt-tab-macos/ui/Application.swift @@ -102,7 +102,7 @@ class Application: NSApplication, NSApplicationDelegate, NSWindowDelegate { func cycleSelection(_ step: Int) { selectedOpenWindow = cellWithStep(step) - thumbnailsPanel!.highlightCell(step) + thumbnailsPanel!.highlightCellAt(step) } func showUiOrCycleSelection(_ step: Int) { diff --git a/alt-tab-macos/ui/Cell.swift b/alt-tab-macos/ui/Cell.swift index 515eba5f..8a82b1bc 100644 --- a/alt-tab-macos/ui/Cell.swift +++ b/alt-tab-macos/ui/Cell.swift @@ -1,23 +1,15 @@ import Cocoa +typealias MouseDownCallback = (OpenWindow) -> Void +typealias MouseMovedCallback = (Cell) -> Void + class Cell: NSCollectionViewItem { var thumbnail = NSImageView() var icon = NSImageView() var label = CellTitle() var openWindow: OpenWindow? - var mouseDownCallback: ((OpenWindow) -> Void)? - - static func makeShadow(_ color: NSColor) -> NSShadow { - let shadow = NSShadow() - shadow.shadowColor = color - shadow.shadowOffset = NSMakeSize(0, 0) - shadow.shadowBlurRadius = 1 - return shadow - } - - override func mouseDown(with theEvent: NSEvent) { - mouseDownCallback!(openWindow!) - } + var mouseDownCallback: MouseDownCallback? + var mouseMovedCallback: MouseMovedCallback? override func loadView() { let hStackView = makeHStackView() @@ -28,6 +20,52 @@ class Cell: NSCollectionViewItem { view = vStackView } + override func mouseMoved(with event: NSEvent) { + mouseMovedCallback!(self) + } + + override func mouseDown(with theEvent: NSEvent) { + mouseDownCallback!(openWindow!) + } + + override var isSelected: Bool { + didSet { + view.layer!.backgroundColor = isSelected ? Preferences.highlightBackgroundColor!.cgColor : .clear + view.layer!.borderColor = isSelected ? Preferences.highlightBorderColor!.cgColor : .clear + } + } + + + + func updateWithNewContent(_ element: OpenWindow, _ mouseDownCallback: @escaping MouseDownCallback, _ mouseMovedCallback: @escaping MouseMovedCallback) { + openWindow = element + thumbnail.image = element.thumbnail + let (width, height) = computeDownscaledSize(element.thumbnail) + thumbnail.image!.size = NSSize(width: width, height: height) + thumbnail.frame.size = NSSize(width: width, height: height) + icon.image = element.icon + icon.image?.size = NSSize(width: Preferences.iconSize!, height: Preferences.iconSize!) + icon.frame.size = NSSize(width: Preferences.iconSize!, height: Preferences.iconSize!) + label.string = element.cgTitle + // workaround: setting string on NSTextView change the font (most likely a Cocoa bug) + label.font = Preferences.font! + label.textContainer!.size.width = thumbnail.frame.size.width - Preferences.iconSize! - Preferences.interItemPadding + self.mouseDownCallback = mouseDownCallback + self.mouseMovedCallback = mouseMovedCallback + if view.trackingAreas.count > 0 { + view.removeTrackingArea(view.trackingAreas[0]) + } + view.addTrackingArea(NSTrackingArea(rect: view.bounds, options: [.mouseMoved, .activeAlways], owner: self, userInfo: nil)) + } + + static func makeShadow(_ color: NSColor) -> NSShadow { + let shadow = NSShadow() + shadow.shadowColor = color + shadow.shadowOffset = NSMakeSize(0, 0) + shadow.shadowBlurRadius = 1 + return shadow + } + private func makeHStackView() -> NSStackView { let hStackView = NSStackView() hStackView.spacing = Preferences.interItemPadding @@ -50,27 +88,4 @@ class Cell: NSCollectionViewItem { vStackView.addView(thumbnail, in: .leading) return vStackView } - - override var isSelected: Bool { - didSet { - view.layer!.backgroundColor = isSelected ? Preferences.highlightBackgroundColor!.cgColor : .clear - view.layer!.borderColor = isSelected ? Preferences.highlightBorderColor!.cgColor : .clear - } - } - - func updateWithNewContent(_ element: OpenWindow, _ fn: @escaping (OpenWindow) -> Void) { - openWindow = element - thumbnail.image = element.thumbnail - let (width, height) = computeDownscaledSize(element.thumbnail) - thumbnail.image!.size = NSSize(width: width, height: height) - thumbnail.frame.size = NSSize(width: width, height: height) - icon.image = element.icon - icon.image?.size = NSSize(width: Preferences.iconSize!, height: Preferences.iconSize!) - icon.frame.size = NSSize(width: Preferences.iconSize!, height: Preferences.iconSize!) - label.string = element.cgTitle - // workaround: setting string on NSTextView change the font (most likely a Cocoa bug) - label.font = Preferences.font! - label.textContainer!.size.width = thumbnail.frame.size.width - Preferences.iconSize! - Preferences.interItemPadding - mouseDownCallback = fn - } } diff --git a/alt-tab-macos/ui/ThumbnailsPanel.swift b/alt-tab-macos/ui/ThumbnailsPanel.swift index 04b4e0bc..f8211722 100644 --- a/alt-tab-macos/ui/ThumbnailsPanel.swift +++ b/alt-tab-macos/ui/ThumbnailsPanel.swift @@ -64,7 +64,7 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { // debugPrint("collectionView: make item", indexPath.item) let item = collectionView.makeItem(withIdentifier: cellId, for: indexPath) as! Cell - item.updateWithNewContent(application!.openWindows[indexPath.item], application!.focusSelectedWindow) + item.updateWithNewContent(application!.openWindows[indexPath.item], application!.focusSelectedWindow, application!.thumbnailsPanel!.highlightCell) return item } @@ -77,11 +77,20 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele return .zero } - func highlightCell(_ step: Int) { + func highlightCellAt(_ step: Int) { collectionView_!.selectItems(at: [IndexPath(item: application!.selectedOpenWindow, section: 0)], scrollPosition: .top) collectionView_!.deselectItems(at: [IndexPath(item: application!.cellWithStep(-step), section: 0)]) } + func highlightCell(_ cell: Cell) { + let newIndex = collectionView_.indexPath(for: cell)! + if application!.selectedOpenWindow != newIndex.item { + collectionView_!.selectItems(at: [newIndex], scrollPosition: .top) + collectionView_!.deselectItems(at: [IndexPath(item: application!.selectedOpenWindow, section: 0)]) + application!.selectedOpenWindow = newIndex.item + } + } + func computeThumbnails() { let maxSize = NSSize(width: NSScreen.main!.frame.width * Preferences.maxScreenUsage!, height: NSScreen.main!.frame.height * Preferences.maxScreenUsage!) collectionView_!.setFrameSize(maxSize)