Lazarus

Programming => LCL => Topic started by: Arioch on September 20, 2022, 05:36:13 pm

Title: TTaskDialog musings
Post by: Arioch on September 20, 2022, 05:36:13 pm
Windows Vista introduced new kind of "common dialogs" to ask user about their choices, Task Dialogs.  A good brief article wih examples is at https://specials.rejbrand.se/TTaskDialog/

Being more generic and feature-full iteration of MessageDlg/CreateMessageDialog
https://lazarus-ccr.sourceforge.io/docs/lcl/dialogs/createmessagedialog.html

Especially after Lazarus expanded MessageDlg to include random-amount of developer-captioned button - those dialogs tend to become non-proportional,  ultra-wide while thin.

Windows TaksDialog tends to be veritcally-stacked instead, usually making a more harmonious window shape.

mORMot project developed pre-Vista TaskDialog implementation using stock VCL components, later it was adapted to us LCL components and donated to LCL/Lazarus.

https://wiki.freepascal.org/TTaskDialog

That Lazarus dialog however lacks a lot of Windows features, which is understandable given emphasis on cross-platform and least-common-base reuquiments of LCL.

Simple example: compare https://lazarus-ccr.sourceforge.io/docs/lcl/dialogs/ttaskdialog-5.html with https://docwiki.embarcadero.com/Libraries/Sydney/en/Vcl.Dialogs.TTaskDialog_Events


This became especially apparent in debugger interface thread: https://forum.lazarus.freepascal.org/index.php/topic,60624.0.html

So, i guess, some reflections of how TTaskDialog could be enhanced are to be collected somewhere, rather than pollute debugger's thread.



Microsoft decided that in "Vista age" every user knows what is hyperlink in the internet, and i think they do, They probably also thought, that if explanation is required for common problem - the chance is that number of explanations for different terms are. IOW, one single Help button is not many enough.

This or other reasoning, there is explicitly no HELP buttons in TaskDialog API. More so, eveyr button, even with ModalResult set to zero, would close the dialog.

Martin pointed to a hack making a non-closing button:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.dlgDWARFButtonClicked(Sender: TObject;
  2.   AModalResult: TModalResult; var ACanClose: Boolean);
  3. begin
  4.   ACanClose := AModalResult <> 0; // or any other MR assigned to non-closing buttons
  5. end;  
  6.  

This seems to work indeed, but still has drawbacks:

1. This violates MS intentions, that are materialized in hundred of TaskDialog use cases in dozens of programs. Users would NOT expect that Help button is "harmless".

Even if they did - violating UI guidelines is questionable choice always.

But as a temptorary hack it works.

2. Such a button would have no visual cue it is fundamentally different from other, "final" buttons. It is okay when "horizontal bottom bar of buttons" mode is used, as in traditional dialogs. People got used that Help button there is a non-closing kind. But if the verical arrangement of button is selected (AKA Command buttons mode, it would probably be confusing)


3. The "Command buttons" have two texts in them, Large "caption" and smaller "hint" text. In Delphi.
Such an "extended caption" could explain to suer the Help button is not going to close the dialog. Bad design, but at least user is forewarned.

Since LCL dialog is rooted in pure LCL for "Least common denominator", though, it does not have command button hint at all.


To backport it - 2-captioned buttons have to be added to core LCL.



4. Microsoft made a dubious choice about hyperlinks - the texts in the dialog explicitly support the <A> tag and none of other HTML features.

https://learn.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-taskdialogconfig

This solution seems practical, but also a very ad-hoc-ish. Non-elegant.

This precludes "normal" connecting help systems to the LCL dialog. The dialog needs "on hyperlink clicked" event - whic hcan not be implemented while the dialog does not know what hyperlink is.

One can implement a custom one-tag-HTML parser and x-platform rendred rendered for TTaskDialog, but seems a weird one-use-only solution.

Once can also ascend some basic HTML parser and rendered into LCL code. Examples:

However...

