Quick Tip: macOS System Colors without Declares

A small, subtle note from @Greg_Ođ–˝‘Lone in the thread Prepping your Xojo made Mac app for Big Sur shows that since Xojo 2019.03 we no longer need external libraries to get macOS system colors back. ColorGroups, which we already know from iOS projects, can currently only be used via code in desktop projects. And ColorGroup.NamedColor help us to use the native color values in dark/light mode in macOS desktop applications. Here is a short overview.

' The string "controlAccentColor" can be replaced by the values
' in the column "Value" in the following tables.

Var c As Color = ColorGroup.NamedColor("controlAccentColor")

Apple gives an overview of the available color values, including version notes, on the developer pages https://developer.apple.com/documentation/appkit/nscolor/standard_colors?language=objc and https://developer.apple.com/documentation/appkit/nscolor/ui_element_colors?language=objc.

Standard Colors

Retrieve the standard color objects for common colors like red, blue, green, black, white, and more.

Adaptable System Colors

Value Description
systemBlueColor Returns a color object for blue that automatically adapts to vibrancy and accessibility settings.
systemBrownColor Returns a color object for brown that automatically adapts to vibrancy and accessibility settings.
systemGrayColor Returns a color object for gray that automatically adapts to vibrancy and accessibility settings.
systemGreenColor Returns a color object for green that automatically adapts to vibrancy and accessibility settings.
systemOrangeColor Returns a color object for orange that automatically adapts to vibrancy and accessibility settings
systemPinkColor Returns a color object for pink that automatically adapts to vibrancy and accessibility settings.
systemPurpleColor Returns a color object for purple that automatically adapts to vibrancy and accessibility settings.
systemRedColor Returns a color object for red that automatically adapts to vibrancy and accessibility settings.
systemYellowColor Returns a color object for yellow that automatically adapts to vibrancy and accessibility settings.

UI Element Colors

Retrieve standard color objects for use with windows, controls, labels, text, selections and other content in your app

Label Colors

Value Description
labelColor The primary color to use for text labels.
secondaryLabelColor The secondary color to use for text labels.
tertiaryLabelColor The tertiary color to use for text labels.
quaternaryLabelColor The quaternary color to use for text labels and separators.

Text Colors

Value Description
textColor The color to use for text.
placeholderTextColor The color to use for placeholder text in controls or text views.
selectedTextColor The color to use for selected text.
textBackgroundColor The color to use for the background area behind text.
selectedTextBackgroundColor The color to use for the background of selected text.
keyboardFocusIndicatorColor The color to use for the keyboard focus ring around controls.
unemphasizedSelectedTextColor The color to use for selected text in an unemphasized context.
unemphasizedSelectedTextBackgroundColor The color to use for the text background in an unemphasized context.

Content Colors

Value Description
linkColor The color to use for links.
separatorColor The color to use for separators between different sections of content
selectedContentBackgroundColor The color to use for the background of selected and emphasized content.
unemphasizedSelectedContentBackgroundColor The color to use for selected and unemphasized content.

Menu Colors

Value Description
selectedMenuItemTextColor The color to use for the text in menu items.

Table Colors

Value Description
gridColor The color to use for the optional gridlines, such as those in a table view.
headerTextColor The color to use for text in header cells in table views and outline views.
alternatingContentBackgroundColors The colors to use for alternating content, typically found in table views and collection views.

Control Colors

Value Description
controlAccentColor The user’s current accent color preference.
controlColor The color to use for the flat surfaces of a control.
controlBackgroundColor The color to use for the background of large controls, such as scroll views or table views.
controlTextColor The color to use for text on enabled controls.
disabledControlTextColor The color to use for text on disabled controls.
currentControlTint The current system control tint color.
selectedControlColor The color to use for the face of a selected control—that is, a control that has been clicked or is being dragged.
selectedControlTextColor The color to use for text in a selected control—that is, a control being clicked or dragged.
alternateSelectedControlTextColor The color to use for text in a selected control.
scrubberTexturedBackgroundColor The patterned color to use for the background of a scrubber control.

Window Colors

Value Description
windowBackgroundColor The color to use for the window background.
windowFrameTextColor The color to use for text in a window’s frame.
underPageBackgroundColor The color to use in the area beneath your window’s views.

Highlights and Shadows

Value Description
findHighlightColor The highlight color to use for the bubble that shows inline search result values.
highlightColor The color to use as a virtual light source on the screen.
shadowColor The color to use for virtual shadows cast by raised objects on the screen.

Happy coding!

5 Likes

They had the opportunity to make it better: https://forum.xojo.com/t/named-color-groups-are-a-leaky-abstraction-that-needs-to-be-fixed-now/51255/3

Additional things:

  1. Color names are case sensitive because we’re asking the OS for them and it cares.
  2. Some of the colors are only available on newer OSs.
  3. Requesting a named color on Windows or Linux will raise an UnsupportedOperationException.
  4. Pattern colors that are truly a pattern and not a flat color are not retrieved by ColorGroup.NamedColor.

Is there caching going on in the framework of these colours @Greg_Ođ–˝‘Lone? For instance, AFAIK there is a real performance cost for querying the Xojo framework IsDarkMode function in a tight loop because its value seems not be cached). Is this the same with the colours? Just wondering whether I need to be caching the values once retrieved and then only recalling the named colour method when I detect an AppearanceChanged event in the app.

Don’t cache your results in AppearanceChanged. I have an app that, IIRC, doesn’t use the event at all, and barely uses IsDarkMode. Just paint with the colors you need.

I would store the color in a variable to prevent querying in a loop, this isn’t a huge deal.

2 Likes

First of all, when you call ColorGroup.NamedColor, what you get back is a ColorGroup, not a Color. It’s also important to understand that ColorGroups are not “resolved” until you actually ask for the color value. That is, when you assign the obj to a value that takes a color.

So yes, if you’ve got code that looks like this:
Label1.FontColor = ColorGroup.NamedColor(“labelColor”)

Then you’ll always be pulling the color directly from the OS.

FWIW, IsDarkMode is slow because we have to trick the OS into getting the current correct system appearance every time as technically, whether you’re in dark mode isn’t valid unless you’re in a drawing context (like a canvas).

1 Like

Is that really true? The documentation says that a color is returned.

' Returns the specified named color.
ColorGroup.NamedColor(name As Text) As Color

I wondered the same …

My guess is misleading docs. Probably returns a group, and the group probably has an operator_convert.

1 Like

Considering I looked at the code to answer this, we’re fixing the docs.

1 Like