diff --git a/TheHeartOfTheParty/Commands.cs b/TheHeartOfTheParty/Commands.cs new file mode 100644 index 0000000..a9f7a63 --- /dev/null +++ b/TheHeartOfTheParty/Commands.cs @@ -0,0 +1,32 @@ +using Dalamud.Game.Command; + +namespace TheHeartOfTheParty; + +internal class Commands : IDisposable { + private static readonly string[] CommandNames = { + "/thotp", + "/titles", + }; + + private Plugin Plugin { get; } + + internal Commands(Plugin plugin) { + this.Plugin = plugin; + + foreach (var name in CommandNames) { + this.Plugin.CommandManager.AddHandler(name, new CommandInfo(this.OnCommand) { + HelpMessage = $"Toggles {this.Plugin.Name}", + }); + } + } + + public void Dispose() { + foreach (var name in CommandNames) { + this.Plugin.CommandManager.RemoveHandler(name); + } + } + + private void OnCommand(string command, string arguments) { + this.Plugin.Ui.Toggle(); + } +} diff --git a/TheHeartOfTheParty/Configuration.cs b/TheHeartOfTheParty/Configuration.cs new file mode 100644 index 0000000..0b89b06 --- /dev/null +++ b/TheHeartOfTheParty/Configuration.cs @@ -0,0 +1,15 @@ +using Dalamud.Configuration; + +namespace TheHeartOfTheParty; + +internal class Configuration : IPluginConfiguration { + public int Version { get; set; } = 1; + + public bool OnlyUnlocked = true; + public SortOrder SortOrder = SortOrder.Default; +} + +internal enum SortOrder { + Default, + Alphabetical, +} diff --git a/TheHeartOfTheParty/Plugin.cs b/TheHeartOfTheParty/Plugin.cs index 839585f..8fac621 100755 --- a/TheHeartOfTheParty/Plugin.cs +++ b/TheHeartOfTheParty/Plugin.cs @@ -1,5 +1,6 @@ using Dalamud.Data; using Dalamud.Game.ClientState; +using Dalamud.Game.Command; using Dalamud.IoC; using Dalamud.Plugin; @@ -14,19 +15,31 @@ public class Plugin : IDalamudPlugin { [PluginService] internal ClientState ClientState { get; init; } + [PluginService] + internal CommandManager CommandManager { get; init; } + [PluginService] internal DataManager DataManager { get; init; } - internal GameFunctions GameFunctions { get; } - - private PluginUi Ui { get; } + internal Configuration Config { get; } + internal GameFunctions Functions { get; } + internal PluginUi Ui { get; } + private Commands Commands { get; } public Plugin() { - this.GameFunctions = new GameFunctions(this); + this.Config = this.Interface!.GetPluginConfig() as Configuration ?? new Configuration(); + + this.Functions = new GameFunctions(this); this.Ui = new PluginUi(this); + this.Commands = new Commands(this); } public void Dispose() { + this.Commands.Dispose(); this.Ui.Dispose(); } + + internal void SaveConfig() { + this.Interface.SavePluginConfig(this.Config); + } } diff --git a/TheHeartOfTheParty/PluginUi.cs b/TheHeartOfTheParty/PluginUi.cs index e275769..00355c1 100755 --- a/TheHeartOfTheParty/PluginUi.cs +++ b/TheHeartOfTheParty/PluginUi.cs @@ -1,71 +1,117 @@ using ImGuiNET; using Lumina.Excel.GeneratedSheets; +using Lumina.Text; -namespace TheHeartOfTheParty; +namespace TheHeartOfTheParty; internal class PluginUi : IDisposable { private Plugin Plugin { get; } - - private string _searchText = ""; - private bool _unlockedOnly = true; - + + private bool _visible; + private string _searchText = string.Empty; + internal PluginUi(Plugin plugin) { this.Plugin = plugin; - + this.Plugin.Interface.UiBuilder.Draw += this.OnDraw; } - + public void Dispose() { this.Plugin.Interface.UiBuilder.Draw -= this.OnDraw; } + internal void Toggle() { + this._visible ^= true; + } + private void OnDraw() { - if (!ImGui.Begin(this.Plugin.Name)) { + if (!this._visible) { + return; + } + + if (!ImGui.Begin(this.Plugin.Name, ref this._visible)) { ImGui.End(); return; } - - ImGui.Checkbox("Only show unlocked titles", ref this._unlockedOnly); - - ImGui.SetNextItemWidth(-1); - ImGui.InputTextWithHint("##search", "Search...", ref this._searchText, 64); + + var anyChanged = false; + + anyChanged |= ImGui.Checkbox("Only show unlocked titles", ref this.Plugin.Config.OnlyUnlocked); + + if (ImGui.BeginCombo("Sort", this.Plugin.Config.SortOrder.ToString())) { + foreach (var ordering in Enum.GetValues()) { + if (ImGui.Selectable(ordering.ToString(), this.Plugin.Config.SortOrder == ordering)) { + this.Plugin.Config.SortOrder = ordering; + anyChanged = true; + } + } + + ImGui.EndCombo(); + } + + if (anyChanged) { + this.Plugin.SaveConfig(); + } var fem = true; - if (this.Plugin.ClientState.LocalPlayer is {} player) { + if (this.Plugin.ClientState.LocalPlayer is { } player) { fem = player.Customize[1] == 1; } - var titles = this.Plugin.DataManager.GetExcelSheet()! - .Where(row => row.Order != 0) - .Select(row => (row, this.Plugin.GameFunctions.IsTitleUnlocked(row.RowId))); - - if (this._unlockedOnly) { - titles = titles.Where(t => t.Item2); - } - - if (this._searchText.Length > 0) { - var search = this._searchText.ToLower(); - titles = titles.Where(t => t.Item1.Feminine.RawString.ToLower().Contains(search) || t.Item1.Masculine.RawString.ToLower().Contains(search)); - } - - titles = titles.OrderBy(t => t.Item1.Order); - - if (ImGui.BeginChild("##titles")) { - foreach (var (title, unlocked) in titles) { - var name = fem ? title.Feminine : title.Masculine; + var titles = this.GetTitles(fem).ToList(); - if (unlocked) { - if (ImGui.Selectable(name)) { - this.Plugin.GameFunctions.SetTitle(title.RowId); + var hint = titles.Count == 1 ? "Search 1 title..." : $"Search {titles} titles..."; + + ImGui.SetNextItemWidth(-1); + ImGui.InputTextWithHint("##search", hint, ref this._searchText, 64); + + if (ImGui.BeginChild("##titles")) { + foreach (var title in titles) { + if (title.Unlocked) { + if (ImGui.Selectable(title.Text)) { + this.Plugin.Functions.SetTitle(title.Row.RowId); } } else { - ImGui.TextDisabled(name); + ImGui.TextDisabled(title.Text); } } - + ImGui.EndChild(); } ImGui.End(); } + + private IEnumerable<TitleInfo> GetTitles(bool fem) { + var titles = this.Plugin.DataManager.GetExcelSheet<Title>()! + .Where(row => row.Order != 0) + .Select(row => new TitleInfo { + Row = row, + Unlocked = this.Plugin.Functions.IsTitleUnlocked(row.RowId), + Text = fem ? row.Feminine : row.Masculine, + }); + + if (this.Plugin.Config.OnlyUnlocked) { + titles = titles.Where(t => t.Unlocked); + } + + if (this._searchText.Length > 0) { + var search = this._searchText.ToLowerInvariant(); + titles = titles.Where(t => t.Text.RawString.ToLowerInvariant().Contains(search)); + } + + titles = this.Plugin.Config.SortOrder switch { + SortOrder.Default => titles.OrderBy(t => t.Row.Order), + SortOrder.Alphabetical => titles.OrderBy(t => t.Text.RawString), + _ => titles, + }; + + return titles; + } +} + +internal class TitleInfo { + internal Title Row { get; init; } = null!; + internal bool Unlocked { get; init; } + internal SeString Text { get; init; } = null!; } diff --git a/TheHeartOfTheParty/TheHeartOfTheParty.csproj b/TheHeartOfTheParty/TheHeartOfTheParty.csproj index e7d0cd9..581d127 100755 --- a/TheHeartOfTheParty/TheHeartOfTheParty.csproj +++ b/TheHeartOfTheParty/TheHeartOfTheParty.csproj @@ -8,25 +8,34 @@ <LangVersion>preview</LangVersion> </PropertyGroup> + <PropertyGroup> +<!-- <Dalamud>$(AppData)\XIVLauncher\addon\Hooks\dev</Dalamud>--> + <Dalamud>/home/ascclemens/dalamud</Dalamud> + </PropertyGroup> + + <PropertyGroup Condition="'$(IsCI)' == 'true'"> + <Dalamud>$(HOME)/dalamud</Dalamud> + </PropertyGroup> + <ItemGroup> <Reference Include="Dalamud"> - <HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Dalamud.dll</HintPath> + <HintPath>$(Dalamud)\Dalamud.dll</HintPath> <Private>false</Private> </Reference> <Reference Include="FFXIVClientStructs"> - <HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\FFXIVClientStructs.dll</HintPath> + <HintPath>$(Dalamud)\FFXIVClientStructs.dll</HintPath> <Private>false</Private> </Reference> <Reference Include="ImGui.NET"> - <HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\ImGui.NET.dll</HintPath> + <HintPath>$(Dalamud)\ImGui.NET.dll</HintPath> <Private>false</Private> </Reference> <Reference Include="Lumina"> - <HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.dll</HintPath> + <HintPath>$(Dalamud)\Lumina.dll</HintPath> <Private>false</Private> </Reference> <Reference Include="Lumina.Excel"> - <HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll</HintPath> + <HintPath>$(Dalamud)\Lumina.Excel.dll</HintPath> <Private>false</Private> </Reference> </ItemGroup>