From bfbb52c268f3542e6911d90073c1e0a2136b4a68 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 20 Feb 2024 14:30:05 -0800 Subject: [PATCH 001/200] Initial research notes about screenshot display --- AngelLoader/Forms/MainForm.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 5506a4dc3..571ddd274 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -1,5 +1,29 @@ /* NOTE: MainForm notes: +--- + +@ScreenshotDisplay(TDM screenshot filename formats): + +We need to check all versions to see if there are any other formats. + +Format 1 (2.06 at the very least): +mapname + "_%Y-%m-%d_%H.%M.%S." + extension +Example: river1_1_2016-11-03_21.47.21.png +Extracted fm name should be "river1_1" + +Format 2 (2.11 at the very least): +mapname + " (%Y-%m-%d %H-%M-%S) (" + playerViewOriginStr + ")." + extension +Example: written (2023-10-03 20-19-23) (889.44 -1464.35 174.68).jpg +Extracted fm name should be "written" + +So if these are the only two formats, then the FM name extraction logic should be: + +If a space exists, substring to the first space +Else if a second-last underscore exists, substring to that +Else skip the file + +--- + @LazyLoad: Controls that can be lazy-loaded in principle: -Game buttons and game tabs (one or the other will be invisible on startup) -Game tabs image list From 56bf3b7670c6ad78e8fae1a2c296712f5ae1c11a Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 20 Feb 2024 15:22:18 -0800 Subject: [PATCH 002/200] Abstract the readme container --- .../LazyLoaded/ChooseReadmeLLPanel.cs | 3 +-- .../LazyLoaded/ViewHTMLReadmeLLButton.cs | 5 ++-- AngelLoader/Forms/MainForm.Designer.cs | 2 +- AngelLoader/Forms/MainForm.cs | 23 +++++++++++-------- AngelLoader/Forms/MainForm_InitManual.cs | 2 +- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/ChooseReadmeLLPanel.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/ChooseReadmeLLPanel.cs index 5bb3236f3..8a7374c94 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/ChooseReadmeLLPanel.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/ChooseReadmeLLPanel.cs @@ -51,8 +51,6 @@ private void Construct() { if (_constructed) return; - Control container = _owner.MainSplitContainer.Panel2; - OKButton = new StandardButton { Tag = LoadType.Lazy, @@ -103,6 +101,7 @@ private void Construct() Panel.Controls.Add(_listBox); Panel.Controls.Add(OK_FLP); + Control container = _owner.ReadmeContainer; container.Controls.Add(Panel); Panel.CenterHV(container); diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/ViewHTMLReadmeLLButton.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/ViewHTMLReadmeLLButton.cs index 871a40644..c2c8d6ff2 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/ViewHTMLReadmeLLButton.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/ViewHTMLReadmeLLButton.cs @@ -33,7 +33,7 @@ internal void Localize() if (!_constructed) return; Button.Text = LText.ReadmeArea.ViewHTMLReadme; - Button.CenterHV(_owner.MainSplitContainer.Panel2); + Button.CenterHV(_owner.ReadmeContainer); } internal bool Visible => _constructed && Button.Visible; @@ -47,8 +47,6 @@ internal void Show() { if (!_constructed) { - var container = _owner.MainSplitContainer.Panel2; - Button = new DarkButton { Tag = LoadType.Lazy, @@ -65,6 +63,7 @@ internal void Show() DarkModeEnabled = _darkModeEnabled }; + Control container = _owner.ReadmeContainer; container.Controls.Add(Button); Button.Click += _owner.ViewHTMLReadmeButton_Click; Button.MouseLeave += _owner.ReadmeArea_MouseLeave; diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index da1cb366f..7cec7072c 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -262,7 +262,7 @@ private void InitializeComponent() this.MainSplitContainer.Panel2.Controls.Add(this.ChooseReadmeComboBox); this.MainSplitContainer.Panel2.Controls.Add(this.ReadmeRichTextBox); this.MainSplitContainer.Panel2.Padding = new System.Windows.Forms.Padding(1, 1, 2, 2); - this.MainSplitContainer.Panel2.Paint += new System.Windows.Forms.PaintEventHandler(this.MainSplitContainer_Panel2_Paint); + this.MainSplitContainer.Panel2.Paint += new System.Windows.Forms.PaintEventHandler(this.ReadmeContainer_Paint); this.MainSplitContainer.Panel2.MouseLeave += new System.EventHandler(this.ReadmeArea_MouseLeave); this.MainSplitContainer.Panel2MinSize = 38; this.MainSplitContainer.RefreshSiblingFirst = true; diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 571ddd274..ff8aee211 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -397,10 +397,10 @@ static bool TryGetHWndFromMousePos(Message msg, out IntPtr result, [NotNullWhen( { TopSplitContainer.Panel2.Focus(); } - else if (CursorOverControl(MainSplitContainer.Panel2) && + else if (CursorOverControl(ReadmeContainer) && !ReadmeRichTextBox.Focused) { - MainSplitContainer.Panel2.Focus(); + ReadmeContainer.Focus(); } } if (controlOver is DarkComboBox { SuppressScrollWheelValueChange: true, Focused: false } cb) @@ -564,7 +564,7 @@ bool AnyControlFocusedInTabPage(TabPage tabPage) => AnyControlFocusedInTabPage(TagsTabPage) || TagsTabPage.AddTagLLDropDownFocused() ? HelpSections.TagsTab : AnyControlFocusedInTabPage(PatchTabPage) ? HelpSections.PatchTab : AnyControlFocusedInTabPage(ModsTabPage) ? HelpSections.ModsTab : - AnyControlFocusedIn(MainSplitContainer.Panel2) ? HelpSections.ReadmeArea : + AnyControlFocusedIn(ReadmeContainer) ? HelpSections.ReadmeArea : HelpSections.MainWindow; Core.OpenHelpFile(section); @@ -1368,7 +1368,7 @@ private async void MainForm_KeyDown(object sender, KeyEventArgs e) System.Diagnostics.Trace.WriteLine(""); } #if DateAccTest - else if (e.KeyCode == Keys.Space && (FMsDGV.Focused || ReadmeRichTextBox.Focused || MainSplitContainer.Panel2.Focused)) + else if (e.KeyCode == Keys.Space && (FMsDGV.Focused || ReadmeRichTextBox.Focused || ReadmeContainer.Focused)) { FanMission? fm = GetMainSelectedFMOrNull(); if (fm != null) @@ -4809,18 +4809,18 @@ public void SetReadmeLocalizableMessage(ReadmeLocalizableMessage messageType) // Draw a nice separator between the bottom of the readme and the bottom bar. Every other side is already // visually separated enough. - private void MainSplitContainer_Panel2_Paint(object sender, PaintEventArgs e) + private void ReadmeContainer_Paint(object sender, PaintEventArgs e) { - SplitterPanel panel2 = MainSplitContainer.Panel2; + Control rc = ReadmeContainer; if (MainSplitContainer.DarkModeEnabled) { - e.Graphics.DrawLine(DarkColors.GreySelectionPen, panel2.Left, panel2.Height - 2, panel2.Right, panel2.Height - 2); - e.Graphics.DrawLine(DarkColors.Fen_ControlBackgroundPen, panel2.Left, panel2.Height - 1, panel2.Right, panel2.Height - 1); + e.Graphics.DrawLine(DarkColors.GreySelectionPen, rc.Left, rc.Height - 2, rc.Right, rc.Height - 2); + e.Graphics.DrawLine(DarkColors.Fen_ControlBackgroundPen, rc.Left, rc.Height - 1, rc.Right, rc.Height - 1); } else { - e.Graphics.DrawLine(SystemPens.ControlLight, panel2.Left, panel2.Height - 2, panel2.Right, panel2.Height - 2); + e.Graphics.DrawLine(SystemPens.ControlLight, rc.Left, rc.Height - 2, rc.Right, rc.Height - 2); } } @@ -5026,7 +5026,7 @@ public void UpdateConfig() private bool CursorOverReadmeArea() { return ReadmeRichTextBox.Visible ? CursorOverControl(ReadmeRichTextBox) : - ViewHTMLReadmeLLButton.Visible && CursorOverControl(MainSplitContainer.Panel2); + ViewHTMLReadmeLLButton.Visible && CursorOverControl(ReadmeContainer); } // Standard Windows drop-down behavior: nothing else responds until the drop-down closes @@ -5348,4 +5348,7 @@ public void ShowUpdateNotification(bool show) Lazy_UpdateNotification.SetVisible(show); } } + + // We might want to change this, if we want something beside the readme or whatever + internal Control ReadmeContainer => MainSplitContainer.Panel2; } diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index 2c4fd1ed2..38757edb6 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -212,7 +212,7 @@ private void InitComponentManual() MainSplitContainer.Panel2.Controls.Add(ChooseReadmeComboBox); MainSplitContainer.Panel2.Controls.Add(ReadmeRichTextBox); MainSplitContainer.Panel2.MouseLeave += ReadmeArea_MouseLeave; - MainSplitContainer.Panel2.Paint += MainSplitContainer_Panel2_Paint; + MainSplitContainer.Panel2.Paint += ReadmeContainer_Paint; MainSplitContainer.Panel2MinSize = 38; MainSplitContainer.Panel2.Padding = new Padding(1, 1, 2, 2); MainSplitContainer.RefreshSiblingFirst = true; From 4375c0dfcc15e258a9109ec0319828f92516f8a9 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 21 Feb 2024 02:26:13 -0800 Subject: [PATCH 003/200] Update research notes --- AngelLoader/Forms/MainForm.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index ff8aee211..0cb751402 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -4,19 +4,17 @@ @ScreenshotDisplay(TDM screenshot filename formats): -We need to check all versions to see if there are any other formats. - -Format 1 (2.06 at the very least): +Format 1 (1.08 - 2.10): mapname + "_%Y-%m-%d_%H.%M.%S." + extension Example: river1_1_2016-11-03_21.47.21.png Extracted fm name should be "river1_1" -Format 2 (2.11 at the very least): +Format 2 (2.11+): mapname + " (%Y-%m-%d %H-%M-%S) (" + playerViewOriginStr + ")." + extension Example: written (2023-10-03 20-19-23) (889.44 -1464.35 174.68).jpg Extracted fm name should be "written" -So if these are the only two formats, then the FM name extraction logic should be: +So the FM name extraction logic should be: If a space exists, substring to the first space Else if a second-last underscore exists, substring to that From c14d6b36b9105c61b4578bc6caedb7a03c87da1f Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 21 Feb 2024 03:33:14 -0800 Subject: [PATCH 004/200] Implement Screenshots tab at a basic level --- .../DataClasses/ConfigDataSupporting.cs | 31 ++-- AngelLoader/Common/EnumData.Generated.cs | 1 + AngelLoader/Core.cs | 2 +- .../Forms/CustomControls/DarkArrowButton.cs | 1 + .../LazyLoaded/TopRightLLMenu.cs | 7 +- .../Lazy_ScreenshotsPage.Designer.cs | 86 ++++++++++ .../TopRightPages/Lazy_ScreenshotsPage.cs | 15 ++ .../TopRightPages/Lazy_ScreenshotsPage.resx | 120 ++++++++++++++ ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 46 ++++++ .../TopRightPages/ScreenshotsTabPage.cs | 147 ++++++++++++++++++ AngelLoader/Forms/MainForm.Designer.cs | 12 ++ AngelLoader/Forms/MainForm.cs | 24 +-- AngelLoader/Forms/MainForm_InitManual.cs | 1 + 13 files changed, 466 insertions(+), 27 deletions(-) create mode 100644 AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs create mode 100644 AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs create mode 100644 AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.resx create mode 100644 AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs create mode 100644 AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs diff --git a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs index 087c12d11..1570c1ac8 100644 --- a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs +++ b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs @@ -98,24 +98,29 @@ public enum CheckForUpdates #region Top-right tabs // IMPORTANT(TopRightTab enum): Do not rename members, they're used in the config file -internal enum TopRightTab { Statistics, EditFM, Comment, Tags, Patch, Mods } +[FenGenEnumCount] +internal enum TopRightTab +{ + Statistics, + EditFM, + Comment, + Tags, + Patch, + Mods, + Screenshots +} internal sealed class TopRightTabData { private int _displayIndex; - internal int DisplayIndex { get => _displayIndex; set => _displayIndex = value.Clamp(0, TopRightTabsData.Count - 1); } + internal int DisplayIndex { get => _displayIndex; set => _displayIndex = value.Clamp(0, TopRightTabCount - 1); } internal bool Visible = true; } internal sealed class TopRightTabsData { - /// - /// Returns the number of tabs that have been defined in the enum. - /// - internal static readonly int Count = Enum.GetValues(typeof(TopRightTab)).Length; - - internal readonly TopRightTabData[] Tabs = InitializedArray(Count); + internal readonly TopRightTabData[] Tabs = InitializedArray(TopRightTabCount); internal TopRightTab SelectedTab = TopRightTab.Statistics; @@ -128,7 +133,7 @@ internal void EnsureValidity() #region Fallback if multiple tabs have the same display index var displayIndexesSet = new HashSet(); - for (int i = 0; i < Count; i++) + for (int i = 0; i < TopRightTabCount; i++) { if (!displayIndexesSet.Add(Tabs[i].DisplayIndex)) { @@ -144,7 +149,7 @@ internal void EnsureValidity() // Fallback if selected tab is not marked as visible if (!GetTab(SelectedTab).Visible) { - for (int i = 0; i < Count; i++) + for (int i = 0; i < TopRightTabCount; i++) { if (Tabs[i].Visible) { @@ -157,18 +162,18 @@ internal void EnsureValidity() private bool NoneVisible() { - for (int i = 0; i < Count; i++) if (Tabs[i].Visible) return false; + for (int i = 0; i < TopRightTabCount; i++) if (Tabs[i].Visible) return false; return true; } private void SetAllVisible(bool visible) { - for (int i = 0; i < Count; i++) Tabs[i].Visible = visible; + for (int i = 0; i < TopRightTabCount; i++) Tabs[i].Visible = visible; } private void ResetAllDisplayIndexes() { - for (int i = 0; i < Count; i++) Tabs[i].DisplayIndex = i; + for (int i = 0; i < TopRightTabCount; i++) Tabs[i].DisplayIndex = i; } } diff --git a/AngelLoader/Common/EnumData.Generated.cs b/AngelLoader/Common/EnumData.Generated.cs index 55c9d2d3b..134490fbe 100644 --- a/AngelLoader/Common/EnumData.Generated.cs +++ b/AngelLoader/Common/EnumData.Generated.cs @@ -9,6 +9,7 @@ public static partial class Misc { public const int ColumnCount = 14; public const int HideableFilterControlsCount = 10; + public const int TopRightTabCount = 7; public const int SettingsTabCount = 5; public static readonly string[] CustomResourcesNames = { diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index ffe6767a9..1e049db08 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2567,7 +2567,7 @@ internal static void UpdateConfig( Config.TopRightTabsData.SelectedTab = topRightTabsData.SelectedTab; - for (int i = 0; i < TopRightTabsData.Count; i++) + for (int i = 0; i < TopRightTabCount; i++) { Config.TopRightTabsData.Tabs[i].DisplayIndex = topRightTabsData.Tabs[i].DisplayIndex; Config.TopRightTabsData.Tabs[i].Visible = topRightTabsData.Tabs[i].Visible; diff --git a/AngelLoader/Forms/CustomControls/DarkArrowButton.cs b/AngelLoader/Forms/CustomControls/DarkArrowButton.cs index 9cb0a8ac6..b40acb483 100644 --- a/AngelLoader/Forms/CustomControls/DarkArrowButton.cs +++ b/AngelLoader/Forms/CustomControls/DarkArrowButton.cs @@ -32,6 +32,7 @@ public Direction ArrowDirection protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); + if (DesignMode) return; Images.PaintArrow7x4( g: e.Graphics, direction: _arrowDirection, diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs index 972d3e543..5c6aefbd9 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs @@ -4,13 +4,14 @@ using JetBrains.Annotations; using static AL_Common.Common; using static AngelLoader.Global; +using static AngelLoader.Misc; namespace AngelLoader.Forms.CustomControls.LazyLoaded; internal sealed class TopRightLLMenu : IDarkable { private bool _constructed; - private readonly bool[] _checkedStates = InitializedArray(TopRightTabsData.Count, true); + private readonly bool[] _checkedStates = InitializedArray(TopRightTabCount, true); private readonly MainForm _owner; @@ -25,7 +26,7 @@ internal DarkContextMenu Menu _menu = new DarkContextMenu(_owner); - var menuItems = new ToolStripItem[TopRightTabsData.Count]; + var menuItems = new ToolStripItem[TopRightTabCount]; for (int i = 0; i < menuItems.Length; i++) { var item = new ToolStripMenuItemCustom @@ -126,6 +127,8 @@ internal void Localize() _menu.Items[(int)TopRightTab.Tags].Text = LText.TagsTab.TabText; _menu.Items[(int)TopRightTab.Patch].Text = LText.PatchTab.TabText; _menu.Items[(int)TopRightTab.Mods].Text = LText.ModsTab.TabText; + // @ScreenshotDisplay: Localize this + _menu.Items[(int)TopRightTab.Screenshots].Text = "Screenshots"; } internal bool Focused => _constructed && _menu.Focused; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs new file mode 100644 index 000000000..1e7ca83e6 --- /dev/null +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -0,0 +1,86 @@ +#define FenGen_DesignerSource + +namespace AngelLoader.Forms.CustomControls; + +public sealed partial class Lazy_ScreenshotsPage +{ + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + +#if DEBUG + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.ScreenshotsPictureBox = new System.Windows.Forms.PictureBox(); + this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkButton(); + this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkButton(); + ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); + this.SuspendLayout(); + // + // ScreenshotsPictureBox + // + this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); + this.ScreenshotsPictureBox.Name = "ScreenshotsPictureBox"; + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(328, 192); + this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.ScreenshotsPictureBox.TabIndex = 0; + this.ScreenshotsPictureBox.TabStop = false; + // + // ScreenshotsPrevButton + // + this.ScreenshotsPrevButton.Location = new System.Drawing.Point(187, 200); + this.ScreenshotsPrevButton.Name = "ScreenshotsPrevButton"; + this.ScreenshotsPrevButton.Size = new System.Drawing.Size(75, 23); + this.ScreenshotsPrevButton.TabIndex = 1; + this.ScreenshotsPrevButton.Text = "Prev"; + // + // ScreenshotsNextButton + // + this.ScreenshotsNextButton.Location = new System.Drawing.Point(262, 200); + this.ScreenshotsNextButton.Name = "ScreenshotsNextButton"; + this.ScreenshotsNextButton.Size = new System.Drawing.Size(75, 23); + this.ScreenshotsNextButton.TabIndex = 1; + this.ScreenshotsNextButton.Text = "Next"; + // + // Lazy_ScreenshotsPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoScroll = true; + this.Controls.Add(this.ScreenshotsNextButton); + this.Controls.Add(this.ScreenshotsPrevButton); + this.Controls.Add(this.ScreenshotsPictureBox); + this.Name = "Lazy_ScreenshotsPage"; + this.Size = new System.Drawing.Size(527, 284); + ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).EndInit(); + this.ResumeLayout(false); + + } +#endif + + #endregion + + internal System.Windows.Forms.PictureBox ScreenshotsPictureBox; + internal DarkButton ScreenshotsPrevButton; + internal DarkButton ScreenshotsNextButton; +} diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs new file mode 100644 index 000000000..6b1854213 --- /dev/null +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs @@ -0,0 +1,15 @@ +using System.Windows.Forms; + +namespace AngelLoader.Forms.CustomControls; + +public sealed partial class Lazy_ScreenshotsPage : UserControl +{ + public Lazy_ScreenshotsPage() + { +#if DEBUG + InitializeComponent(); +#else + InitSlim(); +#endif + } +} diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.resx b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.resx new file mode 100644 index 000000000..1af7de150 --- /dev/null +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs new file mode 100644 index 000000000..0cea8221b --- /dev/null +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -0,0 +1,46 @@ +namespace AngelLoader.Forms.CustomControls; + +public sealed partial class Lazy_ScreenshotsPage +{ + /// + /// Custom generated component initializer with cruft removed. + /// + private void InitSlim() + { + this.ScreenshotsPictureBox = new System.Windows.Forms.PictureBox(); + this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkButton(); + this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkButton(); + ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); + this.SuspendLayout(); + // + // ScreenshotsPictureBox + // + this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(328, 192); + this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + // + // ScreenshotsPrevButton + // + this.ScreenshotsPrevButton.Location = new System.Drawing.Point(187, 200); + this.ScreenshotsPrevButton.Size = new System.Drawing.Size(75, 23); + this.ScreenshotsPrevButton.TabIndex = 1; + // + // ScreenshotsNextButton + // + this.ScreenshotsNextButton.Location = new System.Drawing.Point(262, 200); + this.ScreenshotsNextButton.Size = new System.Drawing.Size(75, 23); + this.ScreenshotsNextButton.TabIndex = 1; + // + // Lazy_ScreenshotsPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoScroll = true; + this.Controls.Add(this.ScreenshotsNextButton); + this.Controls.Add(this.ScreenshotsPrevButton); + this.Controls.Add(this.ScreenshotsPictureBox); + this.Size = new System.Drawing.Size(527, 284); + ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).EndInit(); + this.ResumeLayout(false); + } +} diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs new file mode 100644 index 000000000..f3a0b4894 --- /dev/null +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -0,0 +1,147 @@ +using System; +using System.ComponentModel; +using System.IO; +using System.Linq; +using AngelLoader.DataClasses; +using JetBrains.Annotations; +using static AngelLoader.GameSupport; +using static AngelLoader.Utils; + +namespace AngelLoader.Forms.CustomControls; + +public sealed class ScreenshotsTabPage : Lazy_TabsBase +{ + private Lazy_ScreenshotsPage _page = null!; + + #region Theme + + [PublicAPI] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public override bool DarkModeEnabled + { + get => base.DarkModeEnabled; + set + { + if (DarkModeEnabled == value) return; + base.DarkModeEnabled = value; + } + } + + #endregion + + #region Public common + + public override void Construct() + { + if (_constructed) return; + + _page = ConstructPage(); + + using (new DisableEvents(_owner)) + { + Controls.Add(_page); + + _page.ScreenshotsPrevButton.Click += ScreenshotsPrevButton_Click; + _page.ScreenshotsNextButton.Click += ScreenshotsNextButton_Click; + + FinishConstruct(); + } + + _page.Show(); + } + + public override void Localize() + { + if (!_constructed) return; + + // @ScreenshotDisplay: Localize these + _page.ScreenshotsPrevButton.Text = "Prev"; + _page.ScreenshotsNextButton.Text = "Next"; + } + + public override void UpdatePage() + { + if (!_constructed) return; + + FanMission? fm = _owner.GetMainSelectedFMOrNull(); + + if (fm != null) + { + _page.ScreenshotsPictureBox.Enabled = true; + _page.ScreenshotsPrevButton.Enabled = true; + _page.ScreenshotsNextButton.Enabled = true; + + LoadScreenshots(fm); + } + else + { + _page.ScreenshotsPictureBox.Image = null; + _page.ScreenshotsPictureBox.Enabled = false; + _page.ScreenshotsPrevButton.Enabled = false; + _page.ScreenshotsNextButton.Enabled = false; + } + } + + // @ScreenshotDisplay: Move business logic out? + private void LoadScreenshots(FanMission fm) + { + if (!GameIsKnownAndSupported(fm.Game)) + { + _page.ScreenshotsPictureBox.Image = null; + } + else if (fm.Game == Game.TDM) + { + // @ScreenshotDisplay: Implement later + _page.ScreenshotsPictureBox.Image = null; + } + else + { + // @ScreenshotDisplay: Performance... we need a custom FileInfo getter without the 8.3 stuff + // And a custom comparer to avoid OrderBy() + if (fm.Installed && FMIsReallyInstalled(fm, out string fmInstalledPath)) + { + FileInfo[] files; + try + { + string ssPath = Path.Combine(fmInstalledPath, "screenshots"); + files = new DirectoryInfo(ssPath).GetFiles("*"); + } + catch + { + _page.ScreenshotsPictureBox.Image = null; + return; + } + + if (files.Length == 0) + { + _page.ScreenshotsPictureBox.Image = null; + return; + } + + files = files.OrderBy(static x => x.LastWriteTime).ToArray(); + _page.ScreenshotsPictureBox.Load(files[0].FullName); + } + else + { + _page.ScreenshotsPictureBox.Image = null; + } + } + } + + #region Page + + private void ScreenshotsPrevButton_Click(object sender, EventArgs e) + { + // @ScreenshotDisplay: Implement + } + + private void ScreenshotsNextButton_Click(object sender, EventArgs e) + { + // @ScreenshotDisplay: Implement + } + + #endregion + + #endregion +} diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 7cec7072c..9be337d25 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -109,6 +109,7 @@ private void InitializeComponent() this.TagsTabPage = new AngelLoader.Forms.CustomControls.TagsTabPage(); this.PatchTabPage = new AngelLoader.Forms.CustomControls.PatchTabPage(); this.ModsTabPage = new AngelLoader.Forms.CustomControls.ModsTabPage(); + this.ScreenshotsTabPage = new AngelLoader.Forms.CustomControls.ScreenshotsTabPage(); this.ReadmeEncodingButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ReadmeFullScreenButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ReadmeZoomInButton = new AngelLoader.Forms.CustomControls.DarkButton(); @@ -906,6 +907,7 @@ private void InitializeComponent() this.TopRightTabControl.Controls.Add(this.TagsTabPage); this.TopRightTabControl.Controls.Add(this.PatchTabPage); this.TopRightTabControl.Controls.Add(this.ModsTabPage); + this.TopRightTabControl.Controls.Add(this.ScreenshotsTabPage); this.TopRightTabControl.EnableScrollButtonsRefreshHack = true; this.TopRightTabControl.Location = new System.Drawing.Point(0, 0); this.TopRightTabControl.Name = "TopRightTabControl"; @@ -967,6 +969,15 @@ private void InitializeComponent() this.ModsTabPage.TabIndex = 4; this.ModsTabPage.Text = "Mods"; // + // ScreenshotsTabPage + // + this.ScreenshotsTabPage.BackColor = System.Drawing.SystemColors.Control; + this.ScreenshotsTabPage.Location = new System.Drawing.Point(4, 22); + this.ScreenshotsTabPage.Name = "ScreenshotsTabPage"; + this.ScreenshotsTabPage.Size = new System.Drawing.Size(527, 284); + this.ScreenshotsTabPage.TabIndex = 5; + this.ScreenshotsTabPage.Text = "Screenshots"; + // // ReadmeEncodingButton // this.ReadmeEncodingButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); @@ -1227,6 +1238,7 @@ private void InitializeComponent() internal CustomControls.TagsTabPage TagsTabPage; internal CustomControls.PatchTabPage PatchTabPage; internal CustomControls.ModsTabPage ModsTabPage; + internal CustomControls.ScreenshotsTabPage ScreenshotsTabPage; internal CustomControls.DarkButton TopRightMenuButton; internal CustomControls.DarkArrowButton TopRightCollapseButton; diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 0cb751402..cd3b8ab2c 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -678,14 +678,16 @@ and does NOT have its text transferred over. It ends up with blank text. _fmsListDefaultFontSizeInPoints = FMsDGV.DefaultCellStyle.Font.SizeInPoints; _fmsListDefaultRowHeight = FMsDGV.RowTemplate.Height; - _topRightTabs = new Lazy_TabsBase[] + // ReSharper disable once RedundantExplicitArraySize + _topRightTabs = new Lazy_TabsBase[TopRightTabCount] { StatisticsTabPage, EditFMTabPage, CommentTabPage, TagsTabPage, PatchTabPage, - ModsTabPage + ModsTabPage, + ScreenshotsTabPage }; for (int i = 0; i < _topRightTabs.Length; i++) @@ -917,23 +919,21 @@ and does NOT have its text transferred over. It ends up with blank text. #region Top-right tabs - AssertR(_topRightTabs.Length == TopRightTabsData.Count, nameof(_topRightTabs) + " length is different than enum length"); - var topRightTabsDict = new Dictionary(); - for (int i = 0; i < TopRightTabsData.Count; i++) + for (int i = 0; i < TopRightTabCount; i++) { topRightTabsDict.Add(Config.TopRightTabsData.Tabs[i].DisplayIndex, _topRightTabs[i]); } - var topRightTabs = new TabPage[TopRightTabsData.Count]; - for (int i = 0; i < TopRightTabsData.Count; i++) + var topRightTabs = new TabPage[TopRightTabCount]; + for (int i = 0; i < TopRightTabCount; i++) { topRightTabs[i] = topRightTabsDict[i]; } TopRightTabControl.SetTabsFull(topRightTabs); - for (int i = 0; i < TopRightTabsData.Count; i++) + for (int i = 0; i < TopRightTabCount; i++) { bool visible = Config.TopRightTabsData.Tabs[i].Visible; // They're visible by default - shave off a bit of time @@ -945,7 +945,7 @@ and does NOT have its text transferred over. It ends up with blank text. } // EnsureValidity() guarantees selected tab will not be invisible - for (int i = 0; i < TopRightTabsData.Count; i++) + for (int i = 0; i < TopRightTabCount; i++) { if ((int)Config.TopRightTabsData.SelectedTab == i) { @@ -1864,6 +1864,8 @@ private void Localize(bool startup) TagsTabPage.Text = LText.TagsTab.TabText; PatchTabPage.Text = LText.PatchTab.TabText; ModsTabPage.Text = LText.ModsTab.TabText; + // @ScreenshotDisplay: Localize this + ScreenshotsTabPage.Text = "Screenshots"; for (int i = 0; i < _topRightTabs.Length; i++) { @@ -3288,7 +3290,7 @@ internal void TopRightMenu_MenuItems_Click(object sender, EventArgs e) { var s = (ToolStripMenuItemCustom)sender; - TabPage tab = GetObjectFromMenuItem(TopRightLLMenu.Menu, s, _topRightTabs, TopRightTabsData.Count); + TabPage tab = GetObjectFromMenuItem(TopRightLLMenu.Menu, s, _topRightTabs, TopRightTabCount); if (!s.Checked && TopRightTabControl.TabCount == 1) { @@ -4972,7 +4974,7 @@ public void UpdateConfig() SelectedTab = (TopRightTab)Array.IndexOf(_topRightTabs.Cast().ToArray(), TopRightTabControl.SelectedTab) }; - for (int i = 0; i < TopRightTabsData.Count; i++) + for (int i = 0; i < TopRightTabCount; i++) { topRightTabs.Tabs[i].DisplayIndex = TopRightTabControl.GetTabDisplayIndex(_topRightTabs[i]); topRightTabs.Tabs[i].Visible = TopRightTabControl.Contains(_topRightTabs[i]); diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index 38757edb6..c54a27dec 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -86,6 +86,7 @@ private void InitComponentManual() TagsTabPage = new TagsTabPage(); PatchTabPage = new PatchTabPage(); ModsTabPage = new ModsTabPage(); + ScreenshotsTabPage = new ScreenshotsTabPage(); ReadmeEncodingButton = new DarkButton(); ReadmeFullScreenButton = new DarkButton(); ReadmeZoomInButton = new DarkButton(); From d0fca35dc9e53d8e4090278f523a7cf6fcb06215 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 21 Feb 2024 10:29:54 -0800 Subject: [PATCH 005/200] More screenshot display work, and support TDM screenshots --- AngelLoader/Core.cs | 102 ++++++++++++++++++ .../TopRightPages/ScreenshotsTabPage.cs | 67 +++--------- AngelLoader/Forms/MainForm.cs | 22 ---- 3 files changed, 114 insertions(+), 77 deletions(-) diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index 1e049db08..af5847429 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2739,4 +2739,106 @@ internal static VisualTheme GetSystemTheme() return VisualTheme.Classic; } + + /// + /// If there are screenshots on disk, will contain their full names. + /// If there are none, or if is , will be empty. + /// + /// + /// + internal static void PopulateScreenshotFileNames(FanMission? fm, List screenshotFileNames) + { + screenshotFileNames.Clear(); + if (fm == null) return; + if (!GameIsKnownAndSupported(fm.Game)) return; + + if (fm.Game == Game.TDM) + { + /* + TDM screenshot filename formats: + + Format 1 (1.08 - 2.10): + mapname + "_%Y-%m-%d_%H.%M.%S." + extension + Example: river1_1_2016-11-03_21.47.21.png + Extracted fm name should be "river1_1" + + Format 2 (2.11+): + mapname + " (%Y-%m-%d %H-%M-%S) (" + playerViewOriginStr + ")." + extension + Example: written (2023-10-03 20-19-23) (889.44 -1464.35 174.68).jpg + Extracted fm name should be "written" + */ + + string tdmGamePath = Config.GetGamePath(GameIndex.TDM); + if (!tdmGamePath.IsEmpty() && + /* + TDM stores all FMs' screenshots in the same dir. To prevent having to get the entire set (which + could be very large), just get ones starting with our FM name and do a proper filter afterwards. + */ + TryGetSortedScreenshotFileInfos(tdmGamePath, fm.TDMInstalledDir + "*.*", out FileInfo[]? files)) + { + for (int i = 0; i < files.Length; i++) + { + FileInfo item = files[i]; + string fn = item.Name; + + int spaceIndex = fn.IndexOf(' '); + // @TDM_CASE: Screenshot FM name comparison + if (spaceIndex > -1 && fn.Substring(0, spaceIndex).Trim().EqualsI(fm.TDMInstalledDir)) + { + screenshotFileNames.Add(item.FullName); + } + else + { + int underscoreIndex = fn.LastIndexOf('_'); + if (underscoreIndex == -1) continue; + + int secondToLastUnderscoreIndex = fn.LastIndexOf('_', (underscoreIndex - 1).ClampToZero()); + if (secondToLastUnderscoreIndex <= -1) continue; + + // @TDM_CASE: Screenshot FM name comparison + if (fn.Substring(0, secondToLastUnderscoreIndex).Trim().EqualsI(fm.TDMInstalledDir)) + { + screenshotFileNames.Add(item.FullName); + } + } + } + } + } + else + { + if (fm.Installed && FMIsReallyInstalled(fm, out string fmInstalledPath) && + TryGetSortedScreenshotFileInfos(fmInstalledPath, "*", out FileInfo[]? files)) + { + for (int i = 0; i < files.Length; i++) + { + screenshotFileNames.Add(files[i].FullName); + } + } + } + + return; + + static bool TryGetSortedScreenshotFileInfos( + string screenshotsDirParentPath, + string pattern, + [NotNullWhen(true)] out FileInfo[]? screenshots) + { + // @ScreenshotDisplay: Performance... we need a custom FileInfo getter without the 8.3 stuff + // And a custom comparer to avoid OrderBy() + try + { + string ssPath = Path.Combine(screenshotsDirParentPath, "screenshots"); + screenshots = new DirectoryInfo(ssPath) + .GetFiles(pattern) + .OrderBy(static x => x.LastWriteTime) + .ToArray(); + return true; + } + catch + { + screenshots = null; + return false; + } + } + } } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index f3a0b4894..063506323 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,11 +1,8 @@ using System; +using System.Collections.Generic; using System.ComponentModel; -using System.IO; -using System.Linq; using AngelLoader.DataClasses; using JetBrains.Annotations; -using static AngelLoader.GameSupport; -using static AngelLoader.Utils; namespace AngelLoader.Forms.CustomControls; @@ -13,6 +10,8 @@ public sealed class ScreenshotsTabPage : Lazy_TabsBase { private Lazy_ScreenshotsPage _page = null!; + private readonly List ScreenshotFileNames = new(); + #region Theme [PublicAPI] @@ -60,72 +59,30 @@ public override void Localize() _page.ScreenshotsNextButton.Text = "Next"; } + // @ScreenshotDisplay: Implement not loading images when hidden, and loading on show + public override void UpdatePage() { if (!_constructed) return; FanMission? fm = _owner.GetMainSelectedFMOrNull(); - if (fm != null) - { - _page.ScreenshotsPictureBox.Enabled = true; - _page.ScreenshotsPrevButton.Enabled = true; - _page.ScreenshotsNextButton.Enabled = true; + Core.PopulateScreenshotFileNames(fm, ScreenshotFileNames); - LoadScreenshots(fm); - } - else + if (ScreenshotFileNames.Count == 0) { _page.ScreenshotsPictureBox.Image = null; _page.ScreenshotsPictureBox.Enabled = false; _page.ScreenshotsPrevButton.Enabled = false; _page.ScreenshotsNextButton.Enabled = false; } - } - - // @ScreenshotDisplay: Move business logic out? - private void LoadScreenshots(FanMission fm) - { - if (!GameIsKnownAndSupported(fm.Game)) - { - _page.ScreenshotsPictureBox.Image = null; - } - else if (fm.Game == Game.TDM) - { - // @ScreenshotDisplay: Implement later - _page.ScreenshotsPictureBox.Image = null; - } else { - // @ScreenshotDisplay: Performance... we need a custom FileInfo getter without the 8.3 stuff - // And a custom comparer to avoid OrderBy() - if (fm.Installed && FMIsReallyInstalled(fm, out string fmInstalledPath)) - { - FileInfo[] files; - try - { - string ssPath = Path.Combine(fmInstalledPath, "screenshots"); - files = new DirectoryInfo(ssPath).GetFiles("*"); - } - catch - { - _page.ScreenshotsPictureBox.Image = null; - return; - } - - if (files.Length == 0) - { - _page.ScreenshotsPictureBox.Image = null; - return; - } - - files = files.OrderBy(static x => x.LastWriteTime).ToArray(); - _page.ScreenshotsPictureBox.Load(files[0].FullName); - } - else - { - _page.ScreenshotsPictureBox.Image = null; - } + // @ScreenshotDisplay: Should we save the selected screenshot in the FM object? + _page.ScreenshotsPictureBox.Load(ScreenshotFileNames[0]); + _page.ScreenshotsPictureBox.Enabled = true; + _page.ScreenshotsPrevButton.Enabled = ScreenshotFileNames.Count > 1; + _page.ScreenshotsNextButton.Enabled = ScreenshotFileNames.Count > 1; } } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index cd3b8ab2c..4695ec48c 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -1,27 +1,5 @@ /* NOTE: MainForm notes: ---- - -@ScreenshotDisplay(TDM screenshot filename formats): - -Format 1 (1.08 - 2.10): -mapname + "_%Y-%m-%d_%H.%M.%S." + extension -Example: river1_1_2016-11-03_21.47.21.png -Extracted fm name should be "river1_1" - -Format 2 (2.11+): -mapname + " (%Y-%m-%d %H-%M-%S) (" + playerViewOriginStr + ")." + extension -Example: written (2023-10-03 20-19-23) (889.44 -1464.35 174.68).jpg -Extracted fm name should be "written" - -So the FM name extraction logic should be: - -If a space exists, substring to the first space -Else if a second-last underscore exists, substring to that -Else skip the file - ---- - @LazyLoad: Controls that can be lazy-loaded in principle: -Game buttons and game tabs (one or the other will be invisible on startup) -Game tabs image list From 4301ff9ebe7ebfc63e125d7ffa2b1a8c966a2311 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 21 Feb 2024 14:44:41 -0800 Subject: [PATCH 006/200] Don't load screenshot into the picture box when it's not visible We still have to get the list of files from disk to do the filename equality comparison, but that's extremely fast and the picturebox load is the slow thing, so it's fine. --- .../TopRightPages/ScreenshotsTabPage.cs | 24 ++++++++++++++++--- AngelLoader/Forms/MainForm.cs | 6 ++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 063506323..10187bb82 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using AL_Common; using AngelLoader.DataClasses; using JetBrains.Annotations; @@ -11,6 +12,7 @@ public sealed class ScreenshotsTabPage : Lazy_TabsBase private Lazy_ScreenshotsPage _page = null!; private readonly List ScreenshotFileNames = new(); + private string StoredScreenshotFileName = ""; #region Theme @@ -65,27 +67,43 @@ public override void UpdatePage() { if (!_constructed) return; + if (!_owner.StartupState && !Visible) return; + FanMission? fm = _owner.GetMainSelectedFMOrNull(); Core.PopulateScreenshotFileNames(fm, ScreenshotFileNames); if (ScreenshotFileNames.Count == 0) { + StoredScreenshotFileName = ""; _page.ScreenshotsPictureBox.Image = null; _page.ScreenshotsPictureBox.Enabled = false; _page.ScreenshotsPrevButton.Enabled = false; _page.ScreenshotsNextButton.Enabled = false; } - else + // @ScreenshotDisplay: Should we save the selected screenshot in the FM object? + // @TDM_CASE (when the FM is TDM) + else if (!StoredScreenshotFileName.EqualsI(ScreenshotFileNames[0])) { - // @ScreenshotDisplay: Should we save the selected screenshot in the FM object? - _page.ScreenshotsPictureBox.Load(ScreenshotFileNames[0]); + // @ScreenshotDisplay: We can't just use the 0th element, we need to use the actual selected one + StoredScreenshotFileName = ScreenshotFileNames[0]; + _page.ScreenshotsPictureBox.Load(StoredScreenshotFileName); _page.ScreenshotsPictureBox.Enabled = true; _page.ScreenshotsPrevButton.Enabled = ScreenshotFileNames.Count > 1; _page.ScreenshotsNextButton.Enabled = ScreenshotFileNames.Count > 1; } } + protected override void OnVisibleChanged(EventArgs e) + { + base.OnVisibleChanged(e); + + if (!_owner.StartupState && Visible) + { + UpdatePage(); + } + } + #region Page private void ScreenshotsPrevButton_Click(object sender, EventArgs e) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 4695ec48c..c57c91b2e 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -71,7 +71,7 @@ public sealed partial class MainForm : DarkFormBase, #region Private fields // Stupid hack for if event handlers need to know - private bool _startupState = true; + internal bool StartupState { get; private set; } = true; private ISplashScreen_Safe? _splashScreen; @@ -1202,7 +1202,7 @@ private void SetWindowStateAndSize() _splashScreen?.Hide(); _splashScreen = null; - _startupState = false; + StartupState = false; } #endregion @@ -1242,7 +1242,7 @@ protected override void OnDeactivate(EventArgs e) protected override void OnSizeChanged(EventArgs e) { // Prevent unpleasant visual garbage drawing in the window on startup if we do the full thing - if (_startupState) + if (StartupState) { if (WindowState != FormWindowState.Minimized) { From 5fcec79367e88ee78a4bfe9b0c1b900eb0131a42 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 21 Feb 2024 15:21:38 -0800 Subject: [PATCH 007/200] Only use screenshot files in supported formats --- AngelLoader/Common/Utility/PathUtils.cs | 13 +++++++++++++ AngelLoader/Core.cs | 16 ++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/AngelLoader/Common/Utility/PathUtils.cs b/AngelLoader/Common/Utility/PathUtils.cs index d60572aad..713a1b5ca 100644 --- a/AngelLoader/Common/Utility/PathUtils.cs +++ b/AngelLoader/Common/Utility/PathUtils.cs @@ -129,6 +129,19 @@ internal static bool ExtIsArchive(this string value) => internal static bool ExtIsRar(this string value) => value.EndsWithI(".rar"); + // Another leak of view implementation details into here (GDI+/Bitmap supported formats) + // @ScreenshotDisplay: NewDark games can also have .pcx, and TDM can also have .tga + // Neither are supported by Bitmap, so, you're kinda out of luck on those. + internal static bool ExtIsUISupportedImage(this string value) => + // Common/likely ones first + value.EndsWithI(".png") || + value.EndsWithI(".bmp") || + value.EndsWithI(".jpg") || + value.EndsWithI(".jpeg") || + value.EndsWithI(".gif") || + value.EndsWithI(".tif") || + value.EndsWithI(".tiff"); + #endregion #endregion diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index af5847429..e71f18457 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2785,7 +2785,7 @@ Extracted fm name should be "written" // @TDM_CASE: Screenshot FM name comparison if (spaceIndex > -1 && fn.Substring(0, spaceIndex).Trim().EqualsI(fm.TDMInstalledDir)) { - screenshotFileNames.Add(item.FullName); + AddIfValidFormat(screenshotFileNames, item.FullName); } else { @@ -2798,7 +2798,7 @@ Extracted fm name should be "written" // @TDM_CASE: Screenshot FM name comparison if (fn.Substring(0, secondToLastUnderscoreIndex).Trim().EqualsI(fm.TDMInstalledDir)) { - screenshotFileNames.Add(item.FullName); + AddIfValidFormat(screenshotFileNames, item.FullName); } } } @@ -2811,7 +2811,7 @@ Extracted fm name should be "written" { for (int i = 0; i < files.Length; i++) { - screenshotFileNames.Add(files[i].FullName); + AddIfValidFormat(screenshotFileNames, files[i].FullName); } } } @@ -2824,7 +2824,7 @@ static bool TryGetSortedScreenshotFileInfos( [NotNullWhen(true)] out FileInfo[]? screenshots) { // @ScreenshotDisplay: Performance... we need a custom FileInfo getter without the 8.3 stuff - // And a custom comparer to avoid OrderBy() + // @ScreenshotDisplay: And a custom comparer to avoid OrderBy() try { string ssPath = Path.Combine(screenshotsDirParentPath, "screenshots"); @@ -2840,5 +2840,13 @@ static bool TryGetSortedScreenshotFileInfos( return false; } } + + static void AddIfValidFormat(List screenshotFileNames, string filename) + { + if (filename.ExtIsUISupportedImage()) + { + screenshotFileNames.Add(filename); + } + } } } From 0e5ff0cfa4ef274565f13d29f055d7f2d9858213 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 22 Feb 2024 11:38:27 -0800 Subject: [PATCH 008/200] Implement prev/next, and disable caching for now Let's finish the feature before we add the perf complexity --- .../TopRightPages/ScreenshotsTabPage.cs | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 10187bb82..8655bed5c 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using AL_Common; using AngelLoader.DataClasses; using JetBrains.Annotations; @@ -12,7 +11,7 @@ public sealed class ScreenshotsTabPage : Lazy_TabsBase private Lazy_ScreenshotsPage _page = null!; private readonly List ScreenshotFileNames = new(); - private string StoredScreenshotFileName = ""; + private string CurrentScreenshotFileName = ""; #region Theme @@ -67,53 +66,54 @@ public override void UpdatePage() { if (!_constructed) return; - if (!_owner.StartupState && !Visible) return; - FanMission? fm = _owner.GetMainSelectedFMOrNull(); Core.PopulateScreenshotFileNames(fm, ScreenshotFileNames); if (ScreenshotFileNames.Count == 0) { - StoredScreenshotFileName = ""; + CurrentScreenshotFileName = ""; _page.ScreenshotsPictureBox.Image = null; _page.ScreenshotsPictureBox.Enabled = false; _page.ScreenshotsPrevButton.Enabled = false; _page.ScreenshotsNextButton.Enabled = false; } // @ScreenshotDisplay: Should we save the selected screenshot in the FM object? - // @TDM_CASE (when the FM is TDM) - else if (!StoredScreenshotFileName.EqualsI(ScreenshotFileNames[0])) + else { - // @ScreenshotDisplay: We can't just use the 0th element, we need to use the actual selected one - StoredScreenshotFileName = ScreenshotFileNames[0]; - _page.ScreenshotsPictureBox.Load(StoredScreenshotFileName); + CurrentScreenshotFileName = ScreenshotFileNames[0]; + DisplayCurrentScreenshot(); _page.ScreenshotsPictureBox.Enabled = true; _page.ScreenshotsPrevButton.Enabled = ScreenshotFileNames.Count > 1; _page.ScreenshotsNextButton.Enabled = ScreenshotFileNames.Count > 1; } } - protected override void OnVisibleChanged(EventArgs e) + private void DisplayCurrentScreenshot() { - base.OnVisibleChanged(e); - - if (!_owner.StartupState && Visible) - { - UpdatePage(); - } + _page.ScreenshotsPictureBox.Load(CurrentScreenshotFileName); } #region Page - private void ScreenshotsPrevButton_Click(object sender, EventArgs e) - { - // @ScreenshotDisplay: Implement - } + private void ScreenshotsPrevButton_Click(object sender, EventArgs e) => CycleScreenshot(step: -1); + + private void ScreenshotsNextButton_Click(object sender, EventArgs e) => CycleScreenshot(step: 1); - private void ScreenshotsNextButton_Click(object sender, EventArgs e) + private void CycleScreenshot(int step) { - // @ScreenshotDisplay: Implement + if (ScreenshotFileNames.Count <= 1) return; + int index = ScreenshotFileNames.IndexOf(CurrentScreenshotFileName); + + if (index == -1) return; + + index = + step == 1 + ? index == ScreenshotFileNames.Count - 1 ? 0 : index + 1 + : index == 0 ? ScreenshotFileNames.Count - 1 : index - 1; + + CurrentScreenshotFileName = ScreenshotFileNames[index]; + DisplayCurrentScreenshot(); } #endregion From a4aa2be1d7ac33102efb95c7d48faa1ee6af9eba Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 07:58:02 -0800 Subject: [PATCH 009/200] Screenshots work: -Finish no-load-when-invisible logic -Fix slow perf when screenshots dir doesn't exist --- AngelLoader/Core.cs | 10 +++++++++- .../TopRightPages/ScreenshotsTabPage.cs | 18 +++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index e71f18457..014459f73 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2828,7 +2828,15 @@ static bool TryGetSortedScreenshotFileInfos( try { string ssPath = Path.Combine(screenshotsDirParentPath, "screenshots"); - screenshots = new DirectoryInfo(ssPath) + DirectoryInfo di = new(ssPath); + // Standard practice is to let the GetFiles() call throw if the directory doesn't exist, but for + // some reason that takes ~30ms whereas this check is <2ms (cold) to <.1ms (warm). + if (!di.Exists) + { + screenshots = null; + return false; + } + screenshots = di .GetFiles(pattern) .OrderBy(static x => x.LastWriteTime) .ToArray(); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 8655bed5c..a6db79569 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using AL_Common; using AngelLoader.DataClasses; using JetBrains.Annotations; @@ -74,6 +75,7 @@ public override void UpdatePage() { CurrentScreenshotFileName = ""; _page.ScreenshotsPictureBox.Image = null; + _page.ScreenshotsPictureBox.ImageLocation = ""; _page.ScreenshotsPictureBox.Enabled = false; _page.ScreenshotsPrevButton.Enabled = false; _page.ScreenshotsNextButton.Enabled = false; @@ -91,7 +93,21 @@ public override void UpdatePage() private void DisplayCurrentScreenshot() { - _page.ScreenshotsPictureBox.Load(CurrentScreenshotFileName); + if (!_constructed) return; + if (!_owner.StartupState && !Visible) return; + + if (!CurrentScreenshotFileName.IsEmpty() && + // @TDM_CASE when FM is TDM + (_page.ScreenshotsPictureBox.ImageLocation?.EqualsI(CurrentScreenshotFileName) != true)) + { + _page.ScreenshotsPictureBox.Load(CurrentScreenshotFileName); + } + } + + protected override void OnVisibleChanged(EventArgs e) + { + base.OnVisibleChanged(e); + if (Visible) DisplayCurrentScreenshot(); } #region Page From 468556749fbbeee7046529a225a71ef5d0cd312b Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 08:15:28 -0800 Subject: [PATCH 010/200] Display number / count of screenshots --- .../Lazy_ScreenshotsPage.Designer.cs | 36 ++++++++++++------- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 24 +++++++++---- .../TopRightPages/ScreenshotsTabPage.cs | 16 ++++----- 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 1e7ca83e6..28328d33e 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -32,8 +32,9 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.ScreenshotsPictureBox = new System.Windows.Forms.PictureBox(); - this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkButton(); - this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkButton(); + this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); + this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); + this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); this.SuspendLayout(); // @@ -46,27 +47,36 @@ private void InitializeComponent() this.ScreenshotsPictureBox.TabIndex = 0; this.ScreenshotsPictureBox.TabStop = false; // + // ScreenshotsNextButton + // + this.ScreenshotsNextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; + this.ScreenshotsNextButton.Location = new System.Drawing.Point(262, 200); + this.ScreenshotsNextButton.Name = "ScreenshotsNextButton"; + this.ScreenshotsNextButton.Size = new System.Drawing.Size(75, 23); + this.ScreenshotsNextButton.TabIndex = 2; + // // ScreenshotsPrevButton // + this.ScreenshotsPrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; this.ScreenshotsPrevButton.Location = new System.Drawing.Point(187, 200); this.ScreenshotsPrevButton.Name = "ScreenshotsPrevButton"; this.ScreenshotsPrevButton.Size = new System.Drawing.Size(75, 23); - this.ScreenshotsPrevButton.TabIndex = 1; - this.ScreenshotsPrevButton.Text = "Prev"; + this.ScreenshotsPrevButton.TabIndex = 2; // - // ScreenshotsNextButton + // NumberLabel // - this.ScreenshotsNextButton.Location = new System.Drawing.Point(262, 200); - this.ScreenshotsNextButton.Name = "ScreenshotsNextButton"; - this.ScreenshotsNextButton.Size = new System.Drawing.Size(75, 23); - this.ScreenshotsNextButton.TabIndex = 1; - this.ScreenshotsNextButton.Text = "Next"; + this.NumberLabel.AutoSize = true; + this.NumberLabel.Location = new System.Drawing.Point(8, 204); + this.NumberLabel.Name = "NumberLabel"; + this.NumberLabel.Size = new System.Drawing.Size(0, 13); + this.NumberLabel.TabIndex = 3; // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; + this.Controls.Add(this.NumberLabel); this.Controls.Add(this.ScreenshotsNextButton); this.Controls.Add(this.ScreenshotsPrevButton); this.Controls.Add(this.ScreenshotsPictureBox); @@ -74,6 +84,7 @@ private void InitializeComponent() this.Size = new System.Drawing.Size(527, 284); ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).EndInit(); this.ResumeLayout(false); + this.PerformLayout(); } #endif @@ -81,6 +92,7 @@ private void InitializeComponent() #endregion internal System.Windows.Forms.PictureBox ScreenshotsPictureBox; - internal DarkButton ScreenshotsPrevButton; - internal DarkButton ScreenshotsNextButton; + internal DarkArrowButton ScreenshotsPrevButton; + internal DarkArrowButton ScreenshotsNextButton; + internal DarkLabel NumberLabel; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 0cea8221b..d9c313662 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -8,8 +8,9 @@ public sealed partial class Lazy_ScreenshotsPage private void InitSlim() { this.ScreenshotsPictureBox = new System.Windows.Forms.PictureBox(); - this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkButton(); - this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkButton(); + this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); + this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); + this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); this.SuspendLayout(); // @@ -19,28 +20,37 @@ private void InitSlim() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(328, 192); this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; // + // ScreenshotsNextButton + // + this.ScreenshotsNextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; + this.ScreenshotsNextButton.Location = new System.Drawing.Point(262, 200); + this.ScreenshotsNextButton.Size = new System.Drawing.Size(75, 23); + this.ScreenshotsNextButton.TabIndex = 2; + // // ScreenshotsPrevButton // + this.ScreenshotsPrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; this.ScreenshotsPrevButton.Location = new System.Drawing.Point(187, 200); this.ScreenshotsPrevButton.Size = new System.Drawing.Size(75, 23); - this.ScreenshotsPrevButton.TabIndex = 1; + this.ScreenshotsPrevButton.TabIndex = 2; // - // ScreenshotsNextButton + // NumberLabel // - this.ScreenshotsNextButton.Location = new System.Drawing.Point(262, 200); - this.ScreenshotsNextButton.Size = new System.Drawing.Size(75, 23); - this.ScreenshotsNextButton.TabIndex = 1; + this.NumberLabel.AutoSize = true; + this.NumberLabel.Location = new System.Drawing.Point(8, 204); // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; + this.Controls.Add(this.NumberLabel); this.Controls.Add(this.ScreenshotsNextButton); this.Controls.Add(this.ScreenshotsPrevButton); this.Controls.Add(this.ScreenshotsPictureBox); this.Size = new System.Drawing.Size(527, 284); ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).EndInit(); this.ResumeLayout(false); + this.PerformLayout(); } } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index a6db79569..417fc3d31 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,4 +1,6 @@ -using System; +// @ScreenshotDisplay: Make screenshot scale with resize + +using System; using System.Collections.Generic; using System.ComponentModel; using AL_Common; @@ -52,15 +54,6 @@ public override void Construct() _page.Show(); } - public override void Localize() - { - if (!_constructed) return; - - // @ScreenshotDisplay: Localize these - _page.ScreenshotsPrevButton.Text = "Prev"; - _page.ScreenshotsNextButton.Text = "Next"; - } - // @ScreenshotDisplay: Implement not loading images when hidden, and loading on show public override void UpdatePage() @@ -79,6 +72,7 @@ public override void UpdatePage() _page.ScreenshotsPictureBox.Enabled = false; _page.ScreenshotsPrevButton.Enabled = false; _page.ScreenshotsNextButton.Enabled = false; + _page.NumberLabel.Text = ""; } // @ScreenshotDisplay: Should we save the selected screenshot in the FM object? else @@ -101,6 +95,8 @@ private void DisplayCurrentScreenshot() (_page.ScreenshotsPictureBox.ImageLocation?.EqualsI(CurrentScreenshotFileName) != true)) { _page.ScreenshotsPictureBox.Load(CurrentScreenshotFileName); + _page.NumberLabel.Text = (ScreenshotFileNames.IndexOf(CurrentScreenshotFileName) + 1).ToStrInv() + " / " + + ScreenshotFileNames.Count.ToStrInv(); } } From 4a324be576bcca4e0edf9d277f5ddfff44948ac1 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 08:25:38 -0800 Subject: [PATCH 011/200] DarkPictureBox to support being on a lazy tab --- .../Forms/CustomControls/DarkPictureBox.cs | 31 +++++++++++++++++++ .../Lazy_ScreenshotsPage.Designer.cs | 4 +-- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 2 +- 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 AngelLoader/Forms/CustomControls/DarkPictureBox.cs diff --git a/AngelLoader/Forms/CustomControls/DarkPictureBox.cs b/AngelLoader/Forms/CustomControls/DarkPictureBox.cs new file mode 100644 index 000000000..bdffe4763 --- /dev/null +++ b/AngelLoader/Forms/CustomControls/DarkPictureBox.cs @@ -0,0 +1,31 @@ +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using AngelLoader.DataClasses; +using JetBrains.Annotations; + +namespace AngelLoader.Forms.CustomControls; + +public sealed class DarkPictureBox : PictureBox, IDarkable +{ + [PublicAPI] + public Color DrawnBackColor = SystemColors.Control; + + [PublicAPI] + public Color DarkModeDrawnBackColor = DarkColors.Fen_ControlBackground; + + private bool _darkModeEnabled; + [PublicAPI] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool DarkModeEnabled + { + get => _darkModeEnabled; + set + { + if (_darkModeEnabled == value) return; + _darkModeEnabled = value; + BackColor = _darkModeEnabled ? DarkModeDrawnBackColor : DrawnBackColor; + } + } +} diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 28328d33e..68a4c7252 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,7 +31,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.ScreenshotsPictureBox = new System.Windows.Forms.PictureBox(); + this.ScreenshotsPictureBox = new DarkPictureBox(); this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -91,7 +91,7 @@ private void InitializeComponent() #endregion - internal System.Windows.Forms.PictureBox ScreenshotsPictureBox; + internal DarkPictureBox ScreenshotsPictureBox; internal DarkArrowButton ScreenshotsPrevButton; internal DarkArrowButton ScreenshotsNextButton; internal DarkLabel NumberLabel; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index d9c313662..fde00bc36 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,7 +7,7 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { - this.ScreenshotsPictureBox = new System.Windows.Forms.PictureBox(); + this.ScreenshotsPictureBox = new DarkPictureBox(); this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); From b09eccac4b6aa9c3f824e17288d71cde66e6b647 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 08:35:19 -0800 Subject: [PATCH 012/200] Update notes/comments --- .../CustomControls/TopRightPages/ScreenshotsTabPage.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 417fc3d31..2ff8c2c85 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -54,8 +54,6 @@ public override void Construct() _page.Show(); } - // @ScreenshotDisplay: Implement not loading images when hidden, and loading on show - public override void UpdatePage() { if (!_constructed) return; @@ -85,6 +83,12 @@ public override void UpdatePage() } } + /* + The standard behavior for lazy loaded tabs is that they don't update until loaded, after which they always + update. However, loading an image could take a significant amount of time, and we don't want to punish users + with that lag time if they're not actually able to see the image. So we only update when visible (or when we + become visible). + */ private void DisplayCurrentScreenshot() { if (!_constructed) return; From 379e3337ea74c4fdeb9b7c2b87e7d450a611b1e8 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 08:39:15 -0800 Subject: [PATCH 013/200] Cleanup --- .../CustomControls/TopRightPages/ScreenshotsTabPage.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 2ff8c2c85..ba15fdee2 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -83,6 +83,10 @@ public override void UpdatePage() } } + #endregion + + #region Page + /* The standard behavior for lazy loaded tabs is that they don't update until loaded, after which they always update. However, loading an image could take a significant amount of time, and we don't want to punish users @@ -110,8 +114,6 @@ protected override void OnVisibleChanged(EventArgs e) if (Visible) DisplayCurrentScreenshot(); } - #region Page - private void ScreenshotsPrevButton_Click(object sender, EventArgs e) => CycleScreenshot(step: -1); private void ScreenshotsNextButton_Click(object sender, EventArgs e) => CycleScreenshot(step: 1); @@ -133,6 +135,4 @@ private void CycleScreenshot(int step) } #endregion - - #endregion } From cf9e856eadd392e0b4257832542a7e9725714817 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 08:45:06 -0800 Subject: [PATCH 014/200] Remove unused DarkModeEnabled override --- .../TopRightPages/ScreenshotsTabPage.cs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index ba15fdee2..cb7cb555f 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -2,10 +2,8 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using AL_Common; using AngelLoader.DataClasses; -using JetBrains.Annotations; namespace AngelLoader.Forms.CustomControls; @@ -16,23 +14,6 @@ public sealed class ScreenshotsTabPage : Lazy_TabsBase private readonly List ScreenshotFileNames = new(); private string CurrentScreenshotFileName = ""; - #region Theme - - [PublicAPI] - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public override bool DarkModeEnabled - { - get => base.DarkModeEnabled; - set - { - if (DarkModeEnabled == value) return; - base.DarkModeEnabled = value; - } - } - - #endregion - #region Public common public override void Construct() From b9f9dcde1d1b6fd0373561135e37960569b0cd2a Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 13:04:08 -0800 Subject: [PATCH 015/200] Note --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index cb7cb555f..36e03ff59 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,4 +1,5 @@ // @ScreenshotDisplay: Make screenshot scale with resize +// @ScreenshotDisplay: Watch screenshot folder and reload from disk using System; using System.Collections.Generic; From 6809bcccee768dc7093fa645a8389f1dc4622267 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 13:45:43 -0800 Subject: [PATCH 016/200] Tab order --- .../TopRightPages/Lazy_ScreenshotsPage.Designer.cs | 6 +++--- .../Lazy_ScreenshotsPage_InitSlim.Generated.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 68a4c7252..01c723517 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,7 +31,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.ScreenshotsPictureBox = new DarkPictureBox(); + this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -61,7 +61,7 @@ private void InitializeComponent() this.ScreenshotsPrevButton.Location = new System.Drawing.Point(187, 200); this.ScreenshotsPrevButton.Name = "ScreenshotsPrevButton"; this.ScreenshotsPrevButton.Size = new System.Drawing.Size(75, 23); - this.ScreenshotsPrevButton.TabIndex = 2; + this.ScreenshotsPrevButton.TabIndex = 1; // // NumberLabel // @@ -69,7 +69,7 @@ private void InitializeComponent() this.NumberLabel.Location = new System.Drawing.Point(8, 204); this.NumberLabel.Name = "NumberLabel"; this.NumberLabel.Size = new System.Drawing.Size(0, 13); - this.NumberLabel.TabIndex = 3; + this.NumberLabel.TabIndex = 0; // // Lazy_ScreenshotsPage // diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index fde00bc36..741404001 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,7 +7,7 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { - this.ScreenshotsPictureBox = new DarkPictureBox(); + this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -32,7 +32,7 @@ private void InitSlim() this.ScreenshotsPrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; this.ScreenshotsPrevButton.Location = new System.Drawing.Point(187, 200); this.ScreenshotsPrevButton.Size = new System.Drawing.Size(75, 23); - this.ScreenshotsPrevButton.TabIndex = 2; + this.ScreenshotsPrevButton.TabIndex = 1; // // NumberLabel // From 4ad36fcdb802cc2869081119c5c7bc1d69e316bb Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 14:07:48 -0800 Subject: [PATCH 017/200] Picture box resizes with tab resizing --- .../Lazy_ScreenshotsPage.Designer.cs | 41 +++++++++++-------- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 30 +++++++++----- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 01c723517..8e3c8e941 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,51 +31,58 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); + this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); - this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); + this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); this.SuspendLayout(); // - // ScreenshotsPictureBox + // NumberLabel // - this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); - this.ScreenshotsPictureBox.Name = "ScreenshotsPictureBox"; - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(328, 192); - this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; - this.ScreenshotsPictureBox.TabIndex = 0; - this.ScreenshotsPictureBox.TabStop = false; + this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.NumberLabel.AutoSize = true; + this.NumberLabel.Location = new System.Drawing.Point(8, 260); + this.NumberLabel.Name = "NumberLabel"; + this.NumberLabel.Size = new System.Drawing.Size(0, 13); + this.NumberLabel.TabIndex = 0; // // ScreenshotsNextButton // + this.ScreenshotsNextButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsNextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; - this.ScreenshotsNextButton.Location = new System.Drawing.Point(262, 200); + this.ScreenshotsNextButton.Location = new System.Drawing.Point(446, 256); this.ScreenshotsNextButton.Name = "ScreenshotsNextButton"; this.ScreenshotsNextButton.Size = new System.Drawing.Size(75, 23); this.ScreenshotsNextButton.TabIndex = 2; // // ScreenshotsPrevButton // + this.ScreenshotsPrevButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; - this.ScreenshotsPrevButton.Location = new System.Drawing.Point(187, 200); + this.ScreenshotsPrevButton.Location = new System.Drawing.Point(371, 256); this.ScreenshotsPrevButton.Name = "ScreenshotsPrevButton"; this.ScreenshotsPrevButton.Size = new System.Drawing.Size(75, 23); this.ScreenshotsPrevButton.TabIndex = 1; // - // NumberLabel + // ScreenshotsPictureBox // - this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(8, 204); - this.NumberLabel.Name = "NumberLabel"; - this.NumberLabel.Size = new System.Drawing.Size(0, 13); - this.NumberLabel.TabIndex = 0; + this.ScreenshotsPictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); + this.ScreenshotsPictureBox.Name = "ScreenshotsPictureBox"; + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 248); + this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.ScreenshotsPictureBox.TabIndex = 0; + this.ScreenshotsPictureBox.TabStop = false; // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; + this.AutoScrollMinSize = new System.Drawing.Size(220, 100); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.ScreenshotsNextButton); this.Controls.Add(this.ScreenshotsPrevButton); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 741404001..942c921c2 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,43 +7,51 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { - this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); + this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); - this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); + this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); this.SuspendLayout(); // - // ScreenshotsPictureBox + // NumberLabel // - this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(328, 192); - this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.NumberLabel.AutoSize = true; + this.NumberLabel.Location = new System.Drawing.Point(8, 260); + this.NumberLabel.Size = new System.Drawing.Size(0, 13); // // ScreenshotsNextButton // + this.ScreenshotsNextButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsNextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; - this.ScreenshotsNextButton.Location = new System.Drawing.Point(262, 200); + this.ScreenshotsNextButton.Location = new System.Drawing.Point(446, 256); this.ScreenshotsNextButton.Size = new System.Drawing.Size(75, 23); this.ScreenshotsNextButton.TabIndex = 2; // // ScreenshotsPrevButton // + this.ScreenshotsPrevButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; - this.ScreenshotsPrevButton.Location = new System.Drawing.Point(187, 200); + this.ScreenshotsPrevButton.Location = new System.Drawing.Point(371, 256); this.ScreenshotsPrevButton.Size = new System.Drawing.Size(75, 23); this.ScreenshotsPrevButton.TabIndex = 1; // - // NumberLabel + // ScreenshotsPictureBox // - this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(8, 204); + this.ScreenshotsPictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 248); + this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; + this.AutoScrollMinSize = new System.Drawing.Size(220, 100); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.ScreenshotsNextButton); this.Controls.Add(this.ScreenshotsPrevButton); From a78fc604eabfb1b8b873ffad453325c9af182efc Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 14:31:05 -0800 Subject: [PATCH 018/200] Remove dummy autoscroll panels and do it the proper way Seriously, I didn't notice the AutoScrollMinSize property all these years? Really?! --- .../Forms/CustomControls/ModsControl.Designer.cs | 15 +++------------ .../ModsControl_InitSlim.Generated.cs | 12 +++--------- .../Forms/Settings/AppearancePage.Designer.cs | 11 +---------- .../Settings/AppearancePage_InitSlim.Generated.cs | 8 +------- AngelLoader/Forms/Settings/OtherPage.Designer.cs | 11 +---------- .../Settings/OtherPage_InitSlim.Generated.cs | 8 +------- AngelLoader/Forms/Settings/PathsPage.Designer.cs | 11 +---------- .../Settings/PathsPage_InitSlim.Generated.cs | 8 +------- .../Forms/Settings/ThiefBuddyPage.Designer.cs | 11 +---------- .../Settings/ThiefBuddyPage_InitSlim.Generated.cs | 8 +------- AngelLoader/Forms/Settings/UpdatePage.Designer.cs | 11 +---------- .../Settings/UpdatePage_InitSlim.Generated.cs | 8 +------- 12 files changed, 16 insertions(+), 106 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/ModsControl.Designer.cs b/AngelLoader/Forms/CustomControls/ModsControl.Designer.cs index fa15ed79f..3a0794fcb 100644 --- a/AngelLoader/Forms/CustomControls/ModsControl.Designer.cs +++ b/AngelLoader/Forms/CustomControls/ModsControl.Designer.cs @@ -33,15 +33,14 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.HeaderLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); - this.ResetFLP = new DarkFlowLayoutPanel(); + this.ResetFLP = new AngelLoader.Forms.CustomControls.DarkFlowLayoutPanel(); this.DisableNonImportantButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.EnableAllButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ShowImportantCheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); this.DisabledModsTextBox = new AngelLoader.Forms.CustomControls.DarkTextBox(); this.DisabledModsLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.CheckList = new AngelLoader.Forms.CustomControls.ModsPanel(); - this.AutoScrollDummyPanel = new DrawnPanel(); - this.MainToolTip = new ToolTipCustom(this.components); + this.MainToolTip = new AngelLoader.Forms.CustomControls.ToolTipCustom(this.components); this.ResetFLP.SuspendLayout(); this.SuspendLayout(); // @@ -138,24 +137,17 @@ private void InitializeComponent() this.CheckList.Size = new System.Drawing.Size(512, 184); this.CheckList.TabIndex = 6; // - // AutoScrollDummyPanel - // - this.AutoScrollDummyPanel.Location = new System.Drawing.Point(7, 8); - this.AutoScrollDummyPanel.Name = "AutoScrollDummyPanel"; - this.AutoScrollDummyPanel.Size = new System.Drawing.Size(280, 208); - this.AutoScrollDummyPanel.TabIndex = 11; - // // ModsControl // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScroll = true; + this.AutoScrollMinSize = new System.Drawing.Size(287, 216); this.Controls.Add(this.HeaderLabel); this.Controls.Add(this.ResetFLP); this.Controls.Add(this.DisabledModsTextBox); this.Controls.Add(this.DisabledModsLabel); this.Controls.Add(this.CheckList); - this.Controls.Add(this.AutoScrollDummyPanel); this.Name = "ModsControl"; this.Size = new System.Drawing.Size(527, 284); this.ResetFLP.ResumeLayout(false); @@ -176,6 +168,5 @@ private void InitializeComponent() internal DarkTextBox DisabledModsTextBox; internal DarkLabel DisabledModsLabel; internal ModsPanel CheckList; - internal DrawnPanel AutoScrollDummyPanel; internal ToolTipCustom MainToolTip; } diff --git a/AngelLoader/Forms/CustomControls/ModsControl_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/ModsControl_InitSlim.Generated.cs index 410b26434..90bc5a53c 100644 --- a/AngelLoader/Forms/CustomControls/ModsControl_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/ModsControl_InitSlim.Generated.cs @@ -9,15 +9,14 @@ private void InitSlim() { this.components = new System.ComponentModel.Container(); this.HeaderLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); - this.ResetFLP = new DarkFlowLayoutPanel(); + this.ResetFLP = new AngelLoader.Forms.CustomControls.DarkFlowLayoutPanel(); this.DisableNonImportantButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.EnableAllButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ShowImportantCheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); this.DisabledModsTextBox = new AngelLoader.Forms.CustomControls.DarkTextBox(); this.DisabledModsLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.CheckList = new AngelLoader.Forms.CustomControls.ModsPanel(); - this.AutoScrollDummyPanel = new DrawnPanel(); - this.MainToolTip = new ToolTipCustom(this.components); + this.MainToolTip = new AngelLoader.Forms.CustomControls.ToolTipCustom(this.components); this.ResetFLP.SuspendLayout(); this.SuspendLayout(); // @@ -92,22 +91,17 @@ private void InitSlim() this.CheckList.Size = new System.Drawing.Size(512, 184); this.CheckList.TabIndex = 6; // - // AutoScrollDummyPanel - // - this.AutoScrollDummyPanel.Location = new System.Drawing.Point(7, 8); - this.AutoScrollDummyPanel.Size = new System.Drawing.Size(280, 208); - // // ModsControl // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScroll = true; + this.AutoScrollMinSize = new System.Drawing.Size(287, 216); this.Controls.Add(this.HeaderLabel); this.Controls.Add(this.ResetFLP); this.Controls.Add(this.DisabledModsTextBox); this.Controls.Add(this.DisabledModsLabel); this.Controls.Add(this.CheckList); - this.Controls.Add(this.AutoScrollDummyPanel); this.Size = new System.Drawing.Size(527, 284); this.ResetFLP.ResumeLayout(false); this.ResetFLP.PerformLayout(); diff --git a/AngelLoader/Forms/Settings/AppearancePage.Designer.cs b/AngelLoader/Forms/Settings/AppearancePage.Designer.cs index 0cbd16d99..ca156d291 100644 --- a/AngelLoader/Forms/Settings/AppearancePage.Designer.cs +++ b/AngelLoader/Forms/Settings/AppearancePage.Designer.cs @@ -82,7 +82,6 @@ private void InitializeComponent() this.ClassicThemeRadioButton = new AngelLoader.Forms.CustomControls.DarkRadioButton(); this.LanguageGroupBox = new AngelLoader.Forms.CustomControls.DarkGroupBox(); this.LanguageComboBox = new AngelLoader.Forms.CustomControls.DarkComboBoxWithBackingItems(); - this.DummyAutoScrollPanel = new System.Windows.Forms.Control(); this.PagePanel.SuspendLayout(); this.PlayWithoutFMGroupBox.SuspendLayout(); this.FMsListGroupBox.SuspendLayout(); @@ -102,13 +101,13 @@ private void InitializeComponent() // PagePanel // this.PagePanel.AutoScroll = true; + this.PagePanel.AutoScrollMinSize = new System.Drawing.Size(488, 0); this.PagePanel.Controls.Add(this.PlayWithoutFMGroupBox); this.PagePanel.Controls.Add(this.FMsListGroupBox); this.PagePanel.Controls.Add(this.ReadmeGroupBox); this.PagePanel.Controls.Add(this.ShowOrHideUIElementsGroupBox); this.PagePanel.Controls.Add(this.VisualThemeGroupBox); this.PagePanel.Controls.Add(this.LanguageGroupBox); - this.PagePanel.Controls.Add(this.DummyAutoScrollPanel); this.PagePanel.Dock = System.Windows.Forms.DockStyle.Fill; this.PagePanel.Location = new System.Drawing.Point(0, 0); this.PagePanel.Name = "PagePanel"; @@ -661,13 +660,6 @@ private void InitializeComponent() this.LanguageComboBox.Size = new System.Drawing.Size(184, 21); this.LanguageComboBox.TabIndex = 0; // - // DummyAutoScrollPanel - // - this.DummyAutoScrollPanel.Location = new System.Drawing.Point(8, 288); - this.DummyAutoScrollPanel.Name = "DummyAutoScrollPanel"; - this.DummyAutoScrollPanel.Size = new System.Drawing.Size(480, 8); - this.DummyAutoScrollPanel.TabIndex = 0; - // // AppearancePage // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -705,7 +697,6 @@ private void InitializeComponent() #endregion internal System.Windows.Forms.Panel PagePanel; - internal System.Windows.Forms.Control DummyAutoScrollPanel; internal AngelLoader.Forms.CustomControls.DarkGroupBox LanguageGroupBox; internal AngelLoader.Forms.CustomControls.DarkComboBoxWithBackingItems LanguageComboBox; internal AngelLoader.Forms.CustomControls.DarkGroupBox VisualThemeGroupBox; diff --git a/AngelLoader/Forms/Settings/AppearancePage_InitSlim.Generated.cs b/AngelLoader/Forms/Settings/AppearancePage_InitSlim.Generated.cs index 14db420cf..76b81519a 100644 --- a/AngelLoader/Forms/Settings/AppearancePage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/Settings/AppearancePage_InitSlim.Generated.cs @@ -58,7 +58,6 @@ private void InitSlim() this.ClassicThemeRadioButton = new AngelLoader.Forms.CustomControls.DarkRadioButton(); this.LanguageGroupBox = new AngelLoader.Forms.CustomControls.DarkGroupBox(); this.LanguageComboBox = new AngelLoader.Forms.CustomControls.DarkComboBoxWithBackingItems(); - this.DummyAutoScrollPanel = new System.Windows.Forms.Control(); this.PagePanel.SuspendLayout(); this.PlayWithoutFMGroupBox.SuspendLayout(); this.FMsListGroupBox.SuspendLayout(); @@ -78,13 +77,13 @@ private void InitSlim() // PagePanel // this.PagePanel.AutoScroll = true; + this.PagePanel.AutoScrollMinSize = new System.Drawing.Size(488, 0); this.PagePanel.Controls.Add(this.PlayWithoutFMGroupBox); this.PagePanel.Controls.Add(this.FMsListGroupBox); this.PagePanel.Controls.Add(this.ReadmeGroupBox); this.PagePanel.Controls.Add(this.ShowOrHideUIElementsGroupBox); this.PagePanel.Controls.Add(this.VisualThemeGroupBox); this.PagePanel.Controls.Add(this.LanguageGroupBox); - this.PagePanel.Controls.Add(this.DummyAutoScrollPanel); this.PagePanel.Dock = System.Windows.Forms.DockStyle.Fill; this.PagePanel.Size = new System.Drawing.Size(496, 1219); this.PagePanel.TabIndex = 0; @@ -513,11 +512,6 @@ private void InitSlim() this.LanguageComboBox.Size = new System.Drawing.Size(184, 21); this.LanguageComboBox.TabIndex = 0; // - // DummyAutoScrollPanel - // - this.DummyAutoScrollPanel.Location = new System.Drawing.Point(8, 288); - this.DummyAutoScrollPanel.Size = new System.Drawing.Size(480, 8); - // // AppearancePage // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); diff --git a/AngelLoader/Forms/Settings/OtherPage.Designer.cs b/AngelLoader/Forms/Settings/OtherPage.Designer.cs index d2095ce97..52503f9ff 100644 --- a/AngelLoader/Forms/Settings/OtherPage.Designer.cs +++ b/AngelLoader/Forms/Settings/OtherPage.Designer.cs @@ -69,7 +69,6 @@ private void InitializeComponent() this.OldMantleForOldDarkFMsCheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); this.ConvertOGGsToWAVsOnInstallCheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); this.ConvertWAVsTo16BitOnInstallCheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); - this.DummyAutoScrollPanel = new System.Windows.Forms.Control(); this.PagePanel.SuspendLayout(); this.FilteringGroupBox.SuspendLayout(); this.InstallingFMsGroupBox.SuspendLayout(); @@ -82,13 +81,13 @@ private void InitializeComponent() // PagePanel // this.PagePanel.AutoScroll = true; + this.PagePanel.AutoScrollMinSize = new System.Drawing.Size(432, 0); this.PagePanel.Controls.Add(this.FilteringGroupBox); this.PagePanel.Controls.Add(this.InstallingFMsGroupBox); this.PagePanel.Controls.Add(this.PlayFMOnDCOrEnterGroupBox); this.PagePanel.Controls.Add(this.WebSearchGroupBox); this.PagePanel.Controls.Add(this.UninstallingFMsGroupBox); this.PagePanel.Controls.Add(this.FMSettingsGroupBox); - this.PagePanel.Controls.Add(this.DummyAutoScrollPanel); this.PagePanel.Dock = System.Windows.Forms.DockStyle.Fill; this.PagePanel.Location = new System.Drawing.Point(0, 0); this.PagePanel.Name = "PagePanel"; @@ -495,13 +494,6 @@ private void InitializeComponent() this.ConvertWAVsTo16BitOnInstallCheckBox.TabIndex = 0; this.ConvertWAVsTo16BitOnInstallCheckBox.Text = "Convert .wavs to 16 bit on install"; // - // DummyAutoScrollPanel - // - this.DummyAutoScrollPanel.Location = new System.Drawing.Point(8, 48); - this.DummyAutoScrollPanel.Name = "DummyAutoScrollPanel"; - this.DummyAutoScrollPanel.Size = new System.Drawing.Size(424, 8); - this.DummyAutoScrollPanel.TabIndex = 12; - // // OtherPage // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -544,7 +536,6 @@ private void InitializeComponent() internal AngelLoader.Forms.CustomControls.DarkGroupBox FMSettingsGroupBox; internal AngelLoader.Forms.CustomControls.DarkCheckBox ConvertOGGsToWAVsOnInstallCheckBox; internal AngelLoader.Forms.CustomControls.DarkCheckBox ConvertWAVsTo16BitOnInstallCheckBox; - internal System.Windows.Forms.Control DummyAutoScrollPanel; internal CustomControls.DarkGroupBox InstallingFMsGroupBox; internal CustomControls.DarkRadioButton Install_ConfirmNeverRadioButton; internal CustomControls.DarkRadioButton Install_ConfirmMultipleOnlyRadioButton; diff --git a/AngelLoader/Forms/Settings/OtherPage_InitSlim.Generated.cs b/AngelLoader/Forms/Settings/OtherPage_InitSlim.Generated.cs index fdb0085fd..95100e23b 100644 --- a/AngelLoader/Forms/Settings/OtherPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/Settings/OtherPage_InitSlim.Generated.cs @@ -45,7 +45,6 @@ private void InitSlim() this.OldMantleForOldDarkFMsCheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); this.ConvertOGGsToWAVsOnInstallCheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); this.ConvertWAVsTo16BitOnInstallCheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); - this.DummyAutoScrollPanel = new System.Windows.Forms.Control(); this.PagePanel.SuspendLayout(); this.FilteringGroupBox.SuspendLayout(); this.InstallingFMsGroupBox.SuspendLayout(); @@ -58,13 +57,13 @@ private void InitSlim() // PagePanel // this.PagePanel.AutoScroll = true; + this.PagePanel.AutoScrollMinSize = new System.Drawing.Size(432, 0); this.PagePanel.Controls.Add(this.FilteringGroupBox); this.PagePanel.Controls.Add(this.InstallingFMsGroupBox); this.PagePanel.Controls.Add(this.PlayFMOnDCOrEnterGroupBox); this.PagePanel.Controls.Add(this.WebSearchGroupBox); this.PagePanel.Controls.Add(this.UninstallingFMsGroupBox); this.PagePanel.Controls.Add(this.FMSettingsGroupBox); - this.PagePanel.Controls.Add(this.DummyAutoScrollPanel); this.PagePanel.Dock = System.Windows.Forms.DockStyle.Fill; this.PagePanel.Size = new System.Drawing.Size(440, 897); this.PagePanel.TabIndex = 0; @@ -376,11 +375,6 @@ private void InitSlim() this.ConvertWAVsTo16BitOnInstallCheckBox.Size = new System.Drawing.Size(400, 32); this.ConvertWAVsTo16BitOnInstallCheckBox.TabIndex = 0; // - // DummyAutoScrollPanel - // - this.DummyAutoScrollPanel.Location = new System.Drawing.Point(8, 48); - this.DummyAutoScrollPanel.Size = new System.Drawing.Size(424, 8); - // // OtherPage // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); diff --git a/AngelLoader/Forms/Settings/PathsPage.Designer.cs b/AngelLoader/Forms/Settings/PathsPage.Designer.cs index 55fde2b24..d1c19f787 100644 --- a/AngelLoader/Forms/Settings/PathsPage.Designer.cs +++ b/AngelLoader/Forms/Settings/PathsPage.Designer.cs @@ -75,7 +75,6 @@ private void InitializeComponent() this.Thief3ExePathTextBox = new AngelLoader.Forms.CustomControls.DarkTextBox(); this.Thief2ExePathTextBox = new AngelLoader.Forms.CustomControls.DarkTextBox(); this.Thief1ExePathTextBox = new AngelLoader.Forms.CustomControls.DarkTextBox(); - this.DummyAutoScrollPanel = new System.Windows.Forms.Control(); this.PagePanel.SuspendLayout(); this.ActualPathsPanel.SuspendLayout(); this.LayoutFLP.SuspendLayout(); @@ -93,8 +92,8 @@ private void InitializeComponent() // PagePanel // this.PagePanel.AutoScroll = true; + this.PagePanel.AutoScrollMinSize = new System.Drawing.Size(432, 0); this.PagePanel.Controls.Add(this.ActualPathsPanel); - this.PagePanel.Controls.Add(this.DummyAutoScrollPanel); this.PagePanel.Dock = System.Windows.Forms.DockStyle.Fill; this.PagePanel.Location = new System.Drawing.Point(0, 0); this.PagePanel.Name = "PagePanel"; @@ -557,13 +556,6 @@ private void InitializeComponent() this.Thief1ExePathTextBox.Size = new System.Drawing.Size(320, 20); this.Thief1ExePathTextBox.TabIndex = 1; // - // DummyAutoScrollPanel - // - this.DummyAutoScrollPanel.Location = new System.Drawing.Point(8, 200); - this.DummyAutoScrollPanel.Name = "DummyAutoScrollPanel"; - this.DummyAutoScrollPanel.Size = new System.Drawing.Size(424, 8); - this.DummyAutoScrollPanel.TabIndex = 13; - // // PathsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -618,7 +610,6 @@ private void InitializeComponent() internal AngelLoader.Forms.CustomControls.DarkButton RemoveFMArchivePathButton; internal AngelLoader.Forms.CustomControls.DarkListBox FMArchivePathsListBox; internal System.Windows.Forms.Panel ActualPathsPanel; - internal System.Windows.Forms.Control DummyAutoScrollPanel; internal AngelLoader.Forms.CustomControls.DarkLabel SteamExeLabel; internal AngelLoader.Forms.CustomControls.DarkTextBox SteamExeTextBox; internal AngelLoader.Forms.CustomControls.StandardButton SteamExeBrowseButton; diff --git a/AngelLoader/Forms/Settings/PathsPage_InitSlim.Generated.cs b/AngelLoader/Forms/Settings/PathsPage_InitSlim.Generated.cs index b24fb327e..f53280b40 100644 --- a/AngelLoader/Forms/Settings/PathsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/Settings/PathsPage_InitSlim.Generated.cs @@ -51,7 +51,6 @@ private void InitSlim() this.Thief3ExePathTextBox = new AngelLoader.Forms.CustomControls.DarkTextBox(); this.Thief2ExePathTextBox = new AngelLoader.Forms.CustomControls.DarkTextBox(); this.Thief1ExePathTextBox = new AngelLoader.Forms.CustomControls.DarkTextBox(); - this.DummyAutoScrollPanel = new System.Windows.Forms.Control(); this.PagePanel.SuspendLayout(); this.ActualPathsPanel.SuspendLayout(); this.LayoutFLP.SuspendLayout(); @@ -69,8 +68,8 @@ private void InitSlim() // PagePanel // this.PagePanel.AutoScroll = true; + this.PagePanel.AutoScrollMinSize = new System.Drawing.Size(432, 0); this.PagePanel.Controls.Add(this.ActualPathsPanel); - this.PagePanel.Controls.Add(this.DummyAutoScrollPanel); this.PagePanel.Dock = System.Windows.Forms.DockStyle.Fill; this.PagePanel.Size = new System.Drawing.Size(440, 910); this.PagePanel.TabIndex = 3; @@ -423,11 +422,6 @@ private void InitSlim() this.Thief1ExePathTextBox.Size = new System.Drawing.Size(320, 20); this.Thief1ExePathTextBox.TabIndex = 1; // - // DummyAutoScrollPanel - // - this.DummyAutoScrollPanel.Location = new System.Drawing.Point(8, 200); - this.DummyAutoScrollPanel.Size = new System.Drawing.Size(424, 8); - // // PathsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); diff --git a/AngelLoader/Forms/Settings/ThiefBuddyPage.Designer.cs b/AngelLoader/Forms/Settings/ThiefBuddyPage.Designer.cs index f572bfd5a..fe3f4681d 100644 --- a/AngelLoader/Forms/Settings/ThiefBuddyPage.Designer.cs +++ b/AngelLoader/Forms/Settings/ThiefBuddyPage.Designer.cs @@ -40,7 +40,6 @@ private void InitializeComponent() this.RunTBNeverRadioButton = new AngelLoader.Forms.CustomControls.DarkRadioButton(); this.RunTBAskRadioButton = new AngelLoader.Forms.CustomControls.DarkRadioButton(); this.GetTBLinkLabel = new AngelLoader.Forms.CustomControls.DarkLinkLabel(); - this.DummyAutoScrollPanel = new System.Windows.Forms.Control(); this.TBHelpPictureBox = new System.Windows.Forms.PictureBox(); this.WhatIsTBHelpLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.PagePanel.SuspendLayout(); @@ -52,9 +51,9 @@ private void InitializeComponent() // PagePanel // this.PagePanel.AutoScroll = true; + this.PagePanel.AutoScrollMinSize = new System.Drawing.Size(432, 0); this.PagePanel.Controls.Add(this.ThiefBuddyOptionsGroupBox); this.PagePanel.Controls.Add(this.GetTBLinkLabel); - this.PagePanel.Controls.Add(this.DummyAutoScrollPanel); this.PagePanel.Controls.Add(this.TBHelpPictureBox); this.PagePanel.Controls.Add(this.WhatIsTBHelpLabel); this.PagePanel.Dock = System.Windows.Forms.DockStyle.Fill; @@ -147,13 +146,6 @@ private void InitializeComponent() this.GetTBLinkLabel.TabStop = true; this.GetTBLinkLabel.Text = "Get Thief Buddy"; // - // DummyAutoScrollPanel - // - this.DummyAutoScrollPanel.Location = new System.Drawing.Point(8, 48); - this.DummyAutoScrollPanel.Name = "DummyAutoScrollPanel"; - this.DummyAutoScrollPanel.Size = new System.Drawing.Size(424, 8); - this.DummyAutoScrollPanel.TabIndex = 12; - // // TBHelpPictureBox // this.TBHelpPictureBox.Location = new System.Drawing.Point(8, 186); @@ -198,7 +190,6 @@ private void InitializeComponent() #endregion internal System.Windows.Forms.Panel PagePanel; - internal System.Windows.Forms.Control DummyAutoScrollPanel; internal CustomControls.DarkGroupBox ThiefBuddyOptionsGroupBox; internal CustomControls.DarkRadioButton RunTBNeverRadioButton; internal CustomControls.DarkRadioButton RunTBAskRadioButton; diff --git a/AngelLoader/Forms/Settings/ThiefBuddyPage_InitSlim.Generated.cs b/AngelLoader/Forms/Settings/ThiefBuddyPage_InitSlim.Generated.cs index 0004eb396..e7dd0a349 100644 --- a/AngelLoader/Forms/Settings/ThiefBuddyPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/Settings/ThiefBuddyPage_InitSlim.Generated.cs @@ -16,7 +16,6 @@ private void InitSlim() this.RunTBNeverRadioButton = new AngelLoader.Forms.CustomControls.DarkRadioButton(); this.RunTBAskRadioButton = new AngelLoader.Forms.CustomControls.DarkRadioButton(); this.GetTBLinkLabel = new AngelLoader.Forms.CustomControls.DarkLinkLabel(); - this.DummyAutoScrollPanel = new System.Windows.Forms.Control(); this.TBHelpPictureBox = new System.Windows.Forms.PictureBox(); this.WhatIsTBHelpLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.PagePanel.SuspendLayout(); @@ -28,9 +27,9 @@ private void InitSlim() // PagePanel // this.PagePanel.AutoScroll = true; + this.PagePanel.AutoScrollMinSize = new System.Drawing.Size(432, 0); this.PagePanel.Controls.Add(this.ThiefBuddyOptionsGroupBox); this.PagePanel.Controls.Add(this.GetTBLinkLabel); - this.PagePanel.Controls.Add(this.DummyAutoScrollPanel); this.PagePanel.Controls.Add(this.TBHelpPictureBox); this.PagePanel.Controls.Add(this.WhatIsTBHelpLabel); this.PagePanel.Dock = System.Windows.Forms.DockStyle.Fill; @@ -97,11 +96,6 @@ private void InitSlim() this.GetTBLinkLabel.TabIndex = 2; this.GetTBLinkLabel.TabStop = true; // - // DummyAutoScrollPanel - // - this.DummyAutoScrollPanel.Location = new System.Drawing.Point(8, 48); - this.DummyAutoScrollPanel.Size = new System.Drawing.Size(424, 8); - // // TBHelpPictureBox // this.TBHelpPictureBox.Location = new System.Drawing.Point(8, 186); diff --git a/AngelLoader/Forms/Settings/UpdatePage.Designer.cs b/AngelLoader/Forms/Settings/UpdatePage.Designer.cs index ecd2835a9..1223d0a7d 100644 --- a/AngelLoader/Forms/Settings/UpdatePage.Designer.cs +++ b/AngelLoader/Forms/Settings/UpdatePage.Designer.cs @@ -34,7 +34,6 @@ private void InitializeComponent() this.PagePanel = new System.Windows.Forms.Panel(); this.UpdateOptionsGroupBox = new AngelLoader.Forms.CustomControls.DarkGroupBox(); this.CheckForUpdatesOnStartupCheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); - this.DummyAutoScrollPanel = new System.Windows.Forms.Control(); this.PagePanel.SuspendLayout(); this.UpdateOptionsGroupBox.SuspendLayout(); this.SuspendLayout(); @@ -42,8 +41,8 @@ private void InitializeComponent() // PagePanel // this.PagePanel.AutoScroll = true; + this.PagePanel.AutoScrollMinSize = new System.Drawing.Size(432, 0); this.PagePanel.Controls.Add(this.UpdateOptionsGroupBox); - this.PagePanel.Controls.Add(this.DummyAutoScrollPanel); this.PagePanel.Dock = System.Windows.Forms.DockStyle.Fill; this.PagePanel.Location = new System.Drawing.Point(0, 0); this.PagePanel.Name = "PagePanel"; @@ -73,13 +72,6 @@ private void InitializeComponent() this.CheckForUpdatesOnStartupCheckBox.TabIndex = 0; this.CheckForUpdatesOnStartupCheckBox.Text = "Check for updates on startup"; // - // DummyAutoScrollPanel - // - this.DummyAutoScrollPanel.Location = new System.Drawing.Point(8, 48); - this.DummyAutoScrollPanel.Name = "DummyAutoScrollPanel"; - this.DummyAutoScrollPanel.Size = new System.Drawing.Size(424, 8); - this.DummyAutoScrollPanel.TabIndex = 0; - // // UpdatePage // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -98,6 +90,5 @@ private void InitializeComponent() internal System.Windows.Forms.Panel PagePanel; internal CustomControls.DarkGroupBox UpdateOptionsGroupBox; - internal System.Windows.Forms.Control DummyAutoScrollPanel; internal CustomControls.DarkCheckBox CheckForUpdatesOnStartupCheckBox; } diff --git a/AngelLoader/Forms/Settings/UpdatePage_InitSlim.Generated.cs b/AngelLoader/Forms/Settings/UpdatePage_InitSlim.Generated.cs index 674432e21..8d28ceba9 100644 --- a/AngelLoader/Forms/Settings/UpdatePage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/Settings/UpdatePage_InitSlim.Generated.cs @@ -10,7 +10,6 @@ private void InitSlim() this.PagePanel = new System.Windows.Forms.Panel(); this.UpdateOptionsGroupBox = new AngelLoader.Forms.CustomControls.DarkGroupBox(); this.CheckForUpdatesOnStartupCheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); - this.DummyAutoScrollPanel = new System.Windows.Forms.Control(); this.PagePanel.SuspendLayout(); this.UpdateOptionsGroupBox.SuspendLayout(); this.SuspendLayout(); @@ -18,8 +17,8 @@ private void InitSlim() // PagePanel // this.PagePanel.AutoScroll = true; + this.PagePanel.AutoScrollMinSize = new System.Drawing.Size(432, 0); this.PagePanel.Controls.Add(this.UpdateOptionsGroupBox); - this.PagePanel.Controls.Add(this.DummyAutoScrollPanel); this.PagePanel.Dock = System.Windows.Forms.DockStyle.Fill; this.PagePanel.Size = new System.Drawing.Size(440, 692); this.PagePanel.TabIndex = 0; @@ -43,11 +42,6 @@ private void InitSlim() this.CheckForUpdatesOnStartupCheckBox.Size = new System.Drawing.Size(392, 32); this.CheckForUpdatesOnStartupCheckBox.TabIndex = 0; // - // DummyAutoScrollPanel - // - this.DummyAutoScrollPanel.Location = new System.Drawing.Point(8, 48); - this.DummyAutoScrollPanel.Size = new System.Drawing.Size(424, 8); - // // UpdatePage // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); From d411c2107feb1f659636dc994ff4a223ec3507e9 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 15:10:05 -0800 Subject: [PATCH 019/200] Remove last dummy autoscroll thing, and remove DarkControl --- .../Forms/CustomControls/DarkControl.cs | 27 ------------------- .../TopRightPages/Lazy_TagsPage.Designer.cs | 11 +------- .../Lazy_TagsPage_InitSlim.Generated.cs | 7 +---- 3 files changed, 2 insertions(+), 43 deletions(-) delete mode 100644 AngelLoader/Forms/CustomControls/DarkControl.cs diff --git a/AngelLoader/Forms/CustomControls/DarkControl.cs b/AngelLoader/Forms/CustomControls/DarkControl.cs deleted file mode 100644 index 84ef4bc99..000000000 --- a/AngelLoader/Forms/CustomControls/DarkControl.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.ComponentModel; -using System.Drawing; -using System.Windows.Forms; -using AngelLoader.DataClasses; -using JetBrains.Annotations; - -namespace AngelLoader.Forms.CustomControls; - -public sealed class DarkControl : Control, IDarkable -{ - [PublicAPI] - public Color DrawnBackColor = SystemColors.Control; - - [PublicAPI] - public Color DarkModeDrawnBackColor = DarkColors.Fen_ControlBackground; - - [PublicAPI] - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public bool DarkModeEnabled { get; set; } - - protected override void OnPaint(PaintEventArgs e) - { - using var brush = new SolidBrush(DarkModeEnabled ? DarkModeDrawnBackColor : DrawnBackColor); - e.Graphics.FillRectangle(brush, ClientRectangle); - } -} diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TagsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TagsPage.Designer.cs index 75f8a2e17..b9095939e 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TagsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TagsPage.Designer.cs @@ -37,7 +37,6 @@ private void InitializeComponent() this.RemoveTagButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.AddTagFromListButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.TagsTreeView = new AngelLoader.Forms.CustomControls.DarkTreeView(); - this.TagsTabAutoScrollMarker = new AngelLoader.Forms.CustomControls.DarkControl(); this.AddRemoveTagFLP.SuspendLayout(); this.SuspendLayout(); // @@ -116,23 +115,16 @@ private void InitializeComponent() this.TagsTreeView.Size = new System.Drawing.Size(512, 216); this.TagsTreeView.TabIndex = 8; // - // TagsTabAutoScrollMarker - // - this.TagsTabAutoScrollMarker.Location = new System.Drawing.Point(0, 0); - this.TagsTabAutoScrollMarker.Name = "TagsTabAutoScrollMarker"; - this.TagsTabAutoScrollMarker.Size = new System.Drawing.Size(240, 152); - this.TagsTabAutoScrollMarker.TabIndex = 10; - // // Lazy_TagsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; + this.AutoScrollMinSize = new System.Drawing.Size(240, 152); this.Controls.Add(this.AddTagButton); this.Controls.Add(this.AddTagTextBox); this.Controls.Add(this.AddRemoveTagFLP); this.Controls.Add(this.TagsTreeView); - this.Controls.Add(this.TagsTabAutoScrollMarker); this.Name = "Lazy_TagsPage"; this.Size = new System.Drawing.Size(527, 284); this.AddRemoveTagFLP.ResumeLayout(false); @@ -151,5 +143,4 @@ private void InitializeComponent() internal DarkButton RemoveTagButton; internal DarkButton AddTagFromListButton; internal DarkTreeView TagsTreeView; - internal DarkControl TagsTabAutoScrollMarker; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TagsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TagsPage_InitSlim.Generated.cs index 04bd8e085..5bd7b10fb 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TagsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TagsPage_InitSlim.Generated.cs @@ -13,7 +13,6 @@ private void InitSlim() this.RemoveTagButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.AddTagFromListButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.TagsTreeView = new AngelLoader.Forms.CustomControls.DarkTreeView(); - this.TagsTabAutoScrollMarker = new AngelLoader.Forms.CustomControls.DarkControl(); this.AddRemoveTagFLP.SuspendLayout(); this.SuspendLayout(); // @@ -79,20 +78,16 @@ private void InitSlim() this.TagsTreeView.Size = new System.Drawing.Size(512, 216); this.TagsTreeView.TabIndex = 8; // - // TagsTabAutoScrollMarker - // - this.TagsTabAutoScrollMarker.Size = new System.Drawing.Size(240, 152); - // // Lazy_TagsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; + this.AutoScrollMinSize = new System.Drawing.Size(240, 152); this.Controls.Add(this.AddTagButton); this.Controls.Add(this.AddTagTextBox); this.Controls.Add(this.AddRemoveTagFLP); this.Controls.Add(this.TagsTreeView); - this.Controls.Add(this.TagsTabAutoScrollMarker); this.Size = new System.Drawing.Size(527, 284); this.AddRemoveTagFLP.ResumeLayout(false); this.AddRemoveTagFLP.PerformLayout(); From ba11e44f94e5290808a5081986577a24b5f84020 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 15:14:19 -0800 Subject: [PATCH 020/200] pragma warning disable --- AL_Common/FenGenAttributes.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AL_Common/FenGenAttributes.cs b/AL_Common/FenGenAttributes.cs index 1a145a5c1..41685bf26 100644 --- a/AL_Common/FenGenAttributes.cs +++ b/AL_Common/FenGenAttributes.cs @@ -6,6 +6,7 @@ #pragma warning disable IDE0060 // Remove unused parameter. #pragma warning disable RCS1163 // Unused parameter. #pragma warning disable RCS1139 // Add summary element to documentation comment. +#pragma warning disable CS9113 // Parameter is unread. namespace AL_Common; From abe6db49f57ab30aafba3066528b4fbe12e26ffe Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 15:36:49 -0800 Subject: [PATCH 021/200] Custom comparer for screenshot sorting --- AngelLoader/Common/Comparers.cs | 17 +++++++++++++++-- AngelLoader/Core.cs | 7 ++----- .../TopRightPages/ScreenshotsTabPage.cs | 3 +-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/AngelLoader/Common/Comparers.cs b/AngelLoader/Common/Comparers.cs index 4ab06e7b6..b39858a85 100644 --- a/AngelLoader/Common/Comparers.cs +++ b/AngelLoader/Common/Comparers.cs @@ -45,8 +45,9 @@ internal static class Comparers #region Misc comparers - private static FileNameNoExtComparer? _fileNameNoExtComparer; - internal static FileNameNoExtComparer FileNameNoExt => _fileNameNoExtComparer ??= new FileNameNoExtComparer(); + internal static FileNameNoExtComparer FileNameNoExt = new(); + + internal static ScreenshotComparer Screenshot = new(); #endregion @@ -442,5 +443,17 @@ public int Compare(string x, string y) => StringComparison.OrdinalIgnoreCase); } + internal sealed class ScreenshotComparer : IComparer + { + public int Compare(FileInfo x, FileInfo y) + { + int cmp = x.LastWriteTime.CompareTo(y.LastWriteTime); + return cmp == 0 + // @TDM_CASE when file is a TDM screenshot + ? string.Compare(x.Name, y.Name, StringComparison.OrdinalIgnoreCase) + : cmp; + } + } + #endregion } diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index 014459f73..79b1d1461 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2824,7 +2824,6 @@ static bool TryGetSortedScreenshotFileInfos( [NotNullWhen(true)] out FileInfo[]? screenshots) { // @ScreenshotDisplay: Performance... we need a custom FileInfo getter without the 8.3 stuff - // @ScreenshotDisplay: And a custom comparer to avoid OrderBy() try { string ssPath = Path.Combine(screenshotsDirParentPath, "screenshots"); @@ -2836,10 +2835,8 @@ static bool TryGetSortedScreenshotFileInfos( screenshots = null; return false; } - screenshots = di - .GetFiles(pattern) - .OrderBy(static x => x.LastWriteTime) - .ToArray(); + screenshots = di.GetFiles(pattern); + Array.Sort(screenshots, Comparers.Screenshot); return true; } catch diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 36e03ff59..5924ecf4d 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,5 +1,4 @@ -// @ScreenshotDisplay: Make screenshot scale with resize -// @ScreenshotDisplay: Watch screenshot folder and reload from disk +// @ScreenshotDisplay: Watch screenshot folder and reload from disk using System; using System.Collections.Generic; From d0dd2bc5fbe6674cf2114e793ac517e316cdd937 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 15:55:31 -0800 Subject: [PATCH 022/200] Note --- AngelLoader/Core.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index 79b1d1461..4411d2494 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2826,6 +2826,7 @@ static bool TryGetSortedScreenshotFileInfos( // @ScreenshotDisplay: Performance... we need a custom FileInfo getter without the 8.3 stuff try { + // @ScreenshotDisplay: Support Thief 3 central screenshots string ssPath = Path.Combine(screenshotsDirParentPath, "screenshots"); DirectoryInfo di = new(ssPath); // Standard practice is to let the GetFiles() call throw if the directory doesn't exist, but for From a18d0426c666ff599843e0c297520a9f350adce0 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 17:12:29 -0800 Subject: [PATCH 023/200] Fix image locking the file it loaded from Causing uninstall to fail --- AngelLoader/Core.cs | 10 +++- .../TopRightPages/ScreenshotsTabPage.cs | 56 +++++++++++++++++-- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index 4411d2494..b549a1beb 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2826,7 +2826,15 @@ static bool TryGetSortedScreenshotFileInfos( // @ScreenshotDisplay: Performance... we need a custom FileInfo getter without the 8.3 stuff try { - // @ScreenshotDisplay: Support Thief 3 central screenshots + /* + @ScreenshotDisplay(Thief 3 central screenshots): + These get put into one directory with the FM mission name (not overall FM name!) at the start of + the file. For example, "All The World's A Stage" screenshots get prefixed "Bohn Street Theatre". + These names are listed in \CONTENT\T3\Books\English\String_Tags\Misc.sch but also in other languages + so we'd have to check every one of them, which also means we can't make one single search pattern, + so we'd have a performance issue too. It's not even close to worth it to try to do this, so we're + just not supporting central screenshots for Thief 3 right now. + */ string ssPath = Path.Combine(screenshotsDirParentPath, "screenshots"); DirectoryInfo di = new(ssPath); // Standard practice is to let the GetFiles() call throw if the directory doesn't exist, but for diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 5924ecf4d..8319b335e 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -2,6 +2,8 @@ using System; using System.Collections.Generic; +using System.Drawing; +using System.IO; using AL_Common; using AngelLoader.DataClasses; @@ -11,8 +13,35 @@ public sealed class ScreenshotsTabPage : Lazy_TabsBase { private Lazy_ScreenshotsPage _page = null!; + /* + Images loaded from files keep the file stream alive for their entire lifetime, insanely. This means the file + is "in use" and will cause delete attempts (like FM uninstallation) to fail. So we need to use this workaround + of loading the file into a memory stream first, so it's only the memory stream being kept alive. This does + mean we carry around the full file bytes in memory as well as the displayed image, but since we're only + displaying one at a time and they'll probably be a few megs at most, it's not a big deal. + */ + private sealed class MemoryImage : IDisposable + { + private readonly MemoryStream _memoryStream; + internal readonly Image Img; + + public MemoryImage(string path) + { + byte[] bytes = File.ReadAllBytes(path); + _memoryStream = new MemoryStream(bytes); + Img = Image.FromStream(_memoryStream); + } + + public void Dispose() + { + Img.Dispose(); + _memoryStream.Dispose(); + } + } + private readonly List ScreenshotFileNames = new(); private string CurrentScreenshotFileName = ""; + private MemoryImage? _currentScreenshotStream; #region Public common @@ -46,8 +75,7 @@ public override void UpdatePage() if (ScreenshotFileNames.Count == 0) { CurrentScreenshotFileName = ""; - _page.ScreenshotsPictureBox.Image = null; - _page.ScreenshotsPictureBox.ImageLocation = ""; + ClearCurrentScreenshot(); _page.ScreenshotsPictureBox.Enabled = false; _page.ScreenshotsPrevButton.Enabled = false; _page.ScreenshotsNextButton.Enabled = false; @@ -68,6 +96,13 @@ public override void UpdatePage() #region Page + private void ClearCurrentScreenshot() + { + _page.ScreenshotsPictureBox.Image = null; + _page.ScreenshotsPictureBox.ImageLocation = ""; + _currentScreenshotStream?.Dispose(); + } + /* The standard behavior for lazy loaded tabs is that they don't update until loaded, after which they always update. However, loading an image could take a significant amount of time, and we don't want to punish users @@ -83,9 +118,20 @@ private void DisplayCurrentScreenshot() // @TDM_CASE when FM is TDM (_page.ScreenshotsPictureBox.ImageLocation?.EqualsI(CurrentScreenshotFileName) != true)) { - _page.ScreenshotsPictureBox.Load(CurrentScreenshotFileName); - _page.NumberLabel.Text = (ScreenshotFileNames.IndexOf(CurrentScreenshotFileName) + 1).ToStrInv() + " / " + - ScreenshotFileNames.Count.ToStrInv(); + try + { + _currentScreenshotStream?.Dispose(); + _currentScreenshotStream = new MemoryImage(CurrentScreenshotFileName); + _page.ScreenshotsPictureBox.Image = _currentScreenshotStream.Img; + _page.NumberLabel.Text = + (ScreenshotFileNames.IndexOf(CurrentScreenshotFileName) + 1).ToStrInv() + " / " + + ScreenshotFileNames.Count.ToStrInv(); + } + catch + { + ClearCurrentScreenshot(); + // @ScreenshotDisplay: Put an error message on top of the PictureBox or something + } } } From 2c4b69301c3d29bfcca8bc305a2c552365c622f9 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 17:23:28 -0800 Subject: [PATCH 024/200] Update comment wording --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 8319b335e..6b83b822f 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -105,8 +105,8 @@ private void ClearCurrentScreenshot() /* The standard behavior for lazy loaded tabs is that they don't update until loaded, after which they always - update. However, loading an image could take a significant amount of time, and we don't want to punish users - with that lag time if they're not actually able to see the image. So we only update when visible (or when we + update. However, loading an image could take a significant amount of time, and we don't want users to pay the + performance cost if they're not actually able to see the image. So we only update when visible (or when we become visible). */ private void DisplayCurrentScreenshot() From 90ad5e95e5b8818bdd4073e39e30a5c821fe05ea Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 23 Feb 2024 21:48:57 -0800 Subject: [PATCH 025/200] Un-break screenshot caching again --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 6b83b822f..ed587fcf7 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -24,9 +24,11 @@ private sealed class MemoryImage : IDisposable { private readonly MemoryStream _memoryStream; internal readonly Image Img; + internal string Path { get; private set; } public MemoryImage(string path) { + Path = path; byte[] bytes = File.ReadAllBytes(path); _memoryStream = new MemoryStream(bytes); Img = Image.FromStream(_memoryStream); @@ -34,6 +36,7 @@ public MemoryImage(string path) public void Dispose() { + Path = ""; Img.Dispose(); _memoryStream.Dispose(); } @@ -116,7 +119,7 @@ private void DisplayCurrentScreenshot() if (!CurrentScreenshotFileName.IsEmpty() && // @TDM_CASE when FM is TDM - (_page.ScreenshotsPictureBox.ImageLocation?.EqualsI(CurrentScreenshotFileName) != true)) + _currentScreenshotStream?.Path.EqualsI(CurrentScreenshotFileName) != true) { try { From 011294d6a6fe0b625113b6c78211b7bdc451f3e0 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 24 Feb 2024 06:18:50 -0800 Subject: [PATCH 026/200] Show broken image picture when screenshot not found --- .../TopRightPages/ScreenshotsTabPage.cs | 44 ++++++++++++++++-- AngelLoader/Forms/Images.cs | 21 ++++++--- AngelLoader/Properties/Resources.Designer.cs | 10 ++++ AngelLoader/Properties/Resources.resx | 3 ++ AngelLoader/Resources/broken_file.png | Bin 0 -> 1163 bytes 5 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 AngelLoader/Resources/broken_file.png diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index ed587fcf7..be675080f 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -2,10 +2,13 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Drawing; using System.IO; +using System.Windows.Forms; using AL_Common; using AngelLoader.DataClasses; +using JetBrains.Annotations; namespace AngelLoader.Forms.CustomControls; @@ -45,6 +48,31 @@ public void Dispose() private readonly List ScreenshotFileNames = new(); private string CurrentScreenshotFileName = ""; private MemoryImage? _currentScreenshotStream; + private bool _currentImageBroken; + + #region Theme + + [PublicAPI] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public override bool DarkModeEnabled + { + get => base.DarkModeEnabled; + set + { + if (DarkModeEnabled == value) return; + base.DarkModeEnabled = value; + + if (!_constructed) return; + + if (_currentImageBroken) + { + _page.ScreenshotsPictureBox.Image = Images.BrokenFile; + } + } + } + + #endregion #region Public common @@ -101,6 +129,8 @@ public override void UpdatePage() private void ClearCurrentScreenshot() { + _currentImageBroken = false; + _page.ScreenshotsPictureBox.SizeMode = PictureBoxSizeMode.Zoom; _page.ScreenshotsPictureBox.Image = null; _page.ScreenshotsPictureBox.ImageLocation = ""; _currentScreenshotStream?.Dispose(); @@ -123,18 +153,26 @@ private void DisplayCurrentScreenshot() { try { + _currentImageBroken = false; _currentScreenshotStream?.Dispose(); _currentScreenshotStream = new MemoryImage(CurrentScreenshotFileName); + _page.ScreenshotsPictureBox.SizeMode = PictureBoxSizeMode.Zoom; _page.ScreenshotsPictureBox.Image = _currentScreenshotStream.Img; - _page.NumberLabel.Text = - (ScreenshotFileNames.IndexOf(CurrentScreenshotFileName) + 1).ToStrInv() + " / " + - ScreenshotFileNames.Count.ToStrInv(); } catch { + _currentImageBroken = true; ClearCurrentScreenshot(); + _page.ScreenshotsPictureBox.SizeMode = PictureBoxSizeMode.CenterImage; + _page.ScreenshotsPictureBox.Image = Images.BrokenFile; // @ScreenshotDisplay: Put an error message on top of the PictureBox or something } + finally + { + _page.NumberLabel.Text = + (ScreenshotFileNames.IndexOf(CurrentScreenshotFileName) + 1).ToStrInv() + " / " + + ScreenshotFileNames.Count.ToStrInv(); + } } } diff --git a/AngelLoader/Forms/Images.cs b/AngelLoader/Forms/Images.cs index c36a851db..ebbcda7ac 100644 --- a/AngelLoader/Forms/Images.cs +++ b/AngelLoader/Forms/Images.cs @@ -1081,13 +1081,6 @@ public static Bitmap GetZoomImage(Rectangle rect, Zoom zoomType) #endregion - private static Bitmap? _updateIcon; - private static Bitmap? _updateIcon_Dark; - public static Bitmap UpdateIcon => - Config.DarkMode - ? _updateIcon_Dark ??= CreateUpdateIcon() - : _updateIcon ??= CreateUpdateIcon(); - #region FMs list only private static Bitmap? _greenCheckCircle; @@ -1174,6 +1167,20 @@ public static Bitmap GetZoomImage(Rectangle rect, Zoom zoomType) ? _refresh_Dark ??= DarkModeImageConversion.CreateDarkModeVersion(Resources.Refresh) : _refresh ??= Resources.Refresh; + private static Bitmap? _updateIcon; + private static Bitmap? _updateIcon_Dark; + public static Bitmap UpdateIcon => + Config.DarkMode + ? _updateIcon_Dark ??= CreateUpdateIcon() + : _updateIcon ??= CreateUpdateIcon(); + + private static Bitmap? _brokenFile; + private static Bitmap? _brokenFile_Dark; + public static Bitmap BrokenFile => + Config.DarkMode + ? _brokenFile_Dark ??= DarkModeImageConversion.CreateDarkModeVersion(Resources.BrokenFile) + : _brokenFile ??= Resources.BrokenFile; + #endregion #endregion diff --git a/AngelLoader/Properties/Resources.Designer.cs b/AngelLoader/Properties/Resources.Designer.cs index 1a9cafa03..8ddf67699 100644 --- a/AngelLoader/Properties/Resources.Designer.cs +++ b/AngelLoader/Properties/Resources.Designer.cs @@ -80,6 +80,16 @@ internal static System.Drawing.Icon AngelLoader { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap BrokenFile { + get { + object obj = ResourceManager.GetObject("BrokenFile", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/AngelLoader/Properties/Resources.resx b/AngelLoader/Properties/Resources.resx index 9edf32120..68e17cb61 100644 --- a/AngelLoader/Properties/Resources.resx +++ b/AngelLoader/Properties/Resources.resx @@ -241,4 +241,7 @@ ..\Resources\TDM_21.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\broken_file.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/AngelLoader/Resources/broken_file.png b/AngelLoader/Resources/broken_file.png new file mode 100644 index 0000000000000000000000000000000000000000..8f161d8bd446381baeb1866488adc41abdb47d16 GIT binary patch literal 1163 zcmbVMU1$_n6dqY^gGQlR(G-H?q_h>?nR{nN^`TU(Hc(2j`Vv}@f(R<8526pEy_4*weF#1{ zFmwOD?|kQ+d(M1V>D{?{r*zvbnl3K(;7vD9YVv7r*e1B z{lu}3t#bWR8I*kujW|7%0qUFVtyz_2|gb-g5ghr#mH&Q$fh6O0gvH(Ou6q6K@3@1EdMoBO1YFW@xXa$Z>9PF{N zMRN#`6P2T$E`;FvJWSYCD3&lX{jj|_j=%turI=04L+TilWt64SF#OV^>gO|JG- zuA&9VBsi#HJl3j!$_OSn9Kk-T^+`Nr`yJ25jWE8Rg=lpYIQx)Y46w`2=T~u-(ATwM zwg`$@4dkUbZW^>9=R{z@Vj&Ggk!y18XUUmBoe|>V_+PQKwrB;$)5X%Ki^b+a9_^Tb zw#Lq$zdxgGb*`l6Yth`5gKw@$Y;H65pM8@2^YYDuUvAiRedgtLA15xY`smbG_Ql`s z%dm-hle}C_Rp1r0(Coxb^4@T@Szi>&&WZyZGaZO8*QG z9v?mY>!k>uxqsryjXi_!UX^BsC#R>Bw%?Z@K8~+`{!T~dcM>Fd3jm)hr W?{)t3-KT5g-$Tjh)xRzbPW=lD8Goe! literal 0 HcmV?d00001 From f6bc7f15bf05624b9c4969114ebf5b81bafece99 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 24 Feb 2024 06:23:32 -0800 Subject: [PATCH 027/200] Fix broken image dark mode switch --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index be675080f..8a518fbc2 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -153,19 +153,18 @@ private void DisplayCurrentScreenshot() { try { - _currentImageBroken = false; _currentScreenshotStream?.Dispose(); _currentScreenshotStream = new MemoryImage(CurrentScreenshotFileName); _page.ScreenshotsPictureBox.SizeMode = PictureBoxSizeMode.Zoom; _page.ScreenshotsPictureBox.Image = _currentScreenshotStream.Img; + _currentImageBroken = false; } catch { - _currentImageBroken = true; ClearCurrentScreenshot(); _page.ScreenshotsPictureBox.SizeMode = PictureBoxSizeMode.CenterImage; _page.ScreenshotsPictureBox.Image = Images.BrokenFile; - // @ScreenshotDisplay: Put an error message on top of the PictureBox or something + _currentImageBroken = true; } finally { From c81b0e9695281b68855853a5986a54bca1fc741a Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 24 Feb 2024 07:48:26 -0800 Subject: [PATCH 028/200] Screenshots work: -Add "open screenshots dir" button -Localize some strings --- AngelLoader/Common/DataClasses/ErrorText.cs | 1 + .../Common/DataClasses/LocalizationData.cs | 9 +++ AngelLoader/Common/Native/NativeCommon.cs | 43 ++++++++++++- AngelLoader/Core.cs | 46 ++++++++++++++ .../LazyLoaded/TopRightLLMenu.cs | 3 +- .../Lazy_ScreenshotsPage.Designer.cs | 62 +++++++++++-------- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 49 +++++++++------ .../TopRightPages/ScreenshotsTabPage.cs | 32 ++++++++-- AngelLoader/Forms/MainForm.cs | 3 +- AngelLoader/Languages/English.ini | 5 ++ 10 files changed, 197 insertions(+), 56 deletions(-) diff --git a/AngelLoader/Common/DataClasses/ErrorText.cs b/AngelLoader/Common/DataClasses/ErrorText.cs index c6faca423..f80e0e2f4 100644 --- a/AngelLoader/Common/DataClasses/ErrorText.cs +++ b/AngelLoader/Common/DataClasses/ErrorText.cs @@ -41,6 +41,7 @@ internal static class ErrorText internal static readonly string FoundRegKey = "Found the registry key but "; internal static readonly string RegKeyPath = "Registry key path was: "; internal static readonly string FMInstDirNF = "FM install directory not found."; + internal static readonly string FMScreenshotsDirNF = "FM screenshot directory not found."; internal static readonly string ExInLWT = Ex + "in last write time compare "; } #pragma warning restore RCS1187 // Use constant instead of field. diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index f09af284d..5c511ec42 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -43,6 +43,7 @@ internal sealed class LText_Class internal readonly TagsTab_Class TagsTab = new(); internal readonly PatchTab_Class PatchTab = new(); internal readonly ModsTab_Class ModsTab = new(); + internal readonly ScreenshotsTab_Class ScreenshotsTabs = new(); internal readonly ReadmeArea_Class ReadmeArea = new(); internal readonly PlayOriginalGameMenu_Class PlayOriginalGameMenu = new(); internal readonly MainButtons_Class MainButtons = new(); @@ -626,6 +627,14 @@ internal sealed class ModsTab_Class // @GENGAMES (Localization - ModsTab_Class) - End } + internal sealed class ScreenshotsTab_Class + { + // @ScreenshotDisplay: Finalize this text, improve it if necessary etc. + internal readonly string TabText = "Screenshots"; + internal readonly string ScreenshotsFolderNotFound = "Screenshots folder not found."; + internal readonly string ScreenshotsFolderOpenError = "There was an error trying to open the screenshots folder."; + } + internal sealed class ReadmeArea_Class { internal readonly string ViewHTMLReadme = "View HTML Readme"; diff --git a/AngelLoader/Common/Native/NativeCommon.cs b/AngelLoader/Common/Native/NativeCommon.cs index d07a0ba8b..018240e02 100644 --- a/AngelLoader/Common/Native/NativeCommon.cs +++ b/AngelLoader/Common/Native/NativeCommon.cs @@ -1,4 +1,5 @@ -using System.Runtime.InteropServices; +using System; +using System.Runtime.InteropServices; using System.Text; using Microsoft.Win32.SafeHandles; @@ -22,4 +23,44 @@ Admin privileges(?!). At least on Framework anyway. internal static extern SafeProcessHandle OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId); #endregion + + #region Open folder and select file + + internal static bool OpenFolderAndSelectFile(string filePath) + { + try + { + IntPtr pidl = ILCreateFromPathW(filePath); + if (pidl == IntPtr.Zero) return false; + + try + { + int result = SHOpenFolderAndSelectItems(pidl, 0, IntPtr.Zero, 0); + return result == 0; + } + catch + { + return false; + } + finally + { + ILFree(pidl); + } + } + catch + { + return false; + } + } + + [DllImport("shell32.dll", CharSet = CharSet.Unicode)] + private static extern IntPtr ILCreateFromPathW(string pszPath); + + [DllImport("shell32.dll")] + private static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, int cild, IntPtr apidl, int dwFlags); + + [DllImport("shell32.dll")] + private static extern void ILFree(IntPtr pidl); + + #endregion } diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index b549a1beb..eb1af7ffc 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2051,6 +2051,51 @@ internal static void OpenFMFolder(FanMission fm) } } + internal static void OpenFMScreenshotsFolder(FanMission fm, string screenshotFile) + { + try + { + if (screenshotFile.IsEmpty()) + { + LogNotFound(fm); + return; + } + + if (!NativeCommon.OpenFolderAndSelectFile(screenshotFile)) + { + string? ssDir = Path.GetDirectoryName(screenshotFile); + if (ssDir.IsEmpty()) + { + LogNotFound(fm); + return; + } + + try + { + ProcessStart_UseShellExecute(ssDir); + } + catch (Exception ex) + { + LogFMInfo(fm, ErrorText.ExTry + "open FM screenshots folder " + ssDir, ex); + Dialogs.ShowError(LText.ScreenshotsTabs.ScreenshotsFolderOpenError); + } + } + } + catch (Exception ex) + { + LogFMInfo(fm, ErrorText.ExTry + "open FM screenshots folder where " + screenshotFile + " is located.", ex); + Dialogs.ShowError(LText.ScreenshotsTabs.ScreenshotsFolderOpenError); + } + + return; + + static void LogNotFound(FanMission fm) + { + LogFMInfo(fm, ErrorText.FMScreenshotsDirNF); + Dialogs.ShowError(LText.ScreenshotsTabs.ScreenshotsFolderNotFound); + } + } + internal static void OpenWebSearchUrl() { FanMission? fm = View.GetMainSelectedFMOrNull(); @@ -2752,6 +2797,7 @@ internal static void PopulateScreenshotFileNames(FanMission? fm, List sc if (fm == null) return; if (!GameIsKnownAndSupported(fm.Game)) return; + // @GENGAMES(Screenshots) if (fm.Game == Game.TDM) { /* diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs index 5c6aefbd9..4c0e673f6 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs @@ -127,8 +127,7 @@ internal void Localize() _menu.Items[(int)TopRightTab.Tags].Text = LText.TagsTab.TabText; _menu.Items[(int)TopRightTab.Patch].Text = LText.PatchTab.TabText; _menu.Items[(int)TopRightTab.Mods].Text = LText.ModsTab.TabText; - // @ScreenshotDisplay: Localize this - _menu.Items[(int)TopRightTab.Screenshots].Text = "Screenshots"; + _menu.Items[(int)TopRightTab.Screenshots].Text = LText.ScreenshotsTabs.TabText; } internal bool Focused => _constructed && _menu.Focused; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 8e3c8e941..cdb5400b3 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -32,38 +32,40 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); - this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); - this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); + this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); + this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); + this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); this.SuspendLayout(); // // NumberLabel // - this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(8, 260); + this.NumberLabel.Location = new System.Drawing.Point(472, 238); this.NumberLabel.Name = "NumberLabel"; - this.NumberLabel.Size = new System.Drawing.Size(0, 13); - this.NumberLabel.TabIndex = 0; + this.NumberLabel.Size = new System.Drawing.Size(48, 13); + this.NumberLabel.TabIndex = 3; + this.NumberLabel.Text = "[number]"; // - // ScreenshotsNextButton + // NextButton // - this.ScreenshotsNextButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.ScreenshotsNextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; - this.ScreenshotsNextButton.Location = new System.Drawing.Point(446, 256); - this.ScreenshotsNextButton.Name = "ScreenshotsNextButton"; - this.ScreenshotsNextButton.Size = new System.Drawing.Size(75, 23); - this.ScreenshotsNextButton.TabIndex = 2; + this.NextButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; + this.NextButton.Location = new System.Drawing.Point(446, 256); + this.NextButton.Name = "NextButton"; + this.NextButton.Size = new System.Drawing.Size(75, 23); + this.NextButton.TabIndex = 2; // - // ScreenshotsPrevButton + // PrevButton // - this.ScreenshotsPrevButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.ScreenshotsPrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; - this.ScreenshotsPrevButton.Location = new System.Drawing.Point(371, 256); - this.ScreenshotsPrevButton.Name = "ScreenshotsPrevButton"; - this.ScreenshotsPrevButton.Size = new System.Drawing.Size(75, 23); - this.ScreenshotsPrevButton.TabIndex = 1; + this.PrevButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.PrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; + this.PrevButton.Location = new System.Drawing.Point(371, 256); + this.PrevButton.Name = "PrevButton"; + this.PrevButton.Size = new System.Drawing.Size(75, 23); + this.PrevButton.TabIndex = 1; // // ScreenshotsPictureBox // @@ -72,20 +74,29 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); this.ScreenshotsPictureBox.Name = "ScreenshotsPictureBox"; - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 248); + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 224); this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; this.ScreenshotsPictureBox.TabIndex = 0; this.ScreenshotsPictureBox.TabStop = false; // + // OpenScreenshotsFolderButton + // + this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); + this.OpenScreenshotsFolderButton.Name = "OpenScreenshotsFolderButton"; + this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); + this.OpenScreenshotsFolderButton.TabIndex = 0; + // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(220, 100); + this.Controls.Add(this.OpenScreenshotsFolderButton); this.Controls.Add(this.NumberLabel); - this.Controls.Add(this.ScreenshotsNextButton); - this.Controls.Add(this.ScreenshotsPrevButton); + this.Controls.Add(this.NextButton); + this.Controls.Add(this.PrevButton); this.Controls.Add(this.ScreenshotsPictureBox); this.Name = "Lazy_ScreenshotsPage"; this.Size = new System.Drawing.Size(527, 284); @@ -99,7 +110,8 @@ private void InitializeComponent() #endregion internal DarkPictureBox ScreenshotsPictureBox; - internal DarkArrowButton ScreenshotsPrevButton; - internal DarkArrowButton ScreenshotsNextButton; + internal DarkArrowButton PrevButton; + internal DarkArrowButton NextButton; internal DarkLabel NumberLabel; + internal DarkButton OpenScreenshotsFolderButton; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 942c921c2..697a93439 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -8,34 +8,35 @@ public sealed partial class Lazy_ScreenshotsPage private void InitSlim() { this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); - this.ScreenshotsNextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); - this.ScreenshotsPrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); + this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); + this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); + this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); this.SuspendLayout(); // // NumberLabel // - this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(8, 260); - this.NumberLabel.Size = new System.Drawing.Size(0, 13); + this.NumberLabel.Location = new System.Drawing.Point(472, 238); + this.NumberLabel.Size = new System.Drawing.Size(48, 13); // - // ScreenshotsNextButton + // NextButton // - this.ScreenshotsNextButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.ScreenshotsNextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; - this.ScreenshotsNextButton.Location = new System.Drawing.Point(446, 256); - this.ScreenshotsNextButton.Size = new System.Drawing.Size(75, 23); - this.ScreenshotsNextButton.TabIndex = 2; + this.NextButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; + this.NextButton.Location = new System.Drawing.Point(446, 256); + this.NextButton.Size = new System.Drawing.Size(75, 23); + this.NextButton.TabIndex = 2; // - // ScreenshotsPrevButton + // PrevButton // - this.ScreenshotsPrevButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.ScreenshotsPrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; - this.ScreenshotsPrevButton.Location = new System.Drawing.Point(371, 256); - this.ScreenshotsPrevButton.Size = new System.Drawing.Size(75, 23); - this.ScreenshotsPrevButton.TabIndex = 1; + this.PrevButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.PrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; + this.PrevButton.Location = new System.Drawing.Point(371, 256); + this.PrevButton.Size = new System.Drawing.Size(75, 23); + this.PrevButton.TabIndex = 1; // // ScreenshotsPictureBox // @@ -43,18 +44,26 @@ private void InitSlim() | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 248); + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 224); this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; // + // OpenScreenshotsFolderButton + // + this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); + this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); + this.OpenScreenshotsFolderButton.TabIndex = 0; + // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(220, 100); + this.Controls.Add(this.OpenScreenshotsFolderButton); this.Controls.Add(this.NumberLabel); - this.Controls.Add(this.ScreenshotsNextButton); - this.Controls.Add(this.ScreenshotsPrevButton); + this.Controls.Add(this.NextButton); + this.Controls.Add(this.PrevButton); this.Controls.Add(this.ScreenshotsPictureBox); this.Size = new System.Drawing.Size(527, 284); ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).EndInit(); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 8a518fbc2..b4a26e759 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -86,8 +86,10 @@ public override void Construct() { Controls.Add(_page); - _page.ScreenshotsPrevButton.Click += ScreenshotsPrevButton_Click; - _page.ScreenshotsNextButton.Click += ScreenshotsNextButton_Click; + _page.PrevButton.Click += ScreenshotsPrevButton_Click; + _page.NextButton.Click += ScreenshotsNextButton_Click; + _page.OpenScreenshotsFolderButton.PaintCustom += OpenScreenshotsFolderButton_PaintCustom; + _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; FinishConstruct(); } @@ -108,8 +110,9 @@ public override void UpdatePage() CurrentScreenshotFileName = ""; ClearCurrentScreenshot(); _page.ScreenshotsPictureBox.Enabled = false; - _page.ScreenshotsPrevButton.Enabled = false; - _page.ScreenshotsNextButton.Enabled = false; + _page.OpenScreenshotsFolderButton.Enabled = false; + _page.PrevButton.Enabled = false; + _page.NextButton.Enabled = false; _page.NumberLabel.Text = ""; } // @ScreenshotDisplay: Should we save the selected screenshot in the FM object? @@ -118,8 +121,9 @@ public override void UpdatePage() CurrentScreenshotFileName = ScreenshotFileNames[0]; DisplayCurrentScreenshot(); _page.ScreenshotsPictureBox.Enabled = true; - _page.ScreenshotsPrevButton.Enabled = ScreenshotFileNames.Count > 1; - _page.ScreenshotsNextButton.Enabled = ScreenshotFileNames.Count > 1; + _page.OpenScreenshotsFolderButton.Enabled = true; + _page.PrevButton.Enabled = ScreenshotFileNames.Count > 1; + _page.NextButton.Enabled = ScreenshotFileNames.Count > 1; } } @@ -181,6 +185,22 @@ protected override void OnVisibleChanged(EventArgs e) if (Visible) DisplayCurrentScreenshot(); } + private void OpenScreenshotsFolderButton_Click(object sender, EventArgs e) + { + Core.OpenFMScreenshotsFolder(_owner.FMsDGV.GetMainSelectedFM(), CurrentScreenshotFileName); + } + + private void OpenScreenshotsFolderButton_PaintCustom(object sender, PaintEventArgs e) + { + Image image = Images.Folder; + DarkButton button = _page.OpenScreenshotsFolderButton; + Images.PaintBitmapButton( + button, + e, + button.Enabled ? image : Images.GetDisabledImage(image), + x: (button.Width - image.Width) / 2); + } + private void ScreenshotsPrevButton_Click(object sender, EventArgs e) => CycleScreenshot(step: -1); private void ScreenshotsNextButton_Click(object sender, EventArgs e) => CycleScreenshot(step: 1); diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index c57c91b2e..f38252499 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -1842,8 +1842,7 @@ private void Localize(bool startup) TagsTabPage.Text = LText.TagsTab.TabText; PatchTabPage.Text = LText.PatchTab.TabText; ModsTabPage.Text = LText.ModsTab.TabText; - // @ScreenshotDisplay: Localize this - ScreenshotsTabPage.Text = "Screenshots"; + ScreenshotsTabPage.Text = LText.ScreenshotsTabs.TabText; for (int i = 0; i < _topRightTabs.Length; i++) { diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index cb15d1398..dfe02e932 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -487,6 +487,11 @@ TDM_ModsNotSupported=Mod management is not supported for The Dark Mod. ; This is for when the selected FM has an unknown or unsupported game type. Generic_ModsNotSupported=Mod management is not supported for unknown FMs. +[ScreenshotsTabs] +TabText=Screenshots +ScreenshotsFolderNotFound=Screenshots folder not found. +ScreenshotsFolderOpenError=There was an error trying to open the screenshots folder. + [ReadmeArea] ViewHTMLReadme=View HTML Readme FullScreenToolTip=Fullscreen From c2404667988e50aa3006e7cfe8cc371d233c4ec0 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 24 Feb 2024 07:56:37 -0800 Subject: [PATCH 029/200] Right-align number label on text set --- .../Lazy_ScreenshotsPage.Designer.cs | 20 +++++++++---------- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 18 ++++++++--------- .../TopRightPages/ScreenshotsTabPage.cs | 17 +++++++++++++--- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index cdb5400b3..f9c90226c 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,14 +31,22 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); - this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); this.SuspendLayout(); // + // OpenScreenshotsFolderButton + // + this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); + this.OpenScreenshotsFolderButton.Name = "OpenScreenshotsFolderButton"; + this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); + this.OpenScreenshotsFolderButton.TabIndex = 0; + // // NumberLabel // this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); @@ -79,20 +87,12 @@ private void InitializeComponent() this.ScreenshotsPictureBox.TabIndex = 0; this.ScreenshotsPictureBox.TabStop = false; // - // OpenScreenshotsFolderButton - // - this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); - this.OpenScreenshotsFolderButton.Name = "OpenScreenshotsFolderButton"; - this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); - this.OpenScreenshotsFolderButton.TabIndex = 0; - // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; - this.AutoScrollMinSize = new System.Drawing.Size(220, 100); + this.AutoScrollMinSize = new System.Drawing.Size(200, 100); this.Controls.Add(this.OpenScreenshotsFolderButton); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.NextButton); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 697a93439..944f942a5 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,14 +7,21 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { + this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); - this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); this.SuspendLayout(); // + // OpenScreenshotsFolderButton + // + this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); + this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); + this.OpenScreenshotsFolderButton.TabIndex = 0; + // // NumberLabel // this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); @@ -47,19 +54,12 @@ private void InitSlim() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 224); this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; // - // OpenScreenshotsFolderButton - // - this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); - this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); - this.OpenScreenshotsFolderButton.TabIndex = 0; - // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; - this.AutoScrollMinSize = new System.Drawing.Size(220, 100); + this.AutoScrollMinSize = new System.Drawing.Size(200, 100); this.Controls.Add(this.OpenScreenshotsFolderButton); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.NextButton); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index b4a26e759..12087b8bd 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -113,7 +113,7 @@ public override void UpdatePage() _page.OpenScreenshotsFolderButton.Enabled = false; _page.PrevButton.Enabled = false; _page.NextButton.Enabled = false; - _page.NumberLabel.Text = ""; + SetNumberLabelText(""); } // @ScreenshotDisplay: Should we save the selected screenshot in the FM object? else @@ -131,6 +131,16 @@ public override void UpdatePage() #region Page + // Manual right-align to avoid needing a FlowLayoutPanel + private void SetNumberLabelText(string text) + { + _page.NumberLabel.Text = text; + _page.NumberLabel.Location = _page.NumberLabel.Location with + { + X = (_page.ClientSize.Width - 8) - _page.NumberLabel.Width + }; + } + private void ClearCurrentScreenshot() { _currentImageBroken = false; @@ -172,9 +182,10 @@ private void DisplayCurrentScreenshot() } finally { - _page.NumberLabel.Text = + SetNumberLabelText( (ScreenshotFileNames.IndexOf(CurrentScreenshotFileName) + 1).ToStrInv() + " / " + - ScreenshotFileNames.Count.ToStrInv(); + ScreenshotFileNames.Count.ToStrInv() + ); } } } From 6c178808b3c0b8f9593e3a94ac4d61c130eddbb4 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 24 Feb 2024 15:31:07 -0800 Subject: [PATCH 030/200] Testing gamma change functionality --- .../Forms/CustomControls/ImagePanelCustom.cs | 37 ++++++ .../TopRightPages/ScreenshotsTabPage.cs | 6 +- AngelLoader/Forms/Images.cs | 2 +- AngelLoader/Forms/ImgTestForm.Designer.cs | 78 ++++++++++++ AngelLoader/Forms/ImgTestForm.cs | 59 +++++++++ AngelLoader/Forms/ImgTestForm.resx | 120 ++++++++++++++++++ AngelLoader/Forms/MainForm.cs | 3 + 7 files changed, 301 insertions(+), 4 deletions(-) create mode 100644 AngelLoader/Forms/CustomControls/ImagePanelCustom.cs create mode 100644 AngelLoader/Forms/ImgTestForm.Designer.cs create mode 100644 AngelLoader/Forms/ImgTestForm.cs create mode 100644 AngelLoader/Forms/ImgTestForm.resx diff --git a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs new file mode 100644 index 000000000..7e9b8b98c --- /dev/null +++ b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs @@ -0,0 +1,37 @@ +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using AngelLoader.DataClasses; +using JetBrains.Annotations; + +namespace AngelLoader.Forms.CustomControls; + +public sealed class ImagePanelCustom : Panel, IDarkable +{ + [PublicAPI] + public Color DrawnBackColor = SystemColors.Control; + + [PublicAPI] + public Color DarkModeDrawnBackColor = DarkColors.Fen_ControlBackground; + + private bool _darkModeEnabled; + [PublicAPI] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool DarkModeEnabled + { + get => _darkModeEnabled; + set + { + if (_darkModeEnabled == value) return; + _darkModeEnabled = value; + BackColor = _darkModeEnabled ? DarkModeDrawnBackColor : DrawnBackColor; + } + } + + public ImagePanelCustom() + { + ResizeRedraw = true; + DoubleBuffered = true; + } +} diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 12087b8bd..abe5e23db 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -23,11 +23,11 @@ public sealed class ScreenshotsTabPage : Lazy_TabsBase mean we carry around the full file bytes in memory as well as the displayed image, but since we're only displaying one at a time and they'll probably be a few megs at most, it's not a big deal. */ - private sealed class MemoryImage : IDisposable + public sealed class MemoryImage : IDisposable { private readonly MemoryStream _memoryStream; - internal readonly Image Img; - internal string Path { get; private set; } + public readonly Image Img; + public string Path { get; private set; } public MemoryImage(string path) { diff --git a/AngelLoader/Forms/Images.cs b/AngelLoader/Forms/Images.cs index ebbcda7ac..a6d4b7bd1 100644 --- a/AngelLoader/Forms/Images.cs +++ b/AngelLoader/Forms/Images.cs @@ -1666,7 +1666,7 @@ private static GraphicsPath MakeGraphicsPath(float[] points, byte[] types) return new GraphicsPath(rawPoints, types); } - private static void FitRectInBounds(Graphics g, RectangleF drawRect, RectangleF boundsRect) + internal static void FitRectInBounds(Graphics g, RectangleF drawRect, RectangleF boundsRect) { if (boundsRect.Width < 1 || boundsRect.Height < 1) return; diff --git a/AngelLoader/Forms/ImgTestForm.Designer.cs b/AngelLoader/Forms/ImgTestForm.Designer.cs new file mode 100644 index 000000000..9ebec488c --- /dev/null +++ b/AngelLoader/Forms/ImgTestForm.Designer.cs @@ -0,0 +1,78 @@ +namespace AngelLoader.Forms; + +sealed partial class ImgTestForm +{ + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.ImageBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); + this.GammaTrackBar = new System.Windows.Forms.TrackBar(); + ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); + this.SuspendLayout(); + // + // ImageBox + // + this.ImageBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ImageBox.Location = new System.Drawing.Point(8, 8); + this.ImageBox.Name = "ImageBox"; + this.ImageBox.Size = new System.Drawing.Size(784, 376); + this.ImageBox.TabIndex = 0; + this.ImageBox.Paint += new System.Windows.Forms.PaintEventHandler(this.ImageBox_Paint); + // + // GammaTrackBar + // + this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.GammaTrackBar.Location = new System.Drawing.Point(8, 392); + this.GammaTrackBar.Maximum = 20; + this.GammaTrackBar.Name = "GammaTrackBar"; + this.GammaTrackBar.Size = new System.Drawing.Size(784, 45); + this.GammaTrackBar.TabIndex = 0; + this.GammaTrackBar.Value = 10; + this.GammaTrackBar.Scroll += new System.EventHandler(this.GammaTrackBar_Scroll); + // + // ImgTestForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.GammaTrackBar); + this.Controls.Add(this.ImageBox); + this.Name = "ImgTestForm"; + this.Text = "ImgTestForm"; + ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private CustomControls.ImagePanelCustom ImageBox; + private System.Windows.Forms.TrackBar GammaTrackBar; +} \ No newline at end of file diff --git a/AngelLoader/Forms/ImgTestForm.cs b/AngelLoader/Forms/ImgTestForm.cs new file mode 100644 index 000000000..3d4ef3868 --- /dev/null +++ b/AngelLoader/Forms/ImgTestForm.cs @@ -0,0 +1,59 @@ +/* +@ScreenshotDisplay: This form is a test, remove it later and bring this into the actual screenshot display UI area + +@ScreenshotDisplay(Custom image box notes): +-This is slower to draw than PictureBox, but it's faster/trivial to change the gamma. With the PictureBox, we'd + have to draw the bitmap onto another bitmap with the gamma adjust, then set the PictureBox.Image property again, + with a full load time and all. +*/ + +using System.Drawing; +using System.Drawing.Imaging; +using System.Windows.Forms; +using AL_Common; +using static AngelLoader.Forms.CustomControls.ScreenshotsTabPage; + +namespace AngelLoader.Forms; + +public sealed partial class ImgTestForm : Form +{ + public ImgTestForm() + { + InitializeComponent(); + } + + private readonly MemoryImage _currentScreenshotStream = new(@"C:\Thief Games\Thief2-ND-T2Fix\FMs\Calendras_Legacy_v1a\screenshots\dump000.png"); + + private readonly ImageAttributes _imageAttributes = new(); + + private readonly Size _imageSize = new(2560, 1440); + + private readonly RectangleF _imageRect = new(0, 0, 2560, 1440); + + private float _gamma = 1.0f; + + private void ImageBox_Paint(object sender, PaintEventArgs e) + { + Images.FitRectInBounds(e.Graphics, _imageRect, ImageBox.Bounds); + + _imageAttributes.SetGamma(_gamma, ColorAdjustType.Bitmap); + + e.Graphics.DrawImage( + _currentScreenshotStream.Img, + new Rectangle(0, 0, _imageSize.Width, _imageSize.Height), + 0, + 0, + _imageSize.Width, + _imageSize.Height, + GraphicsUnit.Pixel, + _imageAttributes + ); + } + + private void GammaTrackBar_Scroll(object sender, System.EventArgs e) + { + // @ScreenshotDisplay(Gamma slider): The clamp is a hack to prevent 0 which is invalid, polish it up later + _gamma = ((GammaTrackBar.Maximum - GammaTrackBar.Value) * 0.10f).ClampToMin(0.01f); + ImageBox.Invalidate(); + } +} diff --git a/AngelLoader/Forms/ImgTestForm.resx b/AngelLoader/Forms/ImgTestForm.resx new file mode 100644 index 000000000..1af7de150 --- /dev/null +++ b/AngelLoader/Forms/ImgTestForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index f38252499..ce42f5504 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -252,8 +252,11 @@ private void Test2Button_Click(object sender, EventArgs e) Height = 872; } + // @ScreenshotDisplay: Remove test code private void Test3Button_Click(object sender, EventArgs e) { + using var f = new ImgTestForm(); + f.ShowDialog(this); } private void Test4Button_Click(object sender, EventArgs e) From c30425c2261c745e3a41dd7aacb27c02d5148855 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 24 Feb 2024 15:57:31 -0800 Subject: [PATCH 031/200] Implement copy gamma'd image to clipboard --- AngelLoader/Forms/ImgTestForm.Designer.cs | 18 ++++++++++++--- AngelLoader/Forms/ImgTestForm.cs | 27 ++++++++++++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/AngelLoader/Forms/ImgTestForm.Designer.cs b/AngelLoader/Forms/ImgTestForm.Designer.cs index 9ebec488c..1b5b75ac8 100644 --- a/AngelLoader/Forms/ImgTestForm.Designer.cs +++ b/AngelLoader/Forms/ImgTestForm.Designer.cs @@ -30,6 +30,7 @@ private void InitializeComponent() { this.ImageBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); this.GammaTrackBar = new System.Windows.Forms.TrackBar(); + this.CopyButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // @@ -40,7 +41,7 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.ImageBox.Location = new System.Drawing.Point(8, 8); this.ImageBox.Name = "ImageBox"; - this.ImageBox.Size = new System.Drawing.Size(784, 376); + this.ImageBox.Size = new System.Drawing.Size(784, 384); this.ImageBox.TabIndex = 0; this.ImageBox.Paint += new System.Windows.Forms.PaintEventHandler(this.ImageBox_Paint); // @@ -48,7 +49,7 @@ private void InitializeComponent() // this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.GammaTrackBar.Location = new System.Drawing.Point(8, 392); + this.GammaTrackBar.Location = new System.Drawing.Point(16, 400); this.GammaTrackBar.Maximum = 20; this.GammaTrackBar.Name = "GammaTrackBar"; this.GammaTrackBar.Size = new System.Drawing.Size(784, 45); @@ -56,11 +57,21 @@ private void InitializeComponent() this.GammaTrackBar.Value = 10; this.GammaTrackBar.Scroll += new System.EventHandler(this.GammaTrackBar_Scroll); // + // CopyButton + // + this.CopyButton.Location = new System.Drawing.Point(336, 464); + this.CopyButton.Name = "CopyButton"; + this.CopyButton.Size = new System.Drawing.Size(144, 24); + this.CopyButton.TabIndex = 1; + this.CopyButton.Text = "Copy to clipboard"; + this.CopyButton.Click += new System.EventHandler(this.CopyButton_Click); + // // ImgTestForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(800, 450); + this.ClientSize = new System.Drawing.Size(800, 522); + this.Controls.Add(this.CopyButton); this.Controls.Add(this.GammaTrackBar); this.Controls.Add(this.ImageBox); this.Name = "ImgTestForm"; @@ -75,4 +86,5 @@ private void InitializeComponent() private CustomControls.ImagePanelCustom ImageBox; private System.Windows.Forms.TrackBar GammaTrackBar; + private CustomControls.DarkButton CopyButton; } \ No newline at end of file diff --git a/AngelLoader/Forms/ImgTestForm.cs b/AngelLoader/Forms/ImgTestForm.cs index 3d4ef3868..95949ceac 100644 --- a/AngelLoader/Forms/ImgTestForm.cs +++ b/AngelLoader/Forms/ImgTestForm.cs @@ -38,7 +38,12 @@ private void ImageBox_Paint(object sender, PaintEventArgs e) _imageAttributes.SetGamma(_gamma, ColorAdjustType.Bitmap); - e.Graphics.DrawImage( + DrawImageOnGraphics(e.Graphics); + } + + private void DrawImageOnGraphics(Graphics g) + { + g.DrawImage( _currentScreenshotStream.Img, new Rectangle(0, 0, _imageSize.Width, _imageSize.Height), 0, @@ -50,10 +55,30 @@ private void ImageBox_Paint(object sender, PaintEventArgs e) ); } + private Bitmap GetFinalBitmap() + { + Bitmap bmp = new( + _currentScreenshotStream.Img.Width, + _currentScreenshotStream.Img.Height, + _currentScreenshotStream.Img.PixelFormat); + + using var g = Graphics.FromImage(bmp); + + DrawImageOnGraphics(g); + + return bmp; + } + private void GammaTrackBar_Scroll(object sender, System.EventArgs e) { // @ScreenshotDisplay(Gamma slider): The clamp is a hack to prevent 0 which is invalid, polish it up later _gamma = ((GammaTrackBar.Maximum - GammaTrackBar.Value) * 0.10f).ClampToMin(0.01f); ImageBox.Invalidate(); } + + private void CopyButton_Click(object sender, System.EventArgs e) + { + using Bitmap bmp = GetFinalBitmap(); + Clipboard.SetImage(bmp); + } } From 15432fa0a99eedd59445cf121c2b32f2d8b00678 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 02:29:57 -0800 Subject: [PATCH 032/200] ImagePanelCustom finalization work --- .../Forms/CustomControls/ImagePanelCustom.cs | 80 +++++++++++++++++++ AngelLoader/Forms/ImgTestForm.Designer.cs | 4 +- AngelLoader/Forms/ImgTestForm.cs | 51 +----------- 3 files changed, 86 insertions(+), 49 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs index 7e9b8b98c..fb2b9fd11 100644 --- a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs +++ b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs @@ -1,5 +1,6 @@ using System.ComponentModel; using System.Drawing; +using System.Drawing.Imaging; using System.Windows.Forms; using AngelLoader.DataClasses; using JetBrains.Annotations; @@ -29,9 +30,88 @@ public bool DarkModeEnabled } } + private readonly ImageAttributes _imageAttributes = new(); + private Size _imageSize = Size.Empty; + private RectangleF _imageRect = RectangleF.Empty; + + private float _gamma = 1.0f; + [PublicAPI] + public float Gamma + { + get => _gamma; + set => _gamma = value; + } + + private Image? _image; + [PublicAPI] + public Image? Image + { + get => _image; + set + { + _image = value; + if (_image != null) + { + _imageSize = _image.Size; + _imageRect = new RectangleF(0, 0, _imageSize.Width, _imageSize.Height); + } + else + { + _imageSize = Size.Empty; + _imageRect = RectangleF.Empty; + } + } + } + public ImagePanelCustom() { ResizeRedraw = true; DoubleBuffered = true; } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + if (_image == null) return; + + Images.FitRectInBounds(e.Graphics, _imageRect, Bounds); + + _imageAttributes.SetGamma(_gamma, ColorAdjustType.Bitmap); + + DrawImageOnGraphics(e.Graphics, _image); + } + + private void DrawImageOnGraphics(Graphics g, Image image) + { + g.DrawImage( + image, + new Rectangle(0, 0, _imageSize.Width, _imageSize.Height), + 0, + 0, + _imageSize.Width, + _imageSize.Height, + GraphicsUnit.Pixel, + _imageAttributes + ); + } + + public Bitmap GetFinalBitmap() + { + if (_image == null) + { + return new Bitmap(0, 0, PixelFormat.Format32bppPArgb); + } + + Bitmap bmp = new( + _image.Width, + _image.Height, + _image.PixelFormat); + + using var g = Graphics.FromImage(bmp); + + DrawImageOnGraphics(g, _image); + + return bmp; + } } diff --git a/AngelLoader/Forms/ImgTestForm.Designer.cs b/AngelLoader/Forms/ImgTestForm.Designer.cs index 1b5b75ac8..e918c872f 100644 --- a/AngelLoader/Forms/ImgTestForm.Designer.cs +++ b/AngelLoader/Forms/ImgTestForm.Designer.cs @@ -39,11 +39,12 @@ private void InitializeComponent() this.ImageBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.ImageBox.Gamma = 1F; + this.ImageBox.Image = null; this.ImageBox.Location = new System.Drawing.Point(8, 8); this.ImageBox.Name = "ImageBox"; this.ImageBox.Size = new System.Drawing.Size(784, 384); this.ImageBox.TabIndex = 0; - this.ImageBox.Paint += new System.Windows.Forms.PaintEventHandler(this.ImageBox_Paint); // // GammaTrackBar // @@ -59,6 +60,7 @@ private void InitializeComponent() // // CopyButton // + this.CopyButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom; this.CopyButton.Location = new System.Drawing.Point(336, 464); this.CopyButton.Name = "CopyButton"; this.CopyButton.Size = new System.Drawing.Size(144, 24); diff --git a/AngelLoader/Forms/ImgTestForm.cs b/AngelLoader/Forms/ImgTestForm.cs index 95949ceac..af2d1e2fe 100644 --- a/AngelLoader/Forms/ImgTestForm.cs +++ b/AngelLoader/Forms/ImgTestForm.cs @@ -8,7 +8,6 @@ with a full load time and all. */ using System.Drawing; -using System.Drawing.Imaging; using System.Windows.Forms; using AL_Common; using static AngelLoader.Forms.CustomControls.ScreenshotsTabPage; @@ -20,65 +19,21 @@ public sealed partial class ImgTestForm : Form public ImgTestForm() { InitializeComponent(); + ImageBox.Image = _currentScreenshotStream.Img; } private readonly MemoryImage _currentScreenshotStream = new(@"C:\Thief Games\Thief2-ND-T2Fix\FMs\Calendras_Legacy_v1a\screenshots\dump000.png"); - private readonly ImageAttributes _imageAttributes = new(); - - private readonly Size _imageSize = new(2560, 1440); - - private readonly RectangleF _imageRect = new(0, 0, 2560, 1440); - - private float _gamma = 1.0f; - - private void ImageBox_Paint(object sender, PaintEventArgs e) - { - Images.FitRectInBounds(e.Graphics, _imageRect, ImageBox.Bounds); - - _imageAttributes.SetGamma(_gamma, ColorAdjustType.Bitmap); - - DrawImageOnGraphics(e.Graphics); - } - - private void DrawImageOnGraphics(Graphics g) - { - g.DrawImage( - _currentScreenshotStream.Img, - new Rectangle(0, 0, _imageSize.Width, _imageSize.Height), - 0, - 0, - _imageSize.Width, - _imageSize.Height, - GraphicsUnit.Pixel, - _imageAttributes - ); - } - - private Bitmap GetFinalBitmap() - { - Bitmap bmp = new( - _currentScreenshotStream.Img.Width, - _currentScreenshotStream.Img.Height, - _currentScreenshotStream.Img.PixelFormat); - - using var g = Graphics.FromImage(bmp); - - DrawImageOnGraphics(g); - - return bmp; - } - private void GammaTrackBar_Scroll(object sender, System.EventArgs e) { // @ScreenshotDisplay(Gamma slider): The clamp is a hack to prevent 0 which is invalid, polish it up later - _gamma = ((GammaTrackBar.Maximum - GammaTrackBar.Value) * 0.10f).ClampToMin(0.01f); + ImageBox.Gamma = ((GammaTrackBar.Maximum - GammaTrackBar.Value) * 0.10f).ClampToMin(0.01f); ImageBox.Invalidate(); } private void CopyButton_Click(object sender, System.EventArgs e) { - using Bitmap bmp = GetFinalBitmap(); + using Bitmap bmp = ImageBox.GetFinalBitmap(); Clipboard.SetImage(bmp); } } From 9462f49eaafa8090552810c65a62aa283ab0eef3 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 03:08:06 -0800 Subject: [PATCH 033/200] Switch to custom image box for screenshots tab --- .../Forms/CustomControls/ImagePanelCustom.cs | 78 +++++++++++++++---- .../Lazy_ScreenshotsPage.Designer.cs | 7 +- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 7 +- .../TopRightPages/ScreenshotsTabPage.cs | 16 +--- 4 files changed, 68 insertions(+), 40 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs index fb2b9fd11..9c97c5220 100644 --- a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs +++ b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs @@ -26,16 +26,26 @@ public bool DarkModeEnabled { if (_darkModeEnabled == value) return; _darkModeEnabled = value; + BackColor = _darkModeEnabled ? DarkModeDrawnBackColor : DrawnBackColor; + + if (_showingErrorImage) + { + SetImageInternal(Images.BrokenFile); + } } } private readonly ImageAttributes _imageAttributes = new(); private Size _imageSize = Size.Empty; private RectangleF _imageRect = RectangleF.Empty; + private bool _showingErrorImage; private float _gamma = 1.0f; [PublicAPI] + [Browsable(false)] + [DefaultValue(1.0f)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public float Gamma { get => _gamma; @@ -44,23 +54,39 @@ public float Gamma private Image? _image; [PublicAPI] + [Browsable(false)] + [DefaultValue(1.0f)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Image? Image { get => _image; set { - _image = value; - if (_image != null) - { - _imageSize = _image.Size; - _imageRect = new RectangleF(0, 0, _imageSize.Width, _imageSize.Height); - } - else - { - _imageSize = Size.Empty; - _imageRect = RectangleF.Empty; - } + _showingErrorImage = false; + SetImageInternal(value); + } + } + + private void SetImageInternal(Image? image) + { + _image = image; + if (_image != null) + { + _imageSize = _image.Size; + _imageRect = new RectangleF(0, 0, _imageSize.Width, _imageSize.Height); } + else + { + _imageSize = Size.Empty; + _imageRect = RectangleF.Empty; + } + Invalidate(); + } + + public void SetErrorImage() + { + _showingErrorImage = true; + SetImageInternal(Images.BrokenFile); } public ImagePanelCustom() @@ -75,11 +101,20 @@ protected override void OnPaint(PaintEventArgs e) if (_image == null) return; - Images.FitRectInBounds(e.Graphics, _imageRect, Bounds); - - _imageAttributes.SetGamma(_gamma, ColorAdjustType.Bitmap); - - DrawImageOnGraphics(e.Graphics, _image); + if (_showingErrorImage) + { + e.Graphics.DrawImage( + _image, + (ClientSize.Width / 2) - (_image.Width / 2), + (ClientSize.Height / 2) - (_image.Height / 2) + ); + } + else + { + Images.FitRectInBounds(e.Graphics, _imageRect, Bounds); + _imageAttributes.SetGamma(_gamma, ColorAdjustType.Bitmap); + DrawImageOnGraphics(e.Graphics, _image); + } } private void DrawImageOnGraphics(Graphics g, Image image) @@ -114,4 +149,15 @@ public Bitmap GetFinalBitmap() return bmp; } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _imageAttributes.Dispose(); + _image = null; + } + + base.Dispose(disposing); + } } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index f9c90226c..ccc4e4d58 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -35,8 +35,7 @@ private void InitializeComponent() this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); - this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); - ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); + this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); this.SuspendLayout(); // // OpenScreenshotsFolderButton @@ -83,7 +82,6 @@ private void InitializeComponent() this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); this.ScreenshotsPictureBox.Name = "ScreenshotsPictureBox"; this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 224); - this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; this.ScreenshotsPictureBox.TabIndex = 0; this.ScreenshotsPictureBox.TabStop = false; // @@ -100,7 +98,6 @@ private void InitializeComponent() this.Controls.Add(this.ScreenshotsPictureBox); this.Name = "Lazy_ScreenshotsPage"; this.Size = new System.Drawing.Size(527, 284); - ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -109,7 +106,7 @@ private void InitializeComponent() #endregion - internal DarkPictureBox ScreenshotsPictureBox; + internal ImagePanelCustom ScreenshotsPictureBox; internal DarkArrowButton PrevButton; internal DarkArrowButton NextButton; internal DarkLabel NumberLabel; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 944f942a5..01a3c544a 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -11,8 +11,7 @@ private void InitSlim() this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); - this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.DarkPictureBox(); - ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).BeginInit(); + this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); this.SuspendLayout(); // // OpenScreenshotsFolderButton @@ -52,7 +51,8 @@ private void InitSlim() | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 224); - this.ScreenshotsPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.ScreenshotsPictureBox.TabIndex = 0; + this.ScreenshotsPictureBox.TabStop = false; // // Lazy_ScreenshotsPage // @@ -66,7 +66,6 @@ private void InitSlim() this.Controls.Add(this.PrevButton); this.Controls.Add(this.ScreenshotsPictureBox); this.Size = new System.Drawing.Size(527, 284); - ((System.ComponentModel.ISupportInitialize)(this.ScreenshotsPictureBox)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index abe5e23db..3234d5015 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -48,8 +48,6 @@ public void Dispose() private readonly List ScreenshotFileNames = new(); private string CurrentScreenshotFileName = ""; private MemoryImage? _currentScreenshotStream; - private bool _currentImageBroken; - #region Theme [PublicAPI] @@ -64,11 +62,6 @@ public override bool DarkModeEnabled base.DarkModeEnabled = value; if (!_constructed) return; - - if (_currentImageBroken) - { - _page.ScreenshotsPictureBox.Image = Images.BrokenFile; - } } } @@ -143,10 +136,7 @@ private void SetNumberLabelText(string text) private void ClearCurrentScreenshot() { - _currentImageBroken = false; - _page.ScreenshotsPictureBox.SizeMode = PictureBoxSizeMode.Zoom; _page.ScreenshotsPictureBox.Image = null; - _page.ScreenshotsPictureBox.ImageLocation = ""; _currentScreenshotStream?.Dispose(); } @@ -169,16 +159,12 @@ private void DisplayCurrentScreenshot() { _currentScreenshotStream?.Dispose(); _currentScreenshotStream = new MemoryImage(CurrentScreenshotFileName); - _page.ScreenshotsPictureBox.SizeMode = PictureBoxSizeMode.Zoom; _page.ScreenshotsPictureBox.Image = _currentScreenshotStream.Img; - _currentImageBroken = false; } catch { ClearCurrentScreenshot(); - _page.ScreenshotsPictureBox.SizeMode = PictureBoxSizeMode.CenterImage; - _page.ScreenshotsPictureBox.Image = Images.BrokenFile; - _currentImageBroken = true; + _page.ScreenshotsPictureBox.SetErrorImage(); } finally { From e982df292e261bfbcc86c9e22a36b43e95a5c215 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 04:29:31 -0800 Subject: [PATCH 034/200] Screenshots gamma work --- .../Common/DataClasses/LocalizationData.cs | 3 ++- AngelLoader/Core.cs | 6 ++--- .../Forms/CustomControls/ImagePanelCustom.cs | 6 ++++- .../LazyLoaded/TopRightLLMenu.cs | 2 +- .../Lazy_ScreenshotsPage.Designer.cs | 27 +++++++++++++++---- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 23 +++++++++++++--- .../TopRightPages/ScreenshotsTabPage.cs | 19 +++++++++++++ AngelLoader/Forms/ImgTestForm.Designer.cs | 2 -- AngelLoader/Forms/ImgTestForm.cs | 1 - AngelLoader/Forms/MainForm.cs | 2 +- AngelLoader/Languages/English.ini | 3 ++- 11 files changed, 74 insertions(+), 20 deletions(-) diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 5c511ec42..473846b9e 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -43,7 +43,7 @@ internal sealed class LText_Class internal readonly TagsTab_Class TagsTab = new(); internal readonly PatchTab_Class PatchTab = new(); internal readonly ModsTab_Class ModsTab = new(); - internal readonly ScreenshotsTab_Class ScreenshotsTabs = new(); + internal readonly ScreenshotsTab_Class ScreenshotsTab = new(); internal readonly ReadmeArea_Class ReadmeArea = new(); internal readonly PlayOriginalGameMenu_Class PlayOriginalGameMenu = new(); internal readonly MainButtons_Class MainButtons = new(); @@ -631,6 +631,7 @@ internal sealed class ScreenshotsTab_Class { // @ScreenshotDisplay: Finalize this text, improve it if necessary etc. internal readonly string TabText = "Screenshots"; + internal readonly string AdjustGamma = "Adjust gamma"; internal readonly string ScreenshotsFolderNotFound = "Screenshots folder not found."; internal readonly string ScreenshotsFolderOpenError = "There was an error trying to open the screenshots folder."; } diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index eb1af7ffc..e2ffcea16 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2077,14 +2077,14 @@ internal static void OpenFMScreenshotsFolder(FanMission fm, string screenshotFil catch (Exception ex) { LogFMInfo(fm, ErrorText.ExTry + "open FM screenshots folder " + ssDir, ex); - Dialogs.ShowError(LText.ScreenshotsTabs.ScreenshotsFolderOpenError); + Dialogs.ShowError(LText.ScreenshotsTab.ScreenshotsFolderOpenError); } } } catch (Exception ex) { LogFMInfo(fm, ErrorText.ExTry + "open FM screenshots folder where " + screenshotFile + " is located.", ex); - Dialogs.ShowError(LText.ScreenshotsTabs.ScreenshotsFolderOpenError); + Dialogs.ShowError(LText.ScreenshotsTab.ScreenshotsFolderOpenError); } return; @@ -2092,7 +2092,7 @@ internal static void OpenFMScreenshotsFolder(FanMission fm, string screenshotFil static void LogNotFound(FanMission fm) { LogFMInfo(fm, ErrorText.FMScreenshotsDirNF); - Dialogs.ShowError(LText.ScreenshotsTabs.ScreenshotsFolderNotFound); + Dialogs.ShowError(LText.ScreenshotsTab.ScreenshotsFolderNotFound); } } diff --git a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs index 9c97c5220..8f3c79848 100644 --- a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs +++ b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs @@ -49,7 +49,11 @@ public bool DarkModeEnabled public float Gamma { get => _gamma; - set => _gamma = value; + set + { + _gamma = value; + Invalidate(); + } } private Image? _image; diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs index 4c0e673f6..c08126d6a 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs @@ -127,7 +127,7 @@ internal void Localize() _menu.Items[(int)TopRightTab.Tags].Text = LText.TagsTab.TabText; _menu.Items[(int)TopRightTab.Patch].Text = LText.PatchTab.TabText; _menu.Items[(int)TopRightTab.Mods].Text = LText.ModsTab.TabText; - _menu.Items[(int)TopRightTab.Screenshots].Text = LText.ScreenshotsTabs.TabText; + _menu.Items[(int)TopRightTab.Screenshots].Text = LText.ScreenshotsTab.TabText; } internal bool Focused => _constructed && _menu.Focused; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index ccc4e4d58..d814f6ba2 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,13 +31,28 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.GammaTrackBar = new System.Windows.Forms.TrackBar(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); + ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // + // GammaTrackBar + // + this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.GammaTrackBar.AutoSize = false; + this.GammaTrackBar.Location = new System.Drawing.Point(8, 208); + this.GammaTrackBar.Maximum = 40; + this.GammaTrackBar.Name = "GammaTrackBar"; + this.GammaTrackBar.Size = new System.Drawing.Size(512, 24); + this.GammaTrackBar.TabIndex = 5; + this.GammaTrackBar.TickStyle = System.Windows.Forms.TickStyle.None; + this.GammaTrackBar.Value = 20; + // // OpenScreenshotsFolderButton // this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); @@ -52,9 +67,9 @@ private void InitializeComponent() this.NumberLabel.AutoSize = true; this.NumberLabel.Location = new System.Drawing.Point(472, 238); this.NumberLabel.Name = "NumberLabel"; - this.NumberLabel.Size = new System.Drawing.Size(48, 13); + this.NumberLabel.Size = new System.Drawing.Size(54, 13); this.NumberLabel.TabIndex = 3; - this.NumberLabel.Text = "[number]"; + this.NumberLabel.Text = "999 / 999"; // // NextButton // @@ -81,9 +96,8 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); this.ScreenshotsPictureBox.Name = "ScreenshotsPictureBox"; - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 224); - this.ScreenshotsPictureBox.TabIndex = 0; - this.ScreenshotsPictureBox.TabStop = false; + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 200); + this.ScreenshotsPictureBox.TabIndex = 4; // // Lazy_ScreenshotsPage // @@ -91,6 +105,7 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.GammaTrackBar); this.Controls.Add(this.OpenScreenshotsFolderButton); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.NextButton); @@ -98,6 +113,7 @@ private void InitializeComponent() this.Controls.Add(this.ScreenshotsPictureBox); this.Name = "Lazy_ScreenshotsPage"; this.Size = new System.Drawing.Size(527, 284); + ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -111,4 +127,5 @@ private void InitializeComponent() internal DarkArrowButton NextButton; internal DarkLabel NumberLabel; internal DarkButton OpenScreenshotsFolderButton; + internal System.Windows.Forms.TrackBar GammaTrackBar; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 01a3c544a..9f2e70533 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,13 +7,27 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { + this.GammaTrackBar = new System.Windows.Forms.TrackBar(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); + ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // + // GammaTrackBar + // + this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.GammaTrackBar.AutoSize = false; + this.GammaTrackBar.Location = new System.Drawing.Point(8, 208); + this.GammaTrackBar.Maximum = 40; + this.GammaTrackBar.Size = new System.Drawing.Size(512, 24); + this.GammaTrackBar.TabIndex = 5; + this.GammaTrackBar.TickStyle = System.Windows.Forms.TickStyle.None; + this.GammaTrackBar.Value = 20; + // // OpenScreenshotsFolderButton // this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); @@ -26,7 +40,7 @@ private void InitSlim() this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.NumberLabel.AutoSize = true; this.NumberLabel.Location = new System.Drawing.Point(472, 238); - this.NumberLabel.Size = new System.Drawing.Size(48, 13); + this.NumberLabel.Size = new System.Drawing.Size(54, 13); // // NextButton // @@ -50,9 +64,8 @@ private void InitSlim() | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 224); - this.ScreenshotsPictureBox.TabIndex = 0; - this.ScreenshotsPictureBox.TabStop = false; + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 200); + this.ScreenshotsPictureBox.TabIndex = 4; // // Lazy_ScreenshotsPage // @@ -60,12 +73,14 @@ private void InitSlim() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.GammaTrackBar); this.Controls.Add(this.OpenScreenshotsFolderButton); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.NextButton); this.Controls.Add(this.PrevButton); this.Controls.Add(this.ScreenshotsPictureBox); this.Size = new System.Drawing.Size(527, 284); + ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 3234d5015..d39c1d69c 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -9,6 +9,7 @@ using AL_Common; using AngelLoader.DataClasses; using JetBrains.Annotations; +using static AngelLoader.Global; namespace AngelLoader.Forms.CustomControls; @@ -83,6 +84,7 @@ public override void Construct() _page.NextButton.Click += ScreenshotsNextButton_Click; _page.OpenScreenshotsFolderButton.PaintCustom += OpenScreenshotsFolderButton_PaintCustom; _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; + _page.GammaTrackBar.Scroll += GammaTrackBar_Scroll; FinishConstruct(); } @@ -120,6 +122,13 @@ public override void UpdatePage() } } + public override void Localize() + { + if (!_constructed) return; + + _owner.MainToolTip.SetToolTip(_page.GammaTrackBar, LText.ScreenshotsTab.AdjustGamma); + } + #endregion #region Page @@ -159,6 +168,8 @@ private void DisplayCurrentScreenshot() { _currentScreenshotStream?.Dispose(); _currentScreenshotStream = new MemoryImage(CurrentScreenshotFileName); + // @ScreenshotDisplay: Inefficient because it refreshes, improve this later + SetGamma(); _page.ScreenshotsPictureBox.Image = _currentScreenshotStream.Img; } catch @@ -218,5 +229,13 @@ private void CycleScreenshot(int step) DisplayCurrentScreenshot(); } + private void GammaTrackBar_Scroll(object sender, EventArgs e) => SetGamma(); + + private void SetGamma() + { + TrackBar? tb = _page.GammaTrackBar; + _page.ScreenshotsPictureBox.Gamma = ((tb.Maximum - tb.Value) * (1.0f / (tb.Maximum / 2.0f))).ClampToMin(0.01f); + } + #endregion } diff --git a/AngelLoader/Forms/ImgTestForm.Designer.cs b/AngelLoader/Forms/ImgTestForm.Designer.cs index e918c872f..7401b5e09 100644 --- a/AngelLoader/Forms/ImgTestForm.Designer.cs +++ b/AngelLoader/Forms/ImgTestForm.Designer.cs @@ -39,8 +39,6 @@ private void InitializeComponent() this.ImageBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.ImageBox.Gamma = 1F; - this.ImageBox.Image = null; this.ImageBox.Location = new System.Drawing.Point(8, 8); this.ImageBox.Name = "ImageBox"; this.ImageBox.Size = new System.Drawing.Size(784, 384); diff --git a/AngelLoader/Forms/ImgTestForm.cs b/AngelLoader/Forms/ImgTestForm.cs index af2d1e2fe..38a519a10 100644 --- a/AngelLoader/Forms/ImgTestForm.cs +++ b/AngelLoader/Forms/ImgTestForm.cs @@ -28,7 +28,6 @@ private void GammaTrackBar_Scroll(object sender, System.EventArgs e) { // @ScreenshotDisplay(Gamma slider): The clamp is a hack to prevent 0 which is invalid, polish it up later ImageBox.Gamma = ((GammaTrackBar.Maximum - GammaTrackBar.Value) * 0.10f).ClampToMin(0.01f); - ImageBox.Invalidate(); } private void CopyButton_Click(object sender, System.EventArgs e) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index ce42f5504..d7f16091c 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -1845,7 +1845,7 @@ private void Localize(bool startup) TagsTabPage.Text = LText.TagsTab.TabText; PatchTabPage.Text = LText.PatchTab.TabText; ModsTabPage.Text = LText.ModsTab.TabText; - ScreenshotsTabPage.Text = LText.ScreenshotsTabs.TabText; + ScreenshotsTabPage.Text = LText.ScreenshotsTab.TabText; for (int i = 0; i < _topRightTabs.Length; i++) { diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index dfe02e932..4981623ac 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -487,8 +487,9 @@ TDM_ModsNotSupported=Mod management is not supported for The Dark Mod. ; This is for when the selected FM has an unknown or unsupported game type. Generic_ModsNotSupported=Mod management is not supported for unknown FMs. -[ScreenshotsTabs] +[ScreenshotsTab] TabText=Screenshots +AdjustGamma=Adjust gamma ScreenshotsFolderNotFound=Screenshots folder not found. ScreenshotsFolderOpenError=There was an error trying to open the screenshots folder. From 51429389ec54ada42516c245cfdef25abd376885 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 04:53:01 -0800 Subject: [PATCH 035/200] Screenshot gamma fixes, work, whatever --- .../Forms/CustomControls/ImagePanelCustom.cs | 55 +++++++++---------- .../TopRightPages/ScreenshotsTabPage.cs | 14 ++--- AngelLoader/Forms/ImgTestForm.cs | 11 ++-- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs index 8f3c79848..2c82580af 100644 --- a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs +++ b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs @@ -2,6 +2,7 @@ using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; +using AL_Common; using AngelLoader.DataClasses; using JetBrains.Annotations; @@ -36,44 +37,37 @@ public bool DarkModeEnabled } } + private bool _showingErrorImage; + private readonly ImageAttributes _imageAttributes = new(); + + private Image? _image; private Size _imageSize = Size.Empty; private RectangleF _imageRect = RectangleF.Empty; - private bool _showingErrorImage; private float _gamma = 1.0f; - [PublicAPI] - [Browsable(false)] - [DefaultValue(1.0f)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public float Gamma + + public void SetGamma(float gamma) { - get => _gamma; - set - { - _gamma = value; - Invalidate(); - } + _gamma = gamma.ClampToMin(0.01f); + Invalidate(); } - private Image? _image; - [PublicAPI] - [Browsable(false)] - [DefaultValue(1.0f)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public Image? Image + public void SetImage(Image? image, float? gamma = null) { - get => _image; - set - { - _showingErrorImage = false; - SetImageInternal(value); - } + _showingErrorImage = false; + SetImageInternal(image, gamma); } - private void SetImageInternal(Image? image) + private void SetImageInternal(Image? image, float? gamma = null) { _image = image; + + if (gamma != null) + { + _gamma = (float)gamma; + } + if (_image != null) { _imageSize = _image.Size; @@ -135,11 +129,16 @@ private void DrawImageOnGraphics(Graphics g, Image image) ); } - public Bitmap GetFinalBitmap() + /// + /// Returns a new bitmap with all effects applied (an exact visual copy) of the displayed image, or + /// if there is no image displayed. + /// + /// + public Bitmap? GetSnapshot() { - if (_image == null) + if (_image == null || _showingErrorImage) { - return new Bitmap(0, 0, PixelFormat.Format32bppPArgb); + return null; } Bitmap bmp = new( diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index d39c1d69c..4087137f6 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -145,7 +145,7 @@ private void SetNumberLabelText(string text) private void ClearCurrentScreenshot() { - _page.ScreenshotsPictureBox.Image = null; + _page.ScreenshotsPictureBox.SetImage(null); _currentScreenshotStream?.Dispose(); } @@ -168,9 +168,7 @@ private void DisplayCurrentScreenshot() { _currentScreenshotStream?.Dispose(); _currentScreenshotStream = new MemoryImage(CurrentScreenshotFileName); - // @ScreenshotDisplay: Inefficient because it refreshes, improve this later - SetGamma(); - _page.ScreenshotsPictureBox.Image = _currentScreenshotStream.Img; + _page.ScreenshotsPictureBox.SetImage(_currentScreenshotStream.Img, GetGamma()); } catch { @@ -229,12 +227,12 @@ private void CycleScreenshot(int step) DisplayCurrentScreenshot(); } - private void GammaTrackBar_Scroll(object sender, EventArgs e) => SetGamma(); + private void GammaTrackBar_Scroll(object sender, EventArgs e) => _page.ScreenshotsPictureBox.SetGamma(GetGamma()); - private void SetGamma() + private float GetGamma() { - TrackBar? tb = _page.GammaTrackBar; - _page.ScreenshotsPictureBox.Gamma = ((tb.Maximum - tb.Value) * (1.0f / (tb.Maximum / 2.0f))).ClampToMin(0.01f); + TrackBar tb = _page.GammaTrackBar; + return (tb.Maximum - tb.Value) * (1.0f / (tb.Maximum / 2.0f)); } #endregion diff --git a/AngelLoader/Forms/ImgTestForm.cs b/AngelLoader/Forms/ImgTestForm.cs index 38a519a10..6568a3454 100644 --- a/AngelLoader/Forms/ImgTestForm.cs +++ b/AngelLoader/Forms/ImgTestForm.cs @@ -19,7 +19,7 @@ public sealed partial class ImgTestForm : Form public ImgTestForm() { InitializeComponent(); - ImageBox.Image = _currentScreenshotStream.Img; + ImageBox.SetImage(_currentScreenshotStream.Img); } private readonly MemoryImage _currentScreenshotStream = new(@"C:\Thief Games\Thief2-ND-T2Fix\FMs\Calendras_Legacy_v1a\screenshots\dump000.png"); @@ -27,12 +27,15 @@ public ImgTestForm() private void GammaTrackBar_Scroll(object sender, System.EventArgs e) { // @ScreenshotDisplay(Gamma slider): The clamp is a hack to prevent 0 which is invalid, polish it up later - ImageBox.Gamma = ((GammaTrackBar.Maximum - GammaTrackBar.Value) * 0.10f).ClampToMin(0.01f); + ImageBox.SetGamma(((GammaTrackBar.Maximum - GammaTrackBar.Value) * 0.10f).ClampToMin(0.01f)); } private void CopyButton_Click(object sender, System.EventArgs e) { - using Bitmap bmp = ImageBox.GetFinalBitmap(); - Clipboard.SetImage(bmp); + using Bitmap? bmp = ImageBox.GetSnapshot(); + if (bmp != null) + { + Clipboard.SetImage(bmp); + } } } From 2d6380fc2d51e6756fa60c6c85433b7ba40188b9 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 04:57:22 -0800 Subject: [PATCH 036/200] Remove test stuff --- .../Forms/CustomControls/DarkPictureBox.cs | 31 ----- .../TopRightPages/ScreenshotsTabPage.cs | 9 ++ AngelLoader/Forms/ImgTestForm.Designer.cs | 90 ------------- AngelLoader/Forms/ImgTestForm.cs | 41 ------ AngelLoader/Forms/ImgTestForm.resx | 120 ------------------ AngelLoader/Forms/MainForm.cs | 3 - 6 files changed, 9 insertions(+), 285 deletions(-) delete mode 100644 AngelLoader/Forms/CustomControls/DarkPictureBox.cs delete mode 100644 AngelLoader/Forms/ImgTestForm.Designer.cs delete mode 100644 AngelLoader/Forms/ImgTestForm.cs delete mode 100644 AngelLoader/Forms/ImgTestForm.resx diff --git a/AngelLoader/Forms/CustomControls/DarkPictureBox.cs b/AngelLoader/Forms/CustomControls/DarkPictureBox.cs deleted file mode 100644 index bdffe4763..000000000 --- a/AngelLoader/Forms/CustomControls/DarkPictureBox.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.ComponentModel; -using System.Drawing; -using System.Windows.Forms; -using AngelLoader.DataClasses; -using JetBrains.Annotations; - -namespace AngelLoader.Forms.CustomControls; - -public sealed class DarkPictureBox : PictureBox, IDarkable -{ - [PublicAPI] - public Color DrawnBackColor = SystemColors.Control; - - [PublicAPI] - public Color DarkModeDrawnBackColor = DarkColors.Fen_ControlBackground; - - private bool _darkModeEnabled; - [PublicAPI] - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public bool DarkModeEnabled - { - get => _darkModeEnabled; - set - { - if (_darkModeEnabled == value) return; - _darkModeEnabled = value; - BackColor = _darkModeEnabled ? DarkModeDrawnBackColor : DrawnBackColor; - } - } -} diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 4087137f6..60b6da440 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -235,5 +235,14 @@ private float GetGamma() return (tb.Maximum - tb.Value) * (1.0f / (tb.Maximum / 2.0f)); } + /* + @ScreenshotDisplay: Copy-paste code should be like this + using Bitmap? bmp = ImageBox.GetSnapshot(); + if (bmp != null) + { + Clipboard.SetImage(bmp); + } + */ + #endregion } diff --git a/AngelLoader/Forms/ImgTestForm.Designer.cs b/AngelLoader/Forms/ImgTestForm.Designer.cs deleted file mode 100644 index 7401b5e09..000000000 --- a/AngelLoader/Forms/ImgTestForm.Designer.cs +++ /dev/null @@ -1,90 +0,0 @@ -namespace AngelLoader.Forms; - -sealed partial class ImgTestForm -{ - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.ImageBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); - this.GammaTrackBar = new System.Windows.Forms.TrackBar(); - this.CopyButton = new AngelLoader.Forms.CustomControls.DarkButton(); - ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); - this.SuspendLayout(); - // - // ImageBox - // - this.ImageBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.ImageBox.Location = new System.Drawing.Point(8, 8); - this.ImageBox.Name = "ImageBox"; - this.ImageBox.Size = new System.Drawing.Size(784, 384); - this.ImageBox.TabIndex = 0; - // - // GammaTrackBar - // - this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.GammaTrackBar.Location = new System.Drawing.Point(16, 400); - this.GammaTrackBar.Maximum = 20; - this.GammaTrackBar.Name = "GammaTrackBar"; - this.GammaTrackBar.Size = new System.Drawing.Size(784, 45); - this.GammaTrackBar.TabIndex = 0; - this.GammaTrackBar.Value = 10; - this.GammaTrackBar.Scroll += new System.EventHandler(this.GammaTrackBar_Scroll); - // - // CopyButton - // - this.CopyButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom; - this.CopyButton.Location = new System.Drawing.Point(336, 464); - this.CopyButton.Name = "CopyButton"; - this.CopyButton.Size = new System.Drawing.Size(144, 24); - this.CopyButton.TabIndex = 1; - this.CopyButton.Text = "Copy to clipboard"; - this.CopyButton.Click += new System.EventHandler(this.CopyButton_Click); - // - // ImgTestForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(800, 522); - this.Controls.Add(this.CopyButton); - this.Controls.Add(this.GammaTrackBar); - this.Controls.Add(this.ImageBox); - this.Name = "ImgTestForm"; - this.Text = "ImgTestForm"; - ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private CustomControls.ImagePanelCustom ImageBox; - private System.Windows.Forms.TrackBar GammaTrackBar; - private CustomControls.DarkButton CopyButton; -} \ No newline at end of file diff --git a/AngelLoader/Forms/ImgTestForm.cs b/AngelLoader/Forms/ImgTestForm.cs deleted file mode 100644 index 6568a3454..000000000 --- a/AngelLoader/Forms/ImgTestForm.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* -@ScreenshotDisplay: This form is a test, remove it later and bring this into the actual screenshot display UI area - -@ScreenshotDisplay(Custom image box notes): --This is slower to draw than PictureBox, but it's faster/trivial to change the gamma. With the PictureBox, we'd - have to draw the bitmap onto another bitmap with the gamma adjust, then set the PictureBox.Image property again, - with a full load time and all. -*/ - -using System.Drawing; -using System.Windows.Forms; -using AL_Common; -using static AngelLoader.Forms.CustomControls.ScreenshotsTabPage; - -namespace AngelLoader.Forms; - -public sealed partial class ImgTestForm : Form -{ - public ImgTestForm() - { - InitializeComponent(); - ImageBox.SetImage(_currentScreenshotStream.Img); - } - - private readonly MemoryImage _currentScreenshotStream = new(@"C:\Thief Games\Thief2-ND-T2Fix\FMs\Calendras_Legacy_v1a\screenshots\dump000.png"); - - private void GammaTrackBar_Scroll(object sender, System.EventArgs e) - { - // @ScreenshotDisplay(Gamma slider): The clamp is a hack to prevent 0 which is invalid, polish it up later - ImageBox.SetGamma(((GammaTrackBar.Maximum - GammaTrackBar.Value) * 0.10f).ClampToMin(0.01f)); - } - - private void CopyButton_Click(object sender, System.EventArgs e) - { - using Bitmap? bmp = ImageBox.GetSnapshot(); - if (bmp != null) - { - Clipboard.SetImage(bmp); - } - } -} diff --git a/AngelLoader/Forms/ImgTestForm.resx b/AngelLoader/Forms/ImgTestForm.resx deleted file mode 100644 index 1af7de150..000000000 --- a/AngelLoader/Forms/ImgTestForm.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index d7f16091c..4859fc001 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -252,11 +252,8 @@ private void Test2Button_Click(object sender, EventArgs e) Height = 872; } - // @ScreenshotDisplay: Remove test code private void Test3Button_Click(object sender, EventArgs e) { - using var f = new ImgTestForm(); - f.ShowDialog(this); } private void Test4Button_Click(object sender, EventArgs e) From 91c1ab16d75864e662b73d144f02530ebcff7faa Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 07:36:43 -0800 Subject: [PATCH 037/200] Fix position of image --- AngelLoader/Forms/CustomControls/ImagePanelCustom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs index 2c82580af..d27f1ad72 100644 --- a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs +++ b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs @@ -109,7 +109,7 @@ protected override void OnPaint(PaintEventArgs e) } else { - Images.FitRectInBounds(e.Graphics, _imageRect, Bounds); + Images.FitRectInBounds(e.Graphics, _imageRect, ClientRectangle); _imageAttributes.SetGamma(_gamma, ColorAdjustType.Bitmap); DrawImageOnGraphics(e.Graphics, _image); } From 096db6a6324a604ff06f5aa2acdd6f27eff3996e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 08:29:36 -0800 Subject: [PATCH 038/200] Gamma bar now goes 0-100 --- .../TopRightPages/Lazy_ScreenshotsPage.Designer.cs | 4 ++-- .../TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index d814f6ba2..a363f40c4 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -46,12 +46,12 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.GammaTrackBar.AutoSize = false; this.GammaTrackBar.Location = new System.Drawing.Point(8, 208); - this.GammaTrackBar.Maximum = 40; + this.GammaTrackBar.Maximum = 100; this.GammaTrackBar.Name = "GammaTrackBar"; this.GammaTrackBar.Size = new System.Drawing.Size(512, 24); this.GammaTrackBar.TabIndex = 5; this.GammaTrackBar.TickStyle = System.Windows.Forms.TickStyle.None; - this.GammaTrackBar.Value = 20; + this.GammaTrackBar.Value = 50; // // OpenScreenshotsFolderButton // diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 9f2e70533..e6db6f2e9 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -22,11 +22,11 @@ private void InitSlim() | System.Windows.Forms.AnchorStyles.Right))); this.GammaTrackBar.AutoSize = false; this.GammaTrackBar.Location = new System.Drawing.Point(8, 208); - this.GammaTrackBar.Maximum = 40; + this.GammaTrackBar.Maximum = 100; this.GammaTrackBar.Size = new System.Drawing.Size(512, 24); this.GammaTrackBar.TabIndex = 5; this.GammaTrackBar.TickStyle = System.Windows.Forms.TickStyle.None; - this.GammaTrackBar.Value = 20; + this.GammaTrackBar.Value = 50; // // OpenScreenshotsFolderButton // From a36432c3b4e1d9d9d90c476c3546ec5805c58730 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 08:42:03 -0800 Subject: [PATCH 039/200] Middle-click to reset gamma slider --- .../CustomControls/TopRightPages/ScreenshotsTabPage.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 60b6da440..f7d4b4c99 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -85,6 +85,7 @@ public override void Construct() _page.OpenScreenshotsFolderButton.PaintCustom += OpenScreenshotsFolderButton_PaintCustom; _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; _page.GammaTrackBar.Scroll += GammaTrackBar_Scroll; + _page.GammaTrackBar.MouseDown += GammaTrackBar_MouseDown; FinishConstruct(); } @@ -235,6 +236,15 @@ private float GetGamma() return (tb.Maximum - tb.Value) * (1.0f / (tb.Maximum / 2.0f)); } + private void GammaTrackBar_MouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Middle) + { + _page.GammaTrackBar.Value = 50; + _page.ScreenshotsPictureBox.SetGamma(1.0f); + } + } + /* @ScreenshotDisplay: Copy-paste code should be like this using Bitmap? bmp = ImageBox.GetSnapshot(); From d7bc9028c1b3406a9c548f2921d62f00651e825d Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 08:51:25 -0800 Subject: [PATCH 040/200] Round gamma float --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index f7d4b4c99..f976530ca 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -233,7 +233,9 @@ private void CycleScreenshot(int step) private float GetGamma() { TrackBar tb = _page.GammaTrackBar; - return (tb.Maximum - tb.Value) * (1.0f / (tb.Maximum / 2.0f)); + float ret = (tb.Maximum - tb.Value) * (1.0f / (tb.Maximum / 2.0f)); + ret = (float)Math.Round(ret, 2, MidpointRounding.AwayFromZero); + return ret; } private void GammaTrackBar_MouseDown(object sender, MouseEventArgs e) From 5f2ab1a09f8695c51da9daccaf260d354f8f1554 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 08:58:34 -0800 Subject: [PATCH 041/200] Add gamma reset button --- .../Lazy_ScreenshotsPage.Designer.cs | 14 +++++++++++++- .../TopRightPages/Lazy_ScreenshotsPage.cs | 15 ++++++++++++++- .../Lazy_ScreenshotsPage_InitSlim.Generated.cs | 12 +++++++++++- .../TopRightPages/ScreenshotsTabPage.cs | 12 ++++++++++-- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index a363f40c4..2dad0464f 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -32,6 +32,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.GammaTrackBar = new System.Windows.Forms.TrackBar(); + this.GammaResetButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); @@ -48,11 +49,20 @@ private void InitializeComponent() this.GammaTrackBar.Location = new System.Drawing.Point(8, 208); this.GammaTrackBar.Maximum = 100; this.GammaTrackBar.Name = "GammaTrackBar"; - this.GammaTrackBar.Size = new System.Drawing.Size(512, 24); + this.GammaTrackBar.Size = new System.Drawing.Size(488, 24); this.GammaTrackBar.TabIndex = 5; this.GammaTrackBar.TickStyle = System.Windows.Forms.TickStyle.None; this.GammaTrackBar.Value = 50; // + // GammaResetButton + // + this.GammaResetButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.GammaResetButton.Location = new System.Drawing.Point(496, 208); + this.GammaResetButton.Name = "GammaResetButton"; + this.GammaResetButton.Size = new System.Drawing.Size(24, 23); + this.GammaResetButton.TabIndex = 0; + this.GammaResetButton.PaintCustom += new System.EventHandler(this.GammaResetButton_PaintCustom); + // // OpenScreenshotsFolderButton // this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); @@ -105,6 +115,7 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.GammaResetButton); this.Controls.Add(this.GammaTrackBar); this.Controls.Add(this.OpenScreenshotsFolderButton); this.Controls.Add(this.NumberLabel); @@ -128,4 +139,5 @@ private void InitializeComponent() internal DarkLabel NumberLabel; internal DarkButton OpenScreenshotsFolderButton; internal System.Windows.Forms.TrackBar GammaTrackBar; + internal DarkButton GammaResetButton; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs index 6b1854213..d41e8c99c 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs @@ -1,4 +1,5 @@ -using System.Windows.Forms; +using System.Drawing; +using System.Windows.Forms; namespace AngelLoader.Forms.CustomControls; @@ -12,4 +13,16 @@ public Lazy_ScreenshotsPage() InitSlim(); #endif } + + private void GammaResetButton_PaintCustom(object sender, PaintEventArgs e) + { + Rectangle cr = ((DarkButton)sender).ClientRectangle; + Images.PaintBitmapButton(e, + Images.Refresh, + scaledRect: new RectangleF( + cr.X + 2f, + cr.Y + 2f, + cr.Width - 4f, + cr.Height - 4f)); + } } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index e6db6f2e9..6ea99eb44 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -8,6 +8,7 @@ public sealed partial class Lazy_ScreenshotsPage private void InitSlim() { this.GammaTrackBar = new System.Windows.Forms.TrackBar(); + this.GammaResetButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); @@ -23,11 +24,19 @@ private void InitSlim() this.GammaTrackBar.AutoSize = false; this.GammaTrackBar.Location = new System.Drawing.Point(8, 208); this.GammaTrackBar.Maximum = 100; - this.GammaTrackBar.Size = new System.Drawing.Size(512, 24); + this.GammaTrackBar.Size = new System.Drawing.Size(488, 24); this.GammaTrackBar.TabIndex = 5; this.GammaTrackBar.TickStyle = System.Windows.Forms.TickStyle.None; this.GammaTrackBar.Value = 50; // + // GammaResetButton + // + this.GammaResetButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.GammaResetButton.Location = new System.Drawing.Point(496, 208); + this.GammaResetButton.Size = new System.Drawing.Size(24, 23); + this.GammaResetButton.TabIndex = 0; + this.GammaResetButton.PaintCustom += new System.EventHandler(this.GammaResetButton_PaintCustom); + // // OpenScreenshotsFolderButton // this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); @@ -73,6 +82,7 @@ private void InitSlim() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.GammaResetButton); this.Controls.Add(this.GammaTrackBar); this.Controls.Add(this.OpenScreenshotsFolderButton); this.Controls.Add(this.NumberLabel); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index f976530ca..2b1c50510 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -86,6 +86,7 @@ public override void Construct() _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; _page.GammaTrackBar.Scroll += GammaTrackBar_Scroll; _page.GammaTrackBar.MouseDown += GammaTrackBar_MouseDown; + _page.GammaResetButton.Click += GammaResetButton_Click; FinishConstruct(); } @@ -242,11 +243,18 @@ private void GammaTrackBar_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Middle) { - _page.GammaTrackBar.Value = 50; - _page.ScreenshotsPictureBox.SetGamma(1.0f); + ResetGammaSlider(); } } + private void GammaResetButton_Click(object sender, EventArgs e) => ResetGammaSlider(); + + private void ResetGammaSlider() + { + _page.GammaTrackBar.Value = 50; + _page.ScreenshotsPictureBox.SetGamma(1.0f); + } + /* @ScreenshotDisplay: Copy-paste code should be like this using Bitmap? bmp = ImageBox.GetSnapshot(); From 051ab33161866061faf27fd36da274333598ec01 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 09:03:23 -0800 Subject: [PATCH 042/200] DarkTrackBar - fix backcolor --- .../Forms/CustomControls/DarkTrackBar.cs | 31 +++++++++++++++++++ .../Lazy_ScreenshotsPage.Designer.cs | 4 +-- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 2 +- 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 AngelLoader/Forms/CustomControls/DarkTrackBar.cs diff --git a/AngelLoader/Forms/CustomControls/DarkTrackBar.cs b/AngelLoader/Forms/CustomControls/DarkTrackBar.cs new file mode 100644 index 000000000..5b82ec403 --- /dev/null +++ b/AngelLoader/Forms/CustomControls/DarkTrackBar.cs @@ -0,0 +1,31 @@ +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using AngelLoader.DataClasses; +using JetBrains.Annotations; + +namespace AngelLoader.Forms.CustomControls; + +public sealed class DarkTrackBar : TrackBar, IDarkable +{ + [PublicAPI] + public Color DrawnBackColor = SystemColors.Control; + + [PublicAPI] + public Color DarkModeDrawnBackColor = DarkColors.Fen_ControlBackground; + + private bool _darkModeEnabled; + [PublicAPI] + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool DarkModeEnabled + { + get => _darkModeEnabled; + set + { + if (_darkModeEnabled == value) return; + _darkModeEnabled = value; + BackColor = _darkModeEnabled ? DarkModeDrawnBackColor : DrawnBackColor; + } + } +} diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 2dad0464f..dd5fb7ea1 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,7 +31,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.GammaTrackBar = new System.Windows.Forms.TrackBar(); + this.GammaTrackBar = new DarkTrackBar(); this.GammaResetButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -138,6 +138,6 @@ private void InitializeComponent() internal DarkArrowButton NextButton; internal DarkLabel NumberLabel; internal DarkButton OpenScreenshotsFolderButton; - internal System.Windows.Forms.TrackBar GammaTrackBar; + internal DarkTrackBar GammaTrackBar; internal DarkButton GammaResetButton; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 6ea99eb44..f9fb4f236 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,7 +7,7 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { - this.GammaTrackBar = new System.Windows.Forms.TrackBar(); + this.GammaTrackBar = new DarkTrackBar(); this.GammaResetButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); From 3ec8b32b86e20f44439f54bf4a9486080a3fd9cb Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 10:56:43 -0800 Subject: [PATCH 043/200] Screenshots work: -Display ticks on slider -Remove reset button and add "right click to reset" tooltip -Slider is now dark themed -Typos --- AngelLoader/Common/DataClasses/DarkColors.cs | 2 +- .../Common/DataClasses/LocalizationData.cs | 2 +- .../Lazy_ScreenshotsPage.Designer.cs | 26 ++---- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 24 ++--- .../TopRightPages/ScreenshotsTabPage.cs | 5 +- .../Forms/WinFormsNative/Win32ThemeHooks.cs | 93 ++++++++++++++++++- .../Forms/WinFormsNative/WinFormsNative.cs | 65 +++++++++++++ AngelLoader/Languages/English.ini | 2 +- 8 files changed, 171 insertions(+), 48 deletions(-) diff --git a/AngelLoader/Common/DataClasses/DarkColors.cs b/AngelLoader/Common/DataClasses/DarkColors.cs index c148418e5..88b797a73 100644 --- a/AngelLoader/Common/DataClasses/DarkColors.cs +++ b/AngelLoader/Common/DataClasses/DarkColors.cs @@ -96,7 +96,7 @@ public static class DarkColors //public static readonly Pen DarkBlueBackgroundPen = new Pen(DarkBlueBackground); public static readonly Pen DarkBackgroundPen = new Pen(DarkBackground); //public static readonly Pen MediumBackgroundPen = new Pen(MediumBackground); - //public static readonly Pen LightBackgroundPen = new Pen(LightBackground); + public static readonly Pen LightBackgroundPen = new Pen(LightBackground); public static readonly Pen LighterBackgroundPen = new Pen(LighterBackground); //public static readonly Pen LightestBackgroundPen = new Pen(LightestBackground); public static readonly Pen LightBorderPen = new Pen(LightBorder); diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 473846b9e..90addc5ea 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -631,7 +631,7 @@ internal sealed class ScreenshotsTab_Class { // @ScreenshotDisplay: Finalize this text, improve it if necessary etc. internal readonly string TabText = "Screenshots"; - internal readonly string AdjustGamma = "Adjust gamma"; + internal readonly string AdjustGamma = "Adjust gamma. Right-click to reset."; internal readonly string ScreenshotsFolderNotFound = "Screenshots folder not found."; internal readonly string ScreenshotsFolderOpenError = "There was an error trying to open the screenshots folder."; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index dd5fb7ea1..efad5967e 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,8 +31,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.GammaTrackBar = new DarkTrackBar(); - this.GammaResetButton = new AngelLoader.Forms.CustomControls.DarkButton(); + this.GammaTrackBar = new AngelLoader.Forms.CustomControls.DarkTrackBar(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); @@ -46,23 +45,14 @@ private void InitializeComponent() this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.GammaTrackBar.AutoSize = false; - this.GammaTrackBar.Location = new System.Drawing.Point(8, 208); + this.GammaTrackBar.Location = new System.Drawing.Point(8, 223); this.GammaTrackBar.Maximum = 100; this.GammaTrackBar.Name = "GammaTrackBar"; - this.GammaTrackBar.Size = new System.Drawing.Size(488, 24); + this.GammaTrackBar.Size = new System.Drawing.Size(512, 32); this.GammaTrackBar.TabIndex = 5; - this.GammaTrackBar.TickStyle = System.Windows.Forms.TickStyle.None; + this.GammaTrackBar.TickFrequency = 10; this.GammaTrackBar.Value = 50; // - // GammaResetButton - // - this.GammaResetButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.GammaResetButton.Location = new System.Drawing.Point(496, 208); - this.GammaResetButton.Name = "GammaResetButton"; - this.GammaResetButton.Size = new System.Drawing.Size(24, 23); - this.GammaResetButton.TabIndex = 0; - this.GammaResetButton.PaintCustom += new System.EventHandler(this.GammaResetButton_PaintCustom); - // // OpenScreenshotsFolderButton // this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); @@ -75,7 +65,7 @@ private void InitializeComponent() // this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(472, 238); + this.NumberLabel.Location = new System.Drawing.Point(472, 204); this.NumberLabel.Name = "NumberLabel"; this.NumberLabel.Size = new System.Drawing.Size(54, 13); this.NumberLabel.TabIndex = 3; @@ -106,7 +96,7 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); this.ScreenshotsPictureBox.Name = "ScreenshotsPictureBox"; - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 200); + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 4; // // Lazy_ScreenshotsPage @@ -115,10 +105,9 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); - this.Controls.Add(this.GammaResetButton); + this.Controls.Add(this.NumberLabel); this.Controls.Add(this.GammaTrackBar); this.Controls.Add(this.OpenScreenshotsFolderButton); - this.Controls.Add(this.NumberLabel); this.Controls.Add(this.NextButton); this.Controls.Add(this.PrevButton); this.Controls.Add(this.ScreenshotsPictureBox); @@ -139,5 +128,4 @@ private void InitializeComponent() internal DarkLabel NumberLabel; internal DarkButton OpenScreenshotsFolderButton; internal DarkTrackBar GammaTrackBar; - internal DarkButton GammaResetButton; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index f9fb4f236..bcc943f3f 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,8 +7,7 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { - this.GammaTrackBar = new DarkTrackBar(); - this.GammaResetButton = new AngelLoader.Forms.CustomControls.DarkButton(); + this.GammaTrackBar = new AngelLoader.Forms.CustomControls.DarkTrackBar(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); @@ -22,21 +21,13 @@ private void InitSlim() this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.GammaTrackBar.AutoSize = false; - this.GammaTrackBar.Location = new System.Drawing.Point(8, 208); + this.GammaTrackBar.Location = new System.Drawing.Point(8, 223); this.GammaTrackBar.Maximum = 100; - this.GammaTrackBar.Size = new System.Drawing.Size(488, 24); + this.GammaTrackBar.Size = new System.Drawing.Size(512, 32); this.GammaTrackBar.TabIndex = 5; - this.GammaTrackBar.TickStyle = System.Windows.Forms.TickStyle.None; + this.GammaTrackBar.TickFrequency = 10; this.GammaTrackBar.Value = 50; // - // GammaResetButton - // - this.GammaResetButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.GammaResetButton.Location = new System.Drawing.Point(496, 208); - this.GammaResetButton.Size = new System.Drawing.Size(24, 23); - this.GammaResetButton.TabIndex = 0; - this.GammaResetButton.PaintCustom += new System.EventHandler(this.GammaResetButton_PaintCustom); - // // OpenScreenshotsFolderButton // this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); @@ -48,7 +39,7 @@ private void InitSlim() // this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(472, 238); + this.NumberLabel.Location = new System.Drawing.Point(472, 204); this.NumberLabel.Size = new System.Drawing.Size(54, 13); // // NextButton @@ -73,7 +64,7 @@ private void InitSlim() | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 200); + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 4; // // Lazy_ScreenshotsPage @@ -82,10 +73,9 @@ private void InitSlim() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); - this.Controls.Add(this.GammaResetButton); + this.Controls.Add(this.NumberLabel); this.Controls.Add(this.GammaTrackBar); this.Controls.Add(this.OpenScreenshotsFolderButton); - this.Controls.Add(this.NumberLabel); this.Controls.Add(this.NextButton); this.Controls.Add(this.PrevButton); this.Controls.Add(this.ScreenshotsPictureBox); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 2b1c50510..e3b46e852 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -86,7 +86,6 @@ public override void Construct() _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; _page.GammaTrackBar.Scroll += GammaTrackBar_Scroll; _page.GammaTrackBar.MouseDown += GammaTrackBar_MouseDown; - _page.GammaResetButton.Click += GammaResetButton_Click; FinishConstruct(); } @@ -241,14 +240,12 @@ private float GetGamma() private void GammaTrackBar_MouseDown(object sender, MouseEventArgs e) { - if (e.Button == MouseButtons.Middle) + if (e.Button is MouseButtons.Middle or MouseButtons.Right) { ResetGammaSlider(); } } - private void GammaResetButton_Click(object sender, EventArgs e) => ResetGammaSlider(); - private void ResetGammaSlider() { _page.GammaTrackBar.Value = 50; diff --git a/AngelLoader/Forms/WinFormsNative/Win32ThemeHooks.cs b/AngelLoader/Forms/WinFormsNative/Win32ThemeHooks.cs index b36ab3bc0..0aacd7877 100644 --- a/AngelLoader/Forms/WinFormsNative/Win32ThemeHooks.cs +++ b/AngelLoader/Forms/WinFormsNative/Win32ThemeHooks.cs @@ -14,6 +14,7 @@ on GetSysColor(). using System; using System.Collections.Generic; using System.Drawing; +using System.Drawing.Drawing2D; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Windows.Forms; @@ -203,6 +204,10 @@ private static int DrawThemeBackground_Hooked( { succeeded = TabScrollButtons_TryDrawThemeBackground(hdc, iPartId, iStateId, ref pRect); } + else if (hTheme == _hThemes[(int)RenderedControl.Trackbar] && TrackBarEnabled()) + { + succeeded = TrackBar_TryDrawThemeBackground(hdc, iPartId, iStateId, ref pRect); + } } return succeeded @@ -232,6 +237,10 @@ private static int GetThemeColor_Hooked( { succeeded = ToolTip_TryGetThemeColor(iPropId, out pColor); } + else if (hTheme == _hThemes[(int)RenderedControl.Trackbar] && TrackBarEnabled()) + { + succeeded = TrackBar_TryGetThemeColor(iPartId, iStateId, out pColor); + } } return succeeded @@ -412,13 +421,14 @@ internal readonly ref struct OverrideSysColorScope #region Arrays - private const int _renderedControlCount = 4; + private const int _renderedControlCount = 5; private enum RenderedControl { ScrollBar, ToolTip, TreeView, - TabScrollButtons + TabScrollButtons, + Trackbar } private static readonly IntPtr[] _hThemes = new IntPtr[_renderedControlCount]; @@ -428,7 +438,8 @@ private enum RenderedControl "Scrollbar", "ToolTip", "TreeView", - "Spin" + "Spin", + "Trackbar" }; #endregion @@ -457,10 +468,82 @@ internal static void ReloadTheme() #region Control rendering + #region Trackbar + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TrackBarEnabled() => Global.Config.DarkMode; + + private static bool TrackBar_TryGetThemeColor( + int iPartId, + int iStateId, + out int pColor) + { + if (iPartId == Native.TKP_TICS && iStateId == Native.TSS_NORMAL) + { + pColor = ColorTranslator.ToWin32(DarkColors.LightBackground); + return true; + } + else + { + pColor = 0; + return false; + } + } + + private static readonly PointF[] _trackBarThumbBottomPoints = new PointF[4]; + + private static bool TrackBar_TryDrawThemeBackground( + IntPtr hdc, + int iPartId, + int iStateId, + ref Native.RECT pRect) + { + using Graphics g = Graphics.FromHdc(hdc); + + Rectangle rect = pRect.ToRectangle(); + + switch (iPartId) + { + case Native.TKP_TRACK: + g.FillRectangle(DarkColors.DarkBackgroundBrush, rect); + Rectangle borderRect = rect with { Width = rect.Width - 1, Height = rect.Height - 1 }; + g.DrawRectangle(DarkColors.LightBackgroundPen, borderRect); + break; + case Native.TKP_THUMBBOTTOM: + { + Brush brush = iStateId switch + { + Native.TUBS_HOT => DarkColors.BlueHighlightBrush, + Native.TUBS_PRESSED => DarkColors.BlueBackgroundBrush, + Native.TUBS_DISABLED => DarkColors.LightBackgroundBrush, + //Native.TUBS_NORMAL => DarkColors.BlueSelectionBrush, + //Native.TUBS_FOCUSED => DarkColors.BlueSelectionBrush, + _ => DarkColors.BlueSelectionBrush + }; + + Rectangle squarePartRect = rect with { Height = rect.Height - 5 }; + g.FillRectangle(brush, squarePartRect); + + _trackBarThumbBottomPoints[0] = new PointF(rect.X + -0.5f, rect.Y + 13); + _trackBarThumbBottomPoints[1] = new PointF(rect.X + 5, rect.Y + 18.5f); + _trackBarThumbBottomPoints[2] = new PointF(rect.X + 10.5f, rect.Y + 13); + _trackBarThumbBottomPoints[3] = new PointF(rect.X + -0.5f, rect.Y + 13); + + g.SmoothingMode = SmoothingMode.HighQuality; + g.FillPolygon(brush, _trackBarThumbBottomPoints); + break; + } + } + + return true; + } + + #endregion + #region Tab scroll buttons - // This really for all horizontal spinners, as no messages are sent when the tab control's spinner needs to - // be painted, so we can't override just for that... + // This is really for all horizontal spinners, as no messages are sent when the tab control's spinner needs + // to be painted, so we can't override just for that... // It's okay because we don't use them anywhere else, but yeah. [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs b/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs index 75307ed4a..0e950c070 100644 --- a/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs +++ b/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs @@ -550,6 +550,71 @@ internal enum ScrollInfoMask internal const int TMT_FILLCOLOR = 3802; internal const int TMT_TEXTCOLOR = 3803; + #region Trackbar parts + + internal const int TKP_TRACK = 1; + //internal const int TKP_TRACKVERT = 2; + //internal const int TKP_THUMB = 3; + internal const int TKP_THUMBBOTTOM = 4; + //internal const int TKP_THUMBTOP = 5; + //internal const int TKP_THUMBVERT = 6; + //internal const int TKP_THUMBLEFT = 7; + //internal const int TKP_THUMBRIGHT = 8; + internal const int TKP_TICS = 9; + //internal const int TKP_TICSVERT = 10; + +#if false + internal const int TKS_NORMAL = 1; + internal const int TRS_NORMAL = 1; + internal const int TRVS_NORMAL = 1; + + internal const int TUS_NORMAL = 1; + internal const int TUS_HOT = 2; + internal const int TUS_PRESSED = 3; + internal const int TUS_FOCUSED = 4; + internal const int TUS_DISABLED = 5; +#endif + + //internal const int TUBS_NORMAL = 1; + internal const int TUBS_HOT = 2; + internal const int TUBS_PRESSED = 3; + //internal const int TUBS_FOCUSED = 4; + internal const int TUBS_DISABLED = 5; + +#if false + internal const int TUTS_NORMAL = 1; + internal const int TUTS_HOT = 2; + internal const int TUTS_PRESSED = 3; + internal const int TUTS_FOCUSED = 4; + internal const int TUTS_DISABLED = 5; + + internal const int TUVS_NORMAL = 1; + internal const int TUVS_HOT = 2; + internal const int TUVS_PRESSED = 3; + internal const int TUVS_FOCUSED = 4; + internal const int TUVS_DISABLED = 5; + + internal const int TUVLS_NORMAL = 1; + internal const int TUVLS_HOT = 2; + internal const int TUVLS_PRESSED = 3; + internal const int TUVLS_FOCUSED = 4; + internal const int TUVLS_DISABLED = 5; + + internal const int TUVRS_NORMAL = 1; + internal const int TUVRS_HOT = 2; + internal const int TUVRS_PRESSED = 3; + internal const int TUVRS_FOCUSED = 4; + internal const int TUVRS_DISABLED = 5; +#endif + + internal const int TSS_NORMAL = 1; + +#if false + internal const int TSVS_NORMAL = 1; +#endif + + #endregion + #region ToolTip parts internal const int TTP_STANDARD = 1; diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index 4981623ac..2eb7e0872 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -489,7 +489,7 @@ Generic_ModsNotSupported=Mod management is not supported for unknown FMs. [ScreenshotsTab] TabText=Screenshots -AdjustGamma=Adjust gamma +AdjustGamma=Adjust gamma. Right-click to reset. ScreenshotsFolderNotFound=Screenshots folder not found. ScreenshotsFolderOpenError=There was an error trying to open the screenshots folder. From 0a49c6bcd3fe8297011a1acc55215f34eb4ae6d5 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 11:28:22 -0800 Subject: [PATCH 044/200] Add gamma label and localization tweaks --- AngelLoader/Common/DataClasses/LocalizationData.cs | 3 ++- .../TopRightPages/Lazy_ScreenshotsPage.Designer.cs | 13 +++++++++++++ .../Lazy_ScreenshotsPage_InitSlim.Generated.cs | 9 +++++++++ .../TopRightPages/ScreenshotsTabPage.cs | 4 ++-- AngelLoader/Languages/English.ini | 3 ++- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 90addc5ea..ff15e98f5 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -631,7 +631,8 @@ internal sealed class ScreenshotsTab_Class { // @ScreenshotDisplay: Finalize this text, improve it if necessary etc. internal readonly string TabText = "Screenshots"; - internal readonly string AdjustGamma = "Adjust gamma. Right-click to reset."; + internal readonly string Gamma = "Gamma:"; + internal readonly string ResetGammaToolTip = "Right-click to reset"; internal readonly string ScreenshotsFolderNotFound = "Screenshots folder not found."; internal readonly string ScreenshotsFolderOpenError = "There was an error trying to open the screenshots folder."; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index efad5967e..6926baff0 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -37,6 +37,7 @@ private void InitializeComponent() this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); + this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // @@ -99,12 +100,23 @@ private void InitializeComponent() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 4; // + // GammaLabel + // + this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.GammaLabel.AutoSize = true; + this.GammaLabel.Location = new System.Drawing.Point(8, 204); + this.GammaLabel.Name = "GammaLabel"; + this.GammaLabel.Size = new System.Drawing.Size(46, 13); + this.GammaLabel.TabIndex = 6; + this.GammaLabel.Text = "Gamma:"; + // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.GammaTrackBar); this.Controls.Add(this.OpenScreenshotsFolderButton); @@ -128,4 +140,5 @@ private void InitializeComponent() internal DarkLabel NumberLabel; internal DarkButton OpenScreenshotsFolderButton; internal DarkTrackBar GammaTrackBar; + internal DarkLabel GammaLabel; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index bcc943f3f..baf691f7f 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -13,6 +13,7 @@ private void InitSlim() this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); + this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // @@ -67,12 +68,20 @@ private void InitSlim() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 4; // + // GammaLabel + // + this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.GammaLabel.AutoSize = true; + this.GammaLabel.Location = new System.Drawing.Point(8, 204); + this.GammaLabel.Size = new System.Drawing.Size(46, 13); + // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.GammaTrackBar); this.Controls.Add(this.OpenScreenshotsFolderButton); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index e3b46e852..fff742195 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -126,8 +126,8 @@ public override void UpdatePage() public override void Localize() { if (!_constructed) return; - - _owner.MainToolTip.SetToolTip(_page.GammaTrackBar, LText.ScreenshotsTab.AdjustGamma); + _page.GammaLabel.Text = LText.ScreenshotsTab.Gamma; + _owner.MainToolTip.SetToolTip(_page.GammaTrackBar, LText.ScreenshotsTab.ResetGammaToolTip); } #endregion diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index 2eb7e0872..c162ca601 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -489,7 +489,8 @@ Generic_ModsNotSupported=Mod management is not supported for unknown FMs. [ScreenshotsTab] TabText=Screenshots -AdjustGamma=Adjust gamma. Right-click to reset. +Gamma=Gamma: +ResetGammaToolTip=Right-click to reset ScreenshotsFolderNotFound=Screenshots folder not found. ScreenshotsFolderOpenError=There was an error trying to open the screenshots folder. From 26a6628a31efe2e8de40b60c5a3f8cf6ac843a70 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 14:14:31 -0800 Subject: [PATCH 045/200] Disable new controls when needed --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index fff742195..07e6833b4 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -101,11 +101,14 @@ public override void UpdatePage() Core.PopulateScreenshotFileNames(fm, ScreenshotFileNames); + // @ScreenshotDisplay: Should we hide everything and just put a label "No screenshots"? if (ScreenshotFileNames.Count == 0) { CurrentScreenshotFileName = ""; ClearCurrentScreenshot(); + _page.GammaLabel.Enabled = false; _page.ScreenshotsPictureBox.Enabled = false; + _page.GammaTrackBar.Enabled = false; _page.OpenScreenshotsFolderButton.Enabled = false; _page.PrevButton.Enabled = false; _page.NextButton.Enabled = false; @@ -116,7 +119,9 @@ public override void UpdatePage() { CurrentScreenshotFileName = ScreenshotFileNames[0]; DisplayCurrentScreenshot(); + _page.GammaLabel.Enabled = true; _page.ScreenshotsPictureBox.Enabled = true; + _page.GammaTrackBar.Enabled = true; _page.OpenScreenshotsFolderButton.Enabled = true; _page.PrevButton.Enabled = ScreenshotFileNames.Count > 1; _page.NextButton.Enabled = ScreenshotFileNames.Count > 1; From fd3c4db1bdce1e0e539c47327f706429bb970b54 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 15:07:27 -0800 Subject: [PATCH 046/200] Implement image copy functionality --- AngelLoader/Common/DataClasses/DarkColors.cs | 2 + .../Common/DataClasses/LocalizationData.cs | 2 + .../Forms/CustomControls/ImagePanelCustom.cs | 11 ++- .../Lazy_ScreenshotsPage.Designer.cs | 68 +++++++++++-------- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 52 ++++++++------ .../TopRightPages/ScreenshotsTabPage.cs | 68 +++++++++++++++++-- AngelLoader/Forms/MainForm.cs | 49 +++++++------ AngelLoader/Languages/English.ini | 2 + 8 files changed, 177 insertions(+), 77 deletions(-) diff --git a/AngelLoader/Common/DataClasses/DarkColors.cs b/AngelLoader/Common/DataClasses/DarkColors.cs index 88b797a73..0aa895e33 100644 --- a/AngelLoader/Common/DataClasses/DarkColors.cs +++ b/AngelLoader/Common/DataClasses/DarkColors.cs @@ -47,6 +47,8 @@ public static class DarkColors public static readonly Color DGV_RecentHighlightColorLight = Color.LightGoldenrodYellow; public static readonly Color DGV_UnavailableColorLight = Color.MistyRose; + public static readonly Color SuccessGreenDark = Color.FromArgb(68, 178, 68); + #endregion #region DarkUI diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index ff15e98f5..5e1374fe9 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -635,6 +635,8 @@ internal sealed class ScreenshotsTab_Class internal readonly string ResetGammaToolTip = "Right-click to reset"; internal readonly string ScreenshotsFolderNotFound = "Screenshots folder not found."; internal readonly string ScreenshotsFolderOpenError = "There was an error trying to open the screenshots folder."; + internal readonly string ImageCopied = "Image copied"; + internal readonly string ImageCopyFailed = "Image copy failed"; } internal sealed class ReadmeArea_Class diff --git a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs index d27f1ad72..f190af88c 100644 --- a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs +++ b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System; +using System.ComponentModel; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; @@ -93,6 +94,14 @@ public ImagePanelCustom() DoubleBuffered = true; } + protected override void OnClick(EventArgs e) + { + // Force focus on click so we can allow Ctrl+C to copy the image only when the image is focused. + // Clicks don't normally focus panel-type controls so we need this. + Focus(); + base.OnClick(e); + } + protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 6926baff0..4af6d154f 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,16 +31,48 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); + this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); + this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaTrackBar = new AngelLoader.Forms.CustomControls.DarkTrackBar(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); - this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); - this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // + // CopiedMessageLabel + // + this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; + this.CopiedMessageLabel.AutoSize = true; + this.CopiedMessageLabel.Location = new System.Drawing.Point(240, 204); + this.CopiedMessageLabel.Name = "CopiedMessageLabel"; + this.CopiedMessageLabel.Size = new System.Drawing.Size(46, 13); + this.CopiedMessageLabel.TabIndex = 2; + this.CopiedMessageLabel.Text = "[Copied]"; + this.CopiedMessageLabel.Visible = false; + // + // GammaLabel + // + this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.GammaLabel.AutoSize = true; + this.GammaLabel.Location = new System.Drawing.Point(8, 204); + this.GammaLabel.Name = "GammaLabel"; + this.GammaLabel.Size = new System.Drawing.Size(46, 13); + this.GammaLabel.TabIndex = 1; + this.GammaLabel.Text = "Gamma:"; + // + // NumberLabel + // + this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.NumberLabel.AutoSize = true; + this.NumberLabel.Location = new System.Drawing.Point(472, 204); + this.NumberLabel.Name = "NumberLabel"; + this.NumberLabel.Size = new System.Drawing.Size(54, 13); + this.NumberLabel.TabIndex = 3; + this.NumberLabel.Text = "999 / 999"; + // // GammaTrackBar // this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) @@ -50,7 +82,7 @@ private void InitializeComponent() this.GammaTrackBar.Maximum = 100; this.GammaTrackBar.Name = "GammaTrackBar"; this.GammaTrackBar.Size = new System.Drawing.Size(512, 32); - this.GammaTrackBar.TabIndex = 5; + this.GammaTrackBar.TabIndex = 4; this.GammaTrackBar.TickFrequency = 10; this.GammaTrackBar.Value = 50; // @@ -60,17 +92,7 @@ private void InitializeComponent() this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); this.OpenScreenshotsFolderButton.Name = "OpenScreenshotsFolderButton"; this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); - this.OpenScreenshotsFolderButton.TabIndex = 0; - // - // NumberLabel - // - this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(472, 204); - this.NumberLabel.Name = "NumberLabel"; - this.NumberLabel.Size = new System.Drawing.Size(54, 13); - this.NumberLabel.TabIndex = 3; - this.NumberLabel.Text = "999 / 999"; + this.OpenScreenshotsFolderButton.TabIndex = 5; // // NextButton // @@ -79,7 +101,7 @@ private void InitializeComponent() this.NextButton.Location = new System.Drawing.Point(446, 256); this.NextButton.Name = "NextButton"; this.NextButton.Size = new System.Drawing.Size(75, 23); - this.NextButton.TabIndex = 2; + this.NextButton.TabIndex = 7; // // PrevButton // @@ -88,7 +110,7 @@ private void InitializeComponent() this.PrevButton.Location = new System.Drawing.Point(371, 256); this.PrevButton.Name = "PrevButton"; this.PrevButton.Size = new System.Drawing.Size(75, 23); - this.PrevButton.TabIndex = 1; + this.PrevButton.TabIndex = 6; // // ScreenshotsPictureBox // @@ -98,17 +120,7 @@ private void InitializeComponent() this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); this.ScreenshotsPictureBox.Name = "ScreenshotsPictureBox"; this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); - this.ScreenshotsPictureBox.TabIndex = 4; - // - // GammaLabel - // - this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.GammaLabel.AutoSize = true; - this.GammaLabel.Location = new System.Drawing.Point(8, 204); - this.GammaLabel.Name = "GammaLabel"; - this.GammaLabel.Size = new System.Drawing.Size(46, 13); - this.GammaLabel.TabIndex = 6; - this.GammaLabel.Text = "Gamma:"; + this.ScreenshotsPictureBox.TabIndex = 0; // // Lazy_ScreenshotsPage // @@ -116,6 +128,7 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.GammaTrackBar); @@ -141,4 +154,5 @@ private void InitializeComponent() internal DarkButton OpenScreenshotsFolderButton; internal DarkTrackBar GammaTrackBar; internal DarkLabel GammaLabel; + internal DarkLabel CopiedMessageLabel; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index baf691f7f..7819665db 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,16 +7,39 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { + this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); + this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); + this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaTrackBar = new AngelLoader.Forms.CustomControls.DarkTrackBar(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); - this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); - this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // + // CopiedMessageLabel + // + this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; + this.CopiedMessageLabel.AutoSize = true; + this.CopiedMessageLabel.Location = new System.Drawing.Point(240, 204); + this.CopiedMessageLabel.Size = new System.Drawing.Size(46, 13); + this.CopiedMessageLabel.Visible = false; + // + // GammaLabel + // + this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.GammaLabel.AutoSize = true; + this.GammaLabel.Location = new System.Drawing.Point(8, 204); + this.GammaLabel.Size = new System.Drawing.Size(46, 13); + // + // NumberLabel + // + this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.NumberLabel.AutoSize = true; + this.NumberLabel.Location = new System.Drawing.Point(472, 204); + this.NumberLabel.Size = new System.Drawing.Size(54, 13); + // // GammaTrackBar // this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) @@ -25,7 +48,7 @@ private void InitSlim() this.GammaTrackBar.Location = new System.Drawing.Point(8, 223); this.GammaTrackBar.Maximum = 100; this.GammaTrackBar.Size = new System.Drawing.Size(512, 32); - this.GammaTrackBar.TabIndex = 5; + this.GammaTrackBar.TabIndex = 4; this.GammaTrackBar.TickFrequency = 10; this.GammaTrackBar.Value = 50; // @@ -34,14 +57,7 @@ private void InitSlim() this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); - this.OpenScreenshotsFolderButton.TabIndex = 0; - // - // NumberLabel - // - this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(472, 204); - this.NumberLabel.Size = new System.Drawing.Size(54, 13); + this.OpenScreenshotsFolderButton.TabIndex = 5; // // NextButton // @@ -49,7 +65,7 @@ private void InitSlim() this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; this.NextButton.Location = new System.Drawing.Point(446, 256); this.NextButton.Size = new System.Drawing.Size(75, 23); - this.NextButton.TabIndex = 2; + this.NextButton.TabIndex = 7; // // PrevButton // @@ -57,7 +73,7 @@ private void InitSlim() this.PrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; this.PrevButton.Location = new System.Drawing.Point(371, 256); this.PrevButton.Size = new System.Drawing.Size(75, 23); - this.PrevButton.TabIndex = 1; + this.PrevButton.TabIndex = 6; // // ScreenshotsPictureBox // @@ -66,14 +82,7 @@ private void InitSlim() | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); - this.ScreenshotsPictureBox.TabIndex = 4; - // - // GammaLabel - // - this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.GammaLabel.AutoSize = true; - this.GammaLabel.Location = new System.Drawing.Point(8, 204); - this.GammaLabel.Size = new System.Drawing.Size(46, 13); + this.ScreenshotsPictureBox.TabIndex = 0; // // Lazy_ScreenshotsPage // @@ -81,6 +90,7 @@ private void InitSlim() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.GammaTrackBar); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 07e6833b4..b69cd9fff 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -24,7 +24,7 @@ public sealed class ScreenshotsTabPage : Lazy_TabsBase mean we carry around the full file bytes in memory as well as the displayed image, but since we're only displaying one at a time and they'll probably be a few megs at most, it's not a big deal. */ - public sealed class MemoryImage : IDisposable + private sealed class MemoryImage : IDisposable { private readonly MemoryStream _memoryStream; public readonly Image Img; @@ -49,6 +49,8 @@ public void Dispose() private readonly List ScreenshotFileNames = new(); private string CurrentScreenshotFileName = ""; private MemoryImage? _currentScreenshotStream; + private readonly Timer CopiedMessageFadeoutTimer = new(); + #region Theme [PublicAPI] @@ -80,6 +82,9 @@ public override void Construct() { Controls.Add(_page); + CopiedMessageFadeoutTimer.Interval = 5000; + CopiedMessageFadeoutTimer.Tick += CopiedMessageFadeoutTimer_Tick; + _page.PrevButton.Click += ScreenshotsPrevButton_Click; _page.NextButton.Click += ScreenshotsNextButton_Click; _page.OpenScreenshotsFolderButton.PaintCustom += OpenScreenshotsFolderButton_PaintCustom; @@ -257,14 +262,63 @@ private void ResetGammaSlider() _page.ScreenshotsPictureBox.SetGamma(1.0f); } - /* - @ScreenshotDisplay: Copy-paste code should be like this - using Bitmap? bmp = ImageBox.GetSnapshot(); - if (bmp != null) + private void SetCopiedMessageLabelText(string text, bool success) { - Clipboard.SetImage(bmp); + if (!_constructed) return; + if (CopiedMessageFadeoutTimer.Enabled) return; + + _page.CopiedMessageLabel.ForeColor = success ? Color.Green : Color.DarkRed; + _page.CopiedMessageLabel.DarkModeForeColor = success ? DarkColors.SuccessGreenDark : DarkColors.Fen_CautionText; + + _page.CopiedMessageLabel.Text = text; + _page.CopiedMessageLabel.CenterH(_page); + _page.CopiedMessageLabel.Show(); + CopiedMessageFadeoutTimer.Start(); + } + + private void CopiedMessageFadeoutTimer_Tick(object sender, EventArgs e) + { + if (!_constructed) return; + if (Disposing || _owner.AboutToClose) return; + try + { + _page.CopiedMessageLabel.Hide(); + CopiedMessageFadeoutTimer.Stop(); + } + catch + { + // Just in case it happens during dispose or whatever + } + } + + public void CopyImageToClipboard() + { + if (!_constructed) return; + + using Bitmap? bmp = _page.ScreenshotsPictureBox.GetSnapshot(); + if (bmp != null) + { + try + { + Clipboard.SetImage(bmp); + SetCopiedMessageLabelText(LText.ScreenshotsTab.ImageCopied, success: true); + } + catch + { + SetCopiedMessageLabelText(LText.ScreenshotsTab.ImageCopyFailed, success: false); + } + } } - */ #endregion + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _currentScreenshotStream?.Dispose(); + CopiedMessageFadeoutTimer.Dispose(); + } + base.Dispose(disposing); + } } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 4859fc001..e65adbf2b 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -504,27 +504,6 @@ Native.WM_MBUTTONDOWN or int wParam = (int)m.WParam; if (wParam == (int)Keys.F1 && CanFocus) { - static bool AnyControlFocusedIn(Control control, int stackCounter = 0) - { - stackCounter++; - if (stackCounter > 100) return false; - - if (control.Focused) return true; - - Control.ControlCollection controls = control.Controls; - int count = controls.Count; - for (int i = 0; i < count; i++) - { - if (AnyControlFocusedIn(controls[i], stackCounter)) return true; - } - - return false; - } - - bool AnyControlFocusedInTabPage(TabPage tabPage) => - (TopRightTabControl.Focused && TopRightTabControl.SelectedTab == tabPage) || - AnyControlFocusedIn(tabPage); - bool mainMenuWasOpen = MainLLMenu.Visible; string section = @@ -1664,6 +1643,13 @@ async Task HandleHomeOrEnd(bool home, bool selectionSyncHack = true) textBox.SelectAll(); } } + else if (e.KeyCode == Keys.C) + { + if (AnyControlFocusedInTabPage(ScreenshotsTabPage)) + { + ScreenshotsTabPage.CopyImageToClipboard(); + } + } else if (e.KeyCode is Keys.Add or Keys.Oemplus) { if ((ReadmeRichTextBox.Focused && !CursorOverControl(FMsDGV)) || CursorOverReadmeArea()) @@ -4882,6 +4868,27 @@ private void ReadmeButtons_Paint(object sender, PaintEventArgs e) #region Helpers & misc + private static bool AnyControlFocusedIn(Control control, int stackCounter = 0) + { + stackCounter++; + if (stackCounter > 100) return false; + + if (control.Focused) return true; + + Control.ControlCollection controls = control.Controls; + int count = controls.Count; + for (int i = 0; i < count; i++) + { + if (AnyControlFocusedIn(controls[i], stackCounter)) return true; + } + + return false; + } + + private bool AnyControlFocusedInTabPage(TabPage tabPage) => + (TopRightTabControl.Focused && TopRightTabControl.SelectedTab == tabPage) || + AnyControlFocusedIn(tabPage); + private Zoom GetReadmeZoomButton(DarkButton button) => (Zoom)(Array.IndexOf(_readmeControlButtons, button) - 1); private static FormWindowState WindowStateToFormWindowState(WindowState windowState) => windowState switch diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index c162ca601..1a7fd03e9 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -493,6 +493,8 @@ Gamma=Gamma: ResetGammaToolTip=Right-click to reset ScreenshotsFolderNotFound=Screenshots folder not found. ScreenshotsFolderOpenError=There was an error trying to open the screenshots folder. +ImageCopied=Image copied +ImageCopyFailed=Image copy failed [ReadmeArea] ViewHTMLReadme=View HTML Readme From 350f04b4ec98e8bfd9022f0cf60a4d0abcdb690e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 15:11:15 -0800 Subject: [PATCH 047/200] Tweak copy message up time --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index b69cd9fff..585b6bf60 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -82,7 +82,7 @@ public override void Construct() { Controls.Add(_page); - CopiedMessageFadeoutTimer.Interval = 5000; + CopiedMessageFadeoutTimer.Interval = 2500; CopiedMessageFadeoutTimer.Tick += CopiedMessageFadeoutTimer_Tick; _page.PrevButton.Click += ScreenshotsPrevButton_Click; From 1000e91b20cc2c2979781f54c6c5911b0bf2de12 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 15:37:48 -0800 Subject: [PATCH 048/200] Save/load gamma --- AngelLoader/Common/DataClasses/ConfigData.cs | 7 +++++ .../Forms/CustomControls/ImagePanelCustom.cs | 6 ++-- .../TopRightPages/ScreenshotsTabPage.cs | 30 +++++-------------- AngelLoader/Ini/ConfigIni.cs | 16 ++++++---- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/AngelLoader/Common/DataClasses/ConfigData.cs b/AngelLoader/Common/DataClasses/ConfigData.cs index f6d41f44e..5e3a88a53 100644 --- a/AngelLoader/Common/DataClasses/ConfigData.cs +++ b/AngelLoader/Common/DataClasses/ConfigData.cs @@ -462,6 +462,13 @@ private static string[] InitWebSearchUrls() internal CheckForUpdates CheckForUpdates = CheckForUpdates.FirstTimeAsk; + private int _screenshotGammaPercent = 50; + internal int ScreenshotGammaPercent + { + get => _screenshotGammaPercent; + set => _screenshotGammaPercent = value.Clamp(0, 100); + } + #if !ReleaseBeta && !ReleasePublic // Quick-n-dirty session-only var for now internal bool ForceWindowed; diff --git a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs index f190af88c..6622caf09 100644 --- a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs +++ b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs @@ -50,10 +50,12 @@ public bool DarkModeEnabled public void SetGamma(float gamma) { - _gamma = gamma.ClampToMin(0.01f); + SetGammaNoRefresh(gamma); Invalidate(); } + private void SetGammaNoRefresh(float gamma) => _gamma = gamma.ClampToMin(0.01f); + public void SetImage(Image? image, float? gamma = null) { _showingErrorImage = false; @@ -66,7 +68,7 @@ private void SetImageInternal(Image? image, float? gamma = null) if (gamma != null) { - _gamma = (float)gamma; + SetGammaNoRefresh((float)gamma); } if (_image != null) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 585b6bf60..8d488ea29 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -2,13 +2,11 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows.Forms; using AL_Common; using AngelLoader.DataClasses; -using JetBrains.Annotations; using static AngelLoader.Global; namespace AngelLoader.Forms.CustomControls; @@ -51,25 +49,6 @@ public void Dispose() private MemoryImage? _currentScreenshotStream; private readonly Timer CopiedMessageFadeoutTimer = new(); - #region Theme - - [PublicAPI] - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public override bool DarkModeEnabled - { - get => base.DarkModeEnabled; - set - { - if (DarkModeEnabled == value) return; - base.DarkModeEnabled = value; - - if (!_constructed) return; - } - } - - #endregion - #region Public common public override void Construct() @@ -82,6 +61,8 @@ public override void Construct() { Controls.Add(_page); + _page.GammaTrackBar.Value = Config.ScreenshotGammaPercent; + CopiedMessageFadeoutTimer.Interval = 2500; CopiedMessageFadeoutTimer.Tick += CopiedMessageFadeoutTimer_Tick; @@ -238,7 +219,11 @@ private void CycleScreenshot(int step) DisplayCurrentScreenshot(); } - private void GammaTrackBar_Scroll(object sender, EventArgs e) => _page.ScreenshotsPictureBox.SetGamma(GetGamma()); + private void GammaTrackBar_Scroll(object sender, EventArgs e) + { + Config.ScreenshotGammaPercent = _page.GammaTrackBar.Value; + _page.ScreenshotsPictureBox.SetGamma(GetGamma()); + } private float GetGamma() { @@ -259,6 +244,7 @@ private void GammaTrackBar_MouseDown(object sender, MouseEventArgs e) private void ResetGammaSlider() { _page.GammaTrackBar.Value = 50; + Config.ScreenshotGammaPercent = 50; _page.ScreenshotsPictureBox.SetGamma(1.0f); } diff --git a/AngelLoader/Ini/ConfigIni.cs b/AngelLoader/Ini/ConfigIni.cs index a73a1fe78..290e6e0cc 100644 --- a/AngelLoader/Ini/ConfigIni.cs +++ b/AngelLoader/Ini/ConfigIni.cs @@ -796,6 +796,14 @@ private static void Config_CheckForUpdates_Set(ConfigData config, string valTrim } } + private static void Config_ScreenshotGammaPercent_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) + { + if (Int_TryParseInv(valTrimmed, out int result)) + { + config.ScreenshotGammaPercent = result; + } + } + #endregion private readonly unsafe struct Config_DelegatePointerWrapper @@ -986,12 +994,10 @@ private static unsafe Dictionary { "EnableCharacterDetailFix", new Config_DelegatePointerWrapper(&Config_EnableCharacterDetailFix_Set) }, { "PlayOriginalSeparateButtons", new Config_DelegatePointerWrapper(&Config_PlayOriginalSeparateButtons_Set) }, - { "AskedToScanForMisCounts", new Config_DelegatePointerWrapper(&Config_AskedToScanForMisCounts_Set) }, - { "EnableFuzzySearch", new Config_DelegatePointerWrapper(&Config_EnableFuzzySearch_Set) }, - { "CheckForUpdates", new Config_DelegatePointerWrapper(&Config_CheckForUpdates_Set) }, + { "ScreenshotGammaPercent", new Config_DelegatePointerWrapper(&Config_ScreenshotGammaPercent_Set) }, #region Backward compatibility @@ -1382,11 +1388,9 @@ private static void WriteConfigIniInternal(ConfigData config, string fileName) sw.Append("EnableCharacterDetailFix").Append('=').Append(config.EnableCharacterDetailFix).AppendLine(); sw.Append("PlayOriginalSeparateButtons").Append('=').Append(config.PlayOriginalSeparateButtons).AppendLine(); - sw.Append("AskedToScanForMisCounts").Append('=').Append(config.AskedToScanForMisCounts).AppendLine(); - sw.Append("EnableFuzzySearch").Append('=').Append(config.EnableFuzzySearch).AppendLine(); - sw.Append("CheckForUpdates").Append('=').Append(config.CheckForUpdates).AppendLine(); + sw.Append("ScreenshotGammaPercent").Append('=').Append(config.ScreenshotGammaPercent).AppendLine(); } } From 0bca87e5bb2e7b853c223f6eee36053244ddc5f6 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 16:32:38 -0800 Subject: [PATCH 049/200] try-catch around entire image copy attempt --- .../TopRightPages/ScreenshotsTabPage.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 8d488ea29..f2a0105b9 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -281,18 +281,18 @@ public void CopyImageToClipboard() { if (!_constructed) return; - using Bitmap? bmp = _page.ScreenshotsPictureBox.GetSnapshot(); - if (bmp != null) + try { - try + using Bitmap? bmp = _page.ScreenshotsPictureBox.GetSnapshot(); + if (bmp != null) { Clipboard.SetImage(bmp); SetCopiedMessageLabelText(LText.ScreenshotsTab.ImageCopied, success: true); } - catch - { - SetCopiedMessageLabelText(LText.ScreenshotsTab.ImageCopyFailed, success: false); - } + } + catch + { + SetCopiedMessageLabelText(LText.ScreenshotsTab.ImageCopyFailed, success: false); } } From cea794e4b55ee7d8e1703d49124ea319c5d51ad2 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 17:18:18 -0800 Subject: [PATCH 050/200] Add manual refresh button --- .../Lazy_ScreenshotsPage.Designer.cs | 19 +++++-- .../TopRightPages/Lazy_ScreenshotsPage.cs | 20 ++++++-- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 17 +++++-- .../TopRightPages/ScreenshotsTabPage.cs | 50 +++++++++---------- 4 files changed, 69 insertions(+), 37 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 4af6d154f..663d455ab 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -39,6 +39,7 @@ private void InitializeComponent() this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); + this.RefreshButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // @@ -92,7 +93,8 @@ private void InitializeComponent() this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); this.OpenScreenshotsFolderButton.Name = "OpenScreenshotsFolderButton"; this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); - this.OpenScreenshotsFolderButton.TabIndex = 5; + this.OpenScreenshotsFolderButton.TabIndex = 6; + this.OpenScreenshotsFolderButton.PaintCustom += new System.EventHandler(this.OpenScreenshotsFolderButton_PaintCustom); // // NextButton // @@ -101,7 +103,7 @@ private void InitializeComponent() this.NextButton.Location = new System.Drawing.Point(446, 256); this.NextButton.Name = "NextButton"; this.NextButton.Size = new System.Drawing.Size(75, 23); - this.NextButton.TabIndex = 7; + this.NextButton.TabIndex = 8; // // PrevButton // @@ -110,7 +112,7 @@ private void InitializeComponent() this.PrevButton.Location = new System.Drawing.Point(371, 256); this.PrevButton.Name = "PrevButton"; this.PrevButton.Size = new System.Drawing.Size(75, 23); - this.PrevButton.TabIndex = 6; + this.PrevButton.TabIndex = 7; // // ScreenshotsPictureBox // @@ -122,12 +124,22 @@ private void InitializeComponent() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 0; // + // RefreshButton + // + this.RefreshButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.RefreshButton.Location = new System.Drawing.Point(6, 256); + this.RefreshButton.Name = "RefreshButton"; + this.RefreshButton.Size = new System.Drawing.Size(23, 23); + this.RefreshButton.TabIndex = 5; + this.RefreshButton.PaintCustom += new System.EventHandler(this.RefreshButton_PaintCustom); + // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.RefreshButton); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); @@ -155,4 +167,5 @@ private void InitializeComponent() internal DarkTrackBar GammaTrackBar; internal DarkLabel GammaLabel; internal DarkLabel CopiedMessageLabel; + internal DarkButton RefreshButton; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs index d41e8c99c..05bb2d300 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs @@ -14,15 +14,27 @@ public Lazy_ScreenshotsPage() #endif } - private void GammaResetButton_PaintCustom(object sender, PaintEventArgs e) + private void RefreshButton_PaintCustom(object sender, PaintEventArgs e) { - Rectangle cr = ((DarkButton)sender).ClientRectangle; - Images.PaintBitmapButton(e, - Images.Refresh, + Rectangle cr = RefreshButton.ClientRectangle; + Images.PaintBitmapButton( + e, + RefreshButton.Enabled ? Images.Refresh : Images.GetDisabledImage(Images.Refresh), scaledRect: new RectangleF( cr.X + 2f, cr.Y + 2f, cr.Width - 4f, cr.Height - 4f)); } + + private void OpenScreenshotsFolderButton_PaintCustom(object sender, PaintEventArgs e) + { + Image image = Images.Folder; + DarkButton button = OpenScreenshotsFolderButton; + Images.PaintBitmapButton( + button, + e, + button.Enabled ? image : Images.GetDisabledImage(image), + x: (button.Width - image.Width) / 2); + } } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 7819665db..1dfa33a71 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -15,6 +15,7 @@ private void InitSlim() this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); + this.RefreshButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // @@ -57,7 +58,8 @@ private void InitSlim() this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); - this.OpenScreenshotsFolderButton.TabIndex = 5; + this.OpenScreenshotsFolderButton.TabIndex = 6; + this.OpenScreenshotsFolderButton.PaintCustom += new System.EventHandler(this.OpenScreenshotsFolderButton_PaintCustom); // // NextButton // @@ -65,7 +67,7 @@ private void InitSlim() this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; this.NextButton.Location = new System.Drawing.Point(446, 256); this.NextButton.Size = new System.Drawing.Size(75, 23); - this.NextButton.TabIndex = 7; + this.NextButton.TabIndex = 8; // // PrevButton // @@ -73,7 +75,7 @@ private void InitSlim() this.PrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; this.PrevButton.Location = new System.Drawing.Point(371, 256); this.PrevButton.Size = new System.Drawing.Size(75, 23); - this.PrevButton.TabIndex = 6; + this.PrevButton.TabIndex = 7; // // ScreenshotsPictureBox // @@ -84,12 +86,21 @@ private void InitSlim() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 0; // + // RefreshButton + // + this.RefreshButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.RefreshButton.Location = new System.Drawing.Point(6, 256); + this.RefreshButton.Size = new System.Drawing.Size(23, 23); + this.RefreshButton.TabIndex = 5; + this.RefreshButton.PaintCustom += new System.EventHandler(this.RefreshButton_PaintCustom); + // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.RefreshButton); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index f2a0105b9..ba40fadd8 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -66,9 +66,9 @@ public override void Construct() CopiedMessageFadeoutTimer.Interval = 2500; CopiedMessageFadeoutTimer.Tick += CopiedMessageFadeoutTimer_Tick; + _page.RefreshButton.Click += RefreshButton_Click; _page.PrevButton.Click += ScreenshotsPrevButton_Click; _page.NextButton.Click += ScreenshotsNextButton_Click; - _page.OpenScreenshotsFolderButton.PaintCustom += OpenScreenshotsFolderButton_PaintCustom; _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; _page.GammaTrackBar.Scroll += GammaTrackBar_Scroll; _page.GammaTrackBar.MouseDown += GammaTrackBar_MouseDown; @@ -82,7 +82,22 @@ public override void Construct() public override void UpdatePage() { if (!_constructed) return; + UpdatePageInternal(forceUpdate: false); + } + + public override void Localize() + { + if (!_constructed) return; + _page.GammaLabel.Text = LText.ScreenshotsTab.Gamma; + _owner.MainToolTip.SetToolTip(_page.GammaTrackBar, LText.ScreenshotsTab.ResetGammaToolTip); + } + + #endregion + #region Page + + private void UpdatePageInternal(bool forceUpdate) + { FanMission? fm = _owner.GetMainSelectedFMOrNull(); Core.PopulateScreenshotFileNames(fm, ScreenshotFileNames); @@ -104,7 +119,7 @@ public override void UpdatePage() else { CurrentScreenshotFileName = ScreenshotFileNames[0]; - DisplayCurrentScreenshot(); + DisplayCurrentScreenshot(forceUpdate); _page.GammaLabel.Enabled = true; _page.ScreenshotsPictureBox.Enabled = true; _page.GammaTrackBar.Enabled = true; @@ -114,17 +129,6 @@ public override void UpdatePage() } } - public override void Localize() - { - if (!_constructed) return; - _page.GammaLabel.Text = LText.ScreenshotsTab.Gamma; - _owner.MainToolTip.SetToolTip(_page.GammaTrackBar, LText.ScreenshotsTab.ResetGammaToolTip); - } - - #endregion - - #region Page - // Manual right-align to avoid needing a FlowLayoutPanel private void SetNumberLabelText(string text) { @@ -147,14 +151,15 @@ private void ClearCurrentScreenshot() performance cost if they're not actually able to see the image. So we only update when visible (or when we become visible). */ - private void DisplayCurrentScreenshot() + private void DisplayCurrentScreenshot(bool forceUpdate = false) { if (!_constructed) return; if (!_owner.StartupState && !Visible) return; - if (!CurrentScreenshotFileName.IsEmpty() && + if (forceUpdate || + (!CurrentScreenshotFileName.IsEmpty() && // @TDM_CASE when FM is TDM - _currentScreenshotStream?.Path.EqualsI(CurrentScreenshotFileName) != true) + _currentScreenshotStream?.Path.EqualsI(CurrentScreenshotFileName) != true)) { try { @@ -183,22 +188,13 @@ protected override void OnVisibleChanged(EventArgs e) if (Visible) DisplayCurrentScreenshot(); } + private void RefreshButton_Click(object sender, EventArgs e) => UpdatePageInternal(forceUpdate: true); + private void OpenScreenshotsFolderButton_Click(object sender, EventArgs e) { Core.OpenFMScreenshotsFolder(_owner.FMsDGV.GetMainSelectedFM(), CurrentScreenshotFileName); } - private void OpenScreenshotsFolderButton_PaintCustom(object sender, PaintEventArgs e) - { - Image image = Images.Folder; - DarkButton button = _page.OpenScreenshotsFolderButton; - Images.PaintBitmapButton( - button, - e, - button.Enabled ? image : Images.GetDisabledImage(image), - x: (button.Width - image.Width) / 2); - } - private void ScreenshotsPrevButton_Click(object sender, EventArgs e) => CycleScreenshot(step: -1); private void ScreenshotsNextButton_Click(object sender, EventArgs e) => CycleScreenshot(step: 1); From 423fcda01b98bcbab76dd848b42459f820f2a020 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 25 Feb 2024 17:47:29 -0800 Subject: [PATCH 051/200] Notes on the plan for file system watching --- .../TopRightPages/ScreenshotsTabPage.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index ba40fadd8..b8b034cf7 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,4 +1,18 @@ -// @ScreenshotDisplay: Watch screenshot folder and reload from disk +/* +@ScreenshotDisplay: Options for watching screenshot folders and reloading from disk automatically + +-Have one FileSystemWatcher and change its watch path every FM load. This will add time (up to 20-30ms iirc?) + to FM selection. It will also need to be turned off any time the FM installed directory is modified in some way + (install/uninstall/audio convert/etc.) to prevent a tsunami of events (perf). + +-Have one FileSystemWatcher per game, and watch the FM install base dir (and global screenshots dir for TDM). + Again, it would need to be disabled during FM dir modifications (to ANY fm subdir!). This would prevent having + to set the watcher path for every FM selection change. The event handlers give us the affected filename, and we + can filter to just image types for perf. + +We could also have the watchers be wrapped in a lazy-loaded class that only loads them up when the screenshots +tab shows for the first time per game. +*/ using System; using System.Collections.Generic; From 02e9c3a2a01b41f4eebc4d5440d5ba8ae2364e42 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 10:12:57 -0800 Subject: [PATCH 052/200] Screenshot auto-refresh working at a basic level Still more work to do though --- AngelLoader/Common/Comparers.cs | 5 +- AngelLoader/Common/DataClasses/ConfigData.cs | 17 ++ .../DataClasses/ConfigDataSupporting.cs | 174 ++++++++++++++++++ AngelLoader/Common/Misc.cs | 15 ++ AngelLoader/Common/Utility/PathUtils.cs | 20 +- AngelLoader/Core.cs | 69 +++++-- AngelLoader/FMInstallAndPlay.cs | 3 + .../TopRightPages/ScreenshotsTabPage.cs | 26 ++- AngelLoader/Forms/MainForm.cs | 2 + AngelLoader/Interfaces.cs | 2 + 10 files changed, 301 insertions(+), 32 deletions(-) diff --git a/AngelLoader/Common/Comparers.cs b/AngelLoader/Common/Comparers.cs index b39858a85..319260f69 100644 --- a/AngelLoader/Common/Comparers.cs +++ b/AngelLoader/Common/Comparers.cs @@ -445,13 +445,16 @@ public int Compare(string x, string y) => internal sealed class ScreenshotComparer : IComparer { + public SortDirection SortDirection = SortDirection.Ascending; + public int Compare(FileInfo x, FileInfo y) { int cmp = x.LastWriteTime.CompareTo(y.LastWriteTime); - return cmp == 0 + int ret = cmp == 0 // @TDM_CASE when file is a TDM screenshot ? string.Compare(x.Name, y.Name, StringComparison.OrdinalIgnoreCase) : cmp; + return SortDirection == SortDirection.Descending ? -ret : ret; } } diff --git a/AngelLoader/Common/DataClasses/ConfigData.cs b/AngelLoader/Common/DataClasses/ConfigData.cs index 5e3a88a53..aa5d245b0 100644 --- a/AngelLoader/Common/DataClasses/ConfigData.cs +++ b/AngelLoader/Common/DataClasses/ConfigData.cs @@ -37,6 +37,8 @@ internal ConfigData() GameFilterControlVisibilities = new bool[SupportedGameCount]; + _screenshotWatchers = new ScreenshotWatcher[SupportedGameCount]; + #endregion FilterControlVisibilities = InitializedArray(HideableFilterControlsCount, true); @@ -54,6 +56,8 @@ internal ConfigData() _startupFMSelectorLines[i] = new List(); GameFilterControlVisibilities[i] = true; + + _screenshotWatchers[i] = new ScreenshotWatcher((GameIndex)i); } // Must set the display indexes, otherwise we crash! @@ -66,6 +70,19 @@ internal ConfigData() //internal int Version = 1; + #region Screenshot watchers + + /* + @ScreenshotDisplay: These contain disposable objects (not initialized to start with, but still) + When Settings instantiates a new Config object, it will construct this set too. That won't currently result + in the disposable FileSystemWatcher objects being instantiated so it's fine, but we should maybe put this + somewhere else and make it static, because it's supposed to live for the live of the app. + */ + private readonly ScreenshotWatcher[] _screenshotWatchers; + internal ScreenshotWatcher GetScreenshotWatcher(GameIndex gameIndex) => _screenshotWatchers[(int)gameIndex]; + + #endregion + #region Saved-on-startup loader config values #region fm_selector lines diff --git a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs index 1570c1ac8..e34c8136e 100644 --- a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs +++ b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs @@ -2,12 +2,14 @@ using System; using System.Collections.Generic; +using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using AL_Common; using static AL_Common.Common; using static AL_Common.FenGenAttributes; using static AngelLoader.GameSupport; +using static AngelLoader.Global; using static AngelLoader.Misc; namespace AngelLoader.DataClasses; @@ -471,3 +473,175 @@ internal Mod(string internalName, ModType type) IsUber = type is ModType.UberModPath or ModType.MPUberModPath; } } + +// @ScreenshotDisplay: Cleanup test Trace.WriteLines etc. +public sealed class ScreenshotWatcher +{ + private sealed class ScreenshotWatcherTimer(double interval) : System.Timers.Timer(interval) + { + internal string FullPath { get; private set; } = ""; + internal WatcherChangeTypes ChangeType { get; private set; } + + internal void ResetWith(string fullPath, WatcherChangeTypes changeType) + { + this.Reset(); + FullPath = fullPath; + ChangeType = changeType; + } + } + + private bool _constructed; + private FileSystemWatcher _watcher = null!; + + private readonly GameIndex _gameIndex; + + private static readonly ScreenshotWatcherTimer _timer = new(1000) { Enabled = false, AutoReset = false }; + + private string _path = ""; + public string Path + { + get => _constructed ? _watcher.Path : _path; + set + { + if (_constructed) + { + try + { + _watcher.Path = value; + } + catch + { + EnableWatching = false; + } + } + else + { + _path = value; + } + } + } + + private bool _enableWatching; + public bool EnableWatching + { + get => _constructed ? _watcher.EnableRaisingEvents : _enableWatching; + set + { + if (_constructed) + { + try + { + _watcher.EnableRaisingEvents = value; + } + catch + { + try + { + _watcher.EnableRaisingEvents = false; + } + catch + { + // ignore + } + } + } + else + { + _enableWatching = value; + } + } + } + + public ScreenshotWatcher(GameIndex gameIndex) + { + _gameIndex = gameIndex; + _timer.Elapsed += Timer_Elapsed; + } + + public void Construct() + { + if (_constructed) return; + if (_path.IsEmpty()) return; + + try + { + _watcher = new FileSystemWatcher(Path); + _watcher.Changed += Watcher_ChangedCreatedDeleted; + _watcher.Created += Watcher_ChangedCreatedDeleted; + _watcher.Deleted += Watcher_ChangedCreatedDeleted; + _watcher.Renamed += Watcher_Renamed; + _watcher.IncludeSubdirectories = true; + _watcher.EnableRaisingEvents = EnableWatching; + } + catch + { + _constructed = false; + return; + } + + _constructed = true; + } + + private void Watcher_ChangedCreatedDeleted(object sender, FileSystemEventArgs e) + { + //Trace.WriteLine(nameof(Watcher_ChangedCreatedDeleted) + ": " + e.ChangeType + "\r\n" + e.FullPath); + _timer.ResetWith(e.FullPath, e.ChangeType); + } + + private void Watcher_Renamed(object sender, RenamedEventArgs e) + { + //Trace.WriteLine(nameof(Watcher_Renamed) + ": " + e.ChangeType + "\r\n" + e.OldFullPath); + _timer.ResetWith(e.OldFullPath, e.ChangeType); + } + + private void HandleEvent(string fullPath, WatcherChangeTypes changeType) => Core.View.Invoke(() => + { + if (!_constructed) return; + if (!EnableWatching) return; + + FanMission? fm = Core.View.GetMainSelectedFMOrNull(); + if (fm == null) return; + if (!fm.Game.ConvertsToKnownAndSupported(out GameIndex gameIndex)) return; + if (gameIndex != _gameIndex) return; + + fullPath = fullPath.ToForwardSlashes_Net(); + + string screenshotsParentDir; + + // @GENGAMES(Screenshots watcher) + if (gameIndex == GameIndex.TDM) + { + string gamePath = Config.GetGamePath(GameIndex.TDM).ToForwardSlashes_Net(); + if (gamePath.IsEmpty()) return; + screenshotsParentDir = gamePath.GetDirNameFast(); + } + else + { + screenshotsParentDir = fm.RealInstalledDir; + } + + string fmPlusScreenshotsPathSegment = "/" + screenshotsParentDir + "/screenshots"; + if (fullPath.ContainsI(fmPlusScreenshotsPathSegment + "/") || + fullPath.PathEndsWithI(fmPlusScreenshotsPathSegment)) + { + /* + @ScreenshotDisplay: If this is enabled, it's possible a non-matching change will override the matching one. + Unlikely, but meh. But if we disable it, then any TDM FM will attempt refresh if anything in the + central screenshots dir gets modified, even if doesn't match our FM name. Also not a big deal. We + could fix both cases by keeping a list of filenames and then checking if our name exists in it, and + refreshing then. + */ + //if (gameIndex != GameIndex.TDM || Core.ScreenshotFileMatchesTDMName(fm.TDMInstalledDir, fullPath.GetFileNameFast())) + { + //System.Diagnostics.Trace.WriteLine("---------------------------------------------- Refreshing"); + Core.View.RefreshCurrentFMScreenshots(); + } + } + }); + + private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + if (Core.View == null!) return; + HandleEvent(_timer.FullPath, _timer.ChangeType); + } +} diff --git a/AngelLoader/Common/Misc.cs b/AngelLoader/Common/Misc.cs index a84b5f2b2..4231747a9 100644 --- a/AngelLoader/Common/Misc.cs +++ b/AngelLoader/Common/Misc.cs @@ -197,4 +197,19 @@ internal static class Defaults internal const int StreamCopyBufferSize = 81920; internal const int FileStreamBufferSize = 4096; + + // Another leak of view implementation details into here (GDI+/Bitmap supported formats) + // @ScreenshotDisplay: NewDark games can also have .pcx, and TDM can also have .tga + // Neither are supported by Bitmap, so, you're kinda outta luck on those. + public static readonly string[] SupportedScreenshotExtensions = + { + // Common/likely ones first + ".png", + ".bmp", + ".jpg", + ".jpeg", + ".gif", + ".tif", + ".tiff" + }; } diff --git a/AngelLoader/Common/Utility/PathUtils.cs b/AngelLoader/Common/Utility/PathUtils.cs index 713a1b5ca..6d5955500 100644 --- a/AngelLoader/Common/Utility/PathUtils.cs +++ b/AngelLoader/Common/Utility/PathUtils.cs @@ -129,18 +129,14 @@ internal static bool ExtIsArchive(this string value) => internal static bool ExtIsRar(this string value) => value.EndsWithI(".rar"); - // Another leak of view implementation details into here (GDI+/Bitmap supported formats) - // @ScreenshotDisplay: NewDark games can also have .pcx, and TDM can also have .tga - // Neither are supported by Bitmap, so, you're kinda out of luck on those. - internal static bool ExtIsUISupportedImage(this string value) => - // Common/likely ones first - value.EndsWithI(".png") || - value.EndsWithI(".bmp") || - value.EndsWithI(".jpg") || - value.EndsWithI(".jpeg") || - value.EndsWithI(".gif") || - value.EndsWithI(".tif") || - value.EndsWithI(".tiff"); + internal static bool ExtIsUISupportedImage(this string value) + { + for (int i = 0; i < Misc.SupportedScreenshotExtensions.Length; i++) + { + if (value.EndsWithI(Misc.SupportedScreenshotExtensions[i])) return true; + } + return false; + } #endregion diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index e2ffcea16..e65b2ac3a 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -829,6 +829,7 @@ private static (SetGameDataError Error, bool EnableTDMWatchers, List? Ca // This must come first, so below methods can use it Config.SetGamePath(gameIndex, gamePath); + // @GENGAMES(Set game data from disk - main) if (GameIsDark(gameIndex)) { if (!gamePath.IsEmpty() && !DirectoryHasWritePermission(gamePath)) @@ -982,6 +983,29 @@ private static (SetGameDataError Error, bool EnableTDMWatchers, List? Ca // We don't set mod dirs for Thief 3 because it doesn't support programmatic mod enabling/disabling } + ScreenshotWatcher watcher = Config.GetScreenshotWatcher(gameIndex); + string fmInstallPath = Config.GetFMInstallPath(gameIndex); + try + { + if (gameExeSpecified && !fmInstallPath.IsEmpty()) + { + watcher.EnableWatching = false; + // @GENGAMES(Set game data from disk - screenshot watchers) + watcher.Path = gameIndex == GameIndex.TDM + ? Path.Combine(Config.GetGamePath(GameIndex.TDM), "screenshots") + : fmInstallPath; + watcher.EnableWatching = true; + } + else + { + watcher.EnableWatching = false; + } + } + catch + { + watcher.EnableWatching = false; + } + return (error, enableTDMWatchers, camModIniLines); } @@ -2827,26 +2851,10 @@ Extracted fm name should be "written" FileInfo item = files[i]; string fn = item.Name; - int spaceIndex = fn.IndexOf(' '); - // @TDM_CASE: Screenshot FM name comparison - if (spaceIndex > -1 && fn.Substring(0, spaceIndex).Trim().EqualsI(fm.TDMInstalledDir)) + if (ScreenshotFileMatchesTDMName(fm.TDMInstalledDir, fn)) { AddIfValidFormat(screenshotFileNames, item.FullName); } - else - { - int underscoreIndex = fn.LastIndexOf('_'); - if (underscoreIndex == -1) continue; - - int secondToLastUnderscoreIndex = fn.LastIndexOf('_', (underscoreIndex - 1).ClampToZero()); - if (secondToLastUnderscoreIndex <= -1) continue; - - // @TDM_CASE: Screenshot FM name comparison - if (fn.Substring(0, secondToLastUnderscoreIndex).Trim().EqualsI(fm.TDMInstalledDir)) - { - AddIfValidFormat(screenshotFileNames, item.FullName); - } - } } } } @@ -2891,6 +2899,7 @@ These names are listed in \CONTENT\T3\Books\English\String_Tags\Misc.sch but als return false; } screenshots = di.GetFiles(pattern); + Comparers.Screenshot.SortDirection = SortDirection.Descending; Array.Sort(screenshots, Comparers.Screenshot); return true; } @@ -2909,4 +2918,30 @@ static void AddIfValidFormat(List screenshotFileNames, string filename) } } } + + internal static bool ScreenshotFileMatchesTDMName(string tdmInstalledDir, string fn) + { + int spaceIndex = fn.IndexOf(' '); + // @TDM_CASE: Screenshot FM name comparison + if (spaceIndex > -1 && fn.Substring(0, spaceIndex).Trim().EqualsI(tdmInstalledDir)) + { + return true; + } + else + { + int underscoreIndex = fn.LastIndexOf('_'); + if (underscoreIndex == -1) return false; + + int secondToLastUnderscoreIndex = fn.LastIndexOf('_', (underscoreIndex - 1).ClampToZero()); + if (secondToLastUnderscoreIndex <= -1) return false; + + // @TDM_CASE: Screenshot FM name comparison + if (fn.Substring(0, secondToLastUnderscoreIndex).Trim().EqualsI(tdmInstalledDir)) + { + return true; + } + } + + return false; + } } diff --git a/AngelLoader/FMInstallAndPlay.cs b/AngelLoader/FMInstallAndPlay.cs index e13f47157..7d70b92d2 100644 --- a/AngelLoader/FMInstallAndPlay.cs +++ b/AngelLoader/FMInstallAndPlay.cs @@ -26,6 +26,9 @@ namespace AngelLoader; +// @ScreenshotDisplay(FM dir modification): +// Make a system for cleanly disabling/enabling screenshot watchers during modification of anything within the +// watched path (install/uninstall/audio convert etc.) internal static class FMInstallAndPlay { #region Private fields diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index b8b034cf7..117b35c2f 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -21,6 +21,7 @@ We could also have the watchers be wrapped in a lazy-loaded class that only load using System.Windows.Forms; using AL_Common; using AngelLoader.DataClasses; +using static AngelLoader.GameSupport; using static AngelLoader.Global; namespace AngelLoader.Forms.CustomControls; @@ -106,6 +107,12 @@ public override void Localize() _owner.MainToolTip.SetToolTip(_page.GammaTrackBar, LText.ScreenshotsTab.ResetGammaToolTip); } + public void RefreshScreenshots() + { + if (!_constructed) return; + UpdatePageInternal(forceUpdate: true); + } + #endregion #region Page @@ -113,6 +120,10 @@ public override void Localize() private void UpdatePageInternal(bool forceUpdate) { FanMission? fm = _owner.GetMainSelectedFMOrNull(); + if (fm != null && fm.Game.ConvertsToKnownAndSupported(out GameIndex gameIndex)) + { + Config.GetScreenshotWatcher(gameIndex).Construct(); + } Core.PopulateScreenshotFileNames(fm, ScreenshotFileNames); @@ -147,6 +158,11 @@ private void UpdatePageInternal(bool forceUpdate) private void SetNumberLabelText(string text) { _page.NumberLabel.Text = text; + SetNumberLabelPosition(); + } + + private void SetNumberLabelPosition() + { _page.NumberLabel.Location = _page.NumberLabel.Location with { X = (_page.ClientSize.Width - 8) - _page.NumberLabel.Width @@ -168,7 +184,9 @@ private void ClearCurrentScreenshot() private void DisplayCurrentScreenshot(bool forceUpdate = false) { if (!_constructed) return; - if (!_owner.StartupState && !Visible) return; + // @ScreenshotDisplay: I think the unconditional-if-force-update check is not quite correct + // That would probably make it update even if the tab is hidden? Maybe that's fine? + if (!forceUpdate && !_owner.StartupState && !Visible) return; if (forceUpdate || (!CurrentScreenshotFileName.IsEmpty() && @@ -199,7 +217,11 @@ private void DisplayCurrentScreenshot(bool forceUpdate = false) protected override void OnVisibleChanged(EventArgs e) { base.OnVisibleChanged(e); - if (Visible) DisplayCurrentScreenshot(); + if (Visible) + { + SetNumberLabelPosition(); + DisplayCurrentScreenshot(); + } } private void RefreshButton_Click(object sender, EventArgs e) => UpdatePageInternal(forceUpdate: true); diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index e65adbf2b..cb94fa34f 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5335,4 +5335,6 @@ public void ShowUpdateNotification(bool show) // We might want to change this, if we want something beside the readme or whatever internal Control ReadmeContainer => MainSplitContainer.Panel2; + + public void RefreshCurrentFMScreenshots() => ScreenshotsTabPage.RefreshScreenshots(); } diff --git a/AngelLoader/Interfaces.cs b/AngelLoader/Interfaces.cs index dd4261b8d..07daa9c36 100644 --- a/AngelLoader/Interfaces.cs +++ b/AngelLoader/Interfaces.cs @@ -374,4 +374,6 @@ Task SortAndSetFilter(SelectedFM? selectedFM = null, bool forceDisplayFM = false void Close(); void ShowUpdateNotification(bool show); + + void RefreshCurrentFMScreenshots(); } From 0a8f6924d6d85d098a783dd0abeecaaf3bb93610 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 12:15:10 -0800 Subject: [PATCH 053/200] Add system for temp disabling screenshot watchers During operations which write to the FMs directory --- AngelLoader/Common/Misc.cs | 44 +++++++++++++++ AngelLoader/Core.cs | 4 ++ AngelLoader/FMAudio.cs | 91 +++++++++++++++++-------------- AngelLoader/FMBackupAndRestore.cs | 2 +- AngelLoader/FMDelete.cs | 2 + AngelLoader/FMInstallAndPlay.cs | 27 +++++++-- AngelLoader/FMScan.cs | 56 +++++++++---------- AngelLoader/FindFMs.cs | 5 ++ 8 files changed, 155 insertions(+), 76 deletions(-) diff --git a/AngelLoader/Common/Misc.cs b/AngelLoader/Common/Misc.cs index 4231747a9..0bd816857 100644 --- a/AngelLoader/Common/Misc.cs +++ b/AngelLoader/Common/Misc.cs @@ -3,8 +3,10 @@ using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Threading.Tasks; +using AL_Common; using AngelLoader.DataClasses; using static AngelLoader.GameSupport; +using static AngelLoader.Global; namespace AngelLoader; @@ -212,4 +214,46 @@ internal static class Defaults ".tif", ".tiff" }; + + public sealed class FMInstalledDirModificationScope : IDisposable + { + /* + IMPORTANT! @THREADING(FMInstalledDirModificationScope): + If we ever make it so that things can go in parallel (install/uninstall, scan, delete, etc.), this will + no longer be safe! We're threading noobs so we don't know if volatile will solve the problem or what. + Needs testing. + */ + private static int _count; + + private readonly bool[] _originalValues = new bool[SupportedGameCount]; + + public FMInstalledDirModificationScope() + { + if (_count == 0) + { + for (int i = 0; i < SupportedGameCount; i++) + { + GameIndex gameIndex = (GameIndex)i; + ScreenshotWatcher watcher = Config.GetScreenshotWatcher(gameIndex); + _originalValues[i] = watcher.EnableWatching; + watcher.EnableWatching = false; + } + } + _count++; + } + + public void Dispose() + { + if (_count == 1) + { + for (int i = 0; i < SupportedGameCount; i++) + { + GameIndex gameIndex = (GameIndex)i; + ScreenshotWatcher watcher = Config.GetScreenshotWatcher(gameIndex); + watcher.EnableWatching = _originalValues[i]; + } + } + _count = (_count - 1).ClampToZero(); + } + } } diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index e65b2ac3a..b0c3c9236 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -1591,6 +1591,8 @@ internal static bool AddDML(FanMission fm, string sourceDMLPath) return false; } + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + try { string dmlFile = Path.GetFileName(sourceDMLPath); @@ -1618,6 +1620,8 @@ internal static bool RemoveDML(FanMission fm, string dmlFile) return false; } + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + try { File.Delete(Path.Combine(installedFMPath, dmlFile)); diff --git a/AngelLoader/FMAudio.cs b/AngelLoader/FMAudio.cs index ce308395c..8b16ab652 100644 --- a/AngelLoader/FMAudio.cs +++ b/AngelLoader/FMAudio.cs @@ -43,44 +43,7 @@ internal static class FMAudio internal static async Task ConvertSelected(AudioConvert convertType) { - #region Local functions - - static bool ChecksPassed(List fms) - { - bool[] gamesChecked = new bool[SupportedGameCount]; - - for (int i = 0; i < fms.Count; i++) - { - FanMission fm = fms[i]; - - AssertR(GameIsKnownAndSupported(fm.Game), nameof(fm) + "." + nameof(fm.Game) + " is not known or supported (not convertible to GameIndex)."); - - GameIndex gameIndex = GameToGameIndex(fm.Game); - int intGameIndex = (int)gameIndex; - - if (!gamesChecked[intGameIndex]) - { - string gameExe = Config.GetGameExe(gameIndex); - string gameName = GetLocalizedGameName(gameIndex); - - if (GameIsRunning(gameExe)) - { - Core.Dialogs.ShowAlert( - gameName + ":\r\n" + - LText.AlertMessages.AudioConversion_GameIsRunning, - LText.AlertMessages.Alert); - - return false; - } - - gamesChecked[intGameIndex] = true; - } - } - - return true; - } - - #endregion + using var fmInstDirModScope = new FMInstalledDirModificationScope(); List fms = Core.View.GetSelectedFMs_InOrder_List(); if (fms.Count == 0) return; @@ -147,13 +110,57 @@ static bool ChecksPassed(List fms) Core.View.HideProgressBox(); _conversionCts.Dispose(); } + + return; + + #region Local functions + + static bool ChecksPassed(List fms) + { + bool[] gamesChecked = new bool[SupportedGameCount]; + + for (int i = 0; i < fms.Count; i++) + { + FanMission fm = fms[i]; + + AssertR(GameIsKnownAndSupported(fm.Game), nameof(fm) + "." + nameof(fm.Game) + " is not known or supported (not convertible to GameIndex)."); + + GameIndex gameIndex = GameToGameIndex(fm.Game); + int intGameIndex = (int)gameIndex; + + if (!gamesChecked[intGameIndex]) + { + string gameExe = Config.GetGameExe(gameIndex); + string gameName = GetLocalizedGameName(gameIndex); + + if (GameIsRunning(gameExe)) + { + Core.Dialogs.ShowAlert( + gameName + ":\r\n" + + LText.AlertMessages.AudioConversion_GameIsRunning, + LText.AlertMessages.Alert); + + return false; + } + + gamesChecked[intGameIndex] = true; + } + } + + return true; + } + + #endregion } - internal static Task ConvertToWAVs(FanMission fm, AudioConvert type, BinaryBuffer buffer, byte[] fileStreamBuffer, CancellationToken? ct = null) + internal static Task ConvertAsPartOfInstall(FanMission fm, AudioConvert type, BinaryBuffer buffer, byte[] fileStreamBuffer, CancellationToken? ct = null) { - if (!GameIsDark(fm.Game)) return VoidTask; + return ConvertToWAVs(fm, type, buffer, fileStreamBuffer, ct); + } - static bool Canceled(CancellationToken? ct) => ct != null && ((CancellationToken)ct).IsCancellationRequested; + private static Task ConvertToWAVs(FanMission fm, AudioConvert type, BinaryBuffer buffer, byte[] fileStreamBuffer, CancellationToken? ct = null) + { + if (!GameIsDark(fm.Game)) return VoidTask; return Task.Run(async () => { @@ -365,6 +372,8 @@ static int GetBitDepthSlow(string file) } } }); + + static bool Canceled(CancellationToken? ct) => ct != null && ((CancellationToken)ct).IsCancellationRequested; } #endregion diff --git a/AngelLoader/FMBackupAndRestore.cs b/AngelLoader/FMBackupAndRestore.cs index f05307d7d..b14e6123e 100644 --- a/AngelLoader/FMBackupAndRestore.cs +++ b/AngelLoader/FMBackupAndRestore.cs @@ -30,7 +30,7 @@ We could be in a messed-up state and the user won't know and we don't even try t Because we're trimming from the start of a relative path, so we won't trim any "\\" from "\\netPC" or anything */ -internal static class FMBackupAndRestore +internal static partial class FMInstallAndPlay { #region Private fields // fmsel source code says: diff --git a/AngelLoader/FMDelete.cs b/AngelLoader/FMDelete.cs index 3ec647149..03b6d9d19 100644 --- a/AngelLoader/FMDelete.cs +++ b/AngelLoader/FMDelete.cs @@ -196,6 +196,8 @@ private static (bool Success, List FinalArchives) // * NIGHTMARE REALM * internal static async Task DeleteFMsFromDisk(List fms) { + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + int origCount = fms.Count; bool single = origCount == 1; diff --git a/AngelLoader/FMInstallAndPlay.cs b/AngelLoader/FMInstallAndPlay.cs index 7d70b92d2..b3b0fcc1f 100644 --- a/AngelLoader/FMInstallAndPlay.cs +++ b/AngelLoader/FMInstallAndPlay.cs @@ -18,7 +18,6 @@ using static AL_Common.Common; using static AL_Common.LanguageSupport; using static AL_Common.Logger; -using static AngelLoader.FMBackupAndRestore; using static AngelLoader.GameSupport; using static AngelLoader.Global; using static AngelLoader.Misc; @@ -29,7 +28,7 @@ namespace AngelLoader; // @ScreenshotDisplay(FM dir modification): // Make a system for cleanly disabling/enabling screenshot watchers during modification of anything within the // watched path (install/uninstall/audio convert etc.) -internal static class FMInstallAndPlay +internal static partial class FMInstallAndPlay { #region Private fields @@ -65,6 +64,8 @@ private enum PlaySource internal static async Task InstallOrUninstall(FanMission[] fms) { + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + AssertR(fms.Length > 0, nameof(fms) + ".Length == 0"); FanMission firstFM = fms[0]; @@ -116,6 +117,8 @@ private static bool SelectTdmFM(FanMission? fm, bool deselect = false) internal static async Task InstallIfNeededAndPlay(FanMission fm, bool askConfIfRequired = false, bool playMP = false) { + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + if (!fm.Game.ConvertsToKnownAndSupported(out GameIndex gameIndex)) { LogFMInfo(fm, ErrorText.FMGameU, stackTrace: true); @@ -192,6 +195,8 @@ await InstallInternal(fromPlay: true, suppressConfirmation: askingConfirmation, internal static bool PlayOriginalGame(GameIndex gameIndex, bool playMP = false) { + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + try { Core.View.SetWaitCursor(true); @@ -256,6 +261,8 @@ internal static bool PlayOriginalGame(GameIndex gameIndex, bool playMP = false) private static bool PlayFM(FanMission fm, GameIndex gameIndex, bool playMP = false) { + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + (bool success, string gameExe, string gamePath) = CheckAndReturnFinalGameExeAndGamePath(gameIndex, playingOriginalGame: false, playMP); if (!success) return false; @@ -383,6 +390,8 @@ DOES have the desired effect. internal static bool OpenFMInEditor(FanMission fm) { + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + try { Core.View.SetWaitCursor(true); @@ -1433,7 +1442,11 @@ private sealed class Buffers internal byte[] FileStreamBuffer => _fileStreamBuffer ??= new byte[FileStreamBufferSize]; } - internal static Task Install(params FanMission[] fms) => InstallInternal(false, false, fms); + internal static Task Install(params FanMission[] fms) + { + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + return InstallInternal(false, false, fms); + } private static async Task InstallInternal(bool fromPlay, bool suppressConfirmation, params FanMission[] fms) { @@ -1657,7 +1670,7 @@ static void RemoveFMFromDisk(FMData fmData) // This one won't be called anywhere except during install, because it always runs during // install so there's no need to make it optional elsewhere. So we don't need to have a // check bool or anything. - await FMAudio.ConvertToWAVs(fmData.FM, AudioConvert.MP3ToWAV, buffer, buffers.FileStreamBuffer, _installCts.Token); + await FMAudio.ConvertAsPartOfInstall(fmData.FM, AudioConvert.MP3ToWAV, buffer, buffers.FileStreamBuffer, _installCts.Token); if (_installCts.IsCancellationRequested) { @@ -1667,7 +1680,7 @@ static void RemoveFMFromDisk(FMData fmData) if (Config.ConvertOGGsToWAVsOnInstall) { - await FMAudio.ConvertToWAVs(fmData.FM, AudioConvert.OGGToWAV, buffer, buffers.FileStreamBuffer, _installCts.Token); + await FMAudio.ConvertAsPartOfInstall(fmData.FM, AudioConvert.OGGToWAV, buffer, buffers.FileStreamBuffer, _installCts.Token); } if (_installCts.IsCancellationRequested) @@ -1678,7 +1691,7 @@ static void RemoveFMFromDisk(FMData fmData) if (Config.ConvertWAVsTo16BitOnInstall) { - await FMAudio.ConvertToWAVs(fmData.FM, AudioConvert.WAVToWAV16, buffer, buffers.FileStreamBuffer, _installCts.Token); + await FMAudio.ConvertAsPartOfInstall(fmData.FM, AudioConvert.WAVToWAV16, buffer, buffers.FileStreamBuffer, _installCts.Token); } if (_installCts.IsCancellationRequested) @@ -2019,6 +2032,8 @@ void ReportProgress(Fen7z.ProgressReport pr) internal static async Task<(bool Success, bool AtLeastOneFMMarkedUnavailable)> Uninstall(FanMission[] fms, bool doEndTasks = true) { + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + var fail = (false, false); var fmDataList = new FMData[fms.Length]; diff --git a/AngelLoader/FMScan.cs b/AngelLoader/FMScan.cs index e4ecab180..095f52b70 100644 --- a/AngelLoader/FMScan.cs +++ b/AngelLoader/FMScan.cs @@ -46,34 +46,6 @@ internal static async Task ScanFMs( bool setForceReCacheReadmes = false, string? scanMessage = null) { - #region Local functions - - static FMScanner.ScanOptions GetDefaultScanOptions() => FMScanner.ScanOptions.FalseDefault( - scanTitle: true, - scanAuthor: true, - scanGameType: true, - scanCustomResources: true, - scanSize: true, - scanReleaseDate: true, - scanTags: true, - scanMissionCount: true); - - void ReportProgress(FMScanner.ProgressReport pr) => Core.View.SetProgressBoxState_Single( - message1: - scanMessage ?? - (LText.ProgressBox.ReportScanningFirst + - pr.FMNumber.ToString(NumberFormatInfo.CurrentInfo) + - (pr.CachedString ??= - (LText.ProgressBox.ReportScanningBetweenNumAndTotal + - pr.FMsTotal.ToString(NumberFormatInfo.CurrentInfo) + - LText.ProgressBox.ReportScanningLast))), - message2: - pr.FMName, - percent: pr.Percent - ); - - #endregion - scanOptions ??= GetDefaultScanOptions(); if (fmsToScan.Count == 0) return false; @@ -478,6 +450,34 @@ static void ShowProgressBox(bool suppressShow) Core.View.Block(false); Core.View.HideProgressBox(); } + + #region Local functions + + static FMScanner.ScanOptions GetDefaultScanOptions() => FMScanner.ScanOptions.FalseDefault( + scanTitle: true, + scanAuthor: true, + scanGameType: true, + scanCustomResources: true, + scanSize: true, + scanReleaseDate: true, + scanTags: true, + scanMissionCount: true); + + void ReportProgress(FMScanner.ProgressReport pr) => Core.View.SetProgressBoxState_Single( + message1: + scanMessage ?? + (LText.ProgressBox.ReportScanningFirst + + pr.FMNumber.ToString(NumberFormatInfo.CurrentInfo) + + (pr.CachedString ??= + (LText.ProgressBox.ReportScanningBetweenNumAndTotal + + pr.FMsTotal.ToString(NumberFormatInfo.CurrentInfo) + + LText.ProgressBox.ReportScanningLast))), + message2: + pr.FMName, + percent: pr.Percent + ); + + #endregion } internal static Task ScanNewFMs(List fmsViewListUnscanned) diff --git a/AngelLoader/FindFMs.cs b/AngelLoader/FindFMs.cs index b4de25508..809066d59 100644 --- a/AngelLoader/FindFMs.cs +++ b/AngelLoader/FindFMs.cs @@ -8,6 +8,7 @@ using static AL_Common.Logger; using static AngelLoader.GameSupport; using static AngelLoader.Global; +using static AngelLoader.Misc; using static AngelLoader.Utils; namespace AngelLoader; @@ -215,6 +216,8 @@ internal static (List FMsViewListUnscanned, Exception? Ex) // tasks or anything here... just return an exception and handle it on the main thread... try { + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + List fmsViewListUnscanned = FindInternal(startup: true); splashScreen.SetCheckAtStoredMessageWidth(); return (fmsViewListUnscanned, null); @@ -233,6 +236,8 @@ internal static List Find() { AssertR(Core.View != null!, "View was null during FindFMs.Find() call"); + using var fmInstDirModScope = new FMInstalledDirModificationScope(); + List fmsViewListUnscanned = FindInternal(startup: false); Core.View!.SetAvailableAndFinishedFMCount(); return fmsViewListUnscanned; From 6b2488fc33640f86e591d5ab87112f671e0fa1e4 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 12:17:55 -0800 Subject: [PATCH 054/200] Don't refresh screenshots if UI is disabled/blocked/dialog is up --- AngelLoader/Forms/MainForm.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index cb94fa34f..41eb0f15f 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5336,5 +5336,11 @@ public void ShowUpdateNotification(bool show) // We might want to change this, if we want something beside the readme or whatever internal Control ReadmeContainer => MainSplitContainer.Panel2; - public void RefreshCurrentFMScreenshots() => ScreenshotsTabPage.RefreshScreenshots(); + public void RefreshCurrentFMScreenshots() + { + if (UIEnabled && !ViewBlocked && CanFocus) + { + ScreenshotsTabPage.RefreshScreenshots(); + } + } } From f6f562bbe5d781baddf3600111062f1c15f717a0 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 12:18:29 -0800 Subject: [PATCH 055/200] Rename --- AngelLoader/Common/Misc.cs | 4 ++-- AngelLoader/Core.cs | 4 ++-- AngelLoader/FMAudio.cs | 2 +- AngelLoader/FMDelete.cs | 2 +- AngelLoader/FMInstallAndPlay.cs | 14 +++++++------- AngelLoader/FindFMs.cs | 4 ++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/AngelLoader/Common/Misc.cs b/AngelLoader/Common/Misc.cs index 0bd816857..39c971e15 100644 --- a/AngelLoader/Common/Misc.cs +++ b/AngelLoader/Common/Misc.cs @@ -215,7 +215,7 @@ internal static class Defaults ".tiff" }; - public sealed class FMInstalledDirModificationScope : IDisposable + public sealed class DisableScreenshotWatchers : IDisposable { /* IMPORTANT! @THREADING(FMInstalledDirModificationScope): @@ -227,7 +227,7 @@ Needs testing. private readonly bool[] _originalValues = new bool[SupportedGameCount]; - public FMInstalledDirModificationScope() + public DisableScreenshotWatchers() { if (_count == 0) { diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index b0c3c9236..b577941de 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -1591,7 +1591,7 @@ internal static bool AddDML(FanMission fm, string sourceDMLPath) return false; } - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); try { @@ -1620,7 +1620,7 @@ internal static bool RemoveDML(FanMission fm, string dmlFile) return false; } - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); try { diff --git a/AngelLoader/FMAudio.cs b/AngelLoader/FMAudio.cs index 8b16ab652..e5f82ace7 100644 --- a/AngelLoader/FMAudio.cs +++ b/AngelLoader/FMAudio.cs @@ -43,7 +43,7 @@ internal static class FMAudio internal static async Task ConvertSelected(AudioConvert convertType) { - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); List fms = Core.View.GetSelectedFMs_InOrder_List(); if (fms.Count == 0) return; diff --git a/AngelLoader/FMDelete.cs b/AngelLoader/FMDelete.cs index 03b6d9d19..46af5118c 100644 --- a/AngelLoader/FMDelete.cs +++ b/AngelLoader/FMDelete.cs @@ -196,7 +196,7 @@ private static (bool Success, List FinalArchives) // * NIGHTMARE REALM * internal static async Task DeleteFMsFromDisk(List fms) { - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); int origCount = fms.Count; diff --git a/AngelLoader/FMInstallAndPlay.cs b/AngelLoader/FMInstallAndPlay.cs index b3b0fcc1f..1385eae87 100644 --- a/AngelLoader/FMInstallAndPlay.cs +++ b/AngelLoader/FMInstallAndPlay.cs @@ -64,7 +64,7 @@ private enum PlaySource internal static async Task InstallOrUninstall(FanMission[] fms) { - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); AssertR(fms.Length > 0, nameof(fms) + ".Length == 0"); FanMission firstFM = fms[0]; @@ -117,7 +117,7 @@ private static bool SelectTdmFM(FanMission? fm, bool deselect = false) internal static async Task InstallIfNeededAndPlay(FanMission fm, bool askConfIfRequired = false, bool playMP = false) { - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); if (!fm.Game.ConvertsToKnownAndSupported(out GameIndex gameIndex)) { @@ -195,7 +195,7 @@ await InstallInternal(fromPlay: true, suppressConfirmation: askingConfirmation, internal static bool PlayOriginalGame(GameIndex gameIndex, bool playMP = false) { - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); try { @@ -261,7 +261,7 @@ internal static bool PlayOriginalGame(GameIndex gameIndex, bool playMP = false) private static bool PlayFM(FanMission fm, GameIndex gameIndex, bool playMP = false) { - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); (bool success, string gameExe, string gamePath) = CheckAndReturnFinalGameExeAndGamePath(gameIndex, playingOriginalGame: false, playMP); @@ -390,7 +390,7 @@ DOES have the desired effect. internal static bool OpenFMInEditor(FanMission fm) { - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); try { @@ -1444,7 +1444,7 @@ private sealed class Buffers internal static Task Install(params FanMission[] fms) { - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); return InstallInternal(false, false, fms); } @@ -2032,7 +2032,7 @@ void ReportProgress(Fen7z.ProgressReport pr) internal static async Task<(bool Success, bool AtLeastOneFMMarkedUnavailable)> Uninstall(FanMission[] fms, bool doEndTasks = true) { - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); var fail = (false, false); diff --git a/AngelLoader/FindFMs.cs b/AngelLoader/FindFMs.cs index 809066d59..fe43543c8 100644 --- a/AngelLoader/FindFMs.cs +++ b/AngelLoader/FindFMs.cs @@ -216,7 +216,7 @@ internal static (List FMsViewListUnscanned, Exception? Ex) // tasks or anything here... just return an exception and handle it on the main thread... try { - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); List fmsViewListUnscanned = FindInternal(startup: true); splashScreen.SetCheckAtStoredMessageWidth(); @@ -236,7 +236,7 @@ internal static List Find() { AssertR(Core.View != null!, "View was null during FindFMs.Find() call"); - using var fmInstDirModScope = new FMInstalledDirModificationScope(); + using var fmInstDirModScope = new DisableScreenshotWatchers(); List fmsViewListUnscanned = FindInternal(startup: false); Core.View!.SetAvailableAndFinishedFMCount(); From 6693143caba892d5e760de991d0a61788870ae1e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 12:45:11 -0800 Subject: [PATCH 056/200] Screenshots cleanup work: -Move all screenshots-related code to new Screenshots.cs -Make screenshots watcher timer non-static (copy-paste mistake) -Make screenshots watcher time lazy-loaded as well -Move watchers array from Config to static Screenshots class --- AngelLoader/Common/DataClasses/ConfigData.cs | 17 - .../DataClasses/ConfigDataSupporting.cs | 174 -------- AngelLoader/Common/Misc.cs | 44 --- AngelLoader/Core.cs | 138 +------ AngelLoader/FindFMs.cs | 1 - .../TopRightPages/ScreenshotsTabPage.cs | 4 +- AngelLoader/Screenshots.cs | 371 ++++++++++++++++++ 7 files changed, 374 insertions(+), 375 deletions(-) create mode 100644 AngelLoader/Screenshots.cs diff --git a/AngelLoader/Common/DataClasses/ConfigData.cs b/AngelLoader/Common/DataClasses/ConfigData.cs index aa5d245b0..5e3a88a53 100644 --- a/AngelLoader/Common/DataClasses/ConfigData.cs +++ b/AngelLoader/Common/DataClasses/ConfigData.cs @@ -37,8 +37,6 @@ internal ConfigData() GameFilterControlVisibilities = new bool[SupportedGameCount]; - _screenshotWatchers = new ScreenshotWatcher[SupportedGameCount]; - #endregion FilterControlVisibilities = InitializedArray(HideableFilterControlsCount, true); @@ -56,8 +54,6 @@ internal ConfigData() _startupFMSelectorLines[i] = new List(); GameFilterControlVisibilities[i] = true; - - _screenshotWatchers[i] = new ScreenshotWatcher((GameIndex)i); } // Must set the display indexes, otherwise we crash! @@ -70,19 +66,6 @@ internal ConfigData() //internal int Version = 1; - #region Screenshot watchers - - /* - @ScreenshotDisplay: These contain disposable objects (not initialized to start with, but still) - When Settings instantiates a new Config object, it will construct this set too. That won't currently result - in the disposable FileSystemWatcher objects being instantiated so it's fine, but we should maybe put this - somewhere else and make it static, because it's supposed to live for the live of the app. - */ - private readonly ScreenshotWatcher[] _screenshotWatchers; - internal ScreenshotWatcher GetScreenshotWatcher(GameIndex gameIndex) => _screenshotWatchers[(int)gameIndex]; - - #endregion - #region Saved-on-startup loader config values #region fm_selector lines diff --git a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs index e34c8136e..1570c1ac8 100644 --- a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs +++ b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs @@ -2,14 +2,12 @@ using System; using System.Collections.Generic; -using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using AL_Common; using static AL_Common.Common; using static AL_Common.FenGenAttributes; using static AngelLoader.GameSupport; -using static AngelLoader.Global; using static AngelLoader.Misc; namespace AngelLoader.DataClasses; @@ -473,175 +471,3 @@ internal Mod(string internalName, ModType type) IsUber = type is ModType.UberModPath or ModType.MPUberModPath; } } - -// @ScreenshotDisplay: Cleanup test Trace.WriteLines etc. -public sealed class ScreenshotWatcher -{ - private sealed class ScreenshotWatcherTimer(double interval) : System.Timers.Timer(interval) - { - internal string FullPath { get; private set; } = ""; - internal WatcherChangeTypes ChangeType { get; private set; } - - internal void ResetWith(string fullPath, WatcherChangeTypes changeType) - { - this.Reset(); - FullPath = fullPath; - ChangeType = changeType; - } - } - - private bool _constructed; - private FileSystemWatcher _watcher = null!; - - private readonly GameIndex _gameIndex; - - private static readonly ScreenshotWatcherTimer _timer = new(1000) { Enabled = false, AutoReset = false }; - - private string _path = ""; - public string Path - { - get => _constructed ? _watcher.Path : _path; - set - { - if (_constructed) - { - try - { - _watcher.Path = value; - } - catch - { - EnableWatching = false; - } - } - else - { - _path = value; - } - } - } - - private bool _enableWatching; - public bool EnableWatching - { - get => _constructed ? _watcher.EnableRaisingEvents : _enableWatching; - set - { - if (_constructed) - { - try - { - _watcher.EnableRaisingEvents = value; - } - catch - { - try - { - _watcher.EnableRaisingEvents = false; - } - catch - { - // ignore - } - } - } - else - { - _enableWatching = value; - } - } - } - - public ScreenshotWatcher(GameIndex gameIndex) - { - _gameIndex = gameIndex; - _timer.Elapsed += Timer_Elapsed; - } - - public void Construct() - { - if (_constructed) return; - if (_path.IsEmpty()) return; - - try - { - _watcher = new FileSystemWatcher(Path); - _watcher.Changed += Watcher_ChangedCreatedDeleted; - _watcher.Created += Watcher_ChangedCreatedDeleted; - _watcher.Deleted += Watcher_ChangedCreatedDeleted; - _watcher.Renamed += Watcher_Renamed; - _watcher.IncludeSubdirectories = true; - _watcher.EnableRaisingEvents = EnableWatching; - } - catch - { - _constructed = false; - return; - } - - _constructed = true; - } - - private void Watcher_ChangedCreatedDeleted(object sender, FileSystemEventArgs e) - { - //Trace.WriteLine(nameof(Watcher_ChangedCreatedDeleted) + ": " + e.ChangeType + "\r\n" + e.FullPath); - _timer.ResetWith(e.FullPath, e.ChangeType); - } - - private void Watcher_Renamed(object sender, RenamedEventArgs e) - { - //Trace.WriteLine(nameof(Watcher_Renamed) + ": " + e.ChangeType + "\r\n" + e.OldFullPath); - _timer.ResetWith(e.OldFullPath, e.ChangeType); - } - - private void HandleEvent(string fullPath, WatcherChangeTypes changeType) => Core.View.Invoke(() => - { - if (!_constructed) return; - if (!EnableWatching) return; - - FanMission? fm = Core.View.GetMainSelectedFMOrNull(); - if (fm == null) return; - if (!fm.Game.ConvertsToKnownAndSupported(out GameIndex gameIndex)) return; - if (gameIndex != _gameIndex) return; - - fullPath = fullPath.ToForwardSlashes_Net(); - - string screenshotsParentDir; - - // @GENGAMES(Screenshots watcher) - if (gameIndex == GameIndex.TDM) - { - string gamePath = Config.GetGamePath(GameIndex.TDM).ToForwardSlashes_Net(); - if (gamePath.IsEmpty()) return; - screenshotsParentDir = gamePath.GetDirNameFast(); - } - else - { - screenshotsParentDir = fm.RealInstalledDir; - } - - string fmPlusScreenshotsPathSegment = "/" + screenshotsParentDir + "/screenshots"; - if (fullPath.ContainsI(fmPlusScreenshotsPathSegment + "/") || - fullPath.PathEndsWithI(fmPlusScreenshotsPathSegment)) - { - /* - @ScreenshotDisplay: If this is enabled, it's possible a non-matching change will override the matching one. - Unlikely, but meh. But if we disable it, then any TDM FM will attempt refresh if anything in the - central screenshots dir gets modified, even if doesn't match our FM name. Also not a big deal. We - could fix both cases by keeping a list of filenames and then checking if our name exists in it, and - refreshing then. - */ - //if (gameIndex != GameIndex.TDM || Core.ScreenshotFileMatchesTDMName(fm.TDMInstalledDir, fullPath.GetFileNameFast())) - { - //System.Diagnostics.Trace.WriteLine("---------------------------------------------- Refreshing"); - Core.View.RefreshCurrentFMScreenshots(); - } - } - }); - - private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) - { - if (Core.View == null!) return; - HandleEvent(_timer.FullPath, _timer.ChangeType); - } -} diff --git a/AngelLoader/Common/Misc.cs b/AngelLoader/Common/Misc.cs index 39c971e15..4231747a9 100644 --- a/AngelLoader/Common/Misc.cs +++ b/AngelLoader/Common/Misc.cs @@ -3,10 +3,8 @@ using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Threading.Tasks; -using AL_Common; using AngelLoader.DataClasses; using static AngelLoader.GameSupport; -using static AngelLoader.Global; namespace AngelLoader; @@ -214,46 +212,4 @@ internal static class Defaults ".tif", ".tiff" }; - - public sealed class DisableScreenshotWatchers : IDisposable - { - /* - IMPORTANT! @THREADING(FMInstalledDirModificationScope): - If we ever make it so that things can go in parallel (install/uninstall, scan, delete, etc.), this will - no longer be safe! We're threading noobs so we don't know if volatile will solve the problem or what. - Needs testing. - */ - private static int _count; - - private readonly bool[] _originalValues = new bool[SupportedGameCount]; - - public DisableScreenshotWatchers() - { - if (_count == 0) - { - for (int i = 0; i < SupportedGameCount; i++) - { - GameIndex gameIndex = (GameIndex)i; - ScreenshotWatcher watcher = Config.GetScreenshotWatcher(gameIndex); - _originalValues[i] = watcher.EnableWatching; - watcher.EnableWatching = false; - } - } - _count++; - } - - public void Dispose() - { - if (_count == 1) - { - for (int i = 0; i < SupportedGameCount; i++) - { - GameIndex gameIndex = (GameIndex)i; - ScreenshotWatcher watcher = Config.GetScreenshotWatcher(gameIndex); - watcher.EnableWatching = _originalValues[i]; - } - } - _count = (_count - 1).ClampToZero(); - } - } } diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index b577941de..a8f53210d 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -983,7 +983,7 @@ private static (SetGameDataError Error, bool EnableTDMWatchers, List? Ca // We don't set mod dirs for Thief 3 because it doesn't support programmatic mod enabling/disabling } - ScreenshotWatcher watcher = Config.GetScreenshotWatcher(gameIndex); + ScreenshotWatcher watcher = Screenshots.GetScreenshotWatcher(gameIndex); string fmInstallPath = Config.GetFMInstallPath(gameIndex); try { @@ -2812,140 +2812,4 @@ internal static VisualTheme GetSystemTheme() return VisualTheme.Classic; } - - /// - /// If there are screenshots on disk, will contain their full names. - /// If there are none, or if is , will be empty. - /// - /// - /// - internal static void PopulateScreenshotFileNames(FanMission? fm, List screenshotFileNames) - { - screenshotFileNames.Clear(); - if (fm == null) return; - if (!GameIsKnownAndSupported(fm.Game)) return; - - // @GENGAMES(Screenshots) - if (fm.Game == Game.TDM) - { - /* - TDM screenshot filename formats: - - Format 1 (1.08 - 2.10): - mapname + "_%Y-%m-%d_%H.%M.%S." + extension - Example: river1_1_2016-11-03_21.47.21.png - Extracted fm name should be "river1_1" - - Format 2 (2.11+): - mapname + " (%Y-%m-%d %H-%M-%S) (" + playerViewOriginStr + ")." + extension - Example: written (2023-10-03 20-19-23) (889.44 -1464.35 174.68).jpg - Extracted fm name should be "written" - */ - - string tdmGamePath = Config.GetGamePath(GameIndex.TDM); - if (!tdmGamePath.IsEmpty() && - /* - TDM stores all FMs' screenshots in the same dir. To prevent having to get the entire set (which - could be very large), just get ones starting with our FM name and do a proper filter afterwards. - */ - TryGetSortedScreenshotFileInfos(tdmGamePath, fm.TDMInstalledDir + "*.*", out FileInfo[]? files)) - { - for (int i = 0; i < files.Length; i++) - { - FileInfo item = files[i]; - string fn = item.Name; - - if (ScreenshotFileMatchesTDMName(fm.TDMInstalledDir, fn)) - { - AddIfValidFormat(screenshotFileNames, item.FullName); - } - } - } - } - else - { - if (fm.Installed && FMIsReallyInstalled(fm, out string fmInstalledPath) && - TryGetSortedScreenshotFileInfos(fmInstalledPath, "*", out FileInfo[]? files)) - { - for (int i = 0; i < files.Length; i++) - { - AddIfValidFormat(screenshotFileNames, files[i].FullName); - } - } - } - - return; - - static bool TryGetSortedScreenshotFileInfos( - string screenshotsDirParentPath, - string pattern, - [NotNullWhen(true)] out FileInfo[]? screenshots) - { - // @ScreenshotDisplay: Performance... we need a custom FileInfo getter without the 8.3 stuff - try - { - /* - @ScreenshotDisplay(Thief 3 central screenshots): - These get put into one directory with the FM mission name (not overall FM name!) at the start of - the file. For example, "All The World's A Stage" screenshots get prefixed "Bohn Street Theatre". - These names are listed in \CONTENT\T3\Books\English\String_Tags\Misc.sch but also in other languages - so we'd have to check every one of them, which also means we can't make one single search pattern, - so we'd have a performance issue too. It's not even close to worth it to try to do this, so we're - just not supporting central screenshots for Thief 3 right now. - */ - string ssPath = Path.Combine(screenshotsDirParentPath, "screenshots"); - DirectoryInfo di = new(ssPath); - // Standard practice is to let the GetFiles() call throw if the directory doesn't exist, but for - // some reason that takes ~30ms whereas this check is <2ms (cold) to <.1ms (warm). - if (!di.Exists) - { - screenshots = null; - return false; - } - screenshots = di.GetFiles(pattern); - Comparers.Screenshot.SortDirection = SortDirection.Descending; - Array.Sort(screenshots, Comparers.Screenshot); - return true; - } - catch - { - screenshots = null; - return false; - } - } - - static void AddIfValidFormat(List screenshotFileNames, string filename) - { - if (filename.ExtIsUISupportedImage()) - { - screenshotFileNames.Add(filename); - } - } - } - - internal static bool ScreenshotFileMatchesTDMName(string tdmInstalledDir, string fn) - { - int spaceIndex = fn.IndexOf(' '); - // @TDM_CASE: Screenshot FM name comparison - if (spaceIndex > -1 && fn.Substring(0, spaceIndex).Trim().EqualsI(tdmInstalledDir)) - { - return true; - } - else - { - int underscoreIndex = fn.LastIndexOf('_'); - if (underscoreIndex == -1) return false; - - int secondToLastUnderscoreIndex = fn.LastIndexOf('_', (underscoreIndex - 1).ClampToZero()); - if (secondToLastUnderscoreIndex <= -1) return false; - - // @TDM_CASE: Screenshot FM name comparison - if (fn.Substring(0, secondToLastUnderscoreIndex).Trim().EqualsI(tdmInstalledDir)) - { - return true; - } - } - - return false; - } } diff --git a/AngelLoader/FindFMs.cs b/AngelLoader/FindFMs.cs index fe43543c8..510707789 100644 --- a/AngelLoader/FindFMs.cs +++ b/AngelLoader/FindFMs.cs @@ -8,7 +8,6 @@ using static AL_Common.Logger; using static AngelLoader.GameSupport; using static AngelLoader.Global; -using static AngelLoader.Misc; using static AngelLoader.Utils; namespace AngelLoader; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 117b35c2f..f64980383 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -122,10 +122,10 @@ private void UpdatePageInternal(bool forceUpdate) FanMission? fm = _owner.GetMainSelectedFMOrNull(); if (fm != null && fm.Game.ConvertsToKnownAndSupported(out GameIndex gameIndex)) { - Config.GetScreenshotWatcher(gameIndex).Construct(); + Screenshots.GetScreenshotWatcher(gameIndex).Construct(); } - Core.PopulateScreenshotFileNames(fm, ScreenshotFileNames); + Screenshots.PopulateScreenshotFileNames(fm, ScreenshotFileNames); // @ScreenshotDisplay: Should we hide everything and just put a label "No screenshots"? if (ScreenshotFileNames.Count == 0) diff --git a/AngelLoader/Screenshots.cs b/AngelLoader/Screenshots.cs new file mode 100644 index 000000000..eba46d684 --- /dev/null +++ b/AngelLoader/Screenshots.cs @@ -0,0 +1,371 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using AngelLoader.DataClasses; +using static AL_Common.Common; +using static AngelLoader.GameSupport; +using static AngelLoader.Global; +using static AngelLoader.Misc; +using static AngelLoader.Utils; + +namespace AngelLoader; + +// @ScreenshotDisplay: Cleanup test Trace.WriteLines etc. +public sealed class ScreenshotWatcher(GameIndex _gameIndex) +{ + private sealed class ScreenshotWatcherTimer(double interval) : System.Timers.Timer(interval) + { + internal string FullPath { get; private set; } = ""; + internal WatcherChangeTypes ChangeType { get; private set; } + + internal void ResetWith(string fullPath, WatcherChangeTypes changeType) + { + this.Reset(); + FullPath = fullPath; + ChangeType = changeType; + } + } + + private bool _constructed; + private FileSystemWatcher _watcher = null!; + + private ScreenshotWatcherTimer _timer = null!; + + private string _path = ""; + public string Path + { + get => _constructed ? _watcher.Path : _path; + set + { + if (_constructed) + { + try + { + _watcher.Path = value; + } + catch + { + EnableWatching = false; + } + } + else + { + _path = value; + } + } + } + + private bool _enableWatching; + public bool EnableWatching + { + get => _constructed ? _watcher.EnableRaisingEvents : _enableWatching; + set + { + if (_constructed) + { + try + { + _watcher.EnableRaisingEvents = value; + } + catch + { + try + { + _watcher.EnableRaisingEvents = false; + } + catch + { + // ignore + } + } + } + else + { + _enableWatching = value; + } + } + } + + public void Construct() + { + if (_constructed) return; + if (_path.IsEmpty()) return; + + try + { + _watcher = new FileSystemWatcher(Path); + _watcher.Changed += Watcher_ChangedCreatedDeleted; + _watcher.Created += Watcher_ChangedCreatedDeleted; + _watcher.Deleted += Watcher_ChangedCreatedDeleted; + _watcher.Renamed += Watcher_Renamed; + _watcher.IncludeSubdirectories = true; + _watcher.EnableRaisingEvents = EnableWatching; + + _timer = new ScreenshotWatcherTimer(1000) { Enabled = false, AutoReset = false }; + _timer.Elapsed += Timer_Elapsed; + } + catch + { + _constructed = false; + return; + } + + _constructed = true; + } + + private void Watcher_ChangedCreatedDeleted(object sender, FileSystemEventArgs e) + { + //Trace.WriteLine(nameof(Watcher_ChangedCreatedDeleted) + ": " + e.ChangeType + "\r\n" + e.FullPath); + _timer.ResetWith(e.FullPath, e.ChangeType); + } + + private void Watcher_Renamed(object sender, RenamedEventArgs e) + { + //Trace.WriteLine(nameof(Watcher_Renamed) + ": " + e.ChangeType + "\r\n" + e.OldFullPath); + _timer.ResetWith(e.OldFullPath, e.ChangeType); + } + + private void HandleEvent(string fullPath, WatcherChangeTypes changeType) => Core.View.Invoke(() => + { + if (!_constructed) return; + if (!EnableWatching) return; + + FanMission? fm = Core.View.GetMainSelectedFMOrNull(); + if (fm == null) return; + if (!fm.Game.ConvertsToKnownAndSupported(out GameIndex gameIndex)) return; + if (gameIndex != _gameIndex) return; + + fullPath = fullPath.ToForwardSlashes_Net(); + + string screenshotsParentDir; + + // @GENGAMES(Screenshots watcher) + if (gameIndex == GameIndex.TDM) + { + string gamePath = Config.GetGamePath(GameIndex.TDM).ToForwardSlashes_Net(); + if (gamePath.IsEmpty()) return; + screenshotsParentDir = gamePath.GetDirNameFast(); + } + else + { + screenshotsParentDir = fm.RealInstalledDir; + } + + string fmPlusScreenshotsPathSegment = "/" + screenshotsParentDir + "/screenshots"; + if (fullPath.ContainsI(fmPlusScreenshotsPathSegment + "/") || + fullPath.PathEndsWithI(fmPlusScreenshotsPathSegment)) + { + /* + @ScreenshotDisplay: If this is enabled, it's possible a non-matching change will override the matching one. + Unlikely, but meh. But if we disable it, then any TDM FM will attempt refresh if anything in the + central screenshots dir gets modified, even if doesn't match our FM name. Also not a big deal. We + could fix both cases by keeping a list of filenames and then checking if our name exists in it, and + refreshing then. + */ + //if (gameIndex != GameIndex.TDM || Core.ScreenshotFileMatchesTDMName(fm.TDMInstalledDir, fullPath.GetFileNameFast())) + { + //System.Diagnostics.Trace.WriteLine("---------------------------------------------- Refreshing"); + Core.View.RefreshCurrentFMScreenshots(); + } + } + }); + + private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + if (Core.View == null!) return; + HandleEvent(_timer.FullPath, _timer.ChangeType); + } +} + +public sealed class DisableScreenshotWatchers : IDisposable +{ + /* + IMPORTANT! @THREADING(FMInstalledDirModificationScope): + If we ever make it so that things can go in parallel (install/uninstall, scan, delete, etc.), this will + no longer be safe! We're threading noobs so we don't know if volatile will solve the problem or what. + Needs testing. + */ + private static int _count; + + private readonly bool[] _originalValues = new bool[SupportedGameCount]; + + public DisableScreenshotWatchers() + { + if (_count == 0) + { + for (int i = 0; i < SupportedGameCount; i++) + { + GameIndex gameIndex = (GameIndex)i; + ScreenshotWatcher watcher = Screenshots.GetScreenshotWatcher(gameIndex); + _originalValues[i] = watcher.EnableWatching; + watcher.EnableWatching = false; + } + } + _count++; + } + + public void Dispose() + { + if (_count == 1) + { + for (int i = 0; i < SupportedGameCount; i++) + { + GameIndex gameIndex = (GameIndex)i; + ScreenshotWatcher watcher = Screenshots.GetScreenshotWatcher(gameIndex); + watcher.EnableWatching = _originalValues[i]; + } + } + _count = (_count - 1).ClampToZero(); + } +} + +internal static class Screenshots +{ + private static readonly ScreenshotWatcher[] _screenshotWatchers = new ScreenshotWatcher[SupportedGameCount]; + internal static ScreenshotWatcher GetScreenshotWatcher(GameIndex gameIndex) => _screenshotWatchers[(int)gameIndex]; + + static Screenshots() + { + for (int i = 0; i < SupportedGameCount; i++) + { + _screenshotWatchers[i] = new ScreenshotWatcher((GameIndex)i); + } + } + + /// + /// If there are screenshots on disk, will contain their full names. + /// If there are none, or if is , will be empty. + /// + /// + /// + internal static void PopulateScreenshotFileNames(FanMission? fm, List screenshotFileNames) + { + screenshotFileNames.Clear(); + if (fm == null) return; + if (!GameIsKnownAndSupported(fm.Game)) return; + + // @GENGAMES(Screenshots) + if (fm.Game == Game.TDM) + { + /* + TDM screenshot filename formats: + + Format 1 (1.08 - 2.10): + mapname + "_%Y-%m-%d_%H.%M.%S." + extension + Example: river1_1_2016-11-03_21.47.21.png + Extracted fm name should be "river1_1" + + Format 2 (2.11+): + mapname + " (%Y-%m-%d %H-%M-%S) (" + playerViewOriginStr + ")." + extension + Example: written (2023-10-03 20-19-23) (889.44 -1464.35 174.68).jpg + Extracted fm name should be "written" + */ + + string tdmGamePath = Config.GetGamePath(GameIndex.TDM); + if (!tdmGamePath.IsEmpty() && + /* + TDM stores all FMs' screenshots in the same dir. To prevent having to get the entire set (which + could be very large), just get ones starting with our FM name and do a proper filter afterwards. + */ + TryGetSortedScreenshotFileInfos(tdmGamePath, fm.TDMInstalledDir + "*.*", out FileInfo[]? files)) + { + for (int i = 0; i < files.Length; i++) + { + FileInfo item = files[i]; + string fn = item.Name; + + if (ScreenshotFileMatchesTDMName(fm.TDMInstalledDir, fn)) + { + AddIfValidFormat(screenshotFileNames, item.FullName); + } + } + } + } + else + { + if (fm.Installed && FMIsReallyInstalled(fm, out string fmInstalledPath) && + TryGetSortedScreenshotFileInfos(fmInstalledPath, "*", out FileInfo[]? files)) + { + for (int i = 0; i < files.Length; i++) + { + AddIfValidFormat(screenshotFileNames, files[i].FullName); + } + } + } + + return; + + static bool TryGetSortedScreenshotFileInfos( + string screenshotsDirParentPath, + string pattern, + [NotNullWhen(true)] out FileInfo[]? screenshots) + { + // @ScreenshotDisplay: Performance... we need a custom FileInfo getter without the 8.3 stuff + try + { + /* + @ScreenshotDisplay(Thief 3 central screenshots): + These get put into one directory with the FM mission name (not overall FM name!) at the start of + the file. For example, "All The World's A Stage" screenshots get prefixed "Bohn Street Theatre". + These names are listed in \CONTENT\T3\Books\English\String_Tags\Misc.sch but also in other languages + so we'd have to check every one of them, which also means we can't make one single search pattern, + so we'd have a performance issue too. It's not even close to worth it to try to do this, so we're + just not supporting central screenshots for Thief 3 right now. + */ + string ssPath = Path.Combine(screenshotsDirParentPath, "screenshots"); + DirectoryInfo di = new(ssPath); + // Standard practice is to let the GetFiles() call throw if the directory doesn't exist, but for + // some reason that takes ~30ms whereas this check is <2ms (cold) to <.1ms (warm). + if (!di.Exists) + { + screenshots = null; + return false; + } + screenshots = di.GetFiles(pattern); + Comparers.Screenshot.SortDirection = SortDirection.Descending; + Array.Sort(screenshots, Comparers.Screenshot); + return true; + } + catch + { + screenshots = null; + return false; + } + } + + static void AddIfValidFormat(List screenshotFileNames, string filename) + { + if (filename.ExtIsUISupportedImage()) + { + screenshotFileNames.Add(filename); + } + } + } + + internal static bool ScreenshotFileMatchesTDMName(string tdmInstalledDir, string fn) + { + int spaceIndex = fn.IndexOf(' '); + // @TDM_CASE: Screenshot FM name comparison + if (spaceIndex > -1 && fn.Substring(0, spaceIndex).Trim().EqualsI(tdmInstalledDir)) + { + return true; + } + else + { + int underscoreIndex = fn.LastIndexOf('_'); + if (underscoreIndex == -1) return false; + + int secondToLastUnderscoreIndex = fn.LastIndexOf('_', (underscoreIndex - 1).ClampToZero()); + if (secondToLastUnderscoreIndex <= -1) return false; + + // @TDM_CASE: Screenshot FM name comparison + if (fn.Substring(0, secondToLastUnderscoreIndex).Trim().EqualsI(tdmInstalledDir)) + { + return true; + } + } + + return false; + } +} From 60490a2645c65dd590ad44f4d82f7e58865ca403 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 12:48:19 -0800 Subject: [PATCH 057/200] Cleanup --- AngelLoader/Screenshots.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AngelLoader/Screenshots.cs b/AngelLoader/Screenshots.cs index eba46d684..7a7b7c960 100644 --- a/AngelLoader/Screenshots.cs +++ b/AngelLoader/Screenshots.cs @@ -163,7 +163,7 @@ private void HandleEvent(string fullPath, WatcherChangeTypes changeType) => Core could fix both cases by keeping a list of filenames and then checking if our name exists in it, and refreshing then. */ - //if (gameIndex != GameIndex.TDM || Core.ScreenshotFileMatchesTDMName(fm.TDMInstalledDir, fullPath.GetFileNameFast())) + //if (gameIndex != GameIndex.TDM || Screenshots.ScreenshotFileMatchesTDMName(fm.TDMInstalledDir, fullPath.GetFileNameFast())) { //System.Diagnostics.Trace.WriteLine("---------------------------------------------- Refreshing"); Core.View.RefreshCurrentFMScreenshots(); From 7fc3921d95d8fa595fde1a011f99825e58178788 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 12:56:47 -0800 Subject: [PATCH 058/200] Note about TrackBar visual glitch --- AngelLoader/Forms/CustomControls/DarkTrackBar.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AngelLoader/Forms/CustomControls/DarkTrackBar.cs b/AngelLoader/Forms/CustomControls/DarkTrackBar.cs index 5b82ec403..05c5405f1 100644 --- a/AngelLoader/Forms/CustomControls/DarkTrackBar.cs +++ b/AngelLoader/Forms/CustomControls/DarkTrackBar.cs @@ -6,6 +6,9 @@ namespace AngelLoader.Forms.CustomControls; +// @ScreenshotDisplay: TrackBar white flickering on game close +// TrackBars (even stock ones) seem to have this white-flicker problem on game close (I guess when a game window +// disappears and the app window is revealed?). See if we can figure out a fix or workaround. public sealed class DarkTrackBar : TrackBar, IDarkable { [PublicAPI] From 970b8992a85c45e7925f300469b2c02958a4ed61 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 13:16:48 -0800 Subject: [PATCH 059/200] Fix white flicker on TrackBar --- AngelLoader/Forms/CustomControls/DarkTrackBar.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTrackBar.cs b/AngelLoader/Forms/CustomControls/DarkTrackBar.cs index 05c5405f1..a3cef3118 100644 --- a/AngelLoader/Forms/CustomControls/DarkTrackBar.cs +++ b/AngelLoader/Forms/CustomControls/DarkTrackBar.cs @@ -2,13 +2,11 @@ using System.Drawing; using System.Windows.Forms; using AngelLoader.DataClasses; +using AngelLoader.Forms.WinFormsNative; using JetBrains.Annotations; namespace AngelLoader.Forms.CustomControls; -// @ScreenshotDisplay: TrackBar white flickering on game close -// TrackBars (even stock ones) seem to have this white-flicker problem on game close (I guess when a game window -// disappears and the app window is revealed?). See if we can figure out a fix or workaround. public sealed class DarkTrackBar : TrackBar, IDarkable { [PublicAPI] @@ -31,4 +29,12 @@ public bool DarkModeEnabled BackColor = _darkModeEnabled ? DarkModeDrawnBackColor : DrawnBackColor; } } + + protected override void WndProc(ref Message m) + { + // Prevents white flicker when the main window redraws in certain cases (restore from minimize, game + // window closing, etc.) + if (m.Msg == Native.WM_ERASEBKGND) return; + base.WndProc(ref m); + } } From efd30d3b438b5f01c49cde98a1a996deb9a68734 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 13:43:56 -0800 Subject: [PATCH 060/200] Screenshots work: -Copy image on click -Add tooltip saying such -Remove refresh button now that we're auto-refreshing --- AngelLoader/Common/DataClasses/LocalizationData.cs | 1 + .../TopRightPages/Lazy_ScreenshotsPage.Designer.cs | 12 ------------ .../TopRightPages/Lazy_ScreenshotsPage.cs | 13 ------------- .../Lazy_ScreenshotsPage_InitSlim.Generated.cs | 10 ---------- .../TopRightPages/ScreenshotsTabPage.cs | 9 +++++++-- AngelLoader/Languages/English.ini | 1 + 6 files changed, 9 insertions(+), 37 deletions(-) diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 5e1374fe9..3147eeef1 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -631,6 +631,7 @@ internal sealed class ScreenshotsTab_Class { // @ScreenshotDisplay: Finalize this text, improve it if necessary etc. internal readonly string TabText = "Screenshots"; + internal readonly string CopyScreenshotToolTip = "Click to copy"; internal readonly string Gamma = "Gamma:"; internal readonly string ResetGammaToolTip = "Right-click to reset"; internal readonly string ScreenshotsFolderNotFound = "Screenshots folder not found."; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 663d455ab..20baf2b69 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -39,7 +39,6 @@ private void InitializeComponent() this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); - this.RefreshButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // @@ -124,22 +123,12 @@ private void InitializeComponent() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 0; // - // RefreshButton - // - this.RefreshButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.RefreshButton.Location = new System.Drawing.Point(6, 256); - this.RefreshButton.Name = "RefreshButton"; - this.RefreshButton.Size = new System.Drawing.Size(23, 23); - this.RefreshButton.TabIndex = 5; - this.RefreshButton.PaintCustom += new System.EventHandler(this.RefreshButton_PaintCustom); - // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); - this.Controls.Add(this.RefreshButton); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); @@ -167,5 +156,4 @@ private void InitializeComponent() internal DarkTrackBar GammaTrackBar; internal DarkLabel GammaLabel; internal DarkLabel CopiedMessageLabel; - internal DarkButton RefreshButton; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs index 05bb2d300..ec3d04afb 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs @@ -14,19 +14,6 @@ public Lazy_ScreenshotsPage() #endif } - private void RefreshButton_PaintCustom(object sender, PaintEventArgs e) - { - Rectangle cr = RefreshButton.ClientRectangle; - Images.PaintBitmapButton( - e, - RefreshButton.Enabled ? Images.Refresh : Images.GetDisabledImage(Images.Refresh), - scaledRect: new RectangleF( - cr.X + 2f, - cr.Y + 2f, - cr.Width - 4f, - cr.Height - 4f)); - } - private void OpenScreenshotsFolderButton_PaintCustom(object sender, PaintEventArgs e) { Image image = Images.Folder; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 1dfa33a71..9c53c668a 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -15,7 +15,6 @@ private void InitSlim() this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); - this.RefreshButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // @@ -86,21 +85,12 @@ private void InitSlim() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 0; // - // RefreshButton - // - this.RefreshButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.RefreshButton.Location = new System.Drawing.Point(6, 256); - this.RefreshButton.Size = new System.Drawing.Size(23, 23); - this.RefreshButton.TabIndex = 5; - this.RefreshButton.PaintCustom += new System.EventHandler(this.RefreshButton_PaintCustom); - // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); - this.Controls.Add(this.RefreshButton); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index f64980383..56d84318f 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -81,7 +81,8 @@ public override void Construct() CopiedMessageFadeoutTimer.Interval = 2500; CopiedMessageFadeoutTimer.Tick += CopiedMessageFadeoutTimer_Tick; - _page.RefreshButton.Click += RefreshButton_Click; + _page.ScreenshotsPictureBox.MouseClick += ScreenshotsPictureBox_MouseClick; + _page.PrevButton.Click += ScreenshotsPrevButton_Click; _page.NextButton.Click += ScreenshotsNextButton_Click; _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; @@ -105,6 +106,7 @@ public override void Localize() if (!_constructed) return; _page.GammaLabel.Text = LText.ScreenshotsTab.Gamma; _owner.MainToolTip.SetToolTip(_page.GammaTrackBar, LText.ScreenshotsTab.ResetGammaToolTip); + _owner.MainToolTip.SetToolTip(_page.ScreenshotsPictureBox, LText.ScreenshotsTab.CopyScreenshotToolTip); } public void RefreshScreenshots() @@ -224,7 +226,10 @@ protected override void OnVisibleChanged(EventArgs e) } } - private void RefreshButton_Click(object sender, EventArgs e) => UpdatePageInternal(forceUpdate: true); + private void ScreenshotsPictureBox_MouseClick(object sender, MouseEventArgs e) + { + CopyImageToClipboard(); + } private void OpenScreenshotsFolderButton_Click(object sender, EventArgs e) { diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index 1a7fd03e9..312640044 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -489,6 +489,7 @@ Generic_ModsNotSupported=Mod management is not supported for unknown FMs. [ScreenshotsTab] TabText=Screenshots +CopyScreenshotToolTip=Click to copy Gamma=Gamma: ResetGammaToolTip=Right-click to reset ScreenshotsFolderNotFound=Screenshots folder not found. From 6b0a85e3fc8d14c074460f5c171465e7776b4290 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 13:57:59 -0800 Subject: [PATCH 061/200] Remove done todos and fix a missing constructed check And add a few more just for robustness --- AngelLoader/FMInstallAndPlay.cs | 3 -- .../TopRightPages/ScreenshotsTabPage.cs | 28 +++++-------------- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/AngelLoader/FMInstallAndPlay.cs b/AngelLoader/FMInstallAndPlay.cs index 1385eae87..bd49fe7e9 100644 --- a/AngelLoader/FMInstallAndPlay.cs +++ b/AngelLoader/FMInstallAndPlay.cs @@ -25,9 +25,6 @@ namespace AngelLoader; -// @ScreenshotDisplay(FM dir modification): -// Make a system for cleanly disabling/enabling screenshot watchers during modification of anything within the -// watched path (install/uninstall/audio convert etc.) internal static partial class FMInstallAndPlay { #region Private fields diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 56d84318f..3fa01da44 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,20 +1,4 @@ -/* -@ScreenshotDisplay: Options for watching screenshot folders and reloading from disk automatically - --Have one FileSystemWatcher and change its watch path every FM load. This will add time (up to 20-30ms iirc?) - to FM selection. It will also need to be turned off any time the FM installed directory is modified in some way - (install/uninstall/audio convert/etc.) to prevent a tsunami of events (perf). - --Have one FileSystemWatcher per game, and watch the FM install base dir (and global screenshots dir for TDM). - Again, it would need to be disabled during FM dir modifications (to ANY fm subdir!). This would prevent having - to set the watcher path for every FM selection change. The event handlers give us the affected filename, and we - can filter to just image types for perf. - -We could also have the watchers be wrapped in a lazy-loaded class that only loads them up when the screenshots -tab shows for the first time per game. -*/ - -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.IO; @@ -121,6 +105,8 @@ public void RefreshScreenshots() private void UpdatePageInternal(bool forceUpdate) { + if (!_constructed) return; + FanMission? fm = _owner.GetMainSelectedFMOrNull(); if (fm != null && fm.Game.ConvertsToKnownAndSupported(out GameIndex gameIndex)) { @@ -159,12 +145,14 @@ private void UpdatePageInternal(bool forceUpdate) // Manual right-align to avoid needing a FlowLayoutPanel private void SetNumberLabelText(string text) { + if (!_constructed) return; _page.NumberLabel.Text = text; SetNumberLabelPosition(); } private void SetNumberLabelPosition() { + if (!_constructed) return; _page.NumberLabel.Location = _page.NumberLabel.Location with { X = (_page.ClientSize.Width - 8) - _page.NumberLabel.Width @@ -173,6 +161,7 @@ private void SetNumberLabelPosition() private void ClearCurrentScreenshot() { + if (!_constructed) return; _page.ScreenshotsPictureBox.SetImage(null); _currentScreenshotStream?.Dispose(); } @@ -226,10 +215,7 @@ protected override void OnVisibleChanged(EventArgs e) } } - private void ScreenshotsPictureBox_MouseClick(object sender, MouseEventArgs e) - { - CopyImageToClipboard(); - } + private void ScreenshotsPictureBox_MouseClick(object sender, MouseEventArgs e) => CopyImageToClipboard(); private void OpenScreenshotsFolderButton_Click(object sender, EventArgs e) { From e24aed6027a616e2b0817db9c5cfdd1b7e4bf332 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 15:40:25 -0800 Subject: [PATCH 062/200] Add a delete button --- .../Lazy_ScreenshotsPage.Designer.cs | 12 ++++++ .../TopRightPages/Lazy_ScreenshotsPage.cs | 11 ++++++ ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 10 +++++ .../TopRightPages/ScreenshotsTabPage.cs | 37 +++++++++++++++++-- 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 20baf2b69..3ee3c2593 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -39,6 +39,7 @@ private void InitializeComponent() this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); + this.DeleteButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // @@ -123,12 +124,22 @@ private void InitializeComponent() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 0; // + // DeleteButton + // + this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.DeleteButton.Location = new System.Drawing.Point(8, 256); + this.DeleteButton.Name = "DeleteButton"; + this.DeleteButton.Size = new System.Drawing.Size(23, 23); + this.DeleteButton.TabIndex = 9; + this.DeleteButton.PaintCustom += new System.EventHandler(this.DeleteButton_PaintCustom); + // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.DeleteButton); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); @@ -156,4 +167,5 @@ private void InitializeComponent() internal DarkTrackBar GammaTrackBar; internal DarkLabel GammaLabel; internal DarkLabel CopiedMessageLabel; + internal DarkButton DeleteButton; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs index ec3d04afb..03063b805 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs @@ -24,4 +24,15 @@ private void OpenScreenshotsFolderButton_PaintCustom(object sender, PaintEventAr button.Enabled ? image : Images.GetDisabledImage(image), x: (button.Width - image.Width) / 2); } + + private void DeleteButton_PaintCustom(object sender, PaintEventArgs e) + { + Image image = Images.Trash; + DarkButton button = DeleteButton; + Images.PaintBitmapButton( + button, + e, + button.Enabled ? image : Images.GetDisabledImage(image), + x: (button.Width - image.Width) / 2); + } } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 9c53c668a..92ae08c9b 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -15,6 +15,7 @@ private void InitSlim() this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); + this.DeleteButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // @@ -85,12 +86,21 @@ private void InitSlim() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 0; // + // DeleteButton + // + this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.DeleteButton.Location = new System.Drawing.Point(8, 256); + this.DeleteButton.Size = new System.Drawing.Size(23, 23); + this.DeleteButton.TabIndex = 9; + this.DeleteButton.PaintCustom += new System.EventHandler(this.DeleteButton_PaintCustom); + // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.DeleteButton); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 3fa01da44..76967303b 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,10 +1,13 @@ -using System; +// @ScreenshotDisplay: Keep the place in the screenshot set on reload? + +using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Windows.Forms; using AL_Common; using AngelLoader.DataClasses; +using Microsoft.VisualBasic.FileIO; using static AngelLoader.GameSupport; using static AngelLoader.Global; @@ -67,9 +70,10 @@ public override void Construct() _page.ScreenshotsPictureBox.MouseClick += ScreenshotsPictureBox_MouseClick; + _page.DeleteButton.Click += DeleteButton_Click; + _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; _page.PrevButton.Click += ScreenshotsPrevButton_Click; _page.NextButton.Click += ScreenshotsNextButton_Click; - _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; _page.GammaTrackBar.Scroll += GammaTrackBar_Scroll; _page.GammaTrackBar.MouseDown += GammaTrackBar_MouseDown; @@ -120,9 +124,10 @@ private void UpdatePageInternal(bool forceUpdate) { CurrentScreenshotFileName = ""; ClearCurrentScreenshot(); - _page.GammaLabel.Enabled = false; _page.ScreenshotsPictureBox.Enabled = false; + _page.GammaLabel.Enabled = false; _page.GammaTrackBar.Enabled = false; + _page.DeleteButton.Enabled = false; _page.OpenScreenshotsFolderButton.Enabled = false; _page.PrevButton.Enabled = false; _page.NextButton.Enabled = false; @@ -133,9 +138,10 @@ private void UpdatePageInternal(bool forceUpdate) { CurrentScreenshotFileName = ScreenshotFileNames[0]; DisplayCurrentScreenshot(forceUpdate); - _page.GammaLabel.Enabled = true; _page.ScreenshotsPictureBox.Enabled = true; + _page.GammaLabel.Enabled = true; _page.GammaTrackBar.Enabled = true; + _page.DeleteButton.Enabled = true; _page.OpenScreenshotsFolderButton.Enabled = true; _page.PrevButton.Enabled = ScreenshotFileNames.Count > 1; _page.NextButton.Enabled = ScreenshotFileNames.Count > 1; @@ -217,6 +223,29 @@ protected override void OnVisibleChanged(EventArgs e) private void ScreenshotsPictureBox_MouseClick(object sender, MouseEventArgs e) => CopyImageToClipboard(); + // @ScreenshotDisplay(Delete): Somehow convey that this only sends them to the recycle bin + private void DeleteButton_Click(object sender, EventArgs e) + { + using var fmInstDirModScope = new DisableScreenshotWatchers(); + + if (!CurrentScreenshotFileName.IsEmpty()) + { + try + { + FileSystem.DeleteFile( + CurrentScreenshotFileName, + UIOption.OnlyErrorDialogs, + RecycleOption.SendToRecycleBin); + } + catch + { + // @ScreenshotDisplay: Do we want an error dialog here? + } + } + + UpdatePageInternal(forceUpdate: true); + } + private void OpenScreenshotsFolderButton_Click(object sender, EventArgs e) { Core.OpenFMScreenshotsFolder(_owner.FMsDGV.GetMainSelectedFM(), CurrentScreenshotFileName); From 28f69dc97e17566685bb86902498ae1af9bae997 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 15:42:10 -0800 Subject: [PATCH 063/200] Rename --- AngelLoader/Core.cs | 4 ++-- AngelLoader/FMAudio.cs | 2 +- AngelLoader/FMDelete.cs | 2 +- AngelLoader/FMInstallAndPlay.cs | 14 +++++++------- AngelLoader/FindFMs.cs | 4 ++-- .../TopRightPages/ScreenshotsTabPage.cs | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index a8f53210d..6441a9f9e 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -1591,7 +1591,7 @@ internal static bool AddDML(FanMission fm, string sourceDMLPath) return false; } - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); try { @@ -1620,7 +1620,7 @@ internal static bool RemoveDML(FanMission fm, string dmlFile) return false; } - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); try { diff --git a/AngelLoader/FMAudio.cs b/AngelLoader/FMAudio.cs index e5f82ace7..5e7385abb 100644 --- a/AngelLoader/FMAudio.cs +++ b/AngelLoader/FMAudio.cs @@ -43,7 +43,7 @@ internal static class FMAudio internal static async Task ConvertSelected(AudioConvert convertType) { - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); List fms = Core.View.GetSelectedFMs_InOrder_List(); if (fms.Count == 0) return; diff --git a/AngelLoader/FMDelete.cs b/AngelLoader/FMDelete.cs index 46af5118c..2519f8845 100644 --- a/AngelLoader/FMDelete.cs +++ b/AngelLoader/FMDelete.cs @@ -196,7 +196,7 @@ private static (bool Success, List FinalArchives) // * NIGHTMARE REALM * internal static async Task DeleteFMsFromDisk(List fms) { - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); int origCount = fms.Count; diff --git a/AngelLoader/FMInstallAndPlay.cs b/AngelLoader/FMInstallAndPlay.cs index bd49fe7e9..f9da74f40 100644 --- a/AngelLoader/FMInstallAndPlay.cs +++ b/AngelLoader/FMInstallAndPlay.cs @@ -61,7 +61,7 @@ private enum PlaySource internal static async Task InstallOrUninstall(FanMission[] fms) { - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); AssertR(fms.Length > 0, nameof(fms) + ".Length == 0"); FanMission firstFM = fms[0]; @@ -114,7 +114,7 @@ private static bool SelectTdmFM(FanMission? fm, bool deselect = false) internal static async Task InstallIfNeededAndPlay(FanMission fm, bool askConfIfRequired = false, bool playMP = false) { - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); if (!fm.Game.ConvertsToKnownAndSupported(out GameIndex gameIndex)) { @@ -192,7 +192,7 @@ await InstallInternal(fromPlay: true, suppressConfirmation: askingConfirmation, internal static bool PlayOriginalGame(GameIndex gameIndex, bool playMP = false) { - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); try { @@ -258,7 +258,7 @@ internal static bool PlayOriginalGame(GameIndex gameIndex, bool playMP = false) private static bool PlayFM(FanMission fm, GameIndex gameIndex, bool playMP = false) { - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); (bool success, string gameExe, string gamePath) = CheckAndReturnFinalGameExeAndGamePath(gameIndex, playingOriginalGame: false, playMP); @@ -387,7 +387,7 @@ DOES have the desired effect. internal static bool OpenFMInEditor(FanMission fm) { - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); try { @@ -1441,7 +1441,7 @@ private sealed class Buffers internal static Task Install(params FanMission[] fms) { - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); return InstallInternal(false, false, fms); } @@ -2029,7 +2029,7 @@ void ReportProgress(Fen7z.ProgressReport pr) internal static async Task<(bool Success, bool AtLeastOneFMMarkedUnavailable)> Uninstall(FanMission[] fms, bool doEndTasks = true) { - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); var fail = (false, false); diff --git a/AngelLoader/FindFMs.cs b/AngelLoader/FindFMs.cs index 510707789..5a40f0c4a 100644 --- a/AngelLoader/FindFMs.cs +++ b/AngelLoader/FindFMs.cs @@ -215,7 +215,7 @@ internal static (List FMsViewListUnscanned, Exception? Ex) // tasks or anything here... just return an exception and handle it on the main thread... try { - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); List fmsViewListUnscanned = FindInternal(startup: true); splashScreen.SetCheckAtStoredMessageWidth(); @@ -235,7 +235,7 @@ internal static List Find() { AssertR(Core.View != null!, "View was null during FindFMs.Find() call"); - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); List fmsViewListUnscanned = FindInternal(startup: false); Core.View!.SetAvailableAndFinishedFMCount(); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 76967303b..1302cdd4c 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -226,7 +226,7 @@ protected override void OnVisibleChanged(EventArgs e) // @ScreenshotDisplay(Delete): Somehow convey that this only sends them to the recycle bin private void DeleteButton_Click(object sender, EventArgs e) { - using var fmInstDirModScope = new DisableScreenshotWatchers(); + using var dsw = new DisableScreenshotWatchers(); if (!CurrentScreenshotFileName.IsEmpty()) { From a072304a6364bdf2ba31527aaecea23c9660cd57 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 18:00:34 -0800 Subject: [PATCH 064/200] Keep place in list on delete --- .../CustomControls/TopRightPages/ScreenshotsTabPage.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 1302cdd4c..840fa70f6 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -107,7 +107,7 @@ public void RefreshScreenshots() #region Page - private void UpdatePageInternal(bool forceUpdate) + private void UpdatePageInternal(bool forceUpdate, int index = -1) { if (!_constructed) return; @@ -136,7 +136,7 @@ private void UpdatePageInternal(bool forceUpdate) // @ScreenshotDisplay: Should we save the selected screenshot in the FM object? else { - CurrentScreenshotFileName = ScreenshotFileNames[0]; + CurrentScreenshotFileName = ScreenshotFileNames[index > -1 ? index : 0]; DisplayCurrentScreenshot(forceUpdate); _page.ScreenshotsPictureBox.Enabled = true; _page.GammaLabel.Enabled = true; @@ -243,7 +243,10 @@ private void DeleteButton_Click(object sender, EventArgs e) } } - UpdatePageInternal(forceUpdate: true); + int index = ScreenshotFileNames.IndexOf(CurrentScreenshotFileName); + if (index > 0) index--; + + UpdatePageInternal(forceUpdate: true, index); } private void OpenScreenshotsFolderButton_Click(object sender, EventArgs e) From 03cbbdb600387d387a0ff8388a1694430189e07b Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 26 Feb 2024 19:16:27 -0800 Subject: [PATCH 065/200] Add tooltip to delete button and tweak its backcolor and size --- .../Common/DataClasses/LocalizationData.cs | 1 + .../Lazy_ScreenshotsPage.Designer.cs | 20 +++++++++---------- .../TopRightPages/Lazy_ScreenshotsPage.cs | 3 +++ ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 18 ++++++++--------- .../TopRightPages/ScreenshotsTabPage.cs | 3 ++- AngelLoader/Languages/English.ini | 1 + 6 files changed, 26 insertions(+), 20 deletions(-) diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 3147eeef1..901b23f01 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -634,6 +634,7 @@ internal sealed class ScreenshotsTab_Class internal readonly string CopyScreenshotToolTip = "Click to copy"; internal readonly string Gamma = "Gamma:"; internal readonly string ResetGammaToolTip = "Right-click to reset"; + internal readonly string DeleteToolTip = "Delete (send to recycle bin)"; internal readonly string ScreenshotsFolderNotFound = "Screenshots folder not found."; internal readonly string ScreenshotsFolderOpenError = "There was an error trying to open the screenshots folder."; internal readonly string ImageCopied = "Image copied"; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 3ee3c2593..0997c8ac5 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,6 +31,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.DeleteButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -39,10 +40,18 @@ private void InitializeComponent() this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); - this.DeleteButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // + // DeleteButton + // + this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.DeleteButton.Location = new System.Drawing.Point(8, 256); + this.DeleteButton.Name = "DeleteButton"; + this.DeleteButton.Size = new System.Drawing.Size(24, 23); + this.DeleteButton.TabIndex = 9; + this.DeleteButton.PaintCustom += new System.EventHandler(this.DeleteButton_PaintCustom); + // // CopiedMessageLabel // this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; @@ -124,15 +133,6 @@ private void InitializeComponent() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 0; // - // DeleteButton - // - this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.DeleteButton.Location = new System.Drawing.Point(8, 256); - this.DeleteButton.Name = "DeleteButton"; - this.DeleteButton.Size = new System.Drawing.Size(23, 23); - this.DeleteButton.TabIndex = 9; - this.DeleteButton.PaintCustom += new System.EventHandler(this.DeleteButton_PaintCustom); - // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs index 03063b805..d60930ef3 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs @@ -1,5 +1,6 @@ using System.Drawing; using System.Windows.Forms; +using AngelLoader.DataClasses; namespace AngelLoader.Forms.CustomControls; @@ -12,6 +13,8 @@ public Lazy_ScreenshotsPage() #else InitSlim(); #endif + + DeleteButton.DarkModeBackColor = DarkColors.Fen_ControlBackground; } private void OpenScreenshotsFolderButton_PaintCustom(object sender, PaintEventArgs e) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 92ae08c9b..076b89940 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,6 +7,7 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { + this.DeleteButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -15,10 +16,17 @@ private void InitSlim() this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); - this.DeleteButton = new AngelLoader.Forms.CustomControls.DarkButton(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // + // DeleteButton + // + this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.DeleteButton.Location = new System.Drawing.Point(8, 256); + this.DeleteButton.Size = new System.Drawing.Size(24, 23); + this.DeleteButton.TabIndex = 9; + this.DeleteButton.PaintCustom += new System.EventHandler(this.DeleteButton_PaintCustom); + // // CopiedMessageLabel // this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; @@ -86,14 +94,6 @@ private void InitSlim() this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 0; // - // DeleteButton - // - this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.DeleteButton.Location = new System.Drawing.Point(8, 256); - this.DeleteButton.Size = new System.Drawing.Size(23, 23); - this.DeleteButton.TabIndex = 9; - this.DeleteButton.PaintCustom += new System.EventHandler(this.DeleteButton_PaintCustom); - // // Lazy_ScreenshotsPage // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 840fa70f6..cc81c2a26 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -92,9 +92,10 @@ public override void UpdatePage() public override void Localize() { if (!_constructed) return; + _owner.MainToolTip.SetToolTip(_page.ScreenshotsPictureBox, LText.ScreenshotsTab.CopyScreenshotToolTip); _page.GammaLabel.Text = LText.ScreenshotsTab.Gamma; _owner.MainToolTip.SetToolTip(_page.GammaTrackBar, LText.ScreenshotsTab.ResetGammaToolTip); - _owner.MainToolTip.SetToolTip(_page.ScreenshotsPictureBox, LText.ScreenshotsTab.CopyScreenshotToolTip); + _owner.MainToolTip.SetToolTip(_page.DeleteButton, LText.ScreenshotsTab.DeleteToolTip); } public void RefreshScreenshots() diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index 312640044..de25e2c4d 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -492,6 +492,7 @@ TabText=Screenshots CopyScreenshotToolTip=Click to copy Gamma=Gamma: ResetGammaToolTip=Right-click to reset +DeleteToolTip=Delete (send to recycle bin) ScreenshotsFolderNotFound=Screenshots folder not found. ScreenshotsFolderOpenError=There was an error trying to open the screenshots folder. ImageCopied=Image copied From fad2c9d572f68cd0e8ffaca8957dd7afc47cf163 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 09:49:36 -0800 Subject: [PATCH 066/200] Sort screenshots highest-number-is-latest --- .../CustomControls/TopRightPages/ScreenshotsTabPage.cs | 8 +++++++- AngelLoader/Screenshots.cs | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index cc81c2a26..1caf559c5 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,4 +1,5 @@ // @ScreenshotDisplay: Keep the place in the screenshot set on reload? +// @ScreenshotDisplay: Have a gamma number/percent indicator, maybe reuse the "copied" label? using System; using System.Collections.Generic; @@ -137,7 +138,7 @@ private void UpdatePageInternal(bool forceUpdate, int index = -1) // @ScreenshotDisplay: Should we save the selected screenshot in the FM object? else { - CurrentScreenshotFileName = ScreenshotFileNames[index > -1 ? index : 0]; + CurrentScreenshotFileName = ScreenshotFileNames[index > -1 ? index : ScreenshotFileNames.Count - 1]; DisplayCurrentScreenshot(forceUpdate); _page.ScreenshotsPictureBox.Enabled = true; _page.GammaLabel.Enabled = true; @@ -245,7 +246,12 @@ private void DeleteButton_Click(object sender, EventArgs e) } int index = ScreenshotFileNames.IndexOf(CurrentScreenshotFileName); + // Two different styles... The second one might make more sense for highest-number-is-most-recent? +#if false if (index > 0) index--; +#else + if (index == ScreenshotFileNames.Count - 1) index--; +#endif UpdatePageInternal(forceUpdate: true, index); } diff --git a/AngelLoader/Screenshots.cs b/AngelLoader/Screenshots.cs index 7a7b7c960..656261d12 100644 --- a/AngelLoader/Screenshots.cs +++ b/AngelLoader/Screenshots.cs @@ -323,7 +323,7 @@ These names are listed in \CONTENT\T3\Books\English\String_Tags\Misc.sch but als return false; } screenshots = di.GetFiles(pattern); - Comparers.Screenshot.SortDirection = SortDirection.Descending; + Comparers.Screenshot.SortDirection = SortDirection.Ascending; Array.Sort(screenshots, Comparers.Screenshot); return true; } From c6f00193ef5246c1d919cacae932cf740e4e080e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 09:59:36 -0800 Subject: [PATCH 067/200] Show error when screenshot delete fails --- AngelLoader/Common/DataClasses/LocalizationData.cs | 1 + .../CustomControls/TopRightPages/ScreenshotsTabPage.cs | 7 ++++--- AngelLoader/Languages/English.ini | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 901b23f01..21e0e0ec6 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -639,6 +639,7 @@ internal sealed class ScreenshotsTab_Class internal readonly string ScreenshotsFolderOpenError = "There was an error trying to open the screenshots folder."; internal readonly string ImageCopied = "Image copied"; internal readonly string ImageCopyFailed = "Image copy failed"; + internal readonly string ScreenshotDeleteFailed = "The screenshot could not be deleted."; } internal sealed class ReadmeArea_Class diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 1caf559c5..101dda0c6 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -225,7 +225,6 @@ protected override void OnVisibleChanged(EventArgs e) private void ScreenshotsPictureBox_MouseClick(object sender, MouseEventArgs e) => CopyImageToClipboard(); - // @ScreenshotDisplay(Delete): Somehow convey that this only sends them to the recycle bin private void DeleteButton_Click(object sender, EventArgs e) { using var dsw = new DisableScreenshotWatchers(); @@ -239,9 +238,11 @@ private void DeleteButton_Click(object sender, EventArgs e) UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin); } - catch + catch (Exception ex) { - // @ScreenshotDisplay: Do we want an error dialog here? + Logger.Log(ErrorText.ExTry + "delete screenshot " + CurrentScreenshotFileName, ex); + Core.Dialogs.ShowError(LText.ScreenshotsTab.ScreenshotDeleteFailed); + return; } } diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index de25e2c4d..22a760558 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -497,6 +497,7 @@ ScreenshotsFolderNotFound=Screenshots folder not found. ScreenshotsFolderOpenError=There was an error trying to open the screenshots folder. ImageCopied=Image copied ImageCopyFailed=Image copy failed +ScreenshotDeleteFailed=The screenshot could not be deleted. [ReadmeArea] ViewHTMLReadme=View HTML Readme From 88f341803b31e4520b6c97b282c163fb7bcaba84 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 11:22:53 -0800 Subject: [PATCH 068/200] Implement custom double-click-to-reset on gamma slider --- .../Common/DataClasses/LocalizationData.cs | 1 - .../Forms/CustomControls/DarkTrackBar.cs | 65 +++++++++++++++++++ .../TopRightPages/ScreenshotsTabPage.cs | 7 +- AngelLoader/Languages/English.ini | 1 - 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 21e0e0ec6..283d9c797 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -633,7 +633,6 @@ internal sealed class ScreenshotsTab_Class internal readonly string TabText = "Screenshots"; internal readonly string CopyScreenshotToolTip = "Click to copy"; internal readonly string Gamma = "Gamma:"; - internal readonly string ResetGammaToolTip = "Right-click to reset"; internal readonly string DeleteToolTip = "Delete (send to recycle bin)"; internal readonly string ScreenshotsFolderNotFound = "Screenshots folder not found."; internal readonly string ScreenshotsFolderOpenError = "There was an error trying to open the screenshots folder."; diff --git a/AngelLoader/Forms/CustomControls/DarkTrackBar.cs b/AngelLoader/Forms/CustomControls/DarkTrackBar.cs index a3cef3118..1036318c0 100644 --- a/AngelLoader/Forms/CustomControls/DarkTrackBar.cs +++ b/AngelLoader/Forms/CustomControls/DarkTrackBar.cs @@ -30,6 +30,71 @@ public bool DarkModeEnabled } } + #region Double-click + + // TrackBars don't fire double-click events, so we roll our own + + private MouseButtons _lastClickButton = MouseButtons.None; + private Point _lastMouseDownPoint = Point.Empty; + private readonly System.Timers.Timer _doubleClickTimer = new() { AutoReset = false }; + + public event MouseEventHandler? DoubleClickEndingOnMouseDown; + + protected override void OnMouseClick(MouseEventArgs e) + { + base.OnMouseClick(e); + + if (!_doubleClickTimer.Enabled) + { + _lastClickButton = e.Button; + _lastMouseDownPoint = this.ClientCursorPos(); + _doubleClickTimer.Interval = SystemInformation.DoubleClickTime; + _doubleClickTimer.Reset(); + } + else + { + FireDoubleClickEvent(e, endingInDownVersion: false); + } + } + + protected override void OnMouseDown(MouseEventArgs e) + { + base.OnMouseDown(e); + + if (_doubleClickTimer.Enabled) + { + FireDoubleClickEvent(e, endingInDownVersion: true); + } + } + + private void FireDoubleClickEvent(MouseEventArgs e, bool endingInDownVersion) + { + Size doubleClickSize = SystemInformation.DoubleClickSize; + Point cursorPos = this.ClientCursorPos(); + Rectangle rect = new( + _lastMouseDownPoint.X - (doubleClickSize.Width / 2), + _lastMouseDownPoint.Y - (doubleClickSize.Height / 2), + doubleClickSize.Width, + doubleClickSize.Height + ); + if (rect.Contains(cursorPos) && e.Button == _lastClickButton) + { + if (endingInDownVersion) + { + DoubleClickEndingOnMouseDown?.Invoke(this, e); + } + else + { + OnMouseDoubleClick(e); + } + } + _lastClickButton = MouseButtons.None; + _lastMouseDownPoint = Point.Empty; + _doubleClickTimer.Stop(); + } + + #endregion + protected override void WndProc(ref Message m) { // Prevents white flicker when the main window redraws in certain cases (restore from minimize, game diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 101dda0c6..8216ddc72 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -76,7 +76,7 @@ public override void Construct() _page.PrevButton.Click += ScreenshotsPrevButton_Click; _page.NextButton.Click += ScreenshotsNextButton_Click; _page.GammaTrackBar.Scroll += GammaTrackBar_Scroll; - _page.GammaTrackBar.MouseDown += GammaTrackBar_MouseDown; + _page.GammaTrackBar.DoubleClickEndingOnMouseDown += GammaTrackBar_MouseDoubleClick; FinishConstruct(); } @@ -95,7 +95,6 @@ public override void Localize() if (!_constructed) return; _owner.MainToolTip.SetToolTip(_page.ScreenshotsPictureBox, LText.ScreenshotsTab.CopyScreenshotToolTip); _page.GammaLabel.Text = LText.ScreenshotsTab.Gamma; - _owner.MainToolTip.SetToolTip(_page.GammaTrackBar, LText.ScreenshotsTab.ResetGammaToolTip); _owner.MainToolTip.SetToolTip(_page.DeleteButton, LText.ScreenshotsTab.DeleteToolTip); } @@ -296,9 +295,9 @@ private float GetGamma() return ret; } - private void GammaTrackBar_MouseDown(object sender, MouseEventArgs e) + private void GammaTrackBar_MouseDoubleClick(object sender, MouseEventArgs e) { - if (e.Button is MouseButtons.Middle or MouseButtons.Right) + if (e.Button == MouseButtons.Left) { ResetGammaSlider(); } diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index 22a760558..6952fa2e6 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -491,7 +491,6 @@ Generic_ModsNotSupported=Mod management is not supported for unknown FMs. TabText=Screenshots CopyScreenshotToolTip=Click to copy Gamma=Gamma: -ResetGammaToolTip=Right-click to reset DeleteToolTip=Delete (send to recycle bin) ScreenshotsFolderNotFound=Screenshots folder not found. ScreenshotsFolderOpenError=There was an error trying to open the screenshots folder. From 430637541017f02b6cec0453c567c621f150e5f2 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 11:44:13 -0800 Subject: [PATCH 069/200] Note for future reference --- AngelLoader/Forms/WinFormsNative/WinFormsNative.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs b/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs index 0e950c070..e98ccb802 100644 --- a/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs +++ b/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs @@ -868,6 +868,9 @@ internal static bool TryGetRealWindowBounds(Form form, out Rectangle rect) #region Get system metrics + // SystemInformation gives us most of these, but it doesn't give us iPaddedBorderWidth and we need that. + // All this just for that one thing. + private const int LF_FACESIZE = 32; private const int SPI_GETNONCLIENTMETRICS = 0x0029; From 9bbbf91056d148dff0fd03df91c809b976b5e2a5 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 12:09:36 -0800 Subject: [PATCH 070/200] If screenshots tab is hidden, arm auto-update for next show --- .../TopRightPages/ScreenshotsTabPage.cs | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 8216ddc72..87f8d4102 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -51,6 +51,7 @@ public void Dispose() private string CurrentScreenshotFileName = ""; private MemoryImage? _currentScreenshotStream; private readonly Timer CopiedMessageFadeoutTimer = new(); + private bool _forceUpdateArmed; #region Public common @@ -87,7 +88,7 @@ public override void Construct() public override void UpdatePage() { if (!_constructed) return; - UpdatePageInternal(forceUpdate: false); + UpdatePageInternal(); } public override void Localize() @@ -101,14 +102,16 @@ public override void Localize() public void RefreshScreenshots() { if (!_constructed) return; - UpdatePageInternal(forceUpdate: true); + + _forceUpdateArmed = true; + UpdatePageInternal(); } #endregion #region Page - private void UpdatePageInternal(bool forceUpdate, int index = -1) + private void UpdatePageInternal(int index = -1) { if (!_constructed) return; @@ -133,12 +136,13 @@ private void UpdatePageInternal(bool forceUpdate, int index = -1) _page.PrevButton.Enabled = false; _page.NextButton.Enabled = false; SetNumberLabelText(""); + _forceUpdateArmed = false; } // @ScreenshotDisplay: Should we save the selected screenshot in the FM object? else { CurrentScreenshotFileName = ScreenshotFileNames[index > -1 ? index : ScreenshotFileNames.Count - 1]; - DisplayCurrentScreenshot(forceUpdate); + DisplayCurrentScreenshot(); _page.ScreenshotsPictureBox.Enabled = true; _page.GammaLabel.Enabled = true; _page.GammaTrackBar.Enabled = true; @@ -179,17 +183,15 @@ private void ClearCurrentScreenshot() performance cost if they're not actually able to see the image. So we only update when visible (or when we become visible). */ - private void DisplayCurrentScreenshot(bool forceUpdate = false) + private void DisplayCurrentScreenshot() { if (!_constructed) return; - // @ScreenshotDisplay: I think the unconditional-if-force-update check is not quite correct - // That would probably make it update even if the tab is hidden? Maybe that's fine? - if (!forceUpdate && !_owner.StartupState && !Visible) return; + if (!_owner.StartupState && !Visible) return; - if (forceUpdate || + if (_forceUpdateArmed || (!CurrentScreenshotFileName.IsEmpty() && - // @TDM_CASE when FM is TDM - _currentScreenshotStream?.Path.EqualsI(CurrentScreenshotFileName) != true)) + // @TDM_CASE when FM is TDM + _currentScreenshotStream?.Path.EqualsI(CurrentScreenshotFileName) != true)) { try { @@ -204,6 +206,7 @@ private void DisplayCurrentScreenshot(bool forceUpdate = false) } finally { + _forceUpdateArmed = false; SetNumberLabelText( (ScreenshotFileNames.IndexOf(CurrentScreenshotFileName) + 1).ToStrInv() + " / " + ScreenshotFileNames.Count.ToStrInv() @@ -253,7 +256,8 @@ private void DeleteButton_Click(object sender, EventArgs e) if (index == ScreenshotFileNames.Count - 1) index--; #endif - UpdatePageInternal(forceUpdate: true, index); + _forceUpdateArmed = true; + UpdatePageInternal(index); } private void OpenScreenshotsFolderButton_Click(object sender, EventArgs e) From a2ce095abb48acf17f869ba9957c94ddb8e2dd99 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 12:10:10 -0800 Subject: [PATCH 071/200] Note --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 87f8d4102..eaa80c904 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,5 +1,6 @@ // @ScreenshotDisplay: Keep the place in the screenshot set on reload? // @ScreenshotDisplay: Have a gamma number/percent indicator, maybe reuse the "copied" label? +// @ScreenshotDisplay: Move the delete button to somewhere less enticing to click using System; using System.Collections.Generic; From a105eb255b5c21c3fbebdfd56e0097564af1eb68 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 12:39:44 -0800 Subject: [PATCH 072/200] Remove delete button and move dir button to left --- .../Common/DataClasses/LocalizationData.cs | 2 - .../Lazy_ScreenshotsPage.Designer.cs | 18 ++------- .../TopRightPages/Lazy_ScreenshotsPage.cs | 13 ------- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 16 ++------ .../TopRightPages/ScreenshotsTabPage.cs | 37 ------------------- AngelLoader/Languages/English.ini | 2 - 6 files changed, 6 insertions(+), 82 deletions(-) diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 283d9c797..196580dcc 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -633,12 +633,10 @@ internal sealed class ScreenshotsTab_Class internal readonly string TabText = "Screenshots"; internal readonly string CopyScreenshotToolTip = "Click to copy"; internal readonly string Gamma = "Gamma:"; - internal readonly string DeleteToolTip = "Delete (send to recycle bin)"; internal readonly string ScreenshotsFolderNotFound = "Screenshots folder not found."; internal readonly string ScreenshotsFolderOpenError = "There was an error trying to open the screenshots folder."; internal readonly string ImageCopied = "Image copied"; internal readonly string ImageCopyFailed = "Image copy failed"; - internal readonly string ScreenshotDeleteFailed = "The screenshot could not be deleted."; } internal sealed class ReadmeArea_Class diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 0997c8ac5..5295d71aa 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,7 +31,6 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.DeleteButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -43,15 +42,6 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // - // DeleteButton - // - this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.DeleteButton.Location = new System.Drawing.Point(8, 256); - this.DeleteButton.Name = "DeleteButton"; - this.DeleteButton.Size = new System.Drawing.Size(24, 23); - this.DeleteButton.TabIndex = 9; - this.DeleteButton.PaintCustom += new System.EventHandler(this.DeleteButton_PaintCustom); - // // CopiedMessageLabel // this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; @@ -98,10 +88,10 @@ private void InitializeComponent() // // OpenScreenshotsFolderButton // - this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); + this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(8, 256); this.OpenScreenshotsFolderButton.Name = "OpenScreenshotsFolderButton"; - this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); + this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(24, 23); this.OpenScreenshotsFolderButton.TabIndex = 6; this.OpenScreenshotsFolderButton.PaintCustom += new System.EventHandler(this.OpenScreenshotsFolderButton_PaintCustom); // @@ -139,7 +129,6 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); - this.Controls.Add(this.DeleteButton); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); @@ -167,5 +156,4 @@ private void InitializeComponent() internal DarkTrackBar GammaTrackBar; internal DarkLabel GammaLabel; internal DarkLabel CopiedMessageLabel; - internal DarkButton DeleteButton; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs index d60930ef3..b18158d12 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs @@ -13,8 +13,6 @@ public Lazy_ScreenshotsPage() #else InitSlim(); #endif - - DeleteButton.DarkModeBackColor = DarkColors.Fen_ControlBackground; } private void OpenScreenshotsFolderButton_PaintCustom(object sender, PaintEventArgs e) @@ -27,15 +25,4 @@ private void OpenScreenshotsFolderButton_PaintCustom(object sender, PaintEventAr button.Enabled ? image : Images.GetDisabledImage(image), x: (button.Width - image.Width) / 2); } - - private void DeleteButton_PaintCustom(object sender, PaintEventArgs e) - { - Image image = Images.Trash; - DarkButton button = DeleteButton; - Images.PaintBitmapButton( - button, - e, - button.Enabled ? image : Images.GetDisabledImage(image), - x: (button.Width - image.Width) / 2); - } } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 076b89940..184ecab07 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,7 +7,6 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { - this.DeleteButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -19,14 +18,6 @@ private void InitSlim() ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // - // DeleteButton - // - this.DeleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.DeleteButton.Location = new System.Drawing.Point(8, 256); - this.DeleteButton.Size = new System.Drawing.Size(24, 23); - this.DeleteButton.TabIndex = 9; - this.DeleteButton.PaintCustom += new System.EventHandler(this.DeleteButton_PaintCustom); - // // CopiedMessageLabel // this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; @@ -63,9 +54,9 @@ private void InitSlim() // // OpenScreenshotsFolderButton // - this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(336, 256); - this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(35, 23); + this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(8, 256); + this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(24, 23); this.OpenScreenshotsFolderButton.TabIndex = 6; this.OpenScreenshotsFolderButton.PaintCustom += new System.EventHandler(this.OpenScreenshotsFolderButton_PaintCustom); // @@ -100,7 +91,6 @@ private void InitSlim() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); - this.Controls.Add(this.DeleteButton); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index eaa80c904..6d2693801 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -73,7 +73,6 @@ public override void Construct() _page.ScreenshotsPictureBox.MouseClick += ScreenshotsPictureBox_MouseClick; - _page.DeleteButton.Click += DeleteButton_Click; _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; _page.PrevButton.Click += ScreenshotsPrevButton_Click; _page.NextButton.Click += ScreenshotsNextButton_Click; @@ -97,7 +96,6 @@ public override void Localize() if (!_constructed) return; _owner.MainToolTip.SetToolTip(_page.ScreenshotsPictureBox, LText.ScreenshotsTab.CopyScreenshotToolTip); _page.GammaLabel.Text = LText.ScreenshotsTab.Gamma; - _owner.MainToolTip.SetToolTip(_page.DeleteButton, LText.ScreenshotsTab.DeleteToolTip); } public void RefreshScreenshots() @@ -132,7 +130,6 @@ private void UpdatePageInternal(int index = -1) _page.ScreenshotsPictureBox.Enabled = false; _page.GammaLabel.Enabled = false; _page.GammaTrackBar.Enabled = false; - _page.DeleteButton.Enabled = false; _page.OpenScreenshotsFolderButton.Enabled = false; _page.PrevButton.Enabled = false; _page.NextButton.Enabled = false; @@ -147,7 +144,6 @@ private void UpdatePageInternal(int index = -1) _page.ScreenshotsPictureBox.Enabled = true; _page.GammaLabel.Enabled = true; _page.GammaTrackBar.Enabled = true; - _page.DeleteButton.Enabled = true; _page.OpenScreenshotsFolderButton.Enabled = true; _page.PrevButton.Enabled = ScreenshotFileNames.Count > 1; _page.NextButton.Enabled = ScreenshotFileNames.Count > 1; @@ -228,39 +224,6 @@ protected override void OnVisibleChanged(EventArgs e) private void ScreenshotsPictureBox_MouseClick(object sender, MouseEventArgs e) => CopyImageToClipboard(); - private void DeleteButton_Click(object sender, EventArgs e) - { - using var dsw = new DisableScreenshotWatchers(); - - if (!CurrentScreenshotFileName.IsEmpty()) - { - try - { - FileSystem.DeleteFile( - CurrentScreenshotFileName, - UIOption.OnlyErrorDialogs, - RecycleOption.SendToRecycleBin); - } - catch (Exception ex) - { - Logger.Log(ErrorText.ExTry + "delete screenshot " + CurrentScreenshotFileName, ex); - Core.Dialogs.ShowError(LText.ScreenshotsTab.ScreenshotDeleteFailed); - return; - } - } - - int index = ScreenshotFileNames.IndexOf(CurrentScreenshotFileName); - // Two different styles... The second one might make more sense for highest-number-is-most-recent? -#if false - if (index > 0) index--; -#else - if (index == ScreenshotFileNames.Count - 1) index--; -#endif - - _forceUpdateArmed = true; - UpdatePageInternal(index); - } - private void OpenScreenshotsFolderButton_Click(object sender, EventArgs e) { Core.OpenFMScreenshotsFolder(_owner.FMsDGV.GetMainSelectedFM(), CurrentScreenshotFileName); diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index 6952fa2e6..9a61969ba 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -491,12 +491,10 @@ Generic_ModsNotSupported=Mod management is not supported for unknown FMs. TabText=Screenshots CopyScreenshotToolTip=Click to copy Gamma=Gamma: -DeleteToolTip=Delete (send to recycle bin) ScreenshotsFolderNotFound=Screenshots folder not found. ScreenshotsFolderOpenError=There was an error trying to open the screenshots folder. ImageCopied=Image copied ImageCopyFailed=Image copy failed -ScreenshotDeleteFailed=The screenshot could not be deleted. [ReadmeArea] ViewHTMLReadme=View HTML Readme From c5f97d4938f246b778a90be67b2a06ca6425536a Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 13:50:30 -0800 Subject: [PATCH 073/200] Quick and crappy way to get more range in the dark half of the slider --- .../CustomControls/TopRightPages/ScreenshotsTabPage.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 6d2693801..391614439 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,6 +1,5 @@ // @ScreenshotDisplay: Keep the place in the screenshot set on reload? // @ScreenshotDisplay: Have a gamma number/percent indicator, maybe reuse the "copied" label? -// @ScreenshotDisplay: Move the delete button to somewhere less enticing to click using System; using System.Collections.Generic; @@ -9,7 +8,6 @@ using System.Windows.Forms; using AL_Common; using AngelLoader.DataClasses; -using Microsoft.VisualBasic.FileIO; using static AngelLoader.GameSupport; using static AngelLoader.Global; @@ -260,6 +258,12 @@ private float GetGamma() TrackBar tb = _page.GammaTrackBar; float ret = (tb.Maximum - tb.Value) * (1.0f / (tb.Maximum / 2.0f)); ret = (float)Math.Round(ret, 2, MidpointRounding.AwayFromZero); + + // Utter noob crap. + // This gets us more range in the darker half. There's math that will make a nice fast-start/slow-end + // curve but I don't know it. + if (tb.Value < tb.Maximum / 2) ret *= ret; + return ret; } From da5c2e47078ed9309083cedf6b9c33606f76d8c5 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 15:26:14 -0800 Subject: [PATCH 074/200] Add gamma value display and tweak math --- .../Lazy_ScreenshotsPage.Designer.cs | 23 +++++++++++---- .../TopRightPages/Lazy_ScreenshotsPage.cs | 1 - ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 19 +++++++++---- .../TopRightPages/ScreenshotsTabPage.cs | 28 ++++++++++++++----- 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 5295d71aa..306a12418 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,6 +31,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.GammaValueLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -42,11 +43,21 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // + // GammaValueLabel + // + this.GammaValueLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; + this.GammaValueLabel.Location = new System.Drawing.Point(0, 240); + this.GammaValueLabel.Name = "GammaValueLabel"; + this.GammaValueLabel.Size = new System.Drawing.Size(528, 13); + this.GammaValueLabel.TabIndex = 9; + this.GammaValueLabel.Text = "[gamma value]"; + this.GammaValueLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter; + // // CopiedMessageLabel // this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; this.CopiedMessageLabel.AutoSize = true; - this.CopiedMessageLabel.Location = new System.Drawing.Point(240, 204); + this.CopiedMessageLabel.Location = new System.Drawing.Point(240, 183); this.CopiedMessageLabel.Name = "CopiedMessageLabel"; this.CopiedMessageLabel.Size = new System.Drawing.Size(46, 13); this.CopiedMessageLabel.TabIndex = 2; @@ -57,7 +68,7 @@ private void InitializeComponent() // this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.GammaLabel.AutoSize = true; - this.GammaLabel.Location = new System.Drawing.Point(8, 204); + this.GammaLabel.Location = new System.Drawing.Point(8, 183); this.GammaLabel.Name = "GammaLabel"; this.GammaLabel.Size = new System.Drawing.Size(46, 13); this.GammaLabel.TabIndex = 1; @@ -67,7 +78,7 @@ private void InitializeComponent() // this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(472, 204); + this.NumberLabel.Location = new System.Drawing.Point(472, 183); this.NumberLabel.Name = "NumberLabel"; this.NumberLabel.Size = new System.Drawing.Size(54, 13); this.NumberLabel.TabIndex = 3; @@ -78,7 +89,7 @@ private void InitializeComponent() this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.GammaTrackBar.AutoSize = false; - this.GammaTrackBar.Location = new System.Drawing.Point(8, 223); + this.GammaTrackBar.Location = new System.Drawing.Point(8, 202); this.GammaTrackBar.Maximum = 100; this.GammaTrackBar.Name = "GammaTrackBar"; this.GammaTrackBar.Size = new System.Drawing.Size(512, 32); @@ -120,7 +131,7 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); this.ScreenshotsPictureBox.Name = "ScreenshotsPictureBox"; - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 172); this.ScreenshotsPictureBox.TabIndex = 0; // // Lazy_ScreenshotsPage @@ -129,6 +140,7 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.GammaValueLabel); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); @@ -156,4 +168,5 @@ private void InitializeComponent() internal DarkTrackBar GammaTrackBar; internal DarkLabel GammaLabel; internal DarkLabel CopiedMessageLabel; + internal DarkLabel GammaValueLabel; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs index b18158d12..ec3d04afb 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs @@ -1,6 +1,5 @@ using System.Drawing; using System.Windows.Forms; -using AngelLoader.DataClasses; namespace AngelLoader.Forms.CustomControls; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 184ecab07..3a78defd5 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,6 +7,7 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { + this.GammaValueLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -18,11 +19,18 @@ private void InitSlim() ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // + // GammaValueLabel + // + this.GammaValueLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; + this.GammaValueLabel.Location = new System.Drawing.Point(0, 240); + this.GammaValueLabel.Size = new System.Drawing.Size(528, 13); + this.GammaValueLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter; + // // CopiedMessageLabel // this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; this.CopiedMessageLabel.AutoSize = true; - this.CopiedMessageLabel.Location = new System.Drawing.Point(240, 204); + this.CopiedMessageLabel.Location = new System.Drawing.Point(240, 183); this.CopiedMessageLabel.Size = new System.Drawing.Size(46, 13); this.CopiedMessageLabel.Visible = false; // @@ -30,14 +38,14 @@ private void InitSlim() // this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.GammaLabel.AutoSize = true; - this.GammaLabel.Location = new System.Drawing.Point(8, 204); + this.GammaLabel.Location = new System.Drawing.Point(8, 183); this.GammaLabel.Size = new System.Drawing.Size(46, 13); // // NumberLabel // this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(472, 204); + this.NumberLabel.Location = new System.Drawing.Point(472, 183); this.NumberLabel.Size = new System.Drawing.Size(54, 13); // // GammaTrackBar @@ -45,7 +53,7 @@ private void InitSlim() this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.GammaTrackBar.AutoSize = false; - this.GammaTrackBar.Location = new System.Drawing.Point(8, 223); + this.GammaTrackBar.Location = new System.Drawing.Point(8, 202); this.GammaTrackBar.Maximum = 100; this.GammaTrackBar.Size = new System.Drawing.Size(512, 32); this.GammaTrackBar.TabIndex = 4; @@ -82,7 +90,7 @@ private void InitSlim() | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 172); this.ScreenshotsPictureBox.TabIndex = 0; // // Lazy_ScreenshotsPage @@ -91,6 +99,7 @@ private void InitSlim() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.Controls.Add(this.GammaValueLabel); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 391614439..dc1ab03be 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Globalization; using System.IO; using System.Windows.Forms; using AL_Common; @@ -78,6 +79,8 @@ public override void Construct() _page.GammaTrackBar.DoubleClickEndingOnMouseDown += GammaTrackBar_MouseDoubleClick; FinishConstruct(); + + SetGammaValueLabelText(); } _page.Show(); @@ -251,18 +254,22 @@ private void GammaTrackBar_Scroll(object sender, EventArgs e) { Config.ScreenshotGammaPercent = _page.GammaTrackBar.Value; _page.ScreenshotsPictureBox.SetGamma(GetGamma()); + SetGammaValueLabelText(); } - private float GetGamma() + private float GetGamma(bool userFacing = false) { TrackBar tb = _page.GammaTrackBar; - float ret = (tb.Maximum - tb.Value) * (1.0f / (tb.Maximum / 2.0f)); - ret = (float)Math.Round(ret, 2, MidpointRounding.AwayFromZero); - // Utter noob crap. - // This gets us more range in the darker half. There's math that will make a nice fast-start/slow-end - // curve but I don't know it. - if (tb.Value < tb.Maximum / 2) ret *= ret; + int param = !userFacing ? tb.Maximum - tb.Value : tb.Maximum - (tb.Maximum - tb.Value); + float ret = param * (1.0f / (tb.Maximum / 2.0f)); + + // @ScreenshotDisplay(gamma math): + // Trial-and-error flailing until we get something with a good range and that has 1.0 in the middle for + // non-confusing UX. The last 4 values end up differing by a small enough amount that the image doesn't + // change between them (not that I can see anyway). Whatever... I might come back to it later... + ret *= ret / 1.18f; + ret += 0.15f; return ret; } @@ -280,6 +287,7 @@ private void ResetGammaSlider() _page.GammaTrackBar.Value = 50; Config.ScreenshotGammaPercent = 50; _page.ScreenshotsPictureBox.SetGamma(1.0f); + SetGammaValueLabelText(); } private void SetCopiedMessageLabelText(string text, bool success) @@ -296,6 +304,12 @@ private void SetCopiedMessageLabelText(string text, bool success) CopiedMessageFadeoutTimer.Start(); } + private void SetGammaValueLabelText() + { + if (!_constructed) return; + _page.GammaValueLabel.Text = GetGamma(userFacing: true).ToString("N2", NumberFormatInfo.InvariantInfo); + } + private void CopiedMessageFadeoutTimer_Tick(object sender, EventArgs e) { if (!_constructed) return; From 223c9d6907a609e5ec5e70b068b9bcb923887b2e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 16:03:14 -0800 Subject: [PATCH 075/200] Remove gamma display again... it just isn't ever right --- .../Lazy_ScreenshotsPage.Designer.cs | 23 ++++--------------- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 19 ++++----------- .../TopRightPages/ScreenshotsTabPage.cs | 15 ++---------- 3 files changed, 12 insertions(+), 45 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 306a12418..5295d71aa 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,7 +31,6 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.GammaValueLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -43,21 +42,11 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // - // GammaValueLabel - // - this.GammaValueLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; - this.GammaValueLabel.Location = new System.Drawing.Point(0, 240); - this.GammaValueLabel.Name = "GammaValueLabel"; - this.GammaValueLabel.Size = new System.Drawing.Size(528, 13); - this.GammaValueLabel.TabIndex = 9; - this.GammaValueLabel.Text = "[gamma value]"; - this.GammaValueLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter; - // // CopiedMessageLabel // this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; this.CopiedMessageLabel.AutoSize = true; - this.CopiedMessageLabel.Location = new System.Drawing.Point(240, 183); + this.CopiedMessageLabel.Location = new System.Drawing.Point(240, 204); this.CopiedMessageLabel.Name = "CopiedMessageLabel"; this.CopiedMessageLabel.Size = new System.Drawing.Size(46, 13); this.CopiedMessageLabel.TabIndex = 2; @@ -68,7 +57,7 @@ private void InitializeComponent() // this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.GammaLabel.AutoSize = true; - this.GammaLabel.Location = new System.Drawing.Point(8, 183); + this.GammaLabel.Location = new System.Drawing.Point(8, 204); this.GammaLabel.Name = "GammaLabel"; this.GammaLabel.Size = new System.Drawing.Size(46, 13); this.GammaLabel.TabIndex = 1; @@ -78,7 +67,7 @@ private void InitializeComponent() // this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(472, 183); + this.NumberLabel.Location = new System.Drawing.Point(472, 204); this.NumberLabel.Name = "NumberLabel"; this.NumberLabel.Size = new System.Drawing.Size(54, 13); this.NumberLabel.TabIndex = 3; @@ -89,7 +78,7 @@ private void InitializeComponent() this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.GammaTrackBar.AutoSize = false; - this.GammaTrackBar.Location = new System.Drawing.Point(8, 202); + this.GammaTrackBar.Location = new System.Drawing.Point(8, 223); this.GammaTrackBar.Maximum = 100; this.GammaTrackBar.Name = "GammaTrackBar"; this.GammaTrackBar.Size = new System.Drawing.Size(512, 32); @@ -131,7 +120,7 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); this.ScreenshotsPictureBox.Name = "ScreenshotsPictureBox"; - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 172); + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 0; // // Lazy_ScreenshotsPage @@ -140,7 +129,6 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); - this.Controls.Add(this.GammaValueLabel); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); @@ -168,5 +156,4 @@ private void InitializeComponent() internal DarkTrackBar GammaTrackBar; internal DarkLabel GammaLabel; internal DarkLabel CopiedMessageLabel; - internal DarkLabel GammaValueLabel; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 3a78defd5..184ecab07 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,7 +7,6 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { - this.GammaValueLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); @@ -19,18 +18,11 @@ private void InitSlim() ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // - // GammaValueLabel - // - this.GammaValueLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; - this.GammaValueLabel.Location = new System.Drawing.Point(0, 240); - this.GammaValueLabel.Size = new System.Drawing.Size(528, 13); - this.GammaValueLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter; - // // CopiedMessageLabel // this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; this.CopiedMessageLabel.AutoSize = true; - this.CopiedMessageLabel.Location = new System.Drawing.Point(240, 183); + this.CopiedMessageLabel.Location = new System.Drawing.Point(240, 204); this.CopiedMessageLabel.Size = new System.Drawing.Size(46, 13); this.CopiedMessageLabel.Visible = false; // @@ -38,14 +30,14 @@ private void InitSlim() // this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.GammaLabel.AutoSize = true; - this.GammaLabel.Location = new System.Drawing.Point(8, 183); + this.GammaLabel.Location = new System.Drawing.Point(8, 204); this.GammaLabel.Size = new System.Drawing.Size(46, 13); // // NumberLabel // this.NumberLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.NumberLabel.AutoSize = true; - this.NumberLabel.Location = new System.Drawing.Point(472, 183); + this.NumberLabel.Location = new System.Drawing.Point(472, 204); this.NumberLabel.Size = new System.Drawing.Size(54, 13); // // GammaTrackBar @@ -53,7 +45,7 @@ private void InitSlim() this.GammaTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.GammaTrackBar.AutoSize = false; - this.GammaTrackBar.Location = new System.Drawing.Point(8, 202); + this.GammaTrackBar.Location = new System.Drawing.Point(8, 223); this.GammaTrackBar.Maximum = 100; this.GammaTrackBar.Size = new System.Drawing.Size(512, 32); this.GammaTrackBar.TabIndex = 4; @@ -90,7 +82,7 @@ private void InitSlim() | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.ScreenshotsPictureBox.Location = new System.Drawing.Point(8, 8); - this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 172); + this.ScreenshotsPictureBox.Size = new System.Drawing.Size(512, 192); this.ScreenshotsPictureBox.TabIndex = 0; // // Lazy_ScreenshotsPage @@ -99,7 +91,6 @@ private void InitSlim() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 100); - this.Controls.Add(this.GammaValueLabel); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index dc1ab03be..d9879bea1 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Globalization; using System.IO; using System.Windows.Forms; using AL_Common; @@ -79,8 +78,6 @@ public override void Construct() _page.GammaTrackBar.DoubleClickEndingOnMouseDown += GammaTrackBar_MouseDoubleClick; FinishConstruct(); - - SetGammaValueLabelText(); } _page.Show(); @@ -254,14 +251,13 @@ private void GammaTrackBar_Scroll(object sender, EventArgs e) { Config.ScreenshotGammaPercent = _page.GammaTrackBar.Value; _page.ScreenshotsPictureBox.SetGamma(GetGamma()); - SetGammaValueLabelText(); } - private float GetGamma(bool userFacing = false) + private float GetGamma() { TrackBar tb = _page.GammaTrackBar; - int param = !userFacing ? tb.Maximum - tb.Value : tb.Maximum - (tb.Maximum - tb.Value); + int param = tb.Maximum - tb.Value; float ret = param * (1.0f / (tb.Maximum / 2.0f)); // @ScreenshotDisplay(gamma math): @@ -287,7 +283,6 @@ private void ResetGammaSlider() _page.GammaTrackBar.Value = 50; Config.ScreenshotGammaPercent = 50; _page.ScreenshotsPictureBox.SetGamma(1.0f); - SetGammaValueLabelText(); } private void SetCopiedMessageLabelText(string text, bool success) @@ -304,12 +299,6 @@ private void SetCopiedMessageLabelText(string text, bool success) CopiedMessageFadeoutTimer.Start(); } - private void SetGammaValueLabelText() - { - if (!_constructed) return; - _page.GammaValueLabel.Text = GetGamma(userFacing: true).ToString("N2", NumberFormatInfo.InvariantInfo); - } - private void CopiedMessageFadeoutTimer_Tick(object sender, EventArgs e) { if (!_constructed) return; From 819ece245f657611ada3766d6cc0c7fe2e3ec736 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 16:11:41 -0800 Subject: [PATCH 076/200] Ctrl-click now also resets gamma --- .../CustomControls/TopRightPages/ScreenshotsTabPage.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index d9879bea1..da63fc55e 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,5 +1,4 @@ // @ScreenshotDisplay: Keep the place in the screenshot set on reload? -// @ScreenshotDisplay: Have a gamma number/percent indicator, maybe reuse the "copied" label? using System; using System.Collections.Generic; @@ -75,6 +74,7 @@ public override void Construct() _page.PrevButton.Click += ScreenshotsPrevButton_Click; _page.NextButton.Click += ScreenshotsNextButton_Click; _page.GammaTrackBar.Scroll += GammaTrackBar_Scroll; + _page.GammaTrackBar.MouseDown += GammaTrackBar_MouseDown; _page.GammaTrackBar.DoubleClickEndingOnMouseDown += GammaTrackBar_MouseDoubleClick; FinishConstruct(); @@ -270,6 +270,14 @@ private float GetGamma() return ret; } + private void GammaTrackBar_MouseDown(object sender, MouseEventArgs e) + { + if ((ModifierKeys & Keys.Control) != 0 && e.Button == MouseButtons.Left) + { + ResetGammaSlider(); + } + } + private void GammaTrackBar_MouseDoubleClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) From dfa68019300517264a4d65a64036779796461fe3 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 19:30:38 -0800 Subject: [PATCH 077/200] Make sure 1.0 gamma is exactly 1.0 --- .../CustomControls/TopRightPages/ScreenshotsTabPage.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index da63fc55e..357048700 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -257,6 +257,12 @@ private float GetGamma() { TrackBar tb = _page.GammaTrackBar; + // Make sure 1.0 is really 1.0 exactly, not like eg. 1.001234 + if (tb.Value == tb.Maximum / 2) + { + return 1.0f; + } + int param = tb.Maximum - tb.Value; float ret = param * (1.0f / (tb.Maximum / 2.0f)); From d2f8eafa7648a06c27d0058f25f0de80a7839c28 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 19:38:48 -0800 Subject: [PATCH 078/200] Remove todos and cleanup notes --- AngelLoader/Common/DataClasses/LocalizationData.cs | 1 - .../CustomControls/TopRightPages/ScreenshotsTabPage.cs | 6 +----- AngelLoader/Screenshots.cs | 10 ++++------ 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 196580dcc..1dc7a19a6 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -629,7 +629,6 @@ internal sealed class ModsTab_Class internal sealed class ScreenshotsTab_Class { - // @ScreenshotDisplay: Finalize this text, improve it if necessary etc. internal readonly string TabText = "Screenshots"; internal readonly string CopyScreenshotToolTip = "Click to copy"; internal readonly string Gamma = "Gamma:"; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 357048700..e10659776 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,6 +1,4 @@ -// @ScreenshotDisplay: Keep the place in the screenshot set on reload? - -using System; +using System; using System.Collections.Generic; using System.Drawing; using System.IO; @@ -120,7 +118,6 @@ private void UpdatePageInternal(int index = -1) Screenshots.PopulateScreenshotFileNames(fm, ScreenshotFileNames); - // @ScreenshotDisplay: Should we hide everything and just put a label "No screenshots"? if (ScreenshotFileNames.Count == 0) { CurrentScreenshotFileName = ""; @@ -134,7 +131,6 @@ private void UpdatePageInternal(int index = -1) SetNumberLabelText(""); _forceUpdateArmed = false; } - // @ScreenshotDisplay: Should we save the selected screenshot in the FM object? else { CurrentScreenshotFileName = ScreenshotFileNames[index > -1 ? index : ScreenshotFileNames.Count - 1]; diff --git a/AngelLoader/Screenshots.cs b/AngelLoader/Screenshots.cs index 656261d12..34aec285d 100644 --- a/AngelLoader/Screenshots.cs +++ b/AngelLoader/Screenshots.cs @@ -11,7 +11,6 @@ namespace AngelLoader; -// @ScreenshotDisplay: Cleanup test Trace.WriteLines etc. public sealed class ScreenshotWatcher(GameIndex _gameIndex) { private sealed class ScreenshotWatcherTimer(double interval) : System.Timers.Timer(interval) @@ -116,13 +115,11 @@ public void Construct() private void Watcher_ChangedCreatedDeleted(object sender, FileSystemEventArgs e) { - //Trace.WriteLine(nameof(Watcher_ChangedCreatedDeleted) + ": " + e.ChangeType + "\r\n" + e.FullPath); _timer.ResetWith(e.FullPath, e.ChangeType); } private void Watcher_Renamed(object sender, RenamedEventArgs e) { - //Trace.WriteLine(nameof(Watcher_Renamed) + ": " + e.ChangeType + "\r\n" + e.OldFullPath); _timer.ResetWith(e.OldFullPath, e.ChangeType); } @@ -159,13 +156,14 @@ private void HandleEvent(string fullPath, WatcherChangeTypes changeType) => Core /* @ScreenshotDisplay: If this is enabled, it's possible a non-matching change will override the matching one. Unlikely, but meh. But if we disable it, then any TDM FM will attempt refresh if anything in the - central screenshots dir gets modified, even if doesn't match our FM name. Also not a big deal. We + central screenshots dir gets modified, even if it doesn't match our FM name. Also not a big deal. We could fix both cases by keeping a list of filenames and then checking if our name exists in it, and refreshing then. */ - //if (gameIndex != GameIndex.TDM || Screenshots.ScreenshotFileMatchesTDMName(fm.TDMInstalledDir, fullPath.GetFileNameFast())) +#if false + if (gameIndex != GameIndex.TDM || ScreenshotFileMatchesTDMName(fm.TDMInstalledDir, fullPath.GetFileNameFast())) +#endif { - //System.Diagnostics.Trace.WriteLine("---------------------------------------------- Refreshing"); Core.View.RefreshCurrentFMScreenshots(); } } From 1cba593e231b4382fc193b288870cc3417410e53 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 19:44:22 -0800 Subject: [PATCH 079/200] Cleanup --- AngelLoader/Screenshots.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/AngelLoader/Screenshots.cs b/AngelLoader/Screenshots.cs index 34aec285d..1fac13101 100644 --- a/AngelLoader/Screenshots.cs +++ b/AngelLoader/Screenshots.cs @@ -16,13 +16,11 @@ public sealed class ScreenshotWatcher(GameIndex _gameIndex) private sealed class ScreenshotWatcherTimer(double interval) : System.Timers.Timer(interval) { internal string FullPath { get; private set; } = ""; - internal WatcherChangeTypes ChangeType { get; private set; } - internal void ResetWith(string fullPath, WatcherChangeTypes changeType) + internal void ResetWith(string fullPath) { this.Reset(); FullPath = fullPath; - ChangeType = changeType; } } @@ -115,15 +113,15 @@ public void Construct() private void Watcher_ChangedCreatedDeleted(object sender, FileSystemEventArgs e) { - _timer.ResetWith(e.FullPath, e.ChangeType); + _timer.ResetWith(e.FullPath); } private void Watcher_Renamed(object sender, RenamedEventArgs e) { - _timer.ResetWith(e.OldFullPath, e.ChangeType); + _timer.ResetWith(e.OldFullPath); } - private void HandleEvent(string fullPath, WatcherChangeTypes changeType) => Core.View.Invoke(() => + private void HandleEvent(string fullPath) => Core.View.Invoke(() => { if (!_constructed) return; if (!EnableWatching) return; @@ -172,7 +170,7 @@ refreshing then. private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (Core.View == null!) return; - HandleEvent(_timer.FullPath, _timer.ChangeType); + HandleEvent(_timer.FullPath); } } @@ -341,7 +339,7 @@ static void AddIfValidFormat(List screenshotFileNames, string filename) } } - internal static bool ScreenshotFileMatchesTDMName(string tdmInstalledDir, string fn) + private static bool ScreenshotFileMatchesTDMName(string tdmInstalledDir, string fn) { int spaceIndex = fn.IndexOf(' '); // @TDM_CASE: Screenshot FM name comparison From b9c3800c8a8d2d099cd53715e1959cea071a9afc Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 27 Feb 2024 20:55:50 -0800 Subject: [PATCH 080/200] Note about perf findings --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index e10659776..c9c12326d 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -27,6 +27,10 @@ private sealed class MemoryImage : IDisposable public readonly Image Img; public string Path { get; private set; } + /* + @ScreenshotDisplay: This takes substantial time (~42ms for Calendra test screenshot) + We should preload this in the same way as rtf readmes + */ public MemoryImage(string path) { Path = path; From 28c3155fde76046937e23f3dee9e8ba9634e759f Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 10:26:25 -0800 Subject: [PATCH 081/200] Preload screenshot in parallel on startup --- AngelLoader/Core.cs | 7 +- .../TopRightPages/ScreenshotsTabPage.cs | 104 +++++++++++------- AngelLoader/Forms/FormsData.cs | 35 +++++- AngelLoader/Forms/FormsViewEnvironment.cs | 34 ++++++ AngelLoader/Forms/ScreenshotsPreprocessing.cs | 98 +++++++++++++++++ AngelLoader/Interfaces.cs | 1 + 6 files changed, 237 insertions(+), 42 deletions(-) create mode 100644 AngelLoader/Forms/ScreenshotsPreprocessing.cs diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index 6441a9f9e..f8e665ad5 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -359,10 +359,13 @@ Task DoParallelLoad(bool askForImport) (fmsViewListUnscanned, ex) = FindFMs.Find_Startup(splashScreen); if (ex == null) { + // Do this before anything, because it modifies the FMs list + TDM.UpdateTDMDataFromDisk(refresh: false); + + // Do this one first, because it starts a thread that will run behind all of the loading work + viewEnv.PreloadScreenshot(Config, FMsViewList); ViewEnv.PreprocessRTFReadme(Config, FMsViewList, fmsViewListUnscanned); } - - TDM.UpdateTDMDataFromDisk(refresh: false); }); // Construct and init the view right here, because it's a heavy operation and we want it to run diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index c9c12326d..129d54c98 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -1,7 +1,8 @@ -using System; +//#define TESTING + +using System; using System.Collections.Generic; using System.Drawing; -using System.IO; using System.Windows.Forms; using AL_Common; using AngelLoader.DataClasses; @@ -14,39 +15,6 @@ public sealed class ScreenshotsTabPage : Lazy_TabsBase { private Lazy_ScreenshotsPage _page = null!; - /* - Images loaded from files keep the file stream alive for their entire lifetime, insanely. This means the file - is "in use" and will cause delete attempts (like FM uninstallation) to fail. So we need to use this workaround - of loading the file into a memory stream first, so it's only the memory stream being kept alive. This does - mean we carry around the full file bytes in memory as well as the displayed image, but since we're only - displaying one at a time and they'll probably be a few megs at most, it's not a big deal. - */ - private sealed class MemoryImage : IDisposable - { - private readonly MemoryStream _memoryStream; - public readonly Image Img; - public string Path { get; private set; } - - /* - @ScreenshotDisplay: This takes substantial time (~42ms for Calendra test screenshot) - We should preload this in the same way as rtf readmes - */ - public MemoryImage(string path) - { - Path = path; - byte[] bytes = File.ReadAllBytes(path); - _memoryStream = new MemoryStream(bytes); - Img = Image.FromStream(_memoryStream); - } - - public void Dispose() - { - Path = ""; - Img.Dispose(); - _memoryStream.Dispose(); - } - } - private readonly List ScreenshotFileNames = new(); private string CurrentScreenshotFileName = ""; private MemoryImage? _currentScreenshotStream; @@ -120,7 +88,14 @@ private void UpdatePageInternal(int index = -1) Screenshots.GetScreenshotWatcher(gameIndex).Construct(); } - Screenshots.PopulateScreenshotFileNames(fm, ScreenshotFileNames); + if (_owner.StartupState && ScreenshotsPreprocessing.HasBeenActivated) + { + ScreenshotFileNames.ClearAndAdd_Small(ScreenshotsPreprocessing.ScreenshotFileNames); + } + else + { + Screenshots.PopulateScreenshotFileNames(fm, ScreenshotFileNames); + } if (ScreenshotFileNames.Count == 0) { @@ -137,7 +112,7 @@ private void UpdatePageInternal(int index = -1) } else { - CurrentScreenshotFileName = ScreenshotFileNames[index > -1 ? index : ScreenshotFileNames.Count - 1]; + SetCurrentScreenshotFileName(index); DisplayCurrentScreenshot(); _page.ScreenshotsPictureBox.Enabled = true; _page.GammaLabel.Enabled = true; @@ -148,6 +123,11 @@ private void UpdatePageInternal(int index = -1) } } + private void SetCurrentScreenshotFileName(int index = -1) + { + CurrentScreenshotFileName = ScreenshotFileNames[index > -1 ? index : ScreenshotFileNames.Count - 1]; + } + // Manual right-align to avoid needing a FlowLayoutPanel private void SetNumberLabelText(string text) { @@ -183,6 +163,10 @@ private void DisplayCurrentScreenshot() if (!_constructed) return; if (!_owner.StartupState && !Visible) return; +#if TESTING + System.Diagnostics.Trace.WriteLine("Startup state: " + _owner.StartupState); +#endif + if (_forceUpdateArmed || (!CurrentScreenshotFileName.IsEmpty() && // @TDM_CASE when FM is TDM @@ -190,8 +174,49 @@ private void DisplayCurrentScreenshot() { try { - _currentScreenshotStream?.Dispose(); - _currentScreenshotStream = new MemoryImage(CurrentScreenshotFileName); + if (_owner.StartupState) + { + FanMission? fm = _owner.GetMainSelectedFMOrNull(); + try + { + MemoryImage? mi = ScreenshotsPreprocessing.GetMemoryImage(fm); + if (mi != null) + { +#if TESTING + System.Diagnostics.Trace.WriteLine("Preload succeeded"); +#endif + _currentScreenshotStream = mi; + } + else + { +#if TESTING + System.Diagnostics.Trace.WriteLine("Preload failed"); +#endif + Screenshots.PopulateScreenshotFileNames(fm, ScreenshotFileNames); + SetCurrentScreenshotFileName(); + _currentScreenshotStream?.Dispose(); + _currentScreenshotStream = new MemoryImage(CurrentScreenshotFileName); + } + } + catch + { +#if TESTING + System.Diagnostics.Trace.WriteLine("Preload failed"); +#endif + Screenshots.PopulateScreenshotFileNames(fm, ScreenshotFileNames); + SetCurrentScreenshotFileName(); + _currentScreenshotStream?.Dispose(); + _currentScreenshotStream = new MemoryImage(CurrentScreenshotFileName); + } + } + else + { +#if TESTING + System.Diagnostics.Trace.WriteLine("Didn't preload"); +#endif + _currentScreenshotStream?.Dispose(); + _currentScreenshotStream = new MemoryImage(CurrentScreenshotFileName); + } _page.ScreenshotsPictureBox.SetImage(_currentScreenshotStream.Img, GetGamma()); } catch @@ -201,6 +226,7 @@ private void DisplayCurrentScreenshot() } finally { + ScreenshotsPreprocessing.Clear(); _forceUpdateArmed = false; SetNumberLabelText( (ScreenshotFileNames.IndexOf(CurrentScreenshotFileName) + 1).ToStrInv() + " / " + diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index f9b429bc2..c89d89d3b 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -1,4 +1,8 @@ -namespace AngelLoader.Forms; +using System; +using System.Drawing; +using System.IO; + +namespace AngelLoader.Forms; internal static class FormsData { @@ -16,3 +20,32 @@ public enum Direction { Left, Right, Up, Down } // IMPORTANT: Don't change the order, they're used as indices! public enum Zoom { In, Out, Reset } + +/* +Images loaded from files keep the file stream alive for their entire lifetime, insanely. This means the file +is "in use" and will cause delete attempts (like FM uninstallation) to fail. So we need to use this workaround +of loading the file into a memory stream first, so it's only the memory stream being kept alive. This does +mean we carry around the full file bytes in memory as well as the displayed image, but since we're only +displaying one at a time and they'll probably be a few megs at most, it's not a big deal. +*/ +public sealed class MemoryImage : IDisposable +{ + private readonly MemoryStream _memoryStream; + public readonly Image Img; + public string Path { get; private set; } + + public MemoryImage(string path) + { + Path = path; + byte[] bytes = File.ReadAllBytes(path); + _memoryStream = new MemoryStream(bytes); + Img = Image.FromStream(_memoryStream); + } + + public void Dispose() + { + Path = ""; + Img.Dispose(); + _memoryStream.Dispose(); + } +} diff --git a/AngelLoader/Forms/FormsViewEnvironment.cs b/AngelLoader/Forms/FormsViewEnvironment.cs index 0d4ead1c6..600b2ccbc 100644 --- a/AngelLoader/Forms/FormsViewEnvironment.cs +++ b/AngelLoader/Forms/FormsViewEnvironment.cs @@ -43,6 +43,40 @@ internal static MainForm ViewInternal public string ProductVersion => Application.ProductVersion; + public void PreloadScreenshot(ConfigData config, List fmsViewList) + { + // @ScreenshotDisplay: UI-specific preload conditions + // If we allow moving the screenshots tab beside the readme or wherever else, we'll have to update + // this code to match whatever the UI setup is. + if (config.TopRightPanelCollapsed || + config.TopRightTabsData.SelectedTab != TopRightTab.Screenshots) + { + return; + } + + SelectedFM selFM = config.GameOrganization == GameOrganization.OneList + ? config.SelFM + : config.GameTabsState.GetSelectedFM(config.GameTab); + + if (selFM.InstalledName.IsWhiteSpace()) return; + + FanMission? fm = fmsViewList.Find(x => x.InstalledDir.EqualsI(selFM.InstalledName)); + if (fm == null) return; + if (!Utils.FMIsReallyInstalled(fm, out _)) return; + + // @ScreenshotDisplay: If we save the position in the screenshot cycle, we'll have to update this to match! + List screenshotFileNames = new(); + Screenshots.PopulateScreenshotFileNames(fm, screenshotFileNames); + if (screenshotFileNames.Count == 0) return; + + string currentScreenshotFileName = screenshotFileNames[screenshotFileNames.Count - 1]; + + ScreenshotsPreprocessing.Run( + fm.InstalledDir, + currentScreenshotFileName, + screenshotFileNames); + } + public void PreprocessRTFReadme(ConfigData config, List fmsViewList, List fmsViewListUnscanned) { SelectedFM selFM = config.GameOrganization == GameOrganization.OneList diff --git a/AngelLoader/Forms/ScreenshotsPreprocessing.cs b/AngelLoader/Forms/ScreenshotsPreprocessing.cs new file mode 100644 index 000000000..943389b8f --- /dev/null +++ b/AngelLoader/Forms/ScreenshotsPreprocessing.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using System.Threading; +using AL_Common; +using AngelLoader.DataClasses; + +namespace AngelLoader.Forms; + +internal static class ScreenshotsPreprocessing +{ + private static Thread? _thread; + private static MemoryImage? _memoryImage; + private static string _fmInstalledDir = ""; + internal static readonly List ScreenshotFileNames = new(); + internal static bool HasBeenActivated; + + internal static void Clear() + { + _thread = null; + _memoryImage = null; + _fmInstalledDir = ""; + ScreenshotFileNames.Clear(); + try + { + ScreenshotFileNames.Capacity = 0; + } + catch + { + // ignore + } + } + + internal static MemoryImage? GetMemoryImage(FanMission? fm) + { + WaitOnThread(); + + if (fm == null) return null; + + if (!fm.InstalledDir.IsWhiteSpace() && + !_fmInstalledDir.IsWhiteSpace() && + fm.InstalledDir.EqualsI(_fmInstalledDir)) + { + return _memoryImage; + } + else + { + return null; + } + } + + private static void WaitOnThread() + { + if (_thread == null) return; + try + { + _thread.Join(); + } + catch + { + // Not started or whatever + } + } + + // If we ran this in the startup work thread, it would stop before FinishInitAndShow(). But since users might + // be loading 4K resolution pngs and whatnot, we want to overlap across as great a timespan as possible - + // right up until the screenshot is due to be displayed. + // We also make it a foreground thread so it doesn't keep the app alive if something goes wrong and we close. + internal static void Run( + string fmInstalledDir, + string currentScreenshotFileName, + List screenshotFileNames) + { + HasBeenActivated = true; + _fmInstalledDir = fmInstalledDir; + ScreenshotFileNames.ClearAndAdd_Small(screenshotFileNames); + + try + { + _thread = new Thread(() => + { + try + { + _memoryImage = new MemoryImage(currentScreenshotFileName); + } + catch + { + _memoryImage = null; + } + }); + + _thread.IsBackground = false; + _thread.Start(); + } + catch + { + _memoryImage = null; + } + } +} diff --git a/AngelLoader/Interfaces.cs b/AngelLoader/Interfaces.cs index 07daa9c36..71d03c394 100644 --- a/AngelLoader/Interfaces.cs +++ b/AngelLoader/Interfaces.cs @@ -44,6 +44,7 @@ public interface IViewEnvironment IDialogs GetDialogs(); ISplashScreen GetSplashScreen(); IView GetView(); + void PreloadScreenshot(ConfigData config, List fmsViewList); void PreprocessRTFReadme(ConfigData config, List fmsViewList, List fmsViewListUnscanned); (bool Accepted, ConfigData OutConfig, bool AskForImport) ShowSettingsWindow(ISettingsChangeableView? view, ConfigData inConfig, SettingsWindowData.SettingsWindowState state); From 3b29be9f5ab1a572eae8e4238dc83175cc99c5c0 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 10:32:18 -0800 Subject: [PATCH 082/200] If startup OpenSettings canceled, return immediately Before, we were setting up TDM watchers even if the window was canceled. This ultimately resulted in no issues, but it's correct now. --- AngelLoader/Core.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index f8e665ad5..bc59c2ee6 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -410,6 +410,10 @@ Task DoParallelLoad(bool askForImport) splashScreen.Show(Config.VisualTheme); await DoParallelLoad(askForImport); } + else + { + return; + } } TDMWatchers.DeferredWatchersEnable(enableTDMWatchers); From f724f9bed7bf4ea09c79cfe9d313940cc4dde5e9 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 11:24:02 -0800 Subject: [PATCH 083/200] Tweak gamma math some more --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 129d54c98..305c1c636 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -296,7 +296,7 @@ private float GetGamma() // Trial-and-error flailing until we get something with a good range and that has 1.0 in the middle for // non-confusing UX. The last 4 values end up differing by a small enough amount that the image doesn't // change between them (not that I can see anyway). Whatever... I might come back to it later... - ret *= ret / 1.18f; + ret = (ret * ret) / 1.18f; ret += 0.15f; return ret; From b4762e376d5915b256d543150a9603231bbfe853 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 14:25:41 -0800 Subject: [PATCH 084/200] Fix screenshots tab not saved/loaded from config file --- AngelLoader/Ini/ConfigIni.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/AngelLoader/Ini/ConfigIni.cs b/AngelLoader/Ini/ConfigIni.cs index 290e6e0cc..0f53b792e 100644 --- a/AngelLoader/Ini/ConfigIni.cs +++ b/AngelLoader/Ini/ConfigIni.cs @@ -754,6 +754,16 @@ private static void Config_ModsTabVisible_Set(ConfigData config, string valTrimm config.TopRightTabsData.GetTab(TopRightTab.Mods).Visible = valTrimmed.EqualsTrue(); } + private static void Config_ScreenshotsTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) + { + Int_TryParseInv(valTrimmed, out int result); + config.TopRightTabsData.GetTab(TopRightTab.Screenshots).DisplayIndex = result; + } + private static void Config_ScreenshotsTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) + { + config.TopRightTabsData.GetTab(TopRightTab.Screenshots).Visible = valTrimmed.EqualsTrue(); + } + #endregion private static void Config_ReadmeZoomFactor_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) @@ -987,6 +997,9 @@ private static unsafe Dictionary { "ModsTabPosition", new Config_DelegatePointerWrapper(&Config_ModsTabPosition_Set) }, { "ModsTabVisible", new Config_DelegatePointerWrapper(&Config_ModsTabVisible_Set) }, + { "ScreenshotsTabPosition", new Config_DelegatePointerWrapper(&Config_ModsTabPosition_Set) }, + { "ScreenshotsTabVisible", new Config_DelegatePointerWrapper(&Config_ModsTabVisible_Set) }, + #endregion { "ReadmeZoomFactor", new Config_DelegatePointerWrapper(&Config_ReadmeZoomFactor_Set) }, @@ -1373,6 +1386,7 @@ private static void WriteConfigIniInternal(ConfigData config, string fileName) sw.Append("TagsTabPosition").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Tags).DisplayIndex).AppendLine(); sw.Append("PatchTabPosition").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Patch).DisplayIndex).AppendLine(); sw.Append("ModsTabPosition").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Mods).DisplayIndex).AppendLine(); + sw.Append("ScreenshotsTabPosition").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Screenshots).DisplayIndex).AppendLine(); sw.Append("StatsTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Statistics).Visible).AppendLine(); sw.Append("EditFMTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.EditFM).Visible).AppendLine(); @@ -1380,6 +1394,7 @@ private static void WriteConfigIniInternal(ConfigData config, string fileName) sw.Append("TagsTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Tags).Visible).AppendLine(); sw.Append("PatchTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Patch).Visible).AppendLine(); sw.Append("ModsTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Mods).Visible).AppendLine(); + sw.Append("ScreenshotsTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Screenshots).Visible).AppendLine(); sw.Append("ReadmeZoomFactor").Append('=').AppendLine(config.ReadmeZoomFactor.ToString(NumberFormatInfo.InvariantInfo)); sw.Append("ReadmeUseFixedWidthFont").Append('=').Append(config.ReadmeUseFixedWidthFont).AppendLine(); From 6db2ce58c9c8ff517a16d4005be2a726a3789e86 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 14:31:38 -0800 Subject: [PATCH 085/200] Really fix config screenshots reading --- AngelLoader/Ini/ConfigIni.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Ini/ConfigIni.cs b/AngelLoader/Ini/ConfigIni.cs index 0f53b792e..3a4d6cdf2 100644 --- a/AngelLoader/Ini/ConfigIni.cs +++ b/AngelLoader/Ini/ConfigIni.cs @@ -997,8 +997,8 @@ private static unsafe Dictionary { "ModsTabPosition", new Config_DelegatePointerWrapper(&Config_ModsTabPosition_Set) }, { "ModsTabVisible", new Config_DelegatePointerWrapper(&Config_ModsTabVisible_Set) }, - { "ScreenshotsTabPosition", new Config_DelegatePointerWrapper(&Config_ModsTabPosition_Set) }, - { "ScreenshotsTabVisible", new Config_DelegatePointerWrapper(&Config_ModsTabVisible_Set) }, + { "ScreenshotsTabPosition", new Config_DelegatePointerWrapper(&Config_ScreenshotsTabPosition_Set) }, + { "ScreenshotsTabVisible", new Config_DelegatePointerWrapper(&Config_ScreenshotsTabVisible_Set) }, #endregion From f2175e78985d140f927cfae16d20c3b660b94d89 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 15:31:10 -0800 Subject: [PATCH 086/200] Start work on readme area horizontal split --- AngelLoader/Forms/MainForm.Designer.cs | 41 +++++-- AngelLoader/Forms/MainForm.cs | 7 +- AngelLoader/Forms/MainForm.resx | 146 +++++++++++------------ AngelLoader/Forms/MainForm_InitManual.cs | 38 ++++-- 4 files changed, 139 insertions(+), 93 deletions(-) diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 9be337d25..78aaa6348 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -110,6 +110,7 @@ private void InitializeComponent() this.PatchTabPage = new AngelLoader.Forms.CustomControls.PatchTabPage(); this.ModsTabPage = new AngelLoader.Forms.CustomControls.ModsTabPage(); this.ScreenshotsTabPage = new AngelLoader.Forms.CustomControls.ScreenshotsTabPage(); + this.LowerSplitContainer = new AngelLoader.Forms.CustomControls.DarkSplitContainerCustom(); this.ReadmeEncodingButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ReadmeFullScreenButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ReadmeZoomInButton = new AngelLoader.Forms.CustomControls.DarkButton(); @@ -117,7 +118,7 @@ private void InitializeComponent() this.ReadmeResetZoomButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ChooseReadmeComboBox = new AngelLoader.Forms.CustomControls.DarkComboBoxWithBackingItems(); this.ReadmeRichTextBox = new AngelLoader.Forms.CustomControls.RichTextBoxCustom(); - this.MainToolTip = new CustomControls.ToolTipCustom(this.components); + this.MainToolTip = new AngelLoader.Forms.CustomControls.ToolTipCustom(this.components); this.BottomRightFLP.SuspendLayout(); this.BottomLeftFLP.SuspendLayout(); this.EverythingPanel.SuspendLayout(); @@ -135,6 +136,9 @@ private void InitializeComponent() this.FilterIconButtonsToolStrip.SuspendLayout(); this.RefreshAreaToolStrip.SuspendLayout(); this.TopRightTabControl.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.LowerSplitContainer)).BeginInit(); + this.LowerSplitContainer.Panel1.SuspendLayout(); + this.LowerSplitContainer.SuspendLayout(); this.SuspendLayout(); // // GameTabsImageList @@ -255,13 +259,7 @@ private void InitializeComponent() // MainSplitContainer.Panel2 // this.MainSplitContainer.Panel2.BackColor = System.Drawing.SystemColors.Control; - this.MainSplitContainer.Panel2.Controls.Add(this.ReadmeEncodingButton); - this.MainSplitContainer.Panel2.Controls.Add(this.ReadmeFullScreenButton); - this.MainSplitContainer.Panel2.Controls.Add(this.ReadmeZoomInButton); - this.MainSplitContainer.Panel2.Controls.Add(this.ReadmeZoomOutButton); - this.MainSplitContainer.Panel2.Controls.Add(this.ReadmeResetZoomButton); - this.MainSplitContainer.Panel2.Controls.Add(this.ChooseReadmeComboBox); - this.MainSplitContainer.Panel2.Controls.Add(this.ReadmeRichTextBox); + this.MainSplitContainer.Panel2.Controls.Add(this.LowerSplitContainer); this.MainSplitContainer.Panel2.Padding = new System.Windows.Forms.Padding(1, 1, 2, 2); this.MainSplitContainer.Panel2.Paint += new System.Windows.Forms.PaintEventHandler(this.ReadmeContainer_Paint); this.MainSplitContainer.Panel2.MouseLeave += new System.EventHandler(this.ReadmeArea_MouseLeave); @@ -978,6 +976,29 @@ private void InitializeComponent() this.ScreenshotsTabPage.TabIndex = 5; this.ScreenshotsTabPage.Text = "Screenshots"; // + // LowerSplitContainer + // + this.LowerSplitContainer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.LowerSplitContainer.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.LowerSplitContainer.Location = new System.Drawing.Point(1, 1); + this.LowerSplitContainer.Name = "LowerSplitContainer"; + // + // LowerSplitContainer.Panel1 + // + this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeEncodingButton); + this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeFullScreenButton); + this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeZoomInButton); + this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeZoomOutButton); + this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeResetZoomButton); + this.LowerSplitContainer.Panel1.Controls.Add(this.ChooseReadmeComboBox); + this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeRichTextBox); + this.LowerSplitContainer.Panel2Collapsed = true; + this.LowerSplitContainer.Size = new System.Drawing.Size(1670, 356); + this.LowerSplitContainer.SplitterDistance = 1613; + this.LowerSplitContainer.TabIndex = 0; + // // ReadmeEncodingButton // this.ReadmeEncodingButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); @@ -1127,6 +1148,9 @@ private void InitializeComponent() this.RefreshAreaToolStrip.ResumeLayout(false); this.RefreshAreaToolStrip.PerformLayout(); this.TopRightTabControl.ResumeLayout(false); + this.LowerSplitContainer.Panel1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.LowerSplitContainer)).EndInit(); + this.LowerSplitContainer.ResumeLayout(false); this.ResumeLayout(false); } @@ -1255,6 +1279,7 @@ private void InitializeComponent() internal CustomControls.DarkButton ReadmeZoomOutButton; internal CustomControls.DarkButton ReadmeResetZoomButton; internal CustomControls.DarkButton ReadmeFullScreenButton; + internal CustomControls.DarkSplitContainerCustom LowerSplitContainer; #endregion diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 41eb0f15f..ac12ee4eb 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -925,6 +925,9 @@ and does NOT have its text transferred over. It ends up with blank text. TopSplitContainer.Panel1DarkBackColor = DarkColors.Fen_ControlBackground; TopSplitContainer.Panel2DarkBackColor = DarkColors.Fen_DarkBackground; + LowerSplitContainer.Panel1DarkBackColor = DarkColors.Fen_DarkBackground; + LowerSplitContainer.Panel2DarkBackColor = DarkColors.Fen_DarkBackground; + #endregion #region FMs DataGridView @@ -4774,7 +4777,7 @@ public void SetReadmeLocalizableMessage(ReadmeLocalizableMessage messageType) // visually separated enough. private void ReadmeContainer_Paint(object sender, PaintEventArgs e) { - Control rc = ReadmeContainer; + Control rc = MainSplitContainer.Panel2; if (MainSplitContainer.DarkModeEnabled) { @@ -5334,7 +5337,7 @@ public void ShowUpdateNotification(bool show) } // We might want to change this, if we want something beside the readme or whatever - internal Control ReadmeContainer => MainSplitContainer.Panel2; + internal Control ReadmeContainer => LowerSplitContainer.Panel1; public void RefreshCurrentFMScreenshots() { diff --git a/AngelLoader/Forms/MainForm.resx b/AngelLoader/Forms/MainForm.resx index 164dadae4..47cf093b2 100644 --- a/AngelLoader/Forms/MainForm.resx +++ b/AngelLoader/Forms/MainForm.resx @@ -125,45 +125,45 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAK - EwAAAk1TRnQBSQFMAgEBBAEAATABGwEwARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + EwAAAk1TRnQBSQFMAgEBBAEAAWABGwFgARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgADBQEGA0IBdANP AZkDVQGxA1sBygNWAbUDTAGRA0YBgAMcAScoAAMNAREDSgGLA1ABmgMeASsYAAMDAQQDVQGtA1gBvQNO AZYDYAHgA1ABnzQAAwIBAwMZASIDWgHHA1IBoANBAXMDQAFvAzQBUwMpAT0DHQEpAx4BKgMPARMDBQEG DAADIwEzA2AB6AMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/Az4BahgAAwwBEAMFAQYEAAMr AUECAAGXAf8DAAH/A0ABcAwAAwMEBAEFBAADBQEGAYYBiwEAAf8ByQHNAQAB/wGQAZYBAAH/AaoBugEA Af8DWgHHAy0BRgMZASIDKAE7AzkBXgNCAXQDPwFuAzkBXgMIAQoMAAQBAw8BFAMuAUgDVgGwA0AB/QNA - Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABRAFgAXcB/gMAAf8DWgHE + Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABSgFmAX0B/gMAAf8DWgHE ASMBXgEhAfsDAAH/AgABnAH/AwAB/wMAAf8DWwHkA0EB+QMAAf8DQwF3DAADCQEMA1ABnwNdAckDPQFo A0YBgQNdAc8BAAGVAcoB/wMAAf8DXgHXA0MBdgMzAVEDVgGwA0YBfgMTARkIAAMsAUMDYQHiAv8BAAH/ - A1wB2QFvAXQBPgH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA + A1wB2QF1AXoBRAH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA ARABAAH/AwAB/wEKAQwBBwH/ASYBPQE6Af8BHwEyATAB/wEAARABAAH/AwAB/wEGASMBAAH/AQMBIgEA Af8DXgHwA0QBeQMIAQoEAANdAdEDAAH/A0sBjANdAcwDAAH/AwAB/wIAAZgB/wIAAZYB/wNAAf0DXAH4 A1EBpANRAfcDAAH/AyIBMQgAAx8BLAEAAY4BpwH/AgABmgH/AwAB/wEAAZQBvQH/AQABzgL/AQABsQHe Af8BAAGYAdIB/wEAAYUBygH/AwAB/wMrAfwBAAGnAcgB/wNZAe8DHgErDAADRgF9AbwBwQEAAf8DVQG0 - A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFPAWQBPgH+ + A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFVAWoBRAH+ ARIBSQEAAf8BDAE0AQAB/wEsAjUB/wEPARYBFwH/ARcCHwH/ARcBHQEeAf8BCgE2AQAB/wEKASQBAAH/ - AWQBdgFQAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 + AWoBfAFWAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 AwAB/wNGAYEDTgGXAwAB/wNWAbAMAANEAXsBAAGyAdgB/wEAAbcB9QH/AQAB0QH5Af8BAAGZAZ4B/wEA AbMBzwH/AQABjgGtAf8BAAGyAccB/wEAAdcC/wEAAesC/wEAAZ0BoQH/A08BmwMOARIMAANGAYABxQHJ - AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgE8 - AjsB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ + AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFC + AkEB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ AwAB/wEVAQABAwH/A0AB/QNWAbUDGQEjA1gBvQMAAf8DXQHUAx4BKgNZAcMDAAH/A0AB/QIAAbwB/wMA Af8DAAH/AwAB/wMoATsDNQFWAwAB/wIhASMB+wMTARoIAANQAZ0BAAGtAesB/wEAAaEBygH/AwAB/wMA Af8BAAGUAbcB/wIAAYIB/wMAAf8BAAGZAZ8B/wEAAegC/wMAAf8DTAGOAwUBBgwAA0gBhAG6Ab8BAAH/ A10B3AFsAW0BUQH3AdgB6AEAAf8BtwG6AQAB/wHcAeEBAAH/AwAB/wNZAcMBwQHGAQAB/wNdAd8DGAEh CAADOARcAdYDKwH8AwAB/wEGAQoBDAH/AaEBpwGmAf8BhAGMAY0B/wErATcBPwH/AQ4BHQEmAf8BkgGY AZkB/wFQAVYBVwH/AwAB/wMAAf8DTQH6A0sBjAMPARQDXgHtAwAB/wMrAfwDRQF8Az0BaQNNAfoBKQIy - AfsDTQH6AUwBUQF9Af4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu + AfsDTQH6AVIBVwGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu Af8DAAH/AwAB/wMAAf8BAAGMAbgB/wMAAf8BggIAAf8DAAH/AQABuAHOAf8BAAGFAcQB/wNeAd0DOgFg AxUBHAgAA0cBgwGVAZsBAAH/AwAB/wHbAesBAAH/A1UBrwMQARUCUwFSAaUBwwHKAQAB/wNcAecBqAGw - AQAB/wNiAeEDGwElCAADSQGHAUsBSgFLAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ + AQAB/wNiAeEDGwElCAADSQGHAVEBUAFRAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ AUgBVwGBAf8BNgFKAVIB/wGrArIB/wGjAagBqQH/ARwBHwEjAf8BFQEJAQ4B/wNAAf0DWwHTAyoBPwNI - AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBUwGAAUcB/gNgAegDXgHXAzsBZQNKAYoCAAGI + AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBWQGAAU0B/gNgAegDXgHXAzsBZQNKAYoCAAGI Af8CAAGfAf8DPwFsA18B2gMAAf8BAAGyAeMB/wEAAY4BqQH/AwAB/wMAAf8DAAH/AQABkQHDAf8DAAH/ AwAB/wMAAf8DAAH/AQABsAHuAf8DAAH/AwAB/wNOAZYIAANHAYMBAAGGAQAB/wHXAdwBAAH/AwAB/wNQ AZ0DGwElA1UBrAHCAc4BAAH/A1wB2QGgAaoBAAH/A1oB6QMeASoIAANGAX0DTQH6AQ8BHgEAAf8BIgEx ARMB/wE1AU4BOQH/ASgBUgFGAf8BFAEkASYB/wFQAV0BhAH/ATUBRAFIAf8BGQEwASwB/wEjAT4BOQH/ - ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A04B/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 + ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1QB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 A00B+gMrAfwBIQEyASEB+wNYAb0DKQE9A14B1wIAAZIB/wMAAf8DPgFqAgABhgH/AQABqAHSAf8BAAHS Av8CAAGEAf8DAAH/AwAB/wMAAf8BAAGKAcEB/wMAAf8DAAH/AwAB/wMAAf8BAAG8AfYB/wEAAaoB3gH/ AgABmQH/A1IBqAgAA0MBdgGHAZMBAAH/AmgBQQH5Ad4B4QEAAf8DAAH/AwAB/wHOAeABAAH/Al4BXAHZ @@ -177,30 +177,30 @@ ASgBLwExAf8BAQEHAQoB/wMAAf8BFwE5AQAB/wNNAfoDPgFrA1YBtgIAAZgB/wMAAf8CAAGIAf8DXgHd AzQBVANVAa4BlwGpAd0B/wJeAV8B+wNHAYMDUgGlAwAB/wMAAf8DAAH/A00B+gMPARQEAAQBAV0CZQHs AQABoQHmAf8DAAH/AYICAAH/AwAB/wEAAYwBuAH/AwAB/wMAAf8DAAH/AgABvQH/AQABlgHAAf8DVgGy - AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABWgH+ - AdEB1wEAAf8CgAFXAf4CgAFBAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ - AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BQwFAAUEB/gNZAcMDIQEv + AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABYAH+ + AdEB1wEAAf8CgAFdAf4CgAFHAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ + AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BSQFGAUcB/gNZAcMDIQEv AzABSgMAAf8DAAH/AgABnwH/AQABgQG2Af8DAAH/A2AB8wMAAf8DXAH4A00B+gEAAYQBsgH/AwAB/wMA Af8DAAH/A1MBpgwAA0IBdQEAAeMC/wEAAZQBzAH/AwAB/wMAAf8BAAGAAbEB/wMAAf8DAAH/AgABjgH/ AQABuQH7Af8DAAH/A0wBjgMSARcEAAMlATcDAAH/AdsB3AGOAf8B+AH7AZ0B/wGlAagBAAH/Al8BMgH7 AZcBmgEAAf8DWgH1AZABkgEAAf8BpAGnAQAB/wJiAVkB7wHtAfIBjgH/AckBzQEAAf8BoAGlAQAB/wNb AdgDFAEbAxUBHANiAeEDAAH/AR8BDwEVAf8BJAEiAScB/wE/AVwBOgH/AbgBywG4Af8B2ALdAf8B3QLg - Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AVgBTgFRAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ + Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AV4BVAFXAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ AwAB/wIAAYUB/wIAAaoB/wMAAf8BAAGAAZsB/wEAAY4BuAH/AwAB/wMAAf8CAAG0Af8DTQH6AxMBGQgA AxgBIQFbAl0BygEAAeUB+gH/AQAD/wEAAcQB9wH/AgABlAH/AQABjQG6Af8CAAGXAf8CAAHCAf8BAAHR Av8BAAHKAe4B/wIAAYcB/wNbAeQDIQEvCAADAgEDA00BkwG8AcYBAAH/A1YBsANeAeIDAAH/A2UB8QMA Af8DOQFeA1IBoAL/AQAB/wMAAf8DWgG/AxYBHgQAAy0BRQNIAfYBGQEFAQoB/wEYAQ4BEwH/ARQBDAEO Af8BLgFVARoB/wFdAZwBVgH/AY0BjAGOAf8BqAGvAbAB/wFVAaMBQgH/ATABRwEUAf8DAAH/AQMCAAH/ - AUoBRwFIAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA + AVABTQFOAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA Af8CAAGkAf8CAAGGAf8DLQFFDAADIAEtAQABlQGsAf8BAAGAAZIB/wNRAaEDXQHqAQAB4gH4Af8BAAHe AfMB/wEAAcoB8wH/AQABpgHIAf8DWQG7A1kBuwEAAa8B0AH/A1cBvAMLAQ4MAAMmATkDXQHMAyUBNwNT AakDUgGgA1UBrANVAa8DQwF2A4AB/gG0AbgBAAH/AbsBxwEAAf8DZQHxAzIBTwQAA0IBdANcAcsDKwH8 AysB/AEdAUQBBgH/AS8BNwEYAf8BNwFCASIB/wEoARsBIQH/ASwBKQErAf8BNAGBARMB/wEmAUIBDgH/ - AR4BNAEDAf8BAQIAAf8BSwFBAUUB/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ + AR4BNAEDAf8BAQIAAf8BUQFHAUsB/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wIAAZEB/wJeAWEB4gMtAUUUAAMmATgDMwFRBAADDAEPA0QBewEAAewC/wEAAYIBlAH/A0oBiQME AQUDAwEEAzQBVAMNAREsAANdAdEByQHSAQAB/wNLAY8CbQFRAfcBmwGoAQAB/wM+AWoEAAMDAQQDDAEP - AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFcAVUBVwH+ - AXEBgAFNAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ + AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFiAVsBXQH+ + AXcBgAFTAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ ARUDZQHxA2AB4EAAA0QBeQNSAaUEAANGAYEDWQHBAw8BFAQAAwQBBQQABAEDOAFcA0IBdANGAX4DUwGq A1UBrQNYAboDWgHEA1EBogNUAasDQAFvAwwBDwQBBAABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEA AQEGAAEBFgAD/4EAAeABDwH8AT8BAwH/AeABAQHAAQcB5AE5AQABAwGAAQABgAEDAYABAQGAAQMBgAEA @@ -209,9 +209,6 @@ AgAB8AEPAfwBfwH/AZEBQAEBCw== - - True - True @@ -282,78 +279,79 @@ iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGuSURBVDhPYxhQEKvEFB+nzHwiVoXlQ5wKyzso/R+EY5WZ - p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD4CuayqwkQUbBDME - hs9snf7/yKoeMHt9fyHYYKg23ADkwkJb2f8vb+/DMPDinnlArzMfjlVmWbN3UQtYDBQUUK3YAciFIAOx - uRCEbx5bAXLZeaBBOw6v7AaL4TUU5mVsLkTG1w4t/X96yzQw++3DI0BLWD5BjUAFQC+3FdnJETQQHb+6 - ewBk6FuoMQgAc+Gb+9i9jA9/eXUW5P1/UKMgABjoLcR4GRd+dn0nyKVPocYBvazM3FxsrwD2AjYNhPDH - Zyf+V3po/I9TZamBGgnyNsubV3f2Y9VACMMNVGbuhxoHAaCkAUoi2DThwx+fncRuIAjEK7OmpejwgNMe - Ns3YMMiFVZ6aoLQ6AWoMJgAZnKTJSZTBOL2MDSAMXonVMBCGuZAoA2EAGIPpuFxMkgvRATYXU2QgDEBc - zPX/yv5F/x9e3EK6l3GBOGWmOGDsHgcadi9WlaUUKjwQgIEBAExb1Vj6X25iAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG4SURBVDhPYxhQEKvEFB+nxHQiVoXlQ5wKyzso/R+EY5WZ + p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD+KUmZsKbGTBBsEM + geEzW6f/P7KqB8xe318INhiqDTcAubDQVvb/y9v7MAy8uGce0OtMh2OVWdbsXdQCFgMFBVQrdgByIchA + bC4E4ZvHVvyPUWI6DzRox+GV3WAxvIbCvIzNhcj42qGl/09vmQZmv3145H+0IssnqBGoAOjltiI7OYIG + ouNXdw/8j1FmeQs1BgFgLnxzH7uX8eEvr86CvP8PahQExKkwtxDjZVz42fWd/2OVWJ5CjQN6WZm5udhe + AewFbBoI4Y/PTvyv9ND4H6fKUgM1EuhKRZY3r+7sx6qBEIYbqMzcDzUOAkBJA5REsGnChz8+O4ndQBCI + V2ZNS9HhAac9bJqxYZALqzw1QbloAtQYTAAyOEmTkyiDcXoZG0AYvBKrYSAMcyFRBsIAMAbTcbmYJBei + A2wupshAGIC4mOv/lf2L/j+8uIV0L+MCccpMccAS/3icEvO9WFWWUqjwQAAGBgD++NVEgXhbGQAAAABJ + RU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VVPKARhFN+jNDO7KLmoLRcHBy7iIi6SFDks - TqtmZtlcpEQuOGjNzK4p5F/tKiku4qAkB8vGYg97cLCJkAs3N0fmN71PY7Raa8rFr17tfu997+/vfeP6 - hx28pPa6JbWa/joLt6g1lg3M3RQH9WdB1rrp2Bm4+0Le4uDMtS+WvPXFLh7Lh5YzvKxNkPqX8I8XGM7S - 7QuJs57V1BukO3b+UhLUX8jidxAkdbspsn/InENqp7aOeFHZIJP8gTZUja1/ZA5p1g/igqwmURmZ5Qcu - oHSg113R1Ctz3rl0mi4KRO4xEzLLD6Ai2IKBMuf4jTNemq4jMxtQUg5lFfrVMo8cziBb5hxVmMwx9oDM - bDAcc5K2B/k2iKFDf9Fn5hyCORjc18nKBnJeM7mZaNB2zQG5/bqHtJ/Ay+FFMMTqHAziZeWQTL4CdIJz - dgHZgddoBZmYMMof9A6vXFqHCu5zonaXLSFzWEZprx3LJyl2CdI6G0+YF4kNgqi2lA7MP3ZFL56ZDba2 - pH/mgQuEK01n2YAgnj7tqW3h+MQaBEFBOdARel80mWE6bCoCQkduvgeyQMbI3BoETMHK24NXjq6ljKpG - 6XpuQDsEUbnCoK3OrG2B1Id24nge6NrPgGFhwHamMEEl0OeyL9lhoa2VMZiBI8+ACXOhtFX0GkHQJnxM - 8FEhC2eAxcITUDESTQuS0k/HzgJPcvZn4E/hcr0DUbSOqjT7gYIAAAAASUVORK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIeSURBVEhL7VVPKENxHN9R7L1tKbmInBwcnMRFXCQpUhan + yd7bvJuULBccxHtv6xWihSkpJ3FQksPG2qbtsIODJUIu3NwceZ/X96fnaZp55eJT39p+3+/v+/fz/T3H + P6zgBGXUJSgt9NdeuPxqZ620cuORtGdeVIfp2B64gosNHily7Y2lb72x7GPdZLTAieocqX8J32yF7izf + v5a8GNnOvUGGY5mXakl7IYvfgReUg67ISZw5h7Qu7J9xfnmPTMoH2tA8s/uROaRbO03wopJBZWRWHpwB + eQC9HtrIvTLng+vpvCcQucdMyKw8gIpgCwbKnOM3zjhhqY3MLEBJJZRV6VNq3WK4gGyZc1RhMEffAzKz + QHfsFNRjyLdBdB36iz4z5xDMQee+RlYWkPOW+b1kh3pkDMjl09yk/QRODK+DIWbnYBAnynEy+QrQCc7Z + BWQHXqMVZGJAL3+ifip6aR4quF/lV++KJWQMSy/tdSCayrFLkN7lRNK4SGzg/UpPjbT66N3MPjMbbG31 + ePjBGQg3Gc6KAUHcQeWpb+08ZQ6CoKAc6Ai9dytTYDpsKgJCR26+B7JAxsjcHARMwcpbgzeFdnJ6VSG6 + XhrQDn5MvsKgzc7MbYG0Lx4m8DzQtZ8Bw8KArUxhgkqgL2VfisNEWzNjMANbngEDxkKp2+g1gqBN+Jjg + o0IW9gCLhSegcXozzwvyOB3bCzzJxZ+BP4XD8Q5UnY5o0DYeqQAAAABJRU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGZSURBVEhL7ZQhUMNAEEUjGSZ3QSKRSCQSiUTiykzuChKJ - AweX60wkEolEIiuRSCQSicSyf/vDHEdpO00EgjeTafdfZu9u92+Kf3KMa04q1+wxHJaqjge2Di/WxTfr - 4zHlYahOr3eQvBxPdvHf+PgszxWXezK63EDCchyOqBTVqN0qfXhn2A/rmgdbNxcMFeMnt6YO9wzXB2XA - BgwVafS59c0TbkZpPVASlCZNhEaXdXxFHyitB6wIt6SJtNGiGXezTykDJ1nhWpujZhuOwWkpfTUac0Al - Q14oXXzEs3ATWUN9UWcqijbax5ZhBpPLC3faNEkAm3H1G+oOeRgqcJDxYcrwJ7ATkjNUF+C6KAUlZZ47 - 0Ght6i8HmjXLxw85xSElBbVM3YB1xOmmmFpo+KU0n84R+fejS4pTqmOSj5hOKtcoLaY7Te4C9bWMfL65 - 9iyb3qWoj8V+aDQlJe+FbNbm07syuLr6OXNKB26C9YVWXkpi2zQReoAy9v4MKJIYG3SDN3d6h2A2WChZ - mFoXzigPC5qOxjL8SxTFJ00CxZeT7IG4AAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGaSURBVEhL7ZQhUMQwEEUrmaNNkUgkEolEIpG4MjQ5kEgc + uKPJzVQikUgk8iQSiUQikVjy936ZEErvpq1A8GY6d/vT2SS7f5v8E5Npe5Jru8dwXPLSHajT6kVp96aM + O6Y8DvnZbAfJ0+l8F/8z4579c83lgRRXG0iYTqsjKkle1FsTM3tnOAyl7YMq7SVDITPz26ys7hn2B2XA + BgwF3+gLZewTbkapHygJShMmQqM3S/eKPlDqB6wIt4SJpNFey/TNPqUInGSNa00Kuw3H4LSUvhqNOaAS + 4V9ItXvE07mJX0N9UWcqgjTauJphBJP7F+6kaT4BbMbVb4g7/MNQgIMyUy0Y/gR2QnKG4gJcF6WgJLS5 + A42Wpv5yoGWzjPvwpzikJKCWoRuwjjjcFFMLDb+U2mkcEX8/mqQ4pTgm+IjhxM0apW6a08QugFMw8vHm + 0rNoelciPvb2Q6MpCXEv/GZ1PL1rg6uLnyOnNOAmWO+08koC24aJ0AOUcfBnQPCJsUEzeK3TOwbLwULJ + qoXS1TnlcUHT0ViGf4kk+QTumMWBCXX91gAAAABJRU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH/SURBVEhLzVTPK0RRGD1LS0tLS0tLS0tLS8v5D4wx5Ech - CVkgJSmSlCkJSVm+maEMCUmykB9JshCSjKTrO2++25g3b3h4C6dOvXfv/c798Z3vw7+D04Q6/QwfTjfK - kk04d+Ko0KFw4TQikumAkU0GdChciPD+8wJMugW3vI0OhwM5ffVRP4xZgzkdhuFtdCocJKOYuZvNbfCy - 6D7Tvk79HUzqdieyFLfkbXgrXfI3iFD0aiIvTvI2yUYkdElpSHClsFZZLz7vIekUoUOmYnh4WyncgNzp - xKtdk4xhxMYKG6ym9fbyZgvMxViO15Mw93M5vi4VC38mN7Zrb6fzGmrnfJ7kZ+KwD+Z91V/oJ6TL5PnW - i6zsRNG225U7lV/gd+ThjgdFXBynksWQd4tk2pGlFf1ESpGHOugVZ0kOVKo0ZFHdRjMeHuf9xbzkYSTh - Pys+WVzNxPsJeumeXByoocEgAZXMh5+glydDv9sgQjf4CXp5MyWJlTrQ0GCgbelrrxgr2GtldtgCzwcB - Az476SkBs9ft+jvBvmQbn+VGHNnALVyep5yVyEDaTwtny4mhyp2X5icHWGbDs5Wuza/WFfgOTBgD+ESb - rXhkPnSqALRzKo6Ly3GYs1HZQApVp74Gi4UWZR54Gx32BZ+F69MxvPBWOvw1tDPW6G8g8PmK2zfwAeUN - UaR56NgIAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIASURBVEhLzVTPK0RRFD5LS0tLS0tLS0tLS8v5D+aNZuRH + IQlZICUpkpQpCUlZvjGUSUKSLMRI0ixkJM1M0nW+985tZt67wxvewldfvXfvPd/9cb5z6N/BjlGHfIYP + e4gaUjG6s+PUJEPhwo5SJNNPijcZl6FwwcJn7+u8QYJyuI0MhwM+fevlGCm1S+pmihRuI1PhIGXR8vOK + u0Fhw3mmM5n6O5DUzAAVIa6J2+BWsuRvYCHrYb4sDuI2qSglZUltcHAzs13YyT4fBuEUpg3uW5T/2K7e + AMz0UUmvSXXTtI5ldmlN7e2twwSp7KzLxwVSL6suS5t+4UpiY702t1TWEDuX88Q/8xejpD53zEL1EC7j + 59vzWdm2qPdk0D2VKfAn4nBXEyzOjhNJP/jdIvy2RVjRJFKLONT5CDuLcyBStcGLOg5ilH9dM4t5icMc + D9RZfLy4FYk3CXrpnJwdKKHBwAHNyIdJ0Mvryd9tEIEbTIJePi1yYrkOJDQYYFv42iuGCvZa2emw9fYm + BFQ66S1J6nTI8XcSfUk3Ps2DOBUDt3B+nkZUIgJhPymcI7ubWpx5bn58gC00PF3p0vzaHYGfgIQhAE+U + 7qFX5EOmqgA778cpez9H6naGN+BClanvgWKBRZEH3EaGjcCzYH3aogJuJcPfQzpjm/wGAp7P376JvgCj + K1GUp6hnkgAAAABJRU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANYSURBVDhPvZRJTFNRFIbPuS8xxmFjXDmGBUaNCxNduDCa - GDUmulOjiQsTo0QFKm0BESFlkEEZRLRMpS2zglBBhjJUJsGCMohIBFlolKCAKBAXosD13MeVCDGmuPDb - vL7/nHd67z3/ufDfydLDcrOPsv9+MCZWRLHW6ljWaY9mLeLdpFEOpHrAMpnqGimXYE9JGJZ1Z+PMWA1w - 3gJ82jn7HKf3l6QXh2NpqgZ2y0/+jkXPvJ5nIJ9+BvxrHfB2E048iscXlTcwzxGH3eJd6NNtwDszkZt1 - 7IL89M9YdOzsOxty3gG82YiDVl8WTKvZkO4HK5O8lH3W07DUooP1Qm8y4keRJ/LTdeyMLDGfVC07+Tqf - tvgUeEko671zETbKEBSFYOiLDKHjNSlBmhe4FYexfpHfn4/cpGMnZGgWqwGWVsewAd4O3BGLb5I14C5D - KqWRWDzZQLEYVi8llduesKkmDt+LFdfEsgFRR4ZolRrl6OdK4EOlyI1eymEpz/EwAnMmqEFVN7BMSnMY - vZWDQw+Bf64CnuajHJMygC0UrZP1wBsTWKuU5vGrqD0aC6U0j/pb2CV28iAMM1Qh1gNW1ydg/1Qj8Exf - tKjiAtSiDuAV0VhLTTmVG8B0WQHKIRmGe1fRPNUEvCERe6H0GhZVXcdXPVk4M/1YnCcbdsSjMzsQdsl8 - FeHZHxT/Qqv9UEJbpT9oT6eu62GbiOdewRgRdybjGNjC2MhENXWcGjTTTE868L488p6fckStJrkbyC4L - C5F/R7usONKdhWN18awr2x/WiTgVvSlWSkWH1a6XRzHnlCjYA/yTnY7AH6PVSgvI0MLaND24CZ9a/MBd - jLEMgS0EC7/T8TnimVMVkjSwg6aETwl/hrM28ucKNeAiJi2s6jTjx2/UqLxAjJCyuj2P8gisy9bDVim5 - jFmLEaLzb+8jT/GBnVKexWAAJn+6TJIn8+jLRT5DF01BENZK+d9J92bePTl0T3Sp09RLTpgba5ehS2VN - Ck1Pph87T35tGyynguQaMv6g6RJskWmuY9XB5idGHBsmd4zaqVgr8IFy4DYDaxK3mExbHFZf2N5BDhkn - 09OgfCmLRIdVy84VHAdFpiwecZ8Wh2KSPYp13gvCqFQt7C0wwBIZ/g2An2e+o9ziKCLsAAAAAElFTkSu - QmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANaSURBVDhPvZRLSJRRFMfPuR+E9NhEq564KCpaBLVoEQVR + EdSuoqBFECWVOjozaqXJpDVqmvYwH+M4L5/5TFMbtUnNlNFytFEkzUVRYmZlJi16qLdzP2+SEjG26Lf5 + 5vv/z3fm3nvOPfDfydHDIkuosrskGm/VxLH2+musy5nA2sS7WaPsMQXAQhnqG5khsKMyFqu9DpwaewCc + twGfdE8/P9N7N+kVl7HKpIHt8pO/Y9WzoGd25JNPgX9pBO4x4fjDFOyuTcQCVzL2iHehT3YA73Igt+jY + Gfnpn7Hq2MnX5ch5J/DWVByyhbFoWs3q7HBYkh6k7LIdBz+rDlYJvTkNh0WciM/WsRMyxWxMWnb0RRFt + 8QnwSgPru30W1kgLyi5hTLed9Bi8IiXICgL/8lg2IOIHipCbdeyItKaxGcCv9iob5B7gD5LwZYYG1kpL + pcqIFd8eAXclsSYpqaQGwrr6ZHwjVlyXyAZFHmnRKjXKwdFa4O+qkKcFKfulPEOlEfPGqUB1V7FaSjOk + BSt7390DPloHPCtUOSRldXu2b03Am2+wdinN4lfS+wlYKqVZNN5Er9jJ3Vi0q8K1AFjWdAMHJpqBO8LQ + qopzUJO6KGk8NlBRjuWfZ7qc88o+aUNhFFomWoA33cI+uHcFy2hLz3vsODX5WD2zEVcKunMjYZuMVxE9 + +4P8T7Tat5W0VfoDTzZVXQ+bhJ9/AZOE35qGY1Aay96P11PFqUBTrfSkA+8voN4LVw6o2SSFkeycaKFO + O3702vB9jwPHGpOZNzcCVgqfkl4XK3Vn4Iha9ao45p4QCXuBf3DSEURggpppDnYtrMjSg7/oU2s4rBXX + WFpQZsDS73R8rhTmVoV0DWzxmJFPiP68zDqoPxerho+YtbDUY8Hhr1Sogkg0SlndXkCNERtz9bBRSj5j + 0aJRVP5VCfLMUNgq5WkMBmDyp8+kB7KA/nzkUzRoiqOwQcr/TnYwC+7NoznhBU5jsY86YeZa+wwNleWZ + dHsc4ew0XYKOoRpKSF3TcBOHzCGwQYb5jk0H61tScWyEuuOjk5K1Ax+sAV5uYC1iismw+WELg82d1CGf + qel7c/BTdRy6bFp2qvgwKDJk/oh5WhGD6c541nXnIsabtLCz2AALpP0bAD8BKayjjoW1yOIAAAAASUVO + RK5CYII= diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index c54a27dec..a8ea62ea5 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -87,6 +87,7 @@ private void InitComponentManual() PatchTabPage = new PatchTabPage(); ModsTabPage = new ModsTabPage(); ScreenshotsTabPage = new ScreenshotsTabPage(); + LowerSplitContainer = new DarkSplitContainerCustom(); ReadmeEncodingButton = new DarkButton(); ReadmeFullScreenButton = new DarkButton(); ReadmeZoomInButton = new DarkButton(); @@ -112,6 +113,9 @@ private void InitComponentManual() FilterIconButtonsToolStrip.SuspendLayout(); RefreshAreaToolStrip.SuspendLayout(); TopRightTabControl.SuspendLayout(); + ((ISupportInitialize)LowerSplitContainer).BeginInit(); + LowerSplitContainer.Panel1.SuspendLayout(); + LowerSplitContainer.SuspendLayout(); SuspendLayout(); // // GameTabsImageList @@ -205,17 +209,11 @@ private void InitComponentManual() // MainSplitContainer.Panel2 // MainSplitContainer.Panel2.BackColor = SystemColors.Control; - MainSplitContainer.Panel2.Controls.Add(ReadmeEncodingButton); - MainSplitContainer.Panel2.Controls.Add(ReadmeFullScreenButton); - MainSplitContainer.Panel2.Controls.Add(ReadmeZoomInButton); - MainSplitContainer.Panel2.Controls.Add(ReadmeZoomOutButton); - MainSplitContainer.Panel2.Controls.Add(ReadmeResetZoomButton); - MainSplitContainer.Panel2.Controls.Add(ChooseReadmeComboBox); - MainSplitContainer.Panel2.Controls.Add(ReadmeRichTextBox); - MainSplitContainer.Panel2.MouseLeave += ReadmeArea_MouseLeave; + MainSplitContainer.Panel2.Controls.Add(LowerSplitContainer); + MainSplitContainer.Panel2.Padding = new Padding(1, 1, 2, 2); MainSplitContainer.Panel2.Paint += ReadmeContainer_Paint; + MainSplitContainer.Panel2.MouseLeave += ReadmeArea_MouseLeave; MainSplitContainer.Panel2MinSize = 38; - MainSplitContainer.Panel2.Padding = new Padding(1, 1, 2, 2); MainSplitContainer.RefreshSiblingFirst = true; MainSplitContainer.Size = new Size(1671, 672); MainSplitContainer.SplitterDistance = 309; @@ -560,6 +558,25 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir TopRightTabControl.EnableScrollButtonsRefreshHack = true; TopRightTabControl.Size = new Size(535, 310); TopRightTabControl.TabIndex = 15; + // + // LowerSplitContainer + // + LowerSplitContainer.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + LowerSplitContainer.BackColor = SystemColors.ActiveBorder; + LowerSplitContainer.Location = new Point(1, 1); + // + // LowerSplitContainer.Panel1 + // + LowerSplitContainer.Panel1.Controls.Add(ReadmeEncodingButton); + LowerSplitContainer.Panel1.Controls.Add(ReadmeFullScreenButton); + LowerSplitContainer.Panel1.Controls.Add(ReadmeZoomInButton); + LowerSplitContainer.Panel1.Controls.Add(ReadmeZoomOutButton); + LowerSplitContainer.Panel1.Controls.Add(ReadmeResetZoomButton); + LowerSplitContainer.Panel1.Controls.Add(ChooseReadmeComboBox); + LowerSplitContainer.Panel1.Controls.Add(ReadmeRichTextBox); + LowerSplitContainer.Panel2Collapsed = true; + LowerSplitContainer.Size = new Size(1670, 356); + LowerSplitContainer.SplitterDistance = 1613; void SetReadmeButton(DarkButton button, int x, int tabIndex) { @@ -640,6 +657,9 @@ void SetReadmeButton(DarkButton button, int x, int tabIndex) RefreshAreaToolStrip.ResumeLayout(false); RefreshAreaToolStrip.PerformLayout(); TopRightTabControl.ResumeLayout(false); + LowerSplitContainer.Panel1.ResumeLayout(false); + ((ISupportInitialize)LowerSplitContainer).EndInit(); + LowerSplitContainer.ResumeLayout(false); ResumeLayout(false); } } From 0ce00db2b6326cc443080cb36251f11dd9f3074b Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 15:42:32 -0800 Subject: [PATCH 087/200] Fix BackColor of readme container --- AngelLoader/Forms/MainForm.Designer.cs | 1 + AngelLoader/Forms/MainForm.resx | 143 +++++++++++------------ AngelLoader/Forms/MainForm_InitManual.cs | 1 + 3 files changed, 73 insertions(+), 72 deletions(-) diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 78aaa6348..7ff76923c 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -987,6 +987,7 @@ private void InitializeComponent() // // LowerSplitContainer.Panel1 // + this.LowerSplitContainer.Panel1.BackColor = System.Drawing.SystemColors.Control; this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeEncodingButton); this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeFullScreenButton); this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeZoomInButton); diff --git a/AngelLoader/Forms/MainForm.resx b/AngelLoader/Forms/MainForm.resx index 47cf093b2..2042a322d 100644 --- a/AngelLoader/Forms/MainForm.resx +++ b/AngelLoader/Forms/MainForm.resx @@ -125,45 +125,45 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAK - EwAAAk1TRnQBSQFMAgEBBAEAAWABGwFgARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + EwAAAk1TRnQBSQFMAgEBBAEAAWgBGwFoARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgADBQEGA0IBdANP AZkDVQGxA1sBygNWAbUDTAGRA0YBgAMcAScoAAMNAREDSgGLA1ABmgMeASsYAAMDAQQDVQGtA1gBvQNO AZYDYAHgA1ABnzQAAwIBAwMZASIDWgHHA1IBoANBAXMDQAFvAzQBUwMpAT0DHQEpAx4BKgMPARMDBQEG DAADIwEzA2AB6AMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/Az4BahgAAwwBEAMFAQYEAAMr AUECAAGXAf8DAAH/A0ABcAwAAwMEBAEFBAADBQEGAYYBiwEAAf8ByQHNAQAB/wGQAZYBAAH/AaoBugEA Af8DWgHHAy0BRgMZASIDKAE7AzkBXgNCAXQDPwFuAzkBXgMIAQoMAAQBAw8BFAMuAUgDVgGwA0AB/QNA - Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABSgFmAX0B/gMAAf8DWgHE + Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABSwFnAX4B/gMAAf8DWgHE ASMBXgEhAfsDAAH/AgABnAH/AwAB/wMAAf8DWwHkA0EB+QMAAf8DQwF3DAADCQEMA1ABnwNdAckDPQFo A0YBgQNdAc8BAAGVAcoB/wMAAf8DXgHXA0MBdgMzAVEDVgGwA0YBfgMTARkIAAMsAUMDYQHiAv8BAAH/ - A1wB2QF1AXoBRAH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA + A1wB2QF2AXsBRQH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA ARABAAH/AwAB/wEKAQwBBwH/ASYBPQE6Af8BHwEyATAB/wEAARABAAH/AwAB/wEGASMBAAH/AQMBIgEA Af8DXgHwA0QBeQMIAQoEAANdAdEDAAH/A0sBjANdAcwDAAH/AwAB/wIAAZgB/wIAAZYB/wNAAf0DXAH4 A1EBpANRAfcDAAH/AyIBMQgAAx8BLAEAAY4BpwH/AgABmgH/AwAB/wEAAZQBvQH/AQABzgL/AQABsQHe Af8BAAGYAdIB/wEAAYUBygH/AwAB/wMrAfwBAAGnAcgB/wNZAe8DHgErDAADRgF9AbwBwQEAAf8DVQG0 - A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFVAWoBRAH+ + A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFWAWsBRQH+ ARIBSQEAAf8BDAE0AQAB/wEsAjUB/wEPARYBFwH/ARcCHwH/ARcBHQEeAf8BCgE2AQAB/wEKASQBAAH/ - AWoBfAFWAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 + AWsBfQFXAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 AwAB/wNGAYEDTgGXAwAB/wNWAbAMAANEAXsBAAGyAdgB/wEAAbcB9QH/AQAB0QH5Af8BAAGZAZ4B/wEA AbMBzwH/AQABjgGtAf8BAAGyAccB/wEAAdcC/wEAAesC/wEAAZ0BoQH/A08BmwMOARIMAANGAYABxQHJ - AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFC - AkEB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ + AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFD + AkIB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ AwAB/wEVAQABAwH/A0AB/QNWAbUDGQEjA1gBvQMAAf8DXQHUAx4BKgNZAcMDAAH/A0AB/QIAAbwB/wMA Af8DAAH/AwAB/wMoATsDNQFWAwAB/wIhASMB+wMTARoIAANQAZ0BAAGtAesB/wEAAaEBygH/AwAB/wMA Af8BAAGUAbcB/wIAAYIB/wMAAf8BAAGZAZ8B/wEAAegC/wMAAf8DTAGOAwUBBgwAA0gBhAG6Ab8BAAH/ A10B3AFsAW0BUQH3AdgB6AEAAf8BtwG6AQAB/wHcAeEBAAH/AwAB/wNZAcMBwQHGAQAB/wNdAd8DGAEh CAADOARcAdYDKwH8AwAB/wEGAQoBDAH/AaEBpwGmAf8BhAGMAY0B/wErATcBPwH/AQ4BHQEmAf8BkgGY AZkB/wFQAVYBVwH/AwAB/wMAAf8DTQH6A0sBjAMPARQDXgHtAwAB/wMrAfwDRQF8Az0BaQNNAfoBKQIy - AfsDTQH6AVIBVwGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu + AfsDTQH6AVMBWAGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu Af8DAAH/AwAB/wMAAf8BAAGMAbgB/wMAAf8BggIAAf8DAAH/AQABuAHOAf8BAAGFAcQB/wNeAd0DOgFg AxUBHAgAA0cBgwGVAZsBAAH/AwAB/wHbAesBAAH/A1UBrwMQARUCUwFSAaUBwwHKAQAB/wNcAecBqAGw - AQAB/wNiAeEDGwElCAADSQGHAVEBUAFRAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ + AQAB/wNiAeEDGwElCAADSQGHAVIBUQFSAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ AUgBVwGBAf8BNgFKAVIB/wGrArIB/wGjAagBqQH/ARwBHwEjAf8BFQEJAQ4B/wNAAf0DWwHTAyoBPwNI - AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBWQGAAU0B/gNgAegDXgHXAzsBZQNKAYoCAAGI + AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBWgGAAU4B/gNgAegDXgHXAzsBZQNKAYoCAAGI Af8CAAGfAf8DPwFsA18B2gMAAf8BAAGyAeMB/wEAAY4BqQH/AwAB/wMAAf8DAAH/AQABkQHDAf8DAAH/ AwAB/wMAAf8DAAH/AQABsAHuAf8DAAH/AwAB/wNOAZYIAANHAYMBAAGGAQAB/wHXAdwBAAH/AwAB/wNQ AZ0DGwElA1UBrAHCAc4BAAH/A1wB2QGgAaoBAAH/A1oB6QMeASoIAANGAX0DTQH6AQ8BHgEAAf8BIgEx ARMB/wE1AU4BOQH/ASgBUgFGAf8BFAEkASYB/wFQAV0BhAH/ATUBRAFIAf8BGQEwASwB/wEjAT4BOQH/ - ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1QB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 + ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1UB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 A00B+gMrAfwBIQEyASEB+wNYAb0DKQE9A14B1wIAAZIB/wMAAf8DPgFqAgABhgH/AQABqAHSAf8BAAHS Av8CAAGEAf8DAAH/AwAB/wMAAf8BAAGKAcEB/wMAAf8DAAH/AwAB/wMAAf8BAAG8AfYB/wEAAaoB3gH/ AgABmQH/A1IBqAgAA0MBdgGHAZMBAAH/AmgBQQH5Ad4B4QEAAf8DAAH/AwAB/wHOAeABAAH/Al4BXAHZ @@ -177,30 +177,30 @@ ASgBLwExAf8BAQEHAQoB/wMAAf8BFwE5AQAB/wNNAfoDPgFrA1YBtgIAAZgB/wMAAf8CAAGIAf8DXgHd AzQBVANVAa4BlwGpAd0B/wJeAV8B+wNHAYMDUgGlAwAB/wMAAf8DAAH/A00B+gMPARQEAAQBAV0CZQHs AQABoQHmAf8DAAH/AYICAAH/AwAB/wEAAYwBuAH/AwAB/wMAAf8DAAH/AgABvQH/AQABlgHAAf8DVgGy - AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABYAH+ - AdEB1wEAAf8CgAFdAf4CgAFHAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ - AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BSQFGAUcB/gNZAcMDIQEv + AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABYQH+ + AdEB1wEAAf8CgAFeAf4CgAFIAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ + AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BSgFHAUgB/gNZAcMDIQEv AzABSgMAAf8DAAH/AgABnwH/AQABgQG2Af8DAAH/A2AB8wMAAf8DXAH4A00B+gEAAYQBsgH/AwAB/wMA Af8DAAH/A1MBpgwAA0IBdQEAAeMC/wEAAZQBzAH/AwAB/wMAAf8BAAGAAbEB/wMAAf8DAAH/AgABjgH/ AQABuQH7Af8DAAH/A0wBjgMSARcEAAMlATcDAAH/AdsB3AGOAf8B+AH7AZ0B/wGlAagBAAH/Al8BMgH7 AZcBmgEAAf8DWgH1AZABkgEAAf8BpAGnAQAB/wJiAVkB7wHtAfIBjgH/AckBzQEAAf8BoAGlAQAB/wNb AdgDFAEbAxUBHANiAeEDAAH/AR8BDwEVAf8BJAEiAScB/wE/AVwBOgH/AbgBywG4Af8B2ALdAf8B3QLg - Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AV4BVAFXAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ + Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AV8BVQFYAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ AwAB/wIAAYUB/wIAAaoB/wMAAf8BAAGAAZsB/wEAAY4BuAH/AwAB/wMAAf8CAAG0Af8DTQH6AxMBGQgA AxgBIQFbAl0BygEAAeUB+gH/AQAD/wEAAcQB9wH/AgABlAH/AQABjQG6Af8CAAGXAf8CAAHCAf8BAAHR Av8BAAHKAe4B/wIAAYcB/wNbAeQDIQEvCAADAgEDA00BkwG8AcYBAAH/A1YBsANeAeIDAAH/A2UB8QMA Af8DOQFeA1IBoAL/AQAB/wMAAf8DWgG/AxYBHgQAAy0BRQNIAfYBGQEFAQoB/wEYAQ4BEwH/ARQBDAEO Af8BLgFVARoB/wFdAZwBVgH/AY0BjAGOAf8BqAGvAbAB/wFVAaMBQgH/ATABRwEUAf8DAAH/AQMCAAH/ - AVABTQFOAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA + AVEBTgFPAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA Af8CAAGkAf8CAAGGAf8DLQFFDAADIAEtAQABlQGsAf8BAAGAAZIB/wNRAaEDXQHqAQAB4gH4Af8BAAHe AfMB/wEAAcoB8wH/AQABpgHIAf8DWQG7A1kBuwEAAa8B0AH/A1cBvAMLAQ4MAAMmATkDXQHMAyUBNwNT AakDUgGgA1UBrANVAa8DQwF2A4AB/gG0AbgBAAH/AbsBxwEAAf8DZQHxAzIBTwQAA0IBdANcAcsDKwH8 AysB/AEdAUQBBgH/AS8BNwEYAf8BNwFCASIB/wEoARsBIQH/ASwBKQErAf8BNAGBARMB/wEmAUIBDgH/ - AR4BNAEDAf8BAQIAAf8BUQFHAUsB/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ + AR4BNAEDAf8BAQIAAf8BUgFIAUwB/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wIAAZEB/wJeAWEB4gMtAUUUAAMmATgDMwFRBAADDAEPA0QBewEAAewC/wEAAYIBlAH/A0oBiQME AQUDAwEEAzQBVAMNAREsAANdAdEByQHSAQAB/wNLAY8CbQFRAfcBmwGoAQAB/wM+AWoEAAMDAQQDDAEP - AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFiAVsBXQH+ - AXcBgAFTAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ + AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFjAVwBXgH+ + AXgBgAFUAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ ARUDZQHxA2AB4EAAA0QBeQNSAaUEAANGAYEDWQHBAw8BFAQAAwQBBQQABAEDOAFcA0IBdANGAX4DUwGq A1UBrQNYAboDWgHEA1EBogNUAasDQAFvAwwBDwQBBAABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEA AQEGAAEBFgAD/4EAAeABDwH8AT8BAwH/AeABAQHAAQcB5AE5AQABAwGAAQABgAEDAYABAQGAAQMBgAEA @@ -279,79 +279,78 @@ iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG4SURBVDhPYxhQEKvEFB+nxHQiVoXlQ5wKyzso/R+EY5WZ - p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD+KUmZsKbGTBBsEM - geEzW6f/P7KqB8xe318INhiqDTcAubDQVvb/y9v7MAy8uGce0OtMh2OVWdbsXdQCFgMFBVQrdgByIchA - bC4E4ZvHVvyPUWI6DzRox+GV3WAxvIbCvIzNhcj42qGl/09vmQZmv3145H+0IssnqBGoAOjltiI7OYIG - ouNXdw/8j1FmeQs1BgFgLnxzH7uX8eEvr86CvP8PahQExKkwtxDjZVz42fWd/2OVWJ5CjQN6WZm5udhe - AewFbBoI4Y/PTvyv9ND4H6fKUgM1EuhKRZY3r+7sx6qBEIYbqMzcDzUOAkBJA5REsGnChz8+O4ndQBCI - V2ZNS9HhAac9bJqxYZALqzw1QbloAtQYTAAyOEmTkyiDcXoZG0AYvBKrYSAMcyFRBsIAMAbTcbmYJBei - A2wupshAGIC4mOv/lf2L/j+8uIV0L+MCccpMccAS/3icEvO9WFWWUqjwQAAGBgD++NVEgXhbGQAAAABJ - RU5ErkJggg== + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGuSURBVDhPYxhQEKvEFB+nzHwiVoXlQ5wKyzso/R+EY5WZ + p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD4CuayqwkQUbBDME + hs9snf7/yKoeMHt9fyHYYKg23ADkwkJb2f8vb+/DMPDinnlArzMfjlVmWbN3UQtYDBQUUK3YAciFIAOx + uRCEbx5bAXLZeaBBOw6v7AaL4TUU5mVsLkTG1w4t/X96yzQw++3DI0BLWD5BjUAFQC+3FdnJETQQHb+6 + ewBk6FuoMQgAc+Gb+9i9jA9/eXUW5P1/UKMgABjoLcR4GRd+dn0nyKVPocYBvazM3FxsrwD2AjYNhPDH + Zyf+V3po/I9TZamBGgnyNsubV3f2Y9VACMMNVGbuhxoHAaCkAUoi2DThwx+fncRuIAjEK7OmpejwgNMe + Ns3YMMiFVZ6aoLQ6AWoMJgAZnKTJSZTBOL2MDSAMXonVMBCGuZAoA2EAGIPpuFxMkgvRATYXU2QgDEBc + zPX/yv5F/x9e3EK6l3GBOGWmOGDsHgcadi9WlaUUKjwQgIEBAExb1Vj6X25iAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIeSURBVEhL7VVPKENxHN9R7L1tKbmInBwcnMRFXCQpUhan - yd7bvJuULBccxHtv6xWihSkpJ3FQksPG2qbtsIODJUIu3NwceZ/X96fnaZp55eJT39p+3+/v+/fz/T3H - P6zgBGXUJSgt9NdeuPxqZ620cuORtGdeVIfp2B64gosNHily7Y2lb72x7GPdZLTAieocqX8J32yF7izf - v5a8GNnOvUGGY5mXakl7IYvfgReUg67ISZw5h7Qu7J9xfnmPTMoH2tA8s/uROaRbO03wopJBZWRWHpwB - eQC9HtrIvTLng+vpvCcQucdMyKw8gIpgCwbKnOM3zjhhqY3MLEBJJZRV6VNq3WK4gGyZc1RhMEffAzKz - QHfsFNRjyLdBdB36iz4z5xDMQee+RlYWkPOW+b1kh3pkDMjl09yk/QRODK+DIWbnYBAnynEy+QrQCc7Z - BWQHXqMVZGJAL3+ifip6aR4quF/lV++KJWQMSy/tdSCayrFLkN7lRNK4SGzg/UpPjbT66N3MPjMbbG31 - ePjBGQg3Gc6KAUHcQeWpb+08ZQ6CoKAc6Ai9dytTYDpsKgJCR26+B7JAxsjcHARMwcpbgzeFdnJ6VSG6 - XhrQDn5MvsKgzc7MbYG0Lx4m8DzQtZ8Bw8KArUxhgkqgL2VfisNEWzNjMANbngEDxkKp2+g1gqBN+Jjg - o0IW9gCLhSegcXozzwvyOB3bCzzJxZ+BP4XD8Q5UnY5o0DYeqQAAAABJRU5ErkJggg== + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VVPKARhFN+jNDO7KLmoLRcHBy7iIi6SFDks + TqtmZtlcpEQuOGjNzK4p5F/tKiku4qAkB8vGYg97cLCJkAs3N0fmN71PY7Raa8rFr17tfu997+/vfeP6 + hx28pPa6JbWa/joLt6g1lg3M3RQH9WdB1rrp2Bm4+0Le4uDMtS+WvPXFLh7Lh5YzvKxNkPqX8I8XGM7S + 7QuJs57V1BukO3b+UhLUX8jidxAkdbspsn/InENqp7aOeFHZIJP8gTZUja1/ZA5p1g/igqwmURmZ5Qcu + oHSg113R1Ctz3rl0mi4KRO4xEzLLD6Ai2IKBMuf4jTNemq4jMxtQUg5lFfrVMo8cziBb5hxVmMwx9oDM + bDAcc5K2B/k2iKFDf9Fn5hyCORjc18nKBnJeM7mZaNB2zQG5/bqHtJ/Ay+FFMMTqHAziZeWQTL4CdIJz + dgHZgddoBZmYMMof9A6vXFqHCu5zonaXLSFzWEZprx3LJyl2CdI6G0+YF4kNgqi2lA7MP3ZFL56ZDba2 + pH/mgQuEK01n2YAgnj7tqW3h+MQaBEFBOdARel80mWE6bCoCQkduvgeyQMbI3BoETMHK24NXjq6ljKpG + 6XpuQDsEUbnCoK3OrG2B1Id24nge6NrPgGFhwHamMEEl0OeyL9lhoa2VMZiBI8+ACXOhtFX0GkHQJnxM + 8FEhC2eAxcITUDESTQuS0k/HzgJPcvZn4E/hcr0DUbSOqjT7gYIAAAAASUVORK5CYII= iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGaSURBVEhL7ZQhUMQwEEUrmaNNkUgkEolEIpG4MjQ5kEgc - uKPJzVQikUgk8iQSiUQikVjy936ZEErvpq1A8GY6d/vT2SS7f5v8E5Npe5Jru8dwXPLSHajT6kVp96aM - O6Y8DvnZbAfJ0+l8F/8z4579c83lgRRXG0iYTqsjKkle1FsTM3tnOAyl7YMq7SVDITPz26ys7hn2B2XA - BgwF3+gLZewTbkapHygJShMmQqM3S/eKPlDqB6wIt4SJpNFey/TNPqUInGSNa00Kuw3H4LSUvhqNOaAS - 4V9ItXvE07mJX0N9UWcqgjTauJphBJP7F+6kaT4BbMbVb4g7/MNQgIMyUy0Y/gR2QnKG4gJcF6WgJLS5 - A42Wpv5yoGWzjPvwpzikJKCWoRuwjjjcFFMLDb+U2mkcEX8/mqQ4pTgm+IjhxM0apW6a08QugFMw8vHm - 0rNoelciPvb2Q6MpCXEv/GZ1PL1rg6uLnyOnNOAmWO+08koC24aJ0AOUcfBnQPCJsUEzeK3TOwbLwULJ - qoXS1TnlcUHT0ViGf4kk+QTumMWBCXX91gAAAABJRU5ErkJggg== + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGZSURBVEhL7ZQhUMNAEEUjGSZ3QSKRSCQSiUTiykzuChKJ + AweX60wkEolEIiuRSCQSicSyf/vDHEdpO00EgjeTafdfZu9u92+Kf3KMa04q1+wxHJaqjge2Di/WxTfr + 4zHlYahOr3eQvBxPdvHf+PgszxWXezK63EDCchyOqBTVqN0qfXhn2A/rmgdbNxcMFeMnt6YO9wzXB2XA + BgwVafS59c0TbkZpPVASlCZNhEaXdXxFHyitB6wIt6SJtNGiGXezTykDJ1nhWpujZhuOwWkpfTUac0Al + Q14oXXzEs3ATWUN9UWcqijbax5ZhBpPLC3faNEkAm3H1G+oOeRgqcJDxYcrwJ7ATkjNUF+C6KAUlZZ47 + 0Ght6i8HmjXLxw85xSElBbVM3YB1xOmmmFpo+KU0n84R+fejS4pTqmOSj5hOKtcoLaY7Te4C9bWMfL65 + 9iyb3qWoj8V+aDQlJe+FbNbm07syuLr6OXNKB26C9YVWXkpi2zQReoAy9v4MKJIYG3SDN3d6h2A2WChZ + mFoXzigPC5qOxjL8SxTFJ00CxZeT7IG4AAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIASURBVEhLzVTPK0RRFD5LS0tLS0tLS0tLS8v5D+aNZuRH - IQlZICUpkpQpCUlZvjGUSUKSLMRI0ixkJM1M0nW+985tZt67wxvewldfvXfvPd/9cb5z6N/BjlGHfIYP - e4gaUjG6s+PUJEPhwo5SJNNPijcZl6FwwcJn7+u8QYJyuI0MhwM+fevlGCm1S+pmihRuI1PhIGXR8vOK - u0Fhw3mmM5n6O5DUzAAVIa6J2+BWsuRvYCHrYb4sDuI2qSglZUltcHAzs13YyT4fBuEUpg3uW5T/2K7e - AMz0UUmvSXXTtI5ldmlN7e2twwSp7KzLxwVSL6suS5t+4UpiY702t1TWEDuX88Q/8xejpD53zEL1EC7j - 59vzWdm2qPdk0D2VKfAn4nBXEyzOjhNJP/jdIvy2RVjRJFKLONT5CDuLcyBStcGLOg5ilH9dM4t5icMc - D9RZfLy4FYk3CXrpnJwdKKHBwAHNyIdJ0Mvryd9tEIEbTIJePi1yYrkOJDQYYFv42iuGCvZa2emw9fYm - BFQ66S1J6nTI8XcSfUk3Ps2DOBUDt3B+nkZUIgJhPymcI7ubWpx5bn58gC00PF3p0vzaHYGfgIQhAE+U - 7qFX5EOmqgA778cpez9H6naGN+BClanvgWKBRZEH3EaGjcCzYH3aogJuJcPfQzpjm/wGAp7P376JvgCj - K1GUp6hnkgAAAABJRU5ErkJggg== + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH/SURBVEhLzVTPK0RRGD1LS0tLS0tLS0tLS8v5D4wx5Ech + CVkgJSmSlCkJSVm+maEMCUmykB9JshCSjKTrO2++25g3b3h4C6dOvXfv/c798Z3vw7+D04Q6/QwfTjfK + kk04d+Ko0KFw4TQikumAkU0GdChciPD+8wJMugW3vI0OhwM5ffVRP4xZgzkdhuFtdCocJKOYuZvNbfCy + 6D7Tvk79HUzqdieyFLfkbXgrXfI3iFD0aiIvTvI2yUYkdElpSHClsFZZLz7vIekUoUOmYnh4WyncgNzp + xKtdk4xhxMYKG6ym9fbyZgvMxViO15Mw93M5vi4VC38mN7Zrb6fzGmrnfJ7kZ+KwD+Z91V/oJ6TL5PnW + i6zsRNG225U7lV/gd+ThjgdFXBynksWQd4tk2pGlFf1ESpGHOugVZ0kOVKo0ZFHdRjMeHuf9xbzkYSTh + Pys+WVzNxPsJeumeXByoocEgAZXMh5+glydDv9sgQjf4CXp5MyWJlTrQ0GCgbelrrxgr2GtldtgCzwcB + Az476SkBs9ft+jvBvmQbn+VGHNnALVyep5yVyEDaTwtny4mhyp2X5icHWGbDs5Wuza/WFfgOTBgD+ESb + rXhkPnSqALRzKo6Ly3GYs1HZQApVp74Gi4UWZR54Gx32BZ+F69MxvPBWOvw1tDPW6G8g8PmK2zfwAeUN + UaR56NgIAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANaSURBVDhPvZRLSJRRFMfPuR+E9NhEq564KCpaBLVoEQVR - EdSuoqBFECWVOjozaqXJpDVqmvYwH+M4L5/5TFMbtUnNlNFytFEkzUVRYmZlJi16qLdzP2+SEjG26Lf5 - 5vv/z3fm3nvOPfDfydHDIkuosrskGm/VxLH2+musy5nA2sS7WaPsMQXAQhnqG5khsKMyFqu9DpwaewCc - twGfdE8/P9N7N+kVl7HKpIHt8pO/Y9WzoGd25JNPgX9pBO4x4fjDFOyuTcQCVzL2iHehT3YA73Igt+jY - Gfnpn7Hq2MnX5ch5J/DWVByyhbFoWs3q7HBYkh6k7LIdBz+rDlYJvTkNh0WciM/WsRMyxWxMWnb0RRFt - 8QnwSgPru30W1kgLyi5hTLed9Bi8IiXICgL/8lg2IOIHipCbdeyItKaxGcCv9iob5B7gD5LwZYYG1kpL - pcqIFd8eAXclsSYpqaQGwrr6ZHwjVlyXyAZFHmnRKjXKwdFa4O+qkKcFKfulPEOlEfPGqUB1V7FaSjOk - BSt7390DPloHPCtUOSRldXu2b03Am2+wdinN4lfS+wlYKqVZNN5Er9jJ3Vi0q8K1AFjWdAMHJpqBO8LQ - qopzUJO6KGk8NlBRjuWfZ7qc88o+aUNhFFomWoA33cI+uHcFy2hLz3vsODX5WD2zEVcKunMjYZuMVxE9 - +4P8T7Tat5W0VfoDTzZVXQ+bhJ9/AZOE35qGY1Aay96P11PFqUBTrfSkA+8voN4LVw6o2SSFkeycaKFO - O3702vB9jwPHGpOZNzcCVgqfkl4XK3Vn4Iha9ao45p4QCXuBf3DSEURggpppDnYtrMjSg7/oU2s4rBXX - WFpQZsDS73R8rhTmVoV0DWzxmJFPiP68zDqoPxerho+YtbDUY8Hhr1Sogkg0SlndXkCNERtz9bBRSj5j - 0aJRVP5VCfLMUNgq5WkMBmDyp8+kB7KA/nzkUzRoiqOwQcr/TnYwC+7NoznhBU5jsY86YeZa+wwNleWZ - dHsc4ew0XYKOoRpKSF3TcBOHzCGwQYb5jk0H61tScWyEuuOjk5K1Ax+sAV5uYC1iismw+WELg82d1CGf - qel7c/BTdRy6bFp2qvgwKDJk/oh5WhGD6c541nXnIsabtLCz2AALpP0bAD8BKayjjoW1yOIAAAAASUVO - RK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANYSURBVDhPvZRJTFNRFIbPuS8xxmFjXDmGBUaNCxNduDCa + GDUmulOjiQsTo0QFKm0BESFlkEEZRLRMpS2zglBBhjJUJsGCMohIBFlolKCAKBAXosD13MeVCDGmuPDb + vL7/nHd67z3/ufDfydLDcrOPsv9+MCZWRLHW6ljWaY9mLeLdpFEOpHrAMpnqGimXYE9JGJZ1Z+PMWA1w + 3gJ82jn7HKf3l6QXh2NpqgZ2y0/+jkXPvJ5nIJ9+BvxrHfB2E048iscXlTcwzxGH3eJd6NNtwDszkZt1 + 7IL89M9YdOzsOxty3gG82YiDVl8WTKvZkO4HK5O8lH3W07DUooP1Qm8y4keRJ/LTdeyMLDGfVC07+Tqf + tvgUeEko671zETbKEBSFYOiLDKHjNSlBmhe4FYexfpHfn4/cpGMnZGgWqwGWVsewAd4O3BGLb5I14C5D + KqWRWDzZQLEYVi8llduesKkmDt+LFdfEsgFRR4ZolRrl6OdK4EOlyI1eymEpz/EwAnMmqEFVN7BMSnMY + vZWDQw+Bf64CnuajHJMygC0UrZP1wBsTWKuU5vGrqD0aC6U0j/pb2CV28iAMM1Qh1gNW1ydg/1Qj8Exf + tKjiAtSiDuAV0VhLTTmVG8B0WQHKIRmGe1fRPNUEvCERe6H0GhZVXcdXPVk4M/1YnCcbdsSjMzsQdsl8 + FeHZHxT/Qqv9UEJbpT9oT6eu62GbiOdewRgRdybjGNjC2MhENXWcGjTTTE868L488p6fckStJrkbyC4L + C5F/R7usONKdhWN18awr2x/WiTgVvSlWSkWH1a6XRzHnlCjYA/yTnY7AH6PVSgvI0MLaND24CZ9a/MBd + jLEMgS0EC7/T8TnimVMVkjSwg6aETwl/hrM28ucKNeAiJi2s6jTjx2/UqLxAjJCyuj2P8gisy9bDVim5 + jFmLEaLzb+8jT/GBnVKexWAAJn+6TJIn8+jLRT5DF01BENZK+d9J92bePTl0T3Sp09RLTpgba5ehS2VN + Ck1Pph87T35tGyynguQaMv6g6RJskWmuY9XB5idGHBsmd4zaqVgr8IFy4DYDaxK3mExbHFZf2N5BDhkn + 09OgfCmLRIdVy84VHAdFpiwecZ8Wh2KSPYp13gvCqFQt7C0wwBIZ/g2An2e+o9ziKCLsAAAAAElFTkSu + QmCC diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index a8ea62ea5..1f5cf54de 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -567,6 +567,7 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir // // LowerSplitContainer.Panel1 // + LowerSplitContainer.Panel1.BackColor = SystemColors.Control; LowerSplitContainer.Panel1.Controls.Add(ReadmeEncodingButton); LowerSplitContainer.Panel1.Controls.Add(ReadmeFullScreenButton); LowerSplitContainer.Panel1.Controls.Add(ReadmeZoomInButton); From a055656aad6a12b1ce584674048e53ffff21152c Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 15:56:24 -0800 Subject: [PATCH 088/200] Fix readme position/size --- AngelLoader/Forms/MainForm.Designer.cs | 8 +++-- AngelLoader/Forms/MainForm.resx | 38 ++++++++++++------------ AngelLoader/Forms/MainForm_InitManual.cs | 6 ++-- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 7ff76923c..db4eff912 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -982,7 +982,7 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.LowerSplitContainer.BackColor = System.Drawing.SystemColors.ActiveBorder; - this.LowerSplitContainer.Location = new System.Drawing.Point(1, 1); + this.LowerSplitContainer.Location = new System.Drawing.Point(0, 0); this.LowerSplitContainer.Name = "LowerSplitContainer"; // // LowerSplitContainer.Panel1 @@ -996,7 +996,7 @@ private void InitializeComponent() this.LowerSplitContainer.Panel1.Controls.Add(this.ChooseReadmeComboBox); this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeRichTextBox); this.LowerSplitContainer.Panel2Collapsed = true; - this.LowerSplitContainer.Size = new System.Drawing.Size(1670, 356); + this.LowerSplitContainer.Size = new System.Drawing.Size(1671, 357); this.LowerSplitContainer.SplitterDistance = 1613; this.LowerSplitContainer.TabIndex = 0; // @@ -1099,9 +1099,11 @@ private void InitializeComponent() // // ReadmeRichTextBox // + this.ReadmeRichTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.ReadmeRichTextBox.BackColor = System.Drawing.SystemColors.Window; this.ReadmeRichTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.ReadmeRichTextBox.Dock = System.Windows.Forms.DockStyle.Fill; this.ReadmeRichTextBox.Location = new System.Drawing.Point(1, 1); this.ReadmeRichTextBox.Name = "ReadmeRichTextBox"; this.ReadmeRichTextBox.ReadOnly = true; diff --git a/AngelLoader/Forms/MainForm.resx b/AngelLoader/Forms/MainForm.resx index 2042a322d..20c7c3aab 100644 --- a/AngelLoader/Forms/MainForm.resx +++ b/AngelLoader/Forms/MainForm.resx @@ -125,45 +125,45 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAK - EwAAAk1TRnQBSQFMAgEBBAEAAWgBGwFoARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + EwAAAk1TRnQBSQFMAgEBBAEAAXABGwFwARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgADBQEGA0IBdANP AZkDVQGxA1sBygNWAbUDTAGRA0YBgAMcAScoAAMNAREDSgGLA1ABmgMeASsYAAMDAQQDVQGtA1gBvQNO AZYDYAHgA1ABnzQAAwIBAwMZASIDWgHHA1IBoANBAXMDQAFvAzQBUwMpAT0DHQEpAx4BKgMPARMDBQEG DAADIwEzA2AB6AMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/Az4BahgAAwwBEAMFAQYEAAMr AUECAAGXAf8DAAH/A0ABcAwAAwMEBAEFBAADBQEGAYYBiwEAAf8ByQHNAQAB/wGQAZYBAAH/AaoBugEA Af8DWgHHAy0BRgMZASIDKAE7AzkBXgNCAXQDPwFuAzkBXgMIAQoMAAQBAw8BFAMuAUgDVgGwA0AB/QNA - Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABSwFnAX4B/gMAAf8DWgHE + Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABTAFoAX8B/gMAAf8DWgHE ASMBXgEhAfsDAAH/AgABnAH/AwAB/wMAAf8DWwHkA0EB+QMAAf8DQwF3DAADCQEMA1ABnwNdAckDPQFo A0YBgQNdAc8BAAGVAcoB/wMAAf8DXgHXA0MBdgMzAVEDVgGwA0YBfgMTARkIAAMsAUMDYQHiAv8BAAH/ - A1wB2QF2AXsBRQH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA + A1wB2QF3AXwBRgH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA ARABAAH/AwAB/wEKAQwBBwH/ASYBPQE6Af8BHwEyATAB/wEAARABAAH/AwAB/wEGASMBAAH/AQMBIgEA Af8DXgHwA0QBeQMIAQoEAANdAdEDAAH/A0sBjANdAcwDAAH/AwAB/wIAAZgB/wIAAZYB/wNAAf0DXAH4 A1EBpANRAfcDAAH/AyIBMQgAAx8BLAEAAY4BpwH/AgABmgH/AwAB/wEAAZQBvQH/AQABzgL/AQABsQHe Af8BAAGYAdIB/wEAAYUBygH/AwAB/wMrAfwBAAGnAcgB/wNZAe8DHgErDAADRgF9AbwBwQEAAf8DVQG0 - A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFWAWsBRQH+ + A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFXAWwBRgH+ ARIBSQEAAf8BDAE0AQAB/wEsAjUB/wEPARYBFwH/ARcCHwH/ARcBHQEeAf8BCgE2AQAB/wEKASQBAAH/ - AWsBfQFXAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 + AWwBfgFYAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 AwAB/wNGAYEDTgGXAwAB/wNWAbAMAANEAXsBAAGyAdgB/wEAAbcB9QH/AQAB0QH5Af8BAAGZAZ4B/wEA AbMBzwH/AQABjgGtAf8BAAGyAccB/wEAAdcC/wEAAesC/wEAAZ0BoQH/A08BmwMOARIMAANGAYABxQHJ - AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFD - AkIB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ + AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFE + AkMB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ AwAB/wEVAQABAwH/A0AB/QNWAbUDGQEjA1gBvQMAAf8DXQHUAx4BKgNZAcMDAAH/A0AB/QIAAbwB/wMA Af8DAAH/AwAB/wMoATsDNQFWAwAB/wIhASMB+wMTARoIAANQAZ0BAAGtAesB/wEAAaEBygH/AwAB/wMA Af8BAAGUAbcB/wIAAYIB/wMAAf8BAAGZAZ8B/wEAAegC/wMAAf8DTAGOAwUBBgwAA0gBhAG6Ab8BAAH/ A10B3AFsAW0BUQH3AdgB6AEAAf8BtwG6AQAB/wHcAeEBAAH/AwAB/wNZAcMBwQHGAQAB/wNdAd8DGAEh CAADOARcAdYDKwH8AwAB/wEGAQoBDAH/AaEBpwGmAf8BhAGMAY0B/wErATcBPwH/AQ4BHQEmAf8BkgGY AZkB/wFQAVYBVwH/AwAB/wMAAf8DTQH6A0sBjAMPARQDXgHtAwAB/wMrAfwDRQF8Az0BaQNNAfoBKQIy - AfsDTQH6AVMBWAGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu + AfsDTQH6AVQBWQGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu Af8DAAH/AwAB/wMAAf8BAAGMAbgB/wMAAf8BggIAAf8DAAH/AQABuAHOAf8BAAGFAcQB/wNeAd0DOgFg AxUBHAgAA0cBgwGVAZsBAAH/AwAB/wHbAesBAAH/A1UBrwMQARUCUwFSAaUBwwHKAQAB/wNcAecBqAGw - AQAB/wNiAeEDGwElCAADSQGHAVIBUQFSAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ + AQAB/wNiAeEDGwElCAADSQGHAVMBUgFTAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ AUgBVwGBAf8BNgFKAVIB/wGrArIB/wGjAagBqQH/ARwBHwEjAf8BFQEJAQ4B/wNAAf0DWwHTAyoBPwNI - AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBWgGAAU4B/gNgAegDXgHXAzsBZQNKAYoCAAGI + AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBWwGAAU8B/gNgAegDXgHXAzsBZQNKAYoCAAGI Af8CAAGfAf8DPwFsA18B2gMAAf8BAAGyAeMB/wEAAY4BqQH/AwAB/wMAAf8DAAH/AQABkQHDAf8DAAH/ AwAB/wMAAf8DAAH/AQABsAHuAf8DAAH/AwAB/wNOAZYIAANHAYMBAAGGAQAB/wHXAdwBAAH/AwAB/wNQ AZ0DGwElA1UBrAHCAc4BAAH/A1wB2QGgAaoBAAH/A1oB6QMeASoIAANGAX0DTQH6AQ8BHgEAAf8BIgEx ARMB/wE1AU4BOQH/ASgBUgFGAf8BFAEkASYB/wFQAV0BhAH/ATUBRAFIAf8BGQEwASwB/wEjAT4BOQH/ - ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1UB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 + ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1YB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 A00B+gMrAfwBIQEyASEB+wNYAb0DKQE9A14B1wIAAZIB/wMAAf8DPgFqAgABhgH/AQABqAHSAf8BAAHS Av8CAAGEAf8DAAH/AwAB/wMAAf8BAAGKAcEB/wMAAf8DAAH/AwAB/wMAAf8BAAG8AfYB/wEAAaoB3gH/ AgABmQH/A1IBqAgAA0MBdgGHAZMBAAH/AmgBQQH5Ad4B4QEAAf8DAAH/AwAB/wHOAeABAAH/Al4BXAHZ @@ -177,30 +177,30 @@ ASgBLwExAf8BAQEHAQoB/wMAAf8BFwE5AQAB/wNNAfoDPgFrA1YBtgIAAZgB/wMAAf8CAAGIAf8DXgHd AzQBVANVAa4BlwGpAd0B/wJeAV8B+wNHAYMDUgGlAwAB/wMAAf8DAAH/A00B+gMPARQEAAQBAV0CZQHs AQABoQHmAf8DAAH/AYICAAH/AwAB/wEAAYwBuAH/AwAB/wMAAf8DAAH/AgABvQH/AQABlgHAAf8DVgGy - AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABYQH+ - AdEB1wEAAf8CgAFeAf4CgAFIAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ - AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BSgFHAUgB/gNZAcMDIQEv + AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABYgH+ + AdEB1wEAAf8CgAFfAf4CgAFJAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ + AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BSwFIAUkB/gNZAcMDIQEv AzABSgMAAf8DAAH/AgABnwH/AQABgQG2Af8DAAH/A2AB8wMAAf8DXAH4A00B+gEAAYQBsgH/AwAB/wMA Af8DAAH/A1MBpgwAA0IBdQEAAeMC/wEAAZQBzAH/AwAB/wMAAf8BAAGAAbEB/wMAAf8DAAH/AgABjgH/ AQABuQH7Af8DAAH/A0wBjgMSARcEAAMlATcDAAH/AdsB3AGOAf8B+AH7AZ0B/wGlAagBAAH/Al8BMgH7 AZcBmgEAAf8DWgH1AZABkgEAAf8BpAGnAQAB/wJiAVkB7wHtAfIBjgH/AckBzQEAAf8BoAGlAQAB/wNb AdgDFAEbAxUBHANiAeEDAAH/AR8BDwEVAf8BJAEiAScB/wE/AVwBOgH/AbgBywG4Af8B2ALdAf8B3QLg - Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AV8BVQFYAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ + Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AWABVgFZAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ AwAB/wIAAYUB/wIAAaoB/wMAAf8BAAGAAZsB/wEAAY4BuAH/AwAB/wMAAf8CAAG0Af8DTQH6AxMBGQgA AxgBIQFbAl0BygEAAeUB+gH/AQAD/wEAAcQB9wH/AgABlAH/AQABjQG6Af8CAAGXAf8CAAHCAf8BAAHR Av8BAAHKAe4B/wIAAYcB/wNbAeQDIQEvCAADAgEDA00BkwG8AcYBAAH/A1YBsANeAeIDAAH/A2UB8QMA Af8DOQFeA1IBoAL/AQAB/wMAAf8DWgG/AxYBHgQAAy0BRQNIAfYBGQEFAQoB/wEYAQ4BEwH/ARQBDAEO Af8BLgFVARoB/wFdAZwBVgH/AY0BjAGOAf8BqAGvAbAB/wFVAaMBQgH/ATABRwEUAf8DAAH/AQMCAAH/ - AVEBTgFPAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA + AVIBTwFQAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA Af8CAAGkAf8CAAGGAf8DLQFFDAADIAEtAQABlQGsAf8BAAGAAZIB/wNRAaEDXQHqAQAB4gH4Af8BAAHe AfMB/wEAAcoB8wH/AQABpgHIAf8DWQG7A1kBuwEAAa8B0AH/A1cBvAMLAQ4MAAMmATkDXQHMAyUBNwNT AakDUgGgA1UBrANVAa8DQwF2A4AB/gG0AbgBAAH/AbsBxwEAAf8DZQHxAzIBTwQAA0IBdANcAcsDKwH8 AysB/AEdAUQBBgH/AS8BNwEYAf8BNwFCASIB/wEoARsBIQH/ASwBKQErAf8BNAGBARMB/wEmAUIBDgH/ - AR4BNAEDAf8BAQIAAf8BUgFIAUwB/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ + AR4BNAEDAf8BAQIAAf8BUwFJAU0B/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wIAAZEB/wJeAWEB4gMtAUUUAAMmATgDMwFRBAADDAEPA0QBewEAAewC/wEAAYIBlAH/A0oBiQME AQUDAwEEAzQBVAMNAREsAANdAdEByQHSAQAB/wNLAY8CbQFRAfcBmwGoAQAB/wM+AWoEAAMDAQQDDAEP - AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFjAVwBXgH+ - AXgBgAFUAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ + AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFkAV0BXwH+ + AXkBgAFVAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ ARUDZQHxA2AB4EAAA0QBeQNSAaUEAANGAYEDWQHBAw8BFAQAAwQBBQQABAEDOAFcA0IBdANGAX4DUwGq A1UBrQNYAboDWgHEA1EBogNUAasDQAFvAwwBDwQBBAABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEA AQEGAAEBFgAD/4EAAeABDwH8AT8BAwH/AeABAQHAAQcB5AE5AQABAwGAAQABgAEDAYABAQGAAQMBgAEA diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index 1f5cf54de..7ed1d5ff1 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -563,7 +563,6 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir // LowerSplitContainer.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; LowerSplitContainer.BackColor = SystemColors.ActiveBorder; - LowerSplitContainer.Location = new Point(1, 1); // // LowerSplitContainer.Panel1 // @@ -576,8 +575,9 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir LowerSplitContainer.Panel1.Controls.Add(ChooseReadmeComboBox); LowerSplitContainer.Panel1.Controls.Add(ReadmeRichTextBox); LowerSplitContainer.Panel2Collapsed = true; - LowerSplitContainer.Size = new Size(1670, 356); + LowerSplitContainer.Size = new Size(1671, 357); LowerSplitContainer.SplitterDistance = 1613; + LowerSplitContainer.TabIndex = 0; void SetReadmeButton(DarkButton button, int x, int tabIndex) { @@ -615,9 +615,9 @@ void SetReadmeButton(DarkButton button, int x, int tabIndex) // // ReadmeRichTextBox // + ReadmeRichTextBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; ReadmeRichTextBox.BackColor = SystemColors.Window; ReadmeRichTextBox.BorderStyle = BorderStyle.None; - ReadmeRichTextBox.Dock = DockStyle.Fill; ReadmeRichTextBox.ReadOnly = true; ReadmeRichTextBox.TabIndex = 0; ReadmeRichTextBox.MouseLeave += ReadmeArea_MouseLeave; From c98b93cb019517c5e75acfd436d6f3f957ca1477 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 16:04:51 -0800 Subject: [PATCH 089/200] Fix readme size/position in release mode --- AngelLoader/Forms/MainForm_InitManual.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index 7ed1d5ff1..9d366a2ac 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -618,7 +618,9 @@ void SetReadmeButton(DarkButton button, int x, int tabIndex) ReadmeRichTextBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; ReadmeRichTextBox.BackColor = SystemColors.Window; ReadmeRichTextBox.BorderStyle = BorderStyle.None; + ReadmeRichTextBox.Location = new Point(1, 1); ReadmeRichTextBox.ReadOnly = true; + ReadmeRichTextBox.Size = new Size(1668, 356); ReadmeRichTextBox.TabIndex = 0; ReadmeRichTextBox.MouseLeave += ReadmeArea_MouseLeave; // From a6d2e21a178d172c58a2c809bbc1f7de5d396feb Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 16:13:42 -0800 Subject: [PATCH 090/200] Start notes on docking ui --- AngelLoader/Forms/MainForm.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index ac12ee4eb..3a2d74f30 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -1,4 +1,11 @@ -/* NOTE: MainForm notes: +/* +@DockUI general notes: + We need to handle the readme fullscreening thing. Is it safe to allow interacting with tabs while the readme is + fullscreened? Or should we hide the beside-readme area too? + +---------------------- + +NOTE: MainForm notes: @LazyLoad: Controls that can be lazy-loaded in principle: -Game buttons and game tabs (one or the other will be invisible on startup) From b81d4dd98adba81ece260907ad50ef85ff244c3c Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 16:53:41 -0800 Subject: [PATCH 091/200] Typo --- AngelLoader/Forms/MainForm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 3a2d74f30..c29db8b18 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -1,6 +1,6 @@ /* @DockUI general notes: - We need to handle the readme fullscreening thing. Is it safe to allow interacting with tabs while the readme is +-We need to handle the readme fullscreening thing. Is it safe to allow interacting with tabs while the readme is fullscreened? Or should we hide the beside-readme area too? ---------------------- From fa270fc239ebadf7788abf52e740850679f87743 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 22:33:25 -0800 Subject: [PATCH 092/200] Notes on the plan for tab moving --- AngelLoader/Forms/CustomControls/DarkTabControl.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index ee8d685f7..03aca9820 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -19,7 +19,13 @@ update the backing list ourselves. public sealed class DarkTabControl : TabControl, IDarkable { #region Private fields - + /* + @DockUI(Moving tab pages between controls) + To avoid having a duplicate set of tab pages, we should physically move the tab pages from one control to the + other. But this backing tabs list doesn't really support that. To allow it, we could make this list global + and make Visible into a three-state enum value for Visible Top, Visible Bottom, or Not Visible. That way, we + would minimize the amount of backing tab code we'd have to re-do. + */ private sealed class BackingTab { internal TabPage TabPage; From 7ffc269afd2ec1f3f962ef25ed607a764ec18129 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 28 Feb 2024 22:51:53 -0800 Subject: [PATCH 093/200] Start on experimenting with tab move implementation --- .../Forms/CustomControls/DarkTabControl.cs | 18 ++++++++++++++++-- AngelLoader/Forms/MainForm.cs | 4 ++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 03aca9820..75b34a446 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -25,8 +25,15 @@ public sealed class DarkTabControl : TabControl, IDarkable other. But this backing tabs list doesn't really support that. To allow it, we could make this list global and make Visible into a three-state enum value for Visible Top, Visible Bottom, or Not Visible. That way, we would minimize the amount of backing tab code we'd have to re-do. + -But this needs a concrete enum variable in the backing tab class that only applies to one situation, but + all other tab controls will have to carry it and ignore it... + + -Another idea is we could have the tab pages be nullable in the list? + That way we could have two lists of the same length, and swapping tabs' positions would maintain the same + positions for non-null tabs between the two lists. + But actually this would still require doing every operation on both lists at once, so never mind I guess... */ - private sealed class BackingTab + internal sealed class BackingTab { internal TabPage TabPage; internal bool Visible = true; @@ -35,7 +42,14 @@ private sealed class BackingTab private TabPage? _dragTab; - private readonly List _backingTabList = new(0); + private List _backingTabList = new(0); + + /// + /// Use this to use an external list rather than the internal one. + /// Use when you want multiple controls to use the same list. + /// + /// + internal void SetBackingList(List list) => _backingTabList = list; #endregion diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index c29db8b18..0b92c6bd1 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -195,6 +195,8 @@ private enum ZoomFMsDGVType // Cache visible state because calling Visible redoes the work even if the value is the same private bool _readmeControlsOtherThanComboBoxVisible; + private readonly List _topRightBackingTabs = new(TopRightTabCount); + #endregion #region Non-public-release methods @@ -637,6 +639,8 @@ and does NOT have its text transferred over. It ends up with blank text. InitComponentManual(); #endif + TopRightTabControl.SetBackingList(_topRightBackingTabs); + ChangeReadmeBoxFont(Config.ReadmeUseFixedWidthFont); _fmsListDefaultFontSizeInPoints = FMsDGV.DefaultCellStyle.Font.SizeInPoints; From 5cf115bbf8706ed546c5a480eb158f3985c68c3e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 15:29:28 -0800 Subject: [PATCH 094/200] Add lazy second tab control, and start testing --- .../Forms/CustomControls/DarkTabControl.cs | 5 +- .../LazyLoaded/Lazy_LowerTabControl.cs | 60 +++++++++++++++++++ AngelLoader/Forms/MainForm.cs | 14 ++++- 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 75b34a446..131c573b8 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -464,7 +464,10 @@ public void ShowTab(TabPage tabPage, bool show) [PublicAPI] public int GetTabDisplayIndex(TabPage tabPage) => FindBackingTab(tabPage).Index; - public Rectangle GetTabBarRect() => new(0, 0, Width, GetTabRect(0).Height); + public Rectangle GetTabBarRect() => + TabCount == 0 + ? Rectangle.Empty + : new Rectangle(0, 0, Width, GetTabRect(0).Height); #endregion } diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs new file mode 100644 index 000000000..cd8127a54 --- /dev/null +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -0,0 +1,60 @@ +using System.Windows.Forms; +using JetBrains.Annotations; + +namespace AngelLoader.Forms.CustomControls.LazyLoaded; + +internal sealed class Lazy_LowerTabControl : IDarkable +{ + private bool _constructed; + + private readonly MainForm _owner; + + private DarkTabControl _tabControl = null!; + public DarkTabControl TabControl + { + get + { + Construct(); + return _tabControl; + } + } + + private bool _darkModeEnabled; + [PublicAPI] + public bool DarkModeEnabled + { + set + { + if (_darkModeEnabled == value) return; + _darkModeEnabled = value; + if (!_constructed) return; + + TabControl.DarkModeEnabled = value; + } + } + + public Lazy_LowerTabControl(MainForm owner) => _owner = owner; + + private void Construct() + { + if (_constructed) return; + + var container = _owner.LowerSplitContainer.Panel2; + + _tabControl = new DarkTabControl + { + Tag = LoadType.Lazy, + + AllowReordering = true, + Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, + EnableScrollButtonsRefreshHack = true, + Size = container.Size, + }; + + // Handle hack here instead, because it needs to be for whatever finicky goddamn reason + _ = _tabControl.Handle; + _tabControl.DarkModeEnabled = _darkModeEnabled; + + _constructed = true; + } +} diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 0b92c6bd1..5de7f292c 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -189,6 +189,7 @@ private enum ZoomFMsDGVType private readonly Lazy_WebSearchButton Lazy_WebSearchButton; private readonly Lazy_TopRightBlocker Lazy_TopRightBlocker; internal readonly Lazy_UpdateNotification Lazy_UpdateNotification; + private readonly Lazy_LowerTabControl Lazy_LowerTabControl; #endregion @@ -263,6 +264,16 @@ private void Test2Button_Click(object sender, EventArgs e) private void Test3Button_Click(object sender, EventArgs e) { + /* + @DockUI: Adding a tab to a tab control appears to remove it from any other it was in. + Convenient! So we should just be able to add a way to set the backing collection with visibilities right + off the bat without also adding to the physical collection, and then we can handle both collections in + what way we need to or whatever. + */ + LowerSplitContainer.Panel2Collapsed = false; + //TopRightTabControl.ShowTab(EditFMTabPage, false); + Lazy_LowerTabControl.TabControl.SetTabsFull(new TabPage[] { EditFMTabPage }); + LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); } private void Test4Button_Click(object sender, EventArgs e) @@ -587,7 +598,8 @@ but whatever... ViewHTMLReadmeLLButton = new ViewHTMLReadmeLLButton(this), Lazy_WebSearchButton = new Lazy_WebSearchButton(this), Lazy_TopRightBlocker = new Lazy_TopRightBlocker(this), - Lazy_UpdateNotification = new Lazy_UpdateNotification(this) + Lazy_UpdateNotification = new Lazy_UpdateNotification(this), + Lazy_LowerTabControl = new Lazy_LowerTabControl(this) }; #endregion From 27ee9cbc28608c97f3a0d77b9eb476b5c1bbd288 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 16:01:39 -0800 Subject: [PATCH 095/200] More work on lower tab stuff --- AngelLoader/Forms/ControlUtils.cs | 2 +- AngelLoader/Forms/CustomControls/DarkTabControl.cs | 7 ++++++- .../LazyLoaded/Lazy_LowerTabControl.cs | 8 ++++---- AngelLoader/Forms/MainForm.cs | 12 ++++++++++-- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/AngelLoader/Forms/ControlUtils.cs b/AngelLoader/Forms/ControlUtils.cs index 19ba07697..0ace43bf3 100644 --- a/AngelLoader/Forms/ControlUtils.cs +++ b/AngelLoader/Forms/ControlUtils.cs @@ -726,7 +726,7 @@ backing lists rather than their Controls collection. */ if (control is DarkTabControl dtc) { - Control[] backingPages = dtc.BackingTabPages; + Control[] backingPages = dtc.BackingTabPagesAsControls; int count = backingPages.Length; for (int i = 0; i < count; i++) { diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 131c573b8..c4d3e216b 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; @@ -99,7 +100,7 @@ public bool DarkModeEnabled [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public Control[] BackingTabPages + public Control[] BackingTabPagesAsControls { get { @@ -112,6 +113,10 @@ public Control[] BackingTabPages } } + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + internal ReadOnlyCollection BackingTabPages => _backingTabList.AsReadOnly(); + // Double-buffering prevents flickering when mouse is moved over in dark mode public DarkTabControl() => SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index cd8127a54..43eba1bd7 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -5,7 +5,7 @@ namespace AngelLoader.Forms.CustomControls.LazyLoaded; internal sealed class Lazy_LowerTabControl : IDarkable { - private bool _constructed; + internal bool Constructed { get; private set; } private readonly MainForm _owner; @@ -27,7 +27,7 @@ public bool DarkModeEnabled { if (_darkModeEnabled == value) return; _darkModeEnabled = value; - if (!_constructed) return; + if (!Constructed) return; TabControl.DarkModeEnabled = value; } @@ -37,7 +37,7 @@ public bool DarkModeEnabled private void Construct() { - if (_constructed) return; + if (Constructed) return; var container = _owner.LowerSplitContainer.Panel2; @@ -55,6 +55,6 @@ private void Construct() _ = _tabControl.Handle; _tabControl.DarkModeEnabled = _darkModeEnabled; - _constructed = true; + Constructed = true; } } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 5de7f292c..c716b4a5a 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -271,8 +271,8 @@ private void Test3Button_Click(object sender, EventArgs e) what way we need to or whatever. */ LowerSplitContainer.Panel2Collapsed = false; - //TopRightTabControl.ShowTab(EditFMTabPage, false); - Lazy_LowerTabControl.TabControl.SetTabsFull(new TabPage[] { EditFMTabPage }); + Lazy_LowerTabControl.TabControl.SetBackingList(_topRightBackingTabs); + Lazy_LowerTabControl.TabControl.ShowTab(EditFMTabPage, true); LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); } @@ -3287,7 +3287,15 @@ internal void TopRightMenu_MenuItems_Click(object sender, EventArgs e) return; } + // @DockUI: Partially works, finish this logic - need another menu for lower one that will show/hide on its side TopRightTabControl.ShowTab(tab, s.Checked); + if (!s.Checked) + { + if (Lazy_LowerTabControl.Constructed) + { + Lazy_LowerTabControl.TabControl.ShowTab(tab, false); + } + } } private void SetTopRightBlockerVisible() From 4b89b2f527d5d6d892e301c6e22ddc470d3aeda4 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 16:07:00 -0800 Subject: [PATCH 096/200] Fix back color on lower panel2 --- AngelLoader/Forms/MainForm.Designer.cs | 4 +++ AngelLoader/Forms/MainForm.resx | 38 ++++++++++++------------ AngelLoader/Forms/MainForm_InitManual.cs | 4 +++ 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index db4eff912..239338b9a 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -995,6 +995,10 @@ private void InitializeComponent() this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeResetZoomButton); this.LowerSplitContainer.Panel1.Controls.Add(this.ChooseReadmeComboBox); this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeRichTextBox); + // + // LowerSplitContainer.Panel2 + // + this.LowerSplitContainer.Panel2.BackColor = System.Drawing.SystemColors.Control; this.LowerSplitContainer.Panel2Collapsed = true; this.LowerSplitContainer.Size = new System.Drawing.Size(1671, 357); this.LowerSplitContainer.SplitterDistance = 1613; diff --git a/AngelLoader/Forms/MainForm.resx b/AngelLoader/Forms/MainForm.resx index 20c7c3aab..86c1c6c01 100644 --- a/AngelLoader/Forms/MainForm.resx +++ b/AngelLoader/Forms/MainForm.resx @@ -125,45 +125,45 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAK - EwAAAk1TRnQBSQFMAgEBBAEAAXABGwFwARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + EwAAAk1TRnQBSQFMAgEBBAEAAXgBGwF4ARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgADBQEGA0IBdANP AZkDVQGxA1sBygNWAbUDTAGRA0YBgAMcAScoAAMNAREDSgGLA1ABmgMeASsYAAMDAQQDVQGtA1gBvQNO AZYDYAHgA1ABnzQAAwIBAwMZASIDWgHHA1IBoANBAXMDQAFvAzQBUwMpAT0DHQEpAx4BKgMPARMDBQEG DAADIwEzA2AB6AMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/Az4BahgAAwwBEAMFAQYEAAMr AUECAAGXAf8DAAH/A0ABcAwAAwMEBAEFBAADBQEGAYYBiwEAAf8ByQHNAQAB/wGQAZYBAAH/AaoBugEA Af8DWgHHAy0BRgMZASIDKAE7AzkBXgNCAXQDPwFuAzkBXgMIAQoMAAQBAw8BFAMuAUgDVgGwA0AB/QNA - Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABTAFoAX8B/gMAAf8DWgHE + Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABTQFpAYAB/gMAAf8DWgHE ASMBXgEhAfsDAAH/AgABnAH/AwAB/wMAAf8DWwHkA0EB+QMAAf8DQwF3DAADCQEMA1ABnwNdAckDPQFo A0YBgQNdAc8BAAGVAcoB/wMAAf8DXgHXA0MBdgMzAVEDVgGwA0YBfgMTARkIAAMsAUMDYQHiAv8BAAH/ - A1wB2QF3AXwBRgH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA + A1wB2QF4AX0BRwH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA ARABAAH/AwAB/wEKAQwBBwH/ASYBPQE6Af8BHwEyATAB/wEAARABAAH/AwAB/wEGASMBAAH/AQMBIgEA Af8DXgHwA0QBeQMIAQoEAANdAdEDAAH/A0sBjANdAcwDAAH/AwAB/wIAAZgB/wIAAZYB/wNAAf0DXAH4 A1EBpANRAfcDAAH/AyIBMQgAAx8BLAEAAY4BpwH/AgABmgH/AwAB/wEAAZQBvQH/AQABzgL/AQABsQHe Af8BAAGYAdIB/wEAAYUBygH/AwAB/wMrAfwBAAGnAcgB/wNZAe8DHgErDAADRgF9AbwBwQEAAf8DVQG0 - A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFXAWwBRgH+ + A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFYAW0BRwH+ ARIBSQEAAf8BDAE0AQAB/wEsAjUB/wEPARYBFwH/ARcCHwH/ARcBHQEeAf8BCgE2AQAB/wEKASQBAAH/ - AWwBfgFYAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 + AW0BfwFZAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 AwAB/wNGAYEDTgGXAwAB/wNWAbAMAANEAXsBAAGyAdgB/wEAAbcB9QH/AQAB0QH5Af8BAAGZAZ4B/wEA AbMBzwH/AQABjgGtAf8BAAGyAccB/wEAAdcC/wEAAesC/wEAAZ0BoQH/A08BmwMOARIMAANGAYABxQHJ - AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFE - AkMB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ + AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFF + AkQB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ AwAB/wEVAQABAwH/A0AB/QNWAbUDGQEjA1gBvQMAAf8DXQHUAx4BKgNZAcMDAAH/A0AB/QIAAbwB/wMA Af8DAAH/AwAB/wMoATsDNQFWAwAB/wIhASMB+wMTARoIAANQAZ0BAAGtAesB/wEAAaEBygH/AwAB/wMA Af8BAAGUAbcB/wIAAYIB/wMAAf8BAAGZAZ8B/wEAAegC/wMAAf8DTAGOAwUBBgwAA0gBhAG6Ab8BAAH/ A10B3AFsAW0BUQH3AdgB6AEAAf8BtwG6AQAB/wHcAeEBAAH/AwAB/wNZAcMBwQHGAQAB/wNdAd8DGAEh CAADOARcAdYDKwH8AwAB/wEGAQoBDAH/AaEBpwGmAf8BhAGMAY0B/wErATcBPwH/AQ4BHQEmAf8BkgGY AZkB/wFQAVYBVwH/AwAB/wMAAf8DTQH6A0sBjAMPARQDXgHtAwAB/wMrAfwDRQF8Az0BaQNNAfoBKQIy - AfsDTQH6AVQBWQGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu + AfsDTQH6AVUBWgGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu Af8DAAH/AwAB/wMAAf8BAAGMAbgB/wMAAf8BggIAAf8DAAH/AQABuAHOAf8BAAGFAcQB/wNeAd0DOgFg AxUBHAgAA0cBgwGVAZsBAAH/AwAB/wHbAesBAAH/A1UBrwMQARUCUwFSAaUBwwHKAQAB/wNcAecBqAGw - AQAB/wNiAeEDGwElCAADSQGHAVMBUgFTAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ + AQAB/wNiAeEDGwElCAADSQGHAVQBUwFUAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ AUgBVwGBAf8BNgFKAVIB/wGrArIB/wGjAagBqQH/ARwBHwEjAf8BFQEJAQ4B/wNAAf0DWwHTAyoBPwNI - AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBWwGAAU8B/gNgAegDXgHXAzsBZQNKAYoCAAGI + AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBXAGAAVAB/gNgAegDXgHXAzsBZQNKAYoCAAGI Af8CAAGfAf8DPwFsA18B2gMAAf8BAAGyAeMB/wEAAY4BqQH/AwAB/wMAAf8DAAH/AQABkQHDAf8DAAH/ AwAB/wMAAf8DAAH/AQABsAHuAf8DAAH/AwAB/wNOAZYIAANHAYMBAAGGAQAB/wHXAdwBAAH/AwAB/wNQ AZ0DGwElA1UBrAHCAc4BAAH/A1wB2QGgAaoBAAH/A1oB6QMeASoIAANGAX0DTQH6AQ8BHgEAAf8BIgEx ARMB/wE1AU4BOQH/ASgBUgFGAf8BFAEkASYB/wFQAV0BhAH/ATUBRAFIAf8BGQEwASwB/wEjAT4BOQH/ - ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1YB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 + ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1cB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 A00B+gMrAfwBIQEyASEB+wNYAb0DKQE9A14B1wIAAZIB/wMAAf8DPgFqAgABhgH/AQABqAHSAf8BAAHS Av8CAAGEAf8DAAH/AwAB/wMAAf8BAAGKAcEB/wMAAf8DAAH/AwAB/wMAAf8BAAG8AfYB/wEAAaoB3gH/ AgABmQH/A1IBqAgAA0MBdgGHAZMBAAH/AmgBQQH5Ad4B4QEAAf8DAAH/AwAB/wHOAeABAAH/Al4BXAHZ @@ -177,30 +177,30 @@ ASgBLwExAf8BAQEHAQoB/wMAAf8BFwE5AQAB/wNNAfoDPgFrA1YBtgIAAZgB/wMAAf8CAAGIAf8DXgHd AzQBVANVAa4BlwGpAd0B/wJeAV8B+wNHAYMDUgGlAwAB/wMAAf8DAAH/A00B+gMPARQEAAQBAV0CZQHs AQABoQHmAf8DAAH/AYICAAH/AwAB/wEAAYwBuAH/AwAB/wMAAf8DAAH/AgABvQH/AQABlgHAAf8DVgGy - AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABYgH+ - AdEB1wEAAf8CgAFfAf4CgAFJAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ - AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BSwFIAUkB/gNZAcMDIQEv + AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABYwH+ + AdEB1wEAAf8CgAFgAf4CgAFKAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ + AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BTAFJAUoB/gNZAcMDIQEv AzABSgMAAf8DAAH/AgABnwH/AQABgQG2Af8DAAH/A2AB8wMAAf8DXAH4A00B+gEAAYQBsgH/AwAB/wMA Af8DAAH/A1MBpgwAA0IBdQEAAeMC/wEAAZQBzAH/AwAB/wMAAf8BAAGAAbEB/wMAAf8DAAH/AgABjgH/ AQABuQH7Af8DAAH/A0wBjgMSARcEAAMlATcDAAH/AdsB3AGOAf8B+AH7AZ0B/wGlAagBAAH/Al8BMgH7 AZcBmgEAAf8DWgH1AZABkgEAAf8BpAGnAQAB/wJiAVkB7wHtAfIBjgH/AckBzQEAAf8BoAGlAQAB/wNb AdgDFAEbAxUBHANiAeEDAAH/AR8BDwEVAf8BJAEiAScB/wE/AVwBOgH/AbgBywG4Af8B2ALdAf8B3QLg - Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AWABVgFZAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ + Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AWEBVwFaAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ AwAB/wIAAYUB/wIAAaoB/wMAAf8BAAGAAZsB/wEAAY4BuAH/AwAB/wMAAf8CAAG0Af8DTQH6AxMBGQgA AxgBIQFbAl0BygEAAeUB+gH/AQAD/wEAAcQB9wH/AgABlAH/AQABjQG6Af8CAAGXAf8CAAHCAf8BAAHR Av8BAAHKAe4B/wIAAYcB/wNbAeQDIQEvCAADAgEDA00BkwG8AcYBAAH/A1YBsANeAeIDAAH/A2UB8QMA Af8DOQFeA1IBoAL/AQAB/wMAAf8DWgG/AxYBHgQAAy0BRQNIAfYBGQEFAQoB/wEYAQ4BEwH/ARQBDAEO Af8BLgFVARoB/wFdAZwBVgH/AY0BjAGOAf8BqAGvAbAB/wFVAaMBQgH/ATABRwEUAf8DAAH/AQMCAAH/ - AVIBTwFQAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA + AVMBUAFRAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA Af8CAAGkAf8CAAGGAf8DLQFFDAADIAEtAQABlQGsAf8BAAGAAZIB/wNRAaEDXQHqAQAB4gH4Af8BAAHe AfMB/wEAAcoB8wH/AQABpgHIAf8DWQG7A1kBuwEAAa8B0AH/A1cBvAMLAQ4MAAMmATkDXQHMAyUBNwNT AakDUgGgA1UBrANVAa8DQwF2A4AB/gG0AbgBAAH/AbsBxwEAAf8DZQHxAzIBTwQAA0IBdANcAcsDKwH8 AysB/AEdAUQBBgH/AS8BNwEYAf8BNwFCASIB/wEoARsBIQH/ASwBKQErAf8BNAGBARMB/wEmAUIBDgH/ - AR4BNAEDAf8BAQIAAf8BUwFJAU0B/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ + AR4BNAEDAf8BAQIAAf8BVAFKAU4B/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wIAAZEB/wJeAWEB4gMtAUUUAAMmATgDMwFRBAADDAEPA0QBewEAAewC/wEAAYIBlAH/A0oBiQME AQUDAwEEAzQBVAMNAREsAANdAdEByQHSAQAB/wNLAY8CbQFRAfcBmwGoAQAB/wM+AWoEAAMDAQQDDAEP - AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFkAV0BXwH+ - AXkBgAFVAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ + AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFlAV4BYAH+ + AXoBgAFWAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ ARUDZQHxA2AB4EAAA0QBeQNSAaUEAANGAYEDWQHBAw8BFAQAAwQBBQQABAEDOAFcA0IBdANGAX4DUwGq A1UBrQNYAboDWgHEA1EBogNUAasDQAFvAwwBDwQBBAABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEA AQEGAAEBFgAD/4EAAeABDwH8AT8BAwH/AeABAQHAAQcB5AE5AQABAwGAAQABgAEDAYABAQGAAQMBgAEA diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index 9d366a2ac..a8043983d 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -574,6 +574,10 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir LowerSplitContainer.Panel1.Controls.Add(ReadmeResetZoomButton); LowerSplitContainer.Panel1.Controls.Add(ChooseReadmeComboBox); LowerSplitContainer.Panel1.Controls.Add(ReadmeRichTextBox); + // + // LowerSplitContainer.Panel2 + // + LowerSplitContainer.Panel2.BackColor = SystemColors.Control; LowerSplitContainer.Panel2Collapsed = true; LowerSplitContainer.Size = new Size(1671, 357); LowerSplitContainer.SplitterDistance = 1613; From 783a627d5a8cf699a4d94997af11732fbb82bceb Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 16:18:26 -0800 Subject: [PATCH 097/200] Hook up lower tab area to context menu --- .../Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs | 3 +++ AngelLoader/Forms/MainForm.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 43eba1bd7..472495942 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -55,6 +55,9 @@ private void Construct() _ = _tabControl.Handle; _tabControl.DarkModeEnabled = _darkModeEnabled; + _tabControl.MouseClick += _owner.TopRightTabBar_MouseClick; + _owner.LowerSplitContainer.Panel2.MouseClick += _owner.TopRightTabBar_MouseClick; + Constructed = true; } } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index c716b4a5a..209968d07 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5348,7 +5348,7 @@ private void MainSplitContainer_FullScreenChanged(object sender, EventArgs e) } } - private void TopRightTabBar_MouseClick(object sender, MouseEventArgs e) + internal void TopRightTabBar_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { From 29332a7b83277ab949207358b27419d64ab61042 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 16:55:08 -0800 Subject: [PATCH 098/200] More work on top/bottom tab controls/menus/showing/hiding --- AngelLoader/Forms/ControlUtils.cs | 2 +- .../Forms/CustomControls/DarkContextMenu.cs | 12 +++++ .../LazyLoaded/FMsDGV_FM_LLMenu.cs | 4 +- .../LazyLoaded/Lazy_LowerTabControl.cs | 4 +- AngelLoader/Forms/FormsData.cs | 6 +++ AngelLoader/Forms/MainForm.cs | 45 ++++++++++++------- 6 files changed, 52 insertions(+), 21 deletions(-) diff --git a/AngelLoader/Forms/ControlUtils.cs b/AngelLoader/Forms/ControlUtils.cs index 0ace43bf3..8204355f2 100644 --- a/AngelLoader/Forms/ControlUtils.cs +++ b/AngelLoader/Forms/ControlUtils.cs @@ -629,7 +629,7 @@ internal static void SetAeroSnapRestoreHackValues(Form form, Point nominalWindow #region Show menu internal static void ShowMenu( - ContextMenuStrip menu, + DarkContextMenu menu, Control control, MenuPos pos, int xOffset = 0, diff --git a/AngelLoader/Forms/CustomControls/DarkContextMenu.cs b/AngelLoader/Forms/CustomControls/DarkContextMenu.cs index d568333c5..1333f6de0 100644 --- a/AngelLoader/Forms/CustomControls/DarkContextMenu.cs +++ b/AngelLoader/Forms/CustomControls/DarkContextMenu.cs @@ -10,6 +10,12 @@ public sealed class DarkContextMenu : ContextMenuStrip private bool _preventClose; private ToolStripMenuItemCustom[]? _preventCloseItems; + /// + /// Since event driven architecture is Good Architecture(tm), of course that means you can't simply just pass + /// data from a menu open call to a menu item click handler. So set this data and it will be nulled out on close. + /// + public object? Data; + private readonly IDarkContextMenuOwner _owner; private bool _darkModeEnabled; @@ -66,6 +72,12 @@ protected override void OnClosing(ToolStripDropDownClosingEventArgs e) base.OnClosing(e); } + protected override void OnClosed(ToolStripDropDownClosedEventArgs e) + { + Data = null; + base.OnClosed(e); + } + internal void RefreshDarkModeState() { void SetMenuTheme(ToolStripDropDown menu) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/FMsDGV_FM_LLMenu.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/FMsDGV_FM_LLMenu.cs index 4ca1ec362..f7773d700 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/FMsDGV_FM_LLMenu.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/FMsDGV_FM_LLMenu.cs @@ -389,13 +389,13 @@ internal void UpdateRatingList(RatingDisplayStyle style) } } - internal ContextMenuStrip GetRatingMenu() + internal DarkContextMenu GetRatingMenu() { Construct(); return RatingMenu; } - internal ContextMenuStrip GetFinishedOnMenu() + internal DarkContextMenu GetFinishedOnMenu() { Construct(); return FinishedOnMenu; diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 472495942..1e7a4af84 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -55,8 +55,8 @@ private void Construct() _ = _tabControl.Handle; _tabControl.DarkModeEnabled = _darkModeEnabled; - _tabControl.MouseClick += _owner.TopRightTabBar_MouseClick; - _owner.LowerSplitContainer.Panel2.MouseClick += _owner.TopRightTabBar_MouseClick; + _tabControl.MouseClick += _owner.LowerTabBar_MouseClick; + _owner.LowerSplitContainer.Panel2.MouseClick += _owner.LowerTabBar_MouseClick; Constructed = true; } diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index c89d89d3b..a9b4dfab3 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -21,6 +21,12 @@ public enum Direction { Left, Right, Up, Down } // IMPORTANT: Don't change the order, they're used as indices! public enum Zoom { In, Out, Reset } +public enum WhichTabControl +{ + Top, + Bottom +} + /* Images loaded from files keep the file stream alive for their entire lifetime, insanely. This means the file is "in use" and will cause delete attempts (like FM uninstallation) to fail. So we need to use this workaround diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 209968d07..65e99ad1f 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -2161,7 +2161,8 @@ public void ChangeGameOrganization(bool startup = false) private void GameFilterControlsShowHideButton_Click(object sender, EventArgs e) { - ControlUtils.ShowMenu(GameFilterControlsLLMenu.Menu, + ControlUtils.ShowMenu( + GameFilterControlsLLMenu.Menu, GameFilterControlsShowHideButtonToolStrip, MenuPos.RightDown, -GameFilterControlsShowHideButton.Width, @@ -3272,6 +3273,7 @@ private void SetTopRightCollapsedState(bool collapsed) private void TopRightMenuButton_Click(object sender, EventArgs e) { + TopRightLLMenu.Menu.Data = WhichTabControl.Top; ControlUtils.ShowMenu(TopRightLLMenu.Menu, TopRightMenuButton, MenuPos.BottomLeft); } @@ -3287,15 +3289,12 @@ internal void TopRightMenu_MenuItems_Click(object sender, EventArgs e) return; } - // @DockUI: Partially works, finish this logic - need another menu for lower one that will show/hide on its side - TopRightTabControl.ShowTab(tab, s.Checked); - if (!s.Checked) - { - if (Lazy_LowerTabControl.Constructed) - { - Lazy_LowerTabControl.TabControl.ShowTab(tab, false); - } - } + // @DockUI: We should have menu items' checked states match the tab control you clicked on + DarkTabControl tabControl = s.Owner is DarkContextMenu { Data: WhichTabControl.Bottom } + ? Lazy_LowerTabControl.TabControl + : TopRightTabControl; + + tabControl.ShowTab(tab, s.Checked); } private void SetTopRightBlockerVisible() @@ -5348,14 +5347,28 @@ private void MainSplitContainer_FullScreenChanged(object sender, EventArgs e) } } - internal void TopRightTabBar_MouseClick(object sender, MouseEventArgs e) + private void TopRightTabBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Top); + + internal void LowerTabBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Bottom); + + private void HandleTabsMenu(MouseEventArgs e, WhichTabControl which) { - if (e.Button == MouseButtons.Right) + if (e.Button != MouseButtons.Right) return; + + DarkTabControl tabControl = which == WhichTabControl.Bottom + ? Lazy_LowerTabControl.TabControl + : TopRightTabControl; + + Rectangle rect = tabControl.GetTabBarRect(); + if (rect == Rectangle.Empty) { - if (TopRightTabControl.GetTabBarRect().Contains(TopRightTabControl.ClientCursorPos())) - { - TopRightLLMenu.Menu.Show(Native.GetCursorPosition_Fast()); - } + rect = tabControl.ClientRectangle; + } + + if (rect.Contains(tabControl.ClientCursorPos())) + { + TopRightLLMenu.Menu.Data = which; + TopRightLLMenu.Menu.Show(Native.GetCursorPosition_Fast()); } } From 43479d176f0a8940e1b247cfd5c6446cf33866be Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 17:14:49 -0800 Subject: [PATCH 099/200] Make tab menu checked items match which set you clicked on --- .../LazyLoaded/TopRightLLMenu.cs | 1 + AngelLoader/Forms/MainForm.cs | 27 ++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs index c08126d6a..74d825ff6 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs @@ -46,6 +46,7 @@ internal DarkContextMenu Menu _menu.DarkModeEnabled = _darkModeEnabled; + _menu.Opening += _owner.TopRightMenu_Opening; _menu.Closed += MenuClosed; _constructed = true; diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 65e99ad1f..d71ab4387 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -3277,23 +3277,38 @@ private void TopRightMenuButton_Click(object sender, EventArgs e) ControlUtils.ShowMenu(TopRightLLMenu.Menu, TopRightMenuButton, MenuPos.BottomLeft); } + internal void TopRightMenu_Opening(object sender, CancelEventArgs e) + { + DarkTabControl tabControl = TopRightLLMenu.Menu.Data is WhichTabControl.Bottom + ? Lazy_LowerTabControl.TabControl + : TopRightTabControl; + + for (int i = 0; i < _topRightTabs.Length; i++) + { + Lazy_TabsBase item = _topRightTabs[i]; + TopRightLLMenu.SetItemChecked(i, tabControl.TabPages.Contains(item)); + } + } + internal void TopRightMenu_MenuItems_Click(object sender, EventArgs e) { var s = (ToolStripMenuItemCustom)sender; TabPage tab = GetObjectFromMenuItem(TopRightLLMenu.Menu, s, _topRightTabs, TopRightTabCount); - if (!s.Checked && TopRightTabControl.TabCount == 1) + // @DockUI: It's possible to have zero tabs in one or the other tab controls now + // This is ultimately what we want, but we need to add proper support for this scenario, because we + // currently assume it can't happen (because it couldn't before). + DarkTabControl tabControl = s.Owner is DarkContextMenu { Data: WhichTabControl.Bottom } + ? Lazy_LowerTabControl.TabControl + : TopRightTabControl; + + if (!s.Checked && tabControl.TabCount == 1) { s.Checked = true; return; } - // @DockUI: We should have menu items' checked states match the tab control you clicked on - DarkTabControl tabControl = s.Owner is DarkContextMenu { Data: WhichTabControl.Bottom } - ? Lazy_LowerTabControl.TabControl - : TopRightTabControl; - tabControl.ShowTab(tab, s.Checked); } From 0126de0e9b785b5362ec539eb2b7c908b1da3b19 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 17:19:22 -0800 Subject: [PATCH 100/200] Rename "TopRightLLMenu" to "Lazy_FMTabsMenu" Because it won't necessarily be in the top-right anymore --- .../{TopRightLLMenu.cs => Lazy_FMTabsMenu.cs} | 4 ++-- AngelLoader/Forms/MainForm.cs | 24 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) rename AngelLoader/Forms/CustomControls/LazyLoaded/{TopRightLLMenu.cs => Lazy_FMTabsMenu.cs} (97%) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs similarity index 97% rename from AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs rename to AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs index 74d825ff6..dd9e32628 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/TopRightLLMenu.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs @@ -8,7 +8,7 @@ namespace AngelLoader.Forms.CustomControls.LazyLoaded; -internal sealed class TopRightLLMenu : IDarkable +internal sealed class Lazy_FMTabsMenu : IDarkable { private bool _constructed; private readonly bool[] _checkedStates = InitializedArray(TopRightTabCount, true); @@ -104,7 +104,7 @@ public bool DarkModeEnabled } } - internal TopRightLLMenu(MainForm owner) => _owner = owner; + internal Lazy_FMTabsMenu(MainForm owner) => _owner = owner; internal void SetItemChecked(int index, bool value) { diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index d71ab4387..4e905115c 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -184,7 +184,7 @@ private enum ZoomFMsDGVType private readonly MainLLMenu MainLLMenu; private readonly PlayOriginalGameLLMenu PlayOriginalGameLLMenu; private readonly PlayOriginalT2InMultiplayerLLMenu PlayOriginalT2InMultiplayerLLMenu; - private readonly TopRightLLMenu TopRightLLMenu; + private readonly Lazy_FMTabsMenu Lazy_FMTabsMenu; private readonly ViewHTMLReadmeLLButton ViewHTMLReadmeLLButton; private readonly Lazy_WebSearchButton Lazy_WebSearchButton; private readonly Lazy_TopRightBlocker Lazy_TopRightBlocker; @@ -532,7 +532,7 @@ Native.WM_MBUTTONDOWN or FMsDGV_FM_LLMenu.Visible ? HelpSections.FMContextMenu : FMsDGV_ColumnHeaderLLMenu.Visible ? HelpSections.ColumnHeaderContextMenu : AnyControlFocusedIn(TopSplitContainer.Panel1) ? HelpSections.MissionList : - TopRightMenuButton.Focused || TopRightLLMenu.Focused || AnyControlFocusedInTabPage(StatisticsTabPage) ? HelpSections.StatsTab : + TopRightMenuButton.Focused || Lazy_FMTabsMenu.Focused || AnyControlFocusedInTabPage(StatisticsTabPage) ? HelpSections.StatsTab : AnyControlFocusedInTabPage(EditFMTabPage) ? HelpSections.EditFMTab : AnyControlFocusedInTabPage(CommentTabPage) ? HelpSections.CommentTab : // Add tag dropdown is in EverythingPanel, not tags tab page @@ -594,7 +594,7 @@ but whatever... MainLLMenu = new MainLLMenu(this), PlayOriginalGameLLMenu = new PlayOriginalGameLLMenu(this), PlayOriginalT2InMultiplayerLLMenu = new PlayOriginalT2InMultiplayerLLMenu(this), - TopRightLLMenu = new TopRightLLMenu(this), + Lazy_FMTabsMenu = new Lazy_FMTabsMenu(this), ViewHTMLReadmeLLButton = new ViewHTMLReadmeLLButton(this), Lazy_WebSearchButton = new Lazy_WebSearchButton(this), Lazy_TopRightBlocker = new Lazy_TopRightBlocker(this), @@ -921,7 +921,7 @@ and does NOT have its text transferred over. It ends up with blank text. { TopRightTabControl.ShowTab(_topRightTabs[i], false); } - TopRightLLMenu.SetItemChecked(i, visible); + Lazy_FMTabsMenu.SetItemChecked(i, visible); } // EnsureValidity() guarantees selected tab will not be invisible @@ -1846,7 +1846,7 @@ private void Localize(bool startup) if (!startup) SetFMSelectedCountMessage(FMsDGV.GetRowSelectedCount(), forceRefresh: true); - TopRightLLMenu.Localize(); + Lazy_FMTabsMenu.Localize(); StatisticsTabPage.Text = LText.StatisticsTab.TabText; EditFMTabPage.Text = LText.EditFMTab.TabText; @@ -3273,20 +3273,20 @@ private void SetTopRightCollapsedState(bool collapsed) private void TopRightMenuButton_Click(object sender, EventArgs e) { - TopRightLLMenu.Menu.Data = WhichTabControl.Top; - ControlUtils.ShowMenu(TopRightLLMenu.Menu, TopRightMenuButton, MenuPos.BottomLeft); + Lazy_FMTabsMenu.Menu.Data = WhichTabControl.Top; + ControlUtils.ShowMenu(Lazy_FMTabsMenu.Menu, TopRightMenuButton, MenuPos.BottomLeft); } internal void TopRightMenu_Opening(object sender, CancelEventArgs e) { - DarkTabControl tabControl = TopRightLLMenu.Menu.Data is WhichTabControl.Bottom + DarkTabControl tabControl = Lazy_FMTabsMenu.Menu.Data is WhichTabControl.Bottom ? Lazy_LowerTabControl.TabControl : TopRightTabControl; for (int i = 0; i < _topRightTabs.Length; i++) { Lazy_TabsBase item = _topRightTabs[i]; - TopRightLLMenu.SetItemChecked(i, tabControl.TabPages.Contains(item)); + Lazy_FMTabsMenu.SetItemChecked(i, tabControl.TabPages.Contains(item)); } } @@ -3294,7 +3294,7 @@ internal void TopRightMenu_MenuItems_Click(object sender, EventArgs e) { var s = (ToolStripMenuItemCustom)sender; - TabPage tab = GetObjectFromMenuItem(TopRightLLMenu.Menu, s, _topRightTabs, TopRightTabCount); + TabPage tab = GetObjectFromMenuItem(Lazy_FMTabsMenu.Menu, s, _topRightTabs, TopRightTabCount); // @DockUI: It's possible to have zero tabs in one or the other tab controls now // This is ultimately what we want, but we need to add proper support for this scenario, because we @@ -5382,8 +5382,8 @@ private void HandleTabsMenu(MouseEventArgs e, WhichTabControl which) if (rect.Contains(tabControl.ClientCursorPos())) { - TopRightLLMenu.Menu.Data = which; - TopRightLLMenu.Menu.Show(Native.GetCursorPosition_Fast()); + Lazy_FMTabsMenu.Menu.Data = which; + Lazy_FMTabsMenu.Menu.Show(Native.GetCursorPosition_Fast()); } } From aa97a53c5acb27530775ec7fcf93070aed7b2592 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 17:40:47 -0800 Subject: [PATCH 101/200] Rename most "top-right" stuff to something more specific --- AngelLoader/Common/DataClasses/ConfigData.cs | 2 +- .../DataClasses/ConfigDataSupporting.cs | 30 +++---- AngelLoader/Common/EnumData.Generated.cs | 2 +- AngelLoader/Core.cs | 12 +-- .../LazyLoaded/Lazy_FMTabsMenu.cs | 22 ++--- .../LazyLoaded/Lazy_LowerTabControl.cs | 4 +- .../LazyLoaded/Lazy_TopRightBlocker.cs | 4 +- AngelLoader/Forms/FormsViewEnvironment.cs | 2 +- AngelLoader/Forms/Images.cs | 4 +- AngelLoader/Forms/MainForm.Designer.cs | 2 +- AngelLoader/Forms/MainForm.cs | 90 +++++++++---------- AngelLoader/Forms/MainForm_InitManual.cs | 2 +- AngelLoader/Ini/ConfigIni.cs | 70 +++++++-------- AngelLoader/Ini/IniCommon.cs | 2 +- 14 files changed, 124 insertions(+), 124 deletions(-) diff --git a/AngelLoader/Common/DataClasses/ConfigData.cs b/AngelLoader/Common/DataClasses/ConfigData.cs index 5e3a88a53..fa5bad049 100644 --- a/AngelLoader/Common/DataClasses/ConfigData.cs +++ b/AngelLoader/Common/DataClasses/ConfigData.cs @@ -346,7 +346,7 @@ internal float FMsListFontSizeInPoints internal bool TopRightPanelCollapsed; - internal readonly TopRightTabsData TopRightTabsData = new(); + internal readonly FMTabsData FMTabsData = new(); #endregion diff --git a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs index 1570c1ac8..e3b155a35 100644 --- a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs +++ b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs @@ -97,9 +97,9 @@ public enum CheckForUpdates #region Top-right tabs -// IMPORTANT(TopRightTab enum): Do not rename members, they're used in the config file +// IMPORTANT(FM tabs enum): Do not rename members, they're used in the config file [FenGenEnumCount] -internal enum TopRightTab +internal enum FMTab { Statistics, EditFM, @@ -110,30 +110,30 @@ internal enum TopRightTab Screenshots } -internal sealed class TopRightTabData +internal sealed class FMTabData { private int _displayIndex; - internal int DisplayIndex { get => _displayIndex; set => _displayIndex = value.Clamp(0, TopRightTabCount - 1); } + internal int DisplayIndex { get => _displayIndex; set => _displayIndex = value.Clamp(0, FMTabCount - 1); } internal bool Visible = true; } -internal sealed class TopRightTabsData +internal sealed class FMTabsData { - internal readonly TopRightTabData[] Tabs = InitializedArray(TopRightTabCount); + internal readonly FMTabData[] Tabs = InitializedArray(FMTabCount); - internal TopRightTab SelectedTab = TopRightTab.Statistics; + internal FMTab SelectedTab = FMTab.Statistics; - internal TopRightTabsData() => ResetAllDisplayIndexes(); + internal FMTabsData() => ResetAllDisplayIndexes(); - internal TopRightTabData GetTab(TopRightTab tab) => Tabs[(int)tab]; + internal FMTabData GetTab(FMTab tab) => Tabs[(int)tab]; internal void EnsureValidity() { #region Fallback if multiple tabs have the same display index var displayIndexesSet = new HashSet(); - for (int i = 0; i < TopRightTabCount; i++) + for (int i = 0; i < FMTabCount; i++) { if (!displayIndexesSet.Add(Tabs[i].DisplayIndex)) { @@ -149,11 +149,11 @@ internal void EnsureValidity() // Fallback if selected tab is not marked as visible if (!GetTab(SelectedTab).Visible) { - for (int i = 0; i < TopRightTabCount; i++) + for (int i = 0; i < FMTabCount; i++) { if (Tabs[i].Visible) { - SelectedTab = (TopRightTab)i; + SelectedTab = (FMTab)i; break; } } @@ -162,18 +162,18 @@ internal void EnsureValidity() private bool NoneVisible() { - for (int i = 0; i < TopRightTabCount; i++) if (Tabs[i].Visible) return false; + for (int i = 0; i < FMTabCount; i++) if (Tabs[i].Visible) return false; return true; } private void SetAllVisible(bool visible) { - for (int i = 0; i < TopRightTabCount; i++) Tabs[i].Visible = visible; + for (int i = 0; i < FMTabCount; i++) Tabs[i].Visible = visible; } private void ResetAllDisplayIndexes() { - for (int i = 0; i < TopRightTabCount; i++) Tabs[i].DisplayIndex = i; + for (int i = 0; i < FMTabCount; i++) Tabs[i].DisplayIndex = i; } } diff --git a/AngelLoader/Common/EnumData.Generated.cs b/AngelLoader/Common/EnumData.Generated.cs index 134490fbe..f23ef0885 100644 --- a/AngelLoader/Common/EnumData.Generated.cs +++ b/AngelLoader/Common/EnumData.Generated.cs @@ -9,7 +9,7 @@ public static partial class Misc { public const int ColumnCount = 14; public const int HideableFilterControlsCount = 10; - public const int TopRightTabCount = 7; + public const int FMTabCount = 7; public const int SettingsTabCount = 5; public static readonly string[] CustomResourcesNames = { diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index bc59c2ee6..f445c6842 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2611,7 +2611,7 @@ internal static void UpdateConfig( SelectedFM selectedFM, GameTabsState gameTabsState, GameIndex gameTab, - TopRightTabsData topRightTabsData, + FMTabsData fmTabsData, bool topRightPanelCollapsed, float readmeZoomFactor) { @@ -2645,15 +2645,15 @@ internal static void UpdateConfig( #region Top-right panel - Config.TopRightTabsData.SelectedTab = topRightTabsData.SelectedTab; + Config.FMTabsData.SelectedTab = fmTabsData.SelectedTab; - for (int i = 0; i < TopRightTabCount; i++) + for (int i = 0; i < FMTabCount; i++) { - Config.TopRightTabsData.Tabs[i].DisplayIndex = topRightTabsData.Tabs[i].DisplayIndex; - Config.TopRightTabsData.Tabs[i].Visible = topRightTabsData.Tabs[i].Visible; + Config.FMTabsData.Tabs[i].DisplayIndex = fmTabsData.Tabs[i].DisplayIndex; + Config.FMTabsData.Tabs[i].Visible = fmTabsData.Tabs[i].Visible; } - Config.TopRightTabsData.EnsureValidity(); + Config.FMTabsData.EnsureValidity(); Config.TopRightPanelCollapsed = topRightPanelCollapsed; diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs index dd9e32628..8fde77799 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs @@ -11,7 +11,7 @@ namespace AngelLoader.Forms.CustomControls.LazyLoaded; internal sealed class Lazy_FMTabsMenu : IDarkable { private bool _constructed; - private readonly bool[] _checkedStates = InitializedArray(TopRightTabCount, true); + private readonly bool[] _checkedStates = InitializedArray(FMTabCount, true); private readonly MainForm _owner; @@ -26,7 +26,7 @@ internal DarkContextMenu Menu _menu = new DarkContextMenu(_owner); - var menuItems = new ToolStripItem[TopRightTabCount]; + var menuItems = new ToolStripItem[FMTabCount]; for (int i = 0; i < menuItems.Length; i++) { var item = new ToolStripMenuItemCustom @@ -34,7 +34,7 @@ internal DarkContextMenu Menu CheckOnClick = true, Checked = _checkedStates[i] }; - item.Click += _owner.TopRightMenu_MenuItems_Click; + item.Click += _owner.FMTabsMenu_MenuItems_Click; menuItems[i] = item; } @@ -46,7 +46,7 @@ internal DarkContextMenu Menu _menu.DarkModeEnabled = _darkModeEnabled; - _menu.Opening += _owner.TopRightMenu_Opening; + _menu.Opening += _owner.FMTabsMenu_Opening; _menu.Closed += MenuClosed; _constructed = true; @@ -122,13 +122,13 @@ internal void Localize() { if (!_constructed) return; - _menu.Items[(int)TopRightTab.Statistics].Text = LText.StatisticsTab.TabText; - _menu.Items[(int)TopRightTab.EditFM].Text = LText.EditFMTab.TabText; - _menu.Items[(int)TopRightTab.Comment].Text = LText.CommentTab.TabText; - _menu.Items[(int)TopRightTab.Tags].Text = LText.TagsTab.TabText; - _menu.Items[(int)TopRightTab.Patch].Text = LText.PatchTab.TabText; - _menu.Items[(int)TopRightTab.Mods].Text = LText.ModsTab.TabText; - _menu.Items[(int)TopRightTab.Screenshots].Text = LText.ScreenshotsTab.TabText; + _menu.Items[(int)FMTab.Statistics].Text = LText.StatisticsTab.TabText; + _menu.Items[(int)FMTab.EditFM].Text = LText.EditFMTab.TabText; + _menu.Items[(int)FMTab.Comment].Text = LText.CommentTab.TabText; + _menu.Items[(int)FMTab.Tags].Text = LText.TagsTab.TabText; + _menu.Items[(int)FMTab.Patch].Text = LText.PatchTab.TabText; + _menu.Items[(int)FMTab.Mods].Text = LText.ModsTab.TabText; + _menu.Items[(int)FMTab.Screenshots].Text = LText.ScreenshotsTab.TabText; } internal bool Focused => _constructed && _menu.Focused; diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 1e7a4af84..58c5c108e 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -55,8 +55,8 @@ private void Construct() _ = _tabControl.Handle; _tabControl.DarkModeEnabled = _darkModeEnabled; - _tabControl.MouseClick += _owner.LowerTabBar_MouseClick; - _owner.LowerSplitContainer.Panel2.MouseClick += _owner.LowerTabBar_MouseClick; + _tabControl.MouseClick += _owner.LowerFMTabsBar_MouseClick; + _owner.LowerSplitContainer.Panel2.MouseClick += _owner.LowerFMTabsBar_MouseClick; Constructed = true; } diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs index e41a60315..de49ca0bb 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs @@ -5,7 +5,7 @@ namespace AngelLoader.Forms.CustomControls.LazyLoaded; -internal sealed class Lazy_TopRightBlocker : IDarkable +internal sealed class Lazy_FMTabsBlocker : IDarkable { private readonly MainForm _owner; @@ -31,7 +31,7 @@ public bool DarkModeEnabled } } - internal Lazy_TopRightBlocker(MainForm owner) => _owner = owner; + internal Lazy_FMTabsBlocker(MainForm owner) => _owner = owner; internal void SetText(string text) { diff --git a/AngelLoader/Forms/FormsViewEnvironment.cs b/AngelLoader/Forms/FormsViewEnvironment.cs index 600b2ccbc..10d4139ca 100644 --- a/AngelLoader/Forms/FormsViewEnvironment.cs +++ b/AngelLoader/Forms/FormsViewEnvironment.cs @@ -49,7 +49,7 @@ public void PreloadScreenshot(ConfigData config, List fmsViewList) // If we allow moving the screenshots tab beside the readme or wherever else, we'll have to update // this code to match whatever the UI setup is. if (config.TopRightPanelCollapsed || - config.TopRightTabsData.SelectedTab != TopRightTab.Screenshots) + config.FMTabsData.SelectedTab != FMTab.Screenshots) { return; } diff --git a/AngelLoader/Forms/Images.cs b/AngelLoader/Forms/Images.cs index a6d4b7bd1..f22ac170c 100644 --- a/AngelLoader/Forms/Images.cs +++ b/AngelLoader/Forms/Images.cs @@ -348,7 +348,7 @@ private static GraphicsPath StarFullGPath #region Hamburger - private static readonly Rectangle[] _hamRects_TopRightMenu = + private static readonly Rectangle[] _hamRects_fmTabsMenu = { new Rectangle(2, 3, 14, 2), new Rectangle(2, 9, 14, 2), @@ -1784,7 +1784,7 @@ internal static void PaintXButton(Button button, PaintEventArgs e) internal static void PaintHamburgerMenuButton_TopRight(Button button, PaintEventArgs e) { - e.Graphics.FillRectangles(button.Enabled ? BlackForegroundBrush : SystemBrushes.ControlDark, _hamRects_TopRightMenu); + e.Graphics.FillRectangles(button.Enabled ? BlackForegroundBrush : SystemBrushes.ControlDark, _hamRects_fmTabsMenu); } internal static void PaintHamburgerMenuButton24(Button button, PaintEventArgs e) diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 239338b9a..0c9fafea0 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -878,7 +878,7 @@ private void InitializeComponent() this.TopRightMenuButton.Size = new System.Drawing.Size(18, 20); this.TopRightMenuButton.TabIndex = 13; this.TopRightMenuButton.PaintCustom += new System.EventHandler(this.TopRightMenuButton_Paint); - this.TopRightMenuButton.Click += new System.EventHandler(this.TopRightMenuButton_Click); + this.TopRightMenuButton.Click += new System.EventHandler(this.TopFMTabsMenuButton_Click); // // TopRightCollapseButton // diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 4e905115c..898e61383 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -118,7 +118,7 @@ need to check the accuracy of the selection itself (eg. in FMsDGV nav) so we can private readonly TabPage[] _gameTabs; private readonly ToolStripButtonCustom[] _filterByGameButtons; - private readonly Lazy_TabsBase[] _topRightTabs; + private readonly Lazy_TabsBase[] _fmTabs; private readonly Control[] _filterLabels; private readonly ToolStripItem[] _filtersToolStripSeparatedItems; @@ -187,7 +187,7 @@ private enum ZoomFMsDGVType private readonly Lazy_FMTabsMenu Lazy_FMTabsMenu; private readonly ViewHTMLReadmeLLButton ViewHTMLReadmeLLButton; private readonly Lazy_WebSearchButton Lazy_WebSearchButton; - private readonly Lazy_TopRightBlocker Lazy_TopRightBlocker; + private readonly Lazy_FMTabsBlocker Lazy_FMTabsBlocker; internal readonly Lazy_UpdateNotification Lazy_UpdateNotification; private readonly Lazy_LowerTabControl Lazy_LowerTabControl; @@ -196,7 +196,7 @@ private enum ZoomFMsDGVType // Cache visible state because calling Visible redoes the work even if the value is the same private bool _readmeControlsOtherThanComboBoxVisible; - private readonly List _topRightBackingTabs = new(TopRightTabCount); + private readonly List _backingFMTabs = new(FMTabCount); #endregion @@ -271,7 +271,7 @@ private void Test3Button_Click(object sender, EventArgs e) what way we need to or whatever. */ LowerSplitContainer.Panel2Collapsed = false; - Lazy_LowerTabControl.TabControl.SetBackingList(_topRightBackingTabs); + Lazy_LowerTabControl.TabControl.SetBackingList(_backingFMTabs); Lazy_LowerTabControl.TabControl.ShowTab(EditFMTabPage, true); LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); } @@ -597,7 +597,7 @@ but whatever... Lazy_FMTabsMenu = new Lazy_FMTabsMenu(this), ViewHTMLReadmeLLButton = new ViewHTMLReadmeLLButton(this), Lazy_WebSearchButton = new Lazy_WebSearchButton(this), - Lazy_TopRightBlocker = new Lazy_TopRightBlocker(this), + Lazy_FMTabsBlocker = new Lazy_FMTabsBlocker(this), Lazy_UpdateNotification = new Lazy_UpdateNotification(this), Lazy_LowerTabControl = new Lazy_LowerTabControl(this) }; @@ -651,7 +651,7 @@ and does NOT have its text transferred over. It ends up with blank text. InitComponentManual(); #endif - TopRightTabControl.SetBackingList(_topRightBackingTabs); + TopRightTabControl.SetBackingList(_backingFMTabs); ChangeReadmeBoxFont(Config.ReadmeUseFixedWidthFont); @@ -659,7 +659,7 @@ and does NOT have its text transferred over. It ends up with blank text. _fmsListDefaultRowHeight = FMsDGV.RowTemplate.Height; // ReSharper disable once RedundantExplicitArraySize - _topRightTabs = new Lazy_TabsBase[TopRightTabCount] + _fmTabs = new Lazy_TabsBase[FMTabCount] { StatisticsTabPage, EditFMTabPage, @@ -670,16 +670,16 @@ and does NOT have its text transferred over. It ends up with blank text. ScreenshotsTabPage }; - for (int i = 0; i < _topRightTabs.Length; i++) + for (int i = 0; i < _fmTabs.Length; i++) { - _topRightTabs[i].SetOwner(this); + _fmTabs[i].SetOwner(this); } // For right-clicking on tabs - TopRightTabControl.MouseClick += TopRightTabBar_MouseClick; + TopRightTabControl.MouseClick += TopFMTabsBar_MouseClick; // For right-clicking on blank space in tab bar - TopSplitContainer.Panel2.MouseClick += TopRightTabBar_MouseClick; + TopSplitContainer.Panel2.MouseClick += TopFMTabsBar_MouseClick; #region Construct + init non-public-release controls @@ -900,36 +900,36 @@ and does NOT have its text transferred over. It ends up with blank text. #region Top-right tabs var topRightTabsDict = new Dictionary(); - for (int i = 0; i < TopRightTabCount; i++) + for (int i = 0; i < FMTabCount; i++) { - topRightTabsDict.Add(Config.TopRightTabsData.Tabs[i].DisplayIndex, _topRightTabs[i]); + topRightTabsDict.Add(Config.FMTabsData.Tabs[i].DisplayIndex, _fmTabs[i]); } - var topRightTabs = new TabPage[TopRightTabCount]; - for (int i = 0; i < TopRightTabCount; i++) + var topRightTabs = new TabPage[FMTabCount]; + for (int i = 0; i < FMTabCount; i++) { topRightTabs[i] = topRightTabsDict[i]; } TopRightTabControl.SetTabsFull(topRightTabs); - for (int i = 0; i < TopRightTabCount; i++) + for (int i = 0; i < FMTabCount; i++) { - bool visible = Config.TopRightTabsData.Tabs[i].Visible; + bool visible = Config.FMTabsData.Tabs[i].Visible; // They're visible by default - shave off a bit of time if (!visible) { - TopRightTabControl.ShowTab(_topRightTabs[i], false); + TopRightTabControl.ShowTab(_fmTabs[i], false); } Lazy_FMTabsMenu.SetItemChecked(i, visible); } // EnsureValidity() guarantees selected tab will not be invisible - for (int i = 0; i < TopRightTabCount; i++) + for (int i = 0; i < FMTabCount; i++) { - if ((int)Config.TopRightTabsData.SelectedTab == i) + if ((int)Config.FMTabsData.SelectedTab == i) { - TopRightTabControl.SelectedTab = _topRightTabs[i]; + TopRightTabControl.SelectedTab = _fmTabs[i]; break; } } @@ -1856,9 +1856,9 @@ private void Localize(bool startup) ModsTabPage.Text = LText.ModsTab.TabText; ScreenshotsTabPage.Text = LText.ScreenshotsTab.TabText; - for (int i = 0; i < _topRightTabs.Length; i++) + for (int i = 0; i < _fmTabs.Length; i++) { - _topRightTabs[i].Localize(); + _fmTabs[i].Localize(); } #endregion @@ -1982,7 +1982,7 @@ bool CreateHandlePredicate(Control x) => (//x != TopSplitContainer && //x != TopSplitContainer.Panel2 && x != TopRightTabControl && - !_topRightTabs.Contains(x)); + !_fmTabs.Contains(x)); #endif if (startup && !darkMode) @@ -3259,7 +3259,7 @@ private void SetTopRightCollapsedState(bool collapsed) { TopRightCollapseButton.ArrowDirection = Direction.Right; - if (!Lazy_TopRightBlocker.Visible) + if (!Lazy_FMTabsBlocker.Visible) { TopRightTabControl.Enabled = true; } @@ -3271,30 +3271,30 @@ private void SetTopRightCollapsedState(bool collapsed) } } - private void TopRightMenuButton_Click(object sender, EventArgs e) + private void TopFMTabsMenuButton_Click(object sender, EventArgs e) { Lazy_FMTabsMenu.Menu.Data = WhichTabControl.Top; ControlUtils.ShowMenu(Lazy_FMTabsMenu.Menu, TopRightMenuButton, MenuPos.BottomLeft); } - internal void TopRightMenu_Opening(object sender, CancelEventArgs e) + internal void FMTabsMenu_Opening(object sender, CancelEventArgs e) { DarkTabControl tabControl = Lazy_FMTabsMenu.Menu.Data is WhichTabControl.Bottom ? Lazy_LowerTabControl.TabControl : TopRightTabControl; - for (int i = 0; i < _topRightTabs.Length; i++) + for (int i = 0; i < _fmTabs.Length; i++) { - Lazy_TabsBase item = _topRightTabs[i]; + Lazy_TabsBase item = _fmTabs[i]; Lazy_FMTabsMenu.SetItemChecked(i, tabControl.TabPages.Contains(item)); } } - internal void TopRightMenu_MenuItems_Click(object sender, EventArgs e) + internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) { var s = (ToolStripMenuItemCustom)sender; - TabPage tab = GetObjectFromMenuItem(Lazy_FMTabsMenu.Menu, s, _topRightTabs, TopRightTabCount); + TabPage tab = GetObjectFromMenuItem(Lazy_FMTabsMenu.Menu, s, _fmTabs, FMTabCount); // @DockUI: It's possible to have zero tabs in one or the other tab controls now // This is ultimately what we want, but we need to add proper support for this scenario, because we @@ -3317,13 +3317,13 @@ private void SetTopRightBlockerVisible() // Always make sure the blocker is covering up the enabled changed work, to prevent flicker of it if (FMsDGV.MultipleFMsSelected()) { - Lazy_TopRightBlocker.Visible = true; + Lazy_FMTabsBlocker.Visible = true; if (!TopSplitContainer.FullScreen) TopRightTabControl.Enabled = false; } else { if (!TopSplitContainer.FullScreen) TopRightTabControl.Enabled = true; - Lazy_TopRightBlocker.Visible = false; + Lazy_FMTabsBlocker.Visible = false; } } @@ -4617,13 +4617,13 @@ void UpdateValues(FanMission selectedFM) { SetTopRightBlockerVisible(); - Lazy_TopRightBlocker.SuspendDrawing(); + Lazy_FMTabsBlocker.SuspendDrawing(); SetFMSelectedCountMessage(selRowsCount); } finally { - Lazy_TopRightBlocker.ResumeDrawing(); + Lazy_FMTabsBlocker.ResumeDrawing(); } #endregion @@ -4679,9 +4679,9 @@ private void UpdateTopRightTabs() { using (new DisableEvents(this)) { - for (int i = 0; i < _topRightTabs.Length; i++) + for (int i = 0; i < _fmTabs.Length; i++) { - _topRightTabs[i].UpdatePage(); + _fmTabs[i].UpdatePage(); } } } @@ -5001,15 +5001,15 @@ public void UpdateConfig() SelectedFM selectedFM = FMsDGV.GetMainSelectedFMPosInfo(); - var topRightTabs = new TopRightTabsData + var topRightTabs = new FMTabsData { - SelectedTab = (TopRightTab)Array.IndexOf(_topRightTabs.Cast().ToArray(), TopRightTabControl.SelectedTab) + SelectedTab = (FMTab)Array.IndexOf(_fmTabs.Cast().ToArray(), TopRightTabControl.SelectedTab) }; - for (int i = 0; i < TopRightTabCount; i++) + for (int i = 0; i < FMTabCount; i++) { - topRightTabs.Tabs[i].DisplayIndex = TopRightTabControl.GetTabDisplayIndex(_topRightTabs[i]); - topRightTabs.Tabs[i].Visible = TopRightTabControl.Contains(_topRightTabs[i]); + topRightTabs.Tabs[i].DisplayIndex = TopRightTabControl.GetTabDisplayIndex(_fmTabs[i]); + topRightTabs.Tabs[i].Visible = TopRightTabControl.Contains(_fmTabs[i]); } #region Quick hack to prevent splitter distances from freaking out if we're closing while minimized @@ -5251,7 +5251,7 @@ private void SetFMSelectedCountMessage(int count, bool forceRefresh = false) _fmsSelectedCountText = text; - Lazy_TopRightBlocker.SetText(text); + Lazy_FMTabsBlocker.SetText(text); RefreshFMStatsLabel(); } @@ -5362,9 +5362,9 @@ private void MainSplitContainer_FullScreenChanged(object sender, EventArgs e) } } - private void TopRightTabBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Top); + private void TopFMTabsBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Top); - internal void LowerTabBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Bottom); + internal void LowerFMTabsBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Bottom); private void HandleTabsMenu(MouseEventArgs e, WhichTabControl which) { diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index a8043983d..3041dc055 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -537,7 +537,7 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir TopRightMenuButton.Location = new Point(533, 0); TopRightMenuButton.Size = new Size(18, 20); TopRightMenuButton.TabIndex = 13; - TopRightMenuButton.Click += TopRightMenuButton_Click; + TopRightMenuButton.Click += TopFMTabsMenuButton_Click; TopRightMenuButton.PaintCustom += TopRightMenuButton_Paint; // // TopRightCollapseButton diff --git a/AngelLoader/Ini/ConfigIni.cs b/AngelLoader/Ini/ConfigIni.cs index 3a4d6cdf2..8881b0c39 100644 --- a/AngelLoader/Ini/ConfigIni.cs +++ b/AngelLoader/Ini/ConfigIni.cs @@ -685,83 +685,83 @@ private static void Config_GameTab_Set(ConfigData config, string valTrimmed, str #region Top-right tabs - private static void Config_TopRightTab_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) + private static void Config_FMTab_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - FieldInfo? field = typeof(TopRightTab).GetField(valTrimmed, _bFlagsEnum); + FieldInfo? field = typeof(FMTab).GetField(valTrimmed, _bFlagsEnum); if (field != null) { - config.TopRightTabsData.SelectedTab = (TopRightTab)field.GetValue(null); + config.FMTabsData.SelectedTab = (FMTab)field.GetValue(null); } } private static void Config_StatsTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { Int_TryParseInv(valTrimmed, out int result); - config.TopRightTabsData.GetTab(TopRightTab.Statistics).DisplayIndex = result; + config.FMTabsData.GetTab(FMTab.Statistics).DisplayIndex = result; } private static void Config_StatsTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.TopRightTabsData.GetTab(TopRightTab.Statistics).Visible = valTrimmed.EqualsTrue(); + config.FMTabsData.GetTab(FMTab.Statistics).Visible = valTrimmed.EqualsTrue(); } private static void Config_EditFMTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { Int_TryParseInv(valTrimmed, out int result); - config.TopRightTabsData.GetTab(TopRightTab.EditFM).DisplayIndex = result; + config.FMTabsData.GetTab(FMTab.EditFM).DisplayIndex = result; } private static void Config_EditFMTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.TopRightTabsData.GetTab(TopRightTab.EditFM).Visible = valTrimmed.EqualsTrue(); + config.FMTabsData.GetTab(FMTab.EditFM).Visible = valTrimmed.EqualsTrue(); } private static void Config_CommentTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { Int_TryParseInv(valTrimmed, out int result); - config.TopRightTabsData.GetTab(TopRightTab.Comment).DisplayIndex = result; + config.FMTabsData.GetTab(FMTab.Comment).DisplayIndex = result; } private static void Config_CommentTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.TopRightTabsData.GetTab(TopRightTab.Comment).Visible = valTrimmed.EqualsTrue(); + config.FMTabsData.GetTab(FMTab.Comment).Visible = valTrimmed.EqualsTrue(); } private static void Config_TagsTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { Int_TryParseInv(valTrimmed, out int result); - config.TopRightTabsData.GetTab(TopRightTab.Tags).DisplayIndex = result; + config.FMTabsData.GetTab(FMTab.Tags).DisplayIndex = result; } private static void Config_TagsTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.TopRightTabsData.GetTab(TopRightTab.Tags).Visible = valTrimmed.EqualsTrue(); + config.FMTabsData.GetTab(FMTab.Tags).Visible = valTrimmed.EqualsTrue(); } private static void Config_PatchTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { Int_TryParseInv(valTrimmed, out int result); - config.TopRightTabsData.GetTab(TopRightTab.Patch).DisplayIndex = result; + config.FMTabsData.GetTab(FMTab.Patch).DisplayIndex = result; } private static void Config_PatchTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.TopRightTabsData.GetTab(TopRightTab.Patch).Visible = valTrimmed.EqualsTrue(); + config.FMTabsData.GetTab(FMTab.Patch).Visible = valTrimmed.EqualsTrue(); } private static void Config_ModsTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { Int_TryParseInv(valTrimmed, out int result); - config.TopRightTabsData.GetTab(TopRightTab.Mods).DisplayIndex = result; + config.FMTabsData.GetTab(FMTab.Mods).DisplayIndex = result; } private static void Config_ModsTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.TopRightTabsData.GetTab(TopRightTab.Mods).Visible = valTrimmed.EqualsTrue(); + config.FMTabsData.GetTab(FMTab.Mods).Visible = valTrimmed.EqualsTrue(); } private static void Config_ScreenshotsTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { Int_TryParseInv(valTrimmed, out int result); - config.TopRightTabsData.GetTab(TopRightTab.Screenshots).DisplayIndex = result; + config.FMTabsData.GetTab(FMTab.Screenshots).DisplayIndex = result; } private static void Config_ScreenshotsTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.TopRightTabsData.GetTab(TopRightTab.Screenshots).Visible = valTrimmed.EqualsTrue(); + config.FMTabsData.GetTab(FMTab.Screenshots).Visible = valTrimmed.EqualsTrue(); } #endregion @@ -977,7 +977,7 @@ private static unsafe Dictionary #region Top-right tabs - { "TopRightTab", new Config_DelegatePointerWrapper(&Config_TopRightTab_Set) }, + { "TopRightTab", new Config_DelegatePointerWrapper(&Config_FMTab_Set) }, { "StatsTabPosition", new Config_DelegatePointerWrapper(&Config_StatsTabPosition_Set) }, { "StatsTabVisible", new Config_DelegatePointerWrapper(&Config_StatsTabVisible_Set) }, @@ -1378,23 +1378,23 @@ private static void WriteConfigIniInternal(ConfigData config, string fileName) sw.Append("TopRightPanelCollapsed").Append('=').Append(config.TopRightPanelCollapsed).AppendLine(); sw.Append("GameTab").Append('=').Append(config.GameTab).AppendLine(); - sw.Append("TopRightTab").Append('=').Append(config.TopRightTabsData.SelectedTab).AppendLine(); - - sw.Append("StatsTabPosition").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Statistics).DisplayIndex).AppendLine(); - sw.Append("EditFMTabPosition").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.EditFM).DisplayIndex).AppendLine(); - sw.Append("CommentTabPosition").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Comment).DisplayIndex).AppendLine(); - sw.Append("TagsTabPosition").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Tags).DisplayIndex).AppendLine(); - sw.Append("PatchTabPosition").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Patch).DisplayIndex).AppendLine(); - sw.Append("ModsTabPosition").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Mods).DisplayIndex).AppendLine(); - sw.Append("ScreenshotsTabPosition").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Screenshots).DisplayIndex).AppendLine(); - - sw.Append("StatsTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Statistics).Visible).AppendLine(); - sw.Append("EditFMTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.EditFM).Visible).AppendLine(); - sw.Append("CommentTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Comment).Visible).AppendLine(); - sw.Append("TagsTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Tags).Visible).AppendLine(); - sw.Append("PatchTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Patch).Visible).AppendLine(); - sw.Append("ModsTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Mods).Visible).AppendLine(); - sw.Append("ScreenshotsTabVisible").Append('=').Append(config.TopRightTabsData.GetTab(TopRightTab.Screenshots).Visible).AppendLine(); + sw.Append("TopRightTab").Append('=').Append(config.FMTabsData.SelectedTab).AppendLine(); + + sw.Append("StatsTabPosition").Append('=').Append(config.FMTabsData.GetTab(FMTab.Statistics).DisplayIndex).AppendLine(); + sw.Append("EditFMTabPosition").Append('=').Append(config.FMTabsData.GetTab(FMTab.EditFM).DisplayIndex).AppendLine(); + sw.Append("CommentTabPosition").Append('=').Append(config.FMTabsData.GetTab(FMTab.Comment).DisplayIndex).AppendLine(); + sw.Append("TagsTabPosition").Append('=').Append(config.FMTabsData.GetTab(FMTab.Tags).DisplayIndex).AppendLine(); + sw.Append("PatchTabPosition").Append('=').Append(config.FMTabsData.GetTab(FMTab.Patch).DisplayIndex).AppendLine(); + sw.Append("ModsTabPosition").Append('=').Append(config.FMTabsData.GetTab(FMTab.Mods).DisplayIndex).AppendLine(); + sw.Append("ScreenshotsTabPosition").Append('=').Append(config.FMTabsData.GetTab(FMTab.Screenshots).DisplayIndex).AppendLine(); + + sw.Append("StatsTabVisible").Append('=').Append(config.FMTabsData.GetTab(FMTab.Statistics).Visible).AppendLine(); + sw.Append("EditFMTabVisible").Append('=').Append(config.FMTabsData.GetTab(FMTab.EditFM).Visible).AppendLine(); + sw.Append("CommentTabVisible").Append('=').Append(config.FMTabsData.GetTab(FMTab.Comment).Visible).AppendLine(); + sw.Append("TagsTabVisible").Append('=').Append(config.FMTabsData.GetTab(FMTab.Tags).Visible).AppendLine(); + sw.Append("PatchTabVisible").Append('=').Append(config.FMTabsData.GetTab(FMTab.Patch).Visible).AppendLine(); + sw.Append("ModsTabVisible").Append('=').Append(config.FMTabsData.GetTab(FMTab.Mods).Visible).AppendLine(); + sw.Append("ScreenshotsTabVisible").Append('=').Append(config.FMTabsData.GetTab(FMTab.Screenshots).Visible).AppendLine(); sw.Append("ReadmeZoomFactor").Append('=').AppendLine(config.ReadmeZoomFactor.ToString(NumberFormatInfo.InvariantInfo)); sw.Append("ReadmeUseFixedWidthFont").Append('=').Append(config.ReadmeUseFixedWidthFont).AppendLine(); diff --git a/AngelLoader/Ini/IniCommon.cs b/AngelLoader/Ini/IniCommon.cs index f6c2eb532..d010ba9dd 100644 --- a/AngelLoader/Ini/IniCommon.cs +++ b/AngelLoader/Ini/IniCommon.cs @@ -802,7 +802,7 @@ internal static void FinalizeConfig(ConfigData config) #endregion - config.TopRightTabsData.EnsureValidity(); + config.FMTabsData.EnsureValidity(); // TODO: Make it insert new columns at their default index (currently their position is semi-undefined) // Because they end up being subject to that weird-ass behavior of DisplayIndex setting where one From 71673590abccb0bc1fd2cdbcc3a75ba0f5b2ae9e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 18:05:40 -0800 Subject: [PATCH 102/200] Rename even more things from "top-right" --- .../LazyLoaded/Lazy_FMTabsMenu.cs | 2 +- .../LazyLoaded/Lazy_TopRightBlocker.cs | 2 +- AngelLoader/Forms/Images.cs | 2 +- AngelLoader/Forms/MainForm.Designer.cs | 98 ++++++------ AngelLoader/Forms/MainForm.cs | 74 ++++----- AngelLoader/Forms/MainForm.resx | 143 +++++++++--------- AngelLoader/Forms/MainForm_InitManual.cs | 64 ++++---- 7 files changed, 193 insertions(+), 192 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs index 8fde77799..6148e334b 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs @@ -86,7 +86,7 @@ I guess the framework doesn't let facts get in its way. */ if (Config.DarkMode) { - _owner.TopRightTabControl.Invalidate(_owner.TopRightTabControl.GetTabBarRect()); + _owner.TopFMTabControl.Invalidate(_owner.TopFMTabControl.GetTabBarRect()); } } diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs index de49ca0bb..0e7c7a5b1 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs @@ -56,7 +56,7 @@ private void Construct() Location = Point.Empty, Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom, Size = new Size( - container.Width - _owner.TopRightCollapseButton.Width, + container.Width - _owner.TopFMTabsCollapseButton.Width, container.Height), DarkModeDrawnBackColor = DarkColors.Fen_ControlBackground, diff --git a/AngelLoader/Forms/Images.cs b/AngelLoader/Forms/Images.cs index f22ac170c..acaa31bca 100644 --- a/AngelLoader/Forms/Images.cs +++ b/AngelLoader/Forms/Images.cs @@ -1782,7 +1782,7 @@ internal static void PaintXButton(Button button, PaintEventArgs e) e.Graphics.FillPath(button.Enabled ? BlackForegroundBrush : SystemBrushes.ControlDark, XGPath); } - internal static void PaintHamburgerMenuButton_TopRight(Button button, PaintEventArgs e) + internal static void PaintHamburgerMenuButton_FMTabs(Button button, PaintEventArgs e) { e.Graphics.FillRectangles(button.Enabled ? BlackForegroundBrush : SystemBrushes.ControlDark, _hamRects_fmTabsMenu); } diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 0c9fafea0..401b5855e 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -100,9 +100,9 @@ private void InitializeComponent() this.ClearFiltersButton = new AngelLoader.Forms.CustomControls.ToolStripButtonCustom(); this.ResetLayoutButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.GamesTabControl = new AngelLoader.Forms.CustomControls.DarkTabControl(); - this.TopRightMenuButton = new AngelLoader.Forms.CustomControls.DarkButton(); - this.TopRightCollapseButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); - this.TopRightTabControl = new AngelLoader.Forms.CustomControls.DarkTabControl(); + this.TopFMTabsMenuButton = new AngelLoader.Forms.CustomControls.DarkButton(); + this.TopFMTabsCollapseButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); + this.TopFMTabControl = new AngelLoader.Forms.CustomControls.DarkTabControl(); this.StatisticsTabPage = new AngelLoader.Forms.CustomControls.StatsTabPage(); this.EditFMTabPage = new AngelLoader.Forms.CustomControls.EditFMTabPage(); this.CommentTabPage = new AngelLoader.Forms.CustomControls.CommentTabPage(); @@ -135,7 +135,7 @@ private void InitializeComponent() this.GameFilterControlsShowHideButtonToolStrip.SuspendLayout(); this.FilterIconButtonsToolStrip.SuspendLayout(); this.RefreshAreaToolStrip.SuspendLayout(); - this.TopRightTabControl.SuspendLayout(); + this.TopFMTabControl.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.LowerSplitContainer)).BeginInit(); this.LowerSplitContainer.Panel1.SuspendLayout(); this.LowerSplitContainer.SuspendLayout(); @@ -294,9 +294,9 @@ private void InitializeComponent() // TopSplitContainer.Panel2 // this.TopSplitContainer.Panel2.BackColor = System.Drawing.SystemColors.Control; - this.TopSplitContainer.Panel2.Controls.Add(this.TopRightMenuButton); - this.TopSplitContainer.Panel2.Controls.Add(this.TopRightCollapseButton); - this.TopSplitContainer.Panel2.Controls.Add(this.TopRightTabControl); + this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabsMenuButton); + this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabsCollapseButton); + this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabControl); this.TopSplitContainer.Size = new System.Drawing.Size(1671, 309); this.TopSplitContainer.SplitterDistance = 1116; this.TopSplitContainer.TabIndex = 0; @@ -868,50 +868,50 @@ private void InitializeComponent() this.GamesTabControl.Size = new System.Drawing.Size(1075, 24); this.GamesTabControl.TabIndex = 1; // - // TopRightMenuButton + // TopFMTabsMenuButton // - this.TopRightMenuButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.TopRightMenuButton.FlatAppearance.BorderSize = 0; - this.TopRightMenuButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.TopRightMenuButton.Location = new System.Drawing.Point(533, 0); - this.TopRightMenuButton.Name = "TopRightMenuButton"; - this.TopRightMenuButton.Size = new System.Drawing.Size(18, 20); - this.TopRightMenuButton.TabIndex = 13; - this.TopRightMenuButton.PaintCustom += new System.EventHandler(this.TopRightMenuButton_Paint); - this.TopRightMenuButton.Click += new System.EventHandler(this.TopFMTabsMenuButton_Click); + this.TopFMTabsMenuButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.TopFMTabsMenuButton.FlatAppearance.BorderSize = 0; + this.TopFMTabsMenuButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.TopFMTabsMenuButton.Location = new System.Drawing.Point(533, 0); + this.TopFMTabsMenuButton.Name = "TopFMTabsMenuButton"; + this.TopFMTabsMenuButton.Size = new System.Drawing.Size(18, 20); + this.TopFMTabsMenuButton.TabIndex = 13; + this.TopFMTabsMenuButton.PaintCustom += new System.EventHandler(this.FMTabsMenuButton_Paint); + this.TopFMTabsMenuButton.Click += new System.EventHandler(this.TopFMTabsMenuButton_Click); // - // TopRightCollapseButton + // TopFMTabsCollapseButton // - this.TopRightCollapseButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.TopFMTabsCollapseButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Right))); - this.TopRightCollapseButton.ArrowDirection = AngelLoader.Forms.Direction.Right; - this.TopRightCollapseButton.FlatAppearance.BorderSize = 0; - this.TopRightCollapseButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.TopRightCollapseButton.Location = new System.Drawing.Point(533, 20); - this.TopRightCollapseButton.Name = "TopRightCollapseButton"; - this.TopRightCollapseButton.Size = new System.Drawing.Size(18, 289); - this.TopRightCollapseButton.TabIndex = 14; - this.TopRightCollapseButton.Click += new System.EventHandler(this.TopRightCollapseButton_Click); - // - // TopRightTabControl - // - this.TopRightTabControl.AllowReordering = true; - this.TopRightTabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.TopFMTabsCollapseButton.ArrowDirection = AngelLoader.Forms.Direction.Right; + this.TopFMTabsCollapseButton.FlatAppearance.BorderSize = 0; + this.TopFMTabsCollapseButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.TopFMTabsCollapseButton.Location = new System.Drawing.Point(533, 20); + this.TopFMTabsCollapseButton.Name = "TopFMTabsCollapseButton"; + this.TopFMTabsCollapseButton.Size = new System.Drawing.Size(18, 289); + this.TopFMTabsCollapseButton.TabIndex = 14; + this.TopFMTabsCollapseButton.Click += new System.EventHandler(this.TopFMTabsCollapseButton_Click); + // + // TopFMTabControl + // + this.TopFMTabControl.AllowReordering = true; + this.TopFMTabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.TopRightTabControl.Controls.Add(this.StatisticsTabPage); - this.TopRightTabControl.Controls.Add(this.EditFMTabPage); - this.TopRightTabControl.Controls.Add(this.CommentTabPage); - this.TopRightTabControl.Controls.Add(this.TagsTabPage); - this.TopRightTabControl.Controls.Add(this.PatchTabPage); - this.TopRightTabControl.Controls.Add(this.ModsTabPage); - this.TopRightTabControl.Controls.Add(this.ScreenshotsTabPage); - this.TopRightTabControl.EnableScrollButtonsRefreshHack = true; - this.TopRightTabControl.Location = new System.Drawing.Point(0, 0); - this.TopRightTabControl.Name = "TopRightTabControl"; - this.TopRightTabControl.SelectedIndex = 0; - this.TopRightTabControl.Size = new System.Drawing.Size(535, 310); - this.TopRightTabControl.TabIndex = 15; + this.TopFMTabControl.Controls.Add(this.StatisticsTabPage); + this.TopFMTabControl.Controls.Add(this.EditFMTabPage); + this.TopFMTabControl.Controls.Add(this.CommentTabPage); + this.TopFMTabControl.Controls.Add(this.TagsTabPage); + this.TopFMTabControl.Controls.Add(this.PatchTabPage); + this.TopFMTabControl.Controls.Add(this.ModsTabPage); + this.TopFMTabControl.Controls.Add(this.ScreenshotsTabPage); + this.TopFMTabControl.EnableScrollButtonsRefreshHack = true; + this.TopFMTabControl.Location = new System.Drawing.Point(0, 0); + this.TopFMTabControl.Name = "TopFMTabControl"; + this.TopFMTabControl.SelectedIndex = 0; + this.TopFMTabControl.Size = new System.Drawing.Size(535, 310); + this.TopFMTabControl.TabIndex = 15; // // StatisticsTabPage // @@ -1154,7 +1154,7 @@ private void InitializeComponent() this.FilterIconButtonsToolStrip.PerformLayout(); this.RefreshAreaToolStrip.ResumeLayout(false); this.RefreshAreaToolStrip.PerformLayout(); - this.TopRightTabControl.ResumeLayout(false); + this.TopFMTabControl.ResumeLayout(false); this.LowerSplitContainer.Panel1.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.LowerSplitContainer)).EndInit(); this.LowerSplitContainer.ResumeLayout(false); @@ -1262,7 +1262,7 @@ private void InitializeComponent() #region Top-right - internal CustomControls.DarkTabControl TopRightTabControl; + internal CustomControls.DarkTabControl TopFMTabControl; internal CustomControls.StatsTabPage StatisticsTabPage; internal CustomControls.EditFMTabPage EditFMTabPage; internal CustomControls.CommentTabPage CommentTabPage; @@ -1271,8 +1271,8 @@ private void InitializeComponent() internal CustomControls.ModsTabPage ModsTabPage; internal CustomControls.ScreenshotsTabPage ScreenshotsTabPage; - internal CustomControls.DarkButton TopRightMenuButton; - internal CustomControls.DarkArrowButton TopRightCollapseButton; + internal CustomControls.DarkButton TopFMTabsMenuButton; + internal CustomControls.DarkArrowButton TopFMTabsCollapseButton; #endregion diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 898e61383..78813fb57 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -532,7 +532,7 @@ Native.WM_MBUTTONDOWN or FMsDGV_FM_LLMenu.Visible ? HelpSections.FMContextMenu : FMsDGV_ColumnHeaderLLMenu.Visible ? HelpSections.ColumnHeaderContextMenu : AnyControlFocusedIn(TopSplitContainer.Panel1) ? HelpSections.MissionList : - TopRightMenuButton.Focused || Lazy_FMTabsMenu.Focused || AnyControlFocusedInTabPage(StatisticsTabPage) ? HelpSections.StatsTab : + TopFMTabsMenuButton.Focused || Lazy_FMTabsMenu.Focused || AnyControlFocusedInTabPage(StatisticsTabPage) ? HelpSections.StatsTab : AnyControlFocusedInTabPage(EditFMTabPage) ? HelpSections.EditFMTab : AnyControlFocusedInTabPage(CommentTabPage) ? HelpSections.CommentTab : // Add tag dropdown is in EverythingPanel, not tags tab page @@ -651,7 +651,7 @@ and does NOT have its text transferred over. It ends up with blank text. InitComponentManual(); #endif - TopRightTabControl.SetBackingList(_backingFMTabs); + TopFMTabControl.SetBackingList(_backingFMTabs); ChangeReadmeBoxFont(Config.ReadmeUseFixedWidthFont); @@ -676,7 +676,7 @@ and does NOT have its text transferred over. It ends up with blank text. } // For right-clicking on tabs - TopRightTabControl.MouseClick += TopFMTabsBar_MouseClick; + TopFMTabControl.MouseClick += TopFMTabsBar_MouseClick; // For right-clicking on blank space in tab bar TopSplitContainer.Panel2.MouseClick += TopFMTabsBar_MouseClick; @@ -899,19 +899,19 @@ and does NOT have its text transferred over. It ends up with blank text. #region Top-right tabs - var topRightTabsDict = new Dictionary(); + var fmTabsDict = new Dictionary(); for (int i = 0; i < FMTabCount; i++) { - topRightTabsDict.Add(Config.FMTabsData.Tabs[i].DisplayIndex, _fmTabs[i]); + fmTabsDict.Add(Config.FMTabsData.Tabs[i].DisplayIndex, _fmTabs[i]); } - var topRightTabs = new TabPage[FMTabCount]; + var fmTabs = new TabPage[FMTabCount]; for (int i = 0; i < FMTabCount; i++) { - topRightTabs[i] = topRightTabsDict[i]; + fmTabs[i] = fmTabsDict[i]; } - TopRightTabControl.SetTabsFull(topRightTabs); + TopFMTabControl.SetTabsFull(fmTabs); for (int i = 0; i < FMTabCount; i++) { @@ -919,7 +919,7 @@ and does NOT have its text transferred over. It ends up with blank text. // They're visible by default - shave off a bit of time if (!visible) { - TopRightTabControl.ShowTab(_fmTabs[i], false); + TopFMTabControl.ShowTab(_fmTabs[i], false); } Lazy_FMTabsMenu.SetItemChecked(i, visible); } @@ -929,7 +929,7 @@ and does NOT have its text transferred over. It ends up with blank text. { if ((int)Config.FMTabsData.SelectedTab == i) { - TopRightTabControl.SelectedTab = _fmTabs[i]; + TopFMTabControl.SelectedTab = _fmTabs[i]; break; } } @@ -1033,7 +1033,7 @@ and does NOT have its text transferred over. It ends up with blank text. if (!Config.HideExitButton) ShowExitButton(true); if (!Config.HideWebSearchButton) ShowWebSearchButton(true); - TopSplitContainer.CollapsedSize = TopRightCollapseButton.Width; + TopSplitContainer.CollapsedSize = TopFMTabsCollapseButton.Width; if (Config.TopRightPanelCollapsed) { TopSplitContainer.SetFullScreen(true, suspendResume: false); @@ -1194,11 +1194,11 @@ private void SetWindowStateAndSize() { if (!_firstShowDone) { - if (TopRightTabControl.SelectedTab is Lazy_TabsBase lazyTab && !Config.TopRightPanelCollapsed) + if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab && !Config.TopRightPanelCollapsed) { lazyTab.Construct(); } - TopRightTabControl.Selected += TopRightTabControl_Selected; + TopFMTabControl.Selected += TopRightTabControl_Selected; _firstShowDone = true; } @@ -1981,7 +1981,7 @@ bool CreateHandlePredicate(Control x) => !TopSplitContainer.FullScreen || (//x != TopSplitContainer && //x != TopSplitContainer.Panel2 && - x != TopRightTabControl && + x != TopFMTabControl && !_fmTabs.Contains(x)); #endif @@ -3242,7 +3242,7 @@ private static void TopRightTabControl_Selected(object sender, TabControlEventAr } } - private void TopRightCollapseButton_Click(object sender, EventArgs e) + private void TopFMTabsCollapseButton_Click(object sender, EventArgs e) { TopSplitContainer.ToggleFullScreen(); SetTopRightCollapsedState(TopSplitContainer.FullScreen); @@ -3252,19 +3252,19 @@ private void SetTopRightCollapsedState(bool collapsed) { if (collapsed) { - TopRightCollapseButton.ArrowDirection = Direction.Left; - TopRightTabControl.Enabled = false; + TopFMTabsCollapseButton.ArrowDirection = Direction.Left; + TopFMTabControl.Enabled = false; } else { - TopRightCollapseButton.ArrowDirection = Direction.Right; + TopFMTabsCollapseButton.ArrowDirection = Direction.Right; if (!Lazy_FMTabsBlocker.Visible) { - TopRightTabControl.Enabled = true; + TopFMTabControl.Enabled = true; } - if (TopRightTabControl.SelectedTab is Lazy_TabsBase lazyTab) + if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab) { lazyTab.ConstructWithSuspendResume(); } @@ -3274,14 +3274,14 @@ private void SetTopRightCollapsedState(bool collapsed) private void TopFMTabsMenuButton_Click(object sender, EventArgs e) { Lazy_FMTabsMenu.Menu.Data = WhichTabControl.Top; - ControlUtils.ShowMenu(Lazy_FMTabsMenu.Menu, TopRightMenuButton, MenuPos.BottomLeft); + ControlUtils.ShowMenu(Lazy_FMTabsMenu.Menu, TopFMTabsMenuButton, MenuPos.BottomLeft); } internal void FMTabsMenu_Opening(object sender, CancelEventArgs e) { DarkTabControl tabControl = Lazy_FMTabsMenu.Menu.Data is WhichTabControl.Bottom ? Lazy_LowerTabControl.TabControl - : TopRightTabControl; + : TopFMTabControl; for (int i = 0; i < _fmTabs.Length; i++) { @@ -3301,7 +3301,7 @@ internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) // currently assume it can't happen (because it couldn't before). DarkTabControl tabControl = s.Owner is DarkContextMenu { Data: WhichTabControl.Bottom } ? Lazy_LowerTabControl.TabControl - : TopRightTabControl; + : TopFMTabControl; if (!s.Checked && tabControl.TabCount == 1) { @@ -3318,11 +3318,11 @@ private void SetTopRightBlockerVisible() if (FMsDGV.MultipleFMsSelected()) { Lazy_FMTabsBlocker.Visible = true; - if (!TopSplitContainer.FullScreen) TopRightTabControl.Enabled = false; + if (!TopSplitContainer.FullScreen) TopFMTabControl.Enabled = false; } else { - if (!TopSplitContainer.FullScreen) TopRightTabControl.Enabled = true; + if (!TopSplitContainer.FullScreen) TopFMTabControl.Enabled = true; Lazy_FMTabsBlocker.Visible = false; } } @@ -4477,7 +4477,7 @@ private void ClearShownData() #endregion - UpdateTopRightTabs(); + UpdateFMTabs(); _displayedFM = null; @@ -4675,7 +4675,7 @@ void UpdateValues(FanMission selectedFM) Lazy_WebSearchButton.SetEnabled(webSearchShouldBeEnabled); } - private void UpdateTopRightTabs() + private void UpdateFMTabs() { using (new DisableEvents(this)) { @@ -4701,7 +4701,7 @@ public void UpdateAllFMUIDataExceptReadme(FanMission fm) FMsDGV_FM_LLMenu.SetFinishedOnMenuItemsChecked((Difficulty)fm.FinishedOn, fm.FinishedOnUnknown); - UpdateTopRightTabs(); + UpdateFMTabs(); } #region Readme @@ -4888,7 +4888,7 @@ private void SettingsButton_Paint(object sender, PaintEventArgs e) => Images.Pai SettingsButton.Enabled ? Images.Settings : Images.GetDisabledImage(Images.Settings), x: 10); - private void TopRightMenuButton_Paint(object sender, PaintEventArgs e) => Images.PaintHamburgerMenuButton_TopRight(TopRightMenuButton, e); + private void FMTabsMenuButton_Paint(object sender, PaintEventArgs e) => Images.PaintHamburgerMenuButton_FMTabs(TopFMTabsMenuButton, e); private void MainMenuButton_Paint(object sender, PaintEventArgs e) => Images.PaintHamburgerMenuButton24(MainMenuButton, e); @@ -4934,7 +4934,7 @@ private static bool AnyControlFocusedIn(Control control, int stackCounter = 0) } private bool AnyControlFocusedInTabPage(TabPage tabPage) => - (TopRightTabControl.Focused && TopRightTabControl.SelectedTab == tabPage) || + (TopFMTabControl.Focused && TopFMTabControl.SelectedTab == tabPage) || AnyControlFocusedIn(tabPage); private Zoom GetReadmeZoomButton(DarkButton button) => (Zoom)(Array.IndexOf(_readmeControlButtons, button) - 1); @@ -5001,15 +5001,15 @@ public void UpdateConfig() SelectedFM selectedFM = FMsDGV.GetMainSelectedFMPosInfo(); - var topRightTabs = new FMTabsData + var fmTabs = new FMTabsData { - SelectedTab = (FMTab)Array.IndexOf(_fmTabs.Cast().ToArray(), TopRightTabControl.SelectedTab) + SelectedTab = (FMTab)Array.IndexOf(_fmTabs.Cast().ToArray(), TopFMTabControl.SelectedTab) }; for (int i = 0; i < FMTabCount; i++) { - topRightTabs.Tabs[i].DisplayIndex = TopRightTabControl.GetTabDisplayIndex(_fmTabs[i]); - topRightTabs.Tabs[i].Visible = TopRightTabControl.Contains(_fmTabs[i]); + fmTabs.Tabs[i].DisplayIndex = TopFMTabControl.GetTabDisplayIndex(_fmTabs[i]); + fmTabs.Tabs[i].Visible = TopFMTabControl.Contains(_fmTabs[i]); } #region Quick hack to prevent splitter distances from freaking out if we're closing while minimized @@ -5046,7 +5046,7 @@ public void UpdateConfig() selectedFM, FMsDGV.GameTabsState, gameTab, - topRightTabs, + fmTabs, TopSplitContainer.FullScreen, ReadmeRichTextBox.ZoomFactor); } @@ -5329,7 +5329,7 @@ public bool UIEnabled private void TopSplitContainer_FullScreenChanged(object sender, EventArgs e) { - TopRightTabControl.Visible = !TopSplitContainer.FullScreen; + TopFMTabControl.Visible = !TopSplitContainer.FullScreen; } internal int _storedFMsDGVFirstDisplayedScrollingRowIndex; @@ -5372,7 +5372,7 @@ private void HandleTabsMenu(MouseEventArgs e, WhichTabControl which) DarkTabControl tabControl = which == WhichTabControl.Bottom ? Lazy_LowerTabControl.TabControl - : TopRightTabControl; + : TopFMTabControl; Rectangle rect = tabControl.GetTabBarRect(); if (rect == Rectangle.Empty) diff --git a/AngelLoader/Forms/MainForm.resx b/AngelLoader/Forms/MainForm.resx index 86c1c6c01..ec3224055 100644 --- a/AngelLoader/Forms/MainForm.resx +++ b/AngelLoader/Forms/MainForm.resx @@ -125,45 +125,45 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAK - EwAAAk1TRnQBSQFMAgEBBAEAAXgBGwF4ARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + EwAAAk1TRnQBSQFMAgEBBAEAAYgBGwGIARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgADBQEGA0IBdANP AZkDVQGxA1sBygNWAbUDTAGRA0YBgAMcAScoAAMNAREDSgGLA1ABmgMeASsYAAMDAQQDVQGtA1gBvQNO AZYDYAHgA1ABnzQAAwIBAwMZASIDWgHHA1IBoANBAXMDQAFvAzQBUwMpAT0DHQEpAx4BKgMPARMDBQEG DAADIwEzA2AB6AMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/Az4BahgAAwwBEAMFAQYEAAMr AUECAAGXAf8DAAH/A0ABcAwAAwMEBAEFBAADBQEGAYYBiwEAAf8ByQHNAQAB/wGQAZYBAAH/AaoBugEA Af8DWgHHAy0BRgMZASIDKAE7AzkBXgNCAXQDPwFuAzkBXgMIAQoMAAQBAw8BFAMuAUgDVgGwA0AB/QNA - Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABTQFpAYAB/gMAAf8DWgHE + Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABTwFrAYAB/gMAAf8DWgHE ASMBXgEhAfsDAAH/AgABnAH/AwAB/wMAAf8DWwHkA0EB+QMAAf8DQwF3DAADCQEMA1ABnwNdAckDPQFo A0YBgQNdAc8BAAGVAcoB/wMAAf8DXgHXA0MBdgMzAVEDVgGwA0YBfgMTARkIAAMsAUMDYQHiAv8BAAH/ - A1wB2QF4AX0BRwH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA + A1wB2QF6AX8BSQH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA ARABAAH/AwAB/wEKAQwBBwH/ASYBPQE6Af8BHwEyATAB/wEAARABAAH/AwAB/wEGASMBAAH/AQMBIgEA Af8DXgHwA0QBeQMIAQoEAANdAdEDAAH/A0sBjANdAcwDAAH/AwAB/wIAAZgB/wIAAZYB/wNAAf0DXAH4 A1EBpANRAfcDAAH/AyIBMQgAAx8BLAEAAY4BpwH/AgABmgH/AwAB/wEAAZQBvQH/AQABzgL/AQABsQHe Af8BAAGYAdIB/wEAAYUBygH/AwAB/wMrAfwBAAGnAcgB/wNZAe8DHgErDAADRgF9AbwBwQEAAf8DVQG0 - A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFYAW0BRwH+ + A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFaAW8BSQH+ ARIBSQEAAf8BDAE0AQAB/wEsAjUB/wEPARYBFwH/ARcCHwH/ARcBHQEeAf8BCgE2AQAB/wEKASQBAAH/ - AW0BfwFZAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 + AW8BgAFbAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 AwAB/wNGAYEDTgGXAwAB/wNWAbAMAANEAXsBAAGyAdgB/wEAAbcB9QH/AQAB0QH5Af8BAAGZAZ4B/wEA AbMBzwH/AQABjgGtAf8BAAGyAccB/wEAAdcC/wEAAesC/wEAAZ0BoQH/A08BmwMOARIMAANGAYABxQHJ - AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFF - AkQB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ + AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFH + AkYB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ AwAB/wEVAQABAwH/A0AB/QNWAbUDGQEjA1gBvQMAAf8DXQHUAx4BKgNZAcMDAAH/A0AB/QIAAbwB/wMA Af8DAAH/AwAB/wMoATsDNQFWAwAB/wIhASMB+wMTARoIAANQAZ0BAAGtAesB/wEAAaEBygH/AwAB/wMA Af8BAAGUAbcB/wIAAYIB/wMAAf8BAAGZAZ8B/wEAAegC/wMAAf8DTAGOAwUBBgwAA0gBhAG6Ab8BAAH/ A10B3AFsAW0BUQH3AdgB6AEAAf8BtwG6AQAB/wHcAeEBAAH/AwAB/wNZAcMBwQHGAQAB/wNdAd8DGAEh CAADOARcAdYDKwH8AwAB/wEGAQoBDAH/AaEBpwGmAf8BhAGMAY0B/wErATcBPwH/AQ4BHQEmAf8BkgGY AZkB/wFQAVYBVwH/AwAB/wMAAf8DTQH6A0sBjAMPARQDXgHtAwAB/wMrAfwDRQF8Az0BaQNNAfoBKQIy - AfsDTQH6AVUBWgGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu + AfsDTQH6AVcBXAGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu Af8DAAH/AwAB/wMAAf8BAAGMAbgB/wMAAf8BggIAAf8DAAH/AQABuAHOAf8BAAGFAcQB/wNeAd0DOgFg AxUBHAgAA0cBgwGVAZsBAAH/AwAB/wHbAesBAAH/A1UBrwMQARUCUwFSAaUBwwHKAQAB/wNcAecBqAGw - AQAB/wNiAeEDGwElCAADSQGHAVQBUwFUAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ + AQAB/wNiAeEDGwElCAADSQGHAVYBVQFWAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ AUgBVwGBAf8BNgFKAVIB/wGrArIB/wGjAagBqQH/ARwBHwEjAf8BFQEJAQ4B/wNAAf0DWwHTAyoBPwNI - AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBXAGAAVAB/gNgAegDXgHXAzsBZQNKAYoCAAGI + AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBXgGAAVIB/gNgAegDXgHXAzsBZQNKAYoCAAGI Af8CAAGfAf8DPwFsA18B2gMAAf8BAAGyAeMB/wEAAY4BqQH/AwAB/wMAAf8DAAH/AQABkQHDAf8DAAH/ AwAB/wMAAf8DAAH/AQABsAHuAf8DAAH/AwAB/wNOAZYIAANHAYMBAAGGAQAB/wHXAdwBAAH/AwAB/wNQ AZ0DGwElA1UBrAHCAc4BAAH/A1wB2QGgAaoBAAH/A1oB6QMeASoIAANGAX0DTQH6AQ8BHgEAAf8BIgEx ARMB/wE1AU4BOQH/ASgBUgFGAf8BFAEkASYB/wFQAV0BhAH/ATUBRAFIAf8BGQEwASwB/wEjAT4BOQH/ - ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1cB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 + ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1kB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 A00B+gMrAfwBIQEyASEB+wNYAb0DKQE9A14B1wIAAZIB/wMAAf8DPgFqAgABhgH/AQABqAHSAf8BAAHS Av8CAAGEAf8DAAH/AwAB/wMAAf8BAAGKAcEB/wMAAf8DAAH/AwAB/wMAAf8BAAG8AfYB/wEAAaoB3gH/ AgABmQH/A1IBqAgAA0MBdgGHAZMBAAH/AmgBQQH5Ad4B4QEAAf8DAAH/AwAB/wHOAeABAAH/Al4BXAHZ @@ -177,30 +177,30 @@ ASgBLwExAf8BAQEHAQoB/wMAAf8BFwE5AQAB/wNNAfoDPgFrA1YBtgIAAZgB/wMAAf8CAAGIAf8DXgHd AzQBVANVAa4BlwGpAd0B/wJeAV8B+wNHAYMDUgGlAwAB/wMAAf8DAAH/A00B+gMPARQEAAQBAV0CZQHs AQABoQHmAf8DAAH/AYICAAH/AwAB/wEAAYwBuAH/AwAB/wMAAf8DAAH/AgABvQH/AQABlgHAAf8DVgGy - AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABYwH+ - AdEB1wEAAf8CgAFgAf4CgAFKAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ - AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BTAFJAUoB/gNZAcMDIQEv + AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABZQH+ + AdEB1wEAAf8CgAFiAf4CgAFMAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ + AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BTgFLAUwB/gNZAcMDIQEv AzABSgMAAf8DAAH/AgABnwH/AQABgQG2Af8DAAH/A2AB8wMAAf8DXAH4A00B+gEAAYQBsgH/AwAB/wMA Af8DAAH/A1MBpgwAA0IBdQEAAeMC/wEAAZQBzAH/AwAB/wMAAf8BAAGAAbEB/wMAAf8DAAH/AgABjgH/ AQABuQH7Af8DAAH/A0wBjgMSARcEAAMlATcDAAH/AdsB3AGOAf8B+AH7AZ0B/wGlAagBAAH/Al8BMgH7 AZcBmgEAAf8DWgH1AZABkgEAAf8BpAGnAQAB/wJiAVkB7wHtAfIBjgH/AckBzQEAAf8BoAGlAQAB/wNb AdgDFAEbAxUBHANiAeEDAAH/AR8BDwEVAf8BJAEiAScB/wE/AVwBOgH/AbgBywG4Af8B2ALdAf8B3QLg - Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AWEBVwFaAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ + Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AWMBWQFcAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ AwAB/wIAAYUB/wIAAaoB/wMAAf8BAAGAAZsB/wEAAY4BuAH/AwAB/wMAAf8CAAG0Af8DTQH6AxMBGQgA AxgBIQFbAl0BygEAAeUB+gH/AQAD/wEAAcQB9wH/AgABlAH/AQABjQG6Af8CAAGXAf8CAAHCAf8BAAHR Av8BAAHKAe4B/wIAAYcB/wNbAeQDIQEvCAADAgEDA00BkwG8AcYBAAH/A1YBsANeAeIDAAH/A2UB8QMA Af8DOQFeA1IBoAL/AQAB/wMAAf8DWgG/AxYBHgQAAy0BRQNIAfYBGQEFAQoB/wEYAQ4BEwH/ARQBDAEO Af8BLgFVARoB/wFdAZwBVgH/AY0BjAGOAf8BqAGvAbAB/wFVAaMBQgH/ATABRwEUAf8DAAH/AQMCAAH/ - AVMBUAFRAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA + AVUBUgFTAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA Af8CAAGkAf8CAAGGAf8DLQFFDAADIAEtAQABlQGsAf8BAAGAAZIB/wNRAaEDXQHqAQAB4gH4Af8BAAHe AfMB/wEAAcoB8wH/AQABpgHIAf8DWQG7A1kBuwEAAa8B0AH/A1cBvAMLAQ4MAAMmATkDXQHMAyUBNwNT AakDUgGgA1UBrANVAa8DQwF2A4AB/gG0AbgBAAH/AbsBxwEAAf8DZQHxAzIBTwQAA0IBdANcAcsDKwH8 AysB/AEdAUQBBgH/AS8BNwEYAf8BNwFCASIB/wEoARsBIQH/ASwBKQErAf8BNAGBARMB/wEmAUIBDgH/ - AR4BNAEDAf8BAQIAAf8BVAFKAU4B/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ + AR4BNAEDAf8BAQIAAf8BVgFMAVAB/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wIAAZEB/wJeAWEB4gMtAUUUAAMmATgDMwFRBAADDAEPA0QBewEAAewC/wEAAYIBlAH/A0oBiQME AQUDAwEEAzQBVAMNAREsAANdAdEByQHSAQAB/wNLAY8CbQFRAfcBmwGoAQAB/wM+AWoEAAMDAQQDDAEP - AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFlAV4BYAH+ - AXoBgAFWAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ + AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFnAWABYgH+ + AXwBgAFYAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ ARUDZQHxA2AB4EAAA0QBeQNSAaUEAANGAYEDWQHBAw8BFAQAAwQBBQQABAEDOAFcA0IBdANGAX4DUwGq A1UBrQNYAboDWgHEA1EBogNUAasDQAFvAwwBDwQBBAABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEA AQEGAAEBFgAD/4EAAeABDwH8AT8BAwH/AeABAQHAAQcB5AE5AQABAwGAAQABgAEDAYABAQGAAQMBgAEA @@ -279,78 +279,79 @@ iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGuSURBVDhPYxhQEKvEFB+nzHwiVoXlQ5wKyzso/R+EY5WZ - p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD4CuayqwkQUbBDME - hs9snf7/yKoeMHt9fyHYYKg23ADkwkJb2f8vb+/DMPDinnlArzMfjlVmWbN3UQtYDBQUUK3YAciFIAOx - uRCEbx5bAXLZeaBBOw6v7AaL4TUU5mVsLkTG1w4t/X96yzQw++3DI0BLWD5BjUAFQC+3FdnJETQQHb+6 - ewBk6FuoMQgAc+Gb+9i9jA9/eXUW5P1/UKMgABjoLcR4GRd+dn0nyKVPocYBvazM3FxsrwD2AjYNhPDH - Zyf+V3po/I9TZamBGgnyNsubV3f2Y9VACMMNVGbuhxoHAaCkAUoi2DThwx+fncRuIAjEK7OmpejwgNMe - Ns3YMMiFVZ6aoLQ6AWoMJgAZnKTJSZTBOL2MDSAMXonVMBCGuZAoA2EAGIPpuFxMkgvRATYXU2QgDEBc - zPX/yv5F/x9e3EK6l3GBOGWmOGDsHgcadi9WlaUUKjwQgIEBAExb1Vj6X25iAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG3SURBVDhPYxhQEKvEFB+nxHQiVoXlQ5wKyzso/R+EY5WZ + p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD+KUmZsKbGTBBsEM + geEzW6f/P7KqB8xe318INhiqDTcAubDQVvb/y9v7MAy8uGce0OtMh2OVWdbsXdQCFgMFBVQrdgByIchA + bC4E4ZvHVvyPUWI6DzRox+GV3WAxvIbCvIzNhcj42qGl/09vmQZmv314BGgJyyeoEagA6OW2Ijs5ggai + 41d3D/yPUWZ5CzUGAWAufHMfu5fx4S+vzoK8/w9qFATEqTC3EONlXPjZ9Z3/Y5VYnkKNA3pZmbm52F4B + 7AVsGgjhj89O/K/00Pgfp8pSAzUS6Eolljev7uzHqoEQhhuozNwPNQ4CQEkDlESwacKHPz47id1AEIhX + Zk1L0eEBpz1smrFhkAurPDVBuWgC1BhMADI4SZOTKINxehkbQBi8EqthIAxzIVEGwgAwBtNxuZgkF6ID + bC6myEAYgLiY6/+V/Yv+P7y4hXQv4wJxykxxwBL/eJwS871YVZZSqPBAAAYGAAuu1UcrcTJQAAAAAElF + TkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VVPKARhFN+jNDO7KLmoLRcHBy7iIi6SFDks - TqtmZtlcpEQuOGjNzK4p5F/tKiku4qAkB8vGYg97cLCJkAs3N0fmN71PY7Raa8rFr17tfu997+/vfeP6 - hx28pPa6JbWa/joLt6g1lg3M3RQH9WdB1rrp2Bm4+0Le4uDMtS+WvPXFLh7Lh5YzvKxNkPqX8I8XGM7S - 7QuJs57V1BukO3b+UhLUX8jidxAkdbspsn/InENqp7aOeFHZIJP8gTZUja1/ZA5p1g/igqwmURmZ5Qcu - oHSg113R1Ctz3rl0mi4KRO4xEzLLD6Ai2IKBMuf4jTNemq4jMxtQUg5lFfrVMo8cziBb5hxVmMwx9oDM - bDAcc5K2B/k2iKFDf9Fn5hyCORjc18nKBnJeM7mZaNB2zQG5/bqHtJ/Ay+FFMMTqHAziZeWQTL4CdIJz - dgHZgddoBZmYMMof9A6vXFqHCu5zonaXLSFzWEZprx3LJyl2CdI6G0+YF4kNgqi2lA7MP3ZFL56ZDba2 - pH/mgQuEK01n2YAgnj7tqW3h+MQaBEFBOdARel80mWE6bCoCQkduvgeyQMbI3BoETMHK24NXjq6ljKpG - 6XpuQDsEUbnCoK3OrG2B1Id24nge6NrPgGFhwHamMEEl0OeyL9lhoa2VMZiBI8+ACXOhtFX0GkHQJnxM - 8FEhC2eAxcITUDESTQuS0k/HzgJPcvZn4E/hcr0DUbSOqjT7gYIAAAAASUVORK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VVPKARhFN+j2JndTclF5LQHBydxERdJihwm + Tis7s6yTlMgFBzEzu00h2lq7JeUkDkpysGz+ZA97cLCJkAs3N0e+3/Q+jdFq7U65+NWr3e+97/39vW9c + /7BDkLVBj6w10l9n4QnqbdWjy7e+sPEiKno/HTsDz/BCnS8cvZESZ3dS4vKpZjyWExR9ltQlIjBTxpxl + e1bTFwPJzDukP3HxWhk2XsmiNIiyttMePTjiziFN89vHQlDdIpPigTY0TG9+Zg7pMA5ToqKdozIyKw7u + kNqLXkvxzBt33rd2lvWFog+YCZkVB1ARbMFAuXP8xpkgLzaTmQ0oqYCyygNatVeJ5JDtp3NWhckctgdk + ZgNz7Jb1fciPQZgO/UWfuXMI5sC4b5CVDeS8cW4r3arvmQPyBAwvab9AUCJrYIjVORgkKOoRmXwH6ATn + /AKyA6/RCjIxwcofq52IXVmHCu5XBPX7fAmZw2KlvfXGTjP8EqRrKZU2LxIbxKDWWTW68iTFL1+4Dba2 + ciT66A5F/KazfEAQ77D23L16cmoNgqCgHOgIvbR+nuM6bCoCQkdufgayQMbI3BoETMHK24P7pzYyrKop + ul4Y0A5xSL3GoK3OrG2BtCzspvA80LXfAcPCgO1M4YJKoC9kX/LDQlsrYzADR54BE+ZC6Un0GkHQJnxM + 8FEhC2eAxcITUD8Zz4qyOkLHzgJPcv5n4E/hcn0AlbeOeSP8K6kAAAAASUVORK5CYII= iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGZSURBVEhL7ZQhUMNAEEUjGSZ3QSKRSCQSiUTiykzuChKJ - AweX60wkEolEIiuRSCQSicSyf/vDHEdpO00EgjeTafdfZu9u92+Kf3KMa04q1+wxHJaqjge2Di/WxTfr - 4zHlYahOr3eQvBxPdvHf+PgszxWXezK63EDCchyOqBTVqN0qfXhn2A/rmgdbNxcMFeMnt6YO9wzXB2XA - BgwVafS59c0TbkZpPVASlCZNhEaXdXxFHyitB6wIt6SJtNGiGXezTykDJ1nhWpujZhuOwWkpfTUac0Al - Q14oXXzEs3ATWUN9UWcqijbax5ZhBpPLC3faNEkAm3H1G+oOeRgqcJDxYcrwJ7ATkjNUF+C6KAUlZZ47 - 0Ght6i8HmjXLxw85xSElBbVM3YB1xOmmmFpo+KU0n84R+fejS4pTqmOSj5hOKtcoLaY7Te4C9bWMfL65 - 9iyb3qWoj8V+aDQlJe+FbNbm07syuLr6OXNKB26C9YVWXkpi2zQReoAy9v4MKJIYG3SDN3d6h2A2WChZ - mFoXzigPC5qOxjL8SxTFJ00CxZeT7IG4AAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGaSURBVEhL7ZQhUMNAEEUjGdpckEgkEolEIpG4MuSuIJE4 + cDR3nalEIpFIZCUSiUQikVj2b3+Y4whtJ4lA8GYy7f7L7N3t/k32T0pu/Ulh/R7DfinKcGBOqxdjw5tx + 4ZhyPxRnNztIPhxPd/E/d+FZnmsud2R0tYGEw3F1RCUrRrOtgZu8M+yGsf7BlP6SoZK76W1eVvcM24My + YAOGijT6wjj/hJtRagdKgtLEidDoQRle0QdK7YAV4ZY4kTZatNxO9ikl4CRrXGtz5LfhGJyW0lejMQdU + EuSFoQ2PeJZuImuoL+pMRdFGuzBjmMDk8sKdNk0SwGZc/Ya6Qx6GChyUu2rO8CewE5IzVBfguigFJaXJ + HWi0NvWXAy2a5cKHnOKQkoJaxm7AOuJ4U0wtNPxSaqZ2RPr9qJPilOqY6COmk8o1SsupT5O6QH0tI59u + rj1Lpncl6mOxHxpNSUl7IZvN0uldG1xd/Zw4pQY3wfpSK68ksm2cCD1AGTt/BhRJjA3qwWuc3j5YDBZK + Vs2Nrc4p9wuajsYy/Etk2ScCFcWFAI8TWgAAAABJRU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH/SURBVEhLzVTPK0RRGD1LS0tLS0tLS0tLS8v5D4wx5Ech - CVkgJSmSlCkJSVm+maEMCUmykB9JshCSjKTrO2++25g3b3h4C6dOvXfv/c798Z3vw7+D04Q6/QwfTjfK - kk04d+Ko0KFw4TQikumAkU0GdChciPD+8wJMugW3vI0OhwM5ffVRP4xZgzkdhuFtdCocJKOYuZvNbfCy - 6D7Tvk79HUzqdieyFLfkbXgrXfI3iFD0aiIvTvI2yUYkdElpSHClsFZZLz7vIekUoUOmYnh4WyncgNzp - xKtdk4xhxMYKG6ym9fbyZgvMxViO15Mw93M5vi4VC38mN7Zrb6fzGmrnfJ7kZ+KwD+Z91V/oJ6TL5PnW - i6zsRNG225U7lV/gd+ThjgdFXBynksWQd4tk2pGlFf1ESpGHOugVZ0kOVKo0ZFHdRjMeHuf9xbzkYSTh - Pys+WVzNxPsJeumeXByoocEgAZXMh5+glydDv9sgQjf4CXp5MyWJlTrQ0GCgbelrrxgr2GtldtgCzwcB - Az476SkBs9ft+jvBvmQbn+VGHNnALVyep5yVyEDaTwtny4mhyp2X5icHWGbDs5Wuza/WFfgOTBgD+ESb - rXhkPnSqALRzKo6Ly3GYs1HZQApVp74Gi4UWZR54Gx32BZ+F69MxvPBWOvw1tDPW6G8g8PmK2zfwAeUN - UaR56NgIAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH/SURBVEhLzVTPK0RRGD1LS0tLS0tLS0tLS8v5D8xMQ34U + kpAFUpIiSZmSkJTlmzHKkJAkC/mRJAshyUi6vvPmu41584aHt3Dq1Hv33u/cH9/5Pvw7ODE06Gf4cLpR + kYrh3EmgSofChdOMSLYDRjYZ0KFwIcL7zwsw6Rbc8jY6HA7k9LVH/TBmDeZ0GIa30alwkIpi5m42v8HL + ovtM+zr1dzCp2U7kKG7J2/BWuuRvEKHo1URBnORtUs1I6pLykOBqYb2yUXzeQ9IpQodMx/DwtlK8Abnd + gVe7JhXHiI0VNllN6+3lzRaYi7E8rydh7ufyfF0qFf5MbmzX3k4XNNTOhTzJz8RhH8z7qr/QT0iXyfOt + l1jZiaJttyt/Kr/A78jDHQ+KuDhOJUsh7xbJtiNHK/qJlCMPddArzpIcqFR5yKKGTBwPj/P+Yl7yMDud + Pyw+WVzLxPsJeumeXByoocEgAdXMh5+glydDv9sgQjf4CXp5MyWJlTrQ0GCgbelrrxgr2GtldtgizwcB + Az476SkJs9ft+jvJvmQbn2UmgVzgFi7PU8lKZCDtp4Wz5cRR485L85MDLLPh2UrX5lfvCnwHJowBfKJM + Kx6ZD50qAu2cTuDichzmbFQ2kELVqa/BYqFFmQfeRod9wWfh+o0YXngrHf4a2hnr9DcQ+Hyl7Rv4AMAg + UZuIzzJ2AAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANYSURBVDhPvZRJTFNRFIbPuS8xxmFjXDmGBUaNCxNduDCa - GDUmulOjiQsTo0QFKm0BESFlkEEZRLRMpS2zglBBhjJUJsGCMohIBFlolKCAKBAXosD13MeVCDGmuPDb - vL7/nHd67z3/ufDfydLDcrOPsv9+MCZWRLHW6ljWaY9mLeLdpFEOpHrAMpnqGimXYE9JGJZ1Z+PMWA1w - 3gJ82jn7HKf3l6QXh2NpqgZ2y0/+jkXPvJ5nIJ9+BvxrHfB2E048iscXlTcwzxGH3eJd6NNtwDszkZt1 - 7IL89M9YdOzsOxty3gG82YiDVl8WTKvZkO4HK5O8lH3W07DUooP1Qm8y4keRJ/LTdeyMLDGfVC07+Tqf - tvgUeEko671zETbKEBSFYOiLDKHjNSlBmhe4FYexfpHfn4/cpGMnZGgWqwGWVsewAd4O3BGLb5I14C5D - KqWRWDzZQLEYVi8llduesKkmDt+LFdfEsgFRR4ZolRrl6OdK4EOlyI1eymEpz/EwAnMmqEFVN7BMSnMY - vZWDQw+Bf64CnuajHJMygC0UrZP1wBsTWKuU5vGrqD0aC6U0j/pb2CV28iAMM1Qh1gNW1ydg/1Qj8Exf - tKjiAtSiDuAV0VhLTTmVG8B0WQHKIRmGe1fRPNUEvCERe6H0GhZVXcdXPVk4M/1YnCcbdsSjMzsQdsl8 - FeHZHxT/Qqv9UEJbpT9oT6eu62GbiOdewRgRdybjGNjC2MhENXWcGjTTTE868L488p6fckStJrkbyC4L - C5F/R7usONKdhWN18awr2x/WiTgVvSlWSkWH1a6XRzHnlCjYA/yTnY7AH6PVSgvI0MLaND24CZ9a/MBd - jLEMgS0EC7/T8TnimVMVkjSwg6aETwl/hrM28ucKNeAiJi2s6jTjx2/UqLxAjJCyuj2P8gisy9bDVim5 - jFmLEaLzb+8jT/GBnVKexWAAJn+6TJIn8+jLRT5DF01BENZK+d9J92bePTl0T3Sp09RLTpgba5ehS2VN - Ck1Pph87T35tGyynguQaMv6g6RJskWmuY9XB5idGHBsmd4zaqVgr8IFy4DYDaxK3mExbHFZf2N5BDhkn - 09OgfCmLRIdVy84VHAdFpiwecZ8Wh2KSPYp13gvCqFQt7C0wwBIZ/g2An2e+o9ziKCLsAAAAAElFTkSu - QmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANaSURBVDhPvZRJTFRBEIar+iWGuFyMJ9dw0KjxYKIHD0YT + o8ZEb2o08WBilLjAwMwAIkhGkAGURUQYgWE2EFBkXxyWUVDUAWURkIhy0ChBAVnjQRRoqx8tEWPM4MHv + 8ub9Va+mu+vvgv9Olh4WWQKU3XfDMbkymjXVxLM2ZyxrFO9mjbIn3QcWylTPSPOHHaWRWNGRhdOjtcB5 + I/Ap98xzjN47SS+5jOXpGtguP/k7Vj3zfWFHPvUc+Jc64C0ZOH4/ETuqrmKuKwE7xbvQp5qBtzmQW3Ts + jPz0z1h17OT7IuS8FfiTFOyzBbJwWs3qzCBYYvJVdtmOg5dVB6uE3pCKn0SeyM/UsROyxFzStezomzu0 + xWfASy+x7pSzsEaGoPASRnTYSY/AKClBhi94F0eyHpHfcwe5WceOyNAMNgN4VV9lvbwFeG0cvr2pgbUy + pFJuxJKJh8BdcaxeSio3zsG6mgT8IFZcE8d6RR0ZolVqlIPDVcD7y5Gn+ir7pTxLqRFvjVODqq9ghZRm + SfVT9vaXAR+uBp4RoBySsro920Q98EdJrElKc/hZ9F4sFkhpDnXXsV3spDgS7aoQ7wPL6pOwZ/IRcEcg + WlXxN9SiLioagw+oKcdyQpguK0TZJ8OQF4aWycfA65OxG8qisJC29OqlA6enGtQzG3Alojs7FLbJfBXh + 2e8UH6HVfiylrdIftGRS1/WwScRzLmCciD814SgURrLB8RrqODVo+gk96cBf55L3gpQDajVJXig7LyzU + ZsehdhsOdjpwtC6BtWcHw0oRp6LXxErdN3FA7XpFNHNPioJdwD876QiCMVat9Bt2LazI0IO38Kk1CNaK + ayxDUGjAgm90fK5E5lYFkwa2tJiRTwp/XmbN5M/FasBDzFpY2mrBT1+pUbmhaJSyuj2fSiPWZetho5Q8 + xqJFo+j8u7vI0wJgq5RnMBiAyZ8eYzrHfF7nIJ+mQZMfhg+k/O9k+jG/rls0J9rpNsWzbnLC7LX2GBoq + y9Po9jiC2Gm6BM19lVSQXEPG7zP7wwaZ5jk2HaynqTU6QO4YclKxJuC9lcCLDOyxmGIybX7YAmFzKzlk + jEzflYUjFdHosmnZqfzDoMiU+SPmaUkEmpwxrO32RYxJ18LOfAMskOFfAPgBlbqjqMvuHqMAAAAASUVO + RK5CYII= diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index 3041dc055..684c402ea 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -77,9 +77,9 @@ private void InitComponentManual() ClearFiltersButton = new ToolStripButtonCustom(); ResetLayoutButton = new DarkButton(); GamesTabControl = new DarkTabControl(); - TopRightMenuButton = new DarkButton(); - TopRightCollapseButton = new DarkArrowButton(); - TopRightTabControl = new DarkTabControl(); + TopFMTabsMenuButton = new DarkButton(); + TopFMTabsCollapseButton = new DarkArrowButton(); + TopFMTabControl = new DarkTabControl(); StatisticsTabPage = new StatsTabPage(); EditFMTabPage = new EditFMTabPage(); CommentTabPage = new CommentTabPage(); @@ -112,7 +112,7 @@ private void InitComponentManual() GameFilterControlsShowHideButtonToolStrip.SuspendLayout(); FilterIconButtonsToolStrip.SuspendLayout(); RefreshAreaToolStrip.SuspendLayout(); - TopRightTabControl.SuspendLayout(); + TopFMTabControl.SuspendLayout(); ((ISupportInitialize)LowerSplitContainer).BeginInit(); LowerSplitContainer.Panel1.SuspendLayout(); LowerSplitContainer.SuspendLayout(); @@ -242,9 +242,9 @@ private void InitComponentManual() // TopSplitContainer.Panel2 // TopSplitContainer.Panel2.BackColor = SystemColors.Control; - TopSplitContainer.Panel2.Controls.Add(TopRightMenuButton); - TopSplitContainer.Panel2.Controls.Add(TopRightCollapseButton); - TopSplitContainer.Panel2.Controls.Add(TopRightTabControl); + TopSplitContainer.Panel2.Controls.Add(TopFMTabsMenuButton); + TopSplitContainer.Panel2.Controls.Add(TopFMTabsCollapseButton); + TopSplitContainer.Panel2.Controls.Add(TopFMTabControl); TopSplitContainer.Size = new Size(1671, 309); TopSplitContainer.SplitterDistance = 1116; TopSplitContainer.TabIndex = 0; @@ -529,35 +529,35 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir GamesTabControl.Size = new Size(1075, 24); GamesTabControl.TabIndex = 1; // - // TopRightMenuButton + // TopFMTabsMenuButton // - TopRightMenuButton.Anchor = AnchorStyles.Top | AnchorStyles.Right; - TopRightMenuButton.FlatAppearance.BorderSize = 0; - TopRightMenuButton.FlatStyle = FlatStyle.Flat; - TopRightMenuButton.Location = new Point(533, 0); - TopRightMenuButton.Size = new Size(18, 20); - TopRightMenuButton.TabIndex = 13; - TopRightMenuButton.Click += TopFMTabsMenuButton_Click; - TopRightMenuButton.PaintCustom += TopRightMenuButton_Paint; + TopFMTabsMenuButton.Anchor = AnchorStyles.Top | AnchorStyles.Right; + TopFMTabsMenuButton.FlatAppearance.BorderSize = 0; + TopFMTabsMenuButton.FlatStyle = FlatStyle.Flat; + TopFMTabsMenuButton.Location = new Point(533, 0); + TopFMTabsMenuButton.Size = new Size(18, 20); + TopFMTabsMenuButton.TabIndex = 13; + TopFMTabsMenuButton.Click += TopFMTabsMenuButton_Click; + TopFMTabsMenuButton.PaintCustom += FMTabsMenuButton_Paint; // - // TopRightCollapseButton + // TopFMTabsCollapseButton // - TopRightCollapseButton.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right; - TopRightCollapseButton.ArrowDirection = Direction.Right; - TopRightCollapseButton.FlatAppearance.BorderSize = 0; - TopRightCollapseButton.FlatStyle = FlatStyle.Flat; - TopRightCollapseButton.Location = new Point(533, 20); - TopRightCollapseButton.Size = new Size(18, 289); - TopRightCollapseButton.TabIndex = 14; - TopRightCollapseButton.Click += TopRightCollapseButton_Click; + TopFMTabsCollapseButton.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right; + TopFMTabsCollapseButton.ArrowDirection = Direction.Right; + TopFMTabsCollapseButton.FlatAppearance.BorderSize = 0; + TopFMTabsCollapseButton.FlatStyle = FlatStyle.Flat; + TopFMTabsCollapseButton.Location = new Point(533, 20); + TopFMTabsCollapseButton.Size = new Size(18, 289); + TopFMTabsCollapseButton.TabIndex = 14; + TopFMTabsCollapseButton.Click += TopFMTabsCollapseButton_Click; // - // TopRightTabControl + // TopFMTabControl // - TopRightTabControl.AllowReordering = true; - TopRightTabControl.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - TopRightTabControl.EnableScrollButtonsRefreshHack = true; - TopRightTabControl.Size = new Size(535, 310); - TopRightTabControl.TabIndex = 15; + TopFMTabControl.AllowReordering = true; + TopFMTabControl.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + TopFMTabControl.EnableScrollButtonsRefreshHack = true; + TopFMTabControl.Size = new Size(535, 310); + TopFMTabControl.TabIndex = 15; // // LowerSplitContainer // @@ -663,7 +663,7 @@ void SetReadmeButton(DarkButton button, int x, int tabIndex) FilterIconButtonsToolStrip.PerformLayout(); RefreshAreaToolStrip.ResumeLayout(false); RefreshAreaToolStrip.PerformLayout(); - TopRightTabControl.ResumeLayout(false); + TopFMTabControl.ResumeLayout(false); LowerSplitContainer.Panel1.ResumeLayout(false); ((ISupportInitialize)LowerSplitContainer).EndInit(); LowerSplitContainer.ResumeLayout(false); From 5f543e1552d47313a8845237f9992eecfaef0f8b Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 18:13:00 -0800 Subject: [PATCH 103/200] Hook up bottom tab control to Select handler, and notes --- .../Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs | 2 ++ AngelLoader/Forms/MainForm.cs | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 58c5c108e..100b6ce90 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -58,6 +58,8 @@ private void Construct() _tabControl.MouseClick += _owner.LowerFMTabsBar_MouseClick; _owner.LowerSplitContainer.Panel2.MouseClick += _owner.LowerFMTabsBar_MouseClick; + _tabControl.Selected += _owner.FMTabControl_Selected; + Constructed = true; } } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 78813fb57..770eb28d8 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -1194,11 +1194,12 @@ private void SetWindowStateAndSize() { if (!_firstShowDone) { + // @DockUI: We need to handle the bottom tab control / collapsed state here too if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab && !Config.TopRightPanelCollapsed) { lazyTab.Construct(); } - TopFMTabControl.Selected += TopRightTabControl_Selected; + TopFMTabControl.Selected += FMTabControl_Selected; _firstShowDone = true; } @@ -3234,7 +3235,7 @@ void DoSelect() #region Top-right area - private static void TopRightTabControl_Selected(object sender, TabControlEventArgs e) + internal void FMTabControl_Selected(object sender, TabControlEventArgs e) { if (e.Action == TabControlAction.Selected && e.TabPage is Lazy_TabsBase lazyTab) { @@ -3248,6 +3249,7 @@ private void TopFMTabsCollapseButton_Click(object sender, EventArgs e) SetTopRightCollapsedState(TopSplitContainer.FullScreen); } + // @DockUI: We need to handle the bottom tab control / collapsed state here too private void SetTopRightCollapsedState(bool collapsed) { if (collapsed) From e12e0d3905e36e8d4b04383de3a725ebd8d457f6 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 19:13:03 -0800 Subject: [PATCH 104/200] Fix tab ordering when moving between tab controls --- AngelLoader/Forms/MainForm.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 770eb28d8..958b11c25 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -3311,6 +3311,26 @@ internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) return; } + // @DockUI: Explicitly hide tab + // Although adding a tab to another control automatically removes it from the first one, we need to + // explicitly run our custom ShowTab() method in order to keep the backing list synced. Otherwise, the + // tab order gets messed up. + // @DockUI: Could we make this happen automatically on tab remove? + // We'd need an event disabler and so on, but it might work. + if (s.Checked) + { + if (tabControl == TopFMTabControl) + { + if (Lazy_LowerTabControl.Constructed) + { + Lazy_LowerTabControl.TabControl.ShowTab(tab, false); + } + } + else + { + TopFMTabControl.ShowTab(tab, false); + } + } tabControl.ShowTab(tab, s.Checked); } From 44210b0d967873d340dd8e2e6545bef967026bd7 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 19:23:48 -0800 Subject: [PATCH 105/200] Prevent focus of first control in 1st tab page on selected tab remove --- AngelLoader/Forms/CustomControls/DarkTabControl.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index c4d3e216b..189f90dd8 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -457,7 +457,12 @@ public void ShowTab(TabPage tabPage, bool show) else { bt.Visible = false; - if (TabPages.Contains(bt.TabPage)) TabPages.Remove(bt.TabPage); + if (TabPages.Contains(bt.TabPage)) + { + TabPages.Remove(bt.TabPage); + // Otherwise the first control within the tab page gets selected + if (TabCount > 0) TabPages[0].Focus(); + } } } From 6a842ce910293d1a04fe62d08c40619ecd39e5ea Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 19:46:56 -0800 Subject: [PATCH 106/200] Fix page didn't auto-construct on show+select on bottom tab control --- AngelLoader/Forms/MainForm.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 958b11c25..a70f3bd88 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -265,14 +265,15 @@ private void Test2Button_Click(object sender, EventArgs e) private void Test3Button_Click(object sender, EventArgs e) { /* - @DockUI: Adding a tab to a tab control appears to remove it from any other it was in. - Convenient! So we should just be able to add a way to set the backing collection with visibilities right - off the bat without also adding to the physical collection, and then we can handle both collections in - what way we need to or whatever. + @DockUI: Make this proper functionality, accessed by dragging or a menu "send up/down" option or whatnot */ LowerSplitContainer.Panel2Collapsed = false; Lazy_LowerTabControl.TabControl.SetBackingList(_backingFMTabs); Lazy_LowerTabControl.TabControl.ShowTab(EditFMTabPage, true); + if (Lazy_LowerTabControl.TabControl.SelectedTab is Lazy_TabsBase lazyTab) + { + lazyTab.ConstructWithSuspendResume(); + } LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); } From 5d1f921dc051fd3a0ebe8bf725d37780500ff84c Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Thu, 29 Feb 2024 20:40:56 -0800 Subject: [PATCH 107/200] Work on saving/restoring both selected tabs --- .../DataClasses/ConfigDataSupporting.cs | 12 +++++++++ AngelLoader/Core.cs | 1 + .../Forms/CustomControls/DarkTabControl.cs | 27 +++++-------------- AngelLoader/Forms/FormsViewEnvironment.cs | 1 + AngelLoader/Forms/MainForm.cs | 23 ++++++++++++---- AngelLoader/Ini/ConfigIni.cs | 11 ++++++++ 6 files changed, 50 insertions(+), 25 deletions(-) diff --git a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs index e3b155a35..b7c6ae349 100644 --- a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs +++ b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs @@ -123,6 +123,7 @@ internal sealed class FMTabsData internal readonly FMTabData[] Tabs = InitializedArray(FMTabCount); internal FMTab SelectedTab = FMTab.Statistics; + internal FMTab SelectedTab2 = FMTab.Statistics; internal FMTabsData() => ResetAllDisplayIndexes(); @@ -158,6 +159,17 @@ internal void EnsureValidity() } } } + if (!GetTab(SelectedTab2).Visible) + { + for (int i = 0; i < FMTabCount; i++) + { + if (Tabs[i].Visible) + { + SelectedTab2 = (FMTab)i; + break; + } + } + } } private bool NoneVisible() diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index f445c6842..607808496 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2646,6 +2646,7 @@ internal static void UpdateConfig( #region Top-right panel Config.FMTabsData.SelectedTab = fmTabsData.SelectedTab; + Config.FMTabsData.SelectedTab2 = fmTabsData.SelectedTab2; for (int i = 0; i < FMTabCount; i++) { diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 189f90dd8..52cb4878d 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; @@ -113,21 +112,17 @@ public Control[] BackingTabPagesAsControls } } - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - internal ReadOnlyCollection BackingTabPages => _backingTabList.AsReadOnly(); - // Double-buffering prevents flickering when mouse is moved over in dark mode public DarkTabControl() => SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); #region Private methods - private (int Index, BackingTab BackingTab) - FindBackingTab(TabPage tabPage, bool indexVisibleOnly = false) + internal static (int Index, BackingTab BackingTab) + FindBackingTab(List backingTabs, TabPage tabPage, bool indexVisibleOnly = false) { - for (int i = 0, vi = 0; i < _backingTabList.Count; i++) + for (int i = 0, vi = 0; i < backingTabs.Count; i++) { - BackingTab backingTab = _backingTabList[i]; + BackingTab backingTab = backingTabs[i]; if (indexVisibleOnly && backingTab.Visible) vi++; if (backingTab.TabPage == tabPage) return (indexVisibleOnly ? vi : i, backingTab); } @@ -155,7 +150,7 @@ public Control[] BackingTabPagesAsControls if (contains) { TabPage tabPage = TabPages[i]; - var (index, backingTab) = FindBackingTab(tabPage); + var (index, backingTab) = FindBackingTab(_backingTabList, tabPage); return index == -1 || backingTab == null! ? (-1, null) : (index, tabPage); } @@ -349,7 +344,7 @@ protected override void OnMouseMove(MouseEventArgs e) // weird happens int dragTabIndex = TabPages.IndexOf(_dragTab); - var (bDragTabIndex, _) = FindBackingTab(_dragTab); + var (bDragTabIndex, _) = FindBackingTab(_backingTabList, _dragTab); Rectangle dragTabRect = GetTabRect(dragTabIndex); @@ -446,7 +441,7 @@ of the intended one [PublicAPI] public void ShowTab(TabPage tabPage, bool show) { - var (index, bt) = FindBackingTab(tabPage, indexVisibleOnly: true); + var (index, bt) = FindBackingTab(_backingTabList, tabPage, indexVisibleOnly: true); if (index < 0 || bt == null!) return; if (show) @@ -466,14 +461,6 @@ public void ShowTab(TabPage tabPage, bool show) } } - /// - /// Returns the display index of the specified . - /// - /// - /// - [PublicAPI] - public int GetTabDisplayIndex(TabPage tabPage) => FindBackingTab(tabPage).Index; - public Rectangle GetTabBarRect() => TabCount == 0 ? Rectangle.Empty diff --git a/AngelLoader/Forms/FormsViewEnvironment.cs b/AngelLoader/Forms/FormsViewEnvironment.cs index 10d4139ca..84a42436a 100644 --- a/AngelLoader/Forms/FormsViewEnvironment.cs +++ b/AngelLoader/Forms/FormsViewEnvironment.cs @@ -48,6 +48,7 @@ public void PreloadScreenshot(ConfigData config, List fmsViewList) // @ScreenshotDisplay: UI-specific preload conditions // If we allow moving the screenshots tab beside the readme or wherever else, we'll have to update // this code to match whatever the UI setup is. + // @DockUI: Finalize these conditions if (config.TopRightPanelCollapsed || config.FMTabsData.SelectedTab != FMTab.Screenshots) { diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index a70f3bd88..b9a44aeaf 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -926,6 +926,7 @@ and does NOT have its text transferred over. It ends up with blank text. } // EnsureValidity() guarantees selected tab will not be invisible + // @DockUI: Set selected tab on bottom (if constructed and has at least one tab) for (int i = 0; i < FMTabCount; i++) { if ((int)Config.FMTabsData.SelectedTab == i) @@ -5024,15 +5025,27 @@ public void UpdateConfig() SelectedFM selectedFM = FMsDGV.GetMainSelectedFMPosInfo(); - var fmTabs = new FMTabsData + FMTabsData fmTabs = new(); + + int selectedTabIndex = -1; + if (TopFMTabControl.TabCount > 0) { - SelectedTab = (FMTab)Array.IndexOf(_fmTabs.Cast().ToArray(), TopFMTabControl.SelectedTab) - }; + selectedTabIndex = Array.IndexOf(_fmTabs.Cast().ToArray(), TopFMTabControl.SelectedTab); + } + fmTabs.SelectedTab = selectedTabIndex > -1 ? (FMTab)selectedTabIndex : Config.FMTabsData.SelectedTab; + + int selectedTab2Index = -1; + if (Lazy_LowerTabControl is { Constructed: true, TabControl.TabCount: > 0 }) + { + selectedTab2Index = Array.IndexOf(_fmTabs.Cast().ToArray(), Lazy_LowerTabControl.TabControl.SelectedTab); + } + fmTabs.SelectedTab2 = selectedTab2Index > -1 ? (FMTab)selectedTab2Index : Config.FMTabsData.SelectedTab2; for (int i = 0; i < FMTabCount; i++) { - fmTabs.Tabs[i].DisplayIndex = TopFMTabControl.GetTabDisplayIndex(_fmTabs[i]); - fmTabs.Tabs[i].Visible = TopFMTabControl.Contains(_fmTabs[i]); + Lazy_TabsBase fmTab = _fmTabs[i]; + fmTabs.Tabs[i].DisplayIndex = DarkTabControl.FindBackingTab(_backingFMTabs, fmTab).Index; + fmTabs.Tabs[i].Visible = _backingFMTabs.Any(x => x.TabPage == fmTab && x.Visible); } #region Quick hack to prevent splitter distances from freaking out if we're closing while minimized diff --git a/AngelLoader/Ini/ConfigIni.cs b/AngelLoader/Ini/ConfigIni.cs index 8881b0c39..aba2bdfe5 100644 --- a/AngelLoader/Ini/ConfigIni.cs +++ b/AngelLoader/Ini/ConfigIni.cs @@ -694,6 +694,15 @@ private static void Config_FMTab_Set(ConfigData config, string valTrimmed, strin } } + private static void Config_FMTab2_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) + { + FieldInfo? field = typeof(FMTab).GetField(valTrimmed, _bFlagsEnum); + if (field != null) + { + config.FMTabsData.SelectedTab2 = (FMTab)field.GetValue(null); + } + } + private static void Config_StatsTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { Int_TryParseInv(valTrimmed, out int result); @@ -978,6 +987,7 @@ private static unsafe Dictionary #region Top-right tabs { "TopRightTab", new Config_DelegatePointerWrapper(&Config_FMTab_Set) }, + { "TopRightTab2", new Config_DelegatePointerWrapper(&Config_FMTab2_Set) }, { "StatsTabPosition", new Config_DelegatePointerWrapper(&Config_StatsTabPosition_Set) }, { "StatsTabVisible", new Config_DelegatePointerWrapper(&Config_StatsTabVisible_Set) }, @@ -1379,6 +1389,7 @@ private static void WriteConfigIniInternal(ConfigData config, string fileName) sw.Append("GameTab").Append('=').Append(config.GameTab).AppendLine(); sw.Append("TopRightTab").Append('=').Append(config.FMTabsData.SelectedTab).AppendLine(); + sw.Append("TopRightTab2").Append('=').Append(config.FMTabsData.SelectedTab2).AppendLine(); sw.Append("StatsTabPosition").Append('=').Append(config.FMTabsData.GetTab(FMTab.Statistics).DisplayIndex).AppendLine(); sw.Append("EditFMTabPosition").Append('=').Append(config.FMTabsData.GetTab(FMTab.EditFM).DisplayIndex).AppendLine(); From a635f4f831127e77e1edff1c57f128811b4d70ad Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 11:50:52 -0800 Subject: [PATCH 108/200] Start work on between-control tab dragging --- .../Forms/CustomControls/DarkTabControl.cs | 35 +++--- AngelLoader/Forms/MainForm.Designer.cs | 2 + AngelLoader/Forms/MainForm.cs | 112 ++++++++++++++++-- AngelLoader/Forms/MainForm.resx | 38 +++--- AngelLoader/Forms/MainForm_InitManual.cs | 2 + 5 files changed, 142 insertions(+), 47 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 52cb4878d..b38ec1ce7 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -40,7 +40,7 @@ internal sealed class BackingTab internal BackingTab(TabPage tabPage) => TabPage = tabPage; } - private TabPage? _dragTab; + internal TabPage? DragTab { get; private set; } private List _backingTabList = new(0); @@ -89,6 +89,8 @@ public bool DarkModeEnabled } } + public event MouseEventHandler? MouseMoveCustom; + [PublicAPI] [DefaultValue(false)] public bool AllowReordering { get; set; } @@ -127,10 +129,6 @@ internal static (int Index, BackingTab BackingTab) if (backingTab.TabPage == tabPage) return (indexVisibleOnly ? vi : i, backingTab); } -#if DEBUG - if (DesignMode) return (-1, null!); -#endif - // We should never get here! (unless we're in infernal-forsaken design mode...!) throw new InvalidOperationException("Can't find backing tab?!"); } @@ -308,7 +306,7 @@ protected override void OnMouseDown(MouseEventArgs e) return; } - if (e.Button == MouseButtons.Left) (_, _dragTab) = GetTabAtPoint(e.Location); + if (e.Button == MouseButtons.Left) (_, DragTab) = GetTabAtPoint(e.Location); base.OnMouseDown(e); } @@ -320,9 +318,11 @@ protected override void OnMouseUp(MouseEventArgs e) return; } - // Fix: Ensure we don't start dragging a tab again after we've released the button. - _dragTab = null; + // Do this first so DragTab is still valid when we handle drag-and-drop between tab controls base.OnMouseUp(e); + + // Fix: Ensure we don't start dragging a tab again after we've released the button. + DragTab = null; } protected override void OnMouseMove(MouseEventArgs e) @@ -334,17 +334,18 @@ protected override void OnMouseMove(MouseEventArgs e) } // Run the base event handler if we're not actually dragging a tab - if (e.Button != MouseButtons.Left || _dragTab == null || TabCount <= 1) + if (e.Button != MouseButtons.Left || DragTab == null || TabCount <= 1) { base.OnMouseMove(e); return; } - // If we are dragging a tab, don't run the handler, because we want to be "modal" and block so nothing - // weird happens + // If we are dragging a tab, don't run the normal handler, because we want to be "modal" and block s + // nothing weird happens + MouseMoveCustom?.Invoke(this, e); - int dragTabIndex = TabPages.IndexOf(_dragTab); - var (bDragTabIndex, _) = FindBackingTab(_backingTabList, _dragTab); + int dragTabIndex = TabPages.IndexOf(DragTab); + var (bDragTabIndex, _) = FindBackingTab(_backingTabList, DragTab); Rectangle dragTabRect = GetTabRect(dragTabIndex); @@ -361,16 +362,16 @@ protected override void OnMouseMove(MouseEventArgs e) // If the user has moved the mouse off of the tab bar vertically, still stay in the move. This prevents // a mis-ordering bug if the user drags a tab off the bar then back onto the bar at a different position. var (bNewTabIndex, newTab) = GetTabAtPoint(e.Location, xOnly: true); - if (bNewTabIndex == -1 || newTab == null || newTab == _dragTab) return; + if (bNewTabIndex == -1 || newTab == null || newTab == DragTab) return; int newTabIndex = TabPages.IndexOf(newTab); TabPages[dragTabIndex] = newTab; - TabPages[newTabIndex] = _dragTab; + TabPages[newTabIndex] = DragTab; _backingTabList[bDragTabIndex].TabPage = newTab; - _backingTabList[bNewTabIndex].TabPage = _dragTab; + _backingTabList[bNewTabIndex].TabPage = DragTab; - SelectedTab = _dragTab; + SelectedTab = DragTab; // Otherwise the first control within the tab page gets selected SelectedTab.Focus(); diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 401b5855e..07a137c56 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -912,6 +912,8 @@ private void InitializeComponent() this.TopFMTabControl.SelectedIndex = 0; this.TopFMTabControl.Size = new System.Drawing.Size(535, 310); this.TopFMTabControl.TabIndex = 15; + this.TopFMTabControl.MouseMoveCustom += new System.Windows.Forms.MouseEventHandler(this.TopFMTabControl_MouseMoveCustom); + this.TopFMTabControl.MouseUp += new System.Windows.Forms.MouseEventHandler(this.TopFMTabControl_MouseUp); // // StatisticsTabPage // diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index b9a44aeaf..12b7d23fb 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -46,6 +46,7 @@ behavior that comes part and parcel with what should be a simple #$@!ing propert using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Globalization; @@ -264,17 +265,6 @@ private void Test2Button_Click(object sender, EventArgs e) private void Test3Button_Click(object sender, EventArgs e) { - /* - @DockUI: Make this proper functionality, accessed by dragging or a menu "send up/down" option or whatnot - */ - LowerSplitContainer.Panel2Collapsed = false; - Lazy_LowerTabControl.TabControl.SetBackingList(_backingFMTabs); - Lazy_LowerTabControl.TabControl.ShowTab(EditFMTabPage, true); - if (Lazy_LowerTabControl.TabControl.SelectedTab is Lazy_TabsBase lazyTab) - { - lazyTab.ConstructWithSuspendResume(); - } - LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); } private void Test4Button_Click(object sender, EventArgs e) @@ -5441,4 +5431,104 @@ public void RefreshCurrentFMScreenshots() ScreenshotsTabPage.RefreshScreenshots(); } } + + #region Tab dragging + + // @DockUI: Working/testing code, finalize before release + + private bool _inTabDragArea; + + private void TopFMTabControl_MouseMoveCustom(object sender, MouseEventArgs e) + { + DarkSplitContainerCustom lsp = LowerSplitContainer; + + Point cp = Native.GetCursorPosition_Fast(); + + // @DockUI: Make light and dark mode colors + Color overlayColor = Color.FromArgb( + alpha: 64, + red: DarkColors.BlueSelection.R, + green: DarkColors.BlueSelection.G, + blue: DarkColors.BlueSelection.B); + + if (lsp.Panel2Collapsed && lsp.ClientRectangle.Contains(lsp.PointToClient_Fast(cp))) + { + if (!_inTabDragArea) + { + _inTabDragArea = true; + Trace.WriteLine("Hit closed"); + using var gc = new Native.GraphicsContext(lsp.Handle); + using var b = new SolidBrush(overlayColor); + gc.G.FillRectangle( + b, + new Rectangle( + TopSplitContainer.SplitterDistance, + 0, + lsp.ClientRectangle.Width - TopSplitContainer.SplitterDistance, + lsp.ClientRectangle.Height) + ); + } + } + else if (lsp.Panel2.ClientRectangle.Contains(lsp.Panel2.PointToClient_Fast(cp))) + { + if (!_inTabDragArea) + { + _inTabDragArea = true; + Trace.WriteLine("Hit open"); + using var gc = new Native.GraphicsContext(lsp.Panel2.Handle); + using var b = new SolidBrush(overlayColor); + gc.G.FillRectangle( + b, + lsp.Panel2.ClientRectangle with { X = 0, Y = 0 } + ); + } + } + else + { + if (_inTabDragArea) + { + _inTabDragArea = false; + Trace.WriteLine("Miss"); + lsp.Refresh(); + } + } + } + + #endregion + + private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) + { + if (!_inTabDragArea) return; + + try + { + EverythingPanel.SuspendDrawing(); + + TabPage? dragTab = TopFMTabControl.DragTab; + if (dragTab == null) return; + + if (!Lazy_LowerTabControl.Constructed) + { + LowerSplitContainer.Panel2Collapsed = false; + LowerSplitContainer.SplitterDistance = TopSplitContainer.SplitterDistance; + + Lazy_LowerTabControl.TabControl.SetBackingList(_backingFMTabs); + LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); + + if (Lazy_LowerTabControl.TabControl.SelectedTab is Lazy_TabsBase lazyTab) + { + lazyTab.ConstructWithSuspendResume(); + } + } + TopFMTabControl.ShowTab(dragTab, false); + Lazy_LowerTabControl.TabControl.ShowTab(dragTab, true); + + Lazy_LowerTabControl.TabControl.SelectedTab = dragTab; + } + finally + { + _inTabDragArea = false; + EverythingPanel.ResumeDrawing(); + } + } } diff --git a/AngelLoader/Forms/MainForm.resx b/AngelLoader/Forms/MainForm.resx index ec3224055..8e8cd7081 100644 --- a/AngelLoader/Forms/MainForm.resx +++ b/AngelLoader/Forms/MainForm.resx @@ -125,45 +125,45 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAK - EwAAAk1TRnQBSQFMAgEBBAEAAYgBGwGIARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + EwAAAk1TRnQBSQFMAgEBBAEAAZgBGwGYARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgADBQEGA0IBdANP AZkDVQGxA1sBygNWAbUDTAGRA0YBgAMcAScoAAMNAREDSgGLA1ABmgMeASsYAAMDAQQDVQGtA1gBvQNO AZYDYAHgA1ABnzQAAwIBAwMZASIDWgHHA1IBoANBAXMDQAFvAzQBUwMpAT0DHQEpAx4BKgMPARMDBQEG DAADIwEzA2AB6AMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/Az4BahgAAwwBEAMFAQYEAAMr AUECAAGXAf8DAAH/A0ABcAwAAwMEBAEFBAADBQEGAYYBiwEAAf8ByQHNAQAB/wGQAZYBAAH/AaoBugEA Af8DWgHHAy0BRgMZASIDKAE7AzkBXgNCAXQDPwFuAzkBXgMIAQoMAAQBAw8BFAMuAUgDVgGwA0AB/QNA - Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABTwFrAYAB/gMAAf8DWgHE + Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABUQFtAYAB/gMAAf8DWgHE ASMBXgEhAfsDAAH/AgABnAH/AwAB/wMAAf8DWwHkA0EB+QMAAf8DQwF3DAADCQEMA1ABnwNdAckDPQFo A0YBgQNdAc8BAAGVAcoB/wMAAf8DXgHXA0MBdgMzAVEDVgGwA0YBfgMTARkIAAMsAUMDYQHiAv8BAAH/ - A1wB2QF6AX8BSQH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA + A1wB2QF8AYABSwH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA ARABAAH/AwAB/wEKAQwBBwH/ASYBPQE6Af8BHwEyATAB/wEAARABAAH/AwAB/wEGASMBAAH/AQMBIgEA Af8DXgHwA0QBeQMIAQoEAANdAdEDAAH/A0sBjANdAcwDAAH/AwAB/wIAAZgB/wIAAZYB/wNAAf0DXAH4 A1EBpANRAfcDAAH/AyIBMQgAAx8BLAEAAY4BpwH/AgABmgH/AwAB/wEAAZQBvQH/AQABzgL/AQABsQHe Af8BAAGYAdIB/wEAAYUBygH/AwAB/wMrAfwBAAGnAcgB/wNZAe8DHgErDAADRgF9AbwBwQEAAf8DVQG0 - A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFaAW8BSQH+ + A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFcAXEBSwH+ ARIBSQEAAf8BDAE0AQAB/wEsAjUB/wEPARYBFwH/ARcCHwH/ARcBHQEeAf8BCgE2AQAB/wEKASQBAAH/ - AW8BgAFbAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 + AXEBgAFdAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 AwAB/wNGAYEDTgGXAwAB/wNWAbAMAANEAXsBAAGyAdgB/wEAAbcB9QH/AQAB0QH5Af8BAAGZAZ4B/wEA AbMBzwH/AQABjgGtAf8BAAGyAccB/wEAAdcC/wEAAesC/wEAAZ0BoQH/A08BmwMOARIMAANGAYABxQHJ - AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFH - AkYB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ + AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFJ + AkgB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ AwAB/wEVAQABAwH/A0AB/QNWAbUDGQEjA1gBvQMAAf8DXQHUAx4BKgNZAcMDAAH/A0AB/QIAAbwB/wMA Af8DAAH/AwAB/wMoATsDNQFWAwAB/wIhASMB+wMTARoIAANQAZ0BAAGtAesB/wEAAaEBygH/AwAB/wMA Af8BAAGUAbcB/wIAAYIB/wMAAf8BAAGZAZ8B/wEAAegC/wMAAf8DTAGOAwUBBgwAA0gBhAG6Ab8BAAH/ A10B3AFsAW0BUQH3AdgB6AEAAf8BtwG6AQAB/wHcAeEBAAH/AwAB/wNZAcMBwQHGAQAB/wNdAd8DGAEh CAADOARcAdYDKwH8AwAB/wEGAQoBDAH/AaEBpwGmAf8BhAGMAY0B/wErATcBPwH/AQ4BHQEmAf8BkgGY AZkB/wFQAVYBVwH/AwAB/wMAAf8DTQH6A0sBjAMPARQDXgHtAwAB/wMrAfwDRQF8Az0BaQNNAfoBKQIy - AfsDTQH6AVcBXAGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu + AfsDTQH6AVkBXgGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu Af8DAAH/AwAB/wMAAf8BAAGMAbgB/wMAAf8BggIAAf8DAAH/AQABuAHOAf8BAAGFAcQB/wNeAd0DOgFg AxUBHAgAA0cBgwGVAZsBAAH/AwAB/wHbAesBAAH/A1UBrwMQARUCUwFSAaUBwwHKAQAB/wNcAecBqAGw - AQAB/wNiAeEDGwElCAADSQGHAVYBVQFWAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ + AQAB/wNiAeEDGwElCAADSQGHAVgBVwFYAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ AUgBVwGBAf8BNgFKAVIB/wGrArIB/wGjAagBqQH/ARwBHwEjAf8BFQEJAQ4B/wNAAf0DWwHTAyoBPwNI - AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBXgGAAVIB/gNgAegDXgHXAzsBZQNKAYoCAAGI + AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBYAGAAVQB/gNgAegDXgHXAzsBZQNKAYoCAAGI Af8CAAGfAf8DPwFsA18B2gMAAf8BAAGyAeMB/wEAAY4BqQH/AwAB/wMAAf8DAAH/AQABkQHDAf8DAAH/ AwAB/wMAAf8DAAH/AQABsAHuAf8DAAH/AwAB/wNOAZYIAANHAYMBAAGGAQAB/wHXAdwBAAH/AwAB/wNQ AZ0DGwElA1UBrAHCAc4BAAH/A1wB2QGgAaoBAAH/A1oB6QMeASoIAANGAX0DTQH6AQ8BHgEAAf8BIgEx ARMB/wE1AU4BOQH/ASgBUgFGAf8BFAEkASYB/wFQAV0BhAH/ATUBRAFIAf8BGQEwASwB/wEjAT4BOQH/ - ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1kB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 + ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1sB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 A00B+gMrAfwBIQEyASEB+wNYAb0DKQE9A14B1wIAAZIB/wMAAf8DPgFqAgABhgH/AQABqAHSAf8BAAHS Av8CAAGEAf8DAAH/AwAB/wMAAf8BAAGKAcEB/wMAAf8DAAH/AwAB/wMAAf8BAAG8AfYB/wEAAaoB3gH/ AgABmQH/A1IBqAgAA0MBdgGHAZMBAAH/AmgBQQH5Ad4B4QEAAf8DAAH/AwAB/wHOAeABAAH/Al4BXAHZ @@ -177,30 +177,30 @@ ASgBLwExAf8BAQEHAQoB/wMAAf8BFwE5AQAB/wNNAfoDPgFrA1YBtgIAAZgB/wMAAf8CAAGIAf8DXgHd AzQBVANVAa4BlwGpAd0B/wJeAV8B+wNHAYMDUgGlAwAB/wMAAf8DAAH/A00B+gMPARQEAAQBAV0CZQHs AQABoQHmAf8DAAH/AYICAAH/AwAB/wEAAYwBuAH/AwAB/wMAAf8DAAH/AgABvQH/AQABlgHAAf8DVgGy - AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABZQH+ - AdEB1wEAAf8CgAFiAf4CgAFMAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ - AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BTgFLAUwB/gNZAcMDIQEv + AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABZwH+ + AdEB1wEAAf8CgAFkAf4CgAFOAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ + AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BUAFNAU4B/gNZAcMDIQEv AzABSgMAAf8DAAH/AgABnwH/AQABgQG2Af8DAAH/A2AB8wMAAf8DXAH4A00B+gEAAYQBsgH/AwAB/wMA Af8DAAH/A1MBpgwAA0IBdQEAAeMC/wEAAZQBzAH/AwAB/wMAAf8BAAGAAbEB/wMAAf8DAAH/AgABjgH/ AQABuQH7Af8DAAH/A0wBjgMSARcEAAMlATcDAAH/AdsB3AGOAf8B+AH7AZ0B/wGlAagBAAH/Al8BMgH7 AZcBmgEAAf8DWgH1AZABkgEAAf8BpAGnAQAB/wJiAVkB7wHtAfIBjgH/AckBzQEAAf8BoAGlAQAB/wNb AdgDFAEbAxUBHANiAeEDAAH/AR8BDwEVAf8BJAEiAScB/wE/AVwBOgH/AbgBywG4Af8B2ALdAf8B3QLg - Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AWMBWQFcAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ + Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AWUBWwFeAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ AwAB/wIAAYUB/wIAAaoB/wMAAf8BAAGAAZsB/wEAAY4BuAH/AwAB/wMAAf8CAAG0Af8DTQH6AxMBGQgA AxgBIQFbAl0BygEAAeUB+gH/AQAD/wEAAcQB9wH/AgABlAH/AQABjQG6Af8CAAGXAf8CAAHCAf8BAAHR Av8BAAHKAe4B/wIAAYcB/wNbAeQDIQEvCAADAgEDA00BkwG8AcYBAAH/A1YBsANeAeIDAAH/A2UB8QMA Af8DOQFeA1IBoAL/AQAB/wMAAf8DWgG/AxYBHgQAAy0BRQNIAfYBGQEFAQoB/wEYAQ4BEwH/ARQBDAEO Af8BLgFVARoB/wFdAZwBVgH/AY0BjAGOAf8BqAGvAbAB/wFVAaMBQgH/ATABRwEUAf8DAAH/AQMCAAH/ - AVUBUgFTAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA + AVcBVAFVAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA Af8CAAGkAf8CAAGGAf8DLQFFDAADIAEtAQABlQGsAf8BAAGAAZIB/wNRAaEDXQHqAQAB4gH4Af8BAAHe AfMB/wEAAcoB8wH/AQABpgHIAf8DWQG7A1kBuwEAAa8B0AH/A1cBvAMLAQ4MAAMmATkDXQHMAyUBNwNT AakDUgGgA1UBrANVAa8DQwF2A4AB/gG0AbgBAAH/AbsBxwEAAf8DZQHxAzIBTwQAA0IBdANcAcsDKwH8 AysB/AEdAUQBBgH/AS8BNwEYAf8BNwFCASIB/wEoARsBIQH/ASwBKQErAf8BNAGBARMB/wEmAUIBDgH/ - AR4BNAEDAf8BAQIAAf8BVgFMAVAB/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ + AR4BNAEDAf8BAQIAAf8BWAFOAVIB/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wIAAZEB/wJeAWEB4gMtAUUUAAMmATgDMwFRBAADDAEPA0QBewEAAewC/wEAAYIBlAH/A0oBiQME AQUDAwEEAzQBVAMNAREsAANdAdEByQHSAQAB/wNLAY8CbQFRAfcBmwGoAQAB/wM+AWoEAAMDAQQDDAEP - AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFnAWABYgH+ - AXwBgAFYAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ + AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFpAWIBZAH+ + AX4BgAFaAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ ARUDZQHxA2AB4EAAA0QBeQNSAaUEAANGAYEDWQHBAw8BFAQAAwQBBQQABAEDOAFcA0IBdANGAX4DUwGq A1UBrQNYAboDWgHEA1EBogNUAasDQAFvAwwBDwQBBAABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEA AQEGAAEBFgAD/4EAAeABDwH8AT8BAwH/AeABAQHAAQcB5AE5AQABAwGAAQABgAEDAYABAQGAAQMBgAEA diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index 684c402ea..8d3ba2e89 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -558,6 +558,8 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir TopFMTabControl.EnableScrollButtonsRefreshHack = true; TopFMTabControl.Size = new Size(535, 310); TopFMTabControl.TabIndex = 15; + TopFMTabControl.MouseMoveCustom += TopFMTabControl_MouseMoveCustom; + TopFMTabControl.MouseUp += TopFMTabControl_MouseUp; // // LowerSplitContainer // From 2e642b92837bd63c31fc0b5d11c265a2b23955e6 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 12:05:55 -0800 Subject: [PATCH 109/200] Note --- .../Forms/CustomControls/DarkSplitContainerCustom.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs index 76562482c..0048788f5 100644 --- a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs +++ b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs @@ -1,4 +1,8 @@ -using System; +/* +@DockUI: Figure out how we want to allow moving of the new cross-section which can now be 4-way (3 splitters) +*/ + +using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Drawing; From 20a15b60ddb2f962862444ef8a0c753ab997c97a Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 13:05:53 -0800 Subject: [PATCH 110/200] Implement tab dragging bottom-to-top --- .../Forms/CustomControls/DarkTabControl.cs | 9 +- .../LazyLoaded/Lazy_LowerTabControl.cs | 2 + AngelLoader/Forms/MainForm.cs | 106 ++++++++++++++++-- 3 files changed, 109 insertions(+), 8 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index b38ec1ce7..127ad17b6 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -334,12 +334,19 @@ protected override void OnMouseMove(MouseEventArgs e) } // Run the base event handler if we're not actually dragging a tab - if (e.Button != MouseButtons.Left || DragTab == null || TabCount <= 1) + if (e.Button != MouseButtons.Left || DragTab == null) { base.OnMouseMove(e); return; } + if (TabCount <= 1) + { + MouseMoveCustom?.Invoke(this, e); + base.OnMouseMove(e); + return; + } + // If we are dragging a tab, don't run the normal handler, because we want to be "modal" and block s // nothing weird happens MouseMoveCustom?.Invoke(this, e); diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 100b6ce90..15bf45427 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -59,6 +59,8 @@ private void Construct() _owner.LowerSplitContainer.Panel2.MouseClick += _owner.LowerFMTabsBar_MouseClick; _tabControl.Selected += _owner.FMTabControl_Selected; + _tabControl.MouseMoveCustom += _owner.Lazy_LowerTabControl_MouseMoveCustom; + _tabControl.MouseUp += _owner.Lazy_LowerTabControl_MouseUp; Constructed = true; } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 12b7d23fb..25813013c 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5438,18 +5438,22 @@ public void RefreshCurrentFMScreenshots() private bool _inTabDragArea; - private void TopFMTabControl_MouseMoveCustom(object sender, MouseEventArgs e) + private static Color GetOverlayColor() { - DarkSplitContainerCustom lsp = LowerSplitContainer; - - Point cp = Native.GetCursorPosition_Fast(); - // @DockUI: Make light and dark mode colors - Color overlayColor = Color.FromArgb( + return Color.FromArgb( alpha: 64, red: DarkColors.BlueSelection.R, green: DarkColors.BlueSelection.G, blue: DarkColors.BlueSelection.B); + } + + private void TopFMTabControl_MouseMoveCustom(object sender, MouseEventArgs e) + { + Point cp = Native.GetCursorPosition_Fast(); + Color overlayColor = GetOverlayColor(); + + DarkSplitContainerCustom lsp = LowerSplitContainer; if (lsp.Panel2Collapsed && lsp.ClientRectangle.Contains(lsp.PointToClient_Fast(cp))) { @@ -5494,7 +5498,6 @@ private void TopFMTabControl_MouseMoveCustom(object sender, MouseEventArgs e) } } - #endregion private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) { @@ -5531,4 +5534,93 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) EverythingPanel.ResumeDrawing(); } } + + internal void Lazy_LowerTabControl_MouseMoveCustom(object sender, MouseEventArgs e) + { + Point cp = Native.GetCursorPosition_Fast(); + Color overlayColor = GetOverlayColor(); + + DarkSplitContainerCustom tsp = TopSplitContainer; + DarkSplitContainerCustom lsp = LowerSplitContainer; + + if ((tsp.Panel2Collapsed || tsp.FullScreen) && tsp.ClientRectangle.Contains(tsp.PointToClient_Fast(cp))) + { + if (!_inTabDragArea) + { + _inTabDragArea = true; + Trace.WriteLine("Hit closed"); + using var gc = new Native.GraphicsContext(tsp.Handle); + using var b = new SolidBrush(overlayColor); + gc.G.FillRectangle( + b, + new Rectangle( + lsp.SplitterDistance, + 0, + tsp.ClientRectangle.Width - lsp.SplitterDistance, + tsp.ClientRectangle.Height) + ); + } + } + else if (tsp.Panel2.ClientRectangle.Contains(tsp.Panel2.PointToClient_Fast(cp))) + { + if (!_inTabDragArea) + { + _inTabDragArea = true; + Trace.WriteLine("Hit open"); + using var gc = new Native.GraphicsContext(tsp.Panel2.Handle); + using var b = new SolidBrush(overlayColor); + gc.G.FillRectangle( + b, + tsp.Panel2.ClientRectangle with { X = 0, Y = 0 } + ); + } + } + else + { + if (_inTabDragArea) + { + _inTabDragArea = false; + Trace.WriteLine("Miss"); + tsp.Refresh(); + } + } + } + + internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) + { + if (!_inTabDragArea) return; + + try + { + EverythingPanel.SuspendDrawing(); + + TabPage? dragTab = Lazy_LowerTabControl.TabControl.DragTab; + if (dragTab == null) return; + + if (false) + { + LowerSplitContainer.Panel2Collapsed = false; + LowerSplitContainer.SplitterDistance = TopSplitContainer.SplitterDistance; + + TopFMTabControl.SetBackingList(_backingFMTabs); + LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); + + if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab) + { + lazyTab.ConstructWithSuspendResume(); + } + } + Lazy_LowerTabControl.TabControl.ShowTab(dragTab, false); + TopFMTabControl.ShowTab(dragTab, true); + + TopFMTabControl.SelectedTab = dragTab; + } + finally + { + _inTabDragArea = false; + EverythingPanel.ResumeDrawing(); + } + } + + #endregion } From 755a505c7b80b411644c9f4fdbaab77c4a01c11c Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 13:21:46 -0800 Subject: [PATCH 111/200] Auto collapse/expand panels if they have 0 or >0 pages --- AngelLoader/Forms/MainForm.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 25813013c..a17fef1d1 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5510,9 +5510,10 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) TabPage? dragTab = TopFMTabControl.DragTab; if (dragTab == null) return; + LowerSplitContainer.Panel2Collapsed = false; + if (!Lazy_LowerTabControl.Constructed) { - LowerSplitContainer.Panel2Collapsed = false; LowerSplitContainer.SplitterDistance = TopSplitContainer.SplitterDistance; Lazy_LowerTabControl.TabControl.SetBackingList(_backingFMTabs); @@ -5525,6 +5526,10 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) } TopFMTabControl.ShowTab(dragTab, false); Lazy_LowerTabControl.TabControl.ShowTab(dragTab, true); + if (TopFMTabControl.TabCount == 0) + { + TopSplitContainer.Panel2Collapsed = true; + } Lazy_LowerTabControl.TabControl.SelectedTab = dragTab; } @@ -5597,14 +5602,9 @@ internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) TabPage? dragTab = Lazy_LowerTabControl.TabControl.DragTab; if (dragTab == null) return; - if (false) + if (TopSplitContainer.Panel2Collapsed) { - LowerSplitContainer.Panel2Collapsed = false; - LowerSplitContainer.SplitterDistance = TopSplitContainer.SplitterDistance; - - TopFMTabControl.SetBackingList(_backingFMTabs); - LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); - + TopSplitContainer.Panel2Collapsed = false; if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab) { lazyTab.ConstructWithSuspendResume(); @@ -5612,6 +5612,10 @@ internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) } Lazy_LowerTabControl.TabControl.ShowTab(dragTab, false); TopFMTabControl.ShowTab(dragTab, true); + if (Lazy_LowerTabControl.TabControl.TabCount == 0) + { + LowerSplitContainer.Panel2Collapsed = true; + } TopFMTabControl.SelectedTab = dragTab; } From 76d964897ce499854a02c2ee8e247158a3f4fdeb Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 14:43:06 -0800 Subject: [PATCH 112/200] Save/restore lower splitter distance --- AngelLoader/Common/DataClasses/ConfigData.cs | 3 +++ AngelLoader/Common/Misc.cs | 1 + AngelLoader/Core.cs | 2 ++ AngelLoader/Forms/MainForm.cs | 7 +++++-- AngelLoader/Ini/ConfigIni.cs | 13 +++++++++++++ 5 files changed, 24 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Common/DataClasses/ConfigData.cs b/AngelLoader/Common/DataClasses/ConfigData.cs index fa5bad049..21ad4277a 100644 --- a/AngelLoader/Common/DataClasses/ConfigData.cs +++ b/AngelLoader/Common/DataClasses/ConfigData.cs @@ -344,6 +344,9 @@ internal float FMsListFontSizeInPoints private float _topSplitterPercent = Defaults.TopSplitterPercent; internal float TopSplitterPercent { get => _topSplitterPercent; set => _topSplitterPercent = value.ClampZeroToOne(); } + private float _lowerSplitterPercent = Defaults.LowerSplitterPercent; + internal float LowerSplitterPercent { get => _lowerSplitterPercent; set => _lowerSplitterPercent = value.ClampZeroToOne(); } + internal bool TopRightPanelCollapsed; internal readonly FMTabsData FMTabsData = new(); diff --git a/AngelLoader/Common/Misc.cs b/AngelLoader/Common/Misc.cs index 4231747a9..3fa2da30b 100644 --- a/AngelLoader/Common/Misc.cs +++ b/AngelLoader/Common/Misc.cs @@ -160,6 +160,7 @@ internal static class Defaults internal const float TopSplitterPercent = 0.741f; internal const float MainSplitterPercent = 0.4425f; + internal const float LowerSplitterPercent = 0.741f; // @NET5: Remember to change this to match the new font internal const float FMsListFontSizeInPoints = 8.25f; diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index 607808496..5c1b090a0 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2601,6 +2601,7 @@ internal static void UpdateConfig( Point mainWindowLocation, float mainSplitterPercent, float topSplitterPercent, + float lowerSplitterPercent, ColumnData[] columns, Column sortedColumn, SortDirection sortDirection, @@ -2622,6 +2623,7 @@ internal static void UpdateConfig( Config.MainWindowLocation = mainWindowLocation; Config.MainSplitterPercent = mainSplitterPercent; Config.TopSplitterPercent = topSplitterPercent; + Config.LowerSplitterPercent = lowerSplitterPercent; #endregion diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index a17fef1d1..a2011fd93 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -932,6 +932,9 @@ and does NOT have its text transferred over. It ends up with blank text. MainSplitContainer.SetSplitterPercent(Config.MainSplitterPercent, setIfFullScreen: true, suspendResume: false); TopSplitContainer.SetSplitterPercent(Config.TopSplitterPercent, setIfFullScreen: false, suspendResume: false); + LowerSplitContainer.SetSplitterPercent(Config.LowerSplitterPercent, setIfFullScreen: false, suspendResume: false); + // @DockUI: We need to save/restore which tab control each tab is in (or none for invisible in both) + LowerSplitContainer.Panel2Collapsed = true; MainSplitContainer.SetSibling(TopSplitContainer); MainSplitContainer.Panel1DarkBackColor = DarkColors.Fen_ControlBackground; @@ -5051,6 +5054,7 @@ public void UpdateConfig() float mainSplitterPercent = MainSplitContainer.SplitterPercentReal; float topSplitterPercent = TopSplitContainer.SplitterPercentReal; + float lowerSplitterPercent = LowerSplitContainer.SplitterPercentReal; if (minimized) WindowState = nominalState; @@ -5062,6 +5066,7 @@ public void UpdateConfig() _nominalWindowLocation, mainSplitterPercent, topSplitterPercent, + lowerSplitterPercent, FMsDGV.GetColumnData(), FMsDGV.CurrentSortedColumn, FMsDGV.CurrentSortDirection, @@ -5514,8 +5519,6 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) if (!Lazy_LowerTabControl.Constructed) { - LowerSplitContainer.SplitterDistance = TopSplitContainer.SplitterDistance; - Lazy_LowerTabControl.TabControl.SetBackingList(_backingFMTabs); LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); diff --git a/AngelLoader/Ini/ConfigIni.cs b/AngelLoader/Ini/ConfigIni.cs index aba2bdfe5..3b5ea3244 100644 --- a/AngelLoader/Ini/ConfigIni.cs +++ b/AngelLoader/Ini/ConfigIni.cs @@ -663,6 +663,7 @@ private static void Config_MainSplitterPercent_Set(ConfigData config, string val config.MainSplitterPercent = result; } } + private static void Config_TopSplitterPercent_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { if (Float_TryParseInv(valTrimmed, out float result)) @@ -670,10 +671,20 @@ private static void Config_TopSplitterPercent_Set(ConfigData config, string valT config.TopSplitterPercent = result; } } + + private static void Config_LowerSplitterPercent_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) + { + if (Float_TryParseInv(valTrimmed, out float result)) + { + config.LowerSplitterPercent = result; + } + } + private static void Config_TopRightPanelCollapsed_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { config.TopRightPanelCollapsed = valTrimmed.EqualsTrue(); } + private static void Config_GameTab_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { FieldInfo? field = typeof(GameIndex).GetField(valTrimmed, _bFlagsEnum); @@ -981,6 +992,7 @@ private static unsafe Dictionary { "MainSplitterPercent", new Config_DelegatePointerWrapper(&Config_MainSplitterPercent_Set) }, { "TopSplitterPercent", new Config_DelegatePointerWrapper(&Config_TopSplitterPercent_Set) }, + { "LowerSplitterPercent", new Config_DelegatePointerWrapper(&Config_LowerSplitterPercent_Set) }, { "TopRightPanelCollapsed", new Config_DelegatePointerWrapper(&Config_TopRightPanelCollapsed_Set) }, { "GameTab", new Config_DelegatePointerWrapper(&Config_GameTab_Set) }, @@ -1385,6 +1397,7 @@ private static void WriteConfigIniInternal(ConfigData config, string fileName) sw.Append("MainSplitterPercent").Append('=').AppendLine(config.MainSplitterPercent.ToString(NumberFormatInfo.InvariantInfo)); sw.Append("TopSplitterPercent").Append('=').AppendLine(config.TopSplitterPercent.ToString(NumberFormatInfo.InvariantInfo)); + sw.Append("LowerSplitterPercent").Append('=').AppendLine(config.LowerSplitterPercent.ToString(NumberFormatInfo.InvariantInfo)); sw.Append("TopRightPanelCollapsed").Append('=').Append(config.TopRightPanelCollapsed).AppendLine(); sw.Append("GameTab").Append('=').Append(config.GameTab).AppendLine(); From 1cbcc07689a2c6752defc41dd31db21b7b698c4a Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 14:49:00 -0800 Subject: [PATCH 113/200] Reset lower splitter on reset layout --- AngelLoader/Forms/MainForm.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index a2011fd93..0322278d4 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -3010,6 +3010,7 @@ private void ResetLayoutButton_Click(object sender, EventArgs e) { MainSplitContainer.SetSplitterPercent(Defaults.MainSplitterPercent, setIfFullScreen: true); TopSplitContainer.SetSplitterPercent(Defaults.TopSplitterPercent, setIfFullScreen: false); + LowerSplitContainer.SetSplitterPercent(Defaults.LowerSplitterPercent, setIfFullScreen: false); if (FilterBarScrollRightButton.Visible) SetFilterBarScrollButtons(); } From 87676fd30efe21b9ae407b22a0728d59bf2977c3 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 15:33:03 -0800 Subject: [PATCH 114/200] Save/restore which tab control a given tab is in --- .../DataClasses/ConfigDataSupporting.cs | 24 ++++++++---- .../Forms/CustomControls/DarkTabControl.cs | 12 ++++-- .../LazyLoaded/Lazy_LowerTabControl.cs | 9 +++++ AngelLoader/Forms/MainForm.cs | 39 ++++++++++--------- AngelLoader/Ini/ConfigIni.cs | 34 ++++++++++++---- 5 files changed, 81 insertions(+), 37 deletions(-) diff --git a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs index b7c6ae349..54a54fa9a 100644 --- a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs +++ b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs @@ -110,12 +110,19 @@ internal enum FMTab Screenshots } +public enum FMTabVisibleIn +{ + None, + Top, + Bottom +} + internal sealed class FMTabData { private int _displayIndex; internal int DisplayIndex { get => _displayIndex; set => _displayIndex = value.Clamp(0, FMTabCount - 1); } - internal bool Visible = true; + internal FMTabVisibleIn Visible = FMTabVisibleIn.Top; } internal sealed class FMTabsData @@ -129,6 +136,7 @@ internal sealed class FMTabsData internal FMTabData GetTab(FMTab tab) => Tabs[(int)tab]; + // @DockUI: Test to make sure this works in all cases with the new tab code! internal void EnsureValidity() { #region Fallback if multiple tabs have the same display index @@ -145,25 +153,25 @@ internal void EnsureValidity() #endregion - if (NoneVisible()) SetAllVisible(true); + if (NoneVisible()) SetAllVisible(FMTabVisibleIn.Top); // Fallback if selected tab is not marked as visible - if (!GetTab(SelectedTab).Visible) + if (GetTab(SelectedTab).Visible == FMTabVisibleIn.None) { for (int i = 0; i < FMTabCount; i++) { - if (Tabs[i].Visible) + if (Tabs[i].Visible == FMTabVisibleIn.Top) { SelectedTab = (FMTab)i; break; } } } - if (!GetTab(SelectedTab2).Visible) + if (GetTab(SelectedTab2).Visible == FMTabVisibleIn.None) { for (int i = 0; i < FMTabCount; i++) { - if (Tabs[i].Visible) + if (Tabs[i].Visible == FMTabVisibleIn.Bottom) { SelectedTab2 = (FMTab)i; break; @@ -174,11 +182,11 @@ internal void EnsureValidity() private bool NoneVisible() { - for (int i = 0; i < FMTabCount; i++) if (Tabs[i].Visible) return false; + for (int i = 0; i < FMTabCount; i++) if (Tabs[i].Visible != FMTabVisibleIn.None) return false; return true; } - private void SetAllVisible(bool visible) + private void SetAllVisible(FMTabVisibleIn visible) { for (int i = 0; i < FMTabCount; i++) Tabs[i].Visible = visible; } diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 127ad17b6..7d0d8b4c7 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -36,7 +36,7 @@ all other tab controls will have to carry it and ignore it... internal sealed class BackingTab { internal TabPage TabPage; - internal bool Visible = true; + internal FMTabVisibleIn Visible = FMTabVisibleIn.Top; internal BackingTab(TabPage tabPage) => TabPage = tabPage; } @@ -51,6 +51,9 @@ internal sealed class BackingTab /// internal void SetBackingList(List list) => _backingTabList = list; + private bool _isTop; + internal void SetIsTop(bool value) => _isTop = value; + #endregion private bool _darkModeEnabled; @@ -125,7 +128,8 @@ internal static (int Index, BackingTab BackingTab) for (int i = 0, vi = 0; i < backingTabs.Count; i++) { BackingTab backingTab = backingTabs[i]; - if (indexVisibleOnly && backingTab.Visible) vi++; + // @DockUI: Could we make this our specific top/bottom value and get better ordering between moves? + if (indexVisibleOnly && backingTab.Visible != FMTabVisibleIn.None) vi++; if (backingTab.TabPage == tabPage) return (indexVisibleOnly ? vi : i, backingTab); } @@ -454,12 +458,12 @@ public void ShowTab(TabPage tabPage, bool show) if (show) { - bt.Visible = true; + bt.Visible = _isTop ? FMTabVisibleIn.Top : FMTabVisibleIn.Bottom; if (!TabPages.Contains(bt.TabPage)) TabPages.Insert(Math.Min(index, TabCount), bt.TabPage); } else { - bt.Visible = false; + bt.Visible = FMTabVisibleIn.None; if (TabPages.Contains(bt.TabPage)) { TabPages.Remove(bt.TabPage); diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 15bf45427..9ef4fcf2c 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -61,7 +61,16 @@ private void Construct() _tabControl.Selected += _owner.FMTabControl_Selected; _tabControl.MouseMoveCustom += _owner.Lazy_LowerTabControl_MouseMoveCustom; _tabControl.MouseUp += _owner.Lazy_LowerTabControl_MouseUp; + _tabControl.VisibleChanged += TabControl_VisibleChanged; Constructed = true; } + + private void TabControl_VisibleChanged(object sender, System.EventArgs e) + { + if (_tabControl is { Visible: true, SelectedTab: Lazy_TabsBase lazyTab }) + { + lazyTab.ConstructWithSuspendResume(); + } + } } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 0322278d4..552c92838 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -643,6 +643,7 @@ and does NOT have its text transferred over. It ends up with blank text. #endif TopFMTabControl.SetBackingList(_backingFMTabs); + TopFMTabControl.SetIsTop(true); ChangeReadmeBoxFont(Config.ReadmeUseFixedWidthFont); @@ -906,13 +907,18 @@ and does NOT have its text transferred over. It ends up with blank text. for (int i = 0; i < FMTabCount; i++) { - bool visible = Config.FMTabsData.Tabs[i].Visible; + FMTabVisibleIn visible = Config.FMTabsData.Tabs[i].Visible; // They're visible by default - shave off a bit of time - if (!visible) + if (visible != FMTabVisibleIn.Top) { TopFMTabControl.ShowTab(_fmTabs[i], false); } - Lazy_FMTabsMenu.SetItemChecked(i, visible); + if (visible == FMTabVisibleIn.Bottom) + { + ConstructLazyLowerTabControl(); + Lazy_LowerTabControl.TabControl.ShowTab(_fmTabs[i], true); + } + Lazy_FMTabsMenu.SetItemChecked(i, visible != FMTabVisibleIn.None); } // EnsureValidity() guarantees selected tab will not be invisible @@ -933,8 +939,6 @@ and does NOT have its text transferred over. It ends up with blank text. MainSplitContainer.SetSplitterPercent(Config.MainSplitterPercent, setIfFullScreen: true, suspendResume: false); TopSplitContainer.SetSplitterPercent(Config.TopSplitterPercent, setIfFullScreen: false, suspendResume: false); LowerSplitContainer.SetSplitterPercent(Config.LowerSplitterPercent, setIfFullScreen: false, suspendResume: false); - // @DockUI: We need to save/restore which tab control each tab is in (or none for invisible in both) - LowerSplitContainer.Panel2Collapsed = true; MainSplitContainer.SetSibling(TopSplitContainer); MainSplitContainer.Panel1DarkBackColor = DarkColors.Fen_ControlBackground; @@ -5039,7 +5043,7 @@ public void UpdateConfig() { Lazy_TabsBase fmTab = _fmTabs[i]; fmTabs.Tabs[i].DisplayIndex = DarkTabControl.FindBackingTab(_backingFMTabs, fmTab).Index; - fmTabs.Tabs[i].Visible = _backingFMTabs.Any(x => x.TabPage == fmTab && x.Visible); + fmTabs.Tabs[i].Visible = _backingFMTabs.FirstOrDefault(x => x.TabPage == fmTab)?.Visible ?? FMTabVisibleIn.Top; } #region Quick hack to prevent splitter distances from freaking out if we're closing while minimized @@ -5516,18 +5520,7 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) TabPage? dragTab = TopFMTabControl.DragTab; if (dragTab == null) return; - LowerSplitContainer.Panel2Collapsed = false; - - if (!Lazy_LowerTabControl.Constructed) - { - Lazy_LowerTabControl.TabControl.SetBackingList(_backingFMTabs); - LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); - - if (Lazy_LowerTabControl.TabControl.SelectedTab is Lazy_TabsBase lazyTab) - { - lazyTab.ConstructWithSuspendResume(); - } - } + ConstructLazyLowerTabControl(); TopFMTabControl.ShowTab(dragTab, false); Lazy_LowerTabControl.TabControl.ShowTab(dragTab, true); if (TopFMTabControl.TabCount == 0) @@ -5544,6 +5537,16 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) } } + private void ConstructLazyLowerTabControl() + { + if (!Lazy_LowerTabControl.Constructed) + { + LowerSplitContainer.Panel2Collapsed = false; + Lazy_LowerTabControl.TabControl.SetBackingList(_backingFMTabs); + LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); + } + } + internal void Lazy_LowerTabControl_MouseMoveCustom(object sender, MouseEventArgs e) { Point cp = Native.GetCursorPosition_Fast(); diff --git a/AngelLoader/Ini/ConfigIni.cs b/AngelLoader/Ini/ConfigIni.cs index 3b5ea3244..c03c29a7f 100644 --- a/AngelLoader/Ini/ConfigIni.cs +++ b/AngelLoader/Ini/ConfigIni.cs @@ -714,6 +714,26 @@ private static void Config_FMTab2_Set(ConfigData config, string valTrimmed, stri } } + private static void SetFMTabVisibility(ConfigData config, FMTab fmTab, string valTrimmed) + { + // Backward compatibility - match old behavior exactly + if (valTrimmed.EqualsTrue()) + { + config.FMTabsData.GetTab(fmTab).Visible = FMTabVisibleIn.Top; + } + else if (valTrimmed.EqualsFalse()) + { + config.FMTabsData.GetTab(fmTab).Visible = FMTabVisibleIn.None; + } + else + { + FieldInfo? field = typeof(FMTabVisibleIn).GetField(valTrimmed, _bFlagsEnum); + config.FMTabsData.GetTab(fmTab).Visible = field != null + ? (FMTabVisibleIn)field.GetValue(null) + : FMTabVisibleIn.None; + } + } + private static void Config_StatsTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { Int_TryParseInv(valTrimmed, out int result); @@ -721,7 +741,7 @@ private static void Config_StatsTabPosition_Set(ConfigData config, string valTri } private static void Config_StatsTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.FMTabsData.GetTab(FMTab.Statistics).Visible = valTrimmed.EqualsTrue(); + SetFMTabVisibility(config, FMTab.Statistics, valTrimmed); } private static void Config_EditFMTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) @@ -731,7 +751,7 @@ private static void Config_EditFMTabPosition_Set(ConfigData config, string valTr } private static void Config_EditFMTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.FMTabsData.GetTab(FMTab.EditFM).Visible = valTrimmed.EqualsTrue(); + SetFMTabVisibility(config, FMTab.EditFM, valTrimmed); } private static void Config_CommentTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) @@ -741,7 +761,7 @@ private static void Config_CommentTabPosition_Set(ConfigData config, string valT } private static void Config_CommentTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.FMTabsData.GetTab(FMTab.Comment).Visible = valTrimmed.EqualsTrue(); + SetFMTabVisibility(config, FMTab.Comment, valTrimmed); } private static void Config_TagsTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) @@ -751,7 +771,7 @@ private static void Config_TagsTabPosition_Set(ConfigData config, string valTrim } private static void Config_TagsTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.FMTabsData.GetTab(FMTab.Tags).Visible = valTrimmed.EqualsTrue(); + SetFMTabVisibility(config, FMTab.Tags, valTrimmed); } private static void Config_PatchTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) @@ -761,7 +781,7 @@ private static void Config_PatchTabPosition_Set(ConfigData config, string valTri } private static void Config_PatchTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.FMTabsData.GetTab(FMTab.Patch).Visible = valTrimmed.EqualsTrue(); + SetFMTabVisibility(config, FMTab.Patch, valTrimmed); } private static void Config_ModsTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) @@ -771,7 +791,7 @@ private static void Config_ModsTabPosition_Set(ConfigData config, string valTrim } private static void Config_ModsTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.FMTabsData.GetTab(FMTab.Mods).Visible = valTrimmed.EqualsTrue(); + SetFMTabVisibility(config, FMTab.Mods, valTrimmed); } private static void Config_ScreenshotsTabPosition_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) @@ -781,7 +801,7 @@ private static void Config_ScreenshotsTabPosition_Set(ConfigData config, string } private static void Config_ScreenshotsTabVisible_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.FMTabsData.GetTab(FMTab.Screenshots).Visible = valTrimmed.EqualsTrue(); + SetFMTabVisibility(config, FMTab.Screenshots, valTrimmed); } #endregion From 8d2a8a4c67168c6bfe3cb0a42c64b61ee0f4bc41 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 16:59:49 -0800 Subject: [PATCH 115/200] Try a different style of logic for FM tab menu --- .../LazyLoaded/Lazy_FMTabsMenu.cs | 16 +++++++++++++++- AngelLoader/Forms/MainForm.cs | 18 +++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs index 6148e334b..055538c3d 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsMenu.cs @@ -12,6 +12,7 @@ internal sealed class Lazy_FMTabsMenu : IDarkable { private bool _constructed; private readonly bool[] _checkedStates = InitializedArray(FMTabCount, true); + private readonly bool[] _visibleStates = InitializedArray(FMTabCount, true); private readonly MainForm _owner; @@ -32,7 +33,8 @@ internal DarkContextMenu Menu var item = new ToolStripMenuItemCustom { CheckOnClick = true, - Checked = _checkedStates[i] + Checked = _checkedStates[i], + Visible = _visibleStates[i] }; item.Click += _owner.FMTabsMenu_MenuItems_Click; menuItems[i] = item; @@ -118,6 +120,18 @@ internal void SetItemChecked(int index, bool value) } } + internal void SetItemVisible(int index, bool value) + { + if (_constructed) + { + ((ToolStripMenuItemCustom)_menu.Items[index]).Visible = value; + } + else + { + _visibleStates[index] = value; + } + } + internal void Localize() { if (!_constructed) return; diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 552c92838..4d6636c59 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -3281,14 +3281,26 @@ private void TopFMTabsMenuButton_Click(object sender, EventArgs e) internal void FMTabsMenu_Opening(object sender, CancelEventArgs e) { - DarkTabControl tabControl = Lazy_FMTabsMenu.Menu.Data is WhichTabControl.Bottom - ? Lazy_LowerTabControl.TabControl - : TopFMTabControl; + (FMTabVisibleIn which, DarkTabControl tabControl) = Lazy_FMTabsMenu.Menu.Data is WhichTabControl.Bottom + ? (FMTabVisibleIn.Bottom, Lazy_LowerTabControl.TabControl) + : (FMTabVisibleIn.Top, TopFMTabControl); for (int i = 0; i < _fmTabs.Length; i++) { Lazy_TabsBase item = _fmTabs[i]; Lazy_FMTabsMenu.SetItemChecked(i, tabControl.TabPages.Contains(item)); + /* + @DockUI(FM per-tab show/hide menu logic) + I'm not sure which style is the best/most intuitive/principle-of-least-surprise etc. + They're all a little weird. Decide on something for the final release. + */ +#if true + DarkTabControl.BackingTab? backingTab = _backingFMTabs.FirstOrDefault(x => x.TabPage == item); + if (backingTab != null) + { + Lazy_FMTabsMenu.SetItemVisible(i, backingTab.Visible == FMTabVisibleIn.None || backingTab.Visible == which); + } +#endif } } From 80d9cae969408b08a8711d4202a449a44e943c38 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 17:06:36 -0800 Subject: [PATCH 116/200] Cleanup and more notes --- AngelLoader/Forms/CustomControls/DarkTabControl.cs | 6 +++--- .../CustomControls/LazyLoaded/Lazy_LowerTabControl.cs | 2 ++ AngelLoader/Forms/MainForm.cs | 9 ++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 7d0d8b4c7..862b341a9 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -51,8 +51,8 @@ internal sealed class BackingTab /// internal void SetBackingList(List list) => _backingTabList = list; - private bool _isTop; - internal void SetIsTop(bool value) => _isTop = value; + private WhichTabControl _whichTabControl; + internal void SetWhich(WhichTabControl value) => _whichTabControl = value; #endregion @@ -458,7 +458,7 @@ public void ShowTab(TabPage tabPage, bool show) if (show) { - bt.Visible = _isTop ? FMTabVisibleIn.Top : FMTabVisibleIn.Bottom; + bt.Visible = _whichTabControl == WhichTabControl.Bottom ? FMTabVisibleIn.Bottom : FMTabVisibleIn.Top; if (!TabPages.Contains(bt.TabPage)) TabPages.Insert(Math.Min(index, TabCount), bt.TabPage); } else diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 9ef4fcf2c..4b95dd0dc 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -51,6 +51,8 @@ private void Construct() Size = container.Size, }; + _tabControl.SetWhich(WhichTabControl.Bottom); + // Handle hack here instead, because it needs to be for whatever finicky goddamn reason _ = _tabControl.Handle; _tabControl.DarkModeEnabled = _darkModeEnabled; diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 4d6636c59..0fa071a8a 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -643,7 +643,7 @@ and does NOT have its text transferred over. It ends up with blank text. #endif TopFMTabControl.SetBackingList(_backingFMTabs); - TopFMTabControl.SetIsTop(true); + TopFMTabControl.SetWhich(WhichTabControl.Top); ChangeReadmeBoxFont(Config.ReadmeUseFixedWidthFont); @@ -5455,8 +5455,11 @@ public void RefreshCurrentFMScreenshots() } #region Tab dragging - - // @DockUI: Working/testing code, finalize before release + /* + @DockUI: Working/testing code, finalize before release + @DockUI: Detect the position dragged to, and if it's in the tab bar, insert the tab at that location + @DockUI: Focus tab when moving between tab controls, to prevent first-control-select issue again + */ private bool _inTabDragArea; From 7f292a5c0ac8966f977b8775b985163860052cac Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 17:08:09 -0800 Subject: [PATCH 117/200] Add another note --- AngelLoader/Forms/MainForm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 0fa071a8a..9eeb6eefd 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5443,7 +5443,7 @@ public void ShowUpdateNotification(bool show) } } - // We might want to change this, if we want something beside the readme or whatever + // @DockUI: Could make this a field that gets set in the ctor (efficiency) internal Control ReadmeContainer => LowerSplitContainer.Panel1; public void RefreshCurrentFMScreenshots() From 738ad397be80104c523055ada03e8daa0f5e780f Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 17:30:28 -0800 Subject: [PATCH 118/200] Fix some tab moving edge cases, and cleanup --- AngelLoader/Forms/MainForm.cs | 98 ++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 37 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 9eeb6eefd..0227ba253 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -119,7 +119,7 @@ need to check the accuracy of the selection itself (eg. in FMsDGV nav) so we can private readonly TabPage[] _gameTabs; private readonly ToolStripButtonCustom[] _filterByGameButtons; - private readonly Lazy_TabsBase[] _fmTabs; + private readonly Lazy_TabsBase[] _fmTabPages; private readonly Control[] _filterLabels; private readonly ToolStripItem[] _filtersToolStripSeparatedItems; @@ -651,7 +651,7 @@ and does NOT have its text transferred over. It ends up with blank text. _fmsListDefaultRowHeight = FMsDGV.RowTemplate.Height; // ReSharper disable once RedundantExplicitArraySize - _fmTabs = new Lazy_TabsBase[FMTabCount] + _fmTabPages = new Lazy_TabsBase[FMTabCount] { StatisticsTabPage, EditFMTabPage, @@ -662,9 +662,9 @@ and does NOT have its text transferred over. It ends up with blank text. ScreenshotsTabPage }; - for (int i = 0; i < _fmTabs.Length; i++) + for (int i = 0; i < _fmTabPages.Length; i++) { - _fmTabs[i].SetOwner(this); + _fmTabPages[i].SetOwner(this); } // For right-clicking on tabs @@ -894,7 +894,7 @@ and does NOT have its text transferred over. It ends up with blank text. var fmTabsDict = new Dictionary(); for (int i = 0; i < FMTabCount; i++) { - fmTabsDict.Add(Config.FMTabsData.Tabs[i].DisplayIndex, _fmTabs[i]); + fmTabsDict.Add(Config.FMTabsData.Tabs[i].DisplayIndex, _fmTabPages[i]); } var fmTabs = new TabPage[FMTabCount]; @@ -907,16 +907,23 @@ and does NOT have its text transferred over. It ends up with blank text. for (int i = 0; i < FMTabCount; i++) { + Lazy_TabsBase fmTabPage = _fmTabPages[i]; + FMTabVisibleIn visible = Config.FMTabsData.Tabs[i].Visible; // They're visible by default - shave off a bit of time - if (visible != FMTabVisibleIn.Top) + if (visible == FMTabVisibleIn.None) { - TopFMTabControl.ShowTab(_fmTabs[i], false); + TopFMTabControl.ShowTab(fmTabPage, false); + // @DockUI: Duplicate code - brittle + if (TopFMTabControl.TabCount == 0) + { + TopSplitContainer.Panel2Collapsed = true; + } } - if (visible == FMTabVisibleIn.Bottom) + else if (visible == FMTabVisibleIn.Bottom) { ConstructLazyLowerTabControl(); - Lazy_LowerTabControl.TabControl.ShowTab(_fmTabs[i], true); + MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, fmTabPage); } Lazy_FMTabsMenu.SetItemChecked(i, visible != FMTabVisibleIn.None); } @@ -927,7 +934,7 @@ and does NOT have its text transferred over. It ends up with blank text. { if ((int)Config.FMTabsData.SelectedTab == i) { - TopFMTabControl.SelectedTab = _fmTabs[i]; + TopFMTabControl.SelectedTab = _fmTabPages[i]; break; } } @@ -1856,9 +1863,9 @@ private void Localize(bool startup) ModsTabPage.Text = LText.ModsTab.TabText; ScreenshotsTabPage.Text = LText.ScreenshotsTab.TabText; - for (int i = 0; i < _fmTabs.Length; i++) + for (int i = 0; i < _fmTabPages.Length; i++) { - _fmTabs[i].Localize(); + _fmTabPages[i].Localize(); } #endregion @@ -1982,7 +1989,7 @@ bool CreateHandlePredicate(Control x) => (//x != TopSplitContainer && //x != TopSplitContainer.Panel2 && x != TopFMTabControl && - !_fmTabs.Contains(x)); + !_fmTabPages.Contains(x)); #endif if (startup && !darkMode) @@ -3285,9 +3292,9 @@ internal void FMTabsMenu_Opening(object sender, CancelEventArgs e) ? (FMTabVisibleIn.Bottom, Lazy_LowerTabControl.TabControl) : (FMTabVisibleIn.Top, TopFMTabControl); - for (int i = 0; i < _fmTabs.Length; i++) + for (int i = 0; i < _fmTabPages.Length; i++) { - Lazy_TabsBase item = _fmTabs[i]; + Lazy_TabsBase item = _fmTabPages[i]; Lazy_FMTabsMenu.SetItemChecked(i, tabControl.TabPages.Contains(item)); /* @DockUI(FM per-tab show/hide menu logic) @@ -3308,7 +3315,7 @@ internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) { var s = (ToolStripMenuItemCustom)sender; - TabPage tab = GetObjectFromMenuItem(Lazy_FMTabsMenu.Menu, s, _fmTabs, FMTabCount); + TabPage tab = GetObjectFromMenuItem(Lazy_FMTabsMenu.Menu, s, _fmTabPages, FMTabCount); // @DockUI: It's possible to have zero tabs in one or the other tab controls now // This is ultimately what we want, but we need to add proper support for this scenario, because we @@ -4713,9 +4720,9 @@ private void UpdateFMTabs() { using (new DisableEvents(this)) { - for (int i = 0; i < _fmTabs.Length; i++) + for (int i = 0; i < _fmTabPages.Length; i++) { - _fmTabs[i].UpdatePage(); + _fmTabPages[i].UpdatePage(); } } } @@ -5040,20 +5047,20 @@ public void UpdateConfig() int selectedTabIndex = -1; if (TopFMTabControl.TabCount > 0) { - selectedTabIndex = Array.IndexOf(_fmTabs.Cast().ToArray(), TopFMTabControl.SelectedTab); + selectedTabIndex = Array.IndexOf(_fmTabPages.Cast().ToArray(), TopFMTabControl.SelectedTab); } fmTabs.SelectedTab = selectedTabIndex > -1 ? (FMTab)selectedTabIndex : Config.FMTabsData.SelectedTab; int selectedTab2Index = -1; if (Lazy_LowerTabControl is { Constructed: true, TabControl.TabCount: > 0 }) { - selectedTab2Index = Array.IndexOf(_fmTabs.Cast().ToArray(), Lazy_LowerTabControl.TabControl.SelectedTab); + selectedTab2Index = Array.IndexOf(_fmTabPages.Cast().ToArray(), Lazy_LowerTabControl.TabControl.SelectedTab); } fmTabs.SelectedTab2 = selectedTab2Index > -1 ? (FMTab)selectedTab2Index : Config.FMTabsData.SelectedTab2; for (int i = 0; i < FMTabCount; i++) { - Lazy_TabsBase fmTab = _fmTabs[i]; + Lazy_TabsBase fmTab = _fmTabPages[i]; fmTabs.Tabs[i].DisplayIndex = DarkTabControl.FindBackingTab(_backingFMTabs, fmTab).Index; fmTabs.Tabs[i].Visible = _backingFMTabs.FirstOrDefault(x => x.TabPage == fmTab)?.Visible ?? FMTabVisibleIn.Top; } @@ -5536,14 +5543,7 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) if (dragTab == null) return; ConstructLazyLowerTabControl(); - TopFMTabControl.ShowTab(dragTab, false); - Lazy_LowerTabControl.TabControl.ShowTab(dragTab, true); - if (TopFMTabControl.TabCount == 0) - { - TopSplitContainer.Panel2Collapsed = true; - } - - Lazy_LowerTabControl.TabControl.SelectedTab = dragTab; + MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, dragTab); } finally { @@ -5552,6 +5552,37 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) } } + private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPage) + { + if (source == dest) return; + + DarkTabControl sourceTabControl = source == WhichTabControl.Bottom + ? Lazy_LowerTabControl.TabControl + : TopFMTabControl; + + DarkTabControl destTabControl = dest == WhichTabControl.Bottom + ? Lazy_LowerTabControl.TabControl + : TopFMTabControl; + + DarkSplitContainerCustom sourceSplitContainer = source == WhichTabControl.Bottom + ? LowerSplitContainer + : TopSplitContainer; + + DarkSplitContainerCustom destSplitContainer = dest == WhichTabControl.Bottom + ? LowerSplitContainer + : TopSplitContainer; + + sourceTabControl.ShowTab(tabPage, false); + destTabControl.ShowTab(tabPage, true); + if (sourceTabControl.TabCount == 0) + { + sourceSplitContainer.Panel2Collapsed = true; + } + destSplitContainer.Panel2Collapsed = false; + destTabControl.SelectedTab = tabPage; + tabPage.Focus(); + } + private void ConstructLazyLowerTabControl() { if (!Lazy_LowerTabControl.Constructed) @@ -5632,14 +5663,7 @@ internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) lazyTab.ConstructWithSuspendResume(); } } - Lazy_LowerTabControl.TabControl.ShowTab(dragTab, false); - TopFMTabControl.ShowTab(dragTab, true); - if (Lazy_LowerTabControl.TabControl.TabCount == 0) - { - LowerSplitContainer.Panel2Collapsed = true; - } - - TopFMTabControl.SelectedTab = dragTab; + MoveTab(WhichTabControl.Bottom, WhichTabControl.Top, dragTab); } finally { From fdaf35ca36b85815ed2efec8d9d781a3b05a622b Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Fri, 1 Mar 2024 17:33:50 -0800 Subject: [PATCH 119/200] Move BackingTab to FormsData, and remove old notes --- .../Forms/CustomControls/DarkTabControl.cs | 20 ------------------- AngelLoader/Forms/FormsData.cs | 8 ++++++++ AngelLoader/Forms/MainForm.cs | 4 ++-- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 862b341a9..842285b96 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -19,26 +19,6 @@ update the backing list ourselves. public sealed class DarkTabControl : TabControl, IDarkable { #region Private fields - /* - @DockUI(Moving tab pages between controls) - To avoid having a duplicate set of tab pages, we should physically move the tab pages from one control to the - other. But this backing tabs list doesn't really support that. To allow it, we could make this list global - and make Visible into a three-state enum value for Visible Top, Visible Bottom, or Not Visible. That way, we - would minimize the amount of backing tab code we'd have to re-do. - -But this needs a concrete enum variable in the backing tab class that only applies to one situation, but - all other tab controls will have to carry it and ignore it... - - -Another idea is we could have the tab pages be nullable in the list? - That way we could have two lists of the same length, and swapping tabs' positions would maintain the same - positions for non-null tabs between the two lists. - But actually this would still require doing every operation on both lists at once, so never mind I guess... - */ - internal sealed class BackingTab - { - internal TabPage TabPage; - internal FMTabVisibleIn Visible = FMTabVisibleIn.Top; - internal BackingTab(TabPage tabPage) => TabPage = tabPage; - } internal TabPage? DragTab { get; private set; } diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index a9b4dfab3..19802c65e 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -1,6 +1,8 @@ using System; using System.Drawing; using System.IO; +using System.Windows.Forms; +using AngelLoader.DataClasses; namespace AngelLoader.Forms; @@ -55,3 +57,9 @@ public void Dispose() _memoryStream.Dispose(); } } + +public sealed class BackingTab(TabPage tabPage) +{ + public TabPage TabPage = tabPage; + public FMTabVisibleIn Visible = FMTabVisibleIn.Top; +} diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 0227ba253..72a10e98c 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -197,7 +197,7 @@ private enum ZoomFMsDGVType // Cache visible state because calling Visible redoes the work even if the value is the same private bool _readmeControlsOtherThanComboBoxVisible; - private readonly List _backingFMTabs = new(FMTabCount); + private readonly List _backingFMTabs = new(FMTabCount); #endregion @@ -3302,7 +3302,7 @@ internal void FMTabsMenu_Opening(object sender, CancelEventArgs e) They're all a little weird. Decide on something for the final release. */ #if true - DarkTabControl.BackingTab? backingTab = _backingFMTabs.FirstOrDefault(x => x.TabPage == item); + BackingTab? backingTab = _backingFMTabs.FirstOrDefault(x => x.TabPage == item); if (backingTab != null) { Lazy_FMTabsMenu.SetItemVisible(i, backingTab.Visible == FMTabVisibleIn.None || backingTab.Visible == which); From e9cc88a667c375adc3d2d42055c3d2b82ced9cdc Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 07:07:09 -0800 Subject: [PATCH 120/200] Fix tab dragging highlight area sizes --- .../Forms/CustomControls/DarkSplitContainerCustom.cs | 5 +++++ AngelLoader/Forms/MainForm.cs | 9 ++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs index 0048788f5..4d21726e2 100644 --- a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs +++ b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs @@ -101,6 +101,11 @@ public bool DarkModeEnabled internal float SplitterPercentReal => FullScreen ? _storedSplitterPercent : SplitterPercent; + internal int SplitterDistanceLogical => + FullScreen + ? (int)Math.Round(_storedSplitterPercent * CrossLength) + : SplitterDistance; + internal bool FullScreen { get; private set; } internal int CollapsedSize; diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 72a10e98c..10878cc42 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5498,9 +5498,9 @@ private void TopFMTabControl_MouseMoveCustom(object sender, MouseEventArgs e) gc.G.FillRectangle( b, new Rectangle( - TopSplitContainer.SplitterDistance, + lsp.SplitterDistanceLogical, 0, - lsp.ClientRectangle.Width - TopSplitContainer.SplitterDistance, + lsp.ClientRectangle.Width - lsp.SplitterDistanceLogical, lsp.ClientRectangle.Height) ); } @@ -5599,7 +5599,6 @@ internal void Lazy_LowerTabControl_MouseMoveCustom(object sender, MouseEventArgs Color overlayColor = GetOverlayColor(); DarkSplitContainerCustom tsp = TopSplitContainer; - DarkSplitContainerCustom lsp = LowerSplitContainer; if ((tsp.Panel2Collapsed || tsp.FullScreen) && tsp.ClientRectangle.Contains(tsp.PointToClient_Fast(cp))) { @@ -5612,9 +5611,9 @@ internal void Lazy_LowerTabControl_MouseMoveCustom(object sender, MouseEventArgs gc.G.FillRectangle( b, new Rectangle( - lsp.SplitterDistance, + tsp.SplitterDistanceLogical, 0, - tsp.ClientRectangle.Width - lsp.SplitterDistance, + tsp.ClientRectangle.Width - tsp.SplitterDistanceLogical, tsp.ClientRectangle.Height) ); } From 7b38059d793a6fdf1607b06e330e583269ee8f1e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 07:48:16 -0800 Subject: [PATCH 121/200] Cleanup/dedupe tab drag handling code --- AngelLoader/Forms/MainForm.cs | 162 ++++++++++++---------------------- 1 file changed, 56 insertions(+), 106 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 10878cc42..2186fc790 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5470,68 +5470,38 @@ public void RefreshCurrentFMScreenshots() private bool _inTabDragArea; - private static Color GetOverlayColor() + private void TopFMTabControl_MouseMoveCustom(object sender, MouseEventArgs e) { - // @DockUI: Make light and dark mode colors - return Color.FromArgb( - alpha: 64, - red: DarkColors.BlueSelection.R, - green: DarkColors.BlueSelection.G, - blue: DarkColors.BlueSelection.B); + HandleTabDrag(LowerSplitContainer); } - private void TopFMTabControl_MouseMoveCustom(object sender, MouseEventArgs e) + internal void Lazy_LowerTabControl_MouseMoveCustom(object sender, MouseEventArgs e) { - Point cp = Native.GetCursorPosition_Fast(); - Color overlayColor = GetOverlayColor(); + HandleTabDrag(TopSplitContainer); + } - DarkSplitContainerCustom lsp = LowerSplitContainer; + private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) + { + if (!_inTabDragArea) return; - if (lsp.Panel2Collapsed && lsp.ClientRectangle.Contains(lsp.PointToClient_Fast(cp))) - { - if (!_inTabDragArea) - { - _inTabDragArea = true; - Trace.WriteLine("Hit closed"); - using var gc = new Native.GraphicsContext(lsp.Handle); - using var b = new SolidBrush(overlayColor); - gc.G.FillRectangle( - b, - new Rectangle( - lsp.SplitterDistanceLogical, - 0, - lsp.ClientRectangle.Width - lsp.SplitterDistanceLogical, - lsp.ClientRectangle.Height) - ); - } - } - else if (lsp.Panel2.ClientRectangle.Contains(lsp.Panel2.PointToClient_Fast(cp))) + try { - if (!_inTabDragArea) - { - _inTabDragArea = true; - Trace.WriteLine("Hit open"); - using var gc = new Native.GraphicsContext(lsp.Panel2.Handle); - using var b = new SolidBrush(overlayColor); - gc.G.FillRectangle( - b, - lsp.Panel2.ClientRectangle with { X = 0, Y = 0 } - ); - } + EverythingPanel.SuspendDrawing(); + + TabPage? dragTab = TopFMTabControl.DragTab; + if (dragTab == null) return; + + ConstructLazyLowerTabControl(); + MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, dragTab); } - else + finally { - if (_inTabDragArea) - { - _inTabDragArea = false; - Trace.WriteLine("Miss"); - lsp.Refresh(); - } + _inTabDragArea = false; + EverythingPanel.ResumeDrawing(); } } - - private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) + internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) { if (!_inTabDragArea) return; @@ -5539,11 +5509,18 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) { EverythingPanel.SuspendDrawing(); - TabPage? dragTab = TopFMTabControl.DragTab; + TabPage? dragTab = Lazy_LowerTabControl.TabControl.DragTab; if (dragTab == null) return; - ConstructLazyLowerTabControl(); - MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, dragTab); + if (TopSplitContainer.Panel2Collapsed) + { + TopSplitContainer.Panel2Collapsed = false; + if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab) + { + lazyTab.ConstructWithSuspendResume(); + } + } + MoveTab(WhichTabControl.Bottom, WhichTabControl.Top, dragTab); } finally { @@ -5552,6 +5529,16 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) } } + private static Color GetOverlayColor() + { + // @DockUI: Make light and dark mode colors + return Color.FromArgb( + alpha: 64, + red: DarkColors.BlueSelection.R, + green: DarkColors.BlueSelection.G, + blue: DarkColors.BlueSelection.B); + } + private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPage) { if (source == dest) return; @@ -5593,81 +5580,44 @@ private void ConstructLazyLowerTabControl() } } - internal void Lazy_LowerTabControl_MouseMoveCustom(object sender, MouseEventArgs e) + private void HandleTabDrag(DarkSplitContainerCustom sc) { Point cp = Native.GetCursorPosition_Fast(); - Color overlayColor = GetOverlayColor(); - - DarkSplitContainerCustom tsp = TopSplitContainer; - if ((tsp.Panel2Collapsed || tsp.FullScreen) && tsp.ClientRectangle.Contains(tsp.PointToClient_Fast(cp))) + if ((sc.Panel2Collapsed || sc.FullScreen) && sc.ClientRectangle.Contains(sc.PointToClient_Fast(cp))) { if (!_inTabDragArea) { _inTabDragArea = true; - Trace.WriteLine("Hit closed"); - using var gc = new Native.GraphicsContext(tsp.Handle); - using var b = new SolidBrush(overlayColor); + Trace.WriteLine("Hit collapsed"); + using var gc = new Native.GraphicsContext(sc.Handle); + using var b = new SolidBrush(GetOverlayColor()); + int splitterDistance = sc.SplitterDistanceLogical; gc.G.FillRectangle( b, new Rectangle( - tsp.SplitterDistanceLogical, + splitterDistance, 0, - tsp.ClientRectangle.Width - tsp.SplitterDistanceLogical, - tsp.ClientRectangle.Height) - ); + sc.ClientRectangle.Width - splitterDistance, + sc.ClientRectangle.Height)); } } - else if (tsp.Panel2.ClientRectangle.Contains(tsp.Panel2.PointToClient_Fast(cp))) + else if (sc.Panel2.ClientRectangle.Contains(sc.Panel2.PointToClient_Fast(cp))) { if (!_inTabDragArea) { _inTabDragArea = true; Trace.WriteLine("Hit open"); - using var gc = new Native.GraphicsContext(tsp.Panel2.Handle); - using var b = new SolidBrush(overlayColor); - gc.G.FillRectangle( - b, - tsp.Panel2.ClientRectangle with { X = 0, Y = 0 } - ); + using var gc = new Native.GraphicsContext(sc.Panel2.Handle); + using var b = new SolidBrush(GetOverlayColor()); + gc.G.FillRectangle(b, sc.Panel2.ClientRectangle with { X = 0, Y = 0 }); } } - else - { - if (_inTabDragArea) - { - _inTabDragArea = false; - Trace.WriteLine("Miss"); - tsp.Refresh(); - } - } - } - - internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) - { - if (!_inTabDragArea) return; - - try - { - EverythingPanel.SuspendDrawing(); - - TabPage? dragTab = Lazy_LowerTabControl.TabControl.DragTab; - if (dragTab == null) return; - - if (TopSplitContainer.Panel2Collapsed) - { - TopSplitContainer.Panel2Collapsed = false; - if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab) - { - lazyTab.ConstructWithSuspendResume(); - } - } - MoveTab(WhichTabControl.Bottom, WhichTabControl.Top, dragTab); - } - finally + else if (_inTabDragArea) { _inTabDragArea = false; - EverythingPanel.ResumeDrawing(); + Trace.WriteLine("Miss"); + sc.Refresh(); } } From 623bbe705a54112243e4b6c9c117b9eff1b9d7f4 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 07:49:56 -0800 Subject: [PATCH 122/200] Rename for clarity --- AngelLoader/Forms/CustomControls/DarkTabControl.cs | 8 ++++---- .../CustomControls/LazyLoaded/Lazy_LowerTabControl.cs | 2 +- AngelLoader/Forms/MainForm.Designer.cs | 2 +- AngelLoader/Forms/MainForm.cs | 4 ++-- AngelLoader/Forms/MainForm_InitManual.cs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 842285b96..1ac69c45d 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -72,7 +72,7 @@ public bool DarkModeEnabled } } - public event MouseEventHandler? MouseMoveCustom; + public event MouseEventHandler? MouseDragCustom; [PublicAPI] [DefaultValue(false)] @@ -326,14 +326,14 @@ protected override void OnMouseMove(MouseEventArgs e) if (TabCount <= 1) { - MouseMoveCustom?.Invoke(this, e); + MouseDragCustom?.Invoke(this, e); base.OnMouseMove(e); return; } - // If we are dragging a tab, don't run the normal handler, because we want to be "modal" and block s + // If we are dragging a tab, don't run the normal handler, because we want to be "modal" and block so // nothing weird happens - MouseMoveCustom?.Invoke(this, e); + MouseDragCustom?.Invoke(this, e); int dragTabIndex = TabPages.IndexOf(DragTab); var (bDragTabIndex, _) = FindBackingTab(_backingTabList, DragTab); diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 4b95dd0dc..12668cc24 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -61,7 +61,7 @@ private void Construct() _owner.LowerSplitContainer.Panel2.MouseClick += _owner.LowerFMTabsBar_MouseClick; _tabControl.Selected += _owner.FMTabControl_Selected; - _tabControl.MouseMoveCustom += _owner.Lazy_LowerTabControl_MouseMoveCustom; + _tabControl.MouseDragCustom += _owner.Lazy_LowerTabControl_MouseDragCustom; _tabControl.MouseUp += _owner.Lazy_LowerTabControl_MouseUp; _tabControl.VisibleChanged += TabControl_VisibleChanged; diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 07a137c56..2bc3080a8 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -912,7 +912,7 @@ private void InitializeComponent() this.TopFMTabControl.SelectedIndex = 0; this.TopFMTabControl.Size = new System.Drawing.Size(535, 310); this.TopFMTabControl.TabIndex = 15; - this.TopFMTabControl.MouseMoveCustom += new System.Windows.Forms.MouseEventHandler(this.TopFMTabControl_MouseMoveCustom); + this.TopFMTabControl.MouseDragCustom += new System.Windows.Forms.MouseEventHandler(this.TopFMTabControl_MouseDragCustom); this.TopFMTabControl.MouseUp += new System.Windows.Forms.MouseEventHandler(this.TopFMTabControl_MouseUp); // // StatisticsTabPage diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 2186fc790..5da47a3b2 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5470,12 +5470,12 @@ public void RefreshCurrentFMScreenshots() private bool _inTabDragArea; - private void TopFMTabControl_MouseMoveCustom(object sender, MouseEventArgs e) + private void TopFMTabControl_MouseDragCustom(object sender, MouseEventArgs e) { HandleTabDrag(LowerSplitContainer); } - internal void Lazy_LowerTabControl_MouseMoveCustom(object sender, MouseEventArgs e) + internal void Lazy_LowerTabControl_MouseDragCustom(object sender, MouseEventArgs e) { HandleTabDrag(TopSplitContainer); } diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index 8d3ba2e89..e572a3235 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -558,7 +558,7 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir TopFMTabControl.EnableScrollButtonsRefreshHack = true; TopFMTabControl.Size = new Size(535, 310); TopFMTabControl.TabIndex = 15; - TopFMTabControl.MouseMoveCustom += TopFMTabControl_MouseMoveCustom; + TopFMTabControl.MouseDragCustom += TopFMTabControl_MouseDragCustom; TopFMTabControl.MouseUp += TopFMTabControl_MouseUp; // // LowerSplitContainer From ac234872640029c193acc19412306f24c815b54e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 08:04:10 -0800 Subject: [PATCH 123/200] Explicitly default _whichTabControl to top --- AngelLoader/Forms/CustomControls/DarkTabControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 1ac69c45d..131d3f9d4 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -31,7 +31,7 @@ public sealed class DarkTabControl : TabControl, IDarkable /// internal void SetBackingList(List list) => _backingTabList = list; - private WhichTabControl _whichTabControl; + private WhichTabControl _whichTabControl = WhichTabControl.Top; internal void SetWhich(WhichTabControl value) => _whichTabControl = value; #endregion From 8bca9b0ccd7fe5fb8e2be8985931f50cd256fb9e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 08:35:08 -0800 Subject: [PATCH 124/200] Update preload logic for lower tab page And fix attended lazy-load bug --- .../LazyLoaded/Lazy_LowerTabControl.cs | 6 ++++- AngelLoader/Forms/FormsViewEnvironment.cs | 25 ++++++++++++++----- AngelLoader/Forms/MainForm.cs | 1 + 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 12668cc24..f427f716e 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -60,7 +60,7 @@ private void Construct() _tabControl.MouseClick += _owner.LowerFMTabsBar_MouseClick; _owner.LowerSplitContainer.Panel2.MouseClick += _owner.LowerFMTabsBar_MouseClick; - _tabControl.Selected += _owner.FMTabControl_Selected; + _tabControl.Selected += TabControl_Selected; _tabControl.MouseDragCustom += _owner.Lazy_LowerTabControl_MouseDragCustom; _tabControl.MouseUp += _owner.Lazy_LowerTabControl_MouseUp; _tabControl.VisibleChanged += TabControl_VisibleChanged; @@ -68,6 +68,10 @@ private void Construct() Constructed = true; } + private void TabControl_Selected(object sender, TabControlEventArgs e) => Selected?.Invoke(_tabControl, e); + + public event TabControlEventHandler? Selected; + private void TabControl_VisibleChanged(object sender, System.EventArgs e) { if (_tabControl is { Visible: true, SelectedTab: Lazy_TabsBase lazyTab }) diff --git a/AngelLoader/Forms/FormsViewEnvironment.cs b/AngelLoader/Forms/FormsViewEnvironment.cs index 84a42436a..00908ab79 100644 --- a/AngelLoader/Forms/FormsViewEnvironment.cs +++ b/AngelLoader/Forms/FormsViewEnvironment.cs @@ -45,12 +45,25 @@ internal static MainForm ViewInternal public void PreloadScreenshot(ConfigData config, List fmsViewList) { - // @ScreenshotDisplay: UI-specific preload conditions - // If we allow moving the screenshots tab beside the readme or wherever else, we'll have to update - // this code to match whatever the UI setup is. - // @DockUI: Finalize these conditions - if (config.TopRightPanelCollapsed || - config.FMTabsData.SelectedTab != FMTab.Screenshots) + /* + @ScreenshotDisplay: UI-specific preload conditions + If we allow moving the screenshots tab beside the readme or wherever else, we'll have to update this code + to match whatever the UI setup is. + @DockUI: Finalize these conditions + */ + var screenshotsTab = config.FMTabsData.GetTab(FMTab.Screenshots); + if (screenshotsTab.Visible == FMTabVisibleIn.Top && + (config.TopRightPanelCollapsed || + config.FMTabsData.SelectedTab != FMTab.Screenshots)) + { + return; + } + else if (screenshotsTab.Visible == FMTabVisibleIn.Bottom && + config.FMTabsData.SelectedTab2 != FMTab.Screenshots) + { + return; + } + else if (screenshotsTab.Visible == FMTabVisibleIn.None) { return; } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 5da47a3b2..f67a584c2 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -1206,6 +1206,7 @@ private void SetWindowStateAndSize() lazyTab.Construct(); } TopFMTabControl.Selected += FMTabControl_Selected; + Lazy_LowerTabControl.Selected += FMTabControl_Selected; _firstShowDone = true; } From cb18e23689e9db1d6058daa8f0ab7e92bcb98dc7 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 09:28:18 -0800 Subject: [PATCH 125/200] Expose lazy-load versions of a few fields/methods --- .../LazyLoaded/Lazy_LowerTabControl.cs | 24 +++++++++++++++++-- AngelLoader/Forms/MainForm.cs | 22 +++++++---------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index f427f716e..16a93f554 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -33,6 +33,8 @@ public bool DarkModeEnabled } } + public event TabControlEventHandler? Selected; + public Lazy_LowerTabControl(MainForm owner) => _owner = owner; private void Construct() @@ -68,9 +70,27 @@ private void Construct() Constructed = true; } - private void TabControl_Selected(object sender, TabControlEventArgs e) => Selected?.Invoke(_tabControl, e); + public void ShowTab(TabPage tabPage, bool show) + { + if (show) + { + Construct(); + _tabControl.ShowTab(tabPage, true); + } + else + { + if (!Constructed) return; + _tabControl.ShowTab(tabPage, false); + } + } - public event TabControlEventHandler? Selected; + public int TabCount => Constructed ? _tabControl.TabCount : 0; + + public TabPage? SelectedTab => Constructed ? _tabControl.SelectedTab : null; + + public TabPage? DragTab => Constructed ? _tabControl.DragTab : null; + + private void TabControl_Selected(object sender, TabControlEventArgs e) => Selected?.Invoke(_tabControl, e); private void TabControl_VisibleChanged(object sender, System.EventArgs e) { diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index f67a584c2..0965dcda3 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -3341,10 +3341,7 @@ internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) { if (tabControl == TopFMTabControl) { - if (Lazy_LowerTabControl.Constructed) - { - Lazy_LowerTabControl.TabControl.ShowTab(tab, false); - } + Lazy_LowerTabControl.ShowTab(tab, false); } else { @@ -5048,14 +5045,15 @@ public void UpdateConfig() int selectedTabIndex = -1; if (TopFMTabControl.TabCount > 0) { + // @DockUI: Duplicate Cast/ToArray() selectedTabIndex = Array.IndexOf(_fmTabPages.Cast().ToArray(), TopFMTabControl.SelectedTab); } fmTabs.SelectedTab = selectedTabIndex > -1 ? (FMTab)selectedTabIndex : Config.FMTabsData.SelectedTab; int selectedTab2Index = -1; - if (Lazy_LowerTabControl is { Constructed: true, TabControl.TabCount: > 0 }) + if (Lazy_LowerTabControl.TabCount > 0) { - selectedTab2Index = Array.IndexOf(_fmTabPages.Cast().ToArray(), Lazy_LowerTabControl.TabControl.SelectedTab); + selectedTab2Index = Array.IndexOf(_fmTabPages.Cast().ToArray(), Lazy_LowerTabControl.SelectedTab); } fmTabs.SelectedTab2 = selectedTab2Index > -1 ? (FMTab)selectedTab2Index : Config.FMTabsData.SelectedTab2; @@ -5510,7 +5508,7 @@ internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) { EverythingPanel.SuspendDrawing(); - TabPage? dragTab = Lazy_LowerTabControl.TabControl.DragTab; + TabPage? dragTab = Lazy_LowerTabControl.DragTab; if (dragTab == null) return; if (TopSplitContainer.Panel2Collapsed) @@ -5573,12 +5571,10 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa private void ConstructLazyLowerTabControl() { - if (!Lazy_LowerTabControl.Constructed) - { - LowerSplitContainer.Panel2Collapsed = false; - Lazy_LowerTabControl.TabControl.SetBackingList(_backingFMTabs); - LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); - } + if (Lazy_LowerTabControl.Constructed) return; + LowerSplitContainer.Panel2Collapsed = false; + Lazy_LowerTabControl.TabControl.SetBackingList(_backingFMTabs); + LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); } private void HandleTabDrag(DarkSplitContainerCustom sc) From 4cf0204b08ea7ca4898846a752dc12d87a876665 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 13:59:57 -0800 Subject: [PATCH 126/200] Notes on the tab order on fast move bug, and the plan to solve it --- .../Forms/CustomControls/DarkTabControl.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 131d3f9d4..750944339 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -331,6 +331,45 @@ protected override void OnMouseMove(MouseEventArgs e) return; } + /* + @DockUI: The mis-ordering of tabs on quick moving occurs when a tab moves by more than one position in one go. + + Debug log demonstrates: + -The first entry is moving Statistics from 0 to 1. The order is still correct. + -The second entry is moving Statistics from 1 to 5. Statistics displaces Screenshots, and Screenshots + is swapped to Statistics' old position, which is 1. The order is now incorrect. + + I believe all items should be shifted back by 1 in order for this to work. Either that or we can just + do remove/insert and it will work out on its own (but we may need to disable events during the remove/ + insert for the TabPages collection). + + Debug log: + =============================== + Edit FM, newTabIndex: 1, dragTabIndex: 0 + NEW TAB INDEX PAGE: Edit FM + ------------- + Backing list: + 0: TabPage: EditFM, VisibleIn: Top + 1: TabPage: Statistics, VisibleIn: Top + 2: TabPage: Comment, VisibleIn: Top + 3: TabPage: Patch, VisibleIn: None + 4: TabPage: Tags, VisibleIn: Top + 5: TabPage: Mods, VisibleIn: Top + 6: TabPage: Screenshots, VisibleIn: Top + =============================== + Screenshots, newTabIndex: 5, dragTabIndex: 1 + NEW TAB INDEX PAGE: Screenshots + ------------- + Backing list: + 0: TabPage: EditFM, VisibleIn: Top + 1: TabPage: Screenshots, VisibleIn: Top + 2: TabPage: Comment, VisibleIn: Top + 3: TabPage: Patch, VisibleIn: None + 4: TabPage: Tags, VisibleIn: Top + 5: TabPage: Mods, VisibleIn: Top + 6: TabPage: Statistics, VisibleIn: Top + */ + // If we are dragging a tab, don't run the normal handler, because we want to be "modal" and block so // nothing weird happens MouseDragCustom?.Invoke(this, e); From b7dc445c669308003b680659cdfbab7a71b85883 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 14:10:51 -0800 Subject: [PATCH 127/200] Rename BackingTab.Visible to VisibleIn --- AngelLoader/Forms/CustomControls/DarkTabControl.cs | 6 +++--- AngelLoader/Forms/FormsData.cs | 2 +- AngelLoader/Forms/MainForm.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 750944339..d3c48b1a6 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -109,7 +109,7 @@ internal static (int Index, BackingTab BackingTab) { BackingTab backingTab = backingTabs[i]; // @DockUI: Could we make this our specific top/bottom value and get better ordering between moves? - if (indexVisibleOnly && backingTab.Visible != FMTabVisibleIn.None) vi++; + if (indexVisibleOnly && backingTab.VisibleIn != FMTabVisibleIn.None) vi++; if (backingTab.TabPage == tabPage) return (indexVisibleOnly ? vi : i, backingTab); } @@ -477,12 +477,12 @@ public void ShowTab(TabPage tabPage, bool show) if (show) { - bt.Visible = _whichTabControl == WhichTabControl.Bottom ? FMTabVisibleIn.Bottom : FMTabVisibleIn.Top; + bt.VisibleIn = _whichTabControl == WhichTabControl.Bottom ? FMTabVisibleIn.Bottom : FMTabVisibleIn.Top; if (!TabPages.Contains(bt.TabPage)) TabPages.Insert(Math.Min(index, TabCount), bt.TabPage); } else { - bt.Visible = FMTabVisibleIn.None; + bt.VisibleIn = FMTabVisibleIn.None; if (TabPages.Contains(bt.TabPage)) { TabPages.Remove(bt.TabPage); diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index 19802c65e..843655978 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -61,5 +61,5 @@ public void Dispose() public sealed class BackingTab(TabPage tabPage) { public TabPage TabPage = tabPage; - public FMTabVisibleIn Visible = FMTabVisibleIn.Top; + public FMTabVisibleIn VisibleIn = FMTabVisibleIn.Top; } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 0965dcda3..b9fbb841b 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -3306,7 +3306,7 @@ internal void FMTabsMenu_Opening(object sender, CancelEventArgs e) BackingTab? backingTab = _backingFMTabs.FirstOrDefault(x => x.TabPage == item); if (backingTab != null) { - Lazy_FMTabsMenu.SetItemVisible(i, backingTab.Visible == FMTabVisibleIn.None || backingTab.Visible == which); + Lazy_FMTabsMenu.SetItemVisible(i, backingTab.VisibleIn == FMTabVisibleIn.None || backingTab.VisibleIn == which); } #endif } @@ -5061,7 +5061,7 @@ public void UpdateConfig() { Lazy_TabsBase fmTab = _fmTabPages[i]; fmTabs.Tabs[i].DisplayIndex = DarkTabControl.FindBackingTab(_backingFMTabs, fmTab).Index; - fmTabs.Tabs[i].Visible = _backingFMTabs.FirstOrDefault(x => x.TabPage == fmTab)?.Visible ?? FMTabVisibleIn.Top; + fmTabs.Tabs[i].Visible = _backingFMTabs.FirstOrDefault(x => x.TabPage == fmTab)?.VisibleIn ?? FMTabVisibleIn.Top; } #region Quick hack to prevent splitter distances from freaking out if we're closing while minimized From 83e321332d27aa349732181081ea66e40258c129 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 17:47:02 -0800 Subject: [PATCH 128/200] Try, and fail, the easy way --- .../Forms/CustomControls/DarkTabControl.cs | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index d3c48b1a6..6297c3fea 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -16,10 +16,14 @@ namespace AngelLoader.Forms.CustomControls; When we show/hide tabs, set the bool so that OnControlAdded()/OnControlRemoved() don't do anything while we update the backing list ourselves. */ -public sealed class DarkTabControl : TabControl, IDarkable +public sealed class DarkTabControl : TabControl, IDarkable, IEventDisabler { #region Private fields + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int EventsDisabled { get; set; } + internal TabPage? DragTab { get; private set; } private List _backingTabList = new(0); @@ -395,18 +399,86 @@ protected override void OnMouseMove(MouseEventArgs e) if (bNewTabIndex == -1 || newTab == null || newTab == DragTab) return; int newTabIndex = TabPages.IndexOf(newTab); + +#if true TabPages[dragTabIndex] = newTab; TabPages[newTabIndex] = DragTab; _backingTabList[bDragTabIndex].TabPage = newTab; _backingTabList[bNewTabIndex].TabPage = DragTab; +#else + // This results in terrible flickering, as expected of removing/inserting from a live tab collection. + // Suspend/resume doesn't help either. Looks like we have to do the other idea, of bumping them all over + // by one. + try + { + using (new DisableEvents(this)) + { + this.SuspendDrawing(); + if (newTabIndex > dragTabIndex) + { + TabPages.Remove(DragTab); + TabPages.Insert(newTabIndex, DragTab); + + BackingTab backingDragTab = _backingTabList[bDragTabIndex]; + _backingTabList.Remove(backingDragTab); + _backingTabList.Insert(bNewTabIndex, backingDragTab); + } + else // newTabIndex < dragTabIndex + { + TabPages.Remove(DragTab); + TabPages.Insert(newTabIndex, DragTab); + + BackingTab backingDragTab = _backingTabList[bDragTabIndex]; + _backingTabList.Remove(backingDragTab); + _backingTabList.Insert(bNewTabIndex, backingDragTab); + + } + } + } + finally + { + this.ResumeDrawing(); + } +#endif + SelectedTab = DragTab; // Otherwise the first control within the tab page gets selected SelectedTab.Focus(); } + protected override void OnDeselecting(TabControlCancelEventArgs e) + { + if (EventsDisabled > 0) return; + base.OnDeselecting(e); + } + + protected override void OnDeselected(TabControlEventArgs e) + { + if (EventsDisabled > 0) return; + base.OnDeselected(e); + } + + protected override void OnSelecting(TabControlCancelEventArgs e) + { + if (EventsDisabled > 0) return; + base.OnSelecting(e); + } + + protected override void OnSelected(TabControlEventArgs e) + { + if (EventsDisabled > 0) return; + base.OnSelected(e); + } + + protected override void OnSelectedIndexChanged(EventArgs e) + { + if (EventsDisabled > 0) return; + base.OnSelectedIndexChanged(e); + } + #endregion #region Public methods From f9f215f269332477ee1392713db3eea4fa1170d5 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 18:32:54 -0800 Subject: [PATCH 129/200] Fix tab misordering on quick move bug for good --- .../Forms/CustomControls/DarkTabControl.cs | 140 +++++------------- 1 file changed, 33 insertions(+), 107 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 6297c3fea..0a0b0a3ac 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -16,14 +16,10 @@ namespace AngelLoader.Forms.CustomControls; When we show/hide tabs, set the bool so that OnControlAdded()/OnControlRemoved() don't do anything while we update the backing list ourselves. */ -public sealed class DarkTabControl : TabControl, IDarkable, IEventDisabler +public sealed class DarkTabControl : TabControl, IDarkable { #region Private fields - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public int EventsDisabled { get; set; } - internal TabPage? DragTab { get; private set; } private List _backingTabList = new(0); @@ -335,45 +331,6 @@ protected override void OnMouseMove(MouseEventArgs e) return; } - /* - @DockUI: The mis-ordering of tabs on quick moving occurs when a tab moves by more than one position in one go. - - Debug log demonstrates: - -The first entry is moving Statistics from 0 to 1. The order is still correct. - -The second entry is moving Statistics from 1 to 5. Statistics displaces Screenshots, and Screenshots - is swapped to Statistics' old position, which is 1. The order is now incorrect. - - I believe all items should be shifted back by 1 in order for this to work. Either that or we can just - do remove/insert and it will work out on its own (but we may need to disable events during the remove/ - insert for the TabPages collection). - - Debug log: - =============================== - Edit FM, newTabIndex: 1, dragTabIndex: 0 - NEW TAB INDEX PAGE: Edit FM - ------------- - Backing list: - 0: TabPage: EditFM, VisibleIn: Top - 1: TabPage: Statistics, VisibleIn: Top - 2: TabPage: Comment, VisibleIn: Top - 3: TabPage: Patch, VisibleIn: None - 4: TabPage: Tags, VisibleIn: Top - 5: TabPage: Mods, VisibleIn: Top - 6: TabPage: Screenshots, VisibleIn: Top - =============================== - Screenshots, newTabIndex: 5, dragTabIndex: 1 - NEW TAB INDEX PAGE: Screenshots - ------------- - Backing list: - 0: TabPage: EditFM, VisibleIn: Top - 1: TabPage: Screenshots, VisibleIn: Top - 2: TabPage: Comment, VisibleIn: Top - 3: TabPage: Patch, VisibleIn: None - 4: TabPage: Tags, VisibleIn: Top - 5: TabPage: Mods, VisibleIn: Top - 6: TabPage: Statistics, VisibleIn: Top - */ - // If we are dragging a tab, don't run the normal handler, because we want to be "modal" and block so // nothing weird happens MouseDragCustom?.Invoke(this, e); @@ -400,48 +357,47 @@ protected override void OnMouseMove(MouseEventArgs e) int newTabIndex = TabPages.IndexOf(newTab); -#if true - TabPages[dragTabIndex] = newTab; - TabPages[newTabIndex] = DragTab; - - _backingTabList[bDragTabIndex].TabPage = newTab; - _backingTabList[bNewTabIndex].TabPage = DragTab; + int distance = Math.Abs(newTabIndex - dragTabIndex); + if (distance == 1) + { + TabPages[dragTabIndex] = newTab; + TabPages[newTabIndex] = DragTab; -#else - // This results in terrible flickering, as expected of removing/inserting from a live tab collection. - // Suspend/resume doesn't help either. Looks like we have to do the other idea, of bumping them all over - // by one. - try + _backingTabList[bDragTabIndex].TabPage = newTab; + _backingTabList[bNewTabIndex].TabPage = DragTab; + } + else { - using (new DisableEvents(this)) + // Handle the case where the tab is moving more than one position in one go. + // The easy way would be to insert/remove, but that results in terrible flickering for the TabPages + // collection, and suspend/resume doesn't fix it either. So just move everything over manually. + + if (newTabIndex > dragTabIndex) { - this.SuspendDrawing(); - if (newTabIndex > dragTabIndex) + for (int i = dragTabIndex; i < newTabIndex; i++) { - TabPages.Remove(DragTab); - TabPages.Insert(newTabIndex, DragTab); - - BackingTab backingDragTab = _backingTabList[bDragTabIndex]; - _backingTabList.Remove(backingDragTab); - _backingTabList.Insert(bNewTabIndex, backingDragTab); + TabPages[i] = TabPages[i + 1]; } - else // newTabIndex < dragTabIndex + for (int i = bDragTabIndex; i < bNewTabIndex; i++) { - TabPages.Remove(DragTab); - TabPages.Insert(newTabIndex, DragTab); - - BackingTab backingDragTab = _backingTabList[bDragTabIndex]; - _backingTabList.Remove(backingDragTab); - _backingTabList.Insert(bNewTabIndex, backingDragTab); - + _backingTabList[i].TabPage = _backingTabList[i + 1].TabPage; } } + else + { + for (int i = dragTabIndex - 1; i >= newTabIndex; i--) + { + TabPages[i + 1] = TabPages[i]; + } + for (int i = bDragTabIndex - 1; i >= bNewTabIndex; i--) + { + _backingTabList[i + 1].TabPage = _backingTabList[i].TabPage; + } + } + + TabPages[newTabIndex] = DragTab; + _backingTabList[bNewTabIndex].TabPage = DragTab; } - finally - { - this.ResumeDrawing(); - } -#endif SelectedTab = DragTab; @@ -449,36 +405,6 @@ protected override void OnMouseMove(MouseEventArgs e) SelectedTab.Focus(); } - protected override void OnDeselecting(TabControlCancelEventArgs e) - { - if (EventsDisabled > 0) return; - base.OnDeselecting(e); - } - - protected override void OnDeselected(TabControlEventArgs e) - { - if (EventsDisabled > 0) return; - base.OnDeselected(e); - } - - protected override void OnSelecting(TabControlCancelEventArgs e) - { - if (EventsDisabled > 0) return; - base.OnSelecting(e); - } - - protected override void OnSelected(TabControlEventArgs e) - { - if (EventsDisabled > 0) return; - base.OnSelected(e); - } - - protected override void OnSelectedIndexChanged(EventArgs e) - { - if (EventsDisabled > 0) return; - base.OnSelectedIndexChanged(e); - } - #endregion #region Public methods From fbb239459f249edff061cf001ebf74c8ad96ac23 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 18:47:55 -0800 Subject: [PATCH 130/200] Keep tab pos consistent when dragging between tab controls --- .../Forms/CustomControls/DarkTabControl.cs | 47 ++++++++++++++++++- AngelLoader/Forms/MainForm.cs | 1 + 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 0a0b0a3ac..9bbcb48e9 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -24,6 +24,46 @@ public sealed class DarkTabControl : TabControl, IDarkable private List _backingTabList = new(0); + #region Back up backing tabs + + /* + The user can drag tabs horizontally in the same move as they're trying to drag them into the other tab + control. In that case, if the user commits the move, we want to revert the horizontal movement they did + and put the tab in the new control at the same relative position as it was before the user started the + drag. The easiest way to do that is to simply save the backing tabs list before the move and then restore + it if and only if the user commits the between-tab-control move. + */ + + private List? _backedUpBackingTabs; + + private void BackUpBackingTabs() + { + _backedUpBackingTabs = new List(_backingTabList.Count); + foreach (BackingTab backingTab in _backingTabList) + { + _backedUpBackingTabs.Add(new BackingTab(backingTab.TabPage) { VisibleIn = backingTab.VisibleIn }); + } + } + + internal void RestoreBackedUpBackingTabs() + { + if (_backedUpBackingTabs == null || _backedUpBackingTabs.Count != _backingTabList.Count) + { + return; + } + + for (int i = 0; i < _backingTabList.Count; i++) + { + BackingTab backingTab = _backingTabList[i]; + BackingTab backedUpBackingTab = _backedUpBackingTabs[i]; + backingTab.TabPage = backedUpBackingTab.TabPage; + backingTab.VisibleIn = backedUpBackingTab.VisibleIn; + } + _backedUpBackingTabs = null; + } + + #endregion + /// /// Use this to use an external list rather than the internal one. /// Use when you want multiple controls to use the same list. @@ -290,7 +330,11 @@ protected override void OnMouseDown(MouseEventArgs e) return; } - if (e.Button == MouseButtons.Left) (_, DragTab) = GetTabAtPoint(e.Location); + if (e.Button == MouseButtons.Left) + { + (_, DragTab) = GetTabAtPoint(e.Location); + if (DragTab != null) BackUpBackingTabs(); + } base.OnMouseDown(e); } @@ -307,6 +351,7 @@ protected override void OnMouseUp(MouseEventArgs e) // Fix: Ensure we don't start dragging a tab again after we've released the button. DragTab = null; + _backedUpBackingTabs = null; } protected override void OnMouseMove(MouseEventArgs e) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index b9fbb841b..ea5565f1e 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5558,6 +5558,7 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa ? LowerSplitContainer : TopSplitContainer; + sourceTabControl.RestoreBackedUpBackingTabs(); sourceTabControl.ShowTab(tabPage, false); destTabControl.ShowTab(tabPage, true); if (sourceTabControl.TabCount == 0) From 3c22e19f402ea39557a5d5bd55d10d54a1303131 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 19:26:26 -0800 Subject: [PATCH 131/200] Fix bottom tab order wasn't preserved across app runs --- .../Forms/CustomControls/DarkTabControl.cs | 9 ++++--- AngelLoader/Forms/MainForm.cs | 25 +++++++++++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 9bbcb48e9..6df2c67e9 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -142,19 +142,22 @@ public Control[] BackingTabPagesAsControls #region Private methods - internal static (int Index, BackingTab BackingTab) + internal (int Index, BackingTab BackingTab) FindBackingTab(List backingTabs, TabPage tabPage, bool indexVisibleOnly = false) { for (int i = 0, vi = 0; i < backingTabs.Count; i++) { BackingTab backingTab = backingTabs[i]; - // @DockUI: Could we make this our specific top/bottom value and get better ordering between moves? - if (indexVisibleOnly && backingTab.VisibleIn != FMTabVisibleIn.None) vi++; + if (indexVisibleOnly && VisibleInEqualsWhich(backingTab.VisibleIn, _whichTabControl)) vi++; if (backingTab.TabPage == tabPage) return (indexVisibleOnly ? vi : i, backingTab); } // We should never get here! (unless we're in infernal-forsaken design mode...!) throw new InvalidOperationException("Can't find backing tab?!"); + + static bool VisibleInEqualsWhich(FMTabVisibleIn visibleIn, WhichTabControl which) => + (visibleIn == FMTabVisibleIn.Top && which == WhichTabControl.Top) || + (visibleIn == FMTabVisibleIn.Bottom && which == WhichTabControl.Bottom); } private (int BackingTabIndex, TabPage? TabPage) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index ea5565f1e..165db105d 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -929,7 +929,6 @@ and does NOT have its text transferred over. It ends up with blank text. } // EnsureValidity() guarantees selected tab will not be invisible - // @DockUI: Set selected tab on bottom (if constructed and has at least one tab) for (int i = 0; i < FMTabCount; i++) { if ((int)Config.FMTabsData.SelectedTab == i) @@ -938,6 +937,17 @@ and does NOT have its text transferred over. It ends up with blank text. break; } } + if (Lazy_LowerTabControl.Constructed) + { + for (int i = 0; i < FMTabCount; i++) + { + if ((int)Config.FMTabsData.SelectedTab2 == i) + { + Lazy_LowerTabControl.TabControl.SelectedTab = _fmTabPages[i]; + break; + } + } + } #endregion @@ -5060,7 +5070,7 @@ public void UpdateConfig() for (int i = 0; i < FMTabCount; i++) { Lazy_TabsBase fmTab = _fmTabPages[i]; - fmTabs.Tabs[i].DisplayIndex = DarkTabControl.FindBackingTab(_backingFMTabs, fmTab).Index; + fmTabs.Tabs[i].DisplayIndex = TopFMTabControl.FindBackingTab(_backingFMTabs, fmTab).Index; fmTabs.Tabs[i].Visible = _backingFMTabs.FirstOrDefault(x => x.TabPage == fmTab)?.VisibleIn ?? FMTabVisibleIn.Top; } @@ -5619,5 +5629,16 @@ private void HandleTabDrag(DarkSplitContainerCustom sc) } } + // @DockUI: Test code, remove for final release + internal void PrintBackingTabs() + { + Trace.WriteLine("========================="); + for (int i = 0; i < _backingFMTabs.Count; i++) + { + BackingTab backingTab = _backingFMTabs[i]; + Trace.WriteLine(i.ToStrInv() + ": Tab: " + backingTab.TabPage.Text + ", VisibleIn: " + backingTab.VisibleIn); + } + } + #endregion } From e76c8fafdbca51e72e5f7bf94f6124a59f1cdd4a Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 19:58:18 -0800 Subject: [PATCH 132/200] Fix another glitch with the fast movement --- AngelLoader/Forms/CustomControls/DarkTabControl.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 6df2c67e9..1385987e4 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -429,6 +429,7 @@ protected override void OnMouseMove(MouseEventArgs e) for (int i = bDragTabIndex; i < bNewTabIndex; i++) { _backingTabList[i].TabPage = _backingTabList[i + 1].TabPage; + _backingTabList[i].VisibleIn = _backingTabList[i + 1].VisibleIn; } } else @@ -440,6 +441,7 @@ protected override void OnMouseMove(MouseEventArgs e) for (int i = bDragTabIndex - 1; i >= bNewTabIndex; i--) { _backingTabList[i + 1].TabPage = _backingTabList[i].TabPage; + _backingTabList[i + 1].VisibleIn = _backingTabList[i].VisibleIn; } } From ff180d768e2bc90b7fab3a0542e3a3b4ed5c9f4b Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 20:50:37 -0800 Subject: [PATCH 133/200] Fix the stubborn focus thing when moving tabs between controls Got you... --- AngelLoader/Forms/ControlUtils.cs | 24 ++++++++++++++++++++++++ AngelLoader/Forms/MainForm.cs | 11 ++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/AngelLoader/Forms/ControlUtils.cs b/AngelLoader/Forms/ControlUtils.cs index 8204355f2..ea1baeeee 100644 --- a/AngelLoader/Forms/ControlUtils.cs +++ b/AngelLoader/Forms/ControlUtils.cs @@ -43,6 +43,30 @@ internal static void ResumeDrawing(this Control control, bool invalidateInsteadO } } + internal static void ResumeDrawingAndFocusControl(this Control control, Control? controlToFocus, bool invalidateInsteadOfRefresh = false) + { + if (!control.IsHandleCreated || !control.Visible) return; + Native.SendMessage(control.Handle, Native.WM_SETREDRAW, true, IntPtr.Zero); + + /* + Focus after the enable-redraw message but before the refresh. + If we put it before the enable-redraw message, the focus will be lost; if we put it after, there's a + short visible blip of the default focus before we change it. + + Designed originally for the tab control, but use it for whatever... + */ + controlToFocus?.Focus(); + + if (invalidateInsteadOfRefresh) + { + control.Invalidate(); + } + else + { + control.Refresh(); + } + } + #endregion #region Centering diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 165db105d..9124f3878 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5492,12 +5492,12 @@ internal void Lazy_LowerTabControl_MouseDragCustom(object sender, MouseEventArgs private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) { if (!_inTabDragArea) return; - + TabPage? dragTab = null; try { EverythingPanel.SuspendDrawing(); - TabPage? dragTab = TopFMTabControl.DragTab; + dragTab = TopFMTabControl.DragTab; if (dragTab == null) return; ConstructLazyLowerTabControl(); @@ -5506,7 +5506,7 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) finally { _inTabDragArea = false; - EverythingPanel.ResumeDrawing(); + EverythingPanel.ResumeDrawingAndFocusControl(dragTab); } } @@ -5514,11 +5514,12 @@ internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) { if (!_inTabDragArea) return; + TabPage? dragTab = null; try { EverythingPanel.SuspendDrawing(); - TabPage? dragTab = Lazy_LowerTabControl.DragTab; + dragTab = Lazy_LowerTabControl.DragTab; if (dragTab == null) return; if (TopSplitContainer.Panel2Collapsed) @@ -5534,7 +5535,7 @@ internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) finally { _inTabDragArea = false; - EverythingPanel.ResumeDrawing(); + EverythingPanel.ResumeDrawingAndFocusControl(dragTab); } } From 8b2485232db048bf102c4196f6821377127b8ea6 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 21:19:28 -0800 Subject: [PATCH 134/200] Cleanup and remove old todos --- AngelLoader/Forms/MainForm.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 9124f3878..2f4ec3b1d 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -1,10 +1,4 @@ /* -@DockUI general notes: --We need to handle the readme fullscreening thing. Is it safe to allow interacting with tabs while the readme is - fullscreened? Or should we hide the beside-readme area too? - ----------------------- - NOTE: MainForm notes: @LazyLoad: Controls that can be lazy-loaded in principle: @@ -4267,6 +4261,11 @@ private void ReadmeButtons_Click(object sender, EventArgs e) { if (sender == ReadmeFullScreenButton) { + /* + @DockUI(readme fullscreen): + We need to handle the readme fullscreening thing. Is it safe to allow interacting with tabs while the + readme is fullscreened? Or should we hide the beside-readme area too? + */ MainSplitContainer.ToggleFullScreen(); ShowReadmeControls(CursorOverReadmeArea()); } @@ -5473,8 +5472,6 @@ public void RefreshCurrentFMScreenshots() #region Tab dragging /* @DockUI: Working/testing code, finalize before release - @DockUI: Detect the position dragged to, and if it's in the tab bar, insert the tab at that location - @DockUI: Focus tab when moving between tab controls, to prevent first-control-select issue again */ private bool _inTabDragArea; From 8096f48c1dacb38cbe2cd879457248a7c313fbb3 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sat, 2 Mar 2024 21:48:20 -0800 Subject: [PATCH 135/200] Remove duplicate array cast thing --- AngelLoader/Forms/MainForm.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 2f4ec3b1d..603ff8870 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5049,20 +5049,23 @@ public void UpdateConfig() SelectedFM selectedFM = FMsDGV.GetMainSelectedFMPosInfo(); + #region FM tabs + FMTabsData fmTabs = new(); + TabPage[] fmTabPagesAsTabPages = _fmTabPages.Cast().ToArray(); + int selectedTabIndex = -1; if (TopFMTabControl.TabCount > 0) { - // @DockUI: Duplicate Cast/ToArray() - selectedTabIndex = Array.IndexOf(_fmTabPages.Cast().ToArray(), TopFMTabControl.SelectedTab); + selectedTabIndex = Array.IndexOf(fmTabPagesAsTabPages, TopFMTabControl.SelectedTab); } fmTabs.SelectedTab = selectedTabIndex > -1 ? (FMTab)selectedTabIndex : Config.FMTabsData.SelectedTab; int selectedTab2Index = -1; if (Lazy_LowerTabControl.TabCount > 0) { - selectedTab2Index = Array.IndexOf(_fmTabPages.Cast().ToArray(), Lazy_LowerTabControl.SelectedTab); + selectedTab2Index = Array.IndexOf(fmTabPagesAsTabPages, Lazy_LowerTabControl.SelectedTab); } fmTabs.SelectedTab2 = selectedTab2Index > -1 ? (FMTab)selectedTab2Index : Config.FMTabsData.SelectedTab2; @@ -5073,6 +5076,8 @@ public void UpdateConfig() fmTabs.Tabs[i].Visible = _backingFMTabs.FirstOrDefault(x => x.TabPage == fmTab)?.VisibleIn ?? FMTabVisibleIn.Top; } + #endregion + #region Quick hack to prevent splitter distances from freaking out if we're closing while minimized FormWindowState nominalState = _nominalWindowState; From 5a2a565c65ccba55365a6c4dea8b8d02112d0b1f Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 08:09:59 -0800 Subject: [PATCH 136/200] Start implementing lower collapse/menu buttons --- .../LazyLoaded/Lazy_LowerTabControl.cs | 57 +++++++++++++++++-- AngelLoader/Forms/MainForm.cs | 30 ++++++---- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 16a93f554..82ded4087 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -1,4 +1,5 @@ -using System.Windows.Forms; +using System.Drawing; +using System.Windows.Forms; using JetBrains.Annotations; namespace AngelLoader.Forms.CustomControls.LazyLoaded; @@ -19,6 +20,9 @@ public DarkTabControl TabControl } } + internal DarkButton MenuButton = null!; + internal DarkArrowButton CollapseButton = null!; + private bool _darkModeEnabled; [PublicAPI] public bool DarkModeEnabled @@ -29,6 +33,8 @@ public bool DarkModeEnabled _darkModeEnabled = value; if (!Constructed) return; + MenuButton.DarkModeEnabled = value; + CollapseButton.DarkModeEnabled = value; TabControl.DarkModeEnabled = value; } } @@ -37,12 +43,15 @@ public bool DarkModeEnabled public Lazy_LowerTabControl(MainForm owner) => _owner = owner; - private void Construct() + // @DockUI: We may be able to just call this implicitly through accessing TabControl + internal void Construct() { if (Constructed) return; var container = _owner.LowerSplitContainer.Panel2; + _owner.LowerSplitContainer.Panel2Collapsed = false; + _tabControl = new DarkTabControl { Tag = LoadType.Lazy, @@ -50,23 +59,61 @@ private void Construct() AllowReordering = true, Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, EnableScrollButtonsRefreshHack = true, - Size = container.Size, + Size = new Size(container.Width - 16, container.Height + 1), + + DarkModeEnabled = _darkModeEnabled }; _tabControl.SetWhich(WhichTabControl.Bottom); + _tabControl.SetBackingList(_owner._backingFMTabs); // Handle hack here instead, because it needs to be for whatever finicky goddamn reason _ = _tabControl.Handle; - _tabControl.DarkModeEnabled = _darkModeEnabled; _tabControl.MouseClick += _owner.LowerFMTabsBar_MouseClick; - _owner.LowerSplitContainer.Panel2.MouseClick += _owner.LowerFMTabsBar_MouseClick; + container.MouseClick += _owner.LowerFMTabsBar_MouseClick; _tabControl.Selected += TabControl_Selected; _tabControl.MouseDragCustom += _owner.Lazy_LowerTabControl_MouseDragCustom; _tabControl.MouseUp += _owner.Lazy_LowerTabControl_MouseUp; _tabControl.VisibleChanged += TabControl_VisibleChanged; + MenuButton = new DarkButton + { + Tag = LoadType.Lazy, + + Anchor = AnchorStyles.Top | AnchorStyles.Right, + FlatAppearance = { BorderSize = 0 }, + FlatStyle = FlatStyle.Flat, + Location = new Point(container.Width - 18, 0), + Size = new Size(18, 20), + TabIndex = 1, + + DarkModeEnabled = _darkModeEnabled + }; + MenuButton.Click += _owner.LowerFMTabsMenuButton_Click; + MenuButton.PaintCustom += _owner.FMTabsMenuButton_Paint; + + CollapseButton = new DarkArrowButton + { + Tag = LoadType.Lazy, + + Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right, + ArrowDirection = Direction.Right, + FlatAppearance = { BorderSize = 0 }, + FlatStyle = FlatStyle.Flat, + Location = new Point(container.Width - 18, 20), + Size = new Size(18, container.Height - 20), + TabIndex = 2, + + DarkModeEnabled = _darkModeEnabled + }; + CollapseButton.Click += _owner.LowerFMTabsCollapseButton_Click; + + container.Controls.Add(MenuButton); + container.Controls.Add(CollapseButton); + container.Controls.Add(_tabControl); + Constructed = true; } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 603ff8870..7128a8184 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -191,7 +191,7 @@ private enum ZoomFMsDGVType // Cache visible state because calling Visible redoes the work even if the value is the same private bool _readmeControlsOtherThanComboBoxVisible; - private readonly List _backingFMTabs = new(FMTabCount); + internal readonly List _backingFMTabs = new(FMTabCount); #endregion @@ -916,7 +916,7 @@ and does NOT have its text transferred over. It ends up with blank text. } else if (visible == FMTabVisibleIn.Bottom) { - ConstructLazyLowerTabControl(); + Lazy_LowerTabControl.Construct(); MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, fmTabPage); } Lazy_FMTabsMenu.SetItemChecked(i, visible != FMTabVisibleIn.None); @@ -3261,6 +3261,13 @@ private void TopFMTabsCollapseButton_Click(object sender, EventArgs e) SetTopRightCollapsedState(TopSplitContainer.FullScreen); } + internal void LowerFMTabsCollapseButton_Click(object sender, EventArgs e) + { + // @DockUI: Implement + //TopSplitContainer.ToggleFullScreen(); + //SetTopRightCollapsedState(TopSplitContainer.FullScreen); + } + // @DockUI: We need to handle the bottom tab control / collapsed state here too private void SetTopRightCollapsedState(bool collapsed) { @@ -3285,12 +3292,19 @@ private void SetTopRightCollapsedState(bool collapsed) } } + // @DockUI: Could we combine these eventually? private void TopFMTabsMenuButton_Click(object sender, EventArgs e) { Lazy_FMTabsMenu.Menu.Data = WhichTabControl.Top; ControlUtils.ShowMenu(Lazy_FMTabsMenu.Menu, TopFMTabsMenuButton, MenuPos.BottomLeft); } + internal void LowerFMTabsMenuButton_Click(object sender, EventArgs e) + { + Lazy_FMTabsMenu.Menu.Data = WhichTabControl.Bottom; + ControlUtils.ShowMenu(Lazy_FMTabsMenu.Menu, Lazy_LowerTabControl.MenuButton, MenuPos.BottomLeft); + } + internal void FMTabsMenu_Opening(object sender, CancelEventArgs e) { (FMTabVisibleIn which, DarkTabControl tabControl) = Lazy_FMTabsMenu.Menu.Data is WhichTabControl.Bottom @@ -4936,7 +4950,7 @@ private void SettingsButton_Paint(object sender, PaintEventArgs e) => Images.Pai SettingsButton.Enabled ? Images.Settings : Images.GetDisabledImage(Images.Settings), x: 10); - private void FMTabsMenuButton_Paint(object sender, PaintEventArgs e) => Images.PaintHamburgerMenuButton_FMTabs(TopFMTabsMenuButton, e); + internal void FMTabsMenuButton_Paint(object sender, PaintEventArgs e) => Images.PaintHamburgerMenuButton_FMTabs((Button)sender, e); private void MainMenuButton_Paint(object sender, PaintEventArgs e) => Images.PaintHamburgerMenuButton24(MainMenuButton, e); @@ -5502,7 +5516,7 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) dragTab = TopFMTabControl.DragTab; if (dragTab == null) return; - ConstructLazyLowerTabControl(); + Lazy_LowerTabControl.Construct(); MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, dragTab); } finally @@ -5583,14 +5597,6 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa tabPage.Focus(); } - private void ConstructLazyLowerTabControl() - { - if (Lazy_LowerTabControl.Constructed) return; - LowerSplitContainer.Panel2Collapsed = false; - Lazy_LowerTabControl.TabControl.SetBackingList(_backingFMTabs); - LowerSplitContainer.Panel2.Controls.Add(Lazy_LowerTabControl.TabControl); - } - private void HandleTabDrag(DarkSplitContainerCustom sc) { Point cp = Native.GetCursorPosition_Fast(); From 01e068f1f6805b087a3e1d6e14fd9d6eee37022d Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 09:09:28 -0800 Subject: [PATCH 137/200] Mostly finish implementing bottom tab collapsing --- AngelLoader/Common/DataClasses/ConfigData.cs | 3 +- AngelLoader/Core.cs | 6 +- .../LazyLoaded/Lazy_LowerTabControl.cs | 20 +++ .../LazyLoaded/Lazy_TopRightBlocker.cs | 11 +- AngelLoader/Forms/FormsViewEnvironment.cs | 5 +- AngelLoader/Forms/MainForm.Designer.cs | 1 + AngelLoader/Forms/MainForm.cs | 83 ++++++---- AngelLoader/Forms/MainForm.resx | 143 +++++++++--------- AngelLoader/Forms/MainForm_InitManual.cs | 1 + AngelLoader/Ini/ConfigIni.cs | 15 +- 10 files changed, 177 insertions(+), 111 deletions(-) diff --git a/AngelLoader/Common/DataClasses/ConfigData.cs b/AngelLoader/Common/DataClasses/ConfigData.cs index 21ad4277a..9110c8aa2 100644 --- a/AngelLoader/Common/DataClasses/ConfigData.cs +++ b/AngelLoader/Common/DataClasses/ConfigData.cs @@ -347,7 +347,8 @@ internal float FMsListFontSizeInPoints private float _lowerSplitterPercent = Defaults.LowerSplitterPercent; internal float LowerSplitterPercent { get => _lowerSplitterPercent; set => _lowerSplitterPercent = value.ClampZeroToOne(); } - internal bool TopRightPanelCollapsed; + internal bool TopFMTabsPanelCollapsed; + internal bool BottomFMTabsPanelCollapsed; internal readonly FMTabsData FMTabsData = new(); diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index 5c1b090a0..3817137f5 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2613,7 +2613,8 @@ internal static void UpdateConfig( GameTabsState gameTabsState, GameIndex gameTab, FMTabsData fmTabsData, - bool topRightPanelCollapsed, + bool topFMTabsPanelCollapsed, + bool bottomFMTabsPanelCollapsed, float readmeZoomFactor) { #region Main window state @@ -2658,7 +2659,8 @@ internal static void UpdateConfig( Config.FMTabsData.EnsureValidity(); - Config.TopRightPanelCollapsed = topRightPanelCollapsed; + Config.TopFMTabsPanelCollapsed = topFMTabsPanelCollapsed; + Config.BottomFMTabsPanelCollapsed = bottomFMTabsPanelCollapsed; #endregion diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 82ded4087..6e078b13c 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -20,6 +20,8 @@ public DarkTabControl TabControl } } + private bool _enabled = true; + internal DarkButton MenuButton = null!; internal DarkArrowButton CollapseButton = null!; @@ -114,6 +116,8 @@ internal void Construct() container.Controls.Add(CollapseButton); container.Controls.Add(_tabControl); + _tabControl.Enabled = _enabled; + Constructed = true; } @@ -131,6 +135,22 @@ public void ShowTab(TabPage tabPage, bool show) } } + public bool Enabled + { + get => Constructed ? _tabControl.Enabled : _enabled; + set + { + if (Constructed) + { + _tabControl.Enabled = value; + } + else + { + _enabled = value; + } + } + } + public int TabCount => Constructed ? _tabControl.TabCount : 0; public TabPage? SelectedTab => Constructed ? _tabControl.SelectedTab : null; diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs index 0e7c7a5b1..6e592e935 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs @@ -11,6 +11,8 @@ internal sealed class Lazy_FMTabsBlocker : IDarkable private bool _constructed; + private WhichTabControl _which; + private string _text = ""; private DrawnPanel Panel = null!; @@ -33,6 +35,8 @@ public bool DarkModeEnabled internal Lazy_FMTabsBlocker(MainForm owner) => _owner = owner; + internal void SetWhich(WhichTabControl which) => _which = which; + internal void SetText(string text) { if (_constructed) @@ -49,13 +53,18 @@ private void Construct() { if (_constructed) return; - var container = _owner.TopSplitContainer.Panel2; + var container = + _which == WhichTabControl.Bottom + ? _owner.LowerSplitContainer.Panel2 + : _owner.TopSplitContainer.Panel2; Panel = new DrawnPanel { Location = Point.Empty, Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom, Size = new Size( + // @DockUI: Button widths are the same so this works for now, but make it better + // Maybe once we lazy-load the top control, we can have a global constant for width container.Width - _owner.TopFMTabsCollapseButton.Width, container.Height), DarkModeDrawnBackColor = DarkColors.Fen_ControlBackground, diff --git a/AngelLoader/Forms/FormsViewEnvironment.cs b/AngelLoader/Forms/FormsViewEnvironment.cs index 00908ab79..4f9df4d10 100644 --- a/AngelLoader/Forms/FormsViewEnvironment.cs +++ b/AngelLoader/Forms/FormsViewEnvironment.cs @@ -53,13 +53,14 @@ to match whatever the UI setup is. */ var screenshotsTab = config.FMTabsData.GetTab(FMTab.Screenshots); if (screenshotsTab.Visible == FMTabVisibleIn.Top && - (config.TopRightPanelCollapsed || + (config.TopFMTabsPanelCollapsed || config.FMTabsData.SelectedTab != FMTab.Screenshots)) { return; } else if (screenshotsTab.Visible == FMTabVisibleIn.Bottom && - config.FMTabsData.SelectedTab2 != FMTab.Screenshots) + (config.BottomFMTabsPanelCollapsed || + config.FMTabsData.SelectedTab2 != FMTab.Screenshots)) { return; } diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 2bc3080a8..1042ea2ed 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -984,6 +984,7 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.LowerSplitContainer.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.LowerSplitContainer.FullScreenCollapsePanel = AngelLoader.Forms.CustomControls.DarkSplitContainerCustom.Panel.Panel2; this.LowerSplitContainer.Location = new System.Drawing.Point(0, 0); this.LowerSplitContainer.Name = "LowerSplitContainer"; // diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 7128a8184..b4e26f06b 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -182,7 +182,8 @@ private enum ZoomFMsDGVType private readonly Lazy_FMTabsMenu Lazy_FMTabsMenu; private readonly ViewHTMLReadmeLLButton ViewHTMLReadmeLLButton; private readonly Lazy_WebSearchButton Lazy_WebSearchButton; - private readonly Lazy_FMTabsBlocker Lazy_FMTabsBlocker; + private readonly Lazy_FMTabsBlocker Lazy_TopFMTabsBlocker; + private readonly Lazy_FMTabsBlocker Lazy_BottomFMTabsBlocker; internal readonly Lazy_UpdateNotification Lazy_UpdateNotification; private readonly Lazy_LowerTabControl Lazy_LowerTabControl; @@ -582,10 +583,13 @@ but whatever... Lazy_FMTabsMenu = new Lazy_FMTabsMenu(this), ViewHTMLReadmeLLButton = new ViewHTMLReadmeLLButton(this), Lazy_WebSearchButton = new Lazy_WebSearchButton(this), - Lazy_FMTabsBlocker = new Lazy_FMTabsBlocker(this), + Lazy_TopFMTabsBlocker = new Lazy_FMTabsBlocker(this), + Lazy_BottomFMTabsBlocker = new Lazy_FMTabsBlocker(this), Lazy_UpdateNotification = new Lazy_UpdateNotification(this), Lazy_LowerTabControl = new Lazy_LowerTabControl(this) }; + Lazy_TopFMTabsBlocker.SetWhich(WhichTabControl.Top); + Lazy_BottomFMTabsBlocker.SetWhich(WhichTabControl.Bottom); #endregion @@ -1044,10 +1048,18 @@ and does NOT have its text transferred over. It ends up with blank text. if (!Config.HideWebSearchButton) ShowWebSearchButton(true); TopSplitContainer.CollapsedSize = TopFMTabsCollapseButton.Width; - if (Config.TopRightPanelCollapsed) + // @DockUI: Button widths are the same so this works for now, but make it better + LowerSplitContainer.CollapsedSize = TopFMTabsCollapseButton.Width; + + if (Config.TopFMTabsPanelCollapsed) { TopSplitContainer.SetFullScreen(true, suspendResume: false); - SetTopRightCollapsedState(true); + SetFMTabsCollapsedState(WhichTabControl.Top, true); + } + if (Config.BottomFMTabsPanelCollapsed) + { + LowerSplitContainer.SetFullScreen(true, suspendResume: false); + SetFMTabsCollapsedState(WhichTabControl.Bottom, true); } #endregion @@ -1205,7 +1217,7 @@ private void SetWindowStateAndSize() if (!_firstShowDone) { // @DockUI: We need to handle the bottom tab control / collapsed state here too - if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab && !Config.TopRightPanelCollapsed) + if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab && !Config.TopFMTabsPanelCollapsed) { lazyTab.Construct(); } @@ -1489,7 +1501,7 @@ async Task HandleHomeOrEnd(bool home, bool selectionSyncHack = true) { _displayedFM = await Core.DisplayFM(); } - SetTopRightBlockerVisible(); + SetFMTabBlockersVisible(); if (selectionSyncHack) { @@ -1543,7 +1555,7 @@ async Task HandleHomeOrEnd(bool home, bool selectionSyncHack = true) } SelectAndSuppress(edgeRow.Index, singleSelect: !e.Shift, selectionSyncHack: true); // Have to do these manually because we're suppressing the normal chain of selection logic - SetTopRightBlockerVisible(); + SetFMTabBlockersVisible(); UpdateUIControlsForMultiSelectState(FMsDGV.GetMainSelectedFM()); } } @@ -3247,7 +3259,7 @@ void DoSelect() #region Top-right area - internal void FMTabControl_Selected(object sender, TabControlEventArgs e) + private void FMTabControl_Selected(object sender, TabControlEventArgs e) { if (e.Action == TabControlAction.Selected && e.TabPage is Lazy_TabsBase lazyTab) { @@ -3258,34 +3270,37 @@ internal void FMTabControl_Selected(object sender, TabControlEventArgs e) private void TopFMTabsCollapseButton_Click(object sender, EventArgs e) { TopSplitContainer.ToggleFullScreen(); - SetTopRightCollapsedState(TopSplitContainer.FullScreen); + SetFMTabsCollapsedState(WhichTabControl.Top, TopSplitContainer.FullScreen); } internal void LowerFMTabsCollapseButton_Click(object sender, EventArgs e) { - // @DockUI: Implement - //TopSplitContainer.ToggleFullScreen(); - //SetTopRightCollapsedState(TopSplitContainer.FullScreen); + LowerSplitContainer.ToggleFullScreen(); + SetFMTabsCollapsedState(WhichTabControl.Bottom, LowerSplitContainer.FullScreen); } - // @DockUI: We need to handle the bottom tab control / collapsed state here too - private void SetTopRightCollapsedState(bool collapsed) + private void SetFMTabsCollapsedState(WhichTabControl which, bool collapsed) { + (DarkArrowButton collapseButton, DarkTabControl tabControl, Lazy_FMTabsBlocker blocker) = + which == WhichTabControl.Bottom + ? (Lazy_LowerTabControl.CollapseButton, Lazy_LowerTabControl.TabControl, Lazy_TopFMTabsBlocker) + : (TopFMTabsCollapseButton, TopFMTabControl, Lazy_BottomFMTabsBlocker); + if (collapsed) { - TopFMTabsCollapseButton.ArrowDirection = Direction.Left; - TopFMTabControl.Enabled = false; + collapseButton.ArrowDirection = Direction.Left; + tabControl.Enabled = false; } else { - TopFMTabsCollapseButton.ArrowDirection = Direction.Right; + collapseButton.ArrowDirection = Direction.Right; - if (!Lazy_FMTabsBlocker.Visible) + if (!blocker.Visible) { - TopFMTabControl.Enabled = true; + tabControl.Enabled = true; } - if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab) + if (tabControl.SelectedTab is Lazy_TabsBase lazyTab) { lazyTab.ConstructWithSuspendResume(); } @@ -3369,18 +3384,24 @@ internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) tabControl.ShowTab(tab, s.Checked); } - private void SetTopRightBlockerVisible() + private void SetFMTabBlockersVisible() { // Always make sure the blocker is covering up the enabled changed work, to prevent flicker of it if (FMsDGV.MultipleFMsSelected()) { - Lazy_FMTabsBlocker.Visible = true; + Lazy_TopFMTabsBlocker.Visible = true; if (!TopSplitContainer.FullScreen) TopFMTabControl.Enabled = false; + + Lazy_BottomFMTabsBlocker.Visible = true; + if (!LowerSplitContainer.FullScreen) Lazy_LowerTabControl.Enabled = false; } else { if (!TopSplitContainer.FullScreen) TopFMTabControl.Enabled = true; - Lazy_FMTabsBlocker.Visible = false; + Lazy_TopFMTabsBlocker.Visible = false; + + if (!LowerSplitContainer.FullScreen) Lazy_LowerTabControl.Enabled = true; + Lazy_BottomFMTabsBlocker.Visible = false; } } @@ -4543,7 +4564,7 @@ private void ClearShownData() _displayedFM = null; - SetTopRightBlockerVisible(); + SetFMTabBlockersVisible(); } /* @@ -4674,18 +4695,20 @@ void UpdateValues(FanMission selectedFM) anyAreTDM = gameIsTDMCount > 0; } - // Exactly this order or we get the top-right tabs not being in a properly refreshed state + // Exactly this order or we get the FM tabs not being in a properly refreshed state try { - SetTopRightBlockerVisible(); + SetFMTabBlockersVisible(); - Lazy_FMTabsBlocker.SuspendDrawing(); + Lazy_TopFMTabsBlocker.SuspendDrawing(); + Lazy_BottomFMTabsBlocker.SuspendDrawing(); SetFMSelectedCountMessage(selRowsCount); } finally { - Lazy_FMTabsBlocker.ResumeDrawing(); + Lazy_BottomFMTabsBlocker.ResumeDrawing(); + Lazy_TopFMTabsBlocker.ResumeDrawing(); } #endregion @@ -5130,6 +5153,7 @@ public void UpdateConfig() gameTab, fmTabs, TopSplitContainer.FullScreen, + LowerSplitContainer.FullScreen, ReadmeRichTextBox.ZoomFactor); } @@ -5333,7 +5357,8 @@ private void SetFMSelectedCountMessage(int count, bool forceRefresh = false) _fmsSelectedCountText = text; - Lazy_FMTabsBlocker.SetText(text); + Lazy_TopFMTabsBlocker.SetText(text); + Lazy_BottomFMTabsBlocker.SetText(text); RefreshFMStatsLabel(); } diff --git a/AngelLoader/Forms/MainForm.resx b/AngelLoader/Forms/MainForm.resx index 8e8cd7081..bfc7cdc79 100644 --- a/AngelLoader/Forms/MainForm.resx +++ b/AngelLoader/Forms/MainForm.resx @@ -125,45 +125,45 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAK - EwAAAk1TRnQBSQFMAgEBBAEAAZgBGwGYARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + EwAAAk1TRnQBSQFMAgEBBAEAAaABGwGgARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgADBQEGA0IBdANP AZkDVQGxA1sBygNWAbUDTAGRA0YBgAMcAScoAAMNAREDSgGLA1ABmgMeASsYAAMDAQQDVQGtA1gBvQNO AZYDYAHgA1ABnzQAAwIBAwMZASIDWgHHA1IBoANBAXMDQAFvAzQBUwMpAT0DHQEpAx4BKgMPARMDBQEG DAADIwEzA2AB6AMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/Az4BahgAAwwBEAMFAQYEAAMr AUECAAGXAf8DAAH/A0ABcAwAAwMEBAEFBAADBQEGAYYBiwEAAf8ByQHNAQAB/wGQAZYBAAH/AaoBugEA Af8DWgHHAy0BRgMZASIDKAE7AzkBXgNCAXQDPwFuAzkBXgMIAQoMAAQBAw8BFAMuAUgDVgGwA0AB/QNA - Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABUQFtAYAB/gMAAf8DWgHE + Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABUgFuAYAB/gMAAf8DWgHE ASMBXgEhAfsDAAH/AgABnAH/AwAB/wMAAf8DWwHkA0EB+QMAAf8DQwF3DAADCQEMA1ABnwNdAckDPQFo A0YBgQNdAc8BAAGVAcoB/wMAAf8DXgHXA0MBdgMzAVEDVgGwA0YBfgMTARkIAAMsAUMDYQHiAv8BAAH/ - A1wB2QF8AYABSwH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA + A1wB2QF9AYABTAH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA ARABAAH/AwAB/wEKAQwBBwH/ASYBPQE6Af8BHwEyATAB/wEAARABAAH/AwAB/wEGASMBAAH/AQMBIgEA Af8DXgHwA0QBeQMIAQoEAANdAdEDAAH/A0sBjANdAcwDAAH/AwAB/wIAAZgB/wIAAZYB/wNAAf0DXAH4 A1EBpANRAfcDAAH/AyIBMQgAAx8BLAEAAY4BpwH/AgABmgH/AwAB/wEAAZQBvQH/AQABzgL/AQABsQHe Af8BAAGYAdIB/wEAAYUBygH/AwAB/wMrAfwBAAGnAcgB/wNZAe8DHgErDAADRgF9AbwBwQEAAf8DVQG0 - A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFcAXEBSwH+ + A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFdAXIBTAH+ ARIBSQEAAf8BDAE0AQAB/wEsAjUB/wEPARYBFwH/ARcCHwH/ARcBHQEeAf8BCgE2AQAB/wEKASQBAAH/ - AXEBgAFdAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 + AXIBgAFeAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 AwAB/wNGAYEDTgGXAwAB/wNWAbAMAANEAXsBAAGyAdgB/wEAAbcB9QH/AQAB0QH5Af8BAAGZAZ4B/wEA AbMBzwH/AQABjgGtAf8BAAGyAccB/wEAAdcC/wEAAesC/wEAAZ0BoQH/A08BmwMOARIMAANGAYABxQHJ - AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFJ - AkgB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ + AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFK + AkkB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ AwAB/wEVAQABAwH/A0AB/QNWAbUDGQEjA1gBvQMAAf8DXQHUAx4BKgNZAcMDAAH/A0AB/QIAAbwB/wMA Af8DAAH/AwAB/wMoATsDNQFWAwAB/wIhASMB+wMTARoIAANQAZ0BAAGtAesB/wEAAaEBygH/AwAB/wMA Af8BAAGUAbcB/wIAAYIB/wMAAf8BAAGZAZ8B/wEAAegC/wMAAf8DTAGOAwUBBgwAA0gBhAG6Ab8BAAH/ A10B3AFsAW0BUQH3AdgB6AEAAf8BtwG6AQAB/wHcAeEBAAH/AwAB/wNZAcMBwQHGAQAB/wNdAd8DGAEh CAADOARcAdYDKwH8AwAB/wEGAQoBDAH/AaEBpwGmAf8BhAGMAY0B/wErATcBPwH/AQ4BHQEmAf8BkgGY AZkB/wFQAVYBVwH/AwAB/wMAAf8DTQH6A0sBjAMPARQDXgHtAwAB/wMrAfwDRQF8Az0BaQNNAfoBKQIy - AfsDTQH6AVkBXgGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu + AfsDTQH6AVoBXwGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu Af8DAAH/AwAB/wMAAf8BAAGMAbgB/wMAAf8BggIAAf8DAAH/AQABuAHOAf8BAAGFAcQB/wNeAd0DOgFg AxUBHAgAA0cBgwGVAZsBAAH/AwAB/wHbAesBAAH/A1UBrwMQARUCUwFSAaUBwwHKAQAB/wNcAecBqAGw - AQAB/wNiAeEDGwElCAADSQGHAVgBVwFYAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ + AQAB/wNiAeEDGwElCAADSQGHAVkBWAFZAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ AUgBVwGBAf8BNgFKAVIB/wGrArIB/wGjAagBqQH/ARwBHwEjAf8BFQEJAQ4B/wNAAf0DWwHTAyoBPwNI - AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBYAGAAVQB/gNgAegDXgHXAzsBZQNKAYoCAAGI + AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBYQGAAVUB/gNgAegDXgHXAzsBZQNKAYoCAAGI Af8CAAGfAf8DPwFsA18B2gMAAf8BAAGyAeMB/wEAAY4BqQH/AwAB/wMAAf8DAAH/AQABkQHDAf8DAAH/ AwAB/wMAAf8DAAH/AQABsAHuAf8DAAH/AwAB/wNOAZYIAANHAYMBAAGGAQAB/wHXAdwBAAH/AwAB/wNQ AZ0DGwElA1UBrAHCAc4BAAH/A1wB2QGgAaoBAAH/A1oB6QMeASoIAANGAX0DTQH6AQ8BHgEAAf8BIgEx ARMB/wE1AU4BOQH/ASgBUgFGAf8BFAEkASYB/wFQAV0BhAH/ATUBRAFIAf8BGQEwASwB/wEjAT4BOQH/ - ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1sB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 + ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1wB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 A00B+gMrAfwBIQEyASEB+wNYAb0DKQE9A14B1wIAAZIB/wMAAf8DPgFqAgABhgH/AQABqAHSAf8BAAHS Av8CAAGEAf8DAAH/AwAB/wMAAf8BAAGKAcEB/wMAAf8DAAH/AwAB/wMAAf8BAAG8AfYB/wEAAaoB3gH/ AgABmQH/A1IBqAgAA0MBdgGHAZMBAAH/AmgBQQH5Ad4B4QEAAf8DAAH/AwAB/wHOAeABAAH/Al4BXAHZ @@ -177,30 +177,30 @@ ASgBLwExAf8BAQEHAQoB/wMAAf8BFwE5AQAB/wNNAfoDPgFrA1YBtgIAAZgB/wMAAf8CAAGIAf8DXgHd AzQBVANVAa4BlwGpAd0B/wJeAV8B+wNHAYMDUgGlAwAB/wMAAf8DAAH/A00B+gMPARQEAAQBAV0CZQHs AQABoQHmAf8DAAH/AYICAAH/AwAB/wEAAYwBuAH/AwAB/wMAAf8DAAH/AgABvQH/AQABlgHAAf8DVgGy - AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABZwH+ - AdEB1wEAAf8CgAFkAf4CgAFOAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ - AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BUAFNAU4B/gNZAcMDIQEv + AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABaAH+ + AdEB1wEAAf8CgAFlAf4CgAFPAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ + AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BUQFOAU8B/gNZAcMDIQEv AzABSgMAAf8DAAH/AgABnwH/AQABgQG2Af8DAAH/A2AB8wMAAf8DXAH4A00B+gEAAYQBsgH/AwAB/wMA Af8DAAH/A1MBpgwAA0IBdQEAAeMC/wEAAZQBzAH/AwAB/wMAAf8BAAGAAbEB/wMAAf8DAAH/AgABjgH/ AQABuQH7Af8DAAH/A0wBjgMSARcEAAMlATcDAAH/AdsB3AGOAf8B+AH7AZ0B/wGlAagBAAH/Al8BMgH7 AZcBmgEAAf8DWgH1AZABkgEAAf8BpAGnAQAB/wJiAVkB7wHtAfIBjgH/AckBzQEAAf8BoAGlAQAB/wNb AdgDFAEbAxUBHANiAeEDAAH/AR8BDwEVAf8BJAEiAScB/wE/AVwBOgH/AbgBywG4Af8B2ALdAf8B3QLg - Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AWUBWwFeAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ + Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AWYBXAFfAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ AwAB/wIAAYUB/wIAAaoB/wMAAf8BAAGAAZsB/wEAAY4BuAH/AwAB/wMAAf8CAAG0Af8DTQH6AxMBGQgA AxgBIQFbAl0BygEAAeUB+gH/AQAD/wEAAcQB9wH/AgABlAH/AQABjQG6Af8CAAGXAf8CAAHCAf8BAAHR Av8BAAHKAe4B/wIAAYcB/wNbAeQDIQEvCAADAgEDA00BkwG8AcYBAAH/A1YBsANeAeIDAAH/A2UB8QMA Af8DOQFeA1IBoAL/AQAB/wMAAf8DWgG/AxYBHgQAAy0BRQNIAfYBGQEFAQoB/wEYAQ4BEwH/ARQBDAEO Af8BLgFVARoB/wFdAZwBVgH/AY0BjAGOAf8BqAGvAbAB/wFVAaMBQgH/ATABRwEUAf8DAAH/AQMCAAH/ - AVcBVAFVAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA + AVgBVQFWAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA Af8CAAGkAf8CAAGGAf8DLQFFDAADIAEtAQABlQGsAf8BAAGAAZIB/wNRAaEDXQHqAQAB4gH4Af8BAAHe AfMB/wEAAcoB8wH/AQABpgHIAf8DWQG7A1kBuwEAAa8B0AH/A1cBvAMLAQ4MAAMmATkDXQHMAyUBNwNT AakDUgGgA1UBrANVAa8DQwF2A4AB/gG0AbgBAAH/AbsBxwEAAf8DZQHxAzIBTwQAA0IBdANcAcsDKwH8 AysB/AEdAUQBBgH/AS8BNwEYAf8BNwFCASIB/wEoARsBIQH/ASwBKQErAf8BNAGBARMB/wEmAUIBDgH/ - AR4BNAEDAf8BAQIAAf8BWAFOAVIB/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ + AR4BNAEDAf8BAQIAAf8BWQFPAVMB/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ AwAB/wIAAZEB/wJeAWEB4gMtAUUUAAMmATgDMwFRBAADDAEPA0QBewEAAewC/wEAAYIBlAH/A0oBiQME AQUDAwEEAzQBVAMNAREsAANdAdEByQHSAQAB/wNLAY8CbQFRAfcBmwGoAQAB/wM+AWoEAAMDAQQDDAEP - AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFpAWIBZAH+ - AX4BgAFaAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ + AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFqAWMBZQH+ + AX8BgAFbAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ ARUDZQHxA2AB4EAAA0QBeQNSAaUEAANGAYEDWQHBAw8BFAQAAwQBBQQABAEDOAFcA0IBdANGAX4DUwGq A1UBrQNYAboDWgHEA1EBogNUAasDQAFvAwwBDwQBBAABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEA AQEGAAEBFgAD/4EAAeABDwH8AT8BAwH/AeABAQHAAQcB5AE5AQABAwGAAQABgAEDAYABAQGAAQMBgAEA @@ -279,79 +279,78 @@ iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG3SURBVDhPYxhQEKvEFB+nxHQiVoXlQ5wKyzso/R+EY5WZ - p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD+KUmZsKbGTBBsEM - geEzW6f/P7KqB8xe318INhiqDTcAubDQVvb/y9v7MAy8uGce0OtMh2OVWdbsXdQCFgMFBVQrdgByIchA - bC4E4ZvHVvyPUWI6DzRox+GV3WAxvIbCvIzNhcj42qGl/09vmQZmv314BGgJyyeoEagA6OW2Ijs5ggai - 41d3D/yPUWZ5CzUGAWAufHMfu5fx4S+vzoK8/w9qFATEqTC3EONlXPjZ9Z3/Y5VYnkKNA3pZmbm52F4B - 7AVsGgjhj89O/K/00Pgfp8pSAzUS6Eolljev7uzHqoEQhhuozNwPNQ4CQEkDlESwacKHPz47id1AEIhX - Zk1L0eEBpz1smrFhkAurPDVBuWgC1BhMADI4SZOTKINxehkbQBi8EqthIAxzIVEGwgAwBtNxuZgkF6ID - bC6myEAYgLiY6/+V/Yv+P7y4hXQv4wJxykxxwBL/eJwS871YVZZSqPBAAAYGAAuu1UcrcTJQAAAAAElF - TkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGuSURBVDhPYxhQEKvEFB+nzHwiVoXlQ5wKyzso/R+EY5WZ + p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD4CuayqwkQUbBDME + hs9snf7/yKoeMHt9fyHYYKg23ADkwkJb2f8vb+/DMPDinnlArzMfjlVmWbN3UQtYDBQUUK3YAciFIAOx + uRCEbx5bAXLZeaBBOw6v7AaL4TUU5mVsLkTG1w4t/X96yzQw++3DI0BLWD5BjUAFQC+3FdnJETQQHb+6 + ewBk6FuoMQgAc+Gb+9i9jA9/eXUW5P1/UKMgABjoLcR4GRd+dn0nyKVPocYBvazM3FxsrwD2AjYNhPDH + Zyf+V3po/I9TZamBGgnyNsubV3f2Y9VACMMNVGbuhxoHAaCkAUoi2DThwx+fncRuIAjEK7OmpejwgNMe + Ns3YMMiFVZ6aoLQ6AWoMJgAZnKTJSZTBOL2MDSAMXonVMBCGuZAoA2EAGIPpuFxMkgvRATYXU2QgDEBc + zPX/yv5F/x9e3EK6l3GBOGWmOGDsHgcadi9WlaUUKjwQgIEBAExb1Vj6X25iAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VVPKARhFN+j2JndTclF5LQHBydxERdJihwm - Tis7s6yTlMgFBzEzu00h2lq7JeUkDkpysGz+ZA97cLCJkAs3N0e+3/Q+jdFq7U65+NWr3e+97/39vW9c - /7BDkLVBj6w10l9n4QnqbdWjy7e+sPEiKno/HTsDz/BCnS8cvZESZ3dS4vKpZjyWExR9ltQlIjBTxpxl - e1bTFwPJzDukP3HxWhk2XsmiNIiyttMePTjiziFN89vHQlDdIpPigTY0TG9+Zg7pMA5ToqKdozIyKw7u - kNqLXkvxzBt33rd2lvWFog+YCZkVB1ARbMFAuXP8xpkgLzaTmQ0oqYCyygNatVeJ5JDtp3NWhckctgdk - ZgNz7Jb1fciPQZgO/UWfuXMI5sC4b5CVDeS8cW4r3arvmQPyBAwvab9AUCJrYIjVORgkKOoRmXwH6ATn - /AKyA6/RCjIxwcofq52IXVmHCu5XBPX7fAmZw2KlvfXGTjP8EqRrKZU2LxIbxKDWWTW68iTFL1+4Dba2 - ciT66A5F/KazfEAQ77D23L16cmoNgqCgHOgIvbR+nuM6bCoCQkdufgayQMbI3BoETMHK24P7pzYyrKop - ul4Y0A5xSL3GoK3OrG2BtCzspvA80LXfAcPCgO1M4YJKoC9kX/LDQlsrYzADR54BE+ZC6Un0GkHQJnxM - 8FEhC2eAxcITUD8Zz4qyOkLHzgJPcv5n4E/hcn0AlbeOeSP8K6kAAAAASUVORK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VVPKARhFN+jNDO7KLmoLRcHBy7iIi6SFDks + TqtmZtlcpEQuOGjNzK4p5F/tKiku4qAkB8vGYg97cLCJkAs3N0fmN71PY7Raa8rFr17tfu997+/vfeP6 + hx28pPa6JbWa/joLt6g1lg3M3RQH9WdB1rrp2Bm4+0Le4uDMtS+WvPXFLh7Lh5YzvKxNkPqX8I8XGM7S + 7QuJs57V1BukO3b+UhLUX8jidxAkdbspsn/InENqp7aOeFHZIJP8gTZUja1/ZA5p1g/igqwmURmZ5Qcu + oHSg113R1Ctz3rl0mi4KRO4xEzLLD6Ai2IKBMuf4jTNemq4jMxtQUg5lFfrVMo8cziBb5hxVmMwx9oDM + bDAcc5K2B/k2iKFDf9Fn5hyCORjc18nKBnJeM7mZaNB2zQG5/bqHtJ/Ay+FFMMTqHAziZeWQTL4CdIJz + dgHZgddoBZmYMMof9A6vXFqHCu5zonaXLSFzWEZprx3LJyl2CdI6G0+YF4kNgqi2lA7MP3ZFL56ZDba2 + pH/mgQuEK01n2YAgnj7tqW3h+MQaBEFBOdARel80mWE6bCoCQkduvgeyQMbI3BoETMHK24NXjq6ljKpG + 6XpuQDsEUbnCoK3OrG2B1Id24nge6NrPgGFhwHamMEEl0OeyL9lhoa2VMZiBI8+ACXOhtFX0GkHQJnxM + 8FEhC2eAxcITUDESTQuS0k/HzgJPcvZn4E/hcr0DUbSOqjT7gYIAAAAASUVORK5CYII= iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGaSURBVEhL7ZQhUMNAEEUjGdpckEgkEolEIpG4MuSuIJE4 - cDR3nalEIpFIZCUSiUQikVj2b3+Y4whtJ4lA8GYy7f7L7N3t/k32T0pu/Ulh/R7DfinKcGBOqxdjw5tx - 4ZhyPxRnNztIPhxPd/E/d+FZnmsud2R0tYGEw3F1RCUrRrOtgZu8M+yGsf7BlP6SoZK76W1eVvcM24My - YAOGijT6wjj/hJtRagdKgtLEidDoQRle0QdK7YAV4ZY4kTZatNxO9ikl4CRrXGtz5LfhGJyW0lejMQdU - EuSFoQ2PeJZuImuoL+pMRdFGuzBjmMDk8sKdNk0SwGZc/Ya6Qx6GChyUu2rO8CewE5IzVBfguigFJaXJ - HWi0NvWXAy2a5cKHnOKQkoJaxm7AOuJ4U0wtNPxSaqZ2RPr9qJPilOqY6COmk8o1SsupT5O6QH0tI59u - rj1Lpncl6mOxHxpNSUl7IZvN0uldG1xd/Zw4pQY3wfpSK68ksm2cCD1AGTt/BhRJjA3qwWuc3j5YDBZK - Vs2Nrc4p9wuajsYy/Etk2ScCFcWFAI8TWgAAAABJRU5ErkJggg== + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGZSURBVEhL7ZQhUMNAEEUjGSZ3QSKRSCQSiUTiykzuChKJ + AweX60wkEolEIiuRSCQSicSyf/vDHEdpO00EgjeTafdfZu9u92+Kf3KMa04q1+wxHJaqjge2Di/WxTfr + 4zHlYahOr3eQvBxPdvHf+PgszxWXezK63EDCchyOqBTVqN0qfXhn2A/rmgdbNxcMFeMnt6YO9wzXB2XA + BgwVafS59c0TbkZpPVASlCZNhEaXdXxFHyitB6wIt6SJtNGiGXezTykDJ1nhWpujZhuOwWkpfTUac0Al + Q14oXXzEs3ATWUN9UWcqijbax5ZhBpPLC3faNEkAm3H1G+oOeRgqcJDxYcrwJ7ATkjNUF+C6KAUlZZ47 + 0Ght6i8HmjXLxw85xSElBbVM3YB1xOmmmFpo+KU0n84R+fejS4pTqmOSj5hOKtcoLaY7Te4C9bWMfL65 + 9iyb3qWoj8V+aDQlJe+FbNbm07syuLr6OXNKB26C9YVWXkpi2zQReoAy9v4MKJIYG3SDN3d6h2A2WChZ + mFoXzigPC5qOxjL8SxTFJ00CxZeT7IG4AAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH/SURBVEhLzVTPK0RRGD1LS0tLS0tLS0tLS8v5D8xMQ34U - kpAFUpIiSZmSkJTlmzHKkJAkC/mRJAshyUi6vvPmu41584aHt3Dq1Hv33u/cH9/5Pvw7ODE06Gf4cLpR - kYrh3EmgSofChdOMSLYDRjYZ0KFwIcL7zwsw6Rbc8jY6HA7k9LVH/TBmDeZ0GIa30alwkIpi5m42v8HL - ovtM+zr1dzCp2U7kKG7J2/BWuuRvEKHo1URBnORtUs1I6pLykOBqYb2yUXzeQ9IpQodMx/DwtlK8Abnd - gVe7JhXHiI0VNllN6+3lzRaYi7E8rydh7ufyfF0qFf5MbmzX3k4XNNTOhTzJz8RhH8z7qr/QT0iXyfOt - l1jZiaJttyt/Kr/A78jDHQ+KuDhOJUsh7xbJtiNHK/qJlCMPddArzpIcqFR5yKKGTBwPj/P+Yl7yMDud - Pyw+WVzLxPsJeumeXByoocEgAdXMh5+glydDv9sgQjf4CXp5MyWJlTrQ0GCgbelrrxgr2GtldtgizwcB - Az476SkJs9ft+jvJvmQbn2UmgVzgFi7PU8lKZCDtp4Wz5cRR485L85MDLLPh2UrX5lfvCnwHJowBfKJM - Kx6ZD50qAu2cTuDichzmbFQ2kELVqa/BYqFFmQfeRod9wWfh+o0YXngrHf4a2hnr9DcQ+Hyl7Rv4AMAg - UZuIzzJ2AAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH/SURBVEhLzVTPK0RRGD1LS0tLS0tLS0tLS8v5D4wx5Ech + CVkgJSmSlCkJSVm+maEMCUmykB9JshCSjKTrO2++25g3b3h4C6dOvXfv/c798Z3vw7+D04Q6/QwfTjfK + kk04d+Ko0KFw4TQikumAkU0GdChciPD+8wJMugW3vI0OhwM5ffVRP4xZgzkdhuFtdCocJKOYuZvNbfCy + 6D7Tvk79HUzqdieyFLfkbXgrXfI3iFD0aiIvTvI2yUYkdElpSHClsFZZLz7vIekUoUOmYnh4WyncgNzp + xKtdk4xhxMYKG6ym9fbyZgvMxViO15Mw93M5vi4VC38mN7Zrb6fzGmrnfJ7kZ+KwD+Z91V/oJ6TL5PnW + i6zsRNG225U7lV/gd+ThjgdFXBynksWQd4tk2pGlFf1ESpGHOugVZ0kOVKo0ZFHdRjMeHuf9xbzkYSTh + Pys+WVzNxPsJeumeXByoocEgAZXMh5+glydDv9sgQjf4CXp5MyWJlTrQ0GCgbelrrxgr2GtldtgCzwcB + Az476SkBs9ft+jvBvmQbn+VGHNnALVyep5yVyEDaTwtny4mhyp2X5icHWGbDs5Wuza/WFfgOTBgD+ESb + rXhkPnSqALRzKo6Ly3GYs1HZQApVp74Gi4UWZR54Gx32BZ+F69MxvPBWOvw1tDPW6G8g8PmK2zfwAeUN + UaR56NgIAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANaSURBVDhPvZRJTFRBEIar+iWGuFyMJ9dw0KjxYKIHD0YT - o8ZEb2o08WBilLjAwMwAIkhGkAGURUQYgWE2EFBkXxyWUVDUAWURkIhy0ChBAVnjQRRoqx8tEWPM4MHv - 8ub9Va+mu+vvgv9Olh4WWQKU3XfDMbkymjXVxLM2ZyxrFO9mjbIn3QcWylTPSPOHHaWRWNGRhdOjtcB5 - I/Ap98xzjN47SS+5jOXpGtguP/k7Vj3zfWFHPvUc+Jc64C0ZOH4/ETuqrmKuKwE7xbvQp5qBtzmQW3Ts - jPz0z1h17OT7IuS8FfiTFOyzBbJwWs3qzCBYYvJVdtmOg5dVB6uE3pCKn0SeyM/UsROyxFzStezomzu0 - xWfASy+x7pSzsEaGoPASRnTYSY/AKClBhi94F0eyHpHfcwe5WceOyNAMNgN4VV9lvbwFeG0cvr2pgbUy - pFJuxJKJh8BdcaxeSio3zsG6mgT8IFZcE8d6RR0ZolVqlIPDVcD7y5Gn+ir7pTxLqRFvjVODqq9ghZRm - SfVT9vaXAR+uBp4RoBySsro920Q98EdJrElKc/hZ9F4sFkhpDnXXsV3spDgS7aoQ7wPL6pOwZ/IRcEcg - WlXxN9SiLioagw+oKcdyQpguK0TZJ8OQF4aWycfA65OxG8qisJC29OqlA6enGtQzG3Alojs7FLbJfBXh - 2e8UH6HVfiylrdIftGRS1/WwScRzLmCciD814SgURrLB8RrqODVo+gk96cBf55L3gpQDajVJXig7LyzU - ZsehdhsOdjpwtC6BtWcHw0oRp6LXxErdN3FA7XpFNHNPioJdwD876QiCMVat9Bt2LazI0IO38Kk1CNaK - ayxDUGjAgm90fK5E5lYFkwa2tJiRTwp/XmbN5M/FasBDzFpY2mrBT1+pUbmhaJSyuj2fSiPWZetho5Q8 - xqJFo+j8u7vI0wJgq5RnMBiAyZ8eYzrHfF7nIJ+mQZMfhg+k/O9k+jG/rls0J9rpNsWzbnLC7LX2GBoq - y9Po9jiC2Gm6BM19lVSQXEPG7zP7wwaZ5jk2HaynqTU6QO4YclKxJuC9lcCLDOyxmGIybX7YAmFzKzlk - jEzflYUjFdHosmnZqfzDoMiU+SPmaUkEmpwxrO32RYxJ18LOfAMskOFfAPgBlbqjqMvuHqMAAAAASUVO - RK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANYSURBVDhPvZRJTFNRFIbPuS8xxmFjXDmGBUaNCxNduDCa + GDUmulOjiQsTo0QFKm0BESFlkEEZRLRMpS2zglBBhjJUJsGCMohIBFlolKCAKBAXosD13MeVCDGmuPDb + vL7/nHd67z3/ufDfydLDcrOPsv9+MCZWRLHW6ljWaY9mLeLdpFEOpHrAMpnqGimXYE9JGJZ1Z+PMWA1w + 3gJ82jn7HKf3l6QXh2NpqgZ2y0/+jkXPvJ5nIJ9+BvxrHfB2E048iscXlTcwzxGH3eJd6NNtwDszkZt1 + 7IL89M9YdOzsOxty3gG82YiDVl8WTKvZkO4HK5O8lH3W07DUooP1Qm8y4keRJ/LTdeyMLDGfVC07+Tqf + tvgUeEko671zETbKEBSFYOiLDKHjNSlBmhe4FYexfpHfn4/cpGMnZGgWqwGWVsewAd4O3BGLb5I14C5D + KqWRWDzZQLEYVi8llduesKkmDt+LFdfEsgFRR4ZolRrl6OdK4EOlyI1eymEpz/EwAnMmqEFVN7BMSnMY + vZWDQw+Bf64CnuajHJMygC0UrZP1wBsTWKuU5vGrqD0aC6U0j/pb2CV28iAMM1Qh1gNW1ydg/1Qj8Exf + tKjiAtSiDuAV0VhLTTmVG8B0WQHKIRmGe1fRPNUEvCERe6H0GhZVXcdXPVk4M/1YnCcbdsSjMzsQdsl8 + FeHZHxT/Qqv9UEJbpT9oT6eu62GbiOdewRgRdybjGNjC2MhENXWcGjTTTE868L488p6fckStJrkbyC4L + C5F/R7usONKdhWN18awr2x/WiTgVvSlWSkWH1a6XRzHnlCjYA/yTnY7AH6PVSgvI0MLaND24CZ9a/MBd + jLEMgS0EC7/T8TnimVMVkjSwg6aETwl/hrM28ucKNeAiJi2s6jTjx2/UqLxAjJCyuj2P8gisy9bDVim5 + jFmLEaLzb+8jT/GBnVKexWAAJn+6TJIn8+jLRT5DF01BENZK+d9J92bePTl0T3Sp09RLTpgba5ehS2VN + Ck1Pph87T35tGyynguQaMv6g6RJskWmuY9XB5idGHBsmd4zaqVgr8IFy4DYDaxK3mExbHFZf2N5BDhkn + 09OgfCmLRIdVy84VHAdFpiwecZ8Wh2KSPYp13gvCqFQt7C0wwBIZ/g2An2e+o9ziKCLsAAAAAElFTkSu + QmCC diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index e572a3235..ceef4e7ac 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -565,6 +565,7 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir // LowerSplitContainer.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; LowerSplitContainer.BackColor = SystemColors.ActiveBorder; + LowerSplitContainer.FullScreenCollapsePanel = DarkSplitContainerCustom.Panel.Panel2; // // LowerSplitContainer.Panel1 // diff --git a/AngelLoader/Ini/ConfigIni.cs b/AngelLoader/Ini/ConfigIni.cs index c03c29a7f..15beca810 100644 --- a/AngelLoader/Ini/ConfigIni.cs +++ b/AngelLoader/Ini/ConfigIni.cs @@ -680,9 +680,14 @@ private static void Config_LowerSplitterPercent_Set(ConfigData config, string va } } - private static void Config_TopRightPanelCollapsed_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) + private static void Config_TopFMTabsPanelCollapsed_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { - config.TopRightPanelCollapsed = valTrimmed.EqualsTrue(); + config.TopFMTabsPanelCollapsed = valTrimmed.EqualsTrue(); + } + + private static void Config_BottomFMTabsPanelCollapsed_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) + { + config.BottomFMTabsPanelCollapsed = valTrimmed.EqualsTrue(); } private static void Config_GameTab_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) @@ -1013,7 +1018,8 @@ private static unsafe Dictionary { "MainSplitterPercent", new Config_DelegatePointerWrapper(&Config_MainSplitterPercent_Set) }, { "TopSplitterPercent", new Config_DelegatePointerWrapper(&Config_TopSplitterPercent_Set) }, { "LowerSplitterPercent", new Config_DelegatePointerWrapper(&Config_LowerSplitterPercent_Set) }, - { "TopRightPanelCollapsed", new Config_DelegatePointerWrapper(&Config_TopRightPanelCollapsed_Set) }, + { "TopRightPanelCollapsed", new Config_DelegatePointerWrapper(&Config_TopFMTabsPanelCollapsed_Set) }, + { "BottomRightPanelCollapsed", new Config_DelegatePointerWrapper(&Config_BottomFMTabsPanelCollapsed_Set) }, { "GameTab", new Config_DelegatePointerWrapper(&Config_GameTab_Set) }, #region Top-right tabs @@ -1418,7 +1424,8 @@ private static void WriteConfigIniInternal(ConfigData config, string fileName) sw.Append("MainSplitterPercent").Append('=').AppendLine(config.MainSplitterPercent.ToString(NumberFormatInfo.InvariantInfo)); sw.Append("TopSplitterPercent").Append('=').AppendLine(config.TopSplitterPercent.ToString(NumberFormatInfo.InvariantInfo)); sw.Append("LowerSplitterPercent").Append('=').AppendLine(config.LowerSplitterPercent.ToString(NumberFormatInfo.InvariantInfo)); - sw.Append("TopRightPanelCollapsed").Append('=').Append(config.TopRightPanelCollapsed).AppendLine(); + sw.Append("TopRightPanelCollapsed").Append('=').Append(config.TopFMTabsPanelCollapsed).AppendLine(); + sw.Append("BottomRightPanelCollapsed").Append('=').Append(config.BottomFMTabsPanelCollapsed).AppendLine(); sw.Append("GameTab").Append('=').Append(config.GameTab).AppendLine(); sw.Append("TopRightTab").Append('=').Append(config.FMTabsData.SelectedTab).AppendLine(); From 54fd5415a90a375250931242e81ac1b5b5d1023c Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 09:17:14 -0800 Subject: [PATCH 138/200] Remove single-move path from tab move handler The multi-move path also handles the single-move case --- .../Forms/CustomControls/DarkTabControl.cs | 56 ++++++++----------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 1385987e4..120f2db16 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -405,50 +405,38 @@ protected override void OnMouseMove(MouseEventArgs e) int newTabIndex = TabPages.IndexOf(newTab); - int distance = Math.Abs(newTabIndex - dragTabIndex); - if (distance == 1) - { - TabPages[dragTabIndex] = newTab; - TabPages[newTabIndex] = DragTab; + // Handle the case where the tab is moving more than one position in one go. + // The easy way would be to insert/remove, but that results in terrible flickering for the TabPages + // collection, and suspend/resume doesn't fix it either. So just move everything over manually. - _backingTabList[bDragTabIndex].TabPage = newTab; - _backingTabList[bNewTabIndex].TabPage = DragTab; + if (newTabIndex > dragTabIndex) + { + for (int i = dragTabIndex; i < newTabIndex; i++) + { + TabPages[i] = TabPages[i + 1]; + } + for (int i = bDragTabIndex; i < bNewTabIndex; i++) + { + _backingTabList[i].TabPage = _backingTabList[i + 1].TabPage; + _backingTabList[i].VisibleIn = _backingTabList[i + 1].VisibleIn; + } } else { - // Handle the case where the tab is moving more than one position in one go. - // The easy way would be to insert/remove, but that results in terrible flickering for the TabPages - // collection, and suspend/resume doesn't fix it either. So just move everything over manually. - - if (newTabIndex > dragTabIndex) + for (int i = dragTabIndex - 1; i >= newTabIndex; i--) { - for (int i = dragTabIndex; i < newTabIndex; i++) - { - TabPages[i] = TabPages[i + 1]; - } - for (int i = bDragTabIndex; i < bNewTabIndex; i++) - { - _backingTabList[i].TabPage = _backingTabList[i + 1].TabPage; - _backingTabList[i].VisibleIn = _backingTabList[i + 1].VisibleIn; - } + TabPages[i + 1] = TabPages[i]; } - else + for (int i = bDragTabIndex - 1; i >= bNewTabIndex; i--) { - for (int i = dragTabIndex - 1; i >= newTabIndex; i--) - { - TabPages[i + 1] = TabPages[i]; - } - for (int i = bDragTabIndex - 1; i >= bNewTabIndex; i--) - { - _backingTabList[i + 1].TabPage = _backingTabList[i].TabPage; - _backingTabList[i + 1].VisibleIn = _backingTabList[i].VisibleIn; - } + _backingTabList[i + 1].TabPage = _backingTabList[i].TabPage; + _backingTabList[i + 1].VisibleIn = _backingTabList[i].VisibleIn; } - - TabPages[newTabIndex] = DragTab; - _backingTabList[bNewTabIndex].TabPage = DragTab; } + TabPages[newTabIndex] = DragTab; + _backingTabList[bNewTabIndex].TabPage = DragTab; + SelectedTab = DragTab; // Otherwise the first control within the tab page gets selected From a9f5a951b8ed348a335a1d7ef2b257d0f40f2321 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 09:27:31 -0800 Subject: [PATCH 139/200] Rename all remaining "top-right" to "FM tabs" --- .../Common/DataClasses/ConfigDataSupporting.cs | 2 +- AngelLoader/Core.cs | 2 +- AngelLoader/Forms/CustomControls/DarkTabControl.cs | 4 ++-- .../DataGridViewCustom/DataGridViewCustom.cs | 2 +- ...zy_TopRightBlocker.cs => Lazy_FMTabsBlocker.cs} | 0 .../CustomControls/TopRightPages/Lazy_TabsBase.cs | 2 +- AngelLoader/Forms/MainForm.Designer.cs | 2 +- AngelLoader/Forms/MainForm.cs | 14 ++++++++------ AngelLoader/Ini/ConfigIni.cs | 4 ++-- 9 files changed, 17 insertions(+), 15 deletions(-) rename AngelLoader/Forms/CustomControls/LazyLoaded/{Lazy_TopRightBlocker.cs => Lazy_FMTabsBlocker.cs} (100%) diff --git a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs index 54a54fa9a..6a1d28fe5 100644 --- a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs +++ b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs @@ -95,7 +95,7 @@ public enum CheckForUpdates False } -#region Top-right tabs +#region FM tabs // IMPORTANT(FM tabs enum): Do not rename members, they're used in the config file [FenGenEnumCount] diff --git a/AngelLoader/Core.cs b/AngelLoader/Core.cs index 3817137f5..64e788328 100644 --- a/AngelLoader/Core.cs +++ b/AngelLoader/Core.cs @@ -2646,7 +2646,7 @@ internal static void UpdateConfig( filter.DeepCopyTo(Config.Filter); - #region Top-right panel + #region FM tabs Config.FMTabsData.SelectedTab = fmTabsData.SelectedTab; Config.FMTabsData.SelectedTab2 = fmTabsData.SelectedTab2; diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 120f2db16..445266b38 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -477,8 +477,8 @@ public void SetTabsFull(TabPage[] tabPages) { /* Create handle before adding tabs to prevent the following: - -You start the app in dark mode and with the top-right area hidden - -You show the top-right area + -You start the app in dark mode and with the FM tabs area(s) hidden + -You show the FM tabs area(s) -The tabs are all the same width, and if you switch to light mode, they have a crappy bold font instead of the intended one */ diff --git a/AngelLoader/Forms/CustomControls/DataGridViewCustom/DataGridViewCustom.cs b/AngelLoader/Forms/CustomControls/DataGridViewCustom/DataGridViewCustom.cs index 2685e9be3..a82e2f803 100644 --- a/AngelLoader/Forms/CustomControls/DataGridViewCustom/DataGridViewCustom.cs +++ b/AngelLoader/Forms/CustomControls/DataGridViewCustom/DataGridViewCustom.cs @@ -265,7 +265,7 @@ internal void SelectSingle(int index, bool suppressSelectionChangedEvent = false { if (suppressSelectionChangedEvent) SuppressSelectionEvent = true; - // Stops the no-FM-selected code from being run (would clear the top-right area etc.) causing flicker. + // Stops the no-FM-selected code from being run (would clear the FM tabs area(s) etc.) causing flicker. // Because clearing the selection is just some stupid crap we have to do to make one be selected, // so it shouldn't count as actually having none selected. using (new DisableZeroSelectCode(_owner)) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs similarity index 100% rename from AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_TopRightBlocker.cs rename to AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TabsBase.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TabsBase.cs index 9bfc72914..ce538e20d 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TabsBase.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_TabsBase.cs @@ -6,7 +6,7 @@ namespace AngelLoader.Forms.CustomControls; -// @ViewBusinessLogic: Lots of it in the lazy-loaded top-right tabs now. +// @ViewBusinessLogic: Lots of it in the lazy-loaded FM tabs now. public class Lazy_TabsBase : DarkTabPageCustom { internal enum ScanSender diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 1042ea2ed..2021bef1d 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -1263,7 +1263,7 @@ private void InitializeComponent() #endregion - #region Top-right + #region FM tabs internal CustomControls.DarkTabControl TopFMTabControl; internal CustomControls.StatsTabPage StatisticsTabPage; diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index b4e26f06b..a41d54c75 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -9,8 +9,9 @@ "Don't lazy load the filter bar scroll buttons, as they screw the whole thing up (FMsDGV doesn't anchor in its panel correctly, etc.). If we figure out how to solve this later, we can lazy load them then." -All filter controls (they're hideable) --Top-right tab pages themselves (even though they're blank containers of lazy-loaded contents now) --Top-right tab control (the container of the tab pages) +-FM tab pages themselves (even though they're blank containers of lazy-loaded contents now) +@DockUI: We're going to lazy-load both of these in the final release - remove this comment then +-FM tab controls (the containers of the tab pages) -Rating columns (text or image) - one or the other will not be shown @NET5: Fonts will change and control sizes will all change too. @@ -887,7 +888,7 @@ and does NOT have its text transferred over. It ends up with blank text. // Set here specifically (before anything else) so that splitter positioning etc. works right. SetWindowStateAndSize(); - #region Top-right tabs + #region FM tabs var fmTabsDict = new Dictionary(); for (int i = 0; i < FMTabCount; i++) @@ -901,6 +902,7 @@ and does NOT have its text transferred over. It ends up with blank text. fmTabs[i] = fmTabsDict[i]; } + // @DockUI: We'll need to change this logic when we lazy-load both tab controls TopFMTabControl.SetTabsFull(fmTabs); for (int i = 0; i < FMTabCount; i++) @@ -1866,7 +1868,7 @@ private void Localize(bool startup) #endregion - #region Top-right tabs area + #region FM tabs if (!startup) SetFMSelectedCountMessage(FMsDGV.GetRowSelectedCount(), forceRefresh: true); @@ -3257,7 +3259,7 @@ void DoSelect() #endregion - #region Top-right area + #region FM tabs private void FMTabControl_Selected(object sender, TabControlEventArgs e) { @@ -4524,7 +4526,7 @@ internal void PlayT2MPMenuItem_Click(object sender, EventArgs e) #region FM display - // Perpetual TODO: Make sure this clears everything including the top right tab stuff + // Perpetual TODO: Make sure this clears everything including the FM tab stuff private void ClearShownData() { // Hack to stop this being run when we clear selection for the purpose of selecting just one immediately diff --git a/AngelLoader/Ini/ConfigIni.cs b/AngelLoader/Ini/ConfigIni.cs index 15beca810..c330fbc1a 100644 --- a/AngelLoader/Ini/ConfigIni.cs +++ b/AngelLoader/Ini/ConfigIni.cs @@ -699,7 +699,7 @@ private static void Config_GameTab_Set(ConfigData config, string valTrimmed, str } } - #region Top-right tabs + #region FM tabs private static void Config_FMTab_Set(ConfigData config, string valTrimmed, string valRaw, GameIndex gameIndex, bool ignoreGameIndex) { @@ -1022,7 +1022,7 @@ private static unsafe Dictionary { "BottomRightPanelCollapsed", new Config_DelegatePointerWrapper(&Config_BottomFMTabsPanelCollapsed_Set) }, { "GameTab", new Config_DelegatePointerWrapper(&Config_GameTab_Set) }, - #region Top-right tabs + #region FM tabs { "TopRightTab", new Config_DelegatePointerWrapper(&Config_FMTab_Set) }, { "TopRightTab2", new Config_DelegatePointerWrapper(&Config_FMTab2_Set) }, From e87b8ae02387c99ef20d6a99523e3802fefe49d6 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 09:34:41 -0800 Subject: [PATCH 140/200] Note --- AngelLoader/Forms/CustomControls/DarkTabControl.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 445266b38..08c1e063b 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -523,6 +523,7 @@ public void ShowTab(TabPage tabPage, bool show) { TabPages.Remove(bt.TabPage); // Otherwise the first control within the tab page gets selected + // @DockUI: We should probably select the nearest tab when we remove one if (TabCount > 0) TabPages[0].Focus(); } } From 67ae2180124ade447d409cd0fdca800be01e006d Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 14:12:18 -0800 Subject: [PATCH 141/200] Note --- AngelLoader/Forms/MainForm.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index a41d54c75..f451743f6 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -903,6 +903,11 @@ and does NOT have its text transferred over. It ends up with blank text. } // @DockUI: We'll need to change this logic when we lazy-load both tab controls + /* + @DockUI: Tab pages need to be added to a tab control once in order to work properly. + At the very least, setting tab text throws an ArgumentOutOfRangeException in release mode. + This being the case, we should just keep the top control non-lazy-loaded and keep the logic as it is. + */ TopFMTabControl.SetTabsFull(fmTabs); for (int i = 0; i < FMTabCount; i++) From a942f5705d2041a852fbfc7c525be91d307d3aa4 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 14:58:23 -0800 Subject: [PATCH 142/200] Fix regression with bottom tabs handle hack not working --- .../Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 6e078b13c..b1a3dea16 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -61,9 +61,7 @@ internal void Construct() AllowReordering = true, Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, EnableScrollButtonsRefreshHack = true, - Size = new Size(container.Width - 16, container.Height + 1), - - DarkModeEnabled = _darkModeEnabled + Size = new Size(container.Width - 16, container.Height + 1) }; _tabControl.SetWhich(WhichTabControl.Bottom); @@ -71,6 +69,8 @@ internal void Construct() // Handle hack here instead, because it needs to be for whatever finicky goddamn reason _ = _tabControl.Handle; + // Dark mode set MUST come AFTER the handle hack, otherwise it doesn't work! + _tabControl.DarkModeEnabled = _darkModeEnabled; _tabControl.MouseClick += _owner.LowerFMTabsBar_MouseClick; container.MouseClick += _owner.LowerFMTabsBar_MouseClick; From 9b86bf0657dcfed7b4dd86522c34e0e3019bdb44 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 14:59:52 -0800 Subject: [PATCH 143/200] Remove extraneous Construct() calls It's constructed implicitly in those cases --- .../Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs | 3 +-- AngelLoader/Forms/MainForm.cs | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index b1a3dea16..6c1142cc9 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -45,8 +45,7 @@ public bool DarkModeEnabled public Lazy_LowerTabControl(MainForm owner) => _owner = owner; - // @DockUI: We may be able to just call this implicitly through accessing TabControl - internal void Construct() + private void Construct() { if (Constructed) return; diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index f451743f6..629054f27 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -927,7 +927,6 @@ and does NOT have its text transferred over. It ends up with blank text. } else if (visible == FMTabVisibleIn.Bottom) { - Lazy_LowerTabControl.Construct(); MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, fmTabPage); } Lazy_FMTabsMenu.SetItemChecked(i, visible != FMTabVisibleIn.None); @@ -5548,7 +5547,6 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) dragTab = TopFMTabControl.DragTab; if (dragTab == null) return; - Lazy_LowerTabControl.Construct(); MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, dragTab); } finally From ecc8c222547e8fbd52206158adaebc49105d6df8 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 15:23:39 -0800 Subject: [PATCH 144/200] Cleanup notes --- AngelLoader/Forms/MainForm.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 629054f27..d26152c6b 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -10,8 +10,8 @@ in its panel correctly, etc.). If we figure out how to solve this later, we can lazy load them then." -All filter controls (they're hideable) -FM tab pages themselves (even though they're blank containers of lazy-loaded contents now) -@DockUI: We're going to lazy-load both of these in the final release - remove this comment then --FM tab controls (the containers of the tab pages) +-FM tab controls (the containers of the tab pages) (but can't really, because tab pages need to be added to a tab + control before they can be considered to be in a proper working state) -Rating columns (text or image) - one or the other will not be shown @NET5: Fonts will change and control sizes will all change too. @@ -902,11 +902,11 @@ and does NOT have its text transferred over. It ends up with blank text. fmTabs[i] = fmTabsDict[i]; } - // @DockUI: We'll need to change this logic when we lazy-load both tab controls /* @DockUI: Tab pages need to be added to a tab control once in order to work properly. - At the very least, setting tab text throws an ArgumentOutOfRangeException in release mode. - This being the case, we should just keep the top control non-lazy-loaded and keep the logic as it is. + If they haven't been added, then at the very least, setting tab text throws an ArgumentOutOfRangeException + in release mode. This being the case, we should just keep the top control non-lazy-loaded and keep the + logic as it is. */ TopFMTabControl.SetTabsFull(fmTabs); @@ -1222,7 +1222,7 @@ private void SetWindowStateAndSize() { if (!_firstShowDone) { - // @DockUI: We need to handle the bottom tab control / collapsed state here too + // @DockUI: Bottom (lazy-loaded) control handles this itself if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab && !Config.TopFMTabsPanelCollapsed) { lazyTab.Construct(); @@ -3313,7 +3313,6 @@ private void SetFMTabsCollapsedState(WhichTabControl which, bool collapsed) } } - // @DockUI: Could we combine these eventually? private void TopFMTabsMenuButton_Click(object sender, EventArgs e) { Lazy_FMTabsMenu.Menu.Data = WhichTabControl.Top; @@ -3357,9 +3356,6 @@ internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) TabPage tab = GetObjectFromMenuItem(Lazy_FMTabsMenu.Menu, s, _fmTabPages, FMTabCount); - // @DockUI: It's possible to have zero tabs in one or the other tab controls now - // This is ultimately what we want, but we need to add proper support for this scenario, because we - // currently assume it can't happen (because it couldn't before). DarkTabControl tabControl = s.Owner is DarkContextMenu { Data: WhichTabControl.Bottom } ? Lazy_LowerTabControl.TabControl : TopFMTabControl; From ca1c28a63503d3b38d6ea2327b98741872041d35 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 19:31:05 -0800 Subject: [PATCH 145/200] Testing and plan for image cursor during drag --- AngelLoader/Forms/ControlUtils.cs | 81 +++++++++++++++++++ AngelLoader/Forms/MainForm.cs | 20 +++++ .../Forms/WinFormsNative/WinFormsNative.cs | 24 ++++++ 3 files changed, 125 insertions(+) diff --git a/AngelLoader/Forms/ControlUtils.cs b/AngelLoader/Forms/ControlUtils.cs index ea1baeeee..08fae191a 100644 --- a/AngelLoader/Forms/ControlUtils.cs +++ b/AngelLoader/Forms/ControlUtils.cs @@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Drawing.Drawing2D; +using System.Drawing.Imaging; using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; @@ -961,4 +962,84 @@ internal static void TrySetMaxDelay(this ToolTip toolTip) } } } + + #region Cursor + + public static bool TryCreateCursor(Bitmap bitmap, int xHotspot, int yHotspot, [NotNullWhen(true)] out Cursor? cursor) + { + cursor = null; + + Native.ICONINFO iconInfo = new(); + IntPtr iconHandle = IntPtr.Zero; + IntPtr cursorPtr = IntPtr.Zero; + try + { + iconHandle = bitmap.GetHicon(); + + if (!Native.GetIconInfo(iconHandle, ref iconInfo) || iconHandle == IntPtr.Zero) + { + return false; + } + + iconInfo.xHotspot = xHotspot; + iconInfo.yHotspot = yHotspot; + + // false means it's a cursor (not an icon) + iconInfo.fIcon = false; + + cursorPtr = Native.CreateIconIndirect(ref iconInfo); + if (cursorPtr == IntPtr.Zero) + { + Native.DeleteObject(cursorPtr); + return false; + } + + cursor = new Cursor(cursorPtr); + return true; + } + catch + { + Native.DeleteObject(cursorPtr); + return false; + } + finally + { + Native.DeleteObject(iconInfo.hbmMask); + Native.DeleteObject(iconInfo.hbmColor); + Native.DestroyIcon(iconHandle); + } + } + + public static Bitmap? CloneWithOpacity(this Bitmap bitmap, float opacity) + { + try + { + Bitmap retBmp = new(bitmap.Width, bitmap.Height); + + using Graphics g = Graphics.FromImage(retBmp); + + using ImageAttributes imgAttrib = new(); + + ColorMatrix opacityMatrix = new() { Matrix33 = opacity }; + imgAttrib.SetColorMatrix(opacityMatrix); + + g.DrawImage( + image: bitmap, + destRect: new Rectangle(0, 0, retBmp.Width, retBmp.Height), + srcX: 0, + srcY: 0, + srcWidth: bitmap.Width, + srcHeight: bitmap.Height, + srcUnit: GraphicsUnit.Pixel, + imageAttr: imgAttrib); + + return retBmp; + } + catch + { + return null; + } + } + + #endregion } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index d26152c6b..705c2cf30 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -259,8 +259,28 @@ private void Test2Button_Click(object sender, EventArgs e) Height = 872; } + /* + @DockUI(Cursor image plan): + -Create a disposable class to wrap up the bitmap and cursor. Make it one field that just gets disposed and + re-instantiated, that way even in the worst case if somehow our drag doesn't get properly ended, we'll only + ever leak one cursor and one bitmap at maximum. + -Cut out the parts of the tab bar around the selected tab in the image, so it will be the only tab visible. + */ private void Test3Button_Click(object sender, EventArgs e) { + Control c = TopFMTabControl; + + using Bitmap bmpPre = new(c.Width, c.Height); + c.DrawToBitmap(bmpPre, new Rectangle(0, 0, c.Width, c.Height)); + + Bitmap? bmpFinal = bmpPre.CloneWithOpacity(0.88f); + if (bmpFinal != null) + { + if (ControlUtils.TryCreateCursor(bmpFinal, 0, 0, out Cursor? cursor)) + { + Cursor = cursor; + } + } } private void Test4Button_Click(object sender, EventArgs e) diff --git a/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs b/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs index e98ccb802..8fb6a6cc8 100644 --- a/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs +++ b/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs @@ -929,4 +929,28 @@ public static NONCLIENTMETRICSW GetNonClientMetrics() } #endregion + + #region Cursor + + [PublicAPI] + internal struct ICONINFO + { + public bool fIcon; + public int xHotspot; + public int yHotspot; + public IntPtr hbmMask; + public IntPtr hbmColor; + } + + [DllImport("user32.dll")] + internal static extern IntPtr CreateIconIndirect(ref ICONINFO icon); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool GetIconInfo(IntPtr hIcon, ref ICONINFO pIconInfo); + + [DllImport("gdi32.dll")] + internal static extern bool DeleteObject(IntPtr handle); + + #endregion } From c4fa61c29833fe60499aa72696bc54cff2d427dd Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 19:56:31 -0800 Subject: [PATCH 146/200] Implement most of the image cursor plan --- AngelLoader/Forms/FormsData.cs | 43 ++++++++++++++++++++++++++++ AngelLoader/Forms/MainForm.cs | 52 +++++++++++++++++----------------- 2 files changed, 69 insertions(+), 26 deletions(-) diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index 843655978..7826aad78 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -63,3 +63,46 @@ public sealed class BackingTab(TabPage tabPage) public TabPage TabPage = tabPage; public FMTabVisibleIn VisibleIn = FMTabVisibleIn.Top; } + +/* +@DockUI(Cursor image plan): +-Cut out the parts of the tab bar around the selected tab in the image, so it will be the only tab visible. +*/ +public sealed class ImageCursor : IDisposable +{ + private readonly Bitmap? _bitmap; + public readonly Cursor Cursor; + + public ImageCursor(Control c) + { + try + { + using Bitmap bmpPre = new(c.Width, c.Height); + c.DrawToBitmap(bmpPre, new Rectangle(0, 0, c.Width, c.Height)); + + Bitmap? bmpFinal = bmpPre.CloneWithOpacity(0.88f); + if (bmpFinal != null && + ControlUtils.TryCreateCursor(bmpFinal, 0, 0, out Cursor? cursor)) + { + _bitmap = bmpFinal; + Cursor = cursor; + } + else + { + _bitmap = null; + Cursor = Cursors.Default; + } + } + catch + { + _bitmap = null; + Cursor = Cursors.Default; + } + } + + public void Dispose() + { + Cursor.Dispose(); + _bitmap?.Dispose(); + } +} \ No newline at end of file diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 705c2cf30..f8f5c69f5 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -259,28 +259,8 @@ private void Test2Button_Click(object sender, EventArgs e) Height = 872; } - /* - @DockUI(Cursor image plan): - -Create a disposable class to wrap up the bitmap and cursor. Make it one field that just gets disposed and - re-instantiated, that way even in the worst case if somehow our drag doesn't get properly ended, we'll only - ever leak one cursor and one bitmap at maximum. - -Cut out the parts of the tab bar around the selected tab in the image, so it will be the only tab visible. - */ private void Test3Button_Click(object sender, EventArgs e) { - Control c = TopFMTabControl; - - using Bitmap bmpPre = new(c.Width, c.Height); - c.DrawToBitmap(bmpPre, new Rectangle(0, 0, c.Width, c.Height)); - - Bitmap? bmpFinal = bmpPre.CloneWithOpacity(0.88f); - if (bmpFinal != null) - { - if (ControlUtils.TryCreateCursor(bmpFinal, 0, 0, out Cursor? cursor)) - { - Cursor = cursor; - } - } } private void Test4Button_Click(object sender, EventArgs e) @@ -5544,20 +5524,21 @@ public void RefreshCurrentFMScreenshots() private void TopFMTabControl_MouseDragCustom(object sender, MouseEventArgs e) { - HandleTabDrag(LowerSplitContainer); + HandleTabDrag(dest: WhichTabControl.Bottom); } internal void Lazy_LowerTabControl_MouseDragCustom(object sender, MouseEventArgs e) { - HandleTabDrag(TopSplitContainer); + HandleTabDrag(dest: WhichTabControl.Top); } private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) { - if (!_inTabDragArea) return; TabPage? dragTab = null; try { + if (!_inTabDragArea) return; + EverythingPanel.SuspendDrawing(); dragTab = TopFMTabControl.DragTab; @@ -5567,6 +5548,7 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) } finally { + DestroyImageCursor(); _inTabDragArea = false; EverythingPanel.ResumeDrawingAndFocusControl(dragTab); } @@ -5574,11 +5556,11 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) { - if (!_inTabDragArea) return; - TabPage? dragTab = null; try { + if (!_inTabDragArea) return; + EverythingPanel.SuspendDrawing(); dragTab = Lazy_LowerTabControl.DragTab; @@ -5596,11 +5578,19 @@ internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) } finally { + DestroyImageCursor(); _inTabDragArea = false; EverythingPanel.ResumeDrawingAndFocusControl(dragTab); } } + private void DestroyImageCursor() + { + Cursor = Cursors.Default; + _imageCursor?.Dispose(); + _imageCursor = null; + } + private static Color GetOverlayColor() { // @DockUI: Make light and dark mode colors @@ -5643,8 +5633,18 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa tabPage.Focus(); } - private void HandleTabDrag(DarkSplitContainerCustom sc) + private ImageCursor? _imageCursor; + + private void HandleTabDrag(WhichTabControl dest) { + (DarkTabControl tabControl, DarkSplitContainerCustom sc) = + (dest == WhichTabControl.Bottom) + ? (TopFMTabControl, LowerSplitContainer) + : (Lazy_LowerTabControl.TabControl, TopSplitContainer); + + _imageCursor ??= new ImageCursor(tabControl); + Cursor = _imageCursor.Cursor; + Point cp = Native.GetCursorPosition_Fast(); if ((sc.Panel2Collapsed || sc.FullScreen) && sc.ClientRectangle.Contains(sc.PointToClient_Fast(cp))) From 99bac34e188cfe14e2d5ecc51b943f4e256c7039 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 20:44:28 -0800 Subject: [PATCH 147/200] Show only selected tab on tab image cursor --- AngelLoader/Forms/FormsData.cs | 56 ++++++++++++++++++++++++++++------ AngelLoader/Forms/MainForm.cs | 4 +-- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index 7826aad78..cb0221b0d 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -1,5 +1,6 @@ using System; using System.Drawing; +using System.Drawing.Imaging; using System.IO; using System.Windows.Forms; using AngelLoader.DataClasses; @@ -64,23 +65,54 @@ public sealed class BackingTab(TabPage tabPage) public FMTabVisibleIn VisibleIn = FMTabVisibleIn.Top; } -/* -@DockUI(Cursor image plan): --Cut out the parts of the tab bar around the selected tab in the image, so it will be the only tab visible. -*/ -public sealed class ImageCursor : IDisposable +public sealed class TabControlImageCursor : IDisposable { private readonly Bitmap? _bitmap; public readonly Cursor Cursor; - public ImageCursor(Control c) + public TabControlImageCursor(TabControl tabControl) { + Bitmap? bmpChopped = null; try { - using Bitmap bmpPre = new(c.Width, c.Height); - c.DrawToBitmap(bmpPre, new Rectangle(0, 0, c.Width, c.Height)); + using Bitmap bmpPre = new(tabControl.Width, tabControl.Height); + tabControl.DrawToBitmap(bmpPre, new Rectangle(0, 0, tabControl.Width, tabControl.Height)); + + Rectangle tabRect = tabControl.SelectedIndex > -1 + ? tabControl.GetTabRect(tabControl.SelectedIndex) + : Rectangle.Empty; + + if (tabRect != Rectangle.Empty) + { + // Remove all other tabs from the image and show only the selected tab at the left side, for more + // visual clarity and a clean look + int tabRectHeight = tabRect.Height + (Global.Config.DarkMode ? 2 : 3); + int tabRectWidth = tabRect.Width + (Global.Config.DarkMode ? 1 : 2); + + bmpChopped = new Bitmap(bmpPre.Width, bmpPre.Height, PixelFormat.Format32bppPArgb); + using Graphics g = Graphics.FromImage(bmpChopped); + g.DrawImage( + image: bmpPre, + destRect: new Rectangle(0, tabRectHeight, bmpPre.Width, bmpPre.Height - tabRectHeight), + srcX: 0, + srcY: tabRectHeight, + srcWidth: bmpPre.Width, + srcHeight: bmpPre.Height - tabRectHeight, + srcUnit: GraphicsUnit.Pixel + ); - Bitmap? bmpFinal = bmpPre.CloneWithOpacity(0.88f); + g.DrawImage( + image: bmpPre, + destRect: new Rectangle(0, 0, tabRectWidth, tabRectHeight), + srcX: tabRect.Left, + srcY: 0, + srcWidth: tabRectWidth, + srcHeight: tabRectHeight, + srcUnit: GraphicsUnit.Pixel + ); + } + + Bitmap? bmpFinal = (bmpChopped ?? bmpPre).CloneWithOpacity(0.88f); if (bmpFinal != null && ControlUtils.TryCreateCursor(bmpFinal, 0, 0, out Cursor? cursor)) { @@ -95,8 +127,12 @@ public ImageCursor(Control c) } catch { - _bitmap = null; Cursor = Cursors.Default; + _bitmap = null; + } + finally + { + bmpChopped?.Dispose(); } } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index f8f5c69f5..8599f38d2 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5633,7 +5633,7 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa tabPage.Focus(); } - private ImageCursor? _imageCursor; + private TabControlImageCursor? _imageCursor; private void HandleTabDrag(WhichTabControl dest) { @@ -5642,7 +5642,7 @@ private void HandleTabDrag(WhichTabControl dest) ? (TopFMTabControl, LowerSplitContainer) : (Lazy_LowerTabControl.TabControl, TopSplitContainer); - _imageCursor ??= new ImageCursor(tabControl); + _imageCursor ??= new TabControlImageCursor(tabControl); Cursor = _imageCursor.Cursor; Point cp = Native.GetCursorPosition_Fast(); From c4ff254bee5aaa3cbd1d5cdae9749d7676cdccf8 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 21:03:53 -0800 Subject: [PATCH 148/200] Start drag only when outside the tab bar --- .../Forms/CustomControls/DarkTabControl.cs | 14 +++++++++-- AngelLoader/Forms/MainForm.cs | 24 +++++++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 08c1e063b..bb6ea61d5 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -357,6 +357,16 @@ protected override void OnMouseUp(MouseEventArgs e) _backedUpBackingTabs = null; } + private void InvokeMouseDragCustomIfNeeded(MouseEventArgs e) + { + Rectangle tabBarExpanded = GetTabBarRect(); + tabBarExpanded.Inflate(4, 16); + if (!tabBarExpanded.Contains(e.Location)) + { + MouseDragCustom?.Invoke(this, e); + } + } + protected override void OnMouseMove(MouseEventArgs e) { if (DesignMode || !AllowReordering) @@ -374,14 +384,14 @@ protected override void OnMouseMove(MouseEventArgs e) if (TabCount <= 1) { - MouseDragCustom?.Invoke(this, e); + InvokeMouseDragCustomIfNeeded(e); base.OnMouseMove(e); return; } // If we are dragging a tab, don't run the normal handler, because we want to be "modal" and block so // nothing weird happens - MouseDragCustom?.Invoke(this, e); + InvokeMouseDragCustomIfNeeded(e); int dragTabIndex = TabPages.IndexOf(DragTab); var (bDragTabIndex, _) = FindBackingTab(_backingTabList, DragTab); diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 8599f38d2..6d7df5004 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5535,9 +5535,14 @@ internal void Lazy_LowerTabControl_MouseDragCustom(object sender, MouseEventArgs private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) { TabPage? dragTab = null; + bool refresh = true; try { - if (!_inTabDragArea) return; + if (!_inTabDragArea) + { + refresh = false; + return; + } EverythingPanel.SuspendDrawing(); @@ -5550,16 +5555,24 @@ private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) { DestroyImageCursor(); _inTabDragArea = false; - EverythingPanel.ResumeDrawingAndFocusControl(dragTab); + if (refresh) + { + EverythingPanel.ResumeDrawingAndFocusControl(dragTab); + } } } internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) { TabPage? dragTab = null; + bool refresh = true; try { - if (!_inTabDragArea) return; + if (!_inTabDragArea) + { + refresh = false; + return; + } EverythingPanel.SuspendDrawing(); @@ -5580,7 +5593,10 @@ internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) { DestroyImageCursor(); _inTabDragArea = false; - EverythingPanel.ResumeDrawingAndFocusControl(dragTab); + if (refresh) + { + EverythingPanel.ResumeDrawingAndFocusControl(dragTab); + } } } From 235a754c347417aebc38dfd3fc72009d3c3716b4 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 21:19:24 -0800 Subject: [PATCH 149/200] Select nearest tab on remove --- .../Forms/CustomControls/DarkTabControl.cs | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index bb6ea61d5..ae3df4048 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -531,10 +531,29 @@ public void ShowTab(TabPage tabPage, bool show) bt.VisibleIn = FMTabVisibleIn.None; if (TabPages.Contains(bt.TabPage)) { - TabPages.Remove(bt.TabPage); - // Otherwise the first control within the tab page gets selected - // @DockUI: We should probably select the nearest tab when we remove one - if (TabCount > 0) TabPages[0].Focus(); + if (TabPages.Count > 1 && SelectedIndex > 0) + { + if (SelectedTab == bt.TabPage) + { + Control? parent = Parent; + try + { + parent?.SuspendDrawing(); + int newIndex = SelectedIndex == TabCount - 1 ? SelectedIndex - 1 : SelectedIndex + 1; + SelectedTab = TabPages[newIndex]; + TabPages.Remove(bt.TabPage); + } + finally + { + parent?.ResumeDrawing(); + } + } + } + else + { + TabPages.Remove(bt.TabPage); + } + if (TabCount > 0) SelectedTab.Focus(); } } } From 3bc1328236b532aaa458ff65bb486682221d4181 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 21:27:00 -0800 Subject: [PATCH 150/200] Expand collapsed tab controls on tab move-to --- AngelLoader/Forms/MainForm.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 6d7df5004..a40846ab8 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -927,7 +927,7 @@ logic as it is. } else if (visible == FMTabVisibleIn.Bottom) { - MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, fmTabPage); + MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, fmTabPage, expandCollapsed: false); } Lazy_FMTabsMenu.SetItemChecked(i, visible != FMTabVisibleIn.None); } @@ -5617,7 +5617,7 @@ private static Color GetOverlayColor() blue: DarkColors.BlueSelection.B); } - private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPage) + private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPage, bool expandCollapsed = true) { if (source == dest) return; @@ -5645,6 +5645,16 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa sourceSplitContainer.Panel2Collapsed = true; } destSplitContainer.Panel2Collapsed = false; + + if (expandCollapsed) + { + if (destSplitContainer.FullScreen) + { + destSplitContainer.ToggleFullScreen(); + SetFMTabsCollapsedState(dest, false); + } + } + destTabControl.SelectedTab = tabPage; tabPage.Focus(); } From f8e1eb283c2a8b9264d697dac11c27e4dcd79291 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 21:36:54 -0800 Subject: [PATCH 151/200] Dedupe the MouseUp tab dragging code --- AngelLoader/Forms/MainForm.cs | 158 ++++++++++++++-------------------- 1 file changed, 65 insertions(+), 93 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index a40846ab8..f44c33f39 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5516,11 +5516,13 @@ public void RefreshCurrentFMScreenshots() } #region Tab dragging + /* @DockUI: Working/testing code, finalize before release */ private bool _inTabDragArea; + private TabControlImageCursor? _imageCursor; private void TopFMTabControl_MouseDragCustom(object sender, MouseEventArgs e) { @@ -5534,41 +5536,70 @@ internal void Lazy_LowerTabControl_MouseDragCustom(object sender, MouseEventArgs private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) { - TabPage? dragTab = null; - bool refresh = true; - try + HandleTabDragFinish(WhichTabControl.Top, WhichTabControl.Bottom); + } + + internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) + { + HandleTabDragFinish(WhichTabControl.Bottom, WhichTabControl.Top); + } + + private void HandleTabDrag(WhichTabControl dest) + { + (DarkTabControl tabControl, DarkSplitContainerCustom sc) = + (dest == WhichTabControl.Bottom) + ? (TopFMTabControl, LowerSplitContainer) + : (Lazy_LowerTabControl.TabControl, TopSplitContainer); + + _imageCursor ??= new TabControlImageCursor(tabControl); + Cursor = _imageCursor.Cursor; + + Point cp = Native.GetCursorPosition_Fast(); + + if ((sc.Panel2Collapsed || sc.FullScreen) && sc.ClientRectangle.Contains(sc.PointToClient_Fast(cp))) { if (!_inTabDragArea) { - refresh = false; - return; + _inTabDragArea = true; + Trace.WriteLine("Hit collapsed"); + using var gc = new Native.GraphicsContext(sc.Handle); + using var b = new SolidBrush(GetOverlayColor()); + int splitterDistance = sc.SplitterDistanceLogical; + gc.G.FillRectangle( + b, + new Rectangle( + splitterDistance, + 0, + sc.ClientRectangle.Width - splitterDistance, + sc.ClientRectangle.Height)); } - - EverythingPanel.SuspendDrawing(); - - dragTab = TopFMTabControl.DragTab; - if (dragTab == null) return; - - MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, dragTab); } - finally + else if (sc.Panel2.ClientRectangle.Contains(sc.Panel2.PointToClient_Fast(cp))) { - DestroyImageCursor(); - _inTabDragArea = false; - if (refresh) + if (!_inTabDragArea) { - EverythingPanel.ResumeDrawingAndFocusControl(dragTab); + _inTabDragArea = true; + Trace.WriteLine("Hit open"); + using var gc = new Native.GraphicsContext(sc.Panel2.Handle); + using var b = new SolidBrush(GetOverlayColor()); + gc.G.FillRectangle(b, sc.Panel2.ClientRectangle with { X = 0, Y = 0 }); } } + else if (_inTabDragArea) + { + _inTabDragArea = false; + Trace.WriteLine("Miss"); + sc.Refresh(); + } } - internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) + private void HandleTabDragFinish(WhichTabControl source, WhichTabControl dest) { TabPage? dragTab = null; bool refresh = true; try { - if (!_inTabDragArea) + if (!_inTabDragArea || source == dest) { refresh = false; return; @@ -5576,18 +5607,10 @@ internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) EverythingPanel.SuspendDrawing(); - dragTab = Lazy_LowerTabControl.DragTab; + dragTab = source == WhichTabControl.Bottom ? Lazy_LowerTabControl.DragTab : TopFMTabControl.DragTab; if (dragTab == null) return; - if (TopSplitContainer.Panel2Collapsed) - { - TopSplitContainer.Panel2Collapsed = false; - if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab) - { - lazyTab.ConstructWithSuspendResume(); - } - } - MoveTab(WhichTabControl.Bottom, WhichTabControl.Top, dragTab); + MoveTab(source, dest, dragTab); } finally { @@ -5600,23 +5623,6 @@ internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) } } - private void DestroyImageCursor() - { - Cursor = Cursors.Default; - _imageCursor?.Dispose(); - _imageCursor = null; - } - - private static Color GetOverlayColor() - { - // @DockUI: Make light and dark mode colors - return Color.FromArgb( - alpha: 64, - red: DarkColors.BlueSelection.R, - green: DarkColors.BlueSelection.G, - blue: DarkColors.BlueSelection.B); - } - private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPage, bool expandCollapsed = true) { if (source == dest) return; @@ -5659,55 +5665,21 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa tabPage.Focus(); } - private TabControlImageCursor? _imageCursor; - - private void HandleTabDrag(WhichTabControl dest) + private void DestroyImageCursor() { - (DarkTabControl tabControl, DarkSplitContainerCustom sc) = - (dest == WhichTabControl.Bottom) - ? (TopFMTabControl, LowerSplitContainer) - : (Lazy_LowerTabControl.TabControl, TopSplitContainer); - - _imageCursor ??= new TabControlImageCursor(tabControl); - Cursor = _imageCursor.Cursor; - - Point cp = Native.GetCursorPosition_Fast(); + Cursor = Cursors.Default; + _imageCursor?.Dispose(); + _imageCursor = null; + } - if ((sc.Panel2Collapsed || sc.FullScreen) && sc.ClientRectangle.Contains(sc.PointToClient_Fast(cp))) - { - if (!_inTabDragArea) - { - _inTabDragArea = true; - Trace.WriteLine("Hit collapsed"); - using var gc = new Native.GraphicsContext(sc.Handle); - using var b = new SolidBrush(GetOverlayColor()); - int splitterDistance = sc.SplitterDistanceLogical; - gc.G.FillRectangle( - b, - new Rectangle( - splitterDistance, - 0, - sc.ClientRectangle.Width - splitterDistance, - sc.ClientRectangle.Height)); - } - } - else if (sc.Panel2.ClientRectangle.Contains(sc.Panel2.PointToClient_Fast(cp))) - { - if (!_inTabDragArea) - { - _inTabDragArea = true; - Trace.WriteLine("Hit open"); - using var gc = new Native.GraphicsContext(sc.Panel2.Handle); - using var b = new SolidBrush(GetOverlayColor()); - gc.G.FillRectangle(b, sc.Panel2.ClientRectangle with { X = 0, Y = 0 }); - } - } - else if (_inTabDragArea) - { - _inTabDragArea = false; - Trace.WriteLine("Miss"); - sc.Refresh(); - } + private static Color GetOverlayColor() + { + // @DockUI: Make light and dark mode colors + return Color.FromArgb( + alpha: 64, + red: DarkColors.BlueSelection.R, + green: DarkColors.BlueSelection.G, + blue: DarkColors.BlueSelection.B); } // @DockUI: Test code, remove for final release From 18cb9dcaf941fc414d818acf41af4d5b251e3ad9 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 21:43:58 -0800 Subject: [PATCH 152/200] Note --- AngelLoader/Forms/MainForm.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index f44c33f39..1cb6fef65 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -3370,8 +3370,7 @@ internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) // Although adding a tab to another control automatically removes it from the first one, we need to // explicitly run our custom ShowTab() method in order to keep the backing list synced. Otherwise, the // tab order gets messed up. - // @DockUI: Could we make this happen automatically on tab remove? - // We'd need an event disabler and so on, but it might work. + // @DockUI: The show/hide logic needs to also do whatever extra logic MoveTab() does if (s.Checked) { if (tabControl == TopFMTabControl) From 1542dd84e260b82f7974528cc75e3bc4151afb15 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 23:36:16 -0800 Subject: [PATCH 153/200] Fix unthemed DateTimePickers in the tab drag image --- .../CustomControls/DarkDateTimePicker.cs | 60 +++++++++++++++++-- AngelLoader/Forms/FormsData.cs | 32 ++++++++++ .../Forms/WinFormsNative/WinFormsNative.cs | 3 + 3 files changed, 89 insertions(+), 6 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkDateTimePicker.cs b/AngelLoader/Forms/CustomControls/DarkDateTimePicker.cs index 4e41b4cc9..b6ce46156 100644 --- a/AngelLoader/Forms/CustomControls/DarkDateTimePicker.cs +++ b/AngelLoader/Forms/CustomControls/DarkDateTimePicker.cs @@ -79,7 +79,7 @@ protected override void OnMouseLeave(EventArgs e) } } - private void DrawButton(Graphics g) + private void DrawButton(Graphics g, Point? offset = null) { var (dtpInfo, buttonRect) = GetDTPInfoAndButtonRect(); @@ -90,19 +90,57 @@ private void DrawButton(Graphics g) ? DarkColors.LighterBackgroundBrush : DarkColors.LightBackgroundBrush; + if (offset != null) + { + buttonRect = buttonRect with + { + X = buttonRect.X + offset.Value.X, + Y = buttonRect.Y + offset.Value.Y + }; + } + g.FillRectangle(buttonBrush, buttonRect); Images.PaintArrow7x4(g, Direction.Down, buttonRect, Enabled); } - private void PaintCustom() + // This thing's theme doesn't get fully captured in the control DrawToBitmap() image, so we also use this + // method to paint the themed visuals directly onto the image after the fact. + public void PaintCustom(Graphics? g = null, Point? offset = null) + { + if (g == null) + { + using var gc = new Native.GraphicsContext(Handle); + PaintCustomInternal(gc.G); + } + else if (offset != null) + { + PaintCustomInternal(g, offset); + } + } + + private void PaintCustomInternal(Graphics g, Point? offset = null) { - using var gc = new Native.GraphicsContext(Handle); + int x1, y1, x2, y2; + if (offset != null) + { + x1 = offset.Value.X; + y1 = offset.Value.Y; + x2 = offset.Value.X + 1; + y2 = offset.Value.Y + 1; + } + else + { + x1 = 0; + y1 = 0; + x2 = 1; + y2 = 1; + } - gc.G.DrawRectangle(DarkColors.LightBorderPen, 0, 0, Width - 1, Height - 1); - gc.G.DrawRectangle(DarkColors.Fen_ControlBackgroundPen, 1, 1, Width - 3, Height - 3); + g.DrawRectangle(DarkColors.LightBorderPen, x1, y1, Width - 1, Height - 1); + g.DrawRectangle(DarkColors.Fen_ControlBackgroundPen, x2, y2, Width - 3, Height - 3); - DrawButton(gc.G); + DrawButton(g, offset); } protected override void WndProc(ref Message m) @@ -115,6 +153,16 @@ protected override void WndProc(ref Message m) switch (m.Msg) { + case Native.WM_PRINT: + case Native.WM_PRINTCLIENT: + { + using (new Win32ThemeHooks.OverrideSysColorScope(Win32ThemeHooks.Override.Full)) + { + base.WndProc(ref m); + } + PaintCustom(); + break; + } // @DarkModeNote(DateTimePicker): Still flickers the classic border somewhat on move/resize // Not the end of the world, but if we find a quick way to fix it, we should do it. Otherwise, // we'll just call it done. diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index cb0221b0d..5214c1228 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -4,6 +4,8 @@ using System.IO; using System.Windows.Forms; using AngelLoader.DataClasses; +using AngelLoader.Forms.CustomControls; +using AngelLoader.Forms.WinFormsNative; namespace AngelLoader.Forms; @@ -70,6 +72,30 @@ public sealed class TabControlImageCursor : IDisposable private readonly Bitmap? _bitmap; public readonly Cursor Cursor; + // Draw the themed DateTimePickers manually onto the image, because their themes don't get fully captured. + private static void DrawDateTimePickers( + Control control, + Graphics g, + TabControl tabControl, + int stackCounter = 0) + { + stackCounter++; + if (stackCounter > 100) return; + + if (control is DarkDateTimePicker dtp) + { + Point offset = tabControl.PointToClient_Fast(dtp.Parent.PointToScreen_Fast(dtp.Location)); + dtp.PaintCustom(g, offset); + } + + Control.ControlCollection controls = control.Controls; + int count = controls.Count; + for (int i = 0; i < count; i++) + { + DrawDateTimePickers(controls[i], g, tabControl, stackCounter); + } + } + public TabControlImageCursor(TabControl tabControl) { Bitmap? bmpChopped = null; @@ -110,6 +136,12 @@ public TabControlImageCursor(TabControl tabControl) srcHeight: tabRectHeight, srcUnit: GraphicsUnit.Pixel ); + + DrawDateTimePickers( + tabControl.SelectedTab, + g, + tabControl + ); } Bitmap? bmpFinal = (bmpChopped ?? bmpPre).CloneWithOpacity(0.88f); diff --git a/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs b/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs index 8fb6a6cc8..2f6773631 100644 --- a/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs +++ b/AngelLoader/Forms/WinFormsNative/WinFormsNative.cs @@ -36,6 +36,9 @@ internal static class Native internal const int WM_SETTINGCHANGE = 0x001A; + internal const int WM_PRINT = 0x0317; + internal const int WM_PRINTCLIENT = 0x0318; + [PublicAPI] [StructLayout(LayoutKind.Sequential)] public readonly struct RECT From 0c3ed2789ffdec4bd0eec406dc13e9a760cab75c Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 23:38:49 -0800 Subject: [PATCH 154/200] Don't do the DateTimePicker fix in light mode --- AngelLoader/Forms/FormsData.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index 5214c1228..cd821a2fc 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -137,11 +137,14 @@ public TabControlImageCursor(TabControl tabControl) srcUnit: GraphicsUnit.Pixel ); - DrawDateTimePickers( - tabControl.SelectedTab, - g, - tabControl - ); + if (Global.Config.DarkMode) + { + DrawDateTimePickers( + tabControl.SelectedTab, + g, + tabControl + ); + } } Bitmap? bmpFinal = (bmpChopped ?? bmpPre).CloneWithOpacity(0.88f); From 7b65f67125ee9704e5d8aaace891dfd94b555760 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Sun, 3 Mar 2024 23:50:05 -0800 Subject: [PATCH 155/200] Fix left side of light mode tab rectangle in drag image --- AngelLoader/Forms/FormsData.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index cd821a2fc..3434e25b0 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -3,6 +3,7 @@ using System.Drawing.Imaging; using System.IO; using System.Windows.Forms; +using AL_Common; using AngelLoader.DataClasses; using AngelLoader.Forms.CustomControls; using AngelLoader.Forms.WinFormsNative; @@ -113,7 +114,8 @@ public TabControlImageCursor(TabControl tabControl) // Remove all other tabs from the image and show only the selected tab at the left side, for more // visual clarity and a clean look int tabRectHeight = tabRect.Height + (Global.Config.DarkMode ? 2 : 3); - int tabRectWidth = tabRect.Width + (Global.Config.DarkMode ? 1 : 2); + int tabRectWidth = tabRect.Width + (Global.Config.DarkMode ? 1 : 4); + int tabRectLeft = (tabRect.Left - (Global.Config.DarkMode ? 0 : 2).ClampToZero()); bmpChopped = new Bitmap(bmpPre.Width, bmpPre.Height, PixelFormat.Format32bppPArgb); using Graphics g = Graphics.FromImage(bmpChopped); @@ -130,7 +132,7 @@ public TabControlImageCursor(TabControl tabControl) g.DrawImage( image: bmpPre, destRect: new Rectangle(0, 0, tabRectWidth, tabRectHeight), - srcX: tabRect.Left, + srcX: tabRectLeft, srcY: 0, srcWidth: tabRectWidth, srcHeight: tabRectHeight, From fe576dd667a8775702fcfee667b9bf000091eead Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 01:01:29 -0800 Subject: [PATCH 156/200] Fix completely broken tab show/hide menu functionality --- .../Forms/CustomControls/DarkTabControl.cs | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index ae3df4048..29bb5c506 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -531,22 +531,19 @@ public void ShowTab(TabPage tabPage, bool show) bt.VisibleIn = FMTabVisibleIn.None; if (TabPages.Contains(bt.TabPage)) { - if (TabPages.Count > 1 && SelectedIndex > 0) + if (TabPages.Count > 1 && SelectedIndex > 0 && SelectedTab == bt.TabPage) { - if (SelectedTab == bt.TabPage) + Control? parent = Parent; + try { - Control? parent = Parent; - try - { - parent?.SuspendDrawing(); - int newIndex = SelectedIndex == TabCount - 1 ? SelectedIndex - 1 : SelectedIndex + 1; - SelectedTab = TabPages[newIndex]; - TabPages.Remove(bt.TabPage); - } - finally - { - parent?.ResumeDrawing(); - } + parent?.SuspendDrawing(); + int newIndex = SelectedIndex == TabCount - 1 ? SelectedIndex - 1 : SelectedIndex + 1; + SelectedTab = TabPages[newIndex]; + TabPages.Remove(bt.TabPage); + } + finally + { + parent?.ResumeDrawing(); } } else From 00657997fe3fec63ef29483a9724d97f42371561 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 01:04:30 -0800 Subject: [PATCH 157/200] Git line ending police --- AngelLoader/Forms/FormsData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index 3434e25b0..f81bfac01 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -178,4 +178,4 @@ public void Dispose() Cursor.Dispose(); _bitmap?.Dispose(); } -} \ No newline at end of file +} From 149d3c9b48ae10008e0a834f9ae0a61567ce6648 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 01:14:02 -0800 Subject: [PATCH 158/200] Comments and precedence fix --- AngelLoader/Forms/FormsData.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index f81bfac01..2a187d170 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -115,10 +115,12 @@ public TabControlImageCursor(TabControl tabControl) // visual clarity and a clean look int tabRectHeight = tabRect.Height + (Global.Config.DarkMode ? 2 : 3); int tabRectWidth = tabRect.Width + (Global.Config.DarkMode ? 1 : 4); - int tabRectLeft = (tabRect.Left - (Global.Config.DarkMode ? 0 : 2).ClampToZero()); + int tabRectLeft = (tabRect.Left - (Global.Config.DarkMode ? 0 : 2)).ClampToZero(); bmpChopped = new Bitmap(bmpPre.Width, bmpPre.Height, PixelFormat.Format32bppPArgb); using Graphics g = Graphics.FromImage(bmpChopped); + + // Main body g.DrawImage( image: bmpPre, destRect: new Rectangle(0, tabRectHeight, bmpPre.Width, bmpPre.Height - tabRectHeight), @@ -129,6 +131,7 @@ public TabControlImageCursor(TabControl tabControl) srcUnit: GraphicsUnit.Pixel ); + // Top bar g.DrawImage( image: bmpPre, destRect: new Rectangle(0, 0, tabRectWidth, tabRectHeight), From 9723100d3651e9e1c7220ddf003feb857adfdc2f Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 09:09:02 -0800 Subject: [PATCH 159/200] Fix edge case with EnsureValidity() --- AngelLoader/Common/DataClasses/ConfigDataSupporting.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs index 6a1d28fe5..f25ead9cb 100644 --- a/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs +++ b/AngelLoader/Common/DataClasses/ConfigDataSupporting.cs @@ -136,7 +136,6 @@ internal sealed class FMTabsData internal FMTabData GetTab(FMTab tab) => Tabs[(int)tab]; - // @DockUI: Test to make sure this works in all cases with the new tab code! internal void EnsureValidity() { #region Fallback if multiple tabs have the same display index @@ -156,7 +155,7 @@ internal void EnsureValidity() if (NoneVisible()) SetAllVisible(FMTabVisibleIn.Top); // Fallback if selected tab is not marked as visible - if (GetTab(SelectedTab).Visible == FMTabVisibleIn.None) + if (GetTab(SelectedTab).Visible != FMTabVisibleIn.Top) { for (int i = 0; i < FMTabCount; i++) { @@ -167,7 +166,7 @@ internal void EnsureValidity() } } } - if (GetTab(SelectedTab2).Visible == FMTabVisibleIn.None) + if (GetTab(SelectedTab2).Visible != FMTabVisibleIn.Bottom) { for (int i = 0; i < FMTabCount; i++) { From 642c6f14941a4b23821f3ab1a671cc95b89cf04c Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 09:28:07 -0800 Subject: [PATCH 160/200] Change a few tab-related key names in config While we can, so hopefully they'll be as sane as they can be before release locks them in --- AngelLoader/Ini/ConfigIni.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/AngelLoader/Ini/ConfigIni.cs b/AngelLoader/Ini/ConfigIni.cs index c330fbc1a..3287a3eaa 100644 --- a/AngelLoader/Ini/ConfigIni.cs +++ b/AngelLoader/Ini/ConfigIni.cs @@ -1017,15 +1017,15 @@ private static unsafe Dictionary { "MainSplitterPercent", new Config_DelegatePointerWrapper(&Config_MainSplitterPercent_Set) }, { "TopSplitterPercent", new Config_DelegatePointerWrapper(&Config_TopSplitterPercent_Set) }, - { "LowerSplitterPercent", new Config_DelegatePointerWrapper(&Config_LowerSplitterPercent_Set) }, + { "BottomSplitterPercent", new Config_DelegatePointerWrapper(&Config_LowerSplitterPercent_Set) }, { "TopRightPanelCollapsed", new Config_DelegatePointerWrapper(&Config_TopFMTabsPanelCollapsed_Set) }, { "BottomRightPanelCollapsed", new Config_DelegatePointerWrapper(&Config_BottomFMTabsPanelCollapsed_Set) }, { "GameTab", new Config_DelegatePointerWrapper(&Config_GameTab_Set) }, #region FM tabs - { "TopRightTab", new Config_DelegatePointerWrapper(&Config_FMTab_Set) }, - { "TopRightTab2", new Config_DelegatePointerWrapper(&Config_FMTab2_Set) }, + { "SelectedTab1", new Config_DelegatePointerWrapper(&Config_FMTab_Set) }, + { "SelectedTab2", new Config_DelegatePointerWrapper(&Config_FMTab2_Set) }, { "StatsTabPosition", new Config_DelegatePointerWrapper(&Config_StatsTabPosition_Set) }, { "StatsTabVisible", new Config_DelegatePointerWrapper(&Config_StatsTabVisible_Set) }, @@ -1062,6 +1062,8 @@ private static unsafe Dictionary #region Backward compatibility + { "TopRightTab", new Config_DelegatePointerWrapper(&Config_FMTab_Set) }, + /* I put the game type as the suffix rather than the prefix on these for some reason, and then put them in the next public release. So now I have to support reading them suffixed. But let's just @@ -1423,13 +1425,13 @@ private static void WriteConfigIniInternal(ConfigData config, string fileName) sw.Append("MainSplitterPercent").Append('=').AppendLine(config.MainSplitterPercent.ToString(NumberFormatInfo.InvariantInfo)); sw.Append("TopSplitterPercent").Append('=').AppendLine(config.TopSplitterPercent.ToString(NumberFormatInfo.InvariantInfo)); - sw.Append("LowerSplitterPercent").Append('=').AppendLine(config.LowerSplitterPercent.ToString(NumberFormatInfo.InvariantInfo)); + sw.Append("BottomSplitterPercent").Append('=').AppendLine(config.LowerSplitterPercent.ToString(NumberFormatInfo.InvariantInfo)); sw.Append("TopRightPanelCollapsed").Append('=').Append(config.TopFMTabsPanelCollapsed).AppendLine(); sw.Append("BottomRightPanelCollapsed").Append('=').Append(config.BottomFMTabsPanelCollapsed).AppendLine(); sw.Append("GameTab").Append('=').Append(config.GameTab).AppendLine(); - sw.Append("TopRightTab").Append('=').Append(config.FMTabsData.SelectedTab).AppendLine(); - sw.Append("TopRightTab2").Append('=').Append(config.FMTabsData.SelectedTab2).AppendLine(); + sw.Append("SelectedTab1").Append('=').Append(config.FMTabsData.SelectedTab).AppendLine(); + sw.Append("SelectedTab2").Append('=').Append(config.FMTabsData.SelectedTab2).AppendLine(); sw.Append("StatsTabPosition").Append('=').Append(config.FMTabsData.GetTab(FMTab.Statistics).DisplayIndex).AppendLine(); sw.Append("EditFMTabPosition").Append('=').Append(config.FMTabsData.GetTab(FMTab.EditFM).DisplayIndex).AppendLine(); From 5ca98f5f12dcce750ef1eb1654391a1164e3628a Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 10:12:49 -0800 Subject: [PATCH 161/200] Work on tab show/hide via menu --- AngelLoader/Forms/ControlUtils.cs | 13 +++++-- AngelLoader/Forms/MainForm.cs | 59 ++++++++++++++++++++++++------- 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/AngelLoader/Forms/ControlUtils.cs b/AngelLoader/Forms/ControlUtils.cs index 08fae191a..c4b1fcf80 100644 --- a/AngelLoader/Forms/ControlUtils.cs +++ b/AngelLoader/Forms/ControlUtils.cs @@ -44,7 +44,10 @@ internal static void ResumeDrawing(this Control control, bool invalidateInsteadO } } - internal static void ResumeDrawingAndFocusControl(this Control control, Control? controlToFocus, bool invalidateInsteadOfRefresh = false) + internal static void ResumeDrawingAndFocusControl( + this Control control, + Control?[]? controlsToFocus, + bool invalidateInsteadOfRefresh = false) { if (!control.IsHandleCreated || !control.Visible) return; Native.SendMessage(control.Handle, Native.WM_SETREDRAW, true, IntPtr.Zero); @@ -56,7 +59,13 @@ Focus after the enable-redraw message but before the refresh. Designed originally for the tab control, but use it for whatever... */ - controlToFocus?.Focus(); + if (controlsToFocus != null) + { + foreach (Control? c in controlsToFocus) + { + c?.Focus(); + } + } if (invalidateInsteadOfRefresh) { diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 1cb6fef65..04f609a15 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -919,7 +919,7 @@ logic as it is. if (visible == FMTabVisibleIn.None) { TopFMTabControl.ShowTab(fmTabPage, false); - // @DockUI: Duplicate code - brittle + // @DockUI: This panel collapse logic always happens after a ShowTab(false). We should put the two into a function if (TopFMTabControl.TabCount == 0) { TopSplitContainer.Panel2Collapsed = true; @@ -3340,7 +3340,7 @@ internal void FMTabsMenu_Opening(object sender, CancelEventArgs e) I'm not sure which style is the best/most intuitive/principle-of-least-surprise etc. They're all a little weird. Decide on something for the final release. */ -#if true +#if false BackingTab? backingTab = _backingFMTabs.FirstOrDefault(x => x.TabPage == item); if (backingTab != null) { @@ -3366,23 +3366,56 @@ internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) return; } - // @DockUI: Explicitly hide tab - // Although adding a tab to another control automatically removes it from the first one, we need to - // explicitly run our custom ShowTab() method in order to keep the backing list synced. Otherwise, the - // tab order gets messed up. - // @DockUI: The show/hide logic needs to also do whatever extra logic MoveTab() does - if (s.Checked) + try + { + // MUST suspend drawing or we get crashes! + EverythingPanel.SuspendDrawing(); + + /* + @DockUI: Explicitly hide tab + Although adding a tab to another control automatically removes it from the first one, we need to + explicitly run our custom ShowTab() method in order to keep the backing list synced. Otherwise, the + tab order gets messed up. + + @DockUI: We could have three-state menu items - top, bottom, and none. + Because when you click a checkbox and it hides the other tab control, it's not a great UX because you + think "crap, how do I get it back?" + */ + if (s.Checked) + { + if (tabControl == TopFMTabControl) + { + Lazy_LowerTabControl.ShowTab(tab, false); + if (Lazy_LowerTabControl.TabCount == 0) + { + LowerSplitContainer.Panel2Collapsed = true; + } + } + else + { + TopFMTabControl.ShowTab(tab, false); + if (TopFMTabControl.TabCount == 0) + { + TopSplitContainer.Panel2Collapsed = true; + } + } + } + tabControl.ShowTab(tab, s.Checked); + } + finally { - if (tabControl == TopFMTabControl) + if (s.Checked) { - Lazy_LowerTabControl.ShowTab(tab, false); + TabPage? selectedTab = tabControl == TopFMTabControl + ? TopFMTabControl.SelectedTab + : Lazy_LowerTabControl.SelectedTab; + EverythingPanel.ResumeDrawingAndFocusControl(new Control?[] { tab, selectedTab }); } else { - TopFMTabControl.ShowTab(tab, false); + EverythingPanel.ResumeDrawing(); } } - tabControl.ShowTab(tab, s.Checked); } private void SetFMTabBlockersVisible() @@ -5617,7 +5650,7 @@ private void HandleTabDragFinish(WhichTabControl source, WhichTabControl dest) _inTabDragArea = false; if (refresh) { - EverythingPanel.ResumeDrawingAndFocusControl(dragTab); + EverythingPanel.ResumeDrawingAndFocusControl(new Control?[] { dragTab }); } } } From 35a659458c11bb6f8621908cd97d4b5a19c26280 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 10:19:09 -0800 Subject: [PATCH 162/200] Note --- AngelLoader/Forms/MainForm.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 04f609a15..8b91e28a3 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5655,6 +5655,8 @@ private void HandleTabDragFinish(WhichTabControl source, WhichTabControl dest) } } + // @DockUI: Original control nearest tab should be the one from before the drag moved the tab in the bar. + // That drag is supposed to have all its effects completely canceled when we commit the between-control drag. private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPage, bool expandCollapsed = true) { if (source == dest) return; From 10144e73894f71f2adf59b0fb51f240700b680f2 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 10:32:43 -0800 Subject: [PATCH 163/200] Fix lower tab page could construct when hidden --- .../Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 6c1142cc9..092fdb34e 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -160,7 +160,8 @@ public bool Enabled private void TabControl_VisibleChanged(object sender, System.EventArgs e) { - if (_tabControl is { Visible: true, SelectedTab: Lazy_TabsBase lazyTab }) + if (_tabControl is { Visible: true, SelectedTab: Lazy_TabsBase lazyTab } && + !_owner.LowerSplitContainer.FullScreen) { lazyTab.ConstructWithSuspendResume(); } From 2f67635e337268f977081504b2b4b70353cc1304 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 16:42:52 -0800 Subject: [PATCH 164/200] Dedupe some code into a function --- AngelLoader/Forms/MainForm.cs | 44 ++++++++++++++--------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 8b91e28a3..9bed1e615 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -918,12 +918,7 @@ logic as it is. // They're visible by default - shave off a bit of time if (visible == FMTabVisibleIn.None) { - TopFMTabControl.ShowTab(fmTabPage, false); - // @DockUI: This panel collapse logic always happens after a ShowTab(false). We should put the two into a function - if (TopFMTabControl.TabCount == 0) - { - TopSplitContainer.Panel2Collapsed = true; - } + HideTab(WhichTabControl.Top, fmTabPage); } else if (visible == FMTabVisibleIn.Bottom) { @@ -3383,22 +3378,7 @@ tab order gets messed up. */ if (s.Checked) { - if (tabControl == TopFMTabControl) - { - Lazy_LowerTabControl.ShowTab(tab, false); - if (Lazy_LowerTabControl.TabCount == 0) - { - LowerSplitContainer.Panel2Collapsed = true; - } - } - else - { - TopFMTabControl.ShowTab(tab, false); - if (TopFMTabControl.TabCount == 0) - { - TopSplitContainer.Panel2Collapsed = true; - } - } + HideTab(tabControl == TopFMTabControl ? WhichTabControl.Bottom : WhichTabControl.Top, tab); } tabControl.ShowTab(tab, s.Checked); } @@ -5678,12 +5658,8 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa : TopSplitContainer; sourceTabControl.RestoreBackedUpBackingTabs(); - sourceTabControl.ShowTab(tabPage, false); + HideTab(source, tabPage); destTabControl.ShowTab(tabPage, true); - if (sourceTabControl.TabCount == 0) - { - sourceSplitContainer.Panel2Collapsed = true; - } destSplitContainer.Panel2Collapsed = false; if (expandCollapsed) @@ -5699,6 +5675,20 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa tabPage.Focus(); } + private void HideTab(WhichTabControl which, TabPage tabPage) + { + (DarkTabControl tabControl, DarkSplitContainerCustom splitter) = + which == WhichTabControl.Bottom + ? (Lazy_LowerTabControl.TabControl, LowerSplitContainer) + : (TopFMTabControl, TopSplitContainer); + + tabControl.ShowTab(tabPage, false); + if (tabControl.TabCount == 0) + { + splitter.Panel2Collapsed = true; + } + } + private void DestroyImageCursor() { Cursor = Cursors.Default; From 744b508cb87112661ecc9489baad992874b33000 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 19:16:30 -0800 Subject: [PATCH 165/200] Select original nearest tab after a between-control drag --- .../Forms/CustomControls/DarkTabControl.cs | 41 ++++++++++++++++--- AngelLoader/Forms/MainForm.cs | 11 +++-- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index 29bb5c506..d27ec9dbd 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -35,14 +35,19 @@ The user can drag tabs horizontally in the same move as they're trying to drag t */ private List? _backedUpBackingTabs; + private TabPage? _backedUpNearestTabPage; - private void BackUpBackingTabs() + private void BackUpTempDragData() { _backedUpBackingTabs = new List(_backingTabList.Count); foreach (BackingTab backingTab in _backingTabList) { _backedUpBackingTabs.Add(new BackingTab(backingTab.TabPage) { VisibleIn = backingTab.VisibleIn }); } + if (TabCount > 1 && SelectedIndex > 0) + { + _backedUpNearestTabPage = TabPages[GetNearestIndex_NoBoundsChecks()]; + } } internal void RestoreBackedUpBackingTabs() @@ -62,6 +67,12 @@ internal void RestoreBackedUpBackingTabs() _backedUpBackingTabs = null; } + internal void ResetTempDragData() + { + _backedUpBackingTabs = null; + _backedUpNearestTabPage = null; + } + #endregion /// @@ -336,7 +347,7 @@ protected override void OnMouseDown(MouseEventArgs e) if (e.Button == MouseButtons.Left) { (_, DragTab) = GetTabAtPoint(e.Location); - if (DragTab != null) BackUpBackingTabs(); + if (DragTab != null) BackUpTempDragData(); } base.OnMouseDown(e); } @@ -531,14 +542,26 @@ public void ShowTab(TabPage tabPage, bool show) bt.VisibleIn = FMTabVisibleIn.None; if (TabPages.Contains(bt.TabPage)) { - if (TabPages.Count > 1 && SelectedIndex > 0 && SelectedTab == bt.TabPage) + Control? parent = Parent; + if (_backedUpNearestTabPage != null && TabPages.Contains(_backedUpNearestTabPage)) + { + try + { + parent?.SuspendDrawing(); + SelectedTab = _backedUpNearestTabPage; + TabPages.Remove(bt.TabPage); + } + finally + { + parent?.ResumeDrawing(); + } + } + else if (TabPages.Count > 1 && SelectedIndex > 0 && SelectedTab == bt.TabPage) { - Control? parent = Parent; try { parent?.SuspendDrawing(); - int newIndex = SelectedIndex == TabCount - 1 ? SelectedIndex - 1 : SelectedIndex + 1; - SelectedTab = TabPages[newIndex]; + SelectedTab = TabPages[GetNearestIndex_NoBoundsChecks()]; TabPages.Remove(bt.TabPage); } finally @@ -550,11 +573,17 @@ public void ShowTab(TabPage tabPage, bool show) { TabPages.Remove(bt.TabPage); } + _backedUpNearestTabPage = null; if (TabCount > 0) SelectedTab.Focus(); } } } + private int GetNearestIndex_NoBoundsChecks() + { + return SelectedIndex == TabCount - 1 ? SelectedIndex - 1 : SelectedIndex + 1; + } + public Rectangle GetTabBarRect() => TabCount == 0 ? Rectangle.Empty diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 9bed1e615..96f56c36e 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5627,6 +5627,11 @@ private void HandleTabDragFinish(WhichTabControl source, WhichTabControl dest) finally { DestroyImageCursor(); + // @DockUI: Have a better way to choose controls than this bulky ternary all the time + DarkTabControl sourceTabControl = source == WhichTabControl.Bottom + ? Lazy_LowerTabControl.TabControl + : TopFMTabControl; + sourceTabControl.ResetTempDragData(); _inTabDragArea = false; if (refresh) { @@ -5635,8 +5640,6 @@ private void HandleTabDragFinish(WhichTabControl source, WhichTabControl dest) } } - // @DockUI: Original control nearest tab should be the one from before the drag moved the tab in the bar. - // That drag is supposed to have all its effects completely canceled when we commit the between-control drag. private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPage, bool expandCollapsed = true) { if (source == dest) return; @@ -5649,10 +5652,6 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa ? Lazy_LowerTabControl.TabControl : TopFMTabControl; - DarkSplitContainerCustom sourceSplitContainer = source == WhichTabControl.Bottom - ? LowerSplitContainer - : TopSplitContainer; - DarkSplitContainerCustom destSplitContainer = dest == WhichTabControl.Bottom ? LowerSplitContainer : TopSplitContainer; From 425b7a2fb00a51dd40015ebb60413db5d442b21d Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 20:30:34 -0800 Subject: [PATCH 166/200] Reminder --- AngelLoader/Forms/MainForm.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 96f56c36e..095968b1a 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5531,6 +5531,7 @@ public void RefreshCurrentFMScreenshots() /* @DockUI: Working/testing code, finalize before release + @DockUI: Remove Trace.WriteLines */ private bool _inTabDragArea; From 12be685c1fe10631f45d4af8dcc5f14afaf579e7 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 22:28:10 -0800 Subject: [PATCH 167/200] Bump up vertical AutoScrollMinSize for screenshots tab --- .../TopRightPages/Lazy_ScreenshotsPage.Designer.cs | 2 +- .../TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 5295d71aa..c69715192 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -128,7 +128,7 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; - this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.AutoScrollMinSize = new System.Drawing.Size(200, 200); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 184ecab07..4ec551834 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -90,7 +90,7 @@ private void InitSlim() this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; - this.AutoScrollMinSize = new System.Drawing.Size(200, 100); + this.AutoScrollMinSize = new System.Drawing.Size(200, 200); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); From 227baaa2f238d4f272aeb9287c49de90962b145d Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Mon, 4 Mar 2024 22:32:18 -0800 Subject: [PATCH 168/200] Note --- AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs index 4d21726e2..766084562 100644 --- a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs +++ b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs @@ -37,6 +37,7 @@ private float SplitterPercent // This is so you can drag both directions by grabbing the corner between the two. One SplitContainer can // control both its own SplitterDistance and that of its orthogonally-oriented sibling at the same time. + // @DockUI: We need to be able to have two siblings now (main splitter: one above, one below) private DarkSplitContainerCustom? _sibling; // This realtime-draw resize stuff still flickers a bit, but it's better than no redraw at all. From 7ac172d7a11b6cd3fd551619e9c9ea2464a0b6e7 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 15:17:00 -0800 Subject: [PATCH 169/200] Notes after trying and failing to expand the splitter siblings notion --- AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs index 766084562..7ed767d3d 100644 --- a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs +++ b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs @@ -1,5 +1,8 @@ /* @DockUI: Figure out how we want to allow moving of the new cross-section which can now be 4-way (3 splitters) +@DockUI(Splitters): This whole dependency-injection "sibling" thing is OOP crap once again, let's control from MainForm +Then we can just use the already-existent mouse move tracking to easily see where the mouse is and control the +splitters all from a central location. */ using System; @@ -37,7 +40,6 @@ private float SplitterPercent // This is so you can drag both directions by grabbing the corner between the two. One SplitContainer can // control both its own SplitterDistance and that of its orthogonally-oriented sibling at the same time. - // @DockUI: We need to be able to have two siblings now (main splitter: one above, one below) private DarkSplitContainerCustom? _sibling; // This realtime-draw resize stuff still flickers a bit, but it's better than no redraw at all. From 1acba7456ec5905b416ebff488d6cbd481a746b3 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 16:37:01 -0800 Subject: [PATCH 170/200] Splitter draggable correctly for all splitters now --- .../DarkSplitContainerCustom.cs | 147 ++++++++++++++---- AngelLoader/Forms/MainForm.cs | 7 +- 2 files changed, 118 insertions(+), 36 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs index 7ed767d3d..098eaf7c6 100644 --- a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs +++ b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs @@ -1,11 +1,4 @@ -/* -@DockUI: Figure out how we want to allow moving of the new cross-section which can now be 4-way (3 splitters) -@DockUI(Splitters): This whole dependency-injection "sibling" thing is OOP crap once again, let's control from MainForm -Then we can just use the already-existent mouse move tracking to easily see where the mouse is and control the -splitters all from a central location. -*/ - -using System; +using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Drawing; @@ -40,14 +33,20 @@ private float SplitterPercent // This is so you can drag both directions by grabbing the corner between the two. One SplitContainer can // control both its own SplitterDistance and that of its orthogonally-oriented sibling at the same time. - private DarkSplitContainerCustom? _sibling; + private DarkSplitContainerCustom? _sibling1; + private DarkSplitContainerCustom? _sibling2; // This realtime-draw resize stuff still flickers a bit, but it's better than no redraw at all. private int _originalDistance; - private bool _mouseOverCrossSection; + private bool _mouseOverCrossSection1; [Browsable(false)] - [MemberNotNullWhen(true, nameof(_sibling))] - private bool MouseOverCrossSection => _sibling != null && _mouseOverCrossSection; + [MemberNotNullWhen(true, nameof(_sibling1))] + private bool MouseOverCrossSection1 => _sibling1 != null && _mouseOverCrossSection1; + + private bool _mouseOverCrossSection2; + [Browsable(false)] + [MemberNotNullWhen(true, nameof(_sibling2))] + private bool MouseOverCrossSection2 => _sibling2 != null && _mouseOverCrossSection2; private Color? _origBackColor; private Color? _origPanel1BackColor; @@ -145,7 +144,8 @@ public DarkSplitContainerCustom() #region Public methods - internal void SetSibling(DarkSplitContainerCustom sibling) => _sibling = sibling; + internal void SetSibling1(DarkSplitContainerCustom sibling) => _sibling1 = sibling; + internal void SetSibling2(DarkSplitContainerCustom sibling) => _sibling2 = sibling; internal void ToggleFullScreen() => SetFullScreen(!FullScreen); @@ -227,8 +227,10 @@ internal void CancelResize() Resizing = false; SplitterDistance = _originalDistance; - if (MouseOverCrossSection) _sibling.SplitterDistance = _sibling._originalDistance; - _mouseOverCrossSection = false; + if (MouseOverCrossSection1) _sibling1.SplitterDistance = _sibling1._originalDistance; + if (MouseOverCrossSection2) _sibling2.SplitterDistance = _sibling2._originalDistance; + _mouseOverCrossSection1 = false; + _mouseOverCrossSection2 = false; } #endregion @@ -277,7 +279,8 @@ protected override void OnMouseDown(MouseEventArgs e) (!IsStacked && Cursor.Current == Cursors.VSplit))) { _originalDistance = SplitterDistance; - if (MouseOverCrossSection) _sibling._originalDistance = _sibling.SplitterDistance; + if (MouseOverCrossSection1) _sibling1._originalDistance = _sibling1.SplitterDistance; + if (MouseOverCrossSection2) _sibling2._originalDistance = _sibling2.SplitterDistance; Resizing = true; } else @@ -298,7 +301,8 @@ protected override void OnMouseUp(MouseEventArgs e) if (FullScreen) return; - _mouseOverCrossSection = false; + _mouseOverCrossSection1 = false; + _mouseOverCrossSection2 = false; Resizing = false; base.OnMouseUp(e); @@ -314,34 +318,61 @@ protected override void OnMouseMove(MouseEventArgs e) if (FullScreen) return; - if (!Resizing && _sibling != null) + // @DockUI: Semantic compress this + if (!Resizing && _sibling1 != null) + { + int sibCursorPos = IsStacked + ? _sibling1.Panel1.ClientCursorPos().X + : _sibling1.Panel1.ClientCursorPos().Y; + + int sibSplitterPos = IsStacked + ? _sibling1.Panel1.Width + : _sibling1.Panel1.Height; + + // Don't do the both-directional-drag if the sibling has a panel collapsed + if (!_sibling1.FullScreen && + sibCursorPos >= sibSplitterPos - 7 && + sibCursorPos <= sibSplitterPos + _sibling1.SplitterWidth + 6) + { + Cursor.Current = Cursors.SizeAll; + _mouseOverCrossSection1 = true; + } + else + { + _mouseOverCrossSection1 = false; + } + } + if (!Resizing && _sibling2 != null) { int sibCursorPos = IsStacked - ? _sibling.Panel1.ClientCursorPos().X - : _sibling.Panel1.ClientCursorPos().Y; + ? _sibling2.Panel1.ClientCursorPos().X + : _sibling2.Panel1.ClientCursorPos().Y; int sibSplitterPos = IsStacked - ? _sibling.Panel1.Width - : _sibling.Panel1.Height; + ? _sibling2.Panel1.Width + : _sibling2.Panel1.Height; // Don't do the both-directional-drag if the sibling has a panel collapsed - if (!_sibling.FullScreen && + if (!_sibling2.FullScreen && sibCursorPos >= sibSplitterPos - 7 && - sibCursorPos <= sibSplitterPos + _sibling.SplitterWidth + 6) + sibCursorPos <= sibSplitterPos + _sibling2.SplitterWidth + 6) { Cursor.Current = Cursors.SizeAll; - _mouseOverCrossSection = true; + _mouseOverCrossSection2 = true; } else { - _mouseOverCrossSection = false; + _mouseOverCrossSection2 = false; } } if (Resizing) { if (e.Button == MouseButtons.Left) { - if (MouseOverCrossSection) Cursor.Current = Cursors.SizeAll; + if (MouseOverCrossSection1 || MouseOverCrossSection2) + { + Cursor.Current = Cursors.SizeAll; + } // SuspendDrawing() / ResumeDrawing() reduces visual artifacts int axis = IsStacked ? e.Y : e.X; @@ -349,20 +380,51 @@ protected override void OnMouseMove(MouseEventArgs e) // Things need to happen in different orders depending on who we are, in order to avoid // flickering. We could also Suspend/Resume them one at a time, but that's perceptibly // laggier. - if (MouseOverCrossSection) + if (MouseOverCrossSection1) { if (RefreshSiblingFirst) { - _sibling.SuspendDrawing(); + _sibling1.SuspendDrawing(); + if (MouseOverCrossSection2) _sibling2.SuspendDrawing(); this.SuspendDrawing(); } else { this.SuspendDrawing(); - _sibling.SuspendDrawing(); + if (MouseOverCrossSection2) _sibling2.ResumeDrawing(); + _sibling1.SuspendDrawing(); } - _sibling.SplitterDistance = (axis == e.X ? e.Y : e.X).ClampToZero(); + Point pt1 = _sibling1.ClientCursorPos(); + _sibling1.SplitterDistance = (axis == e.X ? pt1.Y : pt1.X).ClampToZero(); + if (MouseOverCrossSection2) + { + Point pt2 = _sibling2.ClientCursorPos(); + _sibling2.SplitterDistance = (axis == e.X ? pt2.Y : pt2.X).ClampToZero(); + } + } + else if (MouseOverCrossSection2) + { + if (RefreshSiblingFirst) + { + if (MouseOverCrossSection1) _sibling1.SuspendDrawing(); + _sibling2.SuspendDrawing(); + this.SuspendDrawing(); + } + else + { + this.SuspendDrawing(); + _sibling2.SuspendDrawing(); + if (MouseOverCrossSection1) _sibling1.ResumeDrawing(); + } + + Point pt2 = _sibling2.ClientCursorPos(); + _sibling2.SplitterDistance = (axis == e.X ? pt2.Y : pt2.X).ClampToZero(); + if (MouseOverCrossSection1) + { + Point pt1 = _sibling1.ClientCursorPos(); + _sibling1.SplitterDistance = (axis == e.X ? pt1.Y : pt1.X).ClampToZero(); + } } else { @@ -371,17 +433,34 @@ protected override void OnMouseMove(MouseEventArgs e) SplitterDistance = axis.ClampToZero(); - if (MouseOverCrossSection) + if (MouseOverCrossSection1) + { + if (RefreshSiblingFirst) + { + if (MouseOverCrossSection2) _sibling2.ResumeDrawing(); + _sibling1.ResumeDrawing(); + this.ResumeDrawing(); + } + else + { + this.ResumeDrawing(); + if (MouseOverCrossSection2) _sibling2.ResumeDrawing(); + _sibling1.ResumeDrawing(); + } + } + else if (MouseOverCrossSection2) { if (RefreshSiblingFirst) { - _sibling.ResumeDrawing(); + _sibling2.ResumeDrawing(); + if (MouseOverCrossSection1) _sibling1.ResumeDrawing(); this.ResumeDrawing(); } else { this.ResumeDrawing(); - _sibling.ResumeDrawing(); + _sibling2.ResumeDrawing(); + if (MouseOverCrossSection1) _sibling1.ResumeDrawing(); } } else diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 095968b1a..3fba4b67b 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -956,13 +956,16 @@ logic as it is. TopSplitContainer.SetSplitterPercent(Config.TopSplitterPercent, setIfFullScreen: false, suspendResume: false); LowerSplitContainer.SetSplitterPercent(Config.LowerSplitterPercent, setIfFullScreen: false, suspendResume: false); - MainSplitContainer.SetSibling(TopSplitContainer); + MainSplitContainer.SetSibling1(TopSplitContainer); + MainSplitContainer.SetSibling2(LowerSplitContainer); MainSplitContainer.Panel1DarkBackColor = DarkColors.Fen_ControlBackground; MainSplitContainer.Panel2DarkBackColor = DarkColors.Fen_DarkBackground; - TopSplitContainer.SetSibling(MainSplitContainer); + + TopSplitContainer.SetSibling1(MainSplitContainer); TopSplitContainer.Panel1DarkBackColor = DarkColors.Fen_ControlBackground; TopSplitContainer.Panel2DarkBackColor = DarkColors.Fen_DarkBackground; + LowerSplitContainer.SetSibling1(MainSplitContainer); LowerSplitContainer.Panel1DarkBackColor = DarkColors.Fen_DarkBackground; LowerSplitContainer.Panel2DarkBackColor = DarkColors.Fen_DarkBackground; From cf154b31c07b8c0d2729d501cdc3911077a26996 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 17:04:45 -0800 Subject: [PATCH 171/200] Cleanup and dedupe new splitter drag code --- .../DarkSplitContainerCustom.cs | 256 ++++++++---------- 1 file changed, 119 insertions(+), 137 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs index 098eaf7c6..41cc08989 100644 --- a/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs +++ b/AngelLoader/Forms/CustomControls/DarkSplitContainerCustom.cs @@ -20,6 +20,19 @@ public sealed class DarkSplitContainerCustom : SplitContainer, IDarkable #region Private fields + private sealed class SiblingData + { + internal DarkSplitContainerCustom? SplitContainer; + private bool _mouseOverCrossSection; + + [MemberNotNullWhen(true, nameof(SplitContainer))] + internal bool MouseOverCrossSection + { + get => SplitContainer != null && _mouseOverCrossSection; + set => _mouseOverCrossSection = value; + } + } + private bool IsStacked => Orientation == Orientation.Horizontal; private int CrossLength => IsStacked ? Height : Width; @@ -33,21 +46,11 @@ private float SplitterPercent // This is so you can drag both directions by grabbing the corner between the two. One SplitContainer can // control both its own SplitterDistance and that of its orthogonally-oriented sibling at the same time. - private DarkSplitContainerCustom? _sibling1; - private DarkSplitContainerCustom? _sibling2; + private readonly SiblingData _sibling1 = new(); + private readonly SiblingData _sibling2 = new(); // This realtime-draw resize stuff still flickers a bit, but it's better than no redraw at all. private int _originalDistance; - private bool _mouseOverCrossSection1; - [Browsable(false)] - [MemberNotNullWhen(true, nameof(_sibling1))] - private bool MouseOverCrossSection1 => _sibling1 != null && _mouseOverCrossSection1; - - private bool _mouseOverCrossSection2; - [Browsable(false)] - [MemberNotNullWhen(true, nameof(_sibling2))] - private bool MouseOverCrossSection2 => _sibling2 != null && _mouseOverCrossSection2; - private Color? _origBackColor; private Color? _origPanel1BackColor; private Color? _origPanel2BackColor; @@ -144,8 +147,8 @@ public DarkSplitContainerCustom() #region Public methods - internal void SetSibling1(DarkSplitContainerCustom sibling) => _sibling1 = sibling; - internal void SetSibling2(DarkSplitContainerCustom sibling) => _sibling2 = sibling; + internal void SetSibling1(DarkSplitContainerCustom sibling) => _sibling1.SplitContainer = sibling; + internal void SetSibling2(DarkSplitContainerCustom sibling) => _sibling2.SplitContainer = sibling; internal void ToggleFullScreen() => SetFullScreen(!FullScreen); @@ -227,10 +230,16 @@ internal void CancelResize() Resizing = false; SplitterDistance = _originalDistance; - if (MouseOverCrossSection1) _sibling1.SplitterDistance = _sibling1._originalDistance; - if (MouseOverCrossSection2) _sibling2.SplitterDistance = _sibling2._originalDistance; - _mouseOverCrossSection1 = false; - _mouseOverCrossSection2 = false; + if (_sibling1.MouseOverCrossSection) + { + _sibling1.SplitContainer.SplitterDistance = _sibling1.SplitContainer._originalDistance; + } + if (_sibling2.MouseOverCrossSection) + { + _sibling2.SplitContainer.SplitterDistance = _sibling2.SplitContainer._originalDistance; + } + _sibling1.MouseOverCrossSection = false; + _sibling2.MouseOverCrossSection = false; } #endregion @@ -279,8 +288,14 @@ protected override void OnMouseDown(MouseEventArgs e) (!IsStacked && Cursor.Current == Cursors.VSplit))) { _originalDistance = SplitterDistance; - if (MouseOverCrossSection1) _sibling1._originalDistance = _sibling1.SplitterDistance; - if (MouseOverCrossSection2) _sibling2._originalDistance = _sibling2.SplitterDistance; + if (_sibling1.MouseOverCrossSection) + { + _sibling1.SplitContainer._originalDistance = _sibling1.SplitContainer.SplitterDistance; + } + if (_sibling2.MouseOverCrossSection) + { + _sibling2.SplitContainer._originalDistance = _sibling2.SplitContainer.SplitterDistance; + } Resizing = true; } else @@ -301,75 +316,119 @@ protected override void OnMouseUp(MouseEventArgs e) if (FullScreen) return; - _mouseOverCrossSection1 = false; - _mouseOverCrossSection2 = false; + _sibling1.MouseOverCrossSection = false; + _sibling2.MouseOverCrossSection = false; Resizing = false; base.OnMouseUp(e); } - protected override void OnMouseMove(MouseEventArgs e) + private void SetMouseOverCrossSection(SiblingData sibling) { - if (DesignMode) - { - base.OnMouseMove(e); - return; - } - - if (FullScreen) return; - - // @DockUI: Semantic compress this - if (!Resizing && _sibling1 != null) + if (!Resizing && sibling.SplitContainer != null) { int sibCursorPos = IsStacked - ? _sibling1.Panel1.ClientCursorPos().X - : _sibling1.Panel1.ClientCursorPos().Y; + ? sibling.SplitContainer.Panel1.ClientCursorPos().X + : sibling.SplitContainer.Panel1.ClientCursorPos().Y; int sibSplitterPos = IsStacked - ? _sibling1.Panel1.Width - : _sibling1.Panel1.Height; + ? sibling.SplitContainer.Panel1.Width + : sibling.SplitContainer.Panel1.Height; // Don't do the both-directional-drag if the sibling has a panel collapsed - if (!_sibling1.FullScreen && + if (!sibling.SplitContainer.FullScreen && sibCursorPos >= sibSplitterPos - 7 && - sibCursorPos <= sibSplitterPos + _sibling1.SplitterWidth + 6) + sibCursorPos <= sibSplitterPos + sibling.SplitContainer.SplitterWidth + 6) { Cursor.Current = Cursors.SizeAll; - _mouseOverCrossSection1 = true; + sibling.MouseOverCrossSection = true; } else { - _mouseOverCrossSection1 = false; + sibling.MouseOverCrossSection = false; } } - if (!Resizing && _sibling2 != null) + } + + private bool SuspendDrawingAndMoveSiblingSplitters(SiblingData sibling1, SiblingData sibling2, int axis, int eX) + { + // Things need to happen in different orders depending on who we are, in order to avoid + // flickering. We could also Suspend/Resume them one at a time, but that's perceptibly + // laggier. + if (sibling1.MouseOverCrossSection) { - int sibCursorPos = IsStacked - ? _sibling2.Panel1.ClientCursorPos().X - : _sibling2.Panel1.ClientCursorPos().Y; + if (RefreshSiblingFirst) + { + sibling1.SplitContainer.SuspendDrawing(); + if (sibling2.MouseOverCrossSection) sibling2.SplitContainer.SuspendDrawing(); + this.SuspendDrawing(); + } + else + { + this.SuspendDrawing(); + if (sibling2.MouseOverCrossSection) sibling2.SplitContainer.SuspendDrawing(); + sibling1.SplitContainer.SuspendDrawing(); + } - int sibSplitterPos = IsStacked - ? _sibling2.Panel1.Width - : _sibling2.Panel1.Height; + Point pt1 = sibling1.SplitContainer.ClientCursorPos(); + sibling1.SplitContainer.SplitterDistance = (axis == eX ? pt1.Y : pt1.X).ClampToZero(); + if (sibling2.MouseOverCrossSection) + { + Point pt2 = sibling2.SplitContainer.ClientCursorPos(); + sibling2.SplitContainer.SplitterDistance = (axis == eX ? pt2.Y : pt2.X).ClampToZero(); + } - // Don't do the both-directional-drag if the sibling has a panel collapsed - if (!_sibling2.FullScreen && - sibCursorPos >= sibSplitterPos - 7 && - sibCursorPos <= sibSplitterPos + _sibling2.SplitterWidth + 6) + return true; + } + else + { + return false; + } + } + + private bool ResumeDrawing(SiblingData sibling1, SiblingData sibling2) + { + if (sibling1.MouseOverCrossSection) + { + if (RefreshSiblingFirst) { - Cursor.Current = Cursors.SizeAll; - _mouseOverCrossSection2 = true; + if (sibling2.MouseOverCrossSection) sibling2.SplitContainer.ResumeDrawing(); + sibling1.SplitContainer.ResumeDrawing(); + this.ResumeDrawing(); } else { - _mouseOverCrossSection2 = false; + this.ResumeDrawing(); + sibling1.SplitContainer.ResumeDrawing(); + if (sibling2.MouseOverCrossSection) sibling2.SplitContainer.ResumeDrawing(); } + + return true; } + else + { + return false; + } + } + + protected override void OnMouseMove(MouseEventArgs e) + { + if (DesignMode) + { + base.OnMouseMove(e); + return; + } + + if (FullScreen) return; + + SetMouseOverCrossSection(_sibling1); + SetMouseOverCrossSection(_sibling2); + if (Resizing) { if (e.Button == MouseButtons.Left) { - if (MouseOverCrossSection1 || MouseOverCrossSection2) + if (_sibling1.MouseOverCrossSection || _sibling2.MouseOverCrossSection) { Cursor.Current = Cursors.SizeAll; } @@ -377,93 +436,16 @@ protected override void OnMouseMove(MouseEventArgs e) // SuspendDrawing() / ResumeDrawing() reduces visual artifacts int axis = IsStacked ? e.Y : e.X; - // Things need to happen in different orders depending on who we are, in order to avoid - // flickering. We could also Suspend/Resume them one at a time, but that's perceptibly - // laggier. - if (MouseOverCrossSection1) - { - if (RefreshSiblingFirst) - { - _sibling1.SuspendDrawing(); - if (MouseOverCrossSection2) _sibling2.SuspendDrawing(); - this.SuspendDrawing(); - } - else - { - this.SuspendDrawing(); - if (MouseOverCrossSection2) _sibling2.ResumeDrawing(); - _sibling1.SuspendDrawing(); - } - - Point pt1 = _sibling1.ClientCursorPos(); - _sibling1.SplitterDistance = (axis == e.X ? pt1.Y : pt1.X).ClampToZero(); - if (MouseOverCrossSection2) - { - Point pt2 = _sibling2.ClientCursorPos(); - _sibling2.SplitterDistance = (axis == e.X ? pt2.Y : pt2.X).ClampToZero(); - } - } - else if (MouseOverCrossSection2) - { - if (RefreshSiblingFirst) - { - if (MouseOverCrossSection1) _sibling1.SuspendDrawing(); - _sibling2.SuspendDrawing(); - this.SuspendDrawing(); - } - else - { - this.SuspendDrawing(); - _sibling2.SuspendDrawing(); - if (MouseOverCrossSection1) _sibling1.ResumeDrawing(); - } - - Point pt2 = _sibling2.ClientCursorPos(); - _sibling2.SplitterDistance = (axis == e.X ? pt2.Y : pt2.X).ClampToZero(); - if (MouseOverCrossSection1) - { - Point pt1 = _sibling1.ClientCursorPos(); - _sibling1.SplitterDistance = (axis == e.X ? pt1.Y : pt1.X).ClampToZero(); - } - } - else + if (!SuspendDrawingAndMoveSiblingSplitters(_sibling1, _sibling2, axis, e.X) && + !SuspendDrawingAndMoveSiblingSplitters(_sibling2, _sibling1, axis, e.X)) { this.SuspendDrawing(); } SplitterDistance = axis.ClampToZero(); - if (MouseOverCrossSection1) - { - if (RefreshSiblingFirst) - { - if (MouseOverCrossSection2) _sibling2.ResumeDrawing(); - _sibling1.ResumeDrawing(); - this.ResumeDrawing(); - } - else - { - this.ResumeDrawing(); - if (MouseOverCrossSection2) _sibling2.ResumeDrawing(); - _sibling1.ResumeDrawing(); - } - } - else if (MouseOverCrossSection2) - { - if (RefreshSiblingFirst) - { - _sibling2.ResumeDrawing(); - if (MouseOverCrossSection1) _sibling1.ResumeDrawing(); - this.ResumeDrawing(); - } - else - { - this.ResumeDrawing(); - _sibling2.ResumeDrawing(); - if (MouseOverCrossSection1) _sibling1.ResumeDrawing(); - } - } - else + if (!ResumeDrawing(_sibling1, _sibling2) && + !ResumeDrawing(_sibling2, _sibling1)) { this.ResumeDrawing(); } From ecd1660069ddc74a27f731eb03ba33a96307b323 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 17:18:20 -0800 Subject: [PATCH 172/200] Yet another note --- AngelLoader/Forms/MainForm.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 3fba4b67b..81fa87481 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -4314,9 +4314,10 @@ private void ReadmeButtons_Click(object sender, EventArgs e) if (sender == ReadmeFullScreenButton) { /* - @DockUI(readme fullscreen): - We need to handle the readme fullscreening thing. Is it safe to allow interacting with tabs while the - readme is fullscreened? Or should we hide the beside-readme area too? + @DockUI(readme fullscreen): This needs the always-show-collapse-button-for-both-panels thing to really work + Because of toggling collapsed state of lower splitter panel 2. + We could store the previous collapsed state, but we want to get rid of the auto-collapse-on-no-tabs + anyway, because it's kind of not super great UX. */ MainSplitContainer.ToggleFullScreen(); ShowReadmeControls(CursorOverReadmeArea()); From 649ff2cfca62d25d8ccc651fb28be06425561420 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 21:48:30 -0800 Subject: [PATCH 173/200] Switch to always-shown collapse buttons style Allowing for empty tab areas with an empty-tab-area message about adding tabs and blah blah blah --- .../Common/DataClasses/LocalizationData.cs | 6 + AngelLoader/Forms/CustomControls/DarkLabel.cs | 51 ++-- .../LazyLoaded/Lazy_LowerTabControl.cs | 48 +--- AngelLoader/Forms/MainForm.Designer.cs | 83 +++++- AngelLoader/Forms/MainForm.cs | 86 ++++-- AngelLoader/Forms/MainForm.resx | 255 +++++++++--------- AngelLoader/Forms/MainForm_InitManual.cs | 64 ++++- AngelLoader/Languages/English.ini | 3 + 8 files changed, 359 insertions(+), 237 deletions(-) diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 1dc7a19a6..8f2789f10 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -37,6 +37,7 @@ internal sealed class LText_Class internal readonly FilterBar_Class FilterBar = new(); internal readonly FMsList_Class FMsList = new(); internal readonly FMSelectedStats_Class FMSelectedStats = new(); + internal readonly FMTabs_Class FMTabs = new(); internal readonly StatisticsTab_Class StatisticsTab = new(); internal readonly EditFMTab_Class EditFMTab = new(); internal readonly CommentTab_Class CommentTab = new(); @@ -497,6 +498,11 @@ internal sealed class FMSelectedStats_Class internal readonly string FMsFinished_Plural_AfterNumber = " FMs finished"; } + internal sealed class FMTabs_Class + { + internal readonly string EmptyTabAreaMessage = "Drag a tab here, or right-click to add a tab."; + } + internal sealed class StatisticsTab_Class { internal readonly string TabText = "Statistics"; diff --git a/AngelLoader/Forms/CustomControls/DarkLabel.cs b/AngelLoader/Forms/CustomControls/DarkLabel.cs index 79334b0df..03e535453 100644 --- a/AngelLoader/Forms/CustomControls/DarkLabel.cs +++ b/AngelLoader/Forms/CustomControls/DarkLabel.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System; +using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using AngelLoader.DataClasses; @@ -30,35 +31,39 @@ public sealed class DarkLabel : Label, IDarkable [PublicAPI] public Color? DarkModeBackColor; + public event EventHandler? PaintCustom; + protected override void OnPaint(PaintEventArgs e) { - if (DarkModeEnabled) + if (!DarkModeEnabled) { - TextFormatFlags textFormatFlags = - ControlUtils.GetTextAlignmentFlags(TextAlign) - | TextFormatFlags.NoPrefix - | TextFormatFlags.NoClipping - // This allows long lines with no spaces to still wrap. Matches stock behavior. - // (actually doesn't quite match - we wrap at a different point, but as long as we still wrap - // somewhere then whatever.) - | TextFormatFlags.TextBoxControl - | TextFormatFlags.WordBreak; + base.OnPaint(e); + PaintCustom?.Invoke(this, e); + return; + } + + TextFormatFlags textFormatFlags = + ControlUtils.GetTextAlignmentFlags(TextAlign) + | TextFormatFlags.NoPrefix + | TextFormatFlags.NoClipping + // This allows long lines with no spaces to still wrap. Matches stock behavior. + // (actually doesn't quite match - we wrap at a different point, but as long as we still wrap + // somewhere then whatever.) + | TextFormatFlags.TextBoxControl + | TextFormatFlags.WordBreak; - Color color = Enabled ? DarkModeForeColor ?? DarkColors.LightText : DarkColors.DisabledText; - if (DarkModeBackColor == null) - { - TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, color, textFormatFlags); - } - else - { - using var bgBrush = new SolidBrush((Color)DarkModeBackColor); - e.Graphics.FillRectangle(bgBrush, ClientRectangle); - TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, color, (Color)DarkModeBackColor, textFormatFlags); - } + Color color = Enabled ? DarkModeForeColor ?? DarkColors.LightText : DarkColors.DisabledText; + if (DarkModeBackColor == null) + { + TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, color, textFormatFlags); } else { - base.OnPaint(e); + using var bgBrush = new SolidBrush((Color)DarkModeBackColor); + e.Graphics.FillRectangle(bgBrush, ClientRectangle); + TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, color, (Color)DarkModeBackColor, textFormatFlags); } + + PaintCustom?.Invoke(this, e); } } diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 092fdb34e..3273eb248 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -22,9 +22,6 @@ public DarkTabControl TabControl private bool _enabled = true; - internal DarkButton MenuButton = null!; - internal DarkArrowButton CollapseButton = null!; - private bool _darkModeEnabled; [PublicAPI] public bool DarkModeEnabled @@ -35,8 +32,6 @@ public bool DarkModeEnabled _darkModeEnabled = value; if (!Constructed) return; - MenuButton.DarkModeEnabled = value; - CollapseButton.DarkModeEnabled = value; TabControl.DarkModeEnabled = value; } } @@ -45,14 +40,12 @@ public bool DarkModeEnabled public Lazy_LowerTabControl(MainForm owner) => _owner = owner; - private void Construct() + internal void Construct() { if (Constructed) return; var container = _owner.LowerSplitContainer.Panel2; - _owner.LowerSplitContainer.Panel2Collapsed = false; - _tabControl = new DarkTabControl { Tag = LoadType.Lazy, @@ -73,46 +66,13 @@ private void Construct() _tabControl.MouseClick += _owner.LowerFMTabsBar_MouseClick; container.MouseClick += _owner.LowerFMTabsBar_MouseClick; + _owner.BottomFMTabsEmptyMessageLabel.MouseClick += _owner.LowerFMTabsBar_MouseClick; _tabControl.Selected += TabControl_Selected; _tabControl.MouseDragCustom += _owner.Lazy_LowerTabControl_MouseDragCustom; _tabControl.MouseUp += _owner.Lazy_LowerTabControl_MouseUp; _tabControl.VisibleChanged += TabControl_VisibleChanged; - MenuButton = new DarkButton - { - Tag = LoadType.Lazy, - - Anchor = AnchorStyles.Top | AnchorStyles.Right, - FlatAppearance = { BorderSize = 0 }, - FlatStyle = FlatStyle.Flat, - Location = new Point(container.Width - 18, 0), - Size = new Size(18, 20), - TabIndex = 1, - - DarkModeEnabled = _darkModeEnabled - }; - MenuButton.Click += _owner.LowerFMTabsMenuButton_Click; - MenuButton.PaintCustom += _owner.FMTabsMenuButton_Paint; - - CollapseButton = new DarkArrowButton - { - Tag = LoadType.Lazy, - - Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right, - ArrowDirection = Direction.Right, - FlatAppearance = { BorderSize = 0 }, - FlatStyle = FlatStyle.Flat, - Location = new Point(container.Width - 18, 20), - Size = new Size(18, container.Height - 20), - TabIndex = 2, - - DarkModeEnabled = _darkModeEnabled - }; - CollapseButton.Click += _owner.LowerFMTabsCollapseButton_Click; - - container.Controls.Add(MenuButton); - container.Controls.Add(CollapseButton); container.Controls.Add(_tabControl); _tabControl.Enabled = _enabled; @@ -125,12 +85,12 @@ public void ShowTab(TabPage tabPage, bool show) if (show) { Construct(); - _tabControl.ShowTab(tabPage, true); + _owner.ShowFMTab(WhichTabControl.Bottom, tabPage); } else { if (!Constructed) return; - _tabControl.ShowTab(tabPage, false); + _owner.HideFMTab(WhichTabControl.Bottom, tabPage); } } diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 2021bef1d..a8b5ced89 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -110,6 +110,7 @@ private void InitializeComponent() this.PatchTabPage = new AngelLoader.Forms.CustomControls.PatchTabPage(); this.ModsTabPage = new AngelLoader.Forms.CustomControls.ModsTabPage(); this.ScreenshotsTabPage = new AngelLoader.Forms.CustomControls.ScreenshotsTabPage(); + this.TopFMTabsEmptyMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.LowerSplitContainer = new AngelLoader.Forms.CustomControls.DarkSplitContainerCustom(); this.ReadmeEncodingButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ReadmeFullScreenButton = new AngelLoader.Forms.CustomControls.DarkButton(); @@ -118,6 +119,9 @@ private void InitializeComponent() this.ReadmeResetZoomButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ChooseReadmeComboBox = new AngelLoader.Forms.CustomControls.DarkComboBoxWithBackingItems(); this.ReadmeRichTextBox = new AngelLoader.Forms.CustomControls.RichTextBoxCustom(); + this.BottomFMTabsEmptyMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); + this.BottomFMTabsMenuButton = new AngelLoader.Forms.CustomControls.DarkButton(); + this.BottomFMTabsCollapseButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.MainToolTip = new AngelLoader.Forms.CustomControls.ToolTipCustom(this.components); this.BottomRightFLP.SuspendLayout(); this.BottomLeftFLP.SuspendLayout(); @@ -138,6 +142,7 @@ private void InitializeComponent() this.TopFMTabControl.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.LowerSplitContainer)).BeginInit(); this.LowerSplitContainer.Panel1.SuspendLayout(); + this.LowerSplitContainer.Panel2.SuspendLayout(); this.LowerSplitContainer.SuspendLayout(); this.SuspendLayout(); // @@ -297,6 +302,7 @@ private void InitializeComponent() this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabsMenuButton); this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabsCollapseButton); this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabControl); + this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabsEmptyMessageLabel); this.TopSplitContainer.Size = new System.Drawing.Size(1671, 309); this.TopSplitContainer.SplitterDistance = 1116; this.TopSplitContainer.TabIndex = 0; @@ -978,6 +984,19 @@ private void InitializeComponent() this.ScreenshotsTabPage.TabIndex = 5; this.ScreenshotsTabPage.Text = "Screenshots"; // + // TopFMTabsEmptyMessageLabel + // + this.TopFMTabsEmptyMessageLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TopFMTabsEmptyMessageLabel.Location = new System.Drawing.Point(0, 0); + this.TopFMTabsEmptyMessageLabel.Name = "TopFMTabsEmptyMessageLabel"; + this.TopFMTabsEmptyMessageLabel.Size = new System.Drawing.Size(533, 309); + this.TopFMTabsEmptyMessageLabel.TabIndex = 16; + this.TopFMTabsEmptyMessageLabel.Text = "[empty message]"; + this.TopFMTabsEmptyMessageLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.TopFMTabsEmptyMessageLabel.PaintCustom += new System.EventHandler(this.FMTabsEmptyMessageLabels_Paint); + // // LowerSplitContainer // this.LowerSplitContainer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) @@ -1002,9 +1021,11 @@ private void InitializeComponent() // LowerSplitContainer.Panel2 // this.LowerSplitContainer.Panel2.BackColor = System.Drawing.SystemColors.Control; - this.LowerSplitContainer.Panel2Collapsed = true; + this.LowerSplitContainer.Panel2.Controls.Add(this.BottomFMTabsEmptyMessageLabel); + this.LowerSplitContainer.Panel2.Controls.Add(this.BottomFMTabsMenuButton); + this.LowerSplitContainer.Panel2.Controls.Add(this.BottomFMTabsCollapseButton); this.LowerSplitContainer.Size = new System.Drawing.Size(1671, 357); - this.LowerSplitContainer.SplitterDistance = 1613; + this.LowerSplitContainer.SplitterDistance = 1116; this.LowerSplitContainer.TabIndex = 0; // // ReadmeEncodingButton @@ -1013,7 +1034,7 @@ private void InitializeComponent() this.ReadmeEncodingButton.BackColor = System.Drawing.SystemColors.Window; this.ReadmeEncodingButton.FlatAppearance.BorderSize = 0; this.ReadmeEncodingButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.ReadmeEncodingButton.Location = new System.Drawing.Point(1502, 8); + this.ReadmeEncodingButton.Location = new System.Drawing.Point(947, 8); this.ReadmeEncodingButton.Name = "ReadmeEncodingButton"; this.ReadmeEncodingButton.Size = new System.Drawing.Size(21, 21); this.ReadmeEncodingButton.TabIndex = 2; @@ -1029,7 +1050,7 @@ private void InitializeComponent() this.ReadmeFullScreenButton.BackColor = System.Drawing.SystemColors.Window; this.ReadmeFullScreenButton.FlatAppearance.BorderSize = 0; this.ReadmeFullScreenButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.ReadmeFullScreenButton.Location = new System.Drawing.Point(1616, 8); + this.ReadmeFullScreenButton.Location = new System.Drawing.Point(1061, 8); this.ReadmeFullScreenButton.Name = "ReadmeFullScreenButton"; this.ReadmeFullScreenButton.Size = new System.Drawing.Size(21, 21); this.ReadmeFullScreenButton.TabIndex = 6; @@ -1046,7 +1067,7 @@ private void InitializeComponent() this.ReadmeZoomInButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; this.ReadmeZoomInButton.FlatAppearance.BorderSize = 0; this.ReadmeZoomInButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.ReadmeZoomInButton.Location = new System.Drawing.Point(1534, 8); + this.ReadmeZoomInButton.Location = new System.Drawing.Point(979, 8); this.ReadmeZoomInButton.Name = "ReadmeZoomInButton"; this.ReadmeZoomInButton.Size = new System.Drawing.Size(21, 21); this.ReadmeZoomInButton.TabIndex = 3; @@ -1063,7 +1084,7 @@ private void InitializeComponent() this.ReadmeZoomOutButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; this.ReadmeZoomOutButton.FlatAppearance.BorderSize = 0; this.ReadmeZoomOutButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.ReadmeZoomOutButton.Location = new System.Drawing.Point(1559, 8); + this.ReadmeZoomOutButton.Location = new System.Drawing.Point(1004, 8); this.ReadmeZoomOutButton.Name = "ReadmeZoomOutButton"; this.ReadmeZoomOutButton.Size = new System.Drawing.Size(21, 21); this.ReadmeZoomOutButton.TabIndex = 4; @@ -1080,7 +1101,7 @@ private void InitializeComponent() this.ReadmeResetZoomButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; this.ReadmeResetZoomButton.FlatAppearance.BorderSize = 0; this.ReadmeResetZoomButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.ReadmeResetZoomButton.Location = new System.Drawing.Point(1584, 8); + this.ReadmeResetZoomButton.Location = new System.Drawing.Point(1029, 8); this.ReadmeResetZoomButton.Name = "ReadmeResetZoomButton"; this.ReadmeResetZoomButton.Size = new System.Drawing.Size(21, 21); this.ReadmeResetZoomButton.TabIndex = 5; @@ -1095,7 +1116,7 @@ private void InitializeComponent() this.ChooseReadmeComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.ChooseReadmeComboBox.FireMouseLeaveOnLeaveWindow = true; this.ChooseReadmeComboBox.FormattingEnabled = true; - this.ChooseReadmeComboBox.Location = new System.Drawing.Point(1321, 8); + this.ChooseReadmeComboBox.Location = new System.Drawing.Point(766, 8); this.ChooseReadmeComboBox.Name = "ChooseReadmeComboBox"; this.ChooseReadmeComboBox.Size = new System.Drawing.Size(170, 21); this.ChooseReadmeComboBox.TabIndex = 1; @@ -1114,11 +1135,49 @@ private void InitializeComponent() this.ReadmeRichTextBox.Location = new System.Drawing.Point(1, 1); this.ReadmeRichTextBox.Name = "ReadmeRichTextBox"; this.ReadmeRichTextBox.ReadOnly = true; - this.ReadmeRichTextBox.Size = new System.Drawing.Size(1668, 356); + this.ReadmeRichTextBox.Size = new System.Drawing.Size(1113, 356); this.ReadmeRichTextBox.TabIndex = 0; this.ReadmeRichTextBox.Text = ""; this.ReadmeRichTextBox.MouseLeave += new System.EventHandler(this.ReadmeArea_MouseLeave); // + // BottomFMTabsEmptyMessageLabel + // + this.BottomFMTabsEmptyMessageLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.BottomFMTabsEmptyMessageLabel.Location = new System.Drawing.Point(0, 0); + this.BottomFMTabsEmptyMessageLabel.Name = "BottomFMTabsEmptyMessageLabel"; + this.BottomFMTabsEmptyMessageLabel.Size = new System.Drawing.Size(533, 357); + this.BottomFMTabsEmptyMessageLabel.TabIndex = 17; + this.BottomFMTabsEmptyMessageLabel.Text = "[empty message]"; + this.BottomFMTabsEmptyMessageLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.BottomFMTabsEmptyMessageLabel.PaintCustom += new System.EventHandler(this.FMTabsEmptyMessageLabels_Paint); + // + // BottomFMTabsMenuButton + // + this.BottomFMTabsMenuButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.BottomFMTabsMenuButton.FlatAppearance.BorderSize = 0; + this.BottomFMTabsMenuButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.BottomFMTabsMenuButton.Location = new System.Drawing.Point(533, 0); + this.BottomFMTabsMenuButton.Name = "BottomFMTabsMenuButton"; + this.BottomFMTabsMenuButton.Size = new System.Drawing.Size(18, 20); + this.BottomFMTabsMenuButton.TabIndex = 15; + this.BottomFMTabsMenuButton.PaintCustom += new System.EventHandler(this.FMTabsMenuButton_Paint); + this.BottomFMTabsMenuButton.Click += new System.EventHandler(this.LowerFMTabsMenuButton_Click); + // + // BottomFMTabsCollapseButton + // + this.BottomFMTabsCollapseButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.BottomFMTabsCollapseButton.ArrowDirection = AngelLoader.Forms.Direction.Right; + this.BottomFMTabsCollapseButton.FlatAppearance.BorderSize = 0; + this.BottomFMTabsCollapseButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.BottomFMTabsCollapseButton.Location = new System.Drawing.Point(533, 20); + this.BottomFMTabsCollapseButton.Name = "BottomFMTabsCollapseButton"; + this.BottomFMTabsCollapseButton.Size = new System.Drawing.Size(18, 337); + this.BottomFMTabsCollapseButton.TabIndex = 16; + this.BottomFMTabsCollapseButton.Click += new System.EventHandler(this.LowerFMTabsCollapseButton_Click); + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -1159,6 +1218,7 @@ private void InitializeComponent() this.RefreshAreaToolStrip.PerformLayout(); this.TopFMTabControl.ResumeLayout(false); this.LowerSplitContainer.Panel1.ResumeLayout(false); + this.LowerSplitContainer.Panel2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.LowerSplitContainer)).EndInit(); this.LowerSplitContainer.ResumeLayout(false); this.ResumeLayout(false); @@ -1276,6 +1336,11 @@ private void InitializeComponent() internal CustomControls.DarkButton TopFMTabsMenuButton; internal CustomControls.DarkArrowButton TopFMTabsCollapseButton; + internal CustomControls.DarkLabel TopFMTabsEmptyMessageLabel; + + internal CustomControls.DarkButton BottomFMTabsMenuButton; + internal CustomControls.DarkArrowButton BottomFMTabsCollapseButton; + internal CustomControls.DarkLabel BottomFMTabsEmptyMessageLabel; #endregion diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 81fa87481..a26e50b5d 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -672,6 +672,9 @@ and does NOT have its text transferred over. It ends up with blank text. // For right-clicking on blank space in tab bar TopSplitContainer.Panel2.MouseClick += TopFMTabsBar_MouseClick; + // For right-clicking on the tab area when no tabs are present + TopFMTabsEmptyMessageLabel.MouseClick += TopFMTabsBar_MouseClick; + #region Construct + init non-public-release controls #if DEBUG || (Release_Testing && !RT_StartupOnly) @@ -918,11 +921,11 @@ logic as it is. // They're visible by default - shave off a bit of time if (visible == FMTabVisibleIn.None) { - HideTab(WhichTabControl.Top, fmTabPage); + HideFMTab(WhichTabControl.Top, fmTabPage); } else if (visible == FMTabVisibleIn.Bottom) { - MoveTab(WhichTabControl.Top, WhichTabControl.Bottom, fmTabPage, expandCollapsed: false); + MoveFMTab(WhichTabControl.Top, WhichTabControl.Bottom, fmTabPage, expandCollapsed: false); } Lazy_FMTabsMenu.SetItemChecked(i, visible != FMTabVisibleIn.None); } @@ -1225,6 +1228,10 @@ private void SetWindowStateAndSize() { lazyTab.Construct(); } + if (!LowerSplitContainer.FullScreen) + { + Lazy_LowerTabControl.Construct(); + } TopFMTabControl.Selected += FMTabControl_Selected; Lazy_LowerTabControl.Selected += FMTabControl_Selected; @@ -1876,6 +1883,9 @@ private void Localize(bool startup) Lazy_FMTabsMenu.Localize(); + TopFMTabsEmptyMessageLabel.Text = LText.FMTabs.EmptyTabAreaMessage; + BottomFMTabsEmptyMessageLabel.Text = LText.FMTabs.EmptyTabAreaMessage; + StatisticsTabPage.Text = LText.StatisticsTab.TabText; EditFMTabPage.Text = LText.EditFMTab.TabText; CommentTabPage.Text = LText.CommentTab.TabText; @@ -3277,7 +3287,7 @@ private void TopFMTabsCollapseButton_Click(object sender, EventArgs e) SetFMTabsCollapsedState(WhichTabControl.Top, TopSplitContainer.FullScreen); } - internal void LowerFMTabsCollapseButton_Click(object sender, EventArgs e) + private void LowerFMTabsCollapseButton_Click(object sender, EventArgs e) { LowerSplitContainer.ToggleFullScreen(); SetFMTabsCollapsedState(WhichTabControl.Bottom, LowerSplitContainer.FullScreen); @@ -3287,7 +3297,7 @@ private void SetFMTabsCollapsedState(WhichTabControl which, bool collapsed) { (DarkArrowButton collapseButton, DarkTabControl tabControl, Lazy_FMTabsBlocker blocker) = which == WhichTabControl.Bottom - ? (Lazy_LowerTabControl.CollapseButton, Lazy_LowerTabControl.TabControl, Lazy_TopFMTabsBlocker) + ? (BottomFMTabsCollapseButton, Lazy_LowerTabControl.TabControl, Lazy_TopFMTabsBlocker) : (TopFMTabsCollapseButton, TopFMTabControl, Lazy_BottomFMTabsBlocker); if (collapsed) @@ -3317,10 +3327,10 @@ private void TopFMTabsMenuButton_Click(object sender, EventArgs e) ControlUtils.ShowMenu(Lazy_FMTabsMenu.Menu, TopFMTabsMenuButton, MenuPos.BottomLeft); } - internal void LowerFMTabsMenuButton_Click(object sender, EventArgs e) + private void LowerFMTabsMenuButton_Click(object sender, EventArgs e) { Lazy_FMTabsMenu.Menu.Data = WhichTabControl.Bottom; - ControlUtils.ShowMenu(Lazy_FMTabsMenu.Menu, Lazy_LowerTabControl.MenuButton, MenuPos.BottomLeft); + ControlUtils.ShowMenu(Lazy_FMTabsMenu.Menu, BottomFMTabsMenuButton, MenuPos.BottomLeft); } internal void FMTabsMenu_Opening(object sender, CancelEventArgs e) @@ -3358,12 +3368,6 @@ internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) ? Lazy_LowerTabControl.TabControl : TopFMTabControl; - if (!s.Checked && tabControl.TabCount == 1) - { - s.Checked = true; - return; - } - try { // MUST suspend drawing or we get crashes! @@ -3381,9 +3385,18 @@ tab order gets messed up. */ if (s.Checked) { - HideTab(tabControl == TopFMTabControl ? WhichTabControl.Bottom : WhichTabControl.Top, tab); + // @DockUI: Expand tab panels when a tab is shown via the menu + HideFMTab(tabControl == TopFMTabControl ? WhichTabControl.Bottom : WhichTabControl.Top, tab); + ShowFMTab(tabControl == TopFMTabControl ? WhichTabControl.Top : WhichTabControl.Bottom, tab); + if (tab is Lazy_TabsBase lazyTab) + { + lazyTab.Construct(); + } + } + else + { + HideFMTab(tabControl == TopFMTabControl ? WhichTabControl.Top : WhichTabControl.Bottom, tab); } - tabControl.ShowTab(tab, s.Checked); } finally { @@ -5573,7 +5586,7 @@ private void HandleTabDrag(WhichTabControl dest) Point cp = Native.GetCursorPosition_Fast(); - if ((sc.Panel2Collapsed || sc.FullScreen) && sc.ClientRectangle.Contains(sc.PointToClient_Fast(cp))) + if (sc.FullScreen && sc.ClientRectangle.Contains(sc.PointToClient_Fast(cp))) { if (!_inTabDragArea) { @@ -5627,7 +5640,7 @@ private void HandleTabDragFinish(WhichTabControl source, WhichTabControl dest) dragTab = source == WhichTabControl.Bottom ? Lazy_LowerTabControl.DragTab : TopFMTabControl.DragTab; if (dragTab == null) return; - MoveTab(source, dest, dragTab); + MoveFMTab(source, dest, dragTab); } finally { @@ -5645,7 +5658,7 @@ private void HandleTabDragFinish(WhichTabControl source, WhichTabControl dest) } } - private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPage, bool expandCollapsed = true) + private void MoveFMTab(WhichTabControl source, WhichTabControl dest, TabPage tabPage, bool expandCollapsed = true) { if (source == dest) return; @@ -5662,9 +5675,8 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa : TopSplitContainer; sourceTabControl.RestoreBackedUpBackingTabs(); - HideTab(source, tabPage); - destTabControl.ShowTab(tabPage, true); - destSplitContainer.Panel2Collapsed = false; + HideFMTab(source, tabPage); + ShowFMTab(dest, tabPage); if (expandCollapsed) { @@ -5679,17 +5691,32 @@ private void MoveTab(WhichTabControl source, WhichTabControl dest, TabPage tabPa tabPage.Focus(); } - private void HideTab(WhichTabControl which, TabPage tabPage) + internal void ShowFMTab(WhichTabControl which, TabPage tabPage) + { + if (which == WhichTabControl.Bottom) + { + BottomFMTabsEmptyMessageLabel.Hide(); + Lazy_LowerTabControl.TabControl.ShowTab(tabPage, true); + } + else + { + TopFMTabsEmptyMessageLabel.Hide(); + TopFMTabControl.ShowTab(tabPage, true); + } + } + + internal void HideFMTab(WhichTabControl which, TabPage tabPage) { - (DarkTabControl tabControl, DarkSplitContainerCustom splitter) = + (DarkTabControl tabControl, DarkLabel emptyMessageLabel) = which == WhichTabControl.Bottom - ? (Lazy_LowerTabControl.TabControl, LowerSplitContainer) - : (TopFMTabControl, TopSplitContainer); + ? (Lazy_LowerTabControl.TabControl, BottomFMTabsEmptyMessageLabel) + : (TopFMTabControl, TopFMTabsEmptyMessageLabel); tabControl.ShowTab(tabPage, false); if (tabControl.TabCount == 0) { - splitter.Panel2Collapsed = true; + emptyMessageLabel.BringToFront(); + emptyMessageLabel.Show(); } } @@ -5722,4 +5749,13 @@ internal void PrintBackingTabs() } #endregion + + // @DockUI: Lazy-load the empty message labels + private void FMTabsEmptyMessageLabels_Paint(object sender, PaintEventArgs e) + { + DarkLabel label = BottomFMTabsEmptyMessageLabel; + e.Graphics.DrawRectangle( + Config.DarkMode ? DarkColors.LighterBackgroundPen : SystemPens.ControlLight, + new Rectangle(0, 0, label.ClientRectangle.Width - 1, label.ClientRectangle.Height - 1)); + } } diff --git a/AngelLoader/Forms/MainForm.resx b/AngelLoader/Forms/MainForm.resx index bfc7cdc79..abb45a43a 100644 --- a/AngelLoader/Forms/MainForm.resx +++ b/AngelLoader/Forms/MainForm.resx @@ -124,89 +124,89 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAK - EwAAAk1TRnQBSQFMAgEBBAEAAaABGwGgARsBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAG + EwAAAk1TRnQBSQFMAgEBBAEAAQgBHAEIARwBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgADBQEGA0IBdANP AZkDVQGxA1sBygNWAbUDTAGRA0YBgAMcAScoAAMNAREDSgGLA1ABmgMeASsYAAMDAQQDVQGtA1gBvQNO AZYDYAHgA1ABnzQAAwIBAwMZASIDWgHHA1IBoANBAXMDQAFvAzQBUwMpAT0DHQEpAx4BKgMPARMDBQEG DAADIwEzA2AB6AMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/Az4BahgAAwwBEAMFAQYEAAMr AUECAAGXAf8DAAH/A0ABcAwAAwMEBAEFBAADBQEGAYYBiwEAAf8ByQHNAQAB/wGQAZYBAAH/AaoBugEA Af8DWgHHAy0BRgMZASIDKAE7AzkBXgNCAXQDPwFuAzkBXgMIAQoMAAQBAw8BFAMuAUgDVgGwA0AB/QNA - Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABUgFuAYAB/gMAAf8DWgHE + Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABXwF7AYAB/gMAAf8DWgHE ASMBXgEhAfsDAAH/AgABnAH/AwAB/wMAAf8DWwHkA0EB+QMAAf8DQwF3DAADCQEMA1ABnwNdAckDPQFo A0YBgQNdAc8BAAGVAcoB/wMAAf8DXgHXA0MBdgMzAVEDVgGwA0YBfgMTARkIAAMsAUMDYQHiAv8BAAH/ - A1wB2QF9AYABTAH+A1sB0ANbAdgDXwHaAwAB/wMAAf8DAAH/A10B3wMVAR0MAAMLAQ4DTQGSA1kB7wEA - ARABAAH/AwAB/wEKAQwBBwH/ASYBPQE6Af8BHwEyATAB/wEAARABAAH/AwAB/wEGASMBAAH/AQMBIgEA - Af8DXgHwA0QBeQMIAQoEAANdAdEDAAH/A0sBjANdAcwDAAH/AwAB/wIAAZgB/wIAAZYB/wNAAf0DXAH4 - A1EBpANRAfcDAAH/AyIBMQgAAx8BLAEAAY4BpwH/AgABmgH/AwAB/wEAAZQBvQH/AQABzgL/AQABsQHe - Af8BAAGYAdIB/wEAAYUBygH/AwAB/wMrAfwBAAGnAcgB/wNZAe8DHgErDAADRgF9AbwBwQEAAf8DVQG0 - A04BlgNJAYUDYAHbA1YBswNCAXUDTgGVAcYBzQEAAf8DXQHqAxkBIwgABAEDNgFYA2EB5gFdAXIBTAH+ - ARIBSQEAAf8BDAE0AQAB/wEsAjUB/wEPARYBFwH/ARcCHwH/ARcBHQEeAf8BCgE2AQAB/wEKASQBAAH/ - AXIBgAFeAf4DYQHrA0ABcQMMARADNAFTAwAB/wNgAeADLgFIA10B6gMAAf8DAAH/AwAB/wMAAf8DTQH6 - AwAB/wNGAYEDTgGXAwAB/wNWAbAMAANEAXsBAAGyAdgB/wEAAbcB9QH/AQAB0QH5Af8BAAGZAZ4B/wEA - AbMBzwH/AQABjgGtAf8BAAGyAccB/wEAAdcC/wEAAesC/wEAAZ0BoQH/A08BmwMOARIMAANGAYABxQHJ - AQAB/wNRAZ4DJAE1A1gBugNdAewDXwHaAz0BaAM1AVYBwQHHAQAB/wNgAeMDGQEiCAADCQEMA00BkgFK - AkkB/gMAAf8DAAH/ASMBKQEqAf8BgQGMAY4B/wE+AUcBSwH/ASEBKwEyAf8BWwGEAYYB/wELAQ8BEQH/ - AwAB/wEVAQABAwH/A0AB/QNWAbUDGQEjA1gBvQMAAf8DXQHUAx4BKgNZAcMDAAH/A0AB/QIAAbwB/wMA - Af8DAAH/AwAB/wMoATsDNQFWAwAB/wIhASMB+wMTARoIAANQAZ0BAAGtAesB/wEAAaEBygH/AwAB/wMA - Af8BAAGUAbcB/wIAAYIB/wMAAf8BAAGZAZ8B/wEAAegC/wMAAf8DTAGOAwUBBgwAA0gBhAG6Ab8BAAH/ - A10B3AFsAW0BUQH3AdgB6AEAAf8BtwG6AQAB/wHcAeEBAAH/AwAB/wNZAcMBwQHGAQAB/wNdAd8DGAEh - CAADOARcAdYDKwH8AwAB/wEGAQoBDAH/AaEBpwGmAf8BhAGMAY0B/wErATcBPwH/AQ4BHQEmAf8BkgGY - AZkB/wFQAVYBVwH/AwAB/wMAAf8DTQH6A0sBjAMPARQDXgHtAwAB/wMrAfwDRQF8Az0BaQNNAfoBKQIy - AfsDTQH6AVoBXwGAAf4DKwH8A1MBpgQAAz4BawMAAf8DAAH/AzgBWwQCAzkBXwEAAYEBpAH/AQABtAHu - Af8DAAH/AwAB/wMAAf8BAAGMAbgB/wMAAf8BggIAAf8DAAH/AQABuAHOAf8BAAGFAcQB/wNeAd0DOgFg - AxUBHAgAA0cBgwGVAZsBAAH/AwAB/wHbAesBAAH/A1UBrwMQARUCUwFSAaUBwwHKAQAB/wNcAecBqAGw - AQAB/wNiAeEDGwElCAADSQGHAVkBWAFZAf4BBAEAAQIB/wMAAf8BUQFZAVoB/wGrArIB/wGLAZcBmwH/ - AUgBVwGBAf8BNgFKAVIB/wGrArIB/wGjAagBqQH/ARwBHwEjAf8BFQEJAQ4B/wNAAf0DWwHTAyoBPwNI - AfYCAAGaAf8DAAH/AwAB/wNUAasDXwHVAwAB/wNIAfYBYQGAAVUB/gNgAegDXgHXAzsBZQNKAYoCAAGI - Af8CAAGfAf8DPwFsA18B2gMAAf8BAAGyAeMB/wEAAY4BqQH/AwAB/wMAAf8DAAH/AQABkQHDAf8DAAH/ - AwAB/wMAAf8DAAH/AQABsAHuAf8DAAH/AwAB/wNOAZYIAANHAYMBAAGGAQAB/wHXAdwBAAH/AwAB/wNQ - AZ0DGwElA1UBrAHCAc4BAAH/A1wB2QGgAaoBAAH/A1oB6QMeASoIAANGAX0DTQH6AQ8BHgEAAf8BIgEx - ARMB/wE1AU4BOQH/ASgBUgFGAf8BFAEkASYB/wFQAV0BhAH/ATUBRAFIAf8BGQEwASwB/wEjAT4BOQH/ - ASwBOAEyAf8BDgEQAQgB/wEMAQkBCAH/A1wB/gNAAXADUQH3AwAB/wNcAfgDXwHlA1wB+AMAAf8DSAH2 - A00B+gMrAfwBIQEyASEB+wNYAb0DKQE9A14B1wIAAZIB/wMAAf8DPgFqAgABhgH/AQABqAHSAf8BAAHS - Av8CAAGEAf8DAAH/AwAB/wMAAf8BAAGKAcEB/wMAAf8DAAH/AwAB/wMAAf8BAAG8AfYB/wEAAaoB3gH/ - AgABmQH/A1IBqAgAA0MBdgGHAZMBAAH/AmgBQQH5Ad4B4QEAAf8DAAH/AwAB/wHOAeABAAH/Al4BXAHZ - A0EBcwGrAbQBAAH/A14B7QMVAR0IAAMsAUMDXQHqARwBQAEEAf8BEQFDAQAB/wEDASIBAAH/ARcBHwEg - Af8BPgFKAUwB/wGtArUB/wGlAawBrQH/ATMBPQE/Af8BAAEEAQUB/wENATgBAAH/AT8BowEAAf8BGwFO - AQAB/wNBAfkDOAFbA10B7AIAAZIB/wEAAYkBuAH/A2AB4ANIAYQDKgE/A04BmAJHAWoB+QMAAf8DRgF9 - BAADTQGSAgABiQH/AgABnAH/AwAB/wM0AVQDGAEhA0cBggEAAcAB6AH/AgABhAH/AwAB/wMAAf8DAAH/ - AQABpAHIAf8DAAH/AwAB/wMAAf8DAAH/AQABugH5Af8DYgHuA0EBcwMYASAIAANQAZ0BoAGrAQAB/wNb - Ac0DWgHEAm0BUQH3AYMBiwEAAf8DXwHlAz0BaAM5AV8BqwGxAQAB/wNgAfMDOgFhAxkBIgMJAQwDIQEv - A2AB8wEFAQ8BAAH/AwAB/wEKAREBEwH/ATsBQAFBAf8BnAGiAaAB/wHeAuAB/wHZAt0B/wGUAZoBmQH/ - ASgBLwExAf8BAQEHAQoB/wMAAf8BFwE5AQAB/wNNAfoDPgFrA1YBtgIAAZgB/wMAAf8CAAGIAf8DXgHd - AzQBVANVAa4BlwGpAd0B/wJeAV8B+wNHAYMDUgGlAwAB/wMAAf8DAAH/A00B+gMPARQEAAQBAV0CZQHs - AQABoQHmAf8DAAH/AYICAAH/AwAB/wEAAYwBuAH/AwAB/wMAAf8DAAH/AgABvQH/AQABlgHAAf8DVgGy - AwMBBAQAAxkBIwNbAdMBhAGGAQAB/wHRAdcBAAH/A1wB+ANdAd8DYgHuA1EB9wNfAeUDYAHjAoABaAH+ - AdEB1wEAAf8CgAFlAf4CgAFPAf4DYgHuAyoBQAMJAQwDWAG9AwAB/wECAgAB/wEaARcBHAH/AVACVgH/ - AcUCyQH/Ad8B4wHiAf8B4AHkAeMB/wG5Ar4B/wI6AT0B/wMAAf8BBQIAAf8BUQFOAU8B/gNZAcMDIQEv - AzABSgMAAf8DAAH/AgABnwH/AQABgQG2Af8DAAH/A2AB8wMAAf8DXAH4A00B+gEAAYQBsgH/AwAB/wMA - Af8DAAH/A1MBpgwAA0IBdQEAAeMC/wEAAZQBzAH/AwAB/wMAAf8BAAGAAbEB/wMAAf8DAAH/AgABjgH/ - AQABuQH7Af8DAAH/A0wBjgMSARcEAAMlATcDAAH/AdsB3AGOAf8B+AH7AZ0B/wGlAagBAAH/Al8BMgH7 - AZcBmgEAAf8DWgH1AZABkgEAAf8BpAGnAQAB/wJiAVkB7wHtAfIBjgH/AckBzQEAAf8BoAGlAQAB/wNb - AdgDFAEbAxUBHANiAeEDAAH/AR8BDwEVAf8BJAEiAScB/wE/AVwBOgH/AbgBywG4Af8B2ALdAf8B3QLg - Af8BpwHEAaAB/wE8AUwBMwH/AQ8BBQEKAf8DAAH/AWYBXAFfAf4DUgGgAw4BEgQAA1sBxQMAAf8DAAH/ - AwAB/wIAAYUB/wIAAaoB/wMAAf8BAAGAAZsB/wEAAY4BuAH/AwAB/wMAAf8CAAG0Af8DTQH6AxMBGQgA - AxgBIQFbAl0BygEAAeUB+gH/AQAD/wEAAcQB9wH/AgABlAH/AQABjQG6Af8CAAGXAf8CAAHCAf8BAAHR - Av8BAAHKAe4B/wIAAYcB/wNbAeQDIQEvCAADAgEDA00BkwG8AcYBAAH/A1YBsANeAeIDAAH/A2UB8QMA - Af8DOQFeA1IBoAL/AQAB/wMAAf8DWgG/AxYBHgQAAy0BRQNIAfYBGQEFAQoB/wEYAQ4BEwH/ARQBDAEO - Af8BLgFVARoB/wFdAZwBVgH/AY0BjAGOAf8BqAGvAbAB/wFVAaMBQgH/ATABRwEUAf8DAAH/AQMCAAH/ - AVgBVQFWAf4DWAG3AxIBFwQAAw4BEgNdAeoDAAH/AwAB/wIAAZwB/wMAAf8CAAGPAf8DAAH/AwAB/wMA - Af8CAAGkAf8CAAGGAf8DLQFFDAADIAEtAQABlQGsAf8BAAGAAZIB/wNRAaEDXQHqAQAB4gH4Af8BAAHe - AfMB/wEAAcoB8wH/AQABpgHIAf8DWQG7A1kBuwEAAa8B0AH/A1cBvAMLAQ4MAAMmATkDXQHMAyUBNwNT - AakDUgGgA1UBrANVAa8DQwF2A4AB/gG0AbgBAAH/AbsBxwEAAf8DZQHxAzIBTwQAA0IBdANcAcsDKwH8 - AysB/AEdAUQBBgH/AS8BNwEYAf8BNwFCASIB/wEoARsBIQH/ASwBKQErAf8BNAGBARMB/wEmAUIBDgH/ - AR4BNAEDAf8BAQIAAf8BWQFPAVMB/gNOAZUDCgENCAADFQEdA1oBxwMAAf8DAAH/AwAB/wMAAf8DAAH/ - AwAB/wIAAZEB/wJeAWEB4gMtAUUUAAMmATgDMwFRBAADDAEPA0QBewEAAewC/wEAAYIBlAH/A0oBiQME - AQUDAwEEAzQBVAMNAREsAANdAdEByQHSAQAB/wNLAY8CbQFRAfcBmwGoAQAB/wM+AWoEAAMDAQQDDAEP - AzUBVgNRAaQBQQFHAUEB+QNIAfYBMwEvAR4B/wEmARwBIAH/AR8BGAEaAf8BGAEtAQEB/wFqAWMBZQH+ - AX8BgAFbAf4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQ - ARUDZQHxA2AB4EAAA0QBeQNSAaUEAANGAYEDWQHBAw8BFAQAAwQBBQQABAEDOAFcA0IBdANGAX4DUwGq - A1UBrQNYAboDWgHEA1EBogNUAasDQAFvAwwBDwQBBAABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEA - AQEGAAEBFgAD/4EAAeABDwH8AT8BAwH/AeABAQHAAQcB5AE5AQABAwGAAQABgAEDAYABAQGAAQMBgAEA - AYABAQGAAQEBwAEDAwABAQHAAQEBwAEDBAABwAEBAcABAwMAARACAAHAAQMGAAHAAQMGAAHAAQMDAAEg - AgABwAUAAYABAQUAAQEBwAEBBAABgAEBAYABAQGAAQECAAGAAQMBgAEBAcABAQIAAcABBwHIAQMB/wGB - AgAB8AEPAfwBfwH/AZEBQAEBCw== + A1wB2QKAAVkB/gNbAdADWwHYA18B2gMAAf8DAAH/AwAB/wNdAd8DFQEdDAADCwEOA00BkgNZAe8BAAEQ + AQAB/wMAAf8BCgEMAQcB/wEmAT0BOgH/AR8BMgEwAf8BAAEQAQAB/wMAAf8BBgEjAQAB/wEDASIBAAH/ + A14B8ANEAXkDCAEKBAADXQHRAwAB/wNLAYwDXQHMAwAB/wMAAf8CAAGYAf8CAAGWAf8DQAH9A1wB+ANR + AaQDUQH3AwAB/wMiATEIAAMfASwBAAGOAacB/wIAAZoB/wMAAf8BAAGUAb0B/wEAAc4C/wEAAbEB3gH/ + AQABmAHSAf8BAAGFAcoB/wMAAf8DKwH8AQABpwHIAf8DWQHvAx4BKwwAA0YBfQG8AcEBAAH/A1UBtANO + AZYDSQGFA2AB2wNWAbMDQgF1A04BlQHGAc0BAAH/A10B6gMZASMIAAQBAzYBWANhAeYBagF/AVkB/gES + AUkBAAH/AQwBNAEAAf8BLAI1Af8BDwEWARcB/wEXAh8B/wEXAR0BHgH/AQoBNgEAAf8BCgEkAQAB/wF/ + AYABawH+A2EB6wNAAXEDDAEQAzQBUwMAAf8DYAHgAy4BSANdAeoDAAH/AwAB/wMAAf8DAAH/A00B+gMA + Af8DRgGBA04BlwMAAf8DVgGwDAADRAF7AQABsgHYAf8BAAG3AfUB/wEAAdEB+QH/AQABmQGeAf8BAAGz + Ac8B/wEAAY4BrQH/AQABsgHHAf8BAAHXAv8BAAHrAv8BAAGdAaEB/wNPAZsDDgESDAADRgGAAcUByQEA + Af8DUQGeAyQBNQNYAboDXQHsA18B2gM9AWgDNQFWAcEBxwEAAf8DYAHjAxkBIggAAwkBDANNAZIBVwJW + Af4DAAH/AwAB/wEjASkBKgH/AYEBjAGOAf8BPgFHAUsB/wEhASsBMgH/AVsBhAGGAf8BCwEPAREB/wMA + Af8BFQEAAQMB/wNAAf0DVgG1AxkBIwNYAb0DAAH/A10B1AMeASoDWQHDAwAB/wNAAf0CAAG8Af8DAAH/ + AwAB/wMAAf8DKAE7AzUBVgMAAf8CIQEjAfsDEwEaCAADUAGdAQABrQHrAf8BAAGhAcoB/wMAAf8DAAH/ + AQABlAG3Af8CAAGCAf8DAAH/AQABmQGfAf8BAAHoAv8DAAH/A0wBjgMFAQYMAANIAYQBugG/AQAB/wNd + AdwBbAFtAVEB9wHYAegBAAH/AbcBugEAAf8B3AHhAQAB/wMAAf8DWQHDAcEBxgEAAf8DXQHfAxgBIQgA + AzgEXAHWAysB/AMAAf8BBgEKAQwB/wGhAacBpgH/AYQBjAGNAf8BKwE3AT8B/wEOAR0BJgH/AZIBmAGZ + Af8BUAFWAVcB/wMAAf8DAAH/A00B+gNLAYwDDwEUA14B7QMAAf8DKwH8A0UBfAM9AWkDTQH6ASkCMgH7 + A00B+gFnAWwBgAH+AysB/ANTAaYEAAM+AWsDAAH/AwAB/wM4AVsEAgM5AV8BAAGBAaQB/wEAAbQB7gH/ + AwAB/wMAAf8DAAH/AQABjAG4Af8DAAH/AYICAAH/AwAB/wEAAbgBzgH/AQABhQHEAf8DXgHdAzoBYAMV + ARwIAANHAYMBlQGbAQAB/wMAAf8B2wHrAQAB/wNVAa8DEAEVAlMBUgGlAcMBygEAAf8DXAHnAagBsAEA + Af8DYgHhAxsBJQgAA0kBhwFmAWUBZgH+AQQBAAECAf8DAAH/AVEBWQFaAf8BqwKyAf8BiwGXAZsB/wFI + AVcBgQH/ATYBSgFSAf8BqwKyAf8BowGoAakB/wEcAR8BIwH/ARUBCQEOAf8DQAH9A1sB0wMqAT8DSAH2 + AgABmgH/AwAB/wMAAf8DVAGrA18B1QMAAf8DSAH2AW4BgAFiAf4DYAHoA14B1wM7AWUDSgGKAgABiAH/ + AgABnwH/Az8BbANfAdoDAAH/AQABsgHjAf8BAAGOAakB/wMAAf8DAAH/AwAB/wEAAZEBwwH/AwAB/wMA + Af8DAAH/AwAB/wEAAbAB7gH/AwAB/wMAAf8DTgGWCAADRwGDAQABhgEAAf8B1wHcAQAB/wMAAf8DUAGd + AxsBJQNVAawBwgHOAQAB/wNcAdkBoAGqAQAB/wNaAekDHgEqCAADRgF9A00B+gEPAR4BAAH/ASIBMQET + Af8BNQFOATkB/wEoAVIBRgH/ARQBJAEmAf8BUAFdAYQB/wE1AUQBSAH/ARkBMAEsAf8BIwE+ATkB/wEs + ATgBMgH/AQ4BEAEIAf8BDAEJAQgB/wNpAf4DQAFwA1EB9wMAAf8DXAH4A18B5QNcAfgDAAH/A0gB9gNN + AfoDKwH8ASEBMgEhAfsDWAG9AykBPQNeAdcCAAGSAf8DAAH/Az4BagIAAYYB/wEAAagB0gH/AQAB0gL/ + AgABhAH/AwAB/wMAAf8DAAH/AQABigHBAf8DAAH/AwAB/wMAAf8DAAH/AQABvAH2Af8BAAGqAd4B/wIA + AZkB/wNSAagIAANDAXYBhwGTAQAB/wJoAUEB+QHeAeEBAAH/AwAB/wMAAf8BzgHgAQAB/wJeAVwB2QNB + AXMBqwG0AQAB/wNeAe0DFQEdCAADLAFDA10B6gEcAUABBAH/AREBQwEAAf8BAwEiAQAB/wEXAR8BIAH/ + AT4BSgFMAf8BrQK1Af8BpQGsAa0B/wEzAT0BPwH/AQABBAEFAf8BDQE4AQAB/wE/AaMBAAH/ARsBTgEA + Af8DQQH5AzgBWwNdAewCAAGSAf8BAAGJAbgB/wNgAeADSAGEAyoBPwNOAZgCRwFqAfkDAAH/A0YBfQQA + A00BkgIAAYkB/wIAAZwB/wMAAf8DNAFUAxgBIQNHAYIBAAHAAegB/wIAAYQB/wMAAf8DAAH/AwAB/wEA + AaQByAH/AwAB/wMAAf8DAAH/AwAB/wEAAboB+QH/A2IB7gNBAXMDGAEgCAADUAGdAaABqwEAAf8DWwHN + A1oBxAJtAVEB9wGDAYsBAAH/A18B5QM9AWgDOQFfAasBsQEAAf8DYAHzAzoBYQMZASIDCQEMAyEBLwNg + AfMBBQEPAQAB/wMAAf8BCgERARMB/wE7AUABQQH/AZwBogGgAf8B3gLgAf8B2QLdAf8BlAGaAZkB/wEo + AS8BMQH/AQEBBwEKAf8DAAH/ARcBOQEAAf8DTQH6Az4BawNWAbYCAAGYAf8DAAH/AgABiAH/A14B3QM0 + AVQDVQGuAZcBqQHdAf8CXgFfAfsDRwGDA1IBpQMAAf8DAAH/AwAB/wNNAfoDDwEUBAAEAQFdAmUB7AEA + AaEB5gH/AwAB/wGCAgAB/wMAAf8BAAGMAbgB/wMAAf8DAAH/AwAB/wIAAb0B/wEAAZYBwAH/A1YBsgMD + AQQEAAMZASMDWwHTAYQBhgEAAf8B0QHXAQAB/wNcAfgDXQHfA2IB7gNRAfcDXwHlA2AB4wKAAXUB/gHR + AdcBAAH/AoABcgH+AoABXAH+A2IB7gMqAUADCQEMA1gBvQMAAf8BAgIAAf8BGgEXARwB/wFQAlYB/wHF + AskB/wHfAeMB4gH/AeAB5AHjAf8BuQK+Af8COgE9Af8DAAH/AQUCAAH/AV4BWwFcAf4DWQHDAyEBLwMw + AUoDAAH/AwAB/wIAAZ8B/wEAAYEBtgH/AwAB/wNgAfMDAAH/A1wB+ANNAfoBAAGEAbIB/wMAAf8DAAH/ + AwAB/wNTAaYMAANCAXUBAAHjAv8BAAGUAcwB/wMAAf8DAAH/AQABgAGxAf8DAAH/AwAB/wIAAY4B/wEA + AbkB+wH/AwAB/wNMAY4DEgEXBAADJQE3AwAB/wHbAdwBjgH/AfgB+wGdAf8BpQGoAQAB/wJfATIB+wGX + AZoBAAH/A1oB9QGQAZIBAAH/AaQBpwEAAf8CYgFZAe8B7QHyAY4B/wHJAc0BAAH/AaABpQEAAf8DWwHY + AxQBGwMVARwDYgHhAwAB/wEfAQ8BFQH/ASQBIgEnAf8BPwFcAToB/wG4AcsBuAH/AdgC3QH/Ad0C4AH/ + AacBxAGgAf8BPAFMATMB/wEPAQUBCgH/AwAB/wFzAWkBbAH+A1IBoAMOARIEAANbAcUDAAH/AwAB/wMA + Af8CAAGFAf8CAAGqAf8DAAH/AQABgAGbAf8BAAGOAbgB/wMAAf8DAAH/AgABtAH/A00B+gMTARkIAAMY + ASEBWwJdAcoBAAHlAfoB/wEAA/8BAAHEAfcB/wIAAZQB/wEAAY0BugH/AgABlwH/AgABwgH/AQAB0QL/ + AQABygHuAf8CAAGHAf8DWwHkAyEBLwgAAwIBAwNNAZMBvAHGAQAB/wNWAbADXgHiAwAB/wNlAfEDAAH/ + AzkBXgNSAaAC/wEAAf8DAAH/A1oBvwMWAR4EAAMtAUUDSAH2ARkBBQEKAf8BGAEOARMB/wEUAQwBDgH/ + AS4BVQEaAf8BXQGcAVYB/wGNAYwBjgH/AagBrwGwAf8BVQGjAUIB/wEwAUcBFAH/AwAB/wEDAgAB/wFl + AWIBYwH+A1gBtwMSARcEAAMOARIDXQHqAwAB/wMAAf8CAAGcAf8DAAH/AgABjwH/AwAB/wMAAf8DAAH/ + AgABpAH/AgABhgH/Ay0BRQwAAyABLQEAAZUBrAH/AQABgAGSAf8DUQGhA10B6gEAAeIB+AH/AQAB3gHz + Af8BAAHKAfMB/wEAAaYByAH/A1kBuwNZAbsBAAGvAdAB/wNXAbwDCwEODAADJgE5A10BzAMlATcDUwGp + A1IBoANVAawDVQGvA0MBdgOAAf4BtAG4AQAB/wG7AccBAAH/A2UB8QMyAU8EAANCAXQDXAHLAysB/AMr + AfwBHQFEAQYB/wEvATcBGAH/ATcBQgEiAf8BKAEbASEB/wEsASkBKwH/ATQBgQETAf8BJgFCAQ4B/wEe + ATQBAwH/AQECAAH/AWYBXAFgAf4DTgGVAwoBDQgAAxUBHQNaAccDAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8CAAGRAf8CXgFhAeIDLQFFFAADJgE4AzMBUQQAAwwBDwNEAXsBAAHsAv8BAAGCAZQB/wNKAYkDBAEF + AwMBBAM0AVQDDQERLAADXQHRAckB0gEAAf8DSwGPAm0BUQH3AZsBqAEAAf8DPgFqBAADAwEEAwwBDwM1 + AVYDUQGkAUEBRwFBAfkDSAH2ATMBLwEeAf8BJgEcASAB/wEfARgBGgH/ARgBLQEBAf8BdwFwAXIB/gKA + AWgB/gNeAe0DTAGQAyMBMwQCEAADOwFjA1kBvgNeAfADZQHxA2UB8QNbAc0DQwF3AwYBCCgAAxABFQNl + AfEDYAHgQAADRAF5A1IBpQQAA0YBgQNZAcEDDwEUBAADBAEFBAAEAQM4AVwDQgF0A0YBfgNTAaoDVQGt + A1gBugNaAcQDUQGiA1QBqwNAAW8DDAEPBAEEAAFCAU0BPgcAAT4DAAEoAwABQAMAASADAAEBAQABAQYA + AQEWAAP/gQAB4AEPAfwBPwEDAf8B4AEBAcABBwHkATkBAAEDAYABAAGAAQMBgAEBAYABAwGAAQABgAEB + AYABAQHAAQMDAAEBAcABAQHAAQMEAAHAAQEBwAEDAwABEAIAAcABAwYAAcABAwYAAcABAwMAASACAAHA + BQABgAEBBQABAQHAAQEEAAGAAQEBgAEBAYABAQIAAYABAwGAAQEBwAEBAgABwAEHAcgBAwH/AYECAAHw + AQ8B/AF/Af8BkQFAAQEL @@ -279,78 +279,79 @@ iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGuSURBVDhPYxhQEKvEFB+nzHwiVoXlQ5wKyzso/R+EY5WZ - p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD4CuayqwkQUbBDME - hs9snf7/yKoeMHt9fyHYYKg23ADkwkJb2f8vb+/DMPDinnlArzMfjlVmWbN3UQtYDBQUUK3YAciFIAOx - uRCEbx5bAXLZeaBBOw6v7AaL4TUU5mVsLkTG1w4t/X96yzQw++3DI0BLWD5BjUAFQC+3FdnJETQQHb+6 - ewBk6FuoMQgAc+Gb+9i9jA9/eXUW5P1/UKMgABjoLcR4GRd+dn0nyKVPocYBvazM3FxsrwD2AjYNhPDH - Zyf+V3po/I9TZamBGgnyNsubV3f2Y9VACMMNVGbuhxoHAaCkAUoi2DThwx+fncRuIAjEK7OmpejwgNMe - Ns3YMMiFVZ6aoLQ6AWoMJgAZnKTJSZTBOL2MDSAMXonVMBCGuZAoA2EAGIPpuFxMkgvRATYXU2QgDEBc - zPX/yv5F/x9e3EK6l3GBOGWmOGDsHgcadi9WlaUUKjwQgIEBAExb1Vj6X25iAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG4SURBVDhPYxhQEKvEFB+nxHQiVoXlQ5wKyzso/R+EY5WZ + p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD+KUmZsKbGTBBsEM + geEzW6f/P7KqB8xe318INhiqDTcAubDQVvb/y9v7MAy8uGce0OtMh2OVWdbsXdQCFgMFBVQrdgByIchA + bC4E4ZvHVvyPUWI6DzRox+GV3WAxvIbCvIzNhcj42qGl/09vmQZmv3145H+ELMsnqBGoAOjltiI7OYIG + ouNXdw/8j1FmeQs1BgFgLnxzH7uX8eEvr86CvP8PahQExKkwtxDjZVz42fWd/2OVWJ5CjQN6WZm5udhe + AewFbBoI4Y/PTvyv9ND4H6fKUgM1EuhKRZY3r+7sx6qBEIYbqMzcDzUOAkBJA5REsGnChz8+O4ndQBCI + V2ZNS9HhAac9bJqxYZALqzw1QbloAtQYTAAyOEmTkyiDcXoZG0AYvBKrYSAMcyFRBsIAMAbTcbmYJBei + A2wupshAGIC4mOv/lf2L/j+8uIV0L+MCccpMccAS/3icEvO9WFWWUqjwQAAGBgDeOtU9U5quUwAAAABJ + RU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VVPKARhFN+jNDO7KLmoLRcHBy7iIi6SFDks - TqtmZtlcpEQuOGjNzK4p5F/tKiku4qAkB8vGYg97cLCJkAs3N0fmN71PY7Raa8rFr17tfu997+/vfeP6 - hx28pPa6JbWa/joLt6g1lg3M3RQH9WdB1rrp2Bm4+0Le4uDMtS+WvPXFLh7Lh5YzvKxNkPqX8I8XGM7S - 7QuJs57V1BukO3b+UhLUX8jidxAkdbspsn/InENqp7aOeFHZIJP8gTZUja1/ZA5p1g/igqwmURmZ5Qcu - oHSg113R1Ctz3rl0mi4KRO4xEzLLD6Ai2IKBMuf4jTNemq4jMxtQUg5lFfrVMo8cziBb5hxVmMwx9oDM - bDAcc5K2B/k2iKFDf9Fn5hyCORjc18nKBnJeM7mZaNB2zQG5/bqHtJ/Ay+FFMMTqHAziZeWQTL4CdIJz - dgHZgddoBZmYMMof9A6vXFqHCu5zonaXLSFzWEZprx3LJyl2CdI6G0+YF4kNgqi2lA7MP3ZFL56ZDba2 - pH/mgQuEK01n2YAgnj7tqW3h+MQaBEFBOdARel80mWE6bCoCQkduvgeyQMbI3BoETMHK24NXjq6ljKpG - 6XpuQDsEUbnCoK3OrG2B1Id24nge6NrPgGFhwHamMEEl0OeyL9lhoa2VMZiBI8+ACXOhtFX0GkHQJnxM - 8FEhC2eAxcITUDESTQuS0k/HzgJPcvZn4E/hcr0DUbSOqjT7gYIAAAAASUVORK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VU7SMNQFO0o2qQtgnQRxcnBwUl0EV1ERFAc + Sp0qNulnE0EUF3WQmqQl+EEp1AoiOIkOgohDq8UPdujgYBFFxUW3bh01J9wnMVKpbcDFAxfad++733Nf + bP8wgxPkMYcgt9Nfa+HwKz3u8Oq9K6y+8aLipWNr4AhGml3h2J0nefHgSV6/NE7G85yozJO6SvjmajRn + uaH1zNXoVvYd4k1mCvVhtUAW1YEX5P3e2HGKOYd0LO6dcn5pl0wqB9rQNrvzmTmkTz1J86J8icrIrDLY + A9Iwej20nC0y5yMbFzlXIPaEmZBZZQAVwRYMlDnHb5xxwlInmZmAksooq9Ynu51iNI9smXNUoTNH2wMy + M0FzbBeUI8iPQTQd+os+M+cQzEHjvkpWJpDz9oXdTLdyqA/I4VOdpP0CToxugCFG52AQJ0opMvkO0AnO + 2QVkB16jFWSiQyt/omkqfmMcKrhf51ceSyWkD0srrTgcP8+yS5CBlXRGv0hs4P1yf0No7cWTuH5jNtja + +lD02R6IturOSgFBnEH5dXD97NwYBEFBOdARes/mZZ7psKkICB25+RnIAhkjc2MQMAUrbw7eOrOd1aqa + oevlAe3gx6VbDNrozNgWSFfkII3nga79DhgWBmxmChNUAn05+1IaBtoaGYMZWPIM6NAXStlCrxEEbcLH + BB8VsrAGWCw8AS3TiRwvSCE6thZ4kks/A38Km+0DB1GODuPZXHcAAAAASUVORK5CYII= iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGZSURBVEhL7ZQhUMNAEEUjGSZ3QSKRSCQSiUTiykzuChKJ - AweX60wkEolEIiuRSCQSicSyf/vDHEdpO00EgjeTafdfZu9u92+Kf3KMa04q1+wxHJaqjge2Di/WxTfr - 4zHlYahOr3eQvBxPdvHf+PgszxWXezK63EDCchyOqBTVqN0qfXhn2A/rmgdbNxcMFeMnt6YO9wzXB2XA - BgwVafS59c0TbkZpPVASlCZNhEaXdXxFHyitB6wIt6SJtNGiGXezTykDJ1nhWpujZhuOwWkpfTUac0Al - Q14oXXzEs3ATWUN9UWcqijbax5ZhBpPLC3faNEkAm3H1G+oOeRgqcJDxYcrwJ7ATkjNUF+C6KAUlZZ47 - 0Ght6i8HmjXLxw85xSElBbVM3YB1xOmmmFpo+KU0n84R+fejS4pTqmOSj5hOKtcoLaY7Te4C9bWMfL65 - 9iyb3qWoj8V+aDQlJe+FbNbm07syuLr6OXNKB26C9YVWXkpi2zQReoAy9v4MKJIYG3SDN3d6h2A2WChZ - mFoXzigPC5qOxjL8SxTFJ00CxZeT7IG4AAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGaSURBVEhL7ZQhUMQwEEXrYKBNkUgkEolEIpG4MjQ5kEgc + uKPNzVQikUgk8iQSiUQikVjy936YEErvpq1A8GY6d/vT2SS7f5v8E5Pp+iTX9R7DcclLe6BOqxel7Zsy + 9pjyOORn0x0kTyezXfzPjH12zzWXB1JcrSNhOqmOqCR50Wytmek7w2EoXT+osr5kKGRmdpuV1T3D/qAM + 2ICh4Bp9oUz9hJtR6gdKgtKEidDozdK+og+U+gErwi1hImm00zJ9s08pAidZ4VobRb0Nx+C0lL4ajTmg + EuFeSLV9xNO5iVtDfVFnKoI02tiGYQSTuxfupGkuAWzG1W+IO9zDUICDMlPNGf4EdkJyhuICXBeloCS0 + uQONlqb+cqBFs4z9cKc4pCSglqEbsI443BRTCw2/lNrxjoi/Hz4pTimOCT5iOLFfo9SNP03sAjgFIx9v + Lj2Lpncp4mNnPzSakhD3wm3WxNO7Mri6+Dlyigc3wXqnlZcS2DZMhB6gjIM/A4JLjA384LVO7xgsBgsl + q+ZKV+eUxwVNR2MZ/iWS5BPRbcV7uffSLwAAAABJRU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH/SURBVEhLzVTPK0RRGD1LS0tLS0tLS0tLS8v5D4wx5Ech - CVkgJSmSlCkJSVm+maEMCUmykB9JshCSjKTrO2++25g3b3h4C6dOvXfv/c798Z3vw7+D04Q6/QwfTjfK - kk04d+Ko0KFw4TQikumAkU0GdChciPD+8wJMugW3vI0OhwM5ffVRP4xZgzkdhuFtdCocJKOYuZvNbfCy - 6D7Tvk79HUzqdieyFLfkbXgrXfI3iFD0aiIvTvI2yUYkdElpSHClsFZZLz7vIekUoUOmYnh4WyncgNzp - xKtdk4xhxMYKG6ym9fbyZgvMxViO15Mw93M5vi4VC38mN7Zrb6fzGmrnfJ7kZ+KwD+Z91V/oJ6TL5PnW - i6zsRNG225U7lV/gd+ThjgdFXBynksWQd4tk2pGlFf1ESpGHOugVZ0kOVKo0ZFHdRjMeHuf9xbzkYSTh - Pys+WVzNxPsJeumeXByoocEgAZXMh5+glydDv9sgQjf4CXp5MyWJlTrQ0GCgbelrrxgr2GtldtgCzwcB - Az476SkBs9ft+jvBvmQbn+VGHNnALVyep5yVyEDaTwtny4mhyp2X5icHWGbDs5Wuza/WFfgOTBgD+ESb - rXhkPnSqALRzKo6Ly3GYs1HZQApVp74Gi4UWZR54Gx32BZ+F69MxvPBWOvw1tDPW6G8g8PmK2zfwAeUN - UaR56NgIAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAICSURBVEhLzVQ9SwNBEJ3S0tIypaWlpWVKS8v8AhMlET/A + iIiKhYogQVBEBAMiKiJYbmIEg4gREbEQPxCRFKJBJAki67zLLDGXi7mYK3zw4G535u3HvB36d1B95JdP + 76Gi1JLoozsVpjYZ8hYqSIH0MGleZEqGvAULZz42SasIZXEaGfYGvPuOy0nSep/0zSwvwqeRKW+QCNHq + y1ppgfyWdU0ZmWoeKGp6hAoQN8RpcCoJaQ4sFHqMlcVBnCYRpLiE1AYn+5hdwm72+RgIpzAVmOylt8/d + ygVAji+amEQ/zZlcZo/RNN7eOYqQvl8o8WmJ9Ot6icXtauGfxMImNrtS1hA7l+vEP7GLCdJfe85CjRAu + 4+s7qLKyCtHg6WhpV06J9YjNXU2zODtOJKvB9xZID1EBVnQSqUVs6nyc68I1EKna4CB/igub23AWsxOb + ORlp8PFxcAcK7yRop7VzdqCkugMn+FAPJ0E7r2f+tkAAbnAStPN5mQvL70BS3QG2ha/tYnjBdiujw1Z4 + 3g2Q8NNJ73HSZ1HL33H0JdP4DFNhKrhu4Xw9rXiJSIT95OEcq35qt+a5+fEGdtDwzEuX5tdlCdQDCoYE + XJEaoBzqIVMVgJ2TYbp/WCR9O8+x/FBl6nfgscCiqANOI8OOwLUg/jBIeZxKhn+HdMZO+XUFXF91+yb6 + BhrAUXeHueVSAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANYSURBVDhPvZRJTFNRFIbPuS8xxmFjXDmGBUaNCxNduDCa - GDUmulOjiQsTo0QFKm0BESFlkEEZRLRMpS2zglBBhjJUJsGCMohIBFlolKCAKBAXosD13MeVCDGmuPDb - vL7/nHd67z3/ufDfydLDcrOPsv9+MCZWRLHW6ljWaY9mLeLdpFEOpHrAMpnqGimXYE9JGJZ1Z+PMWA1w - 3gJ82jn7HKf3l6QXh2NpqgZ2y0/+jkXPvJ5nIJ9+BvxrHfB2E048iscXlTcwzxGH3eJd6NNtwDszkZt1 - 7IL89M9YdOzsOxty3gG82YiDVl8WTKvZkO4HK5O8lH3W07DUooP1Qm8y4keRJ/LTdeyMLDGfVC07+Tqf - tvgUeEko671zETbKEBSFYOiLDKHjNSlBmhe4FYexfpHfn4/cpGMnZGgWqwGWVsewAd4O3BGLb5I14C5D - KqWRWDzZQLEYVi8llduesKkmDt+LFdfEsgFRR4ZolRrl6OdK4EOlyI1eymEpz/EwAnMmqEFVN7BMSnMY - vZWDQw+Bf64CnuajHJMygC0UrZP1wBsTWKuU5vGrqD0aC6U0j/pb2CV28iAMM1Qh1gNW1ydg/1Qj8Exf - tKjiAtSiDuAV0VhLTTmVG8B0WQHKIRmGe1fRPNUEvCERe6H0GhZVXcdXPVk4M/1YnCcbdsSjMzsQdsl8 - FeHZHxT/Qqv9UEJbpT9oT6eu62GbiOdewRgRdybjGNjC2MhENXWcGjTTTE868L488p6fckStJrkbyC4L - C5F/R7usONKdhWN18awr2x/WiTgVvSlWSkWH1a6XRzHnlCjYA/yTnY7AH6PVSgvI0MLaND24CZ9a/MBd - jLEMgS0EC7/T8TnimVMVkjSwg6aETwl/hrM28ucKNeAiJi2s6jTjx2/UqLxAjJCyuj2P8gisy9bDVim5 - jFmLEaLzb+8jT/GBnVKexWAAJn+6TJIn8+jLRT5DF01BENZK+d9J92bePTl0T3Sp09RLTpgba5ehS2VN - Ck1Pph87T35tGyynguQaMv6g6RJskWmuY9XB5idGHBsmd4zaqVgr8IFy4DYDaxK3mExbHFZf2N5BDhkn - 09OgfCmLRIdVy84VHAdFpiwecZ8Wh2KSPYp13gvCqFQt7C0wwBIZ/g2An2e+o9ziKCLsAAAAAElFTkSu - QmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANXSURBVDhPvZRJTJNREMdn3pcY43IxnlzDAaPGg4kePBhN + jBoTvanRxIOJUeIChbZUESSVpYCyyCJlKV0AQWVREBCECpUlBaUiECLIQaMEFVyAeBCFPud9PIkQY6oH + f5ev7z/zpm/ezBv47xToYbE1RNldGonpNXGsoz6JddUmsHaxtmiUPTkBsEi6+kZ2MOyojMZqdxZ6xxqA + 83bg0+6Z7zit20mviMGqHA1sl1v+jE3PAp85kE8/Af6lCbgnAycepmBP3VUsdiZjr1gLfboTeFc+cquO + nZFbf49Nx06+voOcPwXeloHD9lAWSadZk2eApeZAZZf9OCy06WC10Jsz8Z3wE/55OnZChphLjpYdfXGb + UnwMvNLI+q+fhbXSBOWXMarHQXoUxkoJcgPBrzyaDQr/wdvILTp2RJpmsBthYV0CG+Ie4A2J+DJLA/7S + pFJlworJR8CdicwlJZWMc7CuPhnfiBOL/SKONNEpNcrBT3XA31chzwxU9kt5lkoT3pigAj24gtVSmiUz + SNn7/h7wTw+A54Yoh6SspmefdAFvTmUdUprDz6D3E7BMSnNoSsNukcndaHSoQlIALHel4uBUM/D8ULSp + 4jzUoE4KGo+NVJRjRWFMVxCm7JNmuBmB1qlW4K507Id7sVhOKT3vMKN3ukW9sxFnCroLw2Gb9FcRPfud + 7J/ptG8rKVX6A08eVV0Pm4S96CImCntLKo5BWTQbnainilOBvG30pQsfKKbeMygH1GiSm+HsgmghjwM/ + dttxtDcfx5qSWXfheVgl7BT0mjgpPZYRtepVccw9JQL2Af9QS1dwHhPUSPNwaGFlrh78RJ/aDOAvnrE0 + QbkRy77R9TlTmFsVzBrY4rEgnxL9GcM6qT+XqAYfsWhhmceK775SoYrD0SRlNb2AGhM2Fepho5R8xqpF + k6j8q1Lk2SGwVcozGI3A5E+fMZ9jAQNFyL00aEoisFHK/05eEAvqu0Fzohs4jcV+6oTZZ+0zNFRWZNPr + yTew0/QIOodrKCB1jTMNhy3BsEG6+Y5dB+tFD45Qd3yspWAdwIdqgN8xslYxxaTb32EPhc1PqUPGqen7 + CvBzdRw67Vp2quQwKNLl7xHztCIKzbXxrOvWJYzP0cLOEiMskOZfAPgBbpejM2TyfeAAAAAASUVORK5C + YII= diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index ceef4e7ac..c13a3a6b3 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -87,6 +87,7 @@ private void InitComponentManual() PatchTabPage = new PatchTabPage(); ModsTabPage = new ModsTabPage(); ScreenshotsTabPage = new ScreenshotsTabPage(); + TopFMTabsEmptyMessageLabel = new DarkLabel(); LowerSplitContainer = new DarkSplitContainerCustom(); ReadmeEncodingButton = new DarkButton(); ReadmeFullScreenButton = new DarkButton(); @@ -95,6 +96,10 @@ private void InitComponentManual() ReadmeResetZoomButton = new DarkButton(); ChooseReadmeComboBox = new DarkComboBoxWithBackingItems(); ReadmeRichTextBox = new RichTextBoxCustom(); + BottomFMTabsEmptyMessageLabel = new DarkLabel(); + BottomFMTabsMenuButton = new DarkButton(); + BottomFMTabsCollapseButton = new DarkArrowButton(); + MainToolTip = new ToolTipCustom(components); BottomRightFLP.SuspendLayout(); BottomLeftFLP.SuspendLayout(); @@ -115,6 +120,7 @@ private void InitComponentManual() TopFMTabControl.SuspendLayout(); ((ISupportInitialize)LowerSplitContainer).BeginInit(); LowerSplitContainer.Panel1.SuspendLayout(); + LowerSplitContainer.Panel2.SuspendLayout(); LowerSplitContainer.SuspendLayout(); SuspendLayout(); // @@ -245,6 +251,7 @@ private void InitComponentManual() TopSplitContainer.Panel2.Controls.Add(TopFMTabsMenuButton); TopSplitContainer.Panel2.Controls.Add(TopFMTabsCollapseButton); TopSplitContainer.Panel2.Controls.Add(TopFMTabControl); + TopSplitContainer.Panel2.Controls.Add(TopFMTabsEmptyMessageLabel); TopSplitContainer.Size = new Size(1671, 309); TopSplitContainer.SplitterDistance = 1116; TopSplitContainer.TabIndex = 0; @@ -561,6 +568,13 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir TopFMTabControl.MouseDragCustom += TopFMTabControl_MouseDragCustom; TopFMTabControl.MouseUp += TopFMTabControl_MouseUp; // + // TopFMTabsEmptyMessageLabel + // + TopFMTabsEmptyMessageLabel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + TopFMTabsEmptyMessageLabel.Size = new Size(533, 309); + TopFMTabsEmptyMessageLabel.TextAlign = ContentAlignment.MiddleCenter; + TopFMTabsEmptyMessageLabel.PaintCustom += FMTabsEmptyMessageLabels_Paint; + // // LowerSplitContainer // LowerSplitContainer.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; @@ -581,9 +595,11 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir // LowerSplitContainer.Panel2 // LowerSplitContainer.Panel2.BackColor = SystemColors.Control; - LowerSplitContainer.Panel2Collapsed = true; + LowerSplitContainer.Panel2.Controls.Add(BottomFMTabsEmptyMessageLabel); + LowerSplitContainer.Panel2.Controls.Add(BottomFMTabsMenuButton); + LowerSplitContainer.Panel2.Controls.Add(BottomFMTabsCollapseButton); LowerSplitContainer.Size = new Size(1671, 357); - LowerSplitContainer.SplitterDistance = 1613; + LowerSplitContainer.SplitterDistance = 1116; LowerSplitContainer.TabIndex = 0; void SetReadmeButton(DarkButton button, int x, int tabIndex) @@ -600,11 +616,11 @@ void SetReadmeButton(DarkButton button, int x, int tabIndex) button.MouseLeave += ReadmeArea_MouseLeave; } - SetReadmeButton(ReadmeEncodingButton, 1502, 2); - SetReadmeButton(ReadmeZoomInButton, 1534, 3); - SetReadmeButton(ReadmeZoomOutButton, 1559, 4); - SetReadmeButton(ReadmeResetZoomButton, 1584, 5); - SetReadmeButton(ReadmeFullScreenButton, 1616, 6); + SetReadmeButton(ReadmeEncodingButton, 947, 2); + SetReadmeButton(ReadmeZoomInButton, 979, 3); + SetReadmeButton(ReadmeZoomOutButton, 1004, 4); + SetReadmeButton(ReadmeResetZoomButton, 1029, 5); + SetReadmeButton(ReadmeFullScreenButton, 1061, 6); // // ChooseReadmeComboBox @@ -612,7 +628,7 @@ void SetReadmeButton(DarkButton button, int x, int tabIndex) ChooseReadmeComboBox.Anchor = AnchorStyles.Top | AnchorStyles.Right; ChooseReadmeComboBox.FireMouseLeaveOnLeaveWindow = true; ChooseReadmeComboBox.FormattingEnabled = true; - ChooseReadmeComboBox.Location = new Point(1321, 8); + ChooseReadmeComboBox.Location = new Point(766, 8); ChooseReadmeComboBox.Size = new Size(170, 21); ChooseReadmeComboBox.TabIndex = 1; ChooseReadmeComboBox.Visible = false; @@ -627,10 +643,39 @@ void SetReadmeButton(DarkButton button, int x, int tabIndex) ReadmeRichTextBox.BorderStyle = BorderStyle.None; ReadmeRichTextBox.Location = new Point(1, 1); ReadmeRichTextBox.ReadOnly = true; - ReadmeRichTextBox.Size = new Size(1668, 356); + ReadmeRichTextBox.Size = new Size(1113, 356); ReadmeRichTextBox.TabIndex = 0; ReadmeRichTextBox.MouseLeave += ReadmeArea_MouseLeave; // + // BottomFMTabsEmptyMessageLabel + // + BottomFMTabsEmptyMessageLabel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + BottomFMTabsEmptyMessageLabel.Size = new Size(533, 357); + BottomFMTabsEmptyMessageLabel.TextAlign = ContentAlignment.MiddleCenter; + BottomFMTabsEmptyMessageLabel.PaintCustom += FMTabsEmptyMessageLabels_Paint; + // + // BottomFMTabsMenuButton + // + BottomFMTabsMenuButton.Anchor = AnchorStyles.Top | AnchorStyles.Right; + BottomFMTabsMenuButton.FlatAppearance.BorderSize = 0; + BottomFMTabsMenuButton.FlatStyle = FlatStyle.Flat; + BottomFMTabsMenuButton.Location = new Point(533, 0); + BottomFMTabsMenuButton.Size = new Size(18, 20); + BottomFMTabsMenuButton.TabIndex = 1; + BottomFMTabsMenuButton.PaintCustom += FMTabsMenuButton_Paint; + BottomFMTabsMenuButton.Click += LowerFMTabsMenuButton_Click; + // + // BottomFMTabsCollapseButton + // + BottomFMTabsCollapseButton.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right; + BottomFMTabsCollapseButton.ArrowDirection = Direction.Right; + BottomFMTabsCollapseButton.FlatAppearance.BorderSize = 0; + BottomFMTabsCollapseButton.FlatStyle = FlatStyle.Flat; + BottomFMTabsCollapseButton.Location = new Point(533, 20); + BottomFMTabsCollapseButton.Size = new Size(18, 337); + BottomFMTabsCollapseButton.TabIndex = 2; + BottomFMTabsCollapseButton.Click += LowerFMTabsCollapseButton_Click; + // // MainForm // AutoScaleDimensions = new SizeF(96F, 96F); @@ -668,6 +713,7 @@ void SetReadmeButton(DarkButton button, int x, int tabIndex) RefreshAreaToolStrip.PerformLayout(); TopFMTabControl.ResumeLayout(false); LowerSplitContainer.Panel1.ResumeLayout(false); + LowerSplitContainer.Panel2.ResumeLayout(false); ((ISupportInitialize)LowerSplitContainer).EndInit(); LowerSplitContainer.ResumeLayout(false); ResumeLayout(false); diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index 9a61969ba..79641a8d9 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -376,6 +376,9 @@ FMsFinished_Single_AfterNumber= FM finished FMsFinished_Plural_BeforeNumber= FMsFinished_Plural_AfterNumber= FMs finished +[FMTabs] +EmptyTabAreaMessage=Drag a tab here, or right-click to add a tab. + [StatisticsTab] TabText=Statistics From 06abf118c08c5732e8357bde5177001516ef6c1e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 21:51:55 -0800 Subject: [PATCH 174/200] Fullscreen readme now collapses bottom-right panel --- AngelLoader/Forms/MainForm.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index a26e50b5d..475fc189e 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -4326,13 +4326,8 @@ private void ReadmeButtons_Click(object sender, EventArgs e) { if (sender == ReadmeFullScreenButton) { - /* - @DockUI(readme fullscreen): This needs the always-show-collapse-button-for-both-panels thing to really work - Because of toggling collapsed state of lower splitter panel 2. - We could store the previous collapsed state, but we want to get rid of the auto-collapse-on-no-tabs - anyway, because it's kind of not super great UX. - */ MainSplitContainer.ToggleFullScreen(); + LowerSplitContainer.Panel2Collapsed = MainSplitContainer.FullScreen; ShowReadmeControls(CursorOverReadmeArea()); } else if (sender == ReadmeEncodingButton) From 31b063f9c560df25c291ce3a2823888102cdbdd2 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 22:15:03 -0800 Subject: [PATCH 175/200] Patch tab now scales well with resizing Instead of the old "everything stays small lol" thing --- .../TopRightPages/Lazy_PatchPage.Designer.cs | 72 +++++++++++++------ .../Lazy_PatchPage_InitSlim.Generated.cs | 64 +++++++++++------ 2 files changed, 92 insertions(+), 44 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_PatchPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_PatchPage.Designer.cs index 770ecf2e2..d4924c90d 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_PatchPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_PatchPage.Designer.cs @@ -37,13 +37,15 @@ private void InitializeComponent() this.Patch_NewMantle_CheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); this.PatchMainPanel = new AngelLoader.Forms.CustomControls.DrawnPanel(); this.PatchDMLsPanel = new AngelLoader.Forms.CustomControls.DrawnPanel(); + this.AddRemoveDMLButtonsFLP = new AngelLoader.Forms.CustomControls.DarkFlowLayoutPanel(); + this.PatchAddDMLButton = new AngelLoader.Forms.CustomControls.DarkButton(); + this.PatchRemoveDMLButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.PatchDMLPatchesLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.PatchDMLsListBox = new AngelLoader.Forms.CustomControls.DarkListBox(); - this.PatchRemoveDMLButton = new AngelLoader.Forms.CustomControls.DarkButton(); - this.PatchAddDMLButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.PatchOpenFMFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.PatchMainPanel.SuspendLayout(); this.PatchDMLsPanel.SuspendLayout(); + this.AddRemoveDMLButtonsFLP.SuspendLayout(); this.SuspendLayout(); // // Patch_PerFMValues_Label @@ -93,28 +95,59 @@ private void InitializeComponent() // // PatchMainPanel // - this.PatchMainPanel.AutoSize = true; + this.PatchMainPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.PatchMainPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.PatchMainPanel.Controls.Add(this.PatchDMLsPanel); this.PatchMainPanel.Controls.Add(this.PatchOpenFMFolderButton); this.PatchMainPanel.Location = new System.Drawing.Point(0, 104); this.PatchMainPanel.Name = "PatchMainPanel"; - this.PatchMainPanel.Size = new System.Drawing.Size(307, 250); + this.PatchMainPanel.Size = new System.Drawing.Size(527, 250); this.PatchMainPanel.TabIndex = 43; // // PatchDMLsPanel // - this.PatchDMLsPanel.AutoSize = true; + this.PatchDMLsPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.PatchDMLsPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.PatchDMLsPanel.Controls.Add(this.AddRemoveDMLButtonsFLP); this.PatchDMLsPanel.Controls.Add(this.PatchDMLPatchesLabel); this.PatchDMLsPanel.Controls.Add(this.PatchDMLsListBox); - this.PatchDMLsPanel.Controls.Add(this.PatchRemoveDMLButton); - this.PatchDMLsPanel.Controls.Add(this.PatchAddDMLButton); this.PatchDMLsPanel.Location = new System.Drawing.Point(-2, 0); this.PatchDMLsPanel.Name = "PatchDMLsPanel"; - this.PatchDMLsPanel.Size = new System.Drawing.Size(306, 218); + this.PatchDMLsPanel.Size = new System.Drawing.Size(527, 218); this.PatchDMLsPanel.TabIndex = 39; // + // AddRemoveDMLButtonsFLP + // + this.AddRemoveDMLButtonsFLP.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.AddRemoveDMLButtonsFLP.Controls.Add(this.PatchAddDMLButton); + this.AddRemoveDMLButtonsFLP.Controls.Add(this.PatchRemoveDMLButton); + this.AddRemoveDMLButtonsFLP.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft; + this.AddRemoveDMLButtonsFLP.Location = new System.Drawing.Point(6, 193); + this.AddRemoveDMLButtonsFLP.Name = "AddRemoveDMLButtonsFLP"; + this.AddRemoveDMLButtonsFLP.Size = new System.Drawing.Size(519, 24); + this.AddRemoveDMLButtonsFLP.TabIndex = 44; + // + // PatchAddDMLButton + // + this.PatchAddDMLButton.Location = new System.Drawing.Point(496, 0); + this.PatchAddDMLButton.Margin = new System.Windows.Forms.Padding(1, 0, 0, 0); + this.PatchAddDMLButton.Name = "PatchAddDMLButton"; + this.PatchAddDMLButton.Size = new System.Drawing.Size(23, 23); + this.PatchAddDMLButton.TabIndex = 43; + // + // PatchRemoveDMLButton + // + this.PatchRemoveDMLButton.Location = new System.Drawing.Point(472, 0); + this.PatchRemoveDMLButton.Margin = new System.Windows.Forms.Padding(1, 0, 0, 0); + this.PatchRemoveDMLButton.Name = "PatchRemoveDMLButton"; + this.PatchRemoveDMLButton.Size = new System.Drawing.Size(23, 23); + this.PatchRemoveDMLButton.TabIndex = 42; + // // PatchDMLPatchesLabel // this.PatchDMLPatchesLabel.AutoSize = true; @@ -126,28 +159,18 @@ private void InitializeComponent() // // PatchDMLsListBox // + this.PatchDMLsListBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.PatchDMLsListBox.Location = new System.Drawing.Point(6, 24); this.PatchDMLsListBox.MultiSelect = false; this.PatchDMLsListBox.Name = "PatchDMLsListBox"; - this.PatchDMLsListBox.Size = new System.Drawing.Size(296, 168); + this.PatchDMLsListBox.Size = new System.Drawing.Size(518, 168); this.PatchDMLsListBox.TabIndex = 41; // - // PatchRemoveDMLButton - // - this.PatchRemoveDMLButton.Location = new System.Drawing.Point(256, 192); - this.PatchRemoveDMLButton.Name = "PatchRemoveDMLButton"; - this.PatchRemoveDMLButton.Size = new System.Drawing.Size(23, 23); - this.PatchRemoveDMLButton.TabIndex = 42; - // - // PatchAddDMLButton - // - this.PatchAddDMLButton.Location = new System.Drawing.Point(280, 192); - this.PatchAddDMLButton.Name = "PatchAddDMLButton"; - this.PatchAddDMLButton.Size = new System.Drawing.Size(23, 23); - this.PatchAddDMLButton.TabIndex = 43; - // // PatchOpenFMFolderButton // + this.PatchOpenFMFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.PatchOpenFMFolderButton.AutoSize = true; this.PatchOpenFMFolderButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.PatchOpenFMFolderButton.Location = new System.Drawing.Point(5, 224); @@ -162,6 +185,7 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; + this.AutoScrollMinSize = new System.Drawing.Size(200, 300); this.Controls.Add(this.Patch_PerFMValues_Label); this.Controls.Add(this.Patch_NDSubs_CheckBox); this.Controls.Add(this.Patch_PostProc_CheckBox); @@ -173,6 +197,7 @@ private void InitializeComponent() this.PatchMainPanel.PerformLayout(); this.PatchDMLsPanel.ResumeLayout(false); this.PatchDMLsPanel.PerformLayout(); + this.AddRemoveDMLButtonsFLP.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); @@ -192,4 +217,5 @@ private void InitializeComponent() internal DarkButton PatchRemoveDMLButton; internal DarkButton PatchAddDMLButton; internal DarkButton PatchOpenFMFolderButton; + internal DarkFlowLayoutPanel AddRemoveDMLButtonsFLP; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_PatchPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_PatchPage_InitSlim.Generated.cs index f40028850..e6a102acb 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_PatchPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_PatchPage_InitSlim.Generated.cs @@ -13,13 +13,15 @@ private void InitSlim() this.Patch_NewMantle_CheckBox = new AngelLoader.Forms.CustomControls.DarkCheckBox(); this.PatchMainPanel = new AngelLoader.Forms.CustomControls.DrawnPanel(); this.PatchDMLsPanel = new AngelLoader.Forms.CustomControls.DrawnPanel(); + this.AddRemoveDMLButtonsFLP = new AngelLoader.Forms.CustomControls.DarkFlowLayoutPanel(); + this.PatchAddDMLButton = new AngelLoader.Forms.CustomControls.DarkButton(); + this.PatchRemoveDMLButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.PatchDMLPatchesLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.PatchDMLsListBox = new AngelLoader.Forms.CustomControls.DarkListBox(); - this.PatchRemoveDMLButton = new AngelLoader.Forms.CustomControls.DarkButton(); - this.PatchAddDMLButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.PatchOpenFMFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.PatchMainPanel.SuspendLayout(); this.PatchDMLsPanel.SuspendLayout(); + this.AddRemoveDMLButtonsFLP.SuspendLayout(); this.SuspendLayout(); // // Patch_PerFMValues_Label @@ -56,52 +58,70 @@ private void InitSlim() // // PatchMainPanel // - this.PatchMainPanel.AutoSize = true; + this.PatchMainPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.PatchMainPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.PatchMainPanel.Controls.Add(this.PatchDMLsPanel); this.PatchMainPanel.Controls.Add(this.PatchOpenFMFolderButton); this.PatchMainPanel.Location = new System.Drawing.Point(0, 104); - this.PatchMainPanel.Size = new System.Drawing.Size(307, 250); + this.PatchMainPanel.Size = new System.Drawing.Size(527, 250); this.PatchMainPanel.TabIndex = 43; // // PatchDMLsPanel // - this.PatchDMLsPanel.AutoSize = true; + this.PatchDMLsPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.PatchDMLsPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.PatchDMLsPanel.Controls.Add(this.AddRemoveDMLButtonsFLP); this.PatchDMLsPanel.Controls.Add(this.PatchDMLPatchesLabel); this.PatchDMLsPanel.Controls.Add(this.PatchDMLsListBox); - this.PatchDMLsPanel.Controls.Add(this.PatchRemoveDMLButton); - this.PatchDMLsPanel.Controls.Add(this.PatchAddDMLButton); this.PatchDMLsPanel.Location = new System.Drawing.Point(-2, 0); - this.PatchDMLsPanel.Size = new System.Drawing.Size(306, 218); + this.PatchDMLsPanel.Size = new System.Drawing.Size(527, 218); this.PatchDMLsPanel.TabIndex = 39; // - // PatchDMLPatchesLabel + // AddRemoveDMLButtonsFLP // - this.PatchDMLPatchesLabel.AutoSize = true; - this.PatchDMLPatchesLabel.Location = new System.Drawing.Point(6, 8); + this.AddRemoveDMLButtonsFLP.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.AddRemoveDMLButtonsFLP.Controls.Add(this.PatchAddDMLButton); + this.AddRemoveDMLButtonsFLP.Controls.Add(this.PatchRemoveDMLButton); + this.AddRemoveDMLButtonsFLP.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft; + this.AddRemoveDMLButtonsFLP.Location = new System.Drawing.Point(6, 193); + this.AddRemoveDMLButtonsFLP.Size = new System.Drawing.Size(519, 24); + this.AddRemoveDMLButtonsFLP.TabIndex = 44; // - // PatchDMLsListBox + // PatchAddDMLButton // - this.PatchDMLsListBox.Location = new System.Drawing.Point(6, 24); - this.PatchDMLsListBox.MultiSelect = false; - this.PatchDMLsListBox.Size = new System.Drawing.Size(296, 168); - this.PatchDMLsListBox.TabIndex = 41; + this.PatchAddDMLButton.Margin = new System.Windows.Forms.Padding(1, 0, 0, 0); + this.PatchAddDMLButton.Size = new System.Drawing.Size(23, 23); + this.PatchAddDMLButton.TabIndex = 43; // // PatchRemoveDMLButton // - this.PatchRemoveDMLButton.Location = new System.Drawing.Point(256, 192); + this.PatchRemoveDMLButton.Margin = new System.Windows.Forms.Padding(1, 0, 0, 0); this.PatchRemoveDMLButton.Size = new System.Drawing.Size(23, 23); this.PatchRemoveDMLButton.TabIndex = 42; // - // PatchAddDMLButton + // PatchDMLPatchesLabel // - this.PatchAddDMLButton.Location = new System.Drawing.Point(280, 192); - this.PatchAddDMLButton.Size = new System.Drawing.Size(23, 23); - this.PatchAddDMLButton.TabIndex = 43; + this.PatchDMLPatchesLabel.AutoSize = true; + this.PatchDMLPatchesLabel.Location = new System.Drawing.Point(6, 8); + // + // PatchDMLsListBox + // + this.PatchDMLsListBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.PatchDMLsListBox.Location = new System.Drawing.Point(6, 24); + this.PatchDMLsListBox.MultiSelect = false; + this.PatchDMLsListBox.Size = new System.Drawing.Size(518, 168); + this.PatchDMLsListBox.TabIndex = 41; // // PatchOpenFMFolderButton // + this.PatchOpenFMFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.PatchOpenFMFolderButton.AutoSize = true; this.PatchOpenFMFolderButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.PatchOpenFMFolderButton.Location = new System.Drawing.Point(5, 224); @@ -113,6 +133,7 @@ private void InitSlim() this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; + this.AutoScrollMinSize = new System.Drawing.Size(200, 300); this.Controls.Add(this.Patch_PerFMValues_Label); this.Controls.Add(this.Patch_NDSubs_CheckBox); this.Controls.Add(this.Patch_PostProc_CheckBox); @@ -123,6 +144,7 @@ private void InitSlim() this.PatchMainPanel.PerformLayout(); this.PatchDMLsPanel.ResumeLayout(false); this.PatchDMLsPanel.PerformLayout(); + this.AddRemoveDMLButtonsFLP.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); } From 1e023bf9f09dc23ba0ff22119c4e260a270ba88c Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 22:45:04 -0800 Subject: [PATCH 176/200] Expand tab panels when a tab is shown via the menu --- AngelLoader/Forms/MainForm.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 475fc189e..cb5e8e064 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -3385,13 +3385,22 @@ tab order gets messed up. */ if (s.Checked) { - // @DockUI: Expand tab panels when a tab is shown via the menu HideFMTab(tabControl == TopFMTabControl ? WhichTabControl.Bottom : WhichTabControl.Top, tab); ShowFMTab(tabControl == TopFMTabControl ? WhichTabControl.Top : WhichTabControl.Bottom, tab); if (tab is Lazy_TabsBase lazyTab) { lazyTab.Construct(); } + + (DarkSplitContainerCustom splitter, WhichTabControl which) = tabControl == TopFMTabControl + ? (TopSplitContainer, WhichTabControl.Top) + : (LowerSplitContainer, WhichTabControl.Bottom); + + if (splitter.FullScreen) + { + splitter.ToggleFullScreen(); + SetFMTabsCollapsedState(which, false); + } } else { From 333acea606a0b7b1b61f600753be518d16eb89cc Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 22:50:57 -0800 Subject: [PATCH 177/200] Address todos and cleanup --- .../LazyLoaded/Lazy_FMTabsBlocker.cs | 4 +--- AngelLoader/Forms/MainForm.cs | 23 +------------------ 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs index 6e592e935..5fa4a9b99 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs @@ -63,9 +63,7 @@ private void Construct() Location = Point.Empty, Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom, Size = new Size( - // @DockUI: Button widths are the same so this works for now, but make it better - // Maybe once we lazy-load the top control, we can have a global constant for width - container.Width - _owner.TopFMTabsCollapseButton.Width, + container.Width - _owner.BottomFMTabsCollapseButton.Width, container.Height), DarkModeDrawnBackColor = DarkColors.Fen_ControlBackground, diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index cb5e8e064..2c4bc6f86 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -41,7 +41,6 @@ behavior that comes part and parcel with what should be a simple #$@!ing propert using System; using System.Collections.Generic; using System.ComponentModel; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Globalization; @@ -1055,8 +1054,7 @@ logic as it is. if (!Config.HideWebSearchButton) ShowWebSearchButton(true); TopSplitContainer.CollapsedSize = TopFMTabsCollapseButton.Width; - // @DockUI: Button widths are the same so this works for now, but make it better - LowerSplitContainer.CollapsedSize = TopFMTabsCollapseButton.Width; + LowerSplitContainer.CollapsedSize = BottomFMTabsCollapseButton.Width; if (Config.TopFMTabsPanelCollapsed) { @@ -5550,11 +5548,6 @@ public void RefreshCurrentFMScreenshots() #region Tab dragging - /* - @DockUI: Working/testing code, finalize before release - @DockUI: Remove Trace.WriteLines - */ - private bool _inTabDragArea; private TabControlImageCursor? _imageCursor; @@ -5595,7 +5588,6 @@ private void HandleTabDrag(WhichTabControl dest) if (!_inTabDragArea) { _inTabDragArea = true; - Trace.WriteLine("Hit collapsed"); using var gc = new Native.GraphicsContext(sc.Handle); using var b = new SolidBrush(GetOverlayColor()); int splitterDistance = sc.SplitterDistanceLogical; @@ -5613,7 +5605,6 @@ private void HandleTabDrag(WhichTabControl dest) if (!_inTabDragArea) { _inTabDragArea = true; - Trace.WriteLine("Hit open"); using var gc = new Native.GraphicsContext(sc.Panel2.Handle); using var b = new SolidBrush(GetOverlayColor()); gc.G.FillRectangle(b, sc.Panel2.ClientRectangle with { X = 0, Y = 0 }); @@ -5622,7 +5613,6 @@ private void HandleTabDrag(WhichTabControl dest) else if (_inTabDragArea) { _inTabDragArea = false; - Trace.WriteLine("Miss"); sc.Refresh(); } } @@ -5741,17 +5731,6 @@ private static Color GetOverlayColor() blue: DarkColors.BlueSelection.B); } - // @DockUI: Test code, remove for final release - internal void PrintBackingTabs() - { - Trace.WriteLine("========================="); - for (int i = 0; i < _backingFMTabs.Count; i++) - { - BackingTab backingTab = _backingFMTabs[i]; - Trace.WriteLine(i.ToStrInv() + ": Tab: " + backingTab.TabPage.Text + ", VisibleIn: " + backingTab.VisibleIn); - } - } - #endregion // @DockUI: Lazy-load the empty message labels From a91cf641b1161b17f84225a60be88f39a267595d Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 22:57:22 -0800 Subject: [PATCH 178/200] Default bottom tabs panel collapsed to true --- AngelLoader/Common/DataClasses/ConfigData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AngelLoader/Common/DataClasses/ConfigData.cs b/AngelLoader/Common/DataClasses/ConfigData.cs index 9110c8aa2..7d18ca576 100644 --- a/AngelLoader/Common/DataClasses/ConfigData.cs +++ b/AngelLoader/Common/DataClasses/ConfigData.cs @@ -348,7 +348,7 @@ internal float FMsListFontSizeInPoints internal float LowerSplitterPercent { get => _lowerSplitterPercent; set => _lowerSplitterPercent = value.ClampZeroToOne(); } internal bool TopFMTabsPanelCollapsed; - internal bool BottomFMTabsPanelCollapsed; + internal bool BottomFMTabsPanelCollapsed = true; internal readonly FMTabsData FMTabsData = new(); From 6a15423cc4ab5b83e4fc3140d5f097d8fc8add8b Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 23:12:36 -0800 Subject: [PATCH 179/200] Lower splitter can now all the way to the left (min size 0) --- AngelLoader/Forms/MainForm.Designer.cs | 1 + AngelLoader/Forms/MainForm_InitManual.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index a8b5ced89..71a639bbf 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -1017,6 +1017,7 @@ private void InitializeComponent() this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeResetZoomButton); this.LowerSplitContainer.Panel1.Controls.Add(this.ChooseReadmeComboBox); this.LowerSplitContainer.Panel1.Controls.Add(this.ReadmeRichTextBox); + this.LowerSplitContainer.Panel1MinSize = 0; // // LowerSplitContainer.Panel2 // diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index c13a3a6b3..d9138ce21 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -591,6 +591,7 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir LowerSplitContainer.Panel1.Controls.Add(ReadmeResetZoomButton); LowerSplitContainer.Panel1.Controls.Add(ChooseReadmeComboBox); LowerSplitContainer.Panel1.Controls.Add(ReadmeRichTextBox); + LowerSplitContainer.Panel1MinSize = 0; // // LowerSplitContainer.Panel2 // From 5678ea39cd9f3f0b4af2e131d4607f765b75bbb8 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 23:16:07 -0800 Subject: [PATCH 180/200] Screenshot copy is now right-click only --- AngelLoader/Common/DataClasses/LocalizationData.cs | 2 +- .../CustomControls/TopRightPages/ScreenshotsTabPage.cs | 8 +++++++- AngelLoader/Languages/English.ini | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 8f2789f10..7ee18e4d2 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -636,7 +636,7 @@ internal sealed class ModsTab_Class internal sealed class ScreenshotsTab_Class { internal readonly string TabText = "Screenshots"; - internal readonly string CopyScreenshotToolTip = "Click to copy"; + internal readonly string CopyScreenshotToolTip = "Right-click to copy"; internal readonly string Gamma = "Gamma:"; internal readonly string ScreenshotsFolderNotFound = "Screenshots folder not found."; internal readonly string ScreenshotsFolderOpenError = "There was an error trying to open the screenshots folder."; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 305c1c636..946683268 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -246,7 +246,13 @@ protected override void OnVisibleChanged(EventArgs e) } } - private void ScreenshotsPictureBox_MouseClick(object sender, MouseEventArgs e) => CopyImageToClipboard(); + private void ScreenshotsPictureBox_MouseClick(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Right) + { + CopyImageToClipboard(); + } + } private void OpenScreenshotsFolderButton_Click(object sender, EventArgs e) { diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index 79641a8d9..feb6d94db 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -492,7 +492,7 @@ Generic_ModsNotSupported=Mod management is not supported for unknown FMs. [ScreenshotsTab] TabText=Screenshots -CopyScreenshotToolTip=Click to copy +CopyScreenshotToolTip=Right-click to copy Gamma=Gamma: ScreenshotsFolderNotFound=Screenshots folder not found. ScreenshotsFolderOpenError=There was an error trying to open the screenshots folder. From 731673a9a45b482bc6eb4a030f0dc293d40bdd14 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Tue, 5 Mar 2024 23:48:49 -0800 Subject: [PATCH 181/200] Rename --- AngelLoader/Forms/MainForm.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 2c4bc6f86..0cf17e9ed 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5549,7 +5549,7 @@ public void RefreshCurrentFMScreenshots() #region Tab dragging private bool _inTabDragArea; - private TabControlImageCursor? _imageCursor; + private TabControlImageCursor? _tabControlImageCursor; private void TopFMTabControl_MouseDragCustom(object sender, MouseEventArgs e) { @@ -5578,8 +5578,8 @@ private void HandleTabDrag(WhichTabControl dest) ? (TopFMTabControl, LowerSplitContainer) : (Lazy_LowerTabControl.TabControl, TopSplitContainer); - _imageCursor ??= new TabControlImageCursor(tabControl); - Cursor = _imageCursor.Cursor; + _tabControlImageCursor ??= new TabControlImageCursor(tabControl); + Cursor = _tabControlImageCursor.Cursor; Point cp = Native.GetCursorPosition_Fast(); @@ -5717,8 +5717,8 @@ internal void HideFMTab(WhichTabControl which, TabPage tabPage) private void DestroyImageCursor() { Cursor = Cursors.Default; - _imageCursor?.Dispose(); - _imageCursor = null; + _tabControlImageCursor?.Dispose(); + _tabControlImageCursor = null; } private static Color GetOverlayColor() From 4bfb41e3f07b750b3c992a76e0ddbe6c87556ffb Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 09:05:39 -0800 Subject: [PATCH 182/200] Lazy-load empty tab message labels --- .../Lazy_EmptyTabAreaMessageLabel.cs | 110 ++++++++ .../LazyLoaded/Lazy_FMTabsBlocker.cs | 7 +- .../LazyLoaded/Lazy_LowerTabControl.cs | 5 +- AngelLoader/Forms/MainForm.Designer.cs | 32 --- AngelLoader/Forms/MainForm.cs | 39 ++- AngelLoader/Forms/MainForm.resx | 247 +++++++++--------- AngelLoader/Forms/MainForm_InitManual.cs | 18 -- 7 files changed, 259 insertions(+), 199 deletions(-) create mode 100644 AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_EmptyTabAreaMessageLabel.cs diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_EmptyTabAreaMessageLabel.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_EmptyTabAreaMessageLabel.cs new file mode 100644 index 000000000..292ba3fcc --- /dev/null +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_EmptyTabAreaMessageLabel.cs @@ -0,0 +1,110 @@ +using System.Diagnostics; +using System.Drawing; +using System.Windows.Forms; +using AngelLoader.DataClasses; +using JetBrains.Annotations; + +namespace AngelLoader.Forms.CustomControls.LazyLoaded; + +internal sealed class Lazy_EmptyTabAreaMessageLabel : IDarkable +{ + private readonly MainForm _owner; + + private bool _constructed; + + private WhichTabControl _which; + + private string _text = ""; + + private DarkLabel Label = null!; + + private bool _darkModeEnabled; + [PublicAPI] + public bool DarkModeEnabled + { + set + { + if (_darkModeEnabled == value) return; + _darkModeEnabled = value; + if (!_constructed) return; + + Label.DarkModeEnabled = value; + } + } + + public Lazy_EmptyTabAreaMessageLabel(MainForm owner) => _owner = owner; + + internal void SetWhich(WhichTabControl which) => _which = which; + + internal void SetText(string text) + { + if (_constructed) + { + Label.Text = text; + } + else + { + _text = text; + } + } + + private void Construct() + { + if (_constructed) return; + + var container = + _which == WhichTabControl.Bottom + ? _owner.LowerSplitContainer.Panel2 + : _owner.TopSplitContainer.Panel2; + + var collapseButton = + _which == WhichTabControl.Bottom + ? _owner.BottomFMTabsCollapseButton + : _owner.TopFMTabsCollapseButton; + + Label = new DarkLabel + { + Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, + Size = new Size( + container.Width - collapseButton.Width, + container.Height), + TextAlign = ContentAlignment.MiddleCenter, + + DarkModeEnabled = _darkModeEnabled + }; + + Label.PaintCustom += FMTabsEmptyMessageLabels_Paint; + Label.MouseClick += _which == WhichTabControl.Bottom + ? _owner.LowerFMTabsBar_MouseClick + : _owner.TopFMTabsBar_MouseClick; + + container.Controls.Add(Label); + + _constructed = true; + + SetText(_text); + } + + private void FMTabsEmptyMessageLabels_Paint(object sender, PaintEventArgs e) + { + DarkLabel label = Label; + e.Graphics.DrawRectangle( + _darkModeEnabled ? DarkColors.LighterBackgroundPen : SystemPens.ControlLight, + new Rectangle(0, 0, label.ClientRectangle.Width - 1, label.ClientRectangle.Height - 1)); + } + + internal void Show(bool show) + { + if (show) + { + Trace.WriteLine(_which); + Construct(); + Label.BringToFront(); + Label.Show(); + } + else + { + if (_constructed) Label.Hide(); + } + } +} diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs index 5fa4a9b99..98f8f778e 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs @@ -58,12 +58,17 @@ private void Construct() ? _owner.LowerSplitContainer.Panel2 : _owner.TopSplitContainer.Panel2; + var collapseButton = + _which == WhichTabControl.Bottom + ? _owner.BottomFMTabsCollapseButton + : _owner.TopFMTabsCollapseButton; + Panel = new DrawnPanel { Location = Point.Empty, Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom, Size = new Size( - container.Width - _owner.BottomFMTabsCollapseButton.Width, + container.Width - collapseButton.Width, container.Height), DarkModeDrawnBackColor = DarkColors.Fen_ControlBackground, diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 3273eb248..50faa3597 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -4,6 +4,8 @@ namespace AngelLoader.Forms.CustomControls.LazyLoaded; +// @DockUI: This is always constructed - make it unloaded until panel un-fullscreened + internal sealed class Lazy_LowerTabControl : IDarkable { internal bool Constructed { get; private set; } @@ -66,7 +68,6 @@ internal void Construct() _tabControl.MouseClick += _owner.LowerFMTabsBar_MouseClick; container.MouseClick += _owner.LowerFMTabsBar_MouseClick; - _owner.BottomFMTabsEmptyMessageLabel.MouseClick += _owner.LowerFMTabsBar_MouseClick; _tabControl.Selected += TabControl_Selected; _tabControl.MouseDragCustom += _owner.Lazy_LowerTabControl_MouseDragCustom; @@ -75,6 +76,8 @@ internal void Construct() container.Controls.Add(_tabControl); + _owner.Lazy_BottomFMTabsEmptyMessageLabel.Show(true); + _tabControl.Enabled = _enabled; Constructed = true; diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 71a639bbf..609608e6f 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -110,7 +110,6 @@ private void InitializeComponent() this.PatchTabPage = new AngelLoader.Forms.CustomControls.PatchTabPage(); this.ModsTabPage = new AngelLoader.Forms.CustomControls.ModsTabPage(); this.ScreenshotsTabPage = new AngelLoader.Forms.CustomControls.ScreenshotsTabPage(); - this.TopFMTabsEmptyMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.LowerSplitContainer = new AngelLoader.Forms.CustomControls.DarkSplitContainerCustom(); this.ReadmeEncodingButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ReadmeFullScreenButton = new AngelLoader.Forms.CustomControls.DarkButton(); @@ -119,7 +118,6 @@ private void InitializeComponent() this.ReadmeResetZoomButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ChooseReadmeComboBox = new AngelLoader.Forms.CustomControls.DarkComboBoxWithBackingItems(); this.ReadmeRichTextBox = new AngelLoader.Forms.CustomControls.RichTextBoxCustom(); - this.BottomFMTabsEmptyMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.BottomFMTabsMenuButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.BottomFMTabsCollapseButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.MainToolTip = new AngelLoader.Forms.CustomControls.ToolTipCustom(this.components); @@ -302,7 +300,6 @@ private void InitializeComponent() this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabsMenuButton); this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabsCollapseButton); this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabControl); - this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabsEmptyMessageLabel); this.TopSplitContainer.Size = new System.Drawing.Size(1671, 309); this.TopSplitContainer.SplitterDistance = 1116; this.TopSplitContainer.TabIndex = 0; @@ -984,19 +981,6 @@ private void InitializeComponent() this.ScreenshotsTabPage.TabIndex = 5; this.ScreenshotsTabPage.Text = "Screenshots"; // - // TopFMTabsEmptyMessageLabel - // - this.TopFMTabsEmptyMessageLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.TopFMTabsEmptyMessageLabel.Location = new System.Drawing.Point(0, 0); - this.TopFMTabsEmptyMessageLabel.Name = "TopFMTabsEmptyMessageLabel"; - this.TopFMTabsEmptyMessageLabel.Size = new System.Drawing.Size(533, 309); - this.TopFMTabsEmptyMessageLabel.TabIndex = 16; - this.TopFMTabsEmptyMessageLabel.Text = "[empty message]"; - this.TopFMTabsEmptyMessageLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - this.TopFMTabsEmptyMessageLabel.PaintCustom += new System.EventHandler(this.FMTabsEmptyMessageLabels_Paint); - // // LowerSplitContainer // this.LowerSplitContainer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) @@ -1022,7 +1006,6 @@ private void InitializeComponent() // LowerSplitContainer.Panel2 // this.LowerSplitContainer.Panel2.BackColor = System.Drawing.SystemColors.Control; - this.LowerSplitContainer.Panel2.Controls.Add(this.BottomFMTabsEmptyMessageLabel); this.LowerSplitContainer.Panel2.Controls.Add(this.BottomFMTabsMenuButton); this.LowerSplitContainer.Panel2.Controls.Add(this.BottomFMTabsCollapseButton); this.LowerSplitContainer.Size = new System.Drawing.Size(1671, 357); @@ -1141,19 +1124,6 @@ private void InitializeComponent() this.ReadmeRichTextBox.Text = ""; this.ReadmeRichTextBox.MouseLeave += new System.EventHandler(this.ReadmeArea_MouseLeave); // - // BottomFMTabsEmptyMessageLabel - // - this.BottomFMTabsEmptyMessageLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.BottomFMTabsEmptyMessageLabel.Location = new System.Drawing.Point(0, 0); - this.BottomFMTabsEmptyMessageLabel.Name = "BottomFMTabsEmptyMessageLabel"; - this.BottomFMTabsEmptyMessageLabel.Size = new System.Drawing.Size(533, 357); - this.BottomFMTabsEmptyMessageLabel.TabIndex = 17; - this.BottomFMTabsEmptyMessageLabel.Text = "[empty message]"; - this.BottomFMTabsEmptyMessageLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - this.BottomFMTabsEmptyMessageLabel.PaintCustom += new System.EventHandler(this.FMTabsEmptyMessageLabels_Paint); - // // BottomFMTabsMenuButton // this.BottomFMTabsMenuButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); @@ -1337,11 +1307,9 @@ private void InitializeComponent() internal CustomControls.DarkButton TopFMTabsMenuButton; internal CustomControls.DarkArrowButton TopFMTabsCollapseButton; - internal CustomControls.DarkLabel TopFMTabsEmptyMessageLabel; internal CustomControls.DarkButton BottomFMTabsMenuButton; internal CustomControls.DarkArrowButton BottomFMTabsCollapseButton; - internal CustomControls.DarkLabel BottomFMTabsEmptyMessageLabel; #endregion diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 0cf17e9ed..053a8c09b 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -186,6 +186,8 @@ private enum ZoomFMsDGVType private readonly Lazy_FMTabsBlocker Lazy_BottomFMTabsBlocker; internal readonly Lazy_UpdateNotification Lazy_UpdateNotification; private readonly Lazy_LowerTabControl Lazy_LowerTabControl; + private readonly Lazy_EmptyTabAreaMessageLabel Lazy_TopFMTabsEmptyMessageLabel; + internal readonly Lazy_EmptyTabAreaMessageLabel Lazy_BottomFMTabsEmptyMessageLabel; #endregion @@ -586,10 +588,14 @@ but whatever... Lazy_TopFMTabsBlocker = new Lazy_FMTabsBlocker(this), Lazy_BottomFMTabsBlocker = new Lazy_FMTabsBlocker(this), Lazy_UpdateNotification = new Lazy_UpdateNotification(this), - Lazy_LowerTabControl = new Lazy_LowerTabControl(this) + Lazy_LowerTabControl = new Lazy_LowerTabControl(this), + Lazy_TopFMTabsEmptyMessageLabel = new Lazy_EmptyTabAreaMessageLabel(this), + Lazy_BottomFMTabsEmptyMessageLabel = new Lazy_EmptyTabAreaMessageLabel(this) }; Lazy_TopFMTabsBlocker.SetWhich(WhichTabControl.Top); Lazy_BottomFMTabsBlocker.SetWhich(WhichTabControl.Bottom); + Lazy_TopFMTabsEmptyMessageLabel.SetWhich(WhichTabControl.Top); + Lazy_BottomFMTabsEmptyMessageLabel.SetWhich(WhichTabControl.Bottom); #endregion @@ -671,9 +677,6 @@ and does NOT have its text transferred over. It ends up with blank text. // For right-clicking on blank space in tab bar TopSplitContainer.Panel2.MouseClick += TopFMTabsBar_MouseClick; - // For right-clicking on the tab area when no tabs are present - TopFMTabsEmptyMessageLabel.MouseClick += TopFMTabsBar_MouseClick; - #region Construct + init non-public-release controls #if DEBUG || (Release_Testing && !RT_StartupOnly) @@ -1881,8 +1884,8 @@ private void Localize(bool startup) Lazy_FMTabsMenu.Localize(); - TopFMTabsEmptyMessageLabel.Text = LText.FMTabs.EmptyTabAreaMessage; - BottomFMTabsEmptyMessageLabel.Text = LText.FMTabs.EmptyTabAreaMessage; + Lazy_TopFMTabsEmptyMessageLabel.SetText(LText.FMTabs.EmptyTabAreaMessage); + Lazy_BottomFMTabsEmptyMessageLabel.SetText(LText.FMTabs.EmptyTabAreaMessage); StatisticsTabPage.Text = LText.StatisticsTab.TabText; EditFMTabPage.Text = LText.EditFMTab.TabText; @@ -5502,7 +5505,7 @@ private void MainSplitContainer_FullScreenChanged(object sender, EventArgs e) } } - private void TopFMTabsBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Top); + internal void TopFMTabsBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Top); internal void LowerFMTabsBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Bottom); @@ -5689,28 +5692,27 @@ internal void ShowFMTab(WhichTabControl which, TabPage tabPage) { if (which == WhichTabControl.Bottom) { - BottomFMTabsEmptyMessageLabel.Hide(); + Lazy_BottomFMTabsEmptyMessageLabel.Show(false); Lazy_LowerTabControl.TabControl.ShowTab(tabPage, true); } else { - TopFMTabsEmptyMessageLabel.Hide(); + Lazy_TopFMTabsEmptyMessageLabel.Show(false); TopFMTabControl.ShowTab(tabPage, true); } } internal void HideFMTab(WhichTabControl which, TabPage tabPage) { - (DarkTabControl tabControl, DarkLabel emptyMessageLabel) = + (DarkTabControl tabControl, Lazy_EmptyTabAreaMessageLabel emptyMessageLabel) = which == WhichTabControl.Bottom - ? (Lazy_LowerTabControl.TabControl, BottomFMTabsEmptyMessageLabel) - : (TopFMTabControl, TopFMTabsEmptyMessageLabel); + ? (Lazy_LowerTabControl.TabControl, Lazy_BottomFMTabsEmptyMessageLabel) + : (TopFMTabControl, Lazy_TopFMTabsEmptyMessageLabel); tabControl.ShowTab(tabPage, false); if (tabControl.TabCount == 0) { - emptyMessageLabel.BringToFront(); - emptyMessageLabel.Show(); + emptyMessageLabel.Show(true); } } @@ -5732,13 +5734,4 @@ private static Color GetOverlayColor() } #endregion - - // @DockUI: Lazy-load the empty message labels - private void FMTabsEmptyMessageLabels_Paint(object sender, PaintEventArgs e) - { - DarkLabel label = BottomFMTabsEmptyMessageLabel; - e.Graphics.DrawRectangle( - Config.DarkMode ? DarkColors.LighterBackgroundPen : SystemPens.ControlLight, - new Rectangle(0, 0, label.ClientRectangle.Width - 1, label.ClientRectangle.Height - 1)); - } } diff --git a/AngelLoader/Forms/MainForm.resx b/AngelLoader/Forms/MainForm.resx index abb45a43a..8e0748c67 100644 --- a/AngelLoader/Forms/MainForm.resx +++ b/AngelLoader/Forms/MainForm.resx @@ -124,89 +124,89 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAG - EwAAAk1TRnQBSQFMAgEBBAEAAQgBHAEIARwBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAE + EwAAAk1TRnQBSQFMAgEBBAEAARABHAEQARwBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgADBQEGA0IBdANP AZkDVQGxA1sBygNWAbUDTAGRA0YBgAMcAScoAAMNAREDSgGLA1ABmgMeASsYAAMDAQQDVQGtA1gBvQNO AZYDYAHgA1ABnzQAAwIBAwMZASIDWgHHA1IBoANBAXMDQAFvAzQBUwMpAT0DHQEpAx4BKgMPARMDBQEG DAADIwEzA2AB6AMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/Az4BahgAAwwBEAMFAQYEAAMr AUECAAGXAf8DAAH/A0ABcAwAAwMEBAEFBAADBQEGAYYBiwEAAf8ByQHNAQAB/wGQAZYBAAH/AaoBugEA Af8DWgHHAy0BRgMZASIDKAE7AzkBXgNCAXQDPwFuAzkBXgMIAQoMAAQBAw8BFAMuAUgDVgGwA0AB/QNA - Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABXwF7AYAB/gMAAf8DWgHE + Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABYAF8AYAB/gMAAf8DWgHE ASMBXgEhAfsDAAH/AgABnAH/AwAB/wMAAf8DWwHkA0EB+QMAAf8DQwF3DAADCQEMA1ABnwNdAckDPQFo A0YBgQNdAc8BAAGVAcoB/wMAAf8DXgHXA0MBdgMzAVEDVgGwA0YBfgMTARkIAAMsAUMDYQHiAv8BAAH/ - A1wB2QKAAVkB/gNbAdADWwHYA18B2gMAAf8DAAH/AwAB/wNdAd8DFQEdDAADCwEOA00BkgNZAe8BAAEQ + A1wB2QKAAVoB/gNbAdADWwHYA18B2gMAAf8DAAH/AwAB/wNdAd8DFQEdDAADCwEOA00BkgNZAe8BAAEQ AQAB/wMAAf8BCgEMAQcB/wEmAT0BOgH/AR8BMgEwAf8BAAEQAQAB/wMAAf8BBgEjAQAB/wEDASIBAAH/ A14B8ANEAXkDCAEKBAADXQHRAwAB/wNLAYwDXQHMAwAB/wMAAf8CAAGYAf8CAAGWAf8DQAH9A1wB+ANR AaQDUQH3AwAB/wMiATEIAAMfASwBAAGOAacB/wIAAZoB/wMAAf8BAAGUAb0B/wEAAc4C/wEAAbEB3gH/ AQABmAHSAf8BAAGFAcoB/wMAAf8DKwH8AQABpwHIAf8DWQHvAx4BKwwAA0YBfQG8AcEBAAH/A1UBtANO - AZYDSQGFA2AB2wNWAbMDQgF1A04BlQHGAc0BAAH/A10B6gMZASMIAAQBAzYBWANhAeYBagF/AVkB/gES - AUkBAAH/AQwBNAEAAf8BLAI1Af8BDwEWARcB/wEXAh8B/wEXAR0BHgH/AQoBNgEAAf8BCgEkAQAB/wF/ - AYABawH+A2EB6wNAAXEDDAEQAzQBUwMAAf8DYAHgAy4BSANdAeoDAAH/AwAB/wMAAf8DAAH/A00B+gMA - Af8DRgGBA04BlwMAAf8DVgGwDAADRAF7AQABsgHYAf8BAAG3AfUB/wEAAdEB+QH/AQABmQGeAf8BAAGz - Ac8B/wEAAY4BrQH/AQABsgHHAf8BAAHXAv8BAAHrAv8BAAGdAaEB/wNPAZsDDgESDAADRgGAAcUByQEA - Af8DUQGeAyQBNQNYAboDXQHsA18B2gM9AWgDNQFWAcEBxwEAAf8DYAHjAxkBIggAAwkBDANNAZIBVwJW - Af4DAAH/AwAB/wEjASkBKgH/AYEBjAGOAf8BPgFHAUsB/wEhASsBMgH/AVsBhAGGAf8BCwEPAREB/wMA - Af8BFQEAAQMB/wNAAf0DVgG1AxkBIwNYAb0DAAH/A10B1AMeASoDWQHDAwAB/wNAAf0CAAG8Af8DAAH/ - AwAB/wMAAf8DKAE7AzUBVgMAAf8CIQEjAfsDEwEaCAADUAGdAQABrQHrAf8BAAGhAcoB/wMAAf8DAAH/ - AQABlAG3Af8CAAGCAf8DAAH/AQABmQGfAf8BAAHoAv8DAAH/A0wBjgMFAQYMAANIAYQBugG/AQAB/wNd - AdwBbAFtAVEB9wHYAegBAAH/AbcBugEAAf8B3AHhAQAB/wMAAf8DWQHDAcEBxgEAAf8DXQHfAxgBIQgA - AzgEXAHWAysB/AMAAf8BBgEKAQwB/wGhAacBpgH/AYQBjAGNAf8BKwE3AT8B/wEOAR0BJgH/AZIBmAGZ - Af8BUAFWAVcB/wMAAf8DAAH/A00B+gNLAYwDDwEUA14B7QMAAf8DKwH8A0UBfAM9AWkDTQH6ASkCMgH7 - A00B+gFnAWwBgAH+AysB/ANTAaYEAAM+AWsDAAH/AwAB/wM4AVsEAgM5AV8BAAGBAaQB/wEAAbQB7gH/ - AwAB/wMAAf8DAAH/AQABjAG4Af8DAAH/AYICAAH/AwAB/wEAAbgBzgH/AQABhQHEAf8DXgHdAzoBYAMV - ARwIAANHAYMBlQGbAQAB/wMAAf8B2wHrAQAB/wNVAa8DEAEVAlMBUgGlAcMBygEAAf8DXAHnAagBsAEA - Af8DYgHhAxsBJQgAA0kBhwFmAWUBZgH+AQQBAAECAf8DAAH/AVEBWQFaAf8BqwKyAf8BiwGXAZsB/wFI - AVcBgQH/ATYBSgFSAf8BqwKyAf8BowGoAakB/wEcAR8BIwH/ARUBCQEOAf8DQAH9A1sB0wMqAT8DSAH2 - AgABmgH/AwAB/wMAAf8DVAGrA18B1QMAAf8DSAH2AW4BgAFiAf4DYAHoA14B1wM7AWUDSgGKAgABiAH/ - AgABnwH/Az8BbANfAdoDAAH/AQABsgHjAf8BAAGOAakB/wMAAf8DAAH/AwAB/wEAAZEBwwH/AwAB/wMA - Af8DAAH/AwAB/wEAAbAB7gH/AwAB/wMAAf8DTgGWCAADRwGDAQABhgEAAf8B1wHcAQAB/wMAAf8DUAGd - AxsBJQNVAawBwgHOAQAB/wNcAdkBoAGqAQAB/wNaAekDHgEqCAADRgF9A00B+gEPAR4BAAH/ASIBMQET - Af8BNQFOATkB/wEoAVIBRgH/ARQBJAEmAf8BUAFdAYQB/wE1AUQBSAH/ARkBMAEsAf8BIwE+ATkB/wEs - ATgBMgH/AQ4BEAEIAf8BDAEJAQgB/wNpAf4DQAFwA1EB9wMAAf8DXAH4A18B5QNcAfgDAAH/A0gB9gNN - AfoDKwH8ASEBMgEhAfsDWAG9AykBPQNeAdcCAAGSAf8DAAH/Az4BagIAAYYB/wEAAagB0gH/AQAB0gL/ - AgABhAH/AwAB/wMAAf8DAAH/AQABigHBAf8DAAH/AwAB/wMAAf8DAAH/AQABvAH2Af8BAAGqAd4B/wIA - AZkB/wNSAagIAANDAXYBhwGTAQAB/wJoAUEB+QHeAeEBAAH/AwAB/wMAAf8BzgHgAQAB/wJeAVwB2QNB - AXMBqwG0AQAB/wNeAe0DFQEdCAADLAFDA10B6gEcAUABBAH/AREBQwEAAf8BAwEiAQAB/wEXAR8BIAH/ - AT4BSgFMAf8BrQK1Af8BpQGsAa0B/wEzAT0BPwH/AQABBAEFAf8BDQE4AQAB/wE/AaMBAAH/ARsBTgEA - Af8DQQH5AzgBWwNdAewCAAGSAf8BAAGJAbgB/wNgAeADSAGEAyoBPwNOAZgCRwFqAfkDAAH/A0YBfQQA - A00BkgIAAYkB/wIAAZwB/wMAAf8DNAFUAxgBIQNHAYIBAAHAAegB/wIAAYQB/wMAAf8DAAH/AwAB/wEA - AaQByAH/AwAB/wMAAf8DAAH/AwAB/wEAAboB+QH/A2IB7gNBAXMDGAEgCAADUAGdAaABqwEAAf8DWwHN - A1oBxAJtAVEB9wGDAYsBAAH/A18B5QM9AWgDOQFfAasBsQEAAf8DYAHzAzoBYQMZASIDCQEMAyEBLwNg - AfMBBQEPAQAB/wMAAf8BCgERARMB/wE7AUABQQH/AZwBogGgAf8B3gLgAf8B2QLdAf8BlAGaAZkB/wEo - AS8BMQH/AQEBBwEKAf8DAAH/ARcBOQEAAf8DTQH6Az4BawNWAbYCAAGYAf8DAAH/AgABiAH/A14B3QM0 - AVQDVQGuAZcBqQHdAf8CXgFfAfsDRwGDA1IBpQMAAf8DAAH/AwAB/wNNAfoDDwEUBAAEAQFdAmUB7AEA - AaEB5gH/AwAB/wGCAgAB/wMAAf8BAAGMAbgB/wMAAf8DAAH/AwAB/wIAAb0B/wEAAZYBwAH/A1YBsgMD - AQQEAAMZASMDWwHTAYQBhgEAAf8B0QHXAQAB/wNcAfgDXQHfA2IB7gNRAfcDXwHlA2AB4wKAAXUB/gHR - AdcBAAH/AoABcgH+AoABXAH+A2IB7gMqAUADCQEMA1gBvQMAAf8BAgIAAf8BGgEXARwB/wFQAlYB/wHF - AskB/wHfAeMB4gH/AeAB5AHjAf8BuQK+Af8COgE9Af8DAAH/AQUCAAH/AV4BWwFcAf4DWQHDAyEBLwMw - AUoDAAH/AwAB/wIAAZ8B/wEAAYEBtgH/AwAB/wNgAfMDAAH/A1wB+ANNAfoBAAGEAbIB/wMAAf8DAAH/ - AwAB/wNTAaYMAANCAXUBAAHjAv8BAAGUAcwB/wMAAf8DAAH/AQABgAGxAf8DAAH/AwAB/wIAAY4B/wEA - AbkB+wH/AwAB/wNMAY4DEgEXBAADJQE3AwAB/wHbAdwBjgH/AfgB+wGdAf8BpQGoAQAB/wJfATIB+wGX - AZoBAAH/A1oB9QGQAZIBAAH/AaQBpwEAAf8CYgFZAe8B7QHyAY4B/wHJAc0BAAH/AaABpQEAAf8DWwHY - AxQBGwMVARwDYgHhAwAB/wEfAQ8BFQH/ASQBIgEnAf8BPwFcAToB/wG4AcsBuAH/AdgC3QH/Ad0C4AH/ - AacBxAGgAf8BPAFMATMB/wEPAQUBCgH/AwAB/wFzAWkBbAH+A1IBoAMOARIEAANbAcUDAAH/AwAB/wMA - Af8CAAGFAf8CAAGqAf8DAAH/AQABgAGbAf8BAAGOAbgB/wMAAf8DAAH/AgABtAH/A00B+gMTARkIAAMY - ASEBWwJdAcoBAAHlAfoB/wEAA/8BAAHEAfcB/wIAAZQB/wEAAY0BugH/AgABlwH/AgABwgH/AQAB0QL/ - AQABygHuAf8CAAGHAf8DWwHkAyEBLwgAAwIBAwNNAZMBvAHGAQAB/wNWAbADXgHiAwAB/wNlAfEDAAH/ - AzkBXgNSAaAC/wEAAf8DAAH/A1oBvwMWAR4EAAMtAUUDSAH2ARkBBQEKAf8BGAEOARMB/wEUAQwBDgH/ - AS4BVQEaAf8BXQGcAVYB/wGNAYwBjgH/AagBrwGwAf8BVQGjAUIB/wEwAUcBFAH/AwAB/wEDAgAB/wFl - AWIBYwH+A1gBtwMSARcEAAMOARIDXQHqAwAB/wMAAf8CAAGcAf8DAAH/AgABjwH/AwAB/wMAAf8DAAH/ - AgABpAH/AgABhgH/Ay0BRQwAAyABLQEAAZUBrAH/AQABgAGSAf8DUQGhA10B6gEAAeIB+AH/AQAB3gHz - Af8BAAHKAfMB/wEAAaYByAH/A1kBuwNZAbsBAAGvAdAB/wNXAbwDCwEODAADJgE5A10BzAMlATcDUwGp - A1IBoANVAawDVQGvA0MBdgOAAf4BtAG4AQAB/wG7AccBAAH/A2UB8QMyAU8EAANCAXQDXAHLAysB/AMr - AfwBHQFEAQYB/wEvATcBGAH/ATcBQgEiAf8BKAEbASEB/wEsASkBKwH/ATQBgQETAf8BJgFCAQ4B/wEe - ATQBAwH/AQECAAH/AWYBXAFgAf4DTgGVAwoBDQgAAxUBHQNaAccDAAH/AwAB/wMAAf8DAAH/AwAB/wMA - Af8CAAGRAf8CXgFhAeIDLQFFFAADJgE4AzMBUQQAAwwBDwNEAXsBAAHsAv8BAAGCAZQB/wNKAYkDBAEF - AwMBBAM0AVQDDQERLAADXQHRAckB0gEAAf8DSwGPAm0BUQH3AZsBqAEAAf8DPgFqBAADAwEEAwwBDwM1 - AVYDUQGkAUEBRwFBAfkDSAH2ATMBLwEeAf8BJgEcASAB/wEfARgBGgH/ARgBLQEBAf8BdwFwAXIB/gKA - AWgB/gNeAe0DTAGQAyMBMwQCEAADOwFjA1kBvgNeAfADZQHxA2UB8QNbAc0DQwF3AwYBCCgAAxABFQNl - AfEDYAHgQAADRAF5A1IBpQQAA0YBgQNZAcEDDwEUBAADBAEFBAAEAQM4AVwDQgF0A0YBfgNTAaoDVQGt - A1gBugNaAcQDUQGiA1QBqwNAAW8DDAEPBAEEAAFCAU0BPgcAAT4DAAEoAwABQAMAASADAAEBAQABAQYA - AQEWAAP/gQAB4AEPAfwBPwEDAf8B4AEBAcABBwHkATkBAAEDAYABAAGAAQMBgAEBAYABAwGAAQABgAEB - AYABAQHAAQMDAAEBAcABAQHAAQMEAAHAAQEBwAEDAwABEAIAAcABAwYAAcABAwYAAcABAwMAASACAAHA - BQABgAEBBQABAQHAAQEEAAGAAQEBgAEBAYABAQIAAYABAwGAAQEBwAEBAgABwAEHAcgBAwH/AYECAAHw - AQ8B/AF/Af8BkQFAAQEL + AZYDSQGFA2AB2wNWAbMDQgF1A04BlQHGAc0BAAH/A10B6gMZASMIAAQBAzYBWANhAeYBawGAAVoB/gES + AUkBAAH/AQwBNAEAAf8BLAI1Af8BDwEWARcB/wEXAh8B/wEXAR0BHgH/AQoBNgEAAf8BCgEkAQAB/wKA + AWwB/gNhAesDQAFxAwwBEAM0AVMDAAH/A2AB4AMuAUgDXQHqAwAB/wMAAf8DAAH/AwAB/wNNAfoDAAH/ + A0YBgQNOAZcDAAH/A1YBsAwAA0QBewEAAbIB2AH/AQABtwH1Af8BAAHRAfkB/wEAAZkBngH/AQABswHP + Af8BAAGOAa0B/wEAAbIBxwH/AQAB1wL/AQAB6wL/AQABnQGhAf8DTwGbAw4BEgwAA0YBgAHFAckBAAH/ + A1EBngMkATUDWAG6A10B7ANfAdoDPQFoAzUBVgHBAccBAAH/A2AB4wMZASIIAAMJAQwDTQGSAVgCVwH+ + AwAB/wMAAf8BIwEpASoB/wGBAYwBjgH/AT4BRwFLAf8BIQErATIB/wFbAYQBhgH/AQsBDwERAf8DAAH/ + ARUBAAEDAf8DQAH9A1YBtQMZASMDWAG9AwAB/wNdAdQDHgEqA1kBwwMAAf8DQAH9AgABvAH/AwAB/wMA + Af8DAAH/AygBOwM1AVYDAAH/AiEBIwH7AxMBGggAA1ABnQEAAa0B6wH/AQABoQHKAf8DAAH/AwAB/wEA + AZQBtwH/AgABggH/AwAB/wEAAZkBnwH/AQAB6AL/AwAB/wNMAY4DBQEGDAADSAGEAboBvwEAAf8DXQHc + AWwBbQFRAfcB2AHoAQAB/wG3AboBAAH/AdwB4QEAAf8DAAH/A1kBwwHBAcYBAAH/A10B3wMYASEIAAM4 + BFwB1gMrAfwDAAH/AQYBCgEMAf8BoQGnAaYB/wGEAYwBjQH/ASsBNwE/Af8BDgEdASYB/wGSAZgBmQH/ + AVABVgFXAf8DAAH/AwAB/wNNAfoDSwGMAw8BFANeAe0DAAH/AysB/ANFAXwDPQFpA00B+gEpAjIB+wNN + AfoBaAFtAYAB/gMrAfwDUwGmBAADPgFrAwAB/wMAAf8DOAFbBAIDOQFfAQABgQGkAf8BAAG0Ae4B/wMA + Af8DAAH/AwAB/wEAAYwBuAH/AwAB/wGCAgAB/wMAAf8BAAG4Ac4B/wEAAYUBxAH/A14B3QM6AWADFQEc + CAADRwGDAZUBmwEAAf8DAAH/AdsB6wEAAf8DVQGvAxABFQJTAVIBpQHDAcoBAAH/A1wB5wGoAbABAAH/ + A2IB4QMbASUIAANJAYcBZwFmAWcB/gEEAQABAgH/AwAB/wFRAVkBWgH/AasCsgH/AYsBlwGbAf8BSAFX + AYEB/wE2AUoBUgH/AasCsgH/AaMBqAGpAf8BHAEfASMB/wEVAQkBDgH/A0AB/QNbAdMDKgE/A0gB9gIA + AZoB/wMAAf8DAAH/A1QBqwNfAdUDAAH/A0gB9gFvAYABYwH+A2AB6ANeAdcDOwFlA0oBigIAAYgB/wIA + AZ8B/wM/AWwDXwHaAwAB/wEAAbIB4wH/AQABjgGpAf8DAAH/AwAB/wMAAf8BAAGRAcMB/wMAAf8DAAH/ + AwAB/wMAAf8BAAGwAe4B/wMAAf8DAAH/A04BlggAA0cBgwEAAYYBAAH/AdcB3AEAAf8DAAH/A1ABnQMb + ASUDVQGsAcIBzgEAAf8DXAHZAaABqgEAAf8DWgHpAx4BKggAA0YBfQNNAfoBDwEeAQAB/wEiATEBEwH/ + ATUBTgE5Af8BKAFSAUYB/wEUASQBJgH/AVABXQGEAf8BNQFEAUgB/wEZATABLAH/ASMBPgE5Af8BLAE4 + ATIB/wEOARABCAH/AQwBCQEIAf8DagH+A0ABcANRAfcDAAH/A1wB+ANfAeUDXAH4AwAB/wNIAfYDTQH6 + AysB/AEhATIBIQH7A1gBvQMpAT0DXgHXAgABkgH/AwAB/wM+AWoCAAGGAf8BAAGoAdIB/wEAAdIC/wIA + AYQB/wMAAf8DAAH/AwAB/wEAAYoBwQH/AwAB/wMAAf8DAAH/AwAB/wEAAbwB9gH/AQABqgHeAf8CAAGZ + Af8DUgGoCAADQwF2AYcBkwEAAf8CaAFBAfkB3gHhAQAB/wMAAf8DAAH/Ac4B4AEAAf8CXgFcAdkDQQFz + AasBtAEAAf8DXgHtAxUBHQgAAywBQwNdAeoBHAFAAQQB/wERAUMBAAH/AQMBIgEAAf8BFwEfASAB/wE+ + AUoBTAH/Aa0CtQH/AaUBrAGtAf8BMwE9AT8B/wEAAQQBBQH/AQ0BOAEAAf8BPwGjAQAB/wEbAU4BAAH/ + A0EB+QM4AVsDXQHsAgABkgH/AQABiQG4Af8DYAHgA0gBhAMqAT8DTgGYAkcBagH5AwAB/wNGAX0EAANN + AZICAAGJAf8CAAGcAf8DAAH/AzQBVAMYASEDRwGCAQABwAHoAf8CAAGEAf8DAAH/AwAB/wMAAf8BAAGk + AcgB/wMAAf8DAAH/AwAB/wMAAf8BAAG6AfkB/wNiAe4DQQFzAxgBIAgAA1ABnQGgAasBAAH/A1sBzQNa + AcQCbQFRAfcBgwGLAQAB/wNfAeUDPQFoAzkBXwGrAbEBAAH/A2AB8wM6AWEDGQEiAwkBDAMhAS8DYAHz + AQUBDwEAAf8DAAH/AQoBEQETAf8BOwFAAUEB/wGcAaIBoAH/Ad4C4AH/AdkC3QH/AZQBmgGZAf8BKAEv + ATEB/wEBAQcBCgH/AwAB/wEXATkBAAH/A00B+gM+AWsDVgG2AgABmAH/AwAB/wIAAYgB/wNeAd0DNAFU + A1UBrgGXAakB3QH/Al4BXwH7A0cBgwNSAaUDAAH/AwAB/wMAAf8DTQH6Aw8BFAQABAEBXQJlAewBAAGh + AeYB/wMAAf8BggIAAf8DAAH/AQABjAG4Af8DAAH/AwAB/wMAAf8CAAG9Af8BAAGWAcAB/wNWAbIDAwEE + BAADGQEjA1sB0wGEAYYBAAH/AdEB1wEAAf8DXAH4A10B3wNiAe4DUQH3A18B5QNgAeMCgAF2Af4B0QHX + AQAB/wKAAXMB/gKAAV0B/gNiAe4DKgFAAwkBDANYAb0DAAH/AQICAAH/ARoBFwEcAf8BUAJWAf8BxQLJ + Af8B3wHjAeIB/wHgAeQB4wH/AbkCvgH/AjoBPQH/AwAB/wEFAgAB/wFfAVwBXQH+A1kBwwMhAS8DMAFK + AwAB/wMAAf8CAAGfAf8BAAGBAbYB/wMAAf8DYAHzAwAB/wNcAfgDTQH6AQABhAGyAf8DAAH/AwAB/wMA + Af8DUwGmDAADQgF1AQAB4wL/AQABlAHMAf8DAAH/AwAB/wEAAYABsQH/AwAB/wMAAf8CAAGOAf8BAAG5 + AfsB/wMAAf8DTAGOAxIBFwQAAyUBNwMAAf8B2wHcAY4B/wH4AfsBnQH/AaUBqAEAAf8CXwEyAfsBlwGa + AQAB/wNaAfUBkAGSAQAB/wGkAacBAAH/AmIBWQHvAe0B8gGOAf8ByQHNAQAB/wGgAaUBAAH/A1sB2AMU + ARsDFQEcA2IB4QMAAf8BHwEPARUB/wEkASIBJwH/AT8BXAE6Af8BuAHLAbgB/wHYAt0B/wHdAuAB/wGn + AcQBoAH/ATwBTAEzAf8BDwEFAQoB/wMAAf8BdAFqAW0B/gNSAaADDgESBAADWwHFAwAB/wMAAf8DAAH/ + AgABhQH/AgABqgH/AwAB/wEAAYABmwH/AQABjgG4Af8DAAH/AwAB/wIAAbQB/wNNAfoDEwEZCAADGAEh + AVsCXQHKAQAB5QH6Af8BAAP/AQABxAH3Af8CAAGUAf8BAAGNAboB/wIAAZcB/wIAAcIB/wEAAdEC/wEA + AcoB7gH/AgABhwH/A1sB5AMhAS8IAAMCAQMDTQGTAbwBxgEAAf8DVgGwA14B4gMAAf8DZQHxAwAB/wM5 + AV4DUgGgAv8BAAH/AwAB/wNaAb8DFgEeBAADLQFFA0gB9gEZAQUBCgH/ARgBDgETAf8BFAEMAQ4B/wEu + AVUBGgH/AV0BnAFWAf8BjQGMAY4B/wGoAa8BsAH/AVUBowFCAf8BMAFHARQB/wMAAf8BAwIAAf8BZgFj + AWQB/gNYAbcDEgEXBAADDgESA10B6gMAAf8DAAH/AgABnAH/AwAB/wIAAY8B/wMAAf8DAAH/AwAB/wIA + AaQB/wIAAYYB/wMtAUUMAAMgAS0BAAGVAawB/wEAAYABkgH/A1EBoQNdAeoBAAHiAfgB/wEAAd4B8wH/ + AQABygHzAf8BAAGmAcgB/wNZAbsDWQG7AQABrwHQAf8DVwG8AwsBDgwAAyYBOQNdAcwDJQE3A1MBqQNS + AaADVQGsA1UBrwNDAXYDgAH+AbQBuAEAAf8BuwHHAQAB/wNlAfEDMgFPBAADQgF0A1wBywMrAfwDKwH8 + AR0BRAEGAf8BLwE3ARgB/wE3AUIBIgH/ASgBGwEhAf8BLAEpASsB/wE0AYEBEwH/ASYBQgEOAf8BHgE0 + AQMB/wEBAgAB/wFnAV0BYQH+A04BlQMKAQ0IAAMVAR0DWgHHAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ + AgABkQH/Al4BYQHiAy0BRRQAAyYBOAMzAVEEAAMMAQ8DRAF7AQAB7AL/AQABggGUAf8DSgGJAwQBBQMD + AQQDNAFUAw0BESwAA10B0QHJAdIBAAH/A0sBjwJtAVEB9wGbAagBAAH/Az4BagQAAwMBBAMMAQ8DNQFW + A1EBpAFBAUcBQQH5A0gB9gEzAS8BHgH/ASYBHAEgAf8BHwEYARoB/wEYAS0BAQH/AXgBcQFzAf4CgAFp + Af4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQARUDZQHx + A2AB4EAAA0QBeQNSAaUEAANGAYEDWQHBAw8BFAQAAwQBBQQABAEDOAFcA0IBdANGAX4DUwGqA1UBrQNY + AboDWgHEA1EBogNUAasDQAFvAwwBDwQBBAABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEAAQEGAAEB + FgAD/4EAAeABDwH8AT8BAwH/AeABAQHAAQcB5AE5AQABAwGAAQABgAEDAYABAQGAAQMBgAEAAYABAQGA + AQEBwAEDAwABAQHAAQEBwAEDBAABwAEBAcABAwMAARACAAHAAQMGAAHAAQMGAAHAAQMDAAEgAgABwAUA + AYABAQUAAQEBwAEBBAABgAEBAYABAQGAAQECAAGAAQMBgAEBAcABAQIAAcABBwHIAQMB/wGBAgAB8AEP + AfwBfwH/AZEBQAEBCw== @@ -279,79 +279,78 @@ iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG4SURBVDhPYxhQEKvEFB+nxHQiVoXlQ5wKyzso/R+EY5WZ - p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD+KUmZsKbGTBBsEM - geEzW6f/P7KqB8xe318INhiqDTcAubDQVvb/y9v7MAy8uGce0OtMh2OVWdbsXdQCFgMFBVQrdgByIchA - bC4E4ZvHVvyPUWI6DzRox+GV3WAxvIbCvIzNhcj42qGl/09vmQZmv3145H+ELMsnqBGoAOjltiI7OYIG - ouNXdw/8j1FmeQs1BgFgLnxzH7uX8eEvr86CvP8PahQExKkwtxDjZVz42fWd/2OVWJ5CjQN6WZm5udhe - AewFbBoI4Y/PTvyv9ND4H6fKUgM1EuhKRZY3r+7sx6qBEIYbqMzcDzUOAkBJA5REsGnChz8+O4ndQBCI - V2ZNS9HhAac9bJqxYZALqzw1QbloAtQYTAAyOEmTkyiDcXoZG0AYvBKrYSAMcyFRBsIAMAbTcbmYJBei - A2wupshAGIC4mOv/lf2L/j+8uIV0L+MCccpMccAS/3icEvO9WFWWUqjwQAAGBgDeOtU9U5quUwAAAABJ - RU5ErkJggg== + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGuSURBVDhPYxhQEKvEFB+nzHwiVoXlQ5wKyzso/R+EY5WZ + p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD4CuayqwkQUbBDME + hs9snf7/yKoeMHt9fyHYYKg23ADkwkJb2f8vb+/DMPDinnlArzMfjlVmWbN3UQtYDBQUUK3YAciFIAOx + uRCEbx5bAXLZeaBBOw6v7AaL4TUU5mVsLkTG1w4t/X96yzQw++3DI0BLWD5BjUAFQC+3FdnJETQQHb+6 + ewBk6FuoMQgAc+Gb+9i9jA9/eXUW5P1/UKMgABjoLcR4GRd+dn0nyKVPocYBvazM3FxsrwD2AjYNhPDH + Zyf+V3po/I9TZamBGgnyNsubV3f2Y9VACMMNVGbuhxoHAaCkAUoi2DThwx+fncRuIAjEK7OmpejwgNMe + Ns3YMMiFVZ6aoLQ6AWoMJgAZnKTJSZTBOL2MDSAMXonVMBCGuZAoA2EAGIPpuFxMkgvRATYXU2QgDEBc + zPX/yv5F/x9e3EK6l3GBOGWmOGDsHgcadi9WlaUUKjwQgIEBAExb1Vj6X25iAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VU7SMNQFO0o2qQtgnQRxcnBwUl0EV1ERFAc - Sp0qNulnE0EUF3WQmqQl+EEp1AoiOIkOgohDq8UPdujgYBFFxUW3bh01J9wnMVKpbcDFAxfad++733Nf - bP8wgxPkMYcgt9Nfa+HwKz3u8Oq9K6y+8aLipWNr4AhGml3h2J0nefHgSV6/NE7G85yozJO6SvjmajRn - uaH1zNXoVvYd4k1mCvVhtUAW1YEX5P3e2HGKOYd0LO6dcn5pl0wqB9rQNrvzmTmkTz1J86J8icrIrDLY - A9Iwej20nC0y5yMbFzlXIPaEmZBZZQAVwRYMlDnHb5xxwlInmZmAksooq9Ynu51iNI9smXNUoTNH2wMy - M0FzbBeUI8iPQTQd+os+M+cQzEHjvkpWJpDz9oXdTLdyqA/I4VOdpP0CToxugCFG52AQJ0opMvkO0AnO - 2QVkB16jFWSiQyt/omkqfmMcKrhf51ceSyWkD0srrTgcP8+yS5CBlXRGv0hs4P1yf0No7cWTuH5jNtja - +lD02R6IturOSgFBnEH5dXD97NwYBEFBOdARes/mZZ7psKkICB25+RnIAhkjc2MQMAUrbw7eOrOd1aqa - oevlAe3gx6VbDNrozNgWSFfkII3nga79DhgWBmxmChNUAn05+1IaBtoaGYMZWPIM6NAXStlCrxEEbcLH - BB8VsrAGWCw8AS3TiRwvSCE6thZ4kks/A38Km+0DB1GODuPZXHcAAAAASUVORK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VVPKARhFN+jNDO7KLmoLRcHBy7iIi6SFDks + TqtmZtlcpEQuOGjNzK4p5F/tKiku4qAkB8vGYg97cLCJkAs3N0fmN71PY7Raa8rFr17tfu997+/vfeP6 + hx28pPa6JbWa/joLt6g1lg3M3RQH9WdB1rrp2Bm4+0Le4uDMtS+WvPXFLh7Lh5YzvKxNkPqX8I8XGM7S + 7QuJs57V1BukO3b+UhLUX8jidxAkdbspsn/InENqp7aOeFHZIJP8gTZUja1/ZA5p1g/igqwmURmZ5Qcu + oHSg113R1Ctz3rl0mi4KRO4xEzLLD6Ai2IKBMuf4jTNemq4jMxtQUg5lFfrVMo8cziBb5hxVmMwx9oDM + bDAcc5K2B/k2iKFDf9Fn5hyCORjc18nKBnJeM7mZaNB2zQG5/bqHtJ/Ay+FFMMTqHAziZeWQTL4CdIJz + dgHZgddoBZmYMMof9A6vXFqHCu5zonaXLSFzWEZprx3LJyl2CdI6G0+YF4kNgqi2lA7MP3ZFL56ZDba2 + pH/mgQuEK01n2YAgnj7tqW3h+MQaBEFBOdARel80mWE6bCoCQkduvgeyQMbI3BoETMHK24NXjq6ljKpG + 6XpuQDsEUbnCoK3OrG2B1Id24nge6NrPgGFhwHamMEEl0OeyL9lhoa2VMZiBI8+ACXOhtFX0GkHQJnxM + 8FEhC2eAxcITUDESTQuS0k/HzgJPcvZn4E/hcr0DUbSOqjT7gYIAAAAASUVORK5CYII= iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGaSURBVEhL7ZQhUMQwEEXrYKBNkUgkEolEIpG4MjQ5kEgc - uKPNzVQikUgk8iQSiUQikVjy936YEErvpq1A8GY6d/vT2SS7f5v8E5Pp+iTX9R7DcclLe6BOqxel7Zsy - 9pjyOORn0x0kTyezXfzPjH12zzWXB1JcrSNhOqmOqCR50Wytmek7w2EoXT+osr5kKGRmdpuV1T3D/qAM - 2ICh4Bp9oUz9hJtR6gdKgtKEidDozdK+og+U+gErwi1hImm00zJ9s08pAidZ4VobRb0Nx+C0lL4ajTmg - EuFeSLV9xNO5iVtDfVFnKoI02tiGYQSTuxfupGkuAWzG1W+IO9zDUICDMlPNGf4EdkJyhuICXBeloCS0 - uQONlqb+cqBFs4z9cKc4pCSglqEbsI443BRTCw2/lNrxjoi/Hz4pTimOCT5iOLFfo9SNP03sAjgFIx9v - Lj2Lpncp4mNnPzSakhD3wm3WxNO7Mri6+Dlyigc3wXqnlZcS2DZMhB6gjIM/A4JLjA384LVO7xgsBgsl - q+ZKV+eUxwVNR2MZ/iWS5BPRbcV7uffSLwAAAABJRU5ErkJggg== + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGZSURBVEhL7ZQhUMNAEEUjGSZ3QSKRSCQSiUTiykzuChKJ + AweX60wkEolEIiuRSCQSicSyf/vDHEdpO00EgjeTafdfZu9u92+Kf3KMa04q1+wxHJaqjge2Di/WxTfr + 4zHlYahOr3eQvBxPdvHf+PgszxWXezK63EDCchyOqBTVqN0qfXhn2A/rmgdbNxcMFeMnt6YO9wzXB2XA + BgwVafS59c0TbkZpPVASlCZNhEaXdXxFHyitB6wIt6SJtNGiGXezTykDJ1nhWpujZhuOwWkpfTUac0Al + Q14oXXzEs3ATWUN9UWcqijbax5ZhBpPLC3faNEkAm3H1G+oOeRgqcJDxYcrwJ7ATkjNUF+C6KAUlZZ47 + 0Ght6i8HmjXLxw85xSElBbVM3YB1xOmmmFpo+KU0n84R+fejS4pTqmOSj5hOKtcoLaY7Te4C9bWMfL65 + 9iyb3qWoj8V+aDQlJe+FbNbm07syuLr6OXNKB26C9YVWXkpi2zQReoAy9v4MKJIYG3SDN3d6h2A2WChZ + mFoXzigPC5qOxjL8SxTFJ00CxZeT7IG4AAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAICSURBVEhLzVQ9SwNBEJ3S0tIypaWlpWVKS8v8AhMlET/A - iIiKhYogQVBEBAMiKiJYbmIEg4gREbEQPxCRFKJBJAki67zLLDGXi7mYK3zw4G535u3HvB36d1B95JdP - 76Gi1JLoozsVpjYZ8hYqSIH0MGleZEqGvAULZz42SasIZXEaGfYGvPuOy0nSep/0zSwvwqeRKW+QCNHq - y1ppgfyWdU0ZmWoeKGp6hAoQN8RpcCoJaQ4sFHqMlcVBnCYRpLiE1AYn+5hdwm72+RgIpzAVmOylt8/d - ygVAji+amEQ/zZlcZo/RNN7eOYqQvl8o8WmJ9Ot6icXtauGfxMImNrtS1hA7l+vEP7GLCdJfe85CjRAu - 4+s7qLKyCtHg6WhpV06J9YjNXU2zODtOJKvB9xZID1EBVnQSqUVs6nyc68I1EKna4CB/igub23AWsxOb - ORlp8PFxcAcK7yRop7VzdqCkugMn+FAPJ0E7r2f+tkAAbnAStPN5mQvL70BS3QG2ha/tYnjBdiujw1Z4 - 3g2Q8NNJ73HSZ1HL33H0JdP4DFNhKrhu4Xw9rXiJSIT95OEcq35qt+a5+fEGdtDwzEuX5tdlCdQDCoYE - XJEaoBzqIVMVgJ2TYbp/WCR9O8+x/FBl6nfgscCiqANOI8OOwLUg/jBIeZxKhn+HdMZO+XUFXF91+yb6 - BhrAUXeHueVSAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH/SURBVEhLzVTPK0RRGD1LS0tLS0tLS0tLS8v5D4wx5Ech + CVkgJSmSlCkJSVm+maEMCUmykB9JshCSjKTrO2++25g3b3h4C6dOvXfv/c798Z3vw7+D04Q6/QwfTjfK + kk04d+Ko0KFw4TQikumAkU0GdChciPD+8wJMugW3vI0OhwM5ffVRP4xZgzkdhuFtdCocJKOYuZvNbfCy + 6D7Tvk79HUzqdieyFLfkbXgrXfI3iFD0aiIvTvI2yUYkdElpSHClsFZZLz7vIekUoUOmYnh4WyncgNzp + xKtdk4xhxMYKG6ym9fbyZgvMxViO15Mw93M5vi4VC38mN7Zrb6fzGmrnfJ7kZ+KwD+Z91V/oJ6TL5PnW + i6zsRNG225U7lV/gd+ThjgdFXBynksWQd4tk2pGlFf1ESpGHOugVZ0kOVKo0ZFHdRjMeHuf9xbzkYSTh + Pys+WVzNxPsJeumeXByoocEgAZXMh5+glydDv9sgQjf4CXp5MyWJlTrQ0GCgbelrrxgr2GtldtgCzwcB + Az476SkBs9ft+jvBvmQbn+VGHNnALVyep5yVyEDaTwtny4mhyp2X5icHWGbDs5Wuza/WFfgOTBgD+ESb + rXhkPnSqALRzKo6Ly3GYs1HZQApVp74Gi4UWZR54Gx32BZ+F69MxvPBWOvw1tDPW6G8g8PmK2zfwAeUN + UaR56NgIAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANXSURBVDhPvZRJTJNREMdn3pcY43IxnlzDAaPGg4kePBhN - jBoTvanRxIOJUeIChbZUESSVpYCyyCJlKV0AQWVREBCECpUlBaUiECLIQaMEFVyAeBCFPud9PIkQY6oH - f5ev7z/zpm/ezBv47xToYbE1RNldGonpNXGsoz6JddUmsHaxtmiUPTkBsEi6+kZ2MOyojMZqdxZ6xxqA - 83bg0+6Z7zit20mviMGqHA1sl1v+jE3PAp85kE8/Af6lCbgnAycepmBP3VUsdiZjr1gLfboTeFc+cquO - nZFbf49Nx06+voOcPwXeloHD9lAWSadZk2eApeZAZZf9OCy06WC10Jsz8Z3wE/55OnZChphLjpYdfXGb - UnwMvNLI+q+fhbXSBOWXMarHQXoUxkoJcgPBrzyaDQr/wdvILTp2RJpmsBthYV0CG+Ie4A2J+DJLA/7S - pFJlworJR8CdicwlJZWMc7CuPhnfiBOL/SKONNEpNcrBT3XA31chzwxU9kt5lkoT3pigAj24gtVSmiUz - SNn7/h7wTw+A54Yoh6SspmefdAFvTmUdUprDz6D3E7BMSnNoSsNukcndaHSoQlIALHel4uBUM/D8ULSp - 4jzUoE4KGo+NVJRjRWFMVxCm7JNmuBmB1qlW4K507Id7sVhOKT3vMKN3ukW9sxFnCroLw2Gb9FcRPfud - 7J/ptG8rKVX6A08eVV0Pm4S96CImCntLKo5BWTQbnainilOBvG30pQsfKKbeMygH1GiSm+HsgmghjwM/ - dttxtDcfx5qSWXfheVgl7BT0mjgpPZYRtepVccw9JQL2Af9QS1dwHhPUSPNwaGFlrh78RJ/aDOAvnrE0 - QbkRy77R9TlTmFsVzBrY4rEgnxL9GcM6qT+XqAYfsWhhmceK775SoYrD0SRlNb2AGhM2Fepho5R8xqpF - k6j8q1Lk2SGwVcozGI3A5E+fMZ9jAQNFyL00aEoisFHK/05eEAvqu0Fzohs4jcV+6oTZZ+0zNFRWZNPr - yTew0/QIOodrKCB1jTMNhy3BsEG6+Y5dB+tFD45Qd3yspWAdwIdqgN8xslYxxaTb32EPhc1PqUPGqen7 - CvBzdRw67Vp2quQwKNLl7xHztCIKzbXxrOvWJYzP0cLOEiMskOZfAPgBbpejM2TyfeAAAAAASUVORK5C - YII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANYSURBVDhPvZRJTFNRFIbPuS8xxmFjXDmGBUaNCxNduDCa + GDUmulOjiQsTo0QFKm0BESFlkEEZRLRMpS2zglBBhjJUJsGCMohIBFlolKCAKBAXosD13MeVCDGmuPDb + vL7/nHd67z3/ufDfydLDcrOPsv9+MCZWRLHW6ljWaY9mLeLdpFEOpHrAMpnqGimXYE9JGJZ1Z+PMWA1w + 3gJ82jn7HKf3l6QXh2NpqgZ2y0/+jkXPvJ5nIJ9+BvxrHfB2E048iscXlTcwzxGH3eJd6NNtwDszkZt1 + 7IL89M9YdOzsOxty3gG82YiDVl8WTKvZkO4HK5O8lH3W07DUooP1Qm8y4keRJ/LTdeyMLDGfVC07+Tqf + tvgUeEko671zETbKEBSFYOiLDKHjNSlBmhe4FYexfpHfn4/cpGMnZGgWqwGWVsewAd4O3BGLb5I14C5D + KqWRWDzZQLEYVi8llduesKkmDt+LFdfEsgFRR4ZolRrl6OdK4EOlyI1eymEpz/EwAnMmqEFVN7BMSnMY + vZWDQw+Bf64CnuajHJMygC0UrZP1wBsTWKuU5vGrqD0aC6U0j/pb2CV28iAMM1Qh1gNW1ydg/1Qj8Exf + tKjiAtSiDuAV0VhLTTmVG8B0WQHKIRmGe1fRPNUEvCERe6H0GhZVXcdXPVk4M/1YnCcbdsSjMzsQdsl8 + FeHZHxT/Qqv9UEJbpT9oT6eu62GbiOdewRgRdybjGNjC2MhENXWcGjTTTE868L488p6fckStJrkbyC4L + C5F/R7usONKdhWN18awr2x/WiTgVvSlWSkWH1a6XRzHnlCjYA/yTnY7AH6PVSgvI0MLaND24CZ9a/MBd + jLEMgS0EC7/T8TnimVMVkjSwg6aETwl/hrM28ucKNeAiJi2s6jTjx2/UqLxAjJCyuj2P8gisy9bDVim5 + jFmLEaLzb+8jT/GBnVKexWAAJn+6TJIn8+jLRT5DF01BENZK+d9J92bePTl0T3Sp09RLTpgba5ehS2VN + Ck1Pph87T35tGyynguQaMv6g6RJskWmuY9XB5idGHBsmd4zaqVgr8IFy4DYDaxK3mExbHFZf2N5BDhkn + 09OgfCmLRIdVy84VHAdFpiwecZ8Wh2KSPYp13gvCqFQt7C0wwBIZ/g2An2e+o9ziKCLsAAAAAElFTkSu + QmCC diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index d9138ce21..286350cfb 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -87,7 +87,6 @@ private void InitComponentManual() PatchTabPage = new PatchTabPage(); ModsTabPage = new ModsTabPage(); ScreenshotsTabPage = new ScreenshotsTabPage(); - TopFMTabsEmptyMessageLabel = new DarkLabel(); LowerSplitContainer = new DarkSplitContainerCustom(); ReadmeEncodingButton = new DarkButton(); ReadmeFullScreenButton = new DarkButton(); @@ -96,7 +95,6 @@ private void InitComponentManual() ReadmeResetZoomButton = new DarkButton(); ChooseReadmeComboBox = new DarkComboBoxWithBackingItems(); ReadmeRichTextBox = new RichTextBoxCustom(); - BottomFMTabsEmptyMessageLabel = new DarkLabel(); BottomFMTabsMenuButton = new DarkButton(); BottomFMTabsCollapseButton = new DarkArrowButton(); @@ -251,7 +249,6 @@ private void InitComponentManual() TopSplitContainer.Panel2.Controls.Add(TopFMTabsMenuButton); TopSplitContainer.Panel2.Controls.Add(TopFMTabsCollapseButton); TopSplitContainer.Panel2.Controls.Add(TopFMTabControl); - TopSplitContainer.Panel2.Controls.Add(TopFMTabsEmptyMessageLabel); TopSplitContainer.Size = new Size(1671, 309); TopSplitContainer.SplitterDistance = 1116; TopSplitContainer.TabIndex = 0; @@ -568,13 +565,6 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir TopFMTabControl.MouseDragCustom += TopFMTabControl_MouseDragCustom; TopFMTabControl.MouseUp += TopFMTabControl_MouseUp; // - // TopFMTabsEmptyMessageLabel - // - TopFMTabsEmptyMessageLabel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - TopFMTabsEmptyMessageLabel.Size = new Size(533, 309); - TopFMTabsEmptyMessageLabel.TextAlign = ContentAlignment.MiddleCenter; - TopFMTabsEmptyMessageLabel.PaintCustom += FMTabsEmptyMessageLabels_Paint; - // // LowerSplitContainer // LowerSplitContainer.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; @@ -596,7 +586,6 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir // LowerSplitContainer.Panel2 // LowerSplitContainer.Panel2.BackColor = SystemColors.Control; - LowerSplitContainer.Panel2.Controls.Add(BottomFMTabsEmptyMessageLabel); LowerSplitContainer.Panel2.Controls.Add(BottomFMTabsMenuButton); LowerSplitContainer.Panel2.Controls.Add(BottomFMTabsCollapseButton); LowerSplitContainer.Size = new Size(1671, 357); @@ -648,13 +637,6 @@ void SetReadmeButton(DarkButton button, int x, int tabIndex) ReadmeRichTextBox.TabIndex = 0; ReadmeRichTextBox.MouseLeave += ReadmeArea_MouseLeave; // - // BottomFMTabsEmptyMessageLabel - // - BottomFMTabsEmptyMessageLabel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - BottomFMTabsEmptyMessageLabel.Size = new Size(533, 357); - BottomFMTabsEmptyMessageLabel.TextAlign = ContentAlignment.MiddleCenter; - BottomFMTabsEmptyMessageLabel.PaintCustom += FMTabsEmptyMessageLabels_Paint; - // // BottomFMTabsMenuButton // BottomFMTabsMenuButton.Anchor = AnchorStyles.Top | AnchorStyles.Right; From dfa2aa9f7eb80088aa8e8c40888852bce761d149 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 09:33:58 -0800 Subject: [PATCH 183/200] Revert "Lazy-load empty tab message labels" This reverts commit 4bfb41e3f07b750b3c992a76e0ddbe6c87556ffb. --- .../Lazy_EmptyTabAreaMessageLabel.cs | 110 -------- .../LazyLoaded/Lazy_FMTabsBlocker.cs | 7 +- .../LazyLoaded/Lazy_LowerTabControl.cs | 5 +- AngelLoader/Forms/MainForm.Designer.cs | 32 +++ AngelLoader/Forms/MainForm.cs | 39 +-- AngelLoader/Forms/MainForm.resx | 247 +++++++++--------- AngelLoader/Forms/MainForm_InitManual.cs | 18 ++ 7 files changed, 199 insertions(+), 259 deletions(-) delete mode 100644 AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_EmptyTabAreaMessageLabel.cs diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_EmptyTabAreaMessageLabel.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_EmptyTabAreaMessageLabel.cs deleted file mode 100644 index 292ba3fcc..000000000 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_EmptyTabAreaMessageLabel.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System.Diagnostics; -using System.Drawing; -using System.Windows.Forms; -using AngelLoader.DataClasses; -using JetBrains.Annotations; - -namespace AngelLoader.Forms.CustomControls.LazyLoaded; - -internal sealed class Lazy_EmptyTabAreaMessageLabel : IDarkable -{ - private readonly MainForm _owner; - - private bool _constructed; - - private WhichTabControl _which; - - private string _text = ""; - - private DarkLabel Label = null!; - - private bool _darkModeEnabled; - [PublicAPI] - public bool DarkModeEnabled - { - set - { - if (_darkModeEnabled == value) return; - _darkModeEnabled = value; - if (!_constructed) return; - - Label.DarkModeEnabled = value; - } - } - - public Lazy_EmptyTabAreaMessageLabel(MainForm owner) => _owner = owner; - - internal void SetWhich(WhichTabControl which) => _which = which; - - internal void SetText(string text) - { - if (_constructed) - { - Label.Text = text; - } - else - { - _text = text; - } - } - - private void Construct() - { - if (_constructed) return; - - var container = - _which == WhichTabControl.Bottom - ? _owner.LowerSplitContainer.Panel2 - : _owner.TopSplitContainer.Panel2; - - var collapseButton = - _which == WhichTabControl.Bottom - ? _owner.BottomFMTabsCollapseButton - : _owner.TopFMTabsCollapseButton; - - Label = new DarkLabel - { - Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, - Size = new Size( - container.Width - collapseButton.Width, - container.Height), - TextAlign = ContentAlignment.MiddleCenter, - - DarkModeEnabled = _darkModeEnabled - }; - - Label.PaintCustom += FMTabsEmptyMessageLabels_Paint; - Label.MouseClick += _which == WhichTabControl.Bottom - ? _owner.LowerFMTabsBar_MouseClick - : _owner.TopFMTabsBar_MouseClick; - - container.Controls.Add(Label); - - _constructed = true; - - SetText(_text); - } - - private void FMTabsEmptyMessageLabels_Paint(object sender, PaintEventArgs e) - { - DarkLabel label = Label; - e.Graphics.DrawRectangle( - _darkModeEnabled ? DarkColors.LighterBackgroundPen : SystemPens.ControlLight, - new Rectangle(0, 0, label.ClientRectangle.Width - 1, label.ClientRectangle.Height - 1)); - } - - internal void Show(bool show) - { - if (show) - { - Trace.WriteLine(_which); - Construct(); - Label.BringToFront(); - Label.Show(); - } - else - { - if (_constructed) Label.Hide(); - } - } -} diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs index 98f8f778e..5fa4a9b99 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs @@ -58,17 +58,12 @@ private void Construct() ? _owner.LowerSplitContainer.Panel2 : _owner.TopSplitContainer.Panel2; - var collapseButton = - _which == WhichTabControl.Bottom - ? _owner.BottomFMTabsCollapseButton - : _owner.TopFMTabsCollapseButton; - Panel = new DrawnPanel { Location = Point.Empty, Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom, Size = new Size( - container.Width - collapseButton.Width, + container.Width - _owner.BottomFMTabsCollapseButton.Width, container.Height), DarkModeDrawnBackColor = DarkColors.Fen_ControlBackground, diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 50faa3597..3273eb248 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -4,8 +4,6 @@ namespace AngelLoader.Forms.CustomControls.LazyLoaded; -// @DockUI: This is always constructed - make it unloaded until panel un-fullscreened - internal sealed class Lazy_LowerTabControl : IDarkable { internal bool Constructed { get; private set; } @@ -68,6 +66,7 @@ internal void Construct() _tabControl.MouseClick += _owner.LowerFMTabsBar_MouseClick; container.MouseClick += _owner.LowerFMTabsBar_MouseClick; + _owner.BottomFMTabsEmptyMessageLabel.MouseClick += _owner.LowerFMTabsBar_MouseClick; _tabControl.Selected += TabControl_Selected; _tabControl.MouseDragCustom += _owner.Lazy_LowerTabControl_MouseDragCustom; @@ -76,8 +75,6 @@ internal void Construct() container.Controls.Add(_tabControl); - _owner.Lazy_BottomFMTabsEmptyMessageLabel.Show(true); - _tabControl.Enabled = _enabled; Constructed = true; diff --git a/AngelLoader/Forms/MainForm.Designer.cs b/AngelLoader/Forms/MainForm.Designer.cs index 609608e6f..71a639bbf 100644 --- a/AngelLoader/Forms/MainForm.Designer.cs +++ b/AngelLoader/Forms/MainForm.Designer.cs @@ -110,6 +110,7 @@ private void InitializeComponent() this.PatchTabPage = new AngelLoader.Forms.CustomControls.PatchTabPage(); this.ModsTabPage = new AngelLoader.Forms.CustomControls.ModsTabPage(); this.ScreenshotsTabPage = new AngelLoader.Forms.CustomControls.ScreenshotsTabPage(); + this.TopFMTabsEmptyMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.LowerSplitContainer = new AngelLoader.Forms.CustomControls.DarkSplitContainerCustom(); this.ReadmeEncodingButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ReadmeFullScreenButton = new AngelLoader.Forms.CustomControls.DarkButton(); @@ -118,6 +119,7 @@ private void InitializeComponent() this.ReadmeResetZoomButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.ChooseReadmeComboBox = new AngelLoader.Forms.CustomControls.DarkComboBoxWithBackingItems(); this.ReadmeRichTextBox = new AngelLoader.Forms.CustomControls.RichTextBoxCustom(); + this.BottomFMTabsEmptyMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.BottomFMTabsMenuButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.BottomFMTabsCollapseButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.MainToolTip = new AngelLoader.Forms.CustomControls.ToolTipCustom(this.components); @@ -300,6 +302,7 @@ private void InitializeComponent() this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabsMenuButton); this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabsCollapseButton); this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabControl); + this.TopSplitContainer.Panel2.Controls.Add(this.TopFMTabsEmptyMessageLabel); this.TopSplitContainer.Size = new System.Drawing.Size(1671, 309); this.TopSplitContainer.SplitterDistance = 1116; this.TopSplitContainer.TabIndex = 0; @@ -981,6 +984,19 @@ private void InitializeComponent() this.ScreenshotsTabPage.TabIndex = 5; this.ScreenshotsTabPage.Text = "Screenshots"; // + // TopFMTabsEmptyMessageLabel + // + this.TopFMTabsEmptyMessageLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TopFMTabsEmptyMessageLabel.Location = new System.Drawing.Point(0, 0); + this.TopFMTabsEmptyMessageLabel.Name = "TopFMTabsEmptyMessageLabel"; + this.TopFMTabsEmptyMessageLabel.Size = new System.Drawing.Size(533, 309); + this.TopFMTabsEmptyMessageLabel.TabIndex = 16; + this.TopFMTabsEmptyMessageLabel.Text = "[empty message]"; + this.TopFMTabsEmptyMessageLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.TopFMTabsEmptyMessageLabel.PaintCustom += new System.EventHandler(this.FMTabsEmptyMessageLabels_Paint); + // // LowerSplitContainer // this.LowerSplitContainer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) @@ -1006,6 +1022,7 @@ private void InitializeComponent() // LowerSplitContainer.Panel2 // this.LowerSplitContainer.Panel2.BackColor = System.Drawing.SystemColors.Control; + this.LowerSplitContainer.Panel2.Controls.Add(this.BottomFMTabsEmptyMessageLabel); this.LowerSplitContainer.Panel2.Controls.Add(this.BottomFMTabsMenuButton); this.LowerSplitContainer.Panel2.Controls.Add(this.BottomFMTabsCollapseButton); this.LowerSplitContainer.Size = new System.Drawing.Size(1671, 357); @@ -1124,6 +1141,19 @@ private void InitializeComponent() this.ReadmeRichTextBox.Text = ""; this.ReadmeRichTextBox.MouseLeave += new System.EventHandler(this.ReadmeArea_MouseLeave); // + // BottomFMTabsEmptyMessageLabel + // + this.BottomFMTabsEmptyMessageLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.BottomFMTabsEmptyMessageLabel.Location = new System.Drawing.Point(0, 0); + this.BottomFMTabsEmptyMessageLabel.Name = "BottomFMTabsEmptyMessageLabel"; + this.BottomFMTabsEmptyMessageLabel.Size = new System.Drawing.Size(533, 357); + this.BottomFMTabsEmptyMessageLabel.TabIndex = 17; + this.BottomFMTabsEmptyMessageLabel.Text = "[empty message]"; + this.BottomFMTabsEmptyMessageLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.BottomFMTabsEmptyMessageLabel.PaintCustom += new System.EventHandler(this.FMTabsEmptyMessageLabels_Paint); + // // BottomFMTabsMenuButton // this.BottomFMTabsMenuButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); @@ -1307,9 +1337,11 @@ private void InitializeComponent() internal CustomControls.DarkButton TopFMTabsMenuButton; internal CustomControls.DarkArrowButton TopFMTabsCollapseButton; + internal CustomControls.DarkLabel TopFMTabsEmptyMessageLabel; internal CustomControls.DarkButton BottomFMTabsMenuButton; internal CustomControls.DarkArrowButton BottomFMTabsCollapseButton; + internal CustomControls.DarkLabel BottomFMTabsEmptyMessageLabel; #endregion diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 053a8c09b..0cf17e9ed 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -186,8 +186,6 @@ private enum ZoomFMsDGVType private readonly Lazy_FMTabsBlocker Lazy_BottomFMTabsBlocker; internal readonly Lazy_UpdateNotification Lazy_UpdateNotification; private readonly Lazy_LowerTabControl Lazy_LowerTabControl; - private readonly Lazy_EmptyTabAreaMessageLabel Lazy_TopFMTabsEmptyMessageLabel; - internal readonly Lazy_EmptyTabAreaMessageLabel Lazy_BottomFMTabsEmptyMessageLabel; #endregion @@ -588,14 +586,10 @@ but whatever... Lazy_TopFMTabsBlocker = new Lazy_FMTabsBlocker(this), Lazy_BottomFMTabsBlocker = new Lazy_FMTabsBlocker(this), Lazy_UpdateNotification = new Lazy_UpdateNotification(this), - Lazy_LowerTabControl = new Lazy_LowerTabControl(this), - Lazy_TopFMTabsEmptyMessageLabel = new Lazy_EmptyTabAreaMessageLabel(this), - Lazy_BottomFMTabsEmptyMessageLabel = new Lazy_EmptyTabAreaMessageLabel(this) + Lazy_LowerTabControl = new Lazy_LowerTabControl(this) }; Lazy_TopFMTabsBlocker.SetWhich(WhichTabControl.Top); Lazy_BottomFMTabsBlocker.SetWhich(WhichTabControl.Bottom); - Lazy_TopFMTabsEmptyMessageLabel.SetWhich(WhichTabControl.Top); - Lazy_BottomFMTabsEmptyMessageLabel.SetWhich(WhichTabControl.Bottom); #endregion @@ -677,6 +671,9 @@ and does NOT have its text transferred over. It ends up with blank text. // For right-clicking on blank space in tab bar TopSplitContainer.Panel2.MouseClick += TopFMTabsBar_MouseClick; + // For right-clicking on the tab area when no tabs are present + TopFMTabsEmptyMessageLabel.MouseClick += TopFMTabsBar_MouseClick; + #region Construct + init non-public-release controls #if DEBUG || (Release_Testing && !RT_StartupOnly) @@ -1884,8 +1881,8 @@ private void Localize(bool startup) Lazy_FMTabsMenu.Localize(); - Lazy_TopFMTabsEmptyMessageLabel.SetText(LText.FMTabs.EmptyTabAreaMessage); - Lazy_BottomFMTabsEmptyMessageLabel.SetText(LText.FMTabs.EmptyTabAreaMessage); + TopFMTabsEmptyMessageLabel.Text = LText.FMTabs.EmptyTabAreaMessage; + BottomFMTabsEmptyMessageLabel.Text = LText.FMTabs.EmptyTabAreaMessage; StatisticsTabPage.Text = LText.StatisticsTab.TabText; EditFMTabPage.Text = LText.EditFMTab.TabText; @@ -5505,7 +5502,7 @@ private void MainSplitContainer_FullScreenChanged(object sender, EventArgs e) } } - internal void TopFMTabsBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Top); + private void TopFMTabsBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Top); internal void LowerFMTabsBar_MouseClick(object sender, MouseEventArgs e) => HandleTabsMenu(e, WhichTabControl.Bottom); @@ -5692,27 +5689,28 @@ internal void ShowFMTab(WhichTabControl which, TabPage tabPage) { if (which == WhichTabControl.Bottom) { - Lazy_BottomFMTabsEmptyMessageLabel.Show(false); + BottomFMTabsEmptyMessageLabel.Hide(); Lazy_LowerTabControl.TabControl.ShowTab(tabPage, true); } else { - Lazy_TopFMTabsEmptyMessageLabel.Show(false); + TopFMTabsEmptyMessageLabel.Hide(); TopFMTabControl.ShowTab(tabPage, true); } } internal void HideFMTab(WhichTabControl which, TabPage tabPage) { - (DarkTabControl tabControl, Lazy_EmptyTabAreaMessageLabel emptyMessageLabel) = + (DarkTabControl tabControl, DarkLabel emptyMessageLabel) = which == WhichTabControl.Bottom - ? (Lazy_LowerTabControl.TabControl, Lazy_BottomFMTabsEmptyMessageLabel) - : (TopFMTabControl, Lazy_TopFMTabsEmptyMessageLabel); + ? (Lazy_LowerTabControl.TabControl, BottomFMTabsEmptyMessageLabel) + : (TopFMTabControl, TopFMTabsEmptyMessageLabel); tabControl.ShowTab(tabPage, false); if (tabControl.TabCount == 0) { - emptyMessageLabel.Show(true); + emptyMessageLabel.BringToFront(); + emptyMessageLabel.Show(); } } @@ -5734,4 +5732,13 @@ private static Color GetOverlayColor() } #endregion + + // @DockUI: Lazy-load the empty message labels + private void FMTabsEmptyMessageLabels_Paint(object sender, PaintEventArgs e) + { + DarkLabel label = BottomFMTabsEmptyMessageLabel; + e.Graphics.DrawRectangle( + Config.DarkMode ? DarkColors.LighterBackgroundPen : SystemPens.ControlLight, + new Rectangle(0, 0, label.ClientRectangle.Width - 1, label.ClientRectangle.Height - 1)); + } } diff --git a/AngelLoader/Forms/MainForm.resx b/AngelLoader/Forms/MainForm.resx index 8e0748c67..abb45a43a 100644 --- a/AngelLoader/Forms/MainForm.resx +++ b/AngelLoader/Forms/MainForm.resx @@ -124,89 +124,89 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 - ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAE - EwAAAk1TRnQBSQFMAgEBBAEAARABHAEQARwBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAG + EwAAAk1TRnQBSQFMAgEBBAEAAQgBHAEIARwBEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgADBQEGA0IBdANP AZkDVQGxA1sBygNWAbUDTAGRA0YBgAMcAScoAAMNAREDSgGLA1ABmgMeASsYAAMDAQQDVQGtA1gBvQNO AZYDYAHgA1ABnzQAAwIBAwMZASIDWgHHA1IBoANBAXMDQAFvAzQBUwMpAT0DHQEpAx4BKgMPARMDBQEG DAADIwEzA2AB6AMAAf8DAAH/AwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/Az4BahgAAwwBEAMFAQYEAAMr AUECAAGXAf8DAAH/A0ABcAwAAwMEBAEFBAADBQEGAYYBiwEAAf8ByQHNAQAB/wGQAZYBAAH/AaoBugEA Af8DWgHHAy0BRgMZASIDKAE7AzkBXgNCAXQDPwFuAzkBXgMIAQoMAAQBAw8BFAMuAUgDVgGwA0AB/QNA - Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABYAF8AYAB/gMAAf8DWgHE + Af0DQAH9A0AB/QNcAfgDXgHiA2AB4wNeAdIDUAGcAzABSwMGAQcEAAMYASABXwF7AYAB/gMAAf8DWgHE ASMBXgEhAfsDAAH/AgABnAH/AwAB/wMAAf8DWwHkA0EB+QMAAf8DQwF3DAADCQEMA1ABnwNdAckDPQFo A0YBgQNdAc8BAAGVAcoB/wMAAf8DXgHXA0MBdgMzAVEDVgGwA0YBfgMTARkIAAMsAUMDYQHiAv8BAAH/ - A1wB2QKAAVoB/gNbAdADWwHYA18B2gMAAf8DAAH/AwAB/wNdAd8DFQEdDAADCwEOA00BkgNZAe8BAAEQ + A1wB2QKAAVkB/gNbAdADWwHYA18B2gMAAf8DAAH/AwAB/wNdAd8DFQEdDAADCwEOA00BkgNZAe8BAAEQ AQAB/wMAAf8BCgEMAQcB/wEmAT0BOgH/AR8BMgEwAf8BAAEQAQAB/wMAAf8BBgEjAQAB/wEDASIBAAH/ A14B8ANEAXkDCAEKBAADXQHRAwAB/wNLAYwDXQHMAwAB/wMAAf8CAAGYAf8CAAGWAf8DQAH9A1wB+ANR AaQDUQH3AwAB/wMiATEIAAMfASwBAAGOAacB/wIAAZoB/wMAAf8BAAGUAb0B/wEAAc4C/wEAAbEB3gH/ AQABmAHSAf8BAAGFAcoB/wMAAf8DKwH8AQABpwHIAf8DWQHvAx4BKwwAA0YBfQG8AcEBAAH/A1UBtANO - AZYDSQGFA2AB2wNWAbMDQgF1A04BlQHGAc0BAAH/A10B6gMZASMIAAQBAzYBWANhAeYBawGAAVoB/gES - AUkBAAH/AQwBNAEAAf8BLAI1Af8BDwEWARcB/wEXAh8B/wEXAR0BHgH/AQoBNgEAAf8BCgEkAQAB/wKA - AWwB/gNhAesDQAFxAwwBEAM0AVMDAAH/A2AB4AMuAUgDXQHqAwAB/wMAAf8DAAH/AwAB/wNNAfoDAAH/ - A0YBgQNOAZcDAAH/A1YBsAwAA0QBewEAAbIB2AH/AQABtwH1Af8BAAHRAfkB/wEAAZkBngH/AQABswHP - Af8BAAGOAa0B/wEAAbIBxwH/AQAB1wL/AQAB6wL/AQABnQGhAf8DTwGbAw4BEgwAA0YBgAHFAckBAAH/ - A1EBngMkATUDWAG6A10B7ANfAdoDPQFoAzUBVgHBAccBAAH/A2AB4wMZASIIAAMJAQwDTQGSAVgCVwH+ - AwAB/wMAAf8BIwEpASoB/wGBAYwBjgH/AT4BRwFLAf8BIQErATIB/wFbAYQBhgH/AQsBDwERAf8DAAH/ - ARUBAAEDAf8DQAH9A1YBtQMZASMDWAG9AwAB/wNdAdQDHgEqA1kBwwMAAf8DQAH9AgABvAH/AwAB/wMA - Af8DAAH/AygBOwM1AVYDAAH/AiEBIwH7AxMBGggAA1ABnQEAAa0B6wH/AQABoQHKAf8DAAH/AwAB/wEA - AZQBtwH/AgABggH/AwAB/wEAAZkBnwH/AQAB6AL/AwAB/wNMAY4DBQEGDAADSAGEAboBvwEAAf8DXQHc - AWwBbQFRAfcB2AHoAQAB/wG3AboBAAH/AdwB4QEAAf8DAAH/A1kBwwHBAcYBAAH/A10B3wMYASEIAAM4 - BFwB1gMrAfwDAAH/AQYBCgEMAf8BoQGnAaYB/wGEAYwBjQH/ASsBNwE/Af8BDgEdASYB/wGSAZgBmQH/ - AVABVgFXAf8DAAH/AwAB/wNNAfoDSwGMAw8BFANeAe0DAAH/AysB/ANFAXwDPQFpA00B+gEpAjIB+wNN - AfoBaAFtAYAB/gMrAfwDUwGmBAADPgFrAwAB/wMAAf8DOAFbBAIDOQFfAQABgQGkAf8BAAG0Ae4B/wMA - Af8DAAH/AwAB/wEAAYwBuAH/AwAB/wGCAgAB/wMAAf8BAAG4Ac4B/wEAAYUBxAH/A14B3QM6AWADFQEc - CAADRwGDAZUBmwEAAf8DAAH/AdsB6wEAAf8DVQGvAxABFQJTAVIBpQHDAcoBAAH/A1wB5wGoAbABAAH/ - A2IB4QMbASUIAANJAYcBZwFmAWcB/gEEAQABAgH/AwAB/wFRAVkBWgH/AasCsgH/AYsBlwGbAf8BSAFX - AYEB/wE2AUoBUgH/AasCsgH/AaMBqAGpAf8BHAEfASMB/wEVAQkBDgH/A0AB/QNbAdMDKgE/A0gB9gIA - AZoB/wMAAf8DAAH/A1QBqwNfAdUDAAH/A0gB9gFvAYABYwH+A2AB6ANeAdcDOwFlA0oBigIAAYgB/wIA - AZ8B/wM/AWwDXwHaAwAB/wEAAbIB4wH/AQABjgGpAf8DAAH/AwAB/wMAAf8BAAGRAcMB/wMAAf8DAAH/ - AwAB/wMAAf8BAAGwAe4B/wMAAf8DAAH/A04BlggAA0cBgwEAAYYBAAH/AdcB3AEAAf8DAAH/A1ABnQMb - ASUDVQGsAcIBzgEAAf8DXAHZAaABqgEAAf8DWgHpAx4BKggAA0YBfQNNAfoBDwEeAQAB/wEiATEBEwH/ - ATUBTgE5Af8BKAFSAUYB/wEUASQBJgH/AVABXQGEAf8BNQFEAUgB/wEZATABLAH/ASMBPgE5Af8BLAE4 - ATIB/wEOARABCAH/AQwBCQEIAf8DagH+A0ABcANRAfcDAAH/A1wB+ANfAeUDXAH4AwAB/wNIAfYDTQH6 - AysB/AEhATIBIQH7A1gBvQMpAT0DXgHXAgABkgH/AwAB/wM+AWoCAAGGAf8BAAGoAdIB/wEAAdIC/wIA - AYQB/wMAAf8DAAH/AwAB/wEAAYoBwQH/AwAB/wMAAf8DAAH/AwAB/wEAAbwB9gH/AQABqgHeAf8CAAGZ - Af8DUgGoCAADQwF2AYcBkwEAAf8CaAFBAfkB3gHhAQAB/wMAAf8DAAH/Ac4B4AEAAf8CXgFcAdkDQQFz - AasBtAEAAf8DXgHtAxUBHQgAAywBQwNdAeoBHAFAAQQB/wERAUMBAAH/AQMBIgEAAf8BFwEfASAB/wE+ - AUoBTAH/Aa0CtQH/AaUBrAGtAf8BMwE9AT8B/wEAAQQBBQH/AQ0BOAEAAf8BPwGjAQAB/wEbAU4BAAH/ - A0EB+QM4AVsDXQHsAgABkgH/AQABiQG4Af8DYAHgA0gBhAMqAT8DTgGYAkcBagH5AwAB/wNGAX0EAANN - AZICAAGJAf8CAAGcAf8DAAH/AzQBVAMYASEDRwGCAQABwAHoAf8CAAGEAf8DAAH/AwAB/wMAAf8BAAGk - AcgB/wMAAf8DAAH/AwAB/wMAAf8BAAG6AfkB/wNiAe4DQQFzAxgBIAgAA1ABnQGgAasBAAH/A1sBzQNa - AcQCbQFRAfcBgwGLAQAB/wNfAeUDPQFoAzkBXwGrAbEBAAH/A2AB8wM6AWEDGQEiAwkBDAMhAS8DYAHz - AQUBDwEAAf8DAAH/AQoBEQETAf8BOwFAAUEB/wGcAaIBoAH/Ad4C4AH/AdkC3QH/AZQBmgGZAf8BKAEv - ATEB/wEBAQcBCgH/AwAB/wEXATkBAAH/A00B+gM+AWsDVgG2AgABmAH/AwAB/wIAAYgB/wNeAd0DNAFU - A1UBrgGXAakB3QH/Al4BXwH7A0cBgwNSAaUDAAH/AwAB/wMAAf8DTQH6Aw8BFAQABAEBXQJlAewBAAGh - AeYB/wMAAf8BggIAAf8DAAH/AQABjAG4Af8DAAH/AwAB/wMAAf8CAAG9Af8BAAGWAcAB/wNWAbIDAwEE - BAADGQEjA1sB0wGEAYYBAAH/AdEB1wEAAf8DXAH4A10B3wNiAe4DUQH3A18B5QNgAeMCgAF2Af4B0QHX - AQAB/wKAAXMB/gKAAV0B/gNiAe4DKgFAAwkBDANYAb0DAAH/AQICAAH/ARoBFwEcAf8BUAJWAf8BxQLJ - Af8B3wHjAeIB/wHgAeQB4wH/AbkCvgH/AjoBPQH/AwAB/wEFAgAB/wFfAVwBXQH+A1kBwwMhAS8DMAFK - AwAB/wMAAf8CAAGfAf8BAAGBAbYB/wMAAf8DYAHzAwAB/wNcAfgDTQH6AQABhAGyAf8DAAH/AwAB/wMA - Af8DUwGmDAADQgF1AQAB4wL/AQABlAHMAf8DAAH/AwAB/wEAAYABsQH/AwAB/wMAAf8CAAGOAf8BAAG5 - AfsB/wMAAf8DTAGOAxIBFwQAAyUBNwMAAf8B2wHcAY4B/wH4AfsBnQH/AaUBqAEAAf8CXwEyAfsBlwGa - AQAB/wNaAfUBkAGSAQAB/wGkAacBAAH/AmIBWQHvAe0B8gGOAf8ByQHNAQAB/wGgAaUBAAH/A1sB2AMU - ARsDFQEcA2IB4QMAAf8BHwEPARUB/wEkASIBJwH/AT8BXAE6Af8BuAHLAbgB/wHYAt0B/wHdAuAB/wGn - AcQBoAH/ATwBTAEzAf8BDwEFAQoB/wMAAf8BdAFqAW0B/gNSAaADDgESBAADWwHFAwAB/wMAAf8DAAH/ - AgABhQH/AgABqgH/AwAB/wEAAYABmwH/AQABjgG4Af8DAAH/AwAB/wIAAbQB/wNNAfoDEwEZCAADGAEh - AVsCXQHKAQAB5QH6Af8BAAP/AQABxAH3Af8CAAGUAf8BAAGNAboB/wIAAZcB/wIAAcIB/wEAAdEC/wEA - AcoB7gH/AgABhwH/A1sB5AMhAS8IAAMCAQMDTQGTAbwBxgEAAf8DVgGwA14B4gMAAf8DZQHxAwAB/wM5 - AV4DUgGgAv8BAAH/AwAB/wNaAb8DFgEeBAADLQFFA0gB9gEZAQUBCgH/ARgBDgETAf8BFAEMAQ4B/wEu - AVUBGgH/AV0BnAFWAf8BjQGMAY4B/wGoAa8BsAH/AVUBowFCAf8BMAFHARQB/wMAAf8BAwIAAf8BZgFj - AWQB/gNYAbcDEgEXBAADDgESA10B6gMAAf8DAAH/AgABnAH/AwAB/wIAAY8B/wMAAf8DAAH/AwAB/wIA - AaQB/wIAAYYB/wMtAUUMAAMgAS0BAAGVAawB/wEAAYABkgH/A1EBoQNdAeoBAAHiAfgB/wEAAd4B8wH/ - AQABygHzAf8BAAGmAcgB/wNZAbsDWQG7AQABrwHQAf8DVwG8AwsBDgwAAyYBOQNdAcwDJQE3A1MBqQNS - AaADVQGsA1UBrwNDAXYDgAH+AbQBuAEAAf8BuwHHAQAB/wNlAfEDMgFPBAADQgF0A1wBywMrAfwDKwH8 - AR0BRAEGAf8BLwE3ARgB/wE3AUIBIgH/ASgBGwEhAf8BLAEpASsB/wE0AYEBEwH/ASYBQgEOAf8BHgE0 - AQMB/wEBAgAB/wFnAV0BYQH+A04BlQMKAQ0IAAMVAR0DWgHHAwAB/wMAAf8DAAH/AwAB/wMAAf8DAAH/ - AgABkQH/Al4BYQHiAy0BRRQAAyYBOAMzAVEEAAMMAQ8DRAF7AQAB7AL/AQABggGUAf8DSgGJAwQBBQMD - AQQDNAFUAw0BESwAA10B0QHJAdIBAAH/A0sBjwJtAVEB9wGbAagBAAH/Az4BagQAAwMBBAMMAQ8DNQFW - A1EBpAFBAUcBQQH5A0gB9gEzAS8BHgH/ASYBHAEgAf8BHwEYARoB/wEYAS0BAQH/AXgBcQFzAf4CgAFp - Af4DXgHtA0wBkAMjATMEAhAAAzsBYwNZAb4DXgHwA2UB8QNlAfEDWwHNA0MBdwMGAQgoAAMQARUDZQHx - A2AB4EAAA0QBeQNSAaUEAANGAYEDWQHBAw8BFAQAAwQBBQQABAEDOAFcA0IBdANGAX4DUwGqA1UBrQNY - AboDWgHEA1EBogNUAasDQAFvAwwBDwQBBAABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEAAQEGAAEB - FgAD/4EAAeABDwH8AT8BAwH/AeABAQHAAQcB5AE5AQABAwGAAQABgAEDAYABAQGAAQMBgAEAAYABAQGA - AQEBwAEDAwABAQHAAQEBwAEDBAABwAEBAcABAwMAARACAAHAAQMGAAHAAQMGAAHAAQMDAAEgAgABwAUA - AYABAQUAAQEBwAEBBAABgAEBAYABAQGAAQECAAGAAQMBgAEBAcABAQIAAcABBwHIAQMB/wGBAgAB8AEP - AfwBfwH/AZEBQAEBCw== + AZYDSQGFA2AB2wNWAbMDQgF1A04BlQHGAc0BAAH/A10B6gMZASMIAAQBAzYBWANhAeYBagF/AVkB/gES + AUkBAAH/AQwBNAEAAf8BLAI1Af8BDwEWARcB/wEXAh8B/wEXAR0BHgH/AQoBNgEAAf8BCgEkAQAB/wF/ + AYABawH+A2EB6wNAAXEDDAEQAzQBUwMAAf8DYAHgAy4BSANdAeoDAAH/AwAB/wMAAf8DAAH/A00B+gMA + Af8DRgGBA04BlwMAAf8DVgGwDAADRAF7AQABsgHYAf8BAAG3AfUB/wEAAdEB+QH/AQABmQGeAf8BAAGz + Ac8B/wEAAY4BrQH/AQABsgHHAf8BAAHXAv8BAAHrAv8BAAGdAaEB/wNPAZsDDgESDAADRgGAAcUByQEA + Af8DUQGeAyQBNQNYAboDXQHsA18B2gM9AWgDNQFWAcEBxwEAAf8DYAHjAxkBIggAAwkBDANNAZIBVwJW + Af4DAAH/AwAB/wEjASkBKgH/AYEBjAGOAf8BPgFHAUsB/wEhASsBMgH/AVsBhAGGAf8BCwEPAREB/wMA + Af8BFQEAAQMB/wNAAf0DVgG1AxkBIwNYAb0DAAH/A10B1AMeASoDWQHDAwAB/wNAAf0CAAG8Af8DAAH/ + AwAB/wMAAf8DKAE7AzUBVgMAAf8CIQEjAfsDEwEaCAADUAGdAQABrQHrAf8BAAGhAcoB/wMAAf8DAAH/ + AQABlAG3Af8CAAGCAf8DAAH/AQABmQGfAf8BAAHoAv8DAAH/A0wBjgMFAQYMAANIAYQBugG/AQAB/wNd + AdwBbAFtAVEB9wHYAegBAAH/AbcBugEAAf8B3AHhAQAB/wMAAf8DWQHDAcEBxgEAAf8DXQHfAxgBIQgA + AzgEXAHWAysB/AMAAf8BBgEKAQwB/wGhAacBpgH/AYQBjAGNAf8BKwE3AT8B/wEOAR0BJgH/AZIBmAGZ + Af8BUAFWAVcB/wMAAf8DAAH/A00B+gNLAYwDDwEUA14B7QMAAf8DKwH8A0UBfAM9AWkDTQH6ASkCMgH7 + A00B+gFnAWwBgAH+AysB/ANTAaYEAAM+AWsDAAH/AwAB/wM4AVsEAgM5AV8BAAGBAaQB/wEAAbQB7gH/ + AwAB/wMAAf8DAAH/AQABjAG4Af8DAAH/AYICAAH/AwAB/wEAAbgBzgH/AQABhQHEAf8DXgHdAzoBYAMV + ARwIAANHAYMBlQGbAQAB/wMAAf8B2wHrAQAB/wNVAa8DEAEVAlMBUgGlAcMBygEAAf8DXAHnAagBsAEA + Af8DYgHhAxsBJQgAA0kBhwFmAWUBZgH+AQQBAAECAf8DAAH/AVEBWQFaAf8BqwKyAf8BiwGXAZsB/wFI + AVcBgQH/ATYBSgFSAf8BqwKyAf8BowGoAakB/wEcAR8BIwH/ARUBCQEOAf8DQAH9A1sB0wMqAT8DSAH2 + AgABmgH/AwAB/wMAAf8DVAGrA18B1QMAAf8DSAH2AW4BgAFiAf4DYAHoA14B1wM7AWUDSgGKAgABiAH/ + AgABnwH/Az8BbANfAdoDAAH/AQABsgHjAf8BAAGOAakB/wMAAf8DAAH/AwAB/wEAAZEBwwH/AwAB/wMA + Af8DAAH/AwAB/wEAAbAB7gH/AwAB/wMAAf8DTgGWCAADRwGDAQABhgEAAf8B1wHcAQAB/wMAAf8DUAGd + AxsBJQNVAawBwgHOAQAB/wNcAdkBoAGqAQAB/wNaAekDHgEqCAADRgF9A00B+gEPAR4BAAH/ASIBMQET + Af8BNQFOATkB/wEoAVIBRgH/ARQBJAEmAf8BUAFdAYQB/wE1AUQBSAH/ARkBMAEsAf8BIwE+ATkB/wEs + ATgBMgH/AQ4BEAEIAf8BDAEJAQgB/wNpAf4DQAFwA1EB9wMAAf8DXAH4A18B5QNcAfgDAAH/A0gB9gNN + AfoDKwH8ASEBMgEhAfsDWAG9AykBPQNeAdcCAAGSAf8DAAH/Az4BagIAAYYB/wEAAagB0gH/AQAB0gL/ + AgABhAH/AwAB/wMAAf8DAAH/AQABigHBAf8DAAH/AwAB/wMAAf8DAAH/AQABvAH2Af8BAAGqAd4B/wIA + AZkB/wNSAagIAANDAXYBhwGTAQAB/wJoAUEB+QHeAeEBAAH/AwAB/wMAAf8BzgHgAQAB/wJeAVwB2QNB + AXMBqwG0AQAB/wNeAe0DFQEdCAADLAFDA10B6gEcAUABBAH/AREBQwEAAf8BAwEiAQAB/wEXAR8BIAH/ + AT4BSgFMAf8BrQK1Af8BpQGsAa0B/wEzAT0BPwH/AQABBAEFAf8BDQE4AQAB/wE/AaMBAAH/ARsBTgEA + Af8DQQH5AzgBWwNdAewCAAGSAf8BAAGJAbgB/wNgAeADSAGEAyoBPwNOAZgCRwFqAfkDAAH/A0YBfQQA + A00BkgIAAYkB/wIAAZwB/wMAAf8DNAFUAxgBIQNHAYIBAAHAAegB/wIAAYQB/wMAAf8DAAH/AwAB/wEA + AaQByAH/AwAB/wMAAf8DAAH/AwAB/wEAAboB+QH/A2IB7gNBAXMDGAEgCAADUAGdAaABqwEAAf8DWwHN + A1oBxAJtAVEB9wGDAYsBAAH/A18B5QM9AWgDOQFfAasBsQEAAf8DYAHzAzoBYQMZASIDCQEMAyEBLwNg + AfMBBQEPAQAB/wMAAf8BCgERARMB/wE7AUABQQH/AZwBogGgAf8B3gLgAf8B2QLdAf8BlAGaAZkB/wEo + AS8BMQH/AQEBBwEKAf8DAAH/ARcBOQEAAf8DTQH6Az4BawNWAbYCAAGYAf8DAAH/AgABiAH/A14B3QM0 + AVQDVQGuAZcBqQHdAf8CXgFfAfsDRwGDA1IBpQMAAf8DAAH/AwAB/wNNAfoDDwEUBAAEAQFdAmUB7AEA + AaEB5gH/AwAB/wGCAgAB/wMAAf8BAAGMAbgB/wMAAf8DAAH/AwAB/wIAAb0B/wEAAZYBwAH/A1YBsgMD + AQQEAAMZASMDWwHTAYQBhgEAAf8B0QHXAQAB/wNcAfgDXQHfA2IB7gNRAfcDXwHlA2AB4wKAAXUB/gHR + AdcBAAH/AoABcgH+AoABXAH+A2IB7gMqAUADCQEMA1gBvQMAAf8BAgIAAf8BGgEXARwB/wFQAlYB/wHF + AskB/wHfAeMB4gH/AeAB5AHjAf8BuQK+Af8COgE9Af8DAAH/AQUCAAH/AV4BWwFcAf4DWQHDAyEBLwMw + AUoDAAH/AwAB/wIAAZ8B/wEAAYEBtgH/AwAB/wNgAfMDAAH/A1wB+ANNAfoBAAGEAbIB/wMAAf8DAAH/ + AwAB/wNTAaYMAANCAXUBAAHjAv8BAAGUAcwB/wMAAf8DAAH/AQABgAGxAf8DAAH/AwAB/wIAAY4B/wEA + AbkB+wH/AwAB/wNMAY4DEgEXBAADJQE3AwAB/wHbAdwBjgH/AfgB+wGdAf8BpQGoAQAB/wJfATIB+wGX + AZoBAAH/A1oB9QGQAZIBAAH/AaQBpwEAAf8CYgFZAe8B7QHyAY4B/wHJAc0BAAH/AaABpQEAAf8DWwHY + AxQBGwMVARwDYgHhAwAB/wEfAQ8BFQH/ASQBIgEnAf8BPwFcAToB/wG4AcsBuAH/AdgC3QH/Ad0C4AH/ + AacBxAGgAf8BPAFMATMB/wEPAQUBCgH/AwAB/wFzAWkBbAH+A1IBoAMOARIEAANbAcUDAAH/AwAB/wMA + Af8CAAGFAf8CAAGqAf8DAAH/AQABgAGbAf8BAAGOAbgB/wMAAf8DAAH/AgABtAH/A00B+gMTARkIAAMY + ASEBWwJdAcoBAAHlAfoB/wEAA/8BAAHEAfcB/wIAAZQB/wEAAY0BugH/AgABlwH/AgABwgH/AQAB0QL/ + AQABygHuAf8CAAGHAf8DWwHkAyEBLwgAAwIBAwNNAZMBvAHGAQAB/wNWAbADXgHiAwAB/wNlAfEDAAH/ + AzkBXgNSAaAC/wEAAf8DAAH/A1oBvwMWAR4EAAMtAUUDSAH2ARkBBQEKAf8BGAEOARMB/wEUAQwBDgH/ + AS4BVQEaAf8BXQGcAVYB/wGNAYwBjgH/AagBrwGwAf8BVQGjAUIB/wEwAUcBFAH/AwAB/wEDAgAB/wFl + AWIBYwH+A1gBtwMSARcEAAMOARIDXQHqAwAB/wMAAf8CAAGcAf8DAAH/AgABjwH/AwAB/wMAAf8DAAH/ + AgABpAH/AgABhgH/Ay0BRQwAAyABLQEAAZUBrAH/AQABgAGSAf8DUQGhA10B6gEAAeIB+AH/AQAB3gHz + Af8BAAHKAfMB/wEAAaYByAH/A1kBuwNZAbsBAAGvAdAB/wNXAbwDCwEODAADJgE5A10BzAMlATcDUwGp + A1IBoANVAawDVQGvA0MBdgOAAf4BtAG4AQAB/wG7AccBAAH/A2UB8QMyAU8EAANCAXQDXAHLAysB/AMr + AfwBHQFEAQYB/wEvATcBGAH/ATcBQgEiAf8BKAEbASEB/wEsASkBKwH/ATQBgQETAf8BJgFCAQ4B/wEe + ATQBAwH/AQECAAH/AWYBXAFgAf4DTgGVAwoBDQgAAxUBHQNaAccDAAH/AwAB/wMAAf8DAAH/AwAB/wMA + Af8CAAGRAf8CXgFhAeIDLQFFFAADJgE4AzMBUQQAAwwBDwNEAXsBAAHsAv8BAAGCAZQB/wNKAYkDBAEF + AwMBBAM0AVQDDQERLAADXQHRAckB0gEAAf8DSwGPAm0BUQH3AZsBqAEAAf8DPgFqBAADAwEEAwwBDwM1 + AVYDUQGkAUEBRwFBAfkDSAH2ATMBLwEeAf8BJgEcASAB/wEfARgBGgH/ARgBLQEBAf8BdwFwAXIB/gKA + AWgB/gNeAe0DTAGQAyMBMwQCEAADOwFjA1kBvgNeAfADZQHxA2UB8QNbAc0DQwF3AwYBCCgAAxABFQNl + AfEDYAHgQAADRAF5A1IBpQQAA0YBgQNZAcEDDwEUBAADBAEFBAAEAQM4AVwDQgF0A0YBfgNTAaoDVQGt + A1gBugNaAcQDUQGiA1QBqwNAAW8DDAEPBAEEAAFCAU0BPgcAAT4DAAEoAwABQAMAASADAAEBAQABAQYA + AQEWAAP/gQAB4AEPAfwBPwEDAf8B4AEBAcABBwHkATkBAAEDAYABAAGAAQMBgAEBAYABAwGAAQABgAEB + AYABAQHAAQMDAAEBAcABAQHAAQMEAAHAAQEBwAEDAwABEAIAAcABAwYAAcABAwYAAcABAwMAASACAAHA + BQABgAEBBQABAQHAAQEEAAGAAQEBgAEBAYABAQIAAYABAwGAAQEBwAEBAgABwAEHAcgBAwH/AYECAAHw + AQ8B/AF/Af8BkQFAAQEL @@ -279,78 +279,79 @@ iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGuSURBVDhPYxhQEKvEFB+nzHwiVoXlQ5wKyzso/R+EY5WZ - p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD4CuayqwkQUbBDME - hs9snf7/yKoeMHt9fyHYYKg23ADkwkJb2f8vb+/DMPDinnlArzMfjlVmWbN3UQtYDBQUUK3YAciFIAOx - uRCEbx5bAXLZeaBBOw6v7AaL4TUU5mVsLkTG1w4t/X96yzQw++3DI0BLWD5BjUAFQC+3FdnJETQQHb+6 - ewBk6FuoMQgAc+Gb+9i9jA9/eXUW5P1/UKMgABjoLcR4GRd+dn0nyKVPocYBvazM3FxsrwD2AjYNhPDH - Zyf+V3po/I9TZamBGgnyNsubV3f2Y9VACMMNVGbuhxoHAaCkAUoi2DThwx+fncRuIAjEK7OmpejwgNMe - Ns3YMMiFVZ6aoLQ6AWoMJgAZnKTJSZTBOL2MDSAMXonVMBCGuZAoA2EAGIPpuFxMkgvRATYXU2QgDEBc - zPX/yv5F/x9e3EK6l3GBOGWmOGDsHgcadi9WlaUUKjwQgIEBAExb1Vj6X25iAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAG4SURBVDhPYxhQEKvEFB+nxHQiVoXlQ5wKyzso/R+EY5WZ + p0UoMohDlRIHYlWYW4vs5f9fObDo/5v7h/6/vncQTH99fQ6MV3Vkgg2OV2dXgGrBD+KUmZsKbGTBBsEM + geEzW6f/P7KqB8xe318INhiqDTcAubDQVvb/y9v7MAy8uGce0OtMh2OVWdbsXdQCFgMFBVQrdgByIchA + bC4E4ZvHVvyPUWI6DzRox+GV3WAxvIbCvIzNhcj42qGl/09vmQZmv3145H+ELMsnqBGoAOjltiI7OYIG + ouNXdw/8j1FmeQs1BgFgLnxzH7uX8eEvr86CvP8PahQExKkwtxDjZVz42fWd/2OVWJ5CjQN6WZm5udhe + AewFbBoI4Y/PTvyv9ND4H6fKUgM1EuhKRZY3r+7sx6qBEIYbqMzcDzUOAkBJA5REsGnChz8+O4ndQBCI + V2ZNS9HhAac9bJqxYZALqzw1QbloAtQYTAAyOEmTkyiDcXoZG0AYvBKrYSAMcyFRBsIAMAbTcbmYJBei + A2wupshAGIC4mOv/lf2L/j+8uIV0L+MCccpMccAS/3icEvO9WFWWUqjwQAAGBgDeOtU9U5quUwAAAABJ + RU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VVPKARhFN+jNDO7KLmoLRcHBy7iIi6SFDks - TqtmZtlcpEQuOGjNzK4p5F/tKiku4qAkB8vGYg97cLCJkAs3N0fmN71PY7Raa8rFr17tfu997+/vfeP6 - hx28pPa6JbWa/joLt6g1lg3M3RQH9WdB1rrp2Bm4+0Le4uDMtS+WvPXFLh7Lh5YzvKxNkPqX8I8XGM7S - 7QuJs57V1BukO3b+UhLUX8jidxAkdbspsn/InENqp7aOeFHZIJP8gTZUja1/ZA5p1g/igqwmURmZ5Qcu - oHSg113R1Ctz3rl0mi4KRO4xEzLLD6Ai2IKBMuf4jTNemq4jMxtQUg5lFfrVMo8cziBb5hxVmMwx9oDM - bDAcc5K2B/k2iKFDf9Fn5hyCORjc18nKBnJeM7mZaNB2zQG5/bqHtJ/Ay+FFMMTqHAziZeWQTL4CdIJz - dgHZgddoBZmYMMof9A6vXFqHCu5zonaXLSFzWEZprx3LJyl2CdI6G0+YF4kNgqi2lA7MP3ZFL56ZDba2 - pH/mgQuEK01n2YAgnj7tqW3h+MQaBEFBOdARel80mWE6bCoCQkduvgeyQMbI3BoETMHK24NXjq6ljKpG - 6XpuQDsEUbnCoK3OrG2B1Id24nge6NrPgGFhwHamMEEl0OeyL9lhoa2VMZiBI8+ACXOhtFX0GkHQJnxM - 8FEhC2eAxcITUDESTQuS0k/HzgJPcvZn4E/hcr0DUbSOqjT7gYIAAAAASUVORK5CYII= + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIfSURBVEhL7VU7SMNQFO0o2qQtgnQRxcnBwUl0EV1ERFAc + Sp0qNulnE0EUF3WQmqQl+EEp1AoiOIkOgohDq8UPdujgYBFFxUW3bh01J9wnMVKpbcDFAxfad++733Nf + bP8wgxPkMYcgt9Nfa+HwKz3u8Oq9K6y+8aLipWNr4AhGml3h2J0nefHgSV6/NE7G85yozJO6SvjmajRn + uaH1zNXoVvYd4k1mCvVhtUAW1YEX5P3e2HGKOYd0LO6dcn5pl0wqB9rQNrvzmTmkTz1J86J8icrIrDLY + A9Iwej20nC0y5yMbFzlXIPaEmZBZZQAVwRYMlDnHb5xxwlInmZmAksooq9Ynu51iNI9smXNUoTNH2wMy + M0FzbBeUI8iPQTQd+os+M+cQzEHjvkpWJpDz9oXdTLdyqA/I4VOdpP0CToxugCFG52AQJ0opMvkO0AnO + 2QVkB16jFWSiQyt/omkqfmMcKrhf51ceSyWkD0srrTgcP8+yS5CBlXRGv0hs4P1yf0No7cWTuH5jNtja + +lD02R6IturOSgFBnEH5dXD97NwYBEFBOdARes/mZZ7psKkICB25+RnIAhkjc2MQMAUrbw7eOrOd1aqa + oevlAe3gx6VbDNrozNgWSFfkII3nga79DhgWBmxmChNUAn05+1IaBtoaGYMZWPIM6NAXStlCrxEEbcLH + BB8VsrAGWCw8AS3TiRwvSCE6thZ4kks/A38Km+0DB1GODuPZXHcAAAAASUVORK5CYII= iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGZSURBVEhL7ZQhUMNAEEUjGSZ3QSKRSCQSiUTiykzuChKJ - AweX60wkEolEIiuRSCQSicSyf/vDHEdpO00EgjeTafdfZu9u92+Kf3KMa04q1+wxHJaqjge2Di/WxTfr - 4zHlYahOr3eQvBxPdvHf+PgszxWXezK63EDCchyOqBTVqN0qfXhn2A/rmgdbNxcMFeMnt6YO9wzXB2XA - BgwVafS59c0TbkZpPVASlCZNhEaXdXxFHyitB6wIt6SJtNGiGXezTykDJ1nhWpujZhuOwWkpfTUac0Al - Q14oXXzEs3ATWUN9UWcqijbax5ZhBpPLC3faNEkAm3H1G+oOeRgqcJDxYcrwJ7ATkjNUF+C6KAUlZZ47 - 0Ght6i8HmjXLxw85xSElBbVM3YB1xOmmmFpo+KU0n84R+fejS4pTqmOSj5hOKtcoLaY7Te4C9bWMfL65 - 9iyb3qWoj8V+aDQlJe+FbNbm07syuLr6OXNKB26C9YVWXkpi2zQReoAy9v4MKJIYG3SDN3d6h2A2WChZ - mFoXzigPC5qOxjL8SxTFJ00CxZeT7IG4AAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGaSURBVEhL7ZQhUMQwEEXrYKBNkUgkEolEIpG4MjQ5kEgc + uKPNzVQikUgk8iQSiUQikVjy936YEErvpq1A8GY6d/vT2SS7f5v8E5Pp+iTX9R7DcclLe6BOqxel7Zsy + 9pjyOORn0x0kTyezXfzPjH12zzWXB1JcrSNhOqmOqCR50Wytmek7w2EoXT+osr5kKGRmdpuV1T3D/qAM + 2ICh4Bp9oUz9hJtR6gdKgtKEidDozdK+og+U+gErwi1hImm00zJ9s08pAidZ4VobRb0Nx+C0lL4ajTmg + EuFeSLV9xNO5iVtDfVFnKoI02tiGYQSTuxfupGkuAWzG1W+IO9zDUICDMlPNGf4EdkJyhuICXBeloCS0 + uQONlqb+cqBFs4z9cKc4pCSglqEbsI443BRTCw2/lNrxjoi/Hz4pTimOCT5iOLFfo9SNP03sAjgFIx9v + Lj2Lpncp4mNnPzSakhD3wm3WxNO7Mri6+Dlyigc3wXqnlZcS2DZMhB6gjIM/A4JLjA384LVO7xgsBgsl + q+ZKV+eUxwVNR2MZ/iWS5BPRbcV7uffSLwAAAABJRU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH/SURBVEhLzVTPK0RRGD1LS0tLS0tLS0tLS8v5D4wx5Ech - CVkgJSmSlCkJSVm+maEMCUmykB9JshCSjKTrO2++25g3b3h4C6dOvXfv/c798Z3vw7+D04Q6/QwfTjfK - kk04d+Ko0KFw4TQikumAkU0GdChciPD+8wJMugW3vI0OhwM5ffVRP4xZgzkdhuFtdCocJKOYuZvNbfCy - 6D7Tvk79HUzqdieyFLfkbXgrXfI3iFD0aiIvTvI2yUYkdElpSHClsFZZLz7vIekUoUOmYnh4WyncgNzp - xKtdk4xhxMYKG6ym9fbyZgvMxViO15Mw93M5vi4VC38mN7Zrb6fzGmrnfJ7kZ+KwD+Z91V/oJ6TL5PnW - i6zsRNG225U7lV/gd+ThjgdFXBynksWQd4tk2pGlFf1ESpGHOugVZ0kOVKo0ZFHdRjMeHuf9xbzkYSTh - Pys+WVzNxPsJeumeXByoocEgAZXMh5+glydDv9sgQjf4CXp5MyWJlTrQ0GCgbelrrxgr2GtldtgCzwcB - Az476SkBs9ft+jvBvmQbn+VGHNnALVyep5yVyEDaTwtny4mhyp2X5icHWGbDs5Wuza/WFfgOTBgD+ESb - rXhkPnSqALRzKo6Ly3GYs1HZQApVp74Gi4UWZR54Gx32BZ+F69MxvPBWOvw1tDPW6G8g8PmK2zfwAeUN - UaR56NgIAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAICSURBVEhLzVQ9SwNBEJ3S0tIypaWlpWVKS8v8AhMlET/A + iIiKhYogQVBEBAMiKiJYbmIEg4gREbEQPxCRFKJBJAki67zLLDGXi7mYK3zw4G535u3HvB36d1B95JdP + 76Gi1JLoozsVpjYZ8hYqSIH0MGleZEqGvAULZz42SasIZXEaGfYGvPuOy0nSep/0zSwvwqeRKW+QCNHq + y1ppgfyWdU0ZmWoeKGp6hAoQN8RpcCoJaQ4sFHqMlcVBnCYRpLiE1AYn+5hdwm72+RgIpzAVmOylt8/d + ygVAji+amEQ/zZlcZo/RNN7eOYqQvl8o8WmJ9Ot6icXtauGfxMImNrtS1hA7l+vEP7GLCdJfe85CjRAu + 4+s7qLKyCtHg6WhpV06J9YjNXU2zODtOJKvB9xZID1EBVnQSqUVs6nyc68I1EKna4CB/igub23AWsxOb + ORlp8PFxcAcK7yRop7VzdqCkugMn+FAPJ0E7r2f+tkAAbnAStPN5mQvL70BS3QG2ha/tYnjBdiujw1Z4 + 3g2Q8NNJ73HSZ1HL33H0JdP4DFNhKrhu4Xw9rXiJSIT95OEcq35qt+a5+fEGdtDwzEuX5tdlCdQDCoYE + XJEaoBzqIVMVgJ2TYbp/WCR9O8+x/FBl6nfgscCiqANOI8OOwLUg/jBIeZxKhn+HdMZO+XUFXF91+yb6 + BhrAUXeHueVSAAAAAElFTkSuQmCC iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANYSURBVDhPvZRJTFNRFIbPuS8xxmFjXDmGBUaNCxNduDCa - GDUmulOjiQsTo0QFKm0BESFlkEEZRLRMpS2zglBBhjJUJsGCMohIBFlolKCAKBAXosD13MeVCDGmuPDb - vL7/nHd67z3/ufDfydLDcrOPsv9+MCZWRLHW6ljWaY9mLeLdpFEOpHrAMpnqGimXYE9JGJZ1Z+PMWA1w - 3gJ82jn7HKf3l6QXh2NpqgZ2y0/+jkXPvJ5nIJ9+BvxrHfB2E048iscXlTcwzxGH3eJd6NNtwDszkZt1 - 7IL89M9YdOzsOxty3gG82YiDVl8WTKvZkO4HK5O8lH3W07DUooP1Qm8y4keRJ/LTdeyMLDGfVC07+Tqf - tvgUeEko671zETbKEBSFYOiLDKHjNSlBmhe4FYexfpHfn4/cpGMnZGgWqwGWVsewAd4O3BGLb5I14C5D - KqWRWDzZQLEYVi8llduesKkmDt+LFdfEsgFRR4ZolRrl6OdK4EOlyI1eymEpz/EwAnMmqEFVN7BMSnMY - vZWDQw+Bf64CnuajHJMygC0UrZP1wBsTWKuU5vGrqD0aC6U0j/pb2CV28iAMM1Qh1gNW1ydg/1Qj8Exf - tKjiAtSiDuAV0VhLTTmVG8B0WQHKIRmGe1fRPNUEvCERe6H0GhZVXcdXPVk4M/1YnCcbdsSjMzsQdsl8 - FeHZHxT/Qqv9UEJbpT9oT6eu62GbiOdewRgRdybjGNjC2MhENXWcGjTTTE868L488p6fckStJrkbyC4L - C5F/R7usONKdhWN18awr2x/WiTgVvSlWSkWH1a6XRzHnlCjYA/yTnY7AH6PVSgvI0MLaND24CZ9a/MBd - jLEMgS0EC7/T8TnimVMVkjSwg6aETwl/hrM28ucKNeAiJi2s6jTjx2/UqLxAjJCyuj2P8gisy9bDVim5 - jFmLEaLzb+8jT/GBnVKexWAAJn+6TJIn8+jLRT5DF01BENZK+d9J92bePTl0T3Sp09RLTpgba5ehS2VN - Ck1Pph87T35tGyynguQaMv6g6RJskWmuY9XB5idGHBsmd4zaqVgr8IFy4DYDaxK3mExbHFZf2N5BDhkn - 09OgfCmLRIdVy84VHAdFpiwecZ8Wh2KSPYp13gvCqFQt7C0wwBIZ/g2An2e+o9ziKCLsAAAAAElFTkSu - QmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANXSURBVDhPvZRJTJNREMdn3pcY43IxnlzDAaPGg4kePBhN + jBoTvanRxIOJUeIChbZUESSVpYCyyCJlKV0AQWVREBCECpUlBaUiECLIQaMEFVyAeBCFPud9PIkQY6oH + f5ev7z/zpm/ezBv47xToYbE1RNldGonpNXGsoz6JddUmsHaxtmiUPTkBsEi6+kZ2MOyojMZqdxZ6xxqA + 83bg0+6Z7zit20mviMGqHA1sl1v+jE3PAp85kE8/Af6lCbgnAycepmBP3VUsdiZjr1gLfboTeFc+cquO + nZFbf49Nx06+voOcPwXeloHD9lAWSadZk2eApeZAZZf9OCy06WC10Jsz8Z3wE/55OnZChphLjpYdfXGb + UnwMvNLI+q+fhbXSBOWXMarHQXoUxkoJcgPBrzyaDQr/wdvILTp2RJpmsBthYV0CG+Ie4A2J+DJLA/7S + pFJlworJR8CdicwlJZWMc7CuPhnfiBOL/SKONNEpNcrBT3XA31chzwxU9kt5lkoT3pigAj24gtVSmiUz + SNn7/h7wTw+A54Yoh6SspmefdAFvTmUdUprDz6D3E7BMSnNoSsNukcndaHSoQlIALHel4uBUM/D8ULSp + 4jzUoE4KGo+NVJRjRWFMVxCm7JNmuBmB1qlW4K507Id7sVhOKT3vMKN3ukW9sxFnCroLw2Gb9FcRPfud + 7J/ptG8rKVX6A08eVV0Pm4S96CImCntLKo5BWTQbnainilOBvG30pQsfKKbeMygH1GiSm+HsgmghjwM/ + dttxtDcfx5qSWXfheVgl7BT0mjgpPZYRtepVccw9JQL2Af9QS1dwHhPUSPNwaGFlrh78RJ/aDOAvnrE0 + QbkRy77R9TlTmFsVzBrY4rEgnxL9GcM6qT+XqAYfsWhhmceK775SoYrD0SRlNb2AGhM2Fepho5R8xqpF + k6j8q1Lk2SGwVcozGI3A5E+fMZ9jAQNFyL00aEoisFHK/05eEAvqu0Fzohs4jcV+6oTZZ+0zNFRWZNPr + yTew0/QIOodrKCB1jTMNhy3BsEG6+Y5dB+tFD45Qd3yspWAdwIdqgN8xslYxxaTb32EPhc1PqUPGqen7 + CvBzdRw67Vp2quQwKNLl7xHztCIKzbXxrOvWJYzP0cLOEiMskOZfAPgBbpejM2TyfeAAAAAASUVORK5C + YII= diff --git a/AngelLoader/Forms/MainForm_InitManual.cs b/AngelLoader/Forms/MainForm_InitManual.cs index 286350cfb..d9138ce21 100644 --- a/AngelLoader/Forms/MainForm_InitManual.cs +++ b/AngelLoader/Forms/MainForm_InitManual.cs @@ -87,6 +87,7 @@ private void InitComponentManual() PatchTabPage = new PatchTabPage(); ModsTabPage = new ModsTabPage(); ScreenshotsTabPage = new ScreenshotsTabPage(); + TopFMTabsEmptyMessageLabel = new DarkLabel(); LowerSplitContainer = new DarkSplitContainerCustom(); ReadmeEncodingButton = new DarkButton(); ReadmeFullScreenButton = new DarkButton(); @@ -95,6 +96,7 @@ private void InitComponentManual() ReadmeResetZoomButton = new DarkButton(); ChooseReadmeComboBox = new DarkComboBoxWithBackingItems(); ReadmeRichTextBox = new RichTextBoxCustom(); + BottomFMTabsEmptyMessageLabel = new DarkLabel(); BottomFMTabsMenuButton = new DarkButton(); BottomFMTabsCollapseButton = new DarkArrowButton(); @@ -249,6 +251,7 @@ private void InitComponentManual() TopSplitContainer.Panel2.Controls.Add(TopFMTabsMenuButton); TopSplitContainer.Panel2.Controls.Add(TopFMTabsCollapseButton); TopSplitContainer.Panel2.Controls.Add(TopFMTabControl); + TopSplitContainer.Panel2.Controls.Add(TopFMTabsEmptyMessageLabel); TopSplitContainer.Size = new Size(1671, 309); TopSplitContainer.SplitterDistance = 1116; TopSplitContainer.TabIndex = 0; @@ -565,6 +568,13 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir TopFMTabControl.MouseDragCustom += TopFMTabControl_MouseDragCustom; TopFMTabControl.MouseUp += TopFMTabControl_MouseUp; // + // TopFMTabsEmptyMessageLabel + // + TopFMTabsEmptyMessageLabel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + TopFMTabsEmptyMessageLabel.Size = new Size(533, 309); + TopFMTabsEmptyMessageLabel.TextAlign = ContentAlignment.MiddleCenter; + TopFMTabsEmptyMessageLabel.PaintCustom += FMTabsEmptyMessageLabels_Paint; + // // LowerSplitContainer // LowerSplitContainer.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; @@ -586,6 +596,7 @@ void SetFilterCheckButton(ToolStripButtonCustom button, Padding margin, bool dir // LowerSplitContainer.Panel2 // LowerSplitContainer.Panel2.BackColor = SystemColors.Control; + LowerSplitContainer.Panel2.Controls.Add(BottomFMTabsEmptyMessageLabel); LowerSplitContainer.Panel2.Controls.Add(BottomFMTabsMenuButton); LowerSplitContainer.Panel2.Controls.Add(BottomFMTabsCollapseButton); LowerSplitContainer.Size = new Size(1671, 357); @@ -637,6 +648,13 @@ void SetReadmeButton(DarkButton button, int x, int tabIndex) ReadmeRichTextBox.TabIndex = 0; ReadmeRichTextBox.MouseLeave += ReadmeArea_MouseLeave; // + // BottomFMTabsEmptyMessageLabel + // + BottomFMTabsEmptyMessageLabel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + BottomFMTabsEmptyMessageLabel.Size = new Size(533, 357); + BottomFMTabsEmptyMessageLabel.TextAlign = ContentAlignment.MiddleCenter; + BottomFMTabsEmptyMessageLabel.PaintCustom += FMTabsEmptyMessageLabels_Paint; + // // BottomFMTabsMenuButton // BottomFMTabsMenuButton.Anchor = AnchorStyles.Top | AnchorStyles.Right; From 87213d8bad9e3b9d2846dcbda251c187e3788c4a Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 09:35:02 -0800 Subject: [PATCH 184/200] Use correct collapse button for blocker size --- .../Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs index 5fa4a9b99..08ef274e7 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_FMTabsBlocker.cs @@ -58,12 +58,17 @@ private void Construct() ? _owner.LowerSplitContainer.Panel2 : _owner.TopSplitContainer.Panel2; + DarkArrowButton collapseButton = + _which == WhichTabControl.Bottom + ? _owner.BottomFMTabsCollapseButton + : _owner.TopFMTabsCollapseButton; + Panel = new DrawnPanel { Location = Point.Empty, Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom, Size = new Size( - container.Width - _owner.BottomFMTabsCollapseButton.Width, + container.Width - collapseButton.Width, container.Height), DarkModeDrawnBackColor = DarkColors.Fen_ControlBackground, From 5e3601fc1027c2c389d33889e34ca9ec403f2286 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 09:35:43 -0800 Subject: [PATCH 185/200] Add note --- AngelLoader/Forms/MainForm.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 0cf17e9ed..79760a313 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -13,6 +13,7 @@ -FM tab controls (the containers of the tab pages) (but can't really, because tab pages need to be added to a tab control before they can be considered to be in a proper working state) -Rating columns (text or image) - one or the other will not be shown +-Tab area empty message labels (but a pain due to Show() needing to be lazy executed as well) @NET5: Fonts will change and control sizes will all change too. -.NET 6 seems to have an option to set the font to the old MS Sans Serif 8.25pt app-wide. From 79db9651beca8739a36db6f7c61acd8ec73288b3 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 09:44:08 -0800 Subject: [PATCH 186/200] Fix lower tab control was always loaded --- AngelLoader/Forms/CustomControls/DarkTabControl.cs | 2 +- .../CustomControls/LazyLoaded/Lazy_LowerTabControl.cs | 2 +- AngelLoader/Forms/FormsInterfaces.cs | 7 +++++++ AngelLoader/Forms/MainForm.cs | 9 +++++++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index d27ec9dbd..fd4f37530 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -16,7 +16,7 @@ namespace AngelLoader.Forms.CustomControls; When we show/hide tabs, set the bool so that OnControlAdded()/OnControlRemoved() don't do anything while we update the backing list ourselves. */ -public sealed class DarkTabControl : TabControl, IDarkable +public sealed class DarkTabControl : TabControl, IDarkable, IOptionallyLazyTabControl { #region Private fields diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index 3273eb248..f02f78a0e 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -4,7 +4,7 @@ namespace AngelLoader.Forms.CustomControls.LazyLoaded; -internal sealed class Lazy_LowerTabControl : IDarkable +internal sealed class Lazy_LowerTabControl : IDarkable, IOptionallyLazyTabControl { internal bool Constructed { get; private set; } diff --git a/AngelLoader/Forms/FormsInterfaces.cs b/AngelLoader/Forms/FormsInterfaces.cs index 9cf9ce774..63c51597b 100644 --- a/AngelLoader/Forms/FormsInterfaces.cs +++ b/AngelLoader/Forms/FormsInterfaces.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using System.Windows.Forms; using AL_Common; namespace AngelLoader.Forms; @@ -138,3 +139,9 @@ public interface IListControlWithBackingItems : IUpdateRegion #endregion } + +public interface IOptionallyLazyTabControl +{ + public bool Enabled { get; set; } + public TabPage? SelectedTab { get; } +} diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 79760a313..9c72f98d0 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -3294,9 +3294,9 @@ private void LowerFMTabsCollapseButton_Click(object sender, EventArgs e) private void SetFMTabsCollapsedState(WhichTabControl which, bool collapsed) { - (DarkArrowButton collapseButton, DarkTabControl tabControl, Lazy_FMTabsBlocker blocker) = + (DarkArrowButton collapseButton, IOptionallyLazyTabControl tabControl, Lazy_FMTabsBlocker blocker) = which == WhichTabControl.Bottom - ? (BottomFMTabsCollapseButton, Lazy_LowerTabControl.TabControl, Lazy_TopFMTabsBlocker) + ? (BottomFMTabsCollapseButton, (IOptionallyLazyTabControl)Lazy_LowerTabControl, Lazy_TopFMTabsBlocker) : (TopFMTabsCollapseButton, TopFMTabControl, Lazy_BottomFMTabsBlocker); if (collapsed) @@ -3313,6 +3313,11 @@ private void SetFMTabsCollapsedState(WhichTabControl which, bool collapsed) tabControl.Enabled = true; } + if (tabControl == Lazy_LowerTabControl) + { + Lazy_LowerTabControl.Construct(); + } + if (tabControl.SelectedTab is Lazy_TabsBase lazyTab) { lazyTab.ConstructWithSuspendResume(); From 58609e5637db3b9040b84c1e0bfde661f835e48d Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 10:55:48 -0800 Subject: [PATCH 187/200] Group tab-related controls into a class So we don't need clunky ternaries all over the place --- .../Forms/CustomControls/DarkTabControl.cs | 10 +- .../LazyLoaded/Lazy_LowerTabControl.cs | 50 ++++- AngelLoader/Forms/FormsData.cs | 22 ++- AngelLoader/Forms/FormsInterfaces.cs | 17 +- AngelLoader/Forms/MainForm.cs | 177 ++++++++---------- 5 files changed, 171 insertions(+), 105 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index fd4f37530..df7f105bc 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -50,7 +50,7 @@ private void BackUpTempDragData() } } - internal void RestoreBackedUpBackingTabs() + public void RestoreBackedUpBackingTabs() { if (_backedUpBackingTabs == null || _backedUpBackingTabs.Count != _backingTabList.Count) { @@ -67,7 +67,7 @@ internal void RestoreBackedUpBackingTabs() _backedUpBackingTabs = null; } - internal void ResetTempDragData() + public void ResetTempDragData() { _backedUpBackingTabs = null; _backedUpNearestTabPage = null; @@ -589,5 +589,11 @@ public Rectangle GetTabBarRect() => ? Rectangle.Empty : new Rectangle(0, 0, Width, GetTabRect(0).Height); + public bool TabPagesContains(TabPage tabPage) => TabPages.Contains(tabPage); + + public Point ClientCursorPos() => Native.ClientCursorPos(this); + + public Point PointToClient_Fast(Point point) => Native.PointToClient_Fast(this, point); + #endregion } diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs index f02f78a0e..1a537928b 100644 --- a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_LowerTabControl.cs @@ -85,12 +85,12 @@ public void ShowTab(TabPage tabPage, bool show) if (show) { Construct(); - _owner.ShowFMTab(WhichTabControl.Bottom, tabPage); + _tabControl.ShowTab(tabPage, true); } else { if (!Constructed) return; - _owner.HideFMTab(WhichTabControl.Bottom, tabPage); + _tabControl.ShowTab(tabPage, false); } } @@ -112,7 +112,51 @@ public bool Enabled public int TabCount => Constructed ? _tabControl.TabCount : 0; - public TabPage? SelectedTab => Constructed ? _tabControl.SelectedTab : null; + public TabPage? SelectedTab + { + get => Constructed ? _tabControl.SelectedTab : null; + set + { + if (!Constructed) return; + _tabControl.SelectedTab = value; + } + } + + public bool TabPagesContains(TabPage tabPage) => Constructed && _tabControl.TabPages.Contains(tabPage); + + public Rectangle GetTabRect(int index) => Constructed ? _tabControl.GetTabRect(index) : Rectangle.Empty; + + public Rectangle GetTabBarRect() => Constructed ? _tabControl.GetTabBarRect() : Rectangle.Empty; + + public Rectangle ClientRectangle => Constructed ? _tabControl.ClientRectangle : Rectangle.Empty; + + public Point ClientCursorPos() => Constructed ? _tabControl.ClientCursorPos() : Point.Empty; + + public int Width => Constructed ? _tabControl.Width : 0; + + public int Height => Constructed ? _tabControl.Height : 0; + + public int SelectedIndex => Constructed ? _tabControl.SelectedIndex : -1; + + public void DrawToBitmap(Bitmap bitmap, Rectangle targetBounds) + { + if (!Constructed) return; + _tabControl.DrawToBitmap(bitmap, targetBounds); + } + + public Point PointToClient_Fast(Point point) => Constructed ? _tabControl.PointToClient_Fast(point) : Point.Empty; + + public void RestoreBackedUpBackingTabs() + { + if (!Constructed) return; + _tabControl.RestoreBackedUpBackingTabs(); + } + + public void ResetTempDragData() + { + if (!Constructed) return; + _tabControl.ResetTempDragData(); + } public TabPage? DragTab => Constructed ? _tabControl.DragTab : null; diff --git a/AngelLoader/Forms/FormsData.cs b/AngelLoader/Forms/FormsData.cs index 2a187d170..02e0e16c6 100644 --- a/AngelLoader/Forms/FormsData.cs +++ b/AngelLoader/Forms/FormsData.cs @@ -6,6 +6,7 @@ using AL_Common; using AngelLoader.DataClasses; using AngelLoader.Forms.CustomControls; +using AngelLoader.Forms.CustomControls.LazyLoaded; using AngelLoader.Forms.WinFormsNative; namespace AngelLoader.Forms; @@ -13,6 +14,7 @@ namespace AngelLoader.Forms; internal static class FormsData { internal const int ZoomTypesCount = 3; + internal const int WhichTabCount = 2; } /// @@ -33,6 +35,20 @@ public enum WhichTabControl Bottom } +internal sealed class FMTabControlGroup( + IOptionallyLazyTabControl tabControl, + DarkArrowButton collapseButton, + Lazy_FMTabsBlocker blocker, + DarkSplitContainerCustom splitter, + DarkLabel emptyMessageLabel) +{ + internal readonly IOptionallyLazyTabControl TabControl = tabControl; + internal readonly DarkArrowButton CollapseButton = collapseButton; + internal readonly Lazy_FMTabsBlocker Blocker = blocker; + internal readonly DarkSplitContainerCustom Splitter = splitter; + internal readonly DarkLabel EmptyMessageLabel = emptyMessageLabel; +} + /* Images loaded from files keep the file stream alive for their entire lifetime, insanely. This means the file is "in use" and will cause delete attempts (like FM uninstallation) to fail. So we need to use this workaround @@ -77,7 +93,7 @@ public sealed class TabControlImageCursor : IDisposable private static void DrawDateTimePickers( Control control, Graphics g, - TabControl tabControl, + IOptionallyLazyTabControl tabControl, int stackCounter = 0) { stackCounter++; @@ -97,7 +113,7 @@ private static void DrawDateTimePickers( } } - public TabControlImageCursor(TabControl tabControl) + public TabControlImageCursor(IOptionallyLazyTabControl tabControl) { Bitmap? bmpChopped = null; try @@ -142,7 +158,7 @@ public TabControlImageCursor(TabControl tabControl) srcUnit: GraphicsUnit.Pixel ); - if (Global.Config.DarkMode) + if (Global.Config.DarkMode && tabControl.SelectedTab != null) { DrawDateTimePickers( tabControl.SelectedTab, diff --git a/AngelLoader/Forms/FormsInterfaces.cs b/AngelLoader/Forms/FormsInterfaces.cs index 63c51597b..d6a8d9e8f 100644 --- a/AngelLoader/Forms/FormsInterfaces.cs +++ b/AngelLoader/Forms/FormsInterfaces.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using System.Drawing; using System.Windows.Forms; using AL_Common; @@ -143,5 +144,19 @@ public interface IListControlWithBackingItems : IUpdateRegion public interface IOptionallyLazyTabControl { public bool Enabled { get; set; } - public TabPage? SelectedTab { get; } + public TabPage? SelectedTab { get; set; } + void ShowTab(TabPage tabPage, bool show); + int TabCount { get; } + bool TabPagesContains(TabPage tabPage); + Rectangle GetTabRect(int index); + Rectangle GetTabBarRect(); + Rectangle ClientRectangle { get; } + Point ClientCursorPos(); + int Width { get; } + int Height { get; } + int SelectedIndex { get; } + void DrawToBitmap(Bitmap bitmap, Rectangle targetBounds); + Point PointToClient_Fast(Point point); + void ResetTempDragData(); + void RestoreBackedUpBackingTabs(); } diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 9c72f98d0..e9d964db2 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -125,6 +125,9 @@ need to check the accuracy of the selection itself (eg. in FMsDGV nav) so we can private readonly DarkButton[] _readmeControlButtons; + private readonly FMTabControlGroup[] _fmTabControlGroups = new FMTabControlGroup[FormsData.WhichTabCount]; + private FMTabControlGroup GetFMTabControlGroup(WhichTabControl which) => _fmTabControlGroups[(int)which]; + #endregion #region Enums @@ -641,6 +644,21 @@ and does NOT have its text transferred over. It ends up with blank text. InitComponentManual(); #endif + _fmTabControlGroups[(int)WhichTabControl.Top] = new FMTabControlGroup( + TopFMTabControl, + TopFMTabsCollapseButton, + Lazy_TopFMTabsBlocker, + TopSplitContainer, + TopFMTabsEmptyMessageLabel + ); + _fmTabControlGroups[(int)WhichTabControl.Bottom] = new FMTabControlGroup( + Lazy_LowerTabControl, + BottomFMTabsCollapseButton, + Lazy_BottomFMTabsBlocker, + LowerSplitContainer, + BottomFMTabsEmptyMessageLabel + ); + TopFMTabControl.SetBackingList(_backingFMTabs); TopFMTabControl.SetWhich(WhichTabControl.Top); @@ -3294,31 +3312,28 @@ private void LowerFMTabsCollapseButton_Click(object sender, EventArgs e) private void SetFMTabsCollapsedState(WhichTabControl which, bool collapsed) { - (DarkArrowButton collapseButton, IOptionallyLazyTabControl tabControl, Lazy_FMTabsBlocker blocker) = - which == WhichTabControl.Bottom - ? (BottomFMTabsCollapseButton, (IOptionallyLazyTabControl)Lazy_LowerTabControl, Lazy_TopFMTabsBlocker) - : (TopFMTabsCollapseButton, TopFMTabControl, Lazy_BottomFMTabsBlocker); + FMTabControlGroup group = GetFMTabControlGroup(which); if (collapsed) { - collapseButton.ArrowDirection = Direction.Left; - tabControl.Enabled = false; + group.CollapseButton.ArrowDirection = Direction.Left; + group.TabControl.Enabled = false; } else { - collapseButton.ArrowDirection = Direction.Right; + group.CollapseButton.ArrowDirection = Direction.Right; - if (!blocker.Visible) + if (!group.Blocker.Visible) { - tabControl.Enabled = true; + group.TabControl.Enabled = true; } - if (tabControl == Lazy_LowerTabControl) + if (group.TabControl == Lazy_LowerTabControl) { Lazy_LowerTabControl.Construct(); } - if (tabControl.SelectedTab is Lazy_TabsBase lazyTab) + if (group.TabControl.SelectedTab is Lazy_TabsBase lazyTab) { lazyTab.ConstructWithSuspendResume(); } @@ -3339,26 +3354,16 @@ private void LowerFMTabsMenuButton_Click(object sender, EventArgs e) internal void FMTabsMenu_Opening(object sender, CancelEventArgs e) { - (FMTabVisibleIn which, DarkTabControl tabControl) = Lazy_FMTabsMenu.Menu.Data is WhichTabControl.Bottom - ? (FMTabVisibleIn.Bottom, Lazy_LowerTabControl.TabControl) - : (FMTabVisibleIn.Top, TopFMTabControl); + WhichTabControl which = Lazy_FMTabsMenu.Menu.Data is WhichTabControl dataWhich + ? dataWhich + : WhichTabControl.Top; + + FMTabControlGroup group = GetFMTabControlGroup(which); for (int i = 0; i < _fmTabPages.Length; i++) { Lazy_TabsBase item = _fmTabPages[i]; - Lazy_FMTabsMenu.SetItemChecked(i, tabControl.TabPages.Contains(item)); - /* - @DockUI(FM per-tab show/hide menu logic) - I'm not sure which style is the best/most intuitive/principle-of-least-surprise etc. - They're all a little weird. Decide on something for the final release. - */ -#if false - BackingTab? backingTab = _backingFMTabs.FirstOrDefault(x => x.TabPage == item); - if (backingTab != null) - { - Lazy_FMTabsMenu.SetItemVisible(i, backingTab.VisibleIn == FMTabVisibleIn.None || backingTab.VisibleIn == which); - } -#endif + Lazy_FMTabsMenu.SetItemChecked(i, group.TabControl.TabPagesContains(item)); } } @@ -3368,9 +3373,11 @@ internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) TabPage tab = GetObjectFromMenuItem(Lazy_FMTabsMenu.Menu, s, _fmTabPages, FMTabCount); - DarkTabControl tabControl = s.Owner is DarkContextMenu { Data: WhichTabControl.Bottom } - ? Lazy_LowerTabControl.TabControl - : TopFMTabControl; + WhichTabControl which = s.Owner is DarkContextMenu { Data: WhichTabControl dataWhich } + ? dataWhich + : WhichTabControl.Top; + + FMTabControlGroup group = GetFMTabControlGroup(which); try { @@ -3389,36 +3396,29 @@ tab order gets messed up. */ if (s.Checked) { - HideFMTab(tabControl == TopFMTabControl ? WhichTabControl.Bottom : WhichTabControl.Top, tab); - ShowFMTab(tabControl == TopFMTabControl ? WhichTabControl.Top : WhichTabControl.Bottom, tab); + HideFMTab(which == WhichTabControl.Top ? WhichTabControl.Bottom : WhichTabControl.Top, tab); + ShowFMTab(which, tab); if (tab is Lazy_TabsBase lazyTab) { lazyTab.Construct(); } - (DarkSplitContainerCustom splitter, WhichTabControl which) = tabControl == TopFMTabControl - ? (TopSplitContainer, WhichTabControl.Top) - : (LowerSplitContainer, WhichTabControl.Bottom); - - if (splitter.FullScreen) + if (group.Splitter.FullScreen) { - splitter.ToggleFullScreen(); + group.Splitter.ToggleFullScreen(); SetFMTabsCollapsedState(which, false); } } else { - HideFMTab(tabControl == TopFMTabControl ? WhichTabControl.Top : WhichTabControl.Bottom, tab); + HideFMTab(which, tab); } } finally { if (s.Checked) { - TabPage? selectedTab = tabControl == TopFMTabControl - ? TopFMTabControl.SelectedTab - : Lazy_LowerTabControl.SelectedTab; - EverythingPanel.ResumeDrawingAndFocusControl(new Control?[] { tab, selectedTab }); + EverythingPanel.ResumeDrawingAndFocusControl(new Control?[] { tab, group.TabControl.SelectedTab }); } else { @@ -5516,17 +5516,15 @@ private void HandleTabsMenu(MouseEventArgs e, WhichTabControl which) { if (e.Button != MouseButtons.Right) return; - DarkTabControl tabControl = which == WhichTabControl.Bottom - ? Lazy_LowerTabControl.TabControl - : TopFMTabControl; + FMTabControlGroup group = GetFMTabControlGroup(which); - Rectangle rect = tabControl.GetTabBarRect(); + Rectangle rect = group.TabControl.GetTabBarRect(); if (rect == Rectangle.Empty) { - rect = tabControl.ClientRectangle; + rect = group.TabControl.ClientRectangle; } - if (rect.Contains(tabControl.ClientCursorPos())) + if (rect.Contains(group.TabControl.ClientCursorPos())) { Lazy_FMTabsMenu.Menu.Data = which; Lazy_FMTabsMenu.Menu.Show(Native.GetCursorPosition_Fast()); @@ -5559,12 +5557,12 @@ public void RefreshCurrentFMScreenshots() private void TopFMTabControl_MouseDragCustom(object sender, MouseEventArgs e) { - HandleTabDrag(dest: WhichTabControl.Bottom); + HandleTabDrag(source: WhichTabControl.Top, dest: WhichTabControl.Bottom); } internal void Lazy_LowerTabControl_MouseDragCustom(object sender, MouseEventArgs e) { - HandleTabDrag(dest: WhichTabControl.Top); + HandleTabDrag(source: WhichTabControl.Bottom, dest: WhichTabControl.Top); } private void TopFMTabControl_MouseUp(object sender, MouseEventArgs e) @@ -5577,49 +5575,50 @@ internal void Lazy_LowerTabControl_MouseUp(object sender, MouseEventArgs e) HandleTabDragFinish(WhichTabControl.Bottom, WhichTabControl.Top); } - private void HandleTabDrag(WhichTabControl dest) + private void HandleTabDrag(WhichTabControl source, WhichTabControl dest) { - (DarkTabControl tabControl, DarkSplitContainerCustom sc) = - (dest == WhichTabControl.Bottom) - ? (TopFMTabControl, LowerSplitContainer) - : (Lazy_LowerTabControl.TabControl, TopSplitContainer); + if (source == dest) return; - _tabControlImageCursor ??= new TabControlImageCursor(tabControl); + FMTabControlGroup sourceGroup = GetFMTabControlGroup(source); + FMTabControlGroup destGroup = GetFMTabControlGroup(dest); + + _tabControlImageCursor ??= new TabControlImageCursor(sourceGroup.TabControl); Cursor = _tabControlImageCursor.Cursor; Point cp = Native.GetCursorPosition_Fast(); - if (sc.FullScreen && sc.ClientRectangle.Contains(sc.PointToClient_Fast(cp))) + if (destGroup.Splitter.FullScreen && + destGroup.Splitter.ClientRectangle.Contains(destGroup.Splitter.PointToClient_Fast(cp))) { if (!_inTabDragArea) { _inTabDragArea = true; - using var gc = new Native.GraphicsContext(sc.Handle); + using var gc = new Native.GraphicsContext(destGroup.Splitter.Handle); using var b = new SolidBrush(GetOverlayColor()); - int splitterDistance = sc.SplitterDistanceLogical; + int splitterDistance = destGroup.Splitter.SplitterDistanceLogical; gc.G.FillRectangle( b, new Rectangle( splitterDistance, 0, - sc.ClientRectangle.Width - splitterDistance, - sc.ClientRectangle.Height)); + destGroup.Splitter.ClientRectangle.Width - splitterDistance, + destGroup.Splitter.ClientRectangle.Height)); } } - else if (sc.Panel2.ClientRectangle.Contains(sc.Panel2.PointToClient_Fast(cp))) + else if (destGroup.Splitter.Panel2.ClientRectangle.Contains(destGroup.Splitter.Panel2.PointToClient_Fast(cp))) { if (!_inTabDragArea) { _inTabDragArea = true; - using var gc = new Native.GraphicsContext(sc.Panel2.Handle); + using var gc = new Native.GraphicsContext(destGroup.Splitter.Panel2.Handle); using var b = new SolidBrush(GetOverlayColor()); - gc.G.FillRectangle(b, sc.Panel2.ClientRectangle with { X = 0, Y = 0 }); + gc.G.FillRectangle(b, destGroup.Splitter.Panel2.ClientRectangle with { X = 0, Y = 0 }); } } else if (_inTabDragArea) { _inTabDragArea = false; - sc.Refresh(); + destGroup.Splitter.Refresh(); } } @@ -5645,11 +5644,9 @@ private void HandleTabDragFinish(WhichTabControl source, WhichTabControl dest) finally { DestroyImageCursor(); - // @DockUI: Have a better way to choose controls than this bulky ternary all the time - DarkTabControl sourceTabControl = source == WhichTabControl.Bottom - ? Lazy_LowerTabControl.TabControl - : TopFMTabControl; - sourceTabControl.ResetTempDragData(); + + FMTabControlGroup sourceGroup = GetFMTabControlGroup(source); + sourceGroup.TabControl.ResetTempDragData(); _inTabDragArea = false; if (refresh) { @@ -5662,36 +5659,27 @@ private void MoveFMTab(WhichTabControl source, WhichTabControl dest, TabPage tab { if (source == dest) return; - DarkTabControl sourceTabControl = source == WhichTabControl.Bottom - ? Lazy_LowerTabControl.TabControl - : TopFMTabControl; - - DarkTabControl destTabControl = dest == WhichTabControl.Bottom - ? Lazy_LowerTabControl.TabControl - : TopFMTabControl; - - DarkSplitContainerCustom destSplitContainer = dest == WhichTabControl.Bottom - ? LowerSplitContainer - : TopSplitContainer; + FMTabControlGroup sourceGroup = GetFMTabControlGroup(source); + FMTabControlGroup destGroup = GetFMTabControlGroup(dest); - sourceTabControl.RestoreBackedUpBackingTabs(); + sourceGroup.TabControl.RestoreBackedUpBackingTabs(); HideFMTab(source, tabPage); ShowFMTab(dest, tabPage); if (expandCollapsed) { - if (destSplitContainer.FullScreen) + if (destGroup.Splitter.FullScreen) { - destSplitContainer.ToggleFullScreen(); + destGroup.Splitter.ToggleFullScreen(); SetFMTabsCollapsedState(dest, false); } } - destTabControl.SelectedTab = tabPage; + destGroup.TabControl.SelectedTab = tabPage; tabPage.Focus(); } - internal void ShowFMTab(WhichTabControl which, TabPage tabPage) + private void ShowFMTab(WhichTabControl which, TabPage tabPage) { if (which == WhichTabControl.Bottom) { @@ -5705,18 +5693,15 @@ internal void ShowFMTab(WhichTabControl which, TabPage tabPage) } } - internal void HideFMTab(WhichTabControl which, TabPage tabPage) + private void HideFMTab(WhichTabControl which, TabPage tabPage) { - (DarkTabControl tabControl, DarkLabel emptyMessageLabel) = - which == WhichTabControl.Bottom - ? (Lazy_LowerTabControl.TabControl, BottomFMTabsEmptyMessageLabel) - : (TopFMTabControl, TopFMTabsEmptyMessageLabel); + FMTabControlGroup group = GetFMTabControlGroup(which); - tabControl.ShowTab(tabPage, false); - if (tabControl.TabCount == 0) + group.TabControl.ShowTab(tabPage, false); + if (group.TabControl.TabCount == 0) { - emptyMessageLabel.BringToFront(); - emptyMessageLabel.Show(); + group.EmptyMessageLabel.BringToFront(); + group.EmptyMessageLabel.Show(); } } From 6a785cf5a75bb277a4b3fbc177e79c5bf8362d90 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 11:01:22 -0800 Subject: [PATCH 188/200] Extend menu-clickable tab bar height down a bit So it better aligns with the visual space --- AngelLoader/Forms/MainForm.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index e9d964db2..033cbe2a9 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5519,10 +5519,9 @@ private void HandleTabsMenu(MouseEventArgs e, WhichTabControl which) FMTabControlGroup group = GetFMTabControlGroup(which); Rectangle rect = group.TabControl.GetTabBarRect(); - if (rect == Rectangle.Empty) - { - rect = group.TabControl.ClientRectangle; - } + rect = rect == Rectangle.Empty + ? group.TabControl.ClientRectangle + : rect with { Height = rect.Height + 3 }; if (rect.Contains(group.TabControl.ClientCursorPos())) { From be0a5fad8e83211a8f0b63fe4fc648153037ddd8 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 11:06:54 -0800 Subject: [PATCH 189/200] Remove old todos --- AngelLoader/Forms/FormsViewEnvironment.cs | 5 +---- AngelLoader/Forms/MainForm.cs | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/AngelLoader/Forms/FormsViewEnvironment.cs b/AngelLoader/Forms/FormsViewEnvironment.cs index 4f9df4d10..1c4505222 100644 --- a/AngelLoader/Forms/FormsViewEnvironment.cs +++ b/AngelLoader/Forms/FormsViewEnvironment.cs @@ -46,12 +46,9 @@ internal static MainForm ViewInternal public void PreloadScreenshot(ConfigData config, List fmsViewList) { /* - @ScreenshotDisplay: UI-specific preload conditions - If we allow moving the screenshots tab beside the readme or wherever else, we'll have to update this code - to match whatever the UI setup is. @DockUI: Finalize these conditions */ - var screenshotsTab = config.FMTabsData.GetTab(FMTab.Screenshots); + FMTabData screenshotsTab = config.FMTabsData.GetTab(FMTab.Screenshots); if (screenshotsTab.Visible == FMTabVisibleIn.Top && (config.TopFMTabsPanelCollapsed || config.FMTabsData.SelectedTab != FMTab.Screenshots)) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 033cbe2a9..0f5199209 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -1240,7 +1240,7 @@ private void SetWindowStateAndSize() { if (!_firstShowDone) { - // @DockUI: Bottom (lazy-loaded) control handles this itself + // Bottom (lazy-loaded) control handles this itself if (TopFMTabControl.SelectedTab is Lazy_TabsBase lazyTab && !Config.TopFMTabsPanelCollapsed) { lazyTab.Construct(); @@ -5723,7 +5723,6 @@ private static Color GetOverlayColor() #endregion - // @DockUI: Lazy-load the empty message labels private void FMTabsEmptyMessageLabels_Paint(object sender, PaintEventArgs e) { DarkLabel label = BottomFMTabsEmptyMessageLabel; From 04136591ed33b8c479e133f2ef5db21c381666ea Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 12:33:05 -0800 Subject: [PATCH 190/200] Screenshot copy UX work: -Add copy button -Tooltips for screenshot folder and copy buttons -Ctrl+C copies if mouse is over Screenshots tab --- .../Common/DataClasses/LocalizationData.cs | 3 +- .../Lazy_ScreenshotsPage.Designer.cs | 74 ++++++++++++------ .../TopRightPages/Lazy_ScreenshotsPage.cs | 13 ++- ...Lazy_ScreenshotsPage_InitSlim.Generated.cs | 64 ++++++++++----- .../TopRightPages/ScreenshotsTabPage.cs | 6 +- AngelLoader/Forms/Images.cs | 42 +++++++++- AngelLoader/Forms/MainForm.cs | 3 +- AngelLoader/Languages/English.ini | 3 +- AngelLoader/Properties/Resources.Designer.cs | 10 +++ AngelLoader/Properties/Resources.resx | 3 + AngelLoader/Resources/copy_21.png | Bin 0 -> 1081 bytes 11 files changed, 169 insertions(+), 52 deletions(-) create mode 100644 AngelLoader/Resources/copy_21.png diff --git a/AngelLoader/Common/DataClasses/LocalizationData.cs b/AngelLoader/Common/DataClasses/LocalizationData.cs index 7ee18e4d2..1893d683c 100644 --- a/AngelLoader/Common/DataClasses/LocalizationData.cs +++ b/AngelLoader/Common/DataClasses/LocalizationData.cs @@ -636,8 +636,9 @@ internal sealed class ModsTab_Class internal sealed class ScreenshotsTab_Class { internal readonly string TabText = "Screenshots"; - internal readonly string CopyScreenshotToolTip = "Right-click to copy"; internal readonly string Gamma = "Gamma:"; + internal readonly string OpenScreenshotsFolderToolTip = "Open screenshots folder"; + internal readonly string CopyImageToolTip = "Copy image (Ctrl+C)"; internal readonly string ScreenshotsFolderNotFound = "Screenshots folder not found."; internal readonly string ScreenshotsFolderOpenError = "There was an error trying to open the screenshots folder."; internal readonly string ImageCopied = "Image copied"; diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index c69715192..95fcf27dc 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -31,17 +31,50 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.ButtonsFLP = new AngelLoader.Forms.CustomControls.DarkFlowLayoutPanel(); + this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); + this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); + this.CopyButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaTrackBar = new AngelLoader.Forms.CustomControls.DarkTrackBar(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); - this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); - this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); + this.ButtonsFLP.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // + // ButtonsFLP + // + this.ButtonsFLP.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ButtonsFLP.Controls.Add(this.NextButton); + this.ButtonsFLP.Controls.Add(this.PrevButton); + this.ButtonsFLP.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft; + this.ButtonsFLP.Location = new System.Drawing.Point(56, 256); + this.ButtonsFLP.Name = "ButtonsFLP"; + this.ButtonsFLP.Size = new System.Drawing.Size(466, 24); + this.ButtonsFLP.TabIndex = 6; + // + // NextButton + // + this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; + this.NextButton.Location = new System.Drawing.Point(391, 0); + this.NextButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 3); + this.NextButton.Name = "NextButton"; + this.NextButton.Size = new System.Drawing.Size(75, 23); + this.NextButton.TabIndex = 2; + // + // PrevButton + // + this.PrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; + this.PrevButton.Location = new System.Drawing.Point(313, 0); + this.PrevButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 3); + this.PrevButton.Name = "PrevButton"; + this.PrevButton.Size = new System.Drawing.Size(75, 23); + this.PrevButton.TabIndex = 1; + // // CopiedMessageLabel // this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; @@ -53,6 +86,16 @@ private void InitializeComponent() this.CopiedMessageLabel.Text = "[Copied]"; this.CopiedMessageLabel.Visible = false; // + // CopyButton + // + this.CopyButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.CopyButton.Location = new System.Drawing.Point(32, 256); + this.CopyButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 3); + this.CopyButton.Name = "CopyButton"; + this.CopyButton.Size = new System.Drawing.Size(24, 23); + this.CopyButton.TabIndex = 0; + this.CopyButton.PaintCustom += new System.EventHandler(this.CopyButton_PaintCustom); + // // GammaLabel // this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); @@ -92,27 +135,9 @@ private void InitializeComponent() this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(8, 256); this.OpenScreenshotsFolderButton.Name = "OpenScreenshotsFolderButton"; this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(24, 23); - this.OpenScreenshotsFolderButton.TabIndex = 6; + this.OpenScreenshotsFolderButton.TabIndex = 5; this.OpenScreenshotsFolderButton.PaintCustom += new System.EventHandler(this.OpenScreenshotsFolderButton_PaintCustom); // - // NextButton - // - this.NextButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; - this.NextButton.Location = new System.Drawing.Point(446, 256); - this.NextButton.Name = "NextButton"; - this.NextButton.Size = new System.Drawing.Size(75, 23); - this.NextButton.TabIndex = 8; - // - // PrevButton - // - this.PrevButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.PrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; - this.PrevButton.Location = new System.Drawing.Point(371, 256); - this.PrevButton.Name = "PrevButton"; - this.PrevButton.Size = new System.Drawing.Size(75, 23); - this.PrevButton.TabIndex = 7; - // // ScreenshotsPictureBox // this.ScreenshotsPictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) @@ -129,16 +154,17 @@ private void InitializeComponent() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 200); + this.Controls.Add(this.ButtonsFLP); this.Controls.Add(this.CopiedMessageLabel); + this.Controls.Add(this.CopyButton); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.GammaTrackBar); this.Controls.Add(this.OpenScreenshotsFolderButton); - this.Controls.Add(this.NextButton); - this.Controls.Add(this.PrevButton); this.Controls.Add(this.ScreenshotsPictureBox); this.Name = "Lazy_ScreenshotsPage"; this.Size = new System.Drawing.Size(527, 284); + this.ButtonsFLP.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -156,4 +182,6 @@ private void InitializeComponent() internal DarkTrackBar GammaTrackBar; internal DarkLabel GammaLabel; internal DarkLabel CopiedMessageLabel; + private DarkFlowLayoutPanel ButtonsFLP; + internal DarkButton CopyButton; } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs index ec3d04afb..e7e23d201 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.cs @@ -16,7 +16,7 @@ public Lazy_ScreenshotsPage() private void OpenScreenshotsFolderButton_PaintCustom(object sender, PaintEventArgs e) { - Image image = Images.Folder; + Image image = Images.FolderDim; DarkButton button = OpenScreenshotsFolderButton; Images.PaintBitmapButton( button, @@ -24,4 +24,15 @@ private void OpenScreenshotsFolderButton_PaintCustom(object sender, PaintEventAr button.Enabled ? image : Images.GetDisabledImage(image), x: (button.Width - image.Width) / 2); } + + private void CopyButton_PaintCustom(object sender, PaintEventArgs e) + { + Image image = Images.Copy21; + DarkButton button = CopyButton; + Images.PaintBitmapButton( + button, + e, + button.Enabled ? image : Images.GetDisabledImage(image), + x: (button.Width - image.Width) / 2); + } } diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index 4ec551834..c1e0cc7e7 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -7,17 +7,45 @@ public sealed partial class Lazy_ScreenshotsPage /// private void InitSlim() { + this.ButtonsFLP = new AngelLoader.Forms.CustomControls.DarkFlowLayoutPanel(); + this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); + this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.CopiedMessageLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); + this.CopyButton = new AngelLoader.Forms.CustomControls.DarkButton(); this.GammaLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.NumberLabel = new AngelLoader.Forms.CustomControls.DarkLabel(); this.GammaTrackBar = new AngelLoader.Forms.CustomControls.DarkTrackBar(); this.OpenScreenshotsFolderButton = new AngelLoader.Forms.CustomControls.DarkButton(); - this.NextButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); - this.PrevButton = new AngelLoader.Forms.CustomControls.DarkArrowButton(); this.ScreenshotsPictureBox = new AngelLoader.Forms.CustomControls.ImagePanelCustom(); + this.ButtonsFLP.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).BeginInit(); this.SuspendLayout(); // + // ButtonsFLP + // + this.ButtonsFLP.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ButtonsFLP.Controls.Add(this.NextButton); + this.ButtonsFLP.Controls.Add(this.PrevButton); + this.ButtonsFLP.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft; + this.ButtonsFLP.Location = new System.Drawing.Point(56, 256); + this.ButtonsFLP.Size = new System.Drawing.Size(466, 24); + this.ButtonsFLP.TabIndex = 6; + // + // NextButton + // + this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; + this.NextButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 3); + this.NextButton.Size = new System.Drawing.Size(75, 23); + this.NextButton.TabIndex = 2; + // + // PrevButton + // + this.PrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; + this.PrevButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 3); + this.PrevButton.Size = new System.Drawing.Size(75, 23); + this.PrevButton.TabIndex = 1; + // // CopiedMessageLabel // this.CopiedMessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; @@ -26,6 +54,15 @@ private void InitSlim() this.CopiedMessageLabel.Size = new System.Drawing.Size(46, 13); this.CopiedMessageLabel.Visible = false; // + // CopyButton + // + this.CopyButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.CopyButton.Location = new System.Drawing.Point(32, 256); + this.CopyButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 3); + this.CopyButton.Size = new System.Drawing.Size(24, 23); + this.CopyButton.TabIndex = 0; + this.CopyButton.PaintCustom += new System.EventHandler(this.CopyButton_PaintCustom); + // // GammaLabel // this.GammaLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); @@ -57,25 +94,9 @@ private void InitSlim() this.OpenScreenshotsFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.OpenScreenshotsFolderButton.Location = new System.Drawing.Point(8, 256); this.OpenScreenshotsFolderButton.Size = new System.Drawing.Size(24, 23); - this.OpenScreenshotsFolderButton.TabIndex = 6; + this.OpenScreenshotsFolderButton.TabIndex = 5; this.OpenScreenshotsFolderButton.PaintCustom += new System.EventHandler(this.OpenScreenshotsFolderButton_PaintCustom); // - // NextButton - // - this.NextButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; - this.NextButton.Location = new System.Drawing.Point(446, 256); - this.NextButton.Size = new System.Drawing.Size(75, 23); - this.NextButton.TabIndex = 8; - // - // PrevButton - // - this.PrevButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.PrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; - this.PrevButton.Location = new System.Drawing.Point(371, 256); - this.PrevButton.Size = new System.Drawing.Size(75, 23); - this.PrevButton.TabIndex = 7; - // // ScreenshotsPictureBox // this.ScreenshotsPictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) @@ -91,15 +112,16 @@ private void InitSlim() this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; this.AutoScrollMinSize = new System.Drawing.Size(200, 200); + this.Controls.Add(this.ButtonsFLP); this.Controls.Add(this.CopiedMessageLabel); + this.Controls.Add(this.CopyButton); this.Controls.Add(this.GammaLabel); this.Controls.Add(this.NumberLabel); this.Controls.Add(this.GammaTrackBar); this.Controls.Add(this.OpenScreenshotsFolderButton); - this.Controls.Add(this.NextButton); - this.Controls.Add(this.PrevButton); this.Controls.Add(this.ScreenshotsPictureBox); this.Size = new System.Drawing.Size(527, 284); + this.ButtonsFLP.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.GammaTrackBar)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 946683268..4d518ee10 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -41,6 +41,7 @@ public override void Construct() _page.ScreenshotsPictureBox.MouseClick += ScreenshotsPictureBox_MouseClick; _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; + _page.CopyButton.Click += CopyButton_Click; _page.PrevButton.Click += ScreenshotsPrevButton_Click; _page.NextButton.Click += ScreenshotsNextButton_Click; _page.GammaTrackBar.Scroll += GammaTrackBar_Scroll; @@ -62,7 +63,8 @@ public override void UpdatePage() public override void Localize() { if (!_constructed) return; - _owner.MainToolTip.SetToolTip(_page.ScreenshotsPictureBox, LText.ScreenshotsTab.CopyScreenshotToolTip); + _owner.MainToolTip.SetToolTip(_page.OpenScreenshotsFolderButton, LText.ScreenshotsTab.OpenScreenshotsFolderToolTip); + _owner.MainToolTip.SetToolTip(_page.CopyButton, LText.ScreenshotsTab.CopyImageToolTip); _page.GammaLabel.Text = LText.ScreenshotsTab.Gamma; } @@ -254,6 +256,8 @@ private void ScreenshotsPictureBox_MouseClick(object sender, MouseEventArgs e) } } + private void CopyButton_Click(object sender, EventArgs e) => CopyImageToClipboard(); + private void OpenScreenshotsFolderButton_Click(object sender, EventArgs e) { Core.OpenFMScreenshotsFolder(_owner.FMsDGV.GetMainSelectedFM(), CurrentScreenshotFileName); diff --git a/AngelLoader/Forms/Images.cs b/AngelLoader/Forms/Images.cs index acaa31bca..9dab1bda4 100644 --- a/AngelLoader/Forms/Images.cs +++ b/AngelLoader/Forms/Images.cs @@ -41,6 +41,13 @@ public static class Preload // Also performance hack for the splash screen as above. file static class DarkModeImageConversion { + internal enum Matrix + { + Dark, + DarkDim, + DarkDisabled + } + private static readonly ColorMatrix DarkColorMatrix = new(new[] { new[] { 0.2125f, 0.2125f, 0.2125f, 0, 0 }, @@ -50,6 +57,15 @@ file static class DarkModeImageConversion new[] { 0.99f, 0.99f, 0.99f, 0, 0 } }); + private static readonly ColorMatrix DarkDimColorMatrix = new(new[] + { + new[] { 0.2125f, 0.2125f, 0.2125f, 0, 0 }, + new[] { 0.2577f, 0.2577f, 0.2577f, 0, 0 }, + new[] { 0.0361f, 0.0361f, 0.0361f, 0, 0 }, + new[] { 0, 0, 0, /* The value: */ 0.7425f, 0 }, + new[] { 0.99f, 0.99f, 0.99f, 0, 0 } + }); + private static readonly ColorMatrix DarkDisabledColorMatrix = new(new[] { new[] { 0.2125f, 0.2125f, 0.2125f, 0, 0 }, @@ -59,13 +75,19 @@ file static class DarkModeImageConversion new[] { 0.99f, 0.99f, 0.99f, 0, 0 } }); - public static Bitmap CreateDarkModeVersion(Bitmap normalImage, bool disabled = false) + public static Bitmap CreateDarkModeVersion(Bitmap normalImage, Matrix matrix = Matrix.Dark) { using ImageAttributes imgAttrib = new(); imgAttrib.ClearColorKey(); - imgAttrib.SetColorMatrix(disabled ? DarkDisabledColorMatrix : DarkColorMatrix); + imgAttrib.SetColorMatrix( + matrix switch + { + Matrix.DarkDisabled => DarkDisabledColorMatrix, + Matrix.DarkDim => DarkDimColorMatrix, + _ => DarkColorMatrix + }); Size size = normalImage.Size; @@ -1008,7 +1030,7 @@ private static Bitmap Shock2_21() => private static Image? _charEncLetter_Disabled_Dark; public static Image CharEncLetter_Disabled => Config.DarkMode - ? _charEncLetter_Disabled_Dark ??= DarkModeImageConversion.CreateDarkModeVersion(Resources.CharEnc, true) + ? _charEncLetter_Disabled_Dark ??= DarkModeImageConversion.CreateDarkModeVersion(Resources.CharEnc, DarkModeImageConversion.Matrix.DarkDisabled) : _charEncLetter_Disabled ??= ToolStripRenderer.CreateDisabledImage(Resources.CharEnc); #endregion @@ -1181,6 +1203,20 @@ public static Bitmap GetZoomImage(Rectangle rect, Zoom zoomType) ? _brokenFile_Dark ??= DarkModeImageConversion.CreateDarkModeVersion(Resources.BrokenFile) : _brokenFile ??= Resources.BrokenFile; + private static Bitmap? _folderDim; + private static Bitmap? _folderDim_Dark; + public static Bitmap FolderDim => + Config.DarkMode + ? _folderDim_Dark ??= DarkModeImageConversion.CreateDarkModeVersion(Resources.Folder16, DarkModeImageConversion.Matrix.DarkDim) + : _folderDim ??= Resources.Folder16; + + private static Bitmap? _copy21; + private static Bitmap? _copy21_Dark; + public static Bitmap Copy21 => + Config.DarkMode + ? _copy21_Dark ??= DarkModeImageConversion.CreateDarkModeVersion(Resources.Copy_21, DarkModeImageConversion.Matrix.DarkDim) + : _copy21 ??= Resources.Copy_21; + #endregion #endregion diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 0f5199209..601e78df8 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -1723,7 +1723,8 @@ async Task HandleHomeOrEnd(bool home, bool selectionSyncHack = true) } else if (e.KeyCode == Keys.C) { - if (AnyControlFocusedInTabPage(ScreenshotsTabPage)) + if (CursorOverControl(ScreenshotsTabPage) || + AnyControlFocusedInTabPage(ScreenshotsTabPage)) { ScreenshotsTabPage.CopyImageToClipboard(); } diff --git a/AngelLoader/Languages/English.ini b/AngelLoader/Languages/English.ini index feb6d94db..5da177ac3 100644 --- a/AngelLoader/Languages/English.ini +++ b/AngelLoader/Languages/English.ini @@ -492,8 +492,9 @@ Generic_ModsNotSupported=Mod management is not supported for unknown FMs. [ScreenshotsTab] TabText=Screenshots -CopyScreenshotToolTip=Right-click to copy Gamma=Gamma: +OpenScreenshotsFolderToolTip=Open screenshots folder +CopyImageToolTip=Copy image (Ctrl+C) ScreenshotsFolderNotFound=Screenshots folder not found. ScreenshotsFolderOpenError=There was an error trying to open the screenshots folder. ImageCopied=Image copied diff --git a/AngelLoader/Properties/Resources.Designer.cs b/AngelLoader/Properties/Resources.Designer.cs index 8ddf67699..d451efbb4 100644 --- a/AngelLoader/Properties/Resources.Designer.cs +++ b/AngelLoader/Properties/Resources.Designer.cs @@ -110,6 +110,16 @@ internal static System.Drawing.Bitmap ClearFilters { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Copy_21 { + get { + object obj = ResourceManager.GetObject("Copy_21", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/AngelLoader/Properties/Resources.resx b/AngelLoader/Properties/Resources.resx index 68e17cb61..1c1f40bad 100644 --- a/AngelLoader/Properties/Resources.resx +++ b/AngelLoader/Properties/Resources.resx @@ -244,4 +244,7 @@ ..\Resources\broken_file.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\copy_21.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/AngelLoader/Resources/copy_21.png b/AngelLoader/Resources/copy_21.png new file mode 100644 index 0000000000000000000000000000000000000000..89d3f54baf700713895648921959f03dd2ced928 GIT binary patch literal 1081 zcmbVL&1=(O9F7d;*enPlI`NQY2XUqeABhl!`Q(<@_yube$Vf7eRASzs`o-K zMNz5ZI4G0#Z1VPWlkbyrTN`BQ$JPvrkY)B>zhP+4%`($Ui7$nDxZsViL~v?l zqT;M9I=ah@jnX4cgBb83w&|u{4`QR4WmprhA~=-98!8O;mMV0U8hsrmpb$j*X+ZxxAT^Of3V< zf+`4>l`CWbP-G1VKofytcDThL#&+Pqj;=>^+g$Znu91(RjZsuVsNU&-$pwT_ynsSF zKc%n&J?#Z9YQ#x-4x$Ax@@_-75Fwv#<=60z&DH#U_d4&BBSx`yIdt> Date: Wed, 6 Mar 2024 12:36:00 -0800 Subject: [PATCH 191/200] AutoScrollMinSize tweaks to screenshots tab --- .../TopRightPages/Lazy_ScreenshotsPage.Designer.cs | 6 +++--- .../Lazy_ScreenshotsPage_InitSlim.Generated.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index 95fcf27dc..d505fdc63 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -61,7 +61,7 @@ private void InitializeComponent() // this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; this.NextButton.Location = new System.Drawing.Point(391, 0); - this.NextButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 3); + this.NextButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); this.NextButton.Name = "NextButton"; this.NextButton.Size = new System.Drawing.Size(75, 23); this.NextButton.TabIndex = 2; @@ -70,7 +70,7 @@ private void InitializeComponent() // this.PrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; this.PrevButton.Location = new System.Drawing.Point(313, 0); - this.PrevButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 3); + this.PrevButton.Margin = new System.Windows.Forms.Padding(0); this.PrevButton.Name = "PrevButton"; this.PrevButton.Size = new System.Drawing.Size(75, 23); this.PrevButton.TabIndex = 1; @@ -153,7 +153,7 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; - this.AutoScrollMinSize = new System.Drawing.Size(200, 200); + this.AutoScrollMinSize = new System.Drawing.Size(216, 200); this.Controls.Add(this.ButtonsFLP); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.CopyButton); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index c1e0cc7e7..b8aac4156 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -35,14 +35,14 @@ private void InitSlim() // NextButton // this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; - this.NextButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 3); + this.NextButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); this.NextButton.Size = new System.Drawing.Size(75, 23); this.NextButton.TabIndex = 2; // // PrevButton // this.PrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; - this.PrevButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 3); + this.PrevButton.Margin = new System.Windows.Forms.Padding(0); this.PrevButton.Size = new System.Drawing.Size(75, 23); this.PrevButton.TabIndex = 1; // @@ -111,7 +111,7 @@ private void InitSlim() this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScroll = true; - this.AutoScrollMinSize = new System.Drawing.Size(200, 200); + this.AutoScrollMinSize = new System.Drawing.Size(216, 200); this.Controls.Add(this.ButtonsFLP); this.Controls.Add(this.CopiedMessageLabel); this.Controls.Add(this.CopyButton); From ea4eb9326eda9801b7ec879d90edb92a7c99a511 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 12:39:38 -0800 Subject: [PATCH 192/200] Screenshots tab prev/next buttons margin fix --- .../TopRightPages/Lazy_ScreenshotsPage.Designer.cs | 4 ++-- .../TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs index d505fdc63..f5f01c61e 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage.Designer.cs @@ -61,7 +61,7 @@ private void InitializeComponent() // this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; this.NextButton.Location = new System.Drawing.Point(391, 0); - this.NextButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); + this.NextButton.Margin = new System.Windows.Forms.Padding(0); this.NextButton.Name = "NextButton"; this.NextButton.Size = new System.Drawing.Size(75, 23); this.NextButton.TabIndex = 2; @@ -69,7 +69,7 @@ private void InitializeComponent() // PrevButton // this.PrevButton.ArrowDirection = AngelLoader.Forms.Direction.Left; - this.PrevButton.Location = new System.Drawing.Point(313, 0); + this.PrevButton.Location = new System.Drawing.Point(316, 0); this.PrevButton.Margin = new System.Windows.Forms.Padding(0); this.PrevButton.Name = "PrevButton"; this.PrevButton.Size = new System.Drawing.Size(75, 23); diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs index b8aac4156..9e9f078c9 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/Lazy_ScreenshotsPage_InitSlim.Generated.cs @@ -35,7 +35,7 @@ private void InitSlim() // NextButton // this.NextButton.ArrowDirection = AngelLoader.Forms.Direction.Right; - this.NextButton.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); + this.NextButton.Margin = new System.Windows.Forms.Padding(0); this.NextButton.Size = new System.Drawing.Size(75, 23); this.NextButton.TabIndex = 2; // From cc41c40556b672582154baf80f0a32d6e9f61cdc Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 13:21:21 -0800 Subject: [PATCH 193/200] Copy context menu on screenshot image --- .../Forms/CustomControls/ImagePanelCustom.cs | 12 ++-- .../LazyLoaded/Lazy_ScreenshotCopyMenu.cs | 66 +++++++++++++++++++ .../TopRightPages/ScreenshotsTabPage.cs | 49 ++++++++++++-- 3 files changed, 117 insertions(+), 10 deletions(-) create mode 100644 AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_ScreenshotCopyMenu.cs diff --git a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs index 6622caf09..04edbb880 100644 --- a/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs +++ b/AngelLoader/Forms/CustomControls/ImagePanelCustom.cs @@ -31,14 +31,14 @@ public bool DarkModeEnabled BackColor = _darkModeEnabled ? DarkModeDrawnBackColor : DrawnBackColor; - if (_showingErrorImage) + if (ShowingErrorImage) { SetImageInternal(Images.BrokenFile); } } } - private bool _showingErrorImage; + internal bool ShowingErrorImage { get; private set; } private readonly ImageAttributes _imageAttributes = new(); @@ -58,7 +58,7 @@ public void SetGamma(float gamma) public void SetImage(Image? image, float? gamma = null) { - _showingErrorImage = false; + ShowingErrorImage = false; SetImageInternal(image, gamma); } @@ -86,7 +86,7 @@ private void SetImageInternal(Image? image, float? gamma = null) public void SetErrorImage() { - _showingErrorImage = true; + ShowingErrorImage = true; SetImageInternal(Images.BrokenFile); } @@ -110,7 +110,7 @@ protected override void OnPaint(PaintEventArgs e) if (_image == null) return; - if (_showingErrorImage) + if (ShowingErrorImage) { e.Graphics.DrawImage( _image, @@ -147,7 +147,7 @@ private void DrawImageOnGraphics(Graphics g, Image image) /// public Bitmap? GetSnapshot() { - if (_image == null || _showingErrorImage) + if (_image == null || ShowingErrorImage) { return null; } diff --git a/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_ScreenshotCopyMenu.cs b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_ScreenshotCopyMenu.cs new file mode 100644 index 000000000..e66766922 --- /dev/null +++ b/AngelLoader/Forms/CustomControls/LazyLoaded/Lazy_ScreenshotCopyMenu.cs @@ -0,0 +1,66 @@ +using System.Windows.Forms; +using JetBrains.Annotations; +using static AngelLoader.Global; + +namespace AngelLoader.Forms.CustomControls.LazyLoaded; + +internal sealed class Lazy_ScreenshotCopyMenu : IDarkable +{ + private bool _constructed; + + private readonly ScreenshotsTabPage _owner; + + internal Lazy_ScreenshotCopyMenu(ScreenshotsTabPage owner) => _owner = owner; + + private DarkContextMenu _menu = null!; + internal DarkContextMenu Menu + { + get + { + Construct(); + return _menu; + } + } + + private ToolStripMenuItemCustom CopyMenuItem = null!; + + private bool _darkModeEnabled; + [PublicAPI] + public bool DarkModeEnabled + { + set + { + if (_darkModeEnabled == value) return; + _darkModeEnabled = value; + if (!_constructed) return; + + _menu.DarkModeEnabled = _darkModeEnabled; + } + } + + private void Construct() + { + if (_constructed) return; + + _menu = new DarkContextMenu(_owner); + _menu.Items.AddRange(new ToolStripItem[] + { + CopyMenuItem = new ToolStripMenuItemCustom { ShortcutKeys = Keys.Control | Keys.C }, + }); + + _menu.Opening += _owner.CopyMenu_Opening; + _menu.ItemClicked += _owner.CopyMenu_ItemClicked; + + _menu.DarkModeEnabled = _darkModeEnabled; + + _constructed = true; + + Localize(); + } + + internal void Localize() + { + if (!_constructed) return; + CopyMenuItem.Text = LText.Global.Copy; + } +} diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 4d518ee10..93ff8ff2c 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -2,25 +2,46 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using AL_Common; using AngelLoader.DataClasses; +using AngelLoader.Forms.CustomControls.LazyLoaded; +using JetBrains.Annotations; using static AngelLoader.GameSupport; using static AngelLoader.Global; namespace AngelLoader.Forms.CustomControls; -public sealed class ScreenshotsTabPage : Lazy_TabsBase +public sealed class ScreenshotsTabPage : Lazy_TabsBase, IDarkContextMenuOwner { private Lazy_ScreenshotsPage _page = null!; + private readonly Lazy_ScreenshotCopyMenu CopyMenu; + private readonly List ScreenshotFileNames = new(); private string CurrentScreenshotFileName = ""; private MemoryImage? _currentScreenshotStream; private readonly Timer CopiedMessageFadeoutTimer = new(); private bool _forceUpdateArmed; + [PublicAPI] + public override bool DarkModeEnabled + { + get => base.DarkModeEnabled; + set + { + if (base.DarkModeEnabled == value) return; + base.DarkModeEnabled = value; + if (!_constructed) return; + + CopyMenu.DarkModeEnabled = value; + } + } + + public ScreenshotsTabPage() => CopyMenu = new Lazy_ScreenshotCopyMenu(this); + #region Public common public override void Construct() @@ -38,7 +59,7 @@ public override void Construct() CopiedMessageFadeoutTimer.Interval = 2500; CopiedMessageFadeoutTimer.Tick += CopiedMessageFadeoutTimer_Tick; - _page.ScreenshotsPictureBox.MouseClick += ScreenshotsPictureBox_MouseClick; + _page.ScreenshotsPictureBox.MouseDown += ScreenshotsPictureBox_MouseDown; _page.OpenScreenshotsFolderButton.Click += OpenScreenshotsFolderButton_Click; _page.CopyButton.Click += CopyButton_Click; @@ -66,6 +87,7 @@ public override void Localize() _owner.MainToolTip.SetToolTip(_page.OpenScreenshotsFolderButton, LText.ScreenshotsTab.OpenScreenshotsFolderToolTip); _owner.MainToolTip.SetToolTip(_page.CopyButton, LText.ScreenshotsTab.CopyImageToolTip); _page.GammaLabel.Text = LText.ScreenshotsTab.Gamma; + CopyMenu.Localize(); } public void RefreshScreenshots() @@ -248,14 +270,29 @@ protected override void OnVisibleChanged(EventArgs e) } } - private void ScreenshotsPictureBox_MouseClick(object sender, MouseEventArgs e) + private void ScreenshotsPictureBox_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { - CopyImageToClipboard(); + _page.ScreenshotsPictureBox.ContextMenuStrip ??= CopyMenu.Menu; + } + } + + internal void CopyMenu_Opening(object sender, CancelEventArgs e) + { + if (!_constructed || _page.ScreenshotsPictureBox.ShowingErrorImage) + { + e.Cancel = true; } } + internal void CopyMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e) + { + // Otherwise it won't hide until after the blocking copy operation is finished + CopyMenu.Menu.Hide(); + CopyImageToClipboard(); + } + private void CopyButton_Click(object sender, EventArgs e) => CopyImageToClipboard(); private void OpenScreenshotsFolderButton_Click(object sender, EventArgs e) @@ -385,6 +422,10 @@ public void CopyImageToClipboard() #endregion + public bool ViewBlocked => _owner.ViewBlocked; + + public IContainer GetComponents() => _owner.GetComponents(); + protected override void Dispose(bool disposing) { if (disposing) From 54be2a906b15def4dcf122089ca3e01d577bdd50 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 13:22:41 -0800 Subject: [PATCH 194/200] Fix dark mode not being set on copy menu --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index 93ff8ff2c..d8fbcc0f9 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -34,7 +34,6 @@ public override bool DarkModeEnabled { if (base.DarkModeEnabled == value) return; base.DarkModeEnabled = value; - if (!_constructed) return; CopyMenu.DarkModeEnabled = value; } From 41816bfec3b53ee1730ec3364c542ec11e271861 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 13:26:22 -0800 Subject: [PATCH 195/200] ReadmeContainer to field --- AngelLoader/Forms/MainForm.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index 601e78df8..e1fb41863 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -98,6 +98,8 @@ need to check the accuracy of the selection itself (eg. in FMsDGV nav) so we can #endregion + internal readonly Control ReadmeContainer; + #region FMs list private readonly float _fmsListDefaultFontSizeInPoints; @@ -644,6 +646,8 @@ and does NOT have its text transferred over. It ends up with blank text. InitComponentManual(); #endif + ReadmeContainer = LowerSplitContainer.Panel1; + _fmTabControlGroups[(int)WhichTabControl.Top] = new FMTabControlGroup( TopFMTabControl, TopFMTabsCollapseButton, @@ -5539,9 +5543,6 @@ public void ShowUpdateNotification(bool show) } } - // @DockUI: Could make this a field that gets set in the ctor (efficiency) - internal Control ReadmeContainer => LowerSplitContainer.Panel1; - public void RefreshCurrentFMScreenshots() { if (UIEnabled && !ViewBlocked && CanFocus) From 6c9fbe42a5ce15a52a972a1853ef0785c08aa6ba Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 14:13:17 -0800 Subject: [PATCH 196/200] Fix dragging from bottom to top and down again Tab bar was a dead zone --- .../Forms/CustomControls/DarkTabControl.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/DarkTabControl.cs b/AngelLoader/Forms/CustomControls/DarkTabControl.cs index df7f105bc..b88e43053 100644 --- a/AngelLoader/Forms/CustomControls/DarkTabControl.cs +++ b/AngelLoader/Forms/CustomControls/DarkTabControl.cs @@ -366,18 +366,31 @@ protected override void OnMouseUp(MouseEventArgs e) // Fix: Ensure we don't start dragging a tab again after we've released the button. DragTab = null; _backedUpBackingTabs = null; + _dragging = false; } private void InvokeMouseDragCustomIfNeeded(MouseEventArgs e) { - Rectangle tabBarExpanded = GetTabBarRect(); - tabBarExpanded.Inflate(4, 16); - if (!tabBarExpanded.Contains(e.Location)) + if (_dragging) { MouseDragCustom?.Invoke(this, e); } + else + { + Rectangle tabBarExpanded = TabCount == 1 + ? GetTabRect(0) + : GetTabBarRect(); + tabBarExpanded.Inflate(4, 16); + if (!tabBarExpanded.Contains(e.Location)) + { + _dragging = true; + MouseDragCustom?.Invoke(this, e); + } + } } + private bool _dragging; + protected override void OnMouseMove(MouseEventArgs e) { if (DesignMode || !AllowReordering) From 5e76bbf6d1a153e46f78d685b012b67f92cc989b Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 14:14:42 -0800 Subject: [PATCH 197/200] Finalize dark and light mode colors for drag overlay --- AngelLoader/Common/DataClasses/DarkColors.cs | 6 ++++++ AngelLoader/Forms/MainForm.cs | 13 ++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/AngelLoader/Common/DataClasses/DarkColors.cs b/AngelLoader/Common/DataClasses/DarkColors.cs index 0aa895e33..37d1967f1 100644 --- a/AngelLoader/Common/DataClasses/DarkColors.cs +++ b/AngelLoader/Common/DataClasses/DarkColors.cs @@ -49,6 +49,12 @@ public static class DarkColors public static readonly Color SuccessGreenDark = Color.FromArgb(68, 178, 68); + public static readonly Color TabDragOverlay_Light = Color.FromArgb(60, + SystemColors.Highlight.R, + SystemColors.Highlight.G, + SystemColors.Highlight.B); + public static readonly Color TabDragOverlay_Dark = Color.FromArgb(64, 75, 110, 175); + #endregion #region DarkUI diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index e1fb41863..c9972f414 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -5713,15 +5713,10 @@ private void DestroyImageCursor() _tabControlImageCursor = null; } - private static Color GetOverlayColor() - { - // @DockUI: Make light and dark mode colors - return Color.FromArgb( - alpha: 64, - red: DarkColors.BlueSelection.R, - green: DarkColors.BlueSelection.G, - blue: DarkColors.BlueSelection.B); - } + private static Color GetOverlayColor() => + Config.DarkMode + ? DarkColors.TabDragOverlay_Dark + : DarkColors.TabDragOverlay_Light; #endregion From ed872b88b1e9bbd19283bcc50c5d2b62a3a4715e Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 14:19:20 -0800 Subject: [PATCH 198/200] Remove old todos --- AngelLoader/Forms/MainForm.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/AngelLoader/Forms/MainForm.cs b/AngelLoader/Forms/MainForm.cs index c9972f414..aa68743dc 100644 --- a/AngelLoader/Forms/MainForm.cs +++ b/AngelLoader/Forms/MainForm.cs @@ -928,7 +928,7 @@ and does NOT have its text transferred over. It ends up with blank text. } /* - @DockUI: Tab pages need to be added to a tab control once in order to work properly. + Tab pages need to be added to a tab control once in order to work properly. If they haven't been added, then at the very least, setting tab text throws an ArgumentOutOfRangeException in release mode. This being the case, we should just keep the top control non-lazy-loaded and keep the logic as it is. @@ -3390,14 +3390,9 @@ internal void FMTabsMenu_MenuItems_Click(object sender, EventArgs e) EverythingPanel.SuspendDrawing(); /* - @DockUI: Explicitly hide tab Although adding a tab to another control automatically removes it from the first one, we need to explicitly run our custom ShowTab() method in order to keep the backing list synced. Otherwise, the tab order gets messed up. - - @DockUI: We could have three-state menu items - top, bottom, and none. - Because when you click a checkbox and it hides the other tab control, it's not a great UX because you - think "crap, how do I get it back?" */ if (s.Checked) { From 16e92a6d89a518ea577c843acf8cec71c53ff829 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 15:14:14 -0800 Subject: [PATCH 199/200] Add more robustness to screenshot preload checking --- .../TopRightPages/ScreenshotsTabPage.cs | 39 +++++++++++++------ AngelLoader/Forms/FormsViewEnvironment.cs | 3 -- AngelLoader/Forms/ScreenshotsPreprocessing.cs | 8 +++- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index d8fbcc0f9..dee1a6c71 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -122,16 +122,33 @@ private void UpdatePageInternal(int index = -1) if (ScreenshotFileNames.Count == 0) { - CurrentScreenshotFileName = ""; - ClearCurrentScreenshot(); - _page.ScreenshotsPictureBox.Enabled = false; - _page.GammaLabel.Enabled = false; - _page.GammaTrackBar.Enabled = false; - _page.OpenScreenshotsFolderButton.Enabled = false; - _page.PrevButton.Enabled = false; - _page.NextButton.Enabled = false; - SetNumberLabelText(""); - _forceUpdateArmed = false; + try + { + if (_owner.StartupState && ScreenshotsPreprocessing.HasBeenActivated) + { +#if TESTING + System.Diagnostics.Trace.WriteLine("Startup state, screenshot preload activated, but didn't match FM and current FM has no screenshots. Clearing..."); +#endif + ScreenshotsPreprocessing.WaitOnThread(); + } + CurrentScreenshotFileName = ""; + ClearCurrentScreenshot(); + _page.ScreenshotsPictureBox.Enabled = false; + _page.GammaLabel.Enabled = false; + _page.GammaTrackBar.Enabled = false; + _page.OpenScreenshotsFolderButton.Enabled = false; + _page.PrevButton.Enabled = false; + _page.NextButton.Enabled = false; + SetNumberLabelText(""); + _forceUpdateArmed = false; + } + finally + { + if (_owner.StartupState && ScreenshotsPreprocessing.HasBeenActivated) + { + ScreenshotsPreprocessing.Clear(); + } + } } else { @@ -202,7 +219,7 @@ private void DisplayCurrentScreenshot() FanMission? fm = _owner.GetMainSelectedFMOrNull(); try { - MemoryImage? mi = ScreenshotsPreprocessing.GetMemoryImage(fm); + MemoryImage? mi = ScreenshotsPreprocessing.GetMemoryImage(fm, CurrentScreenshotFileName); if (mi != null) { #if TESTING diff --git a/AngelLoader/Forms/FormsViewEnvironment.cs b/AngelLoader/Forms/FormsViewEnvironment.cs index 1c4505222..d20075323 100644 --- a/AngelLoader/Forms/FormsViewEnvironment.cs +++ b/AngelLoader/Forms/FormsViewEnvironment.cs @@ -45,9 +45,6 @@ internal static MainForm ViewInternal public void PreloadScreenshot(ConfigData config, List fmsViewList) { - /* - @DockUI: Finalize these conditions - */ FMTabData screenshotsTab = config.FMTabsData.GetTab(FMTab.Screenshots); if (screenshotsTab.Visible == FMTabVisibleIn.Top && (config.TopFMTabsPanelCollapsed || diff --git a/AngelLoader/Forms/ScreenshotsPreprocessing.cs b/AngelLoader/Forms/ScreenshotsPreprocessing.cs index 943389b8f..e75efbfa3 100644 --- a/AngelLoader/Forms/ScreenshotsPreprocessing.cs +++ b/AngelLoader/Forms/ScreenshotsPreprocessing.cs @@ -10,6 +10,7 @@ internal static class ScreenshotsPreprocessing private static Thread? _thread; private static MemoryImage? _memoryImage; private static string _fmInstalledDir = ""; + private static string _currentScreenshotName = ""; internal static readonly List ScreenshotFileNames = new(); internal static bool HasBeenActivated; @@ -18,6 +19,7 @@ internal static void Clear() _thread = null; _memoryImage = null; _fmInstalledDir = ""; + _currentScreenshotName = ""; ScreenshotFileNames.Clear(); try { @@ -29,7 +31,7 @@ internal static void Clear() } } - internal static MemoryImage? GetMemoryImage(FanMission? fm) + internal static MemoryImage? GetMemoryImage(FanMission? fm, string currentScreenshotName) { WaitOnThread(); @@ -37,6 +39,7 @@ internal static void Clear() if (!fm.InstalledDir.IsWhiteSpace() && !_fmInstalledDir.IsWhiteSpace() && + currentScreenshotName.PathEqualsI(_currentScreenshotName) && fm.InstalledDir.EqualsI(_fmInstalledDir)) { return _memoryImage; @@ -47,7 +50,7 @@ internal static void Clear() } } - private static void WaitOnThread() + internal static void WaitOnThread() { if (_thread == null) return; try @@ -71,6 +74,7 @@ internal static void Run( { HasBeenActivated = true; _fmInstalledDir = fmInstalledDir; + _currentScreenshotName = currentScreenshotFileName; ScreenshotFileNames.ClearAndAdd_Small(screenshotFileNames); try From 178da9f206a8a05fe9a4d57ec89312ce95163383 Mon Sep 17 00:00:00 2001 From: Brian Tobin Date: Wed, 6 Mar 2024 15:17:17 -0800 Subject: [PATCH 200/200] Disable copy button on blank --- .../Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs index dee1a6c71..b62c155d3 100644 --- a/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs +++ b/AngelLoader/Forms/CustomControls/TopRightPages/ScreenshotsTabPage.cs @@ -137,6 +137,7 @@ private void UpdatePageInternal(int index = -1) _page.GammaLabel.Enabled = false; _page.GammaTrackBar.Enabled = false; _page.OpenScreenshotsFolderButton.Enabled = false; + _page.CopyButton.Enabled = false; _page.PrevButton.Enabled = false; _page.NextButton.Enabled = false; SetNumberLabelText(""); @@ -158,6 +159,7 @@ private void UpdatePageInternal(int index = -1) _page.GammaLabel.Enabled = true; _page.GammaTrackBar.Enabled = true; _page.OpenScreenshotsFolderButton.Enabled = true; + _page.CopyButton.Enabled = true; _page.PrevButton.Enabled = ScreenshotFileNames.Count > 1; _page.NextButton.Enabled = ScreenshotFileNames.Count > 1; }