diff --git a/src/ContextMenus/OpenInteractions.cs b/src/ContextMenus/OpenInteractions.cs new file mode 100644 index 0000000..d572a5e --- /dev/null +++ b/src/ContextMenus/OpenInteractions.cs @@ -0,0 +1,83 @@ +using Comfort.Common; +using EFT.UI; +using EFT.UI.DragAndDrop; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace UIFixes; + +public class OpenInteractions(ItemContextAbstractClass itemContext, ItemUiContext itemUiContext) : ItemInfoInteractionsAbstractClass(itemUiContext) +{ + private readonly ItemContextAbstractClass itemContext = itemContext; + + public override void ExecuteInteractionInternal(Options interaction) + { + if (itemContext == null || itemContext.Item is not LootItemClass compoundItem) + { + return; + } + + var taskSerializer = itemUiContext_0.gameObject.AddComponent(); + taskSerializer.Initialize(GetNestedContainers(itemContext), containerContext => + { + if (containerContext != null) + { + itemUiContext_0.OpenItem(containerContext.Item as LootItemClass, containerContext, true); + } + + return Task.CompletedTask; + }); + } + + public override bool IsActive(Options button) + { + return true; + } + + public override IResult IsInteractive(Options button) + { + return SuccessfulResult.New; + } + + public override bool HasIcons + { + get { return false; } + } + + public enum Options + { + All + } + + private IEnumerable GetNestedContainers(ItemContextAbstractClass first) + { + var windowRoot = Singleton.Instance; + LootItemClass parent = first.Item as LootItemClass; + + yield return first; + + while (true) + { + var innerContainers = parent.GetFirstLevelItems() + .Where(i => i != parent) + .Where(i => i is LootItemClass innerContainer && innerContainer.Grids.Any()); + if (innerContainers.Count() != 1) + { + yield break; + } + + var targetId = innerContainers.First().Id; + var targetItemView = windowRoot.GetComponentsInChildren().FirstOrDefault(itemView => itemView.Item.Id == targetId); + if (targetItemView == null) + { + yield return null; // Keeps returning null until the window is open + } + + parent = targetItemView.Item as LootItemClass; + yield return targetItemView.ItemContext; + } + } +} + +public class NestedContainerTaskSerializer : TaskSerializer { } \ No newline at end of file diff --git a/src/Patches/ContextMenuPatches.cs b/src/Patches/ContextMenuPatches.cs index bab1ba7..811a0c6 100644 --- a/src/Patches/ContextMenuPatches.cs +++ b/src/Patches/ContextMenuPatches.cs @@ -125,9 +125,20 @@ public static class ContextMenuPatches } [PatchPostfix] - public static void Postfix(ref IEnumerable __result) + public static void Postfix(ref IEnumerable __result, Item ___item_0) { __result = __result.Append(EItemInfoButton.Repair).Append(EItemInfoButton.Insure); + + if (___item_0 is LootItemClass container && container.Grids.Any()) + { + var innerContainers = container.GetFirstLevelItems() + .Where(i => i != container) + .Where(i => i is LootItemClass innerContainer && innerContainer.Grids.Any()); + if (innerContainers.Count() == 1) + { + __result = __result.Append(EItemInfoButton.Open); + } + } } } @@ -141,7 +152,12 @@ public static class ContextMenuPatches } [PatchPrefix] - public static bool Prefix(EItemInfoButton parentInteraction, ISubInteractions subInteractionsWrapper, Item ___item_0, ItemUiContext ___itemUiContext_1) + public static bool Prefix( + EItemInfoButton parentInteraction, + ISubInteractions subInteractionsWrapper, + Item ___item_0, + ItemContextAbstractClass ___itemContextAbstractClass, + ItemUiContext ___itemUiContext_1) { // Clear this, since something else should be active (even a different mouseover of the insurance button) LoadingInsuranceActions = false; @@ -179,6 +195,12 @@ public static class ContextMenuPatches return false; } + if (Settings.OpenAllContextMenu.Value && parentInteraction == EItemInfoButton.Open) + { + subInteractionsWrapper.SetSubInteractions(new OpenInteractions(___itemContextAbstractClass, ___itemUiContext_1)); + return false; + } + return true; } } diff --git a/src/Settings.cs b/src/Settings.cs index 06cc81f..4bb9dc7 100644 --- a/src/Settings.cs +++ b/src/Settings.cs @@ -139,6 +139,7 @@ internal class Settings public static ConfigEntry ContextMenuOnRight { get; set; } public static ConfigEntry AddOfferContextMenu { get; set; } public static ConfigEntry WishlistContextEverywhere { get; set; } + public static ConfigEntry OpenAllContextMenu { get; set; } public static ConfigEntry ShowGPCurrency { get; set; } public static ConfigEntry ShowOutOfStockCheckbox { get; set; } public static ConfigEntry SortingTableButton { get; set; } @@ -748,6 +749,15 @@ internal class Settings null, new ConfigurationManagerAttributes { }))); + configEntries.Add(OpenAllContextMenu = config.Bind( + InventorySection, + "Open All Context Flyout", + true, + new ConfigDescription( + "Add a flyout to the Open context menu to recursively open a stack of containers", + null, + new ConfigurationManagerAttributes { }))); + configEntries.Add(ShowGPCurrency = config.Bind( InventorySection, "Show GP Coins in Currency",