a) this would create the reverse problems, UNIX devs would start using all of implemented HTML features, ruining uniformity of the dialogs, and then suddenly becoming incompatible with Windows (see attached pic below)
b) LCL Core team would probably not be very happy to include a Chrome-grade modern parser into the core and have mantainance burder, not to make LCL dependent on Chromium. There is a commercial library Delphi HTML controls, and it seems working good, but it was their intention to use HTML renderer as their foundation. LCL is not that, though, and hardly wishes to be HTML-rewritten.
c) LCL Core team would probably not be happy to have some very-limited-subset rendered enshrined, and then see repeteative complains "your HTML sucks, obsolete, need to be extended".

Potentially it would be posisble just to add the 3rd imlpementation to TTaskDialog, based entirely on THTMLFrame or partially on TJvHTLabel, and let users who need full functionality include it in their projects. But then TaskDialog would be exposing API that is just ignored on core implementation.



The current code raises some eyesbrows.

Code: Pascal  [Select][+][-]
  1.   if (WidgetSet.GetLCLCapability(lcNativeTaskDialog) = LCL_CAPABILITY_YES) and
  2.  
  3. .....
  4.  
  5. // D:\fpcupdeluxe\lazarus\lcl\include\interfacebase.inc
  6.  
  7. function TWidgetSet.GetLCLCapability(ACapability: TLCLCapability): PtrUInt;
  8. begin
  9.   case ACapability of
  10.     lcCanDrawOutsideOnPaint,
  11.     lcNeedMininimizeAppWithMainForm,
  12.     lcApplicationTitle,
  13.     lcFormIcon,
  14.     lcModalWindow,
  15.     lcReceivesLMClearCutCopyPasteReliably,
  16.     lcSendsUTF8KeyPress,
  17.     lcEmulatedMDI,
  18.     lcNativeTaskDialog,
  19.     lcAccelleratorKeys: Result := LCL_CAPABILITY_YES;
  20.   else
  21.     Result := LCL_CAPABILITY_NO;
  22.   end;
  23. end;
  24.  
  25.     /// if TRUE, the Delphi emulation code will always be used
  26.     NonNative: boolean;
  27.  
  28. ...
  29.  
  30.   // use our native (naive?) Delphi implementation
  31.   Dialog.Emulated := true;
  32.   Dialog.Form := TEmulatedTaskDialog.CreateNew(Application);
  33.  

1. I wonder if some standard  layer could be added to override `GetLCLCapability` in runtime, for testing purposes. I could patch LCL and rcecompile, but this does not feel good, and it won't provide for changing behavior in runtime.
2. The use of term "native" is the comments is perverse here. Everywhere else "Native" means native to the platform. Buttons rendered by Windows GDI or MacOX Cocoa in SWT and VCL, as opposed to custom-rendered by Java Swing and FMX. It adds a cognitive burden... Especially since the nameing of the variables/parameters is conventional.
3. The GetLCLCapability asserts every platform to have this, Vista-only API. Which infers it is demanded for every toolkit but Windows to remove that flag.
Yet, better, function TWin32WidgetSet.GetLCLCapability in lazarus\lcl\interfaces\win32\win32object.inc does not override it. But hey, only Vista+ had API, XP- does not, the dialog was precisely developed for Windows 2000 and XP !!! The TaskDialog itself explicitly queries OS API, if the interface function is present or not. This flag makes no sense in LCL Capabilities!

Code: Pascal  [Select][+][-]
  1. function TQtWidgetSet.GetLCLCapability(ACapability: TLCLCapability): PtrUInt;
  2. begin
  3.   case ACapability of
  4. ....
  5.     lcNativeTaskDialog: Result := {$ifdef MSWINDOWS} LCL_CAPABILITY_NO {$else} LCL_CAPABILITY_YES {$endif};
  6.  

Qt, LOL, it is not correct, you have to check Windows version!!!
And why do you say Windows does not have native API and non-Windows do - when it is exactly the opposite???

And GTK2 and GTK3 and what over toolkits should do it too.
And Cocoa, i am looking at you, why don't you opt-out and pretend having Windows-specific API ???

And then it has
Code: Pascal  [Select][+][-]
  1.       {$IFDEF MSWINDOWS}
  2.       if WidgetSet.GetLCLCapability(lcNativeTaskDialog) = LCL_CAPABILITY_NO then
  3.         ARadioOffset := 1
  4.       else
  5.         ARadioOffset := 0;
  6.       {$ELSE}
  7.       ARadioOffset := 1;
  8.       {$ENDIF}
  9.  

