fix: layout is now correct; also removed layout preferences for now
This commit is contained in:
1 parent
bb95e55e02
commit
a1b5266937
7 files changed
+142
-143
No files matched your search
@@ -22,12 +22,6 @@ extension CGWindow {
|
||||
return layer() == 0
|
||||
}
|
||||
|
||||
// workaround: some apps like chrome use a window to implement the search popover
|
||||
func isReasonablyBig() -> Bool {
|
||||
let windowBounds = CGRect(dictionaryRepresentation: bounds()!)!
|
||||
return windowBounds.width > Preferences.minimumWindowSize && windowBounds.height > Preferences.minimumWindowSize
|
||||
}
|
||||
|
||||
func id() -> CGWindowID? {
|
||||
return value(kCGWindowNumber, CGWindowID.self)
|
||||
}
|
||||
|
||||
@@ -3,11 +3,35 @@ import Cocoa
|
||||
import Carbon.HIToolbox.Events
|
||||
|
||||
class Preferences {
|
||||
// the following constant are not exposed as preferences but may be in the future, probably through macro preferences
|
||||
static let windowMaterial = NSVisualEffectView.Material.dark
|
||||
static let iconSize = CGFloat(32)
|
||||
static let fontColor = NSColor.white
|
||||
static let fontHeight = CGFloat(15)
|
||||
static let font = NSFont.systemFont(ofSize: fontHeight)
|
||||
static let windowPadding = CGFloat(23)
|
||||
static let cellPadding = CGFloat(5)
|
||||
static let fontIconSize = CGFloat(20)
|
||||
static let maxScreenUsage = CGFloat(0.8)
|
||||
static let minCellsPerRow = CGFloat(4)
|
||||
static let maxCellsPerRow = CGFloat(6)
|
||||
static let nCellsRows = CGFloat(4)
|
||||
|
||||
static let themeMacro = MacroPreferenceHelper<(CGFloat, CGFloat, CGFloat, NSColor, NSColor)>([
|
||||
MacroPreference(" macOS", (0, 5, 20, .clear, NSColor(red: 0, green: 0, blue: 0, alpha: 0.3))),
|
||||
MacroPreference("❖ Windows 10", (2, 0, 0, .white, .clear))
|
||||
])
|
||||
static let metaKeyMacro = MacroPreferenceHelper<([Int], NSEvent.ModifierFlags)>([
|
||||
MacroPreference("⌥ option", ([kVK_Option, kVK_RightOption], .option)),
|
||||
MacroPreference("⌃ control", ([kVK_Control, kVK_RightControl], .control)),
|
||||
MacroPreference("⌘ command", ([kVK_Command, kVK_RightCommand], .command))
|
||||
])
|
||||
static let showOnScreenMacro = MacroPreferenceHelper<ShowOnScreenPreference>([
|
||||
MacroPreference("Main screen", ShowOnScreenPreference.MAIN),
|
||||
MacroPreference("Screen including mouse", ShowOnScreenPreference.MOUSE),
|
||||
])
|
||||
|
||||
static var defaults: [String: String] = [
|
||||
"maxScreenUsage": "80",
|
||||
"maxThumbnailsPerRow": "4",
|
||||
"iconSize": "32",
|
||||
"fontHeight": "15",
|
||||
"tabKeyCode": String(kVK_Tab),
|
||||
"metaKey": metaKeyMacro.macros[0].label,
|
||||
"windowDisplayDelay": "0",
|
||||
@@ -16,21 +40,9 @@ class Preferences {
|
||||
"hideSpaceNumberLabels": String(false)
|
||||
]
|
||||
static var rawValues = [String: String]()
|
||||
static var minimumWindowSize = CGFloat(200)
|
||||
static var emptyThumbnailWidth = CGFloat(200)
|
||||
static var emptyThumbnailHeight = CGFloat(emptyThumbnailWidth * 9 / 16)
|
||||
static var fontColor = NSColor.white
|
||||
static var windowMaterial = NSVisualEffectView.Material.dark
|
||||
static var windowPadding = CGFloat(23)
|
||||
static var interItemPadding = CGFloat(4)
|
||||
static var fontIconSize = CGFloat(20)
|
||||
static var cellPadding = CGFloat(6)
|
||||
|
||||
static var cellBorderWidth: CGFloat?
|
||||
static var cellCornerRadius: CGFloat?
|
||||
static var maxScreenUsage: CGFloat?
|
||||
static var maxThumbnailsPerRow: CGFloat?
|
||||
static var iconSize: CGFloat?
|
||||
static var fontHeight: CGFloat?
|
||||
static var tabKeyCode: UInt16?
|
||||
static var highlightBorderColor: NSColor?
|
||||
static var highlightBackgroundColor: NSColor?
|
||||
@@ -38,22 +50,8 @@ class Preferences {
|
||||
static var metaModifierFlag: NSEvent.ModifierFlags?
|
||||
static var windowDisplayDelay: DispatchTimeInterval?
|
||||
static var windowCornerRadius: CGFloat?
|
||||
static var font: NSFont?
|
||||
static var showOnScreen: ShowOnScreenPreference?
|
||||
static var hideSpaceNumberLabels = false
|
||||
static var themeMacro = MacroPreferenceHelper<(CGFloat, CGFloat, CGFloat, NSColor, NSColor)>([
|
||||
MacroPreference(" macOS", (0, 5, 20, .clear, NSColor(red: 0, green: 0, blue: 0, alpha: 0.3))),
|
||||
MacroPreference("❖ Windows 10", (2, 0, 0, .white, .clear))
|
||||
])
|
||||
static var metaKeyMacro = MacroPreferenceHelper<([Int], NSEvent.ModifierFlags)>([
|
||||
MacroPreference("⌥ option", ([kVK_Option, kVK_RightOption], .option)),
|
||||
MacroPreference("⌃ control", ([kVK_Control, kVK_RightControl], .control)),
|
||||
MacroPreference("⌘ command", ([kVK_Command, kVK_RightCommand], .command))
|
||||
])
|
||||
static var showOnScreenMacro = MacroPreferenceHelper<ShowOnScreenPreference>([
|
||||
MacroPreference("Main screen", ShowOnScreenPreference.MAIN),
|
||||
MacroPreference("Screen including mouse", ShowOnScreenPreference.MOUSE),
|
||||
])
|
||||
static var hideSpaceNumberLabels: Bool?
|
||||
|
||||
private static let defaultsFile = fileFromPreferencesFolder("alt-tab-macos-defaults.json")
|
||||
private static let userFile = fileFromPreferencesFolder("alt-tab-macos.json")
|
||||
@@ -85,15 +83,6 @@ class Preferences {
|
||||
|
||||
static func updateAndValidateFromString(_ valueName: String, _ value: String) throws {
|
||||
switch valueName {
|
||||
case "maxScreenUsage":
|
||||
maxScreenUsage = try CGFloat(CGFloat(value).orThrow() / 100)
|
||||
case "maxThumbnailsPerRow":
|
||||
maxThumbnailsPerRow = try CGFloat(value).orThrow()
|
||||
case "iconSize":
|
||||
iconSize = try CGFloat(value).orThrow()
|
||||
case "fontHeight":
|
||||
fontHeight = try CGFloat(value).orThrow()
|
||||
font = NSFont.systemFont(ofSize: fontHeight!)
|
||||
case "tabKeyCode":
|
||||
tabKeyCode = try UInt16(value).orThrow()
|
||||
case "metaKey":
|
||||
|
||||
@@ -13,18 +13,6 @@ class Screen {
|
||||
return NSScreen.screens.first { NSMouseInRect(NSEvent.mouseLocation, $0.frame, false) }
|
||||
}
|
||||
|
||||
static func thumbnailMaxSize(_ screen: NSScreen) -> NSSize {
|
||||
let frame = screen.visibleFrame
|
||||
let width = (frame.width * Preferences.maxScreenUsage! - Preferences.windowPadding * 2) / Preferences.maxThumbnailsPerRow! - Preferences.interItemPadding
|
||||
let height = width * (frame.height / frame.width)
|
||||
return NSSize(width: width, height: height)
|
||||
}
|
||||
|
||||
static func thumbnailPanelMaxSize(_ screen: NSScreen) -> NSSize {
|
||||
let frame = screen.visibleFrame
|
||||
return NSSize(width: frame.width * Preferences.maxScreenUsage!, height: frame.height * Preferences.maxScreenUsage!)
|
||||
}
|
||||
|
||||
static func repositionPanel(_ window: NSWindow, _ screen: NSScreen, _ alignment: VerticalAlignment) {
|
||||
let screenFrame = screen.visibleFrame
|
||||
let panelFrame = window.frame
|
||||
|
||||
+51
-27
@@ -7,7 +7,7 @@ typealias MouseMovedCallback = (Cell) -> Void
|
||||
class Cell: NSCollectionViewItem {
|
||||
var thumbnail = NSImageView()
|
||||
var appIcon = NSImageView()
|
||||
var label = CellTitle(Preferences.fontHeight!)
|
||||
var label = CellTitle(Preferences.fontHeight)
|
||||
var minimizedIcon = FontIcon(FontIcon.sfSymbolCircledMinusSign, Preferences.fontIconSize, .white)
|
||||
var hiddenIcon = FontIcon(FontIcon.sfSymbolCircledDotSign, Preferences.fontIconSize, .white)
|
||||
var spaceIcon = FontIcon(FontIcon.sfSymbolCircledNumber0, Preferences.fontIconSize, .white)
|
||||
@@ -20,7 +20,13 @@ class Cell: NSCollectionViewItem {
|
||||
let vStackView = makeVStackView(hStackView)
|
||||
let shadow = Cell.makeShadow(.gray)
|
||||
thumbnail.shadow = shadow
|
||||
thumbnail.wantsLayer = true
|
||||
thumbnail.layer!.backgroundColor = NSColor.blue.cgColor
|
||||
appIcon.shadow = shadow
|
||||
appIcon.wantsLayer = true
|
||||
appIcon.layer!.backgroundColor = NSColor.green.cgColor
|
||||
vStackView.wantsLayer = true
|
||||
vStackView.layer!.backgroundColor = NSColor.gray.cgColor
|
||||
view = vStackView
|
||||
}
|
||||
|
||||
@@ -39,21 +45,22 @@ class Cell: NSCollectionViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
func updateWithNewContent(_ element: Window, _ mouseDownCallback: @escaping MouseDownCallback, _ mouseMovedCallback: @escaping MouseMovedCallback, _ screen: NSScreen) {
|
||||
func updateRecycledCellWithNewContent(_ element: Window, _ mouseDownCallback: @escaping MouseDownCallback, _ mouseMovedCallback: @escaping MouseMovedCallback, _ screen: NSScreen) {
|
||||
window = element
|
||||
thumbnail.image = element.thumbnail
|
||||
let (width, height) = Cell.computeDownscaledSize(element.thumbnail, screen)
|
||||
thumbnail.image?.size = NSSize(width: width, height: height)
|
||||
thumbnail.frame.size = NSSize(width: width, height: height)
|
||||
let thumbnailSize = Cell.thumbnailSize(element.thumbnail, screen)
|
||||
thumbnail.image?.size = thumbnailSize
|
||||
thumbnail.frame.size = thumbnailSize
|
||||
appIcon.image = element.icon
|
||||
appIcon.image?.size = NSSize(width: Preferences.iconSize!, height: Preferences.iconSize!)
|
||||
appIcon.frame.size = NSSize(width: Preferences.iconSize!, height: Preferences.iconSize!)
|
||||
let appIconSize = NSSize(width: Preferences.iconSize, height: Preferences.iconSize)
|
||||
appIcon.image?.size = appIconSize
|
||||
appIcon.frame.size = appIconSize
|
||||
label.string = element.title
|
||||
// workaround: setting string on NSTextView change the font (most likely a Cocoa bug)
|
||||
label.font = Preferences.font!
|
||||
label.font = Preferences.font
|
||||
hiddenIcon.isHidden = !window!.isHidden
|
||||
minimizedIcon.isHidden = !window!.isMinimized
|
||||
spaceIcon.isHidden = element.spaceIndex == nil || Spaces.isSingleSpace || Preferences.hideSpaceNumberLabels
|
||||
spaceIcon.isHidden = element.spaceIndex == nil || Spaces.isSingleSpace || Preferences.hideSpaceNumberLabels!
|
||||
if !spaceIcon.isHidden {
|
||||
if element.isOnAllSpaces {
|
||||
spaceIcon.setStar()
|
||||
@@ -61,8 +68,8 @@ class Cell: NSCollectionViewItem {
|
||||
spaceIcon.setNumber(UInt32(element.spaceIndex!))
|
||||
}
|
||||
}
|
||||
let fontIconWidth = CGFloat([minimizedIcon, hiddenIcon, spaceIcon].filter { !$0.isHidden }.count) * (Preferences.fontIconSize + Preferences.interItemPadding)
|
||||
label.textContainer!.size.width = thumbnail.frame.width - Preferences.iconSize! - Preferences.interItemPadding - fontIconWidth
|
||||
let fontIconWidth = CGFloat([minimizedIcon, hiddenIcon, spaceIcon].filter { !$0.isHidden }.count) * (Preferences.fontIconSize + Preferences.cellPadding)
|
||||
label.textContainer!.size.width = view.frame.width - Preferences.iconSize - Preferences.cellPadding * 3 - fontIconWidth
|
||||
self.mouseDownCallback = mouseDownCallback
|
||||
self.mouseMovedCallback = mouseMovedCallback
|
||||
if view.trackingAreas.count > 0 {
|
||||
@@ -71,20 +78,6 @@ class Cell: NSCollectionViewItem {
|
||||
view.addTrackingArea(NSTrackingArea(rect: view.bounds, options: [.mouseMoved, .activeAlways], owner: self, userInfo: nil))
|
||||
}
|
||||
|
||||
static func computeDownscaledSize(_ image: NSImage?, _ screen: NSScreen) -> (Int, Int) {
|
||||
if let image_ = image {
|
||||
let imageRatio = image_.size.width / image_.size.height
|
||||
let thumbnailMaxSize = Screen.thumbnailMaxSize(screen)
|
||||
let thumbnailWidth = Int(floor(thumbnailMaxSize.height * imageRatio))
|
||||
if thumbnailWidth <= Int(thumbnailMaxSize.width) {
|
||||
return (thumbnailWidth, Int(thumbnailMaxSize.height))
|
||||
} else {
|
||||
return (Int(thumbnailMaxSize.width), Int(floor(thumbnailMaxSize.width / imageRatio)))
|
||||
}
|
||||
}
|
||||
return (Int(Preferences.emptyThumbnailWidth), Int((Preferences.emptyThumbnailHeight)))
|
||||
}
|
||||
|
||||
static func makeShadow(_ color: NSColor) -> NSShadow {
|
||||
let shadow = NSShadow()
|
||||
shadow.shadowColor = color
|
||||
@@ -95,7 +88,9 @@ class Cell: NSCollectionViewItem {
|
||||
|
||||
private func makeHStackView() -> NSStackView {
|
||||
let hStackView = NSStackView()
|
||||
hStackView.spacing = Preferences.interItemPadding
|
||||
hStackView.spacing = Preferences.cellPadding
|
||||
label.wantsLayer = true
|
||||
label.layer!.backgroundColor = NSColor.brown.cgColor
|
||||
hStackView.setViews([appIcon, label, hiddenIcon, minimizedIcon, spaceIcon], in: .leading)
|
||||
return hStackView
|
||||
}
|
||||
@@ -109,8 +104,37 @@ class Cell: NSCollectionViewItem {
|
||||
vStackView.layer!.borderColor = .clear
|
||||
vStackView.edgeInsets = NSEdgeInsets(top: Preferences.cellPadding, left: Preferences.cellPadding, bottom: Preferences.cellPadding, right: Preferences.cellPadding)
|
||||
vStackView.orientation = .vertical
|
||||
vStackView.spacing = Preferences.interItemPadding
|
||||
vStackView.spacing = Preferences.cellPadding
|
||||
vStackView.setViews([hStackView, thumbnail], in: .leading)
|
||||
return vStackView
|
||||
}
|
||||
|
||||
static func widthMax(_ screen: NSScreen) -> CGFloat {
|
||||
return ThumbnailsPanel.widthMax(screen) / Preferences.minCellsPerRow - Preferences.cellPadding
|
||||
}
|
||||
|
||||
static func widthMin(_ screen: NSScreen) -> CGFloat {
|
||||
return ThumbnailsPanel.widthMax(screen) / Preferences.maxCellsPerRow - Preferences.cellPadding
|
||||
}
|
||||
|
||||
static func height(_ screen: NSScreen) -> CGFloat {
|
||||
return ThumbnailsPanel.heightMax(screen) / Preferences.nCellsRows - Preferences.cellPadding
|
||||
}
|
||||
|
||||
static func width(_ image: NSImage?, _ screen: NSScreen) -> CGFloat {
|
||||
return max(thumbnailSize(image, screen).width + Preferences.cellPadding * 2, ThumbnailsPanel.widthMin(screen))
|
||||
}
|
||||
|
||||
static func thumbnailSize(_ image: NSImage?, _ screen: NSScreen) -> NSSize {
|
||||
let thumbnailWidthMin = Cell.widthMin(screen) - Preferences.cellPadding * 2
|
||||
let thumbnailHeightMax = Cell.height(screen) - Preferences.cellPadding * 3 - Preferences.iconSize
|
||||
let thumbnailWidthMax = Cell.widthMax(screen) - Preferences.cellPadding * 2
|
||||
guard let image = image else { return NSSize(width: thumbnailWidthMin, height: thumbnailHeightMax) }
|
||||
let imageRatio = image.size.width / image.size.height
|
||||
let thumbnailRatio = thumbnailWidthMax / thumbnailHeightMax
|
||||
if thumbnailRatio > imageRatio {
|
||||
return NSSize(width: image.size.width * thumbnailHeightMax / image.size.height, height: thumbnailHeightMax)
|
||||
}
|
||||
return NSSize(width: thumbnailWidthMax, height: image.size.height * thumbnailWidthMax / image.size.width)
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,9 @@ class CollectionViewCenterFlowLayout: NSCollectionViewFlowLayout {
|
||||
var currentScreen: NSScreen?
|
||||
|
||||
override func layoutAttributesForElements(in rect: CGRect) -> [NSCollectionViewLayoutAttributes] {
|
||||
let attributes = super.layoutAttributesForElements(in: rect)
|
||||
if attributes.isEmpty {
|
||||
return attributes
|
||||
}
|
||||
let attributes_ = super.layoutAttributesForElements(in: rect)
|
||||
guard !attributes_.isEmpty else { return attributes_ }
|
||||
let attributes = NSArray(array: attributes_, copyItems: true) as! [NSCollectionViewLayoutAttributes]
|
||||
var currentRow: [NSCollectionViewLayoutAttributes] = []
|
||||
var currentRowY = CGFloat(0)
|
||||
var currentRowWidth = CGFloat(0)
|
||||
@@ -15,35 +14,38 @@ class CollectionViewCenterFlowLayout: NSCollectionViewFlowLayout {
|
||||
var currentRowMaxY = CGFloat(0)
|
||||
var widestRow = CGFloat(0)
|
||||
var totalHeight = CGFloat(0)
|
||||
attributes.enumerated().forEach {
|
||||
let isNewRow = abs($1.frame.origin.y - currentRowY) > Screen.thumbnailMaxSize(currentScreen!).height
|
||||
for (index, attribute) in attributes.enumerated() {
|
||||
let isNewRow = abs(attribute.frame.origin.y - currentRowY) > Cell.height(currentScreen!)
|
||||
if isNewRow {
|
||||
computeOriginXForAllItems(currentRowWidth - minimumInteritemSpacing, previousRowMaxY, currentRow)
|
||||
computeOriginXForAllItems(currentRowWidth - Preferences.cellPadding, previousRowMaxY, currentRow)
|
||||
currentRow.removeAll()
|
||||
currentRowY = $1.frame.origin.y
|
||||
currentRowY = attribute.frame.origin.y
|
||||
currentRowWidth = 0
|
||||
previousRowMaxY += currentRowMaxY + minimumLineSpacing
|
||||
previousRowMaxY += currentRowMaxY + Preferences.cellPadding
|
||||
currentRowMaxY = 0
|
||||
}
|
||||
currentRow.append($1)
|
||||
currentRowWidth += $1.frame.size.width + minimumInteritemSpacing
|
||||
currentRow.append(attribute)
|
||||
currentRowWidth += attribute.frame.size.width + Preferences.cellPadding
|
||||
widestRow = max(widestRow, currentRowWidth)
|
||||
currentRowMaxY = max(currentRowMaxY, $1.frame.size.height)
|
||||
if $0 == attributes.count - 1 {
|
||||
computeOriginXForAllItems(currentRowWidth - minimumInteritemSpacing, previousRowMaxY, currentRow)
|
||||
currentRowMaxY = max(currentRowMaxY, attribute.frame.size.height)
|
||||
if index == attributes.count - 1 {
|
||||
computeOriginXForAllItems(currentRowWidth - Preferences.cellPadding, previousRowMaxY, currentRow)
|
||||
totalHeight = previousRowMaxY + currentRowMaxY
|
||||
}
|
||||
}
|
||||
collectionView!.setFrameSize(NSSize(width: widestRow - minimumInteritemSpacing, height: totalHeight))
|
||||
let newWidth = widestRow - Preferences.cellPadding
|
||||
collectionView!.bounds.origin.x = (collectionView!.frame.size.width - newWidth) / 2
|
||||
collectionView!.frame.size.width = newWidth
|
||||
collectionView!.frame.size.height = totalHeight
|
||||
return attributes
|
||||
}
|
||||
|
||||
func computeOriginXForAllItems(_ currentRowWidth: CGFloat, _ previousRowMaxHeight: CGFloat, _ currentRow: [NSCollectionViewLayoutAttributes]) {
|
||||
var marginLeft = floor((collectionView!.frame.size.width - currentRowWidth) / 2)
|
||||
currentRow.forEach {
|
||||
$0.frame.origin.x = marginLeft
|
||||
$0.frame.origin.y = previousRowMaxHeight
|
||||
marginLeft += $0.frame.size.width + minimumInteritemSpacing
|
||||
private func computeOriginXForAllItems(_ currentRowWidth: CGFloat, _ previousRowMaxHeight: CGFloat, _ currentRow: [NSCollectionViewLayoutAttributes]) {
|
||||
var marginLeft = (collectionView!.frame.size.width - currentRowWidth) / 2
|
||||
for attribute in currentRow {
|
||||
attribute.frame.origin.x = marginLeft
|
||||
attribute.frame.origin.y = previousRowMaxHeight
|
||||
marginLeft += attribute.frame.size.width + Preferences.cellPadding
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,10 +82,6 @@ class PreferencesWindow: NSWindow, NSWindowDelegate {
|
||||
makeLabelWithInput("Tab key", rawName: "tabKeyCode", width: 33, suffixText: "KeyCodes Reference", suffixUrl: "https://eastmanreference.com/complete-list-of-applescript-key-codes", validator: tabKeyCodeValidator),
|
||||
makeHorizontalSeparator(),
|
||||
makeLabelWithDropdown("Theme", rawName: "theme", values: Preferences.themeMacro.labels),
|
||||
makeLabelWithSlider("Max screen usage", rawName: "maxScreenUsage", minValue: 10, maxValue: 100, numberOfTickMarks: 0, unitText: "%"),
|
||||
makeLabelWithSlider("Max thumbnails per row", rawName: "maxThumbnailsPerRow", minValue: 3, maxValue: 16, numberOfTickMarks: 0),
|
||||
makeLabelWithSlider("Apps icon size", rawName: "iconSize", minValue: 12, maxValue: 64, numberOfTickMarks: 0, unitText: "px"),
|
||||
makeLabelWithSlider("Window font size", rawName: "fontHeight", minValue: 12, maxValue: 64, numberOfTickMarks: 0, unitText: "px"),
|
||||
makeLabelWithCheckbox("Hide space number labels", rawName: "hideSpaceNumberLabels"),
|
||||
makeHorizontalSeparator(),
|
||||
makeLabelWithSlider("Window apparition delay", rawName: "windowDisplayDelay", minValue: 0, maxValue: 2000, numberOfTickMarks: 0, unitText: "ms"),
|
||||
|
||||
@@ -2,7 +2,7 @@ import Cocoa
|
||||
|
||||
class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDelegate, NSCollectionViewDelegateFlowLayout {
|
||||
var backgroundView: NSVisualEffectView?
|
||||
var collectionView_: NSCollectionView!
|
||||
var collectionView: NSCollectionView!
|
||||
var app: App?
|
||||
let cellId = NSUserInterfaceItemIdentifier("Cell")
|
||||
var currentScreen: NSScreen?
|
||||
@@ -21,7 +21,7 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele
|
||||
titleVisibility = .hidden
|
||||
styleMask.remove(.titled)
|
||||
backgroundColor = .clear
|
||||
collectionView_ = makeCollectionView()
|
||||
collectionView = makeCollectionView()
|
||||
backgroundView = makeBackgroundView()
|
||||
contentView!.addSubview(backgroundView!)
|
||||
// highest level possible; this allows the app to go on top of context menus
|
||||
@@ -41,7 +41,8 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele
|
||||
backgroundView.state = .active
|
||||
backgroundView.wantsLayer = true
|
||||
backgroundView.layer!.cornerRadius = Preferences.windowCornerRadius!
|
||||
backgroundView.addSubview(collectionView_)
|
||||
backgroundView.layer!.backgroundColor = .white
|
||||
backgroundView.addSubview(collectionView)
|
||||
return backgroundView
|
||||
}
|
||||
|
||||
@@ -49,62 +50,67 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele
|
||||
let collectionView_ = NSCollectionView()
|
||||
collectionView_.dataSource = self
|
||||
collectionView_.delegate = self
|
||||
collectionView_.collectionViewLayout = makeLayout()
|
||||
collectionView_.backgroundColors = [.clear]
|
||||
collectionView_.collectionViewLayout = CollectionViewCenterFlowLayout()
|
||||
collectionView_.backgroundColors = [.yellow]
|
||||
collectionView_.isSelectable = true
|
||||
collectionView_.allowsMultipleSelection = false
|
||||
collectionView_.register(Cell.self, forItemWithIdentifier: cellId)
|
||||
return collectionView_
|
||||
}
|
||||
|
||||
func makeLayout() -> CollectionViewCenterFlowLayout {
|
||||
let layout = CollectionViewCenterFlowLayout()
|
||||
layout.estimatedItemSize = NSSize(width: Preferences.emptyThumbnailWidth, height: Preferences.emptyThumbnailHeight)
|
||||
layout.minimumInteritemSpacing = 5
|
||||
layout.minimumLineSpacing = 5
|
||||
return layout
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return Windows.list.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
|
||||
let item = collectionView.makeItem(withIdentifier: cellId, for: indexPath) as! Cell
|
||||
item.updateWithNewContent(Windows.list[indexPath.item], app!.focusSelectedWindow, app!.thumbnailsPanel!.highlightCell, currentScreen!)
|
||||
item.updateRecycledCellWithNewContent(Windows.list[indexPath.item], app!.focusSelectedWindow, app!.thumbnailsPanel!.highlightCell, currentScreen!)
|
||||
return item
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {
|
||||
if indexPath.item < Windows.list.count {
|
||||
let (width, height) = Cell.computeDownscaledSize(Windows.list[indexPath.item].thumbnail, currentScreen!)
|
||||
return NSSize(width: CGFloat(width) + Preferences.cellPadding * 2, height: CGFloat(height) + max(Preferences.fontHeight!, Preferences.iconSize!) + Preferences.interItemPadding + Preferences.cellPadding * 2)
|
||||
}
|
||||
return .zero
|
||||
guard indexPath.item < Windows.list.count else { return .zero }
|
||||
return NSSize(width: Cell.width(Windows.list[indexPath.item].thumbnail, currentScreen!), height: Cell.height(currentScreen!))
|
||||
}
|
||||
|
||||
func highlightCell() {
|
||||
collectionView_.deselectAll(nil)
|
||||
collectionView_!.selectItems(at: [IndexPath(item: Windows.focusedWindowIndex, section: 0)], scrollPosition: .top)
|
||||
collectionView.deselectAll(nil)
|
||||
collectionView.selectItems(at: [IndexPath(item: Windows.focusedWindowIndex, section: 0)], scrollPosition: .top)
|
||||
}
|
||||
|
||||
func highlightCell(_ cell: Cell) {
|
||||
let newIndex = collectionView_.indexPath(for: cell)!
|
||||
let newIndex = collectionView.indexPath(for: cell)!
|
||||
if Windows.focusedWindowIndex != newIndex.item {
|
||||
collectionView_!.selectItems(at: [newIndex], scrollPosition: .top)
|
||||
collectionView_!.deselectItems(at: [IndexPath(item: Windows.focusedWindowIndex, section: 0)])
|
||||
collectionView.selectItems(at: [newIndex], scrollPosition: .top)
|
||||
collectionView.deselectItems(at: [IndexPath(item: Windows.focusedWindowIndex, section: 0)])
|
||||
Windows.focusedWindowIndex = newIndex.item
|
||||
}
|
||||
}
|
||||
|
||||
func refreshCollectionView(_ currentScreen: NSScreen, _ uiWorkShouldBeDone: Bool) {
|
||||
if uiWorkShouldBeDone { self.currentScreen = currentScreen }
|
||||
if uiWorkShouldBeDone { (collectionView_.collectionViewLayout as! CollectionViewCenterFlowLayout).currentScreen = currentScreen }
|
||||
if uiWorkShouldBeDone { collectionView_!.setFrameSize(Screen.thumbnailPanelMaxSize(currentScreen)) }
|
||||
if uiWorkShouldBeDone { collectionView_!.reloadData() }
|
||||
if uiWorkShouldBeDone { collectionView_!.layoutSubtreeIfNeeded() }
|
||||
if uiWorkShouldBeDone { setContentSize(NSSize(width: collectionView_!.frame.size.width + Preferences.windowPadding * 2, height: collectionView_!.frame.size.height + Preferences.windowPadding * 2)) }
|
||||
func refreshCollectionView(_ screen: NSScreen, _ uiWorkShouldBeDone: Bool) {
|
||||
if uiWorkShouldBeDone { self.currentScreen = screen }
|
||||
if uiWorkShouldBeDone { (collectionView.collectionViewLayout as! CollectionViewCenterFlowLayout).currentScreen = screen }
|
||||
if uiWorkShouldBeDone { collectionView.setFrameSize(NSSize(width: ThumbnailsPanel.widthMax(screen), height: ThumbnailsPanel.heightMax(screen))) }
|
||||
if uiWorkShouldBeDone { collectionView.reloadData() }
|
||||
if uiWorkShouldBeDone { collectionView.layoutSubtreeIfNeeded() }
|
||||
if uiWorkShouldBeDone { setContentSize(NSSize(width: collectionView.frame.size.width + Preferences.windowPadding * 2, height: collectionView.frame.size.height + Preferences.windowPadding * 2)) }
|
||||
if uiWorkShouldBeDone { backgroundView!.setFrameSize(frame.size) }
|
||||
if uiWorkShouldBeDone { collectionView_!.setFrameOrigin(NSPoint(x: Preferences.windowPadding, y: Preferences.windowPadding)) }
|
||||
if uiWorkShouldBeDone { collectionView.setFrameOrigin(NSPoint(x: Preferences.windowPadding, y: Preferences.windowPadding)) }
|
||||
}
|
||||
|
||||
static func widthMax(_ screen: NSScreen) -> CGFloat {
|
||||
return screen.frame.width * Preferences.maxScreenUsage - Preferences.windowPadding * 2
|
||||
}
|
||||
|
||||
static func heightMax(_ screen: NSScreen) -> CGFloat {
|
||||
return screen.frame.height * Preferences.maxScreenUsage - Preferences.windowPadding * 2
|
||||
}
|
||||
|
||||
static func widthMin(_ screen: NSScreen) -> CGFloat {
|
||||
return Cell.widthMin(screen) - Preferences.windowPadding * 2
|
||||
}
|
||||
|
||||
static func heightMin(_ screen: NSScreen) -> CGFloat {
|
||||
return Cell.height(screen) - Preferences.windowPadding * 2
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user