From a71cb813841909eba9a7e8f260e1bc57d91f312b Mon Sep 17 00:00:00 2001 From: srkizer Date: Wed, 29 Nov 2023 06:43:41 +0900 Subject: [PATCH] Hold Shift to display Toggle Dev Menu TSM entry (#1538) Co-authored-by: goat <16760685+goaaats@users.noreply.github.com> --- .../Interface/Internal/DalamudInterface.cs | 42 +++++++----- .../Internal/Windows/TitleScreenMenuWindow.cs | 29 +++++---- .../TitleScreenMenu/TitleScreenMenu.cs | 65 +++++++++++++++---- .../TitleScreenMenu/TitleScreenMenuEntry.cs | 28 +++++++- 4 files changed, 124 insertions(+), 40 deletions(-) diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs index 1a6e71194..1dcc5c0c7 100644 --- a/Dalamud/Interface/Internal/DalamudInterface.cs +++ b/Dalamud/Interface/Internal/DalamudInterface.cs @@ -9,6 +9,7 @@ using CheapLoc; using Dalamud.Configuration.Internal; using Dalamud.Game.ClientState; using Dalamud.Game.ClientState.Conditions; +using Dalamud.Game.ClientState.Keys; using Dalamud.Game.Gui; using Dalamud.Game.Internal; using Dalamud.Interface.Animation.EasingFunctions; @@ -151,23 +152,32 @@ internal class DalamudInterface : IDisposable, IServiceType this.interfaceManager.Draw += this.OnDraw; - var tsm = Service.Get(); - tsm.AddEntryCore( - Loc.Localize("TSMDalamudPlugins", "Plugin Installer"), - dalamudAssetManager.GetDalamudTextureWrap(DalamudAsset.LogoSmall), - this.OpenPluginInstaller); - tsm.AddEntryCore( - Loc.Localize("TSMDalamudSettings", "Dalamud Settings"), - dalamudAssetManager.GetDalamudTextureWrap(DalamudAsset.LogoSmall), - this.OpenSettings); + Service.GetAsync().ContinueWith( + _ => + { + titleScreenMenu.AddEntryCore( + Loc.Localize("TSMDalamudPlugins", "Plugin Installer"), + dalamudAssetManager.GetDalamudTextureWrap(DalamudAsset.LogoSmall), + this.OpenPluginInstaller); + titleScreenMenu.AddEntryCore( + Loc.Localize("TSMDalamudSettings", "Dalamud Settings"), + dalamudAssetManager.GetDalamudTextureWrap(DalamudAsset.LogoSmall), + this.OpenSettings); - if (!configuration.DalamudBetaKind.IsNullOrEmpty()) - { - tsm.AddEntryCore( - Loc.Localize("TSMDalamudDevMenu", "Developer Menu"), - dalamudAssetManager.GetDalamudTextureWrap(DalamudAsset.LogoSmall), - () => this.isImGuiDrawDevMenu = true); - } + titleScreenMenu.AddEntryCore( + "Toggle Dev Menu", + dalamudAssetManager.GetDalamudTextureWrap(DalamudAsset.LogoSmall), + () => Service.GetNullable()?.ToggleDevMenu(), + VirtualKey.SHIFT); + + if (!configuration.DalamudBetaKind.IsNullOrEmpty()) + { + titleScreenMenu.AddEntryCore( + Loc.Localize("TSMDalamudDevMenu", "Developer Menu"), + dalamudAssetManager.GetDalamudTextureWrap(DalamudAsset.LogoSmall), + () => this.isImGuiDrawDevMenu = true); + } + }); this.creditsDarkeningAnimation.Point1 = Vector2.Zero; this.creditsDarkeningAnimation.Point2 = new Vector2(CreditsDarkeningMaxAlpha); diff --git a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs index f60ebe4ef..42bca89ff 100644 --- a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs +++ b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs @@ -31,7 +31,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable private readonly GameGui gameGui; private readonly TitleScreenMenu titleScreenMenu; - private readonly IDalamudTextureWrap shadeTexture; + private readonly Lazy shadeTexture; private readonly Dictionary shadeEasings = new(); private readonly Dictionary moveEasings = new(); @@ -77,7 +77,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable this.PositionCondition = ImGuiCond.Always; this.RespectCloseHotkey = false; - this.shadeTexture = dalamudAssetManager.GetDalamudTextureWrap(DalamudAsset.TitleScreenMenuShade); + this.shadeTexture = new(() => dalamudAssetManager.GetDalamudTextureWrap(DalamudAsset.TitleScreenMenuShade)); framework.Update += this.FrameworkOnUpdate; } @@ -122,15 +122,17 @@ internal class TitleScreenMenuWindow : Window, IDisposable return; var scale = ImGui.GetIO().FontGlobalScale; - var entries = this.titleScreenMenu.Entries.OrderByDescending(x => x.IsInternal).ToList(); + var entries = this.titleScreenMenu.Entries; switch (this.state) { case State.Show: { - for (var i = 0; i < entries.Count; i++) + var i = 0; + foreach (var entry in entries) { - var entry = entries[i]; + if (!entry.IsShowConditionSatisfied()) + continue; if (!this.moveEasings.TryGetValue(entry.Id, out var moveEasing)) { @@ -150,7 +152,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable moveEasing.Update(); - var finalPos = (i + 1) * this.shadeTexture.Height * scale; + var finalPos = (i + 1) * this.shadeTexture.Value.Height * scale; var pos = moveEasing.Value * finalPos; // FIXME(goat): Sometimes, easings can overshoot and bring things out of alignment. @@ -164,6 +166,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable var cursor = ImGui.GetCursorPos(); cursor.Y = (float)pos; ImGui.SetCursorPos(cursor); + i++; } if (!ImGui.IsWindowHovered(ImGuiHoveredFlags.RootAndChildWindows | @@ -196,17 +199,20 @@ internal class TitleScreenMenuWindow : Window, IDisposable using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)this.fadeOutEasing.Value)) { - for (var i = 0; i < entries.Count; i++) + var i = 0; + foreach (var entry in entries) { - var entry = entries[i]; + if (!entry.IsShowConditionSatisfied()) + continue; - var finalPos = (i + 1) * this.shadeTexture.Height * scale; + var finalPos = (i + 1) * this.shadeTexture.Value.Height * scale; this.DrawEntry(entry, i != 0, true, i == 0, false, false); var cursor = ImGui.GetCursorPos(); cursor.Y = finalPos; ImGui.SetCursorPos(cursor); + i++; } } @@ -280,7 +286,8 @@ internal class TitleScreenMenuWindow : Window, IDisposable using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, (float)shadeEasing.Value)) { - ImGui.Image(this.shadeTexture.ImGuiHandle, new Vector2(this.shadeTexture.Width * scale, this.shadeTexture.Height * scale)); + var texture = this.shadeTexture.Value; + ImGui.Image(texture.ImGuiHandle, new Vector2(texture.Width, texture.Height) * scale); } var isHover = ImGui.IsItemHovered(); @@ -358,7 +365,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable // Drop shadow using (ImRaii.PushColor(ImGuiCol.Text, 0xFF000000)) { - for (int i = 0, i_ = (int)Math.Ceiling(1 * scale); i < i_; i++) + for (int i = 0, to = (int)Math.Ceiling(1 * scale); i < to; i++) { ImGui.SetCursorPos(new Vector2(cursor.X, cursor.Y + i)); ImGui.Text(entry.Name); diff --git a/Dalamud/Interface/TitleScreenMenu/TitleScreenMenu.cs b/Dalamud/Interface/TitleScreenMenu/TitleScreenMenu.cs index 6665bbafb..1f9a5bc76 100644 --- a/Dalamud/Interface/TitleScreenMenu/TitleScreenMenu.cs +++ b/Dalamud/Interface/TitleScreenMenu/TitleScreenMenu.cs @@ -2,11 +2,12 @@ using System.Linq; using System.Reflection; +using Dalamud.Game.ClientState.Keys; using Dalamud.Interface.Internal; using Dalamud.IoC; using Dalamud.IoC.Internal; using Dalamud.Plugin.Services; -using ImGuiScene; +using Dalamud.Utility; namespace Dalamud.Interface; @@ -23,14 +24,32 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu internal const uint TextureSize = 64; private readonly List entries = new(); + private TitleScreenMenuEntry[]? entriesView; [ServiceManager.ServiceConstructor] private TitleScreenMenu() { } + /// + /// Event to be called when the entry list has been changed. + /// + internal event Action? EntryListChange; + /// - public IReadOnlyList Entries => this.entries; + public IReadOnlyList Entries + { + get + { + lock (this.entries) + { + if (!this.entries.Any()) + return Array.Empty(); + + return this.entriesView ??= this.entries.OrderByDescending(x => x.IsInternal).ToArray(); + } + } + } /// public TitleScreenMenuEntry AddEntry(string text, IDalamudTextureWrap texture, Action onTriggered) @@ -40,19 +59,23 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu throw new ArgumentException("Texture must be 64x64"); } + TitleScreenMenuEntry entry; lock (this.entries) { var entriesOfAssembly = this.entries.Where(x => x.CallingAssembly == Assembly.GetCallingAssembly()).ToList(); var priority = entriesOfAssembly.Any() ? unchecked(entriesOfAssembly.Select(x => x.Priority).Max() + 1) : 0; - var entry = new TitleScreenMenuEntry(Assembly.GetCallingAssembly(), priority, text, texture, onTriggered); + entry = new(Assembly.GetCallingAssembly(), priority, text, texture, onTriggered); var i = this.entries.BinarySearch(entry); if (i < 0) i = ~i; this.entries.Insert(i, entry); - return entry; + this.entriesView = null; } + + this.EntryListChange?.InvokeSafely(); + return entry; } /// @@ -63,15 +86,19 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu throw new ArgumentException("Texture must be 64x64"); } + TitleScreenMenuEntry entry; lock (this.entries) { - var entry = new TitleScreenMenuEntry(Assembly.GetCallingAssembly(), priority, text, texture, onTriggered); + entry = new(Assembly.GetCallingAssembly(), priority, text, texture, onTriggered); var i = this.entries.BinarySearch(entry); if (i < 0) i = ~i; this.entries.Insert(i, entry); - return entry; + this.entriesView = null; } + + this.EntryListChange?.InvokeSafely(); + return entry; } /// @@ -80,7 +107,10 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu lock (this.entries) { this.entries.Remove(entry); + this.entriesView = null; } + + this.EntryListChange?.InvokeSafely(); } /// @@ -99,15 +129,19 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu throw new ArgumentException("Texture must be 64x64"); } + TitleScreenMenuEntry entry; lock (this.entries) { - var entry = new TitleScreenMenuEntry(null, priority, text, texture, onTriggered) + entry = new(null, priority, text, texture, onTriggered) { IsInternal = true, }; this.entries.Add(entry); - return entry; + this.entriesView = null; } + + this.EntryListChange?.InvokeSafely(); + return entry; } /// @@ -116,28 +150,37 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu /// The text to show. /// The texture to show. /// The action to execute when the option is selected. + /// The keys that have to be held to display the menu. /// A object that can be used to manage the entry. /// Thrown when the texture provided does not match the required resolution(64x64). - internal TitleScreenMenuEntry AddEntryCore(string text, IDalamudTextureWrap texture, Action onTriggered) + internal TitleScreenMenuEntry AddEntryCore( + string text, + IDalamudTextureWrap texture, + Action onTriggered, + params VirtualKey[] showConditionKeys) { if (texture.Height != TextureSize || texture.Width != TextureSize) { throw new ArgumentException("Texture must be 64x64"); } + TitleScreenMenuEntry entry; lock (this.entries) { var entriesOfAssembly = this.entries.Where(x => x.CallingAssembly == null).ToList(); var priority = entriesOfAssembly.Any() ? unchecked(entriesOfAssembly.Select(x => x.Priority).Max() + 1) : 0; - var entry = new TitleScreenMenuEntry(null, priority, text, texture, onTriggered) + entry = new(null, priority, text, texture, onTriggered, showConditionKeys) { IsInternal = true, }; this.entries.Add(entry); - return entry; + this.entriesView = null; } + + this.EntryListChange?.InvokeSafely(); + return entry; } } diff --git a/Dalamud/Interface/TitleScreenMenu/TitleScreenMenuEntry.cs b/Dalamud/Interface/TitleScreenMenu/TitleScreenMenuEntry.cs index 76382ace2..8a400db7c 100644 --- a/Dalamud/Interface/TitleScreenMenu/TitleScreenMenuEntry.cs +++ b/Dalamud/Interface/TitleScreenMenu/TitleScreenMenuEntry.cs @@ -1,5 +1,9 @@ -using System.Reflection; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reflection; +using Dalamud.Game.ClientState.Keys; using Dalamud.Interface.Internal; namespace Dalamud.Interface; @@ -19,13 +23,21 @@ public class TitleScreenMenuEntry : IComparable /// The text to show. /// The texture to show. /// The action to execute when the option is selected. - internal TitleScreenMenuEntry(Assembly? callingAssembly, ulong priority, string text, IDalamudTextureWrap texture, Action onTriggered) + /// The keys that have to be held to display the menu. + internal TitleScreenMenuEntry( + Assembly? callingAssembly, + ulong priority, + string text, + IDalamudTextureWrap texture, + Action onTriggered, + IEnumerable? showConditionKeys = null) { this.CallingAssembly = callingAssembly; this.Priority = priority; this.Name = text; this.Texture = texture; this.onTriggered = onTriggered; + this.ShowConditionKeys = (showConditionKeys ?? Array.Empty()).ToImmutableSortedSet(); } /// @@ -58,6 +70,11 @@ public class TitleScreenMenuEntry : IComparable /// internal Guid Id { get; init; } = Guid.NewGuid(); + /// + /// Gets the keys that have to be pressed to show the menu. + /// + internal IReadOnlySet ShowConditionKeys { get; init; } + /// public int CompareTo(TitleScreenMenuEntry? other) { @@ -84,6 +101,13 @@ public class TitleScreenMenuEntry : IComparable return 0; } + /// + /// Determines the displaying condition of this menu entry is met. + /// + /// True if met. + internal bool IsShowConditionSatisfied() => + this.ShowConditionKeys.All(x => Service.GetNullable()?[x] is true); + /// /// Trigger the action associated with this entry. ///