equivalent code:

Code: Pascal  [Select][+][-]
  1.      
  2.    const ARadioOffset = {$IFDEF MSWINDOWS} 0 {$ELSE} 1 {$ENDIF};
  3.  



There is probably a lot more to the TaskDialog. For example Windows/Delphi have some OnNavigate event which is nowhere documented.
Title: Re: TTaskDialog musings
Post by: Arioch on September 20, 2022, 05:41:04 pm
LCL implementation puts command buttons above radiobuttons, native Windows implementaiton does the opposite.

Compare attached pic with https://forum.lazarus.freepascal.org/index.php?action=dlattach;topic=60624.0;attach=50866;image

Also, the HELP button has to be default, and it is on Windows (albeit the highlight is thinly faint), but not in the LCL-only dialog
Title: Re: TTaskDialog musings
Post by: Arioch on September 20, 2022, 06:26:10 pm
Wrong implementation of [tfUseCommandLinks,tfUseCommandLinksNoIcon] set of flags.

tfUseCommandLinks says "use big buttons with green arrows"
tfUseCommandLinksNoIcon says "use big buttons but no green arrows"

When both flags are set, Windows still draws arrows, but LCL does not.
Title: Re: TTaskDialog musings
Post by: wp on September 20, 2022, 07:15:45 pm
LCL implementation puts command buttons above radiobuttons, native Windows implementaiton does the opposite.
Can't confirm what you are saying about command buttons above radiobuttons:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button12Click(Sender: TObject);
  2. begin
  3.   with TTaskDialog.Create(Self) do
  4.     try
  5.       Caption := 'My Application';
  6.       Title := 'The Title';
  7.       Text := 'This is the text of the TaskDialog.';
  8.       Flags := Flags + [tfUseCommandLinks];
  9.       with TTaskDialogButtonItem(Buttons.Add) do
  10.       begin
  11.         Caption := 'Command Item 1';
  12.         ModalResult := mrYes;
  13.       end;
  14.       with TTaskDialogButtonItem(Buttons.Add) do
  15.       begin
  16.         Caption := 'Command Item 2';
  17.         ModalResult := mrNo;
  18.       end;
  19.       with RadioButtons.Add do
  20.         Caption := 'This is one option';
  21.       with RadioButtons.Add do
  22.         Caption := 'This is another option';
  23.       with RadioButtons.Add do
  24.         Caption := 'This is a third option';
  25.       CommonButtons := [tcbYes, tcbNo];
  26.       MainIcon := tdiQuestion;  //tdiNone; // There is no tdiQuestion  -- wp: this comment is for Delphi only
  27.       if Execute then
  28.         if ModalResult = mrYes then
  29.           beep;
  30.     finally
  31.       Free;
  32.     end;
  33. end;
  34.  
Same as with Delphi.
Title: Re: TTaskDialog musings
Post by: Martin_fr on September 20, 2022, 07:27:37 pm
Can't confirm what you are saying about command buttons above radiobuttons:
Same as with Delphi.

Depends on native Windows:

Flags := [tfUseHiconMain,tfAllowDialogCancellation,tfUseCommandLinks]

vs

Flags := [tfAllowDialogCancellation,tfUseCommandLinks]


similar tfUseCommandLinksNoIcon
Title: Re: TTaskDialog musings
Post by: wp on September 20, 2022, 08:12:11 pm
Depends on native Windows:

Flags := [tfUseHiconMain,tfAllowDialogCancellation,tfUseCommandLinks]

vs

Flags := [tfAllowDialogCancellation,tfUseCommandLinks]


similar tfUseCommandLinksNoIcon
Whatever combination of flags I use in the LCL TaskDialog, the command links never are above the radiobuttons, in the code that I posted above. I don't understand how a screenshot such as in reply #1 could have been achieved. Is it the Windows version? I am on Win 11...
Title: Re: TTaskDialog musings
Post by: Arioch on September 20, 2022, 10:31:06 pm
wp, if yo use Windows you have either to use lower level API than TTaskDialog - or patch LCL
or find Win2000/WinXP :-)

The easiest way for you would be to patch

// D:\fpcupdeluxe\lazarus\lcl\include\interfacebase.inc
function TWidgetSet.GetLCLCapability(ACapability: TLCLCapability): PtrUInt;

and make it return xxX_NO  on lcNativeTaskDialog

or to patch a place in TTaskDialog.DoExecute that checks it (that is what i do)

anyway, i alread y made a patch to fix it - https://forum.lazarus.freepascal.org/index.php/topic,60624.msg454399.html#msg454399
Title: Re: TTaskDialog musings
Post by: wp on September 20, 2022, 11:15:50 pm
I am completely lost... You say: "LCL implementation puts command buttons above radiobuttons, native Windows implementation does the opposite." My test shows: No - the command buttons are below the radiobuttons which is like native Windows, according to your statement. Why should I have to patch anything then?
Title: Re: TTaskDialog musings
Post by: Arioch on September 20, 2022, 11:21:13 pm
I am completely lost... You say: "LCL implementation puts command buttons above radiobuttons, native Windows implementation does the opposite." My test shows: No - the command buttons are below the radiobuttons which is like native Windows, according to your statement. Why should I have to patch anything then?

Beause you run Vista implementation. LCL Native implemetation (emulation) is only called when native Windows API is not available.

Since you use Win11, the API is there and native implementation is executed.

Simple test, change Lazarus IDE to some exotic language, then run Test Dialog in the IDE and see if the standard OK/Cancel butto nwould be translated to overrode Lazarus language or remain in Windows language

dialogs.TTaskDialog it NOT implementation, it is merely API bridge, that choses implementation on the run
Title: Re: TTaskDialog musings
Post by: Arioch on September 20, 2022, 11:29:45 pm
wp, trace into Execute method and see for yourself, you call Windows API

d:\fpcupdeluxe\lazarus\lcl\lcltaskdialog.pas

line 800

Code: Pascal  [Select][+][-]
  1.   if (WidgetSet.GetLCLCapability(lcNativeTaskDialog) = LCL_CAPABILITY_YES) and
  2.     Assigned(TaskDialogIndirect) and not aNonNative and
  3.      not (tdfQuery in aFlags) and (Selection='') then begin
  4.     Dialog.Emulated := False;
  5.     // use Vista/Seven TaskDialog implementation (not tdfQuery nor Selection)
  6. ...
  7.  

that is where you go


also TTaskDialogButtonItem(Buttons.Add) is not needed, the Add already returns typecaseted value
Title: Re: TTaskDialog musings
Post by: wp on September 20, 2022, 11:53:53 pm
Ran my test program under Linux, and now I do see the exchanged command and radio buttons. OK - you're correct. I applied your patch and committed it.

I still wonder why you were able to see this on Windows. Your screenshot does not look like you're on XP.
Title: Re: TTaskDialog musings
Post by: Martin_fr on September 21, 2022, 01:06:27 am
Actually on Windows, the button can be above or below:

Flags := [tfUseHiconMain,tfAllowDialogCancellation,tfUseCommandLinks]
vs
Flags := [tfAllowDialogCancellation,tfUseCommandLinks]

Strangely tfUseHiconMain affects their location and style
Title: Re: TTaskDialog musings
Post by: PascalDragon on September 21, 2022, 09:09:18 am
I still wonder why you were able to see this on Windows. Your screenshot does not look like you're on XP.

Because Arioch forced the LCL to use the emulation code instead of the Vista+ dialog.
Title: Re: TTaskDialog musings
Post by: wp on September 21, 2022, 09:39:50 am
Actually on Windows, the button can be above or below:

Flags := [tfUseHiconMain,tfAllowDialogCancellation,tfUseCommandLinks]
vs
Flags := [tfAllowDialogCancellation,tfUseCommandLinks]

Strangely tfUseHiconMain affects their location and style
As I already wrote above I cannot verify this: When I use these Flags settings in my test procedure from reply #3 nothing changes with respect to arrangement of radio and command buttons. But maybe I am missing some point. Can you post some code so that I can reproduce your observation?
Title: Re: TTaskDialog musings
Post by: wp on September 21, 2022, 09:52:50 am
I still wonder why you were able to see this on Windows. Your screenshot does not look like you're on XP.

Because Arioch forced the LCL to use the emulation code instead of the Vista+ dialog.
Ah, now I understand what he means...
Title: Re: TTaskDialog musings
Post by: zamtmn on September 21, 2022, 12:52:22 pm
The answer is from another topic, about colors.
I think that we need some kind of centralized method of selecting the color of the text by background and the background by the text. So that the result is somehow similar to the system colors. It will not be possible to just do with clXXXX constants, there will always be "bad" color themes
Title: Re: TTaskDialog musings
Post by: Arioch on September 21, 2022, 01:55:33 pm
Strangely tfUseHiconMain affects their location and style

Also tfUseHiconMain,

It is not "affecting location", it is switching form Native to LCL-emulated.
It is non-Windows extended feature, most probably.

There is more to it, but it is gladly not exposed on dialogs.TTaskDialog level.
They took lazy approach with Flags though.

And frankly, would Windows and VCL  ever add more flags - the very idea of extending binary bitset with custom flags would lead to troubles.
However, mere hiding from Object Inspector could be had done by the trivial reduced enum type...
Shoud be done, perhaps.

For example, there is (in emulation) an option to turn "verificationText" from a checkbox to a combo drop-down list or radiogroup (according to comments, did not test)
Another example is to emed TEdit into the dialog, so free-form response from user can be asked for, effectively replacing simplistic InputQuery and InputBox dialogs.

https://docwiki.embarcadero.com/Libraries/Sydney/en/Vcl.Dialogs.InputQuery

If you are curious, skim through top comments in LCLTaskDialog looking for Selected... and Quesry... properties being mentioned.

I can sympathisize with both mORMot's desire ot have TEdit because why not, and MS desire to not have, because ugly and breaks tablets-freendly design

----

Not sure what could be a proper design with all this.

DevExpress' Quantum Grid, for example, has a property to chose a database backend from a drop-down list of registered ones, then extended properties appear as sub-properties of selected back-end object. Same can be done with Task-dialog, if to separate Win32 and Natice implementations into totally separate classes (right now they are just two execution paths within one long procedure). This would allow for keeping bare-bones LCL implementation and then adding a 3rd full-feature implementation, for example based on HTML rendered through THtmlFrame package

TTaskDialog itself then would only expose bare-bone properties, and extended one going to sub-properties of an implementation, with default auto-implementation adding none.

Related concern is that currently Lazarus is totally broken when loading a non-found property. In Delphi i regularly switch to direct DFM editing, like when i need to change component type (recent example, you asked me why TStaticText in the proposed DWARF-choosing dialog, and indeed, it had to be TLabel). In Delphi it is a mundane "skip this property?" confirmatin, in Lazarus it is death of IDE.

So, how should Delphi project be imported to Lazarus then, when Delphi expose more properties (especialyl events) ???

Should those all properties be published (to facilitate DFM import) and then forcibly hidden from OI (typical Delphi trick was setting OI property setter to nil procedure, it auto-hid the property as misconfigured)?

Ideally, DFM Import should be an "official feature" of IDE, rather than a separate project, so each LCL component would be encouraged to register itself as some DFM components handler, and have a special loading control flow to import form DFM not LFM.

Another approach would be just making two components  on the palette, one striving at Delphi/Windows compatibility, and another pure LCL caring about nothing and implemented everything LCL developers would think is  good-to-have
Title: Re: TTaskDialog musings
Post by: Arioch on September 21, 2022, 02:02:14 pm
selecting the color of the text by background

like i said, if Abs(Brightness(FontColor) - Brightness(BackColor)) < threshold then FontColor := { Black Or White Opposite to background }

more elborate schemes would require "colors theory" selecting colours from all the palette to make some theoretically pleasant pair, but actually not even that - you would first have to determine all the currently active "screne area" - which is maybe the current TForm, but maybe is several forms, all forms of TApplication, or maybe just all the windows of all the applications...

