fix: render light palettes with matching appearance
This commit is contained in:
@@ -2,10 +2,15 @@ import AppKit
|
||||
|
||||
@MainActor
|
||||
enum ThemePalette {
|
||||
@MainActor
|
||||
struct State {
|
||||
let scheme: ColorScheme
|
||||
var error: String?
|
||||
var usesFallback: Bool
|
||||
let isLight: Bool
|
||||
let appearance: NSAppearance
|
||||
let secondaryText: NSColor
|
||||
let glowStrength: CGFloat
|
||||
let background: NSColor
|
||||
let selectionFill: NSColor
|
||||
let selectionBorder: NSColor
|
||||
@@ -15,11 +20,58 @@ enum ThemePalette {
|
||||
self.scheme = scheme
|
||||
self.error = error
|
||||
self.usesFallback = usesFallback
|
||||
background = scheme.background.withAlphaComponent(0.55)
|
||||
let light = scheme.isLight
|
||||
isLight = light
|
||||
appearance = NSAppearance(named: light ? .aqua : .darkAqua)!
|
||||
glowStrength = light ? 0.35 : 1
|
||||
background = scheme.background.withAlphaComponent(light ? 0.82 : 0.55)
|
||||
secondaryText = light ? Self.readableSecondaryText(scheme) : scheme.secondaryText
|
||||
selectionFill = scheme.accent.withAlphaComponent(0.12)
|
||||
selectionBorder = scheme.accent.withAlphaComponent(0.30)
|
||||
keyBackground = scheme.keyBackground.withAlphaComponent(0.5)
|
||||
}
|
||||
|
||||
private static func readableSecondaryText(_ scheme: ColorScheme) -> NSColor {
|
||||
let background = scheme.background.usingColorSpace(.sRGB)!
|
||||
let accent = scheme.accent.usingColorSpace(.sRGB)!
|
||||
let glow = scheme.glow.usingColorSpace(.sRGB)!
|
||||
// Black behind the translucent fill bounds every desktop. Each gradient may
|
||||
// darken a channel independently, including the third, dimmed accent glow.
|
||||
func darkestChannel(_ base: CGFloat, _ accent: CGFloat, _ glow: CGFloat) -> CGFloat {
|
||||
var value = base * 0.82
|
||||
value = min(value, value * (1 - 0.26 * 0.35) + glow * 0.26 * 0.35)
|
||||
value = min(value, value * (1 - 0.18 * 0.35) + accent * 0.18 * 0.35)
|
||||
return min(value, value * (1 - 0.18 * 0.35 * 0.45) + accent * 0.18 * 0.35 * 0.45)
|
||||
}
|
||||
let surface = ColorScheme.relativeLuminance(
|
||||
red: darkestChannel(background.redComponent, accent.redComponent, glow.redComponent),
|
||||
green: darkestChannel(background.greenComponent, accent.greenComponent, glow.greenComponent),
|
||||
blue: darkestChannel(background.blueComponent, accent.blueComponent, glow.blueComponent))
|
||||
// A small margin covers 8-bit surface rounding.
|
||||
let ceiling = max(0, (surface + 0.05) / 4.55 - 0.05)
|
||||
guard ColorScheme.relativeLuminance(scheme.secondaryText) > ceiling else {
|
||||
return scheme.secondaryText
|
||||
}
|
||||
let source = scheme.secondaryText.usingColorSpace(.sRGB)!
|
||||
let target = (ColorScheme.relativeLuminance(scheme.text) <= ceiling ? scheme.text : .black)
|
||||
.usingColorSpace(.sRGB)!
|
||||
func component(_ from: CGFloat, _ to: CGFloat, _ fraction: CGFloat) -> CGFloat {
|
||||
from + (to - from) * fraction
|
||||
}
|
||||
var lower: CGFloat = 0
|
||||
var upper: CGFloat = 1
|
||||
for _ in 0..<24 {
|
||||
let fraction = (lower + upper) / 2
|
||||
let luminance = ColorScheme.relativeLuminance(
|
||||
red: component(source.redComponent, target.redComponent, fraction),
|
||||
green: component(source.greenComponent, target.greenComponent, fraction),
|
||||
blue: component(source.blueComponent, target.blueComponent, fraction))
|
||||
if luminance > ceiling { lower = fraction } else { upper = fraction }
|
||||
}
|
||||
return NSColor(srgbRed: component(source.redComponent, target.redComponent, upper),
|
||||
green: component(source.greenComponent, target.greenComponent, upper),
|
||||
blue: component(source.blueComponent, target.blueComponent, upper), alpha: 1)
|
||||
}
|
||||
}
|
||||
|
||||
static var loaded: State = {
|
||||
@@ -35,13 +87,16 @@ enum ThemePalette {
|
||||
|
||||
static let didChangeNotification = Notification.Name("ConjureThemePaletteDidChange")
|
||||
static var configurationError: String? { loaded.error }
|
||||
static var isLight: Bool { loaded.isLight }
|
||||
static var appearance: NSAppearance { loaded.appearance }
|
||||
static var background: NSColor { loaded.background }
|
||||
static var text: NSColor { loaded.scheme.text }
|
||||
static var secondaryText: NSColor { loaded.scheme.secondaryText }
|
||||
static var secondaryText: NSColor { loaded.secondaryText }
|
||||
static var accent: NSColor { loaded.scheme.accent }
|
||||
static var selectionFill: NSColor { loaded.selectionFill }
|
||||
static var selectionBorder: NSColor { loaded.selectionBorder }
|
||||
static var glow: NSColor { loaded.scheme.glow }
|
||||
static var glowStrength: CGFloat { loaded.glowStrength }
|
||||
static var keyBackground: NSColor { loaded.keyBackground }
|
||||
static var error: NSColor { loaded.scheme.error }
|
||||
|
||||
@@ -66,7 +121,7 @@ enum ThemePalette {
|
||||
guard scheme.background != previous.background || scheme.text != previous.text
|
||||
|| scheme.secondaryText != previous.secondaryText || scheme.accent != previous.accent
|
||||
|| scheme.glow != previous.glow || scheme.keyBackground != previous.keyBackground
|
||||
|| scheme.error != previous.error else {
|
||||
|| scheme.error != previous.error || scheme.variant != previous.variant else {
|
||||
loaded.error = nil
|
||||
loaded.usesFallback = false
|
||||
return false
|
||||
@@ -88,13 +143,13 @@ enum ThemePalette {
|
||||
final class LauncherBackground: NSView {
|
||||
weak var canvas: NSView?
|
||||
private var amber = NSGradient(colors: [
|
||||
ThemePalette.accent.withAlphaComponent(0.18),
|
||||
ThemePalette.accent.withAlphaComponent(0.065),
|
||||
ThemePalette.accent.withAlphaComponent(0.18 * ThemePalette.glowStrength),
|
||||
ThemePalette.accent.withAlphaComponent(0.065 * ThemePalette.glowStrength),
|
||||
ThemePalette.accent.withAlphaComponent(0),
|
||||
])!
|
||||
private var ember = NSGradient(colors: [
|
||||
ThemePalette.glow.withAlphaComponent(0.26),
|
||||
ThemePalette.glow.withAlphaComponent(0.10),
|
||||
ThemePalette.glow.withAlphaComponent(0.26 * ThemePalette.glowStrength),
|
||||
ThemePalette.glow.withAlphaComponent(0.10 * ThemePalette.glowStrength),
|
||||
ThemePalette.glow.withAlphaComponent(0),
|
||||
])!
|
||||
|
||||
@@ -115,13 +170,13 @@ final class LauncherBackground: NSView {
|
||||
|
||||
@objc private func paletteChanged() {
|
||||
amber = NSGradient(colors: [
|
||||
ThemePalette.accent.withAlphaComponent(0.18),
|
||||
ThemePalette.accent.withAlphaComponent(0.065),
|
||||
ThemePalette.accent.withAlphaComponent(0.18 * ThemePalette.glowStrength),
|
||||
ThemePalette.accent.withAlphaComponent(0.065 * ThemePalette.glowStrength),
|
||||
ThemePalette.accent.withAlphaComponent(0),
|
||||
])!
|
||||
ember = NSGradient(colors: [
|
||||
ThemePalette.glow.withAlphaComponent(0.26),
|
||||
ThemePalette.glow.withAlphaComponent(0.10),
|
||||
ThemePalette.glow.withAlphaComponent(0.26 * ThemePalette.glowStrength),
|
||||
ThemePalette.glow.withAlphaComponent(0.10 * ThemePalette.glowStrength),
|
||||
ThemePalette.glow.withAlphaComponent(0),
|
||||
])!
|
||||
needsDisplay = true
|
||||
|
||||
Reference in New Issue
Block a user