I just did it, partially thanks to ChatGPT for giving me tips and code examples at related syntax and usage questions that I had while I was trying to figure out how to achieve this in a simple way (that is, avoiding to declare and set up all of the controls by myself). And of course, thanks to the Support Classes Reference which helped me more than the AI.
It was very tedious to analyze all the docs and code examples, but at the end it was more easy to put all this in practice than what I thought at first sight.
Note that maybe the control-positioning is not perfect because I'm not sure how to use "ScaleX" "ScaleY" properly, but hey, it seems to work fine for me with my screen DPI.
Here we go:
[Code]
Var
CustomSelectDirPage: TWizardPage;
...
function IsCreateDesktopIconChecked(): Boolean;
var
DesktopShortcutCheckBox: TNewCheckBox;
Page: TWizardPage;
begin
Page := PageFromID(CustomSelectDirPage.ID);
DesktopShortcutCheckBox := TNewCheckBox(Page.Surface.Controls[12])
Result := DesktopShortcutCheckBox.Checked;
end;
function CustomSelectDirPageNextButtonClick(Sender: TWizardPage): Boolean;
var
DirExistsWarning: String;
FDirEdit: TEdit;
begin
Result := True;
FDirEdit := TEdit(Sender.Surface.Controls[4]);
DirExistsWarning := LowerCase('{#SetupSetting("DirExistsWarning")}'); // "auto", "true" or "false"
if (DirExistsWarning = 'true') and (DirExists(ExpandConstant(FDirEdit.Text))) then
begin
if MsgBox('The Folder:' + #13#10#13#10 + ExpandConstant(FDirEdit.Text) + #13#10#13#10 +
'already exists. Would you like to install to that folder anyway?', mbConfirmation, MB_YESNO) = IDNO then
Result := false;
end;
end;
procedure CreateCustomSelectDirPage();
var
WizardStyle: String;
// Pages
ThisPage: TWizardPage;
SelectDirPage: TWizardPage;
SelectProgramGroupPage: TWizardPage;
// Custom Controls
DesktopShortcutCheckBox: TNewCheckBox;
// wpSelectDir Controls
FSelectDirBitmapImage: TBitmapImage;
FDiskSpaceLabel: TNewStaticText;
FDirBrowseButton: TButton;
FDirEdit: TEdit;
FSelectDirBrowseLabel: TNewStaticText;
FSelectDirLabel: TNewStaticText;
// wpSelectProgramGroup Controls
FSelectGroupBitmapImage: TBitmapImage;
FNoIconsCheck: TCheckBox;
FGroupBrowseButton: TButton;
FGroupEdit: TEdit;
FSelectStartMenuFolderBrowseLabel: TNewStaticText;
FSelectStartMenuFolderLabel: TNewStaticText;
begin
WizardStyle := LowerCase('{#SetupSetting("WizardStyle")}'); // "classic" or "modern"
// Pages
SelectDirPage := PageFromID(wpSelectDir);
SelectProgramGroupPage := PageFromID(wpSelectProgramGroup);
ThisPage := CreateCustomPage(wpInfoBefore, SelectDirPage.Caption + ' | ' + SelectProgramGroupPage.Caption,
SelectDirPage.Description + #13#10 + SelectProgramGroupPage.Description);
CustomSelectDirPage := ThisPage
// wpSelectDir Control References
FSelectDirBitmapImage := TBitmapImage(SelectDirPage.Surface.Controls[0]);
FDiskSpaceLabel := TNewStaticText(SelectDirPage.Surface.Controls[1]);
FDirBrowseButton := TButton(SelectDirPage.Surface.Controls[2]);
FDirEdit := TEdit(SelectDirPage.Surface.Controls[3]);
FSelectDirBrowseLabel := TNewStaticText(SelectDirPage.Surface.Controls[4]);
FSelectDirLabel := TNewStaticText(SelectDirPage.Surface.Controls[5]);
// wpSelectDir Control Parenting
FSelectDirBitmapImage.Parent := ThisPage.Surface;
FDiskSpaceLabel.Parent := ThisPage.Surface;
FDirBrowseButton.Parent := ThisPage.Surface;
FDirEdit.Parent := ThisPage.Surface;
FSelectDirBrowseLabel.Parent := ThisPage.Surface;
FSelectDirLabel.Parent := ThisPage.Surface;
// wpSelectDir Control Positioning
if WizardStyle = 'classic' then
begin
FSelectDirBrowseLabel.Visible := False;
FDirEdit.Top := FSelectDirLabel.Top + 30;
FDirBrowseButton.Top := FDirEdit.Top;
end;
// wpSelectProgramGroup Control References
FSelectGroupBitmapImage := TBitmapImage(PageFromID(wpSelectProgramGroup).Surface.Controls[0])
FNoIconsCheck := TCheckBox(PageFromID(wpSelectProgramGroup).Surface.Controls[1])
FGroupBrowseButton := TButton(PageFromID(wpSelectProgramGroup).Surface.Controls[2])
FGroupEdit := TEdit(PageFromID(wpSelectProgramGroup).Surface.Controls[3])
FSelectStartMenuFolderBrowseLabel := TNewStaticText(PageFromID(wpSelectProgramGroup).Surface.Controls[4])
FSelectStartMenuFolderLabel := TNewStaticText(PageFromID(wpSelectProgramGroup).Surface.Controls[5])
// wpSelectProgramGroup Control Parenting
FSelectGroupBitmapImage.Parent := ThisPage.Surface;
FSelectStartMenuFolderLabel.Parent := ThisPage.Surface;
FSelectStartMenuFolderBrowseLabel.Parent := ThisPage.Surface;
FGroupEdit.Parent := ThisPage.Surface;
FGroupBrowseButton.Parent := ThisPage.Surface;
FNoIconsCheck.Parent := ThisPage.Surface;
// wpSelectProgramGroup Control Positioning
if WizardStyle = 'modern' then
begin
FSelectGroupBitmapImage.Top := FDirEdit.Top + 70;
FSelectStartMenuFolderLabel.Top := FSelectGroupBitmapImage.Top + 10;
FSelectStartMenuFolderBrowseLabel.Top := FSelectStartMenuFolderLabel.Top + 35;
FGroupEdit.Top := FSelectStartMenuFolderBrowseLabel.Top + 20;
FGroupBrowseButton.Top := FGroupEdit.Top;
FNoIconsCheck.Top := FGroupEdit.Top - 42;
end
else
begin
FSelectStartMenuFolderBrowseLabel.Visible := False;
FSelectGroupBitmapImage.Top := FDirEdit.Top + 70;
FSelectStartMenuFolderLabel.Top := FSelectGroupBitmapImage.Top + 10;
FGroupEdit.Top := FSelectStartMenuFolderLabel.Top + 30;
FGroupBrowseButton.Top := FGroupEdit.Top;
FNoIconsCheck.Top := FGroupEdit.Top + 28;
end;
// Custom Controls
DesktopShortcutCheckBox := TNewCheckBox.Create(ThisPage);
DesktopShortcutCheckBox.Parent := ThisPage.Surface;
DesktopShortcutCheckBox.Top := FDirEdit.Top + 30;
DesktopShortcutCheckBox.Caption := CustomMessage('CreateDesktopIcon');
DesktopShortcutCheckBox.Checked := True;
DesktopShortcutCheckBox.Width := FNoIconsCheck.Width;
ThisPage.OnNextButtonClick := @CustomSelectDirPageNextButtonClick;
end;
Note that you should set these directives like this:
DisableDirPage=True
DisableProgramGroupPage=True
And this is the resulting custom wizard page. It even looks better than FitGirl installers (without considering the missing additional buttons on the bottom bar in comparison):

UPDATE 1
I've updated the code above to also make it work properly on classic setup mode (WizardStyle=Classic
), this is the resulting visual aspect:

UPDATE 2
I've updated again the code above to implement the functionality of the "Create a desktop shortcut" checkbox, and also to react to the DirExistsWarning
directive setting in the custom wizard page.