Uncertainties start snowballing.

and the background by the text.

big NO.

while black or white text is limited ugliness while preserving the window's vague general uniformity, changing background would create a big contrast patch of a very different (to adjacent ocntrols) colour.

that would be ugly
Title: Re: TTaskDialog musings
Post by: wp on September 21, 2022, 02:29:27 pm
The answer is from another topic, about colors.
I think that we need some kind of centralized method of selecting the color of the text by background and the background by the text. So that the result is somehow similar to the system colors. It will not be possible to just do with clXXXX constants, there will always be "bad" color themes
The system colors usually come in pairs such as clWindow - clWindowText, clHighlight - clHighlightText, clInfoBk - clInfoText. Unfortunately for some colors it is hard to decide whether they are used as background or foreground color (at least without some work). But anyway, Arioch's hint on clHotLight (why didn't they call it clHotText if it used for hyperlinks?) is an interesting tip: zamtmn, could you check whether this could serve in dark mode as a replacement for the $B00000 in the original code?
Title: Re: TTaskDialog musings
Post by: zamtmn on September 21, 2022, 02:41:18 pm
The answer is from another topic, about colors.
I think that we need some kind of centralized method of selecting the color of the text by background and the background by the text. So that the result is somehow similar to the system colors. It will not be possible to just do with clXXXX constants, there will always be "bad" color themes
The system colors usually come in pairs such as clWindow - clWindowText, clHighlight - clHighlightText, clInfoBk - clInfoText. Unfortunately for some colors it is hard to decide whether they are used as background or foreground color (at least without some work). But anyway, Arioch's hint on clHotLight (why didn't they call it clHotText if it used for hyperlinks?) is an interesting tip: zamtmn, could you check whether this could serve in dark mode as a replacement for the $B00000 in the original code?
of course, there just became too many topics and text
Title: Re: TTaskDialog musings
Post by: Arioch on September 21, 2022, 04:40:01 pm
i believe you could just look in the Lazarus itself, any TForm has Color property, so...
Title: Re: TTaskDialog musings
Post by: Arioch on September 21, 2022, 05:00:25 pm
The system colors usually come in pairs such as clWindow - clWindowText, clHighlight - clHighlightText, clInfoBk - clInfoText.

Yet they were directly applied only in 2D looks of Windows 3.x and even DOS Shell

As soon as MS Office 6.0 for Win16 introduced 3D look (and then Win95 and WinNT4 embraced it) - it became convoluted.
It became common point for text of element Y assume the background colour of elemnt Y or vice versa, because that way it was looking slick.

if you would look into VCL sources for properties like Ctrl3D or FlatXXXX mentioned in sources - you would find those examples.
Especially in early Delphi ( Ctrl3D used to make the same program look differently under Win3.1 and Win95, then it was gradually phased out and removed form public VCL API, but traces of it still occasionally found in VCL sources)
Title: Re: TTaskDialog musings
Post by: wp on September 21, 2022, 06:52:56 pm
And just found another issue: Switched my Linux VM to High-DPI - the emulated TaskDialog is not ready for high-dpi, it does not scale.
Title: Re: TTaskDialog musings
Post by: Arioch on September 21, 2022, 07:15:17 pm
yeah, it is hard-coded on per-pixel level

and frankly, VCL design is very bad in scaling.

in 16-bits time the decision to use pixels instead of abstract split-pixel "typographic points" (used by Widows GDI) saved a lot of memory and CPU cycles. Today we pay the price...

from experience, just working with the same DFM files with Delphi IDE run on Windows machines with display set to 96DPI and 120DPI resulted in very bad and quickly snowballing rounding errors

there even was a project on github, TBaseForm = class (TForm), seeking to comlement / replace functions of stock VCL, and scaling/aligning was one of them

LCL dialog should be reformulated as a set zero-border panels with .Align set and .BorderSpacing (in LCL terms, in VCL those are .Margins), then .Scaling := True and cross your fingers and pray it would work.

The premonitions about HighDPI also was one of my thought making implementing the dialog via THTMLFrame crossed my mind.
In general i abhor HTML as widgets toolkit.

