diff --git a/BeatSaberModManager/Forms/FormMain.cs b/BeatSaberModManager/Forms/FormMain.cs index 237e8e7..c6612fc 100644 --- a/BeatSaberModManager/Forms/FormMain.cs +++ b/BeatSaberModManager/Forms/FormMain.cs @@ -24,6 +24,7 @@ public partial class FormMain : MaterialForm InstallerLogic installer; MaterialSkinManager skinManager; bool finishedLoading = false; + bool programmaticCheck = false; bool darkTheme = false; int activeThemeID = 0; List defaultMods = new List(new string[] { "songloader", "scoresaber", "beatsaverdownloader" }); @@ -215,7 +216,7 @@ private void CheckDefaultMod(ReleaseInfo release, ListViewItem item) { string name = release.name.ToLower(); string category = release.category.ToLower(); - if (name.Equals("bsipa") || category.Contains("libraries")) + if (name.Equals("bsipa")) { item.Text = $"[REQUIRED] {release.title}"; item.BackColor = darkTheme ? Color.FromArgb(255, 30, 30, 30) : Color.LightGray; @@ -301,16 +302,17 @@ private void Installer_StatusUpdate(string status) private void listViewMods_ItemChecked(object sender, ItemCheckedEventArgs e) { + if (!finishedLoading || programmaticCheck) + { + return; + } + ReleaseInfo release = (ReleaseInfo)e.Item.Tag; if (release.disabled) { e.Item.Checked = release.install; return; } - else - { - release.install = e.Item.Checked; - } if (e.Item.Checked) { @@ -328,10 +330,7 @@ private void listViewMods_ItemChecked(object sender, ItemCheckedEventArgs e) } } } - } - if (e.Item.Checked) - { if (release.conflictsWith.Count > 0) { foreach (ModLink dependency in release.conflictsWith) @@ -348,7 +347,32 @@ private void listViewMods_ItemChecked(object sender, ItemCheckedEventArgs e) } } } - else + + if (!e.Item.Checked) + { + List parents = new List { release }; + List dependents = GetDependentReleases(parents); + if (dependents.Count > 0) + { + programmaticCheck = true; + string message = string.Format("The following mods depend on '{0}' or one of its dependents, and will also be unchecked. Continue?\n\n{1}", release.name, BuildReleaseNameList(dependents)); + if (MessageBox.Show(message, "Continue?", MessageBoxButtons.YesNo) == DialogResult.No) + { + e.Item.Checked = true; + } + else + { + foreach (ReleaseInfo dependent in dependents) + { + dependent.itemHandle.Checked = false; + dependent.install = false; + } + } + programmaticCheck = false; + } + } + + if (!e.Item.Checked) { if (release.conflictsWith.Count > 0) { @@ -365,9 +389,56 @@ private void listViewMods_ItemChecked(object sender, ItemCheckedEventArgs e) } } } - if (finishedLoading ){ - ReRenderListView(); + + release.install = e.Item.Checked; + + ReRenderListView(); + } + + private List GetDependentReleases(List parents) + { + List dependents = new List(); + + // For each parent, check if any of the enabled releases depends on it + foreach (ReleaseInfo parent in parents) + { + foreach (ReleaseInfo release in remote.releases) + { + if (release.itemHandle == null || !release.itemHandle.Checked) continue; + + foreach (ModLink dependency in release.dependsOn) + { + // If the dependency matches, then this release depends on our parent + if (dependency.name == parent.name) + { + dependents.Add(release); + } + } + } } + + if (dependents.Count > 0) + { + List subDependents = GetDependentReleases(dependents); + if (subDependents.Count > 0) + { + dependents = dependents.Union(subDependents).ToList(); + } + } + + return dependents; + } + + private string BuildReleaseNameList(List releases) + { + string releaseNameList = string.Empty; + + foreach (ReleaseInfo release in releases) + { + releaseNameList += release.name + Environment.NewLine; + } + + return releaseNameList; } private void ReRenderListView ()