ThemeColor
open class ThemeColor: NSColor
ThemeColor
is a NSColor
subclass that dynamically changes its colors whenever
a new theme is make current.
Theme-aware means you don’t need to check any conditions when choosing which color to draw or set on a control. E.g.:
myTextField.textColor = ThemeColor.myContentTextColor
ThemeColor.myCircleFillColor.setFill()
NSBezierPath(rect: bounds).fill()
The text color of myTextField
will automatically change when the user switches
a theme. Similarly, the drawing code will draw with different color depending on
the selected theme. Unless some drawing cache is being done, there’s no need to
refresh the UI after changing the current theme.
You can also define a color to be a pattern image using NSColor(patternImage:)
.
Defining theme-aware colors
The recommended way of adding your own dynamic colors is as follows:
Add a
ThemeColor
class extension (orTKThemeColor
category on Objective-C) to add class methods for your colors. E.g.:In Swift:
extension ThemeColor { static var brandColor: ThemeColor { return ThemeColor.color(with: #function) } }
In Objective-C:
@interface TKThemeColor (Demo) + (TKThemeColor*)brandColor; @end @implementation TKThemeColor (Demo) + (TKThemeColor*)brandColor { return [TKThemeColor colorWithSelector:_cmd]; } @end
Add Class Extensions on any
Theme
you want to support (e.g.,LightTheme
andDarkTheme
-TKLightTheme
andTKDarkTheme
on Objective-C) to provide instance methods for each theme color class method defined on (1). E.g.:In Swift:
extension LightTheme { var brandColor: NSColor { return NSColor.orange } } extension DarkTheme { var brandColor: NSColor { return NSColor.white } }
In Objective-C:
@interface TKLightTheme (Demo) @end @implementation TKLightTheme (Demo) - (NSColor*)brandColor { return [NSColor orangeColor]; } @end @interface TKDarkTheme (Demo) @end @implementation TKDarkTheme (Demo) - (NSColor*)brandColor { return [NSColor whiteColor]; } @end
If supporting
UserTheme
‘s, define properties on user theme files (.theme
) for each theme color class method defined on (1). E.g.:displayName = Sample User Theme identifier = com.luckymarmot.ThemeKit.SampleUserTheme darkTheme = false brandColor = rgba(96, 240, 12, 0.5)
Overriding system colors
Besides your own colors added as ThemeColor
class methods, you can also override
NSColor
class methods so that they return theme-aware colors. The procedure is
exactly the same, so, for example, if adding a method named labelColor
to a
ThemeColor
extension, that method will be overriden in NSColor
and the colors
from Theme
subclasses will be used instead.
In sum, calling NSColor.labelColor
will return theme-aware colors.
You can get the full list of available/overridable color methods (class methods)
calling NSColor.colorMethodNames()
.
At any time, you can check if a system color is being overriden by current theme
by checking the NSColor.isThemeOverriden
property (e.g., NSColor.labelColor.isThemeOverriden
).
When a theme does not override a system color, the original system color will be
used instead. E.g., you have overrided ThemeColor.labelColor
, but currently
applied theme does not implement labelColor
-> original labelColor
will be
used.
Fallback colors
With the exception of system overrided named colors, which defaults to the original
system provided named color when theme does not specifies it, unimplemented
properties/methods on target theme class will default to fallbackForegroundColor
and fallbackBackgroundColor
, for foreground and background colors respectively.
These too, can be customized per theme.
Please check ThemeGradient
for theme-aware gradients and ThemeImage
for theme-aware images.
-
ThemeColor
color selector used as theme instance method for same selector or, if inexistent, as argument in the theme instance methodthemeAsset(_:)
.Declaration
Swift
@objc public var themeColorSelector: Selector = #selector(getter: NSColor.clear)
-
Resolved color from current theme (dynamically changes with the current theme).
Declaration
Swift
@objc public lazy var resolvedThemeColor: NSColor = NSColor.clear
-
Create a new ThemeColor instance for the specified selector.
Returns a color returned by calling
selector
on current theme as an instance method or, if unavailable, the result of callingthemeAsset(_:)
on the current theme.Declaration
Swift
public class func color(with selector: Selector) -> ThemeColor
Parameters
selector
Selector for color method.
Return Value
A
ThemeColor
instance for the specified selector. -
Current theme color, but respecting view appearance and any window specific theme (if set).
If a
NSWindow.windowTheme
was set, it will be used instead. Some views may be using a different appearance than the theme appearance. In thoses cases, color won’t be resolved using current theme, but from eitherlightTheme
ordarkTheme
, depending of whether view appearance is light or dark, respectively.Declaration
Swift
public class func color(for view: NSView, selector: Selector) -> NSColor
Parameters
view
A
NSView
instance.selector
A color selector.
Return Value
Resolved color for specified selector on given view.
-
Forces dynamic color resolution into
resolvedThemeColor
and cache it. You should not need to manually call this function.Declaration
Swift
@objc open func recacheColor()
-
Clear all caches. You should not need to manually call this function.
Declaration
Swift
@objc class open func emptyCache()