Hold Shift to display Toggle Dev Menu TSM entry (#1538)

Co-authored-by: goat <16760685+goaaats@users.noreply.github.com>
This commit is contained in:
srkizer 2023-11-29 06:43:41 +09:00 committed by GitHub
parent d1fad70e8f
commit a71cb81384
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 124 additions and 40 deletions

View file

@ -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<TitleScreenMenu>.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<InterfaceManager.InterfaceManagerWithScene>.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<DalamudInterface>.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);

View file

@ -31,7 +31,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
private readonly GameGui gameGui;
private readonly TitleScreenMenu titleScreenMenu;
private readonly IDalamudTextureWrap shadeTexture;
private readonly Lazy<IDalamudTextureWrap> shadeTexture;
private readonly Dictionary<Guid, InOutCubic> shadeEasings = new();
private readonly Dictionary<Guid, InOutQuint> 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);

View file

@ -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<TitleScreenMenuEntry> entries = new();
private TitleScreenMenuEntry[]? entriesView;
[ServiceManager.ServiceConstructor]
private TitleScreenMenu()
{
}
/// <summary>
/// Event to be called when the entry list has been changed.
/// </summary>
internal event Action? EntryListChange;
/// <inheritdoc/>
public IReadOnlyList<TitleScreenMenuEntry> Entries => this.entries;
public IReadOnlyList<TitleScreenMenuEntry> Entries
{
get
{
lock (this.entries)
{
if (!this.entries.Any())
return Array.Empty<TitleScreenMenuEntry>();
return this.entriesView ??= this.entries.OrderByDescending(x => x.IsInternal).ToArray();
}
}
}
/// <inheritdoc/>
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;
}
/// <inheritdoc/>
@ -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;
}
/// <inheritdoc/>
@ -80,7 +107,10 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu
lock (this.entries)
{
this.entries.Remove(entry);
this.entriesView = null;
}
this.EntryListChange?.InvokeSafely();
}
/// <summary>
@ -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;
}
/// <summary>
@ -116,28 +150,37 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu
/// <param name="text">The text to show.</param>
/// <param name="texture">The texture to show.</param>
/// <param name="onTriggered">The action to execute when the option is selected.</param>
/// <param name="showConditionKeys">The keys that have to be held to display the menu.</param>
/// <returns>A <see cref="TitleScreenMenu"/> object that can be used to manage the entry.</returns>
/// <exception cref="ArgumentException">Thrown when the texture provided does not match the required resolution(64x64).</exception>
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;
}
}

View file

@ -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<TitleScreenMenuEntry>
/// <param name="text">The text to show.</param>
/// <param name="texture">The texture to show.</param>
/// <param name="onTriggered">The action to execute when the option is selected.</param>
internal TitleScreenMenuEntry(Assembly? callingAssembly, ulong priority, string text, IDalamudTextureWrap texture, Action onTriggered)
/// <param name="showConditionKeys">The keys that have to be held to display the menu.</param>
internal TitleScreenMenuEntry(
Assembly? callingAssembly,
ulong priority,
string text,
IDalamudTextureWrap texture,
Action onTriggered,
IEnumerable<VirtualKey>? showConditionKeys = null)
{
this.CallingAssembly = callingAssembly;
this.Priority = priority;
this.Name = text;
this.Texture = texture;
this.onTriggered = onTriggered;
this.ShowConditionKeys = (showConditionKeys ?? Array.Empty<VirtualKey>()).ToImmutableSortedSet();
}
/// <summary>
@ -58,6 +70,11 @@ public class TitleScreenMenuEntry : IComparable<TitleScreenMenuEntry>
/// </summary>
internal Guid Id { get; init; } = Guid.NewGuid();
/// <summary>
/// Gets the keys that have to be pressed to show the menu.
/// </summary>
internal IReadOnlySet<VirtualKey> ShowConditionKeys { get; init; }
/// <inheritdoc/>
public int CompareTo(TitleScreenMenuEntry? other)
{
@ -84,6 +101,13 @@ public class TitleScreenMenuEntry : IComparable<TitleScreenMenuEntry>
return 0;
}
/// <summary>
/// Determines the displaying condition of this menu entry is met.
/// </summary>
/// <returns>True if met.</returns>
internal bool IsShowConditionSatisfied() =>
this.ShowConditionKeys.All(x => Service<KeyState>.GetNullable()?[x] is true);
/// <summary>
/// Trigger the action associated with this entry.
/// </summary>