Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!




Share:
Notifications
Clear all

Lazarus Pascal - Cross platform Dark Theme detection

3 Posts
1 Users
0 Likes
4,733 Views
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2654
Topic starter  
This is what I use for cross platform dark theme detection.
I'm comparing the colors clWindow and clWindowText, since these system colors change perfectly as it is, and they typically should contrast to keep things readable. So it doesn't use any system specific calls.
So far it has worked very reliable under macOS and Linux - please correct me if I'm wrong or if there is an even easier way to do this. 😊 
 
// t4a_IsThisDarkTheme: Detects if the Dark Theme (true) has been enabled or not (false)
function t4a_ThisIsDarkTheme:boolean;
begin
Result := t4a_ColorToGrayScale(clWindow) < t4a_ColorToGrayScale(clWindowText); // guess dark theme
end;

{ Convert a color to grayscale, observing perception }
function t4a_ColorToGrayScale(aColor:TColor):TColor;
var
GreyNumber:integer;
begin
Result:=ColorToRGB(aColor);
// Convert Color to Grayscale if not yet Grayscale
// Grayscale   = (0.3 * Red) + (0.59 * Green) + (0.11 * Blue)
// Alternative = (0.2126 * Red) + (0.7152 * Green) + (0.0722 * Blue)
if (Red(Result)<>Green(Result)) and (Red(Result)<>Blue(Result)) then
  begin
    GreyNumber:= ( ( MathRound(Red(Result)   * 0.3) +
                     MathRound(Green(Result) * 0.59) +
                     MathRound(Blue(Result)  * 0.11) )  div 3);

    if GreyNumber<0 then
      GreyNumber:=0
    else if GreyNumber>255 then
      GreyNumber:=255;

      Result:=RGBToColor(GreyNumber,GreyNumber,GreyNumber);
  end;
end;
 
And I place the detection in the Form.OnPaint event, since this seems to get fired each time a theme changes, so my applications can respond to a theme change.
 
procedure TForm1.FormPaint(Sender: TObject);
begin
Label1.Caption := BoolToStr( t4a_ThisIsDarkTheme, 'Dark Theme', 'Light Theme' );
end;   
 

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2654
Topic starter  

Note: This can be done even shorter without the grayscale function:

 

// t4a_IsThisDarkTheme: Detects if the Dark Theme (true) has been enabled or not (false)
function TForm1.t4a_ThisIsDarkTheme:boolean;
var
RGBWin, RGBText: TColor;
const
Rgray = 0.3;
Ggray = 0.59;
Bgray = 0.11;
begin
RGBWin := ColorToRGB(clWindow);
RGBText:= ColorToRGB(clWindowText);
Result := ((Red(RGBWin)*Rgray)+(Green(RGBWin)*Ggray)+(Blue(RGBWin)*Bgray)) < ((Red(RGBText)*Rgray)+(Green(RGBText)*Ggray)+(Blue(RGBText)*Bgray));
end;

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2654
Topic starter  

And there is even a shorter method (thanks Alextp from the Lazarus forum!):

// by "Hansaplast" & "Alextp" from Lazarus forum
function IsDarkTheme: boolean;
  function _Level(C: TColor): double;
  begin
    Result:= Red(C)*0.3 + Green(C)*0.59 + Blue(C)*0.11;
  end;
begin
  Result:= _Level(ColorToRGB(clWindow)) < _Level(ColorToRGB(clWindowText));
end;

   
ReplyQuote

Like what you see and you'd like to help out? 

The best way to help is of course by assisting others with their questions here in the forum, but you can also help us out in other ways:

- Do your shopping at Amazon, it will not cost you anything extra but may generate a small commission for us,
- send a cup of coffee through PayPal ($5, $10, $20, or custom amount),
- become a Patreon,
- donate BitCoin (BTC), or BitCoinCash (BCH).

Share: