mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-24 13:41:49 +01:00
refactor(Dalamud): switch to file-scoped namespaces
This commit is contained in:
parent
13cf3d93dc
commit
b5f34c3199
325 changed files with 45878 additions and 46218 deletions
|
|
@ -11,338 +11,337 @@ using Dalamud.Game.Gui;
|
|||
using Dalamud.Plugin.Internal;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Interface.Internal
|
||||
namespace Dalamud.Interface.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// Class handling Dalamud core commands.
|
||||
/// </summary>
|
||||
internal class DalamudCommands
|
||||
{
|
||||
/// <summary>
|
||||
/// Class handling Dalamud core commands.
|
||||
/// Initializes a new instance of the <see cref="DalamudCommands"/> class.
|
||||
/// </summary>
|
||||
internal class DalamudCommands
|
||||
public DalamudCommands()
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DalamudCommands"/> class.
|
||||
/// </summary>
|
||||
public DalamudCommands()
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register all command handlers with the Dalamud instance.
|
||||
/// </summary>
|
||||
public void SetupCommands()
|
||||
{
|
||||
var commandManager = Service<CommandManager>.Get();
|
||||
|
||||
commandManager.AddHandler("/xldclose", new CommandInfo(this.OnUnloadCommand)
|
||||
{
|
||||
}
|
||||
HelpMessage = Loc.Localize("DalamudUnloadHelp", "Unloads XIVLauncher in-game addon."),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Register all command handlers with the Dalamud instance.
|
||||
/// </summary>
|
||||
public void SetupCommands()
|
||||
commandManager.AddHandler("/xldreloadplugins", new CommandInfo(this.OnPluginReloadCommand)
|
||||
{
|
||||
var commandManager = Service<CommandManager>.Get();
|
||||
HelpMessage = Loc.Localize("DalamudPluginReloadHelp", "Reloads all plugins."),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xldclose", new CommandInfo(this.OnUnloadCommand)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudUnloadHelp", "Unloads XIVLauncher in-game addon."),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xldreloadplugins", new CommandInfo(this.OnPluginReloadCommand)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudPluginReloadHelp", "Reloads all plugins."),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xlhelp", new CommandInfo(this.OnHelpCommand)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudCmdInfoHelp", "Shows list of commands available."),
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xlmute", new CommandInfo(this.OnBadWordsAddCommand)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudMuteHelp", "Mute a word or sentence from appearing in chat. Usage: /xlmute <word or sentence>"),
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xlmutelist", new CommandInfo(this.OnBadWordsListCommand)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudMuteListHelp", "List muted words or sentences."),
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xlunmute", new CommandInfo(this.OnBadWordsRemoveCommand)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudUnmuteHelp", "Unmute a word or sentence. Usage: /xlunmute <word or sentence>"),
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/ll", new CommandInfo(this.OnLastLinkCommand)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudLastLinkHelp", "Open the last posted link in your default browser."),
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xlbgmset", new CommandInfo(this.OnBgmSetCommand)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudBgmSetHelp", "Set the Game background music. Usage: /xlbgmset <BGM ID>"),
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xldev", new CommandInfo(this.OnDebugDrawDevMenu)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudDevMenuHelp", "Draw dev menu DEBUG"),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xldata", new CommandInfo(this.OnDebugDrawDataMenu)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudDevDataMenuHelp", "Draw dev data menu DEBUG. Usage: /xldata [Data Dropdown Type]"),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xlime", new CommandInfo(this.OnDebugDrawIMEPanel)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudIMEPanelHelp", "Draw IME panel"),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xllog", new CommandInfo(this.OnOpenLog)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudDevLogHelp", "Open dev log DEBUG"),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xlplugins", new CommandInfo(this.OnOpenInstallerCommand)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudInstallerHelp", "Open the plugin installer"),
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xlcredits", new CommandInfo(this.OnOpenCreditsCommand)
|
||||
{
|
||||
HelpMessage = Loc.Localize("DalamudCreditsHelp", "Opens the credits for dalamud."),
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xllanguage", new CommandInfo(this.OnSetLanguageCommand)
|
||||
{
|
||||
HelpMessage =
|
||||
Loc.Localize(
|
||||
"DalamudLanguageHelp",
|
||||
"Set the language for the in-game addon and plugins that support it. Available languages: ") +
|
||||
Localization.ApplicableLangCodes.Aggregate("en", (current, code) => current + ", " + code),
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/xlsettings", new CommandInfo(this.OnOpenSettingsCommand)
|
||||
{
|
||||
HelpMessage = Loc.Localize(
|
||||
"DalamudSettingsHelp",
|
||||
"Change various In-Game-Addon settings like chat channels and the discord bot setup."),
|
||||
});
|
||||
|
||||
commandManager.AddHandler("/imdebug", new CommandInfo(this.OnDebugImInfoCommand)
|
||||
{
|
||||
HelpMessage = "ImGui DEBUG",
|
||||
ShowInHelp = false,
|
||||
});
|
||||
}
|
||||
|
||||
private void OnUnloadCommand(string command, string arguments)
|
||||
commandManager.AddHandler("/xlhelp", new CommandInfo(this.OnHelpCommand)
|
||||
{
|
||||
Service<ChatGui>.Get().Print("Unloading...");
|
||||
Service<Dalamud>.Get().Unload();
|
||||
}
|
||||
HelpMessage = Loc.Localize("DalamudCmdInfoHelp", "Shows list of commands available."),
|
||||
});
|
||||
|
||||
private void OnHelpCommand(string command, string arguments)
|
||||
commandManager.AddHandler("/xlmute", new CommandInfo(this.OnBadWordsAddCommand)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
var commandManager = Service<CommandManager>.Get();
|
||||
HelpMessage = Loc.Localize("DalamudMuteHelp", "Mute a word or sentence from appearing in chat. Usage: /xlmute <word or sentence>"),
|
||||
});
|
||||
|
||||
var showDebug = arguments.Contains("debug");
|
||||
|
||||
chatGui.Print(Loc.Localize("DalamudCmdHelpAvailable", "Available commands:"));
|
||||
foreach (var cmd in commandManager.Commands)
|
||||
{
|
||||
if (!cmd.Value.ShowInHelp && !showDebug)
|
||||
continue;
|
||||
|
||||
chatGui.Print($"{cmd.Key}: {cmd.Value.HelpMessage}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPluginReloadCommand(string command, string arguments)
|
||||
commandManager.AddHandler("/xlmutelist", new CommandInfo(this.OnBadWordsListCommand)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
HelpMessage = Loc.Localize("DalamudMuteListHelp", "List muted words or sentences."),
|
||||
});
|
||||
|
||||
chatGui.Print("Reloading...");
|
||||
|
||||
try
|
||||
{
|
||||
Service<PluginManager>.Get().ReloadAllPlugins();
|
||||
chatGui.Print("OK");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Plugin reload failed.");
|
||||
chatGui.PrintError("Reload failed.");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBadWordsAddCommand(string command, string arguments)
|
||||
commandManager.AddHandler("/xlunmute", new CommandInfo(this.OnBadWordsRemoveCommand)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
HelpMessage = Loc.Localize("DalamudUnmuteHelp", "Unmute a word or sentence. Usage: /xlunmute <word or sentence>"),
|
||||
});
|
||||
|
||||
configuration.BadWords ??= new List<string>();
|
||||
|
||||
if (string.IsNullOrEmpty(arguments))
|
||||
{
|
||||
chatGui.Print(Loc.Localize("DalamudMuteNoArgs", "Please provide a word to mute."));
|
||||
return;
|
||||
}
|
||||
|
||||
configuration.BadWords.Add(arguments);
|
||||
|
||||
configuration.Save();
|
||||
|
||||
chatGui.Print(string.Format(Loc.Localize("DalamudMuted", "Muted \"{0}\"."), arguments));
|
||||
}
|
||||
|
||||
private void OnBadWordsListCommand(string command, string arguments)
|
||||
commandManager.AddHandler("/ll", new CommandInfo(this.OnLastLinkCommand)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
HelpMessage = Loc.Localize("DalamudLastLinkHelp", "Open the last posted link in your default browser."),
|
||||
});
|
||||
|
||||
configuration.BadWords ??= new List<string>();
|
||||
|
||||
if (configuration.BadWords.Count == 0)
|
||||
{
|
||||
chatGui.Print(Loc.Localize("DalamudNoneMuted", "No muted words or sentences."));
|
||||
return;
|
||||
}
|
||||
|
||||
configuration.Save();
|
||||
|
||||
foreach (var word in configuration.BadWords)
|
||||
chatGui.Print($"\"{word}\"");
|
||||
}
|
||||
|
||||
private void OnBadWordsRemoveCommand(string command, string arguments)
|
||||
commandManager.AddHandler("/xlbgmset", new CommandInfo(this.OnBgmSetCommand)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
HelpMessage = Loc.Localize("DalamudBgmSetHelp", "Set the Game background music. Usage: /xlbgmset <BGM ID>"),
|
||||
});
|
||||
|
||||
configuration.BadWords ??= new List<string>();
|
||||
|
||||
configuration.BadWords.RemoveAll(x => x == arguments);
|
||||
|
||||
configuration.Save();
|
||||
|
||||
chatGui.Print(string.Format(Loc.Localize("DalamudUnmuted", "Unmuted \"{0}\"."), arguments));
|
||||
}
|
||||
|
||||
private void OnLastLinkCommand(string command, string arguments)
|
||||
commandManager.AddHandler("/xldev", new CommandInfo(this.OnDebugDrawDevMenu)
|
||||
{
|
||||
var chatHandlers = Service<ChatHandlers>.Get();
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
HelpMessage = Loc.Localize("DalamudDevMenuHelp", "Draw dev menu DEBUG"),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
if (string.IsNullOrEmpty(chatHandlers.LastLink))
|
||||
{
|
||||
chatGui.Print(Loc.Localize("DalamudNoLastLink", "No last link..."));
|
||||
return;
|
||||
}
|
||||
|
||||
chatGui.Print(string.Format(Loc.Localize("DalamudOpeningLink", "Opening {0}"), chatHandlers.LastLink));
|
||||
Process.Start(new ProcessStartInfo(chatHandlers.LastLink)
|
||||
{
|
||||
UseShellExecute = true,
|
||||
});
|
||||
}
|
||||
|
||||
private void OnBgmSetCommand(string command, string arguments)
|
||||
commandManager.AddHandler("/xldata", new CommandInfo(this.OnDebugDrawDataMenu)
|
||||
{
|
||||
var gameGui = Service<GameGui>.Get();
|
||||
HelpMessage = Loc.Localize("DalamudDevDataMenuHelp", "Draw dev data menu DEBUG. Usage: /xldata [Data Dropdown Type]"),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
if (ushort.TryParse(arguments, out var value))
|
||||
{
|
||||
gameGui.SetBgm(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Revert to the original BGM by specifying an invalid one
|
||||
gameGui.SetBgm(9999);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDebugDrawDevMenu(string command, string arguments)
|
||||
commandManager.AddHandler("/xlime", new CommandInfo(this.OnDebugDrawIMEPanel)
|
||||
{
|
||||
Service<DalamudInterface>.Get().ToggleDevMenu();
|
||||
}
|
||||
HelpMessage = Loc.Localize("DalamudIMEPanelHelp", "Draw IME panel"),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
private void OnDebugDrawDataMenu(string command, string arguments)
|
||||
commandManager.AddHandler("/xllog", new CommandInfo(this.OnOpenLog)
|
||||
{
|
||||
var dalamudInterface = Service<DalamudInterface>.Get();
|
||||
HelpMessage = Loc.Localize("DalamudDevLogHelp", "Open dev log DEBUG"),
|
||||
ShowInHelp = false,
|
||||
});
|
||||
|
||||
if (string.IsNullOrEmpty(arguments))
|
||||
dalamudInterface.ToggleDataWindow();
|
||||
else
|
||||
dalamudInterface.ToggleDataWindow(arguments);
|
||||
}
|
||||
|
||||
private void OnDebugDrawIMEPanel(string command, string arguments)
|
||||
commandManager.AddHandler("/xlplugins", new CommandInfo(this.OnOpenInstallerCommand)
|
||||
{
|
||||
Service<DalamudInterface>.Get().OpenIMEWindow();
|
||||
}
|
||||
HelpMessage = Loc.Localize("DalamudInstallerHelp", "Open the plugin installer"),
|
||||
});
|
||||
|
||||
private void OnOpenLog(string command, string arguments)
|
||||
commandManager.AddHandler("/xlcredits", new CommandInfo(this.OnOpenCreditsCommand)
|
||||
{
|
||||
Service<DalamudInterface>.Get().ToggleLogWindow();
|
||||
}
|
||||
HelpMessage = Loc.Localize("DalamudCreditsHelp", "Opens the credits for dalamud."),
|
||||
});
|
||||
|
||||
private void OnDebugImInfoCommand(string command, string arguments)
|
||||
commandManager.AddHandler("/xllanguage", new CommandInfo(this.OnSetLanguageCommand)
|
||||
{
|
||||
var io = Service<InterfaceManager>.Get().LastImGuiIoPtr;
|
||||
var info = $"WantCaptureKeyboard: {io.WantCaptureKeyboard}\n";
|
||||
info += $"WantCaptureMouse: {io.WantCaptureMouse}\n";
|
||||
info += $"WantSetMousePos: {io.WantSetMousePos}\n";
|
||||
info += $"WantTextInput: {io.WantTextInput}\n";
|
||||
info += $"WantSaveIniSettings: {io.WantSaveIniSettings}\n";
|
||||
info += $"BackendFlags: {(int)io.BackendFlags}\n";
|
||||
info += $"DeltaTime: {io.DeltaTime}\n";
|
||||
info += $"DisplaySize: {io.DisplaySize.X} {io.DisplaySize.Y}\n";
|
||||
info += $"Framerate: {io.Framerate}\n";
|
||||
info += $"MetricsActiveWindows: {io.MetricsActiveWindows}\n";
|
||||
info += $"MetricsRenderWindows: {io.MetricsRenderWindows}\n";
|
||||
info += $"MousePos: {io.MousePos.X} {io.MousePos.Y}\n";
|
||||
info += $"MouseClicked: {io.MouseClicked}\n";
|
||||
info += $"MouseDown: {io.MouseDown}\n";
|
||||
info += $"NavActive: {io.NavActive}\n";
|
||||
info += $"NavVisible: {io.NavVisible}\n";
|
||||
HelpMessage =
|
||||
Loc.Localize(
|
||||
"DalamudLanguageHelp",
|
||||
"Set the language for the in-game addon and plugins that support it. Available languages: ") +
|
||||
Localization.ApplicableLangCodes.Aggregate("en", (current, code) => current + ", " + code),
|
||||
});
|
||||
|
||||
Log.Information(info);
|
||||
}
|
||||
|
||||
private void OnOpenInstallerCommand(string command, string arguments)
|
||||
commandManager.AddHandler("/xlsettings", new CommandInfo(this.OnOpenSettingsCommand)
|
||||
{
|
||||
Service<DalamudInterface>.Get().TogglePluginInstallerWindow();
|
||||
}
|
||||
HelpMessage = Loc.Localize(
|
||||
"DalamudSettingsHelp",
|
||||
"Change various In-Game-Addon settings like chat channels and the discord bot setup."),
|
||||
});
|
||||
|
||||
private void OnOpenCreditsCommand(string command, string arguments)
|
||||
commandManager.AddHandler("/imdebug", new CommandInfo(this.OnDebugImInfoCommand)
|
||||
{
|
||||
Service<DalamudInterface>.Get().ToggleCreditsWindow();
|
||||
}
|
||||
HelpMessage = "ImGui DEBUG",
|
||||
ShowInHelp = false,
|
||||
});
|
||||
}
|
||||
|
||||
private void OnSetLanguageCommand(string command, string arguments)
|
||||
private void OnUnloadCommand(string command, string arguments)
|
||||
{
|
||||
Service<ChatGui>.Get().Print("Unloading...");
|
||||
Service<Dalamud>.Get().Unload();
|
||||
}
|
||||
|
||||
private void OnHelpCommand(string command, string arguments)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
var commandManager = Service<CommandManager>.Get();
|
||||
|
||||
var showDebug = arguments.Contains("debug");
|
||||
|
||||
chatGui.Print(Loc.Localize("DalamudCmdHelpAvailable", "Available commands:"));
|
||||
foreach (var cmd in commandManager.Commands)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
var localization = Service<Localization>.Get();
|
||||
if (!cmd.Value.ShowInHelp && !showDebug)
|
||||
continue;
|
||||
|
||||
if (Localization.ApplicableLangCodes.Contains(arguments.ToLower()) || arguments.ToLower() == "en")
|
||||
{
|
||||
localization.SetupWithLangCode(arguments.ToLower());
|
||||
configuration.LanguageOverride = arguments.ToLower();
|
||||
|
||||
chatGui.Print(string.Format(Loc.Localize("DalamudLanguageSetTo", "Language set to {0}"), arguments));
|
||||
}
|
||||
else
|
||||
{
|
||||
localization.SetupWithUiCulture();
|
||||
configuration.LanguageOverride = null;
|
||||
|
||||
chatGui.Print(string.Format(Loc.Localize("DalamudLanguageSetTo", "Language set to {0}"), "default"));
|
||||
}
|
||||
|
||||
configuration.Save();
|
||||
}
|
||||
|
||||
private void OnOpenSettingsCommand(string command, string arguments)
|
||||
{
|
||||
Service<DalamudInterface>.Get().ToggleSettingsWindow();
|
||||
chatGui.Print($"{cmd.Key}: {cmd.Value.HelpMessage}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPluginReloadCommand(string command, string arguments)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
|
||||
chatGui.Print("Reloading...");
|
||||
|
||||
try
|
||||
{
|
||||
Service<PluginManager>.Get().ReloadAllPlugins();
|
||||
chatGui.Print("OK");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Plugin reload failed.");
|
||||
chatGui.PrintError("Reload failed.");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBadWordsAddCommand(string command, string arguments)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
configuration.BadWords ??= new List<string>();
|
||||
|
||||
if (string.IsNullOrEmpty(arguments))
|
||||
{
|
||||
chatGui.Print(Loc.Localize("DalamudMuteNoArgs", "Please provide a word to mute."));
|
||||
return;
|
||||
}
|
||||
|
||||
configuration.BadWords.Add(arguments);
|
||||
|
||||
configuration.Save();
|
||||
|
||||
chatGui.Print(string.Format(Loc.Localize("DalamudMuted", "Muted \"{0}\"."), arguments));
|
||||
}
|
||||
|
||||
private void OnBadWordsListCommand(string command, string arguments)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
configuration.BadWords ??= new List<string>();
|
||||
|
||||
if (configuration.BadWords.Count == 0)
|
||||
{
|
||||
chatGui.Print(Loc.Localize("DalamudNoneMuted", "No muted words or sentences."));
|
||||
return;
|
||||
}
|
||||
|
||||
configuration.Save();
|
||||
|
||||
foreach (var word in configuration.BadWords)
|
||||
chatGui.Print($"\"{word}\"");
|
||||
}
|
||||
|
||||
private void OnBadWordsRemoveCommand(string command, string arguments)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
configuration.BadWords ??= new List<string>();
|
||||
|
||||
configuration.BadWords.RemoveAll(x => x == arguments);
|
||||
|
||||
configuration.Save();
|
||||
|
||||
chatGui.Print(string.Format(Loc.Localize("DalamudUnmuted", "Unmuted \"{0}\"."), arguments));
|
||||
}
|
||||
|
||||
private void OnLastLinkCommand(string command, string arguments)
|
||||
{
|
||||
var chatHandlers = Service<ChatHandlers>.Get();
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
|
||||
if (string.IsNullOrEmpty(chatHandlers.LastLink))
|
||||
{
|
||||
chatGui.Print(Loc.Localize("DalamudNoLastLink", "No last link..."));
|
||||
return;
|
||||
}
|
||||
|
||||
chatGui.Print(string.Format(Loc.Localize("DalamudOpeningLink", "Opening {0}"), chatHandlers.LastLink));
|
||||
Process.Start(new ProcessStartInfo(chatHandlers.LastLink)
|
||||
{
|
||||
UseShellExecute = true,
|
||||
});
|
||||
}
|
||||
|
||||
private void OnBgmSetCommand(string command, string arguments)
|
||||
{
|
||||
var gameGui = Service<GameGui>.Get();
|
||||
|
||||
if (ushort.TryParse(arguments, out var value))
|
||||
{
|
||||
gameGui.SetBgm(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Revert to the original BGM by specifying an invalid one
|
||||
gameGui.SetBgm(9999);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDebugDrawDevMenu(string command, string arguments)
|
||||
{
|
||||
Service<DalamudInterface>.Get().ToggleDevMenu();
|
||||
}
|
||||
|
||||
private void OnDebugDrawDataMenu(string command, string arguments)
|
||||
{
|
||||
var dalamudInterface = Service<DalamudInterface>.Get();
|
||||
|
||||
if (string.IsNullOrEmpty(arguments))
|
||||
dalamudInterface.ToggleDataWindow();
|
||||
else
|
||||
dalamudInterface.ToggleDataWindow(arguments);
|
||||
}
|
||||
|
||||
private void OnDebugDrawIMEPanel(string command, string arguments)
|
||||
{
|
||||
Service<DalamudInterface>.Get().OpenIMEWindow();
|
||||
}
|
||||
|
||||
private void OnOpenLog(string command, string arguments)
|
||||
{
|
||||
Service<DalamudInterface>.Get().ToggleLogWindow();
|
||||
}
|
||||
|
||||
private void OnDebugImInfoCommand(string command, string arguments)
|
||||
{
|
||||
var io = Service<InterfaceManager>.Get().LastImGuiIoPtr;
|
||||
var info = $"WantCaptureKeyboard: {io.WantCaptureKeyboard}\n";
|
||||
info += $"WantCaptureMouse: {io.WantCaptureMouse}\n";
|
||||
info += $"WantSetMousePos: {io.WantSetMousePos}\n";
|
||||
info += $"WantTextInput: {io.WantTextInput}\n";
|
||||
info += $"WantSaveIniSettings: {io.WantSaveIniSettings}\n";
|
||||
info += $"BackendFlags: {(int)io.BackendFlags}\n";
|
||||
info += $"DeltaTime: {io.DeltaTime}\n";
|
||||
info += $"DisplaySize: {io.DisplaySize.X} {io.DisplaySize.Y}\n";
|
||||
info += $"Framerate: {io.Framerate}\n";
|
||||
info += $"MetricsActiveWindows: {io.MetricsActiveWindows}\n";
|
||||
info += $"MetricsRenderWindows: {io.MetricsRenderWindows}\n";
|
||||
info += $"MousePos: {io.MousePos.X} {io.MousePos.Y}\n";
|
||||
info += $"MouseClicked: {io.MouseClicked}\n";
|
||||
info += $"MouseDown: {io.MouseDown}\n";
|
||||
info += $"NavActive: {io.NavActive}\n";
|
||||
info += $"NavVisible: {io.NavVisible}\n";
|
||||
|
||||
Log.Information(info);
|
||||
}
|
||||
|
||||
private void OnOpenInstallerCommand(string command, string arguments)
|
||||
{
|
||||
Service<DalamudInterface>.Get().TogglePluginInstallerWindow();
|
||||
}
|
||||
|
||||
private void OnOpenCreditsCommand(string command, string arguments)
|
||||
{
|
||||
Service<DalamudInterface>.Get().ToggleCreditsWindow();
|
||||
}
|
||||
|
||||
private void OnSetLanguageCommand(string command, string arguments)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
var localization = Service<Localization>.Get();
|
||||
|
||||
if (Localization.ApplicableLangCodes.Contains(arguments.ToLower()) || arguments.ToLower() == "en")
|
||||
{
|
||||
localization.SetupWithLangCode(arguments.ToLower());
|
||||
configuration.LanguageOverride = arguments.ToLower();
|
||||
|
||||
chatGui.Print(string.Format(Loc.Localize("DalamudLanguageSetTo", "Language set to {0}"), arguments));
|
||||
}
|
||||
else
|
||||
{
|
||||
localization.SetupWithUiCulture();
|
||||
configuration.LanguageOverride = null;
|
||||
|
||||
chatGui.Print(string.Format(Loc.Localize("DalamudLanguageSetTo", "Language set to {0}"), "default"));
|
||||
}
|
||||
|
||||
configuration.Save();
|
||||
}
|
||||
|
||||
private void OnOpenSettingsCommand(string command, string arguments)
|
||||
{
|
||||
Service<DalamudInterface>.Get().ToggleSettingsWindow();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,22 +1,21 @@
|
|||
namespace Dalamud.Interface.Internal.ManagedAsserts
|
||||
namespace Dalamud.Interface.Internal.ManagedAsserts;
|
||||
|
||||
/// <summary>
|
||||
/// Offsets to various data in ImGui context.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Last updated for ImGui 1.83.
|
||||
/// </remarks>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the unsage instead.")]
|
||||
internal static class ImGuiContextOffsets
|
||||
{
|
||||
/// <summary>
|
||||
/// Offsets to various data in ImGui context.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Last updated for ImGui 1.83.
|
||||
/// </remarks>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the unsage instead.")]
|
||||
internal static class ImGuiContextOffsets
|
||||
{
|
||||
public const int CurrentWindowStackOffset = 0x73A;
|
||||
public const int CurrentWindowStackOffset = 0x73A;
|
||||
|
||||
public const int ColorStackOffset = 0x79C;
|
||||
public const int ColorStackOffset = 0x79C;
|
||||
|
||||
public const int StyleVarStackOffset = 0x7A0;
|
||||
public const int StyleVarStackOffset = 0x7A0;
|
||||
|
||||
public const int FontStackOffset = 0x7A4;
|
||||
public const int FontStackOffset = 0x7A4;
|
||||
|
||||
public const int BeginPopupStackOffset = 0x7B8;
|
||||
}
|
||||
public const int BeginPopupStackOffset = 0x7B8;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,133 +4,132 @@ using ImGuiNET;
|
|||
|
||||
using static Dalamud.NativeFunctions;
|
||||
|
||||
namespace Dalamud.Interface.Internal.ManagedAsserts
|
||||
namespace Dalamud.Interface.Internal.ManagedAsserts;
|
||||
|
||||
/// <summary>
|
||||
/// Report ImGui problems with a MessageBox dialog.
|
||||
/// </summary>
|
||||
internal static class ImGuiManagedAsserts
|
||||
{
|
||||
/// <summary>
|
||||
/// Report ImGui problems with a MessageBox dialog.
|
||||
/// Gets or sets a value indicating whether asserts are enabled for ImGui.
|
||||
/// </summary>
|
||||
internal static class ImGuiManagedAsserts
|
||||
public static bool AssertsEnabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a snapshot of the current ImGui context.
|
||||
/// Should be called before rendering an ImGui frame.
|
||||
/// </summary>
|
||||
/// <returns>A snapshot of the current context.</returns>
|
||||
public static unsafe ImGuiContextSnapshot GetSnapshot()
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether asserts are enabled for ImGui.
|
||||
/// </summary>
|
||||
public static bool AssertsEnabled { get; set; }
|
||||
var contextPtr = ImGui.GetCurrentContext();
|
||||
|
||||
/// <summary>
|
||||
/// Create a snapshot of the current ImGui context.
|
||||
/// Should be called before rendering an ImGui frame.
|
||||
/// </summary>
|
||||
/// <returns>A snapshot of the current context.</returns>
|
||||
public static unsafe ImGuiContextSnapshot GetSnapshot()
|
||||
var styleVarStack = *((int*)contextPtr + ImGuiContextOffsets.StyleVarStackOffset); // ImVector.Size
|
||||
var colorStack = *((int*)contextPtr + ImGuiContextOffsets.ColorStackOffset); // ImVector.Size
|
||||
var fontStack = *((int*)contextPtr + ImGuiContextOffsets.FontStackOffset); // ImVector.Size
|
||||
var popupStack = *((int*)contextPtr + ImGuiContextOffsets.BeginPopupStackOffset); // ImVector.Size
|
||||
var windowStack = *((int*)contextPtr + ImGuiContextOffsets.CurrentWindowStackOffset); // ImVector.Size
|
||||
|
||||
return new ImGuiContextSnapshot
|
||||
{
|
||||
var contextPtr = ImGui.GetCurrentContext();
|
||||
StyleVarStackSize = styleVarStack,
|
||||
ColorStackSize = colorStack,
|
||||
FontStackSize = fontStack,
|
||||
BeginPopupStackSize = popupStack,
|
||||
WindowStackSize = windowStack,
|
||||
};
|
||||
}
|
||||
|
||||
var styleVarStack = *((int*)contextPtr + ImGuiContextOffsets.StyleVarStackOffset); // ImVector.Size
|
||||
var colorStack = *((int*)contextPtr + ImGuiContextOffsets.ColorStackOffset); // ImVector.Size
|
||||
var fontStack = *((int*)contextPtr + ImGuiContextOffsets.FontStackOffset); // ImVector.Size
|
||||
var popupStack = *((int*)contextPtr + ImGuiContextOffsets.BeginPopupStackOffset); // ImVector.Size
|
||||
var windowStack = *((int*)contextPtr + ImGuiContextOffsets.CurrentWindowStackOffset); // ImVector.Size
|
||||
|
||||
return new ImGuiContextSnapshot
|
||||
{
|
||||
StyleVarStackSize = styleVarStack,
|
||||
ColorStackSize = colorStack,
|
||||
FontStackSize = fontStack,
|
||||
BeginPopupStackSize = popupStack,
|
||||
WindowStackSize = windowStack,
|
||||
};
|
||||
/// <summary>
|
||||
/// Compare a snapshot to the current post-draw state and report any errors in a MessageBox dialog.
|
||||
/// </summary>
|
||||
/// <param name="source">The source of any problems, something to blame.</param>
|
||||
/// <param name="before">ImGui context snapshot.</param>
|
||||
public static void ReportProblems(string source, ImGuiContextSnapshot before)
|
||||
{
|
||||
if (!AssertsEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare a snapshot to the current post-draw state and report any errors in a MessageBox dialog.
|
||||
/// </summary>
|
||||
/// <param name="source">The source of any problems, something to blame.</param>
|
||||
/// <param name="before">ImGui context snapshot.</param>
|
||||
public static void ReportProblems(string source, ImGuiContextSnapshot before)
|
||||
var cSnap = GetSnapshot();
|
||||
|
||||
if (before.StyleVarStackSize != cSnap.StyleVarStackSize)
|
||||
{
|
||||
if (!AssertsEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var cSnap = GetSnapshot();
|
||||
|
||||
if (before.StyleVarStackSize != cSnap.StyleVarStackSize)
|
||||
{
|
||||
ShowAssert(source, $"You forgot to pop a style var!\n\nBefore: {before.StyleVarStackSize}, after: {cSnap.StyleVarStackSize}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (before.ColorStackSize != cSnap.ColorStackSize)
|
||||
{
|
||||
ShowAssert(source, $"You forgot to pop a color!\n\nBefore: {before.ColorStackSize}, after: {cSnap.ColorStackSize}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (before.FontStackSize != cSnap.FontStackSize)
|
||||
{
|
||||
ShowAssert(source, $"You forgot to pop a font!\n\nBefore: {before.FontStackSize}, after: {cSnap.FontStackSize}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (before.BeginPopupStackSize != cSnap.BeginPopupStackSize)
|
||||
{
|
||||
ShowAssert(source, $"You forgot to end a popup!\n\nBefore: {before.BeginPopupStackSize}, after: {cSnap.BeginPopupStackSize}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cSnap.WindowStackSize != 1)
|
||||
{
|
||||
if (cSnap.WindowStackSize > 1)
|
||||
{
|
||||
ShowAssert(source, $"Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?\n\ncSnap.WindowStackSize = {cSnap.WindowStackSize}");
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowAssert(source, $"Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?\n\ncSnap.WindowStackSize = {cSnap.WindowStackSize}");
|
||||
}
|
||||
}
|
||||
ShowAssert(source, $"You forgot to pop a style var!\n\nBefore: {before.StyleVarStackSize}, after: {cSnap.StyleVarStackSize}");
|
||||
return;
|
||||
}
|
||||
|
||||
private static void ShowAssert(string source, string message)
|
||||
if (before.ColorStackSize != cSnap.ColorStackSize)
|
||||
{
|
||||
var caption = $"You fucked up";
|
||||
message = $"{message}\n\nSource: {source}\n\nAsserts are now disabled. You may re-enable them.";
|
||||
var flags = MessageBoxType.Ok | MessageBoxType.IconError;
|
||||
|
||||
_ = MessageBoxW(Process.GetCurrentProcess().MainWindowHandle, message, caption, flags);
|
||||
AssertsEnabled = false;
|
||||
ShowAssert(source, $"You forgot to pop a color!\n\nBefore: {before.ColorStackSize}, after: {cSnap.ColorStackSize}");
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A snapshot of various ImGui context properties.
|
||||
/// </summary>
|
||||
public class ImGuiContextSnapshot
|
||||
if (before.FontStackSize != cSnap.FontStackSize)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the ImGui style var stack size.
|
||||
/// </summary>
|
||||
public int StyleVarStackSize { get; init; }
|
||||
ShowAssert(source, $"You forgot to pop a font!\n\nBefore: {before.FontStackSize}, after: {cSnap.FontStackSize}");
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImGui color stack size.
|
||||
/// </summary>
|
||||
public int ColorStackSize { get; init; }
|
||||
if (before.BeginPopupStackSize != cSnap.BeginPopupStackSize)
|
||||
{
|
||||
ShowAssert(source, $"You forgot to end a popup!\n\nBefore: {before.BeginPopupStackSize}, after: {cSnap.BeginPopupStackSize}");
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImGui font stack size.
|
||||
/// </summary>
|
||||
public int FontStackSize { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImGui begin popup stack size.
|
||||
/// </summary>
|
||||
public int BeginPopupStackSize { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImGui window stack size.
|
||||
/// </summary>
|
||||
public int WindowStackSize { get; init; }
|
||||
if (cSnap.WindowStackSize != 1)
|
||||
{
|
||||
if (cSnap.WindowStackSize > 1)
|
||||
{
|
||||
ShowAssert(source, $"Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?\n\ncSnap.WindowStackSize = {cSnap.WindowStackSize}");
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowAssert(source, $"Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?\n\ncSnap.WindowStackSize = {cSnap.WindowStackSize}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ShowAssert(string source, string message)
|
||||
{
|
||||
var caption = $"You fucked up";
|
||||
message = $"{message}\n\nSource: {source}\n\nAsserts are now disabled. You may re-enable them.";
|
||||
var flags = MessageBoxType.Ok | MessageBoxType.IconError;
|
||||
|
||||
_ = MessageBoxW(Process.GetCurrentProcess().MainWindowHandle, message, caption, flags);
|
||||
AssertsEnabled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A snapshot of various ImGui context properties.
|
||||
/// </summary>
|
||||
public class ImGuiContextSnapshot
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the ImGui style var stack size.
|
||||
/// </summary>
|
||||
public int StyleVarStackSize { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImGui color stack size.
|
||||
/// </summary>
|
||||
public int ColorStackSize { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImGui font stack size.
|
||||
/// </summary>
|
||||
public int FontStackSize { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImGui begin popup stack size.
|
||||
/// </summary>
|
||||
public int BeginPopupStackSize { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ImGui window stack size.
|
||||
/// </summary>
|
||||
public int WindowStackSize { get; init; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,306 +7,305 @@ using Dalamud.Interface.Colors;
|
|||
using Dalamud.Utility;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Notifications
|
||||
namespace Dalamud.Interface.Internal.Notifications;
|
||||
|
||||
/// <summary>
|
||||
/// Class handling notifications/toasts in ImGui.
|
||||
/// Ported from https://github.com/patrickcjk/imgui-notify.
|
||||
/// </summary>
|
||||
internal class NotificationManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Class handling notifications/toasts in ImGui.
|
||||
/// Ported from https://github.com/patrickcjk/imgui-notify.
|
||||
/// Value indicating the bottom-left X padding.
|
||||
/// </summary>
|
||||
internal class NotificationManager
|
||||
internal const float NotifyPaddingX = 20.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating the bottom-left Y padding.
|
||||
/// </summary>
|
||||
internal const float NotifyPaddingY = 20.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating the Y padding between each message.
|
||||
/// </summary>
|
||||
internal const float NotifyPaddingMessageY = 10.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating the fade-in and out duration.
|
||||
/// </summary>
|
||||
internal const int NotifyFadeInOutTime = 500;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating the default time until the notification is dismissed.
|
||||
/// </summary>
|
||||
internal const int NotifyDefaultDismiss = 3000;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating the maximum opacity.
|
||||
/// </summary>
|
||||
internal const float NotifyOpacity = 0.82f;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating default window flags for the notifications.
|
||||
/// </summary>
|
||||
internal const ImGuiWindowFlags NotifyToastFlags =
|
||||
ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoInputs |
|
||||
ImGuiWindowFlags.NoNav | ImGuiWindowFlags.NoBringToFrontOnFocus | ImGuiWindowFlags.NoFocusOnAppearing;
|
||||
|
||||
private readonly List<Notification> notifications = new();
|
||||
|
||||
/// <summary>
|
||||
/// Add a notification to the notification queue.
|
||||
/// </summary>
|
||||
/// <param name="content">The content of the notification.</param>
|
||||
/// <param name="title">The title of the notification.</param>
|
||||
/// <param name="type">The type of the notification.</param>
|
||||
/// <param name="msDelay">The time the notification should be displayed for.</param>
|
||||
public void AddNotification(string content, string? title = null, NotificationType type = NotificationType.None, uint msDelay = NotifyDefaultDismiss)
|
||||
{
|
||||
/// <summary>
|
||||
/// Value indicating the bottom-left X padding.
|
||||
/// </summary>
|
||||
internal const float NotifyPaddingX = 20.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating the bottom-left Y padding.
|
||||
/// </summary>
|
||||
internal const float NotifyPaddingY = 20.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating the Y padding between each message.
|
||||
/// </summary>
|
||||
internal const float NotifyPaddingMessageY = 10.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating the fade-in and out duration.
|
||||
/// </summary>
|
||||
internal const int NotifyFadeInOutTime = 500;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating the default time until the notification is dismissed.
|
||||
/// </summary>
|
||||
internal const int NotifyDefaultDismiss = 3000;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating the maximum opacity.
|
||||
/// </summary>
|
||||
internal const float NotifyOpacity = 0.82f;
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating default window flags for the notifications.
|
||||
/// </summary>
|
||||
internal const ImGuiWindowFlags NotifyToastFlags =
|
||||
ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoInputs |
|
||||
ImGuiWindowFlags.NoNav | ImGuiWindowFlags.NoBringToFrontOnFocus | ImGuiWindowFlags.NoFocusOnAppearing;
|
||||
|
||||
private readonly List<Notification> notifications = new();
|
||||
|
||||
/// <summary>
|
||||
/// Add a notification to the notification queue.
|
||||
/// </summary>
|
||||
/// <param name="content">The content of the notification.</param>
|
||||
/// <param name="title">The title of the notification.</param>
|
||||
/// <param name="type">The type of the notification.</param>
|
||||
/// <param name="msDelay">The time the notification should be displayed for.</param>
|
||||
public void AddNotification(string content, string? title = null, NotificationType type = NotificationType.None, uint msDelay = NotifyDefaultDismiss)
|
||||
this.notifications.Add(new Notification
|
||||
{
|
||||
this.notifications.Add(new Notification
|
||||
{
|
||||
Content = content,
|
||||
Title = title,
|
||||
NotificationType = type,
|
||||
DurationMs = msDelay,
|
||||
});
|
||||
}
|
||||
Content = content,
|
||||
Title = title,
|
||||
NotificationType = type,
|
||||
DurationMs = msDelay,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw all currently queued notifications.
|
||||
/// </summary>
|
||||
public void Draw()
|
||||
/// <summary>
|
||||
/// Draw all currently queued notifications.
|
||||
/// </summary>
|
||||
public void Draw()
|
||||
{
|
||||
var viewportSize = ImGuiHelpers.MainViewport.Size;
|
||||
var height = 0f;
|
||||
|
||||
for (var i = 0; i < this.notifications.Count; i++)
|
||||
{
|
||||
var viewportSize = ImGuiHelpers.MainViewport.Size;
|
||||
var height = 0f;
|
||||
var tn = this.notifications.ElementAt(i);
|
||||
|
||||
for (var i = 0; i < this.notifications.Count; i++)
|
||||
if (tn.GetPhase() == Notification.Phase.Expired)
|
||||
{
|
||||
var tn = this.notifications.ElementAt(i);
|
||||
this.notifications.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tn.GetPhase() == Notification.Phase.Expired)
|
||||
{
|
||||
this.notifications.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
var opacity = tn.GetFadePercent();
|
||||
|
||||
var opacity = tn.GetFadePercent();
|
||||
var iconColor = tn.Color;
|
||||
iconColor.W = opacity;
|
||||
|
||||
var iconColor = tn.Color;
|
||||
iconColor.W = opacity;
|
||||
var windowName = $"##NOTIFY{i}";
|
||||
|
||||
var windowName = $"##NOTIFY{i}";
|
||||
ImGuiHelpers.ForceNextWindowMainViewport();
|
||||
ImGui.SetNextWindowBgAlpha(opacity);
|
||||
ImGui.SetNextWindowPos(new Vector2(viewportSize.X - NotifyPaddingX, viewportSize.Y - NotifyPaddingY - height), ImGuiCond.Always, Vector2.One);
|
||||
ImGui.Begin(windowName, NotifyToastFlags);
|
||||
|
||||
ImGuiHelpers.ForceNextWindowMainViewport();
|
||||
ImGui.SetNextWindowBgAlpha(opacity);
|
||||
ImGui.SetNextWindowPos(new Vector2(viewportSize.X - NotifyPaddingX, viewportSize.Y - NotifyPaddingY - height), ImGuiCond.Always, Vector2.One);
|
||||
ImGui.Begin(windowName, NotifyToastFlags);
|
||||
ImGui.PushTextWrapPos(viewportSize.X / 3.0f);
|
||||
|
||||
ImGui.PushTextWrapPos(viewportSize.X / 3.0f);
|
||||
var wasTitleRendered = false;
|
||||
|
||||
var wasTitleRendered = false;
|
||||
if (!tn.Icon.IsNullOrEmpty())
|
||||
{
|
||||
wasTitleRendered = true;
|
||||
ImGui.PushFont(InterfaceManager.IconFont);
|
||||
ImGui.TextColored(iconColor, tn.Icon);
|
||||
ImGui.PopFont();
|
||||
}
|
||||
|
||||
var textColor = ImGuiColors.DalamudWhite;
|
||||
textColor.W = opacity;
|
||||
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, textColor);
|
||||
|
||||
if (!tn.Title.IsNullOrEmpty())
|
||||
{
|
||||
if (!tn.Icon.IsNullOrEmpty())
|
||||
{
|
||||
wasTitleRendered = true;
|
||||
ImGui.PushFont(InterfaceManager.IconFont);
|
||||
ImGui.TextColored(iconColor, tn.Icon);
|
||||
ImGui.PopFont();
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
var textColor = ImGuiColors.DalamudWhite;
|
||||
textColor.W = opacity;
|
||||
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, textColor);
|
||||
|
||||
if (!tn.Title.IsNullOrEmpty())
|
||||
{
|
||||
if (!tn.Icon.IsNullOrEmpty())
|
||||
{
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted(tn.Title);
|
||||
wasTitleRendered = true;
|
||||
}
|
||||
else if (!tn.DefaultTitle.IsNullOrEmpty())
|
||||
{
|
||||
if (!tn.Icon.IsNullOrEmpty())
|
||||
{
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted(tn.DefaultTitle);
|
||||
wasTitleRendered = true;
|
||||
}
|
||||
|
||||
if (wasTitleRendered && !tn.Content.IsNullOrEmpty())
|
||||
{
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 5.0f);
|
||||
}
|
||||
|
||||
if (!tn.Content.IsNullOrEmpty())
|
||||
{
|
||||
if (wasTitleRendered)
|
||||
{
|
||||
ImGui.Separator();
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted(tn.Content);
|
||||
}
|
||||
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
ImGui.PopTextWrapPos();
|
||||
|
||||
height += ImGui.GetWindowHeight() + NotifyPaddingMessageY;
|
||||
|
||||
ImGui.End();
|
||||
ImGui.TextUnformatted(tn.Title);
|
||||
wasTitleRendered = true;
|
||||
}
|
||||
else if (!tn.DefaultTitle.IsNullOrEmpty())
|
||||
{
|
||||
if (!tn.Icon.IsNullOrEmpty())
|
||||
{
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted(tn.DefaultTitle);
|
||||
wasTitleRendered = true;
|
||||
}
|
||||
|
||||
if (wasTitleRendered && !tn.Content.IsNullOrEmpty())
|
||||
{
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 5.0f);
|
||||
}
|
||||
|
||||
if (!tn.Content.IsNullOrEmpty())
|
||||
{
|
||||
if (wasTitleRendered)
|
||||
{
|
||||
ImGui.Separator();
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted(tn.Content);
|
||||
}
|
||||
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
ImGui.PopTextWrapPos();
|
||||
|
||||
height += ImGui.GetWindowHeight() + NotifyPaddingMessageY;
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Container class for notifications.
|
||||
/// </summary>
|
||||
internal class Notification
|
||||
{
|
||||
/// <summary>
|
||||
/// Possible notification phases.
|
||||
/// </summary>
|
||||
internal enum Phase
|
||||
{
|
||||
/// <summary>
|
||||
/// Phase indicating fade-in.
|
||||
/// </summary>
|
||||
FadeIn,
|
||||
|
||||
/// <summary>
|
||||
/// Phase indicating waiting until fade-out.
|
||||
/// </summary>
|
||||
Wait,
|
||||
|
||||
/// <summary>
|
||||
/// Phase indicating fade-out.
|
||||
/// </summary>
|
||||
FadeOut,
|
||||
|
||||
/// <summary>
|
||||
/// Phase indicating that the notification has expired.
|
||||
/// </summary>
|
||||
Expired,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Container class for notifications.
|
||||
/// Gets the type of the notification.
|
||||
/// </summary>
|
||||
internal class Notification
|
||||
internal NotificationType NotificationType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the title of the notification.
|
||||
/// </summary>
|
||||
internal string? Title { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of the notification.
|
||||
/// </summary>
|
||||
internal string Content { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the notification in milliseconds.
|
||||
/// </summary>
|
||||
internal uint DurationMs { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the creation time of the notification.
|
||||
/// </summary>
|
||||
internal DateTime CreationTime { get; init; } = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default color of the notification.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when <see cref="NotificationType"/> is set to an out-of-range value.</exception>
|
||||
internal Vector4 Color => this.NotificationType switch
|
||||
{
|
||||
/// <summary>
|
||||
/// Possible notification phases.
|
||||
/// </summary>
|
||||
internal enum Phase
|
||||
NotificationType.None => ImGuiColors.DalamudWhite,
|
||||
NotificationType.Success => ImGuiColors.HealerGreen,
|
||||
NotificationType.Warning => ImGuiColors.DalamudOrange,
|
||||
NotificationType.Error => ImGuiColors.DalamudRed,
|
||||
NotificationType.Info => ImGuiColors.TankBlue,
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the icon of the notification.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when <see cref="NotificationType"/> is set to an out-of-range value.</exception>
|
||||
internal string? Icon => this.NotificationType switch
|
||||
{
|
||||
NotificationType.None => null,
|
||||
NotificationType.Success => FontAwesomeIcon.CheckCircle.ToIconString(),
|
||||
NotificationType.Warning => FontAwesomeIcon.ExclamationCircle.ToIconString(),
|
||||
NotificationType.Error => FontAwesomeIcon.TimesCircle.ToIconString(),
|
||||
NotificationType.Info => FontAwesomeIcon.InfoCircle.ToIconString(),
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default title of the notification.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when <see cref="NotificationType"/> is set to an out-of-range value.</exception>
|
||||
internal string? DefaultTitle => this.NotificationType switch
|
||||
{
|
||||
NotificationType.None => null,
|
||||
NotificationType.Success => NotificationType.Success.ToString(),
|
||||
NotificationType.Warning => NotificationType.Warning.ToString(),
|
||||
NotificationType.Error => NotificationType.Error.ToString(),
|
||||
NotificationType.Info => NotificationType.Info.ToString(),
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the elapsed time since creating the notification.
|
||||
/// </summary>
|
||||
internal TimeSpan ElapsedTime => DateTime.Now - this.CreationTime;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the phase of the notification.
|
||||
/// </summary>
|
||||
/// <returns>The phase of the notification.</returns>
|
||||
internal Phase GetPhase()
|
||||
{
|
||||
var elapsed = (int)this.ElapsedTime.TotalMilliseconds;
|
||||
|
||||
if (elapsed > NotifyFadeInOutTime + this.DurationMs + NotifyFadeInOutTime)
|
||||
return Phase.Expired;
|
||||
else if (elapsed > NotifyFadeInOutTime + this.DurationMs)
|
||||
return Phase.FadeOut;
|
||||
else if (elapsed > NotifyFadeInOutTime)
|
||||
return Phase.Wait;
|
||||
else
|
||||
return Phase.FadeIn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the opacity of the notification.
|
||||
/// </summary>
|
||||
/// <returns>The opacity, in a range from 0 to 1.</returns>
|
||||
internal float GetFadePercent()
|
||||
{
|
||||
var phase = this.GetPhase();
|
||||
var elapsed = this.ElapsedTime.TotalMilliseconds;
|
||||
|
||||
if (phase == Phase.FadeIn)
|
||||
{
|
||||
/// <summary>
|
||||
/// Phase indicating fade-in.
|
||||
/// </summary>
|
||||
FadeIn,
|
||||
|
||||
/// <summary>
|
||||
/// Phase indicating waiting until fade-out.
|
||||
/// </summary>
|
||||
Wait,
|
||||
|
||||
/// <summary>
|
||||
/// Phase indicating fade-out.
|
||||
/// </summary>
|
||||
FadeOut,
|
||||
|
||||
/// <summary>
|
||||
/// Phase indicating that the notification has expired.
|
||||
/// </summary>
|
||||
Expired,
|
||||
return (float)elapsed / NotifyFadeInOutTime * NotifyOpacity;
|
||||
}
|
||||
else if (phase == Phase.FadeOut)
|
||||
{
|
||||
return (1.0f - (((float)elapsed - NotifyFadeInOutTime - this.DurationMs) /
|
||||
NotifyFadeInOutTime)) * NotifyOpacity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the notification.
|
||||
/// </summary>
|
||||
internal NotificationType NotificationType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the title of the notification.
|
||||
/// </summary>
|
||||
internal string? Title { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of the notification.
|
||||
/// </summary>
|
||||
internal string Content { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the notification in milliseconds.
|
||||
/// </summary>
|
||||
internal uint DurationMs { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the creation time of the notification.
|
||||
/// </summary>
|
||||
internal DateTime CreationTime { get; init; } = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default color of the notification.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when <see cref="NotificationType"/> is set to an out-of-range value.</exception>
|
||||
internal Vector4 Color => this.NotificationType switch
|
||||
{
|
||||
NotificationType.None => ImGuiColors.DalamudWhite,
|
||||
NotificationType.Success => ImGuiColors.HealerGreen,
|
||||
NotificationType.Warning => ImGuiColors.DalamudOrange,
|
||||
NotificationType.Error => ImGuiColors.DalamudRed,
|
||||
NotificationType.Info => ImGuiColors.TankBlue,
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the icon of the notification.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when <see cref="NotificationType"/> is set to an out-of-range value.</exception>
|
||||
internal string? Icon => this.NotificationType switch
|
||||
{
|
||||
NotificationType.None => null,
|
||||
NotificationType.Success => FontAwesomeIcon.CheckCircle.ToIconString(),
|
||||
NotificationType.Warning => FontAwesomeIcon.ExclamationCircle.ToIconString(),
|
||||
NotificationType.Error => FontAwesomeIcon.TimesCircle.ToIconString(),
|
||||
NotificationType.Info => FontAwesomeIcon.InfoCircle.ToIconString(),
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default title of the notification.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Thrown when <see cref="NotificationType"/> is set to an out-of-range value.</exception>
|
||||
internal string? DefaultTitle => this.NotificationType switch
|
||||
{
|
||||
NotificationType.None => null,
|
||||
NotificationType.Success => NotificationType.Success.ToString(),
|
||||
NotificationType.Warning => NotificationType.Warning.ToString(),
|
||||
NotificationType.Error => NotificationType.Error.ToString(),
|
||||
NotificationType.Info => NotificationType.Info.ToString(),
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the elapsed time since creating the notification.
|
||||
/// </summary>
|
||||
internal TimeSpan ElapsedTime => DateTime.Now - this.CreationTime;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the phase of the notification.
|
||||
/// </summary>
|
||||
/// <returns>The phase of the notification.</returns>
|
||||
internal Phase GetPhase()
|
||||
{
|
||||
var elapsed = (int)this.ElapsedTime.TotalMilliseconds;
|
||||
|
||||
if (elapsed > NotifyFadeInOutTime + this.DurationMs + NotifyFadeInOutTime)
|
||||
return Phase.Expired;
|
||||
else if (elapsed > NotifyFadeInOutTime + this.DurationMs)
|
||||
return Phase.FadeOut;
|
||||
else if (elapsed > NotifyFadeInOutTime)
|
||||
return Phase.Wait;
|
||||
else
|
||||
return Phase.FadeIn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the opacity of the notification.
|
||||
/// </summary>
|
||||
/// <returns>The opacity, in a range from 0 to 1.</returns>
|
||||
internal float GetFadePercent()
|
||||
{
|
||||
var phase = this.GetPhase();
|
||||
var elapsed = this.ElapsedTime.TotalMilliseconds;
|
||||
|
||||
if (phase == Phase.FadeIn)
|
||||
{
|
||||
return (float)elapsed / NotifyFadeInOutTime * NotifyOpacity;
|
||||
}
|
||||
else if (phase == Phase.FadeOut)
|
||||
{
|
||||
return (1.0f - (((float)elapsed - NotifyFadeInOutTime - this.DurationMs) /
|
||||
NotifyFadeInOutTime)) * NotifyOpacity;
|
||||
}
|
||||
|
||||
return 1.0f * NotifyOpacity;
|
||||
}
|
||||
return 1.0f * NotifyOpacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,32 @@
|
|||
namespace Dalamud.Interface.Internal.Notifications
|
||||
namespace Dalamud.Interface.Internal.Notifications;
|
||||
|
||||
/// <summary>
|
||||
/// Possible notification types.
|
||||
/// </summary>
|
||||
public enum NotificationType
|
||||
{
|
||||
/// <summary>
|
||||
/// Possible notification types.
|
||||
/// No special type.
|
||||
/// </summary>
|
||||
public enum NotificationType
|
||||
{
|
||||
/// <summary>
|
||||
/// No special type.
|
||||
/// </summary>
|
||||
None,
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Type indicating success.
|
||||
/// </summary>
|
||||
Success,
|
||||
/// <summary>
|
||||
/// Type indicating success.
|
||||
/// </summary>
|
||||
Success,
|
||||
|
||||
/// <summary>
|
||||
/// Type indicating a warning.
|
||||
/// </summary>
|
||||
Warning,
|
||||
/// <summary>
|
||||
/// Type indicating a warning.
|
||||
/// </summary>
|
||||
Warning,
|
||||
|
||||
/// <summary>
|
||||
/// Type indicating an error.
|
||||
/// </summary>
|
||||
Error,
|
||||
/// <summary>
|
||||
/// Type indicating an error.
|
||||
/// </summary>
|
||||
Error,
|
||||
|
||||
/// <summary>
|
||||
/// Type indicating generic information.
|
||||
/// </summary>
|
||||
Info,
|
||||
}
|
||||
/// <summary>
|
||||
/// Type indicating generic information.
|
||||
/// </summary>
|
||||
Info,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,402 +5,401 @@ using System.Linq;
|
|||
using CheapLoc;
|
||||
using Dalamud.Plugin.Internal.Types;
|
||||
|
||||
namespace Dalamud.Interface.Internal
|
||||
namespace Dalamud.Interface.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// Manage category filters for PluginInstallerWindow.
|
||||
/// </summary>
|
||||
internal class PluginCategoryManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Manage category filters for PluginInstallerWindow.
|
||||
/// First categoryId for tag based categories.
|
||||
/// </summary>
|
||||
internal class PluginCategoryManager
|
||||
{
|
||||
/// <summary>
|
||||
/// First categoryId for tag based categories.
|
||||
/// </summary>
|
||||
public const int FirstTagBasedCategoryId = 100;
|
||||
public const int FirstTagBasedCategoryId = 100;
|
||||
|
||||
private readonly CategoryInfo[] categoryList =
|
||||
{
|
||||
new(0, "special.all", () => Locs.Category_All),
|
||||
new(10, "special.devInstalled", () => Locs.Category_DevInstalled),
|
||||
new(11, "special.devIconTester", () => Locs.Category_IconTester),
|
||||
new(FirstTagBasedCategoryId + 0, "other", () => Locs.Category_Other),
|
||||
new(FirstTagBasedCategoryId + 1, "jobs", () => Locs.Category_Jobs),
|
||||
new(FirstTagBasedCategoryId + 2, "ui", () => Locs.Category_UI),
|
||||
new(FirstTagBasedCategoryId + 3, "minigames", () => Locs.Category_MiniGames),
|
||||
new(FirstTagBasedCategoryId + 4, "inventory", () => Locs.Category_Inventory),
|
||||
new(FirstTagBasedCategoryId + 5, "sound", () => Locs.Category_Sound),
|
||||
new(FirstTagBasedCategoryId + 6, "social", () => Locs.Category_Social),
|
||||
new(FirstTagBasedCategoryId + 7, "utility", () => Locs.Category_Utility),
|
||||
private readonly CategoryInfo[] categoryList =
|
||||
{
|
||||
new(0, "special.all", () => Locs.Category_All),
|
||||
new(10, "special.devInstalled", () => Locs.Category_DevInstalled),
|
||||
new(11, "special.devIconTester", () => Locs.Category_IconTester),
|
||||
new(FirstTagBasedCategoryId + 0, "other", () => Locs.Category_Other),
|
||||
new(FirstTagBasedCategoryId + 1, "jobs", () => Locs.Category_Jobs),
|
||||
new(FirstTagBasedCategoryId + 2, "ui", () => Locs.Category_UI),
|
||||
new(FirstTagBasedCategoryId + 3, "minigames", () => Locs.Category_MiniGames),
|
||||
new(FirstTagBasedCategoryId + 4, "inventory", () => Locs.Category_Inventory),
|
||||
new(FirstTagBasedCategoryId + 5, "sound", () => Locs.Category_Sound),
|
||||
new(FirstTagBasedCategoryId + 6, "social", () => Locs.Category_Social),
|
||||
new(FirstTagBasedCategoryId + 7, "utility", () => Locs.Category_Utility),
|
||||
|
||||
// order doesn't matter, all tag driven categories should have Id >= FirstTagBasedCategoryId
|
||||
};
|
||||
};
|
||||
|
||||
private GroupInfo[] groupList =
|
||||
{
|
||||
new(GroupKind.DevTools, () => Locs.Group_DevTools, 10, 11),
|
||||
new(GroupKind.Installed, () => Locs.Group_Installed, 0),
|
||||
new(GroupKind.Available, () => Locs.Group_Available, 0),
|
||||
private GroupInfo[] groupList =
|
||||
{
|
||||
new(GroupKind.DevTools, () => Locs.Group_DevTools, 10, 11),
|
||||
new(GroupKind.Installed, () => Locs.Group_Installed, 0),
|
||||
new(GroupKind.Available, () => Locs.Group_Available, 0),
|
||||
|
||||
// order important, used for drawing, keep in sync with defaults for currentGroupIdx
|
||||
};
|
||||
};
|
||||
|
||||
private int currentGroupIdx = 2;
|
||||
private int currentCategoryIdx = 0;
|
||||
private bool isContentDirty;
|
||||
private int currentGroupIdx = 2;
|
||||
private int currentCategoryIdx = 0;
|
||||
private bool isContentDirty;
|
||||
|
||||
private Dictionary<PluginManifest, int[]> mapPluginCategories = new();
|
||||
private List<int> highlightedCategoryIds = new();
|
||||
private Dictionary<PluginManifest, int[]> mapPluginCategories = new();
|
||||
private List<int> highlightedCategoryIds = new();
|
||||
|
||||
/// <summary>
|
||||
/// Type of category group.
|
||||
/// </summary>
|
||||
public enum GroupKind
|
||||
{
|
||||
/// <summary>
|
||||
/// UI group: dev mode only.
|
||||
/// </summary>
|
||||
DevTools,
|
||||
|
||||
/// <summary>
|
||||
/// Type of category group.
|
||||
/// UI group: installed plugins.
|
||||
/// </summary>
|
||||
public enum GroupKind
|
||||
Installed,
|
||||
|
||||
/// <summary>
|
||||
/// UI group: plugins that can be installed.
|
||||
/// </summary>
|
||||
Available,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of all known categories.
|
||||
/// </summary>
|
||||
public CategoryInfo[] CategoryList => this.categoryList;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of all known UI groups.
|
||||
/// </summary>
|
||||
public GroupInfo[] GroupList => this.groupList;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets current group.
|
||||
/// </summary>
|
||||
public int CurrentGroupIdx
|
||||
{
|
||||
get => this.currentGroupIdx;
|
||||
set
|
||||
{
|
||||
/// <summary>
|
||||
/// UI group: dev mode only.
|
||||
/// </summary>
|
||||
DevTools,
|
||||
|
||||
/// <summary>
|
||||
/// UI group: installed plugins.
|
||||
/// </summary>
|
||||
Installed,
|
||||
|
||||
/// <summary>
|
||||
/// UI group: plugins that can be installed.
|
||||
/// </summary>
|
||||
Available,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of all known categories.
|
||||
/// </summary>
|
||||
public CategoryInfo[] CategoryList => this.categoryList;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of all known UI groups.
|
||||
/// </summary>
|
||||
public GroupInfo[] GroupList => this.groupList;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets current group.
|
||||
/// </summary>
|
||||
public int CurrentGroupIdx
|
||||
{
|
||||
get => this.currentGroupIdx;
|
||||
set
|
||||
{
|
||||
if (this.currentGroupIdx != value)
|
||||
{
|
||||
this.currentGroupIdx = value;
|
||||
this.currentCategoryIdx = 0;
|
||||
this.isContentDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets current category, index in current Group.Categories array.
|
||||
/// </summary>
|
||||
public int CurrentCategoryIdx
|
||||
{
|
||||
get => this.currentCategoryIdx;
|
||||
set
|
||||
{
|
||||
if (this.currentCategoryIdx != value)
|
||||
{
|
||||
this.currentCategoryIdx = value;
|
||||
this.isContentDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether current group + category selection changed recently.
|
||||
/// Changes in Available group should be followed with <see cref="GetCurrentCategoryContent"/>, everythine else can use <see cref="ResetContentDirty"/>.
|
||||
/// </summary>
|
||||
public bool IsContentDirty => this.isContentDirty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether <see cref="CurrentCategoryIdx"/> and <see cref="CurrentGroupIdx"/> are valid.
|
||||
/// </summary>
|
||||
public bool IsSelectionValid =>
|
||||
(this.currentGroupIdx >= 0) &&
|
||||
(this.currentGroupIdx < this.groupList.Length) &&
|
||||
(this.currentCategoryIdx >= 0) &&
|
||||
(this.currentCategoryIdx < this.groupList[this.currentGroupIdx].Categories.Count);
|
||||
|
||||
/// <summary>
|
||||
/// Rebuild available categories based on currently available plugins.
|
||||
/// </summary>
|
||||
/// <param name="availablePlugins">list of all available plugin manifests to install.</param>
|
||||
public void BuildCategories(IEnumerable<PluginManifest> availablePlugins)
|
||||
{
|
||||
// rebuild map plugin name -> categoryIds
|
||||
this.mapPluginCategories.Clear();
|
||||
|
||||
var groupAvail = Array.Find(this.groupList, x => x.GroupKind == GroupKind.Available);
|
||||
var prevCategoryIds = new List<int>();
|
||||
prevCategoryIds.AddRange(groupAvail.Categories);
|
||||
|
||||
var categoryList = new List<int>();
|
||||
var allCategoryIndices = new List<int>();
|
||||
|
||||
foreach (var plugin in availablePlugins)
|
||||
{
|
||||
categoryList.Clear();
|
||||
|
||||
var pluginCategoryTags = this.GetCategoryTagsForManifest(plugin);
|
||||
if (pluginCategoryTags != null)
|
||||
{
|
||||
foreach (var tag in pluginCategoryTags)
|
||||
{
|
||||
// only tags from whitelist can be accepted
|
||||
var matchIdx = Array.FindIndex(this.CategoryList, x => x.Tag.Equals(tag, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (matchIdx >= 0)
|
||||
{
|
||||
var categoryId = this.CategoryList[matchIdx].CategoryId;
|
||||
if (categoryId >= FirstTagBasedCategoryId)
|
||||
{
|
||||
categoryList.Add(categoryId);
|
||||
|
||||
if (!allCategoryIndices.Contains(matchIdx))
|
||||
{
|
||||
allCategoryIndices.Add(matchIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// always add, even if empty
|
||||
this.mapPluginCategories.Add(plugin, categoryList.ToArray());
|
||||
}
|
||||
|
||||
// sort all categories by their loc name
|
||||
allCategoryIndices.Sort((idxX, idxY) => this.CategoryList[idxX].Name.CompareTo(this.CategoryList[idxY].Name));
|
||||
|
||||
// rebuild all categories in group, leaving first entry = All intact and always on top
|
||||
if (groupAvail.Categories.Count > 1)
|
||||
{
|
||||
groupAvail.Categories.RemoveRange(1, groupAvail.Categories.Count - 1);
|
||||
}
|
||||
|
||||
foreach (var categoryIdx in allCategoryIndices)
|
||||
{
|
||||
groupAvail.Categories.Add(this.CategoryList[categoryIdx].CategoryId);
|
||||
}
|
||||
|
||||
// compare with prev state and mark as dirty if needed
|
||||
var noCategoryChanges = Enumerable.SequenceEqual(prevCategoryIds, groupAvail.Categories);
|
||||
if (!noCategoryChanges)
|
||||
if (this.currentGroupIdx != value)
|
||||
{
|
||||
this.currentGroupIdx = value;
|
||||
this.currentCategoryIdx = 0;
|
||||
this.isContentDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filters list of available plugins based on currently selected category.
|
||||
/// Resets <see cref="IsContentDirty"/>.
|
||||
/// </summary>
|
||||
/// <param name="plugins">List of available plugins to install.</param>
|
||||
/// <returns>Filtered list of plugins.</returns>
|
||||
public List<PluginManifest> GetCurrentCategoryContent(IEnumerable<PluginManifest> plugins)
|
||||
/// <summary>
|
||||
/// Gets or sets current category, index in current Group.Categories array.
|
||||
/// </summary>
|
||||
public int CurrentCategoryIdx
|
||||
{
|
||||
get => this.currentCategoryIdx;
|
||||
set
|
||||
{
|
||||
var result = new List<PluginManifest>();
|
||||
|
||||
if (this.IsSelectionValid)
|
||||
if (this.currentCategoryIdx != value)
|
||||
{
|
||||
var groupInfo = this.groupList[this.currentGroupIdx];
|
||||
|
||||
var includeAll = (this.currentCategoryIdx == 0) || (groupInfo.GroupKind != GroupKind.Available);
|
||||
if (includeAll)
|
||||
{
|
||||
result.AddRange(plugins);
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedCategoryInfo = Array.Find(this.categoryList, x => x.CategoryId == groupInfo.Categories[this.currentCategoryIdx]);
|
||||
|
||||
foreach (var plugin in plugins)
|
||||
{
|
||||
if (this.mapPluginCategories.TryGetValue(plugin, out var pluginCategoryIds))
|
||||
{
|
||||
var matchIdx = Array.IndexOf(pluginCategoryIds, selectedCategoryInfo.CategoryId);
|
||||
if (matchIdx >= 0)
|
||||
{
|
||||
result.Add(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.currentCategoryIdx = value;
|
||||
this.isContentDirty = true;
|
||||
}
|
||||
|
||||
this.ResetContentDirty();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears <see cref="IsContentDirty"/> flag, indicating that all cached values about currently selected group + category have been updated.
|
||||
/// </summary>
|
||||
public void ResetContentDirty()
|
||||
{
|
||||
this.isContentDirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets category highlight based on list of plugins. Used for searching.
|
||||
/// </summary>
|
||||
/// <param name="plugins">List of plugins whose categories should be highlighted.</param>
|
||||
public void SetCategoryHighlightsForPlugins(IEnumerable<PluginManifest> plugins)
|
||||
{
|
||||
this.highlightedCategoryIds.Clear();
|
||||
|
||||
if (plugins != null)
|
||||
{
|
||||
foreach (var entry in plugins)
|
||||
{
|
||||
if (this.mapPluginCategories.TryGetValue(entry, out var pluginCategories))
|
||||
{
|
||||
foreach (var categoryId in pluginCategories)
|
||||
{
|
||||
if (!this.highlightedCategoryIds.Contains(categoryId))
|
||||
{
|
||||
this.highlightedCategoryIds.Add(categoryId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if category should be highlighted.
|
||||
/// </summary>
|
||||
/// <param name="categoryId">CategoryId to check.</param>
|
||||
/// <returns>true if highlight is needed.</returns>
|
||||
public bool IsCategoryHighlighted(int categoryId) => this.highlightedCategoryIds.Contains(categoryId);
|
||||
|
||||
private IEnumerable<string> GetCategoryTagsForManifest(PluginManifest pluginManifest)
|
||||
{
|
||||
if (pluginManifest.CategoryTags != null)
|
||||
{
|
||||
return pluginManifest.CategoryTags;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin installer category info.
|
||||
/// </summary>
|
||||
public struct CategoryInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique Id number of category, tag match based should be greater of equal <see cref="FirstTagBasedCategoryId"/>.
|
||||
/// </summary>
|
||||
public int CategoryId;
|
||||
|
||||
/// <summary>
|
||||
/// Tag from plugin manifest to match.
|
||||
/// </summary>
|
||||
public string Tag;
|
||||
|
||||
private Func<string> nameFunc;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CategoryInfo"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="categoryId">Unique id of category.</param>
|
||||
/// <param name="tag">Tag to match.</param>
|
||||
/// <param name="nameFunc">Function returning localized name of category.</param>
|
||||
public CategoryInfo(int categoryId, string tag, Func<string> nameFunc)
|
||||
{
|
||||
this.CategoryId = categoryId;
|
||||
this.Tag = tag;
|
||||
this.nameFunc = nameFunc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of category.
|
||||
/// </summary>
|
||||
public string Name => this.nameFunc();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin installer UI group, a container for categories.
|
||||
/// </summary>
|
||||
public struct GroupInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of group.
|
||||
/// </summary>
|
||||
public GroupKind GroupKind;
|
||||
|
||||
/// <summary>
|
||||
/// List of categories in container.
|
||||
/// </summary>
|
||||
public List<int> Categories;
|
||||
|
||||
private Func<string> nameFunc;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GroupInfo"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="groupKind">Type of group.</param>
|
||||
/// <param name="nameFunc">Function returning localized name of category.</param>
|
||||
/// <param name="categories">List of category Ids to hardcode.</param>
|
||||
public GroupInfo(GroupKind groupKind, Func<string> nameFunc, params int[] categories)
|
||||
{
|
||||
this.GroupKind = groupKind;
|
||||
this.nameFunc = nameFunc;
|
||||
|
||||
this.Categories = new();
|
||||
this.Categories.AddRange(categories);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of UI group.
|
||||
/// </summary>
|
||||
public string Name => this.nameFunc();
|
||||
}
|
||||
|
||||
private static class Locs
|
||||
{
|
||||
#region UI groups
|
||||
|
||||
public static string Group_DevTools => Loc.Localize("InstallerDevTools", "Dev Tools");
|
||||
|
||||
public static string Group_Installed => Loc.Localize("InstallerInstalledPlugins", "Installed Plugins");
|
||||
|
||||
public static string Group_Available => Loc.Localize("InstallerAvailablePlugins", "Available Plugins");
|
||||
|
||||
#endregion
|
||||
|
||||
#region Categories
|
||||
|
||||
public static string Category_All => Loc.Localize("InstallerCategoryAll", "All");
|
||||
|
||||
public static string Category_DevInstalled => Loc.Localize("InstallerInstalledDevPlugins", "Installed Dev Plugins");
|
||||
|
||||
public static string Category_IconTester => "Image/Icon Tester";
|
||||
|
||||
public static string Category_Other => Loc.Localize("InstallerCategoryOther", "Other");
|
||||
|
||||
public static string Category_Jobs => Loc.Localize("InstallerCategoryJobs", "Jobs");
|
||||
|
||||
public static string Category_UI => Loc.Localize("InstallerCategoryUI", "UI");
|
||||
|
||||
public static string Category_MiniGames => Loc.Localize("InstallerCategoryMiniGames", "Mini games");
|
||||
|
||||
public static string Category_Inventory => Loc.Localize("InstallerCategoryInventory", "Inventory");
|
||||
|
||||
public static string Category_Sound => Loc.Localize("InstallerCategorySound", "Sound");
|
||||
|
||||
public static string Category_Social => Loc.Localize("InstallerCategorySocial", "Social");
|
||||
|
||||
public static string Category_Utility => Loc.Localize("InstallerCategoryUtility", "Utility");
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether current group + category selection changed recently.
|
||||
/// Changes in Available group should be followed with <see cref="GetCurrentCategoryContent"/>, everythine else can use <see cref="ResetContentDirty"/>.
|
||||
/// </summary>
|
||||
public bool IsContentDirty => this.isContentDirty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether <see cref="CurrentCategoryIdx"/> and <see cref="CurrentGroupIdx"/> are valid.
|
||||
/// </summary>
|
||||
public bool IsSelectionValid =>
|
||||
(this.currentGroupIdx >= 0) &&
|
||||
(this.currentGroupIdx < this.groupList.Length) &&
|
||||
(this.currentCategoryIdx >= 0) &&
|
||||
(this.currentCategoryIdx < this.groupList[this.currentGroupIdx].Categories.Count);
|
||||
|
||||
/// <summary>
|
||||
/// Rebuild available categories based on currently available plugins.
|
||||
/// </summary>
|
||||
/// <param name="availablePlugins">list of all available plugin manifests to install.</param>
|
||||
public void BuildCategories(IEnumerable<PluginManifest> availablePlugins)
|
||||
{
|
||||
// rebuild map plugin name -> categoryIds
|
||||
this.mapPluginCategories.Clear();
|
||||
|
||||
var groupAvail = Array.Find(this.groupList, x => x.GroupKind == GroupKind.Available);
|
||||
var prevCategoryIds = new List<int>();
|
||||
prevCategoryIds.AddRange(groupAvail.Categories);
|
||||
|
||||
var categoryList = new List<int>();
|
||||
var allCategoryIndices = new List<int>();
|
||||
|
||||
foreach (var plugin in availablePlugins)
|
||||
{
|
||||
categoryList.Clear();
|
||||
|
||||
var pluginCategoryTags = this.GetCategoryTagsForManifest(plugin);
|
||||
if (pluginCategoryTags != null)
|
||||
{
|
||||
foreach (var tag in pluginCategoryTags)
|
||||
{
|
||||
// only tags from whitelist can be accepted
|
||||
var matchIdx = Array.FindIndex(this.CategoryList, x => x.Tag.Equals(tag, StringComparison.InvariantCultureIgnoreCase));
|
||||
if (matchIdx >= 0)
|
||||
{
|
||||
var categoryId = this.CategoryList[matchIdx].CategoryId;
|
||||
if (categoryId >= FirstTagBasedCategoryId)
|
||||
{
|
||||
categoryList.Add(categoryId);
|
||||
|
||||
if (!allCategoryIndices.Contains(matchIdx))
|
||||
{
|
||||
allCategoryIndices.Add(matchIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// always add, even if empty
|
||||
this.mapPluginCategories.Add(plugin, categoryList.ToArray());
|
||||
}
|
||||
|
||||
// sort all categories by their loc name
|
||||
allCategoryIndices.Sort((idxX, idxY) => this.CategoryList[idxX].Name.CompareTo(this.CategoryList[idxY].Name));
|
||||
|
||||
// rebuild all categories in group, leaving first entry = All intact and always on top
|
||||
if (groupAvail.Categories.Count > 1)
|
||||
{
|
||||
groupAvail.Categories.RemoveRange(1, groupAvail.Categories.Count - 1);
|
||||
}
|
||||
|
||||
foreach (var categoryIdx in allCategoryIndices)
|
||||
{
|
||||
groupAvail.Categories.Add(this.CategoryList[categoryIdx].CategoryId);
|
||||
}
|
||||
|
||||
// compare with prev state and mark as dirty if needed
|
||||
var noCategoryChanges = Enumerable.SequenceEqual(prevCategoryIds, groupAvail.Categories);
|
||||
if (!noCategoryChanges)
|
||||
{
|
||||
this.isContentDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filters list of available plugins based on currently selected category.
|
||||
/// Resets <see cref="IsContentDirty"/>.
|
||||
/// </summary>
|
||||
/// <param name="plugins">List of available plugins to install.</param>
|
||||
/// <returns>Filtered list of plugins.</returns>
|
||||
public List<PluginManifest> GetCurrentCategoryContent(IEnumerable<PluginManifest> plugins)
|
||||
{
|
||||
var result = new List<PluginManifest>();
|
||||
|
||||
if (this.IsSelectionValid)
|
||||
{
|
||||
var groupInfo = this.groupList[this.currentGroupIdx];
|
||||
|
||||
var includeAll = (this.currentCategoryIdx == 0) || (groupInfo.GroupKind != GroupKind.Available);
|
||||
if (includeAll)
|
||||
{
|
||||
result.AddRange(plugins);
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedCategoryInfo = Array.Find(this.categoryList, x => x.CategoryId == groupInfo.Categories[this.currentCategoryIdx]);
|
||||
|
||||
foreach (var plugin in plugins)
|
||||
{
|
||||
if (this.mapPluginCategories.TryGetValue(plugin, out var pluginCategoryIds))
|
||||
{
|
||||
var matchIdx = Array.IndexOf(pluginCategoryIds, selectedCategoryInfo.CategoryId);
|
||||
if (matchIdx >= 0)
|
||||
{
|
||||
result.Add(plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.ResetContentDirty();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears <see cref="IsContentDirty"/> flag, indicating that all cached values about currently selected group + category have been updated.
|
||||
/// </summary>
|
||||
public void ResetContentDirty()
|
||||
{
|
||||
this.isContentDirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets category highlight based on list of plugins. Used for searching.
|
||||
/// </summary>
|
||||
/// <param name="plugins">List of plugins whose categories should be highlighted.</param>
|
||||
public void SetCategoryHighlightsForPlugins(IEnumerable<PluginManifest> plugins)
|
||||
{
|
||||
this.highlightedCategoryIds.Clear();
|
||||
|
||||
if (plugins != null)
|
||||
{
|
||||
foreach (var entry in plugins)
|
||||
{
|
||||
if (this.mapPluginCategories.TryGetValue(entry, out var pluginCategories))
|
||||
{
|
||||
foreach (var categoryId in pluginCategories)
|
||||
{
|
||||
if (!this.highlightedCategoryIds.Contains(categoryId))
|
||||
{
|
||||
this.highlightedCategoryIds.Add(categoryId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if category should be highlighted.
|
||||
/// </summary>
|
||||
/// <param name="categoryId">CategoryId to check.</param>
|
||||
/// <returns>true if highlight is needed.</returns>
|
||||
public bool IsCategoryHighlighted(int categoryId) => this.highlightedCategoryIds.Contains(categoryId);
|
||||
|
||||
private IEnumerable<string> GetCategoryTagsForManifest(PluginManifest pluginManifest)
|
||||
{
|
||||
if (pluginManifest.CategoryTags != null)
|
||||
{
|
||||
return pluginManifest.CategoryTags;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin installer category info.
|
||||
/// </summary>
|
||||
public struct CategoryInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique Id number of category, tag match based should be greater of equal <see cref="FirstTagBasedCategoryId"/>.
|
||||
/// </summary>
|
||||
public int CategoryId;
|
||||
|
||||
/// <summary>
|
||||
/// Tag from plugin manifest to match.
|
||||
/// </summary>
|
||||
public string Tag;
|
||||
|
||||
private Func<string> nameFunc;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CategoryInfo"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="categoryId">Unique id of category.</param>
|
||||
/// <param name="tag">Tag to match.</param>
|
||||
/// <param name="nameFunc">Function returning localized name of category.</param>
|
||||
public CategoryInfo(int categoryId, string tag, Func<string> nameFunc)
|
||||
{
|
||||
this.CategoryId = categoryId;
|
||||
this.Tag = tag;
|
||||
this.nameFunc = nameFunc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of category.
|
||||
/// </summary>
|
||||
public string Name => this.nameFunc();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin installer UI group, a container for categories.
|
||||
/// </summary>
|
||||
public struct GroupInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of group.
|
||||
/// </summary>
|
||||
public GroupKind GroupKind;
|
||||
|
||||
/// <summary>
|
||||
/// List of categories in container.
|
||||
/// </summary>
|
||||
public List<int> Categories;
|
||||
|
||||
private Func<string> nameFunc;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GroupInfo"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="groupKind">Type of group.</param>
|
||||
/// <param name="nameFunc">Function returning localized name of category.</param>
|
||||
/// <param name="categories">List of category Ids to hardcode.</param>
|
||||
public GroupInfo(GroupKind groupKind, Func<string> nameFunc, params int[] categories)
|
||||
{
|
||||
this.GroupKind = groupKind;
|
||||
this.nameFunc = nameFunc;
|
||||
|
||||
this.Categories = new();
|
||||
this.Categories.AddRange(categories);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of UI group.
|
||||
/// </summary>
|
||||
public string Name => this.nameFunc();
|
||||
}
|
||||
|
||||
private static class Locs
|
||||
{
|
||||
#region UI groups
|
||||
|
||||
public static string Group_DevTools => Loc.Localize("InstallerDevTools", "Dev Tools");
|
||||
|
||||
public static string Group_Installed => Loc.Localize("InstallerInstalledPlugins", "Installed Plugins");
|
||||
|
||||
public static string Group_Available => Loc.Localize("InstallerAvailablePlugins", "Available Plugins");
|
||||
|
||||
#endregion
|
||||
|
||||
#region Categories
|
||||
|
||||
public static string Category_All => Loc.Localize("InstallerCategoryAll", "All");
|
||||
|
||||
public static string Category_DevInstalled => Loc.Localize("InstallerInstalledDevPlugins", "Installed Dev Plugins");
|
||||
|
||||
public static string Category_IconTester => "Image/Icon Tester";
|
||||
|
||||
public static string Category_Other => Loc.Localize("InstallerCategoryOther", "Other");
|
||||
|
||||
public static string Category_Jobs => Loc.Localize("InstallerCategoryJobs", "Jobs");
|
||||
|
||||
public static string Category_UI => Loc.Localize("InstallerCategoryUI", "UI");
|
||||
|
||||
public static string Category_MiniGames => Loc.Localize("InstallerCategoryMiniGames", "Mini games");
|
||||
|
||||
public static string Category_Inventory => Loc.Localize("InstallerCategoryInventory", "Inventory");
|
||||
|
||||
public static string Category_Sound => Loc.Localize("InstallerCategorySound", "Sound");
|
||||
|
||||
public static string Category_Social => Loc.Localize("InstallerCategorySocial", "Social");
|
||||
|
||||
public static string Category_Utility => Loc.Localize("InstallerCategoryUtility", "Utility");
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -6,20 +6,20 @@ using Dalamud.Interface.Windowing;
|
|||
using Dalamud.Utility;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows
|
||||
namespace Dalamud.Interface.Internal.Windows;
|
||||
|
||||
/// <summary>
|
||||
/// For major updates, an in-game Changelog window.
|
||||
/// </summary>
|
||||
internal sealed class ChangelogWindow : Window
|
||||
{
|
||||
/// <summary>
|
||||
/// For major updates, an in-game Changelog window.
|
||||
/// Whether the latest update warrants a changelog window.
|
||||
/// </summary>
|
||||
internal sealed class ChangelogWindow : Window
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the latest update warrants a changelog window.
|
||||
/// </summary>
|
||||
public const string WarrantsChangelogForMajorMinor = "6.0.";
|
||||
public const string WarrantsChangelogForMajorMinor = "6.0.";
|
||||
|
||||
private const string ChangeLog =
|
||||
@"This is the biggest update of the in-game addon to date.
|
||||
private const string ChangeLog =
|
||||
@"This is the biggest update of the in-game addon to date.
|
||||
We have redone most of the underlying systems, providing you with a better experience playing and browsing for plugins, including better performance, and developers with a better API and more comfortable development environment.
|
||||
|
||||
We have also added some new features:
|
||||
|
|
@ -29,100 +29,99 @@ We have also added some new features:
|
|||
|
||||
If you note any issues or need help, please make sure to ask on our discord server.";
|
||||
|
||||
private const string UpdatePluginsInfo =
|
||||
@"• All of your plugins were disabled automatically, due to this update. This is normal.
|
||||
private const string UpdatePluginsInfo =
|
||||
@"• All of your plugins were disabled automatically, due to this update. This is normal.
|
||||
• Open the plugin installer, then click 'update plugins'. Updated plugins should update and then re-enable themselves.
|
||||
=> Please keep in mind that not all of your plugins may already be updated for the new version.
|
||||
=> If some plugins are displayed with a red cross in the 'Installed Plugins' tab, they may not yet be available.";
|
||||
|
||||
private readonly string assemblyVersion = Util.AssemblyVersion;
|
||||
private readonly string assemblyVersion = Util.AssemblyVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ChangelogWindow"/> class.
|
||||
/// </summary>
|
||||
public ChangelogWindow()
|
||||
: base("What's new in XIVLauncher?")
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ChangelogWindow"/> class.
|
||||
/// </summary>
|
||||
public ChangelogWindow()
|
||||
: base("What's new in XIVLauncher?")
|
||||
{
|
||||
this.Namespace = "DalamudChangelogWindow";
|
||||
|
||||
this.Size = new Vector2(885, 463);
|
||||
this.SizeCondition = ImGuiCond.Appearing;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
ImGui.Text($"The in-game addon has been updated to version D{this.assemblyVersion}.");
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
ImGui.Text("The following changes were introduced:");
|
||||
ImGui.TextWrapped(ChangeLog);
|
||||
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
|
||||
ImGui.TextColored(ImGuiColors.DalamudRed, " !!! ATTENTION !!!");
|
||||
|
||||
ImGui.TextWrapped(UpdatePluginsInfo);
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
ImGui.Text("Thank you for using our tools!");
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
|
||||
if (ImGui.Button(FontAwesomeIcon.Download.ToIconString()))
|
||||
{
|
||||
this.Namespace = "DalamudChangelogWindow";
|
||||
|
||||
this.Size = new Vector2(885, 463);
|
||||
this.SizeCondition = ImGuiCond.Appearing;
|
||||
Service<DalamudInterface>.Get().OpenPluginInstaller();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.Text($"The in-game addon has been updated to version D{this.assemblyVersion}.");
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
ImGui.Text("The following changes were introduced:");
|
||||
ImGui.TextWrapped(ChangeLog);
|
||||
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
|
||||
ImGui.TextColored(ImGuiColors.DalamudRed, " !!! ATTENTION !!!");
|
||||
|
||||
ImGui.TextWrapped(UpdatePluginsInfo);
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
ImGui.Text("Thank you for using our tools!");
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
|
||||
if (ImGui.Button(FontAwesomeIcon.Download.ToIconString()))
|
||||
{
|
||||
Service<DalamudInterface>.Get().OpenPluginInstaller();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.PopFont();
|
||||
ImGui.SetTooltip("Open Plugin Installer");
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.Button(FontAwesomeIcon.LaughBeam.ToIconString()))
|
||||
{
|
||||
Process.Start("https://discord.gg/3NMcUV5");
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.PopFont();
|
||||
ImGui.SetTooltip("Join our Discord server");
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.Button(FontAwesomeIcon.Globe.ToIconString()))
|
||||
{
|
||||
Process.Start("https://github.com/goatcorp/FFXIVQuickLauncher");
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.PopFont();
|
||||
ImGui.SetTooltip("See our GitHub repository");
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
ImGui.SetTooltip("Open Plugin Installer");
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGuiHelpers.ScaledDummy(20, 0);
|
||||
ImGui.SameLine();
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.Button("Close"))
|
||||
{
|
||||
this.IsOpen = false;
|
||||
}
|
||||
if (ImGui.Button(FontAwesomeIcon.LaughBeam.ToIconString()))
|
||||
{
|
||||
Process.Start("https://discord.gg/3NMcUV5");
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.PopFont();
|
||||
ImGui.SetTooltip("Join our Discord server");
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.Button(FontAwesomeIcon.Globe.ToIconString()))
|
||||
{
|
||||
Process.Start("https://github.com/goatcorp/FFXIVQuickLauncher");
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.PopFont();
|
||||
ImGui.SetTooltip("See our GitHub repository");
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGuiHelpers.ScaledDummy(20, 0);
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.Button("Close"))
|
||||
{
|
||||
this.IsOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,25 +7,25 @@ using Dalamud.Interface.Colors;
|
|||
using Dalamud.Interface.Windowing;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows
|
||||
namespace Dalamud.Interface.Internal.Windows;
|
||||
|
||||
/// <summary>
|
||||
/// Color Demo Window to view custom ImGui colors.
|
||||
/// </summary>
|
||||
internal sealed class ColorDemoWindow : Window
|
||||
{
|
||||
private readonly List<(string Name, Vector4 Color)> colors;
|
||||
|
||||
/// <summary>
|
||||
/// Color Demo Window to view custom ImGui colors.
|
||||
/// Initializes a new instance of the <see cref="ColorDemoWindow"/> class.
|
||||
/// </summary>
|
||||
internal sealed class ColorDemoWindow : Window
|
||||
public ColorDemoWindow()
|
||||
: base("Dalamud Colors Demo")
|
||||
{
|
||||
private readonly List<(string Name, Vector4 Color)> colors;
|
||||
this.Size = new Vector2(600, 500);
|
||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ColorDemoWindow"/> class.
|
||||
/// </summary>
|
||||
public ColorDemoWindow()
|
||||
: base("Dalamud Colors Demo")
|
||||
{
|
||||
this.Size = new Vector2(600, 500);
|
||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
||||
|
||||
this.colors = new List<(string Name, Vector4 Color)>()
|
||||
this.colors = new List<(string Name, Vector4 Color)>()
|
||||
{
|
||||
("DalamudRed", ImGuiColors.DalamudRed),
|
||||
("DalamudGrey", ImGuiColors.DalamudGrey),
|
||||
|
|
@ -47,20 +47,19 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
("ParsedPink", ImGuiColors.ParsedPink),
|
||||
("ParsedGold", ImGuiColors.ParsedGold),
|
||||
}.OrderBy(colorDemo => colorDemo.Name).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
ImGui.Text("This is a collection of UI colors you can use in your plugin.");
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
foreach (var property in typeof(ImGuiColors).GetProperties(BindingFlags.Public | BindingFlags.Static))
|
||||
{
|
||||
ImGui.Text("This is a collection of UI colors you can use in your plugin.");
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
foreach (var property in typeof(ImGuiColors).GetProperties(BindingFlags.Public | BindingFlags.Static))
|
||||
{
|
||||
var color = (Vector4)property.GetValue(null);
|
||||
ImGui.TextColored(color, property.Name);
|
||||
}
|
||||
var color = (Vector4)property.GetValue(null);
|
||||
ImGui.TextColored(color, property.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,154 +9,153 @@ using Dalamud.Interface.Components;
|
|||
using Dalamud.Interface.Windowing;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Component Demo Window to view custom ImGui components.
|
||||
/// </summary>
|
||||
internal sealed class ComponentDemoWindow : Window
|
||||
{
|
||||
private static readonly TimeSpan DefaultEasingTime = new(0, 0, 0, 1700);
|
||||
namespace Dalamud.Interface.Internal.Windows;
|
||||
|
||||
private readonly List<(string Name, Action Demo)> componentDemos;
|
||||
private readonly IReadOnlyList<Easing> easings = new Easing[]
|
||||
{
|
||||
/// <summary>
|
||||
/// Component Demo Window to view custom ImGui components.
|
||||
/// </summary>
|
||||
internal sealed class ComponentDemoWindow : Window
|
||||
{
|
||||
private static readonly TimeSpan DefaultEasingTime = new(0, 0, 0, 1700);
|
||||
|
||||
private readonly List<(string Name, Action Demo)> componentDemos;
|
||||
private readonly IReadOnlyList<Easing> easings = new Easing[]
|
||||
{
|
||||
new InSine(DefaultEasingTime), new OutSine(DefaultEasingTime), new InOutSine(DefaultEasingTime),
|
||||
new InCubic(DefaultEasingTime), new OutCubic(DefaultEasingTime), new InOutCubic(DefaultEasingTime),
|
||||
new InQuint(DefaultEasingTime), new OutQuint(DefaultEasingTime), new InOutQuint(DefaultEasingTime),
|
||||
new InCirc(DefaultEasingTime), new OutCirc(DefaultEasingTime), new InOutCirc(DefaultEasingTime),
|
||||
new InElastic(DefaultEasingTime), new OutElastic(DefaultEasingTime), new InOutElastic(DefaultEasingTime),
|
||||
};
|
||||
};
|
||||
|
||||
private int animationTimeMs = (int)DefaultEasingTime.TotalMilliseconds;
|
||||
private Vector4 defaultColor = ImGuiColors.DalamudOrange;
|
||||
private int animationTimeMs = (int)DefaultEasingTime.TotalMilliseconds;
|
||||
private Vector4 defaultColor = ImGuiColors.DalamudOrange;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ComponentDemoWindow"/> class.
|
||||
/// </summary>
|
||||
public ComponentDemoWindow()
|
||||
: base("Dalamud Components Demo")
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ComponentDemoWindow"/> class.
|
||||
/// </summary>
|
||||
public ComponentDemoWindow()
|
||||
: base("Dalamud Components Demo")
|
||||
{
|
||||
this.Size = new Vector2(600, 500);
|
||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
||||
|
||||
this.RespectCloseHotkey = false;
|
||||
|
||||
this.componentDemos = new()
|
||||
{
|
||||
this.Size = new Vector2(600, 500);
|
||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
||||
("Test", ImGuiComponents.Test),
|
||||
("HelpMarker", HelpMarkerDemo),
|
||||
("IconButton", IconButtonDemo),
|
||||
("TextWithLabel", TextWithLabelDemo),
|
||||
("ColorPickerWithPalette", this.ColorPickerWithPaletteDemo),
|
||||
};
|
||||
}
|
||||
|
||||
this.RespectCloseHotkey = false;
|
||||
/// <inheritdoc/>
|
||||
public override void OnOpen()
|
||||
{
|
||||
foreach (var easing in this.easings)
|
||||
{
|
||||
easing.Restart();
|
||||
}
|
||||
}
|
||||
|
||||
this.componentDemos = new()
|
||||
/// <inheritdoc/>
|
||||
public override void OnClose()
|
||||
{
|
||||
foreach (var easing in this.easings)
|
||||
{
|
||||
easing.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
ImGui.Text("This is a collection of UI components you can use in your plugin.");
|
||||
|
||||
for (var i = 0; i < this.componentDemos.Count; i++)
|
||||
{
|
||||
var componentDemo = this.componentDemos[i];
|
||||
|
||||
if (ImGui.CollapsingHeader($"{componentDemo.Name}###comp{i}"))
|
||||
{
|
||||
("Test", ImGuiComponents.Test),
|
||||
("HelpMarker", HelpMarkerDemo),
|
||||
("IconButton", IconButtonDemo),
|
||||
("TextWithLabel", TextWithLabelDemo),
|
||||
("ColorPickerWithPalette", this.ColorPickerWithPaletteDemo),
|
||||
};
|
||||
componentDemo.Demo();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void OnOpen()
|
||||
if (ImGui.CollapsingHeader("Easing animations"))
|
||||
{
|
||||
foreach (var easing in this.easings)
|
||||
this.EasingsDemo();
|
||||
}
|
||||
}
|
||||
|
||||
private static void HelpMarkerDemo()
|
||||
{
|
||||
ImGui.Text("Hover over the icon to learn more.");
|
||||
ImGuiComponents.HelpMarker("help me!");
|
||||
}
|
||||
|
||||
private static void IconButtonDemo()
|
||||
{
|
||||
ImGui.Text("Click on the icon to use as a button.");
|
||||
ImGui.SameLine();
|
||||
if (ImGuiComponents.IconButton(1, FontAwesomeIcon.Carrot))
|
||||
{
|
||||
ImGui.OpenPopup("IconButtonDemoPopup");
|
||||
}
|
||||
|
||||
if (ImGui.BeginPopup("IconButtonDemoPopup"))
|
||||
{
|
||||
ImGui.Text("You clicked!");
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
private static void TextWithLabelDemo()
|
||||
{
|
||||
ImGuiComponents.TextWithLabel("Label", "Hover to see more", "more");
|
||||
}
|
||||
|
||||
private void EasingsDemo()
|
||||
{
|
||||
ImGui.SliderInt("Speed in MS", ref this.animationTimeMs, 200, 5000);
|
||||
|
||||
foreach (var easing in this.easings)
|
||||
{
|
||||
easing.Duration = new TimeSpan(0, 0, 0, 0, this.animationTimeMs);
|
||||
|
||||
if (!easing.IsRunning)
|
||||
{
|
||||
easing.Start();
|
||||
}
|
||||
|
||||
var cursor = ImGui.GetCursorPos();
|
||||
var p1 = new Vector2(cursor.X + 5, cursor.Y);
|
||||
var p2 = p1 + new Vector2(45, 0);
|
||||
easing.Point1 = p1;
|
||||
easing.Point2 = p2;
|
||||
easing.Update();
|
||||
|
||||
if (easing.IsDone)
|
||||
{
|
||||
easing.Restart();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void OnClose()
|
||||
{
|
||||
foreach (var easing in this.easings)
|
||||
{
|
||||
easing.Stop();
|
||||
}
|
||||
}
|
||||
ImGui.SetCursorPos(easing.EasedPoint);
|
||||
ImGui.Bullet();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
ImGui.Text("This is a collection of UI components you can use in your plugin.");
|
||||
|
||||
for (var i = 0; i < this.componentDemos.Count; i++)
|
||||
{
|
||||
var componentDemo = this.componentDemos[i];
|
||||
|
||||
if (ImGui.CollapsingHeader($"{componentDemo.Name}###comp{i}"))
|
||||
{
|
||||
componentDemo.Demo();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.CollapsingHeader("Easing animations"))
|
||||
{
|
||||
this.EasingsDemo();
|
||||
}
|
||||
}
|
||||
|
||||
private static void HelpMarkerDemo()
|
||||
{
|
||||
ImGui.Text("Hover over the icon to learn more.");
|
||||
ImGuiComponents.HelpMarker("help me!");
|
||||
}
|
||||
|
||||
private static void IconButtonDemo()
|
||||
{
|
||||
ImGui.Text("Click on the icon to use as a button.");
|
||||
ImGui.SameLine();
|
||||
if (ImGuiComponents.IconButton(1, FontAwesomeIcon.Carrot))
|
||||
{
|
||||
ImGui.OpenPopup("IconButtonDemoPopup");
|
||||
}
|
||||
|
||||
if (ImGui.BeginPopup("IconButtonDemoPopup"))
|
||||
{
|
||||
ImGui.Text("You clicked!");
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
private static void TextWithLabelDemo()
|
||||
{
|
||||
ImGuiComponents.TextWithLabel("Label", "Hover to see more", "more");
|
||||
}
|
||||
|
||||
private void EasingsDemo()
|
||||
{
|
||||
ImGui.SliderInt("Speed in MS", ref this.animationTimeMs, 200, 5000);
|
||||
|
||||
foreach (var easing in this.easings)
|
||||
{
|
||||
easing.Duration = new TimeSpan(0, 0, 0, 0, this.animationTimeMs);
|
||||
|
||||
if (!easing.IsRunning)
|
||||
{
|
||||
easing.Start();
|
||||
}
|
||||
|
||||
var cursor = ImGui.GetCursorPos();
|
||||
var p1 = new Vector2(cursor.X + 5, cursor.Y);
|
||||
var p2 = p1 + new Vector2(45, 0);
|
||||
easing.Point1 = p1;
|
||||
easing.Point2 = p2;
|
||||
easing.Update();
|
||||
|
||||
if (easing.IsDone)
|
||||
{
|
||||
easing.Restart();
|
||||
}
|
||||
|
||||
ImGui.SetCursorPos(easing.EasedPoint);
|
||||
ImGui.Bullet();
|
||||
|
||||
ImGui.SetCursorPos(cursor + new Vector2(0, 10));
|
||||
ImGui.Text($"{easing.GetType().Name} ({easing.Value})");
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
}
|
||||
}
|
||||
|
||||
private void ColorPickerWithPaletteDemo()
|
||||
{
|
||||
ImGui.Text("Click on the color button to use the picker.");
|
||||
ImGui.SameLine();
|
||||
this.defaultColor = ImGuiComponents.ColorPickerWithPalette(1, "ColorPickerWithPalette Demo", this.defaultColor);
|
||||
ImGui.SetCursorPos(cursor + new Vector2(0, 10));
|
||||
ImGui.Text($"{easing.GetType().Name} ({easing.Value})");
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
}
|
||||
}
|
||||
|
||||
private void ColorPickerWithPaletteDemo()
|
||||
{
|
||||
ImGui.Text("Click on the color button to use the picker.");
|
||||
ImGui.SameLine();
|
||||
this.defaultColor = ImGuiComponents.ColorPickerWithPalette(1, "ColorPickerWithPalette Demo", this.defaultColor);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,488 +16,487 @@ using ImGuiNET;
|
|||
using Serilog;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows
|
||||
namespace Dalamud.Interface.Internal.Windows;
|
||||
|
||||
/// <summary>
|
||||
/// The window that displays the Dalamud log file in-game.
|
||||
/// </summary>
|
||||
internal class ConsoleWindow : Window, IDisposable
|
||||
{
|
||||
private readonly List<LogEntry> logText = new();
|
||||
private readonly object renderLock = new();
|
||||
|
||||
private readonly string[] logLevelStrings = new[] { "None", "Verbose", "Debug", "Information", "Warning", "Error", "Fatal" };
|
||||
|
||||
private List<LogEntry> filteredLogText = new();
|
||||
private bool autoScroll;
|
||||
private bool openAtStartup;
|
||||
|
||||
private bool? lastCmdSuccess;
|
||||
|
||||
private string commandText = string.Empty;
|
||||
|
||||
private string textFilter = string.Empty;
|
||||
private LogEventLevel? levelFilter = null;
|
||||
private bool isFiltered = false;
|
||||
|
||||
private int historyPos;
|
||||
private List<string> history = new();
|
||||
|
||||
/// <summary>
|
||||
/// The window that displays the Dalamud log file in-game.
|
||||
/// Initializes a new instance of the <see cref="ConsoleWindow"/> class.
|
||||
/// </summary>
|
||||
internal class ConsoleWindow : Window, IDisposable
|
||||
public ConsoleWindow()
|
||||
: base("Dalamud Console")
|
||||
{
|
||||
private readonly List<LogEntry> logText = new();
|
||||
private readonly object renderLock = new();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
private readonly string[] logLevelStrings = new[] { "None", "Verbose", "Debug", "Information", "Warning", "Error", "Fatal" };
|
||||
this.autoScroll = configuration.LogAutoScroll;
|
||||
this.openAtStartup = configuration.LogOpenAtStartup;
|
||||
SerilogEventSink.Instance.LogLine += this.OnLogLine;
|
||||
|
||||
private List<LogEntry> filteredLogText = new();
|
||||
private bool autoScroll;
|
||||
private bool openAtStartup;
|
||||
this.Size = new Vector2(500, 400);
|
||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
||||
|
||||
private bool? lastCmdSuccess;
|
||||
this.RespectCloseHotkey = false;
|
||||
}
|
||||
|
||||
private string commandText = string.Empty;
|
||||
private List<LogEntry> LogEntries => this.isFiltered ? this.filteredLogText : this.logText;
|
||||
|
||||
private string textFilter = string.Empty;
|
||||
private LogEventLevel? levelFilter = null;
|
||||
private bool isFiltered = false;
|
||||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
SerilogEventSink.Instance.LogLine -= this.OnLogLine;
|
||||
}
|
||||
|
||||
private int historyPos;
|
||||
private List<string> history = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConsoleWindow"/> class.
|
||||
/// </summary>
|
||||
public ConsoleWindow()
|
||||
: base("Dalamud Console")
|
||||
/// <summary>
|
||||
/// Clear the window of all log entries.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
lock (this.renderLock)
|
||||
{
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
this.autoScroll = configuration.LogAutoScroll;
|
||||
this.openAtStartup = configuration.LogOpenAtStartup;
|
||||
SerilogEventSink.Instance.LogLine += this.OnLogLine;
|
||||
|
||||
this.Size = new Vector2(500, 400);
|
||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
||||
|
||||
this.RespectCloseHotkey = false;
|
||||
this.logText.Clear();
|
||||
this.filteredLogText.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private List<LogEntry> LogEntries => this.isFiltered ? this.filteredLogText : this.logText;
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
/// <summary>
|
||||
/// Add a single log line to the display.
|
||||
/// </summary>
|
||||
/// <param name="line">The line to add.</param>
|
||||
/// <param name="level">The level of the event.</param>
|
||||
/// <param name="offset">The <see cref="DateTimeOffset"/> of the event.</param>
|
||||
public void HandleLogLine(string line, LogEventLevel level, DateTimeOffset offset)
|
||||
{
|
||||
if (line.IndexOfAny(new[] { '\n', '\r' }) != -1)
|
||||
{
|
||||
SerilogEventSink.Instance.LogLine -= this.OnLogLine;
|
||||
}
|
||||
var subLines = line.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
/// <summary>
|
||||
/// Clear the window of all log entries.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
lock (this.renderLock)
|
||||
this.AddAndFilter(subLines[0], level, offset, false);
|
||||
|
||||
for (var i = 1; i < subLines.Length; i++)
|
||||
{
|
||||
this.logText.Clear();
|
||||
this.filteredLogText.Clear();
|
||||
this.AddAndFilter(subLines[i], level, offset, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a single log line to the display.
|
||||
/// </summary>
|
||||
/// <param name="line">The line to add.</param>
|
||||
/// <param name="level">The level of the event.</param>
|
||||
/// <param name="offset">The <see cref="DateTimeOffset"/> of the event.</param>
|
||||
public void HandleLogLine(string line, LogEventLevel level, DateTimeOffset offset)
|
||||
else
|
||||
{
|
||||
if (line.IndexOfAny(new[] { '\n', '\r' }) != -1)
|
||||
this.AddAndFilter(line, level, offset, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
// Options menu
|
||||
if (ImGui.BeginPopup("Options"))
|
||||
{
|
||||
var dalamud = Service<Dalamud>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
if (ImGui.Checkbox("Auto-scroll", ref this.autoScroll))
|
||||
{
|
||||
var subLines = line.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
configuration.LogAutoScroll = this.autoScroll;
|
||||
configuration.Save();
|
||||
}
|
||||
|
||||
this.AddAndFilter(subLines[0], level, offset, false);
|
||||
if (ImGui.Checkbox("Open at startup", ref this.openAtStartup))
|
||||
{
|
||||
configuration.LogOpenAtStartup = this.openAtStartup;
|
||||
configuration.Save();
|
||||
}
|
||||
|
||||
for (var i = 1; i < subLines.Length; i++)
|
||||
var prevLevel = (int)dalamud.LogLevelSwitch.MinimumLevel;
|
||||
if (ImGui.Combo("Log Level", ref prevLevel, Enum.GetValues(typeof(LogEventLevel)).Cast<LogEventLevel>().Select(x => x.ToString()).ToArray(), 6))
|
||||
{
|
||||
dalamud.LogLevelSwitch.MinimumLevel = (LogEventLevel)prevLevel;
|
||||
configuration.LogLevel = (LogEventLevel)prevLevel;
|
||||
configuration.Save();
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
// Filter menu
|
||||
if (ImGui.BeginPopup("Filters"))
|
||||
{
|
||||
ImGui.Checkbox("Enabled", ref this.isFiltered);
|
||||
|
||||
if (ImGui.InputTextWithHint("##filterText", "Text Filter", ref this.textFilter, 255, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
this.Refilter();
|
||||
}
|
||||
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, "Enter to confirm.");
|
||||
|
||||
var filterVal = this.levelFilter.HasValue ? (int)this.levelFilter.Value + 1 : 0;
|
||||
if (ImGui.Combo("Level", ref filterVal, this.logLevelStrings, 7))
|
||||
{
|
||||
this.levelFilter = (LogEventLevel)(filterVal - 1);
|
||||
this.Refilter();
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Cog))
|
||||
ImGui.OpenPopup("Options");
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Options");
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Search))
|
||||
ImGui.OpenPopup("Filters");
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Filters");
|
||||
|
||||
ImGui.SameLine();
|
||||
var clear = ImGuiComponents.IconButton(FontAwesomeIcon.Trash);
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Clear Log");
|
||||
|
||||
ImGui.SameLine();
|
||||
var copy = ImGuiComponents.IconButton(FontAwesomeIcon.Copy);
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Copy Log");
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Skull))
|
||||
Process.GetCurrentProcess().Kill();
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Kill game");
|
||||
|
||||
ImGui.BeginChild("scrolling", new Vector2(0, ImGui.GetFrameHeightWithSpacing() - 55), false, ImGuiWindowFlags.AlwaysHorizontalScrollbar | ImGuiWindowFlags.AlwaysVerticalScrollbar);
|
||||
|
||||
if (clear)
|
||||
{
|
||||
this.Clear();
|
||||
}
|
||||
|
||||
if (copy)
|
||||
{
|
||||
ImGui.LogToClipboard();
|
||||
}
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
|
||||
|
||||
ImGuiListClipperPtr clipper;
|
||||
unsafe
|
||||
{
|
||||
clipper = new ImGuiListClipperPtr(ImGuiNative.ImGuiListClipper_ImGuiListClipper());
|
||||
}
|
||||
|
||||
ImGui.PushFont(InterfaceManager.MonoFont);
|
||||
|
||||
var childPos = ImGui.GetWindowPos();
|
||||
var childDrawList = ImGui.GetWindowDrawList();
|
||||
var childSize = ImGui.GetWindowSize();
|
||||
|
||||
var cursorDiv = ImGuiHelpers.GlobalScale * 92;
|
||||
var cursorLogLevel = ImGuiHelpers.GlobalScale * 100;
|
||||
var cursorLogLine = ImGuiHelpers.GlobalScale * 135;
|
||||
|
||||
lock (this.renderLock)
|
||||
{
|
||||
clipper.Begin(this.LogEntries.Count);
|
||||
while (clipper.Step())
|
||||
{
|
||||
for (var i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
|
||||
{
|
||||
this.AddAndFilter(subLines[i], level, offset, true);
|
||||
var line = this.LogEntries[i];
|
||||
|
||||
if (!line.IsMultiline)
|
||||
ImGui.Separator();
|
||||
|
||||
ImGui.PushStyleColor(ImGuiCol.Header, this.GetColorForLogEventLevel(line.Level));
|
||||
ImGui.PushStyleColor(ImGuiCol.HeaderActive, this.GetColorForLogEventLevel(line.Level));
|
||||
ImGui.PushStyleColor(ImGuiCol.HeaderHovered, this.GetColorForLogEventLevel(line.Level));
|
||||
|
||||
ImGui.Selectable("###consolenull", true, ImGuiSelectableFlags.AllowItemOverlap | ImGuiSelectableFlags.SpanAllColumns);
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.PopStyleColor(3);
|
||||
|
||||
if (!line.IsMultiline)
|
||||
{
|
||||
ImGui.TextUnformatted(line.TimeStamp.ToString("HH:mm:ss.fff"));
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosX(cursorDiv);
|
||||
ImGui.TextUnformatted("|");
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosX(cursorLogLevel);
|
||||
ImGui.TextUnformatted(this.GetTextForLogEventLevel(line.Level));
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
ImGui.SetCursorPosX(cursorLogLine);
|
||||
ImGui.TextUnformatted(line.Line);
|
||||
}
|
||||
}
|
||||
|
||||
clipper.End();
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
if (this.autoScroll && ImGui.GetScrollY() >= ImGui.GetScrollMaxY())
|
||||
{
|
||||
ImGui.SetScrollHereY(1.0f);
|
||||
}
|
||||
|
||||
// Draw dividing line
|
||||
var offset = ImGuiHelpers.GlobalScale * 127;
|
||||
childDrawList.AddLine(new Vector2(childPos.X + offset, childPos.Y), new Vector2(childPos.X + offset, childPos.Y + childSize.Y), 0x4FFFFFFF, 1.0f);
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
var hadColor = false;
|
||||
if (this.lastCmdSuccess.HasValue)
|
||||
{
|
||||
hadColor = true;
|
||||
if (this.lastCmdSuccess.Value)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.FrameBg, ImGuiColors.HealerGreen - new Vector4(0, 0, 0, 0.7f));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.AddAndFilter(line, level, offset, false);
|
||||
ImGui.PushStyleColor(ImGuiCol.FrameBg, ImGuiColors.DalamudRed - new Vector4(0, 0, 0, 0.7f));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
ImGui.SetNextItemWidth(ImGui.GetWindowSize().X - 80);
|
||||
|
||||
var getFocus = false;
|
||||
unsafe
|
||||
{
|
||||
// Options menu
|
||||
if (ImGui.BeginPopup("Options"))
|
||||
{
|
||||
var dalamud = Service<Dalamud>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
if (ImGui.Checkbox("Auto-scroll", ref this.autoScroll))
|
||||
{
|
||||
configuration.LogAutoScroll = this.autoScroll;
|
||||
configuration.Save();
|
||||
}
|
||||
|
||||
if (ImGui.Checkbox("Open at startup", ref this.openAtStartup))
|
||||
{
|
||||
configuration.LogOpenAtStartup = this.openAtStartup;
|
||||
configuration.Save();
|
||||
}
|
||||
|
||||
var prevLevel = (int)dalamud.LogLevelSwitch.MinimumLevel;
|
||||
if (ImGui.Combo("Log Level", ref prevLevel, Enum.GetValues(typeof(LogEventLevel)).Cast<LogEventLevel>().Select(x => x.ToString()).ToArray(), 6))
|
||||
{
|
||||
dalamud.LogLevelSwitch.MinimumLevel = (LogEventLevel)prevLevel;
|
||||
configuration.LogLevel = (LogEventLevel)prevLevel;
|
||||
configuration.Save();
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
// Filter menu
|
||||
if (ImGui.BeginPopup("Filters"))
|
||||
{
|
||||
ImGui.Checkbox("Enabled", ref this.isFiltered);
|
||||
|
||||
if (ImGui.InputTextWithHint("##filterText", "Text Filter", ref this.textFilter, 255, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
this.Refilter();
|
||||
}
|
||||
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, "Enter to confirm.");
|
||||
|
||||
var filterVal = this.levelFilter.HasValue ? (int)this.levelFilter.Value + 1 : 0;
|
||||
if (ImGui.Combo("Level", ref filterVal, this.logLevelStrings, 7))
|
||||
{
|
||||
this.levelFilter = (LogEventLevel)(filterVal - 1);
|
||||
this.Refilter();
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Cog))
|
||||
ImGui.OpenPopup("Options");
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Options");
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Search))
|
||||
ImGui.OpenPopup("Filters");
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Filters");
|
||||
|
||||
ImGui.SameLine();
|
||||
var clear = ImGuiComponents.IconButton(FontAwesomeIcon.Trash);
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Clear Log");
|
||||
|
||||
ImGui.SameLine();
|
||||
var copy = ImGuiComponents.IconButton(FontAwesomeIcon.Copy);
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Copy Log");
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Skull))
|
||||
Process.GetCurrentProcess().Kill();
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip("Kill game");
|
||||
|
||||
ImGui.BeginChild("scrolling", new Vector2(0, ImGui.GetFrameHeightWithSpacing() - 55), false, ImGuiWindowFlags.AlwaysHorizontalScrollbar | ImGuiWindowFlags.AlwaysVerticalScrollbar);
|
||||
|
||||
if (clear)
|
||||
{
|
||||
this.Clear();
|
||||
}
|
||||
|
||||
if (copy)
|
||||
{
|
||||
ImGui.LogToClipboard();
|
||||
}
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
|
||||
|
||||
ImGuiListClipperPtr clipper;
|
||||
unsafe
|
||||
{
|
||||
clipper = new ImGuiListClipperPtr(ImGuiNative.ImGuiListClipper_ImGuiListClipper());
|
||||
}
|
||||
|
||||
ImGui.PushFont(InterfaceManager.MonoFont);
|
||||
|
||||
var childPos = ImGui.GetWindowPos();
|
||||
var childDrawList = ImGui.GetWindowDrawList();
|
||||
var childSize = ImGui.GetWindowSize();
|
||||
|
||||
var cursorDiv = ImGuiHelpers.GlobalScale * 92;
|
||||
var cursorLogLevel = ImGuiHelpers.GlobalScale * 100;
|
||||
var cursorLogLine = ImGuiHelpers.GlobalScale * 135;
|
||||
|
||||
lock (this.renderLock)
|
||||
{
|
||||
clipper.Begin(this.LogEntries.Count);
|
||||
while (clipper.Step())
|
||||
{
|
||||
for (var i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
|
||||
{
|
||||
var line = this.LogEntries[i];
|
||||
|
||||
if (!line.IsMultiline)
|
||||
ImGui.Separator();
|
||||
|
||||
ImGui.PushStyleColor(ImGuiCol.Header, this.GetColorForLogEventLevel(line.Level));
|
||||
ImGui.PushStyleColor(ImGuiCol.HeaderActive, this.GetColorForLogEventLevel(line.Level));
|
||||
ImGui.PushStyleColor(ImGuiCol.HeaderHovered, this.GetColorForLogEventLevel(line.Level));
|
||||
|
||||
ImGui.Selectable("###consolenull", true, ImGuiSelectableFlags.AllowItemOverlap | ImGuiSelectableFlags.SpanAllColumns);
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.PopStyleColor(3);
|
||||
|
||||
if (!line.IsMultiline)
|
||||
{
|
||||
ImGui.TextUnformatted(line.TimeStamp.ToString("HH:mm:ss.fff"));
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosX(cursorDiv);
|
||||
ImGui.TextUnformatted("|");
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosX(cursorLogLevel);
|
||||
ImGui.TextUnformatted(this.GetTextForLogEventLevel(line.Level));
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
ImGui.SetCursorPosX(cursorLogLine);
|
||||
ImGui.TextUnformatted(line.Line);
|
||||
}
|
||||
}
|
||||
|
||||
clipper.End();
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
if (this.autoScroll && ImGui.GetScrollY() >= ImGui.GetScrollMaxY())
|
||||
{
|
||||
ImGui.SetScrollHereY(1.0f);
|
||||
}
|
||||
|
||||
// Draw dividing line
|
||||
var offset = ImGuiHelpers.GlobalScale * 127;
|
||||
childDrawList.AddLine(new Vector2(childPos.X + offset, childPos.Y), new Vector2(childPos.X + offset, childPos.Y + childSize.Y), 0x4FFFFFFF, 1.0f);
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
var hadColor = false;
|
||||
if (this.lastCmdSuccess.HasValue)
|
||||
{
|
||||
hadColor = true;
|
||||
if (this.lastCmdSuccess.Value)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.FrameBg, ImGuiColors.HealerGreen - new Vector4(0, 0, 0, 0.7f));
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.FrameBg, ImGuiColors.DalamudRed - new Vector4(0, 0, 0, 0.7f));
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SetNextItemWidth(ImGui.GetWindowSize().X - 80);
|
||||
|
||||
var getFocus = false;
|
||||
unsafe
|
||||
{
|
||||
if (ImGui.InputText("##commandbox", ref this.commandText, 255, ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CallbackCompletion | ImGuiInputTextFlags.CallbackHistory, this.CommandInputCallback))
|
||||
{
|
||||
this.ProcessCommand();
|
||||
getFocus = true;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
ImGui.SetItemDefaultFocus();
|
||||
if (getFocus)
|
||||
ImGui.SetKeyboardFocusHere(-1); // Auto focus previous widget
|
||||
|
||||
if (hadColor)
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
if (ImGui.Button("Send"))
|
||||
if (ImGui.InputText("##commandbox", ref this.commandText, 255, ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CallbackCompletion | ImGuiInputTextFlags.CallbackHistory, this.CommandInputCallback))
|
||||
{
|
||||
this.ProcessCommand();
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessCommand()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.historyPos = -1;
|
||||
for (var i = this.history.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (this.history[i] == this.commandText)
|
||||
{
|
||||
this.history.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.history.Add(this.commandText);
|
||||
|
||||
if (this.commandText == "clear" || this.commandText == "cls")
|
||||
{
|
||||
this.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastCmdSuccess = Service<CommandManager>.Get().ProcessCommand("/" + this.commandText);
|
||||
this.commandText = string.Empty;
|
||||
|
||||
// TODO: Force scroll to bottom
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error during command dispatch");
|
||||
this.lastCmdSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe int CommandInputCallback(ImGuiInputTextCallbackData* data)
|
||||
{
|
||||
var ptr = new ImGuiInputTextCallbackDataPtr(data);
|
||||
|
||||
switch (data->EventFlag)
|
||||
{
|
||||
case ImGuiInputTextFlags.CallbackCompletion:
|
||||
var textBytes = new byte[data->BufTextLen];
|
||||
Marshal.Copy((IntPtr)data->Buf, textBytes, 0, data->BufTextLen);
|
||||
var text = Encoding.UTF8.GetString(textBytes);
|
||||
|
||||
var words = text.Split();
|
||||
|
||||
// We can't do any completion for parameters at the moment since it just calls into CommandHandler
|
||||
if (words.Length > 1)
|
||||
return 0;
|
||||
|
||||
// TODO: Improve this, add partial completion
|
||||
// https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp#L6443-L6484
|
||||
var candidates = Service<CommandManager>.Get().Commands.Where(x => x.Key.Contains("/" + words[0])).ToList();
|
||||
if (candidates.Count > 0)
|
||||
{
|
||||
ptr.DeleteChars(0, ptr.BufTextLen);
|
||||
ptr.InsertChars(0, candidates[0].Key.Replace("/", string.Empty));
|
||||
}
|
||||
|
||||
break;
|
||||
case ImGuiInputTextFlags.CallbackHistory:
|
||||
var prevPos = this.historyPos;
|
||||
|
||||
if (ptr.EventKey == ImGuiKey.UpArrow)
|
||||
{
|
||||
if (this.historyPos == -1)
|
||||
this.historyPos = this.history.Count - 1;
|
||||
else if (this.historyPos > 0)
|
||||
this.historyPos--;
|
||||
}
|
||||
else if (data->EventKey == ImGuiKey.DownArrow)
|
||||
{
|
||||
if (this.historyPos != -1)
|
||||
{
|
||||
if (++this.historyPos >= this.history.Count)
|
||||
{
|
||||
this.historyPos = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prevPos != this.historyPos)
|
||||
{
|
||||
var historyStr = this.historyPos >= 0 ? this.history[this.historyPos] : string.Empty;
|
||||
|
||||
ptr.DeleteChars(0, ptr.BufTextLen);
|
||||
ptr.InsertChars(0, historyStr);
|
||||
}
|
||||
|
||||
break;
|
||||
getFocus = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
private void AddAndFilter(string line, LogEventLevel level, DateTimeOffset offset, bool isMultiline)
|
||||
ImGui.SetItemDefaultFocus();
|
||||
if (getFocus)
|
||||
ImGui.SetKeyboardFocusHere(-1); // Auto focus previous widget
|
||||
|
||||
if (hadColor)
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
if (ImGui.Button("Send"))
|
||||
{
|
||||
if (line.StartsWith("TROUBLESHOOTING:") || line.StartsWith("LASTEXCEPTION:"))
|
||||
return;
|
||||
|
||||
var entry = new LogEntry
|
||||
{
|
||||
IsMultiline = isMultiline,
|
||||
Level = level,
|
||||
Line = line,
|
||||
TimeStamp = offset,
|
||||
};
|
||||
|
||||
this.logText.Add(entry);
|
||||
|
||||
if (!this.isFiltered)
|
||||
return;
|
||||
|
||||
if (this.IsFilterApplicable(entry))
|
||||
this.filteredLogText.Add(entry);
|
||||
}
|
||||
|
||||
private bool IsFilterApplicable(LogEntry entry)
|
||||
{
|
||||
if (this.levelFilter.HasValue)
|
||||
{
|
||||
return entry.Level == this.levelFilter.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(this.textFilter))
|
||||
return entry.Line.Contains(this.textFilter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Refilter()
|
||||
{
|
||||
lock (this.renderLock)
|
||||
{
|
||||
this.filteredLogText = this.logText.Where(this.IsFilterApplicable).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private string GetTextForLogEventLevel(LogEventLevel level) => level switch
|
||||
{
|
||||
LogEventLevel.Error => "ERR",
|
||||
LogEventLevel.Verbose => "VRB",
|
||||
LogEventLevel.Debug => "DBG",
|
||||
LogEventLevel.Information => "INF",
|
||||
LogEventLevel.Warning => "WRN",
|
||||
LogEventLevel.Fatal => "FTL",
|
||||
_ => throw new ArgumentOutOfRangeException(level.ToString(), "Invalid LogEventLevel"),
|
||||
};
|
||||
|
||||
private uint GetColorForLogEventLevel(LogEventLevel level) => level switch
|
||||
{
|
||||
LogEventLevel.Error => 0x800000EE,
|
||||
LogEventLevel.Verbose => 0x00000000,
|
||||
LogEventLevel.Debug => 0x00000000,
|
||||
LogEventLevel.Information => 0x00000000,
|
||||
LogEventLevel.Warning => 0x8A0070EE,
|
||||
LogEventLevel.Fatal => 0xFF00000A,
|
||||
_ => throw new ArgumentOutOfRangeException(level.ToString(), "Invalid LogEventLevel"),
|
||||
};
|
||||
|
||||
private void OnLogLine(object sender, (string Line, LogEventLevel Level, DateTimeOffset Offset, Exception? Exception) logEvent)
|
||||
{
|
||||
this.HandleLogLine(logEvent.Line, logEvent.Level, logEvent.Offset);
|
||||
}
|
||||
|
||||
private class LogEntry
|
||||
{
|
||||
public string Line { get; set; }
|
||||
|
||||
public LogEventLevel Level { get; set; }
|
||||
|
||||
public DateTimeOffset TimeStamp { get; set; }
|
||||
|
||||
public bool IsMultiline { get; set; }
|
||||
this.ProcessCommand();
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessCommand()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.historyPos = -1;
|
||||
for (var i = this.history.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (this.history[i] == this.commandText)
|
||||
{
|
||||
this.history.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.history.Add(this.commandText);
|
||||
|
||||
if (this.commandText == "clear" || this.commandText == "cls")
|
||||
{
|
||||
this.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastCmdSuccess = Service<CommandManager>.Get().ProcessCommand("/" + this.commandText);
|
||||
this.commandText = string.Empty;
|
||||
|
||||
// TODO: Force scroll to bottom
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error during command dispatch");
|
||||
this.lastCmdSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe int CommandInputCallback(ImGuiInputTextCallbackData* data)
|
||||
{
|
||||
var ptr = new ImGuiInputTextCallbackDataPtr(data);
|
||||
|
||||
switch (data->EventFlag)
|
||||
{
|
||||
case ImGuiInputTextFlags.CallbackCompletion:
|
||||
var textBytes = new byte[data->BufTextLen];
|
||||
Marshal.Copy((IntPtr)data->Buf, textBytes, 0, data->BufTextLen);
|
||||
var text = Encoding.UTF8.GetString(textBytes);
|
||||
|
||||
var words = text.Split();
|
||||
|
||||
// We can't do any completion for parameters at the moment since it just calls into CommandHandler
|
||||
if (words.Length > 1)
|
||||
return 0;
|
||||
|
||||
// TODO: Improve this, add partial completion
|
||||
// https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp#L6443-L6484
|
||||
var candidates = Service<CommandManager>.Get().Commands.Where(x => x.Key.Contains("/" + words[0])).ToList();
|
||||
if (candidates.Count > 0)
|
||||
{
|
||||
ptr.DeleteChars(0, ptr.BufTextLen);
|
||||
ptr.InsertChars(0, candidates[0].Key.Replace("/", string.Empty));
|
||||
}
|
||||
|
||||
break;
|
||||
case ImGuiInputTextFlags.CallbackHistory:
|
||||
var prevPos = this.historyPos;
|
||||
|
||||
if (ptr.EventKey == ImGuiKey.UpArrow)
|
||||
{
|
||||
if (this.historyPos == -1)
|
||||
this.historyPos = this.history.Count - 1;
|
||||
else if (this.historyPos > 0)
|
||||
this.historyPos--;
|
||||
}
|
||||
else if (data->EventKey == ImGuiKey.DownArrow)
|
||||
{
|
||||
if (this.historyPos != -1)
|
||||
{
|
||||
if (++this.historyPos >= this.history.Count)
|
||||
{
|
||||
this.historyPos = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prevPos != this.historyPos)
|
||||
{
|
||||
var historyStr = this.historyPos >= 0 ? this.history[this.historyPos] : string.Empty;
|
||||
|
||||
ptr.DeleteChars(0, ptr.BufTextLen);
|
||||
ptr.InsertChars(0, historyStr);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void AddAndFilter(string line, LogEventLevel level, DateTimeOffset offset, bool isMultiline)
|
||||
{
|
||||
if (line.StartsWith("TROUBLESHOOTING:") || line.StartsWith("LASTEXCEPTION:"))
|
||||
return;
|
||||
|
||||
var entry = new LogEntry
|
||||
{
|
||||
IsMultiline = isMultiline,
|
||||
Level = level,
|
||||
Line = line,
|
||||
TimeStamp = offset,
|
||||
};
|
||||
|
||||
this.logText.Add(entry);
|
||||
|
||||
if (!this.isFiltered)
|
||||
return;
|
||||
|
||||
if (this.IsFilterApplicable(entry))
|
||||
this.filteredLogText.Add(entry);
|
||||
}
|
||||
|
||||
private bool IsFilterApplicable(LogEntry entry)
|
||||
{
|
||||
if (this.levelFilter.HasValue)
|
||||
{
|
||||
return entry.Level == this.levelFilter.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(this.textFilter))
|
||||
return entry.Line.Contains(this.textFilter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Refilter()
|
||||
{
|
||||
lock (this.renderLock)
|
||||
{
|
||||
this.filteredLogText = this.logText.Where(this.IsFilterApplicable).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private string GetTextForLogEventLevel(LogEventLevel level) => level switch
|
||||
{
|
||||
LogEventLevel.Error => "ERR",
|
||||
LogEventLevel.Verbose => "VRB",
|
||||
LogEventLevel.Debug => "DBG",
|
||||
LogEventLevel.Information => "INF",
|
||||
LogEventLevel.Warning => "WRN",
|
||||
LogEventLevel.Fatal => "FTL",
|
||||
_ => throw new ArgumentOutOfRangeException(level.ToString(), "Invalid LogEventLevel"),
|
||||
};
|
||||
|
||||
private uint GetColorForLogEventLevel(LogEventLevel level) => level switch
|
||||
{
|
||||
LogEventLevel.Error => 0x800000EE,
|
||||
LogEventLevel.Verbose => 0x00000000,
|
||||
LogEventLevel.Debug => 0x00000000,
|
||||
LogEventLevel.Information => 0x00000000,
|
||||
LogEventLevel.Warning => 0x8A0070EE,
|
||||
LogEventLevel.Fatal => 0xFF00000A,
|
||||
_ => throw new ArgumentOutOfRangeException(level.ToString(), "Invalid LogEventLevel"),
|
||||
};
|
||||
|
||||
private void OnLogLine(object sender, (string Line, LogEventLevel Level, DateTimeOffset Offset, Exception? Exception) logEvent)
|
||||
{
|
||||
this.HandleLogLine(logEvent.Line, logEvent.Level, logEvent.Offset);
|
||||
}
|
||||
|
||||
private class LogEntry
|
||||
{
|
||||
public string Line { get; set; }
|
||||
|
||||
public LogEventLevel Level { get; set; }
|
||||
|
||||
public DateTimeOffset TimeStamp { get; set; }
|
||||
|
||||
public bool IsMultiline { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,15 +11,15 @@ using Dalamud.Plugin.Internal;
|
|||
using ImGuiNET;
|
||||
using ImGuiScene;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows
|
||||
namespace Dalamud.Interface.Internal.Windows;
|
||||
|
||||
/// <summary>
|
||||
/// A window documenting contributors to the project.
|
||||
/// </summary>
|
||||
internal class CreditsWindow : Window, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// A window documenting contributors to the project.
|
||||
/// </summary>
|
||||
internal class CreditsWindow : Window, IDisposable
|
||||
{
|
||||
private const float CreditFPS = 60.0f;
|
||||
private const string CreditsTextTempl = @"
|
||||
private const float CreditFPS = 60.0f;
|
||||
private const string CreditsTextTempl = @"
|
||||
Dalamud
|
||||
A FFXIV Plugin Framework
|
||||
Version D{0}
|
||||
|
|
@ -122,121 +122,120 @@ Contribute at: https://github.com/goatsoft/Dalamud
|
|||
Thank you for using XIVLauncher and Dalamud!
|
||||
";
|
||||
|
||||
private readonly TextureWrap logoTexture;
|
||||
private readonly Stopwatch creditsThrottler;
|
||||
private readonly TextureWrap logoTexture;
|
||||
private readonly Stopwatch creditsThrottler;
|
||||
|
||||
private string creditsText;
|
||||
private string creditsText;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CreditsWindow"/> class.
|
||||
/// </summary>
|
||||
public CreditsWindow()
|
||||
: base("Dalamud Credits", ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize, true)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CreditsWindow"/> class.
|
||||
/// </summary>
|
||||
public CreditsWindow()
|
||||
: base("Dalamud Credits", ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize, true)
|
||||
{
|
||||
var dalamud = Service<Dalamud>.Get();
|
||||
var interfaceManager = Service<InterfaceManager>.Get();
|
||||
|
||||
this.logoTexture = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "logo.png"));
|
||||
this.creditsThrottler = new();
|
||||
|
||||
this.Size = new Vector2(500, 400);
|
||||
this.SizeCondition = ImGuiCond.Always;
|
||||
|
||||
this.PositionCondition = ImGuiCond.Always;
|
||||
|
||||
this.BgAlpha = 0.8f;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void OnOpen()
|
||||
{
|
||||
var pluginCredits = Service<PluginManager>.Get().InstalledPlugins
|
||||
.Where(plugin => plugin.Manifest != null)
|
||||
.Select(plugin => $"{plugin.Manifest.Name} by {plugin.Manifest.Author}\n")
|
||||
.Aggregate(string.Empty, (current, next) => $"{current}{next}");
|
||||
|
||||
this.creditsText = string.Format(CreditsTextTempl, typeof(Dalamud).Assembly.GetName().Version, pluginCredits);
|
||||
|
||||
Service<GameGui>.Get().SetBgm(132);
|
||||
this.creditsThrottler.Restart();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void OnClose()
|
||||
{
|
||||
this.creditsThrottler.Reset();
|
||||
Service<GameGui>.Get().SetBgm(9999);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void PreDraw()
|
||||
{
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 0));
|
||||
|
||||
base.PreDraw();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void PostDraw()
|
||||
{
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
base.PostDraw();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
var screenSize = ImGui.GetMainViewport().Size;
|
||||
var windowSize = ImGui.GetWindowSize();
|
||||
|
||||
this.Position = (screenSize - windowSize) / 2;
|
||||
|
||||
ImGui.BeginChild("scrolling", Vector2.Zero, false, ImGuiWindowFlags.NoScrollbar);
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
|
||||
|
||||
ImGuiHelpers.ScaledDummy(0, 340f);
|
||||
ImGui.Text(string.Empty);
|
||||
|
||||
ImGui.SameLine(150f);
|
||||
ImGui.Image(this.logoTexture.ImGuiHandle, ImGuiHelpers.ScaledVector2(190f, 190f));
|
||||
|
||||
ImGuiHelpers.ScaledDummy(0, 20f);
|
||||
|
||||
var windowX = ImGui.GetWindowSize().X;
|
||||
|
||||
foreach (var creditsLine in this.creditsText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None))
|
||||
{
|
||||
var dalamud = Service<Dalamud>.Get();
|
||||
var interfaceManager = Service<InterfaceManager>.Get();
|
||||
var lineLenX = ImGui.CalcTextSize(creditsLine).X;
|
||||
|
||||
this.logoTexture = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "logo.png"));
|
||||
this.creditsThrottler = new();
|
||||
|
||||
this.Size = new Vector2(500, 400);
|
||||
this.SizeCondition = ImGuiCond.Always;
|
||||
|
||||
this.PositionCondition = ImGuiCond.Always;
|
||||
|
||||
this.BgAlpha = 0.8f;
|
||||
ImGui.Dummy(new Vector2((windowX / 2) - (lineLenX / 2), 0f));
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(creditsLine);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void OnOpen()
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
if (this.creditsThrottler.Elapsed.TotalMilliseconds > (1000.0f / CreditFPS))
|
||||
{
|
||||
var pluginCredits = Service<PluginManager>.Get().InstalledPlugins
|
||||
.Where(plugin => plugin.Manifest != null)
|
||||
.Select(plugin => $"{plugin.Manifest.Name} by {plugin.Manifest.Author}\n")
|
||||
.Aggregate(string.Empty, (current, next) => $"{current}{next}");
|
||||
var curY = ImGui.GetScrollY();
|
||||
var maxY = ImGui.GetScrollMaxY();
|
||||
|
||||
this.creditsText = string.Format(CreditsTextTempl, typeof(Dalamud).Assembly.GetName().Version, pluginCredits);
|
||||
|
||||
Service<GameGui>.Get().SetBgm(132);
|
||||
this.creditsThrottler.Restart();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void OnClose()
|
||||
{
|
||||
this.creditsThrottler.Reset();
|
||||
Service<GameGui>.Get().SetBgm(9999);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void PreDraw()
|
||||
{
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 0));
|
||||
|
||||
base.PreDraw();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void PostDraw()
|
||||
{
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
base.PostDraw();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
var screenSize = ImGui.GetMainViewport().Size;
|
||||
var windowSize = ImGui.GetWindowSize();
|
||||
|
||||
this.Position = (screenSize - windowSize) / 2;
|
||||
|
||||
ImGui.BeginChild("scrolling", Vector2.Zero, false, ImGuiWindowFlags.NoScrollbar);
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
|
||||
|
||||
ImGuiHelpers.ScaledDummy(0, 340f);
|
||||
ImGui.Text(string.Empty);
|
||||
|
||||
ImGui.SameLine(150f);
|
||||
ImGui.Image(this.logoTexture.ImGuiHandle, ImGuiHelpers.ScaledVector2(190f, 190f));
|
||||
|
||||
ImGuiHelpers.ScaledDummy(0, 20f);
|
||||
|
||||
var windowX = ImGui.GetWindowSize().X;
|
||||
|
||||
foreach (var creditsLine in this.creditsText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None))
|
||||
if (curY < maxY - 1)
|
||||
{
|
||||
var lineLenX = ImGui.CalcTextSize(creditsLine).X;
|
||||
|
||||
ImGui.Dummy(new Vector2((windowX / 2) - (lineLenX / 2), 0f));
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted(creditsLine);
|
||||
ImGui.SetScrollY(curY + 1);
|
||||
}
|
||||
|
||||
ImGui.PopStyleVar();
|
||||
|
||||
if (this.creditsThrottler.Elapsed.TotalMilliseconds > (1000.0f / CreditFPS))
|
||||
{
|
||||
var curY = ImGui.GetScrollY();
|
||||
var maxY = ImGui.GetScrollMaxY();
|
||||
|
||||
if (curY < maxY - 1)
|
||||
{
|
||||
ImGui.SetScrollY(curY + 1);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.logoTexture?.Dispose();
|
||||
}
|
||||
ImGui.EndChild();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.logoTexture?.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,46 +4,45 @@ using CheapLoc;
|
|||
using Dalamud.Interface.Windowing;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows
|
||||
namespace Dalamud.Interface.Internal.Windows;
|
||||
|
||||
/// <summary>
|
||||
/// Class responsible for drawing a notifier on screen that gamepad mode is active.
|
||||
/// </summary>
|
||||
internal class GamepadModeNotifierWindow : Window
|
||||
{
|
||||
/// <summary>
|
||||
/// Class responsible for drawing a notifier on screen that gamepad mode is active.
|
||||
/// Initializes a new instance of the <see cref="GamepadModeNotifierWindow"/> class.
|
||||
/// </summary>
|
||||
internal class GamepadModeNotifierWindow : Window
|
||||
public GamepadModeNotifierWindow()
|
||||
: base(
|
||||
"###DalamudGamepadModeNotifier",
|
||||
ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoMouseInputs
|
||||
| ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoBackground | ImGuiWindowFlags.NoNav
|
||||
| ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoSavedSettings,
|
||||
true)
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GamepadModeNotifierWindow"/> class.
|
||||
/// </summary>
|
||||
public GamepadModeNotifierWindow()
|
||||
: base(
|
||||
"###DalamudGamepadModeNotifier",
|
||||
ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoMouseInputs
|
||||
| ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoBackground | ImGuiWindowFlags.NoNav
|
||||
| ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoSavedSettings,
|
||||
true)
|
||||
{
|
||||
this.Size = Vector2.Zero;
|
||||
this.SizeCondition = ImGuiCond.Always;
|
||||
this.IsOpen = false;
|
||||
this.Size = Vector2.Zero;
|
||||
this.SizeCondition = ImGuiCond.Always;
|
||||
this.IsOpen = false;
|
||||
|
||||
this.RespectCloseHotkey = false;
|
||||
}
|
||||
this.RespectCloseHotkey = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a light grey-ish, main-viewport-big filled rect in the background draw list alongside a text indicating gamepad mode.
|
||||
/// </summary>
|
||||
public override void Draw()
|
||||
{
|
||||
var drawList = ImGui.GetBackgroundDrawList();
|
||||
drawList.PushClipRectFullScreen();
|
||||
drawList.AddRectFilled(Vector2.Zero, ImGuiHelpers.MainViewport.Size, 0x661A1A1A);
|
||||
drawList.AddText(
|
||||
Vector2.One,
|
||||
0xFFFFFFFF,
|
||||
Loc.Localize(
|
||||
"DalamudGamepadModeNotifierText",
|
||||
"Gamepad mode is ON. Press L1+L3 to deactivate, press R3 to toggle PluginInstaller."));
|
||||
drawList.PopClipRect();
|
||||
}
|
||||
/// <summary>
|
||||
/// Draws a light grey-ish, main-viewport-big filled rect in the background draw list alongside a text indicating gamepad mode.
|
||||
/// </summary>
|
||||
public override void Draw()
|
||||
{
|
||||
var drawList = ImGui.GetBackgroundDrawList();
|
||||
drawList.PushClipRectFullScreen();
|
||||
drawList.AddRectFilled(Vector2.Zero, ImGuiHelpers.MainViewport.Size, 0x661A1A1A);
|
||||
drawList.AddText(
|
||||
Vector2.One,
|
||||
0xFFFFFFFF,
|
||||
Loc.Localize(
|
||||
"DalamudGamepadModeNotifierText",
|
||||
"Gamepad mode is ON. Press L1+L3 to deactivate, press R3 to toggle PluginInstaller."));
|
||||
drawList.PopClipRect();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,65 +5,64 @@ using Dalamud.Interface.Colors;
|
|||
using Dalamud.Interface.Windowing;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows
|
||||
namespace Dalamud.Interface.Internal.Windows;
|
||||
|
||||
/// <summary>
|
||||
/// A window for displaying IME details.
|
||||
/// </summary>
|
||||
internal class IMEWindow : Window
|
||||
{
|
||||
private const int ImePageSize = 9;
|
||||
|
||||
/// <summary>
|
||||
/// A window for displaying IME details.
|
||||
/// Initializes a new instance of the <see cref="IMEWindow"/> class.
|
||||
/// </summary>
|
||||
internal class IMEWindow : Window
|
||||
public IMEWindow()
|
||||
: base("Dalamud IME", ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.AlwaysAutoResize)
|
||||
{
|
||||
private const int ImePageSize = 9;
|
||||
this.Size = new Vector2(100, 200);
|
||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IMEWindow"/> class.
|
||||
/// </summary>
|
||||
public IMEWindow()
|
||||
: base("Dalamud IME", ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.AlwaysAutoResize)
|
||||
this.RespectCloseHotkey = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
var ime = Service<DalamudIME>.GetNullable();
|
||||
|
||||
if (ime == null || !ime.IsEnabled)
|
||||
{
|
||||
this.Size = new Vector2(100, 200);
|
||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
||||
|
||||
this.RespectCloseHotkey = false;
|
||||
ImGui.Text("IME is unavailable.");
|
||||
return;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
ImGui.Text(ime.ImmComp);
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
var native = ime.ImmCandNative;
|
||||
for (var i = 0; i < ime.ImmCand.Count; i++)
|
||||
{
|
||||
var ime = Service<DalamudIME>.GetNullable();
|
||||
var selected = i == (native.Selection % ImePageSize);
|
||||
|
||||
if (ime == null || !ime.IsEnabled)
|
||||
{
|
||||
ImGui.Text("IME is unavailable.");
|
||||
return;
|
||||
}
|
||||
if (selected)
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen);
|
||||
|
||||
ImGui.Text(ime.ImmComp);
|
||||
ImGui.Text($"{i + 1}. {ime.ImmCand[i]}");
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
var native = ime.ImmCandNative;
|
||||
for (var i = 0; i < ime.ImmCand.Count; i++)
|
||||
{
|
||||
var selected = i == (native.Selection % ImePageSize);
|
||||
|
||||
if (selected)
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen);
|
||||
|
||||
ImGui.Text($"{i + 1}. {ime.ImmCand[i]}");
|
||||
|
||||
if (selected)
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
|
||||
var totalIndex = native.Selection + 1;
|
||||
var totalSize = native.Count;
|
||||
|
||||
var pageStart = native.PageStart;
|
||||
var pageIndex = (pageStart / ImePageSize) + 1;
|
||||
var pageCount = (totalSize / ImePageSize) + 1;
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.Text($"{totalIndex}/{totalSize} ({pageIndex}/{pageCount})");
|
||||
if (selected)
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
|
||||
var totalIndex = native.Selection + 1;
|
||||
var totalSize = native.Count;
|
||||
|
||||
var pageStart = native.PageStart;
|
||||
var pageIndex = (pageStart / ImePageSize) + 1;
|
||||
var pageCount = (totalSize / ImePageSize) + 1;
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.Text($"{totalIndex}/{totalSize} ({pageIndex}/{pageCount})");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,394 +14,330 @@ using Dalamud.Utility;
|
|||
using ImGuiScene;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows
|
||||
namespace Dalamud.Interface.Internal.Windows;
|
||||
|
||||
/// <summary>
|
||||
/// A cache for plugin icons and images.
|
||||
/// </summary>
|
||||
internal class PluginImageCache : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// A cache for plugin icons and images.
|
||||
/// Maximum plugin image width.
|
||||
/// </summary>
|
||||
internal class PluginImageCache : IDisposable
|
||||
public const int PluginImageWidth = 730;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum plugin image height.
|
||||
/// </summary>
|
||||
public const int PluginImageHeight = 380;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum plugin icon width.
|
||||
/// </summary>
|
||||
public const int PluginIconWidth = 512;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum plugin height.
|
||||
/// </summary>
|
||||
public const int PluginIconHeight = 512;
|
||||
|
||||
// TODO: Change back to master after release
|
||||
private const string MainRepoImageUrl = "https://raw.githubusercontent.com/goatcorp/DalamudPlugins/api4/{0}/{1}/images/{2}";
|
||||
|
||||
private BlockingCollection<Func<Task>> downloadQueue = new();
|
||||
private CancellationTokenSource downloadToken = new();
|
||||
|
||||
private Dictionary<string, TextureWrap?> pluginIconMap = new();
|
||||
private Dictionary<string, TextureWrap?[]> pluginImagesMap = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginImageCache"/> class.
|
||||
/// </summary>
|
||||
public PluginImageCache()
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum plugin image width.
|
||||
/// </summary>
|
||||
public const int PluginImageWidth = 730;
|
||||
var dalamud = Service<Dalamud>.Get();
|
||||
var interfaceManager = Service<InterfaceManager>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Maximum plugin image height.
|
||||
/// </summary>
|
||||
public const int PluginImageHeight = 380;
|
||||
this.DefaultIcon = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "defaultIcon.png"));
|
||||
this.TroubleIcon = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "troubleIcon.png"));
|
||||
this.UpdateIcon = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "updateIcon.png"));
|
||||
|
||||
/// <summary>
|
||||
/// Maximum plugin icon width.
|
||||
/// </summary>
|
||||
public const int PluginIconWidth = 512;
|
||||
var task = new Task(
|
||||
() => this.DownloadTask(this.downloadToken.Token),
|
||||
this.downloadToken.Token,
|
||||
TaskCreationOptions.LongRunning);
|
||||
task.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maximum plugin height.
|
||||
/// </summary>
|
||||
public const int PluginIconHeight = 512;
|
||||
/// <summary>
|
||||
/// Gets the default plugin icon.
|
||||
/// </summary>
|
||||
public TextureWrap DefaultIcon { get; }
|
||||
|
||||
// TODO: Change back to master after release
|
||||
private const string MainRepoImageUrl = "https://raw.githubusercontent.com/goatcorp/DalamudPlugins/api4/{0}/{1}/images/{2}";
|
||||
/// <summary>
|
||||
/// Gets the plugin trouble icon overlay.
|
||||
/// </summary>
|
||||
public TextureWrap TroubleIcon { get; }
|
||||
|
||||
private BlockingCollection<Func<Task>> downloadQueue = new();
|
||||
private CancellationTokenSource downloadToken = new();
|
||||
/// <summary>
|
||||
/// Gets the plugin update icon overlay.
|
||||
/// </summary>
|
||||
public TextureWrap UpdateIcon { get; }
|
||||
|
||||
private Dictionary<string, TextureWrap?> pluginIconMap = new();
|
||||
private Dictionary<string, TextureWrap?[]> pluginImagesMap = new();
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.DefaultIcon?.Dispose();
|
||||
this.TroubleIcon?.Dispose();
|
||||
this.UpdateIcon?.Dispose();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginImageCache"/> class.
|
||||
/// </summary>
|
||||
public PluginImageCache()
|
||||
this.downloadToken?.Cancel();
|
||||
this.downloadToken?.Dispose();
|
||||
this.downloadQueue?.CompleteAdding();
|
||||
this.downloadQueue?.Dispose();
|
||||
|
||||
foreach (var icon in this.pluginIconMap.Values)
|
||||
{
|
||||
var dalamud = Service<Dalamud>.Get();
|
||||
var interfaceManager = Service<InterfaceManager>.Get();
|
||||
|
||||
this.DefaultIcon = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "defaultIcon.png"));
|
||||
this.TroubleIcon = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "troubleIcon.png"));
|
||||
this.UpdateIcon = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "updateIcon.png"));
|
||||
|
||||
var task = new Task(
|
||||
() => this.DownloadTask(this.downloadToken.Token),
|
||||
this.downloadToken.Token,
|
||||
TaskCreationOptions.LongRunning);
|
||||
task.Start();
|
||||
icon?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default plugin icon.
|
||||
/// </summary>
|
||||
public TextureWrap DefaultIcon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin trouble icon overlay.
|
||||
/// </summary>
|
||||
public TextureWrap TroubleIcon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin update icon overlay.
|
||||
/// </summary>
|
||||
public TextureWrap UpdateIcon { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
foreach (var images in this.pluginImagesMap.Values)
|
||||
{
|
||||
this.DefaultIcon?.Dispose();
|
||||
this.TroubleIcon?.Dispose();
|
||||
this.UpdateIcon?.Dispose();
|
||||
|
||||
this.downloadToken?.Cancel();
|
||||
this.downloadToken?.Dispose();
|
||||
this.downloadQueue?.CompleteAdding();
|
||||
this.downloadQueue?.Dispose();
|
||||
|
||||
foreach (var icon in this.pluginIconMap.Values)
|
||||
foreach (var image in images)
|
||||
{
|
||||
icon?.Dispose();
|
||||
image?.Dispose();
|
||||
}
|
||||
|
||||
foreach (var images in this.pluginImagesMap.Values)
|
||||
{
|
||||
foreach (var image in images)
|
||||
{
|
||||
image?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
this.pluginIconMap.Clear();
|
||||
this.pluginImagesMap.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear the cache of downloaded icons.
|
||||
/// </summary>
|
||||
public void ClearIconCache()
|
||||
this.pluginIconMap.Clear();
|
||||
this.pluginImagesMap.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear the cache of downloaded icons.
|
||||
/// </summary>
|
||||
public void ClearIconCache()
|
||||
{
|
||||
this.pluginIconMap.Clear();
|
||||
this.pluginImagesMap.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to get the icon associated with the internal name of a plugin.
|
||||
/// Uses the name within the manifest to search.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The installed plugin, if available.</param>
|
||||
/// <param name="manifest">The plugin manifest.</param>
|
||||
/// <param name="isThirdParty">If the plugin was third party sourced.</param>
|
||||
/// <param name="iconTexture">Cached image textures, or an empty array.</param>
|
||||
/// <returns>True if an entry exists, may be null if currently downloading.</returns>
|
||||
public bool TryGetIcon(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, out TextureWrap? iconTexture)
|
||||
{
|
||||
if (this.pluginIconMap.TryGetValue(manifest.InternalName, out iconTexture))
|
||||
return true;
|
||||
|
||||
iconTexture = null;
|
||||
this.pluginIconMap.Add(manifest.InternalName, iconTexture);
|
||||
|
||||
if (!this.downloadQueue.IsCompleted)
|
||||
{
|
||||
this.pluginIconMap.Clear();
|
||||
this.pluginImagesMap.Clear();
|
||||
this.downloadQueue.Add(async () => await this.DownloadPluginIconAsync(plugin, manifest, isThirdParty));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to get the icon associated with the internal name of a plugin.
|
||||
/// Uses the name within the manifest to search.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The installed plugin, if available.</param>
|
||||
/// <param name="manifest">The plugin manifest.</param>
|
||||
/// <param name="isThirdParty">If the plugin was third party sourced.</param>
|
||||
/// <param name="iconTexture">Cached image textures, or an empty array.</param>
|
||||
/// <returns>True if an entry exists, may be null if currently downloading.</returns>
|
||||
public bool TryGetIcon(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, out TextureWrap? iconTexture)
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to get any images associated with the internal name of a plugin.
|
||||
/// Uses the name within the manifest to search.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The installed plugin, if available.</param>
|
||||
/// <param name="manifest">The plugin manifest.</param>
|
||||
/// <param name="isThirdParty">If the plugin was third party sourced.</param>
|
||||
/// <param name="imageTextures">Cached image textures, or an empty array.</param>
|
||||
/// <returns>True if the image array exists, may be empty if currently downloading.</returns>
|
||||
public bool TryGetImages(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, out TextureWrap?[] imageTextures)
|
||||
{
|
||||
if (this.pluginImagesMap.TryGetValue(manifest.InternalName, out imageTextures))
|
||||
return true;
|
||||
|
||||
imageTextures = Array.Empty<TextureWrap>();
|
||||
this.pluginImagesMap.Add(manifest.InternalName, imageTextures);
|
||||
|
||||
if (!this.downloadQueue.IsCompleted)
|
||||
{
|
||||
if (this.pluginIconMap.TryGetValue(manifest.InternalName, out iconTexture))
|
||||
return true;
|
||||
|
||||
iconTexture = null;
|
||||
this.pluginIconMap.Add(manifest.InternalName, iconTexture);
|
||||
|
||||
if (!this.downloadQueue.IsCompleted)
|
||||
{
|
||||
this.downloadQueue.Add(async () => await this.DownloadPluginIconAsync(plugin, manifest, isThirdParty));
|
||||
}
|
||||
|
||||
return false;
|
||||
this.downloadQueue.Add(async () => await this.DownloadPluginImagesAsync(plugin, manifest, isThirdParty));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to get any images associated with the internal name of a plugin.
|
||||
/// Uses the name within the manifest to search.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The installed plugin, if available.</param>
|
||||
/// <param name="manifest">The plugin manifest.</param>
|
||||
/// <param name="isThirdParty">If the plugin was third party sourced.</param>
|
||||
/// <param name="imageTextures">Cached image textures, or an empty array.</param>
|
||||
/// <returns>True if the image array exists, may be empty if currently downloading.</returns>
|
||||
public bool TryGetImages(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty, out TextureWrap?[] imageTextures)
|
||||
return false;
|
||||
}
|
||||
|
||||
private async void DownloadTask(CancellationToken token)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (this.pluginImagesMap.TryGetValue(manifest.InternalName, out imageTextures))
|
||||
return true;
|
||||
|
||||
imageTextures = Array.Empty<TextureWrap>();
|
||||
this.pluginImagesMap.Add(manifest.InternalName, imageTextures);
|
||||
|
||||
if (!this.downloadQueue.IsCompleted)
|
||||
try
|
||||
{
|
||||
this.downloadQueue.Add(async () => await this.DownloadPluginImagesAsync(plugin, manifest, isThirdParty));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async void DownloadTask(CancellationToken token)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
if (!this.downloadQueue.TryTake(out var task, -1, token))
|
||||
return;
|
||||
|
||||
await task.Invoke();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Shutdown signal.
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "An unhandled exception occurred in the plugin image downloader");
|
||||
}
|
||||
}
|
||||
|
||||
Log.Debug("Plugin image downloader has shutdown");
|
||||
}
|
||||
|
||||
private async Task DownloadPluginIconAsync(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty)
|
||||
{
|
||||
var interfaceManager = Service<InterfaceManager>.Get();
|
||||
var pluginManager = Service<PluginManager>.Get();
|
||||
|
||||
static bool TryLoadIcon(byte[] bytes, string loc, PluginManifest manifest, InterfaceManager interfaceManager, out TextureWrap icon)
|
||||
{
|
||||
icon = interfaceManager.LoadImage(bytes);
|
||||
|
||||
if (icon == null)
|
||||
{
|
||||
Log.Error($"Could not load icon for {manifest.InternalName} at {loc}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (icon.Width > PluginIconWidth || icon.Height > PluginIconHeight)
|
||||
{
|
||||
Log.Error($"Icon for {manifest.InternalName} at {loc} was larger than the maximum allowed resolution ({PluginIconWidth}x{PluginIconHeight}).");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (icon.Height != icon.Width)
|
||||
{
|
||||
Log.Error($"Icon for {manifest.InternalName} at {loc} was not square.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (plugin != null && plugin.IsDev)
|
||||
{
|
||||
var file = this.GetPluginIconFileInfo(plugin);
|
||||
if (file != null)
|
||||
{
|
||||
Log.Verbose($"Fetching icon for {manifest.InternalName} from {file.FullName}");
|
||||
|
||||
var bytes = await File.ReadAllBytesAsync(file.FullName);
|
||||
if (!TryLoadIcon(bytes, file.FullName, manifest, interfaceManager, out var icon))
|
||||
return;
|
||||
|
||||
this.pluginIconMap[manifest.InternalName] = icon;
|
||||
Log.Verbose($"Plugin icon for {manifest.InternalName} loaded from disk");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Dev plugins are likely going to look like a main repo plugin, the InstalledFrom field is going to be null.
|
||||
// So instead, set the value manually so we download from the urls specified.
|
||||
isThirdParty = true;
|
||||
}
|
||||
|
||||
var useTesting = pluginManager.UseTesting(manifest);
|
||||
var url = this.GetPluginIconUrl(manifest, isThirdParty, useTesting);
|
||||
|
||||
if (!url.IsNullOrEmpty())
|
||||
{
|
||||
Log.Verbose($"Downloading icon for {manifest.InternalName} from {url}");
|
||||
|
||||
HttpResponseMessage data;
|
||||
try
|
||||
{
|
||||
data = await Util.HttpClient.GetAsync(url);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
Log.Error($"Plugin icon for {manifest.InternalName} has an Invalid URI");
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"An unexpected error occurred with the icon for {manifest.InternalName}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.StatusCode == HttpStatusCode.NotFound)
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
data.EnsureSuccessStatusCode();
|
||||
if (!this.downloadQueue.TryTake(out var task, -1, token))
|
||||
return;
|
||||
|
||||
var bytes = await data.Content.ReadAsByteArrayAsync();
|
||||
if (!TryLoadIcon(bytes, url, manifest, interfaceManager, out var icon))
|
||||
await task.Invoke();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Shutdown signal.
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "An unhandled exception occurred in the plugin image downloader");
|
||||
}
|
||||
}
|
||||
|
||||
Log.Debug("Plugin image downloader has shutdown");
|
||||
}
|
||||
|
||||
private async Task DownloadPluginIconAsync(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty)
|
||||
{
|
||||
var interfaceManager = Service<InterfaceManager>.Get();
|
||||
var pluginManager = Service<PluginManager>.Get();
|
||||
|
||||
static bool TryLoadIcon(byte[] bytes, string loc, PluginManifest manifest, InterfaceManager interfaceManager, out TextureWrap icon)
|
||||
{
|
||||
icon = interfaceManager.LoadImage(bytes);
|
||||
|
||||
if (icon == null)
|
||||
{
|
||||
Log.Error($"Could not load icon for {manifest.InternalName} at {loc}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (icon.Width > PluginIconWidth || icon.Height > PluginIconHeight)
|
||||
{
|
||||
Log.Error($"Icon for {manifest.InternalName} at {loc} was larger than the maximum allowed resolution ({PluginIconWidth}x{PluginIconHeight}).");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (icon.Height != icon.Width)
|
||||
{
|
||||
Log.Error($"Icon for {manifest.InternalName} at {loc} was not square.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (plugin != null && plugin.IsDev)
|
||||
{
|
||||
var file = this.GetPluginIconFileInfo(plugin);
|
||||
if (file != null)
|
||||
{
|
||||
Log.Verbose($"Fetching icon for {manifest.InternalName} from {file.FullName}");
|
||||
|
||||
var bytes = await File.ReadAllBytesAsync(file.FullName);
|
||||
if (!TryLoadIcon(bytes, file.FullName, manifest, interfaceManager, out var icon))
|
||||
return;
|
||||
|
||||
this.pluginIconMap[manifest.InternalName] = icon;
|
||||
Log.Verbose($"Plugin icon for {manifest.InternalName} downloaded");
|
||||
Log.Verbose($"Plugin icon for {manifest.InternalName} loaded from disk");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Verbose($"Plugin icon for {manifest.InternalName} is not available");
|
||||
// Dev plugins are likely going to look like a main repo plugin, the InstalledFrom field is going to be null.
|
||||
// So instead, set the value manually so we download from the urls specified.
|
||||
isThirdParty = true;
|
||||
}
|
||||
|
||||
private async Task DownloadPluginImagesAsync(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty)
|
||||
var useTesting = pluginManager.UseTesting(manifest);
|
||||
var url = this.GetPluginIconUrl(manifest, isThirdParty, useTesting);
|
||||
|
||||
if (!url.IsNullOrEmpty())
|
||||
{
|
||||
var interfaceManager = Service<InterfaceManager>.Get();
|
||||
var pluginManager = Service<PluginManager>.Get();
|
||||
Log.Verbose($"Downloading icon for {manifest.InternalName} from {url}");
|
||||
|
||||
static bool TryLoadImage(int i, byte[] bytes, string loc, PluginManifest manifest, InterfaceManager interfaceManager, out TextureWrap image)
|
||||
HttpResponseMessage data;
|
||||
try
|
||||
{
|
||||
image = interfaceManager.LoadImage(bytes);
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
Log.Error($"Could not load image{i + 1} for {manifest.InternalName} at {loc}");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (image.Width > PluginImageWidth || image.Height > PluginImageHeight)
|
||||
{
|
||||
Log.Error($"Plugin image{i + 1} for {manifest.InternalName} at {loc} was larger than the maximum allowed resolution ({PluginImageWidth}x{PluginImageHeight}).");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
data = await Util.HttpClient.GetAsync(url);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
Log.Error($"Plugin icon for {manifest.InternalName} has an Invalid URI");
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"An unexpected error occurred with the icon for {manifest.InternalName}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin != null && plugin.IsDev)
|
||||
if (data.StatusCode == HttpStatusCode.NotFound)
|
||||
return;
|
||||
|
||||
data.EnsureSuccessStatusCode();
|
||||
|
||||
var bytes = await data.Content.ReadAsByteArrayAsync();
|
||||
if (!TryLoadIcon(bytes, url, manifest, interfaceManager, out var icon))
|
||||
return;
|
||||
|
||||
this.pluginIconMap[manifest.InternalName] = icon;
|
||||
Log.Verbose($"Plugin icon for {manifest.InternalName} downloaded");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Verbose($"Plugin icon for {manifest.InternalName} is not available");
|
||||
}
|
||||
|
||||
private async Task DownloadPluginImagesAsync(LocalPlugin? plugin, PluginManifest manifest, bool isThirdParty)
|
||||
{
|
||||
var interfaceManager = Service<InterfaceManager>.Get();
|
||||
var pluginManager = Service<PluginManager>.Get();
|
||||
|
||||
static bool TryLoadImage(int i, byte[] bytes, string loc, PluginManifest manifest, InterfaceManager interfaceManager, out TextureWrap image)
|
||||
{
|
||||
image = interfaceManager.LoadImage(bytes);
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
var files = this.GetPluginImageFileInfos(plugin);
|
||||
if (files != null)
|
||||
{
|
||||
var didAny = false;
|
||||
var pluginImages = new TextureWrap[files.Count];
|
||||
for (var i = 0; i < files.Count; i++)
|
||||
{
|
||||
var file = files[i];
|
||||
|
||||
if (file == null)
|
||||
continue;
|
||||
|
||||
Log.Verbose($"Loading image{i + 1} for {manifest.InternalName} from {file.FullName}");
|
||||
var bytes = await File.ReadAllBytesAsync(file.FullName);
|
||||
|
||||
if (!TryLoadImage(i, bytes, file.FullName, manifest, interfaceManager, out var image))
|
||||
continue;
|
||||
|
||||
Log.Verbose($"Plugin image{i + 1} for {manifest.InternalName} loaded from disk");
|
||||
pluginImages[i] = image;
|
||||
|
||||
didAny = true;
|
||||
}
|
||||
|
||||
if (didAny)
|
||||
{
|
||||
Log.Verbose($"Plugin images for {manifest.InternalName} loaded from disk");
|
||||
|
||||
if (pluginImages.Contains(null))
|
||||
pluginImages = pluginImages.Where(image => image != null).ToArray();
|
||||
|
||||
this.pluginImagesMap[manifest.InternalName] = pluginImages;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Dev plugins are likely going to look like a main repo plugin, the InstalledFrom field is going to be null.
|
||||
// So instead, set the value manually so we download from the urls specified.
|
||||
isThirdParty = true;
|
||||
Log.Error($"Could not load image{i + 1} for {manifest.InternalName} at {loc}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var useTesting = pluginManager.UseTesting(manifest);
|
||||
var urls = this.GetPluginImageUrls(manifest, isThirdParty, useTesting);
|
||||
if (urls != null)
|
||||
if (image.Width > PluginImageWidth || image.Height > PluginImageHeight)
|
||||
{
|
||||
Log.Error($"Plugin image{i + 1} for {manifest.InternalName} at {loc} was larger than the maximum allowed resolution ({PluginImageWidth}x{PluginImageHeight}).");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (plugin != null && plugin.IsDev)
|
||||
{
|
||||
var files = this.GetPluginImageFileInfos(plugin);
|
||||
if (files != null)
|
||||
{
|
||||
var didAny = false;
|
||||
var pluginImages = new TextureWrap[urls.Count];
|
||||
for (var i = 0; i < urls.Count; i++)
|
||||
var pluginImages = new TextureWrap[files.Count];
|
||||
for (var i = 0; i < files.Count; i++)
|
||||
{
|
||||
var url = urls[i];
|
||||
var file = files[i];
|
||||
|
||||
if (url.IsNullOrEmpty())
|
||||
if (file == null)
|
||||
continue;
|
||||
|
||||
Log.Verbose($"Downloading image{i + 1} for {manifest.InternalName} from {url}");
|
||||
Log.Verbose($"Loading image{i + 1} for {manifest.InternalName} from {file.FullName}");
|
||||
var bytes = await File.ReadAllBytesAsync(file.FullName);
|
||||
|
||||
HttpResponseMessage data;
|
||||
try
|
||||
{
|
||||
data = await Util.HttpClient.GetAsync(url);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
Log.Error($"Plugin image{i + 1} for {manifest.InternalName} has an Invalid URI");
|
||||
continue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"An unexpected error occurred with image{i + 1} for {manifest.InternalName}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data.StatusCode == HttpStatusCode.NotFound)
|
||||
if (!TryLoadImage(i, bytes, file.FullName, manifest, interfaceManager, out var image))
|
||||
continue;
|
||||
|
||||
data.EnsureSuccessStatusCode();
|
||||
|
||||
var bytes = await data.Content.ReadAsByteArrayAsync();
|
||||
if (!TryLoadImage(i, bytes, url, manifest, interfaceManager, out var image))
|
||||
continue;
|
||||
|
||||
Log.Verbose($"Plugin image{i + 1} for {manifest.InternalName} downloaded");
|
||||
Log.Verbose($"Plugin image{i + 1} for {manifest.InternalName} loaded from disk");
|
||||
pluginImages[i] = image;
|
||||
|
||||
didAny = true;
|
||||
|
|
@ -409,7 +345,7 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
|
||||
if (didAny)
|
||||
{
|
||||
Log.Verbose($"Plugin images for {manifest.InternalName} downloaded");
|
||||
Log.Verbose($"Plugin images for {manifest.InternalName} loaded from disk");
|
||||
|
||||
if (pluginImages.Contains(null))
|
||||
pluginImages = pluginImages.Where(image => image != null).ToArray();
|
||||
|
|
@ -420,67 +356,130 @@ namespace Dalamud.Interface.Internal.Windows
|
|||
}
|
||||
}
|
||||
|
||||
Log.Verbose($"Images for {manifest.InternalName} are not available");
|
||||
// Dev plugins are likely going to look like a main repo plugin, the InstalledFrom field is going to be null.
|
||||
// So instead, set the value manually so we download from the urls specified.
|
||||
isThirdParty = true;
|
||||
}
|
||||
|
||||
private string? GetPluginIconUrl(PluginManifest manifest, bool isThirdParty, bool isTesting)
|
||||
var useTesting = pluginManager.UseTesting(manifest);
|
||||
var urls = this.GetPluginImageUrls(manifest, isThirdParty, useTesting);
|
||||
if (urls != null)
|
||||
{
|
||||
if (isThirdParty)
|
||||
return manifest.IconUrl;
|
||||
|
||||
return MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, "icon.png");
|
||||
}
|
||||
|
||||
private List<string?>? GetPluginImageUrls(PluginManifest manifest, bool isThirdParty, bool isTesting)
|
||||
{
|
||||
if (isThirdParty)
|
||||
var didAny = false;
|
||||
var pluginImages = new TextureWrap[urls.Count];
|
||||
for (var i = 0; i < urls.Count; i++)
|
||||
{
|
||||
if (manifest.ImageUrls?.Count > 5)
|
||||
var url = urls[i];
|
||||
|
||||
if (url.IsNullOrEmpty())
|
||||
continue;
|
||||
|
||||
Log.Verbose($"Downloading image{i + 1} for {manifest.InternalName} from {url}");
|
||||
|
||||
HttpResponseMessage data;
|
||||
try
|
||||
{
|
||||
Log.Warning($"Plugin {manifest.InternalName} has too many images");
|
||||
return manifest.ImageUrls.Take(5).ToList();
|
||||
data = await Util.HttpClient.GetAsync(url);
|
||||
}
|
||||
|
||||
return manifest.ImageUrls;
|
||||
}
|
||||
|
||||
var output = new List<string>();
|
||||
for (var i = 1; i <= 5; i++)
|
||||
{
|
||||
output.Add(MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, $"image{i}.png"));
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private FileInfo? GetPluginIconFileInfo(LocalPlugin? plugin)
|
||||
{
|
||||
var pluginDir = plugin.DllFile.Directory;
|
||||
|
||||
var devUrl = new FileInfo(Path.Combine(pluginDir.FullName, "images", "icon.png"));
|
||||
if (devUrl.Exists)
|
||||
return devUrl;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<FileInfo?> GetPluginImageFileInfos(LocalPlugin? plugin)
|
||||
{
|
||||
var pluginDir = plugin.DllFile.Directory;
|
||||
var output = new List<FileInfo>();
|
||||
for (var i = 1; i <= 5; i++)
|
||||
{
|
||||
var devUrl = new FileInfo(Path.Combine(pluginDir.FullName, "images", $"image{i}.png"));
|
||||
if (devUrl.Exists)
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
output.Add(devUrl);
|
||||
Log.Error($"Plugin image{i + 1} for {manifest.InternalName} has an Invalid URI");
|
||||
continue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"An unexpected error occurred with image{i + 1} for {manifest.InternalName}");
|
||||
continue;
|
||||
}
|
||||
|
||||
output.Add(null);
|
||||
if (data.StatusCode == HttpStatusCode.NotFound)
|
||||
continue;
|
||||
|
||||
data.EnsureSuccessStatusCode();
|
||||
|
||||
var bytes = await data.Content.ReadAsByteArrayAsync();
|
||||
if (!TryLoadImage(i, bytes, url, manifest, interfaceManager, out var image))
|
||||
continue;
|
||||
|
||||
Log.Verbose($"Plugin image{i + 1} for {manifest.InternalName} downloaded");
|
||||
pluginImages[i] = image;
|
||||
|
||||
didAny = true;
|
||||
}
|
||||
|
||||
return output;
|
||||
if (didAny)
|
||||
{
|
||||
Log.Verbose($"Plugin images for {manifest.InternalName} downloaded");
|
||||
|
||||
if (pluginImages.Contains(null))
|
||||
pluginImages = pluginImages.Where(image => image != null).ToArray();
|
||||
|
||||
this.pluginImagesMap[manifest.InternalName] = pluginImages;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Log.Verbose($"Images for {manifest.InternalName} are not available");
|
||||
}
|
||||
|
||||
private string? GetPluginIconUrl(PluginManifest manifest, bool isThirdParty, bool isTesting)
|
||||
{
|
||||
if (isThirdParty)
|
||||
return manifest.IconUrl;
|
||||
|
||||
return MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, "icon.png");
|
||||
}
|
||||
|
||||
private List<string?>? GetPluginImageUrls(PluginManifest manifest, bool isThirdParty, bool isTesting)
|
||||
{
|
||||
if (isThirdParty)
|
||||
{
|
||||
if (manifest.ImageUrls?.Count > 5)
|
||||
{
|
||||
Log.Warning($"Plugin {manifest.InternalName} has too many images");
|
||||
return manifest.ImageUrls.Take(5).ToList();
|
||||
}
|
||||
|
||||
return manifest.ImageUrls;
|
||||
}
|
||||
|
||||
var output = new List<string>();
|
||||
for (var i = 1; i <= 5; i++)
|
||||
{
|
||||
output.Add(MainRepoImageUrl.Format(isTesting ? "testing" : "plugins", manifest.InternalName, $"image{i}.png"));
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private FileInfo? GetPluginIconFileInfo(LocalPlugin? plugin)
|
||||
{
|
||||
var pluginDir = plugin.DllFile.Directory;
|
||||
|
||||
var devUrl = new FileInfo(Path.Combine(pluginDir.FullName, "images", "icon.png"));
|
||||
if (devUrl.Exists)
|
||||
return devUrl;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<FileInfo?> GetPluginImageFileInfos(LocalPlugin? plugin)
|
||||
{
|
||||
var pluginDir = plugin.DllFile.Directory;
|
||||
var output = new List<FileInfo>();
|
||||
for (var i = 1; i <= 5; i++)
|
||||
{
|
||||
var devUrl = new FileInfo(Path.Combine(pluginDir.FullName, "images", $"image{i}.png"));
|
||||
if (devUrl.Exists)
|
||||
{
|
||||
output.Add(devUrl);
|
||||
continue;
|
||||
}
|
||||
|
||||
output.Add(null);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -11,264 +11,263 @@ using Dalamud.Plugin.Internal;
|
|||
using Dalamud.Plugin.Internal.Types;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows
|
||||
namespace Dalamud.Interface.Internal.Windows;
|
||||
|
||||
/// <summary>
|
||||
/// This window displays plugin statistics for troubleshooting.
|
||||
/// </summary>
|
||||
internal class PluginStatWindow : Window
|
||||
{
|
||||
private bool showDalamudHooks;
|
||||
|
||||
/// <summary>
|
||||
/// This window displays plugin statistics for troubleshooting.
|
||||
/// Initializes a new instance of the <see cref="PluginStatWindow"/> class.
|
||||
/// </summary>
|
||||
internal class PluginStatWindow : Window
|
||||
public PluginStatWindow()
|
||||
: base("Plugin Statistics###DalamudPluginStatWindow")
|
||||
{
|
||||
private bool showDalamudHooks;
|
||||
this.RespectCloseHotkey = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginStatWindow"/> class.
|
||||
/// </summary>
|
||||
public PluginStatWindow()
|
||||
: base("Plugin Statistics###DalamudPluginStatWindow")
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
var pluginManager = Service<PluginManager>.Get();
|
||||
|
||||
ImGui.BeginTabBar("Stat Tabs");
|
||||
|
||||
if (ImGui.BeginTabItem("Draw times"))
|
||||
{
|
||||
this.RespectCloseHotkey = false;
|
||||
}
|
||||
var doStats = UiBuilder.DoStats;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
var pluginManager = Service<PluginManager>.Get();
|
||||
|
||||
ImGui.BeginTabBar("Stat Tabs");
|
||||
|
||||
if (ImGui.BeginTabItem("Draw times"))
|
||||
if (ImGui.Checkbox("Enable Draw Time Tracking", ref doStats))
|
||||
{
|
||||
var doStats = UiBuilder.DoStats;
|
||||
|
||||
if (ImGui.Checkbox("Enable Draw Time Tracking", ref doStats))
|
||||
{
|
||||
UiBuilder.DoStats = doStats;
|
||||
}
|
||||
|
||||
if (doStats)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Reset"))
|
||||
{
|
||||
foreach (var plugin in pluginManager.InstalledPlugins)
|
||||
{
|
||||
plugin.DalamudInterface.UiBuilder.LastDrawTime = -1;
|
||||
plugin.DalamudInterface.UiBuilder.MaxDrawTime = -1;
|
||||
plugin.DalamudInterface.UiBuilder.DrawTimeHistory.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.Columns(4);
|
||||
ImGui.SetColumnWidth(0, 180f);
|
||||
ImGui.SetColumnWidth(1, 100f);
|
||||
ImGui.SetColumnWidth(2, 100f);
|
||||
ImGui.SetColumnWidth(3, 100f);
|
||||
|
||||
ImGui.Text("Plugin");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Last");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Longest");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Average");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
foreach (var plugin in pluginManager.InstalledPlugins.Where(plugin => plugin.State == PluginState.Loaded))
|
||||
{
|
||||
ImGui.Text(plugin.Manifest.Name);
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text($"{plugin.DalamudInterface.UiBuilder.LastDrawTime / 10000f:F4}ms");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text($"{plugin.DalamudInterface.UiBuilder.MaxDrawTime / 10000f:F4}ms");
|
||||
ImGui.NextColumn();
|
||||
|
||||
if (plugin.DalamudInterface.UiBuilder.DrawTimeHistory.Count > 0)
|
||||
{
|
||||
ImGui.Text($"{plugin.DalamudInterface.UiBuilder.DrawTimeHistory.Average() / 10000f:F4}ms");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.Text("-");
|
||||
}
|
||||
|
||||
ImGui.NextColumn();
|
||||
}
|
||||
|
||||
ImGui.Columns(1);
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
UiBuilder.DoStats = doStats;
|
||||
}
|
||||
|
||||
if (ImGui.BeginTabItem("Framework times"))
|
||||
if (doStats)
|
||||
{
|
||||
var doStats = Framework.StatsEnabled;
|
||||
|
||||
if (ImGui.Checkbox("Enable Framework Update Tracking", ref doStats))
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Reset"))
|
||||
{
|
||||
Framework.StatsEnabled = doStats;
|
||||
foreach (var plugin in pluginManager.InstalledPlugins)
|
||||
{
|
||||
plugin.DalamudInterface.UiBuilder.LastDrawTime = -1;
|
||||
plugin.DalamudInterface.UiBuilder.MaxDrawTime = -1;
|
||||
plugin.DalamudInterface.UiBuilder.DrawTimeHistory.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (doStats)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Reset"))
|
||||
{
|
||||
Framework.StatsHistory.Clear();
|
||||
}
|
||||
|
||||
ImGui.Columns(4);
|
||||
|
||||
ImGui.SetColumnWidth(0, ImGui.GetWindowContentRegionWidth() - 300);
|
||||
ImGui.SetColumnWidth(1, 100f);
|
||||
ImGui.SetColumnWidth(2, 100f);
|
||||
ImGui.SetColumnWidth(3, 100f);
|
||||
|
||||
ImGui.Text("Method");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Last");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Longest");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Average");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.Separator();
|
||||
|
||||
foreach (var handlerHistory in Framework.StatsHistory)
|
||||
{
|
||||
if (handlerHistory.Value.Count == 0)
|
||||
continue;
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.Text($"{handlerHistory.Key}");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text($"{handlerHistory.Value.Last():F4}ms");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text($"{handlerHistory.Value.Max():F4}ms");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text($"{handlerHistory.Value.Average():F4}ms");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Separator();
|
||||
}
|
||||
|
||||
ImGui.Columns(0);
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui.BeginTabItem("Hooks"))
|
||||
{
|
||||
ImGui.Columns(4);
|
||||
|
||||
ImGui.SetColumnWidth(0, ImGui.GetWindowContentRegionWidth() - 330);
|
||||
ImGui.SetColumnWidth(1, 180f);
|
||||
ImGui.SetColumnWidth(0, 180f);
|
||||
ImGui.SetColumnWidth(1, 100f);
|
||||
ImGui.SetColumnWidth(2, 100f);
|
||||
ImGui.SetColumnWidth(3, 100f);
|
||||
|
||||
ImGui.Text("Detour Method");
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.Text(" ");
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.Checkbox("Show Dalamud Hooks ###showDalamudHooksCheckbox", ref this.showDalamudHooks);
|
||||
ImGui.Text("Plugin");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Address");
|
||||
ImGui.Text("Last");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Status");
|
||||
ImGui.Text("Longest");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Backend");
|
||||
ImGui.Text("Average");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.Separator();
|
||||
|
||||
foreach (var trackedHook in HookManager.TrackedHooks)
|
||||
foreach (var plugin in pluginManager.InstalledPlugins.Where(plugin => plugin.State == PluginState.Loaded))
|
||||
{
|
||||
try
|
||||
ImGui.Text(plugin.Manifest.Name);
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text($"{plugin.DalamudInterface.UiBuilder.LastDrawTime / 10000f:F4}ms");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text($"{plugin.DalamudInterface.UiBuilder.MaxDrawTime / 10000f:F4}ms");
|
||||
ImGui.NextColumn();
|
||||
|
||||
if (plugin.DalamudInterface.UiBuilder.DrawTimeHistory.Count > 0)
|
||||
{
|
||||
if (!this.showDalamudHooks && trackedHook.Assembly == Assembly.GetExecutingAssembly())
|
||||
continue;
|
||||
|
||||
ImGui.Text($"{trackedHook.Delegate.Target} :: {trackedHook.Delegate.Method.Name}");
|
||||
ImGui.TextDisabled(trackedHook.Assembly.FullName);
|
||||
ImGui.NextColumn();
|
||||
if (!trackedHook.Hook.IsDisposed)
|
||||
{
|
||||
ImGui.Text($"{trackedHook.Hook.Address.ToInt64():X}");
|
||||
if (ImGui.IsItemClicked())
|
||||
{
|
||||
ImGui.SetClipboardText($"{trackedHook.Hook.Address.ToInt64():X}");
|
||||
}
|
||||
|
||||
var processMemoryOffset = trackedHook.InProcessMemory;
|
||||
if (processMemoryOffset.HasValue)
|
||||
{
|
||||
ImGui.Text($"ffxiv_dx11.exe + {processMemoryOffset:X}");
|
||||
if (ImGui.IsItemClicked())
|
||||
{
|
||||
ImGui.SetClipboardText($"ffxiv_dx11.exe+{processMemoryOffset:X}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.NextColumn();
|
||||
|
||||
if (trackedHook.Hook.IsDisposed)
|
||||
{
|
||||
ImGui.Text("Disposed");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.Text(trackedHook.Hook.IsEnabled ? "Enabled" : "Disabled");
|
||||
}
|
||||
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text(trackedHook.Hook.BackendName);
|
||||
|
||||
ImGui.NextColumn();
|
||||
ImGui.Text($"{plugin.DalamudInterface.UiBuilder.DrawTimeHistory.Average() / 10000f:F4}ms");
|
||||
}
|
||||
catch (Exception ex)
|
||||
else
|
||||
{
|
||||
ImGui.Text(ex.Message);
|
||||
ImGui.NextColumn();
|
||||
while (ImGui.GetColumnIndex() != 0) ImGui.NextColumn();
|
||||
ImGui.Text("-");
|
||||
}
|
||||
|
||||
ImGui.NextColumn();
|
||||
}
|
||||
|
||||
ImGui.Columns(1);
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui.BeginTabItem("Framework times"))
|
||||
{
|
||||
var doStats = Framework.StatsEnabled;
|
||||
|
||||
if (ImGui.Checkbox("Enable Framework Update Tracking", ref doStats))
|
||||
{
|
||||
Framework.StatsEnabled = doStats;
|
||||
}
|
||||
|
||||
if (doStats)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button("Reset"))
|
||||
{
|
||||
Framework.StatsHistory.Clear();
|
||||
}
|
||||
|
||||
ImGui.Columns(4);
|
||||
|
||||
ImGui.SetColumnWidth(0, ImGui.GetWindowContentRegionWidth() - 300);
|
||||
ImGui.SetColumnWidth(1, 100f);
|
||||
ImGui.SetColumnWidth(2, 100f);
|
||||
ImGui.SetColumnWidth(3, 100f);
|
||||
|
||||
ImGui.Text("Method");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Last");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Longest");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Average");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.Separator();
|
||||
|
||||
foreach (var handlerHistory in Framework.StatsHistory)
|
||||
{
|
||||
if (handlerHistory.Value.Count == 0)
|
||||
continue;
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.Text($"{handlerHistory.Key}");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text($"{handlerHistory.Value.Last():F4}ms");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text($"{handlerHistory.Value.Max():F4}ms");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text($"{handlerHistory.Value.Average():F4}ms");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Separator();
|
||||
}
|
||||
|
||||
ImGui.Columns();
|
||||
ImGui.Columns(0);
|
||||
}
|
||||
|
||||
if (ImGui.IsWindowAppearing())
|
||||
{
|
||||
HookManager.TrackedHooks.RemoveAll(h => h.Hook.IsDisposed);
|
||||
}
|
||||
|
||||
ImGui.EndTabBar();
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui.BeginTabItem("Hooks"))
|
||||
{
|
||||
ImGui.Columns(4);
|
||||
|
||||
ImGui.SetColumnWidth(0, ImGui.GetWindowContentRegionWidth() - 330);
|
||||
ImGui.SetColumnWidth(1, 180f);
|
||||
ImGui.SetColumnWidth(2, 100f);
|
||||
ImGui.SetColumnWidth(3, 100f);
|
||||
|
||||
ImGui.Text("Detour Method");
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.Text(" ");
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.Checkbox("Show Dalamud Hooks ###showDalamudHooksCheckbox", ref this.showDalamudHooks);
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Address");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Status");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text("Backend");
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.Separator();
|
||||
|
||||
foreach (var trackedHook in HookManager.TrackedHooks)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.showDalamudHooks && trackedHook.Assembly == Assembly.GetExecutingAssembly())
|
||||
continue;
|
||||
|
||||
ImGui.Text($"{trackedHook.Delegate.Target} :: {trackedHook.Delegate.Method.Name}");
|
||||
ImGui.TextDisabled(trackedHook.Assembly.FullName);
|
||||
ImGui.NextColumn();
|
||||
if (!trackedHook.Hook.IsDisposed)
|
||||
{
|
||||
ImGui.Text($"{trackedHook.Hook.Address.ToInt64():X}");
|
||||
if (ImGui.IsItemClicked())
|
||||
{
|
||||
ImGui.SetClipboardText($"{trackedHook.Hook.Address.ToInt64():X}");
|
||||
}
|
||||
|
||||
var processMemoryOffset = trackedHook.InProcessMemory;
|
||||
if (processMemoryOffset.HasValue)
|
||||
{
|
||||
ImGui.Text($"ffxiv_dx11.exe + {processMemoryOffset:X}");
|
||||
if (ImGui.IsItemClicked())
|
||||
{
|
||||
ImGui.SetClipboardText($"ffxiv_dx11.exe+{processMemoryOffset:X}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.NextColumn();
|
||||
|
||||
if (trackedHook.Hook.IsDisposed)
|
||||
{
|
||||
ImGui.Text("Disposed");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.Text(trackedHook.Hook.IsEnabled ? "Enabled" : "Disabled");
|
||||
}
|
||||
|
||||
ImGui.NextColumn();
|
||||
|
||||
ImGui.Text(trackedHook.Hook.BackendName);
|
||||
|
||||
ImGui.NextColumn();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ImGui.Text(ex.Message);
|
||||
ImGui.NextColumn();
|
||||
while (ImGui.GetColumnIndex() != 0) ImGui.NextColumn();
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
}
|
||||
|
||||
ImGui.Columns();
|
||||
}
|
||||
|
||||
if (ImGui.IsWindowAppearing())
|
||||
{
|
||||
HookManager.TrackedHooks.RemoveAll(h => h.Hook.IsDisposed);
|
||||
}
|
||||
|
||||
ImGui.EndTabBar();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,47 +2,46 @@ using Dalamud.Game.ClientState.Objects;
|
|||
using Dalamud.Utility;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for the Actor Table.
|
||||
/// </summary>
|
||||
internal class ActorTableAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for the Actor Table.
|
||||
/// </summary>
|
||||
internal class ActorTableAgingStep : IAgingStep
|
||||
private int index = 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test ActorTable";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
private int index = 0;
|
||||
var objectTable = Service<ObjectTable>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test ActorTable";
|
||||
ImGui.Text("Checking actor table...");
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
if (this.index == objectTable.Length - 1)
|
||||
{
|
||||
var objectTable = Service<ObjectTable>.Get();
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
ImGui.Text("Checking actor table...");
|
||||
|
||||
if (this.index == objectTable.Length - 1)
|
||||
{
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
var actor = objectTable[this.index];
|
||||
this.index++;
|
||||
|
||||
if (actor == null)
|
||||
{
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
Util.ShowObject(actor);
|
||||
var actor = objectTable[this.index];
|
||||
this.index++;
|
||||
|
||||
if (actor == null)
|
||||
{
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
Util.ShowObject(actor);
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,71 +3,70 @@ using Dalamud.Game.Text;
|
|||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for Chat.
|
||||
/// </summary>
|
||||
internal class ChatAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for Chat.
|
||||
/// </summary>
|
||||
internal class ChatAgingStep : IAgingStep
|
||||
private int step = 0;
|
||||
private bool subscribed = false;
|
||||
private bool hasPassed = false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Chat";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
private int step = 0;
|
||||
private bool subscribed = false;
|
||||
private bool hasPassed = false;
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Chat";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
switch (this.step)
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
case 0:
|
||||
chatGui.Print("Testing!");
|
||||
this.step++;
|
||||
|
||||
switch (this.step)
|
||||
{
|
||||
case 0:
|
||||
chatGui.Print("Testing!");
|
||||
this.step++;
|
||||
break;
|
||||
|
||||
break;
|
||||
case 1:
|
||||
ImGui.Text("Type \"/e DALAMUD\" in chat...");
|
||||
|
||||
case 1:
|
||||
ImGui.Text("Type \"/e DALAMUD\" in chat...");
|
||||
if (!this.subscribed)
|
||||
{
|
||||
this.subscribed = true;
|
||||
chatGui.ChatMessage += this.ChatOnOnChatMessage;
|
||||
}
|
||||
|
||||
if (!this.subscribed)
|
||||
{
|
||||
this.subscribed = true;
|
||||
chatGui.ChatMessage += this.ChatOnOnChatMessage;
|
||||
}
|
||||
if (this.hasPassed)
|
||||
{
|
||||
chatGui.ChatMessage -= this.ChatOnOnChatMessage;
|
||||
this.subscribed = false;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
if (this.hasPassed)
|
||||
{
|
||||
chatGui.ChatMessage -= this.ChatOnOnChatMessage;
|
||||
this.subscribed = false;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
break;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
chatGui.ChatMessage -= this.ChatOnOnChatMessage;
|
||||
this.subscribed = false;
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
var chatGui = Service<ChatGui>.Get();
|
||||
|
||||
private void ChatOnOnChatMessage(
|
||||
XivChatType type, uint senderid, ref SeString sender, ref SeString message, ref bool ishandled)
|
||||
chatGui.ChatMessage -= this.ChatOnOnChatMessage;
|
||||
this.subscribed = false;
|
||||
}
|
||||
|
||||
private void ChatOnOnChatMessage(
|
||||
XivChatType type, uint senderid, ref SeString sender, ref SeString message, ref bool ishandled)
|
||||
{
|
||||
if (type == XivChatType.Echo && message.TextValue == "DALAMUD")
|
||||
{
|
||||
if (type == XivChatType.Echo && message.TextValue == "DALAMUD")
|
||||
{
|
||||
this.hasPassed = true;
|
||||
}
|
||||
this.hasPassed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,36 +2,35 @@ using Dalamud.Game.ClientState.Conditions;
|
|||
using ImGuiNET;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for Condition.
|
||||
/// </summary>
|
||||
internal class ConditionAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for Condition.
|
||||
/// </summary>
|
||||
internal class ConditionAgingStep : IAgingStep
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Condition";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Condition";
|
||||
var condition = Service<Condition>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
if (!condition.Any())
|
||||
{
|
||||
var condition = Service<Condition>.Get();
|
||||
|
||||
if (!condition.Any())
|
||||
{
|
||||
Log.Error("No condition flags present.");
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
ImGui.Text("Please jump...");
|
||||
|
||||
return condition[ConditionFlag.Jumping] ? SelfTestStepResult.Pass : SelfTestStepResult.Waiting;
|
||||
Log.Error("No condition flags present.");
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
ImGui.Text("Please jump...");
|
||||
|
||||
return condition[ConditionFlag.Jumping] ? SelfTestStepResult.Pass : SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,70 +1,69 @@
|
|||
using Dalamud.Game.ClientState;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for Territory Change.
|
||||
/// </summary>
|
||||
internal class EnterTerritoryAgingStep : IAgingStep
|
||||
{
|
||||
private readonly ushort territory;
|
||||
private readonly string terriName;
|
||||
private bool subscribed = false;
|
||||
private bool hasPassed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for Territory Change.
|
||||
/// Initializes a new instance of the <see cref="EnterTerritoryAgingStep"/> class.
|
||||
/// </summary>
|
||||
internal class EnterTerritoryAgingStep : IAgingStep
|
||||
/// <param name="terri">The territory to check for.</param>
|
||||
/// <param name="name">Name to show.</param>
|
||||
public EnterTerritoryAgingStep(ushort terri, string name)
|
||||
{
|
||||
private readonly ushort territory;
|
||||
private readonly string terriName;
|
||||
private bool subscribed = false;
|
||||
private bool hasPassed = false;
|
||||
this.terriName = name;
|
||||
this.territory = terri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EnterTerritoryAgingStep"/> class.
|
||||
/// </summary>
|
||||
/// <param name="terri">The territory to check for.</param>
|
||||
/// <param name="name">Name to show.</param>
|
||||
public EnterTerritoryAgingStep(ushort terri, string name)
|
||||
/// <inheritdoc/>
|
||||
public string Name => $"Enter Terri: {this.terriName}";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
ImGui.TextUnformatted(this.Name);
|
||||
|
||||
if (!this.subscribed)
|
||||
{
|
||||
this.terriName = name;
|
||||
this.territory = terri;
|
||||
clientState.TerritoryChanged += this.ClientStateOnTerritoryChanged;
|
||||
this.subscribed = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => $"Enter Terri: {this.terriName}";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
if (this.hasPassed)
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
ImGui.TextUnformatted(this.Name);
|
||||
|
||||
if (!this.subscribed)
|
||||
{
|
||||
clientState.TerritoryChanged += this.ClientStateOnTerritoryChanged;
|
||||
this.subscribed = true;
|
||||
}
|
||||
|
||||
if (this.hasPassed)
|
||||
{
|
||||
clientState.TerritoryChanged -= this.ClientStateOnTerritoryChanged;
|
||||
this.subscribed = false;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
clientState.TerritoryChanged -= this.ClientStateOnTerritoryChanged;
|
||||
this.subscribed = false;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
private void ClientStateOnTerritoryChanged(object sender, ushort e)
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
clientState.TerritoryChanged -= this.ClientStateOnTerritoryChanged;
|
||||
this.subscribed = false;
|
||||
}
|
||||
|
||||
private void ClientStateOnTerritoryChanged(object sender, ushort e)
|
||||
{
|
||||
if (e == this.territory)
|
||||
{
|
||||
if (e == this.territory)
|
||||
{
|
||||
this.hasPassed = true;
|
||||
}
|
||||
this.hasPassed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,47 +2,46 @@ using Dalamud.Game.ClientState.Fates;
|
|||
using Dalamud.Utility;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for the Fate Table.
|
||||
/// </summary>
|
||||
internal class FateTableAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for the Fate Table.
|
||||
/// </summary>
|
||||
internal class FateTableAgingStep : IAgingStep
|
||||
private int index = 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test FateTable";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
private int index = 0;
|
||||
var fateTable = Service<FateTable>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test FateTable";
|
||||
ImGui.Text("Checking fate table...");
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
if (this.index == fateTable.Length - 1)
|
||||
{
|
||||
var fateTable = Service<FateTable>.Get();
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
ImGui.Text("Checking fate table...");
|
||||
|
||||
if (this.index == fateTable.Length - 1)
|
||||
{
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
var actor = fateTable[this.index];
|
||||
this.index++;
|
||||
|
||||
if (actor == null)
|
||||
{
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
Util.ShowObject(actor);
|
||||
var actor = fateTable[this.index];
|
||||
this.index++;
|
||||
|
||||
if (actor == null)
|
||||
{
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
Util.ShowObject(actor);
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,36 @@
|
|||
using Dalamud.Game.ClientState.GamePad;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for the Gamepad State.
|
||||
/// </summary>
|
||||
internal class GamepadStateAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for the Gamepad State.
|
||||
/// </summary>
|
||||
internal class GamepadStateAgingStep : IAgingStep
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test GamePadState";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test GamePadState";
|
||||
var gamepadState = Service<GamepadState>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
ImGui.Text("Hold down North, East, L1");
|
||||
|
||||
if (gamepadState.Pressed(GamepadButtons.North) == 1
|
||||
&& gamepadState.Pressed(GamepadButtons.East) == 1
|
||||
&& gamepadState.Pressed(GamepadButtons.L1) == 1)
|
||||
{
|
||||
var gamepadState = Service<GamepadState>.Get();
|
||||
|
||||
ImGui.Text("Hold down North, East, L1");
|
||||
|
||||
if (gamepadState.Pressed(GamepadButtons.North) == 1
|
||||
&& gamepadState.Pressed(GamepadButtons.East) == 1
|
||||
&& gamepadState.Pressed(GamepadButtons.L1) == 1)
|
||||
{
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,34 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test dedicated to handling of Access Violations.
|
||||
/// </summary>
|
||||
internal class HandledExceptionAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test dedicated to handling of Access Violations.
|
||||
/// </summary>
|
||||
internal class HandledExceptionAgingStep : IAgingStep
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Handled Exception";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Handled Exception";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
Marshal.ReadByte(IntPtr.Zero);
|
||||
}
|
||||
catch (AccessViolationException)
|
||||
{
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Fail;
|
||||
Marshal.ReadByte(IntPtr.Zero);
|
||||
}
|
||||
catch (AccessViolationException)
|
||||
{
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
return SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,58 +1,57 @@
|
|||
using Dalamud.Game.Gui;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for the Hover events.
|
||||
/// </summary>
|
||||
internal class HoverAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for the Hover events.
|
||||
/// </summary>
|
||||
internal class HoverAgingStep : IAgingStep
|
||||
private bool clearedItem = false;
|
||||
private bool clearedAction = false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Hover";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
private bool clearedItem = false;
|
||||
private bool clearedAction = false;
|
||||
var gameGui = Service<GameGui>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Hover";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
if (!this.clearedItem)
|
||||
{
|
||||
var gameGui = Service<GameGui>.Get();
|
||||
ImGui.Text("Hover WHM soul crystal...");
|
||||
|
||||
if (!this.clearedItem)
|
||||
if (gameGui.HoveredItem == 4547)
|
||||
{
|
||||
ImGui.Text("Hover WHM soul crystal...");
|
||||
|
||||
if (gameGui.HoveredItem == 4547)
|
||||
{
|
||||
this.clearedItem = true;
|
||||
}
|
||||
this.clearedItem = true;
|
||||
}
|
||||
|
||||
if (!this.clearedAction)
|
||||
{
|
||||
ImGui.Text("Hover \"Open Linkshells\" action...");
|
||||
|
||||
if (gameGui.HoveredAction != null &&
|
||||
gameGui.HoveredAction.ActionKind == HoverActionKind.MainCommand &&
|
||||
gameGui.HoveredAction.ActionID == 28)
|
||||
{
|
||||
this.clearedAction = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.clearedItem && this.clearedAction)
|
||||
{
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
if (!this.clearedAction)
|
||||
{
|
||||
// ignored
|
||||
ImGui.Text("Hover \"Open Linkshells\" action...");
|
||||
|
||||
if (gameGui.HoveredAction != null &&
|
||||
gameGui.HoveredAction.ActionKind == HoverActionKind.MainCommand &&
|
||||
gameGui.HoveredAction.ActionID == 28)
|
||||
{
|
||||
this.clearedAction = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.clearedItem && this.clearedAction)
|
||||
{
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,23 @@
|
|||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for test implementations.
|
||||
/// </summary>
|
||||
internal interface IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for test implementations.
|
||||
/// Gets the name of the test.
|
||||
/// </summary>
|
||||
internal interface IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name of the test.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Run the test step, once per frame it is active.
|
||||
/// </summary>
|
||||
/// <returns>The result of this frame, test is discarded once a result other than <see cref="SelfTestStepResult.Waiting"/> is returned.</returns>
|
||||
public SelfTestStepResult RunStep();
|
||||
/// <summary>
|
||||
/// Run the test step, once per frame it is active.
|
||||
/// </summary>
|
||||
/// <returns>The result of this frame, test is discarded once a result other than <see cref="SelfTestStepResult.Waiting"/> is returned.</returns>
|
||||
public SelfTestStepResult RunStep();
|
||||
|
||||
/// <summary>
|
||||
/// Clean up this test.
|
||||
/// </summary>
|
||||
public void CleanUp();
|
||||
}
|
||||
/// <summary>
|
||||
/// Clean up this test.
|
||||
/// </summary>
|
||||
public void CleanUp();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,38 @@
|
|||
using Dalamud.Game.ClientState.Keys;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for the Key State.
|
||||
/// </summary>
|
||||
internal class KeyStateAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for the Key State.
|
||||
/// </summary>
|
||||
internal class KeyStateAgingStep : IAgingStep
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test KeyState";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test KeyState";
|
||||
var keyState = Service<KeyState>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
ImGui.Text("Hold down D,A,L,M,U");
|
||||
|
||||
if (keyState[VirtualKey.D]
|
||||
&& keyState[VirtualKey.A]
|
||||
&& keyState[VirtualKey.L]
|
||||
&& keyState[VirtualKey.M]
|
||||
&& keyState[VirtualKey.U])
|
||||
{
|
||||
var keyState = Service<KeyState>.Get();
|
||||
|
||||
ImGui.Text("Hold down D,A,L,M,U");
|
||||
|
||||
if (keyState[VirtualKey.D]
|
||||
&& keyState[VirtualKey.A]
|
||||
&& keyState[VirtualKey.L]
|
||||
&& keyState[VirtualKey.M]
|
||||
&& keyState[VirtualKey.U])
|
||||
{
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,57 +3,56 @@ using System;
|
|||
using Dalamud.Game.ClientState;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for the login events.
|
||||
/// </summary>
|
||||
internal class LoginEventAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for the login events.
|
||||
/// </summary>
|
||||
internal class LoginEventAgingStep : IAgingStep
|
||||
private bool subscribed = false;
|
||||
private bool hasPassed = false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Log-In";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
private bool subscribed = false;
|
||||
private bool hasPassed = false;
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Log-In";
|
||||
ImGui.Text("Log in now...");
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
if (!this.subscribed)
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
ImGui.Text("Log in now...");
|
||||
|
||||
if (!this.subscribed)
|
||||
{
|
||||
clientState.Login += this.ClientStateOnOnLogin;
|
||||
this.subscribed = true;
|
||||
}
|
||||
|
||||
if (this.hasPassed)
|
||||
{
|
||||
clientState.Login -= this.ClientStateOnOnLogin;
|
||||
this.subscribed = false;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
clientState.Login += this.ClientStateOnOnLogin;
|
||||
this.subscribed = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
if (this.hasPassed)
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
if (this.subscribed)
|
||||
{
|
||||
clientState.Login -= this.ClientStateOnOnLogin;
|
||||
this.subscribed = false;
|
||||
}
|
||||
clientState.Login -= this.ClientStateOnOnLogin;
|
||||
this.subscribed = false;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
private void ClientStateOnOnLogin(object sender, EventArgs e)
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
if (this.subscribed)
|
||||
{
|
||||
this.hasPassed = true;
|
||||
clientState.Login -= this.ClientStateOnOnLogin;
|
||||
this.subscribed = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClientStateOnOnLogin(object sender, EventArgs e)
|
||||
{
|
||||
this.hasPassed = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,57 +3,56 @@ using System;
|
|||
using Dalamud.Game.ClientState;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for the login events.
|
||||
/// </summary>
|
||||
internal class LogoutEventAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for the login events.
|
||||
/// </summary>
|
||||
internal class LogoutEventAgingStep : IAgingStep
|
||||
private bool subscribed = false;
|
||||
private bool hasPassed = false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Log-In";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
private bool subscribed = false;
|
||||
private bool hasPassed = false;
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Log-In";
|
||||
ImGui.Text("Log out now...");
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
if (!this.subscribed)
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
ImGui.Text("Log out now...");
|
||||
|
||||
if (!this.subscribed)
|
||||
{
|
||||
clientState.Logout += this.ClientStateOnOnLogout;
|
||||
this.subscribed = true;
|
||||
}
|
||||
|
||||
if (this.hasPassed)
|
||||
{
|
||||
clientState.Logout -= this.ClientStateOnOnLogout;
|
||||
this.subscribed = false;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
clientState.Logout += this.ClientStateOnOnLogout;
|
||||
this.subscribed = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
if (this.hasPassed)
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
if (this.subscribed)
|
||||
{
|
||||
clientState.Logout -= this.ClientStateOnOnLogout;
|
||||
this.subscribed = false;
|
||||
}
|
||||
clientState.Logout -= this.ClientStateOnOnLogout;
|
||||
this.subscribed = false;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
private void ClientStateOnOnLogout(object sender, EventArgs e)
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
if (this.subscribed)
|
||||
{
|
||||
this.hasPassed = true;
|
||||
clientState.Logout -= this.ClientStateOnOnLogout;
|
||||
this.subscribed = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClientStateOnOnLogout(object sender, EventArgs e)
|
||||
{
|
||||
this.hasPassed = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,38 +5,37 @@ using Dalamud.Data;
|
|||
using Dalamud.Utility;
|
||||
using Lumina.Excel;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for Lumina.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">ExcelRow to run test on.</typeparam>
|
||||
internal class LuminaAgingStep<T> : IAgingStep
|
||||
where T : ExcelRow
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for Lumina.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">ExcelRow to run test on.</typeparam>
|
||||
internal class LuminaAgingStep<T> : IAgingStep
|
||||
where T : ExcelRow
|
||||
private int step = 0;
|
||||
private List<T> rows;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Lumina";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
private int step = 0;
|
||||
private List<T> rows;
|
||||
var dataManager = Service<DataManager>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Lumina";
|
||||
this.rows ??= dataManager.GetExcelSheet<T>().ToList();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
var dataManager = Service<DataManager>.Get();
|
||||
Util.ShowObject(this.rows[this.step]);
|
||||
|
||||
this.rows ??= dataManager.GetExcelSheet<T>().ToList();
|
||||
this.step++;
|
||||
return this.step >= this.rows.Count ? SelfTestStepResult.Pass : SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
Util.ShowObject(this.rows[this.step]);
|
||||
|
||||
this.step++;
|
||||
return this.step >= this.rows.Count ? SelfTestStepResult.Pass : SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,57 +2,56 @@ using Dalamud.Game.Gui.PartyFinder;
|
|||
using Dalamud.Game.Gui.PartyFinder.Types;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for Party Finder events.
|
||||
/// </summary>
|
||||
internal class PartyFinderAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for Party Finder events.
|
||||
/// </summary>
|
||||
internal class PartyFinderAgingStep : IAgingStep
|
||||
private bool subscribed = false;
|
||||
private bool hasPassed = false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Party Finder";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
private bool subscribed = false;
|
||||
private bool hasPassed = false;
|
||||
var partyFinderGui = Service<PartyFinderGui>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Party Finder";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
if (!this.subscribed)
|
||||
{
|
||||
var partyFinderGui = Service<PartyFinderGui>.Get();
|
||||
|
||||
if (!this.subscribed)
|
||||
{
|
||||
partyFinderGui.ReceiveListing += this.PartyFinderOnReceiveListing;
|
||||
this.subscribed = true;
|
||||
}
|
||||
|
||||
if (this.hasPassed)
|
||||
{
|
||||
partyFinderGui.ReceiveListing -= this.PartyFinderOnReceiveListing;
|
||||
this.subscribed = false;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
ImGui.Text("Open Party Finder");
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
partyFinderGui.ReceiveListing += this.PartyFinderOnReceiveListing;
|
||||
this.subscribed = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
if (this.hasPassed)
|
||||
{
|
||||
var partyFinderGui = Service<PartyFinderGui>.Get();
|
||||
|
||||
if (this.subscribed)
|
||||
{
|
||||
partyFinderGui.ReceiveListing -= this.PartyFinderOnReceiveListing;
|
||||
this.subscribed = false;
|
||||
}
|
||||
partyFinderGui.ReceiveListing -= this.PartyFinderOnReceiveListing;
|
||||
this.subscribed = false;
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
private void PartyFinderOnReceiveListing(PartyFinderListing listing, PartyFinderListingEventArgs args)
|
||||
ImGui.Text("Open Party Finder");
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
var partyFinderGui = Service<PartyFinderGui>.Get();
|
||||
|
||||
if (this.subscribed)
|
||||
{
|
||||
this.hasPassed = true;
|
||||
partyFinderGui.ReceiveListing -= this.PartyFinderOnReceiveListing;
|
||||
this.subscribed = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void PartyFinderOnReceiveListing(PartyFinderListing listing, PartyFinderListingEventArgs args)
|
||||
{
|
||||
this.hasPassed = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,74 +3,73 @@ using Dalamud.Game.ClientState.Objects.SubKinds;
|
|||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for targets.
|
||||
/// </summary>
|
||||
internal class TargetAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for targets.
|
||||
/// </summary>
|
||||
internal class TargetAgingStep : IAgingStep
|
||||
private int step = 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Target";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
private int step = 0;
|
||||
var targetManager = Service<TargetManager>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Target";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
switch (this.step)
|
||||
{
|
||||
var targetManager = Service<TargetManager>.Get();
|
||||
case 0:
|
||||
targetManager.ClearTarget();
|
||||
targetManager.ClearFocusTarget();
|
||||
|
||||
switch (this.step)
|
||||
{
|
||||
case 0:
|
||||
targetManager.ClearTarget();
|
||||
targetManager.ClearFocusTarget();
|
||||
this.step++;
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ImGui.Text("Target a player...");
|
||||
|
||||
var cTarget = targetManager.Target;
|
||||
if (cTarget is PlayerCharacter)
|
||||
{
|
||||
this.step++;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ImGui.Text("Target a player...");
|
||||
case 2:
|
||||
ImGui.Text("Focus-Target a Battle NPC...");
|
||||
|
||||
var cTarget = targetManager.Target;
|
||||
if (cTarget is PlayerCharacter)
|
||||
{
|
||||
this.step++;
|
||||
}
|
||||
var fTarget = targetManager.FocusTarget;
|
||||
if (fTarget is BattleNpc)
|
||||
{
|
||||
this.step++;
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ImGui.Text("Focus-Target a Battle NPC...");
|
||||
case 3:
|
||||
ImGui.Text("Soft-Target an EventObj...");
|
||||
|
||||
var fTarget = targetManager.FocusTarget;
|
||||
if (fTarget is BattleNpc)
|
||||
{
|
||||
this.step++;
|
||||
}
|
||||
var sTarget = targetManager.FocusTarget;
|
||||
if (sTarget is EventObj)
|
||||
{
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
ImGui.Text("Soft-Target an EventObj...");
|
||||
|
||||
var sTarget = targetManager.FocusTarget;
|
||||
if (sTarget is EventObj)
|
||||
{
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Waiting;
|
||||
break;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
return SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,29 @@
|
|||
using Dalamud.Game.Gui.Toast;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test setup for toasts.
|
||||
/// </summary>
|
||||
internal class ToastAgingStep : IAgingStep
|
||||
{
|
||||
/// <summary>
|
||||
/// Test setup for toasts.
|
||||
/// </summary>
|
||||
internal class ToastAgingStep : IAgingStep
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Toasts";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string Name => "Test Toasts";
|
||||
var toastGui = Service<ToastGui>.Get();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
var toastGui = Service<ToastGui>.Get();
|
||||
toastGui.ShowNormal("Normal Toast");
|
||||
toastGui.ShowError("Error Toast");
|
||||
|
||||
toastGui.ShowNormal("Normal Toast");
|
||||
toastGui.ShowError("Error Toast");
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
return SelfTestStepResult.Pass;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +1,37 @@
|
|||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
|
||||
|
||||
/// <summary>
|
||||
/// Test that waits N frames.
|
||||
/// </summary>
|
||||
internal class WaitFramesAgingStep : IAgingStep
|
||||
{
|
||||
private readonly int frames;
|
||||
private int cFrames;
|
||||
|
||||
/// <summary>
|
||||
/// Test that waits N frames.
|
||||
/// Initializes a new instance of the <see cref="WaitFramesAgingStep"/> class.
|
||||
/// </summary>
|
||||
internal class WaitFramesAgingStep : IAgingStep
|
||||
/// <param name="frames">Amount of frames to wait.</param>
|
||||
public WaitFramesAgingStep(int frames)
|
||||
{
|
||||
private readonly int frames;
|
||||
private int cFrames;
|
||||
this.frames = frames;
|
||||
this.cFrames = frames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WaitFramesAgingStep"/> class.
|
||||
/// </summary>
|
||||
/// <param name="frames">Amount of frames to wait.</param>
|
||||
public WaitFramesAgingStep(int frames)
|
||||
{
|
||||
this.frames = frames;
|
||||
this.cFrames = frames;
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public string Name => $"Wait {this.cFrames} frames";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Name => $"Wait {this.cFrames} frames";
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
this.cFrames--;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SelfTestStepResult RunStep()
|
||||
{
|
||||
this.cFrames--;
|
||||
return this.cFrames <= 0 ? SelfTestStepResult.Pass : SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
return this.cFrames <= 0 ? SelfTestStepResult.Pass : SelfTestStepResult.Waiting;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
this.cFrames = this.frames;
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public void CleanUp()
|
||||
{
|
||||
this.cFrames = this.frames;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,27 @@
|
|||
namespace Dalamud.Interface.Internal.Windows.SelfTest
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest;
|
||||
|
||||
/// <summary>
|
||||
/// Enum declaring result states of tests.
|
||||
/// </summary>
|
||||
internal enum SelfTestStepResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum declaring result states of tests.
|
||||
/// Test was not ran.
|
||||
/// </summary>
|
||||
internal enum SelfTestStepResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Test was not ran.
|
||||
/// </summary>
|
||||
NotRan,
|
||||
NotRan,
|
||||
|
||||
/// <summary>
|
||||
/// Test is waiting for completion.
|
||||
/// </summary>
|
||||
Waiting,
|
||||
/// <summary>
|
||||
/// Test is waiting for completion.
|
||||
/// </summary>
|
||||
Waiting,
|
||||
|
||||
/// <summary>
|
||||
/// Test has failed.
|
||||
/// </summary>
|
||||
Fail,
|
||||
/// <summary>
|
||||
/// Test has failed.
|
||||
/// </summary>
|
||||
Fail,
|
||||
|
||||
/// <summary>
|
||||
/// Test has passed.
|
||||
/// </summary>
|
||||
Pass,
|
||||
}
|
||||
/// <summary>
|
||||
/// Test has passed.
|
||||
/// </summary>
|
||||
Pass,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,246 +11,245 @@ using Dalamud.Logging.Internal;
|
|||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest
|
||||
namespace Dalamud.Interface.Internal.Windows.SelfTest;
|
||||
|
||||
/// <summary>
|
||||
/// Window for the Self-Test logic.
|
||||
/// </summary>
|
||||
internal class SelfTestWindow : Window
|
||||
{
|
||||
private static readonly ModuleLog Log = new("AGING");
|
||||
|
||||
private readonly List<IAgingStep> steps =
|
||||
new()
|
||||
{
|
||||
new LoginEventAgingStep(),
|
||||
new WaitFramesAgingStep(1000),
|
||||
new EnterTerritoryAgingStep(148, "Central Shroud"),
|
||||
new ActorTableAgingStep(),
|
||||
new FateTableAgingStep(),
|
||||
new ConditionAgingStep(),
|
||||
new ToastAgingStep(),
|
||||
new TargetAgingStep(),
|
||||
new KeyStateAgingStep(),
|
||||
new GamepadStateAgingStep(),
|
||||
new ChatAgingStep(),
|
||||
new HoverAgingStep(),
|
||||
new LuminaAgingStep<TerritoryType>(),
|
||||
new PartyFinderAgingStep(),
|
||||
new HandledExceptionAgingStep(),
|
||||
new LogoutEventAgingStep(),
|
||||
};
|
||||
|
||||
private readonly List<(SelfTestStepResult Result, TimeSpan? Duration)> stepResults = new();
|
||||
|
||||
private bool selfTestRunning = false;
|
||||
private int currentStep = 0;
|
||||
|
||||
private DateTimeOffset lastTestStart;
|
||||
|
||||
/// <summary>
|
||||
/// Window for the Self-Test logic.
|
||||
/// Initializes a new instance of the <see cref="SelfTestWindow"/> class.
|
||||
/// </summary>
|
||||
internal class SelfTestWindow : Window
|
||||
public SelfTestWindow()
|
||||
: base("Dalamud Self-Test", ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)
|
||||
{
|
||||
private static readonly ModuleLog Log = new("AGING");
|
||||
this.Size = new Vector2(800, 800);
|
||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
||||
|
||||
private readonly List<IAgingStep> steps =
|
||||
new()
|
||||
{
|
||||
new LoginEventAgingStep(),
|
||||
new WaitFramesAgingStep(1000),
|
||||
new EnterTerritoryAgingStep(148, "Central Shroud"),
|
||||
new ActorTableAgingStep(),
|
||||
new FateTableAgingStep(),
|
||||
new ConditionAgingStep(),
|
||||
new ToastAgingStep(),
|
||||
new TargetAgingStep(),
|
||||
new KeyStateAgingStep(),
|
||||
new GamepadStateAgingStep(),
|
||||
new ChatAgingStep(),
|
||||
new HoverAgingStep(),
|
||||
new LuminaAgingStep<TerritoryType>(),
|
||||
new PartyFinderAgingStep(),
|
||||
new HandledExceptionAgingStep(),
|
||||
new LogoutEventAgingStep(),
|
||||
};
|
||||
this.RespectCloseHotkey = false;
|
||||
}
|
||||
|
||||
private readonly List<(SelfTestStepResult Result, TimeSpan? Duration)> stepResults = new();
|
||||
|
||||
private bool selfTestRunning = false;
|
||||
private int currentStep = 0;
|
||||
|
||||
private DateTimeOffset lastTestStart;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SelfTestWindow"/> class.
|
||||
/// </summary>
|
||||
public SelfTestWindow()
|
||||
: base("Dalamud Self-Test", ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
if (this.selfTestRunning)
|
||||
{
|
||||
this.Size = new Vector2(800, 800);
|
||||
this.SizeCondition = ImGuiCond.FirstUseEver;
|
||||
|
||||
this.RespectCloseHotkey = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Draw()
|
||||
{
|
||||
if (this.selfTestRunning)
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop))
|
||||
{
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop))
|
||||
{
|
||||
this.StopTests();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.StepForward))
|
||||
{
|
||||
this.stepResults.Add((SelfTestStepResult.NotRan, null));
|
||||
this.currentStep++;
|
||||
this.lastTestStart = DateTimeOffset.Now;
|
||||
|
||||
if (this.currentStep >= this.steps.Count)
|
||||
{
|
||||
this.StopTests();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
|
||||
{
|
||||
this.selfTestRunning = true;
|
||||
this.currentStep = 0;
|
||||
this.stepResults.Clear();
|
||||
this.lastTestStart = DateTimeOffset.Now;
|
||||
}
|
||||
this.StopTests();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.TextUnformatted($"Step: {this.currentStep} / {this.steps.Count}");
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
this.DrawResultTable();
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
if (this.currentStep >= this.steps.Count)
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.StepForward))
|
||||
{
|
||||
if (this.selfTestRunning)
|
||||
this.stepResults.Add((SelfTestStepResult.NotRan, null));
|
||||
this.currentStep++;
|
||||
this.lastTestStart = DateTimeOffset.Now;
|
||||
|
||||
if (this.currentStep >= this.steps.Count)
|
||||
{
|
||||
this.StopTests();
|
||||
}
|
||||
|
||||
if (this.stepResults.Any(x => x.Result == SelfTestStepResult.Fail))
|
||||
{
|
||||
ImGui.TextColored(ImGuiColors.DalamudRed, "One or more checks failed!");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TextColored(ImGuiColors.HealerGreen, "All checks passed!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.selfTestRunning)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
var step = this.steps[this.currentStep];
|
||||
ImGui.TextUnformatted($"Current: {step.Name}");
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
SelfTestStepResult result;
|
||||
try
|
||||
{
|
||||
result = step.RunStep();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Step failed: {step.Name}");
|
||||
result = SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
if (result != SelfTestStepResult.Waiting)
|
||||
{
|
||||
var duration = DateTimeOffset.Now - this.lastTestStart;
|
||||
this.currentStep++;
|
||||
this.stepResults.Add((result, duration));
|
||||
|
||||
this.selfTestRunning = true;
|
||||
this.currentStep = 0;
|
||||
this.stepResults.Clear();
|
||||
this.lastTestStart = DateTimeOffset.Now;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawResultTable()
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.TextUnformatted($"Step: {this.currentStep} / {this.steps.Count}");
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
this.DrawResultTable();
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
if (this.currentStep >= this.steps.Count)
|
||||
{
|
||||
if (ImGui.BeginTable("agingResultTable", 4, ImGuiTableFlags.Borders))
|
||||
if (this.selfTestRunning)
|
||||
{
|
||||
ImGui.TableSetupColumn("###index", ImGuiTableColumnFlags.WidthFixed, 12f);
|
||||
ImGui.TableSetupColumn("Name");
|
||||
ImGui.TableSetupColumn("Result", ImGuiTableColumnFlags.WidthFixed, 40f);
|
||||
ImGui.TableSetupColumn("Duration", ImGuiTableColumnFlags.WidthFixed, 90f);
|
||||
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
for (var i = 0; i < this.steps.Count; i++)
|
||||
{
|
||||
var step = this.steps[i];
|
||||
ImGui.TableNextRow();
|
||||
|
||||
ImGui.TableSetColumnIndex(0);
|
||||
ImGui.Text(i.ToString());
|
||||
|
||||
ImGui.TableSetColumnIndex(1);
|
||||
ImGui.Text(step.Name);
|
||||
|
||||
ImGui.TableSetColumnIndex(2);
|
||||
ImGui.PushFont(Interface.Internal.InterfaceManager.MonoFont);
|
||||
if (this.stepResults.Count > i)
|
||||
{
|
||||
var result = this.stepResults[i];
|
||||
|
||||
switch (result.Result)
|
||||
{
|
||||
case SelfTestStepResult.Pass:
|
||||
ImGui.TextColored(ImGuiColors.HealerGreen, "PASS");
|
||||
break;
|
||||
case SelfTestStepResult.Fail:
|
||||
ImGui.TextColored(ImGuiColors.DalamudRed, "FAIL");
|
||||
break;
|
||||
default:
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, "NR");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.selfTestRunning && this.currentStep == i)
|
||||
{
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, "WAIT");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, "NR");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGui.TableSetColumnIndex(3);
|
||||
if (this.stepResults.Count > i)
|
||||
{
|
||||
var (_, duration) = this.stepResults[i];
|
||||
|
||||
if (duration.HasValue)
|
||||
{
|
||||
ImGui.TextUnformatted(duration.Value.ToString("g"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.selfTestRunning && this.currentStep == i)
|
||||
{
|
||||
ImGui.TextUnformatted((DateTimeOffset.Now - this.lastTestStart).ToString("g"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndTable();
|
||||
this.StopTests();
|
||||
}
|
||||
|
||||
if (this.stepResults.Any(x => x.Result == SelfTestStepResult.Fail))
|
||||
{
|
||||
ImGui.TextColored(ImGuiColors.DalamudRed, "One or more checks failed!");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TextColored(ImGuiColors.HealerGreen, "All checks passed!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private void StopTests()
|
||||
if (!this.selfTestRunning)
|
||||
{
|
||||
this.selfTestRunning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var agingStep in this.steps)
|
||||
ImGui.Separator();
|
||||
|
||||
var step = this.steps[this.currentStep];
|
||||
ImGui.TextUnformatted($"Current: {step.Name}");
|
||||
|
||||
ImGuiHelpers.ScaledDummy(10);
|
||||
|
||||
SelfTestStepResult result;
|
||||
try
|
||||
{
|
||||
result = step.RunStep();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Step failed: {step.Name}");
|
||||
result = SelfTestStepResult.Fail;
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
if (result != SelfTestStepResult.Waiting)
|
||||
{
|
||||
var duration = DateTimeOffset.Now - this.lastTestStart;
|
||||
this.currentStep++;
|
||||
this.stepResults.Add((result, duration));
|
||||
|
||||
this.lastTestStart = DateTimeOffset.Now;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawResultTable()
|
||||
{
|
||||
if (ImGui.BeginTable("agingResultTable", 4, ImGuiTableFlags.Borders))
|
||||
{
|
||||
ImGui.TableSetupColumn("###index", ImGuiTableColumnFlags.WidthFixed, 12f);
|
||||
ImGui.TableSetupColumn("Name");
|
||||
ImGui.TableSetupColumn("Result", ImGuiTableColumnFlags.WidthFixed, 40f);
|
||||
ImGui.TableSetupColumn("Duration", ImGuiTableColumnFlags.WidthFixed, 90f);
|
||||
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
for (var i = 0; i < this.steps.Count; i++)
|
||||
{
|
||||
try
|
||||
var step = this.steps[i];
|
||||
ImGui.TableNextRow();
|
||||
|
||||
ImGui.TableSetColumnIndex(0);
|
||||
ImGui.Text(i.ToString());
|
||||
|
||||
ImGui.TableSetColumnIndex(1);
|
||||
ImGui.Text(step.Name);
|
||||
|
||||
ImGui.TableSetColumnIndex(2);
|
||||
ImGui.PushFont(Interface.Internal.InterfaceManager.MonoFont);
|
||||
if (this.stepResults.Count > i)
|
||||
{
|
||||
agingStep.CleanUp();
|
||||
var result = this.stepResults[i];
|
||||
|
||||
switch (result.Result)
|
||||
{
|
||||
case SelfTestStepResult.Pass:
|
||||
ImGui.TextColored(ImGuiColors.HealerGreen, "PASS");
|
||||
break;
|
||||
case SelfTestStepResult.Fail:
|
||||
ImGui.TextColored(ImGuiColors.DalamudRed, "FAIL");
|
||||
break;
|
||||
default:
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, "NR");
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
else
|
||||
{
|
||||
Log.Error(ex, $"Could not clean up AgingStep: {agingStep.Name}");
|
||||
if (this.selfTestRunning && this.currentStep == i)
|
||||
{
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, "WAIT");
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TextColored(ImGuiColors.DalamudGrey, "NR");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGui.TableSetColumnIndex(3);
|
||||
if (this.stepResults.Count > i)
|
||||
{
|
||||
var (_, duration) = this.stepResults[i];
|
||||
|
||||
if (duration.HasValue)
|
||||
{
|
||||
ImGui.TextUnformatted(duration.Value.ToString("g"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.selfTestRunning && this.currentStep == i)
|
||||
{
|
||||
ImGui.TextUnformatted((DateTimeOffset.Now - this.lastTestStart).ToString("g"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
private void StopTests()
|
||||
{
|
||||
this.selfTestRunning = false;
|
||||
|
||||
foreach (var agingStep in this.steps)
|
||||
{
|
||||
try
|
||||
{
|
||||
agingStep.CleanUp();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"Could not clean up AgingStep: {agingStep.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -15,388 +15,387 @@ using ImGuiNET;
|
|||
using Lumina.Excel.GeneratedSheets;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Interface.Internal.Windows.StyleEditor
|
||||
namespace Dalamud.Interface.Internal.Windows.StyleEditor;
|
||||
|
||||
/// <summary>
|
||||
/// Window for the Dalamud style editor.
|
||||
/// </summary>
|
||||
public class StyleEditorWindow : Window
|
||||
{
|
||||
private ImGuiColorEditFlags alphaFlags = ImGuiColorEditFlags.AlphaPreviewHalf;
|
||||
|
||||
private int currentSel = 0;
|
||||
private string initialStyle = string.Empty;
|
||||
private bool didSave = false;
|
||||
|
||||
private string renameText = string.Empty;
|
||||
private bool renameModalDrawing = false;
|
||||
|
||||
/// <summary>
|
||||
/// Window for the Dalamud style editor.
|
||||
/// Initializes a new instance of the <see cref="StyleEditorWindow"/> class.
|
||||
/// </summary>
|
||||
public class StyleEditorWindow : Window
|
||||
public StyleEditorWindow()
|
||||
: base("Dalamud Style Editor")
|
||||
{
|
||||
private ImGuiColorEditFlags alphaFlags = ImGuiColorEditFlags.AlphaPreviewHalf;
|
||||
|
||||
private int currentSel = 0;
|
||||
private string initialStyle = string.Empty;
|
||||
private bool didSave = false;
|
||||
|
||||
private string renameText = string.Empty;
|
||||
private bool renameModalDrawing = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StyleEditorWindow"/> class.
|
||||
/// </summary>
|
||||
public StyleEditorWindow()
|
||||
: base("Dalamud Style Editor")
|
||||
this.IsOpen = true;
|
||||
this.SizeConstraints = new WindowSizeConstraints
|
||||
{
|
||||
this.IsOpen = true;
|
||||
this.SizeConstraints = new WindowSizeConstraints
|
||||
{
|
||||
MinimumSize = new Vector2(890, 560),
|
||||
MaximumSize = new Vector2(10000, 10000),
|
||||
};
|
||||
}
|
||||
MinimumSize = new Vector2(890, 560),
|
||||
MaximumSize = new Vector2(10000, 10000),
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnOpen()
|
||||
{
|
||||
this.didSave = false;
|
||||
/// <inheritdoc />
|
||||
public override void OnOpen()
|
||||
{
|
||||
this.didSave = false;
|
||||
|
||||
var config = Service<DalamudConfiguration>.Get();
|
||||
config.SavedStyles ??= new List<StyleModel>();
|
||||
this.currentSel = config.SavedStyles.FindIndex(x => x.Name == config.ChosenStyle);
|
||||
var config = Service<DalamudConfiguration>.Get();
|
||||
config.SavedStyles ??= new List<StyleModel>();
|
||||
this.currentSel = config.SavedStyles.FindIndex(x => x.Name == config.ChosenStyle);
|
||||
|
||||
this.initialStyle = config.ChosenStyle;
|
||||
this.initialStyle = config.ChosenStyle;
|
||||
|
||||
base.OnOpen();
|
||||
}
|
||||
base.OnOpen();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnClose()
|
||||
{
|
||||
if (!this.didSave)
|
||||
{
|
||||
var config = Service<DalamudConfiguration>.Get();
|
||||
var newStyle = config.SavedStyles.FirstOrDefault(x => x.Name == this.initialStyle);
|
||||
newStyle?.Apply();
|
||||
}
|
||||
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
/// <inheritdoc />
|
||||
public override void OnClose()
|
||||
{
|
||||
if (!this.didSave)
|
||||
{
|
||||
var config = Service<DalamudConfiguration>.Get();
|
||||
var renameModalTitle = Loc.Localize("RenameStyleModalTitle", "Rename Style");
|
||||
|
||||
var workStyle = config.SavedStyles[this.currentSel];
|
||||
workStyle.BuiltInColors ??= StyleModelV1.DalamudStandard.BuiltInColors;
|
||||
|
||||
var appliedThisFrame = false;
|
||||
|
||||
var styleAry = config.SavedStyles.Select(x => x.Name).ToArray();
|
||||
ImGui.Text(Loc.Localize("StyleEditorChooseStyle", "Choose Style:"));
|
||||
if (ImGui.Combo("###styleChooserCombo", ref this.currentSel, styleAry, styleAry.Length))
|
||||
{
|
||||
var newStyle = config.SavedStyles[this.currentSel];
|
||||
newStyle.Apply();
|
||||
appliedThisFrame = true;
|
||||
}
|
||||
|
||||
if (ImGui.Button(Loc.Localize("StyleEditorAddNew", "Add new style")))
|
||||
{
|
||||
this.SaveStyle();
|
||||
|
||||
var newStyle = StyleModelV1.DalamudStandard;
|
||||
newStyle.Name = GetRandomName();
|
||||
config.SavedStyles.Add(newStyle);
|
||||
|
||||
this.currentSel = config.SavedStyles.Count - 1;
|
||||
|
||||
newStyle.Apply();
|
||||
appliedThisFrame = true;
|
||||
|
||||
config.Save();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash) && this.currentSel != 0)
|
||||
{
|
||||
this.currentSel--;
|
||||
var newStyle = config.SavedStyles[this.currentSel];
|
||||
newStyle.Apply();
|
||||
appliedThisFrame = true;
|
||||
|
||||
config.SavedStyles.RemoveAt(this.currentSel + 1);
|
||||
|
||||
config.Save();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip(Loc.Localize("StyleEditorDeleteStyle", "Delete current style"));
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Pen) && this.currentSel != 0)
|
||||
{
|
||||
var newStyle = config.SavedStyles[this.currentSel];
|
||||
this.renameText = newStyle.Name;
|
||||
|
||||
this.renameModalDrawing = true;
|
||||
ImGui.OpenPopup(renameModalTitle);
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip(Loc.Localize("StyleEditorRenameStyle", "Rename style"));
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.FileExport))
|
||||
{
|
||||
var selectedStyle = config.SavedStyles[this.currentSel];
|
||||
var newStyle = StyleModelV1.Get();
|
||||
newStyle.Name = selectedStyle.Name;
|
||||
ImGui.SetClipboardText(newStyle.Serialize());
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip(Loc.Localize("StyleEditorCopy", "Copy style to clipboard for sharing"));
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.FileImport))
|
||||
{
|
||||
this.SaveStyle();
|
||||
|
||||
var styleJson = ImGui.GetClipboardText();
|
||||
|
||||
try
|
||||
{
|
||||
var newStyle = StyleModel.Deserialize(styleJson);
|
||||
|
||||
newStyle.Name ??= GetRandomName();
|
||||
|
||||
if (config.SavedStyles.Any(x => x.Name == newStyle.Name))
|
||||
{
|
||||
newStyle.Name = $"{newStyle.Name} ({GetRandomName()} Mix)";
|
||||
}
|
||||
|
||||
config.SavedStyles.Add(newStyle);
|
||||
newStyle.Apply();
|
||||
appliedThisFrame = true;
|
||||
|
||||
this.currentSel = config.SavedStyles.Count - 1;
|
||||
|
||||
config.Save();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Could not import style");
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip(Loc.Localize("StyleEditorImport", "Import style from clipboard"));
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.50f);
|
||||
|
||||
if (this.currentSel < 2)
|
||||
{
|
||||
ImGui.TextColored(ImGuiColors.DalamudRed, Loc.Localize("StyleEditorNotAllowed", "You cannot edit built-in styles. Please add a new style first."));
|
||||
}
|
||||
else if (appliedThisFrame)
|
||||
{
|
||||
ImGui.Text(Loc.Localize("StyleEditorApplying", "Applying style..."));
|
||||
}
|
||||
else if (ImGui.BeginTabBar("StyleEditorTabs"))
|
||||
{
|
||||
var style = ImGui.GetStyle();
|
||||
|
||||
if (ImGui.BeginTabItem(Loc.Localize("StyleEditorVariables", "Variables")))
|
||||
{
|
||||
ImGui.BeginChild($"ScrollingVars", ImGuiHelpers.ScaledVector2(0, -32), true, ImGuiWindowFlags.HorizontalScrollbar | ImGuiWindowFlags.NoBackground);
|
||||
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 5);
|
||||
|
||||
ImGui.SliderFloat2("WindowPadding", ref style.WindowPadding, 0.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat2("FramePadding", ref style.FramePadding, 0.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat2("CellPadding", ref style.CellPadding, 0.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat2("ItemSpacing", ref style.ItemSpacing, 0.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat2("ItemInnerSpacing", ref style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat2("TouchExtraPadding", ref style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
|
||||
ImGui.SliderFloat("IndentSpacing", ref style.IndentSpacing, 0.0f, 30.0f, "%.0f");
|
||||
ImGui.SliderFloat("ScrollbarSize", ref style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat("GrabMinSize", ref style.GrabMinSize, 1.0f, 20.0f, "%.0f");
|
||||
ImGui.Text("Borders");
|
||||
ImGui.SliderFloat("WindowBorderSize", ref style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui.SliderFloat("ChildBorderSize", ref style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui.SliderFloat("PopupBorderSize", ref style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui.SliderFloat("FrameBorderSize", ref style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui.SliderFloat("TabBorderSize", ref style.TabBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui.Text("Rounding");
|
||||
ImGui.SliderFloat("WindowRounding", ref style.WindowRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("ChildRounding", ref style.ChildRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("FrameRounding", ref style.FrameRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("PopupRounding", ref style.PopupRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("ScrollbarRounding", ref style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("GrabRounding", ref style.GrabRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("LogSliderDeadzone", ref style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("TabRounding", ref style.TabRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.Text("Alignment");
|
||||
ImGui.SliderFloat2("WindowTitleAlign", ref style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
|
||||
var windowMenuButtonPosition = (int)style.WindowMenuButtonPosition + 1;
|
||||
if (ImGui.Combo("WindowMenuButtonPosition", ref windowMenuButtonPosition, "None\0Left\0Right\0"))
|
||||
style.WindowMenuButtonPosition = (ImGuiDir)(windowMenuButtonPosition - 1);
|
||||
ImGui.SliderFloat2("ButtonTextAlign", ref style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
|
||||
ImGui.SameLine();
|
||||
ImGuiComponents.HelpMarker("Alignment applies when a button is larger than its text content.");
|
||||
ImGui.SliderFloat2("SelectableTextAlign", ref style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
|
||||
ImGui.SameLine();
|
||||
ImGuiComponents.HelpMarker("Alignment applies when a selectable is larger than its text content.");
|
||||
ImGui.SliderFloat2("DisplaySafeAreaPadding", ref style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
|
||||
ImGui.SameLine();
|
||||
ImGuiComponents.HelpMarker(
|
||||
"Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
|
||||
ImGui.EndTabItem();
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui.BeginTabItem(Loc.Localize("StyleEditorColors", "Colors")))
|
||||
{
|
||||
ImGui.BeginChild("ScrollingColors", ImGuiHelpers.ScaledVector2(0, -30), true, ImGuiWindowFlags.HorizontalScrollbar | ImGuiWindowFlags.NoBackground);
|
||||
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 5);
|
||||
|
||||
if (ImGui.RadioButton("Opaque", this.alphaFlags == ImGuiColorEditFlags.None))
|
||||
this.alphaFlags = ImGuiColorEditFlags.None;
|
||||
ImGui.SameLine();
|
||||
if (ImGui.RadioButton("Alpha", this.alphaFlags == ImGuiColorEditFlags.AlphaPreview))
|
||||
this.alphaFlags = ImGuiColorEditFlags.AlphaPreview;
|
||||
ImGui.SameLine();
|
||||
if (ImGui.RadioButton("Both", this.alphaFlags == ImGuiColorEditFlags.AlphaPreviewHalf))
|
||||
this.alphaFlags = ImGuiColorEditFlags.AlphaPreviewHalf;
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGuiComponents.HelpMarker(
|
||||
"In the color list:\n" +
|
||||
"Left-click on color square to open color picker,\n" +
|
||||
"Right-click to open edit options menu.");
|
||||
|
||||
foreach (var imGuiCol in Enum.GetValues<ImGuiCol>())
|
||||
{
|
||||
if (imGuiCol == ImGuiCol.COUNT)
|
||||
continue;
|
||||
|
||||
ImGui.PushID(imGuiCol.ToString());
|
||||
|
||||
ImGui.ColorEdit4("##color", ref style.Colors[(int)imGuiCol], ImGuiColorEditFlags.AlphaBar | this.alphaFlags);
|
||||
|
||||
ImGui.SameLine(0.0f, style.ItemInnerSpacing.X);
|
||||
ImGui.TextUnformatted(imGuiCol.ToString());
|
||||
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
foreach (var property in typeof(DalamudColors).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
ImGui.PushID(property.Name);
|
||||
|
||||
var colorVal = property.GetValue(workStyle.BuiltInColors);
|
||||
if (colorVal == null)
|
||||
{
|
||||
colorVal = property.GetValue(StyleModelV1.DalamudStandard.BuiltInColors);
|
||||
property.SetValue(workStyle.BuiltInColors, colorVal);
|
||||
}
|
||||
|
||||
var color = (Vector4)colorVal;
|
||||
|
||||
if (ImGui.ColorEdit4("##color", ref color, ImGuiColorEditFlags.AlphaBar | this.alphaFlags))
|
||||
{
|
||||
property.SetValue(workStyle.BuiltInColors, color);
|
||||
workStyle.BuiltInColors?.Apply();
|
||||
}
|
||||
|
||||
ImGui.SameLine(0.0f, style.ItemInnerSpacing.X);
|
||||
ImGui.TextUnformatted(property.Name);
|
||||
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
ImGui.EndTabBar();
|
||||
}
|
||||
|
||||
ImGui.PopItemWidth();
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
if (ImGui.Button(Loc.Localize("Close", "Close")))
|
||||
{
|
||||
this.IsOpen = false;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.Button(Loc.Localize("SaveAndClose", "Save and Close")))
|
||||
{
|
||||
this.SaveStyle();
|
||||
|
||||
config.ChosenStyle = config.SavedStyles[this.currentSel].Name;
|
||||
Log.Verbose("ChosenStyle = {ChosenStyle}", config.ChosenStyle);
|
||||
|
||||
this.didSave = true;
|
||||
|
||||
this.IsOpen = false;
|
||||
}
|
||||
|
||||
if (ImGui.BeginPopupModal(renameModalTitle, ref this.renameModalDrawing, ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoScrollbar))
|
||||
{
|
||||
ImGui.Text(Loc.Localize("StyleEditorEnterName", "Please enter the new name for this style."));
|
||||
ImGui.Spacing();
|
||||
|
||||
ImGui.InputText("###renameModalInput", ref this.renameText, 255);
|
||||
|
||||
const float buttonWidth = 120f;
|
||||
ImGui.SetCursorPosX((ImGui.GetWindowWidth() - buttonWidth) / 2);
|
||||
|
||||
if (ImGui.Button("OK", new Vector2(buttonWidth, 40)))
|
||||
{
|
||||
config.SavedStyles[this.currentSel].Name = this.renameText;
|
||||
config.Save();
|
||||
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
var newStyle = config.SavedStyles.FirstOrDefault(x => x.Name == this.initialStyle);
|
||||
newStyle?.Apply();
|
||||
}
|
||||
|
||||
private static string GetRandomName()
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
var config = Service<DalamudConfiguration>.Get();
|
||||
var renameModalTitle = Loc.Localize("RenameStyleModalTitle", "Rename Style");
|
||||
|
||||
var workStyle = config.SavedStyles[this.currentSel];
|
||||
workStyle.BuiltInColors ??= StyleModelV1.DalamudStandard.BuiltInColors;
|
||||
|
||||
var appliedThisFrame = false;
|
||||
|
||||
var styleAry = config.SavedStyles.Select(x => x.Name).ToArray();
|
||||
ImGui.Text(Loc.Localize("StyleEditorChooseStyle", "Choose Style:"));
|
||||
if (ImGui.Combo("###styleChooserCombo", ref this.currentSel, styleAry, styleAry.Length))
|
||||
{
|
||||
var data = Service<DataManager>.Get();
|
||||
var names = data.GetExcelSheet<BNpcName>(ClientLanguage.English);
|
||||
var rng = new Random();
|
||||
|
||||
return names.ElementAt(rng.Next(0, names.Count() - 1)).Singular.RawString;
|
||||
}
|
||||
|
||||
private void SaveStyle()
|
||||
{
|
||||
if (this.currentSel < 2)
|
||||
return;
|
||||
|
||||
var config = Service<DalamudConfiguration>.Get();
|
||||
|
||||
var newStyle = StyleModelV1.Get();
|
||||
newStyle.Name = config.SavedStyles[this.currentSel].Name;
|
||||
config.SavedStyles[this.currentSel] = newStyle;
|
||||
var newStyle = config.SavedStyles[this.currentSel];
|
||||
newStyle.Apply();
|
||||
appliedThisFrame = true;
|
||||
}
|
||||
|
||||
if (ImGui.Button(Loc.Localize("StyleEditorAddNew", "Add new style")))
|
||||
{
|
||||
this.SaveStyle();
|
||||
|
||||
var newStyle = StyleModelV1.DalamudStandard;
|
||||
newStyle.Name = GetRandomName();
|
||||
config.SavedStyles.Add(newStyle);
|
||||
|
||||
this.currentSel = config.SavedStyles.Count - 1;
|
||||
|
||||
newStyle.Apply();
|
||||
appliedThisFrame = true;
|
||||
|
||||
config.Save();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash) && this.currentSel != 0)
|
||||
{
|
||||
this.currentSel--;
|
||||
var newStyle = config.SavedStyles[this.currentSel];
|
||||
newStyle.Apply();
|
||||
appliedThisFrame = true;
|
||||
|
||||
config.SavedStyles.RemoveAt(this.currentSel + 1);
|
||||
|
||||
config.Save();
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip(Loc.Localize("StyleEditorDeleteStyle", "Delete current style"));
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Pen) && this.currentSel != 0)
|
||||
{
|
||||
var newStyle = config.SavedStyles[this.currentSel];
|
||||
this.renameText = newStyle.Name;
|
||||
|
||||
this.renameModalDrawing = true;
|
||||
ImGui.OpenPopup(renameModalTitle);
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip(Loc.Localize("StyleEditorRenameStyle", "Rename style"));
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGuiHelpers.ScaledDummy(5);
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.FileExport))
|
||||
{
|
||||
var selectedStyle = config.SavedStyles[this.currentSel];
|
||||
var newStyle = StyleModelV1.Get();
|
||||
newStyle.Name = selectedStyle.Name;
|
||||
ImGui.SetClipboardText(newStyle.Serialize());
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip(Loc.Localize("StyleEditorCopy", "Copy style to clipboard for sharing"));
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.FileImport))
|
||||
{
|
||||
this.SaveStyle();
|
||||
|
||||
var styleJson = ImGui.GetClipboardText();
|
||||
|
||||
try
|
||||
{
|
||||
var newStyle = StyleModel.Deserialize(styleJson);
|
||||
|
||||
newStyle.Name ??= GetRandomName();
|
||||
|
||||
if (config.SavedStyles.Any(x => x.Name == newStyle.Name))
|
||||
{
|
||||
newStyle.Name = $"{newStyle.Name} ({GetRandomName()} Mix)";
|
||||
}
|
||||
|
||||
config.SavedStyles.Add(newStyle);
|
||||
newStyle.Apply();
|
||||
appliedThisFrame = true;
|
||||
|
||||
this.currentSel = config.SavedStyles.Count - 1;
|
||||
|
||||
config.Save();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Could not import style");
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip(Loc.Localize("StyleEditorImport", "Import style from clipboard"));
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.50f);
|
||||
|
||||
if (this.currentSel < 2)
|
||||
{
|
||||
ImGui.TextColored(ImGuiColors.DalamudRed, Loc.Localize("StyleEditorNotAllowed", "You cannot edit built-in styles. Please add a new style first."));
|
||||
}
|
||||
else if (appliedThisFrame)
|
||||
{
|
||||
ImGui.Text(Loc.Localize("StyleEditorApplying", "Applying style..."));
|
||||
}
|
||||
else if (ImGui.BeginTabBar("StyleEditorTabs"))
|
||||
{
|
||||
var style = ImGui.GetStyle();
|
||||
|
||||
if (ImGui.BeginTabItem(Loc.Localize("StyleEditorVariables", "Variables")))
|
||||
{
|
||||
ImGui.BeginChild($"ScrollingVars", ImGuiHelpers.ScaledVector2(0, -32), true, ImGuiWindowFlags.HorizontalScrollbar | ImGuiWindowFlags.NoBackground);
|
||||
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 5);
|
||||
|
||||
ImGui.SliderFloat2("WindowPadding", ref style.WindowPadding, 0.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat2("FramePadding", ref style.FramePadding, 0.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat2("CellPadding", ref style.CellPadding, 0.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat2("ItemSpacing", ref style.ItemSpacing, 0.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat2("ItemInnerSpacing", ref style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat2("TouchExtraPadding", ref style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
|
||||
ImGui.SliderFloat("IndentSpacing", ref style.IndentSpacing, 0.0f, 30.0f, "%.0f");
|
||||
ImGui.SliderFloat("ScrollbarSize", ref style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
|
||||
ImGui.SliderFloat("GrabMinSize", ref style.GrabMinSize, 1.0f, 20.0f, "%.0f");
|
||||
ImGui.Text("Borders");
|
||||
ImGui.SliderFloat("WindowBorderSize", ref style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui.SliderFloat("ChildBorderSize", ref style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui.SliderFloat("PopupBorderSize", ref style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui.SliderFloat("FrameBorderSize", ref style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui.SliderFloat("TabBorderSize", ref style.TabBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui.Text("Rounding");
|
||||
ImGui.SliderFloat("WindowRounding", ref style.WindowRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("ChildRounding", ref style.ChildRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("FrameRounding", ref style.FrameRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("PopupRounding", ref style.PopupRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("ScrollbarRounding", ref style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("GrabRounding", ref style.GrabRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("LogSliderDeadzone", ref style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.SliderFloat("TabRounding", ref style.TabRounding, 0.0f, 12.0f, "%.0f");
|
||||
ImGui.Text("Alignment");
|
||||
ImGui.SliderFloat2("WindowTitleAlign", ref style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
|
||||
var windowMenuButtonPosition = (int)style.WindowMenuButtonPosition + 1;
|
||||
if (ImGui.Combo("WindowMenuButtonPosition", ref windowMenuButtonPosition, "None\0Left\0Right\0"))
|
||||
style.WindowMenuButtonPosition = (ImGuiDir)(windowMenuButtonPosition - 1);
|
||||
ImGui.SliderFloat2("ButtonTextAlign", ref style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
|
||||
ImGui.SameLine();
|
||||
ImGuiComponents.HelpMarker("Alignment applies when a button is larger than its text content.");
|
||||
ImGui.SliderFloat2("SelectableTextAlign", ref style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
|
||||
ImGui.SameLine();
|
||||
ImGuiComponents.HelpMarker("Alignment applies when a selectable is larger than its text content.");
|
||||
ImGui.SliderFloat2("DisplaySafeAreaPadding", ref style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
|
||||
ImGui.SameLine();
|
||||
ImGuiComponents.HelpMarker(
|
||||
"Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
|
||||
ImGui.EndTabItem();
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui.BeginTabItem(Loc.Localize("StyleEditorColors", "Colors")))
|
||||
{
|
||||
ImGui.BeginChild("ScrollingColors", ImGuiHelpers.ScaledVector2(0, -30), true, ImGuiWindowFlags.HorizontalScrollbar | ImGuiWindowFlags.NoBackground);
|
||||
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 5);
|
||||
|
||||
if (ImGui.RadioButton("Opaque", this.alphaFlags == ImGuiColorEditFlags.None))
|
||||
this.alphaFlags = ImGuiColorEditFlags.None;
|
||||
ImGui.SameLine();
|
||||
if (ImGui.RadioButton("Alpha", this.alphaFlags == ImGuiColorEditFlags.AlphaPreview))
|
||||
this.alphaFlags = ImGuiColorEditFlags.AlphaPreview;
|
||||
ImGui.SameLine();
|
||||
if (ImGui.RadioButton("Both", this.alphaFlags == ImGuiColorEditFlags.AlphaPreviewHalf))
|
||||
this.alphaFlags = ImGuiColorEditFlags.AlphaPreviewHalf;
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGuiComponents.HelpMarker(
|
||||
"In the color list:\n" +
|
||||
"Left-click on color square to open color picker,\n" +
|
||||
"Right-click to open edit options menu.");
|
||||
|
||||
foreach (var imGuiCol in Enum.GetValues<ImGuiCol>())
|
||||
{
|
||||
if (imGuiCol == ImGuiCol.COUNT)
|
||||
continue;
|
||||
|
||||
ImGui.PushID(imGuiCol.ToString());
|
||||
|
||||
ImGui.ColorEdit4("##color", ref style.Colors[(int)imGuiCol], ImGuiColorEditFlags.AlphaBar | this.alphaFlags);
|
||||
|
||||
ImGui.SameLine(0.0f, style.ItemInnerSpacing.X);
|
||||
ImGui.TextUnformatted(imGuiCol.ToString());
|
||||
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
foreach (var property in typeof(DalamudColors).GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
ImGui.PushID(property.Name);
|
||||
|
||||
var colorVal = property.GetValue(workStyle.BuiltInColors);
|
||||
if (colorVal == null)
|
||||
{
|
||||
colorVal = property.GetValue(StyleModelV1.DalamudStandard.BuiltInColors);
|
||||
property.SetValue(workStyle.BuiltInColors, colorVal);
|
||||
}
|
||||
|
||||
var color = (Vector4)colorVal;
|
||||
|
||||
if (ImGui.ColorEdit4("##color", ref color, ImGuiColorEditFlags.AlphaBar | this.alphaFlags))
|
||||
{
|
||||
property.SetValue(workStyle.BuiltInColors, color);
|
||||
workStyle.BuiltInColors?.Apply();
|
||||
}
|
||||
|
||||
ImGui.SameLine(0.0f, style.ItemInnerSpacing.X);
|
||||
ImGui.TextUnformatted(property.Name);
|
||||
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
ImGui.EndTabBar();
|
||||
}
|
||||
|
||||
ImGui.PopItemWidth();
|
||||
|
||||
ImGui.Separator();
|
||||
|
||||
if (ImGui.Button(Loc.Localize("Close", "Close")))
|
||||
{
|
||||
this.IsOpen = false;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if (ImGui.Button(Loc.Localize("SaveAndClose", "Save and Close")))
|
||||
{
|
||||
this.SaveStyle();
|
||||
|
||||
config.ChosenStyle = config.SavedStyles[this.currentSel].Name;
|
||||
Log.Verbose("ChosenStyle = {ChosenStyle}", config.ChosenStyle);
|
||||
|
||||
this.didSave = true;
|
||||
|
||||
this.IsOpen = false;
|
||||
}
|
||||
|
||||
if (ImGui.BeginPopupModal(renameModalTitle, ref this.renameModalDrawing, ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoScrollbar))
|
||||
{
|
||||
ImGui.Text(Loc.Localize("StyleEditorEnterName", "Please enter the new name for this style."));
|
||||
ImGui.Spacing();
|
||||
|
||||
ImGui.InputText("###renameModalInput", ref this.renameText, 255);
|
||||
|
||||
const float buttonWidth = 120f;
|
||||
ImGui.SetCursorPosX((ImGui.GetWindowWidth() - buttonWidth) / 2);
|
||||
|
||||
if (ImGui.Button("OK", new Vector2(buttonWidth, 40)))
|
||||
{
|
||||
config.SavedStyles[this.currentSel].Name = this.renameText;
|
||||
config.Save();
|
||||
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetRandomName()
|
||||
{
|
||||
var data = Service<DataManager>.Get();
|
||||
var names = data.GetExcelSheet<BNpcName>(ClientLanguage.English);
|
||||
var rng = new Random();
|
||||
|
||||
return names.ElementAt(rng.Next(0, names.Count() - 1)).Singular.RawString;
|
||||
}
|
||||
|
||||
private void SaveStyle()
|
||||
{
|
||||
if (this.currentSel < 2)
|
||||
return;
|
||||
|
||||
var config = Service<DalamudConfiguration>.Get();
|
||||
|
||||
var newStyle = StyleModelV1.Get();
|
||||
newStyle.Name = config.SavedStyles[this.currentSel].Name;
|
||||
config.SavedStyles[this.currentSel] = newStyle;
|
||||
newStyle.Apply();
|
||||
|
||||
config.Save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue