Skip to content

Commit e52ba3e

Browse files
committed
Make use of pagination for the hooked context menus and restructure the config for them
1 parent 2f4573e commit e52ba3e

5 files changed

Lines changed: 94 additions & 16 deletions

File tree

MonkeyLoader.Resonite.Integration/Locale/Config/de.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@
3636
"MonkeyLoader.Config.NuGet.NuGetModSources.Name": "Quellen für Mods",
3737
"MonkeyLoader.Config.NuGet.NuGetModSources.Description": "NuGet-Feeds, die nach Mods durchsucht werden.",
3838

39-
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.Name": "Kontext-Menüs",
39+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.Name": "Kontextmenüs",
40+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ItemLimit.Name": "Elementlimit",
41+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.Scaling.Name": "Skalierung",
42+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ToolEquipped.Name": "Werkzeug Ausgerüstet",
4043
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.AlwaysAllowScaleToggle.Name": "Umschalten des Skalierens immer erlauben",
4144
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.AlwaysAllowScaleToggle.Description": "Zeigt die Option zum Umschalten des Skalierens an, auch wenn diese nicht gerade der Standardskalierung des Avatars entspricht.",
4245
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.AlwaysShowLocomotion.Name": "Fortbewegung immer anzeigen",
@@ -47,6 +50,10 @@
4750
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ShowResetScaleWithToggle.Description": "Zeigt die Skalierung-Zurücksetzen-Aktion zusammen mit der Option zum Umschalten des Skalierens an, wenn diese immer angezeigt wird.",
4851
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ShowSaveLocation.Name": "Speicherort anzeigen",
4952
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ShowSaveLocation.Description": "Zeigt den aktuellen Inventarpfad für das Speichern an.",
53+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.LimitContextMenuItems.Name": "Kontextmenü-Elemente Limitieren",
54+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.LimitContextMenuItems.Description": "Limitiere die Anzahl der Elemente die im Kontextmenü angezeigt werden. Wenn die konfigurierte Anzahl überschritten wird, wird das Menü in mehrere Seiten unterteilt.",
55+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ContextMenuItemLimit.Name": "Limit für Kontextmenü-Elemente",
56+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ContextMenuItemLimit.Description": "Limitiere die Anzahl der Elemente die im Kontextmenü angezeigt werden. Wenn diese Anzahl überschritten wird, wird das Menü in mehrere Seiten unterteilt.",
5057

5158
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.Name": "Inspektor-Kopfzeile",
5259
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.DestroyOffset.Name": "Löschen Offset",

MonkeyLoader.Resonite.Integration/Locale/Config/en.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
"MonkeyLoader.Config.NuGet.NuGetModSources.Description": "NuGet feeds to check for mods.",
3838

3939
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.Name": "Context Menus",
40+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ItemLimit.Name": "Item Limit",
41+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.Scaling.Name": "Scaling",
42+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ToolEquipped.Name": "Tool Equipped",
4043
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.AlwaysAllowScaleToggle.Name": "Always allow Scale Toggle",
4144
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.AlwaysAllowScaleToggle.Description": "Shows the scaling toggle even when not at the default scale for the avatar.",
4245
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.AlwaysShowLocomotion.Name": "Always show Locomotion Selection",
@@ -47,6 +50,10 @@
4750
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ShowResetScaleWithToggle.Description": "Shows the reset scale action alongside the scaling toggle when it is always allowed.",
4851
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ShowSaveLocation.Name": "Show Save Location",
4952
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ShowSaveLocation.Description": "Shows the current inventory path for saving.",
53+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.LimitContextMenuItems.Name": "Limit Context Menu Items",
54+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.LimitContextMenuItems.Description": "Limit the number of items shown in the context menu. If the configured number is exceeded, the menu will get paginated.",
55+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ContextMenuItemLimit.Name": "Context Menu Item Limit",
56+
"MonkeyLoader.GamePacks.Resonite.Config.ContextMenus.ContextMenuItemLimit.Description": "Limit the number of items shown in the context menu. If this number is exceeded, the menu will get paginated.",
5057

5158
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.Name": "Inspector Header",
5259
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.DestroyOffset.Name": "Destroy Offset",

MonkeyLoader.Resonite.Integration/UI/ContextMenus/ContextMenuInjector.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ protected override bool OnLoaded()
3434

