Recent

Author Topic: [maybe SOLVED] BUG in InputQuery if default colour for TForm and TPanel differ  (Read 4042 times)

robert rozee

  • Sr. Member
  • ****
  • Posts: 265
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #15 on: March 05, 2025, 05:46:40 pm »
A matter of the wibbly wobbly time continuum... It was based on memory of mine, which shortly after was refreshed and thereby established as false [...]

well, the fact that wibbly wobbly time caused you to change your mind is in itself rather important... are you able to confirm what i've been seeing? to date, as far as i can tell, i am the only person who has observed a TPanel sitting on a TForm having a different colour to the form when both are set to the colour clDefault and the panel's ParentColor property is set to True.

i've been starting to think that my sanity has been going wibbly wobbly - if someone (anyone!) could confirm my observations of panels on forms, that would go a long way to calming my concerns   %)


cheers,
rob   :-)

TRon

  • Hero Member
  • *****
  • Posts: 4272
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #16 on: March 05, 2025, 05:50:42 pm »
i've been starting to think that my sanity has been going wibbly wobbly - if someone (anyone!) could confirm my observations of panels on forms, that would go a long way to calming my concerns   %)
No, I can reproduce with certain dark themes. But that is just it /certain/ ones. It is not consistent.

Can you verify something for me ? If you set the panel's colour to parentcolor, then change the form colour from clDefault to f.e. lime. Does then your panel change it's colour to lime as well ?
Today is tomorrow's yesterday.

robert rozee

  • Sr. Member
  • ****
  • Posts: 265
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #17 on: March 05, 2025, 07:27:30 pm »
No, I can reproduce with certain dark themes. But that is just it /certain/ ones. It is not consistent.
Can you verify something for me ? If you set the panel's colour to parentcolor, then change the form colour from clDefault to f.e. lime. Does then your panel change it's colour to lime as well ?

yes, it does; if the colour of the form is set to a named colour such as clLime, then the colour of the panel will also change to clLime. if you download the zip file from Reply #7 and build it, you can see this by double-clicking on the form. this alternates between setting the form's colour to clMoneyGreen and clDefault.

Reply #7 also explains how a TPanel's default background colour maps to clBackground, while a TForm's default backgounnd colour maps to clForm. unfortunately i wasn't able to dig down far enough to find out how/where these were loaded from the desktop theme - the layers of abstraction were just too complicated for me to unravel.


cheers,
rob  :-)

TRon

  • Hero Member
  • *****
  • Posts: 4272
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #18 on: March 05, 2025, 08:00:08 pm »
Thank you for the verification and additional explanation Robert. I have not followed the discussion closely so it might have been a redundant question.

I am afraid that the digging is exactly what is required to be able to get to the bottom of this behaviour. In principle I agree with your view, parentcolor is parentcolor (and not something obtained from thin air). At the same time I am cautious because I am not familiar with the inner workings and peculiarities of certain widgetsets.

I try to give it a closer look but am a bit busy with other things atm (at least busy enough to not be able to give it the attention it most probably deserves).
Today is tomorrow's yesterday.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10997
  • Debugger - SynEdit - and more
    • wiki
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #19 on: March 05, 2025, 08:40:18 pm »
are you able to confirm what i've been seeing? to date, as far as i can tell, i am the only person who has observed a TPanel sitting on a TForm having a different colour to the form when both are set to the colour clDefault and the panel's ParentColor property is set to True.

I haven't tried. I am mainly Windows. (And light theme). My post was on a more generic level, but turned out, not matching the descriptions on your actual report.

I can imagine that something like that happens. And if so probably raises question where else that may happen. But I wont have time to explore it right now. I added my comment because it didn't take me any time (and turned out, it should have taken me the time to *first* refresh my memory of the issue). It was about the general idea of what ParentColor may or may not do in respect to all controls.

I do wonder though, there is a function
Code: Pascal  [Select][+][-]
  1. function ColorToRGB(Color: TColor): Longint;
How does that work, if there is more than one answer... But again, new problem.




The other question of course is (and that only comes to mind now): Would then such a color different be correct?

The question is:
- is the panel only used for positioning, and otherwise waste of a window handle, because functionality and visibility wise the buttons should be part of the parent
Or
- is the panel part of the design, and if a colorscheme makes panels visible by changed color, then that panel is correctly shown according to scheme.



robert rozee

  • Sr. Member
  • ****
  • Posts: 265
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #20 on: March 06, 2025, 11:56:59 am »
the source code for ColorToRGB is:

Code: Pascal  [Select][+][-]
  1. function ColorToRGB(Color: TColor): Longint;
  2. var
  3.   i: integer;
  4. begin
  5.   i := SysColorToSysColorIndex(Color);
  6.   if i <> -1 then
  7.     Result := GetSysColor(i)
  8.   else
  9.     Result := Color;
  10.   Result := Result and $FFFFFF;
  11. end;

if the parent's colour is clDefault, then ColorToRGB returns 0x000000 - which strictly speaking should be black. attached is a test project, that contains a test panel and a test button, along with 3 buttons in a row to select the form's colour setting: clDefault, clBackground, clMoneyGreen. to display an item's ColorToRGB result click on the item (the TPanel, the TButton, or any blank area of the TForm) and a popup message will appear.

the second number displayed in the popup is the result of SysColorToSysColorIndex.

where else that may happen

at least with InputDialog and InputCombo, although i am sure there are other instances, but the thing is it is only visible under the right desktop theme. and even then, many folks would likely not even notice the slight shade difference if it was only minor. or not care - it is really a "style bug" from the user's perspective, like finding a message displayed that has a punctuation or spelling error.


The question is:
- is the panel only used for positioning, and otherwise waste of a window handle, because functionality and visibility wise the buttons should be part of the parent
Or
- is the panel part of the design, and if a colorscheme makes panels visible by changed color, then that panel is correctly shown according to scheme.

my experience - mostly with Linux in recent years - is that a TPanel by default has a beveled border, and that it has NO transparent property. just checked under winXP, and this holds true there too. if used with the default of a beveled border, it would make some aesthetic sense for a TPanel to be a slightly different colour to the form it was sitting on; under winXP there appears to be no colour difference. a TPanel can also respond to mouse clicks, and can indeed be used as a simple button. it can be moved forward in the Z-order and will then obscure other controls that happen to sit behind it. a TPanel can also be used to fix a ragged edge in a multi-line TLabel so that other surreounding controls line up correctly. i would describe it as one of the more versatile controls available   ;D

my feeling is that the real bug lies in how InputDialog et al have been implemented, where whoever coded these routines should have made sure that the TPanel being used there had its colour tightly synchronized to that of the form it was placed upon. but then, if the development of Lazarus was done mostly on windows, perhaps nobody could 'visually' see the problem.


cheers,
rob   :-)

TRon

  • Hero Member
  • *****
  • Posts: 4272
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #21 on: March 06, 2025, 06:51:01 pm »
Inverse high contrast delivers me the best result.

imho it is the panel not adhering to what it should do according to its properties. It is nothing to do with themes, or in case it does completely picks up on the wrong colour.  Might be a GTK restriction, dunno yet. Note that the off-colour is nowhere defined in the theme itself. There is not a single application (outside the ones written in Lazarus or using their own theming or other widget library) that is able to show that colour.

edit: BTW you are not that far off robert as there exists even a special function for it named GetRGBColorResolvingParent (and yes that seem to work as expected). The implementation of tpanel is a bit confusing wrt painting though due to theme-service, UseCLDefault define, opacity etc.
« Last Edit: March 06, 2025, 07:36:39 pm by TRon »
Today is tomorrow's yesterday.

robert rozee

  • Sr. Member
  • ****
  • Posts: 265
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #22 on: March 08, 2025, 08:09:06 pm »
Inverse high contrast delivers me the best result

that is an excellent example you've found! and it nicely shows how the purple is an appropriate colour for the Panel, but not so for the ButtonPanel; evidence that any fix is perhaps best made at the level of TButtonPanel and not any lower.

there exists even a special function for it named GetRGBColorResolvingParent (and yes that seem to work as expected)

actually, i reckon that GetRGBColorResolvingParent does NOT appear to work correctly.

here is the code behind it, extracted from lcl/include/control.inc:

Code: Pascal  [Select][+][-]
  1. function TControl.GetDefaultColor(const DefaultColorType: TDefaultColorType): TColor;
  2. const
  3.   DefColors: array[TDefaultColorType] of TColor = (
  4.   { dctBrush } clWindow,
  5.   { dctFont  } clWindowText
  6.   );
  7. begin
  8.   Result := TWSControlClass(WidgetSetClass).GetDefaultColor(Self, DefaultColorType);
  9.   if (Result = clDefault) then
  10.     if ParentColor and Assigned(Parent) then
  11.       Result := Parent.GetDefaultColor(DefaultColorType)
  12.     else
  13.       Result := DefColors[DefaultColorType];
  14. end;
  15.  
  16. function TControl.GetColorResolvingParent: TColor;
  17. begin
  18.   if Color = clDefault then
  19.     Result := GetDefaultColor(dctBrush) // GetDefaultColor resolves the parent
  20.   else
  21.     Result := Color;
  22. end;
  23.  
  24. function TControl.GetRGBColorResolvingParent: TColor;
  25. begin
  26.   Result := ColorToRGB(GetColorResolvingParent());
  27. end;

i called these routines from a simple project with a Form, Panel, and Button, with the button click event containing:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   writeln;
  4.   writeln(IntToHex(clDefault, 8):12,                         '    clDefault');
  5.   writeln(IntToHex(clWindow, 8):12,                          '    clWindow');
  6.   writeln(IntToHex(clBackGround, 8):12,                      '    clBackGround');
  7.   writeln(IntToHex(clForm, 8):12,                            '    clForm');
  8.   writeln;
  9.   writeln(IntToHex(Form1.Color, 8):12,                       '    Form1.Color');
  10.   writeln(IntToHex(Form1.GetDefaultColor(dctBrush), 8):12,   '    Form1.GetDefaultColor');
  11.   writeln(IntToHex(Form1.GetColorResolvingParent, 8):12  ,   '    Form1.GetColorResolvingParent');
  12.   writeln(IntToHex(Form1.GetRGBColorResolvingParent, 8):12,  '    Form1.GetRGBColorResolvingParent');
  13.   writeln;
  14.   writeln(IntToHex(Panel1.Color, 8):12,                      '    Panel1.Color');
  15.   writeln(IntToHex(Panel1.GetDefaultColor(dctBrush), 8):12,  '    Panel1.GetDefaultColor');
  16.   writeln(IntToHex(Panel1.GetColorResolvingParent, 8):12  ,  '    Panel1.GetColorResolvingParent');
  17.   writeln(IntToHex(Panel1.GetRGBColorResolvingParent, 8):12, '    Panel1.GetRGBColorResolvingParent')
  18. end;

and produced the following output:

Code: Text  [Select][+][-]
  1.     20000000    clDefault
  2.     80000005    clWindow
  3.     80000001    clBackGround
  4.     8000001F    clForm
  5.  
  6.     20000000    Form1.Color
  7.     8000001F    Form1.GetDefaultColor
  8.     8000001F    Form1.GetColorResolvingParent
  9.     00F0F0F0    Form1.GetRGBColorResolvingParent
  10.  
  11.     20000000    Panel1.Color
  12.     80000001    Panel1.GetDefaultColor
  13.     80000001    Panel1.GetColorResolvingParent
  14.     00F5F5F5    Panel1.GetRGBColorResolvingParent

look at lines 8 and 13 in the output. GetColorResolvingParent is NOT resolving back to the parent - Form1 having no parent, and Panel1's parent being Form1. i reckon line 13 should contain the value 8000001F (and thus line 14 should have the value 00F0F0F0).

there are TWO problems:

a. TControl.GetColorResolvingParent contains the comment "GetDefaultColor resolves the parent", which is inconsistent with the function GetDefaultColor's name, and,

b. TControl.GetDefaultColor contains the line:
    Result := TWSControlClass(WidgetSetClass).GetDefaultColor(Self, DefaultColorType);
    that in some way produces a result that prevents recursion. should this line even be there? so far i've not been able to dig into TWSControlClass, and where it comes from is not clear.

the time is 8am now, the sun is shining outside, and i've not slept yet. time to take a break! my apologies if the above is a tad disjointed - think of it as a 'stream of thought from the sleep-deprived'.


cheers,
rob   :-)
« Last Edit: March 09, 2025, 05:11:39 am by robert rozee »

robert rozee

  • Sr. Member
  • ****
  • Posts: 265
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #23 on: March 13, 2025, 07:24:59 am »
carried out further experiments on GetDefaultColor from lcl/include/control.inc:

Code: Pascal  [Select][+][-]
  1. function TControl.GetDefaultColor(const DefaultColorType: TDefaultColorType): TColor;
  2. const
  3.   DefColors: array[TDefaultColorType] of TColor = (
  4.   { dctBrush } clWindow,
  5.   { dctFont  } clWindowText
  6.   );
  7. begin
  8.   Result := TWSControlClass(WidgetSetClass).GetDefaultColor(Self, DefaultColorType);
  9.   if (Result = clDefault) then
  10.     if ParentColor and Assigned(Parent) then
  11.       Result := Parent.GetDefaultColor(DefaultColorType)
  12.     else
  13.       Result := DefColors[DefaultColorType];
  14. end;

the problematic line seems to be ... if (Result = clDefault) then ... that is NEVER true. hence no recursion, and the result returned by GetDefaultColor is ALWAYS simply:
TWSControlClass(WidgetSetClass).GetDefaultColor(Self, DefaultColorType);

note that we appear to be dealing with TWO versions of GetDefaultColor, one belonging to the control we are looking at and that only has ONE parameter passed in, the other belonging to
TWSControlClass(WidgetSetClass) and that takes TWO parameters.

if line 9 (above) is commented out, then a TPanel does seem to assume the same colour as its parent (provided the parent exists and ParentColor of the TPanel is set true), but this hack then creates a cascade of other problems; it produces a pretty odd looking TForm and TPanel as a whole load of other stuff is messed up, likely because the current behavior of GetDefaultColor has been relied upon heavily elsewhere and for a very long time.

this leads me back to where i started - leave the lower-levels of code well alone and just patch things like InputQuery to force colours to match on an as-needed basis. i've submitted this pragmatic solution on GitLab but, as others have said, it could languish there for years.


cheers,
rob   :-)

zeljko

  • Hero Member
  • *****
  • Posts: 1734
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #24 on: March 13, 2025, 03:02:23 pm »
Result is always clDefault if widgetset does not implement GetDefaultColor(), that's why check is there. Now I see that it isn't implemented in qt at all,gtk3,gtk2 ...so implementation will fix that problem. I even didn't know about that function, and no open issues about it, but definitelly implementation is missing.

This is default implementation if WS does not override it.
class function TWSControl.GetDefaultColor(const AControl: TControl; const ADefaultColorType: TDefaultColorType): TColor;
begin
  Result := clDefault;
end;                       

robert rozee

  • Sr. Member
  • ****
  • Posts: 265
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #25 on: March 13, 2025, 03:14:44 pm »
further digging and head-scratching has ensued, with the following offered as a replacement for GetDefaultColor in lcl/include/control.inc:

Code: Pascal  [Select][+][-]
  1. function TControl.GetDefaultColor(const DefaultColorType: TDefaultColorType): TColor;
  2. begin
  3.   Result := TWSControlClass(WidgetSetClass).GetDefaultColor(Self, DefaultColorType);
  4.  
  5.   if (Self.Color = clDefault) and ParentColor and Assigned(Parent) then
  6.       Result := Parent.GetDefaultColor(DefaultColorType)
  7. end;

the routine now recurses correctly. note that the line:
Result := TWSControlClass(WidgetSetClass).GetDefaultColor(Self, DefaultColorType);
returns the 'default' colour (as per the widgetset and desktop theme) of each item passed in, as far as i have been able to determine this is an index into a table of RGB values (clScrollBar..clForm / $80000000..$8000001F). so with a Panel on a Form it will on the first time round operate on the Panel, then on the second time round operate on the Form. for clarity, the line should really be written as:
Result := TWSControlClass(Self.WidgetSetClass).GetDefaultColor(Self, DefaultColorType);

we recurse if it is true that:
a) our colour property (Self.Color) is clDefault (0x20000000), and,
b) we want to use our parent's colour, and,
c) we have a parent.

i'm not sure if a TForm can have a parent and at the same time have ParentColor=TRUE. this is something for others to test. and i believe that the use of DefColors[DefaultColorType] was originally intended as some sort of backstop in case everything else when to custard.


cheers,
rob   :-)

addendum: if it was necessary to have a backstop, then it could probably be implemented something like:

Code: Pascal  [Select][+][-]
  1. function TControl.GetDefaultColor(const DefaultColorType: TDefaultColorType): TColor;
  2. const
  3.   DefColors: array[TDefaultColorType] of TColor = (
  4.   { dctBrush } clWindow,
  5.   { dctFont  } clWindowText
  6.   );
  7. begin
  8.   Result := TWSControlClass(WidgetSetClass).GetDefaultColor(Self, DefaultColorType);
  9.      
  10.   if (Self.Color = clDefault) and ParentColor and Assigned(Parent) then
  11.       Result := Parent.GetDefaultColor(DefaultColorType)                   // recursion
  12.   else
  13.       if Result = clDefault then Result := DefColors[DefaultColorType]     // backstop
  14. end;

which brings us tantalizingly close to the original code - it makes me wonder if someone way back simply made a minor cut-and-paste oopsie late one night!
« Last Edit: March 14, 2025, 07:06:40 pm by robert rozee »

zeljko

  • Hero Member
  • *****
  • Posts: 1734
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: BUG in InputQuery if default colour for TForm and TPanel differ
« Reply #26 on: March 13, 2025, 03:17:10 pm »
I've bit digging into ws sources, some ws override GetDefaultColor() for some controls. Eg in Qt6 form handle have overriden GetDefaultColor() which returns clForm for brush, and clBtnText for text color, other ws also have some overrides (eg gtk3)

robert rozee

  • Sr. Member
  • ****
  • Posts: 265
changes to GetDefaultColor added as an issue to GitLab:
https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/41534

and also just submitted at a merge request:
https://gitlab.com/freepascal.org/lazarus/lazarus/-/merge_requests/452


cheers,
rob   :-)
« Last Edit: March 16, 2025, 11:59:10 am by robert rozee »

TRon

  • Hero Member
  • *****
  • Posts: 4272
Hi robert, pardon the delay (I have better things to do than wait the forum to grant access)

The first offered patch seem to be too intrusive, the second one seem to be more in line with the rest of the theme in use.

Attachments will not fit so I spend a 2nd post. This post only the before.



« Last Edit: March 16, 2025, 08:50:39 pm by TRon »
Today is tomorrow's yesterday.

TRon

  • Hero Member
  • *****
  • Posts: 4272
The patch1 and patch2 results
Today is tomorrow's yesterday.

 

TinyPortal © 2005-2018