diff --git a/Packages/CandidateUI/Sources/CandidateUI/HorizontalCandidateController.swift b/Packages/CandidateUI/Sources/CandidateUI/HorizontalCandidateController.swift index 4945db6f7..7538b636a 100644 --- a/Packages/CandidateUI/Sources/CandidateUI/HorizontalCandidateController.swift +++ b/Packages/CandidateUI/Sources/CandidateUI/HorizontalCandidateController.swift @@ -97,10 +97,10 @@ fileprivate class HorizontalCandidateView: NSView { keyLabelAttrDict = [.font: labelFont, .paragraphStyle: paraStyle, - .foregroundColor: NSColor.black] + .foregroundColor: NSColor.secondaryLabelColor] candidateAttrDict = [.font: candidateFont, .paragraphStyle: paraStyle, - .foregroundColor: NSColor.textColor] + .foregroundColor: NSColor.labelColor] let labelFontSize = labelFont.pointSize let candidateFontSize = candidateFont.pointSize @@ -112,13 +112,9 @@ fileprivate class HorizontalCandidateView: NSView { } override func draw(_ dirtyRect: NSRect) { - let backgroundColor = NSColor.controlBackgroundColor - let darkGray = NSColor(deviceWhite: 0.7, alpha: 1.0) let lightGray = NSColor(deviceWhite: 0.8, alpha: 1.0) let bounds = self.bounds - backgroundColor.setFill() - NSBezierPath.fill(bounds) if #available(macOS 10.14, *) { NSColor.separatorColor.setStroke() @@ -141,20 +137,25 @@ 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) - (index == highlightedIndex ? darkGray : lightGray).setFill() - NSBezierPath.fill(labelRect) - (keyLabels[index] as NSString).draw(in: labelRect, withAttributes: keyLabelAttrDict) + var activeKeyLabelAttrDict = keyLabelAttrDict + if index == highlightedIndex { + NSColor.selectedControlColor.setFill() + NSBezierPath.fill(labelRect) + activeKeyLabelAttrDict[.foregroundColor] = NSColor.selectedControlTextColor + } + (keyLabels[index] as NSString).draw(in: labelRect, withAttributes: activeKeyLabelAttrDict) var activeCandidateAttr = candidateAttrDict if index == highlightedIndex { - NSColor.selectedTextBackgroundColor.setFill() - activeCandidateAttr = candidateAttrDict - activeCandidateAttr[.foregroundColor] = NSColor.selectedTextColor - } else { - backgroundColor.setFill() + if #available(macOS 10.14, *) { + NSColor.controlAccentColor.setFill() + } else { + NSColor.selectedControlColor.setFill() + } + NSBezierPath.fill(candidateRect) + activeCandidateAttr[.foregroundColor] = NSColor.white } - NSBezierPath.fill(candidateRect) (displayedCandidates[index] as NSString).draw(in: candidateRect, withAttributes: activeCandidateAttr) accuWidth += currentWidth + 1.0 } @@ -221,6 +222,19 @@ public class HorizontalCandidateController: CandidateController { 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, *) { + effect.material = .popover + } else { + effect.material = .appearanceBased + } + effect.state = .active + effect.maskImage = .mask(withCornerRadius: 4) + panel.contentView = effect contentRect.origin = NSPoint.zero candidateView = HorizontalCandidateView(frame: contentRect) @@ -230,12 +244,14 @@ public class HorizontalCandidateController: CandidateController { nextPageButton = NSButton(frame: contentRect) nextPageButton.setButtonType(.momentaryLight) nextPageButton.bezelStyle = .smallSquare - nextPageButton.title = "»" + nextPageButton.isBordered = false + nextPageButton.attributedTitle = "»".withColor(.controlTextColor) prevPageButton = NSButton(frame: contentRect) prevPageButton.setButtonType(.momentaryLight) prevPageButton.bezelStyle = .smallSquare - prevPageButton.title = "«" + prevPageButton.isBordered = false + prevPageButton.attributedTitle = "«".withColor(.controlTextColor) panel.contentView?.addSubview(nextPageButton) panel.contentView?.addSubview(prevPageButton) @@ -433,3 +449,10 @@ extension HorizontalCandidateController { } } + +extension String { + func withColor(_ color: NSColor) -> NSAttributedString { + let attrDict: [NSAttributedString.Key: AnyObject] = [.foregroundColor: color] + return NSAttributedString(string: self, attributes: attrDict) + } +} diff --git a/Packages/CandidateUI/Sources/CandidateUI/VerticalCandidateController.swift b/Packages/CandidateUI/Sources/CandidateUI/VerticalCandidateController.swift index 5f38a3247..b9305bd6e 100644 --- a/Packages/CandidateUI/Sources/CandidateUI/VerticalCandidateController.swift +++ b/Packages/CandidateUI/Sources/CandidateUI/VerticalCandidateController.swift @@ -35,17 +35,12 @@ fileprivate class VerticalKeyLabelStripView: NSView { override func draw(_ dirtyRect: NSRect) { let bounds = self.bounds - 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) @@ -53,20 +48,22 @@ fileprivate class VerticalKeyLabelStripView: NSView { let textAttr: [NSAttributedString.Key: AnyObject] = [ .font: keyLabelFont, - .foregroundColor: black, + .foregroundColor: NSColor.secondaryLabelColor, + .paragraphStyle: paraStyle] + let textAttrHighlighted: [NSAttributedString.Key: AnyObject] = [ + .font: keyLabelFont, + .foregroundColor: NSColor.selectedControlTextColor, .paragraphStyle: paraStyle] for index in 0..= count { - cellRect.size.height += 1.0 + if index == highlightedIndex { + NSColor.selectedControlColor.setFill() + NSBezierPath.fill(cellRect) } - - (index == highlightedIndex ? darkGray : lightGray).setFill() - NSBezierPath.fill(cellRect) let text = keyLabels[Int(index)] - (text as NSString).draw(in: textRect, withAttributes: textAttr) + (text as NSString).draw(in: textRect, withAttributes: (index == highlightedIndex) ? textAttrHighlighted : textAttr) } } } @@ -85,13 +82,6 @@ private let kCandidateTextLeftMargin: CGFloat = 8.0 private let kCandidateTextPaddingWithMandatedTableViewPadding: CGFloat = 18.0 private let kCandidateTextLeftMarginWithMandatedTableViewPadding: CGFloat = 0.0 -private class BackgroundView: NSView { - override func draw(_ dirtyRect: NSRect) { - NSColor.windowBackgroundColor.setFill() - NSBezierPath.fill(self.bounds) - } -} - @objc(VTVerticalCandidateController) public class VerticalCandidateController: CandidateController { private var keyLabelStripView: VerticalKeyLabelStripView @@ -110,7 +100,19 @@ public class VerticalCandidateController: CandidateController { let panel = NSPanel(contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false) panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1) panel.hasShadow = true - panel.contentView = BackgroundView() + 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, *) { + effect.material = .popover + } else { + effect.material = .appearanceBased + } + effect.state = .active + effect.maskImage = .mask(withCornerRadius: 4) + panel.contentView = effect tooltipView = NSTextField(frame: NSRect.zero) tooltipView.isEditable = false @@ -130,6 +132,8 @@ public class VerticalCandidateController: CandidateController { scrollViewRect.size.width -= stripRect.size.width scrollView = NSScrollView(frame: scrollViewRect) scrollView.verticalScrollElasticity = .none + scrollView.drawsBackground = false + scrollView.contentView.drawsBackground = false tableView = NSTableView(frame: contentRect) let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "candidate")) @@ -144,6 +148,7 @@ public class VerticalCandidateController: CandidateController { tableView.headerView = nil tableView.allowsMultipleSelection = false tableView.allowsEmptySelection = false + tableView.backgroundColor = .clear if #available(macOS 10.16, *) { tableView.style = .fullWidth @@ -484,3 +489,18 @@ extension VerticalCandidateController: NSTableViewDataSource, NSTableViewDelegat self.window?.setFrame(frameRect, display: false) } } + +extension NSImage { + static func mask(withCornerRadius radius: CGFloat) -> NSImage { + let image = NSImage(size: NSSize(width: radius * 2, height: radius * 2), flipped: false) { + NSBezierPath(roundedRect: $0, xRadius: radius, yRadius: radius).fill() + NSColor.black.set() + return true + } + + image.capInsets = NSEdgeInsets(top: radius, left: radius, bottom: radius, right: radius) + image.resizingMode = .stretch + + return image + } +}