I believe it was one of factors why Microsoft canned the original, written in Delphi Skype and started anew with Electron/JS.

But remember - there already was complain about Lazarus Form Designer on High-DPI screen yesterday, this early LCL/VCL design choice consequences would be recurring now.

On Windows 8+ the best course is setting Display scale 200% - it just turns every logic pixel into 2x2 physical px for non-adapted applications.

Now, recent Delphi versions claim they managed to solve it, but i did not look if they did. Community edition have no sources, and i don't feel like downloading pirated Delphi just for that. I prefer XE2 and "devil i know".

P.S. from a personal COVID lockdowns experience: on Windows you can have HighDPI (200%) Windows connecting by RDP to office machine (Win7 or 8) running the 125% (120PPI) mode, an then running applications written for standard (96PPI) mode. Now THAT's the fest of rounding errors and .Align's going amok.
Title: Re: TTaskDialog musings
Post by: wp on September 21, 2022, 07:27:28 pm
zamtmn, could you check whether this could serve in dark mode as a replacement for the $B00000 in the original code?
No so good... I played a bit with the themes on my Linux-VM and found clHighlight to be fine in all cases that I visited. However, I don't have access to qt/qt5 ATM. zamtmn, would you be so kind to check this color, too?
Title: Re: TTaskDialog musings
Post by: zamtmn on September 21, 2022, 08:20:02 pm
Yes, this is the best color
Title: Re: TTaskDialog musings
Post by: Arioch on September 21, 2022, 08:32:17 pm
...in this theme

but chances are in the hundreds of themes floating around there would be those where clHighlight would not be good choice :-(

in the end, we are doing guesswork after looking at some few (1 or 20 or maybe 10, hardly more) of selected themes

P.S. ...andthen there are also GTK2 and GTK3 with their own themes
Title: Re: TTaskDialog musings
Post by: Arioch on September 21, 2022, 09:39:06 pm
i wonder if slick button animation is required...

https://github.com/jackdp/JPPack/raw/master/docs/img/TJppBasicPngButtonEx.png  - this looks good, but is said to be Delphi-only

But then i thought that TPanel can be a replacement of TBitBtn with two captions.

Border/Bevel can to extent simulate button's borders. But animatiionf of mouse hovering or pressing would be much more rough.

Of course one can just implement such a button on top of TButton ot TBitBtn too, feigning empty caption to OS, and then making it custom-painted. Which then would be bound to look more or less distinct from native buttons of OS.

But TPanel is already there :-)
Title: Re: TTaskDialog musings
Post by: wp on September 21, 2022, 10:11:22 pm
...in this theme