3535
// ContextMenuItemsGenerationEvent is a SubscribableBaseEvent and will trigger derived handlers
3636
await DispatchAsync(eventData);
37+
38+
if (ContextMenusConfig.Instance.LimitContextMenuItems)
39+
eventData.ContextMenu.TryAddPagination(ContextMenusConfig.Instance.ContextMenuItemLimit);
3740
});
3841
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
3942

MonkeyLoader.Resonite.Integration/UI/ContextMenus/ContextMenusConfig.cs

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,51 @@ namespace MonkeyLoader.Resonite.UI.ContextMenus
1010
/// </summary>
1111
public sealed class ContextMenusConfig : SingletonConfigSection<ContextMenusConfig>
1212
{
13-
private static readonly DefiningConfigKey<bool> _alwaysAllowScaleToggle = new("AlwaysAllowScaleToggle", "Show the scaling toggle even when not at the default scale for the avatar.", () => false);
14-
private static readonly DefiningConfigKey<bool> _alwaysShowLocomotion = new("AlwaysShowLocomotion", "Show the locomotion selection even when a tool is equipped.", () => false);
15-
private static readonly DefiningConfigKey<bool> _alwaysShowScaling = new("AlwaysShowScaling", "Show the scaling toggle and/or reset scale action even when a tool is equipped.", () => false);
13+
private static readonly ConfigKeySubgroup _itemLimitSubgroup = new(9, "ItemLimit");
14+
private static readonly ConfigKeySubgroup _scalingSubgroup = new(7, "Scaling");
15+
private static readonly ConfigKeySubgroup _toolEquippedSubgroup = new("ToolEquipped");
1616

17-
private static readonly DefiningConfigKey<bool> _showResetScaleWithToggle = new("ShowResetScaleWithToggle", "Show the reset scale action alongside the scaling toggle when it is always allowed.", () => true)
17+
private readonly DefiningConfigKey<bool> _alwaysAllowScaleToggle = new("AlwaysAllowScaleToggle", "Show the scaling toggle even when not at the default scale for the avatar.", () => false)
1818
{
19+
_scalingSubgroup,
20+
new ConfigKeyPriority(7)
21+
};
22+
23+
private readonly DefiningConfigKey<bool> _alwaysShowLocomotion = new("AlwaysShowLocomotion", "Show the locomotion selection even when a tool is equipped.", () => false)
24+
{
25+
_toolEquippedSubgroup
26+
};
27+
28+
private readonly DefiningConfigKey<bool> _alwaysShowScaling = new("AlwaysShowScaling", "Show the scaling toggle and/or reset scale action even when a tool is equipped.", () => false)
29+
{
30+
_toolEquippedSubgroup
31+
};
32+
33+
private readonly DefiningConfigKey<int> _contextMenuItemLimit = new("ContextMenuItemLimit", "Limit the number of items shown in the context menu. If this number is exceeded, the menu will get paginated.", () => 16)
34+
{
35+
_itemLimitSubgroup,
36+
new ConfigKeyPriority(8),
37+
new ConfigKeyRange<int>(3, 32),
38+
new LimitContextMenuItemsToggleLink()
39+
};
40+
41+
private readonly DefiningConfigKey<bool> _limitContextMenuItems = new("LimitContextMenuItems", "Limit the number of items shown in the context menu. If the configured number is exceeded, the menu will get paginated.", () => true)
42+
{
43+
_itemLimitSubgroup,
44+
new ConfigKeyPriority(9)
45+
};
46+
47+
private readonly DefiningConfigKey<bool> _showResetScaleWithToggle = new("ShowResetScaleWithToggle", "Show the reset scale action alongside the scaling toggle when it is always allowed.", () => true)
48+
{
49+
_scalingSubgroup,
50+
new ConfigKeyPriority(6),
1951
new AlwaysAllowScaleToggleLink()
2052
};
2153

22-
private static readonly DefiningConfigKey<bool> _showSaveLocation = new("ShowSaveLocation", "Show the current inventory path when trying to save something.", () => true);
54+
private readonly DefiningConfigKey<bool> _showSaveLocation = new("ShowSaveLocation", "Show the current inventory path when trying to save something.", () => true)
55+
{
56+
new ConfigKeyPriority(10)
57+
};
2358

2459
/// <summary>
2560
/// Gets whether to show the scaling toggle even when not at the default scale for the avatar.
@@ -42,12 +77,24 @@ public sealed class ContextMenusConfig : SingletonConfigSection<ContextMenusConf
4277
/// </summary>
4378
public bool AlwaysShowScaling => _alwaysShowScaling;
4479

80+
/// <summary>
81+
/// Gets the limit for the number of non-pagination items shown in the context menu.<br/>
82+
/// If this number is exceeded, the menu will get paginated.
83+
/// </summary>
84+
public int ContextMenuItemLimit => _contextMenuItemLimit - 2;
85+
4586
/// <inheritdoc/>
4687
public override string Description => "Contains settings for the generation of Context Menus.";
4788

4889
/// <inheritdoc/>
4990
public override string Id => "ContextMenus";
5091

92+
/// <summary>
93+
/// Limit the number of items shown in the context menu.<br/>
94+
/// If the <see cref="ContextMenuItemLimit">configured number</see> is exceeded, the menu will get paginated.
95+
/// </summary>
96+
public bool LimitContextMenuItems => _limitContextMenuItems;
97+
5198
/// <summary>
5299
/// Gets whether to show the reset scale action alongside the scaling toggle when it is always allowed.
53100
/// </summary>
@@ -59,18 +106,29 @@ public sealed class ContextMenusConfig : SingletonConfigSection<ContextMenusConf
59106
public bool ShowSaveLocation => _showSaveLocation;
60107

61108
/// <inheritdoc/>
62-
public override Version Version { get; } = new(1, 0, 0);
109+
public override Version Version { get; } = new(1, 1, 0);
63110

64111
private sealed class AlwaysAllowScaleToggleLink : ConfigKeyCustomDataFeedItems<bool>
65112
{
66-
public override IAsyncEnumerable<DataFeedItem> Enumerate(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, string? searchPhrase, object? viewData)
113+
public override async IAsyncEnumerable<DataFeedItem> Enumerate(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, string? searchPhrase, object? viewData)
67114
{
68-
var toggle = new DataFeedToggle();
69-
toggle.InitBase(path, groupKeys, ConfigKey);
70-
toggle.InitSetupValue(field => field.SetupConfigKeyField(ConfigKey));
71-
toggle.InitEnabled(field => field.SetupConfigKeyField(_alwaysAllowScaleToggle));
115+
await foreach (var item in ConfigKey.EnumerateDefaultItemsAsync(path, [.. groupKeys]))
116+
{
117+
item.InitEnabled(field => field.SetupConfigKeyField(Instance._alwaysAllowScaleToggle));
118+
yield return item;
119+
}
120+
}
121+
}
72122

73-
return new[] { toggle }.ToAsyncEnumerable();
123+
private sealed class LimitContextMenuItemsToggleLink : ConfigKeyCustomDataFeedItems<int>
124+
{
125+
public override async IAsyncEnumerable<DataFeedItem> Enumerate(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, string? searchPhrase, object? viewData)
126+
{
127+
await foreach (var item in ConfigKey.EnumerateDefaultItemsAsync(path, groupKeys))
128+
{
129+
item.InitEnabled(field => field.SetupConfigKeyField(Instance._limitContextMenuItems));
130+
yield return item;
131+
}
74132
}
75133
}
76134
}

