From 5f91cd6cc2f3bd35190942d0c719300b78ac72f7 Mon Sep 17 00:00:00 2001 From: r00telement <47005506+r00telement@users.noreply.github.com> Date: Tue, 7 Dec 2021 22:20:15 +0000 Subject: [PATCH] Quick party assign + config UI update - Context menu options to add and remove custom tags for players - Quick party assign config - Update to tag config UI so it's collapsible - Now depends on XivCommon --- PlayerTags/PlayerTags.csproj | 1 + PlayerTags/PlayerTags.json | 1 + PlayerTags/Plugin.cs | 96 ++++- PlayerTags/PluginConfiguration.cs | 1 + PlayerTags/PluginConfigurationUI.cs | 485 ++++++++++++----------- PlayerTags/Resources/Strings.Designer.cs | 184 +++++++-- PlayerTags/Resources/Strings.resx | 23 +- PlayerTags/Tag.cs | 41 +- 8 files changed, 558 insertions(+), 274 deletions(-) diff --git a/PlayerTags/PlayerTags.csproj b/PlayerTags/PlayerTags.csproj index 2af85e3..bc65f64 100644 --- a/PlayerTags/PlayerTags.csproj +++ b/PlayerTags/PlayerTags.csproj @@ -21,6 +21,7 @@ + $(DalamudLibPath)FFXIVClientStructs.dll false diff --git a/PlayerTags/PlayerTags.json b/PlayerTags/PlayerTags.json index 5e9b14c..6418fc1 100644 --- a/PlayerTags/PlayerTags.json +++ b/PlayerTags/PlayerTags.json @@ -3,6 +3,7 @@ "Name": "Player Tags", "Description": "See tags for players in nameplates and chat, such as their role and job, or custom tags for players you know.", "Tags": [ "Jobs", "UI" ], + "CategoryTags": [ "jobs", "UI" ], "RepoUrl": "https://github.com/r00telement/PlayerTags", "IconUrl": "https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Icon.png", "ImageUrls": [ diff --git a/PlayerTags/Plugin.cs b/PlayerTags/Plugin.cs index 0f33544..cca35d7 100644 --- a/PlayerTags/Plugin.cs +++ b/PlayerTags/Plugin.cs @@ -4,6 +4,7 @@ using Dalamud.Game.ClientState; using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Game.ClientState.Party; using Dalamud.Game.Command; using Dalamud.Game.Gui; using Dalamud.Game.Text; @@ -12,16 +13,18 @@ using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.IoC; using Dalamud.Logging; using Dalamud.Plugin; +using PlayerTags.Resources; using System; using System.Collections.Generic; using System.Linq; +using XivCommon; +using XivCommon.Functions.ContextMenu; namespace PlayerTags { public sealed class Plugin : IDalamudPlugin { public string Name => "Player Tags"; - private const string c_CommandName = "/playertags"; [PluginService] @@ -48,21 +51,17 @@ namespace PlayerTags [PluginService] private static ClientState ClientState { get; set; } = null!; + [PluginService] + private static PartyList PartyList { get; set; } = null!; + private PluginConfiguration m_PluginConfiguration; - private PluginConfigurationUI m_PluginConfigurationUI; - private RandomNameGenerator m_RandomNameGenerator = new RandomNameGenerator(); - private PluginHooks? m_PluginHooks = null; - private Dictionary> m_TagTargetPayloads = new Dictionary>(); - private TextPayload m_SpaceTextPayload = new TextPayload($" "); - private PluginData m_PluginData = new PluginData(); - - private bool m_OpenConfigClicked = false; + private XivCommonBase XivCommon; public Plugin() { @@ -70,7 +69,7 @@ namespace PlayerTags m_PluginConfiguration = PluginInterface.GetPluginConfig() as PluginConfiguration ?? new PluginConfiguration(); m_PluginConfiguration.Initialize(PluginInterface); m_PluginData.Initialize(DataManager, m_PluginConfiguration); - m_PluginConfigurationUI = new PluginConfigurationUI(m_PluginConfiguration, m_PluginData); + m_PluginConfigurationUI = new PluginConfigurationUI(m_PluginConfiguration, m_PluginData, ClientState, PartyList); ClientState.Login += ClientState_Login; ClientState.Logout += ClientState_Logout; @@ -87,10 +86,14 @@ namespace PlayerTags HelpMessage = "Shows the config" }); Hook(); + XivCommon = new XivCommonBase(Hooks.ContextMenu); + XivCommon.Functions.ContextMenu.OpenContextMenu += ContextMenu_OpenContextMenu; } public void Dispose() { + XivCommon.Functions.ContextMenu.OpenContextMenu -= ContextMenu_OpenContextMenu; + XivCommon.Dispose(); Unhook(); CommandManager.RemoveHandler(c_CommandName); m_PluginConfiguration.Saved -= PluginConfiguration_Saved; @@ -134,25 +137,78 @@ namespace PlayerTags m_TagTargetPayloads.Clear(); } + private void ContextMenu_OpenContextMenu(ContextMenuOpenArgs args) + { + if (args.Text == null || !m_PluginConfiguration.IsCustomTagContextMenuEnabled) + { + return; + } + + string gameObjectName = args.Text.TextValue; + + var removedTags = m_PluginData.CustomTags.Where(tag => !tag.IncludesGameObjectNameToApplyTo(gameObjectName)); + + var addTagItem = new NormalContextSubMenuItem(Strings.Loc_Static_ContextMenu_AddTag, (itemArgs => + { + foreach (var removedTag in removedTags) + { + itemArgs.Items.Add(new NormalContextMenuItem(removedTag.Text.Value, (args => + { + removedTag.AddGameObjectNameToApplyTo(gameObjectName); + }))); + } + + // TODO: Temp hack because when opening somewhere other than the chat log, the last added item for some reason is added to the { }))); + } + })); + + if (!removedTags.Any()) + { + addTagItem.Enabled = false; + } + + args.Items.Add(addTagItem); + + var addedTags = m_PluginData.CustomTags.Where(tag => tag.IncludesGameObjectNameToApplyTo(gameObjectName)); + + var removeTagItem = new NormalContextSubMenuItem(Strings.Loc_Static_ContextMenu_RemoveTag, (itemArgs => + { + foreach (var addedTag in addedTags) + { + itemArgs.Items.Add(new NormalContextMenuItem(addedTag.Text.Value, (args => + { + addedTag.RemoveGameObjectNameToApplyTo(gameObjectName); + }))); + } + + // TODO: Temp hack because when opening somewhere other than the chat log, the last added item for some reason is added to the { }))); + } + })); + + if (!addedTags.Any()) + { + removeTagItem.Enabled = false; + } + + args.Items.Add(removeTagItem); + } + private void UiBuilder_Draw() { if (m_PluginConfiguration.IsVisible) { - // Only allow the config to be shown either when in the world, or when explicitly opened - if (ClientState.LocalPlayer != null || m_OpenConfigClicked) - { - m_PluginConfigurationUI.Draw(); - } - } - else - { - m_OpenConfigClicked = false; + m_PluginConfigurationUI.Draw(); } } private void UiBuilder_OpenConfigUi() { - m_OpenConfigClicked = true; m_PluginConfiguration.IsVisible = true; } diff --git a/PlayerTags/PluginConfiguration.cs b/PlayerTags/PluginConfiguration.cs index c315bf9..40c0832 100644 --- a/PlayerTags/PluginConfiguration.cs +++ b/PlayerTags/PluginConfiguration.cs @@ -16,6 +16,7 @@ namespace PlayerTags public NameplateTitleVisibility NameplateTitleVisibility = NameplateTitleVisibility.WhenHasTags; public NameplateTitlePosition NameplateTitlePosition = NameplateTitlePosition.AlwaysAboveName; public bool IsPlayerNameRandomlyGenerated = false; + public bool IsCustomTagContextMenuEnabled = true; [JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)] public Dictionary AllTagsChanges = new Dictionary(); diff --git a/PlayerTags/PluginConfigurationUI.cs b/PlayerTags/PluginConfigurationUI.cs index 0b25e52..b7799e7 100644 --- a/PlayerTags/PluginConfigurationUI.cs +++ b/PlayerTags/PluginConfigurationUI.cs @@ -1,4 +1,9 @@ -using ImGuiNET; +using Dalamud.Game.ClientState; +using Dalamud.Game.ClientState.Objects; +using Dalamud.Game.ClientState.Objects.SubKinds; +using Dalamud.Game.ClientState.Party; +using FFXIVClientStructs.FFXIV.Client.Game.Character; +using ImGuiNET; using Lumina.Excel.GeneratedSheets; using PlayerTags.Resources; using System; @@ -10,15 +15,17 @@ namespace PlayerTags public class PluginConfigurationUI { private PluginConfiguration m_PluginConfiguration; - private PluginData m_PluginData; - + private ClientState m_ClientState; + private PartyList m_PartyList; private InheritableValue? m_ColorPickerPopupDataContext; - public PluginConfigurationUI(PluginConfiguration config, PluginData pluginData) + public PluginConfigurationUI(PluginConfiguration config, PluginData pluginData, ClientState clientState, PartyList partyList) { m_PluginConfiguration = config; m_PluginData = pluginData; + m_ClientState = clientState; + m_PartyList = partyList; } public void Draw() @@ -34,6 +41,11 @@ namespace PlayerTags ImGui.TextWrapped(Strings.Loc_Static_WarningMessage); ImGui.PopStyleColor(); + DrawHeading(Strings.Loc_Static_General); + ImGui.TreePush(); + DrawCheckbox(nameof(m_PluginConfiguration.IsCustomTagContextMenuEnabled), true, ref m_PluginConfiguration.IsCustomTagContextMenuEnabled, () => m_PluginConfiguration.Save(m_PluginData)); + ImGui.TreePop(); + DrawHeading(Strings.Loc_Static_Nameplates); ImGui.TreePush(); DrawComboBox(true, true, false, ref m_PluginConfiguration.NameplateFreeCompanyVisibility, () => m_PluginConfiguration.Save(m_PluginData)); @@ -45,32 +57,71 @@ namespace PlayerTags ImGui.TreePush(); DrawCheckbox(nameof(m_PluginConfiguration.IsPlayerNameRandomlyGenerated), true, ref m_PluginConfiguration.IsPlayerNameRandomlyGenerated, () => m_PluginConfiguration.Save(m_PluginData)); ImGui.TreePop(); - ImGui.EndTabItem(); + DrawHeading(Strings.Loc_Static_Tags); ImGui.TreePush(); Draw(m_PluginData.AllTags); + ImGui.TreePop(); - ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.1f, 0.3f, 0.1f, 1)); - ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.2f, 0.6f, 0.2f, 1)); - ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.2f, 0.6f, 0.2f, 1)); - if (ImGui.Button(Strings.Loc_Static_AddCustomTag)) + DrawHeading(Strings.Loc_Static_PartyAssign); + ImGui.TreePush(); + if (ImGui.BeginTable("##PartyAssignTable", 1 + m_PluginData.CustomTags.Count)) { - var newTag = new Tag(new LocalizedPluginString(nameof(PluginData.CustomTags))) + ImGui.TableHeader(Strings.Loc_Static_PlayerName); + ImGui.TableSetupColumn(Strings.Loc_Static_PlayerName); + ImGui.NextColumn(); + foreach (var customTag in m_PluginData.CustomTags) { - Text = "", - GameObjectNamesToApplyTo = "" + ImGui.TableHeader(customTag.Text.InheritedValue); + ImGui.TableSetupColumn(customTag.Text.InheritedValue); + ImGui.NextColumn(); + } + ImGui.TableHeadersRow(); + + var drawPartyMember = (string playerName) => + { + ImGui.TableNextRow(); + + ImGui.TableNextColumn(); + ImGui.Text(playerName); + + foreach (Tag customTag in m_PluginData.CustomTags) + { + ImGui.TableNextColumn(); + + bool isTagAssigned = customTag.IncludesGameObjectNameToApplyTo(playerName); + DrawCheckbox("IsEnabled", false, ref isTagAssigned, () => + { + if (isTagAssigned) + { + customTag.AddGameObjectNameToApplyTo(playerName); + } + else + { + customTag.RemoveGameObjectNameToApplyTo(playerName); + } + + m_PluginConfiguration.Save(m_PluginData); + }); + } }; - m_PluginData.CustomTags.Add(newTag); - newTag.Parent = m_PluginData.AllCustomTags; - } - ImGui.PopStyleColor(); - ImGui.PopStyleColor(); - ImGui.PopStyleColor(); + foreach (var partyMember in m_PartyList) + { + drawPartyMember(partyMember.Name.TextValue); + } + if (m_PartyList.Length == 0 && m_ClientState.LocalPlayer != null) + { + drawPartyMember(m_ClientState.LocalPlayer.Name.TextValue); + } + + ImGui.EndTable(); + } ImGui.TreePop(); + ImGui.End(); } @@ -84,189 +135,209 @@ namespace PlayerTags { ImGui.PushID(tag.GetHashCode().ToString()); - ImGui.BeginGroup(); - ImGui.BeginChild(tag.GetHashCode().ToString(), new Vector2(100, 60)); - - var text = tag.Name.Value; - var textSize = ImGui.CalcTextSize(text); - var addButtonSize = new Vector2(23, 23); - var panelSize = ImGui.GetItemRectSize(); - - ImGui.SetCursorPosX(panelSize.X - textSize.X); - ImGui.Text(text); - - if (ImGui.IsPopupOpen("AddPopup")) - { - ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.2f, 0.6f, 0.2f, 1)); - } - else - { - ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.1f, 0.3f, 0.1f, 1)); - } - ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.2f, 0.6f, 0.2f, 1)); - ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.2f, 0.6f, 0.2f, 1)); - ImGui.SetCursorPosX(panelSize.X - addButtonSize.X); - var addPopupPos = ImGui.GetCursorPos(); - addPopupPos.Y -= addButtonSize.Y + 2; - if (ImGui.Button("+", addButtonSize)) - { - ImGui.OpenPopup("AddPopup"); - } - ImGui.PopStyleColor(); - ImGui.PopStyleColor(); - ImGui.PopStyleColor(); - - bool wasPaddingConsumed = false; - ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 5)); - ImGui.SetNextWindowPos(ImGui.GetCursorScreenPos() + addPopupPos); - if (ImGui.BeginPopup("AddPopup")) - { - wasPaddingConsumed = true; - ImGui.PopStyleVar(); - - ImGui.PushStyleColor(ImGuiCol.FrameBg, new Vector4(0f, 0f, 0f, 0)); - if (ImGui.BeginListBox("###SelectableInheritables")) - { - var selectableInheritables = tag.Inheritables.Where(inheritable => inheritable.Value.Behavior == InheritableBehavior.Inherit).ToDictionary(item => item.Key, item => item.Value); - var selectableInheritablesWithLocalizedNames = selectableInheritables - .Select(inheritable => new { Name = inheritable.Key, LocalizedName = Localizer.GetString(inheritable.Key, false) }) - .OrderBy(item => item.LocalizedName); - - foreach (var inheritableLocalizedName in selectableInheritablesWithLocalizedNames) - { - bool isSelected = false; - if (ImGui.Selectable(inheritableLocalizedName.LocalizedName, isSelected)) - { - selectableInheritables[inheritableLocalizedName.Name].Behavior = InheritableBehavior.Enabled; - - if (selectableInheritables[inheritableLocalizedName.Name] is InheritableValue inheritableBool) - { - inheritableBool.Value = true; - } - - m_PluginConfiguration.Save(m_PluginData); - ImGui.CloseCurrentPopup(); - } - - if (isSelected) - { - ImGui.SetItemDefaultFocus(); - } - - if (ImGui.IsItemHovered()) - { - ImGui.SetTooltip(Localizer.GetString(inheritableLocalizedName.Name, true)); - } - } - - ImGui.EndListBox(); - } - ImGui.PopStyleColor(); - ImGui.EndPopup(); - } - if (!wasPaddingConsumed) - { - ImGui.PopStyleVar(); - } - - if (ImGui.IsItemHovered()) - { - ImGui.SetTooltip(Strings.Loc_Static_AddPropertyOverride_Description); - } - ImGui.EndChild(); - ImGui.EndGroup(); - - ImGui.SameLine(); - ImGui.BeginGroup(); - - var selectedInheritables = tag.Inheritables.Where(inheritable => inheritable.Value.Behavior != InheritableBehavior.Inherit).ToDictionary(item => item.Key, item => item.Value); - var selectedInheritablesWithLocalizedNames = selectedInheritables - .Select(inheritable => new { Name = inheritable.Key, LocalizedName = Localizer.GetString(inheritable.Key, false) }) - .OrderBy(item => item.LocalizedName); - - foreach (var selectedInheritablesWithLocalizedName in selectedInheritablesWithLocalizedNames) - { - switch (selectedInheritablesWithLocalizedName.Name) - { - case nameof(tag.Icon): - ImGui.SameLine(); - DrawInheritable(nameof(tag.Icon), false, true, tag.Icon); - break; - case nameof(tag.IsIconVisibleInChat): - ImGui.SameLine(); - DrawInheritable(nameof(tag.IsIconVisibleInChat), tag.IsIconVisibleInChat); - break; - case nameof(tag.IsIconVisibleInNameplates): - ImGui.SameLine(); - DrawInheritable(nameof(tag.IsIconVisibleInNameplates), tag.IsIconVisibleInNameplates); - break; - case nameof(tag.Text): - ImGui.SameLine(); - DrawInheritable(nameof(tag.Text), tag.Text); - break; - case nameof(tag.TextColor): - ImGui.SameLine(); - DrawInheritable(nameof(tag.TextColor), tag.TextColor); - break; - case nameof(tag.IsTextItalic): - ImGui.SameLine(); - DrawInheritable(nameof(tag.IsTextItalic), tag.IsTextItalic); - break; - case nameof(tag.IsTextVisibleInChat): - ImGui.SameLine(); - DrawInheritable(nameof(tag.IsTextVisibleInChat), tag.IsTextVisibleInChat); - break; - case nameof(tag.IsTextVisibleInNameplates): - ImGui.SameLine(); - DrawInheritable(nameof(tag.IsTextVisibleInNameplates), tag.IsTextVisibleInNameplates); - break; - case nameof(tag.TagPositionInChat): - ImGui.SameLine(); - DrawInheritable(nameof(tag.TagPositionInChat), true, false, tag.TagPositionInChat); - break; - case nameof(tag.TagPositionInNameplates): - ImGui.SameLine(); - DrawInheritable(nameof(tag.TagPositionInNameplates), true, false, tag.TagPositionInNameplates); - break; - case nameof(tag.TagTargetInNameplates): - ImGui.SameLine(); - DrawInheritable(nameof(tag.TagTargetInNameplates), true, false, tag.TagTargetInNameplates); - break; - case nameof(tag.GameObjectNamesToApplyTo): - ImGui.SameLine(); - DrawInheritable(nameof(tag.GameObjectNamesToApplyTo), tag.GameObjectNamesToApplyTo); - break; - default: - break; - } - } - + var collapsingHeaderName = tag.Name.Value; if (m_PluginData.CustomTags.Contains(tag)) { - ImGui.SameLine(); - ImGui.BeginGroup(); - ImGui.Indent(); - ImGui.Text(""); + collapsingHeaderName = tag.Text.InheritedValue; + } - ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.3f, 0.1f, 0.1f, 1)); - ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.6f, 0.2f, 0.2f, 1)); - ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.6f, 0.2f, 0.2f, 1)); - if (ImGui.Button(Strings.Loc_Static_RemoveCustomTag)) + if (ImGui.CollapsingHeader($"{collapsingHeaderName}###{tag.GetHashCode()}")) + { + ImGui.TreePush(); + ImGui.BeginGroup(); + + ImGui.BeginGroup(); + var addButtonSize = new Vector2(23, 23); + if (ImGui.IsPopupOpen("AddPopup")) { - m_PluginData.AllCustomTags.Children.Remove(tag); - m_PluginData.CustomTags.Remove(tag); - m_PluginConfiguration.Save(m_PluginData); + ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.2f, 0.6f, 0.2f, 1)); + } + else + { + ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.1f, 0.3f, 0.1f, 1)); + } + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.2f, 0.6f, 0.2f, 1)); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.2f, 0.6f, 0.2f, 1)); + + ImGui.Text(""); + var addPopupPos = ImGui.GetCursorPos(); + addPopupPos.Y -= 4; + if (ImGui.Button("+", addButtonSize)) + { + ImGui.OpenPopup("AddPopup"); } ImGui.PopStyleColor(); ImGui.PopStyleColor(); ImGui.PopStyleColor(); - ImGui.EndGroup(); - } - ImGui.EndGroup(); - foreach (var childTag in tag.Children.ToArray()) - { - Draw(childTag); + bool wasPaddingConsumed = false; + ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 5)); + ImGui.SetNextWindowPos(ImGui.GetCursorScreenPos() + addPopupPos); + if (ImGui.BeginPopup("AddPopup")) + { + wasPaddingConsumed = true; + ImGui.PopStyleVar(); + + ImGui.PushStyleColor(ImGuiCol.FrameBg, new Vector4(0f, 0f, 0f, 0)); + if (ImGui.BeginListBox("###SelectableInheritables")) + { + var selectableInheritables = tag.Inheritables.Where(inheritable => inheritable.Value.Behavior == InheritableBehavior.Inherit).ToDictionary(item => item.Key, item => item.Value); + var selectableInheritablesWithLocalizedNames = selectableInheritables + .Select(inheritable => new { Name = inheritable.Key, LocalizedName = Localizer.GetString(inheritable.Key, false) }) + .OrderBy(item => item.LocalizedName); + + foreach (var inheritableLocalizedName in selectableInheritablesWithLocalizedNames) + { + bool isSelected = false; + if (ImGui.Selectable(inheritableLocalizedName.LocalizedName, isSelected)) + { + selectableInheritables[inheritableLocalizedName.Name].Behavior = InheritableBehavior.Enabled; + + if (selectableInheritables[inheritableLocalizedName.Name] is InheritableValue inheritableBool) + { + inheritableBool.Value = true; + } + + m_PluginConfiguration.Save(m_PluginData); + ImGui.CloseCurrentPopup(); + } + + if (isSelected) + { + ImGui.SetItemDefaultFocus(); + } + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(Localizer.GetString(inheritableLocalizedName.Name, true)); + } + } + + ImGui.EndListBox(); + } + ImGui.PopStyleColor(); + ImGui.EndPopup(); + } + if (!wasPaddingConsumed) + { + ImGui.PopStyleVar(); + } + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(Strings.Loc_Static_AddPropertyOverride_Description); + } + ImGui.EndGroup(); + + var selectedInheritables = tag.Inheritables.Where(inheritable => inheritable.Value.Behavior != InheritableBehavior.Inherit).ToDictionary(item => item.Key, item => item.Value); + var selectedInheritablesWithLocalizedNames = selectedInheritables + .Select(inheritable => new { Name = inheritable.Key, LocalizedName = Localizer.GetString(inheritable.Key, false) }) + .OrderBy(item => item.LocalizedName); + + foreach (var selectedInheritablesWithLocalizedName in selectedInheritablesWithLocalizedNames) + { + ImGui.SameLine(); + ImGui.BeginGroup(); + + ImGui.Indent(); + ImGui.BeginChild(selectedInheritablesWithLocalizedName.Name, new Vector2(180, 50)); + + switch (selectedInheritablesWithLocalizedName.Name) + { + case nameof(tag.Icon): + DrawInheritable(nameof(tag.Icon), false, true, tag.Icon); + break; + case nameof(tag.IsIconVisibleInChat): + DrawInheritable(nameof(tag.IsIconVisibleInChat), tag.IsIconVisibleInChat); + break; + case nameof(tag.IsIconVisibleInNameplates): + DrawInheritable(nameof(tag.IsIconVisibleInNameplates), tag.IsIconVisibleInNameplates); + break; + case nameof(tag.Text): + DrawInheritable(nameof(tag.Text), tag.Text); + break; + case nameof(tag.TextColor): + DrawInheritable(nameof(tag.TextColor), tag.TextColor); + break; + case nameof(tag.IsTextItalic): + DrawInheritable(nameof(tag.IsTextItalic), tag.IsTextItalic); + break; + case nameof(tag.IsTextVisibleInChat): + DrawInheritable(nameof(tag.IsTextVisibleInChat), tag.IsTextVisibleInChat); + break; + case nameof(tag.IsTextVisibleInNameplates): + DrawInheritable(nameof(tag.IsTextVisibleInNameplates), tag.IsTextVisibleInNameplates); + break; + case nameof(tag.TagPositionInChat): + DrawInheritable(nameof(tag.TagPositionInChat), true, false, tag.TagPositionInChat); + break; + case nameof(tag.TagPositionInNameplates): + DrawInheritable(nameof(tag.TagPositionInNameplates), true, false, tag.TagPositionInNameplates); + break; + case nameof(tag.TagTargetInNameplates): + DrawInheritable(nameof(tag.TagTargetInNameplates), true, false, tag.TagTargetInNameplates); + break; + case nameof(tag.GameObjectNamesToApplyTo): + DrawInheritable(nameof(tag.GameObjectNamesToApplyTo), tag.GameObjectNamesToApplyTo); + break; + default: + break; + } + + ImGui.EndChild(); + ImGui.EndGroup(); + } + + if (m_PluginData.CustomTags.Contains(tag)) + { + ImGui.SameLine(); + ImGui.BeginGroup(); + ImGui.Indent(); + ImGui.Text(""); + + ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.3f, 0.1f, 0.1f, 1)); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.6f, 0.2f, 0.2f, 1)); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.6f, 0.2f, 0.2f, 1)); + if (ImGui.Button(Strings.Loc_Static_RemoveCustomTag)) + { + m_PluginData.AllCustomTags.Children.Remove(tag); + m_PluginData.CustomTags.Remove(tag); + m_PluginConfiguration.Save(m_PluginData); + } + ImGui.PopStyleColor(); + ImGui.PopStyleColor(); + ImGui.PopStyleColor(); + ImGui.EndGroup(); + } + + foreach (var childTag in tag.Children.ToArray()) + { + Draw(childTag); + } + + if (tag == m_PluginData.AllCustomTags) + { + ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.1f, 0.3f, 0.1f, 1)); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.2f, 0.6f, 0.2f, 1)); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.2f, 0.6f, 0.2f, 1)); + if (ImGui.Button(Strings.Loc_Static_AddCustomTag)) + { + var newTag = new Tag(new LocalizedPluginString(nameof(PluginData.CustomTags))) + { + Text = "", + GameObjectNamesToApplyTo = "" + }; + + m_PluginData.CustomTags.Add(newTag); + newTag.Parent = m_PluginData.AllCustomTags; + } + ImGui.PopStyleColor(); + ImGui.PopStyleColor(); + ImGui.PopStyleColor(); + } + + ImGui.EndGroup(); + ImGui.TreePop(); } ImGui.PopID(); @@ -295,29 +366,16 @@ namespace PlayerTags private void DrawInheritable(string localizedStringName, InheritableValue inheritable) { - ImGui.BeginGroup(); - ImGui.Indent(); - ImGui.BeginChild(inheritable.GetHashCode().ToString(), new Vector2(180, 47)); - ImGui.Text(Localizer.GetString(localizedStringName, false)); DrawCheckbox("IsEnabled", false, ref inheritable.Value, () => { m_PluginConfiguration.Save(m_PluginData); }); - ImGui.SameLine(); - DrawRemoveButton(inheritable); - - ImGui.EndChild(); - ImGui.EndGroup(); } private void DrawInheritable(string localizedStringName, bool shouldLocalizeNames, bool shouldOrderNames, InheritableValue inheritable) where TEnum : struct, Enum { - ImGui.BeginGroup(); - ImGui.Indent(); - ImGui.BeginChild(inheritable.GetHashCode().ToString(), new Vector2(180, 47)); - ImGui.Text(Localizer.GetString(localizedStringName, false)); bool isEnabled = inheritable.Behavior == InheritableBehavior.Enabled; @@ -342,17 +400,10 @@ namespace PlayerTags ImGui.SameLine(); DrawRemoveButton(inheritable); - - ImGui.EndChild(); - ImGui.EndGroup(); } private void DrawInheritable(string localizedStringName, InheritableValue inheritable) { - ImGui.BeginGroup(); - ImGui.Indent(); - ImGui.BeginChild(inheritable.GetHashCode().ToString(), new Vector2(180, 47)); - ImGui.Text(Localizer.GetString(localizedStringName, false)); bool isEnabled = inheritable.Behavior == InheritableBehavior.Enabled; @@ -412,17 +463,10 @@ namespace PlayerTags ImGui.SameLine(); DrawRemoveButton(inheritable); - - ImGui.EndChild(); - ImGui.EndGroup(); } private void DrawInheritable(string localizedStringName, InheritableReference inheritable) { - ImGui.BeginGroup(); - ImGui.Indent(); - ImGui.BeginChild(inheritable.GetHashCode().ToString(), new Vector2(180, 47)); - ImGui.Text(Localizer.GetString(localizedStringName, false)); bool isEnabled = inheritable.Behavior == InheritableBehavior.Enabled; @@ -447,9 +491,6 @@ namespace PlayerTags ImGui.SameLine(); DrawRemoveButton(inheritable); - - ImGui.EndChild(); - ImGui.EndGroup(); } private void DrawHeading(string label) diff --git a/PlayerTags/Resources/Strings.Designer.cs b/PlayerTags/Resources/Strings.Designer.cs index b2f3a67..ac5a97c 100644 --- a/PlayerTags/Resources/Strings.Designer.cs +++ b/PlayerTags/Resources/Strings.Designer.cs @@ -19,7 +19,7 @@ namespace PlayerTags.Resources { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Strings { @@ -72,9 +72,9 @@ namespace PlayerTags.Resources { /// /// Looks up a localized string similar to All Roles. /// - public static string Loc_AllRoleTagss { + public static string Loc_AllRoleTags { get { - return ResourceManager.GetString("Loc_AllRoleTagss", resourceCulture); + return ResourceManager.GetString("Loc_AllRoleTags", resourceCulture); } } @@ -132,6 +132,33 @@ namespace PlayerTags.Resources { } } + /// + /// Looks up a localized string similar to Enable context menu options for custom tags. + /// + public static string Loc_IsCustomTagContextMenuEnabled { + get { + return ResourceManager.GetString("Loc_IsCustomTagContextMenuEnabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to When opening the player context menu, options will be available to add and remove custom tags for the selected player.. + /// + public static string Loc_IsCustomTagContextMenuEnabled_Description { + get { + return ResourceManager.GetString("Loc_IsCustomTagContextMenuEnabled_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enabled. + /// + public static string Loc_IsEnabled { + get { + return ResourceManager.GetString("Loc_IsEnabled", resourceCulture); + } + } + /// /// Looks up a localized string similar to Enable the value of this override.. /// @@ -144,36 +171,36 @@ namespace PlayerTags.Resources { /// /// Looks up a localized string similar to Icon visible in chat. /// - public static string Loc_IsIconVisibleInChatOption { + public static string Loc_IsIconVisibleInChat { get { - return ResourceManager.GetString("Loc_IsIconVisibleInChatOption", resourceCulture); + return ResourceManager.GetString("Loc_IsIconVisibleInChat", resourceCulture); } } /// /// Looks up a localized string similar to Whether the icon is visible in the tag in chat.. /// - public static string Loc_IsIconVisibleInChatOption_Description { + public static string Loc_IsIconVisibleInChat_Description { get { - return ResourceManager.GetString("Loc_IsIconVisibleInChatOption_Description", resourceCulture); + return ResourceManager.GetString("Loc_IsIconVisibleInChat_Description", resourceCulture); } } /// /// Looks up a localized string similar to Icon visible in nameplates. /// - public static string Loc_IsIconVisibleInNameplateOption { + public static string Loc_IsIconVisibleInNameplates { get { - return ResourceManager.GetString("Loc_IsIconVisibleInNameplateOption", resourceCulture); + return ResourceManager.GetString("Loc_IsIconVisibleInNameplates", resourceCulture); } } /// /// Looks up a localized string similar to Whether the icon is visible in the tag in nameplates.. /// - public static string Loc_IsIconVisibleInNameplateOption_Description { + public static string Loc_IsIconVisibleInNameplates_Description { get { - return ResourceManager.GetString("Loc_IsIconVisibleInNameplateOption_Description", resourceCulture); + return ResourceManager.GetString("Loc_IsIconVisibleInNameplates_Description", resourceCulture); } } @@ -198,54 +225,108 @@ namespace PlayerTags.Resources { /// /// Looks up a localized string similar to Text italic. /// - public static string Loc_IsTextItalicOption { + public static string Loc_IsTextItalic { get { - return ResourceManager.GetString("Loc_IsTextItalicOption", resourceCulture); + return ResourceManager.GetString("Loc_IsTextItalic", resourceCulture); } } /// /// Looks up a localized string similar to Whether the text in the tag is italic.. /// - public static string Loc_IsTextItalicOption_Description { + public static string Loc_IsTextItalic_Description { get { - return ResourceManager.GetString("Loc_IsTextItalicOption_Description", resourceCulture); + return ResourceManager.GetString("Loc_IsTextItalic_Description", resourceCulture); } } /// /// Looks up a localized string similar to Text visible in chat. /// - public static string Loc_IsTextVisibleInChatOption { + public static string Loc_IsTextVisibleInChat { get { - return ResourceManager.GetString("Loc_IsTextVisibleInChatOption", resourceCulture); + return ResourceManager.GetString("Loc_IsTextVisibleInChat", resourceCulture); } } /// /// Looks up a localized string similar to Whether the text is visible in the tag in chat.. /// - public static string Loc_IsTextVisibleInChatOption_Description { + public static string Loc_IsTextVisibleInChat_Description { get { - return ResourceManager.GetString("Loc_IsTextVisibleInChatOption_Description", resourceCulture); + return ResourceManager.GetString("Loc_IsTextVisibleInChat_Description", resourceCulture); } } /// /// Looks up a localized string similar to Text visible in nameplates. /// - public static string Loc_IsTextVisibleInNameplateOption { + public static string Loc_IsTextVisibleInNameplates { get { - return ResourceManager.GetString("Loc_IsTextVisibleInNameplateOption", resourceCulture); + return ResourceManager.GetString("Loc_IsTextVisibleInNameplates", resourceCulture); } } /// /// Looks up a localized string similar to Whether the text is visible in the tag in nameplates.. /// - public static string Loc_IsTextVisibleInNameplateOption_Description { + public static string Loc_IsTextVisibleInNameplates_Description { get { - return ResourceManager.GetString("Loc_IsTextVisibleInNameplateOption_Description", resourceCulture); + return ResourceManager.GetString("Loc_IsTextVisibleInNameplates_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Free company. + /// + public static string Loc_NameplateElement_FreeCompany { + get { + return ResourceManager.GetString("Loc_NameplateElement_FreeCompany", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The free company element on nameplates.. + /// + public static string Loc_NameplateElement_FreeCompany_Description { + get { + return ResourceManager.GetString("Loc_NameplateElement_FreeCompany_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Name. + /// + public static string Loc_NameplateElement_Name { + get { + return ResourceManager.GetString("Loc_NameplateElement_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The name element on nameplates.. + /// + public static string Loc_NameplateElement_Name_Description { + get { + return ResourceManager.GetString("Loc_NameplateElement_Name_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Title. + /// + public static string Loc_NameplateElement_Title { + get { + return ResourceManager.GetString("Loc_NameplateElement_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The title element on nameplates.. + /// + public static string Loc_NameplateElement_Title_Description { + get { + return ResourceManager.GetString("Loc_NameplateElement_Title_Description", resourceCulture); } } @@ -492,6 +573,24 @@ namespace PlayerTags.Resources { } } + /// + /// Looks up a localized string similar to Add tag. + /// + public static string Loc_Static_ContextMenu_AddTag { + get { + return ResourceManager.GetString("Loc_Static_ContextMenu_AddTag", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Remove tag. + /// + public static string Loc_Static_ContextMenu_RemoveTag { + get { + return ResourceManager.GetString("Loc_Static_ContextMenu_RemoveTag", resourceCulture); + } + } + /// /// Looks up a localized string similar to Development. /// @@ -501,6 +600,15 @@ namespace PlayerTags.Resources { } } + /// + /// Looks up a localized string similar to General. + /// + public static string Loc_Static_General { + get { + return ResourceManager.GetString("Loc_Static_General", resourceCulture); + } + } + /// /// Looks up a localized string similar to Nameplates. /// @@ -510,6 +618,24 @@ namespace PlayerTags.Resources { } } + /// + /// Looks up a localized string similar to Assign custom tags to party. + /// + public static string Loc_Static_PartyAssign { + get { + return ResourceManager.GetString("Loc_Static_PartyAssign", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Player name. + /// + public static string Loc_Static_PlayerName { + get { + return ResourceManager.GetString("Loc_Static_PlayerName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Player Tags. /// @@ -628,7 +754,7 @@ namespace PlayerTags.Resources { } /// - /// Looks up a localized string similar to Tag position in chat. + /// Looks up a localized string similar to Tag position in nameplates. /// public static string Loc_TagPositionInNameplates { get { @@ -646,7 +772,7 @@ namespace PlayerTags.Resources { } /// - /// Looks up a localized string similar to Tag target in chat. + /// Looks up a localized string similar to Tag target in nameplates. /// public static string Loc_TagTargetInNameplates { get { @@ -684,18 +810,18 @@ namespace PlayerTags.Resources { /// /// Looks up a localized string similar to Text color. /// - public static string Loc_TextColorOption { + public static string Loc_TextColor { get { - return ResourceManager.GetString("Loc_TextColorOption", resourceCulture); + return ResourceManager.GetString("Loc_TextColor", resourceCulture); } } /// /// Looks up a localized string similar to The color of the text in the tag.. /// - public static string Loc_TextColorOption_Description { + public static string Loc_TextColor_Description { get { - return ResourceManager.GetString("Loc_TextColorOption_Description", resourceCulture); + return ResourceManager.GetString("Loc_TextColor_Description", resourceCulture); } } } diff --git a/PlayerTags/Resources/Strings.resx b/PlayerTags/Resources/Strings.resx index 72a6a24..88d0f56 100644 --- a/PlayerTags/Resources/Strings.resx +++ b/PlayerTags/Resources/Strings.resx @@ -123,9 +123,30 @@ This plugin can modify nameplates. When combined with other plugins that modify nameplates, you are likely to see unexpected behavior. + + General + + + Assign custom tags to party + + + Player name + + + Add tag + + + Remove tag + Nameplates + + Enable context menu options for custom tags + + + When opening the player context menu, options will be available to add and remove custom tags for the selected player. + Free company visibility @@ -292,7 +313,7 @@ Text italic - + Whether the text in the tag is italic. diff --git a/PlayerTags/Tag.cs b/PlayerTags/Tag.cs index 4e55769..0947b58 100644 --- a/PlayerTags/Tag.cs +++ b/PlayerTags/Tag.cs @@ -80,7 +80,7 @@ namespace PlayerTags public InheritableReference GameObjectNamesToApplyTo = new InheritableReference(""); - private string[] CleanGameObjectNamesToApplyTo + private string[] SplitGameObjectNamesToApplyTo { get { @@ -89,7 +89,15 @@ namespace PlayerTags return new string[] { }; } - return GameObjectNamesToApplyTo.InheritedValue.Split(';', ',').Select(gameObjectName => gameObjectName.ToLower().Trim()).ToArray(); + return GameObjectNamesToApplyTo.InheritedValue.Split(';', ','); + } + } + + private string[] CleanGameObjectNamesToApplyTo + { + get + { + return SplitGameObjectNamesToApplyTo.Select(gameObjectName => gameObjectName.ToLower().Trim()).ToArray(); } } @@ -103,6 +111,35 @@ namespace PlayerTags return CleanGameObjectNamesToApplyTo.Contains(gameObjectName.ToLower()); } + public void AddGameObjectNameToApplyTo(string gameObjectName) + { + if (IncludesGameObjectNameToApplyTo(gameObjectName)) + { + return; + } + + List newSplitGameObjectNamesToApplyTo = SplitGameObjectNamesToApplyTo.ToList(); + + newSplitGameObjectNamesToApplyTo.Add(gameObjectName); + + GameObjectNamesToApplyTo = string.Join(";", newSplitGameObjectNamesToApplyTo); + } + + public void RemoveGameObjectNameToApplyTo(string gameObjectName) + { + if (!IncludesGameObjectNameToApplyTo(gameObjectName)) + { + return; + } + + List newSplitGameObjectNamesToApplyTo = SplitGameObjectNamesToApplyTo.ToList(); + + var index = Array.IndexOf(CleanGameObjectNamesToApplyTo, gameObjectName.ToLower()); + newSplitGameObjectNamesToApplyTo.RemoveAt(index); + + GameObjectNamesToApplyTo = string.Join(";", newSplitGameObjectNamesToApplyTo); + } + public Dictionary GetChanges(Dictionary? defaultChanges = null) { Dictionary changes = new Dictionary();