Forum > LCL

'Black on black' combobox items with certain *nix desktops

(1/3) > >>

Sieben:
There is an annoying problem with items of TCustomComboBox and descendants like TColorBox being painted 'black on black' with certain *nix desktops which has already been discussed here and here which I might have found a solution to.

Found a piece of code that calculates the 'intensity' of a background color like this:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---function Intensity(AColor: TColor): Integer;begin  AColor := ColorToRGB(AColor);  Result := GetRValue(AColor) * 61          + GetGValue(AColor) * 174          + GetBValue(AColor) * 21;end;
and suggests a threshold of 32k for deciding whether to use a dark or a bright font color. Code based on this tested ok for TCustomComboBox.DrawItem as well as for overriden methods in descendants. Drawback is of course that every overridden method has to be aware of this pitfall. So I tried 'injecting' this into TCustomComboBox.LMDrawListItem prior to the call of DrawItem instead:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---function IsDarkBackground(AColor: TColor): Boolean;begin  AColor := ColorToRGB(AColor);  Result := (GetRValue(AColor) * 61           + GetGValue(AColor) * 174           + GetBValue(AColor) * 21) <= (128 * 256);end; {------------------------------------------------------------------------------  procedure TCustomComboBox.LMDrawListItem(var TheMessage : TLMDrawListItem);   Handler for custom drawing items. ------------------------------------------------------------------------------}procedure TCustomComboBox.LMDrawListItem(var TheMessage : TLMDrawListItem);begin  with TheMessage.DrawListItemStruct^ do  begin    FCanvas.Handle := DC;    if Font<>nil then    begin      FCanvas.Font := Font;      FCanvas.Font.PixelsPerInch := Font.PixelsPerInch;    end;    if Brush<>nil then      FCanvas.Brush := Brush;    if (ItemID <> UINT(-1)) and (odSelected in ItemState) then    begin      FCanvas.Brush.Color := clHighlight;      FCanvas.Font.Color := clHighlightText    end;     if DroppedDown                            //injection...    and (odBackgroundPainted in ItemState)    and IsDarkBackground(Canvas.Pixels[1,1]) then      Canvas.Font.Color := clHighLightText;     DrawItem(ItemID, Area, ItemState);    {if odFocused in ItemState then      DrawFocusRect(hDC, rcItem)};    FCanvas.Handle := 0;  end;end;
This seems to work for every descendant of TCustomComboBox now. All an overridden DrawItem or custom OnDrawItem handler has to take care of then is not to just repaint the background but instead to use code like this:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---    if not (odBackgroundPainted in AState) then      Canvas.FillRect(ARect);
as suggested by the 'original' DrawItem anyway. And not to reassign font colors of course as this is done already as well.

I don't know, however, if and how this would affect any other widgetset but I think it is quite likely that it won't. I'm including a diff file done with trunk r64267 so that anyone who might be interested can test this. Some feedback would be nice...

EDIT: removed diff file for nonfug, cf below.

wp:
Your code detects whether the background color is dark and then you draw the text in clHighLightText. But clHighlighttext is a themed color, it can be anything. How do you know that clHighlightText isn't dark either? Normally the system colors are well-balanced, there are only a few cases (Ubunto 16.04 and 18.04, and maybe some more) where the theme designers used their own rules.

Sieben:
It's just an assumption that served my tests here I have to admit, and it also depends on whether the canvas comes 'pre-painted' with other widgetsets. But it could easily be replaced with eg clWhite if it proves wrong. Or another test for the brightness of clWindowText vs clHighLightText.

winni:
Hi!

Don't rely on assumptions on system colors.

Use the complement of the given color:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---function  Complement (col: TColor): TColor;beginResult := $FFFFFF - ColorToRGB(col);end;  
Only one trap:
If your input is in the midrange gray the output will also be in the midrange gray.

Winni

Sieben:
Thanks again, this would at least result in a readable font color, but still doesn't look seamless. clWhite would do a slightly better job in this case. But the main misapprehension I took, and I don't really know why right now, was that this early background painting is unique to this specific widgetset.

Now, what assumptions can be made with this issue...?

1) Font color used for item painting will always be either clWindowText or clHighLighText...?

2) Background is already painted, ie odBackgroundPainted in ItemState...?

3) Background is painted in a 'dark' color while Canvas.Brush.Color, indicating the controls 'normal' color, ist not...?


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---    if DroppedDown    and IsDark(Canvas.Pixels[1,1])    and not IsDark(Canvas.Brush.Color)    and (odBackgroundPainted in ItemState) then    begin      if IsDark(clWindowText) then        Canvas.Font.Color := clHighLightText      else        Canvas.Font.Color := clWindowText;    end;
Are there any more conditions besides 2) and 3) to not interfere with font color that can be tested for?

Navigation

[0] Message Index

[#] Next page

Go to full version