From d9f11c5c4648428ac428d6ffe067e26d5bd8dc39 Mon Sep 17 00:00:00 2001 From: Lukhnos Liu Date: Sun, 3 Dec 2023 11:51:59 -0800 Subject: [PATCH] Uses the legacy UI on macOS before Big Sur The NSVisualEffectView usage runs into issues when on macOS versions between 10.13 and 10.15, inclusive, with behavior being different between 10.13 on the one side and 10.14 and 10.15 on the other side. Given the effort that might be required, we think it best to switch back to the legacy design when run on macOS versions earlier than Big Sur (macOS 11.0). --- .../HorizontalCandidateController.swift | 112 +++++++++++++----- .../VerticalCandidateController.swift | 87 ++++++++++---- 2 files changed, 147 insertions(+), 52 deletions(-) diff --git a/Packages/CandidateUI/Sources/CandidateUI/HorizontalCandidateController.swift b/Packages/CandidateUI/Sources/CandidateUI/HorizontalCandidateController.swift index 0e2c797a..02959abd 100644 --- a/Packages/CandidateUI/Sources/CandidateUI/HorizontalCandidateController.swift +++ b/Packages/CandidateUI/Sources/CandidateUI/HorizontalCandidateController.swift @@ -91,16 +91,30 @@ fileprivate class HorizontalCandidateView: NSView { } func set(keyLabelFont labelFont: NSFont, candidateFont: NSFont) { + var bigSurOrHigher = false + if #available(macOS 10.16, *) { + bigSurOrHigher = true + } + let paraStyle = NSMutableParagraphStyle() paraStyle.setParagraphStyle(NSParagraphStyle.default) paraStyle.alignment = .center - keyLabelAttrDict = [.font: labelFont, - .paragraphStyle: paraStyle, - .foregroundColor: NSColor.labelColor] - candidateAttrDict = [.font: candidateFont, - .paragraphStyle: paraStyle, - .foregroundColor: NSColor.labelColor] + if bigSurOrHigher { + keyLabelAttrDict = [.font: labelFont, + .paragraphStyle: paraStyle, + .foregroundColor: NSColor.labelColor] + candidateAttrDict = [.font: candidateFont, + .paragraphStyle: paraStyle, + .foregroundColor: NSColor.labelColor] + } else { + keyLabelAttrDict = [.font: labelFont, + .paragraphStyle: paraStyle, + .foregroundColor: NSColor.black] + candidateAttrDict = [.font: candidateFont, + .paragraphStyle: paraStyle, + .foregroundColor: NSColor.textColor] + } let labelFontSize = labelFont.pointSize let candidateFontSize = candidateFont.pointSize @@ -112,10 +126,21 @@ fileprivate class HorizontalCandidateView: NSView { } override func draw(_ dirtyRect: NSRect) { - let lightGray = NSColor(deviceWhite: 0.8, alpha: 1.0) + var bigSurOrHigher = false + if #available(macOS 10.16, *) { + bigSurOrHigher = true + } + let backgroundColor = NSColor.controlBackgroundColor + let lightGray = NSColor(deviceWhite: 0.8, alpha: 1.0) + let darkGray = NSColor(deviceWhite: 0.7, alpha: 1.0) let bounds = self.bounds + if !bigSurOrHigher { + backgroundColor.setFill() + NSBezierPath.fill(bounds) + } + if #available(macOS 10.14, *) { NSColor.separatorColor.setStroke() } else { @@ -137,25 +162,40 @@ fileprivate class HorizontalCandidateView: NSView { let currentWidth = elementWidths[index] let labelRect = NSRect(x: accuWidth, y: tooltipSize.height, width: currentWidth, height: keyLabelHeight) let candidateRect = NSRect(x: accuWidth, y: tooltipSize.height + keyLabelHeight + 1.0, width: currentWidth, height: candidateTextHeight) + var activeKeyLabelAttrDict = keyLabelAttrDict - if index == highlightedIndex { - NSColor.selectedControlColor.setFill() + if bigSurOrHigher { + if index == highlightedIndex { + NSColor.selectedControlColor.setFill() + NSBezierPath.fill(labelRect) + activeKeyLabelAttrDict[.foregroundColor] = NSColor.selectedControlTextColor + } + } else { + (index == highlightedIndex ? darkGray : lightGray).setFill() NSBezierPath.fill(labelRect) - activeKeyLabelAttrDict[.foregroundColor] = NSColor.selectedControlTextColor } (keyLabels[index] as NSString).draw(in: labelRect, withAttributes: activeKeyLabelAttrDict) var activeCandidateAttr = candidateAttrDict - if index == highlightedIndex { - if #available(macOS 10.14, *) { - NSColor.controlAccentColor.setFill() + if bigSurOrHigher { + if index == highlightedIndex { + if #available(macOS 10.14, *) { + NSColor.controlAccentColor.setFill() + } else { + NSColor.selectedControlColor.setFill() + } + NSBezierPath.fill(candidateRect) + activeCandidateAttr[.foregroundColor] = NSColor.white + } + } else { + if index == highlightedIndex { + NSColor.selectedTextBackgroundColor.setFill() + activeCandidateAttr[.foregroundColor] = NSColor.selectedTextColor } else { - NSColor.selectedControlColor.setFill() + backgroundColor.setFill() } NSBezierPath.fill(candidateRect) - activeCandidateAttr[.foregroundColor] = NSColor.white } - (displayedCandidates[index] as NSString).draw(in: candidateRect, withAttributes: activeCandidateAttr) accuWidth += currentWidth + 1.0 } @@ -217,24 +257,28 @@ public class HorizontalCandidateController: CandidateController { private var currentPage: UInt = 0 public init() { + var bigSurOrHigher = false + if #available(macOS 10.16, *) { + bigSurOrHigher = true + } + var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0) let styleMask: NSWindow.StyleMask = [.borderless, .nonactivatingPanel] let panel = NSPanel(contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false) panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1) panel.hasShadow = true - panel.backgroundColor = .clear - panel.isOpaque = false - let effect = NSVisualEffectView(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) - effect.blendingMode = .behindWindow - if #available(macOS 10.14, *) { + if bigSurOrHigher { + panel.backgroundColor = .clear + panel.isOpaque = false + + let effect = NSVisualEffectView(frame: NSRect(x: 0, y: 0, width: 0, height: 0)) + effect.blendingMode = .behindWindow effect.material = .popover - } else { - effect.material = .appearanceBased + effect.state = .active + effect.maskImage = .mask(withCornerRadius: 4) + panel.contentView = effect } - effect.state = .active - effect.maskImage = .mask(withCornerRadius: 4) - panel.contentView = effect contentRect.origin = NSPoint.zero candidateView = HorizontalCandidateView(frame: contentRect) @@ -244,14 +288,22 @@ public class HorizontalCandidateController: CandidateController { nextPageButton = NSButton(frame: contentRect) nextPageButton.setButtonType(.momentaryLight) nextPageButton.bezelStyle = .smallSquare - nextPageButton.isBordered = false - nextPageButton.attributedTitle = "»".withColor(.controlTextColor) + if bigSurOrHigher { + nextPageButton.isBordered = false + nextPageButton.attributedTitle = "»".withColor(.controlTextColor) + } else { + nextPageButton.title = "»" + } prevPageButton = NSButton(frame: contentRect) prevPageButton.setButtonType(.momentaryLight) prevPageButton.bezelStyle = .smallSquare - prevPageButton.isBordered = false - prevPageButton.attributedTitle = "«".withColor(.controlTextColor) + if bigSurOrHigher { + prevPageButton.isBordered = false + prevPageButton.attributedTitle = "«".withColor(.controlTextColor) + } else { + prevPageButton.title = "«" + } panel.contentView?.addSubview(nextPageButton) panel.contentView?.addSubview(prevPageButton) diff --git a/Packages/CandidateUI/Sources/CandidateUI/VerticalCandidateController.swift b/Packages/CandidateUI/Sources/CandidateUI/VerticalCandidateController.swift index 48339ab4..0f4be1fd 100644 --- a/Packages/CandidateUI/Sources/CandidateUI/VerticalCandidateController.swift +++ b/Packages/CandidateUI/Sources/CandidateUI/VerticalCandidateController.swift @@ -34,36 +34,62 @@ fileprivate class VerticalKeyLabelStripView: NSView { } override func draw(_ dirtyRect: NSRect) { + var bigSurOrHigher = false + if #available(macOS 10.16, *) { + bigSurOrHigher = true + } + let bounds = self.bounds + if !bigSurOrHigher { + NSColor.white.setFill() + NSBezierPath.fill(bounds) + } let count = UInt(keyLabels.count) if count == 0 { return } let cellHeight: CGFloat = bounds.size.height / CGFloat(count) + let black = NSColor.black + let darkGray = NSColor(deviceWhite: 0.7, alpha: 1.0) + let lightGray = NSColor(deviceWhite: 0.8, alpha: 1.0) let paraStyle = NSMutableParagraphStyle() paraStyle.setParagraphStyle(NSParagraphStyle.default) paraStyle.alignment = .center - let textAttr: [NSAttributedString.Key: AnyObject] = [ - .font: keyLabelFont, - .foregroundColor: NSColor.labelColor, - .paragraphStyle: paraStyle] + let textAttr: [NSAttributedString.Key: AnyObject] = + bigSurOrHigher ? [ + .font: keyLabelFont, + .foregroundColor: NSColor.labelColor, + .paragraphStyle: paraStyle] + : [ + .font: keyLabelFont, + .foregroundColor: black, + .paragraphStyle: paraStyle] let textAttrHighlighted: [NSAttributedString.Key: AnyObject] = [ .font: keyLabelFont, .foregroundColor: NSColor.selectedControlTextColor, .paragraphStyle: paraStyle] for index in 0..