Browse Source

Merge branch 'highdpi-wizardimages'

Did minor tweaks during merge.
Martijn Laan 7 years ago
parent
commit
3cac47f9dd
5 changed files with 174 additions and 68 deletions
  1. 41 17
      ISHelp/isetup.xml
  2. 71 25
      Projects/Compile.pas
  3. 29 11
      Projects/Main.pas
  4. 31 14
      Projects/Wizard.pas
  5. 2 1
      whatsnew.htm

+ 41 - 17
ISHelp/isetup.xml

@@ -4443,11 +4443,46 @@ DiskSliceSize=1457664
 <setuptopic directive="WizardImageFile">
 <setupdefault><tt>compiler:WIZMODERNIMAGE.BMP</tt></setupdefault>
 <body>
-<p>Specifies the name of the bitmap file to display on the left side of the wizard in the Setup program. This file must be located in your installation's <link topic="sourcedirectorynotes">source directory</link> when running the Setup Compiler, unless a fully qualified pathname is specified or the pathname is prefixed by "compiler:", in which case it looks for the file in the Compiler directory.</p>
-<p>256-color bitmaps may not display correctly in 256-color mode, since it does not handle palettes. The maximum size of the bitmap is 164x314 pixels. Note that if Windows is running with Large Fonts, the area on the wizard for the bitmap will be larger.</p>
-<example><pre>WizardImageFile=myimage.bmp</pre></example>
+<p>Specifies the name(s) of the bitmap file(s) to display on the left side of the wizard. The files(s) must be located in your installation's <link topic="sourcedirectorynotes">source directory</link> when running the Setup Compiler, unless a fully qualified pathname is specified or the pathname is prefixed by "compiler:", in which case it looks for the file in the Compiler directory.</p>
+<p>256-color bitmaps may not display correctly in 256-color mode, since it does not handle palettes.</p>
+<p>When multiple files are specified, Setup will select the one which best matches the system's DPI setting. The recommended size of the bitmap per DPI setting is:</p>
+<table>
+<tr><td>100%</td><td>164x314</td></tr>
+<tr><td>125%</td><td>192x386</td></tr>
+<tr><td>150%</td><td>246x459</td></tr>
+<tr><td>175%</td><td>273x556</td></tr>
+<tr><td>200%</td><td>328x604</td></tr>
+<tr><td>225%</td><td>355x700</td></tr>
+<tr><td>250%</td><td>410x797</td></tr>
+</table>
+<example><pre>WizardImageFile=myimage.bmp,myimage2.bmp</pre></example>
+<p><b>See also:</b><br/>
+<link topic="setup_wizardsmallimagefile">WizardSmallImageFile</link><br/>
+<link topic="setup_wizardimagealphaformat">WizardImageAlphaFormat</link><br/>
+<link topic="setup_wizardimagestretch">WizardImageStretch</link></p>
+</body>
+</setuptopic>
+
+<setuptopic directive="WizardSmallImageFile">
+<setupdefault><tt>compiler:WIZMODERNSMALLIMAGE.BMP</tt></setupdefault>
+<body>
+<p>Specifies the name(s) of the bitmap file(s) to display in the upper right corner of the wizard. The file(s) must be located in your installation's <link topic="sourcedirectorynotes">source directory</link> when running the Setup Compiler, unless a fully qualified pathname is specified or the pathname is prefixed by "compiler:", in which case it looks for the file in the Compiler directory.</p>
+<p>256-color bitmaps may not display correctly in 256-color mode, since it does not handle palettes.</p>
+<p>When multiple files are specified, Setup will select the one which best matches the system's DPI setting. The recommended size of the bitmap per DPI setting is:</p>
+<table>
+<tr><td>100%</td><td>55x55</td></tr>
+<tr><td>125%</td><td>64x68</td></tr>
+<tr><td>150%</td><td>83x80</td></tr>
+<tr><td>175%</td><td>92x97</td></tr>
+<tr><td>200%</td><td>110x106</td></tr>
+<tr><td>225%</td><td>119x123</td></tr>
+<tr><td>250%</td><td>138x140</td></tr>
+</table>
+<example><pre>WizardSmallImageFile=mysmallimage.bmp,mysmallimage2.bmp</pre></example>
 <p><b>See also:</b><br/>
