3

I have an Inno-setup script with a components page with checkboxs and a combobox. I want to unchecked and disable some components from the Code section, I used this answer to do it and I have now this code :

[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
OutputDir=userdocs:Inno Setup Examples Output

[Types]
Name: "full"; Description: "Full installation"
Name: "compact"; Description: "Compact installation"
Name: "custom"; Description: "Custom installation"; Flags: iscustom

[Components]
Name: "program"; Description: "Program Files"; Types: full compact custom; 
Name: "help"; Description: "Help File"; Types: full
Name: "readme"; Description: "Readme File"; Types: full
Name: "readme\en"; Description: "English"; Flags: exclusive
Name: "readme\de"; Description: "German"; Flags: exclusive

[code]
procedure CurPageChanged(CurPageID: Integer);
begin
  if CurPageID = wpSelectComponents then
    if (True) then  //Here my own condition instead of "(True)"
    begin
      WizardForm.ComponentsList.Checked[1] := False;
      WizardForm.ComponentsList.ItemEnabled[1] := False;
    end;
end;

Using this, the checkbox "help" is unchecked and disabled from the code but, even if the user can't click on the "help" checkbox to check it, he can still choose "Full installation" with the combobox which change the state of the "help" checkbox from unchecked to checked (even if the checkbox stay disabled).

What I would like to do, is completely disable this component and prevent the user from selecting it (without regarding on how the user is trying do it, from clicking it or from choosing "Full installation" in the combobox).

Community
  • 1
  • 1
Alain
  • 380
  • 1
  • 5
  • 15

1 Answers1

3

Here is another, still hacky way to do what you want. I've used a different concept here. Essentially, it's about preparing an array of indices of components that should be disabled and unchecked (which I'm callling ghosted here) and calling UpdateGhostItems(False) which unchecks and disables the items of the indices from that prepared array in the component list.

From the installation type combo box change event is updated only check state that this combo box might change by calling UpdateGhostItems(True):

[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program

[Types]
Name: "full"; Description: "Full installation"
Name: "compact"; Description: "Compact installation"
Name: "custom"; Description: "Custom installation"; Flags: iscustom

[Components]
Name: "program"; Description: "Program Files"; Types: full compact custom; 
Name: "help"; Description: "Help File"; Types: full
Name: "readme"; Description: "Readme File"; Types: full
Name: "readme\en"; Description: "English"; Flags: exclusive
Name: "readme\de"; Description: "German"; Flags: exclusive

[Code]
var
  TypeChange: TNotifyEvent;
  GhostItems: array of Integer;

procedure UpdateGhostItems(CheckOnly: Boolean);
var
  I: Integer;
begin
  for I := 0 to GetArrayLength(GhostItems) - 1 do
  begin
    WizardForm.ComponentsList.Checked[GhostItems[I]] := False;
    if not CheckOnly then
      WizardForm.ComponentsList.ItemEnabled[GhostItems[I]] := False;
  end;
end;

procedure TypesComboChange(Sender: TObject);
begin
  // call the original event method
  TypeChange(Sender);
  // this will uncheck all the items from the GhostItems array;
  // this includes those that were checked by the above method
  // call; for GhostItems array description see below
  UpdateGhostItems(True);
end;

procedure InitializeWizard;
begin
  // store the original TypesCombo change event method
  TypeChange := WizardForm.TypesCombo.OnChange;
  // and assign it our interceptor
  WizardForm.TypesCombo.OnChange := @TypesComboChange;

  // the following code block is for setting ghosted components;
  // in real you might call it in some later stage of your setup

  // quite comfortable looks to me using array of indices of the
  // components that should remain always unchecked and disabled
  // I'm gonna prepare this array at the initialization but it's
  // really upon you when would you do so; so let's ghost 1 item
  SetArrayLength(GhostItems, 1);
  // ...with index 1
  GhostItems[0] := 1;
  // this call will uncheck and disable all the items from the
  // prepared GhostItems array; do note that this is a one way
  // road - once you disable a component, it won't get enabled
  // again (you would have to remember their previous state)
  UpdateGhostItems(False);
end;
TLama
  • 75,147
  • 17
  • 214
  • 392
  • I knew that I could do it but I wanted to keep the possibility to the user to use the combobox (if the component is enable of course). In fact, half of my components can be disabled from code depending on some conditions so if I remove the type for all of them, I have no interest to have a combobox with predefined choice. But I would like to keep it, because it is a nice feature to use for the user. – Alain Jun 17 '15 at 09:06
  • 1
    I see your point but, pfew, that will be ugly, ugly code. Because of missing access to the underlying item attributes you will need to intercept that combo box change event (because the component list itself does not fire any event when the check box is checked by that combo box change) and in that intercept uncheck the just checked component, by, err, disabled state ? No, disabled might be also fixed components, that will need to be controlled by some extra flag. Are you ready for this ? – TLama Jun 17 '15 at 09:58
  • Ok, I see indeed from what you explain that it is not simple ! But I am still interesting to do it. – Alain Jun 17 '15 at 10:17