Skip to content

Commit

Permalink
fix: layout was incorrect resulting in thumbnails clipping
Browse files Browse the repository at this point in the history
  • Loading branch information
louis.pontoise committed Jan 20, 2020
1 parent ef0d2e2 commit 7221b53
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 45 deletions.
9 changes: 5 additions & 4 deletions alt-tab-macos/logic/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ class Preferences {
static let fontHeight = CGFloat(15)
static let font = NSFont.systemFont(ofSize: fontHeight)
static let windowPadding = CGFloat(23)
static let cellPadding = CGFloat(5)
static let interCellPadding = CGFloat(5)
static let intraCellPadding = 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 minCellsPerRow = CGFloat(3)
static let maxCellsPerRow = CGFloat(4)
static let nCellsRows = CGFloat(3)

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))),
Expand Down
25 changes: 13 additions & 12 deletions alt-tab-macos/ui/Cell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ class Cell: NSCollectionViewItem {
spaceIcon.setNumber(UInt32(element.spaceIndex!))
}
}
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
let fontIconWidth = CGFloat([minimizedIcon, hiddenIcon, spaceIcon].filter { !$0.isHidden }.count) * (Preferences.fontIconSize + Preferences.intraCellPadding)
label.textContainer!.size.width = view.frame.width - Preferences.iconSize - Preferences.intraCellPadding * 3 - fontIconWidth
view.subviews.first!.frame.size = view.frame.size
self.mouseDownCallback = mouseDownCallback
self.mouseMovedCallback = mouseMovedCallback
if view.trackingAreas.count > 0 {
Expand All @@ -82,7 +83,7 @@ class Cell: NSCollectionViewItem {

private func makeHStackView() -> NSStackView {
let hStackView = NSStackView()
hStackView.spacing = Preferences.cellPadding
hStackView.spacing = Preferences.intraCellPadding
hStackView.setViews([appIcon, label, hiddenIcon, minimizedIcon, spaceIcon], in: .leading)
return hStackView
}
Expand All @@ -94,9 +95,9 @@ class Cell: NSCollectionViewItem {
vStackView.layer!.cornerRadius = Preferences.cellCornerRadius!
vStackView.layer!.borderWidth = Preferences.cellBorderWidth!
vStackView.layer!.borderColor = .clear
vStackView.edgeInsets = NSEdgeInsets(top: Preferences.cellPadding, left: Preferences.cellPadding, bottom: Preferences.cellPadding, right: Preferences.cellPadding)
vStackView.edgeInsets = NSEdgeInsets(top: Preferences.intraCellPadding, left: Preferences.intraCellPadding, bottom: Preferences.intraCellPadding, right: Preferences.intraCellPadding)
vStackView.orientation = .vertical
vStackView.spacing = Preferences.cellPadding
vStackView.spacing = Preferences.intraCellPadding
vStackView.setViews([hStackView, thumbnail], in: .leading)
return vStackView
}
Expand All @@ -109,19 +110,19 @@ class Cell: NSCollectionViewItem {
}

static func widthMax(_ screen: NSScreen) -> CGFloat {
return floor((ThumbnailsPanel.widthMax(screen) / Preferences.minCellsPerRow - Preferences.cellPadding) * Cell.downscaleFactor())
return floor((ThumbnailsPanel.widthMax(screen) / Preferences.minCellsPerRow - Preferences.interCellPadding) * Cell.downscaleFactor())
}

static func widthMin(_ screen: NSScreen) -> CGFloat {
return floor((ThumbnailsPanel.widthMax(screen) / Preferences.maxCellsPerRow - Preferences.cellPadding) * Cell.downscaleFactor())
return floor((ThumbnailsPanel.widthMax(screen) / Preferences.maxCellsPerRow - Preferences.interCellPadding) * Cell.downscaleFactor())
}

static func height(_ screen: NSScreen) -> CGFloat {
return floor((ThumbnailsPanel.heightMax(screen) / Preferences.nCellsRows - Preferences.cellPadding) * Cell.downscaleFactor())
return floor((ThumbnailsPanel.heightMax(screen) / Preferences.nCellsRows - Preferences.interCellPadding) * Cell.downscaleFactor())
}

static func width(_ image: NSImage?, _ screen: NSScreen) -> CGFloat {
return floor(max(thumbnailSize(image, screen).width + Preferences.cellPadding * 2, ThumbnailsPanel.widthMin(screen)))
return floor(max(thumbnailSize(image, screen).width + Preferences.intraCellPadding * 2, Cell.widthMin(screen)))
}

static func thumbnailSize(_ image: NSImage?, _ screen: NSScreen) -> NSSize {
Expand All @@ -130,9 +131,9 @@ class Cell: NSCollectionViewItem {
}

static func thumbnailSize_(_ image: NSImage?, _ screen: NSScreen) -> (CGFloat, CGFloat) {
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
let thumbnailWidthMin = Cell.widthMin(screen) - Preferences.intraCellPadding * 2
let thumbnailHeightMax = Cell.height(screen) - Preferences.intraCellPadding * 3 - Preferences.iconSize
let thumbnailWidthMax = Cell.widthMax(screen) - Preferences.intraCellPadding * 2
guard let image = image else { return (thumbnailWidthMin, thumbnailHeightMax) }
let imageRatio = image.size.width / image.size.height
let thumbnailRatio = thumbnailWidthMax / thumbnailHeightMax
Expand Down
43 changes: 27 additions & 16 deletions alt-tab-macos/ui/CollectionViewCenterFlowLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Cocoa

class CollectionViewCenterFlowLayout: NSCollectionViewFlowLayout {
var currentScreen: NSScreen?
var widestRow: CGFloat?
var totalHeight: CGFloat?

override func layoutAttributesForElements(in rect: CGRect) -> [NSCollectionViewLayoutAttributes] {
let attributes_ = super.layoutAttributesForElements(in: rect)
Expand All @@ -10,42 +12,51 @@ class CollectionViewCenterFlowLayout: NSCollectionViewFlowLayout {
var currentRow: [NSCollectionViewLayoutAttributes] = []
var currentRowY = CGFloat(0)
var currentRowWidth = CGFloat(0)
var previousRowMaxY = CGFloat(0)
var currentRowMaxY = CGFloat(0)
var previousRowMaxHeight = CGFloat(0)
var currentRowMaxHeight = CGFloat(0)
var widestRow = CGFloat(0)
var totalHeight = CGFloat(0)
for (index, attribute) in attributes.enumerated() {
let isNewRow = abs(attribute.frame.origin.y - currentRowY) > Cell.height(currentScreen!)
if isNewRow {
computeOriginXForAllItems(currentRowWidth - Preferences.cellPadding, previousRowMaxY, currentRow)
currentRowWidth -= Preferences.interCellPadding
widestRow = max(widestRow, currentRowWidth)
setCenteredPositionForPreviousRowCells(currentRowWidth, previousRowMaxHeight, currentRow)
currentRow.removeAll()
currentRowY = attribute.frame.origin.y
currentRowWidth = 0
previousRowMaxY += currentRowMaxY + Preferences.cellPadding
currentRowMaxY = 0
previousRowMaxHeight += currentRowMaxHeight + Preferences.interCellPadding
currentRowMaxHeight = 0
}
currentRow.append(attribute)
currentRowWidth += attribute.frame.size.width + Preferences.cellPadding
widestRow = max(widestRow, currentRowWidth)
currentRowMaxY = max(currentRowMaxY, attribute.frame.size.height)
currentRowWidth += attribute.frame.size.width + Preferences.interCellPadding
currentRowMaxHeight = max(currentRowMaxHeight, attribute.frame.size.height)
if index == attributes.count - 1 {
computeOriginXForAllItems(currentRowWidth - Preferences.cellPadding, previousRowMaxY, currentRow)
totalHeight = previousRowMaxY + currentRowMaxY
currentRowWidth -= Preferences.interCellPadding
widestRow = max(widestRow, currentRowWidth)
totalHeight = previousRowMaxHeight + currentRowMaxHeight
setCenteredPositionForPreviousRowCells(currentRowWidth, previousRowMaxHeight, currentRow)
}
}
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
shiftCenteredElementToTheLeft(attributes, widestRow, totalHeight)
self.widestRow = widestRow
self.totalHeight = totalHeight
return attributes
}

private func computeOriginXForAllItems(_ currentRowWidth: CGFloat, _ previousRowMaxHeight: CGFloat, _ currentRow: [NSCollectionViewLayoutAttributes]) {
private func shiftCenteredElementToTheLeft(_ attributes: [NSCollectionViewLayoutAttributes], _ widestRow: CGFloat, _ totalHeight: CGFloat) {
let horizontalMargin = floor((collectionView!.frame.size.width - widestRow) / 2)
for attribute in attributes {
attribute.frame.origin.x -= horizontalMargin
}
}

private func setCenteredPositionForPreviousRowCells(_ 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
marginLeft += attribute.frame.size.width + Preferences.interCellPadding
}
}
}
34 changes: 21 additions & 13 deletions alt-tab-macos/ui/ThumbnailsPanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele
styleMask.remove(.titled)
backgroundColor = .clear
makeCollectionView()
makeBackgroundView()
contentView!.addSubview(backgroundView!)
backgroundView = ThumbnailsPanel.makeBackgroundView()
backgroundView.addSubview(collectionView)
contentView!.addSubview(backgroundView)
// highest level possible; this allows the app to go on top of context menus
level = .screenSaver
// helps filter out this window from the thumbnails
Expand All @@ -34,27 +35,34 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele
makeKeyAndOrderFront(nil)
}

private func makeBackgroundView() {
backgroundView = NSVisualEffectView()
static func makeBackgroundView() -> NSVisualEffectView {
let backgroundView = NSVisualEffectView()
backgroundView.translatesAutoresizingMaskIntoConstraints = false
backgroundView.material = Preferences.windowMaterial
backgroundView.state = .active
backgroundView.wantsLayer = true
backgroundView.layer!.cornerRadius = Preferences.windowCornerRadius!
backgroundView.addSubview(collectionView)
return backgroundView
}

func makeCollectionView() {
collectionView = NSCollectionView()
collectionView.dataSource = self
collectionView.delegate = self
collectionView.collectionViewLayout = CollectionViewCenterFlowLayout()
collectionView.collectionViewLayout = makeLayout()
collectionView.backgroundColors = [.clear]
collectionView.isSelectable = true
collectionView.allowsMultipleSelection = false
collectionView.register(Cell.self, forItemWithIdentifier: cellId)
}

private func makeLayout() -> CollectionViewCenterFlowLayout {
let layout = CollectionViewCenterFlowLayout()
layout.minimumInteritemSpacing = Preferences.interCellPadding
layout.minimumLineSpacing = Preferences.interCellPadding
return layout
}

func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return Windows.list.count
}
Expand Down Expand Up @@ -86,12 +94,16 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele

func refreshCollectionView(_ screen: NSScreen, _ uiWorkShouldBeDone: Bool) {
if uiWorkShouldBeDone { self.currentScreen = screen }
if uiWorkShouldBeDone { (collectionView.collectionViewLayout as! CollectionViewCenterFlowLayout).currentScreen = screen }
let layout = collectionView.collectionViewLayout as! CollectionViewCenterFlowLayout
if uiWorkShouldBeDone { layout.currentScreen = screen }
if uiWorkShouldBeDone { layout.invalidateLayout() }
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.setFrameSize(NSSize(width: layout.widestRow!, height: layout.totalHeight!)) }
let windowSize = NSSize(width: layout.widestRow! + Preferences.windowPadding * 2, height: layout.totalHeight! + Preferences.windowPadding * 2)
if uiWorkShouldBeDone { setContentSize(windowSize) }
if uiWorkShouldBeDone { backgroundView!.setFrameSize(windowSize) }
if uiWorkShouldBeDone { collectionView.setFrameOrigin(NSPoint(x: Preferences.windowPadding, y: Preferences.windowPadding)) }
}

Expand All @@ -103,10 +115,6 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele
return floor(screen.frame.height * Preferences.maxScreenUsage - Preferences.windowPadding * 2)
}

static func widthMin(_ screen: NSScreen) -> CGFloat {
return floor(Cell.widthMin(screen) - Preferences.windowPadding * 2)
}

static func heightMin(_ screen: NSScreen) -> CGFloat {
return floor(Cell.height(screen) - Preferences.windowPadding * 2)
}
Expand Down

0 comments on commit 7221b53

Please sign in to comment.