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/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/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/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/InstallForm.cs b/CreamInstaller/Forms/InstallForm.cs index e817cce..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, @@ -395,7 +398,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/MainForm.Designer.cs b/CreamInstaller/Forms/MainForm.Designer.cs new file mode 100644 index 0000000..5c287ee --- /dev/null +++ b/CreamInstaller/Forms/MainForm.Designer.cs @@ -0,0 +1,352 @@ +using CreamInstaller.Components; +using CreamInstaller.Resources; +using System.ComponentModel; +using System.Windows.Forms; + +namespace CreamInstaller.Forms +{ + partial class MainForm + { + private IContainer components = null; + protected override void Dispose(bool disposing) + { + if (disposing && components is not null) + components.Dispose(); + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + private void InitializeComponent() + { + installButton = new Button(); + programsGroupBox = new GroupBox(); + noneFoundLabel = new Label(); + useSmokeAPILayoutPanel = new FlowLayoutPanel(); + useSmokeApiToggle = new ToggleSwitch(); + useSmokeApiLabel = new Label(); + useSmokeAPIHelpButton = new Button(); + allCheckBoxLayoutPanel = new FlowLayoutPanel(); + allCheckBox = new CheckBox(); + progressBar = new ProgressBar(); + progressLabel = new Label(); + scanButton = new Button(); + uninstallButton = new Button(); + progressLabelGames = new Label(); + progressLabelDLCs = new Label(); + saveFlowPanel = new FlowLayoutPanel(); + 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(); + saveFlowPanel.SuspendLayout(); + SuspendLayout(); + // + // installButton + // + installButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + installButton.AutoSize = true; + installButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; + installButton.Enabled = false; + 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); + installButton.TabIndex = 10000; + 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 + // + programsGroupBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + programsGroupBox.Controls.Add(selectionTreeView); + programsGroupBox.Location = new System.Drawing.Point(12, 43); + programsGroupBox.Name = "programsGroupBox"; + programsGroupBox.Size = new System.Drawing.Size(656, 252); + programsGroupBox.TabIndex = 1000; + programsGroupBox.TabStop = false; + programsGroupBox.Text = "Programs && Games"; + programsGroupBox.Enter += programsGroupBox_Enter; + // + // noneFoundLabel + // + 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(656, 18); + noneFoundLabel.TabIndex = 1003; + noneFoundLabel.Text = "No applicable programs and/or games found."; + noneFoundLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + noneFoundLabel.Visible = false; + // + // useSmokeAPILayoutPanel + // + useSmokeAPILayoutPanel.AutoSize = true; + useSmokeAPILayoutPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + useSmokeAPILayoutPanel.Controls.Add(useSmokeApiToggle); + useSmokeAPILayoutPanel.Controls.Add(useSmokeApiLabel); + useSmokeAPILayoutPanel.Controls.Add(useSmokeAPIHelpButton); + useSmokeAPILayoutPanel.Margin = new Padding(0); + useSmokeAPILayoutPanel.Name = "useSmokeAPILayoutPanel"; + useSmokeAPILayoutPanel.Size = new System.Drawing.Size(250, 22); + useSmokeAPILayoutPanel.TabIndex = 1006; + useSmokeAPILayoutPanel.WrapContents = false; + // + // useSmokeApiToggle + // + 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(175, 15); + useSmokeApiLabel.TabIndex = 3; + 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(225, 0); + useSmokeAPIHelpButton.Margin = new Padding(2, 0, 1, 0); + useSmokeAPIHelpButton.Name = "useSmokeAPIHelpButton"; + useSmokeAPIHelpButton.Size = new System.Drawing.Size(19, 19); + useSmokeAPIHelpButton.TabIndex = 2; + 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 + // + allCheckBoxLayoutPanel.AutoSize = true; + allCheckBoxLayoutPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; + allCheckBoxLayoutPanel.Controls.Add(allCheckBox); + allCheckBoxLayoutPanel.Margin = new Padding(12, 3, 0, 0); + allCheckBoxLayoutPanel.Name = "allCheckBoxLayoutPanel"; + allCheckBoxLayoutPanel.Size = new System.Drawing.Size(42, 19); + allCheckBoxLayoutPanel.TabIndex = 1007; + allCheckBoxLayoutPanel.WrapContents = false; + // + // allCheckBox + // + 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(75, 22); + allCheckBox.TabIndex = 4; + allCheckBox.Text = "Select All"; + allCheckBox.CheckedChanged += OnAllCheckBoxChanged; + // + // selectionTreeView + // + selectionTreeView.BackColor = System.Drawing.SystemColors.Control; + selectionTreeView.BorderStyle = BorderStyle.None; + selectionTreeView.CheckBoxes = true; + selectionTreeView.Dock = DockStyle.Fill; + selectionTreeView.DrawMode = TreeViewDrawMode.OwnerDrawAll; + selectionTreeView.Enabled = false; + selectionTreeView.FullRowSelect = true; + selectionTreeView.Location = new System.Drawing.Point(3, 19); + selectionTreeView.Name = "selectionTreeView"; + selectionTreeView.Size = new System.Drawing.Size(604, 230); + selectionTreeView.TabIndex = 1001; + // + // progressBar + // + 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(656, 23); + progressBar.TabIndex = 9; + // + // progressLabel + // + 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(656, 23); + progressLabel.TabIndex = 10; + progressLabel.Text = "Gathering and caching programs . . ."; + progressLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + progressLabel.Visible = false; + // + // scanButton + // + scanButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + scanButton.AutoSize = true; + scanButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; + 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(85, 25); + scanButton.TabIndex = 10004; + scanButton.Text = "Rescan"; + scanButton.UseVisualStyleBackColor = true; + scanButton.Click += OnScan; + mainToolTip.SetToolTip(scanButton, "Re-scan for installed games and refresh the DLC list from cache."); + // + // uninstallButton + // + uninstallButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; + uninstallButton.AutoSize = true; + uninstallButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; + uninstallButton.Enabled = false; + 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); + uninstallButton.TabIndex = 10005; + uninstallButton.Text = "Uninstall Selected"; + uninstallButton.UseVisualStyleBackColor = true; + uninstallButton.Click += OnUninstall; + mainToolTip.SetToolTip(uninstallButton, "Remove DLC unlockers from the selected games only."); + // + // progressLabelGames + // + progressLabelGames.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; + progressLabelGames.Location = new System.Drawing.Point(12, 328); + progressLabelGames.Name = "progressLabelGames"; + progressLabelGames.Size = new System.Drawing.Size(375, 18); + progressLabelGames.TabIndex = 10007; + progressLabelGames.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // progressLabelDLCs + // + progressLabelDLCs.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; + progressLabelDLCs.Location = new System.Drawing.Point(393, 328); + progressLabelDLCs.Name = "progressLabelDLCs"; + 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(380, 382); + saveFlowPanel.Name = "saveFlowPanel"; + saveFlowPanel.Size = new System.Drawing.Size(141, 25); + 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; + mainToolTip.SetToolTip(settingsButton, "Open application settings."); + // + // topOptionsTable + // + topOptionsTable.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + topOptionsTable.AutoSize = true; + topOptionsTable.AutoSizeMode = AutoSizeMode.GrowAndShrink; + topOptionsTable.ColumnCount = 4; + topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); + 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); + topOptionsTable.Margin = new Padding(0); + topOptionsTable.Name = "topOptionsTable"; + topOptionsTable.RowCount = 1; + topOptionsTable.RowStyles.Add(new RowStyle(SizeType.AutoSize)); + topOptionsTable.Size = new System.Drawing.Size(656, 25); + topOptionsTable.TabIndex = 10009; + topOptionsTable.Controls.Clear(); + topOptionsTable.Controls.Add(useSmokeAPILayoutPanel, 0, 0); + topOptionsTable.Controls.Add(allCheckBoxLayoutPanel, 2, 0); + topOptionsTable.Controls.Add(settingsButton, 3, 0); + // + // MainForm + // + AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + AutoScaleMode = AutoScaleMode.Dpi; + AutoSizeMode = AutoSizeMode.GrowAndShrink; + ClientSize = new System.Drawing.Size(680, 417); + Controls.Add(topOptionsTable); + Controls.Add(saveFlowPanel); + Controls.Add(progressLabelDLCs); + Controls.Add(progressLabelGames); + Controls.Add(progressLabel); + Controls.Add(progressBar); + Controls.Add(noneFoundLabel); + Controls.Add(programsGroupBox); + Controls.Add(uninstallButton); + Controls.Add(scanButton); + Controls.Add(installButton); + FormBorderStyle = FormBorderStyle.FixedDialog; + HelpButton = true; + Icon = Properties.Resources.Icon; + Margin = new Padding(4, 3, 4, 3); + MaximizeBox = false; + MinimizeBox = false; + Name = "MainForm"; + StartPosition = FormStartPosition.Manual; + Text = "MainForm"; + Load += OnLoad; + programsGroupBox.ResumeLayout(false); + useSmokeAPILayoutPanel.ResumeLayout(false); + useSmokeAPILayoutPanel.PerformLayout(); + allCheckBoxLayoutPanel.ResumeLayout(false); + allCheckBoxLayoutPanel.PerformLayout(); + saveFlowPanel.ResumeLayout(false); + saveFlowPanel.PerformLayout(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Button installButton; + private GroupBox programsGroupBox; + private ProgressBar progressBar; + private Label progressLabel; + internal CheckBox allCheckBox; + private Button scanButton; + private Label noneFoundLabel; + private CustomTreeView selectionTreeView; + private ToggleSwitch useSmokeApiToggle; + private Label useSmokeApiLabel; + private Button useSmokeAPIHelpButton; + private FlowLayoutPanel useSmokeAPILayoutPanel; + private FlowLayoutPanel allCheckBoxLayoutPanel; + private Button uninstallButton; + private Label progressLabelGames; + private Label progressLabelDLCs; + private FlowLayoutPanel saveFlowPanel; + private Button settingsButton; + private TableLayoutPanel topOptionsTable; + private ToolTip mainToolTip; + } +} diff --git a/CreamInstaller/Forms/SelectForm.cs b/CreamInstaller/Forms/MainForm.cs similarity index 91% rename from CreamInstaller/Forms/SelectForm.cs rename to CreamInstaller/Forms/MainForm.cs index cf24623..85537af 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,19 @@ internal sealed partial class SelectForm : CustomForm private List<(Platform platform, string id, string name)> programsToScan; - private SelectForm() + private MainForm() { InitializeComponent(); - selectionTreeView.TreeViewNodeSorter = sortCheckBox.Checked ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName; + selectionTreeView.TreeViewNodeSorter = Program.SortByName ? PlatformIdComparer.NodeText : PlatformIdComparer.NodeName; Text = Program.ApplicationName; } - internal static SelectForm Current + internal void UpdateSortOrder(bool sortByName) + => selectionTreeView.TreeViewNodeSorter = sortByName + ? PlatformIdComparer.NodeText + : PlatformIdComparer.NodeName; + + internal static MainForm Current { get { @@ -51,7 +56,7 @@ internal sealed partial class SelectForm : CustomForm { if (current is null || current.Disposing || current.IsDisposed) { - current = new SelectForm(); + current = new MainForm(); } return current; } @@ -681,15 +686,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; @@ -737,7 +738,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; @@ -803,30 +804,23 @@ 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) { - ProgramData.Log.Error("SelectForm OnLoad failed", ex); + ProgramData.Log.Error("MainForm OnLoad failed", ex); // 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; } } @@ -1164,10 +1158,12 @@ internal sealed partial class SelectForm : 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; @@ -1257,7 +1253,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 @@ -1349,53 +1345,8 @@ internal sealed partial class SelectForm : 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; - cancelButton.Enabled = true; - 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 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 +1361,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 = @@ -1538,7 +1478,10 @@ internal sealed partial class SelectForm : 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, @@ -1557,9 +1500,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 +1507,11 @@ 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 ? "Selected Unlocker: SmokeAPI" : "Selected Unlocker: CreamAPI"; + ProgramData.SaveSettings(Program.AppSettings); selectionTreeView.Invalidate(); } @@ -1614,26 +1525,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 ? "Selected Unlocker: SmokeAPI" : "Selected Unlocker: CreamAPI"; + } } } \ No newline at end of file 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/SelectForm.Designer.cs b/CreamInstaller/Forms/SelectForm.Designer.cs deleted file mode 100644 index 810e051..0000000 --- a/CreamInstaller/Forms/SelectForm.Designer.cs +++ /dev/null @@ -1,482 +0,0 @@ -using CreamInstaller.Components; -using CreamInstaller.Resources; -using System.ComponentModel; -using System.Windows.Forms; - -namespace CreamInstaller.Forms -{ - partial class SelectForm - { - private IContainer components = null; - protected override void Dispose(bool disposing) - { - if (disposing && components is not null) - components.Dispose(); - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - 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(); - useSmokeAPIHelpButton = new Button(); - darkModeFlowPanel = new FlowLayoutPanel(); - darkModeCheckBox = new CheckBox(); - allCheckBoxLayoutPanel = new FlowLayoutPanel(); - allCheckBox = new CheckBox(); - progressBar = new ProgressBar(); - progressLabel = new Label(); - scanButton = new Button(); - uninstallAllButton = new Button(); - uninstallButton = new Button(); - progressLabelGames = new Label(); - progressLabelDLCs = new Label(); - sortCheckBox = new CheckBox(); - saveFlowPanel = new FlowLayoutPanel(); - selectionTreeView = new CustomTreeView(); - topOptionsTable = new TableLayoutPanel(); - programsGroupBox.SuspendLayout(); - proxyFlowPanel.SuspendLayout(); - blockedGamesFlowPanel.SuspendLayout(); - useSmokeAPILayoutPanel.SuspendLayout(); - darkModeFlowPanel.SuspendLayout(); - allCheckBoxLayoutPanel.SuspendLayout(); - saveFlowPanel.SuspendLayout(); - SuspendLayout(); - // - // installButton - // - installButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - installButton.AutoSize = true; - installButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; - installButton.Enabled = false; - installButton.Location = new System.Drawing.Point(495, 376); - installButton.Name = "installButton"; - installButton.Padding = new Padding(3, 0, 3, 0); - installButton.Size = new System.Drawing.Size(127, 25); - installButton.TabIndex = 10000; - installButton.Text = "Generate and Install"; - 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.Name = "programsGroupBox"; - programsGroupBox.Size = new System.Drawing.Size(610, 252); - programsGroupBox.TabIndex = 8; - 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; - // - // noneFoundLabel - // - noneFoundLabel.Dock = DockStyle.Fill; - noneFoundLabel.Location = new System.Drawing.Point(3, 19); - 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.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(useSmokeAPIHelpButton); - useSmokeAPILayoutPanel.Margin = new Padding(12, 0, 0, 0); - useSmokeAPILayoutPanel.Name = "useSmokeAPILayoutPanel"; - useSmokeAPILayoutPanel.Size = new System.Drawing.Size(124, 19); - useSmokeAPILayoutPanel.TabIndex = 1006; - useSmokeAPILayoutPanel.WrapContents = false; - // - // useSmokeAPICheckBox - // - 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; - // - // 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.Name = "useSmokeAPIHelpButton"; - useSmokeAPIHelpButton.Size = new System.Drawing.Size(19, 19); - useSmokeAPIHelpButton.TabIndex = 2; - useSmokeAPIHelpButton.Text = "?"; - 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; - allCheckBoxLayoutPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink; - allCheckBoxLayoutPanel.Controls.Add(allCheckBox); - allCheckBoxLayoutPanel.Margin = new Padding(12, 0, 0, 0); - allCheckBoxLayoutPanel.Name = "allCheckBoxLayoutPanel"; - allCheckBoxLayoutPanel.Size = new System.Drawing.Size(42, 19); - allCheckBoxLayoutPanel.TabIndex = 1007; - allCheckBoxLayoutPanel.WrapContents = false; - // - // allCheckBox - // - allCheckBox.AutoSize = true; - allCheckBox.Checked = true; - allCheckBox.CheckState = CheckState.Checked; - allCheckBox.Enabled = false; - 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.TabIndex = 4; - allCheckBox.Text = "All"; - allCheckBox.CheckedChanged += OnAllCheckBoxChanged; - // - // selectionTreeView - // - selectionTreeView.BackColor = System.Drawing.SystemColors.Control; - selectionTreeView.BorderStyle = BorderStyle.None; - selectionTreeView.CheckBoxes = true; - selectionTreeView.Dock = DockStyle.Fill; - selectionTreeView.DrawMode = TreeViewDrawMode.OwnerDrawAll; - selectionTreeView.Enabled = false; - selectionTreeView.FullRowSelect = true; - selectionTreeView.Location = new System.Drawing.Point(3, 19); - selectionTreeView.Name = "selectionTreeView"; - selectionTreeView.Size = new System.Drawing.Size(604, 230); - selectionTreeView.TabIndex = 1001; - // - // progressBar - // - 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.TabIndex = 9; - // - // progressLabel - // - 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.TabIndex = 10; - progressLabel.Text = "Gathering and caching your applicable games and their DLCs . . . 0%"; - // - // scanButton - // - scanButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; - scanButton.AutoSize = true; - scanButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; - scanButton.Enabled = false; - scanButton.Location = new System.Drawing.Point(186, 376); - scanButton.Name = "scanButton"; - scanButton.Padding = new Padding(3, 0, 3, 0); - scanButton.Size = new System.Drawing.Size(60, 25); - scanButton.TabIndex = 10002; - scanButton.Text = "Rescan"; - scanButton.UseVisualStyleBackColor = true; - scanButton.Click += OnScan; - // - // uninstallAllButton - // - uninstallAllButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - uninstallAllButton.AutoSize = true; - uninstallAllButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; - uninstallAllButton.Location = new System.Drawing.Point(327, 376); - uninstallAllButton.Name = "uninstallAllButton"; - uninstallAllButton.Padding = new Padding(3, 0, 3, 0); - uninstallAllButton.Size = new System.Drawing.Size(87, 25); - uninstallAllButton.TabIndex = 10003; - uninstallAllButton.Text = "Uninstall All"; - uninstallAllButton.UseVisualStyleBackColor = true; - uninstallAllButton.Click += OnUninstallAll; - // - // uninstallButton - // - uninstallButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - uninstallButton.AutoSize = true; - uninstallButton.AutoSizeMode = AutoSizeMode.GrowAndShrink; - uninstallButton.Enabled = false; - uninstallButton.Location = new System.Drawing.Point(420, 376); - 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.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.Name = "progressLabelGames"; - progressLabelGames.Size = new System.Drawing.Size(610, 12); - progressLabelGames.TabIndex = 11; - progressLabelGames.Text = "Remaining games (2): Game 1, Game 2"; - // - // 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.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; - // - // 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.Name = "saveFlowPanel"; - saveFlowPanel.Size = new System.Drawing.Size(141, 25); - saveFlowPanel.TabIndex = 10008; - saveFlowPanel.WrapContents = false; - // - // topOptionsTable - // - topOptionsTable.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; - topOptionsTable.AutoSize = true; - topOptionsTable.AutoSizeMode = AutoSizeMode.GrowAndShrink; - topOptionsTable.ColumnCount = 6; - 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.AutoSize)); - topOptionsTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize)); - topOptionsTable.Location = new System.Drawing.Point(12, 12); - topOptionsTable.Margin = new Padding(0); - topOptionsTable.Name = "topOptionsTable"; - topOptionsTable.RowCount = 1; - topOptionsTable.RowStyles.Add(new RowStyle(SizeType.AutoSize)); - topOptionsTable.Size = new System.Drawing.Size(610, 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); - // - // SelectForm - // - AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - AutoScaleMode = AutoScaleMode.Dpi; - AutoSizeMode = AutoSizeMode.GrowAndShrink; - ClientSize = new System.Drawing.Size(634, 411); - Controls.Add(topOptionsTable); - Controls.Add(saveFlowPanel); - Controls.Add(sortCheckBox); - Controls.Add(progressLabelDLCs); - Controls.Add(progressLabelGames); - 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; - MaximizeBox = false; - MinimizeBox = false; - Name = "SelectForm"; - StartPosition = FormStartPosition.Manual; - 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); - saveFlowPanel.PerformLayout(); - ResumeLayout(false); - PerformLayout(); - } - - #endregion - - private Button installButton; - private Button cancelButton; - private GroupBox programsGroupBox; - private ProgressBar progressBar; - private Label progressLabel; - internal CheckBox allCheckBox; - private Button scanButton; - private Label noneFoundLabel; - private CustomTreeView selectionTreeView; - private CheckBox blockedGamesCheckBox; - private Button blockProtectedHelpButton; - private CheckBox useSmokeAPICheckBox; - 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 TableLayoutPanel topOptionsTable; - private CheckBox darkModeCheckBox; - } -} - diff --git a/CreamInstaller/Forms/SettingsForm.Designer.cs b/CreamInstaller/Forms/SettingsForm.Designer.cs new file mode 100644 index 0000000..6ac8d82 --- /dev/null +++ b/CreamInstaller/Forms/SettingsForm.Designer.cs @@ -0,0 +1,199 @@ +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; + +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() + { + SettingsToolTip = new ToolTip(); + appearanceGroup = new GroupBox(); + darkModeCheckBox = new CheckBox(); + 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 + // + 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.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.UseVisualStyleBackColor = true; + 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.FlatStyle = FlatStyle.System; + blockedGamesCheckBox.Location = new Point(12, 22); + blockedGamesCheckBox.Name = "blockedGamesCheckBox"; + blockedGamesCheckBox.Size = new Size(190, 22); + blockedGamesCheckBox.TabIndex = 0; + 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 + // + sortByNameCheckBox.AutoSize = false; + sortByNameCheckBox.FlatStyle = FlatStyle.System; + sortByNameCheckBox.Location = new Point(12, 48); + sortByNameCheckBox.Name = "sortByNameCheckBox"; + sortByNameCheckBox.Size = new Size(200, 22); + sortByNameCheckBox.TabIndex = 1; + 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."); + // + // 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, 228); + 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(313, 228); + 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(400, 265); + Controls.Add(cancelButton); + Controls.Add(saveButton); + Controls.Add(maintenanceGroup); + Controls.Add(gameManagementGroup); + Controls.Add(appearanceGroup); + FormBorderStyle = FormBorderStyle.FixedDialog; + MaximizeBox = false; + MinimizeBox = false; + Name = "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 new file mode 100644 index 0000000..c5dd2e9 --- /dev/null +++ b/CreamInstaller/Forms/SettingsForm.cs @@ -0,0 +1,123 @@ +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; + +internal sealed partial class SettingsForm : CustomForm +{ + private bool wasDarkModeEnabled; + private bool wasSortByName; + + 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; + wasSortByName = Program.SortByName; + } + + 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(); + if (DebugForm.IsOpen) + ThemeManager.Apply(DebugForm.Current); + } + + if (wasSortByName != sortByNameCheckBox.Checked) + MainForm.Current?.UpdateSortOrder(sortByNameCheckBox.Checked); + + DialogResult = DialogResult.OK; + Close(); + } + + private void OnCancelClick(object sender, EventArgs e) + { + 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/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/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..c3b2f9f 100644 --- a/CreamInstaller/Selection.cs +++ b/CreamInstaller/Selection.cs @@ -71,11 +71,11 @@ 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; - UseProxy = selectForm.proxyAllCheckBox.Checked; + UseProxy = false; } internal static IEnumerable AllEnabled => All.Keys.Where(s => s.Enabled); 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); diff --git a/CreamInstaller/Utility/ProgramData.cs b/CreamInstaller/Utility/ProgramData.cs index 368a591..fa7a07d 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"; @@ -249,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) @@ -256,7 +261,10 @@ internal static event Action OnLog; if (!oldPath.FileExists()) return; if (newPath.FileExists()) + { + oldPath.DeleteFile(); return; + } try { string content = oldPath.ReadFile(); @@ -473,4 +481,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; +}