From dafb719496bdf31928af138198f7af85484656e8 Mon Sep 17 00:00:00 2001 From: GrittyFrog Date: Sat, 21 Sep 2024 00:55:05 +1000 Subject: [PATCH] Add 'Insert Special Character' right click action on macros --- .../Interface/CharPicker/CharPickerDialog.cs | 63 +++++++++++++++++++ .../Extensions/Dalamud/Str/SeStringEx.cs | 11 +++- MacroMate/Extensions/Dotnet/EnumerableExt.cs | 2 + MacroMate/Windows/MacroWindow.cs | 40 ++++++++++++ MacroMate/Windows/PluginWindowManager.cs | 3 + 5 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 MacroMate/Extensions/Dalamud/Interface/CharPicker/CharPickerDialog.cs diff --git a/MacroMate/Extensions/Dalamud/Interface/CharPicker/CharPickerDialog.cs b/MacroMate/Extensions/Dalamud/Interface/CharPicker/CharPickerDialog.cs new file mode 100644 index 0000000..2e5a55b --- /dev/null +++ b/MacroMate/Extensions/Dalamud/Interface/CharPicker/CharPickerDialog.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Windowing; +using ImGuiNET; + +namespace MacroMate.Extensions.Dalamud.Interface.CharPicker; + +/// Class to pick a character from a list of possible characters +public class CharPickerDialog : Window { + public static readonly string NAME = "Char Picker"; + + private Action? Callback { get; set; } + private List Choices { get; set; } = new(); + + /// + /// Counts the number of inserts since this window gained focus. + /// + /// Resets when focus is lost or when the window is opened. + /// + public int ConsecutiveInserts { get; private set; } = 0; + + public CharPickerDialog() : base(NAME) { + this.SizeConstraints = new WindowSizeConstraints { + MinimumSize = new Vector2(375, 330), + MaximumSize = new Vector2(float.MaxValue, float.MaxValue) + }; + } + + public void Open( + List choices, + Action callback + ) { + Choices = choices; + Callback = callback; + ConsecutiveInserts = 0; + if (!IsOpen) { + IsOpen = true; + } else { + ImGui.SetWindowFocus(WindowName); + } + } + + public override void Draw() { + var buttonSize = 36 * ImGuiHelpers.GlobalScale; + var columns = (int)((ImGui.GetContentRegionAvail().X - ImGui.GetStyle().WindowPadding.X) / (buttonSize + ImGui.GetStyle().ItemSpacing.X)); + + if (!IsFocused) { ConsecutiveInserts = 0; } + + ImGuiClip.ClippedDraw(Choices, (choice) => { + var text = (choice).ToString(); + ImGui.SetWindowFontScale(1.3f); + if (ImGui.Button(text, new Vector2(36 * ImGuiHelpers.GlobalScale))) { + if (Callback != null) { + Callback(choice); + ConsecutiveInserts += 1; + } + } + ImGui.SetWindowFontScale(1); + }, columns, lineHeight: buttonSize); + } +} diff --git a/MacroMate/Extensions/Dalamud/Str/SeStringEx.cs b/MacroMate/Extensions/Dalamud/Str/SeStringEx.cs index dc9377b..899d711 100644 --- a/MacroMate/Extensions/Dalamud/Str/SeStringEx.cs +++ b/MacroMate/Extensions/Dalamud/Str/SeStringEx.cs @@ -108,9 +108,14 @@ public static SeString InsertAtTextValueIndex(this SeString self, SeString text, var updatedString = new SeStringBuilder(); var textOffset = 0; + // If we are empty just insert and leave + if (self.Payloads.Count == 0) { + text.Payloads.ForEach(pl => { updatedString.Add(pl); }); + return updatedString.Build(); + } + var remainingPayloads = new Queue(self.Payloads); while (remainingPayloads.TryDequeue(out var payload)) { - Env.PluginLog.Info($"Checking payload: {payload}, offset: {offset}"); var textPayload = payload as ITextProvider; if (textPayload == null || textPayload.Text == null) { updatedString.Add(payload); @@ -132,7 +137,9 @@ public static SeString InsertAtTextValueIndex(this SeString self, SeString text, } else { var beforeText = textPayload.Text[0..textPayloadInsertOffset]; var afterText = textPayload.Text[textPayloadInsertOffset..]; - updatedString.AddText(beforeText); + if (beforeText.Count() > 0) { + updatedString.AddText(beforeText); + } text.Payloads.ForEach(pl => { updatedString.Add(pl); }); if (afterText.Count() > 0) { updatedString.AddText(afterText); diff --git a/MacroMate/Extensions/Dotnet/EnumerableExt.cs b/MacroMate/Extensions/Dotnet/EnumerableExt.cs index 5f9959b..7cf9ff4 100644 --- a/MacroMate/Extensions/Dotnet/EnumerableExt.cs +++ b/MacroMate/Extensions/Dotnet/EnumerableExt.cs @@ -5,6 +5,8 @@ namespace MacroMate.Extensions.Dotnet; public static class EnumerableExt { + public static IEnumerable RangeSE(int start, int end) => Enumerable.Range(start, end - start); + public static IEnumerable<(T item, int index)> WithIndex(this IEnumerable source) { return source.Select((item, index) => (item, index)); } diff --git a/MacroMate/Windows/MacroWindow.cs b/MacroMate/Windows/MacroWindow.cs index 3ba5b0f..6c14e4d 100644 --- a/MacroMate/Windows/MacroWindow.cs +++ b/MacroMate/Windows/MacroWindow.cs @@ -11,6 +11,8 @@ using MacroMate.Extensions.Dalamud.Str; using MacroMate.Extensions.Dalamaud.Interface.Components; using Dalamud.Interface.Utility; +using System.Linq; +using Dalamud.Game.Text; namespace MacroMate.Windows; @@ -253,12 +255,50 @@ private uint DrawMacroTextRightClickPopup(MateNode.Macro macro) { } } + if (ImGui.Selectable("Insert Special Character")) { + OpenMacroSpecialCharacterPopup(macro); + } + ImGui.EndPopup(); } return macroTextRightClickPopupId; } + private void OpenMacroSpecialCharacterPopup(MateNode.Macro macro) { + var seSpecialChars = Enum.GetValues() + .Select(c => c.ToIconChar()) + .ToList(); + + var seUnicodeChars = """ + π™′^¿¿‰øØ×∞∩£¥¢Ð€ªº†‡¤ ŒœÅ + ωψ↑↓→←⇔⇒♂♀♪¶§±<>≥≤≡÷½¼¾©®ª¹²³ + ※⇔「」«»≪≫《》【】℉℃‡。·••‥…¨°º‰ + ╲╳╱☁☀☃♭♯✓〃¹²³ + ●◎○■□▲△▼▽∇♥♡★☆◆◇♦♦♣♠♤♧¶ + αß∇ΘΦΩδ∂∃∀∈∋∑√∝∞∠∟∥∪∩∨∧∫∮∬ + ∴∵∽≠≦≤≥≧⊂⊃⊆⊇⊥⊿⌒─━│┃│¦ + ┗┓└┏┐┌┘┛├┝┠┣┤┥┫┬┯┰┳┴┷┸┻╋ + ┿╂┼¬ ̄,-./:;<=>[\]_`{|}~@ + ⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇ + ⓪①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ + №ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹ + 0123456789!?"#$%&'()*+¢¦¥ + ABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyz + """.Where(c => !Char.IsWhiteSpace(c)); + + var specialChars = seSpecialChars.Concat(seUnicodeChars).ToList(); + + Env.PluginWindowManager.CharPicker.Open(specialChars, (choice) => { + macro.Lines = macro.Lines.InsertAtTextValueIndex( + choice.ToString(), + (seStringInputTextMultiline.GetCursorPos() ?? 0) + Env.PluginWindowManager.CharPicker.ConsecutiveInserts + ); + Env.MacroConfig.NotifyEdit(); + }); + } + private void Save() { if (deleteRequested) { deleteRequested = false; diff --git a/MacroMate/Windows/PluginWindowManager.cs b/MacroMate/Windows/PluginWindowManager.cs index cfa3903..1a599f8 100644 --- a/MacroMate/Windows/PluginWindowManager.cs +++ b/MacroMate/Windows/PluginWindowManager.cs @@ -1,6 +1,7 @@ using System; using Dalamud.Interface.Windowing; using ImGuiNET; +using MacroMate.Extensions.Dalamud.Interface.CharPicker; using MacroMate.Extensions.Dalamud.Interface.ImGuiIconPicker; using MacroMate.Windows.Debug; @@ -11,6 +12,7 @@ public class PluginWindowManager : IDisposable { public SettingsWindow SettingsWindow { get; private set; } = new(); public MacroWindow MacroWindow { get; private set; } = new(); public IconPickerDialog IconPicker { get; private set; } = new(); + public CharPickerDialog CharPicker { get; private set; } = new(); public MacroLinkPicker MacroLinkPicker { get; private set; } = new(); public BackupWindow BackupWindow { get; private set; } = new(); public SubscriptionStatusWindow SubscriptionStatusWindow { get; private set; } = new(); @@ -22,6 +24,7 @@ public PluginWindowManager() { Env.WindowSystem.AddWindow(SettingsWindow); Env.WindowSystem.AddWindow(MacroWindow); Env.WindowSystem.AddWindow(IconPicker); + Env.WindowSystem.AddWindow(CharPicker); Env.WindowSystem.AddWindow(MacroLinkPicker); Env.WindowSystem.AddWindow(BackupWindow); Env.WindowSystem.AddWindow(SubscriptionStatusWindow);