-<link topic="setup_wizardimagealphaformat">WizardImageAlphaFormat</link></p>
+<link topic="setup_wizardimagefile">WizardImageFile</link><br/>
+<link topic="setup_wizardimagealphaformat">WizardImageAlphaFormat</link><br/>
+<link topic="setup_wizardimagestretch">WizardImageStretch</link></p>
 </body>
 </setuptopic>
 
@@ -4508,8 +4543,8 @@ DiskSliceSize=1457664
 <setupvalid><link topic="yesnonotes"><tt>yes</tt> or <tt>no</tt></link></setupvalid>
 <setupdefault><tt>yes</tt></setupdefault>
 <body>
-<p>If set to <tt>yes</tt>, the default, the wizard images will be stretched or shrunk if the wizard is larger or smaller than normal, e.g. if the user is running in Large Fonts.</p>
-<p>If set to <tt>no</tt>, the wizard images will be centered in their respective areas if the wizard is larger than normal, and clipped if the wizard is smaller than normal. (This corresponds to the default behavior of Inno Setup 4.1.2 and earlier.)</p>
+<p>If set to <tt>yes</tt>, the default, the wizard images will be stretched or shrunk if the images are larger or smaller than required.</p>
+<p>If set to <tt>no</tt>, the wizard images will be centered in their respective areas if the images are larger than required, and clipped if the images are smaller than required. (This corresponds to the default behavior of Inno Setup 4.1.2 and earlier.)</p>
 </body>
 </setuptopic>
 
@@ -4549,17 +4584,6 @@ DiskSliceSize=1457664
 </body>
 </setuptopic>
 
-<setuptopic directive="WizardSmallImageFile">
-<setupdefault><tt>compiler:WIZMODERNSMALLIMAGE.BMP</tt></setupdefault>
-<body>
-<p>Specifies the name of the bitmap file to display in the upper right corner of the wizard window. This file must be located in your installation's <link topic="sourcedirectorynotes">source directory</link> when running the Setup Compiler, unless a fully qualified pathname is specified or the pathname is prefixed by "compiler:", in which case it looks for the file in the Compiler directory.</p>
-<p>256-color bitmaps may not display correctly in 256-color mode, since it does not handle palettes. The maximum size of the bitmap is 55x58 pixels.</p>
-<example><pre>WizardSmallImageFile=mysmallimage.bmp</pre></example>
-<p><b>See also:</b><br/>
-<link topic="setup_wizardimagealphaformat">WizardImageAlphaFormat</link></p>
-</body>
-</setuptopic>
-
 <setuptopic directive="AlwaysShowComponentsList">
 <setupvalid><link topic="yesnonotes"><tt>yes</tt> or <tt>no</tt></link></setupvalid>
 <setupdefault><tt>yes</tt></setupdefault>

+ 71 - 25
Projects/Compile.pas

@@ -501,6 +501,7 @@ type
     procedure WriteDebugEntry(Kind: TDebugEntryKind; Index: Integer);
     procedure WriteCompiledCodeText(const CompiledCodeText: Ansistring);
     procedure WriteCompiledCodeDebugInfo(const CompiledCodeDebugInfo: AnsiString);
+    function CreateMemoryStreamsFromFiles(const AFiles: String): TList;
   public
     AppData: Longint;
     CallbackProc: TCompilerCallbackProc;
@@ -701,6 +702,53 @@ begin
   end;
 end;
 
