feat: smarter padding around thumbnails (closes #126)
This commit is contained in:
1 parent
a60750c415
commit
a94582f7f6
6 files changed
+76
-61
No files matched your search
@@ -70,7 +70,9 @@ class Application: NSObject {
|
||||
private func addWindows(_ axWindows: [AXUIElement]) {
|
||||
let windows = axWindows.map { Window($0, self) }
|
||||
Windows.list.insertAndScaleRecycledPool(windows, at: 0)
|
||||
Windows.cycleFocusedWindowIndex(windows.count)
|
||||
if App.app.appIsBeingUsed {
|
||||
Windows.cycleFocusedWindowIndex(windows.count)
|
||||
}
|
||||
App.app.refreshOpenUi(windows)
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ class Preferences {
|
||||
// not exposed as preferences now but may be in the future, probably through macro preferences
|
||||
static var windowMaterial: NSVisualEffectView.Material { .dark }
|
||||
static var fontColor: NSColor { .white }
|
||||
static var windowPadding: CGFloat { 23 }
|
||||
static var windowPadding: CGFloat { 18 }
|
||||
static var interCellPadding: CGFloat { 5 }
|
||||
static var intraCellPadding: CGFloat { 5 }
|
||||
static var fontIconSize: CGFloat { 20 }
|
||||
@@ -223,8 +223,8 @@ enum ThemePreference: String, CaseIterable, MacroPreference {
|
||||
|
||||
var themeParameters: ThemeParameters {
|
||||
switch self {
|
||||
case .macOs: return ThemeParameters(label: self.localizedString, cellBorderWidth: 0, cellCornerRadius: 5, windowCornerRadius: 20, highlightBorderColor: .clear, highlightBackgroundColor: NSColor(red: 0, green: 0, blue: 0, alpha: 0.4))
|
||||
case .windows10: return ThemeParameters(label: self.localizedString, cellBorderWidth: 2, cellCornerRadius: 0, windowCornerRadius: 0, highlightBorderColor: .white, highlightBackgroundColor: .clear)
|
||||
case .macOs: return ThemeParameters(label: localizedString, cellBorderWidth: 0, cellCornerRadius: 10, windowCornerRadius: 23, highlightBorderColor: .clear, highlightBackgroundColor: NSColor(red: 0, green: 0, blue: 0, alpha: 0.4))
|
||||
case .windows10: return ThemeParameters(label: localizedString, cellBorderWidth: 2, cellCornerRadius: 0, windowCornerRadius: 0, highlightBorderColor: .white, highlightBackgroundColor: .clear)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,14 @@ class Windows {
|
||||
static var windowsInSubscriptionRetryLoop = [String]()
|
||||
|
||||
static func updateFocusedWindowIndex(_ newIndex: Int) {
|
||||
previousFocusedWindowIndex = focusedWindowIndex
|
||||
focusedWindowIndex = newIndex
|
||||
let focusedView = ThumbnailsView.recycledViews[focusedWindowIndex]
|
||||
ThumbnailsPanel.highlightCell(ThumbnailsView.recycledViews[previousFocusedWindowIndex], focusedView)
|
||||
App.app.thumbnailsPanel.thumbnailsView.scrollView.contentView.scrollToVisible(focusedView.frame)
|
||||
if newIndex != focusedWindowIndex {
|
||||
previousFocusedWindowIndex = focusedWindowIndex
|
||||
focusedWindowIndex = newIndex
|
||||
let focusedView = ThumbnailsView.recycledViews[focusedWindowIndex]
|
||||
ThumbnailsView.recycledViews[previousFocusedWindowIndex].highlight(false)
|
||||
focusedView.highlight(true)
|
||||
App.app.thumbnailsPanel.thumbnailsView.scrollView.contentView.scrollToVisible(focusedView.frame)
|
||||
}
|
||||
}
|
||||
|
||||
static func focusedWindow() -> Window? {
|
||||
|
||||
@@ -8,18 +8,55 @@ class ThumbnailView: NSStackView {
|
||||
var minimizedIcon = ThumbnailFontIconView(ThumbnailFontIconView.sfSymbolCircledMinusSign, Preferences.fontIconSize, .white)
|
||||
var hiddenIcon = ThumbnailFontIconView(ThumbnailFontIconView.sfSymbolCircledDotSign, Preferences.fontIconSize, .white)
|
||||
var spaceIcon = ThumbnailFontIconView(ThumbnailFontIconView.sfSymbolCircledNumber0, Preferences.fontIconSize, .white)
|
||||
var hStackView: NSStackView!
|
||||
var mouseDownCallback: (() -> Void)!
|
||||
var mouseMovedCallback: (() -> Void)!
|
||||
var dragAndDropTimer: Timer?
|
||||
var isHighlighted = false
|
||||
|
||||
convenience init() {
|
||||
self.init(frame: .zero)
|
||||
let hStackView = makeHStackView()
|
||||
setupView(hStackView)
|
||||
setupView()
|
||||
observeDragAndDrop()
|
||||
}
|
||||
|
||||
private func setupView() {
|
||||
wantsLayer = true
|
||||
layer!.backgroundColor = .clear
|
||||
layer!.borderColor = .clear
|
||||
layer!.cornerRadius = Preferences.cellCornerRadius
|
||||
layer!.borderWidth = Preferences.cellBorderWidth
|
||||
edgeInsets = NSEdgeInsets(top: Preferences.intraCellPadding, left: Preferences.intraCellPadding, bottom: Preferences.intraCellPadding, right: Preferences.intraCellPadding)
|
||||
orientation = .vertical
|
||||
spacing = Preferences.intraCellPadding
|
||||
let shadow = ThumbnailView.makeShadow(.gray)
|
||||
thumbnail.shadow = shadow
|
||||
appIcon.shadow = shadow
|
||||
observeDragAndDrop()
|
||||
hStackView = NSStackView(views: [appIcon, label, hiddenIcon, minimizedIcon, spaceIcon])
|
||||
hStackView.spacing = Preferences.intraCellPadding
|
||||
setViews([hStackView, thumbnail], in: .leading)
|
||||
}
|
||||
|
||||
func highlight(_ highlight: Bool) {
|
||||
if isHighlighted != highlight {
|
||||
isHighlighted = highlight
|
||||
if frame != NSRect.zero {
|
||||
highlightOrNot()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func highlightOrNot() {
|
||||
layer!.backgroundColor = isHighlighted ? Preferences.highlightBackgroundColor.cgColor : .clear
|
||||
layer!.borderColor = isHighlighted ? Preferences.highlightBorderColor.cgColor : .clear
|
||||
let frameInset: CGFloat = Preferences.intraCellPadding * (isHighlighted ? -1 : 1)
|
||||
frame = frame.insetBy(dx: frameInset, dy: frameInset)
|
||||
let edgeInsets_: CGFloat = Preferences.intraCellPadding * (isHighlighted ? 2 : 1)
|
||||
edgeInsets.top = edgeInsets_
|
||||
edgeInsets.right = edgeInsets_
|
||||
edgeInsets.bottom = edgeInsets_
|
||||
edgeInsets.left = edgeInsets_
|
||||
debugPrint("louis", isHighlighted, frame.width, label.string)
|
||||
}
|
||||
|
||||
func updateRecycledCellWithNewContent(_ element: Window, _ index: Int, _ newHeight: CGFloat, _ screen: NSScreen) {
|
||||
@@ -123,19 +160,15 @@ class ThumbnailView: NSStackView {
|
||||
}
|
||||
|
||||
static func widthMax(_ screen: NSScreen) -> CGFloat {
|
||||
return ThumbnailsPanel.widthMax(screen) / Preferences.minCellsPerRow - Preferences.interCellPadding
|
||||
return (ThumbnailsPanel.widthMax(screen) - Preferences.interCellPadding) / Preferences.minCellsPerRow - Preferences.interCellPadding
|
||||
}
|
||||
|
||||
static func widthMin(_ screen: NSScreen) -> CGFloat {
|
||||
return ThumbnailsPanel.widthMax(screen) / Preferences.maxCellsPerRow - Preferences.interCellPadding
|
||||
return (ThumbnailsPanel.widthMax(screen) - Preferences.interCellPadding) / Preferences.maxCellsPerRow - Preferences.interCellPadding
|
||||
}
|
||||
|
||||
static func height(_ screen: NSScreen) -> CGFloat {
|
||||
return ThumbnailsPanel.heightMax(screen) / Preferences.rowsCount - Preferences.interCellPadding
|
||||
}
|
||||
|
||||
static func width(_ image: NSImage?, _ screen: NSScreen) -> CGFloat {
|
||||
return max(thumbnailSize(image, screen).0 + Preferences.intraCellPadding * 2, ThumbnailView.widthMin(screen))
|
||||
return (ThumbnailsPanel.heightMax(screen) - Preferences.interCellPadding) / Preferences.rowsCount - Preferences.interCellPadding
|
||||
}
|
||||
|
||||
static func thumbnailSize(_ image: NSImage?, _ screen: NSScreen) -> (CGFloat, CGFloat) {
|
||||
@@ -151,24 +184,4 @@ class ThumbnailView: NSStackView {
|
||||
}
|
||||
return (thumbnailWidth, image.size.height * thumbnailWidth / image.size.width)
|
||||
}
|
||||
|
||||
private func makeHStackView() -> NSStackView {
|
||||
let hStackView = NSStackView()
|
||||
hStackView.spacing = Preferences.intraCellPadding
|
||||
hStackView.setViews([appIcon, label, hiddenIcon, minimizedIcon, spaceIcon], in: .leading)
|
||||
return hStackView
|
||||
}
|
||||
|
||||
private func setupView(_ hStackView: NSStackView) {
|
||||
wantsLayer = true
|
||||
layer!.backgroundColor = .clear
|
||||
layer!.cornerRadius = Preferences.cellCornerRadius
|
||||
layer!.borderWidth = Preferences.cellBorderWidth
|
||||
layer!.borderColor = .clear
|
||||
edgeInsets = NSEdgeInsets(top: Preferences.intraCellPadding, left: Preferences.intraCellPadding, bottom: Preferences.intraCellPadding, right: Preferences.intraCellPadding)
|
||||
orientation = .vertical
|
||||
spacing = Preferences.intraCellPadding
|
||||
setViews([hStackView, thumbnail], in: .leading)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,6 @@ class ThumbnailsPanel: NSPanel {
|
||||
thumbnailsView.scrollView.flashScrollers()
|
||||
}
|
||||
|
||||
static func highlightCell(_ previousView: NSView, _ newView: NSView) {
|
||||
previousView.layer!.backgroundColor = .clear
|
||||
previousView.layer!.borderColor = .clear
|
||||
newView.layer!.backgroundColor = Preferences.highlightBackgroundColor.cgColor
|
||||
newView.layer!.borderColor = Preferences.highlightBorderColor.cgColor
|
||||
}
|
||||
|
||||
static func widthMax(_ screen: NSScreen) -> CGFloat {
|
||||
return screen.frame.width * Preferences.maxScreenUsage - Preferences.windowPadding * 2
|
||||
}
|
||||
|
||||
@@ -40,10 +40,10 @@ class ThumbnailsView: NSVisualEffectView {
|
||||
let widthMax = ThumbnailsPanel.widthMax(screen).rounded()
|
||||
let heightMax = ThumbnailsPanel.heightMax(screen).rounded()
|
||||
let height = ThumbnailView.height(screen).rounded(.down)
|
||||
var currentX = CGFloat(0)
|
||||
var currentY = CGFloat(0)
|
||||
var currentX = Preferences.interCellPadding
|
||||
var currentY = Preferences.interCellPadding
|
||||
var maxX = CGFloat(0)
|
||||
var maxY = height
|
||||
var maxY = currentY + height + Preferences.interCellPadding
|
||||
var newViews = [ThumbnailView]()
|
||||
rows.removeAll()
|
||||
rows.append([ThumbnailView]())
|
||||
@@ -53,13 +53,13 @@ class ThumbnailsView: NSVisualEffectView {
|
||||
let view = ThumbnailsView.recycledViews[index]
|
||||
view.updateRecycledCellWithNewContent(window, index, height, screen)
|
||||
let width = view.frame.size.width
|
||||
if (currentX + width).rounded(.down) > widthMax {
|
||||
currentX = CGFloat(0)
|
||||
currentY = (currentY + Preferences.interCellPadding + height).rounded(.down)
|
||||
maxY = max(currentY + height, maxY)
|
||||
if (currentX + width + Preferences.interCellPadding).rounded(.down) > widthMax {
|
||||
currentX = Preferences.interCellPadding
|
||||
currentY = (currentY + height + Preferences.interCellPadding).rounded(.down)
|
||||
maxY = max(currentY + height + Preferences.interCellPadding, maxY)
|
||||
rows.append([ThumbnailView]())
|
||||
} else {
|
||||
maxX = max(currentX + width, maxX)
|
||||
maxX = max(currentX + width + Preferences.interCellPadding, maxX)
|
||||
}
|
||||
view.frame.origin = CGPoint(x: currentX, y: currentY)
|
||||
currentX = (currentX + Preferences.interCellPadding + width).rounded(.down)
|
||||
@@ -76,23 +76,27 @@ class ThumbnailsView: NSVisualEffectView {
|
||||
if Preferences.alignThumbnails == .center {
|
||||
centerRows(maxX)
|
||||
}
|
||||
Windows.list.enumerated().first { (index, _) in
|
||||
let view = ThumbnailsView.recycledViews[index]
|
||||
if view.isHighlighted {
|
||||
view.highlightOrNot()
|
||||
}
|
||||
return view.isHighlighted
|
||||
}
|
||||
}
|
||||
|
||||
func centerRows(_ maxX: CGFloat) {
|
||||
var rowStartIndex = 0
|
||||
var rowWidth = CGFloat(0)
|
||||
var rowY = CGFloat(0)
|
||||
var rowWidth = Preferences.interCellPadding
|
||||
var rowY = Preferences.interCellPadding
|
||||
for (index, _) in Windows.list.enumerated() {
|
||||
let view = ThumbnailsView.recycledViews[index]
|
||||
if view.frame.origin.y == rowY {
|
||||
rowWidth += Preferences.interCellPadding + view.frame.size.width
|
||||
rowWidth += view.frame.size.width + Preferences.interCellPadding
|
||||
} else {
|
||||
if rowStartIndex == 0 {
|
||||
rowWidth -= Preferences.interCellPadding // first row has 1 extra padding
|
||||
}
|
||||
shiftRow(maxX, rowWidth, rowStartIndex, index)
|
||||
rowStartIndex = index
|
||||
rowWidth = view.frame.size.width
|
||||
rowWidth = Preferences.interCellPadding + view.frame.size.width + Preferences.interCellPadding
|
||||
rowY = view.frame.origin.y
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user