private ContextMenu CreateModListContextMenu(ModEntry m, OLVListItem currentItem) { var menu = new ContextMenu(); if (m?.ID == null) { return(menu); } var selectedMods = ModList.SelectedObjects.ToList(); MenuItem renameItem = null; MenuItem showInExplorerItem = null; MenuItem showOnSteamItem = null; MenuItem showInBrowser = null; MenuItem fetchWorkshopTagsItem = null; MenuItem enableAllItem = null; MenuItem disableAllItem = null; MenuItem disableDuplicates = null; MenuItem restoreDuplicates = null; // create items that appear only when a single mod is selected if (selectedMods.Count == 1) { renameItem = new MenuItem("Rename"); renameItem.Click += (a, b) => { modlist_ListObjectListView.EditSubItem(currentItem, olvcName.Index); }; showInExplorerItem = new MenuItem("Show in Explorer", delegate { m.ShowInExplorer(); }); menu.MenuItems.Add(showInExplorerItem); if (m.WorkshopID > 0) { showOnSteamItem = new MenuItem("Show on Steam", delegate { m.ShowOnSteam(); }); menu.MenuItems.Add(showOnSteamItem); showInBrowser = new MenuItem("Show in Browser", delegate { m.ShowInBrowser(); }); menu.MenuItems.Add(showInBrowser); } var duplicateMods = Mods.All.Where(mod => mod.ID == m.ID && mod != m).ToList(); if (duplicateMods.Any()) { if (!m.State.HasFlag(ModState.DuplicatePrimary)) { disableDuplicates = new MenuItem("Prefer this duplicate"); disableDuplicates.Click += delegate { // disable all other duplicates foreach (var duplicate in duplicateMods) { duplicate.DisableModFile(); duplicate.RemoveState(ModState.DuplicateID); duplicate.RemoveState(ModState.DuplicatePrimary); duplicate.AddState(ModState.DuplicateDisabled); duplicate.isActive = false; modlist_ListObjectListView.RefreshObject(duplicate); } // mark selected mod as primary duplicate m.EnableModFile(); m.RemoveState(ModState.DuplicateID); m.RemoveState(ModState.DuplicateDisabled); m.AddState(ModState.DuplicatePrimary); m.isActive = true; modlist_ListObjectListView.RefreshObject(m); ProcessModListItemCheckChanged(m); }; } if (m.State.HasFlag(ModState.DuplicatePrimary) || m.State.HasFlag(ModState.DuplicateDisabled)) { restoreDuplicates = new MenuItem("Restore duplicates"); restoreDuplicates.Click += delegate { // restore normal duplicate state foreach (var duplicate in duplicateMods) { duplicate.EnableModFile(); duplicate.RemoveState(ModState.DuplicateDisabled); duplicate.RemoveState(ModState.DuplicatePrimary); duplicate.AddState(ModState.DuplicateID); duplicate.isActive = false; modlist_ListObjectListView.RefreshObject(duplicate); } // mark selected mod as primary duplicate m.EnableModFile(); m.RemoveState(ModState.DuplicateDisabled); m.RemoveState(ModState.DuplicatePrimary); m.AddState(ModState.DuplicateID); m.isActive = false; modlist_ListObjectListView.RefreshObject(m); ProcessModListItemCheckChanged(m); }; } } } MenuItem addTagItem = new MenuItem("Add tag(s)..."); addTagItem.Click += (sender, args) => { var newTag = Interaction.InputBox($"Please specify one or more tags (separated by a semicolon) that should be added to {selectedMods.Count} selected mod(s).", "Add tag(s)"); if (newTag == "") { return; } var tags = newTag.Split(';'); foreach (ModEntry mod in modlist_ListObjectListView.SelectedObjects) { foreach (string tag in tags) { AddTag(mod, tag.Trim()); } } }; // Move to ... var moveToCategoryItem = new MenuItem("Move to category..."); // ... new category moveToCategoryItem.MenuItems.Add("New category", delegate { var category = Interaction.InputBox("Please enter the name of the new category", "Create category", "New category"); if (string.IsNullOrEmpty(category)) { return; } MoveSelectedModsToCategory(category); }); moveToCategoryItem.MenuItems.Add("-"); // ... existing category foreach (var category in Settings.Mods.CategoryNames.OrderBy(c => c)) { if (category == Mods.GetCategory(m)) { continue; } moveToCategoryItem.MenuItems.Add(category, delegate { MoveSelectedModsToCategory(category); }); } // Hide/unhide var toggleVisibility = new MenuItem { Text = m.isHidden ? "Unhide" : "Hide" }; toggleVisibility.Click += delegate { // save as new list so we can remove mods if they are being hidden foreach (var mod in selectedMods) { mod.isHidden = !m.isHidden; if (!Settings.ShowHiddenElements && mod.isHidden) { modlist_ListObjectListView.RemoveObject(mod); } else { modlist_ListObjectListView.RefreshObject(mod); } } }; // Update mods var updateItem = new MenuItem("Update", delegate { if (IsModUpdateTaskRunning) { ShowModUpdateRunningMessageBox(); return; } UpdateMods(selectedMods); }); if (selectedMods.Any(mod => mod.WorkshopID > 0)) { List <ModEntry> modsToUpdate = new List <ModEntry>(selectedMods.Where(mod => mod.WorkshopID > 0)); fetchWorkshopTagsItem = new MenuItem("Use workshop tags"); fetchWorkshopTagsItem.Click += delegate { if (modsToUpdate.Count > 1) { var result = MessageBox.Show($"Tags from the workshop will replace the existing tags for {modsToUpdate.Count} mods." + Environment.NewLine + "Do you want to continue?", "Use workshop tags", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result != DialogResult.Yes) { return; } } Log.Info($"Using workshop tags for {modsToUpdate.Count} mods."); foreach (var selItem in modsToUpdate) { var tags = selItem.SteamTags; if (tags.Any()) { selItem.Tags.Clear(); foreach (string tag in tags) { AddTag(selItem, tag); } } } }; } if (selectedMods.Any(mod => !mod.isActive)) { enableAllItem = new MenuItem("Enable"); enableAllItem.Click += delegate { Cursor.Current = Cursors.WaitCursor; foreach (var mod in selectedMods) { modlist_ListObjectListView.CheckObject(mod); } Cursor.Current = Cursors.Default; }; } if (selectedMods.Any(mod => mod.isActive)) { disableAllItem = new MenuItem("Disable"); disableAllItem.Click += delegate { Cursor.Current = Cursors.WaitCursor; foreach (var mod in selectedMods) { modlist_ListObjectListView.UncheckObject(mod); } Cursor.Current = Cursors.Default; }; } var deleteItem = new MenuItem("Delete / Unsubscribe", delegate { DeleteMods(); }); // create menu structure if (enableAllItem != null) { menu.MenuItems.Add(enableAllItem); } if (disableAllItem != null) { menu.MenuItems.Add(disableAllItem); } if (renameItem != null) { menu.MenuItems.Add(renameItem); } menu.MenuItems.Add(updateItem); menu.MenuItems.Add("-"); menu.MenuItems.Add(addTagItem); if (fetchWorkshopTagsItem != null) { menu.MenuItems.Add(fetchWorkshopTagsItem); } menu.MenuItems.Add(moveToCategoryItem); menu.MenuItems.Add("-"); if (showInExplorerItem != null) { menu.MenuItems.Add(showInExplorerItem); } if (showOnSteamItem != null) { menu.MenuItems.Add(showOnSteamItem); } if (showInBrowser != null) { menu.MenuItems.Add(showInBrowser); } // prevent double separator if (menu.MenuItems[menu.MenuItems.Count - 1].Text != @"-") { menu.MenuItems.Add("-"); } menu.MenuItems.Add(toggleVisibility); menu.MenuItems.Add(deleteItem); if (Settings.EnableDuplicateModIdWorkaround) { if (disableDuplicates != null) { menu.MenuItems.Add("-"); menu.MenuItems.Add(disableDuplicates); } if (restoreDuplicates != null) { // prevent double separator if (menu.MenuItems[menu.MenuItems.Count - 1] != disableDuplicates) { menu.MenuItems.Add("-"); } menu.MenuItems.Add(restoreDuplicates); } } return(menu); }