+function ExtractStr(var S: String; const Separator: Char): String;
+var
+  I: Integer;
+begin
+  repeat
+    I := PathPos(Separator, S);
+    if I = 0 then I := Length(S)+1;
+    Result := Trim(Copy(S, 1, I-1));
+    S := Trim(Copy(S, I+1, Maxint));
+  until (Result <> '') or (S = '');
+end;
+
+function TSetupCompiler.CreateMemoryStreamsFromFiles(const AFiles: String): TList;
+
+  procedure AddFile(const Filename: String);
+  begin
+    AddStatus(Format(SCompilerStatusReadingInFile, [FileName]));
+    Result.Add(CreateMemoryStreamFromFile(FileName));    
+  end;
+
+var
+  S, Filename: String;
+begin
+  Result := TList.Create;
+  try
+    { In older versions only one file could be listed and comma's could be used so
+      before treating AFiles as a list, first check if it's actually a single file
+      with a comma in its name. }
+    Filename := PrependSourceDirName(AFiles);
+    if NewFileExists(Filename) then
+       AddFile(Filename)
+    else begin 
+      S := AFiles;
+      while True do begin
+        Filename := ExtractStr(S, ',');
+        if Filename = '' then
+          Break;
+        Filename := PrependSourceDirName(Filename);
+        AddFile(Filename);
+      end;
+    end;
+  except
+    Result.Free;
+    raise;
+  end;
+end;
+
 function FileSizeAndCRCIs(const Filename: String; const Size: Cardinal;
   const CRC: Longint): Boolean;
 var
@@ -2949,18 +2997,6 @@ begin
   end;
 end;
 
-function ExtractStr(var S: String; const Separator: Char): String;
-var
-  I: Integer;
-begin
-  repeat
-    I := PathPos(Separator, S);
-    if I = 0 then I := Length(S)+1;
-    Result := Trim(Copy(S, 1, I-1));
-    S := Trim(Copy(S, I+1, Maxint));
-  until (Result <> '') or (S = '');
-end;
-
 function ExtractFlag(var S: String; const FlagStrs: array of PChar): Integer;
 var
   I: Integer;
@@ -7661,8 +7697,8 @@ var
   SetupFile: TFile;
   ExeFile: TFile;
   LicenseText, InfoBeforeText, InfoAfterText: AnsiString;
-  WizardImage: TMemoryStream;
-  WizardSmallImage: TMemoryStream;
+  WizardImages: TList;
+  WizardSmallImages: TList;
   DecompressorDLL, DecryptionDLL: TMemoryStream;
 
   SetupLdrOffsetTable: TSetupLdrOffsetTable;
@@ -7764,8 +7800,12 @@ var
         SECompressedBlockWrite(W, UninstallRunEntries[J]^, SizeOf(TSetupRunEntry),
           SetupRunEntryStrings, SetupRunEntryAnsiStrings);
 
-      WriteStream(WizardImage, W);
-      WriteStream(WizardSmallImage, W);
+      W.Write(WizardImages.Count, SizeOf(Integer));
+      for J := 0 to WizardImages.Count-1 do
+        WriteStream(WizardImages[J], W);
+      W.Write(WizardSmallImages.Count, SizeOf(Integer));
+      for J := 0 to WizardSmallImages.Count-1 do
+        WriteStream(WizardSmallImages[J], W);
       if SetupHeader.CompressMethod in [cmZip, cmBzip] then
         WriteStream(DecompressorDLL, W);
       if shEncryptionUsed in SetupHeader.Options then
@@ -8360,8 +8400,8 @@ begin
   InitPreprocessor;
   InitLZMADLL;
 
-  WizardImage := nil;
-  WizardSmallImage := nil;
+  WizardImages := nil;
+  WizardSmallImages := nil;
   SetupE32 := nil;
   DecompressorDLL := nil;
   DecryptionDLL := nil;
@@ -8636,12 +8676,10 @@ begin
     { Read wizard image }
     LineNumber := SetupDirectiveLines[ssWizardImageFile];
     AddStatus(Format(SCompilerStatusReadingFile, ['WizardImageFile']));