but chances are in the hundreds of themes floating around there would be those where clHighlight would not be good choice :-(

in the end, we are doing guesswork after looking at some few (1 or 20 or maybe 10, hardly more) of selected themes

P.S. ...andthen there are also GTK2 and GTK3 with their own themes
And the green bitmap arrows, BTW, have the same issue...

This color combination so far worked for all themes that I checked. It's definitely better than anything else that I've seen before. Committed the version with clWindow and clHighlight to Laz/main. Let's see what users report - they will definitely see it because the TaskDialog version of the debug format selection is in main now.
Title: Re: TTaskDialog musings
Post by: Arioch on September 22, 2022, 10:51:02 pm
But can there be a generic way for LCL back-ends to fetch TBitBtn standard glyphs from Linux toolkit themes?
I doubt...

Meanwhile trying to internalize native behaviour on WIn7 found a funny bug.
Notice, how the last button shape/size was mad for two short strings, but then the caption was rendered as one long string.

Title: Re: TTaskDialog musings
Post by: Arioch on September 22, 2022, 11:01:49 pm
The test was done in Delphi XE2, as some of the properties tested do not exist in LCL.

1. Footer text is word-wrapped and height grows. The long strings in the footer do not increase the dialog's width.

2. Command Buttons height is calculated to fit both Caption and Hint. Different buttons can have different height.

3. Notice, how part of Caption was "downgraded" to the Hint. It seems like either inside Windows ComCtl or inside VCL both caption and hint are merged into "array of string", then first string is considered the caption, and all the rest - multi-line hint.

4. The long caption gets word-wrapped, but at the same time it causes some limited expansion of the dialog's width
Title: Re: TTaskDialog musings
Post by: Arioch on September 22, 2022, 11:08:20 pm
It seems Microsoft Win7 TaskDialog has some rather narrow constraints upon the dialog width.
It varies, but in some very strict margins. i'd estimate width varyation 20-40%

The dialog width does not seem dependent upon screen resolution ( as in Max(X), Max(Y) )

Not sure about screne resolution as in DPI/PPI - this requires logout...
UPD.  Did test with 150% DPI, can't aatch as it is 550 KB

With 150% PPI the dialog size is 1050 x 1030 px
Original size at 100% PPI was 560 x 760 px  ( minimal width was about 500 px )
The proportions changed, but the area is scaled almost exactly 1.5^2 times

The dialog window, i speculate, was squeezed by reduced screen height ( in typographic units, not pixels ) and forced Windows to make the dialog wider.

The window caption is not taken into account w.r.t. the width.
Title: Re: TTaskDialog musings
Post by: Martin_fr on September 22, 2022, 11:18:44 pm
It seems Microsoft Win7 TaskDialog has some rather narrow constraints upon the dialog width.
It varies, but in some very strict margins. i'd estimate width varyation 20-40%

From the docs
https://learn.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-taskdialogconfig
Flags:
Quote
TDF_SIZE_TO_CONTENT

   Indicates that the width of the task dialog is determined by the width of its content area. This flag is ignored if cxWidth is not set to 0.

Quote
cxWidth
Type: UINT

The width of the task dialog's client area, in dialog units. If 0, the task dialog manager will calculate the ideal width.



"dialog units"
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/bb226789(v=vs.85)
Quote
About DLUs: In unmanaged code, the system measures the placement of controls on a surface in dialog units (DLUs), not pixels. A dialog unit is the device-independent measure to use for layout. One horizontal dialog unit is equal to one-fourth of the average character width for the current system font. One vertical dialog unit is equal to one-eighth of an average character height for the current system font. The default height for most single-line controls is 14 DLUs. Be careful if you use a pixel-based drawing program, because it might not provide an accurate representation when you translate your design into dialog units. If you do use a pixel-based drawing tool, you may want to take screen snapshots from a development tool that supports dialog units and use those images. Your application can retrieve the number of pixels per base unit for the current display by using the GetDialogBaseUnits function.


Title: Re: TTaskDialog musings
Post by: Arioch on September 22, 2022, 11:47:17 pm
TDF_SIZE_TO_CONTENT

ATM i am trying to jsut observe VCL XE2 behavior clean-room style. I can look into VCL sources, but don't want to.

It also is not that much important as long as Lazarus goal is compatibility to Delphi, not to Win32 as it can be.

Auto-size in LCL seems to work more reliably than in VCL XE2 (almost all my attempts to set TForm.AutoSize to True failed miserably), so hopefully replacing mORMot's "pixel calculation" implementation with some auto-sizing window built of auto-sizing panels with different Align would be possible.

Meanwhile, three last screenshots.

The captions of radiobuttons get word-wrapped, but do effect the dialog's width.
So do TTaskDialog.Text and TTaskDialog.Title

However, the width in my FullHD (1920x1200) screen varies between 500 and 560, until would be squeeezed by Screen.ActiveMonitor.Height.

I start thinking that LCL implementaiton could strive at some fixed width in physical inches and only change height. Until some developer would pushes the boundaries that seems to be good enouth. And if the boundaries are pushed - then imperfect behaviour would be acceptable.
Title: Re: TTaskDialog musings
Post by: Arioch on September 23, 2022, 09:22:00 pm
3. Notice, how part of Caption was "downgraded" to the Hint. It seems like either inside Windows ComCtl or inside VCL both caption and hint are merged into "array of string", then first string is considered the caption, and all the rest - multi-line hint.

And documented so. https://learn.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-taskdialog_button
Quote
When using Command Links, you delineate the command from the note by placing a new line character in the string.

Interested, how it deviates from usual Microsoft API pattern of have strings separated by #0 and terminated by #0#0
TinyPortal © 2005-2018