fix: layout was incorrect resulting in thumbnails clipping

This commit is contained in:
louis.pontoise authored and lwouis committed 2020-03-10 14:00:37 +09:00
1 parent 2a36196661
commit fd906f46fb
4 files changed
+66 -45

No files matched your search

+5 -4
View File
@@ -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))),
+13 -12
View File
@@ -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 {
@@ -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
}
@@ -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
}
@@ -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 {
@@ -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
@@ -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)
@@ -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
}
}
}
+21 -13
View File
@@ -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
@@ -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
}
@@ -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)) }
}
@@ -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)
}