-    AddStatus(Format(SCompilerStatusReadingInFile, [PrependSourceDirName(WizardImageFile)]));
-    WizardImage := CreateMemoryStreamFromFile(PrependSourceDirName(WizardImageFile));
+    WizardImages := CreateMemoryStreamsFromFiles(WizardImageFile);
     LineNumber := SetupDirectiveLines[ssWizardSmallImageFile];
     AddStatus(Format(SCompilerStatusReadingFile, ['WizardSmallImageFile']));
-    AddStatus(Format(SCompilerStatusReadingInFile, [PrependSourceDirName(WizardSmallImageFile)]));
-    WizardSmallImage := CreateMemoryStreamFromFile(PrependSourceDirName(WizardSmallImageFile));
+    WizardSmallImages := CreateMemoryStreamsFromFiles(WizardSmallImageFile);
     LineNumber := 0;
 
     { Prepare Setup executable & signed uninstaller data }
@@ -8654,7 +8692,7 @@ begin
     { Read languages:
 
       Non Unicode:
-      
+
       1. Read Default.isl messages:
 
       ReadDefaultMessages calls EnumMessages for Default.isl's [Messages], with Ext set to -2.
@@ -9014,8 +9052,16 @@ begin
     DecryptionDLL.Free;
     DecompressorDLL.Free;
     SetupE32.Free;
-    WizardSmallImage.Free;
-    WizardImage.Free;
+    if WizardSmallImages <> nil then begin
+      for I := WizardSmallImages.Count-1 downto 0 do
+        TStream(WizardSmallImages[I]).Free;
+      WizardSmallImages.Free;
+    end;
+    if WizardImages <> nil then begin
+      for I := WizardImages.Count-1 downto 0 do
+        TStream(WizardImages[I]).Free;
+      WizardImages.Free;
+    end;
     FreeListItems(LanguageEntries, SetupLanguageEntryStrings, SetupLanguageEntryAnsiStrings);
     FreeListItems(CustomMessageEntries, SetupCustomMessageEntryStrings, SetupCustomMessageEntryAnsiStrings);
     FreeListItems(PermissionEntries, SetupPermissionEntryStrings, SetupPermissionEntryAnsiStrings);

+ 29 - 11
Projects/Main.pas

@@ -131,8 +131,8 @@ var
   SetupHeader: TSetupHeader;
   LangOptions: TSetupLanguageEntry;
   Entries: array[TEntryType] of TList;
-  WizardImage: TBitmap;
-  WizardSmallImage: TBitmap;
+  WizardImages: TList;
+  WizardSmallImages: TList;
   CloseApplicationsFilterList: TStringList;
 
   { User options }
@@ -2551,7 +2551,7 @@ var
     end;
   end;
 
-  procedure ReadWizardImage(var WizardImage: TBitmap; const R: TCompressedBlockReader);
+  function ReadWizardImage(const R: TCompressedBlockReader): TBitmap;
   var
     MemStream: TMemoryStream;
   begin
@@ -2559,9 +2559,9 @@ var
     try
       ReadFileIntoStream(MemStream, R);
       MemStream.Seek(0, soFromBeginning);
-      WizardImage := TAlphaBitmap.Create;
-      TAlphaBitmap(WizardImage).AlphaFormat := TAlphaFormat(SetupHeader.WizardImageAlphaFormat);
-      WizardImage.LoadFromStream(MemStream);
+      Result := TAlphaBitmap.Create;
+      TAlphaBitmap(Result).AlphaFormat := TAlphaFormat(SetupHeader.WizardImageAlphaFormat);
+      Result.LoadFromStream(MemStream);
     finally
       MemStream.Free;
     end;
@@ -2739,7 +2739,7 @@ var
 var
   ParamName, ParamValue: String;
   StartParam: Integer;
-  I: Integer;
+  I, N: Integer;
   IsRespawnedProcess, EnableLogging, WantToSuppressMsgBoxes, Res: Boolean;
   DebugWndValue: HWND;
   LogFilename: String;
@@ -3021,8 +3021,13 @@ begin
           Integer(@PSetupRunEntry(nil).OnlyBelowVersion));
 
         { Wizard image }
