perf: have views under and over the thumbnailview
This commit is contained in:
1 parent
fe52511885
commit
b9637e5802
5 files changed
+130
-130
No files matched your search
@@ -210,7 +210,8 @@
|
||||
D04BA0DD6819010987B578D1 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA07BBF2237CC6C72D264 /* Localizable.strings */; };
|
||||
D04BA100BD0F47828EB649FF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BAAEC2847830A3991F8D1 /* InfoPlist.strings */; };
|
||||
D04BA11E56383D082D7BE5A5 /* ThumbnailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAA998119CAA8B70A2B67 /* ThumbnailsView.swift */; };
|
||||
D04BAFC1A1B2C3D4E5F60002 /* HighlightOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAFC0A1B2C3D4E5F60001 /* HighlightOverlayView.swift */; };
|
||||
D04BAFC1A1B2C3D4E5F60002 /* ThumbnailOverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAFC0A1B2C3D4E5F60001 /* ThumbnailOverView.swift */; };
|
||||
D04BAFC3A1B2C3D4E5F60004 /* ThumbnailUnderLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAFC2A1B2C3D4E5F60003 /* ThumbnailUnderLayer.swift */; };
|
||||
D04BA14D93726795A6937832 /* LabelAndControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA2526DC6726E0F7ACF7C /* LabelAndControl.swift */; };
|
||||
D04BA15A1B0C4871EA7CB899 /* GeneralTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BACE22DC907F03D193075 /* GeneralTab.swift */; };
|
||||
D04BA1621718FF26F8D5E75D /* CustomRecorderControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAE333F7170E87C5AC0EF /* CustomRecorderControl.swift */; };
|
||||
@@ -675,7 +676,8 @@
|
||||
D04BAA4442D0CE3A4972937F /* nl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = nl; path = InfoPlist.strings; sourceTree = "<group>"; };
|
||||
D04BAA6E43F1E6EB81F953AF /* ru */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ru; path = InfoPlist.strings; sourceTree = "<group>"; };
|
||||
D04BAA998119CAA8B70A2B67 /* ThumbnailsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailsView.swift; sourceTree = "<group>"; };
|
||||
D04BAFC0A1B2C3D4E5F60001 /* HighlightOverlayView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighlightOverlayView.swift; sourceTree = "<group>"; };
|
||||
D04BAFC0A1B2C3D4E5F60001 /* ThumbnailOverView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailOverView.swift; sourceTree = "<group>"; };
|
||||
D04BAFC2A1B2C3D4E5F60003 /* ThumbnailUnderLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailUnderLayer.swift; sourceTree = "<group>"; };
|
||||
D04BAA9E0539EE620D08F63F /* fr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = fr; path = InfoPlist.strings; sourceTree = "<group>"; };
|
||||
D04BAAA1835480F9B3CCF170 /* blacklists@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "blacklists@2x.png"; sourceTree = "<group>"; };
|
||||
D04BAAB92261FC04854FDDE9 /* App.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
|
||||
@@ -1655,7 +1657,8 @@
|
||||
D04BA1DF8CAB2FAB7FE9244B /* ThumbnailFontIconView.swift */,
|
||||
D04BA258B56193958D60978A /* ThumbnailView.swift */,
|
||||
D04BAA998119CAA8B70A2B67 /* ThumbnailsView.swift */,
|
||||
D04BAFC0A1B2C3D4E5F60001 /* HighlightOverlayView.swift */,
|
||||
D04BAFC0A1B2C3D4E5F60001 /* ThumbnailOverView.swift */,
|
||||
D04BAFC2A1B2C3D4E5F60003 /* ThumbnailUnderLayer.swift */,
|
||||
AA974BA829B7D84C0099A29E /* PreviewPanel.swift */,
|
||||
);
|
||||
path = "main-window";
|
||||
@@ -2489,7 +2492,8 @@
|
||||
D04BAD2A7F2E8BF64EE982E9 /* TextArea.swift in Sources */,
|
||||
5F17452E2F1A908D00128EF8 /* WindowDiscriminator.swift in Sources */,
|
||||
D04BA11E56383D082D7BE5A5 /* ThumbnailsView.swift in Sources */,
|
||||
D04BAFC1A1B2C3D4E5F60002 /* HighlightOverlayView.swift in Sources */,
|
||||
D04BAFC1A1B2C3D4E5F60002 /* ThumbnailOverView.swift in Sources */,
|
||||
D04BAFC3A1B2C3D4E5F60004 /* ThumbnailUnderLayer.swift in Sources */,
|
||||
5F21C9E42C6E94700091F72F /* CustomizeStyleSheet.swift in Sources */,
|
||||
D04BA1621718FF26F8D5E75D /* CustomRecorderControl.swift in Sources */,
|
||||
D04BA1637E125D38546C26E2 /* StackView.swift in Sources */,
|
||||
|
||||
+47
-31
@@ -1,13 +1,13 @@
|
||||
import Cocoa
|
||||
|
||||
class HighlightOverlayView: FlippedView {
|
||||
let focusedLayer = noAnimation { CALayer() }
|
||||
let hoveredLayer = noAnimation { CALayer() }
|
||||
class ThumbnailOverView: FlippedView {
|
||||
var quitButton = TrafficLightButton(.quit, NSLocalizedString("Quit app", comment: ""))
|
||||
var closeButton = TrafficLightButton(.close, NSLocalizedString("Close window", comment: ""))
|
||||
var minimizeButton = TrafficLightButton(.miniaturize, NSLocalizedString("Minimize/Deminimize window", comment: ""))
|
||||
var maximizeButton = TrafficLightButton(.fullscreen, NSLocalizedString("Fullscreen/Defullscreen window", comment: ""))
|
||||
var isShowingWindowControls = false
|
||||
weak var scrollView: ScrollView?
|
||||
var previousTarget: ThumbnailView?
|
||||
|
||||
var windowControlButtons: [TrafficLightButton] { [quitButton, closeButton, minimizeButton, maximizeButton] }
|
||||
|
||||
@@ -15,14 +15,11 @@ class HighlightOverlayView: FlippedView {
|
||||
self.init(frame: .zero)
|
||||
wantsLayer = true
|
||||
layer!.masksToBounds = false
|
||||
for highlightLayer in [focusedLayer, hoveredLayer] {
|
||||
highlightLayer.isHidden = true
|
||||
layer!.addSublayer(highlightLayer)
|
||||
}
|
||||
for button in windowControlButtons {
|
||||
addSubview(button)
|
||||
button.isHidden = true
|
||||
}
|
||||
addTrackingArea(NSTrackingArea(rect: .zero, options: [.mouseMoved, .mouseEnteredAndExited, .activeAlways, .inVisibleRect], owner: self, userInfo: nil))
|
||||
}
|
||||
|
||||
override func hitTest(_ point: NSPoint) -> NSView? {
|
||||
@@ -36,35 +33,54 @@ class HighlightOverlayView: FlippedView {
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateHighlight(focusedView: ThumbnailView?, hoveredView: ThumbnailView?) {
|
||||
updateLayer(focusedLayer, for: focusedView, isFocused: true)
|
||||
updateLayer(hoveredLayer, for: hoveredView, isFocused: false)
|
||||
// MARK: - Mouse hover management
|
||||
|
||||
override func mouseExited(with event: NSEvent) {
|
||||
caTransaction {
|
||||
previousTarget = nil
|
||||
resetHoveredWindow()
|
||||
}
|
||||
}
|
||||
|
||||
private func updateLayer(_ highlightLayer: CALayer, for view: ThumbnailView?, isFocused: Bool) {
|
||||
guard let view, view.frame != .zero else {
|
||||
highlightLayer.isHidden = true
|
||||
return
|
||||
override func mouseMoved(with event: NSEvent) {
|
||||
guard let scrollView, !scrollView.isCurrentlyScrolling && CursorEvents.isAllowedToMouseHover else { return }
|
||||
let location = convert(App.app.thumbnailsPanel.mouseLocationOutsideOfEventStream, from: nil)
|
||||
let newTarget = findTarget(location)
|
||||
guard newTarget !== previousTarget else { return }
|
||||
caTransaction {
|
||||
if let newTarget {
|
||||
hideWindowControls()
|
||||
newTarget.mouseMoved()
|
||||
showWindowControls(for: newTarget)
|
||||
} else {
|
||||
resetHoveredWindow()
|
||||
}
|
||||
previousTarget = newTarget
|
||||
}
|
||||
let hf = view.highlightFrame
|
||||
let rect = CGRect(
|
||||
x: view.frame.origin.x + hf.origin.x,
|
||||
y: view.frame.origin.y + hf.origin.y,
|
||||
width: hf.width,
|
||||
height: hf.height
|
||||
)
|
||||
highlightLayer.frame = rect
|
||||
highlightLayer.cornerRadius = Appearance.cellCornerRadius
|
||||
highlightLayer.backgroundColor = (isFocused
|
||||
? Appearance.highlightFocusedBackgroundColor
|
||||
: Appearance.highlightHoveredBackgroundColor).cgColor
|
||||
highlightLayer.borderColor = (isFocused
|
||||
? Appearance.highlightFocusedBorderColor
|
||||
: Appearance.highlightHoveredBorderColor).cgColor
|
||||
highlightLayer.borderWidth = Appearance.highlightBorderWidth
|
||||
highlightLayer.isHidden = false
|
||||
}
|
||||
|
||||
private func findTarget(_ location: NSPoint) -> ThumbnailView? {
|
||||
guard let documentView = superview else { return nil }
|
||||
for case let view as ThumbnailView in documentView.subviews {
|
||||
let frame = view.frame
|
||||
let expandedFrame = CGRect(x: frame.minX - (App.shared.userInterfaceLayoutDirection == .leftToRight ? 0 : 1), y: frame.minY, width: frame.width + 1, height: frame.height + 1)
|
||||
if expandedFrame.contains(location) {
|
||||
return view
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private func resetHoveredWindow() {
|
||||
if let oldIndex = Windows.hoveredWindowIndex {
|
||||
Windows.hoveredWindowIndex = nil
|
||||
ThumbnailsView.highlight(oldIndex)
|
||||
}
|
||||
hideWindowControls()
|
||||
}
|
||||
|
||||
// MARK: - Window controls
|
||||
|
||||
func showWindowControls(for view: ThumbnailView) {
|
||||
guard Preferences.appearanceStyle == .thumbnails else { hideWindowControls(); return }
|
||||
let shouldShow = !Preferences.hideColoredCircles && !Appearance.hideThumbnails
|
||||
@@ -0,0 +1,46 @@
|
||||
import Cocoa
|
||||
|
||||
class ThumbnailUnderLayer: CALayer {
|
||||
let focusedLayer = noAnimation { CALayer() }
|
||||
let hoveredLayer = noAnimation { CALayer() }
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
delegate = NoAnimationDelegate.shared
|
||||
for highlightLayer in [focusedLayer, hoveredLayer] {
|
||||
highlightLayer.isHidden = true
|
||||
addSublayer(highlightLayer)
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) { fatalError() }
|
||||
|
||||
func updateHighlight(focusedView: ThumbnailView?, hoveredView: ThumbnailView?) {
|
||||
updateLayer(focusedLayer, for: focusedView, isFocused: true)
|
||||
updateLayer(hoveredLayer, for: hoveredView, isFocused: false)
|
||||
}
|
||||
|
||||
private func updateLayer(_ highlightLayer: CALayer, for view: ThumbnailView?, isFocused: Bool) {
|
||||
guard let view, view.frame != .zero else {
|
||||
highlightLayer.isHidden = true
|
||||
return
|
||||
}
|
||||
let hf = view.highlightFrame
|
||||
let rect = CGRect(
|
||||
x: view.frame.origin.x + hf.origin.x,
|
||||
y: view.frame.origin.y + hf.origin.y,
|
||||
width: hf.width,
|
||||
height: hf.height
|
||||
)
|
||||
highlightLayer.frame = rect
|
||||
highlightLayer.cornerRadius = Appearance.cellCornerRadius
|
||||
highlightLayer.backgroundColor = (isFocused
|
||||
? Appearance.highlightFocusedBackgroundColor
|
||||
: Appearance.highlightHoveredBackgroundColor).cgColor
|
||||
highlightLayer.borderColor = (isFocused
|
||||
? Appearance.highlightFocusedBorderColor
|
||||
: Appearance.highlightHoveredBorderColor).cgColor
|
||||
highlightLayer.borderWidth = Appearance.highlightBorderWidth
|
||||
highlightLayer.isHidden = false
|
||||
}
|
||||
}
|
||||
@@ -114,7 +114,7 @@ class ThumbnailView: FlippedView {
|
||||
observeDragAndDrop()
|
||||
}
|
||||
|
||||
/// The frame used by HighlightOverlayView to position the highlight rectangle.
|
||||
/// The frame used by ThumbnailUnderLayer to position the highlight rectangle.
|
||||
/// In appIcons style, it covers appIcon + edge insets. Otherwise, it covers the full cell.
|
||||
var highlightFrame: CGRect {
|
||||
if Preferences.appearanceStyle == .appIcons {
|
||||
@@ -360,7 +360,7 @@ class ThumbnailView: FlippedView {
|
||||
// This is because its updated async. We need it positioned correctly always
|
||||
let (offsetX, offsetY) = dockLabelOffset()
|
||||
assignIfDifferent(&dockLabelIcon.frame.origin.x, appIcon.frame.maxX - (ThumbnailsView.layoutCache.dockLabelSize.width * offsetX).rounded())
|
||||
assignIfDifferent(&dockLabelIcon.frame.origin.y, appIcon.frame.maxY - (ThumbnailsView.layoutCache.dockLabelSize.height * offsetY).rounded())
|
||||
assignIfDifferent(&dockLabelIcon.frame.origin.y, (ThumbnailsView.layoutCache.dockLabelSize.height * offsetY).rounded())
|
||||
}
|
||||
|
||||
/// positioning the dock label is messy because it's an NSTextField so it's visual size doesn't match what we can through APIs
|
||||
@@ -376,15 +376,11 @@ class ThumbnailView: FlippedView {
|
||||
offsetX = 0.92
|
||||
}
|
||||
}
|
||||
var offsetY = offsetX
|
||||
if Preferences.appearanceStyle == .appIcons {
|
||||
if Preferences.appearanceSize == .small {
|
||||
offsetY = 0.88
|
||||
} else if Preferences.appearanceSize == .medium {
|
||||
offsetY = 0.90
|
||||
} else { // .large
|
||||
offsetY = 0.92
|
||||
}
|
||||
var offsetY = 0.0
|
||||
if Preferences.appearanceStyle == .thumbnails {
|
||||
offsetY = 0.5
|
||||
} else if Preferences.appearanceStyle == .titles {
|
||||
offsetY = 0.1
|
||||
}
|
||||
return (offsetX, offsetY)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ class ThumbnailsView {
|
||||
static var thumbnailsWidth = CGFloat(0.0)
|
||||
static var thumbnailsHeight = CGFloat(0.0)
|
||||
static var layoutCache = LayoutCache()
|
||||
var highlightOverlay = HighlightOverlayView()
|
||||
var thumbnailUnderLayer = ThumbnailUnderLayer()
|
||||
var thumbnailOverView = ThumbnailOverView()
|
||||
|
||||
init() {
|
||||
updateBackgroundView()
|
||||
@@ -52,7 +53,10 @@ class ThumbnailsView {
|
||||
for i in 0..<ThumbnailsView.recycledViews.count {
|
||||
ThumbnailsView.recycledViews[i] = ThumbnailView()
|
||||
}
|
||||
highlightOverlay = HighlightOverlayView()
|
||||
thumbnailUnderLayer = ThumbnailUnderLayer()
|
||||
thumbnailOverView = ThumbnailOverView()
|
||||
thumbnailOverView.scrollView = scrollView
|
||||
lastRowSignature.removeAll()
|
||||
Self.updateCachedSizes()
|
||||
}
|
||||
|
||||
@@ -61,10 +65,10 @@ class ThumbnailsView {
|
||||
view.indexInRecycledViews = indexInRecycledViews
|
||||
guard view.frame != .zero else { return }
|
||||
view.drawHighlight()
|
||||
let overlay = App.app.thumbnailsPanel.thumbnailsView.highlightOverlay
|
||||
let underLayer = App.app.thumbnailsPanel.thumbnailsView.thumbnailUnderLayer
|
||||
let focusedView = recycledViews[Windows.selectedWindowIndex]
|
||||
let hoveredView = Windows.hoveredWindowIndex.map { recycledViews[$0] }
|
||||
overlay.updateHighlight(
|
||||
underLayer.updateHighlight(
|
||||
focusedView: focusedView.frame != .zero ? focusedView : nil,
|
||||
hoveredView: hoveredView != focusedView && hoveredView?.frame != .zero ? hoveredView : nil
|
||||
)
|
||||
@@ -183,7 +187,12 @@ class ThumbnailsView {
|
||||
}
|
||||
}
|
||||
scrollView.documentView!.subviews = newViews
|
||||
scrollView.documentView!.addSubview(highlightOverlay)
|
||||
scrollView.documentView!.addSubview(thumbnailOverView)
|
||||
thumbnailOverView.scrollView = scrollView
|
||||
let docLayer = scrollView.documentView!.layer!
|
||||
if thumbnailUnderLayer.superlayer !== docLayer {
|
||||
docLayer.insertSublayer(thumbnailUnderLayer, at: 0)
|
||||
}
|
||||
return (maxX, maxY, labelHeight, rowSignature)
|
||||
}
|
||||
|
||||
@@ -227,7 +236,9 @@ class ThumbnailsView {
|
||||
scrollView.documentView!.subviews.forEach { $0.frame.origin.x -= croppedWidth }
|
||||
}
|
||||
scrollView.documentView!.frame.size = NSSize(width: maxX, height: maxY)
|
||||
highlightOverlay.frame = CGRect(origin: .zero, size: scrollView.documentView!.frame.size)
|
||||
let docSize = scrollView.documentView!.frame.size
|
||||
thumbnailOverView.frame = CGRect(origin: .zero, size: docSize)
|
||||
thumbnailUnderLayer.frame = CGRect(origin: .zero, size: docSize)
|
||||
}
|
||||
|
||||
func centerRows(_ maxX: CGFloat) {
|
||||
@@ -254,8 +265,8 @@ class ThumbnailsView {
|
||||
ThumbnailsView.highlight(Windows.selectedWindowIndex)
|
||||
if let hoveredWindowIndex = Windows.hoveredWindowIndex {
|
||||
ThumbnailsView.highlight(hoveredWindowIndex)
|
||||
if highlightOverlay.isShowingWindowControls {
|
||||
highlightOverlay.showWindowControls(for: ThumbnailsView.recycledViews[hoveredWindowIndex])
|
||||
if thumbnailOverView.isShowingWindowControls {
|
||||
thumbnailOverView.showWindowControls(for: ThumbnailsView.recycledViews[hoveredWindowIndex])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,11 +303,11 @@ class ScrollView: NSScrollView {
|
||||
override class var isCompatibleWithResponsiveScrolling: Bool { true }
|
||||
|
||||
var isCurrentlyScrolling = false
|
||||
var previousTarget: ThumbnailView?
|
||||
|
||||
convenience init() {
|
||||
self.init(frame: .zero)
|
||||
documentView = FlippedView(frame: .zero)
|
||||
documentView!.wantsLayer = true
|
||||
drawsBackground = false
|
||||
hasVerticalScroller = true
|
||||
verticalScrollElasticity = .none
|
||||
@@ -304,7 +315,6 @@ class ScrollView: NSScrollView {
|
||||
scrollerKnobStyle = .light
|
||||
horizontalScrollElasticity = .none
|
||||
usesPredominantAxisScrolling = true
|
||||
addTrackingArea(NSTrackingArea(rect: .zero, options: [.mouseMoved, .mouseEnteredAndExited, .activeAlways, .inVisibleRect], owner: self, userInfo: nil))
|
||||
observeScrollingEvents()
|
||||
}
|
||||
|
||||
@@ -313,80 +323,8 @@ class ScrollView: NSScrollView {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(scrollingEnded), name: NSScrollView.didEndLiveScrollNotification, object: nil)
|
||||
}
|
||||
|
||||
@objc private func scrollingStarted() {
|
||||
isCurrentlyScrolling = true
|
||||
}
|
||||
|
||||
@objc private func scrollingEnded() {
|
||||
isCurrentlyScrolling = false
|
||||
}
|
||||
|
||||
private func resetHoveredWindow() {
|
||||
if let oldIndex = Windows.hoveredWindowIndex {
|
||||
Windows.hoveredWindowIndex = nil
|
||||
ThumbnailsView.highlight(oldIndex)
|
||||
}
|
||||
App.app.thumbnailsPanel.thumbnailsView.highlightOverlay.hideWindowControls()
|
||||
}
|
||||
|
||||
override func mouseExited(with event: NSEvent) {
|
||||
caTransaction {
|
||||
previousTarget = nil
|
||||
resetHoveredWindow()
|
||||
}
|
||||
}
|
||||
|
||||
override func mouseMoved(with event: NSEvent) {
|
||||
guard let documentView, !isCurrentlyScrolling && CursorEvents.isAllowedToMouseHover else { return }
|
||||
let location = documentView.convert(App.app.thumbnailsPanel.mouseLocationOutsideOfEventStream, from: nil)
|
||||
let newTarget = findTarget(location)
|
||||
guard newTarget !== previousTarget else { return }
|
||||
let overlay = App.app.thumbnailsPanel.thumbnailsView.highlightOverlay
|
||||
caTransaction {
|
||||
if let newTarget {
|
||||
overlay.hideWindowControls()
|
||||
newTarget.mouseMoved()
|
||||
overlay.showWindowControls(for: newTarget)
|
||||
} else {
|
||||
resetHoveredWindow()
|
||||
}
|
||||
previousTarget = newTarget
|
||||
}
|
||||
}
|
||||
|
||||
private func findTarget(_ location: NSPoint) -> ThumbnailView? {
|
||||
for case let view as ThumbnailView in documentView!.subviews {
|
||||
let frame = view.frame
|
||||
let expandedFrame = CGRect(x: frame.minX - (App.shared.userInterfaceLayoutDirection == .leftToRight ? 0 : 1), y: frame.minY, width: frame.width + 1, height: frame.height + 1)
|
||||
if expandedFrame.contains(location) {
|
||||
return view
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Checks whether the mouse pointer is within the padding area around a thumbnail.
|
||||
///
|
||||
/// This is used to avoid gaps between thumbnail views where the mouse pointer might not be detected.
|
||||
///
|
||||
/// @return `true` if the mouse pointer is within the padding area around a thumbnail; `false` otherwise.
|
||||
private func checkIfWithinInterPadding() -> Bool {
|
||||
if Preferences.appearanceStyle == .appIcons {
|
||||
let mouseLocation = App.app.thumbnailsPanel.mouseLocationOutsideOfEventStream
|
||||
let mouseRect = NSRect(x: mouseLocation.x - Appearance.interCellPadding,
|
||||
y: mouseLocation.y - Appearance.interCellPadding,
|
||||
width: 2 * Appearance.interCellPadding,
|
||||
height: 2 * Appearance.interCellPadding)
|
||||
if let hoveredWindowIndex = Windows.hoveredWindowIndex {
|
||||
let thumbnail = ThumbnailsView.recycledViews[hoveredWindowIndex]
|
||||
let mouseRectInView = thumbnail.convert(mouseRect, from: nil)
|
||||
if thumbnail.bounds.intersects(mouseRectInView) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@objc private func scrollingStarted() { isCurrentlyScrolling = true }
|
||||
@objc private func scrollingEnded() { isCurrentlyScrolling = false }
|
||||
|
||||
/// holding shift and using the scrolling wheel will generate a horizontal movement
|
||||
/// shift can be part of shortcuts so we force shift scrolls to be vertical
|
||||
|
||||
Reference in new issue
Block a user