I would like to be able to disable the selection of a component based on a specific component being selected. I cannot do this through nesting of components, as the componen
The code I used in the end is based entirely on @TLama's code that he provided previously as this does not require the use of an external DLL.
[Code]
const
//Define global constants
CompIndexSync = 15;
CompIndexSyncClient = 16;
CompIndexSyncServer = 17;
var
//Define global variables
CompPageVisited: Boolean;
DefaultCompClickCheck: TNotifyEvent;
DefaultCompTypeChange: TNotifyEvent;
//Uncheck and set the enabled state of the Sync components based on whether the Client component is selected
procedure UpdateComponents;
begin
with WizardForm.ComponentsList do
begin
if IsComponentSelected('Client') then
begin
CheckItem(CompIndexSync, coUncheck);
end;
ItemEnabled[CompIndexSync] := not IsComponentSelected('Client');
ItemEnabled[CompIndexSyncClient] := not IsComponentSelected('Client');
ItemEnabled[CompIndexSyncServer] := not IsComponentSelected('Client');
Invalidate; //required for text state to update correctly
end;
end;
//Update the component states if the component states change and restore the original event handler procedures
procedure ComponentsClickCheck(Sender: TObject);
begin
DefaultCompClickCheck(Sender);
UpdateComponents;
end;
procedure ComponentsTypesComboChange(Sender: TObject);
begin
DefaultCompTypeChange(Sender);
UpdateComponents;
end;
procedure InitializeWizard();
begin
//Store the original Components Page OnClickCheck and Types Combo Box OnChange event procedures and assign custom procedures
DefaultCompClickCheck := WizardForm.ComponentsList.OnClickCheck;
WizardForm.ComponentsList.OnClickCheck := @ComponentsClickCheck;
DefaultCompTypeChange := WizardForm.TypesCombo.OnChange;
WizardForm.TypesCombo.OnChange := @ComponentsTypesComboChange;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
//Update the Components Page if entered for the first time
if (CurPageID = wpSelectComponents) and not CompPageVisited then
begin
CompPageVisited := True;
UpdateComponents;
end;
end;
Although this and @RobeN's solutions both work, they both exhibit a graphical update issue i.e. when changing the status of the components from active to disabled and vice versa, the text doesn't automatically dim or undim until the scroll bar is dragged.
Note that the refresh issue described above is resolved by adding an `Invalidate;' line. Code updated above with a comment to reflect this. See Inno Setup Components graphical refresh issue for further information. Thanks @TLama.
You had TLama's solution which was probably better than the following, but still this code is also a way to achieve the goal (though you will need innocallback.dll):
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Files]
Source: ".\InnoCallback.dll"; DestDir: "{tmp}"; Flags: dontcopy nocompression
[Components]
Name: "Client"; Description: "Client"; Types: custom
Name: "Sync"; Description: "Sync"; Types: custom
[Code]
var
TimerID: Integer;
type
TTimerProc = procedure(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR;
SysTime: DWORD);
function WrapTimerProc(Callback: TTimerProc; ParamCount: Integer): LongWord;
external 'wrapcallback@files:InnoCallback.dll stdcall';
function SetTimer(hWnd: HWND; nIDEvent, uElapse: UINT;
lpTimerFunc: UINT): UINT; external 'SetTimer@user32.dll stdcall';
function KillTimer(hWnd: HWND; uIDEvent: UINT): BOOL;
external 'KillTimer@user32.dll stdcall';
procedure KillComponentsTimer;
begin
if TimerID <> 0 then
begin
if KillTimer(0, TimerID) then
TimerID := 1;
end;
end;
procedure OnComponentsCheck(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR;
SysTime: DWORD);
begin
if IsComponentSelected('Client') then begin
WizardForm.ComponentsList.Checked[1] := False;
WizardForm.ComponentsList.ItemEnabled[1] := False;
end
else begin
WizardForm.ComponentsList.ItemEnabled[1] := True;
end;
if IsComponentSelected('Sync') then begin
WizardForm.ComponentsList.Checked[0] := False;
WizardForm.ComponentsList.ItemEnabled[0] := False;
end
else begin
WizardForm.ComponentsList.ItemEnabled[0] := True;
end;
end;
procedure ComponentsCheck();
var
TimerCallback: LongWord;
begin
TimerCallback := WrapTimerProc(@OnComponentsCheck, 4);
TimerID := SetTimer(0, 0, 100, TimerCallback);
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpSelectComponents then
begin
ComponentsCheck;
end;
if CurPageID = not wpSelectComponents then
begin
KillComponentsTimer;
end;
end;