I'd like to disable controls on my custom page (VST2DirPage) based on selected components. I have tried the condition:
if IsComponentSelected('VST64') then
begin
VST2DirPage.Buttons[0].Enabled := False;
VST2DirPage.PromptLabels[0].Enabled := False;
VST2DirPage.Edits[0].Enabled := False;
end
But the elements seems to be always disabled, so it looks like it is not getting the correct values to work properly. Script below:
[Types]
Name: "full"; Description: "{code:FullInstall}";
Name: "custom"; Description: "{code:CustomInstall}"; Flags: iscustom
[Components]
Name: "VST64"; Description: "64-bit VST2"; Types: full; Check: Is64BitInstallMode
Name: "VST"; Description: "32-bit VST2"; Types: full; Check: Is64BitInstallMode
Name: "VST"; Description: "32-bit VST2"; Types: full; Check: not Is64BitInstallMode
[Code]
var VST2DirPage: TInputDirWizardPage;
procedure InitializeWizard;
begin
VST2DirPage := CreateInputDirPage(wpSelectComponents,
'Confirm VST2 Plugin Directory', '',
'Select the folder in which setup should install the VST2 Plugin, then click Next.',
False, '');
VST2DirPage.Add('64-bit folder');
VST2DirPage.Values[0] := ExpandConstant('{reg:HKLM\SOFTWARE\VST,VSTPluginsPath|{pf}\Steinberg\VSTPlugins}');
VST2DirPage.Add('32-bit folder');
VST2DirPage.Values[1] := ExpandConstant('{reg:HKLM\SOFTWARE\WOW6432NODE\VST,VSTPluginsPath|{pf32}\Steinberg\VSTPlugins}');
if not Is64BitInstallMode then
begin
VST2DirPage.Buttons[0].Enabled := False;
VST2DirPage.PromptLabels[0].Enabled := False;
VST2DirPage.Edits[0].Enabled := False;
end;
end;
InitializeWizard event function happens even before the installer is shown. At that point, you do not know yet, what components a user will select.
You have to update a controls' state only when you know what components are selected:
Either when leaving the "Select Components" page.
Or when entering your custom page.
This shows the later approach (implemented using CurPageChanged event function):
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = VST2DirPage.ID then
begin
VST2DirPage.Buttons[0].Enabled := not WizardIsComponentSelected('VST64');
VST2DirPage.PromptLabels[0].Enabled := VST2DirPage.Buttons[0].Enabled;
VST2DirPage.Edits[0].Enabled := VST2DirPage.Buttons[0].Enabled;
end;
end;
Note that the above code not only disables the controls, when the component is selected. It also re-enables them, if user returns back to "Select Components" page and unselects the component.
See also a similar question:
Inno Setup - Change a task description label's color and have a line break.
Related
My component section:
[Components]
Name: "client"; Description: "Client"; Types: full default monitor;
Name: "server"; Description: "Server"; Types: full default server;
Name: "server/feature"; Description: "Optional feature";
Name: "server/Db"; Description: "Always supported server feature"; Types: full default server; Flags: fixed
Name: "server/Db/latest"; Description: "Latest"; Types: full default server; Flags: exclusive
Name: "server/Db/2_10"; Description: "2.10"; Flags: exclusive
I would like to have component server/Db that is always selected when its parent server is selected. I was able to acomplish it with fixed flag, but then I'm not able to select server/Db/2_10. If I tried to select second exclusive component, server/Db is unsellected altogether.
I can only select server/Db/2_10 if server/Db isn't flaged as fixed, but then I'm able to unselect it.
Edit:
I added procedures like in Inno Setup: how to auto select a component if another component is selected?. Just changed ComponentsListCheckChanges procedure like this, (because I don't want to allow user to uncheck it):
procedure ComponentsListCheckChanges;
begin
// No metter what you chceck/uncheck force component if needed.
if WizardIsComponentSelected('server') then
begin
WizardSelectComponents('server/Db');
end
else
begin
WizardSelectComponents('!server/Db');
end
end;
I just found out, that If I try to uncheck server/Db, its checked back, that's good, but Type change to Custom even if it match other predefined type. Did I made some mistakes?
Old:
I also tried to mark it as Disabled in code. I was able to select both exclusive components, but not able to Uncheck component server anymore.
[code]
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpSelectComponents then
WizardForm.ComponentsList.ItemEnabled[3] := False;
end;
I'm able to create same behavior in component section as with code above by adding custom to Types list. I'm able to select both exclusive components, but can't uncheck server
[Components]
Name: "client"; Description: "Client"; Types: full default monitor;
Name: "server"; Description: "Server"; Types: full default server;
Name: "server/feature"; Description: "Optional feature";
Name: "server/Db"; Description: "Always supported server feature"; Types: full default server custom; Flags: fixed
Name: "server/Db/latest"; Description: "Latest"; Types: full default server; Flags: exclusive
Name: "server/Db/2_10"; Description: "2.10"; Types: custom; Flags: exclusive
Last thing that I tried was setting it to True in code if server is checked. I Tried using code from: https://stackoverflow.com/a/36989894/2416941 , it forced server/Db to behave like I wanted but, in dropdown menu above components, Selected Type stopped changing, It always showed as Default instalation and not Custom or any other type, so I don't think that's a valid solution.
How can I force server/Db to be always checked with server and able to choose one of server/Db's children, and still possible to uncheck server?
Or is there other way to group exclusive components?
I made it works corectly by editing answers for Inno Setup: how to auto select a component if another component is selected? but had to add ComponentsListClickCheckPrev(nil); to Update Type selection corectly after calling WizardSelectComponents.
[Code]
var
TypesComboOnChangePrev: TNotifyEvent;
ComponentsListClickCheckPrev: TNotifyEvent;
procedure ComponentsListCheckChanges;
begin
{ If Check status of components is different }
{ Update child's status with parent's status. }
if WizardIsComponentSelected('server') <> WizardIsComponentSelected('server/Db') then
begin
if WizardIsComponentSelected('server') then { If checked parent }
begin
WizardSelectComponents('server/Db'); { Check component }
end
else
begin
WizardSelectComponents('!server/Db'); { Uncheck component }
end;
ComponentsListClickCheckPrev(nil); { Update Type selection after my edits }
end;
end;
procedure ComponentsListClickCheck(Sender: TObject);
begin
{ First let Inno Setup update the components selection }
ComponentsListClickCheckPrev(Sender);
{ And then check for changes }
ComponentsListCheckChanges;
end;
procedure TypesComboOnChange(Sender: TObject);
begin
{ First let Inno Setup update the components selection }
TypesComboOnChangePrev(Sender);
{ And then check for changes }
ComponentsListCheckChanges;
end;
procedure InitializeWizard();
begin
{ The Inno Setup itself relies on the TypesCombo.OnChange and OnClickCheck. }
{ so we have to preserve their handlers. }
ComponentsListClickCheckPrev := WizardForm.ComponentsList.OnClickCheck;
WizardForm.ComponentsList.OnClickCheck := #ComponentsListClickCheck;
TypesComboOnChangePrev := WizardForm.TypesCombo.OnChange;
WizardForm.TypesCombo.OnChange := #TypesComboOnChange;
end;
I am having issues figuring out why I cannot manipulate the task checkboxes during InitializeWizard, but I can with CurPageChanged:
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"
Name: "Option1"; Description: "Option1"
[Code]
procedure CurPageChanged(CurPageID: Integer);
var Index: Integer;
begin
if CurPageID = wpSelectTasks then
begin
Index := WizardForm.TasksList.Items.IndexOf('Option1');
if Index <> -1 then
MsgBox('Touch device checkbox found.', mbInformation, MB_OK); { THIS WORKS!! }
end;
end;
procedure InitializeWizard();
var Index: Integer;
begin
Index := WizardForm.TasksList.Items.IndexOf('Option1');
if Index <> -1 then
MsgBox('Touch device checkbox found.', mbInformation, MB_OK); { THIS DOES NOT WORK }
end;
Can I not use WizardForm.TasksList.Items in InitializeWizard? I want to be able to call WizardForm.TasksList.Checked[Index] := False; or possibly disable it but I'd rather do it on initialization instead of having to avoid calling code, if the user hits the back button and returns to the wpSelectTasks.
Because task list is populated based on selected components.
Hence, the task list is not known in InitializeWizard yet. The task list is (re)generated, based on select components, whenever the wpSelectTasks page is entered.
So, as you have found out, the earliest moment, you can work with TasksList is CurPageChanged(wpSelectTasks).
When unchecking the task, make sure you do not uncheck it, when user is going back to the tasks page. Actually, you should probably uncheck it on the first visit of the page only.
This code actually download me the files and it does not matter whether the selected component is "test" or not. I want those two files download, if you select a component, can do that? I use Inno Inno Setup 5 + Tools Downloader)
[Components]
Name: Dictionaries; Description: "test"; Types: Full; ExtraDiskSpaceRequired: 50;
[Languages]
Name: english; MessagesFile: compiler:Default.isl
#include ReadReg(HKEY_LOCAL_MACHINE,'Software\Sherlock Software\InnoTools\Downloader','ScriptPath','');
[Code]
procedure InitializeWizard();
begin
itd_init;
itd_addfile('http://www.sherlocksoftware.org/petz/files/dogz5.zip',expandconstant('{tmp}\dogz5.zip'));
itd_addfile('http://www.sherlocksoftware.org/petz/files/petz4.zip',expandconstant('{tmp}\petz4.zip'));
itd_downloadafter(wpReady);
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep=ssInstall then begin
filecopy(expandconstant('{tmp}\dogz5.zip'),expandconstant('{app}\dogz5.zip'),false);
filecopy(expandconstant('{tmp}\petz4.zip'),expandconstant('{app}\petz4.zip'),false);
end;
end;
Yes, that's possible. Your are looking for a little helper function called
IsComponentSelected().
It's basically a boolean tester accepting a component name from the [components] and returning the checkbox value (selected=true).
// for a single component
if IsComponentSelected('NameOfTheComponent') then idpAddFile(URL, ...);`
// multiple components with one selection
if IsComponentSelected('dictionaries') then
begin
idpAddFile(URL1, ...);
idpAddFile(URL2, ...);
end;
Comment by TLama:
In which event and where to enqueue the download files?
I would suggest to use the NextButtonClick event with a condition, that the current (CurPage) has to be the component selection screen (wpSelectComponents).
In other words: when you are on the component selection screen and press next, only the selected components are added to the downloader.
The code could look like this:
function NextButtonClick(CurPage: Integer): Boolean;
(*
Called when the user clicks the Next button.
If you return True, the wizard will move to the next page.
If you return False, it will remain on the current page (specified by CurPageID).
*)
begin
if CurPage = wpSelectComponents then
begin
if IsComponentSelected('NameOfTheComponent') then idpAddFile(URL, ...);
end; // of wpSelectComponents
Result := True;
end;
Sidenote: you might switch your download lib to https://code.google.com/p/inno-download-plugin/ This has better features, including decent https support and is actively maintained. InnoTools Download by SherlockSoftware is outdated (2008).
In a prior question I asked how to have three optional components, where the user could also specify the locations for each component separately (e.g. a code part and two HTML web applications). #Miral gave me a great answer which I have now implemented:
three components in three user defined locations
I have a small esthetic issue remaining. I am always creating and asking the user for a CreateInputDirPage, in the wizard. The question comes after the wpSelectComponents.
Question: How do I skip the page if the component was not selected. That is, how do I skip my custom page?
I have a feeling it has to do with ShouldSkipPage(). But I have no idea what the PageID for my custom page is, and how to test to see what components were selected.
function ShouldSkipPage(PageID: Integer): Boolean;
The wizard calls this event function to determine whether or not a particular page (specified by PageID) should be shown at all. If you return True, the page will be skipped; if you return False, the page may be shown.
My script is enclosed below:
[Components]
Name: "Watson"; Description: "Watson Component"; Types: onlywatson full
Name: "Toby"; Description: "Toby Component"; Types: onlytoby full
Name: "Sherlock"; Description: "Sherlock Component"; Types: onlysherlock full
[Code]
var
TobyDirPage: TInputDirWizardPage;
SherlockDirPage: TInputDirWizardPage;
procedure InitializeWizard;
begin
TobyDirPage := CreateInputDirPage(wpSelectComponents,
'Select Location for Toby Web Pages', 'Where should we store the sample Toby application files?',
'The sample Toby stand-alone map application will be saved in the following folder.'#13#10#13#10 +
'To continue, click Next. If you would like to select a different folder, click Browse.',
False, 'New Folder');
{ Add item (with an empty caption) }
TobyDirPage.Add('');
{ Set initial value (optional) }
TobyDirPage.Values[0] := ExpandConstant('c:\wwwroot\Toby');
SherlockDirPage := CreateInputDirPage(wpSelectComponents,
'Select Location for Sherlock Web Pages', 'Where should we store the Sherlock Catalog Search Tool?',
'Sherlock.html and it'#39 + 's associated files will be saved in the following folder.'#13#10#13#10 +
'To continue, click Next. If you would like to select a different folder, click Browse.',
False, 'New Folder');
{ Add item (with an empty caption) }
SherlockDirPage.Add('');
{ Set initial value (optional) }
SherlockDirPage.Values[0] := ExpandConstant('c:\wwwroot\Sherlock');
end;
function GetTobyDir(Param: String): String;
begin
{ Return the selected TobyDir }
Result := TobyDirPage.Values[0];
end;
function GetSherlockDir(Param: String): String;
begin
{ Return the selected TobyDir }
Result := SherlockDirPage.Values[0];
end;
As you correctly forefelt, you need to use the ShouldSkipPage event handler to conditionally skip the page. To check if a certain component is selected use the IsComponentSelected function and finally, to get ID of your custom page you need to store its ID. Putting all together might give you the following example script:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
OutputDir=userdocs:Inno Setup Examples Output
[Components]
Name: "help"; Description: "Help File";
[Code]
var
CustomPageID: Integer;
procedure InitializeWizard;
var
CustomPage: TInputDirWizardPage;
begin
CustomPage := CreateInputDirPage(wpSelectComponents, 'Caption',
'Description', 'SubCaption', False, 'NewFolderName');
CustomPage.Add('Input');
{ store your custom page ID to further use in the ShouldSkipPage event }
CustomPageID := CustomPage.ID;
end;
function ShouldSkipPage(PageID: Integer): Boolean;
begin
{ initialize result to not skip any page (not necessary, but safer) }
Result := False;
{ if the page that is asked to be skipped is your custom page, then... }
if PageID = CustomPageID then
{ if the component is not selected, skip the page }
Result := not IsComponentSelected('help');
end;
My take on this is to use the TWizardPageShouldSkipEvent, I've made only a case-and-point script:
[Code]
var
TobyDirPage: TInputDirWizardPage;
function SkipEvent (Sender: TWizardPage): Boolean;
begin
Result := not IsComponentSelected('Toby');
end;
procedure InitializeWizard;
begin
TobyDirPage := CreateInputDirPage(wpSelectComponents, yadda yadda yadda
TobyDirPage.OnShouldSkipPage := #SkipEvent;
end;
Now, OnShouldSkipPage fires right after pressing Next on wpSelectComponents and before TobyDirPage gets painted and since you can attach that event to the page itself you don't need to fiddle with PageID's.
I want to execute some code if a user checks a corresponding checkbox during the install. From reading the help file, it looks like the only way to use the task is to associate it with an entry in the Files/Icons/etc. section. I'd really like to associate it with a procedure in the Code section. Can this be done and if so, how?
You don't need to define your own wizard page. You can just add them to the additional tasks page.
[Tasks]
Name: associate; Description:"&Associate .ext files with this version of my program"; \
GroupDescription: "File association:"
[Code]
function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result := True;
if CurPageID = wpSelectTasks then
begin
if WizardIsTaskSelected('taskname') then
MsgBox('First task has been checked.', mbInformation, MB_OK);
else
MsgBox('First task has NOT been checked.', mbInformation, MB_OK);
end;
end;
Credit goes to TLama for this post.
You do that by adding a custom wizard page that has check boxes, and execute the code for all selected check boxes when the user clicks "Next" on that page:
[Code]
var
ActionPage: TInputOptionWizardPage;
procedure InitializeWizard;
begin
ActionPage := CreateInputOptionPage(wpReady,
'Optional Actions Test', 'Which actions should be performed?',
'Please select all optional actions you want to be performed, then click Next.',
False, False);
ActionPage.Add('Action 1');
ActionPage.Add('Action 2');
ActionPage.Add('Action 3');
ActionPage.Values[0] := True;
ActionPage.Values[1] := False;
ActionPage.Values[2] := False;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result := True;
if CurPageID = ActionPage.ID then begin
if ActionPage.Values[0] then
MsgBox('Action 1', mbInformation, MB_OK);
if ActionPage.Values[1] then
MsgBox('Action 2', mbInformation, MB_OK);
if ActionPage.Values[2] then
MsgBox('Action 3', mbInformation, MB_OK);
end;
end;
The check boxes can either be standard controls or items in a list box, see the Inno Setup documentation on Pascal Scripting for details.
If you want your code to be executed depending on whether a certain component or task has been selected, then use the WizardIsComponentSelected() and WizardIsTaskSelected() functions instead.