feat: drag-and-drop files on the ui (closes #74)
This commit is contained in:
1 parent
7eb216d43c
commit
e1e3633148
6 files changed
+187
-133
No files matched your search
@@ -53,6 +53,7 @@
|
||||
D04BAD5A6B2F9EEE6FD4185F /* CollectionViewItemTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA4BABBA0312E0EDBA647 /* CollectionViewItemTitle.swift */; };
|
||||
D04BAD8346A6A32C9749E0B3 /* TabViewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA293C53EC5CE00D11E02 /* TabViewItem.swift */; };
|
||||
D04BAE369A14C3126A1606FE /* HelperExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA8F1AA48A323EE5638DC /* HelperExtensions.swift */; };
|
||||
D04BAE4CE37C303DDD0347B8 /* CollectionViewItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAE073DD0B0D65CD4CBB6 /* CollectionViewItemView.swift */; };
|
||||
D04BAEAB8AB048FF2B16B131 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BAE5FA03065C5D23C0C2C /* Localizable.strings */; };
|
||||
D04BAEF78503D7A2CEFB9E9E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAA44C837F3A67403B9DB /* main.swift */; };
|
||||
D04BAF3B6F75E50E9AA3E1D2 /* LabelAndControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA3D65E7CA78D699EDAB0 /* LabelAndControl.swift */; };
|
||||
@@ -133,6 +134,7 @@
|
||||
D04BADBAFB42AE72DBE1E59E /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = InfoPlist.strings; sourceTree = "<group>"; };
|
||||
D04BADBCA16C1D448D34F473 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = InfoPlist.strings; sourceTree = "<group>"; };
|
||||
D04BADCB1C0F50340A6CAFC2 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
|
||||
D04BAE073DD0B0D65CD4CBB6 /* CollectionViewItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewItemView.swift; sourceTree = "<group>"; };
|
||||
D04BAE1243C9B4BE3ED1B524 /* 7 windows - 2 lines - extra wide window.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "7 windows - 2 lines - extra wide window.jpg"; sourceTree = "<group>"; };
|
||||
D04BAE23C37E0F3B07EEE7B1 /* AboutTab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutTab.swift; sourceTree = "<group>"; };
|
||||
D04BAE80772D25834E440975 /* Window.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Window.swift; sourceTree = "<group>"; };
|
||||
@@ -442,6 +444,7 @@
|
||||
D04BAF40D5E54AD1044B3FF7 /* ThumbnailsPanel.swift */,
|
||||
D04BA4BABBA0312E0EDBA647 /* CollectionViewItemTitle.swift */,
|
||||
D04BAC0416F29ADE7BC5A544 /* CollectionViewItemFontIcon.swift */,
|
||||
D04BAE073DD0B0D65CD4CBB6 /* CollectionViewItemView.swift */,
|
||||
);
|
||||
path = "main-window";
|
||||
sourceTree = "<group>";
|
||||
@@ -558,6 +561,7 @@
|
||||
D04BA6D9DA2A8BCD93347F0E /* CollectionViewItemFontIcon.swift in Sources */,
|
||||
D04BA9EE5D34A2789DCB0EE2 /* Sysctl.swift in Sources */,
|
||||
D04BAC4F69FE9563BC1C5E9C /* DebugProfile.swift in Sources */,
|
||||
D04BAE4CE37C303DDD0347B8 /* CollectionViewItemView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ class CollectionViewFlowLayout: NSCollectionViewFlowLayout {
|
||||
var widestRow = CGFloat(0)
|
||||
var totalHeight = CGFloat(0)
|
||||
for (index, attribute) in attributes.enumerated() {
|
||||
let isNewRow = abs(attribute.frame.origin.y - currentRowY) > CollectionViewItem.height(currentScreen!)
|
||||
let isNewRow = abs(attribute.frame.origin.y - currentRowY) > CollectionViewItemView.height(currentScreen!)
|
||||
if isNewRow {
|
||||
currentRowWidth -= Preferences.interCellPadding
|
||||
widestRow = max(widestRow, currentRowWidth)
|
||||
|
||||
@@ -1,35 +1,12 @@
|
||||
import Cocoa
|
||||
import WebKit
|
||||
|
||||
typealias MouseDownCallback = (Window) -> Void
|
||||
typealias MouseMovedCallback = (CollectionViewItem) -> Void
|
||||
|
||||
class CollectionViewItem: NSCollectionViewItem {
|
||||
var thumbnail = NSImageView()
|
||||
var appIcon = NSImageView()
|
||||
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)
|
||||
var window: Window?
|
||||
var mouseDownCallback: MouseDownCallback?
|
||||
var mouseMovedCallback: MouseMovedCallback?
|
||||
var view_: CollectionViewItemView { view as! CollectionViewItemView }
|
||||
|
||||
override func loadView() {
|
||||
let hStackView = makeHStackView()
|
||||
let vStackView = makeVStackView(hStackView)
|
||||
let shadow = CollectionViewItem.makeShadow(.gray)
|
||||
thumbnail.shadow = shadow
|
||||
appIcon.shadow = shadow
|
||||
view = vStackView
|
||||
}
|
||||
|
||||
override func mouseMoved(with event: NSEvent) {
|
||||
mouseMovedCallback!(self)
|
||||
}
|
||||
|
||||
override func mouseDown(with theEvent: NSEvent) {
|
||||
mouseDownCallback!(window!)
|
||||
view = CollectionViewItemView()
|
||||
view.wantsLayer = true
|
||||
}
|
||||
|
||||
override var isSelected: Bool {
|
||||
@@ -38,105 +15,4 @@ class CollectionViewItem: NSCollectionViewItem {
|
||||
view.layer!.borderColor = isSelected ? Preferences.highlightBorderColor.cgColor : .clear
|
||||
}
|
||||
}
|
||||
|
||||
func updateRecycledCellWithNewContent(_ element: Window, _ mouseDownCallback: @escaping MouseDownCallback, _ mouseMovedCallback: @escaping MouseMovedCallback, _ screen: NSScreen) {
|
||||
window = element
|
||||
thumbnail.image = element.thumbnail
|
||||
let (thumbnailWidth, thumbnailHeight) = CollectionViewItem.thumbnailSize(element.thumbnail, screen)
|
||||
let thumbnailSize = NSSize(width: thumbnailWidth.rounded(), height: thumbnailHeight.rounded())
|
||||
thumbnail.image?.size = thumbnailSize
|
||||
thumbnail.frame.size = thumbnailSize
|
||||
appIcon.image = element.icon
|
||||
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
|
||||
hiddenIcon.isHidden = !window!.isHidden
|
||||
minimizedIcon.isHidden = !window!.isMinimized
|
||||
spaceIcon.isHidden = element.spaceIndex == nil || Spaces.isSingleSpace || Preferences.hideSpaceNumberLabels
|
||||
if !spaceIcon.isHidden {
|
||||
if element.isOnAllSpaces {
|
||||
spaceIcon.setStar()
|
||||
} else {
|
||||
spaceIcon.setNumber(UInt32(element.spaceIndex!))
|
||||
}
|
||||
}
|
||||
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 {
|
||||
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 = .zero
|
||||
shadow.shadowBlurRadius = 1
|
||||
return shadow
|
||||
}
|
||||
|
||||
private func makeHStackView() -> NSStackView {
|
||||
let hStackView = NSStackView()
|
||||
hStackView.spacing = Preferences.intraCellPadding
|
||||
hStackView.setViews([appIcon, label, hiddenIcon, minimizedIcon, spaceIcon], in: .leading)
|
||||
return hStackView
|
||||
}
|
||||
|
||||
private func makeVStackView(_ hStackView: NSStackView) -> NSStackView {
|
||||
let vStackView = NSStackView()
|
||||
vStackView.wantsLayer = true
|
||||
vStackView.layer!.backgroundColor = .clear
|
||||
vStackView.layer!.cornerRadius = Preferences.cellCornerRadius
|
||||
vStackView.layer!.borderWidth = Preferences.cellBorderWidth
|
||||
vStackView.layer!.borderColor = .clear
|
||||
vStackView.edgeInsets = NSEdgeInsets(top: Preferences.intraCellPadding, left: Preferences.intraCellPadding, bottom: Preferences.intraCellPadding, right: Preferences.intraCellPadding)
|
||||
vStackView.orientation = .vertical
|
||||
vStackView.spacing = Preferences.intraCellPadding
|
||||
vStackView.setViews([hStackView, thumbnail], in: .leading)
|
||||
return vStackView
|
||||
}
|
||||
|
||||
static func downscaleFactor() -> CGFloat {
|
||||
let nCellsBeforePotentialOverflow = Preferences.minRows * Preferences.minCellsPerRow
|
||||
guard CGFloat(Windows.list.count) > nCellsBeforePotentialOverflow else { return 1 }
|
||||
// TODO: replace this buggy heuristic with a correct implementation of downscaling
|
||||
return nCellsBeforePotentialOverflow / (nCellsBeforePotentialOverflow + (sqrt(CGFloat(Windows.list.count) - nCellsBeforePotentialOverflow) * 2))
|
||||
}
|
||||
|
||||
static func widthMax(_ screen: NSScreen) -> CGFloat {
|
||||
return (ThumbnailsPanel.widthMax(screen) / Preferences.minCellsPerRow - Preferences.interCellPadding) * CollectionViewItem.downscaleFactor()
|
||||
}
|
||||
|
||||
static func widthMin(_ screen: NSScreen) -> CGFloat {
|
||||
return (ThumbnailsPanel.widthMax(screen) / Preferences.maxCellsPerRow - Preferences.interCellPadding) * CollectionViewItem.downscaleFactor()
|
||||
}
|
||||
|
||||
static func height(_ screen: NSScreen) -> CGFloat {
|
||||
return (ThumbnailsPanel.heightMax(screen) / Preferences.minRows - Preferences.interCellPadding) * CollectionViewItem.downscaleFactor()
|
||||
}
|
||||
|
||||
static func width(_ image: NSImage?, _ screen: NSScreen) -> CGFloat {
|
||||
return max(thumbnailSize(image, screen).0 + Preferences.intraCellPadding * 2, CollectionViewItem.widthMin(screen))
|
||||
}
|
||||
|
||||
static func thumbnailSize(_ image: NSImage?, _ screen: NSScreen) -> (CGFloat, CGFloat) {
|
||||
guard let image = image else { return (0, 0) }
|
||||
let thumbnailHeightMax = CollectionViewItem.height(screen) - Preferences.intraCellPadding * 3 - Preferences.iconSize
|
||||
let thumbnailWidthMax = CollectionViewItem.widthMax(screen) - Preferences.intraCellPadding * 2
|
||||
let thumbnailHeight = min(image.size.height, thumbnailHeightMax)
|
||||
let thumbnailWidth = min(image.size.width, thumbnailWidthMax)
|
||||
let imageRatio = image.size.width / image.size.height
|
||||
let thumbnailRatio = thumbnailWidth / thumbnailHeight
|
||||
if thumbnailRatio > imageRatio {
|
||||
return (image.size.width * thumbnailHeight / image.size.height, thumbnailHeight)
|
||||
}
|
||||
return (thumbnailWidth, image.size.height * thumbnailWidth / image.size.width)
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ class CellTitle: BaseLabel {
|
||||
self.init(NSRect.zero, textContainer)
|
||||
self.magicOffset = magicOffset
|
||||
textColor = Preferences.fontColor
|
||||
shadow = CollectionViewItem.makeShadow(.darkGray)
|
||||
shadow = CollectionViewItemView.makeShadow(.darkGray)
|
||||
defaultParagraphStyle = makeParagraphStyle(size)
|
||||
heightAnchor.constraint(equalToConstant: size + magicOffset).isActive = true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
import Cocoa
|
||||
|
||||
class CollectionViewItemView: NSView {
|
||||
var window_: Window?
|
||||
var thumbnail = NSImageView()
|
||||
var appIcon = NSImageView()
|
||||
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)
|
||||
var mouseDownCallback: MouseDownCallback!
|
||||
var mouseMovedCallback: MouseMovedCallback!
|
||||
var dragAndDropTimer: Timer?
|
||||
|
||||
convenience init() {
|
||||
self.init(frame: .zero)
|
||||
let hStackView = makeHStackView()
|
||||
let vStackView = makeVStackView(hStackView)
|
||||
let shadow = CollectionViewItemView.makeShadow(.gray)
|
||||
thumbnail.shadow = shadow
|
||||
appIcon.shadow = shadow
|
||||
observeDragAndDrop()
|
||||
subviews.append(vStackView)
|
||||
}
|
||||
|
||||
private func observeDragAndDrop() {
|
||||
// NSImageView instances are registered to drag-and-drop by default
|
||||
thumbnail.unregisterDraggedTypes()
|
||||
appIcon.unregisterDraggedTypes()
|
||||
// we only handle URLs (i.e. not text, image, or other draggable things)
|
||||
registerForDraggedTypes([NSPasteboard.PasteboardType(kUTTypeURL as String)])
|
||||
}
|
||||
|
||||
override func draggingUpdated(_ sender: NSDraggingInfo) -> NSDragOperation {
|
||||
mouseMovedCallback()
|
||||
return .link
|
||||
}
|
||||
|
||||
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
|
||||
dragAndDropTimer = Timer.scheduledTimer(withTimeInterval: 2, repeats: false, block: { _ in
|
||||
self.mouseDownCallback()
|
||||
})
|
||||
return .link
|
||||
}
|
||||
|
||||
override func draggingExited(_ sender: NSDraggingInfo?) {
|
||||
dragAndDropTimer?.invalidate()
|
||||
dragAndDropTimer = nil
|
||||
}
|
||||
|
||||
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
|
||||
let urls = sender.draggingPasteboard.readObjects(forClasses: [NSURL.self]) as! [URL]
|
||||
let appUrl = window_!.application.runningApplication.bundleURL!
|
||||
let open = try? NSWorkspace.shared.open(urls, withApplicationAt: appUrl, options: [], configuration: [:])
|
||||
(App.shared as! App).hideUi()
|
||||
return open != nil
|
||||
}
|
||||
|
||||
override func mouseMoved(with event: NSEvent) {
|
||||
mouseMovedCallback()
|
||||
}
|
||||
|
||||
override func mouseDown(with theEvent: NSEvent) {
|
||||
mouseDownCallback()
|
||||
}
|
||||
|
||||
func updateRecycledCellWithNewContent(_ element: Window, _ mouseDownCallback: @escaping MouseDownCallback, _ mouseMovedCallback: @escaping MouseMovedCallback, _ screen: NSScreen) {
|
||||
window_ = element
|
||||
thumbnail.image = element.thumbnail
|
||||
let (thumbnailWidth, thumbnailHeight) = CollectionViewItemView.thumbnailSize(element.thumbnail, screen)
|
||||
let thumbnailSize = NSSize(width: thumbnailWidth.rounded(), height: thumbnailHeight.rounded())
|
||||
thumbnail.image?.size = thumbnailSize
|
||||
thumbnail.frame.size = thumbnailSize
|
||||
appIcon.image = element.icon
|
||||
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
|
||||
hiddenIcon.isHidden = !window_!.isHidden
|
||||
minimizedIcon.isHidden = !window_!.isMinimized
|
||||
spaceIcon.isHidden = element.spaceIndex == nil || Spaces.isSingleSpace || Preferences.hideSpaceNumberLabels
|
||||
if !spaceIcon.isHidden {
|
||||
if element.isOnAllSpaces {
|
||||
spaceIcon.setStar()
|
||||
} else {
|
||||
spaceIcon.setNumber(UInt32(element.spaceIndex!))
|
||||
}
|
||||
}
|
||||
let fontIconWidth = CGFloat([minimizedIcon, hiddenIcon, spaceIcon].filter { !$0.isHidden }.count) * (Preferences.fontIconSize + Preferences.intraCellPadding)
|
||||
label.textContainer!.size.width = frame.width - Preferences.iconSize - Preferences.intraCellPadding * 3 - fontIconWidth
|
||||
subviews.first!.frame.size = frame.size
|
||||
self.mouseDownCallback = mouseDownCallback
|
||||
self.mouseMovedCallback = mouseMovedCallback
|
||||
if trackingAreas.count > 0 {
|
||||
removeTrackingArea(trackingAreas[0])
|
||||
}
|
||||
addTrackingArea(NSTrackingArea(rect: bounds, options: [.mouseMoved, .activeAlways], owner: self, userInfo: nil))
|
||||
}
|
||||
|
||||
static func makeShadow(_ color: NSColor) -> NSShadow {
|
||||
let shadow = NSShadow()
|
||||
shadow.shadowColor = color
|
||||
shadow.shadowOffset = .zero
|
||||
shadow.shadowBlurRadius = 1
|
||||
return shadow
|
||||
}
|
||||
|
||||
static func downscaleFactor() -> CGFloat {
|
||||
let nCellsBeforePotentialOverflow = Preferences.minRows * Preferences.minCellsPerRow
|
||||
guard CGFloat(Windows.list.count) > nCellsBeforePotentialOverflow else { return 1 }
|
||||
// TODO: replace this buggy heuristic with a correct implementation of downscaling
|
||||
return nCellsBeforePotentialOverflow / (nCellsBeforePotentialOverflow + (sqrt(CGFloat(Windows.list.count) - nCellsBeforePotentialOverflow) * 2))
|
||||
}
|
||||
|
||||
static func widthMax(_ screen: NSScreen) -> CGFloat {
|
||||
return (ThumbnailsPanel.widthMax(screen) / Preferences.minCellsPerRow - Preferences.interCellPadding) * CollectionViewItemView.downscaleFactor()
|
||||
}
|
||||
|
||||
static func widthMin(_ screen: NSScreen) -> CGFloat {
|
||||
return (ThumbnailsPanel.widthMax(screen) / Preferences.maxCellsPerRow - Preferences.interCellPadding) * CollectionViewItemView.downscaleFactor()
|
||||
}
|
||||
|
||||
static func height(_ screen: NSScreen) -> CGFloat {
|
||||
return (ThumbnailsPanel.heightMax(screen) / Preferences.minRows - Preferences.interCellPadding) * CollectionViewItemView.downscaleFactor()
|
||||
}
|
||||
|
||||
static func width(_ image: NSImage?, _ screen: NSScreen) -> CGFloat {
|
||||
return max(thumbnailSize(image, screen).0 + Preferences.intraCellPadding * 2, CollectionViewItemView.widthMin(screen))
|
||||
}
|
||||
|
||||
static func thumbnailSize(_ image: NSImage?, _ screen: NSScreen) -> (CGFloat, CGFloat) {
|
||||
guard let image = image else { return (0, 0) }
|
||||
let thumbnailHeightMax = CollectionViewItemView.height(screen) - Preferences.intraCellPadding * 3 - Preferences.iconSize
|
||||
let thumbnailWidthMax = CollectionViewItemView.widthMax(screen) - Preferences.intraCellPadding * 2
|
||||
let thumbnailHeight = min(image.size.height, thumbnailHeightMax)
|
||||
let thumbnailWidth = min(image.size.width, thumbnailWidthMax)
|
||||
let imageRatio = image.size.width / image.size.height
|
||||
let thumbnailRatio = thumbnailWidth / thumbnailHeight
|
||||
if thumbnailRatio > imageRatio {
|
||||
return (image.size.width * thumbnailHeight / image.size.height, thumbnailHeight)
|
||||
}
|
||||
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 makeVStackView(_ hStackView: NSStackView) -> NSStackView {
|
||||
let vStackView = NSStackView()
|
||||
vStackView.wantsLayer = true
|
||||
vStackView.layer!.backgroundColor = .clear
|
||||
vStackView.layer!.cornerRadius = Preferences.cellCornerRadius
|
||||
vStackView.layer!.borderWidth = Preferences.cellBorderWidth
|
||||
vStackView.layer!.borderColor = .clear
|
||||
vStackView.edgeInsets = NSEdgeInsets(top: Preferences.intraCellPadding, left: Preferences.intraCellPadding, bottom: Preferences.intraCellPadding, right: Preferences.intraCellPadding)
|
||||
vStackView.orientation = .vertical
|
||||
vStackView.spacing = Preferences.intraCellPadding
|
||||
vStackView.setViews([hStackView, thumbnail], in: .leading)
|
||||
return vStackView
|
||||
}
|
||||
}
|
||||
|
||||
typealias MouseDownCallback = () -> Void
|
||||
typealias MouseMovedCallback = () -> Void
|
||||
@@ -21,8 +21,9 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele
|
||||
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
|
||||
// 2nd highest level possible; this allows the app to go on top of context menus
|
||||
// highest level is .screenSaver but makes drag and drop on top the main window impossible
|
||||
level = .popUpMenu
|
||||
// helps filter out this window from the thumbnails
|
||||
setAccessibilitySubrole(.unknown)
|
||||
}
|
||||
@@ -65,13 +66,16 @@ class ThumbnailsPanel: NSPanel, NSCollectionViewDataSource, NSCollectionViewDele
|
||||
|
||||
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
|
||||
let item = collectionView.makeItem(withIdentifier: cellId, for: indexPath) as! CollectionViewItem
|
||||
item.updateRecycledCellWithNewContent(Windows.list[indexPath.item], app!.focusSelectedWindow, app!.thumbnailsPanel!.highlightCell, currentScreen!)
|
||||
item.view_.updateRecycledCellWithNewContent(Windows.list[indexPath.item],
|
||||
{ self.app!.focusSelectedWindow(item.view_.window_) },
|
||||
{ self.app!.thumbnailsPanel!.highlightCell(item) },
|
||||
currentScreen!)
|
||||
return item
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {
|
||||
guard indexPath.item < Windows.list.count else { return .zero }
|
||||
return NSSize(width: CollectionViewItem.width(Windows.list[indexPath.item].thumbnail, currentScreen!).rounded(), height: CollectionViewItem.height(currentScreen!).rounded())
|
||||
return NSSize(width: CollectionViewItemView.width(Windows.list[indexPath.item].thumbnail, currentScreen!).rounded(), height: CollectionViewItemView.height(currentScreen!).rounded())
|
||||
}
|
||||
|
||||
func highlightCell() {
|
||||
|
||||
Reference in new issue
Block a user