Is it possible to use alternatingContentBackgroundColors with ColorGroup?

This works, but doesn’t really work:

Var Group As New ColorGroup("alternatingContentBackgroundColors")

When you use the color, you’ll get the first color in the array. There doesn’t appear to be a way to get the second color. So it doesn’t really work.

So I have this semi-functional alternative

Var Colors(1) As Color
#if TargetMacOS
  Declare Function objc_getClass Lib "Cocoa" (ClassName As CString) As Ptr
  Declare Function NSSelectorFromString Lib "Cocoa" (SelectorName As CFStringRef) As Ptr
  Declare Function RespondsToSelector Lib "Cocoa" Selector "respondsToSelector:" (Target As Ptr, Sel As Ptr) As Boolean
  
  Var NSColor As Ptr = objc_getClass("NSColor")
  
  Var ArrayRef As Ptr
  If RespondsToSelector(NSColor, NSSelectorFromString("alternatingContentBackgroundColors")) Then
    Declare Function RowColors Lib "Cocoa" Selector "alternatingContentBackgroundColors" (Target As Ptr) As Ptr
    ArrayRef = RowColors(NSColor)
  Else
    Declare Function RowColors Lib "Cocoa" Selector "controlAlternatingRowBackgroundColors" (Target As Ptr) As Ptr
    ArrayRef = RowColors(NSColor)
  End If
  
  Declare Function ArrayCount Lib "Cocoa" Selector "count" (Target As Ptr) As UInteger
  Declare Function ArrayObjectAtIndex Lib "Cocoa" Selector "objectAtIndex:" (Target As Ptr, Index As UInteger) As Ptr
  Declare Function GetGenericRGBColorSpace Lib "Cocoa" Selector "deviceRGBColorSpace" (Target As Ptr) As Ptr
  Declare Function ColorUsingColorSpace Lib "Cocoa" Selector "colorUsingColorSpace:" (Target As Ptr, ColorSpace As Ptr) As Ptr
  Declare Sub GetRGBValues Lib "Cocoa" Selector "getRed:green:blue:alpha:" (Target As Ptr, ByRef Red As CGFloat, ByRef Green As CGFloat, ByRef Blue As CGFloat, ByRef Alpha As CGFloat)
  
  Var ObjectCount As UInteger = ArrayCount(ArrayRef)
  Var Bound As Integer = CType(ObjectCount, Integer) - 1
  Var NSColorSpace As Ptr = objc_getClass("NSColorSpace")
  Var ColorSpace As Ptr = GetGenericRGBColorSpace(NSColorSpace)
  
  Colors.ResizeTo(Bound)
  For I As Integer = 0 To Bound
    Var Handle As Ptr = ColorUsingColorSpace(ArrayObjectAtIndex(ArrayRef, CType(I, UInteger)), ColorSpace)
    If Handle = Nil Then
      Colors(I) = &cFB02FE00
      Continue
    End If
    
    Var RedValue, GreenValue, BlueValue, AlphaValue As CGFloat
    GetRGBValues(Handle, RedValue, GreenValue, BlueValue, AlphaValue)
    Colors(I) = Color.RGB(255 * RedValue, 255 * GreenValue, 255 * BlueValue, 255 - (AlphaValue * 255))
  Next
  
  // This is to work around an issue where the even dark color isn't getting the proper alpha channel
  // https://forum.xojo.com/50440-dark-mode-alternatingcontentbackgroundcolors-doesn-t-seem-corre
  If SystemColors.IsDarkMode Then
    Colors(0) = Color.RGB(Colors(0).Red, Colors(0).Green, Colors(0).Blue, 153)
  End If
  
  Return Colors
#endif

The trouble is it doesn’t really match with the design of ColorGroup. There’s no way for me to pass the handle of the NSColor to ColorGroup so it can render the final color when needed. I need to pre-render the colors and pack them into a static ColorGroup. It “works” but also defeats the purpose of using ColorGroup.

I don’t think I’ve missed anything, so really I’m just looking for confirmation that there isn’t a way to get this right.

There isn’t, but we’ve got a feature request to make that possible.

2 Likes