MonkeyLoader.Resonite.Integration/UI/ContextMenus/InteractionHandlerContextMenuInjector.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using FrooxEngine.CommonAvatar;
44
using FrooxEngine.UIX;
55
using HarmonyLib;
6-
76
using static FrooxEngine.InteractionHandler;
87

98
namespace MonkeyLoader.Resonite.UI.ContextMenus
@@ -267,13 +266,17 @@ private static bool OpenContextMenuPrefix(InteractionHandler __instance, MenuOpt
267266
break;
268267
}
269268

270-
await __instance.PositionContextMenu(menu);
271-
272269
var eventData = ContextMenuItemsGenerationEvent.CreateFor(menu);
273270
Logger.Info(() => $"Dispatching CM event: {eventData.GetType().CompactDescription()}");
274271

275272
// ContextMenuItemsGenerationEvent is a SubscribableBaseEvent and will trigger derived handlers
276273
await DispatchAsync(eventData);
274+
275+
if (ConfigSection.LimitContextMenuItems)
276+
menu.TryAddPagination(ConfigSection.ContextMenuItemLimit);
277+
278+
// This must happen at the end, otherwise the context menu items will flicker when items are added
279+
await __instance.PositionContextMenu(menu);
277280
});
278281

279282
return false;

0 commit comments

Comments
 (0)