فهرست منبع

Merge branch 'jensg-maxmemos12'

Martijn Laan 1 سال پیش
والد
کامیت
5e5614b757
8فایلهای تغییر یافته به همراه491 افزوده شده و 152 حذف شده
  1. 144 4
      Components/NewTabSet.pas
  2. 36 0
      Projects/CompForm.dfm
  3. 265 55
      Projects/CompForm.pas
  4. 21 16
      Projects/CompFunc.pas
  5. 1 1
      Projects/CompScintEdit.pas
  6. 2 0
      Projects/Debug.iss
  7. 8 0
      Projects/Debug2.iss
  8. 14 76
      whatsnew.htm

+ 144 - 4
Components/NewTabSet.pas

@@ -2,7 +2,7 @@ unit NewTabSet;
 
 
 {
 {
   Inno Setup
   Inno Setup
-  Copyright (C) 1997-2020 Jordan Russell
+  Copyright (C) 1997-2024 Jordan Russell
   Portions by Martijn Laan
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
   For conditions of distribution and use, see LICENSE.TXT.
 
 
@@ -12,34 +12,52 @@ unit NewTabSet;
 interface
 interface
 
 
 uses
 uses
-  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, ModernColors;
+  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Math, Generics.Collections,
+  ModernColors, UxTheme;
 
 
 type
 type
   TTabPosition = (tpTop, tpBottom);
   TTabPosition = (tpTop, tpBottom);
 
 
+  TBoolList = TList<Boolean>;
+
   TNewTabSet = class(TCustomControl)
   TNewTabSet = class(TCustomControl)
   private
   private
+    FCloseButtons: TBoolList;
     FHints: TStrings;
     FHints: TStrings;
+    FMenuThemeData: HTHEME;
+    FOnCloseButtonClick: TNotifyEvent;
     FTabs: TStrings;
     FTabs: TStrings;
     FTabIndex: Integer;
     FTabIndex: Integer;
     FTabPosition: TTabPosition;
     FTabPosition: TTabPosition;
+    FTabsOffset: Integer;
     FTheme: TTheme;
     FTheme: TTheme;
+    FThemeDark: Boolean;
     function GetTabRect(Index: Integer): TRect;
     function GetTabRect(Index: Integer): TRect;
+    function GetCloseButtonRect(const TabRect: TRect): TRect;
     procedure InvalidateTab(Index: Integer);
     procedure InvalidateTab(Index: Integer);
+    procedure CloseButtonsListChanged(Sender: TObject; const Item: Boolean;
+      Action: TCollectionNotification);
     procedure TabsListChanged(Sender: TObject);
     procedure TabsListChanged(Sender: TObject);
+    procedure HintsListChanged(Sender: TObject);
+    procedure SetCloseButtons(Value: TBoolList);
     procedure SetTabs(Value: TStrings);
     procedure SetTabs(Value: TStrings);
     procedure SetTabIndex(Value: Integer);
     procedure SetTabIndex(Value: Integer);
     procedure SetTabPosition(Value: TTabPosition);
     procedure SetTabPosition(Value: TTabPosition);
     procedure SetTheme(Value: TTheme);
     procedure SetTheme(Value: TTheme);
     procedure SetHints(const Value: TStrings);
     procedure SetHints(const Value: TStrings);
+    procedure UpdateThemeData(const Open: Boolean);
+    procedure EnsureCurrentTabIsFullyVisible;
   protected
   protected
     procedure CMHintShow(var Message: TCMHintShow); message CM_HINTSHOW;
     procedure CMHintShow(var Message: TCMHintShow); message CM_HINTSHOW;
+    procedure WMThemeChanged(var Message: TMessage); message WM_THEMECHANGED;
     procedure CreateParams(var Params: TCreateParams); override;
     procedure CreateParams(var Params: TCreateParams); override;
+    procedure CreateWnd; override;
     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
     procedure Paint; override;
     procedure Paint; override;
   public
   public
     constructor Create(AOwner: TComponent); override;
     constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
     destructor Destroy; override;
+    property CloseButtons: TBoolList read FCloseButtons write SetCloseButtons;
     property Theme: TTheme read FTheme write SetTheme;
     property Theme: TTheme read FTheme write SetTheme;
   published
   published
     property Align;
     property Align;
@@ -49,13 +67,18 @@ type
     property TabIndex: Integer read FTabIndex write SetTabIndex;
     property TabIndex: Integer read FTabIndex write SetTabIndex;
     property Tabs: TStrings read FTabs write SetTabs;
     property Tabs: TStrings read FTabs write SetTabs;
     property TabPosition: TTabPosition read FTabPosition write SetTabPosition default tpBottom;
     property TabPosition: TTabPosition read FTabPosition write SetTabPosition default tpBottom;
+    property PopupMenu;
     property OnClick;
     property OnClick;
+    property OnCloseButtonClick: TNotifyEvent read FOnCloseButtonClick write FOnCloseButtonClick;
   end;
   end;
 
 
 procedure Register;
 procedure Register;
 
 
 implementation
 implementation
 
 
+uses
+  WinApi.UxTheme;
+
 procedure Register;
 procedure Register;
 begin
 begin
   RegisterComponents('JR', [TNewTabSet]);
   RegisterComponents('JR', [TNewTabSet]);
@@ -135,14 +158,18 @@ const
   TabPaddingX = 5;
   TabPaddingX = 5;
   TabPaddingY = 3;
   TabPaddingY = 3;
   TabSpacing = 1;
   TabSpacing = 1;
+  CloseButtonSizeX = 12;
 
 
 constructor TNewTabSet.Create(AOwner: TComponent);
 constructor TNewTabSet.Create(AOwner: TComponent);
 begin
 begin
   inherited;
   inherited;
+  FCloseButtons := TBoolList.Create;
+  FCloseButtons.OnNotify := CloseButtonsListChanged;
   FTabs := TStringList.Create;
   FTabs := TStringList.Create;
   TStringList(FTabs).OnChange := TabsListChanged;
   TStringList(FTabs).OnChange := TabsListChanged;
   FTabPosition := tpBottom;
   FTabPosition := tpBottom;
   FHints := TStringList.Create;
   FHints := TStringList.Create;
+  TStringList(FHints).OnChange := HintsListChanged;
   ControlStyle := ControlStyle + [csOpaque];
   ControlStyle := ControlStyle + [csOpaque];
   Width := 129;
   Width := 129;
   Height := 21;
   Height := 21;
@@ -155,8 +182,15 @@ begin
     style := style and not (CS_HREDRAW or CS_VREDRAW);
     style := style and not (CS_HREDRAW or CS_VREDRAW);
 end;
 end;
 
 
+procedure TNewTabSet.CreateWnd;
+begin
+  inherited;
+  UpdateThemeData(True);
+end;
+
 destructor TNewTabSet.Destroy;
 destructor TNewTabSet.Destroy;
 begin
 begin
+  UpdateThemeData(False);
   FTabs.Free;
   FTabs.Free;
   inherited;
   inherited;
 end;
 end;
@@ -181,6 +215,13 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TNewTabSet.WMThemeChanged(var Message: TMessage);
+begin
+  { Don't Run to Cursor into this function, it will interrupt up the theme change }
+  UpdateThemeData(True);
+  inherited;
+end;
+
 function TNewTabSet.GetTabRect(Index: Integer): TRect;
 function TNewTabSet.GetTabRect(Index: Integer): TRect;
 var
 var
   CR: TRect;
   CR: TRect;
@@ -191,10 +232,12 @@ begin
   Canvas.Font.Assign(Font);
   Canvas.Font.Assign(Font);
   if FTabPosition = tpBottom then
   if FTabPosition = tpBottom then
     Result.Top := 0;
     Result.Top := 0;
-  Result.Right := 4;
+  Result.Right := 4 - FTabsOffset;
   for I := 0 to FTabs.Count-1 do begin
   for I := 0 to FTabs.Count-1 do begin
     Size := Canvas.TextExtent(FTabs[I]);
     Size := Canvas.TextExtent(FTabs[I]);
     SizeX := Size.cx + (TabPaddingX * 2) + TabSpacing;
     SizeX := Size.cx + (TabPaddingX * 2) + TabSpacing;
+    if (I < FCloseButtons.Count) and FCloseButtons[I] then
+      Inc(SizeX, MulDiv(CloseButtonSizeX, CurrentPPI, 96));
     SizeY := Size.cy + (TabPaddingY * 2);
     SizeY := Size.cy + (TabPaddingY * 2);
     if FTabPosition = tpTop then
     if FTabPosition = tpTop then
       Result.Top := CR.Bottom - SizeY;
       Result.Top := CR.Bottom - SizeY;
@@ -205,6 +248,12 @@ begin
   SetRectEmpty(Result);
   SetRectEmpty(Result);
 end;
 end;
 
 
+function TNewTabSet.GetCloseButtonRect(const TabRect: TRect): TRect;
+begin
+  Result := TRect.Create(TabRect.Right - MulDiv(CloseButtonSizeX, CurrentPPI, 96) - TabPaddingX div 2,
+    TabRect.Top, TabRect.Right - TabPaddingX div 2, TabRect.Bottom);
+end;
+
 procedure TNewTabSet.InvalidateTab(Index: Integer);
 procedure TNewTabSet.InvalidateTab(Index: Integer);
 var
 var
   R: TRect;
   R: TRect;
@@ -218,11 +267,22 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TNewTabSet.CloseButtonsListChanged(Sender: TObject; const Item: Boolean;
+  Action: TCollectionNotification);
+begin
+  Invalidate;
+end;
+
 procedure TNewTabSet.TabsListChanged(Sender: TObject);
 procedure TNewTabSet.TabsListChanged(Sender: TObject);
 begin
 begin
   Invalidate;
   Invalidate;
 end;
 end;
 
 
+procedure TNewTabSet.HintsListChanged(Sender: TObject);
+begin
+  ShowHint := FHints.Count > 0;
+end;
+
 procedure TNewTabSet.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
 procedure TNewTabSet.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
   Y: Integer);
   Y: Integer);
 var
 var
@@ -233,6 +293,14 @@ begin
     for I := 0 to FTabs.Count-1 do begin
     for I := 0 to FTabs.Count-1 do begin
       R := GetTabRect(I);
       R := GetTabRect(I);
       if (X >= R.Left) and (X < R.Right) then begin
       if (X >= R.Left) and (X < R.Right) then begin
+        if (I = TabIndex) and (I < FCloseButtons.Count) and FCloseButtons[I] then begin
+          var R2 := GetCloseButtonRect(R);
+          if PtInRect(R2, TPoint.Create(X, Y)) then begin
+            if Assigned(OnCloseButtonClick) then
+              OnCloseButtonClick(Self);
+            Break;
+          end;
+        end;
         TabIndex := I;
         TabIndex := I;
         Break;
         Break;
       end;
       end;
@@ -264,6 +332,23 @@ var
         else
         else
           Canvas.Font.Color := clBtnText;
           Canvas.Font.Color := clBtnText;
         Canvas.TextOut(R.Left + TabPaddingX, R.Top + TabPaddingY, FTabs[I]);
         Canvas.TextOut(R.Left + TabPaddingX, R.Top + TabPaddingY, FTabs[I]);
+
+       if (I < FCloseButtons.Count) and FCloseButtons[I] then begin
+          var R2 := GetCloseButtonRect(R);
+          if FMenuThemeData <> 0 then begin
+            var Offset := MulDiv(1, CurrentPPI, 96);
+            Inc(R2.Left, Offset);
+            Inc(R2.Top, Offset);
+            DrawThemeBackground(FMenuThemeData, Canvas.Handle,  MENU_SYSTEMCLOSE, MSYSC_NORMAL, R2, nil);
+          end else begin
+            InflateRect(R2, -MulDiv(3, CurrentPPI, 96), -MulDiv(6, CurrentPPI, 96));
+            Canvas.Pen.Color := Canvas.Font.Color;
+            Canvas.MoveTo(R2.Left, R2.Top);
+            Canvas.LineTo(R2.Right, R2.Bottom);
+            Canvas.MoveTo(R2.Left, R2.Bottom-1);
+            Canvas.LineTo(R2.Right, R2.Top-1);
+          end;
+        end;
         ExcludeClipRect(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom);
         ExcludeClipRect(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom);
         Break;
         Break;
       end;
       end;
@@ -332,10 +417,16 @@ begin
   DrawTabs(False);
   DrawTabs(False);
 end;
 end;
 
 
+procedure TNewTabSet.SetCloseButtons(Value: TBoolList);
+begin
+  FCloseButtons.Clear;
+  for var V in Value do
+    FCloseButtons.Add(V);
+end;
+
 procedure TNewTabSet.SetHints(const Value: TStrings);
 procedure TNewTabSet.SetHints(const Value: TStrings);
 begin
 begin
   FHints.Assign(Value);
   FHints.Assign(Value);
-  ShowHint := FHints.Count > 0;
 end;
 end;
 
 
 procedure TNewTabSet.SetTabIndex(Value: Integer);
 procedure TNewTabSet.SetTabIndex(Value: Integer);
@@ -344,6 +435,7 @@ begin
     InvalidateTab(FTabIndex);
     InvalidateTab(FTabIndex);
     FTabIndex := Value;
     FTabIndex := Value;
     InvalidateTab(Value);
     InvalidateTab(Value);
+    EnsureCurrentTabIsFullyVisible;
     Click;
     Click;
   end;
   end;
 end;
 end;
@@ -367,8 +459,56 @@ procedure TNewTabSet.SetTheme(Value: TTheme);
 begin
 begin
   if FTheme <> Value then begin
   if FTheme <> Value then begin
     FTheme := Value;
     FTheme := Value;
+    var NewThemeDark := (FTheme <> nil) and FTheme.Dark;
+    if FThemeDark <> NewThemeDark then
+      UpdateThemeData(True);
+    FThemeDark := NewThemeDark;
     Invalidate;
     Invalidate;
   end;
   end;
 end;
 end;
 
 
+procedure TNewTabSet.UpdateThemeData(const Open: Boolean);
+begin
+  if FMenuThemeData <> 0 then begin
+    CloseThemeData(FMenuThemeData);
+    FMenuThemeData := 0;
+  end;
+
+  if Open and UseThemes then begin
+    if (FTheme <> nil) and FTheme.Dark then
+      FMenuThemeData := OpenThemeData(Handle, 'DarkMode::Menu');
+    if FMenuThemeData = 0 then
+      FMenuThemeData := OpenThemeData(Handle, 'Menu');
+end;
+end;
+
+procedure TNewTabSet.EnsureCurrentTabIsFullyVisible;
+var
+  rcTab, rcCtl, rcLast: TRect;
+  iExtra, iDelta, iNewOffset: Integer;
+begin
+  rcCtl := ClientRect;
+  rcTab := GetTabRect(FTabIndex);
+
+  { Check and modify tabs offset so everything fits }
+  iExtra := Min(rcCtl.Width div 2, rcTab.Width * 4);  { arbitrary value, adjust as needed }
+  iDelta := rcTab.Width div 2;                        { arbitrary value, adjust as needed }
+
+  { Left side is easy, limit is always 0 }
+  if rcTab.Left < rcCtl.Left + iDelta then begin
+    FTabsOffset := Max(0, FTabsOffset - rcCtl.Left - rcTab.Left - iExtra);
+    Invalidate;
+  end;
+
+  { Right side limit depends on last tab and total available space }
+  if rcTab.Right > rcCtl.Right - iDelta then begin
+    iNewOffset := FTabsOffset + (rcTab.Right - rcCtl.Right) + iExtra;
+    FTabsOffset := 0; { We need the last tabs leftmost position w/o any offset }
+    rcLast := GetTabRect(FTabs.Count-1);
+    FTabsOffset := Max(0, Min(iNewOffset, rcLast.Right - rcCtl.Width + 10));
+    Invalidate;
+  end;
+end;
+
+
 end.
 end.

+ 36 - 0
Projects/CompForm.dfm

@@ -159,6 +159,10 @@ object CompileForm: TCompileForm
         Text = 'Insert'
         Text = 'Insert'
         Width = 64
         Width = 64
       end
       end
+      item
+        Bevel = pbNone
+        Width = 100
+      end
       item
       item
         Bevel = pbNone
         Bevel = pbNone
         Style = psOwnerDraw
         Style = psOwnerDraw
@@ -173,6 +177,7 @@ object CompileForm: TCompileForm
         Bevel = pbNone
         Bevel = pbNone
         Width = 50
         Width = 50
       end>
       end>
+    OnClick = StatusBarClick
     OnDrawPanel = StatusBarDrawPanel
     OnDrawPanel = StatusBarDrawPanel
     OnResize = StatusBarResize
     OnResize = StatusBarResize
   end
   end
@@ -329,10 +334,12 @@ object CompileForm: TCompileForm
     Width = 361
     Width = 361
     Height = 21
     Height = 21
     Align = alTop
     Align = alTop
+    OnCloseButtonClick = MemosTabSetOnCloseButtonClick
     TabIndex = 0
     TabIndex = 0
     Tabs.Strings = (
     Tabs.Strings = (
       'Main Script')
       'Main Script')
     TabPosition = tpTop
     TabPosition = tpTop
+    PopupMenu = MemosTabSetPopupMenu
     OnClick = MemosTabSetClick
     OnClick = MemosTabSetClick
   end
   end
   object MainMenu1: TMainMenu
   object MainMenu1: TMainMenu
@@ -528,6 +535,18 @@ object CompileForm: TCompileForm
         ShortCut = 24585
         ShortCut = 24585
         OnClick = VPreviousTabClick
         OnClick = VPreviousTabClick
       end
       end
+      object VCloseTab: TMenuItem
+        Caption = 'Close Tab'
+        ShortCut = 16499
+        OnClick = VCloseTabClick
+      end
+      object VReopenTab: TMenuItem
+        Caption = 'Reopen Tab'
+      end
+      object VReopenTabs: TMenuItem
+        Caption = 'Reopen All Tabs'
+        OnClick = VReopenTabsClick
+      end
       object N20: TMenuItem
       object N20: TMenuItem
         Caption = '-'
         Caption = '-'
       end
       end
@@ -4307,4 +4326,21 @@ object CompileForm: TCompileForm
     Left = 224
     Left = 224
     Top = 149
     Top = 149
   end
   end
+  object MemosTabSetPopupMenu: TPopupMenu
+    OnPopup = MemosTabSetPopup
+    Left = 48
+    Top = 51
+    object VCloseTab2: TMenuItem
+      Caption = 'Close Current Tab'
+      ShortCut = 16499
+      OnClick = VCloseTabClick
+    end
+    object VReopenTab2: TMenuItem
+      Caption = 'Reopen Tab'
+    end
+    object VReopenTabs2: TMenuItem
+      Caption = 'Reopen All Tabs'
+      OnClick = VReopenTabsClick
+    end
+  end
 end
 end

+ 265 - 55
Projects/CompForm.pas

@@ -211,6 +211,13 @@ type
     PrintDialog: TPrintDialog;
     PrintDialog: TPrintDialog;
     FSaveEncodingUTF8NoPreamble: TMenuItem;
     FSaveEncodingUTF8NoPreamble: TMenuItem;
     TFilesDesigner: TMenuItem;
     TFilesDesigner: TMenuItem;
+    VCloseTab: TMenuItem;
+    VReopenTab: TMenuItem;
+    VReopenTabs: TMenuItem;
+    MemosTabSetPopupMenu: TPopupMenu;
+    VCloseTab2: TMenuItem;
+    VReopenTab2: TMenuItem;
+    VReopenTabs2: TMenuItem;
     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
     procedure FExitClick(Sender: TObject);
     procedure FExitClick(Sender: TObject);
     procedure FOpenMainFileClick(Sender: TObject);
     procedure FOpenMainFileClick(Sender: TObject);
@@ -311,12 +318,19 @@ type
     procedure FindResultsListDblClick(Sender: TObject);
     procedure FindResultsListDblClick(Sender: TObject);
     procedure FPrintClick(Sender: TObject);
     procedure FPrintClick(Sender: TObject);
     procedure TFilesDesignerClick(Sender: TObject);
     procedure TFilesDesignerClick(Sender: TObject);
+    procedure VCloseTabClick(Sender: TObject);
+    procedure VReopenTabClick(Sender: TObject);
+    procedure VReopenTabsClick(Sender: TObject);
+    procedure MemosTabSetPopup(Sender: TObject);
+    procedure MemosTabSetOnCloseButtonClick(Sender: TObject);
+    procedure StatusBarClick(Sender: TObject);
   private
   private
     { Private declarations }
     { Private declarations }
     FMemos: TList<TCompScintEdit>;                      { FMemos[0] is the main memo and FMemos[1] the preprocessor output memo - also see MemosTabSet comment above }
     FMemos: TList<TCompScintEdit>;                      { FMemos[0] is the main memo and FMemos[1] the preprocessor output memo - also see MemosTabSet comment above }
     FMainMemo: TCompScintFileEdit;                      { Doesn't change }
     FMainMemo: TCompScintFileEdit;                      { Doesn't change }
     FPreprocessorOutputMemo: TCompScintEdit;            { Doesn't change }
     FPreprocessorOutputMemo: TCompScintEdit;            { Doesn't change }
-    FFileMemos: TList<TCompScintFileEdit>;              { All memos except FPreprocessorOutputMemo }
+    FFileMemos: TList<TCompScintFileEdit>;              { All memos except FPreprocessorOutputMemo, including those without a tab }
+    FHiddenFiles: TStringList;                          { List of files which *do* use a memo but are hidden by the user and have no tab }
     FActiveMemo: TCompScintEdit;                        { Changes depending on user input }
     FActiveMemo: TCompScintEdit;                        { Changes depending on user input }
     FErrorMemo, FStepMemo: TCompScintFileEdit;          { These change depending on user input }
     FErrorMemo, FStepMemo: TCompScintFileEdit;          { These change depending on user input }
     FMemosStyler: TInnoSetupStyler;                     { Single styler for all memos }
     FMemosStyler: TInnoSetupStyler;                     { Single styler for all memos }
@@ -420,7 +434,7 @@ type
     function InitializeNonFileMemo(const Memo: TCompScintEdit; const PopupMenu: TPopupMenu): TCompScintEdit;
     function InitializeNonFileMemo(const Memo: TCompScintEdit; const PopupMenu: TPopupMenu): TCompScintEdit;
     procedure InitiateAutoComplete(const Key: AnsiChar);
     procedure InitiateAutoComplete(const Key: AnsiChar);
     procedure InvalidateStatusPanel(const Index: Integer);
     procedure InvalidateStatusPanel(const Index: Integer);
-    procedure LoadKnownIncludedFilesAndUpdateMemos(const AFilename: String);
+    procedure LoadKnownIncludedAndHiddenFilesAndUpdateMemos(const AFilename: String);
     procedure MemoChange(Sender: TObject; const Info: TScintEditChangeInfo);
     procedure MemoChange(Sender: TObject; const Info: TScintEditChangeInfo);
     procedure MemoCharAdded(Sender: TObject; Ch: AnsiChar);
     procedure MemoCharAdded(Sender: TObject; Ch: AnsiChar);
     procedure MainMemoDropFiles(Sender: TObject; X, Y: Integer; AFiles: TStrings);
     procedure MainMemoDropFiles(Sender: TObject; X, Y: Integer; AFiles: TStrings);
@@ -434,9 +448,10 @@ type
     procedure MemoModifiedChange(Sender: TObject);
     procedure MemoModifiedChange(Sender: TObject);
     function MemoToTabIndex(const AMemo: TCompScintEdit): Integer;
     function MemoToTabIndex(const AMemo: TCompScintEdit): Integer;
     procedure MemoUpdateUI(Sender: TObject);
     procedure MemoUpdateUI(Sender: TObject);
+    procedure UpdateReopenTabMenu(const Menu: TMenuItem);
     procedure ModifyMRUMainFilesList(const AFilename: String; const AddNewItem: Boolean);
     procedure ModifyMRUMainFilesList(const AFilename: String; const AddNewItem: Boolean);
     procedure ModifyMRUParametersList(const AParameter: String; const AddNewItem: Boolean);
     procedure ModifyMRUParametersList(const AParameter: String; const AddNewItem: Boolean);
-    procedure MoveCaretAndActivateMemo(const AMemo: TCompScintEdit; const LineNumber: Integer; const AlwaysResetColumn: Boolean);
+    procedure MoveCaretAndActivateMemo(AMemo: TCompScintFileEdit; const LineNumber: Integer; const AlwaysResetColumn: Boolean);
     procedure NewMainFile;
     procedure NewMainFile;
     procedure NewMainFileUsingWizard;
     procedure NewMainFileUsingWizard;
     procedure OpenFile(AMemo: TCompScintFileEdit; AFilename: String; const MainMemoAddToRecentDocs: Boolean);
     procedure OpenFile(AMemo: TCompScintFileEdit; AFilename: String; const MainMemoAddToRecentDocs: Boolean);
@@ -444,10 +459,11 @@ type
     procedure ParseDebugInfo(DebugInfo: Pointer);
     procedure ParseDebugInfo(DebugInfo: Pointer);
     procedure ReadMRUMainFilesList;
     procedure ReadMRUMainFilesList;
     procedure ReadMRUParametersList;
     procedure ReadMRUParametersList;
+    procedure ReopenTabOrTabs(const HiddenFileIndex: Integer; const Activate: Boolean);
     procedure ResetAllMemosLineState;
     procedure ResetAllMemosLineState;
     procedure StartProcess;
     procedure StartProcess;
     function SaveFile(const AMemo: TCompScintFileEdit; const SaveAs: Boolean): Boolean;
     function SaveFile(const AMemo: TCompScintFileEdit; const SaveAs: Boolean): Boolean;
-    procedure SaveKnownIncludedFiles(const AFilename: String);
+    procedure SaveKnownIncludedAndHiddenFiles(const AFilename: String);
     procedure SetErrorLine(const AMemo: TCompScintFileEdit; const ALine: Integer);
     procedure SetErrorLine(const AMemo: TCompScintFileEdit; const ALine: Integer);
     procedure SetStatusPanelVisible(const AVisible: Boolean);
     procedure SetStatusPanelVisible(const AVisible: Boolean);
     procedure SetStepLine(const AMemo: TCompScintFileEdit; ALine: Integer);
     procedure SetStepLine(const AMemo: TCompScintFileEdit; ALine: Integer);
@@ -465,6 +481,7 @@ type
     procedure UpdateCompileStatusPanels(const AProgress, AProgressMax: Cardinal;
     procedure UpdateCompileStatusPanels(const AProgress, AProgressMax: Cardinal;
       const ASecondsRemaining: Integer; const ABytesCompressedPerSecond: Cardinal);
       const ASecondsRemaining: Integer; const ABytesCompressedPerSecond: Cardinal);
     procedure UpdateEditModePanel;
     procedure UpdateEditModePanel;
+    procedure UpdateHiddenFilesPanel;
     procedure UpdatePreprocMemos;
     procedure UpdatePreprocMemos;
     procedure UpdateLineMarkers(const AMemo: TCompScintFileEdit; const Line: Integer);
     procedure UpdateLineMarkers(const AMemo: TCompScintFileEdit; const Line: Integer);
     procedure UpdateMemosTabSetVisibility;
     procedure UpdateMemosTabSetVisibility;
@@ -475,7 +492,7 @@ type
     procedure UpdateSaveMenuItemAndButton;
     procedure UpdateSaveMenuItemAndButton;
     procedure UpdateTargetMenu;
     procedure UpdateTargetMenu;
     procedure UpdateTheme;
     procedure UpdateTheme;
-    procedure UpdateThemeData(const Close, Open: Boolean);
+    procedure UpdateThemeData(const Open: Boolean);
     procedure UpdateStatusPanelHeight(H: Integer);
     procedure UpdateStatusPanelHeight(H: Integer);
     procedure WMCopyData(var Message: TWMCopyData); message WM_COPYDATA;
     procedure WMCopyData(var Message: TWMCopyData); message WM_COPYDATA;
     procedure WMDebuggerHello(var Message: TMessage); message WM_Debugger_Hello;
     procedure WMDebuggerHello(var Message: TMessage); message WM_Debugger_Hello;
@@ -527,16 +544,17 @@ uses
 
 
 const
 const
   { Memos }
   { Memos }
-  MaxMemos = 12; { Includes the main and preprocessor output memo's }
+  MaxMemos = 22; { Includes the main and preprocessor output memos }
   FirstIncludedFilesMemoIndex = 1; { This is an index into FFileMemos }
   FirstIncludedFilesMemoIndex = 1; { This is an index into FFileMemos }
 
 
   { Status bar panel indexes }
   { Status bar panel indexes }
   spCaretPos = 0;
   spCaretPos = 0;
   spModified = 1;
   spModified = 1;
   spEditMode = 2;
   spEditMode = 2;
-  spCompileIcon = 3;
-  spCompileProgress = 4;
-  spExtraStatus = 5;
+  spHiddenFilesCount = 3;
+  spCompileIcon = 4;
+  spCompileProgress = 5;
+  spExtraStatus = 6;
 
 
   { Output tab set indexes }
   { Output tab set indexes }
   tiCompilerOutput = 0;
   tiCompilerOutput = 0;
@@ -764,6 +782,7 @@ begin
   for Memo in FMemos do
   for Memo in FMemos do
     if Memo is TCompScintFileEdit then
     if Memo is TCompScintFileEdit then
       FFileMemos.Add(TCompScintFileEdit(Memo));
       FFileMemos.Add(TCompScintFileEdit(Memo));
+  FHiddenFiles := TStringList.Create(dupError, True, True);
   FActiveMemo := FMainMemo;
   FActiveMemo := FMainMemo;
   FActiveMemo.Visible := True;
   FActiveMemo.Visible := True;
   FErrorMemo := FMainMemo;
   FErrorMemo := FMainMemo;
@@ -797,7 +816,7 @@ begin
 
 
   UpdateCaption;
   UpdateCaption;
 
 
-  UpdateThemeData(False, True);
+  UpdateThemeData(True);
 
 
   if CommandLineCompile then begin
   if CommandLineCompile then begin
     ReadSignTools(FSignTools);
     ReadSignTools(FSignTools);
@@ -849,7 +868,7 @@ destructor TCompileForm.Destroy;
   end;
   end;
 
 
 begin
 begin
-  UpdateThemeData(True, False);
+  UpdateThemeData(False);
 
 
   Application.OnActivate := nil;
   Application.OnActivate := nil;
   Application.OnIdle := nil;
   Application.OnIdle := nil;
@@ -870,6 +889,7 @@ begin
   FMRUParametersList.Free;
   FMRUParametersList.Free;
   FMRUMainFilesList.Free;
   FMRUMainFilesList.Free;
   FFileMemos.Free;
   FFileMemos.Free;
+  FHiddenFiles.Free;
   FMemos.Free;
   FMemos.Free;
 
 
   inherited;
   inherited;
@@ -1012,6 +1032,8 @@ begin
     FDebugTarget := dtSetup;
     FDebugTarget := dtSetup;
     UpdateTargetMenu;
     UpdateTargetMenu;
   end;
   end;
+  FHiddenFiles.Clear;
+  UpdateHiddenFilesPanel;
   for Memo in FFileMemos do
   for Memo in FFileMemos do
     if Memo.Used then
     if Memo.Used then
       Memo.BreakPoints.Clear;
       Memo.BreakPoints.Clear;
@@ -1028,7 +1050,7 @@ begin
   FMainMemo.ClearUndo;
   FMainMemo.ClearUndo;
 end;
 end;
 
 
-procedure TCompileForm.LoadKnownIncludedFilesAndUpdateMemos(const AFilename: String);
+procedure TCompileForm.LoadKnownIncludedAndHiddenFilesAndUpdateMemos(const AFilename: String);
 var
 var
   Strings: TStringList;
   Strings: TStringList;
   IncludedFile: TIncludedFile;
   IncludedFile: TIncludedFile;
@@ -1041,7 +1063,7 @@ begin
     if AFilename <> '' then begin
     if AFilename <> '' then begin
       Strings := TStringList.Create;
       Strings := TStringList.Create;
       try
       try
-        LoadKnownIncludedFiles(AFilename, Strings);
+        LoadKnownIncludedAndHiddenFiles(AFilename, Strings, FHiddenFiles);
         if Strings.Count > 0 then begin
         if Strings.Count > 0 then begin
           try
           try
             for I := 0 to Strings.Count-1 do begin
             for I := 0 to Strings.Count-1 do begin
@@ -1065,7 +1087,7 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TCompileForm.SaveKnownIncludedFiles(const AFilename: String);
+procedure TCompileForm.SaveKnownIncludedAndHiddenFiles(const AFilename: String);
 var
 var
   Strings: TStringList;
   Strings: TStringList;
   IncludedFile: TIncludedFile;
   IncludedFile: TIncludedFile;
@@ -1076,7 +1098,7 @@ begin
       try
       try
         for IncludedFile in FIncludedFiles do
         for IncludedFile in FIncludedFiles do
           Strings.Add(IncludedFile.Filename);
           Strings.Add(IncludedFile.Filename);
-        CompFunc.SaveKnownIncludedFiles(AFilename, Strings);
+        CompFunc.SaveKnownIncludedAndHiddenFiles(AFilename, Strings, FHiddenFiles);
       finally
       finally
         Strings.Free;
         Strings.Free;
       end;
       end;
@@ -1184,7 +1206,8 @@ begin
     ModifyMRUMainFilesList(AFilename, True);
     ModifyMRUMainFilesList(AFilename, True);
     if MainMemoAddToRecentDocs then
     if MainMemoAddToRecentDocs then
       AddFileToRecentDocs(AFilename);
       AddFileToRecentDocs(AFilename);
-    LoadKnownIncludedFilesAndUpdateMemos(AFilename);
+    LoadKnownIncludedAndHiddenFilesAndUpdateMemos(AFilename);
+    UpdateHiddenFilesPanel;
   end;
   end;
 end;
 end;
 
 
@@ -1268,7 +1291,7 @@ begin
   Result := True;
   Result := True;
   if AMemo = FMainMemo then begin
   if AMemo = FMainMemo then begin
     ModifyMRUMainFilesList(AMemo.Filename, True);
     ModifyMRUMainFilesList(AMemo.Filename, True);
-    SaveKnownIncludedFiles(AMemo.Filename);
+    SaveKnownIncludedAndHiddenFiles(AMemo.Filename);
   end;
   end;
 end;
 end;
 
 
@@ -1433,6 +1456,30 @@ function CompilerCallbackProc(Code: Integer; var Data: TCompilerCallbackData;
     end;
     end;
   end;
   end;
 
 
+  procedure CleanHiddenFiles(const IncludedFiles: TIncludedFiles; const HiddenFiles: TStringList);
+  var
+    HiddenFileIncluded: array of Boolean;
+  begin
+    if HiddenFiles.Count > 0 then begin
+      { Clean previously hidden files which are no longer included }
+      if IncludedFiles.Count > 0 then begin
+        SetLength(HiddenFileIncluded, HiddenFiles.Count);
+        for var I := 0 to HiddenFiles.Count-1 do
+          HiddenFileIncluded[I] := False;
+        for var I := 0 to IncludedFiles.Count-1 do begin
+          var IncludedFile := IncludedFiles[I];
+          var HiddenFileIndex := HiddenFiles.IndexOf(IncludedFile.Filename);
+          if HiddenFileIndex <> -1 then
+            HiddenFileIncluded[HiddenFileIndex] := True;
+        end;
+        for var I := HiddenFiles.Count-1 downto 0 do
+          if not HiddenFileIncluded[I] then
+            HiddenFiles.Delete(I);
+      end else
+        HiddenFiles.Clear;
+    end;
+  end;
+
 begin
 begin
   Result := iscrSuccess;
   Result := iscrSuccess;
   with PAppData(AppData)^ do
   with PAppData(AppData)^ do
@@ -1480,7 +1527,9 @@ begin
         begin
         begin
           Form.FPreprocessorOutput := TrimRight(Data.PreprocessedScript);
           Form.FPreprocessorOutput := TrimRight(Data.PreprocessedScript);
           DecodeIncludedFilenames(Data.IncludedFilenames, Form.FIncludedFiles); { Also stores last write time }
           DecodeIncludedFilenames(Data.IncludedFilenames, Form.FIncludedFiles); { Also stores last write time }
-          Form.SaveKnownIncludedFiles(Filename);
+          CleanHiddenFiles(Form.FIncludedFiles, Form.FHiddenFiles);
+          Form.UpdateHiddenFilesPanel;
+          Form.SaveKnownIncludedAndHiddenFiles(Filename);
         end;
         end;
       iscbNotifySuccess:
       iscbNotifySuccess:
         begin
         begin
@@ -2247,6 +2296,11 @@ begin
   VStatusBar.Checked := StatusBar.Visible;
   VStatusBar.Checked := StatusBar.Visible;
   VNextTab.Enabled := MemosTabSet.Visible and (MemosTabSet.Tabs.Count > 1);
   VNextTab.Enabled := MemosTabSet.Visible and (MemosTabSet.Tabs.Count > 1);
   VPreviousTab.Enabled := VNextTab.Enabled;
   VPreviousTab.Enabled := VNextTab.Enabled;
+  VCloseTab.Enabled := MemosTabSet.Visible and (FActiveMemo <> FMainMemo) and (FActiveMemo <> FPreprocessorOutputMemo);
+  VReopenTab.Visible := MemosTabSet.Visible and (FHiddenFiles.Count > 0);
+  if VReopenTab.Visible then
+    UpdateReopenTabMenu(VReopenTab);
+  VReopenTabs.Visible := VReopenTab.Visible;
   VHide.Checked := not StatusPanel.Visible;
   VHide.Checked := not StatusPanel.Visible;
   VCompilerOutput.Checked := StatusPanel.Visible and (OutputTabSet.TabIndex = tiCompilerOutput);
   VCompilerOutput.Checked := StatusPanel.Visible and (OutputTabSet.TabIndex = tiCompilerOutput);
   VDebugOutput.Checked := StatusPanel.Visible and (OutputTabSet.TabIndex = tiDebugOutput);
   VDebugOutput.Checked := StatusPanel.Visible and (OutputTabSet.TabIndex = tiDebugOutput);
@@ -2274,6 +2328,59 @@ begin
   MemosTabSet.TabIndex := NewTabIndex;
   MemosTabSet.TabIndex := NewTabIndex;
 end;
 end;
 
 
+procedure TCompileForm.VCloseTabClick(Sender: TObject);
+begin
+  var Index := MemoToTabIndex(FActiveMemo);
+  MemosTabSet.Tabs.Delete(Index);
+  MemosTabSet.Hints.Delete(Index);
+  MemosTabSet.CloseButtons.Delete(Index);
+  FActiveMemo.Visible := False;
+  FHiddenFiles.Add((FActiveMemo as TCompScintFileEdit).Filename);
+  UpdateHiddenFilesPanel;
+  SaveKnownIncludedAndHiddenFiles(FMainMemo.Filename);
+
+  { Select next tab, except when we're already at the end }
+  VNextTabClick(Self);
+  VPreviousTabClick(Self);
+end;
+
+procedure TCompileForm.ReopenTabOrTabs(const HiddenFileIndex: Integer;
+  const Activate: Boolean);
+begin
+  var ReopenFilename: String;
+  if HiddenFileIndex >= 0 then begin
+    ReopenFilename := FHiddenFiles[HiddenFileIndex];
+    FHiddenFiles.Delete(HiddenFileIndex);
+  end else begin
+    ReopenFilename := FHiddenFiles[0];
+    FHiddenFiles.Clear;
+  end;
+  UpdateHiddenFilesPanel;
+
+  UpdatePreprocMemos;
+  SaveKnownIncludedAndHiddenFiles(FMainMemo.Filename);
+
+  { Activate the memo if requested }
+  if Activate then begin
+    for var Memo in FFileMemos do begin
+      if Memo.Used and (PathCompare(Memo.Filename, ReopenFilename) = 0) then begin
+        MemosTabSet.TabIndex := MemoToTabIndex(memo);
+        Break;
+      end;
+    end
+  end;
+end;
+
+procedure TCompileForm.VReopenTabClick(Sender: TObject);
+begin
+  ReopenTabOrTabs((Sender as TMenuItem).Tag, True);
+end;
+
+procedure TCompileForm.VReopenTabsClick(Sender: TObject);
+begin
+  ReopenTabOrTabs(-1, True);
+end;
+
 procedure TCompileForm.SyncZoom;
 procedure TCompileForm.SyncZoom;
 var
 var
   Memo: TCompScintEdit;
   Memo: TCompScintEdit;
@@ -2620,17 +2727,53 @@ begin
     OpenFile(FMainMemo, CommandLineFilename, False);
     OpenFile(FMainMemo, CommandLineFilename, False);
 end;
 end;
 
 
+procedure TCompileForm.UpdateReopenTabMenu(const Menu: TMenuItem);
+begin
+  Menu.Clear;
+  for var I := 0 to FHiddenFiles.Count-1 do begin
+    var MenuItem := TMenuItem.Create(Menu);
+    MenuItem.Caption := ExtractFileName(FHiddenFiles[I]);
+    MenuItem.Tag := I;
+    MenuItem.OnClick := VReopenTabClick;
+    Menu.Add(MenuItem);
+  end;
+end;
+
+procedure TCompileForm.MemosTabSetPopup(Sender: TObject);
+begin
+  { Main and preprocessor memos can't be hidden }
+  VCloseTab2.Enabled := (FActiveMemo <> FMainMemo) and (FActiveMemo <> FPreprocessorOutputMemo);
+
+  VReopenTab2.Visible := FHiddenFiles.Count > 0;
+  if VReopenTab2.Visible then
+    UpdateReopenTabMenu(VReopenTab2);
+  VReopenTabs2.Visible := VReopenTab2.Visible;
+end;
+
 procedure TCompileForm.MemosTabSetClick(Sender: TObject);
 procedure TCompileForm.MemosTabSetClick(Sender: TObject);
 
 
   { Also see MemoToTabIndex }
   { Also see MemoToTabIndex }
-  function TabIndexToMemoIndex(const TabIndex, MaxTabIndex: Integer): Integer;
+  function TabIndexToMemoIndex(const ATabIndex, AMaxTabIndex: Integer): Integer;
   begin
   begin
-    if TabIndex = 0 then
+    if ATabIndex = 0 then
       Result := 0 { First tab displays the main memo which is FMemos[0] }
       Result := 0 { First tab displays the main memo which is FMemos[0] }
-    else if FPreprocessorOutputMemo.Used and (TabIndex = MaxTabIndex) then
+    else if FPreprocessorOutputMemo.Used and (ATabIndex = AMaxTabIndex) then
       Result := 1 { Last tab displays the preprocessor output memo which is FMemos[1] }
       Result := 1 { Last tab displays the preprocessor output memo which is FMemos[1] }
-    else
-      Result := TabIndex+1; { Other tabs display include files which start second tab but at FMemos[2] }
+    else begin
+      { Only count memos not explicitly hidden by the user }
+      var TabIndex := 0;
+      for var MemoIndex := FirstIncludedFilesMemoIndex to FFileMemos.Count-1 do begin
+        if FHiddenFiles.IndexOf(FFileMemos[MemoIndex].Filename) = -1 then begin
+          Inc(TabIndex);
+          if TabIndex = ATabIndex then begin
+            Result := MemoIndex + 1;   { Other tabs display include files which start at second tab but at FMemos[2] }
+            Exit;
+          end;
+        end;
+      end;
+
+      raise Exception.Create('TabIndexToMemoIndex failed');
+    end;
   end;
   end;
 
 
 var
 var
@@ -2655,6 +2798,11 @@ begin
   UpdateModifiedPanel;
   UpdateModifiedPanel;
 end;
 end;
 
 
+procedure TCompileForm.MemosTabSetOnCloseButtonClick(Sender: TObject);
+begin
+  VCloseTabClick(Self);
+end;
+
 procedure TCompileForm.InitializeFindText(Dlg: TFindDialog);
 procedure TCompileForm.InitializeFindText(Dlg: TFindDialog);
 var
 var
   S: String;
   S: String;
@@ -3025,6 +3173,7 @@ begin
     
     
     UpdateCaption;
     UpdateCaption;
     UpdatePreprocMemos;
     UpdatePreprocMemos;
+    UpdateHiddenFilesPanel;
     for Memo in FMemos do begin
     for Memo in FMemos do begin
       { Move caret to start of line to ensure it doesn't end up in the middle
       { Move caret to start of line to ensure it doesn't end up in the middle
         of a double-byte character if the code page changes from SBCS to DBCS }
         of a double-byte character if the code page changes from SBCS to DBCS }
@@ -3080,15 +3229,40 @@ begin
     if not FPreprocessorOutputMemo.Used then
     if not FPreprocessorOutputMemo.Used then
       raise Exception.Create('not FPreprocessorOutputMemo.Used');
       raise Exception.Create('not FPreprocessorOutputMemo.Used');
     Result := MemosTabSet.Tabs.Count-1 { Last tab displays the preprocessor output memo }
     Result := MemosTabSet.Tabs.Count-1 { Last tab displays the preprocessor output memo }
-  end else
-    Result := FFileMemos.IndexOf(AMemo as TCompScintFileEdit) { Other tabs display include files which start second tab }
+  end else begin
+    Result := FFileMemos.IndexOf(AMemo as TCompScintFileEdit); { Other tabs display include files which start second tab }
+
+   { Filter memos explicitly hidden by the user }
+    for var MemoIndex := Result-1 downto 0 do
+      if FHiddenFiles.IndexOf(FFileMemos[MemoIndex].Filename) <> -1 then
+        Dec(Result);
+  end;
 end;
 end;
 
 
-procedure TCompileForm.MoveCaretAndActivateMemo(const AMemo: TCompScintEdit; const LineNumber: Integer;
+procedure TCompileForm.MoveCaretAndActivateMemo(AMemo: TCompScintFileEdit; const LineNumber: Integer;
   const AlwaysResetColumn: Boolean);
   const AlwaysResetColumn: Boolean);
 var
 var
   Pos: Integer;
   Pos: Integer;
 begin
 begin
+  { Reopen tab if needed }
+  var HiddenFileIndex := FHiddenFiles.IndexOf(AMemo.Filename);
+  if HiddenFileIndex <> -1 then begin
+    var SaveFileName := AMemo.Filename;
+    ReopenTabOrTabs(HiddenFileIndex, False);
+    { The above call to ReopenTabOrTabs will currently lead to a call to UpdateIncludedFilesMemos which
+      sets up all the memos. Currently it will keep same memo for the reopened file but in case it no
+      longer does at some point: look it up again }
+    AMemo := nil;
+    for var Memo in FFileMemos do begin
+      if Memo.Used and (PathCompare(Memo.Filename, SaveFilename) = 0) then begin
+        AMemo := Memo;
+        Break;
+      end;
+    end;
+    if AMemo = nil then
+      raise Exception.Create('AMemo MIA');
+  end;
+
   { Move caret }
   { Move caret }
   if AlwaysResetColumn or (AMemo.CaretLine <> LineNumber) then
   if AlwaysResetColumn or (AMemo.CaretLine <> LineNumber) then
     Pos := AMemo.GetPositionFromLine(LineNumber)
     Pos := AMemo.GetPositionFromLine(LineNumber)
@@ -3103,7 +3277,7 @@ begin
   AMemo.CaretPosition := Pos;
   AMemo.CaretPosition := Pos;
 
 
   { Activate memo }
   { Activate memo }
-  MemosTabSet.TabIndex := MemoToTabIndex(AMemo);
+  MemosTabSet.TabIndex := MemoToTabIndex(AMemo); { This causes MemosTabSetClick to show the memo }
 end;
 end;
 
 
 procedure TCompileForm.SetErrorLine(const AMemo: TCompScintFileEdit; const ALine: Integer);
 procedure TCompileForm.SetErrorLine(const AMemo: TCompScintFileEdit; const ALine: Integer);
@@ -3169,6 +3343,14 @@ begin
     StatusBar.Panels[spEditMode].Text := InsertText[FActiveMemo.InsertMode];
     StatusBar.Panels[spEditMode].Text := InsertText[FActiveMemo.InsertMode];
 end;
 end;
 
 
+procedure TCompileForm.UpdateHiddenFilesPanel;
+begin
+  if MemosTabSet.Visible and (FHiddenFiles.Count > 0) then begin
+    StatusBar.Panels[spHiddenFilesCount].Text := Format('Tabs closed: %d', [FHiddenFiles.Count]);
+  end else
+    StatusBar.Panels[spHiddenFilesCount].Text := '';
+end;
+
 procedure TCompileForm.UpdateMemosTabSetVisibility;
 procedure TCompileForm.UpdateMemosTabSetVisibility;
 begin
 begin
   MemosTabSet.Visible := FPreprocessorOutputMemo.Used or FFileMemos[FirstIncludedFilesMemoIndex].Used;
   MemosTabSet.Visible := FPreprocessorOutputMemo.Used or FFileMemos[FirstIncludedFilesMemoIndex].Used;
@@ -3186,12 +3368,14 @@ end;
 
 
 procedure TCompileForm.UpdatePreprocMemos;
 procedure TCompileForm.UpdatePreprocMemos;
 
 
-  procedure UpdatePreprocessorOutputMemo(const NewTabs, NewHints: TStringList);
+  procedure UpdatePreprocessorOutputMemo(const NewTabs, NewHints: TStringList;
+    const NewCloseButtons: TBoolList);
   begin
   begin
     if FOptions.ShowPreprocessorOutput and (FPreprocessorOutput <> '') and
     if FOptions.ShowPreprocessorOutput and (FPreprocessorOutput <> '') and
        not SameStr(TrimRight(FMainMemo.Lines.Text), FPreprocessorOutput) then begin
        not SameStr(TrimRight(FMainMemo.Lines.Text), FPreprocessorOutput) then begin
       NewTabs.Add('Preprocessor Output');
       NewTabs.Add('Preprocessor Output');
       NewHints.Add('');
       NewHints.Add('');
+      NewCloseButtons.Add(False);
       FPreprocessorOutputMemo.ReadOnly := False;
       FPreprocessorOutputMemo.ReadOnly := False;
       try
       try
         FPreprocessorOutputMemo.Lines.Text := FPreprocessorOutput;
         FPreprocessorOutputMemo.Lines.Text := FPreprocessorOutput;
@@ -3206,13 +3390,15 @@ procedure TCompileForm.UpdatePreprocMemos;
     end;
     end;
   end;
   end;
 
 
-  procedure UpdateIncludedFilesMemos(const NewTabs, NewHints: TStringList);
+  procedure UpdateIncludedFilesMemos(const NewTabs, NewHints: TStringList;
+    const NewCloseButtons: TBoolList);
   var
   var
     IncludedFile: TIncludedFile;
     IncludedFile: TIncludedFile;
-    I, NextMemoIndex, NewTabIndex: Integer;
+    I: Integer;
   begin
   begin
     if FOptions.OpenIncludedFiles and (FIncludedFiles.Count > 0) then begin
     if FOptions.OpenIncludedFiles and (FIncludedFiles.Count > 0) then begin
-      NextMemoIndex := FirstIncludedFilesMemoIndex;
+      var NextMemoIndex := FirstIncludedFilesMemoIndex;
+      var NextTabIndex := 1; { First tab displays the main memo  }
       FLoadingIncludedFiles := True;
       FLoadingIncludedFiles := True;
       try
       try
         for IncludedFile in FIncludedFiles do begin
         for IncludedFile in FIncludedFiles do begin
@@ -3228,12 +3414,17 @@ procedure TCompileForm.UpdatePreprocMemos;
               OpenFile(IncludedFile.Memo, IncludedFile.Filename, False); { Also updates FileLastWriteTime }
               OpenFile(IncludedFile.Memo, IncludedFile.Filename, False); { Also updates FileLastWriteTime }
               IncludedFile.Memo.Used := True;
               IncludedFile.Memo.Used := True;
             end else if IncludedFile.Memo.CompilerFileIndex = UnknownCompilerFileIndex then begin
             end else if IncludedFile.Memo.CompilerFileIndex = UnknownCompilerFileIndex then begin
-             { Previously the included file came from the history }
+             { The file already has a memo but CompilerFileIndex is not set yet.
+               This happens if the initial load was from the history loaded by LoadKnownIncludedFiles and then the user does a compile.  }
               IncludedFile.Memo.CompilerFileIndex := IncludedFile.CompilerFileIndex;
               IncludedFile.Memo.CompilerFileIndex := IncludedFile.CompilerFileIndex;
             end;
             end;
-            NewTabIndex := 1+NextMemoIndex-FirstIncludedFilesMemoIndex;
-            NewTabs.Insert(NewTabIndex, PathExtractName(IncludedFile.Filename));
-            NewHints.Insert(NewTabIndex, GetFileTitle(IncludedFile.Filename));
+
+            if FHiddenFiles.IndexOf(IncludedFile.Filename) = -1 then begin
+              NewTabs.Insert(NextTabIndex, PathExtractName(IncludedFile.Filename));
+              NewHints.Insert(NextTabIndex, GetFileTitle(IncludedFile.Filename));
+              NewCloseButtons.Insert(NextTabIndex, True);
+              Inc(NextTabIndex);
+            end;
 
 
             Inc(NextMemoIndex);
             Inc(NextMemoIndex);
             if NextMemoIndex = FFileMemos.Count then
             if NextMemoIndex = FFileMemos.Count then
@@ -3267,25 +3458,30 @@ procedure TCompileForm.UpdatePreprocMemos;
 
 
 var
 var
   NewTabs, NewHints: TStringList;
   NewTabs, NewHints: TStringList;
+  NewCloseButtons: TBoolList;
   I, SaveTabIndex: Integer;
   I, SaveTabIndex: Integer;
   SaveTabName: String;
   SaveTabName: String;
 begin
 begin
   NewTabs := nil;
   NewTabs := nil;
   NewHints := nil;
   NewHints := nil;
+  NewCloseButtons := nil;
   try
   try
     NewTabs := TStringList.Create;
     NewTabs := TStringList.Create;
     NewTabs.Add(MemosTabSet.Tabs[0]); { 'Main Script' }
     NewTabs.Add(MemosTabSet.Tabs[0]); { 'Main Script' }
     NewHints := TStringList.Create;
     NewHints := TStringList.Create;
     NewHints.Add(GetFileTitle(FMainMemo.Filename));
     NewHints.Add(GetFileTitle(FMainMemo.Filename));
+    NewCloseButtons := TBoolList.Create;
+    NewCloseButtons.Add(False);
 
 
-    UpdatePreprocessorOutputMemo(NewTabs, NewHints);
-    UpdateIncludedFilesMemos(NewTabs, NewHints);
+    UpdatePreprocessorOutputMemo(NewTabs, NewHints, NewCloseButtons);
+    UpdateIncludedFilesMemos(NewTabs, NewHints, NewCloseButtons);
 
 
     { Set new tabs, try keep same file open }
     { Set new tabs, try keep same file open }
     SaveTabIndex := MemosTabSet.TabIndex;
     SaveTabIndex := MemosTabSet.TabIndex;
     SaveTabName := MemosTabSet.Tabs[MemosTabSet.TabIndex];
     SaveTabName := MemosTabSet.Tabs[MemosTabSet.TabIndex];
     MemosTabSet.Tabs := NewTabs;
     MemosTabSet.Tabs := NewTabs;
     MemosTabSet.Hints := NewHints;
     MemosTabSet.Hints := NewHints;
+    MemosTabSet.CloseButtons := NewCloseButtons;
     I := MemosTabSet.Tabs.IndexOf(SaveTabName);
     I := MemosTabSet.Tabs.IndexOf(SaveTabName);
     if I <> -1 then
     if I <> -1 then
        MemosTabSet.TabIndex := I;
        MemosTabSet.TabIndex := I;
@@ -3295,6 +3491,7 @@ begin
       MemosTabSetClick(MemosTabSet);
       MemosTabSetClick(MemosTabSet);
    end;
    end;
   finally
   finally
+    NewCloseButtons.Free;
     NewHints.Free;
     NewHints.Free;
     NewTabs.Free;
     NewTabs.Free;
   end;
   end;
@@ -4375,26 +4572,21 @@ begin
   SetListTheme(FindResultsList);
   SetListTheme(FindResultsList);
 end;
 end;
 
 
-procedure TCompileForm.UpdateThemeData(const Close, Open: Boolean);
+procedure TCompileForm.UpdateThemeData(const Open: Boolean);
 begin
 begin
-  if Close then begin
-    if FProgressThemeData <> 0 then begin
-      CloseThemeData(FProgressThemeData);
-      FProgressThemeData := 0;
-    end;
+  if FProgressThemeData <> 0 then begin
+    CloseThemeData(FProgressThemeData);
+    FProgressThemeData := 0;
   end;
   end;
 
 
-  if Open then begin
-    if UseThemes then begin
-      FProgressThemeData := OpenThemeData(Handle, 'Progress');
-      if (GetThemeInt(FProgressThemeData, 0, 0, TMT_PROGRESSCHUNKSIZE, FProgressChunkSize) <> S_OK) or
-         (FProgressChunkSize <= 0) then
-        FProgressChunkSize := 6;
-      if (GetThemeInt(FProgressThemeData, 0, 0, TMT_PROGRESSSPACESIZE, FProgressSpaceSize) <> S_OK) or
-         (FProgressSpaceSize < 0) then  { ...since "OpusOS" theme returns a bogus -1 value }
-        FProgressSpaceSize := 2;
-    end else
-      FProgressThemeData := 0;
+  if Open and UseThemes then begin
+    FProgressThemeData := OpenThemeData(Handle, 'Progress');
+    if (GetThemeInt(FProgressThemeData, 0, 0, TMT_PROGRESSCHUNKSIZE, FProgressChunkSize) <> S_OK) or
+       (FProgressChunkSize <= 0) then
+      FProgressChunkSize := 6;
+    if (GetThemeInt(FProgressThemeData, 0, 0, TMT_PROGRESSSPACESIZE, FProgressSpaceSize) <> S_OK) or
+       (FProgressSpaceSize < 0) then  { ...since "OpusOS" theme returns a bogus -1 value }
+      FProgressSpaceSize := 2;
   end;
   end;
 end;
 end;
 
 
@@ -4764,6 +4956,24 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TCompileForm.StatusBarClick(Sender: TObject);
+begin
+  if MemosTabSet.Visible and (FHiddenFiles.Count > 0) then begin
+    var Point := SmallPointToPoint(TSmallPoint(DWORD(GetMessagePos)));
+    var X := StatusBar.ScreenToClient(Point).X;
+    var W := 0;
+    for var I := 0 to StatusBar.Panels.Count-1 do begin
+      Inc(W, StatusBar.Panels[I].Width);
+      if X < W then begin
+        if I = spHiddenFilesCount then
+          MemosTabSetPopupMenu.Popup(Point.X, Point.Y);
+        Break;
+      end else if I = spHiddenFilesCount then
+        Break;
+    end;
+  end;
+end;
+
 procedure TCompileForm.StatusBarDrawPanel(StatusBar: TStatusBar;
 procedure TCompileForm.StatusBarDrawPanel(StatusBar: TStatusBar;
   Panel: TStatusPanel; const Rect: TRect);
   Panel: TStatusPanel; const Rect: TRect);
 var
 var
@@ -4861,7 +5071,7 @@ end;
 procedure TCompileForm.WMThemeChanged(var Message: TMessage);
 procedure TCompileForm.WMThemeChanged(var Message: TMessage);
 begin
 begin
   { Don't Run to Cursor into this function, it will interrupt up the theme change }
   { Don't Run to Cursor into this function, it will interrupt up the theme change }
-  UpdateThemeData(True, True);
+  UpdateThemeData(True);
   inherited;
   inherited;
 end;
 end;
 
 

+ 21 - 16
Projects/CompFunc.pas

@@ -41,8 +41,8 @@ procedure OpenMailingListSite;
 procedure ReadMRUList(const MRUList: TStringList; const Section, Ident: String);
 procedure ReadMRUList(const MRUList: TStringList; const Section, Ident: String);
 procedure ModifyMRUList(const MRUList: TStringList; const Section, Ident: String;
 procedure ModifyMRUList(const MRUList: TStringList; const Section, Ident: String;
   const AItem: String; const AddNewItem: Boolean; CompareProc: TMRUItemCompareProc);
   const AItem: String; const AddNewItem: Boolean; CompareProc: TMRUItemCompareProc);
-procedure LoadKnownIncludedFiles(const AFilename: String; const IncludedFiles: TStringList);
-procedure SaveKnownIncludedFiles(const AFilename: String; const IncludedFiles: TStringList);
+procedure LoadKnownIncludedAndHiddenFiles(const AFilename: String; const IncludedFiles, HiddenFiles: TStringList);
+procedure SaveKnownIncludedAndHiddenFiles(const AFilename: String; const IncludedFiles, HiddenFiles: TStringList);
 procedure DeleteKnownIncludedFiles(const AFilename: String);
 procedure DeleteKnownIncludedFiles(const AFilename: String);
 procedure SetFakeShortCutText(const MenuItem: TMenuItem; const S: String);
 procedure SetFakeShortCutText(const MenuItem: TMenuItem; const S: String);
 procedure SetFakeShortCut(const MenuItem: TMenuItem; const Key: Word;
 procedure SetFakeShortCut(const MenuItem: TMenuItem; const Key: Word;
@@ -239,26 +239,26 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure LoadKnownIncludedFiles(const AFilename: String; const IncludedFiles: TStringList);
-var
-  Ini: TConfigIniFile;
-  OldDelimiter: Char;
+procedure LoadKnownIncludedAndHiddenFiles(const AFilename: String; const IncludedFiles, HiddenFiles: TStringList);
 begin
 begin
-  OldDelimiter := IncludedFiles.Delimiter;
-  Ini := TConfigIniFile.Create;
+  var OldIncludedFilesDelimiter := IncludedFiles.Delimiter;
+  var OldHiddenFilesDelimiter := HiddenFiles.Delimiter;
+  var Ini := TConfigIniFile.Create;
   try
   try
     IncludedFiles.Delimiter := '*';
     IncludedFiles.Delimiter := '*';
     IncludedFiles.DelimitedText := Ini.ReadString('IncludedFilesHistory', AFilename, '');
     IncludedFiles.DelimitedText := Ini.ReadString('IncludedFilesHistory', AFilename, '');
+
+    HiddenFiles.Delimiter := '*';
+    HiddenFiles.DelimitedText := Ini.ReadString('HiddenFilesHistory', AFilename, '');
+
   finally
   finally
     Ini.Free;
     Ini.Free;
-    IncludedFiles.Delimiter := OldDelimiter;
+    IncludedFiles.Delimiter := OldIncludedFilesDelimiter;
+    HiddenFiles.Delimiter := OldHiddenFilesDelimiter;
   end;
   end;
 end;
 end;
 
 
-procedure SaveKnownIncludedFiles(const AFilename: String; const IncludedFiles: TStringList);
-var
-  Ini: TConfigIniFile;
-  OldDelimiter: Char;
+procedure SaveKnownIncludedAndHiddenFiles(const AFilename: String; const IncludedFiles, HiddenFiles: TStringList);
 begin
 begin
   if IncludedFiles.Count = 0 then begin
   if IncludedFiles.Count = 0 then begin
     DeleteKnownIncludedFiles(AFilename);
     DeleteKnownIncludedFiles(AFilename);
@@ -268,14 +268,18 @@ begin
   if AFilename = '' then
   if AFilename = '' then
     raise Exception.Create('AFilename must be set');
     raise Exception.Create('AFilename must be set');
 
 
-  OldDelimiter := IncludedFiles.Delimiter;
-  Ini := TConfigIniFile.Create;
+  var OldIncludedFilesDelimiter := IncludedFiles.Delimiter;
+  var OldHiddenFilesDelimiter := HiddenFiles.Delimiter;
+  var Ini := TConfigIniFile.Create;
   try
   try
     IncludedFiles.Delimiter := '*';
     IncludedFiles.Delimiter := '*';
     Ini.WriteString('IncludedFilesHistory', AFilename, IncludedFiles.DelimitedText);
     Ini.WriteString('IncludedFilesHistory', AFilename, IncludedFiles.DelimitedText);
+    HiddenFiles.Delimiter := '*';
+    Ini.WriteString('HiddenFilesHistory', AFilename, HiddenFiles.DelimitedText);
   finally
   finally
     Ini.Free;
     Ini.Free;
-    IncludedFiles.Delimiter := OldDelimiter;
+    IncludedFiles.Delimiter := OldIncludedFilesDelimiter;
+    HiddenFiles.Delimiter := OldHiddenFilesDelimiter;
   end;
   end;
 end;
 end;
 
 
@@ -289,6 +293,7 @@ begin
   Ini := TConfigIniFile.Create;
   Ini := TConfigIniFile.Create;
   try
   try
     Ini.DeleteKey('IncludedFilesHistory', AFilename);
     Ini.DeleteKey('IncludedFilesHistory', AFilename);
+    Ini.DeleteKey('HiddenFilesHistory', AFilename);
   finally
   finally
     Ini.Free;
     Ini.Free;
   end;
   end;

+ 1 - 1
Projects/CompScintEdit.pas

@@ -42,7 +42,7 @@ type
   TCompScintEdit = class(TScintEdit)
   TCompScintEdit = class(TScintEdit)
   private
   private
     FTheme: TTheme;
     FTheme: TTheme;
-    FUsed: Boolean;
+    FUsed: Boolean; { The IDE only shows 1 memo at a time so can't use .Visible to check if a memo is used }
   protected
   protected
     procedure CreateWnd; override;
     procedure CreateWnd; override;
   public
   public

+ 2 - 0
Projects/Debug.iss

@@ -2,6 +2,8 @@
 ; Opened when you run the Compil32.dproj project in Debug mode from the Delphi IDE
 ; Opened when you run the Compil32.dproj project in Debug mode from the Delphi IDE
 ; Use it to test the compiler or Setup or the uninstaller
 ; Use it to test the compiler or Setup or the uninstaller
 
 
+#include "Debug2.iss"
+
 [Setup]
 [Setup]
 AppName=ɯɐɹƃoɹd ʎɯ
 AppName=ɯɐɹƃoɹd ʎɯ
 AppVerName=My Program version 1.5
 AppVerName=My Program version 1.5

+ 8 - 0
Projects/Debug2.iss

@@ -0,0 +1,8 @@
+; -- Debug2.iss --
+; Included by Debug.iss
+; Use it to test the compiler or Compiler IDE's support for include files
+
+[Code]
+procedure InitializeWizard;
+begin
+end;

+ 14 - 76
whatsnew.htm

@@ -29,105 +29,43 @@ For conditions of distribution and use, see <a href="https://jrsoftware.org/file
 <p><b>Want to be notified by e-mail of new Inno Setup releases?</b> <a href="https://jrsoftware.org/ismail.php">Subscribe</a> to the Inno Setup Mailing List!</p>
 <p><b>Want to be notified by e-mail of new Inno Setup releases?</b> <a href="https://jrsoftware.org/ismail.php">Subscribe</a> to the Inno Setup Mailing List!</p>
 
 
 <p><a name="6.3.0"></a><span class="ver">6.3.0-dev </span><span class="date">(?)</span></p>
 <p><a name="6.3.0"></a><span class="ver">6.3.0-dev </span><span class="date">(?)</span></p>
+<p><span class="head2">Support from UTF-8 encoded files improved</span></p>
 <ul>
 <ul>
   <li>Inno Setup now supports UTF-8 encoded .iss script files and .isl messages files without an UTF-8 preamble (also called BOM).</li>
   <li>Inno Setup now supports UTF-8 encoded .iss script files and .isl messages files without an UTF-8 preamble (also called BOM).</li>
   <li>Compiler IDE changes:
   <li>Compiler IDE changes:
   <ul>
   <ul>
   <li>Added new <i>UTF-8 without BOM</i> menu item to the <i>Save Encoding</i> submenu of the <i>File</i> menu.</li>
   <li>Added new <i>UTF-8 without BOM</i> menu item to the <i>Save Encoding</i> submenu of the <i>File</i> menu.</li>
   <li>New script files are now saved as UTF-8 with BOM by default. Existing files are still saved as they were.</li>
   <li>New script files are now saved as UTF-8 with BOM by default. Existing files are still saved as they were.</li>
-  <li>Added new <i>[Files] Entries Designer</i> menu item to the <i>Tools</i> menu to design and insert extra entries to the [Files] section.</li>
   </ul>
   </ul>
   </li>
   </li>
-  <li>Added new [Setup] section directive <tt>UninstallLogging</tt>, which defaults to <tt>no</tt>. If set to <tt>yes</tt>, the uninstaller will always create a log file if it is launched from the <i>Add/Remove Programs</i> Control Panel applet. Equivalent to passing /LOG on the command line.</li>
-  <li>During startup Setup would always ask Windows to create any missing <tt>{usercf}</tt>, <tt>{userpf}</tt>, and <tt>{usersavedgames}</tt> folders. It no longer does until the script asks for the folder. Note that scripts running in administrative install mode should not do this because it violates the <a href="https://jrsoftware.org/ishelp/index.php?topic=setup_useduserareaswarning">used user areas warning</a>.</li>
-  <li>Added support for IIS group users identifiers (<tt>iisiusrs</tt>) for use in <tt>Permissions</tt> parameters, contributed by Achim Stuy.</li> 
   <li>Pascal Scripting changes:
   <li>Pascal Scripting changes:
   <ul>
   <ul>
     <li>Support function <tt>LoadStringsFromFile</tt> now also supports UTF8-encoded files without an UTF-8 preamble.</li>
     <li>Support function <tt>LoadStringsFromFile</tt> now also supports UTF8-encoded files without an UTF-8 preamble.</li>
     <li>Added new <tt>SaveStringsToUTF8FileNoPreamble</tt> support function.</li>
     <li>Added new <tt>SaveStringsToUTF8FileNoPreamble</tt> support function.</li>
-    <li>Type <tt>TShellFolderID</tt> was removed because it wasn't used by any support function.</li>
   </ul>
   </ul>
   </li>
   </li>
-  <li>Added official Korean translation.</li>
-  <li>Inno Setup is now built using Delphi 11.3 Alexandria instead of Delphi 10.3 Rio.</li>
-</ul>
-
-<p><a name="6.2.2"></a><span class="ver">6.2.2 </span><span class="date">(2023-02-15)</span></p>
-<ul>
-  <li>Changes to further help protect against potential DLL preloading attacks, contributed by Johannes Schindelin from the Git for Windows team.</li>
-  <li>Pascal Scripting changes: Improved support for downloads using basic authentication, contributed by Christian Beck.
-  <ul>
-    <li>Added new <tt>AddEx</tt> function to the <tt>TDownloadWizardPage</tt> support class.</li>
-    <li>Added new <tt>SetDownloadCredentials</tt> support function.</li>
-  </ul>
-  <li>Added official Hungarian translation.</li>
-</ul>
-
-<p><a name="6.2.1"></a><span class="ver">6.2.1 </span><span class="date">(2022-04-14)</span></p>
-<ul>
-  <li>Changes to further help protect against potential DLL preloading attacks when running installers or uninstallers under the SYSTEM account, contributed by Johannes Schindelin from the Git for Windows team.</li>
-  <li>Fixed a cosmetic issue if the icon file specified by the [Setup] section directive <tt>SetupIconFile</tt> contains more than 13 icons. Thanks to Wilenty and Martin Prikryl for the initial investigation.</li>
-</ul>
-
-<p><a name="6.2.0"></a><span class="ver">6.2.0 </span><span class="date">(2021-06-03)</span></p>
-<p><span class="head2">Graphics modernized</span></p>
-<ul>
-  <li>Updated all Compiler IDE's toolbar icons and the wizard images used by the Compiler IDE's New Script Wizard wizard.</li>
-  <li>Updated the default application icon used by Setup and Uninstall if [Setup] section directive <tt>SetupIconFile</tt> is not set. To use the old icon again set <tt>SetupIconFile</tt> to <tt>compiler:SetupClassicIcon.ico</tt>.</li>
-  <li>[Setup] section directives <tt>WizardImageFile</tt> and <tt>WizardSmallImageFile</tt> now default to a blank value which makes Setup use new built-in wizard images.  To use the old wizard images again set <tt>WizardImageFile</tt> and <tt>WizardSmallImageFile</tt> to <tt>compiler:WizClassicImage.bmp</tt> and <tt>compiler:WizClassicSmallImage.bmp</tt> respectively.</li>
-  <li>Updated Uninstall's default small wizard image if [Setup] section directive <tt>SetupIconFile</tt> is not set. Before it would use Setup's default application icon in this case.</li>
-  <li>Updated the folder, group, and stop icons used by Setup's <i>Select Destination Location</i>, <i>Select Start Menu Folder</i>, and <i>Preparing to Install</i> wizard pages.</li>
-  <li>Updated the disk icon used by Setup's <i>Setup Needs the Next Disk</i> form.</li>
-  <li>Pascal Scripting change: Added new <tt>InitializeBitmapImageFromIcon</tt> support function.</li>
-</ul>
-<p>All these icon and images updates include the automatic use of higher quality versions (which were not available before) on higher DPI settings. This includes new automatic use of higher quality icons for the icon on Setup's <i>Select Setup Language</i> form and Uninstall's small wizard image if <tt>SetupIconFile</tt> is set.</p>
-<p>Example screenshots:</p>
-<ul>
-  <li>Setup wizard pages <a href="https://jrsoftware.org/images/is-welcome-org.png">Select Destination Location</a> and <a href="https://jrsoftware.org/images/is-finished-org.png">Setup Completed</a> at 100% DPI.</li>
-  <li>Setup wizard pages <a href="https://jrsoftware.org/images/is-welcome-org-175.png">Select Destination Location</a> and <a href="https://jrsoftware.org/images/is-finished-org-175.png">Setup Completed</a> at 175% DPI.</li>
-  <li>Compiler IDE themes <a href="https://jrsoftware.org/images/is-ide-org.png">Light</a> and <a href="https://jrsoftware.org/images/is-ide-dark-org.png">Dark</a> at 100% DPI.</li>
-</ul>
-<p>Comparison screenshots of the *previous* version:</p>
-<ul>
-  <li>Setup wizard pages <a href="https://jrsoftware.org/images/is-welcome-org-175-old.png">Select Destination Location</a> and <a href="https://jrsoftware.org/images/is-finished-org-175-old.png">Setup Completed</a> at 175% DPI in version 6.1.2.</li>
 </ul>
 </ul>
 <p><span class="head2">Other changes</span></p>
 <p><span class="head2">Other changes</span></p>
 <ul>
 <ul>
-  <li>Links displayed by [Setup] section directives <tt>LicenseFile</tt>, <tt>InfoBeforeFile</tt> and <tt>InfoAfterFile</tt> are now executed as the original user if possible when clicked.</li>
-  <li>Added new [Setup] section directives <tt>MissingMessagesWarning</tt> and <tt>NotRecognizedMessagesWarning</tt> to disable warnings about messages missing or not recognized for a language.</li>
-  <li>/LOG: Now logs more uninstaller actions.</li>
-  <li>The <tt>{localappdata}</tt> constant can now correctly trigger a <a href="https://jrsoftware.org/ishelp/index.php?topic=setup_useduserareaswarning">used user areas warning</a>.</li>
-  <li>Compiler IDE change: <i>Fix:</i> Autocomplete support for event functions listed some procedures as functions.</li>
-  <li>Pascal Scripting changes:
+  <li>Compiler IDE changes:
   <ul>
   <ul>
-    <li>Added new <tt>CreateOutputMarqueeProgressPage</tt> support function to show marquee progress to the user. See the <i><a href="https://jrsoftware.github.io/issrc/Examples/AllPagesExample.iss">AllPagesExample.iss</a></i> example script for an example.</li>
-    <li>Added new <tt>ItemFontStyle</tt> and <tt>SubItemFontStyle</tt> properties to the <tt>TNewCheckListBox</tt> support class. See the <i><a href="https://jrsoftware.github.io/issrc/Examples/CodeClasses.iss">CodeClasses.iss</a></i> example script for an example.</li>
-    <li>Added new <tt>IsMsiProductInstalled</tt> and <tt>StrToVersion</tt> support functions.</li>
-    <li>Added new <tt>AbortedByUser</tt> property to the <tt>TDownloadWizardPage</tt> support class.</li>
-    <li><i>Fix:</i> <tt>CreateDownloadPage</tt>'s progress bar now supports files larger than 2 GB.</li>
-    <li>Support functions <tt>ParamCount</tt> and <tt>ParamStr</tt> now exclude undocumented internal parameters used by Setup and Uninstall.</li>
-    <li>The built-in download support now allows the download of files for which the server does not specify the file size and its hash checking is no longer case sensitive.</li>
+  <li>The Compiler IDE now opens up to 20 #include files in tabs, instead of up to 10.</li>
+  <li>Tabs for #include files can now be closed: Added new <i>Close Tab (Ctrl+F4)</i>, <i>Reopen Tab</i>, and  <i>Reopen All Tabs</i> menu items to the <i>View</i> menu, also available by right clicking the tab bar. Additionally the tab for a selected #include file now shows a close button.</li>
+  <li>Added a clickable panel to the Status Bar showing the amount of closed tabs if there are any.</li>
+  <li>Added new <i>[Files] Entries Designer</i> menu item to the <i>Tools</i> menu to design and insert extra entries to the [Files] section.</li>
   </ul>
   </ul>
   </li>
   </li>
-  <li>ISPP change: Added new <tt>StrToVersion</tt> support function.</li>
-  <li>Added official Bulgarian translation.</li>
-  <li>Various documentation improvements.</li>
-  <li>Minor tweaks.</li>
-</ul>
-<p><span class="head2">Inno Setup FAQ updated</span></p>
-<ul>
-  <li>The <a href="https://jrsoftware.org/isfaq.php">Inno Setup FAQ</a> has been updated with updated versions of articles taken from the Inno Setup Knowledge Base which is now hidden from the website.</li>
-  <li>The content of the FAQ is now <a href="https://github.com/jrsoftware/isfaq/blob/main/isfaq.html">available on GitHub</a> where you can suggest new entries or other improvements using the Edit button.</li>
-</ul>
-<p><span class="head2">QuickStart Pack removed</span></p>
-<ul>
-  <li>The QuickStart Pack installer has been removed because of a lack of added value.</li>
-  <li>The standard Inno Setup installer now offers to download encryption support if it's missing, like the QuickStart Pack installer did before. If you used the QuickStart Pack installer before, you can use the standard installer to update your installation.</li>
+  <li>Added new [Setup] section directive <tt>UninstallLogging</tt>, which defaults to <tt>no</tt>. If set to <tt>yes</tt>, the uninstaller will always create a log file if it is launched from the <i>Add/Remove Programs</i> Control Panel applet. Equivalent to passing /LOG on the command line.</li>
+  <li>During startup Setup would always ask Windows to create any missing <tt>{usercf}</tt>, <tt>{userpf}</tt>, and <tt>{usersavedgames}</tt> folders. It no longer does until the script asks for the folder. Note that scripts running in administrative install mode should not do this because it violates the <a href="https://jrsoftware.org/ishelp/index.php?topic=setup_useduserareaswarning">used user areas warning</a>.</li>
+  <li>Added support for IIS group users identifiers (<tt>iisiusrs</tt>) for use in <tt>Permissions</tt> parameters.</li> 
+  <li>Pascal Scripting change: Type <tt>TShellFolderID</tt> was removed because it wasn't used by any support function.</li>
+  <li>Added official Korean translation.</li>
+  <li>Inno Setup is now built using Delphi 11.3 Alexandria instead of Delphi 10.3 Rio.</li>
 </ul>
 </ul>
 
 
-<p>Contributions via <a href="https://github.com/jrsoftware/issrc" target="_blank">GitHub</a>: <b>Thanks to Sergii Leonov and Dom Gries for their contributions.</b></p>
+<p>Contributions via <a href="https://github.com/jrsoftware/issrc" target="_blank">GitHub</a>: Thanks to Achim Stuy, ser163, and Jens Geyer for their contributions.</p>
 
 
-<p><a href="https://jrsoftware.org/files/is6.1-whatsnew.htm">Inno Setup 6.1 Revision History</a></p >
+<p><a href="https://jrsoftware.org/files/is6.2-whatsnew.htm">Inno Setup 6.2 Revision History</a></p >
 
 
 </body>
 </body>
 </html>
 </html>