6

I am building an install with Inno Setup and I am using the components section to allow the end user to select optional items to install.

Some of these items need a longer description in order for the user to have enough information to intelligently select them.

Is there a way to add more in-depth descriptions somewhere?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
user1433037
  • 61
  • 1
  • 2
  • 1
    Not natively in Inno but see the [DescriptiveTypes.isi](http://www.mirality.co.nz/inno.php) script. This should be modifiable to show `[Components]` descriptions. – Deanna Jun 07 '12 at 08:26

2 Answers2

6

This solution uses only Inno Setup proper (not the obsolete 3rd party build of the Inno Setup of suspicious origin).

The solution is partially based on my answer to Inno Setup: OnHover event.

Adjust the HoverComponentChanged procedure to your needs.

[Code]

var
  LastMouse: TPoint;
  CompLabel: TLabel;

function GetCursorPos(var lpPoint: TPoint): BOOL;
  external 'GetCursorPos@user32.dll stdcall';
function SetTimer(
  hWnd: longword; nIDEvent, uElapse: LongWord; lpTimerFunc: LongWord): LongWord;
  external 'SetTimer@user32.dll stdcall';
function ScreenToClient(hWnd: HWND; var lpPoint: TPoint): BOOL;
  external 'ScreenToClient@user32.dll stdcall';
function ClientToScreen(hWnd: HWND; var lpPoint: TPoint): BOOL;
  external 'ClientToScreen@user32.dll stdcall';
function ListBox_GetItemRect(
  const hWnd: HWND; const Msg: Integer; Index: LongInt; var Rect: TRect): LongInt;
  external 'SendMessageW@user32.dll stdcall';  

const
  LB_GETITEMRECT = $0198;
  LB_GETTOPINDEX = $018E;

function FindControl(Parent: TWinControl; P: TPoint): TControl;
var
  Control: TControl;
  WinControl: TWinControl;
  I: Integer;
  P2: TPoint;
begin
  for I := 0 to Parent.ControlCount - 1 do
  begin
    Control := Parent.Controls[I];
    if Control.Visible and
       (Control.Left <= P.X) and (P.X < Control.Left + Control.Width) and
       (Control.Top <= P.Y) and (P.Y < Control.Top + Control.Height) then
    begin
      if Control is TWinControl then
      begin
        P2 := P;
        ClientToScreen(Parent.Handle, P2);
        WinControl := TWinControl(Control);
        ScreenToClient(WinControl.Handle, P2);
        Result := FindControl(WinControl, P2);
        if Result <> nil then Exit;
      end;

      Result := Control;
      Exit;
    end;
  end;

  Result := nil;
end;

function PointInRect(const Rect: TRect; const Point: TPoint): Boolean;
begin
  Result :=
    (Point.X >= Rect.Left) and (Point.X <= Rect.Right) and
    (Point.Y >= Rect.Top) and (Point.Y <= Rect.Bottom);
end;

function ListBoxItemAtPos(ListBox: TCustomListBox; Pos: TPoint): Integer;
var
  Count: Integer;
  ItemRect: TRect;
begin
  Result := SendMessage(ListBox.Handle, LB_GETTOPINDEX, 0, 0);
  Count := ListBox.Items.Count;
  while Result < Count do
  begin
    ListBox_GetItemRect(ListBox.Handle, LB_GETITEMRECT, Result, ItemRect);
    if PointInRect(ItemRect, Pos) then Exit;
    Inc(Result);
  end;
  Result := -1;
end;

procedure HoverComponentChanged(Index: Integer);
var 
  Description: string;
begin
  case Index of
    0: Description := 'This is the description of Main Files';
    1: Description := 'This is the description of Additional Files';
    2: Description := 'This is the description of Help Files';
  else
    Description := 'Move your mouse over a component to see its description.';
  end;
  CompLabel.Caption := Description;
end;

procedure HoverTimerProc(
  H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
var
  P: TPoint;
  Control: TControl; 
  Index: Integer;
begin
  GetCursorPos(P);
  if P <> LastMouse then { just optimization }
  begin
    LastMouse := P;
    ScreenToClient(WizardForm.Handle, P);

    if (P.X < 0) or (P.Y < 0) or
       (P.X > WizardForm.ClientWidth) or (P.Y > WizardForm.ClientHeight) then
    begin
      Control := nil;
    end
      else
    begin
      Control := FindControl(WizardForm, P);
    end;

    Index := -1;
    if (Control = WizardForm.ComponentsList) and
       (not WizardForm.TypesCombo.DroppedDown) then
    begin
      P := LastMouse;
      ScreenToClient(WizardForm.ComponentsList.Handle, P);
      Index := ListBoxItemAtPos(WizardForm.ComponentsList, P);
    end;

    HoverComponentChanged(Index);
  end;
end;

procedure InitializeWizard();
begin
  SetTimer(0, 0, 50, CreateCallback(@HoverTimerProc));

  CompLabel := TLabel.Create(WizardForm);
  CompLabel.Parent := WizardForm.SelectComponentsPage;
  CompLabel.Left := WizardForm.ComponentsList.Left;
  CompLabel.Width := WizardForm.ComponentsList.Width;
  CompLabel.Height := ScaleY(32);
  CompLabel.Top :=
    WizardForm.ComponentsList.Top + WizardForm.ComponentsList.Height -
    CompLabel.Height;
  CompLabel.AutoSize := False;
  CompLabel.WordWrap := True;

  WizardForm.ComponentsList.Height :=
    WizardForm.ComponentsList.Height - CompLabel.Height - ScaleY(8);
end;

enter image description here

For CreateCallback function, you need Inno Setup 6. If you are stuck with Inno Setup 5, you can use WrapCallback function from InnoTools InnoCallback library. Use the Unicode version of Inno Setup 5.

To make this work correctly in resized/resizable/modern wizard, you will need some adjustments. See Inno Setup - how to center an animated gif in resized wizard and Long components descriptions in enlarged Inno Setup wizard.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
-2

Use this advanced compiler (download link is somewhere below).

It supports more classes and events than the standard compiler. You can access the property "OnItemMouseMove". Using this you can store a description for every item that is shown by a label. Here is an example:

var
CompLabel: TLabel;

procedure OnItemMouseMove(Sender: TObject; X, Y: Integer; Index: Integer; Area: TItemArea);
begin
  case Index of
    0: CompLabel.Caption := 'This is the description of Component 1';
    1: CompLabel.Caption := 'This is the description of Component 2';
    2: CompLabel.Caption := 'This is the description of Component 3';
    3: CompLabel.Caption := 'This is the description of Component 4'
  else
    CompLabel.Caption := 'Move your mouse over a component to see its description.';
  end;
end;

procedure OnMouseLeave(Sender: TObject);
begin
  CompLabel.Caption := 'Move your mouse over a component to see its description.';
end;

procedure InitializeWizard();
begin
  CompLabel := TLabel.Create(WizardForm);
  CompLabel.Parent := WizardForm.SelectComponentsPage;
  CompLabel.SetBounds(WizardForm.ComponentsList.Left,180,WizardForm.ComponentsList.Width,200);
  CompLabel.Caption := 'Move your mouse over a component to see its description.';
  WizardForm.ComponentsList.OnItemMouseMove := @OnItemMouseMove;
  WizardForm.ComponentsList.OnMouseLeave := @OnMouseLeave;
  WizardForm.ComponentsList.Height := WizardForm.ComponentsList.Height - 40;
end;
caesay
  • 16,932
  • 15
  • 95
  • 160
user1662035
  • 363
  • 4
  • 13