From 6da8ac93fe9490695217e76fd204b785b8d1afd2 Mon Sep 17 00:00:00 2001 From: Jon Kazama Date: Wed, 27 May 2026 13:20:59 +0200 Subject: [PATCH] feat(payload-handler): wire DrawItem/EventItem/Status/Uri popups + InlineIcon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit E4 fills the remaining popup-body methods: - DrawItemPopup: shows item-name, icon (via InlineIcon), and description via _chunkRenderer.DrawChunks; dispatches to DrawEventItemPopup when payload.Kind == ItemKind.EventItem (per v1.5.6 internal split) - DrawEventItemPopup: same shape, Sheets.EventItemSheet/EventItemHelpSheet reads, _chunkRenderer.DrawChunks for description rendering - DrawStatusPopup: status-name + description via _chunkRenderer.DrawChunks; "Link" action appends " " via _inputBar.AppendPending (per ยง4.2) - DrawUriPopup: open-in-browser + copy-link selectables (no LogWindow deps) - InlineIcon: pure static helper for popup-icon rendering Replaces E2's TODO(E4) markers in DrawPopups' Item/Status/Uri switch-cases with real calls + drawn=true. E5 will wire Hover/Click bodies; E6 MoveTooltip. --- HellionChat/PayloadHandler.cs | 174 +++++++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 3 deletions(-) diff --git a/HellionChat/PayloadHandler.cs b/HellionChat/PayloadHandler.cs index 222d42c..21eb304 100644 --- a/HellionChat/PayloadHandler.cs +++ b/HellionChat/PayloadHandler.cs @@ -1,16 +1,23 @@ using System.Linq; +using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Objects.SubKinds; +using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Interface.ImGuiNotification; +using Dalamud.Interface.Textures; +using Dalamud.Interface.Textures.TextureWraps; +using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; +using Dalamud.Utility; using HellionChat.Code; using HellionChat.Resources; using HellionChat.Themes; using HellionChat.Ui.Components; using HellionChat.Ui.Windows; using HellionChat.Util; +using Lumina.Excel.Sheets; using Microsoft.Extensions.Logging; namespace HellionChat; @@ -90,15 +97,15 @@ internal sealed class PayloadHandler drawn = true; break; case ItemPayload item: - // TODO(E4): DrawItemPopup(item); + DrawItemPopup(item); drawn = true; break; case UriPayload uri: - // TODO(E4): DrawUriPopup(uri); + DrawUriPopup(uri); drawn = true; break; case StatusPayload status: - // TODO(E4): DrawStatusPopup(status); + DrawStatusPopup(status); drawn = true; break; } @@ -412,6 +419,167 @@ internal sealed class PayloadHandler return null; } + private void DrawItemPopup(ItemPayload payload) + { + if (payload.Kind == ItemKind.EventItem) + { + DrawEventItemPopup(payload); + return; + } + + if (!Sheets.ItemSheet.TryGetRow(payload.ItemId, out var itemRow)) + return; + + var hq = payload.Kind == ItemKind.Hq; + if ( + Plugin + .TextureProvider.GetFromGameIcon(new GameIconLookup(itemRow.Icon, hq)) + .GetWrapOrDefault() is + { } icon + ) + InlineIcon(icon); + + var name = itemRow.Name.ToDalamudString(); + if (hq) + name.Payloads.Add(new TextPayload(" ")); + else if (payload.Kind == ItemKind.Collectible) + name.Payloads.Add(new TextPayload(" ")); + + _chunkRenderer.DrawChunks(ChunkUtil.ToChunks(name, ChunkSource.None, null).ToList(), false); + ImGui.Separator(); + + var realItemId = payload.RawItemId; + if (itemRow.EquipSlotCategory.RowId != 0) + { + if (ImGui.Selectable(Language.Context_TryOn)) + GameFunctions.Context.TryOn(realItemId, 0); + + if (ImGui.Selectable(Language.Context_ItemComparison)) + GameFunctions.Context.OpenItemComparison(realItemId); + } + + if (itemRow.ItemSearchCategory.Value.Category == 3) + if (ImGui.Selectable(Language.Context_SearchRecipes)) + GameFunctions.Context.SearchForRecipesUsingItem(payload.ItemId); + + if (ImGui.Selectable(Language.Context_SearchForItem)) + GameFunctions.Context.SearchForItem(realItemId); + + if (ImGui.Selectable(Language.Context_Link)) + GameFunctions.Context.LinkItem(realItemId); + + if (ImGui.Selectable(Language.Context_CopyItemName)) + ImGui.SetClipboardText(name.TextValue); + } + + private void DrawEventItemPopup(ItemPayload payload) + { + if (payload.Kind != ItemKind.EventItem) + return; + + if (!Sheets.EventItemSheet.HasRow(payload.ItemId)) + return; + + var item = Sheets.EventItemSheet.GetRow(payload.ItemId); + if ( + Plugin + .TextureProvider.GetFromGameIcon(new GameIconLookup(item.Icon)) + .GetWrapOrDefault() is + { } icon + ) + InlineIcon(icon); + + _chunkRenderer.DrawChunks( + ChunkUtil.ToChunks(item.Name.ToDalamudString(), ChunkSource.None, null).ToList(), + false + ); + ImGui.Separator(); + + var realItemId = payload.RawItemId; + if (ImGui.Selectable(Language.Context_Link)) + GameFunctions.Context.LinkItem(realItemId); + + if (ImGui.Selectable(Language.Context_CopyItemName)) + ImGui.SetClipboardText(item.Name.ToString()); + } + + private void DrawStatusPopup(StatusPayload status) + { + if ( + Plugin + .TextureProvider.GetFromGameIcon(new GameIconLookup(status.Status.Value.Icon)) + .GetWrapOrDefault() is + { } icon + ) + InlineIcon(icon); + + var builder = new SeStringBuilder(); + var nameValue = status.Status.Value.Name.ToString(); + switch (status.Status.Value.StatusCategory) + { + case 1: + builder.AddUiForeground($"{SeIconChar.Buff.ToIconString()}{nameValue}", 517); + break; + case 2: + builder.AddUiForeground($"{SeIconChar.Debuff.ToIconString()}{nameValue}", 518); + break; + default: + builder.AddUiForeground(nameValue, 1); + break; + } + + _chunkRenderer.DrawChunks( + ChunkUtil.ToChunks(builder.BuiltString, ChunkSource.None, null).ToList(), + false + ); + ImGui.Separator(); + + if (ImGui.Selectable(Language.Context_Link)) + { + GameFunctions.Context.LinkStatus(status.Status.RowId); + _inputBar.AppendPending(" "); + } + } + + private void DrawUriPopup(UriPayload uri) + { + ImGui.TextUnformatted(string.Format(Language.Context_URLDomain, uri.Uri.Authority)); + ImGuiUtil.WarningText(Language.Context_URLWarning, false); + ImGui.Separator(); + + if (ImGui.Selectable(Language.Context_OpenInBrowser)) + WrapperUtil.TryOpenUri(uri.Uri); + + if (ImGui.Selectable(Language.Context_CopyLink)) + { + ImGui.SetClipboardText(uri.Uri.ToString()); + WrapperUtil.AddNotification( + Language.Context_CopyLinkNotification, + NotificationType.Info + ); + } + } + + private const float MaxInlineIconSize = 32f; + + private static void InlineIcon(IDalamudTextureWrap icon) + { + if (icon.Size.X <= 0 || icon.Size.Y <= 0) + return; + + var width = (float)icon.Size.X; + var height = (float)icon.Size.Y; + var scale = Math.Min(1f, Math.Min(MaxInlineIconSize / width, MaxInlineIconSize / height)); + var size = ImGuiHelpers.ScaledVector2(width * scale, height * scale); + + var cursor = ImGui.GetCursorPos(); + ImGui.Image(icon.Handle, size); + ImGui.SameLine(); + ImGui.SetCursorPos( + cursor + new Vector2(size.X + 4, size.Y - ImGui.GetTextLineHeightWithSpacing()) + ); + } + internal void Hover(Payload payload) { } internal unsafe void Click(Chunk chunk, Payload? payload, ImGuiMouseButton button) { }