lazarus/lcl/taskdlgemulation.pp

1481 lines
46 KiB
ObjectPascal

{
/***************************************************************************
TaskDlgEmulation.pp
-----------------
Implements TaskDialog Window on systems that do not support it natively
This unit was originally a part of the freeware Synopse mORMot framework,
licensed under a MPL/GPL/LGPL tri-license; version 1.19.
It has been relicensed with permission from Arnaud Bouchez, the original
author, and all contributors.
The original name is SynTaskDialog.pas
***************************************************************************/
*****************************************************************************
This file is part of the Lazarus Component Library (LCL)
See the file COPYING.modifiedLGPL.txt, included in this distribution,
for details about the license.
*****************************************************************************
}
unit TaskDlgEmulation;
{
This unit tries to emulate the functionality of Windows Vista and higher TaskDialogIndirect.
It also adds capabilities that TaskDialogIndirect does not have, currently:
* Query via combobox
* Query via single line edit, which supports masking the input for use eith e.g. passwords
The emulated dialog does not aim to be visually (near) exactly the same as the Vista+ native dialog.
This dialog is invoked by Dialogs.TTaskDialog.Execute on systems that do not support
the native Vista+ dialog, and it is also used as a fallback in case the native
Vista+ dialog fails (when passed invalid combination of arguments).
The dialog therefore uses the Flags property of Dialogs.TTaskDialog, but not
all of these flags are supported (yet) in the emulated dialog.
}
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils,
LazUTF8,
LCLType, LCLStrConsts, LCLIntf, LMessages, InterfaceBase, ImgList, LCLProc, DateUtils, Math, ComCtrls,
LResources, Menus, Graphics, Forms, Controls, StdCtrls, ExtCtrls, Buttons, Dialogs, DialogRes,
LazLoggerBase;
type
TTaskDialogElement = (
tdeContent, tdeExpandedInfo, tdeFooter, tdeMainInstruction,
tdeEdit, tdeVerif);
{ TLCLTaskDialog }
TLCLTaskDialog = class(TForm)
private
const
RadioIndent = 16;
ComboBoxHeight = 22;
QueryEditHeight = 22;
LargeImageSize = 32;
SmallImageSize = 16;
CommandLinkButtonHeight = 40;
RadioVSpacing = 16;
LabelVSpacing = 16;
CommandLinkButtonVSpacing = 2;
BevelMargin = 2;
BevelHeight = 2;
ProgressBarHeight = 20;
ProgressBarVSpacing = 16;
private
/// the Task Dialog structure which created the form
FDlg: TTaskDialog;
FVerifyChecked: Boolean;
FExpanded: Boolean;
CommandLinkButtonWidth: Integer;
CommandLinkButtonMargin: Integer;
CommandLinkButtonSpacing: Integer; //Height of TBitBtns
ButtonHeight: Integer; //Height of TButtons
GlobalLeftMargin: Integer;
ExpandHeightRequired: Integer;
Timer: TTimer;
TimerStartTime: TTime;
RadioButtonArray: array of TRadioButton;
//CustomButtons, Radios: TStringList;
DialogCaption, DlgTitle, DlgText,
ExpandButtonCaption, CollapseButtonCaption, ExpandedText, FooterText,
VerificationText: String;
CommonButtons: TTaskDialogCommonButtons;
TopPanel: TPanel;
MidPanel: TPanel;
BottomPanel: TPanel;
MainImage: TImage;
FooterImage: TImage;
ExpandedTextBevel: TBevel;
/// the labels corresponding to the Task Dialog main elements
Element: array[tdeContent..tdeMainInstruction] of TLabel;
/// the Task Dialog query selection list
QueryCombo: TComboBox;
/// the Task Dialog optional query single line editor
QueryEdit: TEdit;
/// the Task Dialog optional checkbox
VerifyCheckBox: TCheckBox;
/// the Expand/Collapse button
ExpandBtn: TButton;
///
ProgressBar: TProgressBar;
procedure GetDefaultButtons(out aButtonDef, aRadioDef: TModalResult);
procedure InitCaptions;
procedure InitGlobalDimensionsAndStyle(ACustomButtonsTextLength: Integer; out aWidth, aFontHeight: Integer);
function GetGlobalLeftMargin: Integer;
procedure AddMainIcon(out ALeft,ATop: Integer; AGlobalLeftMargin: Integer; AParent: TWinControl);
procedure AddPanels;
procedure AddProgressBar(const ALeft: Integer; var ATop: Integer; AWidth: Integer; AParent: TWinControl);
procedure AddRadios(const ARadioOffSet, AWidth, ARadioDef, AFontHeight, ALeft: Integer; var ATop: Integer; AParent: TWinControl);
procedure AddCommandLinkButtons(const ALeft: Integer; var ATop: Integer; AWidth, AButtonDef, AFontHeight: Integer; AParent: TWinControl);
procedure AddButtons(const ALeft: Integer; var ATop, AButtonLeft: Integer; AWidth, AButtonDef: Integer; APArent: TWinControl);
procedure AddCheckBox(const ALeft: Integer; var ATop, XB: Integer; AWidth: Integer; APArent: TWinControl);
procedure AddExpandButton(const ALeft: Integer; var ATop, XB: Integer; AWidth: Integer; APArent: TWinControl);
function AddBevel(var ATop: Integer; aWidth: Integer; AParent: TWinControl; Hidden: Boolean = False): TBevel;
procedure AddFooter(var ALeft: Integer; var ATop: Integer; AFontHeight, AWidth: Integer; APArent: TWinControl);
function AddLabel(const AText: string; BigFont: Boolean; const ALeft: Integer; var ATop: Integer; AFontHeight,
AWidth: Integer; APArent: TWinControl; Hidden: Boolean = False): TLabel;
procedure AddQueryCombo(const ALeft: Integer; var ATop: Integer; AWidth: Integer; AParent: TWinControl);
procedure AddQueryEdit(var X,Y: Integer; AWidth: Integer; AParent: TWinControl);
procedure SetupTimer;
procedure ResetTimer;
procedure ExpandDialog;
procedure CollapseDialog;
function FindButtonByButtonID(ID: Integer): TCustomButton;
function FindRadioButtonByButtonID(ID: Integer): TRadioButton;
procedure DoDialogConstructed;
procedure DoDialogCreated;
procedure DoDialogDestroyed;
procedure OnButtonClicked(Sender: TObject);
procedure OnRadioButtonClick(Sender: TObject);
procedure OnVerifyClicked(Sender: TObject);
procedure OnTimer(Sender: TObject);
procedure OnExpandButtonClicked(Sender: TObject);
procedure DoOnHelp;
procedure SetProgressBarType(var Msg: TLMessage); message TDM_SET_MARQUEE_PROGRESS_BAR;
procedure SetProgressBarRange(var Msg: TLMessage); message TDM_SET_PROGRESS_BAR_RANGE;
procedure SetProgressBarPos(var Msg: TLMessage); message TDM_SET_PROGRESS_BAR_POS;
procedure ClickVerification(var Msg: TLMessage); message TDM_CLICK_VERIFICATION;
procedure ClickButton(var Msg: TLMessage); message TDM_CLICK_BUTTON;
procedure ClickRadioButton(var Msg: TLMessage); message TDM_CLICK_RADIO_BUTTON;
procedure EnableButton(var Msg: TLMessage); message TDM_ENABLE_BUTTON;
procedure EnableRadioButton(var Msg: TLMessage); message TDM_ENABLE_RADIO_BUTTON;
procedure UpdateElementText(var Msg: TLMessage); message TDM_UPDATE_ELEMENT_TEXT;
protected
procedure SetupControls;
public
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
constructor CreateNew(AOwner: TComponent; Num: Integer = 0); override;
destructor Destroy; override;
procedure AfterConstruction; override;
procedure DoShow; override;
function Execute(AParentWnd: HWND; out ARadioRes: Integer): Integer;
public
end;
function ExecuteLCLTaskDialog(const ADlg: TCustomTaskDialog; AParentWnd: HWND; out ARadioRes: Integer): Integer;
type
TLCLTaskDialogIcon = (
tiBlank, tiWarning, tiQuestion, tiError, tiInformation, tiNotUsed, tiShield);
TLCLTaskDialogFooterIcon = (
tfiBlank, tfiWarning, tfiQuestion, tfiError, tfiInformation, tfiShield);
function IconMessage(Icon: TTaskDialogIcon): string;
implementation
type
TTaskDialogAccess = class(TCustomTaskDialog)
end;
var
LDefaultFont: TFont;
function DefaultFont: TFont;
begin
if LDefaultFont<>nil then
Exit(LDefaultFont);
LDefaultFont := TFont.Create;
LDefaultFont.Name := 'default';
LDefaultFont.Style := [];
LDefaultFont.Size := 10;
Result := LDefaultFont;
{$IFDEF WINDOWS}
if Screen.Fonts.IndexOf('Calibri')>=0 then begin
LDefaultFont.Size := 11;
LDefaultFont.Name := 'Calibri';
end else begin
if Screen.Fonts.IndexOf('Tahoma')>=0 then
LDefaultFont.Name := 'Tahoma'
else
LDefaultFont.Name := 'Arial';
end;
{$ENDIF}
end;
const
LCL_IMAGES: array[TTaskDialogIcon] of Integer = (
0 {tdiNone}, idDialogWarning {tdiWarning}, idDialogError {tdiError}, idDialogInfo {tdiInformation},
idDialogShield {tdiShield}, idDialogConfirm {tdiQuestion});
const
TD_BTNMOD: array[TTaskDialogCommonButton] of Integer = (
mrOk, mrYes, mrNo, mrCancel, mrRetry, mrAbort);
function TD_BTNS(button: TTaskDialogCommonButton): pointer;
begin
case button of
tcbOK: Result := @rsMbOK;
tcbYes: Result := @rsMbYes;
tcbNo: Result := @rsMbNo;
tcbCancel: Result := @rsMbCancel;
tcbRetry: Result := @rsMbRetry;
tcbClose: Result := @rsMbClose;
end;
end;
function IconMessage(Icon: TTaskDialogIcon): string;
begin
case Icon of
tdiWarning: Result := rsMtWarning;
tdiQuestion: Result := rsMtConfirmation;
tdiError: Result := rsMtError;
tdiInformation, tdiShield: Result := rsMtInformation;
else Result := '';
end;
end;
function ExecuteLCLTaskDialog(const ADlg: TCustomTaskDialog; AParentWnd: HWND; out ARadioRes: Integer): Integer;
var
DlgForm: TLCLTaskDialog;
begin
//debugln('ExecuteLCLTaskDialog');
Result := -1;
DlgForm := TLCLTaskDialog.CreateNew(ADlg);
try
Result := DlgForm.Execute(AParentWnd, ARadioRes);
finally
FreeAndNil(DlgForm);
end;
end;
constructor TLCLTaskDialog.CreateNew(AOwner: TComponent; Num: Integer);
begin
if (AOwner is TCustomTaskDialog) then
begin
FDlg := TTaskDialog(AOwner);
if (csDesigning in FDlg.ComponentState) then
AOwner:=nil; // do not inherit csDesigning, a normal taskdialog should be shown
end;
inherited CreateNew(AOwner, Num);
RadioButtonArray := nil;
FExpanded := False;
CommandLinkButtonWidth := -1;
KeyPreview := True;
//DoDialogCreated;
end;
destructor TLCLTaskDialog.Destroy;
begin
DoDialogDestroyed;
inherited Destroy;
end;
procedure TLCLTaskDialog.AfterConstruction;
begin
inherited AfterConstruction;
//DoDialogConstructed;
end;
procedure TLCLTaskDialog.DoShow;
begin
inherited DoShow;
{
If we call GetHandle in AfterConstrucion this triggers a CreateWnd, but later on
(as a consequence of using CreateNew ??) the window gets destroyed and recreated
with a different handle, so we cannot call FDlg.InternalSetDialogHandle in CreateNew
or AfterConstruction.
And since we want to have a valid FDlg.Handle in all OnDialogXXX events, we do it here.
}
DoDialogConstructed;
DoDialogCreated;
end;
function TLCLTaskDialog.Execute(AParentWnd: HWND; out ARadioRes: Integer): Integer;
var
mRes, I: Integer;
begin
//debugln(['TLCLTaskDialog.Execute: Assigned(FDlg)=',Assigned(FDlg)]);
if not Assigned(FDlg) then
Exit(-1);
SetupControls;
//set form parent
if (AParentWnd <> 0) then
for I := 0 to Screen.CustomFormCount-1 do
if Screen.CustomForms[I].Handle = AParentWnd then
begin
PopupParent := Screen.CustomForms[I];
Break;
end;
if not Assigned(PopupParent) then
PopupParent := Screen.ActiveCustomForm;
if Assigned(PopupParent) then
PopupMode := pmExplicit;
Result := ShowModal;
if Assigned(QueryCombo) then
begin
FDlg.QueryItemIndex := QueryCombo.ItemIndex;
FDlg.QueryResult := QueryCombo.Text;
end
else
begin
if Assigned(QueryEdit) then
FDlg.QueryResult := QueryEdit.Text;
end;
if VerifyCheckBox<>nil then
begin
if VerifyCheckBox.Checked then
FDlg.Flags := FDlg.Flags + [tfVerificationFlagChecked]
else
FDlg.Flags := FDlg.Flags - [tfVerificationFlagChecked]
end;
ARadioRes := 0;
for i := 0 to high(RadioButtonArray) do
if RadioButtonArray[i].Checked then
ARadioRes := i+TaskDialogFirstRadioButtonIndex;
end;
procedure TLCLTaskDialog.GetDefaultButtons(out aButtonDef, aRadioDef: TModalResult);
begin
if FDlg.RadioButtons.DefaultButton<> nil then
aRadioDef := FDlg.RadioButtons.DefaultButton.Index
else
aRadioDef := 0;
if FDlg.Buttons.DefaultButton<>nil then
aButtonDef := FDlg.Buttons.DefaultButton.ModalResult
else
aButtonDef := TD_BTNMOD[FDlg.DefaultButton];
end;
procedure TLCLTaskDialog.InitCaptions;
begin
DialogCaption := FDlg.Caption;
DlgTitle := FDlg.Title;
DlgText := FDlg.Text;
ExpandButtonCaption := FDlg.ExpandButtonCaption;
CollapseButtonCaption := FDlg.CollapseButtonCaption;
ExpandedText := FDlg.ExpandedText;
FooterText := FDlg.FooterText;
VerificationText := FDlg.VerificationText;
if (DialogCaption = '') then
if (Application.MainForm = nil) then
DialogCaption := Application.Title
else
DialogCaption := Application.MainForm.Caption;
if (DlgTitle = '') then
DlgTitle := IconMessage(FDlg.MainIcon);
end;
procedure TLCLTaskDialog.InitGlobalDimensionsAndStyle(ACustomButtonsTextLength: Integer; out aWidth, aFontHeight: Integer);
begin
PixelsPerInch := 96; // we are using 96 PPI in the code, scale it automatically at ShowModal
Font.PixelsPerInch := 96;
BorderStyle := bsDialog;
if (tfAllowDialogCancellation in FDlg.Flags) then
BorderIcons := [biSystemMenu]
else
BorderIcons := [];
if (tfPositionRelativeToWindow in FDlg.Flags) then
Position := poOwnerFormCenter
else
Position := poScreenCenter;
if not (tfEmulateClassicStyle in FDlg.Flags) then
Font := DefaultFont;
aFontHeight := Font.Height;
if (aFontHeight = 0) then
aFontHeight := Screen.SystemFont.Height;
aWidth := FDlg.Width;
if (aWidth <= 0) then
begin
aWidth := Canvas.TextWidth(DlgTitle);
if (aWidth > 300) or (Canvas.TextWidth(DlgText) > 300) or
(ACustomButtonsTextLength > 40) then
aWidth := 480 else
aWidth := 420;
end
else
if (aWidth < 120) then aWidth := 120;
ClientWidth := aWidth;
if (tfEmulateClassicStyle in FDlg.Flags) then
begin
CommandLinkButtonMargin := 7;
CommandLinkButtonSpacing := 7;
ButtonHeight := 22;
end
else
begin
CommandLinkButtonMargin := 24;
CommandLinkButtonSpacing := 10;
ButtonHeight := 28;
end;
Height := 200;
//debugln(['Font: Name=',Font.Name,', Size=',Font.Size,', Height=',Font.Height]);
end;
function TLCLTaskDialog.GetGlobalLeftMargin: Integer;
begin
if (tfEmulateClassicStyle in FDlg.Flags) then
Result := 10
else
Result := 16;
end;
procedure TLCLTaskDialog.AddMainIcon(out ALeft,ATop: Integer; AGlobalLeftMargin: Integer; AParent: TWinControl);
var
aDialogIcon: TTaskDialogIcon;
begin
MainImage := nil;
if not (tfUseHIconMain in FDlg.Flags) then
begin
aDialogIcon := FDlg.MainIcon;
if (LCL_IMAGES[aDialogIcon]<>0) then
begin
MainImage := TImage.Create(Self);
MainImage.Parent := AParent;
MainImage.Images := DialogGlyphs;
MainImage.ImageIndex := DialogGlyphs.DialogIcon[LCL_IMAGES[aDialogIcon]];
end;
end
else
begin
if Assigned(FDlg.CustomMainIcon) and not (FDlg.CustomMainIcon.Empty) then
begin
MainImage := TImage.Create(Self);
MainImage.Parent := AParent;
MainImage.Picture.Assign(FDlg.CustomMainIcon);
end;
end;
if Assigned(MainImage) then
begin
MainImage.SetBounds(AGlobalLeftMargin, AGlobalLeftMargin, LargeImageSize, LargeImageSize);
MainImage.Stretch := True;
MainImage.StretchOutEnabled := False;
MainImage.Proportional := True;
MainImage.Center := True;
ALeft := MainImage.Width+AGlobalLeftMargin*2;
ATop := MainImage.Top;
if (tfEmulateClassicStyle in FDlg.Flags) then
inc(ATop, 8);
end
else
begin
ALeft := AGlobalLeftMargin;
ATop := AGlobalLeftMargin;
end;
end;
procedure TLCLTaskDialog.AddPanels;
begin
{
Create 3 different panels:
- the top panel holds main icon, title, text and expanded text
- the mid panel holds radiobuttons, commandlinkbuttons and query's
(basically everything that comes after ExpandedText and needs to be on a "colored" panel)
- the bottom panel has the rest of the controls
The top and mid panel have a distinct color (unless tfEmulateClassicStyle is set)
The reason for the 3 panel setup is that it makes it a lot easier to displace the controls
when Expand or Collapse is invoked: just move/resize the appropriate panels, no need to
iterate the individual controls on it.
}
TopPanel := TPanel.Create(Self);
TopPanel.Parent := Self;
TopPanel.Align := alTop;
TopPanel.BorderStyle := bsNone;
TopPanel.BevelOuter := bvNone;
if not (tfEmulateClassicStyle in FDlg.Flags) then
TopPanel.Color := clWindow;
TopPanel.Name := 'TopPanel'; //for debugging purposes
TopPanel.Caption := '';
MidPanel := TPanel.Create(Self);
MidPanel.Parent := Self;
MidPanel.Top := TopPanel.Top + TopPanel.Height + 1;
MidPanel.Align := alTop;
MidPanel.BorderStyle := bsNone;
MidPanel.BevelOuter := bvNone;
MidPanel.Color := TopPanel.Color;
MidPanel.Name := 'MidPanel'; //for debugging purposes
MidPanel.Caption := '';
BottomPanel := TPanel.Create(Self);
BottomPanel.Parent := Self;
BottomPanel.Top := MidPanel.Top + MidPanel.Height + 1;
BottomPanel.Align := alCLient;
BottomPanel.BorderStyle := bsNone;
BottomPanel.BevelOuter := bvNone;
BottomPanel.Name := 'BottomPanel'; //for debugging purposes
BottomPanel.Caption := '';
end;
procedure TLCLTaskDialog.AddProgressBar(const ALeft: Integer; var ATop: Integer; AWidth: Integer; AParent: TWinControl);
begin
Inc(ATop, ProgressBarVSpacing);
ProgressBar := TProgressBar.Create(Self);
if (tfShowMarqueeProgressBar in FDlg.Flags) then
ProgressBar.Style := pbstMarquee
else
begin
ProgressBar.Style := pbstNormal;
ProgressBar.Min := FDlg.ProgressBar.Min;
ProgressBar.Max := FDlg.ProgressBar.Max;
ProgressBar.Position := FDlg.ProgressBar.Position;
end;
ProgressBar.SetBounds(ALeft, ATop, AWidth-ALeft-GlobalLeftMargin, ProgressBarHeight);
Inc(ATop, ProgressBar.Height + ProgressBarVSpacing);
ProgressBar.Parent := AParent;
end;
procedure TLCLTaskDialog.AddRadios(const ARadioOffSet, AWidth, ARadioDef, AFontHeight, ALeft: Integer; var ATop: Integer; AParent: TWinControl);
var
i: Integer;
aHint: String;
begin
SetLength(RadioButtonArray,FDlg.RadioButtons.Count);
for i := 0 to FDlg.RadioButtons.Count-1 do
begin
RadioButtonArray[i] := TRadioButton.Create(Self);
with RadioButtonArray[i] do
begin
Parent := AParent;
Tag := FDlg.RadioButtons[i].Index + TaskDialogFirstRadioButtonIndex;
AutoSize := False;
SetBounds(ALeft+RadioIndent,ATop,aWidth-(2*RadioIndent)-ALeft, (6-AFontHeight) + ARadioOffset);
Caption := FDlg.RadioButtons[i].Caption;
inc(ATop,Height + ARadioOffset);
if not (tfNoDefaultRadioButton in FDlg.Flags) and ((i=0) or (i=aRadioDef)) then
Checked := True;
OnClick := @OnRadioButtonClick;
end;
end;
inc(ATop,24);
end;
procedure TLCLTaskDialog.AddCommandLinkButtons(const ALeft: Integer; var ATop: Integer; AWidth, AButtonDef, AFontHeight: Integer; AParent: TWinControl);
var
i: Integer;
CommandLink: TBitBtn;
aHint: String;
begin
inc(ATop,8);
for i := 0 to FDlg.Buttons.Count-1 do
begin
CommandLink := TBitBtn.Create(Self);
with CommandLink do
begin
Parent := AParent;
Font.Height := AFontHeight-3;
CommandLinkButtonWidth := aWidth - ALeft - GlobalLeftMargin;
SetBounds(ALeft,ATop,CommandLinkButtonWidth,CommandLinkButtonHeight);
Caption := FDlg.Buttons[i].Caption;
Hint := FDlg.Buttons[i].CommandLinkHint;
if (Hint <> '') then
ShowHint := True;
inc(ATop,Height+CommandLinkButtonVSpacing);
ModalResult := i+TaskDialogFirstButtonIndex;
OnClick := @OnButtonClicked;
if ModalResult=aButtonDef then
ActiveControl := CommandLink;
if (tfEmulateClassicStyle in FDlg.Flags) then
begin
Font.Height := AFontHeight - 2;
Font.Style := [fsBold]
end;
Margin := CommandLinkButtonMargin;
Spacing := CommandLinkButtonSpacing;
if not (tfUseCommandLinksNoIcon in FDlg.Flags) then
begin
Images := LCLGlyphs;
ImageIndex := LCLGlyphs.GetImageIndex('btn_arrowright');
end;
end;
end;
inc(ATop,24);
end;
procedure TLCLTaskDialog.AddButtons(const ALeft: Integer; var ATop, AButtonLeft: Integer; AWidth, AButtonDef: Integer; APArent: TWinControl);
var
CurrTabOrder, i: Integer;
Btn: TTaskDialogCommonButton;
function AddButton(const s: string; AModalResult, ACustomButtonIndex: integer): TButton;
var
WB: integer;
begin
WB := Canvas.TextWidth(s)+52;
dec(AButtonLeft,WB);
if AButtonLeft<ALeft {shr 1} then
begin
AButtonLeft := aWidth-WB;
inc(ATop,32);
end;
Result := TButton.Create(Self);
Result.Parent := AParent;
Result.SetBounds(AButtonLeft,ATop,WB-10,ButtonHeight);
Result.Caption := s;
Result.ModalResult := AModalResult;
Result.TabOrder := CurrTabOrder;
Result.OnClick := @OnButtonClicked;
if Assigned(FDlg.Buttons.DefaultButton) then
begin
if (ACustomButtonIndex >= 0) and
(FDlg.ButtonIDToModalResult(TaskDialogFirstButtonIndex+ACustomButtonIndex) = AButtonDef) then
Result.Default := True;
end
else
begin
case AModalResult of
mrOk: begin
Result.Default := True;
if CommonButtons=[tcbOk] then
Result.Cancel := True;
end;
mrCancel: Result.Cancel := True;
end;//case
end;//else
if Assigned(FDlg.Buttons.DefaultButton) and Result.Default then
ActiveControl := Result
else
if AModalResult=aButtonDef then
ActiveControl := Result;
end;
begin
//debugln(['TLCLTaskDialog.AddButtons: ALeft=',ALeft,', aWidth=',aWidth,', AParent=',DbgSName(AParent),', AParent.ClientWidth=',AParent.ClientWidth]);
if MidPanel.ControlCount > 0 then
CurrTabOrder := MidPanel.TabOrder
else
CurrTabOrder := TopPanel.TabOrder;
inc(ATop, 16);
AButtonLeft := aWidth;
if not (tfUseCommandLinks in FDlg.Flags) then
for i := FDlg.Buttons.Count-1 downto 0 do
AddButton(FDlg.Buttons[i].Caption,i+TaskDialogFirstButtonIndex,i);
for Btn := high(TTaskDialogCommonButton) downto low(TTaskDialogCommonButton) do
begin
if (Btn in CommonButtons) then
AddButton(LoadResString(TD_BTNS(Btn)), TD_BTNMOD[Btn],-1);
end;
end;
procedure TLCLTaskDialog.AddCheckBox(const ALeft: Integer; var ATop, XB: Integer; AWidth: Integer; APArent: TWinControl);
begin
//debugln(['TLCLTaskDialog.AddCheckBox: ALeft=',ALeft]);
VerifyCheckBox := TCheckBox.Create(Self);
with VerifyCheckBox do
begin
Parent := AParent;
if (ALeft+16+Canvas.TextWidth(VerificationText) > XB) then begin
inc(ATop,32);
XB := aWidth;
end;
SetBounds(ALeft,ATop,XB-ALeft,24);
Caption := VerificationText;
Checked := FVerifyChecked;
OnClick := @OnVerifyClicked;
end;
end;
procedure TLCLTaskDialog.AddExpandButton(const ALeft: Integer; var ATop, XB: Integer; AWidth: Integer; APArent: TWinControl);
var
CurrTabOrder: TTabOrder;
WB, AHeight: Integer;
begin
if MidPanel.ControlCount > 0 then
CurrTabOrder := MidPanel.TabOrder
else
CurrTabOrder := TopPanel.TabOrder;
if (ExpandButtonCaption = '') then
begin
if (CollapseButtonCaption = '') then
begin
ExpandButtonCaption := rsShowDetails;
CollapseButtonCaption := rsHideDetails;
end
else
ExpandButtonCaption := CollapseButtonCaption;
end;
if (CollapseButtonCaption = '') then
CollapseButtonCaption := ExpandButtonCaption;
WB := Max(Canvas.TextWidth(ExpandButtonCaption), Canvas.TextWidth(CollapseButtonCaption)) +32;//52;
if (ALeft+WB > XB) then
begin
inc(ATop,32);
XB := aWidth;
end;
ExpandBtn := TButton.Create(Self);
ExpandBtn.Parent := AParent;
if (tfEmulateClassicStyle in FDlg.Flags) then
AHeight := 22
else
AHeight := 28;
ExpandBtn.SetBounds(ALeft,ATop,WB-12,AHeight);
if not (tfExpandedByDefault in FDlg.Flags) then
ExpandBtn.Caption := ExpandButtonCaption
else
ExpandBtn.Caption := CollapseButtonCaption;
ExpandBtn.ModalResult := mrNone;
ExpandBtn.TabOrder := CurrTabOrder;
ExpandBtn.OnClick := @OnExpandButtonClicked;
Inc(ATop, AHeight+8);
end;
function TLCLTaskDialog.AddBevel(var ATop: Integer; aWidth: Integer; AParent: TWinControl; Hidden: Boolean): TBevel;
begin
Result := TBevel.Create(Self);
with Result do begin
Parent := AParent;
//if (FooterImage<>nil) and (ATop<FooterImage.Top+FooterImage.Height) then
// BX := ALeft else
// BX := BevelMargin;
SetBounds(BevelMargin,ATop,aWidth-2*BevelMargin,BevelHeight);
if Hidden then
Visible := False
else
Inc(ATop, BevelHeight);
end;
end;
procedure TLCLTaskDialog.AddFooter(var ALeft: Integer; var ATop: Integer; AFontHeight, AWidth: Integer; APArent: TWinControl);
//ALeft must be adjusted by AddFooter if FooterIcon exists, so that we can left-align
//ExpandedText in the Footer area with the FooterText (in case of tfExpandFooterArea)
var
aFooterIcon: TTaskDialogIcon;
begin
//debugln(['AddFooterText: XB=',XB]);
AddBevel(ATop, aWidth, AParent);
inc(ATop,LabelVSPacing div 2);
FooterImage := nil;
if not (tfUseHIconFooter in FDlg.Flags) then
begin
aFooterIcon := FDlg.FooterIcon;
if (LCL_IMAGES[aFooterIcon]<>0) then
begin
FooterImage := TImage.Create(Self);
FooterImage.Parent := AParent;
FooterImage.Images := DialogGlyphs;
FooterImage.ImageWidth := SmallImageSize;
FooterImage.ImageIndex := DialogGlyphs.DialogIcon[LCL_IMAGES[aFooterIcon]];
end;
end
else
begin
if Assigned(FDlg.CustomFooterIcon) and not (FDlg.CustomFooterIcon.Empty) then
begin
FooterImage := TImage.Create(Self);
FooterImage.Parent := AParent;
FooterImage.ImageWidth := SmallImageSize;
FooterImage.Picture.Assign(FDlg.CustomFooterIcon);
end;
end;
if Assigned(FooterImage) then
begin
FooterImage.Stretch := True;
FooterImage.StretchOutEnabled := False;
FooterImage.Proportional := True;
FooterImage.Center := True;
FooterImage.SetBounds(GlobalLeftMargin,ATop,SmallImageSize,SmallImageSize);
ALeft := GlobalLeftMargin + Aleft + FooterImage.Width;
end;
Element[tdeFooter] := AddLabel(FooterText, False, ALeft, ATop, AFontHeight, AWidth, AParent);
Dec(ATop, LabelVSpacing div 2);
end;
function TLCLTaskDialog.AddLabel(const AText: string; BigFont: Boolean; const ALeft: Integer; var ATop: Integer; AFontHeight,
AWidth: Integer; APArent: TWinControl; Hidden: Boolean = False): TLabel;
var
R: TRect;
W: integer;
begin
//debugln(['TLCLTaskDialog.AddLabel A: AText=',AText,',X=',ALeft,', AParent=',DbgSName(AParent),', AParent.Width=',AParent.Width,', Self.Width=',Self.Width]);
if (AText = '') then
Exit(nil);
Result := TLabel.Create(Self);
Result.WordWrap := True;
if BigFont then
begin
if (tfEmulateClassicStyle in FDlg.Flags) then
begin
Result.Font.Height := AFontHeight-2;
Result.Font.Style := [fsBold]
end
else
begin
Result.Font.Height := AFontHeight-4;
Result.Font.Color := clHighlight;
end;
end
else
Result.Font.Height := AFontHeight;
Result.AutoSize := False;
R.Left := 0;
R.Top := 0;
W := aWidth-ALeft-GlobalLeftMargin;
R.Right := W;
R.Bottom := Result.Height;
Result.Caption := AText;
Result.Parent := AParent;
LCLIntf.DrawText(Result.Canvas.Handle,PChar(AText),Length(AText),R,DT_CALCRECT or DT_WORDBREAK);
Result.SetBounds(ALeft,ATop,W,R.Bottom);
if not Hidden then
inc(ATop,R.Bottom+LabelVSpacing)
else
Result.Visible := False;
//else
// ExpandHeightRequired := R.Bottom+LabelVSpacing;
//debugln(['TLCLTaskDialog.AddLabel End: X=',ALeft,', Result.Left=',Result.Left]);
end;
procedure TLCLTaskDialog.AddQueryCombo(const ALeft: Integer; var ATop: Integer; AWidth: Integer; AParent: TWinControl);
begin
QueryCombo := TComboBox.Create(Self);
with QueryCombo do
begin
Items.Assign(FDlg.QueryChoices);
if (CommandLinkButtonWidth > 0) then
SetBounds(ALeft,ATop,CommandLinkButtonWidth,ComboBoxHeight) //right align with the buttons
else
SetBounds(ALeft,ATop,aWidth-2*GlobalLeftMargin-ALeft,ComboBoxHeight);
if (tfQueryFixedChoices in FDlg.Flags) then
Style := csDropDownList
else
Style := csDropDown;
if (FDlg.QueryItemIndex >= 0) and (FDlg.QueryItemIndex < FDlg.QueryChoices.Count) then
ItemIndex := FDlg.QueryItemIndex
else
begin
if (tfQueryFixedChoices in FDlg.Flags) then
ItemIndex := 0
else
ItemIndex := -1;
end;
Parent := AParent;
end;
inc(ATop,42);
end;
procedure TLCLTaskDialog.AddQueryEdit(var X, Y: Integer; AWidth: Integer; AParent: TWinControl);
begin
QueryEdit := TEdit.Create(Self);
with QueryEdit do
begin
if (CommandLinkButtonWidth > 0) then
SetBounds(X,Y,CommandLinkButtonWidth,QueryEditHeight) //right align with the buttons
else
SetBounds(X,Y,aWidth-16-X,22);
Text := FDlg.SimpleQuery;
PasswordChar := FDlg.SimpleQueryPasswordChar;
Parent := AParent;
end;
inc(Y,42);
end;
procedure TLCLTaskDialog.OnExpandButtonClicked(Sender: TObject);
begin
if not FExpanded then
ExpandDialog
else
CollapseDialog;
FExpanded := not FExpanded;
{$PUSH}
{$ObjectChecks OFF}
{%H-}TTaskDialogAccess(FDlg).DoOnExpandButtonClicked(FExpanded);
{$POP}
end;
procedure TLCLTaskDialog.OnTimer(Sender: TObject);
var
AResetTimer: Boolean;
MSecs: Cardinal;
MSecs64: Int64;
begin
MSecs64 := MilliSecondsBetween(Now, TimerStartTime);
{$PUSH}{$R-}
MSecs := MSecs64;
{$POP}
AResetTimer := False;
{$PUSH}
{$ObjectChecks OFF}
{%H-}TTaskDialogAccess(FDlg).DoOnTimer(MSecs, AResetTimer);
{$POP}
if AResetTimer then
ResetTimer;
end;
procedure TLCLTaskDialog.DoOnHelp;
begin
{$PUSH}
{$ObjectChecks OFF}
{%H-}TTaskDialogAccess(FDlg).DoOnHelp;
{$POP}
end;
procedure TLCLTaskDialog.OnRadioButtonClick(Sender: TObject);
var
ButtonID: Integer;
begin
ButtonID := (Sender as TRadioButton).Tag;
{$PUSH}
{$ObjectChecks OFF}
{%H-}TTaskDialogAccess(FDlg).DoOnRadioButtonClicked(ButtonID);
{$POP}
end;
procedure TLCLTaskDialog.SetupTimer;
begin
Timer := TTimer.Create(Self);
Timer.Interval := 200; //source: https://learn.microsoft.com/en-us/windows/win32/controls/tdn-timer
Timer.OnTimer := @OnTimer;
TimerStartTime := Now;
Timer.Enabled := True;
end;
procedure TLCLTaskDialog.ResetTimer;
begin
Timer.Enabled := False;
TimerStartTime := Now;
Timer.Enabled := True;
end;
procedure TLCLTaskDialog.ExpandDialog;
begin
ExpandBtn.Caption := CollapseButtonCaption;
if not (tfExpandFooterArea in FDlg.Flags) then
begin
Element[tdeExpandedInfo].Parent.Height := Element[tdeExpandedInfo].Parent.Height + ExpandHeightRequired;
Height := Height + ExpandHeightRequired;
Element[tdeExpandedInfo].Visible := True;
end
else
begin
Height := Height + ExpandHeightRequired;
ExpandedTextBevel.Visible := True;
Element[tdeExpandedInfo].Visible := True;
end;
end;
procedure TLCLTaskDialog.CollapseDialog;
begin
ExpandBtn.Caption := ExpandButtonCaption;
if not (tfExpandFooterArea in FDlg.Flags) then
begin
Element[tdeExpandedInfo].Visible := False;
Element[tdeExpandedInfo].Parent.Height := Element[tdeExpandedInfo].Parent.Height - ExpandHeightRequired;
Height := Height - ExpandHeightRequired;
end
else
begin
ExpandedTextBevel.Visible := False;
Element[tdeExpandedInfo].Visible := False;
Height := Height - ExpandHeightRequired;
end;
end;
function TLCLTaskDialog.FindButtonByButtonID(ID: Integer): TCustomButton;
var
i: Integer;
Btn: TCustomButton;
begin
Result := nil;
for i := 0 to ComponentCount -1 do
begin
if (Components[i] is TCustomButton) then
begin
Btn := TCustomButton(Components[i]);
if (Btn.ModalResult = ID) then
begin
Result := Btn;
Break;
end;
end;
end;
end;
function TLCLTaskDialog.FindRadioButtonByButtonID(ID: Integer): TRadioButton;
var
i: Integer;
begin
Result := nil;
for i := Low(RadioButtonArray) to High(RadioButtonArray) do
begin
if (RadioButtonArray[i].Tag = ID) then
begin
Result := RadioButtonArray[i];
Break;
end;
end;
end;
procedure TLCLTaskDialog.DoDialogConstructed;
begin
{$PUSH}
{$ObjectChecks OFF}
{%H-}TTaskDialogAccess(FDlg).InternalSetDialogHandle(Handle);
{%H-}TTaskDialogAccess(FDlg).DoOnDialogConstructed;
{$POP}
end;
procedure TLCLTaskDialog.DoDialogCreated;
begin
{$PUSH}
{$ObjectChecks OFF}
{%H-}TTaskDialogAccess(FDlg).DoOnDialogCreated;
{$POP}
end;
procedure TLCLTaskDialog.DoDialogDestroyed;
begin
{$PUSH}
{$ObjectChecks OFF}
{%H-}TTaskDialogAccess(FDlg).DoOnDialogDestroyed;
{$POP}
end;
procedure TLCLTaskDialog.OnVerifyClicked(Sender: TObject);
begin
{$PUSH}
{$ObjectChecks OFF}
{%H-}TTaskDialogAccess(FDlg).DoOnverificationClicked(VerifyCheckBox.Checked);
{$POP}
end;
procedure TLCLTaskDialog.OnButtonClicked(Sender: TObject);
var Btn: TButton absolute Sender;
CanClose: Boolean;
begin
CanClose := True;
{$PUSH}
{$ObjectChecks OFF}
{%H-}TTaskDialogAccess(FDlg).DoOnButtonClicked(FDlg.ButtonIDToModalResult(Btn.ModalResult), CanClose);
{$POP}
if not CanClose then
ModalResult := mrNone
end;
procedure TLCLTaskDialog.SetupControls;
var
aRadioDef, aButtonDef: TModalResult;
B: TTaskDialogBaseButtonItem;
ButtonID: Integer;
ARadioOffset, FontHeight, aWidth, ALeft {Left for controls aligned right to the icon, so on top 2 panels},
ATop, i, XB: integer;
CurrParent: TWinControl;
aDialogIcon: TLCLTaskDialogIcon;
CommandLink: TBitBtn;
aHint: String;
List: TStringListUTF8Fast;
Btn: TTaskDialogCommonButton;
CustomButtonsTextLength: Integer;
begin
DisableAutoSizing;
try
GetDefaultButtons(aButtonDef, aRadioDef);
CustomButtonsTextLength := 0;
for B in FDlg.Buttons do
CustomButtonsTextLength := CustomButtonsTextLength + Length(B.Caption);
InitCaptions;
FVerifyChecked := (tfVerificationFlagChecked in FDlg.Flags);
CommonButtons := FDlg.CommonButtons;
if (CommonButtons=[]) and (FDlg.Buttons.Count=0) then
begin
CommonButtons := [tcbOk];
if (aButtonDef = 0) then
aButtonDef := mrOk;
end;
InitGlobalDimensionsAndStyle(CustomButtonsTextLength, aWidth, FontHeight);
Caption := DialogCaption;
AddPanels;
CurrParent := TopPanel;
// handle main dialog icon
GlobalLeftMargin := GetGlobalLeftMargin;
AddMainIcon(ALeft, ATop, GlobalLeftMargin, CurrParent);
//debugln('SetupControls');
//debugln([' GlobalLeftMargin=',GlobalLeftMargin]);
//debugln([' ALeft=',ALeft]);
//debugln([' ATop=',ATop]);
// add main texts (DlgTitle, DlgText, Information)
Element[tdeMainInstruction] := AddLabel(DlgTitle, True, ALeft, ATop, FontHeight, aWidth, CurrParent);
Element[tdeContent] := AddLabel(DlgText, False, ALeft, ATop, FontHeight, aWidth, CurrParent);
if (ExpandedText <> '') and not (tfExpandFooterArea in FDlg.Flags) then
begin
Element[tdeExpandedInfo] := AddLabel(ExpandedText, False, ALeft, ATop, FontHeight, aWidth, CurrParent, not (tfExpandedByDefault in Fdlg.Flags));
ExpandHeightRequired := Element[tdeExpandedInfo].Height + LabelVSPacing;
//debugln(['ExpandHeightRequired=',ExpandHeightRequired]);
end;
TopPanel.Height := ATop;
CurrParent := MidPanel;
ATop := 0;
//Add ProgressBar
if ([tfShowProgressBar,tfShowMarqueeProgressBar] * FDlg.Flags <> []) then
AddProgressBar(ALeft, ATop, AWidth, CurrParent);
// add radio CustomButtons
if (FDlg.RadioButtons.Count > 0) then
begin
ARadioOffset := 1;
AddRadios(ARadioOffSet, aWidth, aRadioDef, FontHeight, ALeft, ATop, CurrParent);
end;
// add command links CustomButtons
if (tfUseCommandLinks in FDlg.Flags) and (FDlg.Buttons.Count<>0) then
AddCommandLinkButtons(ALeft, ATop, aWidth, aButtonDef, FontHeight, CurrParent);
// add query combobox list or QueryEdit
if (tfQuery in FDlg.Flags) and (FDlg.QueryChoices.Count > 0) then
AddQueryCombo(ALeft, ATop, aWidth, CurrParent)
else
begin
if (tfSimpleQuery in FDlg.Flags) and (FDlg.SimpleQuery <> '') then
AddQueryEdit(ALeft, ATop, aWidth, CurrParent);
end;
MidPanel.Height := ATop;
if MidPanel.ControlCount = 0 then
MidPanel.Visible := False;
CurrParent := BottomPanel;
ATop := 0;
XB := 0;
//ALeft := GlobalLeftMargin; //Left most margin of the form
// add CustomButtons and verification checkbox
if (CommonButtons <> []) or
((FDlg.Buttons.Count<>0) and not (tfUseCommandLinks in FDlg.Flags)) then
begin
AddButtons(GlobalLeftMargin, ATop, XB, aWidth, aButtonDef, CurrParent);
end;
//Add Expand button
if (ExpandedText <> '') then
AddExpandButton(GlobalLeftMargin, ATop, XB, aWidth, CurrParent);
FExpanded := (ExpandedText <> '') and (tfExpandedByDefault in FDlg.Flags);
if (VerificationText <> '') then
AddCheckBox(GlobalLeftMargin, ATop, XB, aWidth, CurrParent);
inc(ATop,36);
// add FooterText text with optional icon
if (FooterText <> '') then
begin
ALeft := GlobalLeftMargin;
AddFooter(ALeft, ATop, FontHeight, aWidth, CurrParent);
end;
if (ExpandedText <> '') and (tfExpandFooterArea in FDlg.Flags) then
begin
ExpandedTextBevel := AddBevel(ATop, aWidth, CurrParent, not FExpanded);
Inc(ATop, LabelVSpacing div 2);
Element[tdeExpandedInfo] := AddLabel(ExpandedText, False, ALeft, ATop, FontHeight, aWidth, CurrParent, not FExpanded);
ExpandHeightRequired := Element[tdeExpandedInfo].Height + BevelHeight + (LabelVSPacing {div 2});
//debugln(['ExpandHeightRequired=',ExpandHeightRequired]);
//if not FExpanded then
Dec(ATop, LabelVSpacing div 2);
end;
ClientHeight := TopPanel.Height + MidPanel.Height + ATop;
if (tfCallBackTimer in FDlg.Flags) then
SetupTimer;
//AddButtons (which comes after adding query) may have set ActiveControl
//so do this here and not in AddQueryCombo or AddQueryEdit
if Assigned(QueryCombo) and (tfQueryFocused in FDlg.Flags) then
ActiveControl := QueryCombo
else
if Assigned(QueryEdit) and (tfQueryFocused in FDlg.Flags) then
ActiveControl := QueryEdit;
finally
EnableAutoSizing;
end;
end;
procedure TLCLTaskDialog.KeyDown(var Key: Word; Shift: TShiftState);
begin
if (biSystemMenu in BorderIcons) then//is Alt+F4/Esc cancellation allowed?
begin//yes -> cancel on ESC
if Key = VK_ESCAPE then
Close;
end else
begin//no -> block Alt+F4
if (Key = VK_F4) and (ssAlt in Shift) then//IMPORTANT: native task dialog blocks Alt+F4 to close the dialog -> we have to block it as well
Key := 0;
end;
if (Key = VK_F1) and (Shift = []) then
begin
Key := 0;
DoOnHelp;
end;
inherited KeyDown(Key, Shift);
end;
{ ------------- message handling ------------}
procedure TLCLTaskDialog.SetProgressBarType(var Msg: TLMessage);
begin
// wParam: TRUE turns on marquee mode, FALSE turns off marquee mode.
// lParam: Must be zero.
// The return value is ignored
LazLoggerBase.debugln(['TLCLTaskDialog.SetProgressBarType']);
LazLoggerBase.debugln([' Msg.wParam=',Msg.wParam]);
LazLoggerBase.debugln([' Msg.lParam=',Msg.lParam]);
//if both tfShowMarqueeProgressBar and tfShowProgressBar are set, user can switch ProgressBar.Style
if Assigned(ProgressBar) and (Msg.lParam = 0) then
begin
if BOOL(Msg.wParam) then
begin
if (tfShowMarqueeProgressBar in FDlg.Flags) then
begin
LazLoggerBase.Debugln('TLCLTaskDialog.SetProgressBarType: set pbstMarquee');
ProgressBar.Style := pbstMarquee;
end;
end
else
begin
if (tfShowProgressBar in FDlg.Flags) then
begin
LazLoggerBase.Debugln('TLCLTaskDialog.SetProgressBarType: set pbstNormal');
ProgressBar.Style := pbstNormal;
end;
end;
end;
end;
procedure TLCLTaskDialog.SetProgressBarRange(var Msg: TLMessage);
var
OldMin, OldMax: Integer;
begin
// wParam: must be zero
// lParam: The LOWORD specifies the minimum value. The HIWORD specifies the maximum value.
// Returns the previous range if sucessfull, zero otherwise
LazLoggerBase.debugln(['TLCLTaskDialog.SetProgressBarRange']);
LazLoggerBase.debugln([' Msg.wParam=',Msg.wParam]);
LazLoggerBase.debugln([' Msg.lParam LoWord=',LParamLoWord(Msg.lParam)]);
LazLoggerBase.debugln([' Msg.lParam HiWord=',LParamHiWord(Msg.lParam)]);
if Assigned(ProgressBar) and (Msg.wParam = 0) then
begin
OldMin := ProgressBar.Min;
OldMax := ProgressBar.Max;
ProgressBar.Min := LParamLoWord(Msg.lParam);
ProgressBar.Max := LParamHiWord(Msg.lParam);
Msg.Result := MAKELPARAM(OldMin,OldMax);
end
else
Msg.Result := 0;
end;
procedure TLCLTaskDialog.SetProgressBarPos(var Msg: TLMessage);
var
OldPos: Integer;
begin
// wParam: An int that specifies the new position.
// lParam: Must be zero
// Returns the previous position
LazLoggerBase.debugln(['TLCLTaskDialog.SetProgressBarPos']);
LazLoggerBase.debugln([' Msg.wParam=',(Msg.wParam)]);
LazLoggerBase.debugln([' Msg.lParam=',(Msg.lParam)]);
if Assigned(ProgressBar) and (Msg.lParam = 0) then
begin
OldPos := ProgressBar.Position;
ProgressBar.Position := Msg.wParam;
Msg.Result := OldPos;
end
else
Msg.Result := 0;
end;
procedure TLCLTaskDialog.ClickVerification(var Msg: TLMessage);
begin
// wParam: TRUE to set the state of the checkbox to be checked; FALSE to set it to be unchecked.
// lParam TRUE to set the keyboard focus to the checkbox; FALSE otherwise.
// Return value is ignored
LazLoggerBase.debugln('TLCLTaskDialog.ClickVerification');
LazLoggerBase.debugln([' Msg.wParam=',(Msg.wParam)]);
LazLoggerBase.debugln([' Msg.lParam=',(Msg.lParam)]);
if Assigned(VerifyCheckBox) then
begin
VerifyCheckBox.Checked := BOOL(Msg.wParam);
if BOOL(Msg.lParam) then
if VerifyCheckBox.CanSetFocus then
VerifyCheckBox.SetFocus;
end;
end;
procedure TLCLTaskDialog.ClickButton(var Msg: TLMessage);
var
i: Integer;
Btn: TCustomButton;
BitBtn: TBitBtn;
begin
// wParam: An int value that specifies the ID of the button to be clicked.
// lParam: Must be zero.
// Return value is ignored
LazLoggerBase.debugln('TLCLTaskDialog.ClickButton');
LazLoggerBase.debugln([' Msg.wParam=',(Msg.wParam)]);
LazLoggerBase.debugln([' Msg.lParam=',(Msg.lParam)]);
if (Msg.lPARAM = 0) then
begin
Btn := FindButtonByButtonID(Msg.wParam);
if Assigned(Btn) and Btn.Enabled then
Btn.Click;
end;
end;
procedure TLCLTaskDialog.ClickRadioButton(var Msg: TLMessage);
var
i: Integer;
RadioBtn: TRadioButton;
begin
// wParam: An int value that specifies the ID of the radio button to be clicked.
// lParam: Must be zero.
// Return value is ignored
LazLoggerBase.debugln('TLCLTaskDialog.ClickRadioButton');
LazLoggerBase.debugln([' Msg.wParam=',(Msg.wParam)]);
LazLoggerBase.debugln([' Msg.lParam=',(Msg.lParam)]);
if (Msg.lParam = 0) and (FDlg.RadioButtons.Count > 0) then
begin
RadioBtn := FindRadioButtonByButtonID(Msg.wParam);
if Assigned(RadioBtn) and (RadioBtn.Enabled) then
RadioBtn.Checked := True;
end;
end;
procedure TLCLTaskDialog.EnableButton(var Msg: TLMessage);
var
Btn: TCustomButton;
begin
// wParam: An int value that specifies the ID of the button to be enabled/disabled.
// lParam: 0: disable the button, otherwise enable
// Return value is ignored
LazLoggerBase.debugln('TLCLTaskDialog.EnableButton');
LazLoggerBase.debugln([' Msg.wParam=',(Msg.wParam)]);
LazLoggerBase.debugln([' Msg.lParam=',(Msg.lParam)]);
Btn := FindButtonByButtonID(Msg.wParam);
if Assigned(Btn) then
Btn.Enabled := (Msg.lParam <> 0);
end;
procedure TLCLTaskDialog.EnableRadioButton(var Msg: TLMessage);
var
RadioBtn: TRadioButton;
begin
// wParam: An int value that specifies the ID of the radio button to be enabled/disabled.
// lParam: 0: disable the button, otherwise enable
// Return value is ignored
LazLoggerBase.debugln('TLCLTaskDialog.EnableRadioButton');
LazLoggerBase.debugln([' Msg.wParam=',(Msg.wParam)]); //ID of radiobutton
LazLoggerBase.debugln([' Msg.lParam=',(Msg.lParam)]); //must be 0
RadioBtn := FindRadioButtonByButtonID(Msg.wParam);
if Assigned(RadioBtn) then
RadioBtn.Enabled := (Msg.lParam <> 0);
end;
procedure TLCLTaskDialog.UpdateElementText(var Msg: TLMessage);
var
NewText: String;
Lbl: TLabel;
//ARect: TRect;
begin
// wParam: Indicates the element to update.
// lParam: Pointer to a Unicode string that contains the new text.
// Return value is ignored.
LazLoggerBase.debugln('TLCLTaskDialog.UpdateElementText');
LazLoggerBase.debugln([' Msg.wParam=',(Msg.wParam)]);
LazLoggerBase.debugln([' Msg.lParam=',(Msg.lParam)]);
NewText := Utf16ToUtf8(Unicodestring(PWideChar(Msg.lParam)));
LazLoggerBase.debugln(' NewText=',NewText);
//It seems to be that the native Vista+ dialog does not adjust heights (properly),
//if new label height is bigger, then e.g. FooterText may end up falling off the dialog...
// ToDo: do this properly:
// - calculate new BoundsRect, adjust height of panles and dialog and reserved height for expanding
if (Msg.wParam in [TDE_CONTENT..TDE_MAIN_INSTRUCTION]) then
begin
case Msg.wParam of
TDE_CONTENT: //FDlg.Text;
begin
Lbl := Element[tdeContent];
//ARect := Lbl.BoundsRect;
if Assigned(lbl) then Lbl.Caption := NewText;
end;
TDE_EXPANDED_INFORMATION: //FDlg.ExpandedText
begin
Lbl := Element[tdeExpandedInfo];
if Assigned(lbl) then Lbl.Caption := NewText;
end;
TDE_FOOTER: //FDlg.FooterText
begin
Lbl := Element[tdeFooter];
if Assigned(lbl) then Lbl.Caption := NewText;
end;
TDE_MAIN_INSTRUCTION: //FDlg.Title
begin
Lbl := Element[tdeMainInstruction];
if Assigned(lbl) then Lbl.Caption := NewText;
end;
end;
end;
end;
{ ------------- end message handling ------------}
finalization
if assigned(LDefaultFont) then
LDefaultFont.Free;
end.