Skip Inno Setup custom page, unless specific radio button is selected on previous page - inno-setup

I have code which is used for custom installation using Inno Setup. In this I have two radio buttons on a custom page. If user selects the first radio button, it should show another custom page with user input text box and text to be save in file. If user select the other radio button, the other custom page should not show.
Here is my code
[Code]
var
FullRadioButton: TNewRadioButton;
PartRadioButton: TNewRadioButton;
CustomPage: TWizardPage;
UserInputsPage: TInputQueryWizardPage;
FullDescLabel: TLabel;
PartDescLabel: TLabel;
url: String;
const
FullDescText ='Full Installation.';
PartDescText ='Partial Installation.';
procedure InitializeWizard;
begin
CustomPage := CreateCustomPage(wpWelcome, 'Installation type', '');
FullRadioButton := TNewRadioButton.Create(WizardForm);
FullRadioButton.Parent := CustomPage.Surface;
FullRadioButton.Top := 16;
FullRadioButton.Width := CustomPage.SurfaceWidth;
FullRadioButton.Font.Style := [fsBold];
FullRadioButton.Font.Size := 9;
FullRadioButton.Caption := 'Default Installation'
FullDescLabel := TLabel.Create(WizardForm);
FullDescLabel.Parent := CustomPage.Surface;
FullRadioButton.Checked := True;
FullDescLabel.Left := 8;
FullDescLabel.Top := FullRadioButton.Top + FullRadioButton.Height + 8;
FullDescLabel.Width := CustomPage.SurfaceWidth;
FullDescLabel.Height := 40;
FullDescLabel.AutoSize := False;
FullDescLabel.Wordwrap := True;
FullDescLabel.Caption := FullDescText;
PartRadioButton := TNewRadioButton.Create(WizardForm);
PartRadioButton.Parent := CustomPage.Surface;
//PartRadioButton.Checked := True
PartRadioButton.Top := FullDescLabel.Top + FullDescLabel.Height + 16;
PartRadioButton.Width := CustomPage.SurfaceWidth;
PartRadioButton.Font.Style := [fsBold];
PartRadioButton.Font.Size := 9;
PartRadioButton.Caption := 'Custom Installation'
PartDescLabel := TLabel.Create(WizardForm);
PartDescLabel.Parent := CustomPage.Surface;
PartDescLabel.Left := 8;
PartDescLabel.Top := PartRadioButton.Top + PartRadioButton.Height + 8;
PartDescLabel.Width := CustomPage.SurfaceWidth;
PartDescLabel.Height := 40;
PartDescLabel.AutoSize := False;
PartDescLabel.Wordwrap := True;
PartDescLabel.Caption := PartDescText;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
if (PartRadioButton.Checked) then
UserInputsPage := CreateInputQueryPage(wpWelcome,
'Url information', 'Url',
'Please specify the following informat, then click Next.');
UserInputsPage.Add('URL:', False);
UserInputsPage.Values[0] := ExpandConstant('');
if(CurPageID = UserInputsPage.ID) then;
begin
url := UserInputsPage.Values[0];
SaveStringToFile('path', 'user_input='+'"'+url+'"'+#13#10,True);
end;
Result := True;
end;
Please help me out
Thanks in advance!

Use TWizardPage.OnShouldSkipPage event (or ShouldSkipPage event function) to conditionally skip your custom page.
The custom page should better also be created (unconditionally) in the InitializeWizard, not in the NextButtonClick (the NextButtonClick can be called multiple times for the same page, if the user returns back).
Additionally, the UserInputsPage must show after the CustomPage. While you are currently constructing it to show before. For that, pass CustomPage.ID as the first argument of the CreateInputQueryPage.
function UserInputsPageShouldSkipPage(Sender: TWizardPage): Boolean;
begin
Result := not PartRadioButton.Checked;
end;
UserInputsPage :=
CreateInputQueryPage(
CustomPage.ID, 'Url information', 'Url',
'Please specify the following informat, then click Next.');
// ...
UserInputsPage.OnShouldSkipPage := #UserInputsPageShouldSkipPage;
Similar questions:
How to skip custom page based on setup type in Inno Setup
Skipping custom pages based on optional components in Inno Setup
Also, you should not do any changes to the user's system, before the user confirms the installation. So typically, you do not want call SaveStringToFile when user click Next on the custom page (not to mention again that it can happen multiple times, if user returns back). Better use CurStepChanged for ssInstall or ssPostInstall step.
And your NextButtonClick code is wrong anyway, due to the semicolon after the then. Effectively you call SaveStringToFile on each and every page of the wizard.

Related

I must declar instance name on page and dynamically block TEdit [duplicate]

I need a setup page with two radio buttons. Clicking the second button should enable an input to define a path (Like it's done in TInputDirWizardPage).
Is it possible to customize TInputDirWizardPage for my needs?
Or do I need to build a CustomPage and define the controls by myself?
If the second question will be answered with yes, how am I able to use the "directory input" (from the TInputDirWizardPage), or is it also neccessary to build this on my own?
As you correctly guessed you have several options:
Start with TWizardPage and build everything from scratch
Start with TInputDirWizardPage and add the radio buttons
Start with TInputOptionWizardPage and add the edit box
The second option probably involves least customization. Though it needs a hack from Is it possible to allow a user to skip a TInputDirWizardPage in Inno Setup?
{ WORKAROUND }
{ Checkboxes and Radio buttons created on runtime do }
{ not scale their height automatically. }
{ See https://stackoverflow.com/q/30469660/850848 }
procedure ScaleFixedHeightControl(Control: TButtonControl);
begin
Control.Height := ScaleY(Control.Height);
end;
var
Page: TInputDirWizardPage;
DefaultLocationButton: TRadioButton;
CustomLocationButton: TRadioButton;
OldNextButtonOnClick: TNotifyEvent;
procedure LocationButtonClick(Sender: TObject);
begin
Page.Edits[0].Enabled := CustomLocationButton.Checked;
Page.Buttons[0].Enabled := CustomLocationButton.Checked;
end;
procedure NextButtonOnClick(Sender: TObject);
var
PrevDir: string;
begin
{ Do not validate, when "default location" is selected }
if (WizardForm.CurPageID = Page.ID) and DefaultLocationButton.Checked then
begin
PrevDir := Page.Values[0];
Page.Values[0] := GetWinDir; { Force value to pass validation }
OldNextButtonOnClick(Sender);
Page.Values[0] := PrevDir;
end
else
begin
OldNextButtonOnClick(Sender);
end;
end;
procedure InitializeWizard();
begin
Page := CreateInputDirPage(
wpWelcome,
'Select Personal Data Location', 'Where should personal data files be stored?',
'', False, 'New Folder');
Page.Add('');
DefaultLocationButton := TRadioButton.Create(WizardForm);
DefaultLocationButton.Parent := Page.Surface;
DefaultLocationButton.Top := Page.Edits[0].Top;
DefaultLocationButton.Caption := 'Use default location';
DefaultLocationButton.Checked := True;
DefaultLocationButton.OnClick := #LocationButtonClick;
ScaleFixedHeightControl(DefaultLocationButton);
CustomLocationButton := TRadioButton.Create(WizardForm);
CustomLocationButton.Parent := Page.Surface;
CustomLocationButton.Top :=
DefaultLocationButton.Top + DefaultLocationButton.Height + ScaleY(8);
CustomLocationButton.Caption := 'Use custom location';
CustomLocationButton.OnClick := #LocationButtonClick;
ScaleFixedHeightControl(DefaultLocationButton);
Page.Buttons[0].Top :=
Page.Buttons[0].Top +
((CustomLocationButton.Top + CustomLocationButton.Height + ScaleY(8)) -
Page.Edits[0].Top);
Page.Edits[0].Top :=
CustomLocationButton.Top + CustomLocationButton.Height + ScaleY(8);
Page.Edits[0].Left := Page.Edits[0].Left + ScaleX(16);
Page.Edits[0].Width := Page.Edits[0].Width - ScaleX(16);
Page.Edits[0].TabOrder := CustomLocationButton.TabOrder + 1;
Page.Buttons[0].TabOrder := Page.Edits[0].TabOrder + 1;
LocationButtonClick(nil); { Update edit for initial state of buttons }
OldNextButtonOnClick := WizardForm.NextButton.OnClick;
WizardForm.NextButton.OnClick := #NextButtonOnClick;
end;
More general question on the topic: Inno Setup Placing image/control on custom page.

How to add a new page to Inno Setup OuterNotebook?

As part of an installer I'm working on using Inno Setup, I need to replicate the wpWelcome, page but with a different content. I've created a TNotebookPage, added the image, panel and content I want and it displays as expected. However I'm not sure how to add it to the WizardForm at the location I want. I can force it to appear as the first page, but clicking next/back shifts make the page disappear.
How do I insert the notebook page into the OuterNotebook at the relevant position?
function CreatePage: TNewNoteBookPage;
var
page: TNewNoteBookPage;
begin
page := TNewNoteBookPage.Create( WizardForm );
page.Notebook := WizardForm.OuterNotebook;
page.Align := alClient;
page.Color := clWindow;
page.Visible:= True;
Result := page;
end;
procedure InitializeWizard;
var
myPage: TNewNoteBookPage;
begin
WizardForm.OuterNotebook.ActivePage := WizardForm.WelcomePage;
myPage := CreatePage();
{ how do I specify where I want the page in the OuterNotebook? }
end;
In general, you specify a page position using TNewNotebookPage.PageIndex. But I'm afraid that by "manually" modifying the OuterNotebook you break an inner Inno Setup logic.
Why don't you just modify the existing Welcome page, instead of creating a new one?
See, for example, Custom Welcome and Finished page with stretched image in Inno Setup.
Alternatively, create a custom page on the InnerNotebook, but expand it to cover a whole window.
See How to hide the main panel and show an image over the whole page?
Martin's suggestions were very helpful, whilst not solving the problem directly they gave me an idea. I needed more than just a image covering the window. Hence my solution was to create a TNoteBookPage which I could format as needed and also a TWizardPage. Since the notebookpage couldn't be added to the installer without breaking inno-setup's ordering, I used the custom page to maintain ordering and when the CustomPage was set active, I switch the active page to be the notebook page hence showing what I needed.
[Code]
Apage, TWizardPage;
ANotebookPage: TNewNoteBookPage;
function CreatePage: TNewNoteBookPage;
var
page: TNewNoteBookPage;
sideBarImage: TBitmapImage;
panel: TPanel;
begin
{create page, sidebar and panel for our main content}
page := TNewNoteBookPage.Create( WizardForm );
page.Notebook := WizardForm.OuterNotebook;
page.Align := alClient;
page.Color := clWindow;
page.Visible:= True;
{ copies the already loaded sidebar image on the welcome page to this notebook page}
sideBarImage := TBitmapImage.Create( WizardForm );
sideBarImage.Bitmap := WizardForm.WizardBitmapImage.Bitmap;
sideBarImage.Top := WizardForm.WizardBitmapImage.Top;
sideBarImage.Left := WizardForm.WizardBitmapImage.Left;
sideBarImage.Width := WizardForm.WizardBitmapImage.Width;
sideBarImage.Height := WizardForm.WizardBitmapImage.Height;
sideBarImage.BackColor := WizardForm.WizardBitmapImage.BackColor;
sideBarImage.Parent := page;
panel := TPanel.Create( WizardForm );
panel.BevelOuter := bvNone;
panel.Color := clWindow;
panel.Parent := page;
panel.Left := sideBarImage.Width + ScaleX(10);
panel.Height := page.Height;
panel.Width := page.Width - sideBarImage.Width;
{ at this point we have a panel we can populate with content }
Result := page
end
procedure InitializeWizard;
begin
ANotebookPage := CreateOneClickInstallPage();
APage := CreateCustomPage( wpLicense, 'Install', '');
end
procedure CurPageChanged( CurPageID: Integer );
begin
WizardForm.Bevel1.Visible := true;
WizardForm.MainPanel.Visible := true;
WizardForm.InnerNotebook.Visible := true;
if CurPageID = APage.ID then begin
WizardForm.NextButton.Caption := SetupMessage(msgButtonInstall)
WizardForm.Bevel1.Visible := false;
WizardForm.MainPanel.Visible := false;
WizardForm.InnerNotebook.Visible := false;
WizardForm.OuterNotebook.ActivePage := ANoteBookPage;
end;
end

Avoid visual artifacts when initializing background (main) window

I try to change the default background image by my custom image.
I use this code:
procedure PrepareBackGround;
var
BackgroundBitmapImage: TBitmapImage;
TopLeftLabel: TLabel;
BitmapFileName: String;
sWidth,sHeight : integer;
begin
sWidth:=GetSystemMetrics(0);
sHeight:=GetSystemMetrics(1);
MainForm.Width := 848;
MainForm.height := 660;
MainForm.top := (sHeight-MainForm.height)/2;
MainForm.Left := (sWidth-MainForm.Width)/2;
BitmapFileName :=ExpandConstant('{src}\SetupFiles\FullScr.bmp');
BackgroundBitmapImage := TBitmapImage.Create(MainForm);
BackgroundBitmapImage.Bitmap.LoadFromFile(BitmapFileName);
BackgroundBitmapImage.Parent :=MainForm;
BackgroundBitmapImage.Align:=alCLient;
BackgroundBitmapImage.Stretch:=True;
TopLeftLabel := TLabel.Create(MainForm);
TopLeftLabel.Parent := MainForm;
TopLeftLabel.Left := 10;
TopLeftLabel.Top := 10 ;
TopLeftLabel.Font.Color := clBlack;
TopLeftLabel.color := clWhite;
TopLeftLabel.Font := WizardForm.WelcomeLabel1.Font;
TopLeftLabel.Font.Style := [fsitalic,fsBold];
TopLeftLabel.Caption :=
'SoftwareXXX ' +
GetIniString(
'Version Installation', 'Installation', 'unknown',
ExpandConstant('{src}\Sources\File.Ver'));
TopLeftLabel.WordWrap := WizardForm.WelcomeLabel1.WordWrap;
end;
procedure InitializeWizard;
begin
{ to display an image in background Window( see in Supportfunction.iss) }
PrepareBackGround;
{ ... }
end;
But when I run that, I see some lighting (as a flash). The reason of that light is the load of the new image.
How I can avoid this light? How can modify or access to the MainForm to modify the background image before it's displayed?
Thanks.
i can correct this falsh by :
[Setup]
WindowVisible=No
and i add at the end in my function
procedure PrepareBackGround;
var
//...
begin
//..
MainForm.Show;
end;
I believe the "flash", you refer to, is due to a resize of the maximized main window.
Try using WindowStartMaximized directive:
[Setup]
WindowStartMaximized=no
There's no event that is triggered before main window is shown, but after it is created.

Customize content of finish page in InnoSetup

I would like to customize my finish page so I can have radio controls for user to choose what action to apply after finish page.
I tried various methods such as
Page1 := CreateCustomPage(wpInfoAfter, 'test', 'test');
and
Page1 := CreateCustomPage(wpFinished, 'test', 'test');
but none of them gives the result I want.
Any help would be appreciated, thanks!
For customization of the existing page you have to add to your ISS script something like that:
From-scratch code, not compiled:
procedure CurPageChanged(CurPageID: Integer);
var
MyMsg: TLabel;
begin
if (CurPageID <> wpFinished) then return;
MyMsg := TLabel.Create(WizardForm);
MyMsg.Parent := WizardForm.FinishedPage;
MyMsg.Caption := 'Hello World';
MyMsg.AutoSize := True;
end;
To correctly position your label you need to take into account pre-defined controls. Luckily, InnoSetup is open-source product https://github.com/jrsoftware/issrc
You can get a clue of what is contained on each wizard page via evaluating Wizard.pas and Wizard.dfm.txt files. So that, you'll be able to place correct MyMsg.Left and MyMsg.Top values.
If talking about "Custom page from scratch", it's much more complicated approach and again you'll need InnoSetup sources to guess what the system is expecting.
General idea:
constructor TWizardForm.Create(AOwner: TComponent);
begin
...
{ Initialize wpFinished page }
RegisterExistingPage(wpFinished, FinishedPage, nil, '', '');
SetFontNameSize(FinishedHeadingLabel.Font, LangOptions.WelcomeFontName,
LangOptions.WelcomeFontSize, '', 12);
FinishedHeadingLabel.Font.Style := [fsBold];
FinishedHeadingLabel.Caption := ExpandSetupMessage(msgFinishedHeadingLabel) + SNewLine;
AdjustLabelHeight(FinishedHeadingLabel);
FinishedLabel.Top := FinishedHeadingLabel.Top + FinishedHeadingLabel.Height;
YesRadio.Caption := SetupMessages[msgYesRadio];
NoRadio.Caption := SetupMessages[msgNoRadio];
RunList.MinItemHeight := ScalePixelsY(22);
...
end;

Inno Setup custom form is hiding beneath installation page

We are showing custom form during [Run] section in interactive installation. But custom form is hiding beneath installation page. Is any way to show the custom form on installer like message boxes.
Using below code to create custom form. and calling it in [Run] section.
[Setup]
AppId=Display Form
AppName=Display Form
DefaultDirname={sd}\Test
DisableDirPage=yes
WindowVisible=no
OutputDir=C:\Test
[Run]
Filename: C:\Test.exe; Flags: runhidden; AfterInstall : PassphraseForm;
[Code]
Procedure PassphraseForm();
var
Form: TSetupForm;
OKButton: TNewButton;
mLabel:TLabel;
LogFileString : AnsiString;
RichEditViewer: TRichEditViewer;
cancelclick: Boolean;
begin
Form := CreateCustomForm();
try
Form.ClientWidth := ScaleX(400);
Form.ClientHeight := ScaleY(180);
Form.Caption := 'Server';
Form.Center
mLabel:=TLabel.Create(Form);
mLabel.Caption:='';
mLabel.AutoSize:=True;
mLabel.Alignment:=taCenter;
OKButton := TNewButton.Create(Form);
OKButton.Parent := Form;
OKButton.Width := ScaleX(70);
OKButton.Height := ScaleY(30);
OKButton.Left := ScaleX(170);
OKButton.Top := ScaleY(142);
OKButton.Caption := 'OK';
OKButton.ModalResult := mrOk;
RichEditViewer :=TRichEditViewer.Create(Form);
RichEditViewer.Width :=360;
RichEditViewer.Height :=120;
RichEditViewer.Top := 20;
RichEditViewer.Left :=20;
RichEditViewer.Alignment:=taLeftJustify;
RichEditViewer.Parent := Form;
RichEditViewer.WordWrap :=True;
RichEditViewer.ScrollBars := ssBoth;
RichEditViewer.UseRichEdit := True;
RichEditViewer.Font.Size:=9;
RichEditViewer.RTFText := 'Server Value';
RichEditViewer.ReadOnly := True;
Form.ActiveControl := OKButton;
cancelclick:=True;
if Form.ShowModal() = mrOk then
begin
Log('Custom form is displayed succesfully');
end;
finally
Form.Free();
end;
end;
OK, this is really nice (undocumented) feature of Inno Setup!
I had no idea [Run] section support AfterInstall parameter (it is not mentioned in manual :)
Anyway your code works fine for me:
I think there is no way displaying the form below the main form as it is created as Modal form and shown with Form.ShowModal().
Are you sure the form is not displayed somewhere else? E.g. on second monitor/screen or outside of screen borders?
Also check the debugger - maybe a breakpoint was hit just when form is about to show and you need to press F9 to continue.

Resources