Inno Setup - Show children component as sibling an

2019-02-20 02:53发布

问题:

I'm trying to have a children component to be shown as sibling. I'm making a installer for a Game which can have multiple versions of the game coexisting in the same installation folder.

Now I want to have the ability to install optional mods which require to have a specific version of the game installed (dependency). So when the user clicks on a mod, the required game gets selected, and if the game is deselected, all the mods get deselected. The code as is is working as expected and behaves as described before. It just gets a bit confusing for the user sometimes. For example if no mod is installed, in the game a square is shown instead of a check, and the hierarchy of the mods is unnecessary.

What I want to achieve:

  1. I want to have game_2 to show a check instead of a square.
  2. To have game_2\com_mods as sibling of game_2 and not as a children.

This is as far as I have arrived, I guess there is no easy way to have that effect. If I'm not wrong using the [Code] section it is possible to modify the UI but I don't know how to force the checkbox instead of the square and remove the padding of the children.

Here is my example code:

[Setup]
AppName=Demo
AppVersion=1.0
DefaultDirName=.

[Components]
Name: "game_1";    Description: "Game v1";  Types: full custom; Flags: checkablealone
Name: "game_2";    Description: "Game v2";  Types: full custom; Flags: checkablealone
Name: "game_2\com_mods";    Description: "Game Community Mods"; Types: full custom;  Flags: dontinheritcheck
Name: "game_2\com_mods\3rdmod1"; Description: "Mod 1"; Flags: exclusive
Name: "game_2\com_mods\3rdmod1"; Description: "Mod 2"; Flags: exclusive
Name: "game_2\com_mods\3rdmod1"; Description: "Mod 3"; Flags: exclusive 

I hope somebody can help me or point me in the right direction to produce the desired effect.

Greetings and thanks.

回答1:

If I understand your question correctly, you want this layout:

[Components]
Name: "game_1";    Description: "Game v1";  Types: full custom
Name: "game_2";    Description: "Game v2";  Types: full custom
Name: "com_mods";    Description: "Game Community Mods"; Types: full custom
Name: "com_mods\3rdmod1"; Description: "Mod 1"; Flags: exclusive
Name: "com_mods\3rdmod1"; Description: "Mod 2"; Flags: exclusive
Name: "com_mods\3rdmod1"; Description: "Mod 3"; Flags: exclusive 

But you want to keep the behavior of your current layout.

Then you have to code the behavior in Pascal Scripting:

[Code]

const
  Game2Index = 1;
  Game2ModsIndex = 2;

var
  Game2Checked: Boolean;

procedure ComponentsListClickCheck(Sender: TObject);
var
  ComponentsList: TNewCheckListBox;
begin
  ComponentsList := WizardForm.ComponentsList;

  { If Game 2 got unchecked }
  if Game2Checked and
     (not ComponentsList.Checked[Game2Index]) then
  begin
    { uncheck the mods }
    ComponentsList.Checked[Game2ModsIndex] := False;
  end; 

  { If Game 2 mods got checked, make sure Game 2 is checked too }
  if ComponentsList.Checked[Game2ModsIndex] and
     (not ComponentsList.Checked[Game2Index]) then
  begin
    ComponentsList.Checked[Game2Index] := True;
  end; 

  Game2Checked := ComponentsList.Checked[Game2Index];
end;

procedure InitializeWizard();
begin
  WizardForm.ComponentsList.OnClickCheck := @ComponentsListClickCheck;
end;

procedure CurPageChanged(CurPageID: Integer);
begin
  if CurPageID = wpSelectComponents then
  begin
    { Remember the initial state }
    Game2Checked := WizardForm.ComponentsList.Checked[Game2Index];
  end;
end;