-        ReadWizardImage(WizardImage, Reader);
-        ReadWizardImage(WizardSmallImage, Reader);
+
+        Reader.Read(N, SizeOf(LongInt));
+        for I := 0 to N-1 do
+          WizardImages.Add(ReadWizardImage(Reader));
+        Reader.Read(N, SizeOf(LongInt));
+        for I := 0 to N-1 do
+          WizardSmallImages.Add(ReadWizardImage(Reader));
         { Decompressor DLL }
         DecompressorDLL := nil;
         if SetupHeader.CompressMethod in [cmZip, cmBzip] then begin
@@ -4357,6 +4362,18 @@ begin
   end;
 end;
 
+procedure FreeWizardImages;
+var
+  I: Integer;
+begin
+  for I := WizardImages.Count-1 downto 0 do
+    TBitmap(WizardImages[I]).Free;
+  FreeAndNil(WizardImages);
+  for I := WizardSmallImages.Count-1 downto 0 do
+    TBitmap(WizardSmallImages[I]).Free;
+  FreeAndNil(WizardSmallImages);
+end;
+
 initialization
   IsNT := UsingWinNT;
   InitIsWin64AndProcessorArchitecture;
@@ -4374,12 +4391,13 @@ initialization
   DeleteFilesAfterInstallList := TStringList.Create;
   DeleteDirsAfterInstallList := TStringList.Create;
   CloseApplicationsFilterList := TStringList.Create;
+  WizardImages := TList.Create;
+  WizardSmallImages := TList.Create;
   SHGetKnownFolderPathFunc := GetProcAddress(SafeLoadLibrary(AddBackslash(GetSystemDir) + shell32,
     SEM_NOOPENFILEERRORBOX), 'SHGetKnownFolderPath');
 
 finalization
-  FreeAndNil(WizardImage);
-  FreeAndNil(WizardSmallImage);
+  FreeWizardImages;
   FreeAndNil(CloseApplicationsFilterList);
   FreeAndNil(DeleteDirsAfterInstallList);
   FreeAndNil(DeleteFilesAfterInstallList);

+ 31 - 14
Projects/Wizard.pas

@@ -664,6 +664,23 @@ constructor TWizardForm.Create(AOwner: TComponent);
     end;
   end;
 
+  function SelectBestImage(WizardImages: TList; TargetWidth, TargetHeight: Integer): TBitmap;
+  var
+    TargetArea, Difference, SmallestDifference, I: Integer;
+  begin
+    { Find the image with the smallest area difference compared to the target area. }
+    TargetArea := TargetWidth*TargetHeight;
+    SmallestDifference := -1;
+    Result := nil;
+    for I := 0 to WizardImages.Count-1 do begin
+      Difference := Abs(TargetArea-TBitmap(WizardImages[I]).Width*TBitmap(WizardImages[I]).Height);
+      if (SmallestDifference = -1) or (Difference < SmallestDifference) then begin
+        Result := WizardImages[I];
+        SmallestDifference := Difference;
+      end;
+    end;
+  end;
+
 var
   X, W1, W2: Integer;
   SystemMenu: HMENU;
@@ -686,22 +703,22 @@ begin
 {$IFDEF IS_D7}
   MainPanel.ParentBackground := False;
 {$ENDIF}
-
   { Prior to scaling the form, shrink WizardSmallBitmapImage if it's currently
     larger than WizardSmallImage. This way, stretching will not occur if the
     user specifies a smaller-than-default image and WizardImageStretch=yes,
     except if the form has to be scaled (e.g. due to Large Fonts). }
