feat: support app-icon badges with large numbers
This commit is contained in:
1 parent
51db0cb8e4
commit
ceed334b06
3 files changed
+222
-92
No files matched your search
@@ -8,75 +8,237 @@ enum Symbols: String {
|
|||||||
case circledNumber10 = ""
|
case circledNumber10 = ""
|
||||||
case circledStar = ""
|
case circledStar = ""
|
||||||
case filledCircledStar = ""
|
case filledCircledStar = ""
|
||||||
case filledCircled = ""
|
|
||||||
case filledCircledNumber0 = ""
|
|
||||||
case filledCircledNumber10 = ""
|
|
||||||
case circledInfo = ""
|
case circledInfo = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Font icon using SF Symbols from the SF Pro font from Apple
|
class TileFontIconView: NSView {
|
||||||
// see https://developer.apple.com/design/human-interface-guidelines/sf-symbols/overview/
|
enum Rendering {
|
||||||
class TileFontIconView: TileTitleView {
|
case symbol
|
||||||
static var paragraphStyle = {
|
case badge
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SymbolCacheKey: Hashable {
|
||||||
|
var symbol: String
|
||||||
|
var size: CGFloat
|
||||||
|
var colorKey: String
|
||||||
|
}
|
||||||
|
|
||||||
|
static let paragraphStyle = {
|
||||||
let paragraphStyle = NSMutableParagraphStyle()
|
let paragraphStyle = NSMutableParagraphStyle()
|
||||||
// clip the top of the box since we know these symbols are always disks
|
|
||||||
paragraphStyle.lineHeightMultiple = 0.85
|
paragraphStyle.lineHeightMultiple = 0.85
|
||||||
return paragraphStyle
|
return paragraphStyle
|
||||||
}()
|
}()
|
||||||
var initialAttributedString: NSMutableAttributedString!
|
|
||||||
|
|
||||||
convenience init(symbol: Symbols, tooltip: String? = nil, size: CGFloat = Appearance.fontHeight, color: NSColor = Appearance.fontColor) {
|
private struct BadgeSizing {
|
||||||
// This helps SF symbols display vertically centered and not clipped at the top
|
static let containerFromIconRatio = CGFloat(0.43)
|
||||||
self.init(font: NSFont(name: "SF Pro Text", size: (size * 0.85).rounded())!)
|
static let textFromContainerRatio = CGFloat(0.57)
|
||||||
initialAttributedString = NSMutableAttributedString(string: symbol.rawValue, attributes: [.paragraphStyle: TileFontIconView.paragraphStyle])
|
static let minContainerHeight = CGFloat(11)
|
||||||
attributedStringValue = initialAttributedString
|
static let minTextHeight = CGFloat(8)
|
||||||
textColor = color
|
static let maxTextHeight = CGFloat(18)
|
||||||
toolTip = tooltip
|
static let horizontalPaddingRatio = CGFloat(0.10)
|
||||||
frame.size = cell!.cellSize
|
static let minHorizontalPadding = CGFloat(2)
|
||||||
|
static let appIconsMinRectWidthRatio = CGFloat(1.35)
|
||||||
|
static let maxDigits = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
// number should be in the interval [0-50]
|
private struct BadgeMetrics {
|
||||||
func setNumber(_ number: Int, _ filled: Bool) {
|
let containerHeight: CGFloat
|
||||||
let (baseCharacter, offset) = baseCharacterAndOffset(number, filled)
|
let textHeight: CGFloat
|
||||||
replaceCharIfNeeded(String(UnicodeScalar(Int(baseCharacter.unicodeScalars.first!.value) + offset)!))
|
}
|
||||||
|
|
||||||
|
private static var symbolCache = [SymbolCacheKey: NSAttributedString]()
|
||||||
|
|
||||||
|
static func badgeBaseSize(forIconSize iconSize: CGFloat) -> CGFloat {
|
||||||
|
max((iconSize * BadgeSizing.containerFromIconRatio).rounded(), BadgeSizing.minContainerHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
private let rendering: Rendering
|
||||||
|
private let symbolSize: CGFloat
|
||||||
|
private let symbolColor: NSColor
|
||||||
|
private let badgeFillColor: NSColor
|
||||||
|
private let badgeTextColor: NSColor
|
||||||
|
private let symbolFont: NSFont
|
||||||
|
private let badgeFont: NSFont
|
||||||
|
private let badgeContainerHeight: CGFloat
|
||||||
|
private let badgeHorizontalPadding: CGFloat
|
||||||
|
private var text = ""
|
||||||
|
private var cachedSymbolAttributedString: NSAttributedString?
|
||||||
|
private var cachedBadgeAttributedString: NSAttributedString?
|
||||||
|
private var cachedBadgeTextSize = NSSize.zero
|
||||||
|
|
||||||
|
convenience init(symbol: Symbols, tooltip: String? = nil, size: CGFloat = Appearance.fontHeight, color: NSColor = Appearance.fontColor) {
|
||||||
|
self.init(rendering: .symbol, initialText: symbol.rawValue, size: size, symbolColor: color, badgeFillColor: .clear, badgeTextColor: .clear)
|
||||||
|
toolTip = tooltip
|
||||||
|
frame.size = symbolSizeForCurrentText()
|
||||||
|
}
|
||||||
|
|
||||||
|
convenience init(badgeSize: CGFloat,
|
||||||
|
fillColor: NSColor = NSColor(srgbRed: 1, green: 0.25, blue: 0.2, alpha: 0.9),
|
||||||
|
textColor: NSColor = .white) {
|
||||||
|
self.init(rendering: .badge, initialText: "0", size: badgeSize, symbolColor: .clear, badgeFillColor: fillColor, badgeTextColor: textColor)
|
||||||
|
frame.size = badgeFrameSize(textWidth: maxBadgeTextWidth(), text: String(repeating: "8", count: BadgeSizing.maxDigits))
|
||||||
|
}
|
||||||
|
|
||||||
|
init(rendering: Rendering,
|
||||||
|
initialText: String,
|
||||||
|
size: CGFloat,
|
||||||
|
symbolColor: NSColor,
|
||||||
|
badgeFillColor: NSColor,
|
||||||
|
badgeTextColor: NSColor) {
|
||||||
|
self.rendering = rendering
|
||||||
|
self.symbolSize = size
|
||||||
|
self.symbolColor = symbolColor
|
||||||
|
self.badgeFillColor = badgeFillColor
|
||||||
|
self.badgeTextColor = badgeTextColor
|
||||||
|
symbolFont = NSFont(name: "SF Pro Text", size: (size * 0.85).rounded())!
|
||||||
|
let badgeMetrics = Self.badgeMetrics(size)
|
||||||
|
badgeContainerHeight = badgeMetrics.containerHeight
|
||||||
|
badgeHorizontalPadding = Self.badgeHorizontalPadding(badgeMetrics.containerHeight)
|
||||||
|
badgeFont = NSFont.systemFont(ofSize: badgeMetrics.textHeight)
|
||||||
|
text = initialText
|
||||||
|
super.init(frame: .zero)
|
||||||
|
cachedSymbolAttributedString = rendering == .symbol ? cachedSymbolText(initialText) : nil
|
||||||
|
if rendering == .badge {
|
||||||
|
cachedBadgeAttributedString = badgeAttributedText(initialText)
|
||||||
|
cachedBadgeTextSize = cachedBadgeAttributedString!.size()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("Class only supports programmatic initialization")
|
||||||
|
}
|
||||||
|
|
||||||
|
override var isOpaque: Bool { false }
|
||||||
|
override var intrinsicContentSize: NSSize { frame.size }
|
||||||
|
|
||||||
|
static func warmCaches(symbols: [Symbols], size: CGFloat, color: NSColor) {
|
||||||
|
let font = NSFont(name: "SF Pro Text", size: (size * 0.85).rounded())!
|
||||||
|
let attributes: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: color, .paragraphStyle: paragraphStyle]
|
||||||
|
let colorKey = symbolColorKey(color)
|
||||||
|
for symbol in symbols {
|
||||||
|
let key = SymbolCacheKey(symbol: symbol.rawValue, size: size, colorKey: colorKey)
|
||||||
|
if symbolCache[key] == nil {
|
||||||
|
symbolCache[key] = NSAttributedString(string: symbol.rawValue, attributes: attributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setText(_ text: String) {
|
||||||
|
guard text.count <= 4 && rendering == .badge else { setFilledStar(); return }
|
||||||
|
replaceTextIfNeeded(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setStar() {
|
func setStar() {
|
||||||
replaceCharIfNeeded(Symbols.circledStar.rawValue)
|
setStarLike(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFilledStar() {
|
func setFilledStar() {
|
||||||
replaceCharIfNeeded(Symbols.filledCircledStar.rawValue)
|
setStarLike(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func replaceCharIfNeeded(_ newChar: String) {
|
override func draw(_ dirtyRect: NSRect) {
|
||||||
if newChar != attributedStringValue.string {
|
if rendering == .badge {
|
||||||
initialAttributedString.replaceCharacters(in: NSRange(location: 0, length: 1), with: newChar)
|
drawBadge()
|
||||||
attributedStringValue = initialAttributedString
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func baseCharacterAndOffset(_ number: Int, _ filled: Bool) -> (String, Int) {
|
|
||||||
if number <= 9 {
|
|
||||||
// numbers alternate between empty and full circles; we skip the full circles
|
|
||||||
return ((filled ? Symbols.filledCircledNumber0 : Symbols.circledNumber0).rawValue, number * 2)
|
|
||||||
} else {
|
} else {
|
||||||
return ((filled ? Symbols.filledCircledNumber10 : Symbols.circledNumber10).rawValue, number - 10)
|
drawSymbol()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class ThumbnailFilledFontIconView: NSView {
|
private func setStarLike(_ filled: Bool) {
|
||||||
convenience init(_ thumbnailFontIconView: TileFontIconView, backgroundColor: NSColor, size: CGFloat) {
|
let star = rendering == .badge ? "" : (filled ? Symbols.filledCircledStar.rawValue : Symbols.circledStar.rawValue)
|
||||||
self.init(frame: .zero)
|
replaceTextIfNeeded(star)
|
||||||
let backgroundView = TileFontIconView(symbol: .filledCircled, size: size - 3, color: backgroundColor)
|
}
|
||||||
addSubview(backgroundView)
|
|
||||||
addSubview(thumbnailFontIconView, positioned: .above, relativeTo: nil)
|
private func replaceTextIfNeeded(_ newText: String) {
|
||||||
let fgSize = thumbnailFontIconView.frame.size
|
guard newText != text else { return }
|
||||||
let bgSize = backgroundView.frame.size
|
text = newText
|
||||||
let offset = ((fgSize.width - bgSize.width) / 2).rounded()
|
if rendering == .symbol {
|
||||||
thumbnailFontIconView.frame.origin = .zero
|
cachedSymbolAttributedString = cachedSymbolText(newText)
|
||||||
backgroundView.frame.origin = NSPoint(x: (fgSize.width - bgSize.width) / 2, y: offset)
|
frame.size = symbolSizeForCurrentText()
|
||||||
frame.size = fgSize
|
invalidateIntrinsicContentSize()
|
||||||
|
} else {
|
||||||
|
cachedBadgeAttributedString = badgeAttributedText(newText)
|
||||||
|
cachedBadgeTextSize = cachedBadgeAttributedString!.size()
|
||||||
|
}
|
||||||
|
needsDisplay = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private func drawSymbol() {
|
||||||
|
guard let cachedSymbolAttributedString else { return }
|
||||||
|
cachedSymbolAttributedString.draw(at: .zero)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func drawBadge() {
|
||||||
|
let badgeRect = anchoredBadgeRect()
|
||||||
|
let innerRect = badgeRect
|
||||||
|
let innerPath = NSBezierPath(roundedRect: innerRect, xRadius: innerRect.height / 2, yRadius: innerRect.height / 2)
|
||||||
|
badgeFillColor.setFill()
|
||||||
|
innerPath.fill()
|
||||||
|
guard let cachedBadgeAttributedString else { return }
|
||||||
|
let textSize = cachedBadgeTextSize
|
||||||
|
let textPoint = NSPoint(x: innerRect.midX - textSize.width / 2, y: innerRect.midY - textSize.height / 2)
|
||||||
|
cachedBadgeAttributedString.draw(at: textPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func anchoredBadgeRect() -> NSRect {
|
||||||
|
let size = badgeFrameSize(textWidth: cachedBadgeTextSize.width, text: text)
|
||||||
|
return NSRect(x: (frame.width - size.width).rounded(), y: 0, width: size.width, height: size.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func symbolSizeForCurrentText() -> NSSize {
|
||||||
|
cachedSymbolAttributedString?.size() ?? .zero
|
||||||
|
}
|
||||||
|
|
||||||
|
private func badgeFrameSize(textWidth: CGFloat, text: String) -> NSSize {
|
||||||
|
let height = badgeContainerHeight
|
||||||
|
var width = max(height, textWidth + badgeHorizontalPadding * 2)
|
||||||
|
if Preferences.appearanceStyle == .appIcons, text.count > 1 {
|
||||||
|
let minRectWidth = (height * BadgeSizing.appIconsMinRectWidthRatio).rounded(.up)
|
||||||
|
width = max(width, minRectWidth)
|
||||||
|
}
|
||||||
|
return NSSize(width: ceil(width), height: ceil(height))
|
||||||
|
}
|
||||||
|
|
||||||
|
private func badgeAttributedText(_ value: String) -> NSAttributedString {
|
||||||
|
NSAttributedString(string: value, attributes: [.font: badgeFont, .foregroundColor: badgeTextColor])
|
||||||
|
}
|
||||||
|
|
||||||
|
private func badgeTextWidth(_ value: String) -> CGFloat {
|
||||||
|
let attrs: [NSAttributedString.Key: Any] = [.font: badgeFont]
|
||||||
|
return NSAttributedString(string: value, attributes: attrs).size().width
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func badgeHorizontalPadding(_ height: CGFloat) -> CGFloat {
|
||||||
|
max(BadgeSizing.minHorizontalPadding, (height * BadgeSizing.horizontalPaddingRatio).rounded())
|
||||||
|
}
|
||||||
|
|
||||||
|
private func maxBadgeTextWidth() -> CGFloat {
|
||||||
|
badgeTextWidth(String(repeating: "8", count: BadgeSizing.maxDigits))
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func badgeMetrics(_ size: CGFloat) -> BadgeMetrics {
|
||||||
|
let rawContainerHeight = max(BadgeSizing.minContainerHeight, size.rounded())
|
||||||
|
let textHeight = badgeTextHeight(fromRawContainerHeight: rawContainerHeight)
|
||||||
|
let compactContainerHeight = (textHeight / BadgeSizing.textFromContainerRatio).rounded(.up)
|
||||||
|
let containerHeight = max(BadgeSizing.minContainerHeight, min(rawContainerHeight, compactContainerHeight))
|
||||||
|
return BadgeMetrics(containerHeight: containerHeight, textHeight: textHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func badgeTextHeight(fromRawContainerHeight rawContainerHeight: CGFloat) -> CGFloat {
|
||||||
|
min(max((rawContainerHeight * BadgeSizing.textFromContainerRatio).rounded(), BadgeSizing.minTextHeight), BadgeSizing.maxTextHeight)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func cachedSymbolText(_ value: String) -> NSAttributedString {
|
||||||
|
let key = SymbolCacheKey(symbol: value, size: symbolSize, colorKey: Self.symbolColorKey(symbolColor))
|
||||||
|
if let cached = Self.symbolCache[key] {
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
let cached = NSAttributedString(string: value, attributes: [.font: symbolFont, .foregroundColor: symbolColor, .paragraphStyle: Self.paragraphStyle])
|
||||||
|
Self.symbolCache[key] = cached
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func symbolColorKey(_ color: NSColor) -> String {
|
||||||
|
(color.usingColorSpace(.deviceRGB) ?? color).description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,9 +10,7 @@ class TileView: FlippedView {
|
|||||||
var appIcon = LightImageLayer()
|
var appIcon = LightImageLayer()
|
||||||
var label = TileTitleView(font: Appearance.font)
|
var label = TileTitleView(font: Appearance.font)
|
||||||
var statusIcons = StatusIconsView()
|
var statusIcons = StatusIconsView()
|
||||||
var dockLabelIcon = ThumbnailFilledFontIconView(
|
var dockLabelIcon = TileFontIconView(badgeSize: TileFontIconView.badgeBaseSize(forIconSize: TileView.iconSize().width))
|
||||||
TileFontIconView(symbol: .filledCircledNumber0, size: dockLabelLabelSize(), color: NSColor(srgbRed: 1, green: 0.30, blue: 0.25, alpha: 1)),
|
|
||||||
backgroundColor: NSColor.white, size: dockLabelLabelSize())
|
|
||||||
var windowlessAppIndicator = WindowlessAppIndicator(tooltip: TileView.noOpenWindowToolTip)
|
var windowlessAppIndicator = WindowlessAppIndicator(tooltip: TileView.noOpenWindowToolTip)
|
||||||
|
|
||||||
var mouseUpCallback: (() -> Void)!
|
var mouseUpCallback: (() -> Void)!
|
||||||
@@ -116,14 +114,8 @@ class TileView: FlippedView {
|
|||||||
func updateDockLabelIcon(_ dockLabel: String?) {
|
func updateDockLabelIcon(_ dockLabel: String?) {
|
||||||
assignIfDifferent(&dockLabelIcon.isHidden, dockLabel == nil || Preferences.hideAppBadges || Appearance.iconSize == 0)
|
assignIfDifferent(&dockLabelIcon.isHidden, dockLabel == nil || Preferences.hideAppBadges || Appearance.iconSize == 0)
|
||||||
if !dockLabelIcon.isHidden, let dockLabel {
|
if !dockLabelIcon.isHidden, let dockLabel {
|
||||||
let view = dockLabelIcon.subviews[1] as! TileFontIconView
|
dockLabelIcon.setText(dockLabel)
|
||||||
let dockLabelInt = Int(dockLabel)
|
dockLabelIcon.setAccessibilityLabel(getAccessibilityTextForBadge(dockLabel))
|
||||||
if dockLabelInt == nil || dockLabelInt! > 30 {
|
|
||||||
view.setFilledStar()
|
|
||||||
} else {
|
|
||||||
view.setNumber(dockLabelInt!, true)
|
|
||||||
}
|
|
||||||
view.setAccessibilityLabel(getAccessibilityTextForBadge(dockLabel))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,33 +308,16 @@ class TileView: FlippedView {
|
|||||||
thumbnail.centerInSuperlayer(x: true)
|
thumbnail.centerInSuperlayer(x: true)
|
||||||
}
|
}
|
||||||
updateWindowlessAppIndicatorPosition()
|
updateWindowlessAppIndicatorPosition()
|
||||||
// we set dockLabelIcon origin, without checking if .isHidden
|
updateDockLabelIconPosition()
|
||||||
// This is because its updated async. We need it positioned correctly always
|
|
||||||
let (offsetX, offsetY) = dockLabelOffset()
|
|
||||||
assignIfDifferent(&dockLabelIcon.frame.origin.x, appIcon.frame.maxX - (TilesView.layoutCache.dockLabelSize.width * offsetX).rounded())
|
|
||||||
assignIfDifferent(&dockLabelIcon.frame.origin.y, (TilesView.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
|
private func updateDockLabelIconPosition() {
|
||||||
// TODO: remove this; find a better way
|
let iconSize = max(appIcon.frame.width, appIcon.frame.height)
|
||||||
private func dockLabelOffset() -> (CGFloat, CGFloat) {
|
let offset = (iconSize * (Preferences.appearanceStyle == .appIcons && Preferences.appearanceSize == .large ? 0.03 : 0.05)).rounded()
|
||||||
var offsetX = 0.6
|
let badgeTopRightX = appIcon.frame.maxX + offset
|
||||||
if Preferences.appearanceStyle == .appIcons {
|
let badgeTopRightY = appIcon.frame.minY - offset
|
||||||
if Preferences.appearanceSize == .small {
|
assignIfDifferent(&dockLabelIcon.frame.origin.x, badgeTopRightX - dockLabelIcon.frame.width)
|
||||||
offsetX = 0.82
|
assignIfDifferent(&dockLabelIcon.frame.origin.y, badgeTopRightY)
|
||||||
} else if Preferences.appearanceSize == .medium {
|
|
||||||
offsetX = 0.86
|
|
||||||
} else { // .large
|
|
||||||
offsetX = 0.92
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var offsetY = 0.0
|
|
||||||
if Preferences.appearanceStyle == .thumbnails {
|
|
||||||
offsetY = 0.5
|
|
||||||
} else if Preferences.appearanceStyle == .titles {
|
|
||||||
offsetY = 0.1
|
|
||||||
}
|
|
||||||
return (offsetX, offsetY)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateWindowlessAppIndicatorPosition() {
|
private func updateWindowlessAppIndicatorPosition() {
|
||||||
@@ -412,12 +387,6 @@ class TileView: FlippedView {
|
|||||||
registerForDraggedTypes([NSPasteboard.PasteboardType(kUTTypeURL as String)])
|
registerForDraggedTypes([NSPasteboard.PasteboardType(kUTTypeURL as String)])
|
||||||
}
|
}
|
||||||
|
|
||||||
static func dockLabelLabelSize() -> CGFloat {
|
|
||||||
let size = (TileView.iconSize().width * 0.43).rounded()
|
|
||||||
// label should have a minimum size for readability
|
|
||||||
return max(size, 13)
|
|
||||||
}
|
|
||||||
|
|
||||||
static func makeShadow(_ color: NSColor?) -> NSShadow? {
|
static func makeShadow(_ color: NSColor?) -> NSShadow? {
|
||||||
let shadow = NSShadow()
|
let shadow = NSShadow()
|
||||||
shadow.shadowColor = color
|
shadow.shadowColor = color
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ class TilesView {
|
|||||||
let iconCellSize = firstView.statusIcons.iconCellSize
|
let iconCellSize = firstView.statusIcons.iconCellSize
|
||||||
layoutCache.iconWidth = iconCellSize.width
|
layoutCache.iconWidth = iconCellSize.width
|
||||||
layoutCache.iconHeight = iconCellSize.height
|
layoutCache.iconHeight = iconCellSize.height
|
||||||
layoutCache.dockLabelSize = firstView.dockLabelIcon.frame.size
|
|
||||||
layoutCache.comfortableReadabilityWidth = TileView.widthOfComfortableReadability()
|
layoutCache.comfortableReadabilityWidth = TileView.widthOfComfortableReadability()
|
||||||
|
TileFontIconView.warmCaches(symbols: [.circledPlusSign, .circledMinusSign, .circledSlashSign, .circledNumber0, .circledNumber10, .circledStar], size: Appearance.fontHeight, color: Appearance.fontColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateBackgroundView() {
|
func updateBackgroundView() {
|
||||||
@@ -318,7 +318,6 @@ class TilesView {
|
|||||||
var labelHeight = CGFloat(0)
|
var labelHeight = CGFloat(0)
|
||||||
var iconWidth = CGFloat(0)
|
var iconWidth = CGFloat(0)
|
||||||
var iconHeight = CGFloat(0)
|
var iconHeight = CGFloat(0)
|
||||||
var dockLabelSize = NSSize.zero
|
|
||||||
var comfortableReadabilityWidth: CGFloat?
|
var comfortableReadabilityWidth: CGFloat?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user