Forum > LCL
'Black on black' combobox items with certain *nix desktops
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