Alternating row colors for Dark Mode
Xojo 2018r4 has the AppearanceChanged event for Application class, which is very handy to switch colors. Or you check with IsDarkMode function every time you draw something and decide the color. As CellBackgroundPaint event in the Listbox class is called for each cell, it can be called 100s of times just for redrawing the list once. So we like to optimize the handling and cache the colors.
In MBS Plugin we got last summer the dark mode additions for NSColorMBS class. The NSColorMBS.alternatingContentBackgroundColors function returns an array with two NSColor objects with the current preferred background colors for lists. So we want to use this, but not call it for every event as building an array and color objects costs a little bit performance for each draw.
So here is some example code:
Project "Listbox Row Colors.xojo_binary_project"
Class App Inherits Application
EventHandler Sub AppearanceChanged()
QueryRowColors
End EventHandler
EventHandler Sub Open()
QueryRowColors
End EventHandler
Shared Sub QueryRowColors()
// our defaults
RowColorEven = &cFFFFFF
RowColorOdd = &cEEFFEE
#if TargetMacOS then
dim colors() as NSColorMBS = NSColorMBS.alternatingContentBackgroundColors
if colors = nil then
break
return // should not happen
end if
if colors.Ubound = 1 then
// 2 colors
RowColorEven = colors(0).colorValue
RowColorOdd = colors(1).colorValue
end if
#endif
End Sub
Property Shared RowColorEven As color
Property Shared RowColorOdd As color
End Class
Class MainWindow Inherits Window
Control List Inherits Listbox
ControlInstance List Inherits Listbox
EventHandler Function CellBackgroundPaint(g As Graphics, row As Integer, column As Integer) As Boolean
if me.ListIndex = row then
// let Xojo draw selection
else
if row mod 2 = 0 then
g.ForeColor = app.RowColorEven
else
g.ForeColor = app.RowColorOdd
end if
g.FillRect 0, 0, g.Width, g.Height
end if
End EventHandler
End Control
End Class
End Project
This example project will be included with future plugins. As you see this includes all parts necessary. We query the current colors when the application opens or the appearance changes. We cache the colors in RowColorEven and RowColorOdd shared properties. And in the CellBackgroundPaint event, we only draw unselected rows with the right color. For multi selection list boxes, you can check selected() function instead. We use #if to only reference plugin for MacOS and not for Windows. And for Windows we also need the default colors there. By the way, the plugin hides an extra complexity. The alternatingContentBackgroundColors function is only available for macOS 10.14 or newer and we switch to an older function for older MacOS versions and you can call it everywhere without problems.