Setting control width to half of custom page SurfaceWidth does not work correctly in Inno Setup - width

I placed a Panel on my custom page and gave it a width of SurfaceWidth. Then I changed its width to SurfaceWidth div 2. Here's the result:
As you can see from the screenshot the new panel's width is definitely not equal to SurfaceWidth div 2. Why is that so?
Here's the code:
[Setup]
WizardStyle=modern
[Code]
procedure InitializeWizard();
var
Page: TWizardPage;
Panel: TPanel;
begin
Page := CreateCustomPage(wpWelcome, 'Custom wizard page controls', 'TButton and others');
Panel := TPanel.Create(Page);
Panel.Width := Page.SurfaceWidth div 2;
Panel.Left := 0;
Panel.Height := 46;
Panel.Anchors := [akLeft, akTop, akRight];
Panel.Caption := 'TPanel';
Panel.Color := clWindow;
Panel.BevelKind := bkFlat;
Panel.BevelOuter := bvNone;
Panel.ParentBackground := False;
Panel.Parent := Page.Surface;
end;

That's because of the akRight in Panel.Anchors and modern WizardStyle (or rather the 120 WizardSizePercent it implies). The wizard is scaled only after the InitializeWizard. With akRight, the panel width will grow linearly (not proportionally) with the wizard. There are solutions, but they depend on how you actually want the panel to behave in the resizable wizard (also implied by the modern style).
See also Inno Setup - how to center an animated gif in resized wizard.
If you want to keep the panel at half size, when the wizard is resized (either automatically due to WizardSizePercent or by the user due to WizardResizable), handle WizardForm.OnResize:
[Code]
var
Page: TWizardPage;
Panel: TPanel;
procedure WizardFormResize(Sender: TObject);
begin
Panel.Width := Page.SurfaceWidth div 2;
end;
procedure InitializeWizard();
begin
Page := CreateCustomPage(
wpWelcome, 'Custom wizard page controls', 'TButton and others');
Panel := TPanel.Create(Page);
Panel.Width := Page.SurfaceWidth div 2;
// ...
WizardForm.OnResize := #WizardFormResize;
end;
Make sure you do not set the akRight anchor.

Related

Component Caption + Custom Component Page height

I have two #Martin Prikryl codes that I can't get them to work together.
Larger "Select Components" page in Inno Setup
Long descriptions on Inno Setup components
I followed all the instructions Martin said about the #TLama code, but the codes didn't work together.
Component captions do not appear when I activate the code to change the page height.
I would like a way to merge them and make them work together.
I solved the problem by adding the page's custom height value to the CompLabel.Top of the component captions code.
I also had to change the procedure to CurPageChanged and created an <event( ' ' )> to merge the two codes and created a directive #define CustomPageHeight "ScaleY(200)" to define the custom height of the page.
// Set page height here
#define CustomPageHeight "ScaleY(200)"
[Code]
// Final part of code for component captions
Var StopCall: Boolean;
<event('CurPageChanged')> // Added event here
Procedure CurPageChanged1(CurPageID: Integer);
Begin
If StopCall = false Then
Begin
If CurPageID = wpWelcome Then
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(37); // Added here
CompLabel.Top := WizardForm.ComponentsList.Top + WizardForm.ComponentsList.Height + {#CustomPageHeight} - CompLabel.Height;
CompLabel.AutoSize := False;
CompLabel.WordWrap := True;
WizardForm.ComponentsList.Height := WizardForm.ComponentsList.Height - CompLabel.Height - ScaleY(2);
StopCall := true;
End;
End;
End;
// Code for custom height page
var
CompPageModified: Boolean;
<event('CurPageChanged')> // Added event here
procedure CurPageChanged2(CurPageID: Integer);
begin
if CurpageID = wpSelectComponents then
begin // Changed here
WizardForm.Height := WizardForm.Height + {#CustomPageHeight};
CompPageModified := True;
end
else
if CompPageModified then
begin // Changed here
WizardForm.Height := WizardForm.Height - {#CustomPageHeight};
CompPageModified := False;
end;
end;

Can you create a custom page that looks like the Finish page?

Can you create a custom page that looks like the Finish page?
This is the code for custom page,
UserPage2 := CreateCustomPage(
UserPage1.ID,
'Title',
'Details'
);
This custom page,
Needs to look like this,
The reason for this is because, sometimes when the user runs the installer again they will be able to select few options. Based on the options the installer needs to make few changes to the settings used by the installed program without overwriting the files by reinstalling. So the user should get the Finish dialog after the changes.
Recreate the FinishedPage controls on your custom page.
When entering the page, you need to resize WizardForm.InnerNotebook to cover whole wizard window (except for the bottom button area) and hide the page header controls.
var
FakeFinishedPage: TWizardPage;
FakeFinishedBitmapImage: TBitmapImage;
FakeFinishedLabel: TNewStaticText;
FakeFinishedHeadingLabel: TNewStaticText;
procedure CopyBounds(Dest, Source: TControl);
begin
Dest.Left := Source.Left;
Dest.Top := Source.Top;
Dest.Width := Source.Width;
Dest.Height := Source.Height;
end;
procedure FakeFinishedPageActivate(Sender: TWizardPage);
begin
WizardForm.Bevel1.Visible := False;
WizardForm.MainPanel.Visible := False;
WizardForm.InnerNotebook.Left := 0;
WizardForm.InnerNotebook.Top := 0;
WizardForm.InnerNotebook.Width := WizardForm.OuterNotebook.ClientWidth;
WizardForm.InnerNotebook.Height := WizardForm.OuterNotebook.ClientHeight;
// With WizardStyle=modern and/or WizardResizable=yes,
// we cannot copy the sizes in InitializeWizard as they are not final yet.
CopyBounds(FakeFinishedBitmapImage, WizardForm.WizardBitmapImage2);
FakeFinishedBitmapImage.Anchors := WizardForm.WizardBitmapImage2.Anchors;
CopyBounds(FakeFinishedLabel, WizardForm.FinishedLabel);
FakeFinishedLabel.Anchors := WizardForm.FinishedLabel.Anchors;
CopyBounds(FakeFinishedHeadingLabel, WizardForm.FinishedHeadingLabel);
FakeFinishedHeadingLabel.Anchors := WizardForm.FinishedHeadingLabel.Anchors;
WizardForm.BackButton.Visible := False;
WizardForm.NextButton.Caption := SetupMessage(msgButtonFinish);
end;
procedure CopyLabel(Dest, Source: TNewStaticText);
begin
Dest.AutoSize := Source.AutoSize;
Dest.Font := Source.Font;
Dest.ShowAccelChar := Source.ShowAccelChar;
Dest.WordWrap := Source.WordWrap;
end;
procedure InitializeWizard();
var
S: string;
begin
// ...
FakeFinishedPage := CreateCustomPage(UserPage1.ID, '', '');
FakeFinishedPage.OnActivate := #FakeFinishedPageActivate;
FakeFinishedBitmapImage := TBitmapImage.Create(WizardForm);
FakeFinishedBitmapImage.Parent := FakeFinishedPage.Surface;
FakeFinishedBitmapImage.BackColor := WizardForm.WizardBitmapImage2.BackColor;
FakeFinishedBitmapImage.Bitmap := WizardForm.WizardBitmapImage2.Bitmap;
FakeFinishedBitmapImage.Stretch := WizardForm.WizardBitmapImage2.Stretch;
FakeFinishedLabel := TNewStaticText.Create(WizardForm);
FakeFinishedLabel.Parent := FakeFinishedPage.Surface;
CopyLabel(FakeFinishedLabel, WizardForm.FinishedLabel);
S := SetupMessage(msgFinishedLabelNoIcons) + #13#13 + SetupMessage(msgClickFinish);
StringChangeEx(S, '[name]', 'My Program', True);
FakeFinishedLabel.Caption := S;
FakeFinishedHeadingLabel := TNewStaticText.Create(WizardForm);
FakeFinishedHeadingLabel.Parent := FakeFinishedPage.Surface;
CopyLabel(FakeFinishedHeadingLabel, WizardForm.FinishedHeadingLabel);
S := SetupMessage(msgFinishedHeadingLabel);
StringChangeEx(S, '[name]', 'My Program', True);
FakeFinishedHeadingLabel.Caption := S;
end;
There are some limitations:
The code does not handle correctly image resizes, when the wizard resizes (with WizardResizable=yes) – it's easy to fix though.
The solution does not expect that any page will be shown after this fake finish pages shows. I.e. there's no Back button and it's expected that the Finish button is implement to kill the intallater. After all, this is a follow up question to Conditionally skip to a custom page at the end of the Inno Setup installation wizard without installing?
Though to avoid all these hacks, consider allowing the installation to proceed normally, but without changing anything. It might be easier to implement in the end.
Related questions:
Image covering whole page in Inno Setup – An alternative implementation that solves the problem by overlaying a control over whole upper part of the wizard window, hiding/showing it as needed.
Custom Welcome and Finished page with stretched image in Inno Setup
How to hide the main panel and show an image over the whole page?

Image covering whole page in Inno Setup

Following on from this: Inno Setup Placing image/control on custom page.
This is doing what I need:
CustomPage := CreateCustomPage(wpLicense, 'Heading', 'Sub heading.');
ExtractTemporaryFile('image.bmp');
BtnImage := TBitmapImage.Create(WizardForm);
with BtnImage do
begin
Parent := CustomPage.Surface;
Bitmap.LoadFromFile(ExpandConstant('{tmp}')+'\image.bmp');
AutoSize := True;
AutoSize := False;
Height := ScaleX(Height);
Width := ScaleY(Width);
Stretch := True;
Left := ScaleX(90);
Top := WizardForm.SelectTasksPage.Top + WizardForm.SelectTasksPage.Height -
Height - ScaleY(8);
Cursor := crHand;
OnClick := #ImageOnClick;
end;
However I would like the background image to be the full size of the space bellow the heading and above the footer with no side margins. I was trying various stretch/margin/height/width, but the results are messy. What's the best way to achieve this that looks good no matter the DPI?
You can retrieve a size of the (custom) page surface using TWizardPage.SurfaceHeight and TWizardPage.SurfaceWidth.
BtnImage.Height := CustomPage.SurfaceHeight;
BtnImage.Width := CustomPage.SurfaceWidth;
// Needed for WizardStyle=modern
BtnImage.Anchors := [akLeft, akTop, akRight, akBottom];
Though you will see that the (custom) page does not cover whole area between "header" (MainPanel) and "footer" (bottom part with buttons).
If you want to display image across the whole area between "header" and "footer", you cannot place it on the (custom) page. You have to place it on the InnerPage (what is a parent control of all pages with the "header").
BtnImage.Parent := WizardForm.InnerPage;
BtnImage.Left := 0;
BtnImage.Top := WizardForm.Bevel1.Top + 1;
BtnImage.Width := WizardForm.InnerPage.ClientWidth;
BtnImage.Height := WizardForm.InnerPage.ClientHeight - BtnImage.Top;
// Needed for WizardStyle=modern
BtnImage.Anchors := [akLeft, akTop, akRight, akBottom];
But that way the image won't get automatically shown/hidden as the custom page shows/hides. You have to code it. Use CurPageChanged event function.
procedure CurPageChanged(CurPageID: Integer);
begin
WizardForm.InnerNoteBook.Visible := (CurPageID <> CustomPage.ID);
BtnImage.Visible := (CurPageID = CustomPage.ID);
end;
Similar questions:
An alternative implementation that resizes the "pages" to cover whole upper parts of the wizard window:
Can you create a custom page that looks like the Finish page?
Displaying an image even over the "header":
How to hide the main panel and show an image over the whole page?
Displaying an image as a background of whole window: Inno Setup - Image as installer background.

Inno Setup Placing image/control on custom page

I'm trying to have an image on a custom page I can get the custom page to show or the image on a predefined page but not on the custom page.
Problem I think is with Parent := CustomPage.ID;.
Parent := WizardForm.SelectTasksPage; works though.
How to do this properly?
procedure ImageOnClick(Sender: TObject);
var
ErrorCode: Integer;
begin
ShellExec('', 'http://test.com', '', '', SW_SHOW, ewNoWait, ErrorCode);
end;
var
CustomPage: TWizardPage;
BtnImage: TBitmapImage;
procedure InitializeWizard;
begin
CustomPage := CreateCustomPage(wpLicense, 'Heading', 'Sub heading.');
ExtractTemporaryFile('image.bmp');
BtnImage := TBitmapImage.Create(WizardForm);
with BtnImage do
begin
Parent := CustomPage.ID;
Bitmap.LoadFromFile(ExpandConstant('{tmp}')+'\image.bmp');
AutoSize := True;
Left := 90;
Top := WizardForm.SelectTasksPage.Top +
WizardForm.SelectTasksPage.Height - Height - 8;
Cursor := crHand;
OnClick := #ImageOnClick;
end;
end;
That's what TWizardPage.Surface of type TNewNotebookPage is for.
with BtnImage do
begin
Parent := CustomPage.Surface;
{ ... }
end;
Related questions:
TInputDirWizardPage with Radio Buttons
(Similar question about radio buttons with more code)
Add additional controls to standard Inno Setup pages?
Also, never use absolute coordinates and sizes. Your layout will break, when the wizard is shown on high DPI/scaled display, what is quite common nowadays with "retina" displays. Use ScaleX and ScaleY functions. For the same reason, you should have images with different resolutions ready (see Inno Setup WizardImageFile looks bad with font scaling on Windows 7). Or at least scale/stretch the bitmap.
CustomPage := CreateCustomPage(wpLicense, 'Heading', 'Sub heading.');
ExtractTemporaryFile('image.bmp');
BtnImage := TBitmapImage.Create(WizardForm);
with BtnImage do
begin
Parent := CustomPage.Surface;
Bitmap.LoadFromFile(ExpandConstant('{tmp}')+'\image.bmp');
AutoSize := True;
AutoSize := False;
Height := ScaleY(Height);
Width := ScaleX(Width);
Stretch := True;
Left := ScaleX(90);
Top := WizardForm.SelectTasksPage.Top + WizardForm.SelectTasksPage.Height -
Height - ScaleY(8);
Cursor := crHand;
OnClick := #ImageOnClick;
end;
Layout on 100% zoom (96 DPI):
Layout on 150% zoom (144 DPI):
Layout on 150% zoom (144 DPI) with offset/sizes scaling and image stretching:
Similar to Martin Prikryl's answer.
In order to deal with different DPI settings and placing a bitmap:
setup your machine to 100% DPI
make a bitmap with size (width/height) to fit on your InnoSetup page/form
get these width and height (right click/properties on your bmp file)
use the code below
setup your machine to 150% DPI and create your bitmap to fit for 150% DPI and use it instead the first one (which fits for 100% DPI), this way it will look nice for 100% and for 200%
The code:
WarningImage := TBitmapImage.Create(RisksForm);
WarningImage.Parent := RisksForm;
WarningImage.Bitmap.LoadFromFile(ExpandConstant('{app}')+'uninstall-warning-large.bmp');
WarningImage.Left := ScaleX(24);
WarningImage.Top := ScaleY(120);
WarningImage.Width := ScaleX(544);
WarningImage.Height := ScaleY(211);
WarningImage.Stretch := True;
Change 544 with the width of your bitmap and 211 with the height of your bitmap (from step 3)
Stretch := True does the bitmap to expand (if it is smaller) or shrink (if it is bigger) than width/height properties
P.S. ofcourse you could use multiple files and use one depending on users DPI settings (DPI settings with Inno Setup), but bitmaps are without compressions, so I don't like this idea.
you can Use Botva2 library
http://krinkels.org/threads/botva2.1931/
use google translate if u can't understand rusian
u can create some awesome installer using this
image f.e
Botva2 example
[code]
#include "botva2.iss"
var SomeImage : Longint;
procedure InitializeWizard();
begin
{Your Custom page Code Goes Here}
SomeImage := ImgLoad(WizardForm.Handle,'Image.bmp',0,0,854,480,true,true)‌​;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
ImgSetVisibility(SomeImage,false);
if (CurPageID = CustomPage.ID) ImgSetVisibility(SomeImage,true);
end;

Inno Setup - How can I put a version number on the bottom left corner of welcome page

I want to display a version number on bottom left corner of installer Welcome page, just like shown in this image. But I am not sure how to customize launch page. Can anyone suggest how to do this using Inno Setup script?
Create a new TNewStaticText label in the InitializeWizard event function:
[Code]
procedure InitializeWizard();
var
VersionLabel: TNewStaticText;
begin
VersionLabel := TNewStaticText.Create(WizardForm);
VersionLabel.Caption := Format('Version: %s', ['{#SetupSetting("AppVersion")}']);
VersionLabel.Parent := WizardForm;
VersionLabel.Left := ScaleX(16);
VersionLabel.Top :=
WizardForm.BackButton.Top +
(WizardForm.BackButton.Height div 2) -
(VersionLabel.Height div 2)
end;

Resources