From 71d17031b9c319fdf7e163c7232a50b8b327fdb3 Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 01:41:55 -0700 Subject: [PATCH 01/13] WIP Start to Settings Menu / UI Adjustments - Remove the MainForm cancel button > it doesn't really serve a purpose and it breaks the UI cause I suck. - Add the start to a settings dialog, relocated several settings from the top bar into the new setttings dialog - Add a custom Toggle Switch, change the CheckBox for SmokeAPI/CreamAPI to a Toggle Switch - Relocate Uninstall All button to main form (Currently disabled) --- CreamInstaller/Components/ToggleSwitch.cs | 113 +++++++ CreamInstaller/Forms/SelectForm.Designer.cs | 320 ++++++------------ CreamInstaller/Forms/SelectForm.cs | 113 ++----- CreamInstaller/Forms/SettingsForm.Designer.cs | 105 ++++++ CreamInstaller/Forms/SettingsForm.cs | 56 +++ CreamInstaller/Program.cs | 44 ++- CreamInstaller/Selection.cs | 2 +- CreamInstaller/Utility/ProgramData.cs | 28 ++ CreamInstaller/Utility/Settings.cs | 9 + 9 files changed, 465 insertions(+), 325 deletions(-) create mode 100644 CreamInstaller/Components/ToggleSwitch.cs create mode 100644 CreamInstaller/Forms/SettingsForm.Designer.cs create mode 100644 CreamInstaller/Forms/SettingsForm.cs create mode 100644 CreamInstaller/Utility/Settings.cs diff --git a/CreamInstaller/Components/ToggleSwitch.cs b/CreamInstaller/Components/ToggleSwitch.cs new file mode 100644 index 0000000..a8982aa --- /dev/null +++ b/CreamInstaller/Components/ToggleSwitch.cs @@ -0,0 +1,113 @@ +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace CreamInstaller.Components; + +internal sealed class ToggleSwitch : Control +{ + private bool _checked; + private const int TrackPadding = 1; + private const int ThumbDiameter = 18; + private static readonly Color DarkOffTrack = ColorTranslator.FromHtml("#3A3A3D"); + private static readonly Color DarkOnTrack = ColorTranslator.FromHtml("#0E639C"); + private static readonly Color LightOffTrack = ColorTranslator.FromHtml("#CCCCCC"); + private static readonly Color LightOnTrack = SystemColors.Highlight; + private static readonly Color ThumbColor = Color.White; + + public ToggleSwitch() + { + SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true); + Size = new Size(44, 22); + TabStop = true; + Cursor = Cursors.Hand; + } + + public bool Checked + { + get => _checked; + set + { + if (_checked == value) + return; + _checked = value; + Invalidate(); + CheckedChanged?.Invoke(this, EventArgs.Empty); + } + } + + public event EventHandler CheckedChanged; + + protected override void OnClick(EventArgs e) + { + Checked = !Checked; + base.OnClick(e); + } + + protected override void OnKeyDown(KeyEventArgs e) + { + if (e.KeyCode is Keys.Space or Keys.Enter) + { + Checked = !Checked; + e.Handled = true; + return; + } + + base.OnKeyDown(e); + } + + protected override void OnPaint(PaintEventArgs e) + { + Graphics g = e.Graphics; + g.SmoothingMode = SmoothingMode.AntiAlias; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + + bool isDarkMode = Program.DarkModeEnabled; + + int trackHeight = Height - (TrackPadding * 2); + int trackWidth = Width - (TrackPadding * 2); + + // Draw track (rounded) + Color trackColor = _checked + ? (isDarkMode ? DarkOnTrack : LightOnTrack) + : (isDarkMode ? DarkOffTrack : LightOffTrack); + + int cornerRadius = trackHeight / 2; + Rectangle trackRect = new(TrackPadding, TrackPadding, trackWidth, trackHeight); + using GraphicsPath trackPath = CreateRoundedRect(trackRect, cornerRadius); + using SolidBrush trackBrush = new(trackColor); + g.FillPath(trackBrush, trackPath); + + // Draw track border + using Pen trackPen = new(isDarkMode ? ColorTranslator.FromHtml("#555555") : ColorTranslator.FromHtml("#A0A0A0"), 1); + g.DrawPath(trackPen, trackPath); + + // Draw thumb + int thumbX = _checked + ? Width - TrackPadding - ThumbDiameter + : TrackPadding; + int thumbY = (Height - ThumbDiameter) / 2; + + using SolidBrush thumbBrush = new(ThumbColor); + g.FillEllipse(thumbBrush, thumbX, thumbY, ThumbDiameter, ThumbDiameter); + + // Draw thumb shadow + using Pen thumbShadowPen = new(Color.FromArgb(60, 0, 0, 0), 1); + g.DrawEllipse(thumbShadowPen, thumbX, thumbY, ThumbDiameter, ThumbDiameter); + } + + private static GraphicsPath CreateRoundedRect(Rectangle rect, int radius) + { + int d = radius * 2; + GraphicsPath path = new(); + path.StartFigure(); + path.AddArc(rect.X, rect.Y, d, d, 180, 90); + path.AddArc(rect.Right - d, rect.Y, d, d, 270, 90); + path.AddArc(rect.Right - d, rect.Bottom - d, d, d, 0, 90); + path.AddArc(rect.X, rect.Bottom - d, d, d, 90, 90); + path.CloseFigure(); + return path; + } +} diff --git a/CreamInstaller/Forms/SelectForm.Designer.cs b/CreamInstaller/Forms/SelectForm.Designer.cs index 810e051..3d7ec75 100644 --- a/CreamInstaller/Forms/SelectForm.Designer.cs +++ b/CreamInstaller/Forms/SelectForm.Designer.cs @@ -20,19 +20,12 @@ namespace CreamInstaller.Forms private void InitializeComponent() { installButton = new Button(); - cancelButton = new Button(); programsGroupBox = new GroupBox(); - proxyFlowPanel = new FlowLayoutPanel(); - proxyAllCheckBox = new CheckBox(); noneFoundLabel = new Label(); - blockedGamesFlowPanel = new FlowLayoutPanel(); - blockedGamesCheckBox = new CheckBox(); - blockProtectedHelpButton = new Button(); useSmokeAPILayoutPanel = new FlowLayoutPanel(); - useSmokeAPICheckBox = new CheckBox(); + useSmokeApiToggle = new ToggleSwitch(); + useSmokeApiLabel = new Label(); useSmokeAPIHelpButton = new Button(); - darkModeFlowPanel = new FlowLayoutPanel(); - darkModeCheckBox = new CheckBox(); allCheckBoxLayoutPanel = new FlowLayoutPanel(); allCheckBox = new CheckBox(); progressBar = new ProgressBar(); @@ -42,15 +35,12 @@ namespace CreamInstaller.Forms uninstallButton = new Button(); progressLabelGames = new Label(); progressLabelDLCs = new Label(); - sortCheckBox = new CheckBox(); saveFlowPanel = new FlowLayoutPanel(); + settingsButton = new Button(); selectionTreeView = new CustomTreeView(); topOptionsTable = new TableLayoutPanel(); programsGroupBox.SuspendLayout(); - proxyFlowPanel.SuspendLayout(); - blockedGamesFlowPanel.SuspendLayout(); useSmokeAPILayoutPanel.SuspendLayout(); - darkModeFlowPanel.SuspendLayout(); allCheckBoxLayoutPanel.SuspendLayout(); saveFlowPanel.SuspendLayout(); SuspendLayout(); @@ -61,7 +51,7 @@ namespace CreamInstaller.Forms installButton.AutoSize = true; installButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; installButton.Enabled = false; - installButton.Location = new System.Drawing.Point(495, 376); + installButton.Location = new System.Drawing.Point(541, 382); installButton.Name = "installButton"; installButton.Padding = new Padding(3, 0, 3, 0); installButton.Size = new System.Drawing.Size(127, 25); @@ -70,139 +60,67 @@ namespace CreamInstaller.Forms installButton.UseVisualStyleBackColor = true; installButton.Click += OnInstall; // - // cancelButton - // - cancelButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; - cancelButton.AutoSize = true; - cancelButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; - cancelButton.Location = new System.Drawing.Point(12, 376); - cancelButton.Name = "cancelButton"; - cancelButton.Padding = new Padding(3, 0, 3, 0); - cancelButton.Size = new System.Drawing.Size(59, 25); - cancelButton.TabIndex = 10004; - cancelButton.Text = "Cancel"; - cancelButton.UseVisualStyleBackColor = true; - cancelButton.Click += OnCancel; - // // programsGroupBox // programsGroupBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - programsGroupBox.Controls.Add(noneFoundLabel); programsGroupBox.Controls.Add(selectionTreeView); - programsGroupBox.Location = new System.Drawing.Point(12, 47); + programsGroupBox.Location = new System.Drawing.Point(12, 43); programsGroupBox.Name = "programsGroupBox"; - programsGroupBox.Size = new System.Drawing.Size(610, 252); - programsGroupBox.TabIndex = 8; + programsGroupBox.Size = new System.Drawing.Size(656, 252); + programsGroupBox.TabIndex = 1000; programsGroupBox.TabStop = false; - programsGroupBox.Text = "Programs / Games"; - // - // proxyFlowPanel - // - proxyFlowPanel.AutoSize = true; - proxyFlowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; - proxyFlowPanel.Controls.Add(proxyAllCheckBox); - proxyFlowPanel.Margin = new Padding(0); - proxyFlowPanel.Name = "proxyFlowPanel"; - proxyFlowPanel.Size = new System.Drawing.Size(75, 19); - proxyFlowPanel.TabIndex = 10005; - proxyFlowPanel.WrapContents = false; - // - // proxyAllCheckBox - // - proxyAllCheckBox.AutoSize = true; - proxyAllCheckBox.Enabled = false; - proxyAllCheckBox.Location = new System.Drawing.Point(2, 0); - proxyAllCheckBox.Margin = new Padding(2, 0, 0, 0); - proxyAllCheckBox.Name = "proxyAllCheckBox"; - proxyAllCheckBox.Size = new System.Drawing.Size(73, 19); - proxyAllCheckBox.TabIndex = 4; - proxyAllCheckBox.Text = "Proxy All"; - proxyAllCheckBox.CheckedChanged += OnProxyAllCheckBoxChanged; + programsGroupBox.Text = "Programs && Games"; + programsGroupBox.Enter += programsGroupBox_Enter; // // noneFoundLabel // - noneFoundLabel.Dock = DockStyle.Fill; - noneFoundLabel.Location = new System.Drawing.Point(3, 19); + noneFoundLabel.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + noneFoundLabel.Location = new System.Drawing.Point(12, 321); noneFoundLabel.Name = "noneFoundLabel"; - noneFoundLabel.Size = new System.Drawing.Size(604, 230); - noneFoundLabel.TabIndex = 1002; - noneFoundLabel.Text = "No applicable programs nor games were found on your computer!"; + noneFoundLabel.Size = new System.Drawing.Size(656, 18); + noneFoundLabel.TabIndex = 1003; + noneFoundLabel.Text = "No applicable programs and/or games found."; noneFoundLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; noneFoundLabel.Visible = false; // - // blockedGamesFlowPanel - // - blockedGamesFlowPanel.AutoSize = true; - blockedGamesFlowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; - blockedGamesFlowPanel.Controls.Add(blockedGamesCheckBox); - blockedGamesFlowPanel.Controls.Add(blockProtectedHelpButton); - blockedGamesFlowPanel.Margin = new Padding(0); - blockedGamesFlowPanel.Name = "blockedGamesFlowPanel"; - blockedGamesFlowPanel.Size = new System.Drawing.Size(170, 19); - blockedGamesFlowPanel.TabIndex = 1005; - blockedGamesFlowPanel.WrapContents = false; - // - // blockedGamesCheckBox - // - blockedGamesCheckBox.AutoSize = true; - blockedGamesCheckBox.Checked = true; - blockedGamesCheckBox.CheckState = CheckState.Checked; - blockedGamesCheckBox.Enabled = false; - blockedGamesCheckBox.Location = new System.Drawing.Point(2, 0); - blockedGamesCheckBox.Margin = new Padding(2, 0, 0, 0); - blockedGamesCheckBox.Name = "blockedGamesCheckBox"; - blockedGamesCheckBox.Size = new System.Drawing.Size(148, 19); - blockedGamesCheckBox.TabIndex = 1; - blockedGamesCheckBox.Text = "Block Protected Games"; - blockedGamesCheckBox.UseVisualStyleBackColor = true; - blockedGamesCheckBox.CheckedChanged += OnBlockProtectedGamesCheckBoxChanged; - // - // blockProtectedHelpButton - // - blockProtectedHelpButton.Enabled = false; - blockProtectedHelpButton.Font = new System.Drawing.Font("Segoe UI", 7F); - blockProtectedHelpButton.Location = new System.Drawing.Point(150, 0); - blockProtectedHelpButton.Margin = new Padding(0, 0, 1, 0); - blockProtectedHelpButton.Name = "blockProtectedHelpButton"; - blockProtectedHelpButton.Size = new System.Drawing.Size(19, 19); - blockProtectedHelpButton.TabIndex = 2; - blockProtectedHelpButton.Text = "?"; - blockProtectedHelpButton.UseVisualStyleBackColor = true; - blockProtectedHelpButton.Click += OnBlockProtectedGamesHelpButtonClicked; - // // useSmokeAPILayoutPanel // useSmokeAPILayoutPanel.AutoSize = true; useSmokeAPILayoutPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; - useSmokeAPILayoutPanel.Controls.Add(useSmokeAPICheckBox); + useSmokeAPILayoutPanel.Controls.Add(useSmokeApiToggle); + useSmokeAPILayoutPanel.Controls.Add(useSmokeApiLabel); useSmokeAPILayoutPanel.Controls.Add(useSmokeAPIHelpButton); - useSmokeAPILayoutPanel.Margin = new Padding(12, 0, 0, 0); + useSmokeAPILayoutPanel.Margin = new Padding(0); useSmokeAPILayoutPanel.Name = "useSmokeAPILayoutPanel"; - useSmokeAPILayoutPanel.Size = new System.Drawing.Size(124, 19); + useSmokeAPILayoutPanel.Size = new System.Drawing.Size(150, 22); useSmokeAPILayoutPanel.TabIndex = 1006; useSmokeAPILayoutPanel.WrapContents = false; // - // useSmokeAPICheckBox + // useSmokeApiToggle // - useSmokeAPICheckBox.AutoSize = true; - useSmokeAPICheckBox.Checked = true; - useSmokeAPICheckBox.CheckState = CheckState.Checked; - useSmokeAPICheckBox.Enabled = false; - useSmokeAPICheckBox.Location = new System.Drawing.Point(2, 0); - useSmokeAPICheckBox.Margin = new Padding(2, 0, 0, 0); - useSmokeAPICheckBox.Name = "useSmokeAPICheckBox"; - useSmokeAPICheckBox.Size = new System.Drawing.Size(102, 19); - useSmokeAPICheckBox.TabIndex = 1; - useSmokeAPICheckBox.Text = "Use SmokeAPI"; - useSmokeAPICheckBox.UseVisualStyleBackColor = true; - useSmokeAPICheckBox.CheckedChanged += OnUseSmokeAPICheckBoxChanged; + useSmokeApiToggle.Location = new System.Drawing.Point(0, 0); + useSmokeApiToggle.Name = "useSmokeApiToggle"; + useSmokeApiToggle.Size = new System.Drawing.Size(44, 22); + useSmokeApiToggle.TabIndex = 1; + useSmokeApiToggle.CheckedChanged += OnUseSmokeApiToggleChanged; + // + // useSmokeApiLabel + // + useSmokeApiLabel.AutoSize = true; + useSmokeApiLabel.Location = new System.Drawing.Point(47, 2); + useSmokeApiLabel.Margin = new Padding(3, 2, 0, 0); + useSmokeApiLabel.Name = "useSmokeApiLabel"; + useSmokeApiLabel.Size = new System.Drawing.Size(70, 15); + useSmokeApiLabel.TabIndex = 3; + useSmokeApiLabel.Text = "SmokeAPI"; + useSmokeApiLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // useSmokeAPIHelpButton // useSmokeAPIHelpButton.Enabled = false; useSmokeAPIHelpButton.Font = new System.Drawing.Font("Segoe UI", 7F); - useSmokeAPIHelpButton.Location = new System.Drawing.Point(104, 0); - useSmokeAPIHelpButton.Margin = new Padding(0, 0, 1, 0); + useSmokeAPIHelpButton.Location = new System.Drawing.Point(120, 0); + useSmokeAPIHelpButton.Margin = new Padding(2, 0, 1, 0); useSmokeAPIHelpButton.Name = "useSmokeAPIHelpButton"; useSmokeAPIHelpButton.Size = new System.Drawing.Size(19, 19); useSmokeAPIHelpButton.TabIndex = 2; @@ -210,30 +128,6 @@ namespace CreamInstaller.Forms useSmokeAPIHelpButton.UseVisualStyleBackColor = true; useSmokeAPIHelpButton.Click += OnUseSmokeAPIHelpButtonClicked; // - // darkModeFlowPanel - // - darkModeFlowPanel.AutoSize = true; - darkModeFlowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; - darkModeFlowPanel.Margin = new Padding(12, 0, 0, 0); - darkModeFlowPanel.Name = "darkModeFlowPanel"; - darkModeFlowPanel.Size = new System.Drawing.Size(98, 19); - darkModeFlowPanel.TabIndex = 10011; - darkModeFlowPanel.WrapContents = false; - // - // darkModeCheckBox - // - darkModeCheckBox.AutoSize = true; - darkModeCheckBox.Enabled = true; - darkModeCheckBox.Location = new System.Drawing.Point(2, 0); - darkModeCheckBox.Margin = new Padding(2, 0, 0, 0); - darkModeCheckBox.Name = "darkModeCheckBox"; - darkModeCheckBox.Size = new System.Drawing.Size(96, 19); - darkModeCheckBox.TabIndex = 1; - darkModeCheckBox.Text = "Enable Dark Mode"; - darkModeCheckBox.UseVisualStyleBackColor = true; - darkModeCheckBox.CheckedChanged += OnDarkModeCheckBoxChanged; - darkModeFlowPanel.Controls.Add(darkModeCheckBox); - // // allCheckBoxLayoutPanel // allCheckBoxLayoutPanel.AutoSize = true; @@ -278,7 +172,7 @@ namespace CreamInstaller.Forms progressBar.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; progressBar.Location = new System.Drawing.Point(12, 352); progressBar.Name = "progressBar"; - progressBar.Size = new System.Drawing.Size(610, 23); + progressBar.Size = new System.Drawing.Size(656, 23); progressBar.TabIndex = 9; // // progressLabel @@ -286,108 +180,105 @@ namespace CreamInstaller.Forms progressLabel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; progressLabel.Location = new System.Drawing.Point(12, 302); progressLabel.Name = "progressLabel"; - progressLabel.Size = new System.Drawing.Size(610, 23); + progressLabel.Size = new System.Drawing.Size(656, 23); progressLabel.TabIndex = 10; - progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . 0%"; + progressLabel.Text = "Gathering and caching programs . . ."; + progressLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + progressLabel.Visible = false; // // scanButton // - scanButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; + scanButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; scanButton.AutoSize = true; scanButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; - scanButton.Enabled = false; - scanButton.Location = new System.Drawing.Point(186, 376); + scanButton.Location = new System.Drawing.Point(450, 382); scanButton.Name = "scanButton"; scanButton.Padding = new Padding(3, 0, 3, 0); - scanButton.Size = new System.Drawing.Size(60, 25); - scanButton.TabIndex = 10002; + scanButton.Size = new System.Drawing.Size(85, 25); + scanButton.TabIndex = 10004; scanButton.Text = "Rescan"; scanButton.UseVisualStyleBackColor = true; scanButton.Click += OnScan; // // uninstallAllButton // - uninstallAllButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + uninstallAllButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; uninstallAllButton.AutoSize = true; uninstallAllButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; - uninstallAllButton.Location = new System.Drawing.Point(327, 376); + uninstallAllButton.Enabled = false; + uninstallAllButton.Location = new System.Drawing.Point(12, 382); uninstallAllButton.Name = "uninstallAllButton"; uninstallAllButton.Padding = new Padding(3, 0, 3, 0); - uninstallAllButton.Size = new System.Drawing.Size(87, 25); - uninstallAllButton.TabIndex = 10003; + uninstallAllButton.Size = new System.Drawing.Size(85, 25); + uninstallAllButton.TabIndex = 10006; uninstallAllButton.Text = "Uninstall All"; uninstallAllButton.UseVisualStyleBackColor = true; uninstallAllButton.Click += OnUninstallAll; // // uninstallButton // - uninstallButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + uninstallButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; uninstallButton.AutoSize = true; uninstallButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; uninstallButton.Enabled = false; - uninstallButton.Location = new System.Drawing.Point(420, 376); + uninstallButton.Location = new System.Drawing.Point(100, 382); uninstallButton.Name = "uninstallButton"; uninstallButton.Padding = new Padding(3, 0, 3, 0); - uninstallButton.Size = new System.Drawing.Size(69, 25); - uninstallButton.TabIndex = 10001; - uninstallButton.Text = "Uninstall"; + uninstallButton.Size = new System.Drawing.Size(174, 25); + uninstallButton.TabIndex = 10005; + uninstallButton.Text = "Uninstall Selected"; uninstallButton.UseVisualStyleBackColor = true; uninstallButton.Click += OnUninstall; // // progressLabelGames // - progressLabelGames.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - progressLabelGames.Font = new System.Drawing.Font("Segoe UI", 7F); - progressLabelGames.Location = new System.Drawing.Point(12, 325); + progressLabelGames.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; + progressLabelGames.Location = new System.Drawing.Point(12, 328); progressLabelGames.Name = "progressLabelGames"; - progressLabelGames.Size = new System.Drawing.Size(610, 12); - progressLabelGames.TabIndex = 11; - progressLabelGames.Text = "Remaining games (2): Game 1, Game 2"; + progressLabelGames.Size = new System.Drawing.Size(375, 18); + progressLabelGames.TabIndex = 10007; + progressLabelGames.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // progressLabelDLCs // - progressLabelDLCs.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; - progressLabelDLCs.Font = new System.Drawing.Font("Segoe UI", 7F); - progressLabelDLCs.Location = new System.Drawing.Point(12, 337); + progressLabelDLCs.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; + progressLabelDLCs.Location = new System.Drawing.Point(393, 328); progressLabelDLCs.Name = "progressLabelDLCs"; - progressLabelDLCs.Size = new System.Drawing.Size(610, 12); - progressLabelDLCs.TabIndex = 12; - progressLabelDLCs.Text = "Remaining DLC (2): 123456, 654321"; - // - // sortCheckBox - // - sortCheckBox.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; - sortCheckBox.AutoSize = true; - sortCheckBox.Checked = true; // Enable Sort By Name by default - sortCheckBox.Location = new System.Drawing.Point(84, 380); - sortCheckBox.Margin = new Padding(3, 0, 0, 0); - sortCheckBox.Name = "sortCheckBox"; - sortCheckBox.Size = new System.Drawing.Size(98, 19); - sortCheckBox.TabIndex = 10003; - sortCheckBox.Text = "Sort By Name"; - sortCheckBox.CheckedChanged += OnSortCheckBoxChanged; + progressLabelDLCs.Size = new System.Drawing.Size(329, 18); + progressLabelDLCs.TabIndex = 10008; + progressLabelDLCs.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // saveFlowPanel // saveFlowPanel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; saveFlowPanel.AutoSize = true; saveFlowPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; - saveFlowPanel.Location = new System.Drawing.Point(263, 376); + saveFlowPanel.Location = new System.Drawing.Point(380, 382); saveFlowPanel.Name = "saveFlowPanel"; saveFlowPanel.Size = new System.Drawing.Size(141, 25); - saveFlowPanel.TabIndex = 10008; + saveFlowPanel.TabIndex = 10009; saveFlowPanel.WrapContents = false; // + // settingsButton + // + settingsButton.AutoSize = true; + settingsButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; + settingsButton.Location = new System.Drawing.Point(0, 0); + settingsButton.Name = "settingsButton"; + settingsButton.Size = new System.Drawing.Size(60, 25); + settingsButton.TabIndex = 10010; + settingsButton.Text = "Settings"; + settingsButton.UseVisualStyleBackColor = true; + settingsButton.Click += OnSettingsButtonClick; + // // topOptionsTable // topOptionsTable.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; topOptionsTable.AutoSize = true; topOptionsTable.AutoSizeMode = AutoSizeMode.GrowAndShrink; - topOptionsTable.ColumnCount = 6; + topOptionsTable.ColumnCount = 4; topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); - topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); - topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); - topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); // spacer + topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); topOptionsTable.Location = new System.Drawing.Point(12, 12); @@ -395,36 +286,35 @@ namespace CreamInstaller.Forms topOptionsTable.Name = "topOptionsTable"; topOptionsTable.RowCount = 1; topOptionsTable.RowStyles.Add(new RowStyle(SizeType.AutoSize)); - topOptionsTable.Size = new System.Drawing.Size(610, 25); + topOptionsTable.Size = new System.Drawing.Size(656, 25); topOptionsTable.TabIndex = 10009; topOptionsTable.Controls.Clear(); - topOptionsTable.Controls.Add(blockedGamesFlowPanel, 0, 0); - topOptionsTable.Controls.Add(useSmokeAPILayoutPanel, 1, 0); - topOptionsTable.Controls.Add(darkModeFlowPanel, 2, 0); - topOptionsTable.Controls.Add(proxyFlowPanel, 4, 0); - topOptionsTable.Controls.Add(allCheckBoxLayoutPanel, 5, 0); + topOptionsTable.Controls.Add(useSmokeAPILayoutPanel, 0, 0); + topOptionsTable.Controls.Add(settingsButton, 2, 0); + topOptionsTable.Controls.Add(allCheckBoxLayoutPanel, 3, 0); // // SelectForm // AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); AutoScaleMode = AutoScaleMode.Dpi; AutoSizeMode = AutoSizeMode.GrowAndShrink; - ClientSize = new System.Drawing.Size(634, 411); + ClientSize = new System.Drawing.Size(680, 417); Controls.Add(topOptionsTable); Controls.Add(saveFlowPanel); - Controls.Add(sortCheckBox); Controls.Add(progressLabelDLCs); Controls.Add(progressLabelGames); + Controls.Add(progressLabel); + Controls.Add(progressBar); + Controls.Add(noneFoundLabel); + Controls.Add(programsGroupBox); Controls.Add(uninstallAllButton); Controls.Add(uninstallButton); Controls.Add(scanButton); - Controls.Add(programsGroupBox); - Controls.Add(progressBar); - Controls.Add(cancelButton); Controls.Add(installButton); - Controls.Add(progressLabel); - DoubleBuffered = true; - FormBorderStyle = FormBorderStyle.FixedSingle; + FormBorderStyle = FormBorderStyle.FixedDialog; + HelpButton = true; + Icon = Properties.Resources.Icon; + Margin = new Padding(4, 3, 4, 3); MaximizeBox = false; MinimizeBox = false; Name = "SelectForm"; @@ -432,14 +322,8 @@ namespace CreamInstaller.Forms Text = "SelectForm"; Load += OnLoad; programsGroupBox.ResumeLayout(false); - proxyFlowPanel.ResumeLayout(false); - proxyFlowPanel.PerformLayout(); - blockedGamesFlowPanel.ResumeLayout(false); - blockedGamesFlowPanel.PerformLayout(); useSmokeAPILayoutPanel.ResumeLayout(false); useSmokeAPILayoutPanel.PerformLayout(); - darkModeFlowPanel.ResumeLayout(false); - darkModeFlowPanel.PerformLayout(); allCheckBoxLayoutPanel.ResumeLayout(false); allCheckBoxLayoutPanel.PerformLayout(); saveFlowPanel.ResumeLayout(false); @@ -451,7 +335,6 @@ namespace CreamInstaller.Forms #endregion private Button installButton; - private Button cancelButton; private GroupBox programsGroupBox; private ProgressBar progressBar; private Label progressLabel; @@ -459,24 +342,17 @@ namespace CreamInstaller.Forms private Button scanButton; private Label noneFoundLabel; private CustomTreeView selectionTreeView; - private CheckBox blockedGamesCheckBox; - private Button blockProtectedHelpButton; - private CheckBox useSmokeAPICheckBox; + private ToggleSwitch useSmokeApiToggle; + private Label useSmokeApiLabel; private Button useSmokeAPIHelpButton; - private FlowLayoutPanel blockedGamesFlowPanel; private FlowLayoutPanel useSmokeAPILayoutPanel; - private FlowLayoutPanel darkModeFlowPanel; private FlowLayoutPanel allCheckBoxLayoutPanel; private Button uninstallButton; private Button uninstallAllButton; private Label progressLabelGames; private Label progressLabelDLCs; - private CheckBox sortCheckBox; - private FlowLayoutPanel proxyFlowPanel; - internal CheckBox proxyAllCheckBox; private FlowLayoutPanel saveFlowPanel; + private Button settingsButton; private TableLayoutPanel topOptionsTable; - private CheckBox darkModeCheckBox; } } - diff --git a/CreamInstaller/Forms/SelectForm.cs b/CreamInstaller/Forms/SelectForm.cs index cf24623..2a1d28f 100644 --- a/CreamInstaller/Forms/SelectForm.cs +++ b/CreamInstaller/Forms/SelectForm.cs @@ -39,7 +39,7 @@ internal sealed partial class SelectForm : CustomForm private SelectForm() { InitializeComponent(); - selectionTreeView.TreeViewNodeSorter = sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName; + selectionTreeView.TreeViewNodeSorter = Program.SortByName ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName; Text = Program.ApplicationName; } @@ -681,15 +681,11 @@ internal sealed partial class SelectForm : CustomForm try { Program.Canceled = false; - blockedGamesCheckBox.Enabled = false; - blockProtectedHelpButton.Enabled = false; - useSmokeAPICheckBox.Enabled = false; + useSmokeApiToggle.Enabled = false; useSmokeAPIHelpButton.Enabled = false; - cancelButton.Enabled = true; scanButton.Enabled = false; noneFoundLabel.Visible = false; allCheckBox.Enabled = false; - proxyAllCheckBox.Enabled = false; installButton.Enabled = false; uninstallButton.Enabled = installButton.Enabled; selectionTreeView.Enabled = false; @@ -803,18 +799,14 @@ internal sealed partial class SelectForm : CustomForm if (!scan && Selection.All.Keys.Any(s => s.InstalledUnlocker != InstalledUnlocker.None)) RefreshNewDLCsForInstalledGames(); HideProgressBar(); - selectionTreeView.Enabled = !Selection.All.IsEmpty; - allCheckBox.Enabled = selectionTreeView.Enabled; - proxyAllCheckBox.Enabled = selectionTreeView.Enabled; - noneFoundLabel.Visible = !selectionTreeView.Enabled; - installButton.Enabled = Selection.AllEnabled.Any(); - uninstallButton.Enabled = installButton.Enabled; - cancelButton.Enabled = false; - scanButton.Enabled = true; - blockedGamesCheckBox.Enabled = true; - blockProtectedHelpButton.Enabled = true; - useSmokeAPICheckBox.Enabled = true; - useSmokeAPIHelpButton.Enabled = true; + selectionTreeView.Enabled = !Selection.All.IsEmpty; + allCheckBox.Enabled = selectionTreeView.Enabled; + noneFoundLabel.Visible = !selectionTreeView.Enabled; + installButton.Enabled = Selection.AllEnabled.Any(); + uninstallButton.Enabled = installButton.Enabled; + scanButton.Enabled = true; + useSmokeApiToggle.Enabled = true; + useSmokeAPIHelpButton.Enabled = true; } catch (Exception ex) { @@ -822,11 +814,8 @@ internal sealed partial class SelectForm : CustomForm // Show error and clean up ex.HandleException(this); HideProgressBar(); - cancelButton.Enabled = false; scanButton.Enabled = true; - blockedGamesCheckBox.Enabled = true; - blockProtectedHelpButton.Enabled = true; - useSmokeAPICheckBox.Enabled = true; + useSmokeApiToggle.Enabled = true; useSmokeAPIHelpButton.Enabled = true; } } @@ -1356,7 +1345,6 @@ internal sealed partial class SelectForm : CustomForm "Are you sure you want to uninstall everything?\n\nThis will remove all DLC unlockers, CreamAPI, SmokeAPI, ScreamAPI, and proxy DLLs from all games.", acceptButtonText: "Uninstall All", cancelButtonText: "Cancel", customFormText: "Uninstall All") != DialogResult.OK) return; - cancelButton.Enabled = true; scanButton.Enabled = false; installButton.Enabled = false; uninstallButton.Enabled = false; @@ -1390,12 +1378,6 @@ internal sealed partial class SelectForm : CustomForm private void OnScan(object sender, EventArgs e) => OnLoad(forceProvideChoices: true); - private void OnCancel(object sender, EventArgs e) - { - progressLabel.Text = "Cancelling . . . "; - Program.Cleanup(); - } - private void OnAllCheckBoxChanged(object sender, EventArgs e) { bool shouldEnable = Selection.All.Keys.Any(s => !s.Enabled); @@ -1410,17 +1392,6 @@ internal sealed partial class SelectForm : CustomForm allCheckBox.CheckedChanged += OnAllCheckBoxChanged; } - private void OnProxyAllCheckBoxChanged(object sender, EventArgs e) - { - bool shouldEnable = Selection.All.Keys.Any(selection => !selection.UseProxy); - foreach (Selection selection in Selection.All.Keys) - selection.UseProxy = shouldEnable; - selectionTreeView.Invalidate(); - proxyAllCheckBox.CheckedChanged -= OnProxyAllCheckBoxChanged; - proxyAllCheckBox.Checked = shouldEnable; - proxyAllCheckBox.CheckedChanged += OnProxyAllCheckBoxChanged; - } - private void LoadSelections() { List<(Platform platform, string id, string proxy, bool enabled)> proxyChoices = @@ -1557,9 +1528,6 @@ internal sealed partial class SelectForm : CustomForm internal void OnProxyChanged() { selectionTreeView.Invalidate(); - proxyAllCheckBox.CheckedChanged -= OnProxyAllCheckBoxChanged; - proxyAllCheckBox.Checked = Selection.All.Keys.Count != 0 && Selection.All.Keys.All(selection => selection.UseProxy); - proxyAllCheckBox.CheckedChanged += OnProxyAllCheckBoxChanged; } internal void OnExtraProtectionChanged() @@ -1567,40 +1535,10 @@ internal sealed partial class SelectForm : CustomForm selectionTreeView.Invalidate(); } - private void OnBlockProtectedGamesCheckBoxChanged(object sender, EventArgs e) + private void OnUseSmokeApiToggleChanged(object sender, EventArgs e) { - Program.BlockProtectedGames = blockedGamesCheckBox.Checked; - OnLoad(forceProvideChoices: true); - } - - private void OnBlockProtectedGamesHelpButtonClicked(object sender, EventArgs e) - { - StringBuilder blockedGames = new(); - foreach (string name in Program.ProtectedGames) - _ = blockedGames.Append(HelpButtonListPrefix + name); - StringBuilder blockedDirectories = new(); - foreach (string path in Program.ProtectedGameDirectories) - _ = blockedDirectories.Append(HelpButtonListPrefix + path); - StringBuilder blockedDirectoryExceptions = new(); - foreach (string name in Program.ProtectedGameDirectoryExceptions) - _ = blockedDirectoryExceptions.Append(HelpButtonListPrefix + name); - using DialogForm form = new(this); - _ = form.Show(SystemIcons.Information, - "Blocks the program from caching and displaying games protected by anti-cheats." - + "\nYou disable this option and install DLC unlockers to protected games at your own risk!" + - "\n\nBlocked games: " - + (string.IsNullOrWhiteSpace(blockedGames.ToString()) ? "(none)" : blockedGames) + - "\n\nBlocked game sub-directories: " - + (string.IsNullOrWhiteSpace(blockedDirectories.ToString()) ? "(none)" : blockedDirectories) + - "\n\nBlocked game sub-directory exceptions: " - + (string.IsNullOrWhiteSpace(blockedDirectoryExceptions.ToString()) - ? "(none)" - : blockedDirectoryExceptions), - customFormText: "Block Protected Games"); - } - private void OnUseSmokeAPICheckBoxChanged(object sender, EventArgs e) - { - Program.UseSmokeAPI = useSmokeAPICheckBox.Checked; + Program.UseSmokeAPI = useSmokeApiToggle.Checked; + useSmokeApiLabel.Text = useSmokeApiToggle.Checked ? "SmokeAPI" : "CreamAPI"; selectionTreeView.Invalidate(); } @@ -1614,26 +1552,19 @@ internal sealed partial class SelectForm : CustomForm customFormText: "Use SmokeAPI"); } - private void OnSortCheckBoxChanged(object sender, EventArgs e) - => selectionTreeView.TreeViewNodeSorter = - sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName; + private void programsGroupBox_Enter(object sender, EventArgs e) { } - private void programsGroupBox_Enter(object sender, EventArgs e) - { - - } - - private void OnDarkModeCheckBoxChanged(object sender, EventArgs e) - { - Program.DarkModeEnabled = darkModeCheckBox.Checked; - ThemeManager.ApplyToAllOpenForms(); - } + private void OnSettingsButtonClick(object sender, EventArgs e) + => SettingsForm.Show(this); protected override void OnShown(EventArgs e) { base.OnShown(e); ThemeManager.Apply(this); - if (darkModeCheckBox is not null) - darkModeCheckBox.Checked = Program.DarkModeEnabled; + if (useSmokeApiToggle is not null) + { + useSmokeApiToggle.Checked = Program.UseSmokeAPI; + useSmokeApiLabel.Text = Program.UseSmokeAPI ? "SmokeAPI" : "CreamAPI"; + } } } \ No newline at end of file diff --git a/CreamInstaller/Forms/SettingsForm.Designer.cs b/CreamInstaller/Forms/SettingsForm.Designer.cs new file mode 100644 index 0000000..e89e0fa --- /dev/null +++ b/CreamInstaller/Forms/SettingsForm.Designer.cs @@ -0,0 +1,105 @@ +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace CreamInstaller.Forms; + +partial class SettingsForm +{ + private IContainer components = null; + + protected override void Dispose(bool disposing) + { + if (disposing && components is not null) + components.Dispose(); + base.Dispose(disposing); + } + + private void InitializeComponent() + { + darkModeCheckBox = new CheckBox(); + blockedGamesCheckBox = new CheckBox(); + sortByNameCheckBox = new CheckBox(); + saveButton = new Button(); + cancelButton = new Button(); + SuspendLayout(); + // + // darkModeCheckBox + // + darkModeCheckBox.AutoSize = true; + darkModeCheckBox.Location = new Point(20, 20); + darkModeCheckBox.Name = "darkModeCheckBox"; + darkModeCheckBox.Size = new Size(120, 19); + darkModeCheckBox.TabIndex = 0; + darkModeCheckBox.Text = "Enable Dark Mode"; + darkModeCheckBox.UseVisualStyleBackColor = true; + // + // blockedGamesCheckBox + // + blockedGamesCheckBox.AutoSize = true; + blockedGamesCheckBox.Location = new Point(20, 50); + blockedGamesCheckBox.Name = "blockedGamesCheckBox"; + blockedGamesCheckBox.Size = new Size(148, 19); + blockedGamesCheckBox.TabIndex = 1; + blockedGamesCheckBox.Text = "Block Protected Games"; + blockedGamesCheckBox.UseVisualStyleBackColor = true; + // + // sortByNameCheckBox + // + sortByNameCheckBox.AutoSize = true; + sortByNameCheckBox.Location = new Point(20, 80); + sortByNameCheckBox.Name = "sortByNameCheckBox"; + sortByNameCheckBox.Size = new Size(160, 19); + sortByNameCheckBox.TabIndex = 2; + sortByNameCheckBox.Text = "Sort game list by name"; + sortByNameCheckBox.UseVisualStyleBackColor = true; + // + // saveButton + // + saveButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + saveButton.AutoSize = true; + saveButton.Location = new Point(198, 115); + saveButton.Name = "saveButton"; + saveButton.Size = new Size(75, 25); + saveButton.TabIndex = 3; + saveButton.Text = "Save"; + saveButton.UseVisualStyleBackColor = true; + saveButton.Click += OnSaveClick; + // + // cancelButton + // + cancelButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + cancelButton.AutoSize = true; + cancelButton.Location = new Point(279, 115); + cancelButton.Name = "cancelButton"; + cancelButton.Size = new Size(75, 25); + cancelButton.TabIndex = 4; + cancelButton.Text = "Cancel"; + cancelButton.UseVisualStyleBackColor = true; + cancelButton.Click += OnCancelClick; + // + // SettingsForm + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(370, 155); + Controls.Add(cancelButton); + Controls.Add(saveButton); + Controls.Add(sortByNameCheckBox); + Controls.Add(blockedGamesCheckBox); + Controls.Add(darkModeCheckBox); + FormBorderStyle = FormBorderStyle.FixedDialog; + MaximizeBox = false; + MinimizeBox = false; + Name = "SettingsForm"; + StartPosition = FormStartPosition.CenterParent; + ResumeLayout(false); + PerformLayout(); + } + + private CheckBox darkModeCheckBox; + private CheckBox blockedGamesCheckBox; + private CheckBox sortByNameCheckBox; + private Button saveButton; + private Button cancelButton; +} diff --git a/CreamInstaller/Forms/SettingsForm.cs b/CreamInstaller/Forms/SettingsForm.cs new file mode 100644 index 0000000..53f38e6 --- /dev/null +++ b/CreamInstaller/Forms/SettingsForm.cs @@ -0,0 +1,56 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using CreamInstaller.Components; +using CreamInstaller.Utility; + +namespace CreamInstaller.Forms; + +internal sealed partial class SettingsForm : CustomForm +{ + private bool wasDarkModeEnabled; + + private SettingsForm() + { + InitializeComponent(); + Text = "Settings"; + } + + internal static void Show(Form owner) + { + using SettingsForm form = new(); + form.Owner = owner; + form.StartPosition = FormStartPosition.CenterParent; + form.LoadSettings(); + form.ShowDialog(owner); + } + + private void LoadSettings() + { + darkModeCheckBox.Checked = Program.DarkModeEnabled; + blockedGamesCheckBox.Checked = Program.BlockProtectedGames; + sortByNameCheckBox.Checked = Program.SortByName; + wasDarkModeEnabled = Program.DarkModeEnabled; + } + + private void OnSaveClick(object sender, EventArgs e) + { + Program.DarkModeEnabled = darkModeCheckBox.Checked; + Program.BlockProtectedGames = blockedGamesCheckBox.Checked; + Program.SortByName = sortByNameCheckBox.Checked; + + ProgramData.SaveSettings(Program.AppSettings); + + if (wasDarkModeEnabled != darkModeCheckBox.Checked) + ThemeManager.ApplyToAllOpenForms(); + + DialogResult = DialogResult.OK; + Close(); + } + + private void OnCancelClick(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + Close(); + } +} diff --git a/CreamInstaller/Program.cs b/CreamInstaller/Program.cs index 60ef0d6..336c9c9 100644 --- a/CreamInstaller/Program.cs +++ b/CreamInstaller/Program.cs @@ -38,17 +38,37 @@ internal static class Program internal static readonly string CurrentProcessFilePath = CurrentProcess.MainModule?.FileName ?? ""; internal static readonly int CurrentProcessId = CurrentProcess.Id; - // Setting is now toggleable. Huzzah! - internal static bool UseSmokeAPI = true; + // Settings loaded from ProgramData on startup — persisted across sessions + internal static SettingsModel AppSettings { get; private set; } = new(); + + internal static bool UseSmokeAPI + { + get => AppSettings.UseSmokeAPI; + set => AppSettings.UseSmokeAPI = value; + } + + internal static bool BlockProtectedGames + { + get => AppSettings.BlockProtectedGames; + set => AppSettings.BlockProtectedGames = value; + } + + internal static bool DarkModeEnabled + { + get => AppSettings.DarkModeEnabled; + set => AppSettings.DarkModeEnabled = value; + } + + internal static bool SortByName + { + get => AppSettings.SortByName; + set => AppSettings.SortByName = value; + } - internal static bool BlockProtectedGames = true; internal static readonly string[] ProtectedGames = ["PAYDAY 2"]; internal static readonly string[] ProtectedGameDirectories = [@"\EasyAntiCheat", @"\BattlEye"]; internal static readonly string[] ProtectedGameDirectoryExceptions = []; - // Dark mode enabled by default - internal static bool DarkModeEnabled = true; - internal static bool IsGameBlocked(string name, string? directory = null) => GetGameBlockedReason(name, directory) is not null; @@ -83,13 +103,14 @@ internal static class Program { try { - HttpClientManager.Setup(); - using UpdateForm form = new(); + HttpClientManager.Setup(); + AppSettings = ProgramData.LoadSettings(); // load persisted settings + using UpdateForm form = new(); #if DEBUG - DebugForm.Current.Attach(form); + DebugForm.Current.Attach(form); #endif - // Apply initial theme (dark by default) - Utility.ThemeManager.Apply(form); + // Apply initial theme (dark by default) + Utility.ThemeManager.Apply(form); Application.Run(form); retry = false; } @@ -167,6 +188,7 @@ internal static class Program } finally { + ProgramData.SaveSettings(AppSettings); HttpClientManager.Dispose(); } } diff --git a/CreamInstaller/Selection.cs b/CreamInstaller/Selection.cs index 5091f41..bbdfb18 100644 --- a/CreamInstaller/Selection.cs +++ b/CreamInstaller/Selection.cs @@ -75,7 +75,7 @@ internal sealed class Selection : IEquatable if (selectForm is null) return; Enabled = selectForm.allCheckBox.Checked; - UseProxy = selectForm.proxyAllCheckBox.Checked; + UseProxy = false; } internal static IEnumerable AllEnabled => All.Keys.Where(s => s.Enabled); diff --git a/CreamInstaller/Utility/ProgramData.cs b/CreamInstaller/Utility/ProgramData.cs index 368a591..6de833f 100644 --- a/CreamInstaller/Utility/ProgramData.cs +++ b/CreamInstaller/Utility/ProgramData.cs @@ -79,6 +79,7 @@ internal static class ProgramData private static readonly string KoaloaderProxyChoicesPath = CachePath + @"\proxies.json"; private static readonly string ExtraProtectionChoicesPath = CachePath + @"\extraprotection.json"; private static readonly string InstalledGamesPath = CachePath + @"\installed.json"; + private static readonly string SettingsPath = CachePath + @"\settings.json"; private static readonly string LogsPath = DirectoryPath + @"\Logs"; internal static readonly string ScanLogPath = LogsPath + @"\game-scan.log"; @@ -473,4 +474,31 @@ internal static event Action OnLog; if (records.RemoveAll(r => r.Platform == platform && r.Id == id) > 0) WriteInstalledGames(records); } + + internal static SettingsModel LoadSettings() + { + try + { + if (JsonConvert.DeserializeObject(SettingsPath.ReadFile()) is SettingsModel settings) + return settings; + } + catch + { + // ignored + } + + return new SettingsModel(); + } + + internal static void SaveSettings(SettingsModel settings) + { + try + { + SettingsPath.WriteFile(JsonConvert.SerializeObject(settings, Formatting.Indented)); + } + catch + { + // ignored + } + } } \ No newline at end of file diff --git a/CreamInstaller/Utility/Settings.cs b/CreamInstaller/Utility/Settings.cs new file mode 100644 index 0000000..8c68c66 --- /dev/null +++ b/CreamInstaller/Utility/Settings.cs @@ -0,0 +1,9 @@ +namespace CreamInstaller.Utility; + +internal sealed class SettingsModel +{ + public bool UseSmokeAPI { get; set; } = true; + public bool BlockProtectedGames { get; set; } = true; + public bool DarkModeEnabled { get; set; } = true; + public bool SortByName { get; set; } = true; +} From 9bac1f3944772b6c3b698af367fa6158a18fdd76 Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 01:49:30 -0700 Subject: [PATCH 02/13] Rename SelectForm to MainForm and SelectDialogForm to ScanDialog. - MainForm is the primary application window that displays the list of installed games and DLC unlockers, and is where DLC unlockers are configured and installed. - ScanDialog performs a library scan and allows the user to select which games to begin configuring DLC unlockers for. --- CreamInstaller/Components/CustomTreeView.cs | 6 +++--- CreamInstaller/CreamInstaller.csproj | 8 ++++---- CreamInstaller/Forms/InstallForm.cs | 2 +- ...lectForm.Designer.cs => MainForm.Designer.cs} | 8 ++++---- .../Forms/{SelectForm.cs => MainForm.cs} | 16 ++++++++-------- .../Forms/{SelectForm.resx => MainForm.resx} | 0 ...ogForm.Designer.cs => ScanDialog.Designer.cs} | 8 ++++---- .../Forms/{SelectDialogForm.cs => ScanDialog.cs} | 4 ++-- .../{SelectDialogForm.resx => ScanDialog.resx} | 0 CreamInstaller/Forms/UpdateForm.cs | 2 +- CreamInstaller/Selection.cs | 2 +- 11 files changed, 28 insertions(+), 28 deletions(-) rename CreamInstaller/Forms/{SelectForm.Designer.cs => MainForm.Designer.cs} (99%) rename CreamInstaller/Forms/{SelectForm.cs => MainForm.cs} (99%) rename CreamInstaller/Forms/{SelectForm.resx => MainForm.resx} (100%) rename CreamInstaller/Forms/{SelectDialogForm.Designer.cs => ScanDialog.Designer.cs} (98%) rename CreamInstaller/Forms/{SelectDialogForm.cs => ScanDialog.cs} (97%) rename CreamInstaller/Forms/{SelectDialogForm.resx => ScanDialog.resx} (100%) diff --git a/CreamInstaller/Components/CustomTreeView.cs b/CreamInstaller/Components/CustomTreeView.cs index eea1d41..a004def 100644 --- a/CreamInstaller/Components/CustomTreeView.cs +++ b/CreamInstaller/Components/CustomTreeView.cs @@ -199,7 +199,7 @@ internal sealed class CustomTreeView : TreeView Rectangle bounds = node.Bounds; Rectangle selectionBounds = bounds; - if (form is not SelectForm and not SelectDialogForm) + if (form is not MainForm and not ScanDialog) return; string id = node.Name; @@ -255,7 +255,7 @@ internal sealed class CustomTreeView : TreeView TextRenderer.DrawText(graphics, text, font, point, color, TextFormatFlags.Default); } - if (form is SelectForm) + if (form is MainForm) { Selection selection = Selection.FromId(platform, id); if (selection is not null) @@ -448,7 +448,7 @@ internal sealed class CustomTreeView : TreeView base.OnMouseDown(e); Refresh(); Point clickPoint = PointToClient(e.Location); - SelectForm selectForm = (form ??= FindForm()) as SelectForm; + MainForm selectForm = (form ??= FindForm()) as MainForm; foreach (KeyValuePair pair in selectionBounds) if (pair.Key.TreeView is null) _ = selectionBounds.Remove(pair.Key); diff --git a/CreamInstaller/CreamInstaller.csproj b/CreamInstaller/CreamInstaller.csproj index 8cbae6e..a401555 100644 --- a/CreamInstaller/CreamInstaller.csproj +++ b/CreamInstaller/CreamInstaller.csproj @@ -169,10 +169,10 @@ Form - + Form - + Form @@ -194,10 +194,10 @@ Designer - + Designer - + Designer diff --git a/CreamInstaller/Forms/InstallForm.cs b/CreamInstaller/Forms/InstallForm.cs index e817cce..1fb20fe 100644 --- a/CreamInstaller/Forms/InstallForm.cs +++ b/CreamInstaller/Forms/InstallForm.cs @@ -395,7 +395,7 @@ internal sealed partial class InstallForm : CustomForm ProgramData.Log.Info($"[InstallForm] No unlocker detected after install | Game: {selection.Name} ({selection.Id})", LogDestination.Unlocker); } } - SelectForm.Current?.Invoke(() => SelectForm.Current?.InvalidateGameList()); + MainForm.Current?.Invoke(() => MainForm.Current?.InvalidateGameList()); Program.Cleanup(); int activeCount = activeSelections.Count; diff --git a/CreamInstaller/Forms/SelectForm.Designer.cs b/CreamInstaller/Forms/MainForm.Designer.cs similarity index 99% rename from CreamInstaller/Forms/SelectForm.Designer.cs rename to CreamInstaller/Forms/MainForm.Designer.cs index 3d7ec75..5c075bf 100644 --- a/CreamInstaller/Forms/SelectForm.Designer.cs +++ b/CreamInstaller/Forms/MainForm.Designer.cs @@ -5,7 +5,7 @@ using System.Windows.Forms; namespace CreamInstaller.Forms { - partial class SelectForm + partial class MainForm { private IContainer components = null; protected override void Dispose(bool disposing) @@ -293,7 +293,7 @@ namespace CreamInstaller.Forms topOptionsTable.Controls.Add(settingsButton, 2, 0); topOptionsTable.Controls.Add(allCheckBoxLayoutPanel, 3, 0); // - // SelectForm + // MainForm // AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); AutoScaleMode = AutoScaleMode.Dpi; @@ -317,9 +317,9 @@ namespace CreamInstaller.Forms Margin = new Padding(4, 3, 4, 3); MaximizeBox = false; MinimizeBox = false; - Name = "SelectForm"; + Name = "MainForm"; StartPosition = FormStartPosition.Manual; - Text = "SelectForm"; + Text = "MainForm"; Load += OnLoad; programsGroupBox.ResumeLayout(false); useSmokeAPILayoutPanel.ResumeLayout(false); diff --git a/CreamInstaller/Forms/SelectForm.cs b/CreamInstaller/Forms/MainForm.cs similarity index 99% rename from CreamInstaller/Forms/SelectForm.cs rename to CreamInstaller/Forms/MainForm.cs index 2a1d28f..264c0d3 100644 --- a/CreamInstaller/Forms/SelectForm.cs +++ b/CreamInstaller/Forms/MainForm.cs @@ -21,11 +21,11 @@ using static CreamInstaller.Resources.Resources; namespace CreamInstaller.Forms; -internal sealed partial class SelectForm : CustomForm +internal sealed partial class MainForm : CustomForm { private const string HelpButtonListPrefix = "\n • "; - private static SelectForm current; + private static MainForm current; private static readonly object currentLock = new(); private readonly ConcurrentDictionary remainingDLCs = new(); @@ -36,14 +36,14 @@ internal sealed partial class SelectForm : CustomForm private List<(Platform platform, string id, string name)> programsToScan; - private SelectForm() + private MainForm() { InitializeComponent(); selectionTreeView.TreeViewNodeSorter = Program.SortByName ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName; Text = Program.ApplicationName; } - internal static SelectForm Current + internal static MainForm Current { get { @@ -51,7 +51,7 @@ internal sealed partial class SelectForm : CustomForm { if (current is null || current.Disposing || current.IsDisposed) { - current = new SelectForm(); + current = new MainForm(); } return current; } @@ -733,7 +733,7 @@ internal sealed partial class SelectForm : CustomForm ProgramData.Log.Info($"[Total] Total time spent detecting games and libraries: {(selectionTimer.Elapsed.TotalSeconds >= 60 ? $"{selectionTimer.Elapsed.TotalSeconds / 60:F1} minutes" : $"{selectionTimer.Elapsed.TotalSeconds:F3}s")}", LogDestination.Scan); if (gameChoices.Count > 0) { - using SelectDialogForm form = new(this); + using ScanDialog form = new(this); DialogResult selectResult = form.QueryUser("Choose which programs and/or games to scan:", gameChoices, out List<(Platform platform, string id, string name)> choices); scan = selectResult == DialogResult.OK && choices is not null && choices.Count > 0; @@ -810,7 +810,7 @@ internal sealed partial class SelectForm : CustomForm } catch (Exception ex) { - ProgramData.Log.Error("SelectForm OnLoad failed", ex); + ProgramData.Log.Error("MainForm OnLoad failed", ex); // Show error and clean up ex.HandleException(this); HideProgressBar(); @@ -1246,7 +1246,7 @@ internal sealed partial class SelectForm : CustomForm if (newDlcList.Count > 0) { - SelectForm form = SelectForm.Current; + MainForm form = MainForm.Current; if (form is null || form.Disposing || form.IsDisposed) return; form.Invoke(delegate diff --git a/CreamInstaller/Forms/SelectForm.resx b/CreamInstaller/Forms/MainForm.resx similarity index 100% rename from CreamInstaller/Forms/SelectForm.resx rename to CreamInstaller/Forms/MainForm.resx diff --git a/CreamInstaller/Forms/SelectDialogForm.Designer.cs b/CreamInstaller/Forms/ScanDialog.Designer.cs similarity index 98% rename from CreamInstaller/Forms/SelectDialogForm.Designer.cs rename to CreamInstaller/Forms/ScanDialog.Designer.cs index 32f5421..9535802 100644 --- a/CreamInstaller/Forms/SelectDialogForm.Designer.cs +++ b/CreamInstaller/Forms/ScanDialog.Designer.cs @@ -5,7 +5,7 @@ using CreamInstaller.Components; namespace CreamInstaller.Forms { - partial class SelectDialogForm + partial class ScanDialog { private IContainer components = null; protected override void Dispose(bool disposing) @@ -169,7 +169,7 @@ namespace CreamInstaller.Forms saveButton.UseVisualStyleBackColor = true; saveButton.Click += OnSave; // - // SelectDialogForm + // ScanDialog // AcceptButton = acceptButton; AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); @@ -187,10 +187,10 @@ namespace CreamInstaller.Forms FormBorderStyle = FormBorderStyle.FixedSingle; MaximizeBox = false; MinimizeBox = false; - Name = "SelectDialogForm"; + Name = "ScanDialog"; ShowInTaskbar = false; StartPosition = FormStartPosition.Manual; - Text = "SelectDialogForm"; + Text = "ScanDialog"; groupBox.ResumeLayout(false); groupBox.PerformLayout(); allCheckBoxFlowPanel.ResumeLayout(false); diff --git a/CreamInstaller/Forms/SelectDialogForm.cs b/CreamInstaller/Forms/ScanDialog.cs similarity index 97% rename from CreamInstaller/Forms/SelectDialogForm.cs rename to CreamInstaller/Forms/ScanDialog.cs index bc4554f..36c7507 100644 --- a/CreamInstaller/Forms/SelectDialogForm.cs +++ b/CreamInstaller/Forms/ScanDialog.cs @@ -7,12 +7,12 @@ using CreamInstaller.Utility; namespace CreamInstaller.Forms; -internal sealed partial class SelectDialogForm : CustomForm +internal sealed partial class ScanDialog : CustomForm { private readonly List<(Platform platform, string id, string name)> selected = new(); private readonly List<(Platform platform, string id, string name, bool alreadySelected)> allChoices = new(); - internal SelectDialogForm(IWin32Window owner) : base(owner) + internal ScanDialog(IWin32Window owner) : base(owner) { InitializeComponent(); selectionTreeView.TreeViewNodeSorter = sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName; diff --git a/CreamInstaller/Forms/SelectDialogForm.resx b/CreamInstaller/Forms/ScanDialog.resx similarity index 100% rename from CreamInstaller/Forms/SelectDialogForm.resx rename to CreamInstaller/Forms/ScanDialog.resx diff --git a/CreamInstaller/Forms/UpdateForm.cs b/CreamInstaller/Forms/UpdateForm.cs index 2fc8f84..5746106 100644 --- a/CreamInstaller/Forms/UpdateForm.cs +++ b/CreamInstaller/Forms/UpdateForm.cs @@ -32,7 +32,7 @@ internal sealed partial class UpdateForm : CustomForm private void StartProgram() { - SelectForm form = SelectForm.Current; + MainForm form = MainForm.Current; form.InheritLocation(this); form.FormClosing += (_, _) => Close(); form.Show(); diff --git a/CreamInstaller/Selection.cs b/CreamInstaller/Selection.cs index bbdfb18..c3b2f9f 100644 --- a/CreamInstaller/Selection.cs +++ b/CreamInstaller/Selection.cs @@ -71,7 +71,7 @@ internal sealed class Selection : IEquatable ExecutableDirectories = executableDirectories; _ = All.TryAdd(this, default); TreeNode = new() { Tag = Platform, Name = Id, Text = Name }; - SelectForm selectForm = SelectForm.Current; + MainForm selectForm = MainForm.Current; if (selectForm is null) return; Enabled = selectForm.allCheckBox.Checked; From 5686664b98bfa27b96117c1fb0ce92fc684ff7c5 Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 01:57:15 -0700 Subject: [PATCH 03/13] Add Tooltips to Settings / Fix Sort By Name Setting - Fixes bug where game list was not updates after saving settings when changing the sort setting - Add tooltips to the settings menu to describe what each setting does - Add tooltips to the buttons in the mainform --- CreamInstaller/Forms/MainForm.Designer.cs | 12 ++++++++++++ CreamInstaller/Forms/MainForm.cs | 5 +++++ CreamInstaller/Forms/SettingsForm.Designer.cs | 11 +++++++++++ CreamInstaller/Forms/SettingsForm.cs | 5 +++++ 4 files changed, 33 insertions(+) diff --git a/CreamInstaller/Forms/MainForm.Designer.cs b/CreamInstaller/Forms/MainForm.Designer.cs index 5c075bf..6c834ac 100644 --- a/CreamInstaller/Forms/MainForm.Designer.cs +++ b/CreamInstaller/Forms/MainForm.Designer.cs @@ -39,6 +39,10 @@ namespace CreamInstaller.Forms settingsButton = new Button(); selectionTreeView = new CustomTreeView(); topOptionsTable = new TableLayoutPanel(); + mainToolTip = new ToolTip(); + mainToolTip.AutoPopDelay = 8000; + mainToolTip.InitialDelay = 500; + mainToolTip.ReshowDelay = 100; programsGroupBox.SuspendLayout(); useSmokeAPILayoutPanel.SuspendLayout(); allCheckBoxLayoutPanel.SuspendLayout(); @@ -59,6 +63,7 @@ namespace CreamInstaller.Forms installButton.Text = "Generate and Install"; installButton.UseVisualStyleBackColor = true; installButton.Click += OnInstall; + mainToolTip.SetToolTip(installButton, "Generate DLC unlocker configurations and install them into the selected games."); // // programsGroupBox // @@ -127,6 +132,8 @@ namespace CreamInstaller.Forms useSmokeAPIHelpButton.Text = "?"; useSmokeAPIHelpButton.UseVisualStyleBackColor = true; useSmokeAPIHelpButton.Click += OnUseSmokeAPIHelpButtonClicked; + mainToolTip.SetToolTip(useSmokeAPIHelpButton, "Learn more about the SmokeAPI and CreamAPI unlocker engines."); + mainToolTip.SetToolTip(useSmokeApiToggle, "Switch between SmokeAPI (on) and CreamAPI (off) unlocker engines for Steam and Paradox games."); // // allCheckBoxLayoutPanel // @@ -199,6 +206,7 @@ namespace CreamInstaller.Forms scanButton.Text = "Rescan"; scanButton.UseVisualStyleBackColor = true; scanButton.Click += OnScan; + mainToolTip.SetToolTip(scanButton, "Re-scan for installed games and refresh the DLC list from cache."); // // uninstallAllButton // @@ -214,6 +222,7 @@ namespace CreamInstaller.Forms uninstallAllButton.Text = "Uninstall All"; uninstallAllButton.UseVisualStyleBackColor = true; uninstallAllButton.Click += OnUninstallAll; + mainToolTip.SetToolTip(uninstallAllButton, "Remove all installed DLC unlockers from every game."); // // uninstallButton // @@ -229,6 +238,7 @@ namespace CreamInstaller.Forms uninstallButton.Text = "Uninstall Selected"; uninstallButton.UseVisualStyleBackColor = true; uninstallButton.Click += OnUninstall; + mainToolTip.SetToolTip(uninstallButton, "Remove DLC unlockers from the selected games only."); // // progressLabelGames // @@ -270,6 +280,7 @@ namespace CreamInstaller.Forms settingsButton.Text = "Settings"; settingsButton.UseVisualStyleBackColor = true; settingsButton.Click += OnSettingsButtonClick; + mainToolTip.SetToolTip(settingsButton, "Open application settings."); // // topOptionsTable // @@ -354,5 +365,6 @@ namespace CreamInstaller.Forms private FlowLayoutPanel saveFlowPanel; private Button settingsButton; private TableLayoutPanel topOptionsTable; + private ToolTip mainToolTip; } } diff --git a/CreamInstaller/Forms/MainForm.cs b/CreamInstaller/Forms/MainForm.cs index 264c0d3..d86a370 100644 --- a/CreamInstaller/Forms/MainForm.cs +++ b/CreamInstaller/Forms/MainForm.cs @@ -43,6 +43,11 @@ internal sealed partial class MainForm : CustomForm Text = Program.ApplicationName; } + internal void UpdateSortOrder(bool sortByName) + => selectionTreeView.TreeViewNodeSorter = sortByName + ? PlatformIdComparer.NodeText + : PlatformIdComparer.NodeName; + internal static MainForm Current { get diff --git a/CreamInstaller/Forms/SettingsForm.Designer.cs b/CreamInstaller/Forms/SettingsForm.Designer.cs index e89e0fa..e56cd5c 100644 --- a/CreamInstaller/Forms/SettingsForm.Designer.cs +++ b/CreamInstaller/Forms/SettingsForm.Designer.cs @@ -22,8 +22,15 @@ partial class SettingsForm sortByNameCheckBox = new CheckBox(); saveButton = new Button(); cancelButton = new Button(); + settingsToolTip = new ToolTip(); SuspendLayout(); // + // settingsToolTip + // + settingsToolTip.AutoPopDelay = 8000; + settingsToolTip.InitialDelay = 500; + settingsToolTip.ReshowDelay = 100; + // // darkModeCheckBox // darkModeCheckBox.AutoSize = true; @@ -33,6 +40,7 @@ partial class SettingsForm darkModeCheckBox.TabIndex = 0; darkModeCheckBox.Text = "Enable Dark Mode"; darkModeCheckBox.UseVisualStyleBackColor = true; + settingsToolTip.SetToolTip(darkModeCheckBox, "Switches the application between light and dark color themes. Changes apply immediately."); // // blockedGamesCheckBox // @@ -43,6 +51,7 @@ partial class SettingsForm blockedGamesCheckBox.TabIndex = 1; blockedGamesCheckBox.Text = "Block Protected Games"; blockedGamesCheckBox.UseVisualStyleBackColor = true; + settingsToolTip.SetToolTip(blockedGamesCheckBox, "Prevents the program from displaying or modifying games protected by anti-cheat software (e.g. Easy Anti-Cheat, BattlEye). Disable at your own risk."); // // sortByNameCheckBox // @@ -53,6 +62,7 @@ partial class SettingsForm sortByNameCheckBox.TabIndex = 2; sortByNameCheckBox.Text = "Sort game list by name"; sortByNameCheckBox.UseVisualStyleBackColor = true; + settingsToolTip.SetToolTip(sortByNameCheckBox, "When enabled, games in the main list are sorted alphabetically by name. When disabled, games appear in their default platform order."); // // saveButton // @@ -102,4 +112,5 @@ partial class SettingsForm private CheckBox sortByNameCheckBox; private Button saveButton; private Button cancelButton; + private ToolTip settingsToolTip; } diff --git a/CreamInstaller/Forms/SettingsForm.cs b/CreamInstaller/Forms/SettingsForm.cs index 53f38e6..7d660f7 100644 --- a/CreamInstaller/Forms/SettingsForm.cs +++ b/CreamInstaller/Forms/SettingsForm.cs @@ -9,6 +9,7 @@ namespace CreamInstaller.Forms; internal sealed partial class SettingsForm : CustomForm { private bool wasDarkModeEnabled; + private bool wasSortByName; private SettingsForm() { @@ -31,6 +32,7 @@ internal sealed partial class SettingsForm : CustomForm blockedGamesCheckBox.Checked = Program.BlockProtectedGames; sortByNameCheckBox.Checked = Program.SortByName; wasDarkModeEnabled = Program.DarkModeEnabled; + wasSortByName = Program.SortByName; } private void OnSaveClick(object sender, EventArgs e) @@ -44,6 +46,9 @@ internal sealed partial class SettingsForm : CustomForm if (wasDarkModeEnabled != darkModeCheckBox.Checked) ThemeManager.ApplyToAllOpenForms(); + if (wasSortByName != sortByNameCheckBox.Checked) + MainForm.Current?.UpdateSortOrder(sortByNameCheckBox.Checked); + DialogResult = DialogResult.OK; Close(); } From 3d77095ab97750b27273a66196f58bd8400c3e67 Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 02:15:55 -0700 Subject: [PATCH 04/13] Fix Minor Setting UI Bug - Fixes an issue with checkboxes in the settings menu, when checking them there was a slight clipping on the left of the checkbox. --- CreamInstaller/Forms/SettingsForm.Designer.cs | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/CreamInstaller/Forms/SettingsForm.Designer.cs b/CreamInstaller/Forms/SettingsForm.Designer.cs index e56cd5c..9598c39 100644 --- a/CreamInstaller/Forms/SettingsForm.Designer.cs +++ b/CreamInstaller/Forms/SettingsForm.Designer.cs @@ -33,42 +33,45 @@ partial class SettingsForm // // darkModeCheckBox // - darkModeCheckBox.AutoSize = true; - darkModeCheckBox.Location = new Point(20, 20); - darkModeCheckBox.Name = "darkModeCheckBox"; - darkModeCheckBox.Size = new Size(120, 19); - darkModeCheckBox.TabIndex = 0; + darkModeCheckBox.AutoSize = false; + darkModeCheckBox.Location = new Point(36, 20); + darkModeCheckBox.Name = "darkModeCheckBox"; + darkModeCheckBox.Size = new Size(160, 22); + darkModeCheckBox.TabIndex = 0; darkModeCheckBox.Text = "Enable Dark Mode"; - darkModeCheckBox.UseVisualStyleBackColor = true; + darkModeCheckBox.FlatStyle = FlatStyle.System; + darkModeCheckBox.UseVisualStyleBackColor = true; settingsToolTip.SetToolTip(darkModeCheckBox, "Switches the application between light and dark color themes. Changes apply immediately."); // // blockedGamesCheckBox // - blockedGamesCheckBox.AutoSize = true; - blockedGamesCheckBox.Location = new Point(20, 50); - blockedGamesCheckBox.Name = "blockedGamesCheckBox"; - blockedGamesCheckBox.Size = new Size(148, 19); - blockedGamesCheckBox.TabIndex = 1; + blockedGamesCheckBox.AutoSize = false; + blockedGamesCheckBox.Location = new Point(36, 50); + blockedGamesCheckBox.Name = "blockedGamesCheckBox"; + blockedGamesCheckBox.Size = new Size(190, 22); + blockedGamesCheckBox.TabIndex = 1; blockedGamesCheckBox.Text = "Block Protected Games"; - blockedGamesCheckBox.UseVisualStyleBackColor = true; + blockedGamesCheckBox.FlatStyle = FlatStyle.System; + blockedGamesCheckBox.UseVisualStyleBackColor = true; settingsToolTip.SetToolTip(blockedGamesCheckBox, "Prevents the program from displaying or modifying games protected by anti-cheat software (e.g. Easy Anti-Cheat, BattlEye). Disable at your own risk."); // // sortByNameCheckBox // - sortByNameCheckBox.AutoSize = true; - sortByNameCheckBox.Location = new Point(20, 80); - sortByNameCheckBox.Name = "sortByNameCheckBox"; - sortByNameCheckBox.Size = new Size(160, 19); - sortByNameCheckBox.TabIndex = 2; + sortByNameCheckBox.AutoSize = false; + sortByNameCheckBox.Location = new Point(36, 80); + sortByNameCheckBox.Name = "sortByNameCheckBox"; + sortByNameCheckBox.Size = new Size(200, 22); + sortByNameCheckBox.TabIndex = 2; sortByNameCheckBox.Text = "Sort game list by name"; - sortByNameCheckBox.UseVisualStyleBackColor = true; + sortByNameCheckBox.FlatStyle = FlatStyle.System; + sortByNameCheckBox.UseVisualStyleBackColor = true; settingsToolTip.SetToolTip(sortByNameCheckBox, "When enabled, games in the main list are sorted alphabetically by name. When disabled, games appear in their default platform order."); // // saveButton // saveButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; saveButton.AutoSize = true; - saveButton.Location = new Point(198, 115); + saveButton.Location = new Point(220, 115); saveButton.Name = "saveButton"; saveButton.Size = new Size(75, 25); saveButton.TabIndex = 3; @@ -80,7 +83,7 @@ partial class SettingsForm // cancelButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; cancelButton.AutoSize = true; - cancelButton.Location = new Point(279, 115); + cancelButton.Location = new Point(301, 115); cancelButton.Name = "cancelButton"; cancelButton.Size = new Size(75, 25); cancelButton.TabIndex = 4; @@ -92,7 +95,7 @@ partial class SettingsForm // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(370, 155); + ClientSize = new Size(400, 155); Controls.Add(cancelButton); Controls.Add(saveButton); Controls.Add(sortByNameCheckBox); From 8b1cbc65ff1376de897219989b46934e9743844d Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 02:22:51 -0700 Subject: [PATCH 05/13] Fixes some shitty indentation - fixes some shit indentations --- CreamInstaller/Forms/SettingsForm.Designer.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/CreamInstaller/Forms/SettingsForm.Designer.cs b/CreamInstaller/Forms/SettingsForm.Designer.cs index 9598c39..610aff6 100644 --- a/CreamInstaller/Forms/SettingsForm.Designer.cs +++ b/CreamInstaller/Forms/SettingsForm.Designer.cs @@ -34,37 +34,37 @@ partial class SettingsForm // darkModeCheckBox // darkModeCheckBox.AutoSize = false; - darkModeCheckBox.Location = new Point(36, 20); - darkModeCheckBox.Name = "darkModeCheckBox"; - darkModeCheckBox.Size = new Size(160, 22); - darkModeCheckBox.TabIndex = 0; + darkModeCheckBox.Location = new Point(36, 20); + darkModeCheckBox.Name = "darkModeCheckBox"; + darkModeCheckBox.Size = new Size(160, 22); + darkModeCheckBox.TabIndex = 0; darkModeCheckBox.Text = "Enable Dark Mode"; darkModeCheckBox.FlatStyle = FlatStyle.System; - darkModeCheckBox.UseVisualStyleBackColor = true; + darkModeCheckBox.UseVisualStyleBackColor = true; settingsToolTip.SetToolTip(darkModeCheckBox, "Switches the application between light and dark color themes. Changes apply immediately."); // // blockedGamesCheckBox // blockedGamesCheckBox.AutoSize = false; - blockedGamesCheckBox.Location = new Point(36, 50); - blockedGamesCheckBox.Name = "blockedGamesCheckBox"; - blockedGamesCheckBox.Size = new Size(190, 22); - blockedGamesCheckBox.TabIndex = 1; + blockedGamesCheckBox.Location = new Point(36, 50); + blockedGamesCheckBox.Name = "blockedGamesCheckBox"; + blockedGamesCheckBox.Size = new Size(190, 22); + blockedGamesCheckBox.TabIndex = 1; blockedGamesCheckBox.Text = "Block Protected Games"; blockedGamesCheckBox.FlatStyle = FlatStyle.System; - blockedGamesCheckBox.UseVisualStyleBackColor = true; + blockedGamesCheckBox.UseVisualStyleBackColor = true; settingsToolTip.SetToolTip(blockedGamesCheckBox, "Prevents the program from displaying or modifying games protected by anti-cheat software (e.g. Easy Anti-Cheat, BattlEye). Disable at your own risk."); // // sortByNameCheckBox // sortByNameCheckBox.AutoSize = false; - sortByNameCheckBox.Location = new Point(36, 80); - sortByNameCheckBox.Name = "sortByNameCheckBox"; - sortByNameCheckBox.Size = new Size(200, 22); - sortByNameCheckBox.TabIndex = 2; + sortByNameCheckBox.Location = new Point(36, 80); + sortByNameCheckBox.Name = "sortByNameCheckBox"; + sortByNameCheckBox.Size = new Size(200, 22); + sortByNameCheckBox.TabIndex = 2; sortByNameCheckBox.Text = "Sort game list by name"; sortByNameCheckBox.FlatStyle = FlatStyle.System; - sortByNameCheckBox.UseVisualStyleBackColor = true; + sortByNameCheckBox.UseVisualStyleBackColor = true; settingsToolTip.SetToolTip(sortByNameCheckBox, "When enabled, games in the main list are sorted alphabetically by name. When disabled, games appear in their default platform order."); // // saveButton From 07ce06c990e08356c8fe72ea41e7186f0de9143c Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 11:07:14 -0700 Subject: [PATCH 06/13] Adjust DarkMode Settings Tooltip - Remove comment about changes taking effect immeditaely, the change only occurs on setting save now. --- CreamInstaller/Forms/SettingsForm.Designer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CreamInstaller/Forms/SettingsForm.Designer.cs b/CreamInstaller/Forms/SettingsForm.Designer.cs index 610aff6..5086139 100644 --- a/CreamInstaller/Forms/SettingsForm.Designer.cs +++ b/CreamInstaller/Forms/SettingsForm.Designer.cs @@ -41,7 +41,7 @@ partial class SettingsForm darkModeCheckBox.Text = "Enable Dark Mode"; darkModeCheckBox.FlatStyle = FlatStyle.System; darkModeCheckBox.UseVisualStyleBackColor = true; - settingsToolTip.SetToolTip(darkModeCheckBox, "Switches the application between light and dark color themes. Changes apply immediately."); + settingsToolTip.SetToolTip(darkModeCheckBox, "Switches the application between light and dark color themes."); // // blockedGamesCheckBox // From fc89442eb7d662e19302848f34caa9b83b952ad6 Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 15:53:51 -0700 Subject: [PATCH 07/13] Add GroupBoxes to Settings - Adds groupboxes and groups settings to make it a little more organized --- CreamInstaller/Forms/SettingsForm.Designer.cs | 78 +++++++++++++------ 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/CreamInstaller/Forms/SettingsForm.Designer.cs b/CreamInstaller/Forms/SettingsForm.Designer.cs index 5086139..4ec2631 100644 --- a/CreamInstaller/Forms/SettingsForm.Designer.cs +++ b/CreamInstaller/Forms/SettingsForm.Designer.cs @@ -17,64 +17,91 @@ partial class SettingsForm private void InitializeComponent() { + SettingsToolTip = new ToolTip(); + appearanceGroup = new GroupBox(); darkModeCheckBox = new CheckBox(); + gameManagementGroup = new GroupBox(); blockedGamesCheckBox = new CheckBox(); sortByNameCheckBox = new CheckBox(); saveButton = new Button(); cancelButton = new Button(); - settingsToolTip = new ToolTip(); + appearanceGroup.SuspendLayout(); + gameManagementGroup.SuspendLayout(); SuspendLayout(); // // settingsToolTip // - settingsToolTip.AutoPopDelay = 8000; - settingsToolTip.InitialDelay = 500; - settingsToolTip.ReshowDelay = 100; + SettingsToolTip.AutoPopDelay = 8000; + SettingsToolTip.InitialDelay = 500; + SettingsToolTip.ReshowDelay = 100; + // + // appearanceGroup + // + appearanceGroup.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + appearanceGroup.Controls.Add(darkModeCheckBox); + appearanceGroup.Location = new Point(12, 12); + appearanceGroup.Name = "appearanceGroup"; + appearanceGroup.Size = new Size(376, 50); + appearanceGroup.TabIndex = 0; + appearanceGroup.TabStop = false; + appearanceGroup.Text = "Appearance"; // // darkModeCheckBox // darkModeCheckBox.AutoSize = false; - darkModeCheckBox.Location = new Point(36, 20); + darkModeCheckBox.FlatStyle = FlatStyle.System; + darkModeCheckBox.Location = new Point(12, 20); darkModeCheckBox.Name = "darkModeCheckBox"; darkModeCheckBox.Size = new Size(160, 22); darkModeCheckBox.TabIndex = 0; darkModeCheckBox.Text = "Enable Dark Mode"; - darkModeCheckBox.FlatStyle = FlatStyle.System; darkModeCheckBox.UseVisualStyleBackColor = true; - settingsToolTip.SetToolTip(darkModeCheckBox, "Switches the application between light and dark color themes."); + SettingsToolTip.SetToolTip(darkModeCheckBox, "Switches the application between light and dark color themes."); + // + // gameManagementGroup + // + gameManagementGroup.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + gameManagementGroup.Controls.Add(blockedGamesCheckBox); + gameManagementGroup.Controls.Add(sortByNameCheckBox); + gameManagementGroup.Location = new Point(12, 72); + gameManagementGroup.Name = "gameManagementGroup"; + gameManagementGroup.Size = new Size(376, 76); + gameManagementGroup.TabIndex = 1; + gameManagementGroup.TabStop = false; + gameManagementGroup.Text = "Game Management"; // // blockedGamesCheckBox // blockedGamesCheckBox.AutoSize = false; - blockedGamesCheckBox.Location = new Point(36, 50); + blockedGamesCheckBox.FlatStyle = FlatStyle.System; + blockedGamesCheckBox.Location = new Point(12, 22); blockedGamesCheckBox.Name = "blockedGamesCheckBox"; blockedGamesCheckBox.Size = new Size(190, 22); - blockedGamesCheckBox.TabIndex = 1; + blockedGamesCheckBox.TabIndex = 0; blockedGamesCheckBox.Text = "Block Protected Games"; - blockedGamesCheckBox.FlatStyle = FlatStyle.System; blockedGamesCheckBox.UseVisualStyleBackColor = true; - settingsToolTip.SetToolTip(blockedGamesCheckBox, "Prevents the program from displaying or modifying games protected by anti-cheat software (e.g. Easy Anti-Cheat, BattlEye). Disable at your own risk."); + SettingsToolTip.SetToolTip(blockedGamesCheckBox, "Prevents the program from displaying or modifying games protected by anti-cheat software (e.g. Easy Anti-Cheat, BattlEye). Disable at your own risk."); // // sortByNameCheckBox // sortByNameCheckBox.AutoSize = false; - sortByNameCheckBox.Location = new Point(36, 80); + sortByNameCheckBox.FlatStyle = FlatStyle.System; + sortByNameCheckBox.Location = new Point(12, 48); sortByNameCheckBox.Name = "sortByNameCheckBox"; sortByNameCheckBox.Size = new Size(200, 22); - sortByNameCheckBox.TabIndex = 2; + sortByNameCheckBox.TabIndex = 1; sortByNameCheckBox.Text = "Sort game list by name"; - sortByNameCheckBox.FlatStyle = FlatStyle.System; sortByNameCheckBox.UseVisualStyleBackColor = true; - settingsToolTip.SetToolTip(sortByNameCheckBox, "When enabled, games in the main list are sorted alphabetically by name. When disabled, games appear in their default platform order."); + SettingsToolTip.SetToolTip(sortByNameCheckBox, "When enabled, games in the main list are sorted alphabetically by name. When disabled, games appear in their default platform order."); // // saveButton // saveButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; saveButton.AutoSize = true; - saveButton.Location = new Point(220, 115); + saveButton.Location = new Point(232, 160); saveButton.Name = "saveButton"; saveButton.Size = new Size(75, 25); - saveButton.TabIndex = 3; + saveButton.TabIndex = 2; saveButton.Text = "Save"; saveButton.UseVisualStyleBackColor = true; saveButton.Click += OnSaveClick; @@ -83,10 +110,10 @@ partial class SettingsForm // cancelButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; cancelButton.AutoSize = true; - cancelButton.Location = new Point(301, 115); + cancelButton.Location = new Point(313, 160); cancelButton.Name = "cancelButton"; cancelButton.Size = new Size(75, 25); - cancelButton.TabIndex = 4; + cancelButton.TabIndex = 3; cancelButton.Text = "Cancel"; cancelButton.UseVisualStyleBackColor = true; cancelButton.Click += OnCancelClick; @@ -95,25 +122,28 @@ partial class SettingsForm // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(400, 155); + ClientSize = new Size(400, 197); Controls.Add(cancelButton); Controls.Add(saveButton); - Controls.Add(sortByNameCheckBox); - Controls.Add(blockedGamesCheckBox); - Controls.Add(darkModeCheckBox); + Controls.Add(gameManagementGroup); + Controls.Add(appearanceGroup); FormBorderStyle = FormBorderStyle.FixedDialog; MaximizeBox = false; MinimizeBox = false; Name = "SettingsForm"; StartPosition = FormStartPosition.CenterParent; + appearanceGroup.ResumeLayout(false); + gameManagementGroup.ResumeLayout(false); ResumeLayout(false); PerformLayout(); } + private GroupBox appearanceGroup; + private GroupBox gameManagementGroup; private CheckBox darkModeCheckBox; private CheckBox blockedGamesCheckBox; private CheckBox sortByNameCheckBox; private Button saveButton; private Button cancelButton; - private ToolTip settingsToolTip; + private ToolTip SettingsToolTip; } From f8e3ea6e3c46487f49ddf5a553e2bb8086a1b7cb Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 21:36:38 -0700 Subject: [PATCH 08/13] Add Label for Which Unlocker Is Currently In Use - Adds label alongisde toggle switch to clearly indiciate which unlocker is in use. --- CreamInstaller/Forms/MainForm.Designer.cs | 8 ++++---- CreamInstaller/Forms/MainForm.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CreamInstaller/Forms/MainForm.Designer.cs b/CreamInstaller/Forms/MainForm.Designer.cs index 6c834ac..882d850 100644 --- a/CreamInstaller/Forms/MainForm.Designer.cs +++ b/CreamInstaller/Forms/MainForm.Designer.cs @@ -97,7 +97,7 @@ namespace CreamInstaller.Forms useSmokeAPILayoutPanel.Controls.Add(useSmokeAPIHelpButton); useSmokeAPILayoutPanel.Margin = new Padding(0); useSmokeAPILayoutPanel.Name = "useSmokeAPILayoutPanel"; - useSmokeAPILayoutPanel.Size = new System.Drawing.Size(150, 22); + useSmokeAPILayoutPanel.Size = new System.Drawing.Size(250, 22); useSmokeAPILayoutPanel.TabIndex = 1006; useSmokeAPILayoutPanel.WrapContents = false; // @@ -115,16 +115,16 @@ namespace CreamInstaller.Forms useSmokeApiLabel.Location = new System.Drawing.Point(47, 2); useSmokeApiLabel.Margin = new Padding(3, 2, 0, 0); useSmokeApiLabel.Name = "useSmokeApiLabel"; - useSmokeApiLabel.Size = new System.Drawing.Size(70, 15); + useSmokeApiLabel.Size = new System.Drawing.Size(175, 15); useSmokeApiLabel.TabIndex = 3; - useSmokeApiLabel.Text = "SmokeAPI"; + useSmokeApiLabel.Text = "Selected Unlocker: SmokeAPI"; useSmokeApiLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // useSmokeAPIHelpButton // useSmokeAPIHelpButton.Enabled = false; useSmokeAPIHelpButton.Font = new System.Drawing.Font("Segoe UI", 7F); - useSmokeAPIHelpButton.Location = new System.Drawing.Point(120, 0); + useSmokeAPIHelpButton.Location = new System.Drawing.Point(225, 0); useSmokeAPIHelpButton.Margin = new Padding(2, 0, 1, 0); useSmokeAPIHelpButton.Name = "useSmokeAPIHelpButton"; useSmokeAPIHelpButton.Size = new System.Drawing.Size(19, 19); diff --git a/CreamInstaller/Forms/MainForm.cs b/CreamInstaller/Forms/MainForm.cs index d86a370..31ff796 100644 --- a/CreamInstaller/Forms/MainForm.cs +++ b/CreamInstaller/Forms/MainForm.cs @@ -1543,7 +1543,7 @@ internal sealed partial class MainForm : CustomForm private void OnUseSmokeApiToggleChanged(object sender, EventArgs e) { Program.UseSmokeAPI = useSmokeApiToggle.Checked; - useSmokeApiLabel.Text = useSmokeApiToggle.Checked ? "SmokeAPI" : "CreamAPI"; + useSmokeApiLabel.Text = useSmokeApiToggle.Checked ? "Selected Unlocker: SmokeAPI" : "Selected Unlocker: CreamAPI"; selectionTreeView.Invalidate(); } @@ -1569,7 +1569,7 @@ internal sealed partial class MainForm : CustomForm if (useSmokeApiToggle is not null) { useSmokeApiToggle.Checked = Program.UseSmokeAPI; - useSmokeApiLabel.Text = Program.UseSmokeAPI ? "SmokeAPI" : "CreamAPI"; + useSmokeApiLabel.Text = Program.UseSmokeAPI ? "Selected Unlocker: SmokeAPI" : "Selected Unlocker: CreamAPI"; } } } \ No newline at end of file From 9468134c1afdd94ee168668c516050a50d6683cd Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 21:39:43 -0700 Subject: [PATCH 09/13] Fix Bug Where Theme Not applying to Debug Window - Fixes a bug where the selected them wasn't applying to the debug window until the app was relaunched. --- CreamInstaller/Forms/SettingsForm.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CreamInstaller/Forms/SettingsForm.cs b/CreamInstaller/Forms/SettingsForm.cs index 7d660f7..ce4eaca 100644 --- a/CreamInstaller/Forms/SettingsForm.cs +++ b/CreamInstaller/Forms/SettingsForm.cs @@ -44,7 +44,11 @@ internal sealed partial class SettingsForm : CustomForm ProgramData.SaveSettings(Program.AppSettings); if (wasDarkModeEnabled != darkModeCheckBox.Checked) + { ThemeManager.ApplyToAllOpenForms(); + if (DebugForm.IsOpen) + ThemeManager.Apply(DebugForm.Current); + } if (wasSortByName != sortByNameCheckBox.Checked) MainForm.Current?.UpdateSortOrder(sortByNameCheckBox.Checked); From 0b34bc1dad40a0bf1c7278a61c1466fde194661f Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 21:46:30 -0700 Subject: [PATCH 10/13] Save Chose Unlocker Toggle State to Settings - Saves the chosen toggle state for the specified unlocker in the settings --- CreamInstaller/Forms/MainForm.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CreamInstaller/Forms/MainForm.cs b/CreamInstaller/Forms/MainForm.cs index 31ff796..32b52ee 100644 --- a/CreamInstaller/Forms/MainForm.cs +++ b/CreamInstaller/Forms/MainForm.cs @@ -1544,6 +1544,7 @@ internal sealed partial class MainForm : CustomForm { Program.UseSmokeAPI = useSmokeApiToggle.Checked; useSmokeApiLabel.Text = useSmokeApiToggle.Checked ? "Selected Unlocker: SmokeAPI" : "Selected Unlocker: CreamAPI"; + ProgramData.SaveSettings(Program.AppSettings); selectionTreeView.Invalidate(); } From 25c4a6d4c54f5ca19997d91a4750597c0f51070d Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 22:12:50 -0700 Subject: [PATCH 11/13] Remove Uninstall All Button / Adjust Settings and Select All Buttons - Rename "All" to "Select All" - Relocated settings button to top right corner - Better center the Select All button with the settings button - Remove the Uninstall All button > fuck it, you can already do this by selecting all and uninstalling selected. --- CreamInstaller/Forms/MainForm.Designer.cs | 34 +++++--------------- CreamInstaller/Forms/MainForm.cs | 38 ----------------------- 2 files changed, 8 insertions(+), 64 deletions(-) diff --git a/CreamInstaller/Forms/MainForm.Designer.cs b/CreamInstaller/Forms/MainForm.Designer.cs index 882d850..5c287ee 100644 --- a/CreamInstaller/Forms/MainForm.Designer.cs +++ b/CreamInstaller/Forms/MainForm.Designer.cs @@ -31,7 +31,6 @@ namespace CreamInstaller.Forms progressBar = new ProgressBar(); progressLabel = new Label(); scanButton = new Button(); - uninstallAllButton = new Button(); uninstallButton = new Button(); progressLabelGames = new Label(); progressLabelDLCs = new Label(); @@ -140,7 +139,7 @@ namespace CreamInstaller.Forms allCheckBoxLayoutPanel.AutoSize = true; allCheckBoxLayoutPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; allCheckBoxLayoutPanel.Controls.Add(allCheckBox); - allCheckBoxLayoutPanel.Margin = new Padding(12, 0, 0, 0); + allCheckBoxLayoutPanel.Margin = new Padding(12, 3, 0, 0); allCheckBoxLayoutPanel.Name = "allCheckBoxLayoutPanel"; allCheckBoxLayoutPanel.Size = new System.Drawing.Size(42, 19); allCheckBoxLayoutPanel.TabIndex = 1007; @@ -148,16 +147,17 @@ namespace CreamInstaller.Forms // // allCheckBox // - allCheckBox.AutoSize = true; + allCheckBox.AutoSize = false; allCheckBox.Checked = true; allCheckBox.CheckState = CheckState.Checked; allCheckBox.Enabled = false; + allCheckBox.FlatStyle = FlatStyle.System; allCheckBox.Location = new System.Drawing.Point(2, 0); allCheckBox.Margin = new Padding(2, 0, 0, 0); allCheckBox.Name = "allCheckBox"; - allCheckBox.Size = new System.Drawing.Size(40, 19); + allCheckBox.Size = new System.Drawing.Size(75, 22); allCheckBox.TabIndex = 4; - allCheckBox.Text = "All"; + allCheckBox.Text = "Select All"; allCheckBox.CheckedChanged += OnAllCheckBoxChanged; // // selectionTreeView @@ -208,29 +208,13 @@ namespace CreamInstaller.Forms scanButton.Click += OnScan; mainToolTip.SetToolTip(scanButton, "Re-scan for installed games and refresh the DLC list from cache."); // - // uninstallAllButton - // - uninstallAllButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; - uninstallAllButton.AutoSize = true; - uninstallAllButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; - uninstallAllButton.Enabled = false; - uninstallAllButton.Location = new System.Drawing.Point(12, 382); - uninstallAllButton.Name = "uninstallAllButton"; - uninstallAllButton.Padding = new Padding(3, 0, 3, 0); - uninstallAllButton.Size = new System.Drawing.Size(85, 25); - uninstallAllButton.TabIndex = 10006; - uninstallAllButton.Text = "Uninstall All"; - uninstallAllButton.UseVisualStyleBackColor = true; - uninstallAllButton.Click += OnUninstallAll; - mainToolTip.SetToolTip(uninstallAllButton, "Remove all installed DLC unlockers from every game."); - // // uninstallButton // uninstallButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; uninstallButton.AutoSize = true; uninstallButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; uninstallButton.Enabled = false; - uninstallButton.Location = new System.Drawing.Point(100, 382); + uninstallButton.Location = new System.Drawing.Point(12, 382); uninstallButton.Name = "uninstallButton"; uninstallButton.Padding = new Padding(3, 0, 3, 0); uninstallButton.Size = new System.Drawing.Size(174, 25); @@ -301,8 +285,8 @@ namespace CreamInstaller.Forms topOptionsTable.TabIndex = 10009; topOptionsTable.Controls.Clear(); topOptionsTable.Controls.Add(useSmokeAPILayoutPanel, 0, 0); - topOptionsTable.Controls.Add(settingsButton, 2, 0); - topOptionsTable.Controls.Add(allCheckBoxLayoutPanel, 3, 0); + topOptionsTable.Controls.Add(allCheckBoxLayoutPanel, 2, 0); + topOptionsTable.Controls.Add(settingsButton, 3, 0); // // MainForm // @@ -318,7 +302,6 @@ namespace CreamInstaller.Forms Controls.Add(progressBar); Controls.Add(noneFoundLabel); Controls.Add(programsGroupBox); - Controls.Add(uninstallAllButton); Controls.Add(uninstallButton); Controls.Add(scanButton); Controls.Add(installButton); @@ -359,7 +342,6 @@ namespace CreamInstaller.Forms private FlowLayoutPanel useSmokeAPILayoutPanel; private FlowLayoutPanel allCheckBoxLayoutPanel; private Button uninstallButton; - private Button uninstallAllButton; private Label progressLabelGames; private Label progressLabelDLCs; private FlowLayoutPanel saveFlowPanel; diff --git a/CreamInstaller/Forms/MainForm.cs b/CreamInstaller/Forms/MainForm.cs index 32b52ee..2ae30eb 100644 --- a/CreamInstaller/Forms/MainForm.cs +++ b/CreamInstaller/Forms/MainForm.cs @@ -1343,44 +1343,6 @@ internal sealed partial class MainForm : CustomForm private void OnUninstall(object sender, EventArgs e) => OnAccept(true); - private async void OnUninstallAll(object sender, EventArgs e) - { - using DialogForm confirm = new(this); - if (confirm.Show(SystemIcons.Warning, - "Are you sure you want to uninstall everything?\n\nThis will remove all DLC unlockers, CreamAPI, SmokeAPI, ScreamAPI, and proxy DLLs from all games.", - acceptButtonText: "Uninstall All", cancelButtonText: "Cancel", customFormText: "Uninstall All") != DialogResult.OK) - return; - scanButton.Enabled = false; - installButton.Enabled = false; - uninstallButton.Enabled = false; - selectionTreeView.Enabled = false; - int maxProgress = 0; - int curProgress = 0; - Progress progress = new(); - IProgress iProgress = progress; - progress.ProgressChanged += (_, _progress) => - { - if (Program.Canceled) - return; - if (_progress < 0 || _progress > maxProgress) - maxProgress = -_progress; - else - curProgress = _progress; - int p = Math.Max(Math.Min((int)((float)curProgress / maxProgress * 100), 100), 0); - progressLabel.Text = $"Quickly gathering games for uninstallation . . . {p}%"; - progressBar.Value = p; - }; - ShowProgressBar(); - progressLabel.Text = "Quickly gathering games for uninstallation . . . "; - foreach (Selection selection in Selection.All.Keys) - selection.TreeNode.Remove(); - await GetApplicablePrograms(iProgress, true); - if (!Program.Canceled) - OnUninstall(null, null); - Selection.All.Clear(); - programsToScan = null; - } - private void OnScan(object sender, EventArgs e) => OnLoad(forceProvideChoices: true); private void OnAllCheckBoxChanged(object sender, EventArgs e) From 2502f124ee1753221a5103e89b3caa00d1abb83e Mon Sep 17 00:00:00 2001 From: Frog Date: Mon, 20 Jul 2026 22:46:33 -0700 Subject: [PATCH 12/13] Add Clear Cache / Reconfigure SteamCMD Buttons - Add button to clear app cache in settings - Add button to reconfigure SteamCMD in settings - Add a few edge cases to cleanup old legacy folders --- CreamInstaller/Forms/DialogForm.Designer.cs | 2 +- CreamInstaller/Forms/SettingsForm.Designer.cs | 60 +++++++++++++++++-- CreamInstaller/Forms/SettingsForm.cs | 58 ++++++++++++++++++ CreamInstaller/Utility/ProgramData.cs | 7 +++ 4 files changed, 121 insertions(+), 6 deletions(-) diff --git a/CreamInstaller/Forms/DialogForm.Designer.cs b/CreamInstaller/Forms/DialogForm.Designer.cs index 64cd5ac..0de12e2 100644 --- a/CreamInstaller/Forms/DialogForm.Designer.cs +++ b/CreamInstaller/Forms/DialogForm.Designer.cs @@ -98,7 +98,7 @@ namespace CreamInstaller.Forms // // descriptionLabelPanel // - descriptionLabelPanel.AutoScroll = true; + descriptionLabelPanel.AutoScroll = false; descriptionLabelPanel.AutoSize = true; descriptionLabelPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; descriptionLabelPanel.Controls.Add(descriptionLabel); diff --git a/CreamInstaller/Forms/SettingsForm.Designer.cs b/CreamInstaller/Forms/SettingsForm.Designer.cs index 4ec2631..6ac8d82 100644 --- a/CreamInstaller/Forms/SettingsForm.Designer.cs +++ b/CreamInstaller/Forms/SettingsForm.Designer.cs @@ -1,6 +1,10 @@ +using System; using System.ComponentModel; using System.Drawing; +using System.IO; using System.Windows.Forms; +using CreamInstaller.Platforms.Steam; +using CreamInstaller.Utility; namespace CreamInstaller.Forms; @@ -23,10 +27,14 @@ partial class SettingsForm gameManagementGroup = new GroupBox(); blockedGamesCheckBox = new CheckBox(); sortByNameCheckBox = new CheckBox(); + maintenanceGroup = new GroupBox(); + clearCacheButton = new Button(); + reconfigureSteamCMDButton = new Button(); saveButton = new Button(); cancelButton = new Button(); appearanceGroup.SuspendLayout(); gameManagementGroup.SuspendLayout(); + maintenanceGroup.SuspendLayout(); SuspendLayout(); // // settingsToolTip @@ -94,14 +102,50 @@ partial class SettingsForm sortByNameCheckBox.UseVisualStyleBackColor = true; SettingsToolTip.SetToolTip(sortByNameCheckBox, "When enabled, games in the main list are sorted alphabetically by name. When disabled, games appear in their default platform order."); // + // maintenanceGroup + // + maintenanceGroup.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + maintenanceGroup.Controls.Add(clearCacheButton); + maintenanceGroup.Controls.Add(reconfigureSteamCMDButton); + maintenanceGroup.Location = new Point(12, 160); + maintenanceGroup.Name = "maintenanceGroup"; + maintenanceGroup.Size = new Size(376, 55); + maintenanceGroup.TabIndex = 2; + maintenanceGroup.TabStop = false; + maintenanceGroup.Text = "Maintenance"; + // + // clearCacheButton + // + clearCacheButton.AutoSize = true; + clearCacheButton.Location = new Point(12, 20); + clearCacheButton.Name = "clearCacheButton"; + clearCacheButton.Size = new Size(175, 25); + clearCacheButton.TabIndex = 0; + clearCacheButton.Text = "Clear Cached Data"; + clearCacheButton.UseVisualStyleBackColor = true; + clearCacheButton.Click += OnClearCacheClick; + SettingsToolTip.SetToolTip(clearCacheButton, "Deletes all cached game data, forcing a fresh scan on the next launch. Settings are preserved."); + // + // reconfigureSteamCMDButton + // + reconfigureSteamCMDButton.AutoSize = true; + reconfigureSteamCMDButton.Location = new Point(195, 20); + reconfigureSteamCMDButton.Name = "reconfigureSteamCMDButton"; + reconfigureSteamCMDButton.Size = new Size(175, 25); + reconfigureSteamCMDButton.TabIndex = 1; + reconfigureSteamCMDButton.Text = "Reconfigure SteamCMD"; + reconfigureSteamCMDButton.UseVisualStyleBackColor = true; + reconfigureSteamCMDButton.Click += OnReconfigureSteamCMDClick; + SettingsToolTip.SetToolTip(reconfigureSteamCMDButton, "Removes the existing SteamCMD installation. It will be re-downloaded automatically on the next scan."); + // // saveButton // saveButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; saveButton.AutoSize = true; - saveButton.Location = new Point(232, 160); + saveButton.Location = new Point(232, 228); saveButton.Name = "saveButton"; saveButton.Size = new Size(75, 25); - saveButton.TabIndex = 2; + saveButton.TabIndex = 3; saveButton.Text = "Save"; saveButton.UseVisualStyleBackColor = true; saveButton.Click += OnSaveClick; @@ -110,10 +154,10 @@ partial class SettingsForm // cancelButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; cancelButton.AutoSize = true; - cancelButton.Location = new Point(313, 160); + cancelButton.Location = new Point(313, 228); cancelButton.Name = "cancelButton"; cancelButton.Size = new Size(75, 25); - cancelButton.TabIndex = 3; + cancelButton.TabIndex = 4; cancelButton.Text = "Cancel"; cancelButton.UseVisualStyleBackColor = true; cancelButton.Click += OnCancelClick; @@ -122,9 +166,10 @@ partial class SettingsForm // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(400, 197); + ClientSize = new Size(400, 265); Controls.Add(cancelButton); Controls.Add(saveButton); + Controls.Add(maintenanceGroup); Controls.Add(gameManagementGroup); Controls.Add(appearanceGroup); FormBorderStyle = FormBorderStyle.FixedDialog; @@ -134,15 +179,20 @@ partial class SettingsForm StartPosition = FormStartPosition.CenterParent; appearanceGroup.ResumeLayout(false); gameManagementGroup.ResumeLayout(false); + maintenanceGroup.ResumeLayout(false); + maintenanceGroup.PerformLayout(); ResumeLayout(false); PerformLayout(); } private GroupBox appearanceGroup; private GroupBox gameManagementGroup; + private GroupBox maintenanceGroup; private CheckBox darkModeCheckBox; private CheckBox blockedGamesCheckBox; private CheckBox sortByNameCheckBox; + private Button clearCacheButton; + private Button reconfigureSteamCMDButton; private Button saveButton; private Button cancelButton; private ToolTip SettingsToolTip; diff --git a/CreamInstaller/Forms/SettingsForm.cs b/CreamInstaller/Forms/SettingsForm.cs index ce4eaca..c5dd2e9 100644 --- a/CreamInstaller/Forms/SettingsForm.cs +++ b/CreamInstaller/Forms/SettingsForm.cs @@ -1,7 +1,10 @@ using System; using System.Drawing; +using System.IO; +using System.Threading.Tasks; using System.Windows.Forms; using CreamInstaller.Components; +using CreamInstaller.Platforms.Steam; using CreamInstaller.Utility; namespace CreamInstaller.Forms; @@ -62,4 +65,59 @@ internal sealed partial class SettingsForm : CustomForm DialogResult = DialogResult.Cancel; Close(); } + + private void OnClearCacheClick(object sender, EventArgs e) + { + using DialogForm confirm = new(this); + if (confirm.Show(SystemIcons.Warning, + "This will delete all cached game data, installed game records, and proxy configurations.\n\nYour settings will be preserved. A fresh scan will be required on the next launch.", + acceptButtonText: "Clear Cache", cancelButtonText: "Cancel", customFormText: "Clear Cached Data") != DialogResult.OK) + return; + + string cachePath = ProgramData.DirectoryPath + @"\Cache"; + if (Directory.Exists(cachePath)) + { + foreach (string file in Directory.GetFiles(cachePath)) + { + if (Path.GetFileName(file).Equals("settings.json", StringComparison.OrdinalIgnoreCase)) + continue; + try { File.Delete(file); } catch { /* skip locked files */ } + } + foreach (string dir in Directory.GetDirectories(cachePath)) + { + try { Directory.Delete(dir, true); } catch { /* skip locked dirs */ } + } + } + + ProgramData.SaveSettings(Program.AppSettings); + } + + private async void OnReconfigureSteamCMDClick(object sender, EventArgs e) + { + using DialogForm confirm = new(this); + if (confirm.Show(SystemIcons.Warning, + "This will delete and re-download the SteamCMD installation.\n\nCached app data will be preserved.", + acceptButtonText: "Reconfigure", cancelButtonText: "Cancel", customFormText: "Reconfigure SteamCMD") != DialogResult.OK) + return; + + reconfigureSteamCMDButton.Enabled = false; + reconfigureSteamCMDButton.Text = "Reconfiguring..."; + + string steamCmdPath = ProgramData.DirectoryPath + @"\SteamCMD"; + await Task.Run(() => + { + try { Directory.Delete(steamCmdPath, true); } catch { /* directory may not exist */ } + }); + + Progress progress = new(); + await SteamCMD.Setup(progress); + + Color originalColor = reconfigureSteamCMDButton.ForeColor; + reconfigureSteamCMDButton.Text = "Complete"; + reconfigureSteamCMDButton.ForeColor = Color.Green; + await Task.Delay(2000); + reconfigureSteamCMDButton.Text = "Reconfigure SteamCMD"; + reconfigureSteamCMDButton.ForeColor = originalColor; + reconfigureSteamCMDButton.Enabled = true; + } } diff --git a/CreamInstaller/Utility/ProgramData.cs b/CreamInstaller/Utility/ProgramData.cs index 6de833f..fa7a07d 100644 --- a/CreamInstaller/Utility/ProgramData.cs +++ b/CreamInstaller/Utility/ProgramData.cs @@ -250,6 +250,10 @@ internal static event Action OnLog; MigrateOldPath(DirectoryPath + @"\cream-steam.log", SteamLogPath); MigrateOldPath(DirectoryPath + @"\CreamInstaller.log", AppLogPath); MigrateOldPath(DirectoryPath + @"\unlocker.log", UnlockerLogPath); + + // cleanup legacy paths no longer used + string oldCooldown = DirectoryPath + @"\cooldown"; + try { if (Directory.Exists(oldCooldown)) Directory.Delete(oldCooldown, true); } catch { } }); private static void MigrateOldPath(string oldPath, string newPath) @@ -257,7 +261,10 @@ internal static event Action OnLog; if (!oldPath.FileExists()) return; if (newPath.FileExists()) + { + oldPath.DeleteFile(); return; + } try { string content = oldPath.ReadFile(); From c6756067f3dc3a7af32920ed3d6a3e096bf5f071 Mon Sep 17 00:00:00 2001 From: Frog Date: Tue, 21 Jul 2026 00:33:09 -0700 Subject: [PATCH 13/13] Bug Fix for Duplicate DLC Entries - bug fix to avoid duplicates in a games DLC entries from a cached install --- CreamInstaller/Forms/InstallForm.cs | 5 ++++- CreamInstaller/Forms/MainForm.cs | 11 ++++++++--- CreamInstaller/SelectionDLC.cs | 15 ++++++++++++++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/CreamInstaller/Forms/InstallForm.cs b/CreamInstaller/Forms/InstallForm.cs index 1fb20fe..2712a32 100644 --- a/CreamInstaller/Forms/InstallForm.cs +++ b/CreamInstaller/Forms/InstallForm.cs @@ -381,7 +381,10 @@ internal sealed partial class InstallForm : CustomForm UseProxy = selection.UseProxy, ProxyDllName = selection.UseProxy ? selection.Proxy ?? Selection.DefaultProxy : null, UseExtraProtection = selection.UseExtraProtection, - Dlc = selection.DLC.Select(dlc => new InstalledDlcRecord + Dlc = selection.DLC + .GroupBy(dlc => dlc.Id) + .Select(g => g.First()) + .Select(dlc => new InstalledDlcRecord { DlcType = dlc.Type.ToString(), Id = dlc.Id, diff --git a/CreamInstaller/Forms/MainForm.cs b/CreamInstaller/Forms/MainForm.cs index 2ae30eb..85537af 100644 --- a/CreamInstaller/Forms/MainForm.cs +++ b/CreamInstaller/Forms/MainForm.cs @@ -1158,10 +1158,12 @@ internal sealed partial class MainForm : CustomForm if (selection.TreeNode.TreeView is null) _ = selectionTreeView.Nodes.Add(selection.TreeNode); - // Restore DLC children from saved record + // Restore DLC children from saved record, deduplicating by ID if (record.Dlc != null && record.Dlc.Count > 0) { - foreach (InstalledDlcRecord dlcRecord in record.Dlc) + foreach (InstalledDlcRecord dlcRecord in record.Dlc + .GroupBy(d => d.Id) + .Select(g => g.First())) { if (!Enum.TryParse(dlcRecord.DlcType, out DLCType dlcType)) continue; @@ -1476,7 +1478,10 @@ internal sealed partial class MainForm : CustomForm UseProxy = existing?.UseProxy ?? false, ProxyDllName = existing?.UseProxy == true ? existing.ProxyDllName : null, UseExtraProtection = existing?.UseExtraProtection ?? false, - Dlc = selection.DLC.Select(dlc => new InstalledDlcRecord + Dlc = selection.DLC + .GroupBy(dlc => dlc.Id) + .Select(g => g.First()) + .Select(dlc => new InstalledDlcRecord { DlcType = dlc.Type.ToString(), Id = dlc.Id, diff --git a/CreamInstaller/SelectionDLC.cs b/CreamInstaller/SelectionDLC.cs index e5382e0..3258625 100644 --- a/CreamInstaller/SelectionDLC.cs +++ b/CreamInstaller/SelectionDLC.cs @@ -71,7 +71,20 @@ internal sealed class SelectionDLC : IEquatable Type == other.Type && GameId == other.GameId && Id == other.Id); internal static SelectionDLC GetOrCreate(DLCType type, string gameId, string id, string name) - => FromId(type, gameId, id) ?? new SelectionDLC(type, gameId, id, name); + { + // For Steam DLCs, Steam and SteamHidden represent the same DLC discovered + // through different code paths. Look up by (gameId, id) ignoring the Steam + // subtype to prevent duplicate entries for the same DLC. + if (type is DLCType.Steam or DLCType.SteamHidden) + { + SelectionDLC existing = All.Keys.FirstOrDefault( + dlc => dlc.GameId == gameId && dlc.Id == id + && dlc.Type is DLCType.Steam or DLCType.SteamHidden); + if (existing is not null) + return existing; + } + return FromId(type, gameId, id) ?? new SelectionDLC(type, gameId, id, name); + } internal static SelectionDLC FromId(DLCType type, string gameId, string dlcId) => All.Keys.FirstOrDefault(dlc => dlc.Type == type && dlc.GameId == gameId && dlc.Id == dlcId);