-  I := WizardSmallBitmapImage.Height - WizardSmallImage.Height;
-  if I > 0 then begin
-    WizardSmallBitmapImage.Height := WizardSmallBitmapImage.Height - I;
-    WizardSmallBitmapImage.Top := WizardSmallBitmapImage.Top + (I div 2);
-  end;
-  I := WizardSmallBitmapImage.Width - WizardSmallImage.Width;
-  if I > 0 then begin
-    WizardSmallBitmapImage.Width := WizardSmallBitmapImage.Width - I;
-    WizardSmallBitmapImage.Left := WizardSmallBitmapImage.Left + (I div 2);
+  if WizardSmallImages.Count = 1 then begin
+    I := WizardSmallBitmapImage.Height - TBitmap(WizardSmallImages[0]).Height;
+    if I > 0 then begin
+      WizardSmallBitmapImage.Height := WizardSmallBitmapImage.Height - I;
+      WizardSmallBitmapImage.Top := WizardSmallBitmapImage.Top + (I div 2);
+    end;
+    I := WizardSmallBitmapImage.Width - TBitmap(WizardSmallImages[0]).Width;
+    if I > 0 then begin
+      WizardSmallBitmapImage.Width := WizardSmallBitmapImage.Width - I;
+      WizardSmallBitmapImage.Left := WizardSmallBitmapImage.Left + (I div 2);
+    end;
   end;
-
   InitializeFont;
   if shWindowVisible in SetupHeader.Options then
     CenterInsideControl(MainForm, True)
@@ -746,13 +763,13 @@ begin
   BackButton.Left := X;
 
   { Initialize images }
-  WizardBitmapImage.Bitmap := WizardImage;
+  WizardBitmapImage.Bitmap := SelectBestImage(WizardImages, WizardBitmapImage.Width, WizardBitmapImage.Height);
   WizardBitmapImage.Center := True;
   WizardBitmapImage.Stretch := (shWizardImageStretch in SetupHeader.Options);
-  WizardBitmapImage2.Bitmap := WizardImage;
+  WizardBitmapImage2.Bitmap := WizardBitmapImage.Bitmap;
   WizardBitmapImage2.Center := True;
   WizardBitmapImage2.Stretch := (shWizardImageStretch in SetupHeader.Options);
-  WizardSmallBitmapImage.Bitmap := WizardSmallImage;
+  WizardSmallBitmapImage.Bitmap := SelectBestImage(WizardSmallImages, WizardSmallBitmapImage.Width, WizardSmallBitmapImage.Height);
   WizardSmallBitmapImage.Stretch := (shWizardImageStretch in SetupHeader.Options);
   PreparingErrorBitmapImage.Bitmap.Handle := LoadBitmap(HInstance, 'STOPIMAGE');
   PreparingErrorBitmapImage.ReplaceColor := clSilver;

+ 2 - 1
whatsnew.htm

@@ -28,7 +28,8 @@ For conditions of distribution and use, see <a href="http://www.jrsoftware.org/f
 
 <p><a name="5.5.10"></a><span class="ver">5.5.10 </span><span class="date">(?)</span></p>
 <ul>
-<li>Added new [Setup] section directive <tt>ArchitecturesAllowed</tt> value: <tt>arm64</tt>. Can be used to not allow Setup to run on Windows 10 on ARM64. Note that Windows 10 on ARM64 only supports 32-bit (x86) binaries and therefore Setup (even in older versions) will never install in 64-bit mode on Windows 10 on ARM64.</li>
+<li>The <tt>WizardImageFile</tt> and <tt>WizardSmallImageFile</tt> [Setup] section directives now may list multiple files. This can be used to include multiple sizes of the wizard images to avoid blurred images on high DPI systems. See the help file for a list of recommended sizes. Note: when you test this be sure to first log out and back in after any DPI change.</li>
+<li>Added new [Setup] section directive <tt>ArchitecturesAllowed</tt> value: <tt>arm64</tt>. This can be used to not allow Setup to run on Windows 10 on ARM64. Note that Windows 10 on ARM64 only supports 32-bit (x86) binaries and therefore Setup (even in older versions) will never install in 64-bit mode on Windows 10 on ARM64.</li>
 <li><i>Fix:</i>In 5.5.9 it was no longer possible to include a drive colon in [Setup] section directive <tt>OutputManifestFile</tt>.</li>
 <li>Minor tweaks.</li>
 </ul>