3 using Microsoft.Xna.Framework;
5 using System.Collections.Generic;
7 using System.Threading.Tasks;
14 private CorePackage EnabledCorePackage => enabledCoreDropdown.SelectedData as
CorePackage ??
throw new Exception(
"Valid core package not selected");
19 private readonly
GUIListBox enabledRegularModsList;
20 private readonly
GUIListBox disabledRegularModsList;
21 private readonly Action<ItemOrPackage> onInstalledInfoButtonHit;
23 private readonly Dictionary<Filter, GUITickBox> modsListFilterTickboxes;
24 private readonly Option<GUIButton> bulkUpdateButtonOption;
27 private GUIListBox? draggedElementOrigin =
null;
29 private void UpdateSubscribedModInstalls()
31 if (!EnableWorkshopSupport) {
return; }
33 uint numSubscribedMods = SteamManager.GetNumSubscribedItems();
34 if (numSubscribedMods == memSubscribedModCount) {
return; }
35 memSubscribedModCount = numSubscribedMods;
37 var subscribedIds = SteamManager.Workshop.GetSubscribedItemIds();
38 var installedIds = ContentPackageManager.WorkshopPackages
41 .OfType<SteamWorkshopId>()
42 .Select(
id =>
id.Value)
44 foreach (var
id in subscribedIds.Where(id2 => !installedIds.Contains(id2)))
46 Steamworks.Ugc.Item item =
new Steamworks.Ugc.Item(
id);
47 if (!item.IsDownloading && !SteamManager.Workshop.IsInstalling(item))
49 SteamManager.Workshop.DownloadModThenEnqueueInstall(item);
53 SteamManager.Workshop.DeleteUnsubscribedMods(removedPackages =>
55 if (removedPackages.Any())
62 private static (GUILayoutGroup Left, GUIFrame center, GUILayoutGroup Right) CreateSidebars(
64 float leftWidth = 0.3875f,
65 float centerWidth = 0.025f,
66 float rightWidth = 0.5875f,
70 GUILayoutGroup layout =
new GUILayoutGroup(
new RectTransform((1.0f, height), parent.RectTransform), isHorizontal:
true);
71 GUILayoutGroup left =
new GUILayoutGroup(
new RectTransform((leftWidth, 1.0f), layout.RectTransform), isHorizontal:
false);
72 var center =
new GUIFrame(
new RectTransform((centerWidth, 1.0f), layout.RectTransform), style:
null);
75 new GUICustomComponent(
new RectTransform(Vector2.One, center.RectTransform),
78 sb.DrawLine((c.Rect.Center.X, c.Rect.Top), (c.Rect.Center.X, c.Rect.Bottom), GUIStyle.TextColorDim, 2f);
81 GUILayoutGroup right =
new GUILayoutGroup(
new RectTransform((rightWidth, 1.0f), layout.RectTransform), isHorizontal:
false);
82 return (left, center, right);
85 private static void HandleDraggingAcrossModLists(GUIListBox from, GUIListBox to)
87 if (to.Rect.Contains(PlayerInput.MousePosition) && from.DraggedElement !=
null)
90 var draggedElement = from.DraggedElement;
92 var selected = from.AllSelected.ToList();
93 selected.Sort((a, b) => from.Content.GetChildIndex(a) - from.Content.GetChildIndex(b));
96 float newCount = oldCount + selected.Count;
98 var offset = draggedElement.RectTransform.AbsoluteOffset;
99 offset += from.Content.Rect.Location;
100 offset -= to.Content.Rect.Location;
102 for (
int i = 0; i < selected.Count; i++)
105 c.Parent.RemoveChild(c);
106 c.RectTransform.Parent = to.Content.RectTransform;
107 c.RectTransform.RepositionChildInHierarchy((
int)oldCount+i);
110 from.DraggedElement =
null;
112 from.RecalculateChildren();
113 from.RectTransform.RecalculateScale(
true);
114 to.RecalculateChildren();
115 to.RectTransform.RecalculateScale(
true);
119 draggedElement.RectTransform.AbsoluteOffset = offset;
121 to.DraggedElement = draggedElement;
123 to.BarScroll *= (oldCount / newCount);
127 private Action? currentSwapFunc =
null;
130 private void PlaySwapSound()
132 SoundPlayer.PlayUISound(swapSoundType);
135 private void SetSwapFunc(GUIListBox from, GUIListBox to)
137 currentSwapFunc = () =>
140 var selected = from.AllSelected.ToArray();
141 foreach (var frame
in selected)
143 frame.Parent.RemoveChild(frame);
144 frame.RectTransform.Parent = to.Content.RectTransform;
146 from.RecalculateChildren();
147 from.RectTransform.RecalculateScale(
true);
148 to.RecalculateChildren();
149 to.RectTransform.RecalculateScale(
true);
153 if (to == enabledRegularModsList)
157 else if (to == disabledRegularModsList)
163 swapSoundType =
null;
167 private void CreateInstalledModsTab(
168 out GUIDropDown enabledCoreDropdown,
169 out GUIListBox enabledRegularModsList,
170 out GUIListBox disabledRegularModsList,
171 out Action<ItemOrPackage> onInstalledInfoButtonHit,
172 out GUITextBox modsListFilter,
173 out Dictionary<Filter, GUITickBox> modsListFilterTickboxes,
174 out Option<GUIButton> bulkUpdateButton)
176 GUIFrame content = CreateNewContentFrame(
Tab.InstalledMods);
178 CreateWorkshopItemDetailContainer(
180 out var outerContainer,
181 onSelected: (itemOrPackage, selectedFrame) =>
183 if (itemOrPackage.TryGet(out Steamworks.Ugc.Item item)) { PopulateFrameWithItemInfo(item, selectedFrame); }
186 out onInstalledInfoButtonHit, out var deselect);
188 GUILayoutGroup mainLayout =
189 new GUILayoutGroup(
new RectTransform(Vector2.One, outerContainer.Content.RectTransform), childAnchor:
Anchor.TopCenter)
192 AbsoluteSpacing = GUI.IntScale(5)
194 mainLayout.RectTransform.SetAsFirstChild();
196 var (topLeft, _, topRight) = CreateSidebars(mainLayout, centerWidth: 0.05f, leftWidth: 0.475f, rightWidth: 0.475f, height: 0.13f);
197 topLeft.Stretch =
true;
198 Label(topLeft, TextManager.Get(
"enabledcore"), GUIStyle.SubHeadingFont, heightScale: 1.0f);
199 enabledCoreDropdown = Dropdown<CorePackage>(topLeft,
201 ContentPackageManager.CorePackages.ToArray(),
202 ContentPackageManager.EnabledPackages.Core!,
204 heightScale: 1.0f / 13.0f);
205 enabledCoreDropdown.AllowNonText =
true;
206 Label(topLeft,
"", GUIStyle.SubHeadingFont, heightScale: 1.0f);
207 topRight.ChildAnchor =
Anchor.CenterLeft;
209 var topRightButtons =
new GUILayoutGroup(
new RectTransform((1.0f, 0.5f), topRight.RectTransform),
210 isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
213 RelativeSpacing = 0.05f
216 void padTopRight(
float width=1.0f)
218 new GUIFrame(
new RectTransform((width, 1.0f), topRightButtons.RectTransform), style:
null);
223 padTopRight(width: 3.0f);
224 var refreshListsButton
226 new RectTransform(Vector2.One, topRightButtons.RectTransform, scaleBasis:
ScaleBasis.BothHeight),
227 text:
"", style:
"GUIReloadButton")
229 OnClicked = (b, o) =>
234 ToolTip = TextManager.Get(
"RefreshModLists")
237 bulkUpdateButton = EnableWorkshopSupport
240 new RectTransform(Vector2.One, topRightButtons.RectTransform, scaleBasis:
ScaleBasis.BothHeight),
241 text:
"", style:
"GUIUpdateButton")
246 BulkDownloader.PrepareUpdates();
252 padTopRight(width: 0.1f);
254 var (left, center, right) = CreateSidebars(mainLayout, centerWidth: 0.05f, leftWidth: 0.475f, rightWidth: 0.475f, height: 0.8f);
255 right.ChildAnchor =
Anchor.TopRight;
258 var label =
Label(left, TextManager.Get(
"enabledregular"), GUIStyle.SubHeadingFont);
259 new GUIImage(
new RectTransform(
new Point(label.Rect.Height), label.RectTransform,
Anchor.CenterRight), style:
"GUIButtonInfo")
261 ToolTip = TextManager.Get(
"ModLoadOrderExplanation")
264 var enabledModsList =
new GUIListBox(
new RectTransform((1.0f, 0.93f), left.RectTransform))
266 CurrentDragMode = GUIListBox.DragMode.DragOutsideBox,
267 CurrentSelectMode = GUIListBox.SelectMode.RequireShiftToSelectMultiple,
268 HideDraggedElement =
true,
269 PlaySoundOnSelect =
true,
273 enabledRegularModsList = enabledModsList;
276 Label(right, TextManager.Get(
"disabledregular"), GUIStyle.SubHeadingFont);
277 var disabledModsList =
new GUIListBox(
new RectTransform((1.0f, 0.93f), right.RectTransform))
279 CurrentDragMode = GUIListBox.DragMode.DragOutsideBox,
280 CurrentSelectMode = GUIListBox.SelectMode.RequireShiftToSelectMultiple,
281 HideDraggedElement =
true,
282 PlaySoundOnSelect =
true,
286 disabledRegularModsList = disabledModsList;
290 new RectTransform(Vector2.One * 0.95f, center.RectTransform, scaleBasis:
ScaleBasis.BothWidth,
292 style:
"GUIButtonToggleLeft")
294 PlaySoundOnSelect =
false,
296 OnClicked = (button, o) =>
298 if (currentSwapFunc !=
null)
301 currentSwapFunc.Invoke();
307 enabledModsList.OnSelected = (frame, o) =>
309 disabledModsList.Deselect();
311 centerButton.Visible =
true;
312 centerButton.ApplyStyle(GUIStyle.GetComponentStyle(
"GUIButtonToggleRight"));
314 SetSwapFunc(enabledModsList, disabledModsList);
318 disabledModsList.OnSelected = (frame, o) =>
320 enabledModsList.Deselect();
322 centerButton.Visible =
true;
323 centerButton.ApplyStyle(GUIStyle.GetComponentStyle(
"GUIButtonToggleLeft"));
325 SetSwapFunc(disabledModsList, enabledModsList);
330 var filterContainer =
new GUILayoutGroup(
NewItemRectT(mainLayout, heightScale: 1.0f), isHorizontal:
true)
331 { Stretch =
true, RelativeSpacing = 0.01f };
333 void padFilterContainer(
float width = 0.25f)
334 =>
new GUIFrame(
new RectTransform((width, 1.0f), filterContainer!.RectTransform), style:
null);
336 GUIButton filterLayoutButton(
string style)
338 new RectTransform(Vector2.One, filterContainer!.RectTransform, scaleBasis:
ScaleBasis.BothHeight),
341 padFilterContainer(width: 0.2f);
342 var loadPresetBtn = filterLayoutButton(
"OpenButton");
343 loadPresetBtn.ToolTip = TextManager.Get(
"LoadModListPresetHeader");
344 loadPresetBtn.OnClicked = OpenLoadPreset;
345 var savePresetBtn = filterLayoutButton(
"SaveButton");
346 savePresetBtn.ToolTip = TextManager.Get(
"SaveModListPresetHeader");
347 savePresetBtn.OnClicked = OpenSavePreset;
348 padFilterContainer(width: 0.05f);
349 var searchRectT =
new RectTransform((0.5f, 1.0f), filterContainer.RectTransform);
351 modsListFilter = searchBox;
353 var filterTickboxes =
new Dictionary<Filter, GUITickBox>();
354 modsListFilterTickboxes = filterTickboxes;
356 var filterTickboxesDropdown
357 = filterLayoutButton(
"SetupVisibilityButton");
358 var filterTickboxesContainer
359 =
new GUIFrame(
new RectTransform((0.3f, 0.2f), content.RectTransform,
360 scaleBasis:
ScaleBasis.BothWidth), style:
"InnerFrame");
361 var filterTickboxesUpdater
362 =
new GUICustomComponent(
new RectTransform(Vector2.Zero, content.RectTransform),
363 onUpdate: (f, component) =>
365 filterTickboxesContainer.Visible = filterTickboxesDropdown.Selected;
366 filterTickboxesContainer.RectTransform.AbsoluteOffset
367 = (filterTickboxesDropdown.Rect.Location - content.Rect.Location)
368 + (filterTickboxesDropdown.Rect.Width / 2, 0)
369 - (filterTickboxesContainer.Rect.Size.ToVector2() * (0.5f, 1.0f)).ToPoint();
370 filterTickboxesContainer.RectTransform.NonScaledSize
371 = new Point(filterTickboxes.Select(tb => (int)tb.Value.Font.MeasureString(tb.Value.GetChild<GUITextBlock>().Text).X).Max(),
372 filterTickboxes.Select(tb => tb.Value.Rect.Height).Aggregate((a,b) => a+b))
373 +(filterTickboxes.Values.First().Rect.Height * 4, filterTickboxes.Values.First().Rect.Height / 2);
374 if (PlayerInput.PrimaryMouseButtonClicked()
375 && !GUI.IsMouseOn(filterTickboxesDropdown)
376 && !GUI.IsMouseOn(filterTickboxesContainer))
378 filterTickboxesDropdown.Selected = false;
382 var filterTickboxesLayout
383 =
new GUILayoutGroup(
new RectTransform(Vector2.One * 0.95f, filterTickboxesContainer.RectTransform,
Anchor.Center));
385 void addFilterTickbox(Filter filter,
string? style,
bool selected)
387 var tickbox =
new GUITickBox(NewItemRectT(filterTickboxesLayout!, heightScale: 0.5f),
"")
392 UpdateModListItemVisibility();
396 filterTickboxes!.Add(filter, tickbox);
397 var text =
new GUITextBlock(
new RectTransform((1.0f, 1.0f), tickbox.RectTransform,
Anchor.CenterRight)
399 AbsoluteOffset = (-tickbox.Box.Rect.Width * 2, 0),
401 TextManager.Get($
"ModFilter.{filter}"))
405 var icon =
new GUIFrame(
406 new RectTransform(Vector2.One, text.RectTransform,
Anchor.CenterLeft,
Pivot.CenterRight,
407 scaleBasis:
ScaleBasis.BothHeight), style: style)
413 if (EnableWorkshopSupport)
415 addFilterTickbox(Filter.ShowLocal,
"WorkshopMenu.EditButton", selected:
true);
416 addFilterTickbox(Filter.ShowWorkshop,
"WorkshopMenu.DownloadedIcon", selected:
true);
417 addFilterTickbox(Filter.ShowPublished,
"WorkshopMenu.PublishedIcon", selected:
true);
419 addFilterTickbox(Filter.ShowOnlySubs,
null, selected:
false);
420 addFilterTickbox(Filter.ShowOnlyItemAssemblies,
null, selected:
false);
422 padFilterContainer();
424 new GUICustomComponent(
new RectTransform(Vector2.Zero, content.RectTransform),
425 onUpdate: (f, component) =>
427 HandleDraggingAcrossModLists(enabledModsList, disabledModsList);
428 HandleDraggingAcrossModLists(disabledModsList, enabledModsList);
429 UpdateDraggingSounds();
431 if (PlayerInput.PrimaryMouseButtonClicked()
432 && !GUI.IsMouseOn(enabledModsList)
433 && !GUI.IsMouseOn(disabledModsList)
434 && GUIContextMenu.CurrentContextMenu is null)
436 enabledModsList.Deselect();
437 disabledModsList.Deselect();
439 else if (!PlayerInput.IsCtrlDown() && !PlayerInput.IsShiftDown() && PlayerInput.DoubleClicked())
441 currentSwapFunc?.Invoke();
444 onDraw: (spriteBatch, component) =>
446 enabledModsList.DraggedElement?.DrawManually(spriteBatch,
true,
true);
447 disabledModsList.DraggedElement?.DrawManually(spriteBatch,
true,
true);
450 void UpdateDraggingSounds()
452 if (draggedElement !=
null)
454 if (enabledModsList.DraggedElement ==
null && disabledModsList.DraggedElement ==
null)
458 CheckDragStopSound(enabledModsList);
459 CheckDragStopSound(disabledModsList);
461 else if (enabledModsList.DraggedElement !=
null)
463 SetDragOrigin(enabledModsList);
465 else if (disabledModsList.DraggedElement !=
null)
467 SetDragOrigin(disabledModsList);
470 void SetDragOrigin(GUIListBox? listBox)
472 draggedElement = listBox?.DraggedElement;
473 draggedElementOrigin = listBox;
476 void CheckDragStopSound(GUIListBox listBox)
478 listBox.
PlaySoundOnDragStop = listBox.DraggedElement !=
null && draggedElementOrigin != listBox;
485 string str = modsListFilter.Text;
486 enabledRegularModsList.Content.Children.Concat(disabledRegularModsList.Content.Children)
489 || ModNameMatches(p, str) && ModMatchesTickboxes(p, c));
496 bool matches =
false;
498 if (EnableWorkshopSupport)
500 matches |= modsListFilterTickboxes[Filter.ShowLocal].
Selected
501 && ContentPackageManager.LocalPackages.Contains(p);
503 matches |= modsListFilterTickboxes[Filter.ShowPublished].Selected
504 && (ContentPackageManager.WorkshopPackages.Contains(p)
505 && iconBtn?.Style?.Identifier ==
"WorkshopMenu.PublishedIcon");
506 matches |= modsListFilterTickboxes[Filter.ShowWorkshop].Selected
507 && (ContentPackageManager.WorkshopPackages.Contains(p)
508 && iconBtn?.Style?.Identifier !=
"WorkshopMenu.PublishedIcon");
515 if (modsListFilterTickboxes[Filter.ShowOnlySubs].Selected
516 && modsListFilterTickboxes[Filter.ShowOnlyItemAssemblies].Selected
517 && p.
Files.All(f => f is BaseSubFile || f is ItemAssemblyFile))
522 else if (modsListFilterTickboxes[Filter.ShowOnlySubs].Selected
523 && p.
Files.Any(f => f is not BaseSubFile))
527 else if (modsListFilterTickboxes[Filter.ShowOnlyItemAssemblies].Selected
528 && p.
Files.Any(f => f is not ItemAssemblyFile))
536 private void PrepareToShowModInfo(ContentPackage mod)
538 if (!mod.UgcId.TryUnwrap(out var ugcId)
539 || ugcId is not SteamWorkshopId workshopId) {
return; }
540 TaskPool.Add($
"PrepareToShow{mod.UgcId}Info", SteamManager.Workshop.GetItem(workshopId.Value),
543 if (!t.TryGetResult(out Option<Steamworks.Ugc.Item> itemOption)) { return; }
544 if (!itemOption.TryUnwrap(out var item)) { return; }
545 onInstalledInfoButtonHit(item);
551 ViewingItemDetails =
false;
552 if (bulkUpdateButtonOption.TryUnwrap(out var bulkUpdateButton))
554 bulkUpdateButton.Enabled =
false;
555 bulkUpdateButton.ToolTip =
"";
557 ContentPackageManager.UpdateContentPackageList();
559 var corePackages = ContentPackageManager.CorePackages.ToArray();
560 var currentCore = ContentPackageManager.EnabledPackages.Core!;
561 SwapDropdownValues<CorePackage>(enabledCoreDropdown,
570 enabledCoreDropdown.Text = p.Name;
571 enabledCoreDropdown.ButtonTextColor =
574 : GUIStyle.TextColorNormal;
579 if (ContentPackageManager.LocalPackages.Contains(mod))
582 style:
"WorkshopMenu.EditButton")
584 OnClicked = (button, o) =>
586 ToolBox.OpenFileWithShell(mod.
Dir);
589 ToolTip = TextManager.Get(
"OpenLocalModInExplorer")
592 else if (ContentPackageManager.WorkshopPackages.Contains(mod))
598 CanBeSelected =
false,
599 OnClicked = (button, o) =>
601 PrepareToShowModInfo(mod);
605 if (!EnableWorkshopSupport)
607 infoButton.Enabled =
false;
609 TaskPool.AddIfNotFound(
610 $
"DetermineUpdateRequired{mod.UgcId}",
614 if (!t.TryGetResult(out bool isUpToDate)) { return; }
616 if (isUpToDate) {
return; }
618 infoButton.CanBeSelected =
true;
619 infoButton.ApplyStyle(GUIStyle.ComponentStyles[
"WorkshopMenu.InfoButtonUpdate"]);
620 infoButton.ToolTip = TextManager.Get(
"ViewModDetailsUpdateAvailable");
621 if (bulkUpdateButtonOption.TryUnwrap(out var bulkUpdateButton))
623 bulkUpdateButton.Enabled = true;
624 bulkUpdateButton.ToolTip = TextManager.Get(
"ModUpdatesAvailable");
633 style:
"ListBoxElement")
641 RelativeSpacing = 0.02f
644 var modNameScissor =
new GUIScissorComponent(
new RectTransform((0.8f, 1.0f), frameContent.RectTransform))
648 var modName =
new GUITextBlock(
new RectTransform(Vector2.One, modNameScissor.Content.RectTransform),
653 CreateModErrorInfo(mod, modFrame, modName);
654 addButtonForMod(mod, frameContent);
659 foreach (var element
in enabledCoreDropdown.ListBox.Content.Children.ToArray())
661 enabledCoreDropdown.ListBox.RemoveChild(element);
662 if (element.UserData is not ContentPackage mod) {
continue; }
664 createBaseModListUi(mod, enabledCoreDropdown.ListBox, 0.24f);
666 enabledCoreDropdown.Select(corePackages.IndexOf(currentCore));
668 void addRegularModToList(RegularPackage mod, GUIListBox list)
670 var frameContent = createBaseModListUi(mod, list, 0.08f);
672 var modFrame = frameContent.Parent;
674 var contextMenuHandler =
new GUICustomComponent(
new RectTransform(Vector2.Zero, modFrame.RectTransform),
675 onUpdate: (f, component) =>
677 if (modFrame.Parent?.Parent?.Parent is not GUIListBox parentList || GUI.MouseOn != modFrame || parentList.DraggedElement is not null || !PlayerInput.SecondaryMouseButtonClicked()) { return; }
678 if (!parentList.AllSelected.Contains(modFrame))
680 parentList.Select(parentList.Content.GetChildIndex(modFrame));
682 List<ContextMenuOption> contextMenuOptions =
new List<ContextMenuOption>();
683 ContentPackage[] selectedMods = parentList.AllSelected.Select(it => it.UserData).OfType<ContentPackage>().ToArray();
684 Identifier swapLabel = ((parentList == enabledRegularModsList, selectedMods.Length > 1)
switch
686 (false, true) =>
"EnableSelectedWorkshopMods",
687 (false, false) =>
"EnableWorkshopMod",
688 (true, true) =>
"DisableSelectedWorkshopMods",
689 (true, false) =>
"DisableWorkshopMod"
691 contextMenuOptions.Add(
new(swapLabel, isEnabled:
true, currentSwapFunc ?? NoOp));
692 if (ContentPackageManager.WorkshopPackages.Contains(mod))
694 if (selectedMods.Length == 1)
696 contextMenuOptions.Add(new(
"ViewWorkshopModDetails".ToIdentifier(), isEnabled: true, () => PrepareToShowModInfo(mod)));
697 contextMenuOptions.Add(new(
"CopyWorkshopToLocal".ToIdentifier(), isEnabled: true, () => CopyToLocal()));
699 if (selectedMods.All(ContentPackageManager.WorkshopPackages.Contains))
701 if (parentList.AllSelected.All(c => c.GetChild<GUILayoutGroup>()?.GetAllChildren<GUIButton>().Last()?.Style?.Identifier ==
"WorkshopMenu.DownloadedIcon") && selectedMods.Length > 0 && SteamManager.IsInitialized)
703 contextMenuOptions.Add(new((selectedMods.Length > 1 ?
"UnsubscribeFromAllSelected" :
"WorkshopItemUnsubscribe").ToIdentifier(), true, () =>
705 TaskPool.AddIfNotFound(
"UnsubFromSelected", Task.WhenAll(selectedMods.Select(m => m.UgcId).NotNone().OfType<SteamWorkshopId>().Select(id => SteamManager.Workshop.GetItem(id.Value))), t =>
707 if (!t.TryGetResult(out Option<Steamworks.Ugc.Item>[]? itemOptions)) { return; }
708 itemOptions.ForEach(io =>
710 if (!io.TryUnwrap(out Steamworks.Ugc.Item item) || !item.IsSubscribed) { return; }
712 SteamManager.Workshop.Uninstall(item);
713 PopulateInstalledModLists();
720 else if (ContentPackageManager.LocalPackages.Contains(mod))
722 if (selectedMods.Length == 1)
724 contextMenuOptions.Add(new ContextMenuOption(
"RenamePackage".ToIdentifier(), isEnabled: true, AskToRenameLocal));
726 if (selectedMods.All(ContentPackageManager.LocalPackages.Contains))
728 if (selectedMods.Length > 1)
730 contextMenuOptions.Add(new(
"MergeSelectedMods".ToIdentifier(), isEnabled: true, () => ModMerger.AskMerge(selectedMods)));
732 contextMenuOptions.Add(
new(
"Delete".ToIdentifier(), isEnabled:
true, AskToDeleteLocal));
735 GUIContextMenu.CreateContextMenu(PlayerInput.MousePosition, ToolBox.LimitString(mod.Name, GUIStyle.SubHeadingFont, GUI.IntScale(300)),
null, contextMenuOptions.ToArray());
736 static void NoOp() { }
737 void AskToRenameLocal()
739 GUIMessageBox msgBox =
new(TextManager.Get(
"RenamePackage"), mod.Name,
new LocalizedString[] { TextManager.Get(
"Confirm"), TextManager.Get(
"Cancel") }, minSize:
new Point(0, GUI.IntScale(195)));
740 GUITextBox textBox =
new(
new(Vector2.One, msgBox.Content.RectTransform), mod.Name)
742 OnEnterPressed = (textBox, text) =>
744 textBox.Text = text.Trim();
748 msgBox.Buttons[0].OnClicked += msgBox.Close;
749 msgBox.Buttons[1].OnClicked += (_, _) =>
751 if (textBox.Text == mod.Name)
756 if (mod.TryRenameLocal(textBox.Text))
758 PopulateInstalledModLists();
771 if (mod.TryCreateLocalFromWorkshop())
773 PopulateInstalledModLists();
776 void AskToDeleteLocal()
778 GUIMessageBox msgBox =
new(TextManager.Get(
"DeleteMods"), TextManager.GetWithVariables(
"DeleteModsConfirm", (
"[amount]", selectedMods.Length.ToString())),
779 new LocalizedString[] { TextManager.Get(
"Confirm"), TextManager.Get(
"Cancel")}, textAlignment: Alignment.TopCenter);
780 msgBox.Buttons[0].OnClicked += msgBox.Close;
781 msgBox.Buttons[1].OnClicked += (_, _) =>
783 foreach (ContentPackage mod
in selectedMods)
785 mod.TryDeleteLocal();
786 PopulateInstalledModLists();
794 var dragIndicator =
new GUIButton(
new RectTransform((0.5f, 0.5f), frameContent.RectTransform, scaleBasis:
ScaleBasis.BothHeight),
795 style:
"GUIDragIndicator")
799 dragIndicator.RectTransform.SetAsFirstChild();
802 void addRegularModsToList(IEnumerable<RegularPackage> mods, GUIListBox list)
804 list.ClearChildren();
805 foreach (var mod
in mods)
807 addRegularModToList(mod, list);
812 (forceRefreshEnabled || (enabledRegularModsList.Content.CountChildren + disabledRegularModsList.Content.CountChildren == 0)
813 ? ContentPackageManager.EnabledPackages.Regular
814 : enabledRegularModsList.Content.Children
815 .Select(c => c.UserData)
816 .OfType<RegularPackage>()
817 .Where(p => ContentPackageManager.RegularPackages.Contains(p)))
819 var disabledMods = ContentPackageManager.RegularPackages.Where(p => !enabledMods.Contains(p));
821 addRegularModsToList(enabledMods, enabledRegularModsList);
822 if (refreshDisabled) { addRegularModsToList(disabledMods, disabledRegularModsList); }
824 TaskPool.AddIfNotFound(
825 $
"DetermineWorkshopModIcons",
826 SteamManager.Workshop.GetPublishedItems(),
829 if (!t.TryGetResult(out ISet<Steamworks.Ugc.Item>? items)) { return; }
830 var ids = items.Select(it => it.Id).ToHashSet();
832 foreach (var child in enabledRegularModsList.Content.Children
833 .Concat(disabledRegularModsList.Content.Children))
835 var mod = child.UserData as RegularPackage;
836 if (mod is null || !ContentPackageManager.WorkshopPackages.Contains(mod)) { continue; }
837 if (!mod.UgcId.TryUnwrap(out var ugcId)) { continue; }
838 if (ugcId is not SteamWorkshopId workshopId) {
continue; }
840 var btn = child.GetChild<GUILayoutGroup>()?.GetAllChildren<GUIButton>().Last();
841 if (btn is
null) {
continue; }
842 if (btn.Style !=
null) {
continue; }
845 GUIStyle.GetComponentStyle(
846 ids.Contains(workshopId.Value)
847 ?
"WorkshopMenu.PublishedIcon"
848 :
"WorkshopMenu.DownloadedIcon"));
849 btn.ToolTip = TextManager.Get(
850 ids.Contains(workshopId.Value)
851 ?
"PublishedWorkshopMod"
852 :
"DownloadedWorkshopMod");
857 UpdateModListItemVisibility();
ImmutableArray< ContentFile > Files
async Task< bool > IsUpToDate()
GUIComponent GetChild(int index)
RectTransform RectTransform
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.