feat: partially handle some payloads
This commit is contained in:
+2
-2
@@ -4,7 +4,7 @@ using Dalamud.Game.Text.SeStringHandling;
|
|||||||
namespace ChatTwo;
|
namespace ChatTwo;
|
||||||
|
|
||||||
internal abstract class Chunk {
|
internal abstract class Chunk {
|
||||||
internal Payload? Link;
|
internal Payload? Link { get; set; }
|
||||||
|
|
||||||
protected Chunk(Payload? link) {
|
protected Chunk(Payload? link) {
|
||||||
this.Link = link;
|
this.Link = link;
|
||||||
@@ -32,7 +32,7 @@ internal class TextChunk : Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class IconChunk : Chunk {
|
internal class IconChunk : Chunk {
|
||||||
internal BitmapFontIcon Icon;
|
internal BitmapFontIcon Icon { get; set; }
|
||||||
|
|
||||||
public IconChunk(Payload? link, BitmapFontIcon icon) : base(link) {
|
public IconChunk(Payload? link, BitmapFontIcon icon) : base(link) {
|
||||||
this.Icon = icon;
|
this.Icon = icon;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ internal class Configuration : IPluginConfiguration {
|
|||||||
public int Version { get; set; } = 1;
|
public int Version { get; set; } = 1;
|
||||||
|
|
||||||
public bool HideChat = true;
|
public bool HideChat = true;
|
||||||
|
public bool NativeItemTooltips = true;
|
||||||
public float FontSize = 17f;
|
public float FontSize = 17f;
|
||||||
public Dictionary<ChatType, uint> ChatColours = new();
|
public Dictionary<ChatType, uint> ChatColours = new();
|
||||||
public List<Tab> Tabs = new();
|
public List<Tab> Tabs = new();
|
||||||
@@ -43,6 +44,7 @@ internal class Tab {
|
|||||||
if (this.Messages.Count > 1000) {
|
if (this.Messages.Count > 1000) {
|
||||||
this.Messages.RemoveAt(0);
|
this.Messages.RemoveAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.MessagesMutex.ReleaseMutex();
|
this.MessagesMutex.ReleaseMutex();
|
||||||
|
|
||||||
this.Unread += 1;
|
this.Unread += 1;
|
||||||
|
|||||||
@@ -102,6 +102,59 @@ internal unsafe class GameFunctions : IDisposable {
|
|||||||
return (*flags & (1 << 22)) == 0;
|
return (*flags & (1 << 22)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void OpenItemTooltip(uint id) {
|
||||||
|
var atkStage = AtkStage.GetSingleton();
|
||||||
|
var agent = Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.ItemDetail);
|
||||||
|
var addon = atkStage->RaptureAtkUnitManager->GetAddonByName("ItemDetail");
|
||||||
|
if (agent == null || addon == null) {
|
||||||
|
// atkStage ain't gonna be null or we have bigger problems
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var agentPtr = (IntPtr) agent;
|
||||||
|
|
||||||
|
// addresses mentioned here are 6.01
|
||||||
|
// see the call near the end of AgentItemDetail.Update
|
||||||
|
// offsets valid as of 6.01
|
||||||
|
|
||||||
|
// 8BFC49: sets some shit
|
||||||
|
*(uint*) (agentPtr + 0x20) = 22;
|
||||||
|
// 8C04C8: switch goes down to default, which is what we want
|
||||||
|
*(byte*) (agentPtr + 0x118) = 1;
|
||||||
|
// 8BFCF6: item id when hovering over item in chat
|
||||||
|
*(uint*) (agentPtr + 0x11C) = id;
|
||||||
|
// 8BFCE4: always 0 when hovering over item in chat
|
||||||
|
*(uint*) (agentPtr + 0x120) = 0;
|
||||||
|
// 8C0B55: skips a check to do with inventory
|
||||||
|
*(byte*) (agentPtr + 0x128) &= 0xEF;
|
||||||
|
// 8BFC7C: when set to 1, lets everything continue (one frame)
|
||||||
|
*(byte*) (agentPtr + 0x146) = 1;
|
||||||
|
// 8BFC89: skips early return
|
||||||
|
*(byte*) (agentPtr + 0x14A) = 0;
|
||||||
|
|
||||||
|
// this just probably needs to be set
|
||||||
|
agent->AddonId = (uint) addon->ID;
|
||||||
|
|
||||||
|
// vcall from E8 ?? ?? ?? ?? 0F B7 C0 48 83 C4 60
|
||||||
|
var vf5 = (delegate*<AtkUnitBase*, byte, uint, void>*) ((IntPtr) addon->VTable + 40);
|
||||||
|
// E8872D: lets vf5 actually run
|
||||||
|
*(byte*) ((IntPtr) atkStage + 0x2B4) |= 2;
|
||||||
|
(*vf5)(addon, 0, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void CloseItemTooltip() {
|
||||||
|
// hide addon first to prevent the "addon close" sound
|
||||||
|
var addon = AtkStage.GetSingleton()->RaptureAtkUnitManager->GetAddonByName("ItemDetail");
|
||||||
|
if (addon != null) {
|
||||||
|
addon->Hide(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var agent = Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.ItemDetail);
|
||||||
|
if (agent != null) {
|
||||||
|
agent->Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private byte ChatLogRefreshDetour(IntPtr log, ushort eventId, AtkValue* value) {
|
private byte ChatLogRefreshDetour(IntPtr log, ushort eventId, AtkValue* value) {
|
||||||
if (eventId == 0x31 && value != null && value->UInt is 0x05 or 0x0C) {
|
if (eventId == 0x31 && value != null && value->UInt is 0x05 or 0x0C) {
|
||||||
string? eventInput = null;
|
string? eventInput = null;
|
||||||
|
|||||||
Executable
+190
@@ -0,0 +1,190 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using ChatTwo.Ui;
|
||||||
|
using ChatTwo.Util;
|
||||||
|
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
|
using Dalamud.Logging;
|
||||||
|
using Dalamud.Utility;
|
||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
namespace ChatTwo;
|
||||||
|
|
||||||
|
internal sealed class PayloadHandler {
|
||||||
|
private PluginUi Ui { get; }
|
||||||
|
private ChatLog Log { get; }
|
||||||
|
|
||||||
|
private HashSet<PlayerPayload> Popups { get; set; } = new();
|
||||||
|
|
||||||
|
private uint _hoveredItem;
|
||||||
|
private uint _hoverCounter;
|
||||||
|
private uint _lastHoverCounter;
|
||||||
|
|
||||||
|
internal PayloadHandler(PluginUi ui, ChatLog log) {
|
||||||
|
this.Ui = ui;
|
||||||
|
this.Log = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Draw() {
|
||||||
|
var newPopups = new HashSet<PlayerPayload>();
|
||||||
|
foreach (var player in this.Popups) {
|
||||||
|
var id = PopupId(player);
|
||||||
|
if (!ImGui.BeginPopup(id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newPopups.Add(player);
|
||||||
|
ImGui.PushID(id);
|
||||||
|
|
||||||
|
this.DrawPlayerPopup(player);
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Popups = newPopups;
|
||||||
|
|
||||||
|
if (++this._hoverCounter - this._lastHoverCounter > 1) {
|
||||||
|
this.Ui.Plugin.Functions.CloseItemTooltip();
|
||||||
|
this._hoveredItem = 0;
|
||||||
|
this._hoverCounter = this._lastHoverCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Click(Payload payload, ImGuiMouseButton button) {
|
||||||
|
PluginLog.Log($"clicked {payload} with {button}");
|
||||||
|
|
||||||
|
switch (button) {
|
||||||
|
case ImGuiMouseButton.Left:
|
||||||
|
this.LeftClickPayload(payload);
|
||||||
|
break;
|
||||||
|
case ImGuiMouseButton.Right:
|
||||||
|
this.RightClickPayload(payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Hover(Payload payload) {
|
||||||
|
switch (payload) {
|
||||||
|
case StatusPayload status: {
|
||||||
|
this.DoHover(() => this.HoverStatus(status), 250f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ItemPayload item: {
|
||||||
|
if (this.Ui.Plugin.Config.NativeItemTooltips) {
|
||||||
|
this.Ui.Plugin.Functions.OpenItemTooltip(item.ItemId);
|
||||||
|
|
||||||
|
if (this._hoveredItem != item.ItemId) {
|
||||||
|
this._hoveredItem = item.ItemId;
|
||||||
|
this._hoverCounter = this._lastHoverCounter = 0;
|
||||||
|
} else {
|
||||||
|
this._lastHoverCounter = this._hoverCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.DoHover(() => this.HoverItem(item), 250f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoHover(Action inside, float width) {
|
||||||
|
ImGui.SetNextWindowSize(new Vector2(width, -1f));
|
||||||
|
|
||||||
|
ImGui.BeginTooltip();
|
||||||
|
ImGui.PushTextWrapPos();
|
||||||
|
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Text, this.Ui.DefaultText);
|
||||||
|
try {
|
||||||
|
inside();
|
||||||
|
} finally {
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
ImGui.PopTextWrapPos();
|
||||||
|
ImGui.EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HoverStatus(StatusPayload status) {
|
||||||
|
var name = ChunkUtil.ToChunks(status.Status.Name.ToDalamudString(), null);
|
||||||
|
this.Log.DrawChunks(name.ToList());
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
var desc = ChunkUtil.ToChunks(status.Status.Description.ToDalamudString(), null);
|
||||||
|
this.Log.DrawChunks(desc.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HoverItem(ItemPayload item) {
|
||||||
|
var name = ChunkUtil.ToChunks(item.Item.Name.ToDalamudString(), null);
|
||||||
|
this.Log.DrawChunks(name.ToList());
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
var desc = ChunkUtil.ToChunks(item.Item.Description.ToDalamudString(), null);
|
||||||
|
this.Log.DrawChunks(desc.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LeftClickPayload(Payload payload) {
|
||||||
|
switch (payload) {
|
||||||
|
case MapLinkPayload map: {
|
||||||
|
this.Ui.Plugin.GameGui.OpenMapWithMapLink(map);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QuestPayload quest: {
|
||||||
|
this.Ui.Plugin.Common.Functions.Journal.OpenQuest(quest.Quest);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DalamudLinkPayload link: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RightClickPayload(Payload payload) {
|
||||||
|
switch (payload) {
|
||||||
|
case PlayerPayload player: {
|
||||||
|
this.Popups.Add(player);
|
||||||
|
ImGui.OpenPopup(PopupId(player));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawPlayerPopup(PlayerPayload player) {
|
||||||
|
var name = player.PlayerName;
|
||||||
|
if (player.World.IsPublic) {
|
||||||
|
name += $"{player.World.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.TextUnformatted(name);
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
if (player.World.IsPublic && ImGui.Selectable("Send Tell")) {
|
||||||
|
this.Log.Chat = $"/tell {player.PlayerName}@{player.World.Name} ";
|
||||||
|
this.Log.Activate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Selectable("Target")) {
|
||||||
|
foreach (var obj in this.Ui.Plugin.ObjectTable) {
|
||||||
|
if (obj is not PlayerCharacter character) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (character.Name.TextValue != player.PlayerName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.World.IsPublic && character.HomeWorld.Id != player.World.RowId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Ui.Plugin.TargetManager.SetTarget(obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string PopupId(PlayerPayload player) {
|
||||||
|
return $"###player-{player.PlayerName}@{player.World}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Dalamud.Data;
|
using Dalamud.Data;
|
||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
using Dalamud.Game.ClientState;
|
using Dalamud.Game.ClientState;
|
||||||
|
using Dalamud.Game.ClientState.Objects;
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
using Dalamud.Game.Gui;
|
using Dalamud.Game.Gui;
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
@@ -31,9 +32,18 @@ public sealed class Plugin : IDalamudPlugin {
|
|||||||
[PluginService]
|
[PluginService]
|
||||||
internal Framework Framework { get; init; }
|
internal Framework Framework { get; init; }
|
||||||
|
|
||||||
|
[PluginService]
|
||||||
|
internal GameGui GameGui { get; init; }
|
||||||
|
|
||||||
|
[PluginService]
|
||||||
|
internal ObjectTable ObjectTable { get; init; }
|
||||||
|
|
||||||
[PluginService]
|
[PluginService]
|
||||||
internal SigScanner SigScanner { get; init; }
|
internal SigScanner SigScanner { get; init; }
|
||||||
|
|
||||||
|
[PluginService]
|
||||||
|
internal TargetManager TargetManager { get; init; }
|
||||||
|
|
||||||
internal Configuration Config { get; }
|
internal Configuration Config { get; }
|
||||||
internal XivCommonBase Common { get; }
|
internal XivCommonBase Common { get; }
|
||||||
internal GameFunctions Functions { get; }
|
internal GameFunctions Functions { get; }
|
||||||
|
|||||||
+5
-1
@@ -1,4 +1,5 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Numerics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using ChatTwo.Ui;
|
using ChatTwo.Ui;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
@@ -10,6 +11,7 @@ internal sealed class PluginUi : IDisposable {
|
|||||||
internal Plugin Plugin { get; }
|
internal Plugin Plugin { get; }
|
||||||
internal ImFontPtr? RegularFont { get; private set; }
|
internal ImFontPtr? RegularFont { get; private set; }
|
||||||
internal ImFontPtr? ItalicFont { get; private set; }
|
internal ImFontPtr? ItalicFont { get; private set; }
|
||||||
|
internal Vector4 DefaultText { get; private set; }
|
||||||
|
|
||||||
private List<IUiComponent> Components { get; }
|
private List<IUiComponent> Components { get; }
|
||||||
private ImFontConfigPtr _fontCfg;
|
private ImFontConfigPtr _fontCfg;
|
||||||
@@ -104,6 +106,8 @@ internal sealed class PluginUi : IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void Draw() {
|
private void Draw() {
|
||||||
|
this.DefaultText = ImGui.GetStyle().Colors[(int) ImGuiCol.Text];
|
||||||
|
|
||||||
var font = this.RegularFont.HasValue;
|
var font = this.RegularFont.HasValue;
|
||||||
|
|
||||||
if (font) {
|
if (font) {
|
||||||
|
|||||||
+27
-21
@@ -9,15 +9,18 @@ namespace ChatTwo.Ui;
|
|||||||
internal sealed class ChatLog : IUiComponent {
|
internal sealed class ChatLog : IUiComponent {
|
||||||
private PluginUi Ui { get; }
|
private PluginUi Ui { get; }
|
||||||
|
|
||||||
private bool _activate;
|
internal bool Activate;
|
||||||
private string _chat = string.Empty;
|
internal string Chat = string.Empty;
|
||||||
private readonly TextureWrap? _fontIcon;
|
private readonly TextureWrap? _fontIcon;
|
||||||
private readonly List<string> _inputBacklog = new();
|
private readonly List<string> _inputBacklog = new();
|
||||||
private int _inputBacklogIdx = -1;
|
private int _inputBacklogIdx = -1;
|
||||||
private int _lastTab;
|
private int _lastTab;
|
||||||
|
|
||||||
|
private PayloadHandler PayloadHandler { get; }
|
||||||
|
|
||||||
internal ChatLog(PluginUi ui) {
|
internal ChatLog(PluginUi ui) {
|
||||||
this.Ui = ui;
|
this.Ui = ui;
|
||||||
|
this.PayloadHandler = new PayloadHandler(this.Ui, this);
|
||||||
|
|
||||||
this._fontIcon = this.Ui.Plugin.DataManager.GetImGuiTexture("common/font/fonticon_ps5.tex");
|
this._fontIcon = this.Ui.Plugin.DataManager.GetImGuiTexture("common/font/fonticon_ps5.tex");
|
||||||
|
|
||||||
@@ -30,9 +33,9 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void ChatActivated(string? input) {
|
private void ChatActivated(string? input) {
|
||||||
this._activate = true;
|
this.Activate = true;
|
||||||
if (input != null && !this._chat.Contains(input)) {
|
if (input != null && !this.Chat.Contains(input)) {
|
||||||
this._chat += input;
|
this.Chat += input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,11 +97,11 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (message.Sender.Count > 0) {
|
if (message.Sender.Count > 0) {
|
||||||
this.DrawChunks(message.Sender);
|
this.DrawChunks(message.Sender, this.PayloadHandler);
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.DrawChunks(message.Content);
|
this.DrawChunks(message.Content, this.PayloadHandler);
|
||||||
|
|
||||||
// drawnHeight += ImGui.GetCursorPosY() - lastPos;
|
// drawnHeight += ImGui.GetCursorPosY() - lastPos;
|
||||||
// lastPos = ImGui.GetCursorPosY();
|
// lastPos = ImGui.GetCursorPosY();
|
||||||
@@ -125,6 +128,8 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.PayloadHandler.Draw();
|
||||||
|
|
||||||
ImGui.EndChild();
|
ImGui.EndChild();
|
||||||
|
|
||||||
ImGui.EndTabItem();
|
ImGui.EndTabItem();
|
||||||
@@ -134,7 +139,7 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
ImGui.EndTabBar();
|
ImGui.EndTabBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._activate) {
|
if (this.Activate) {
|
||||||
ImGui.SetKeyboardFocusHere();
|
ImGui.SetKeyboardFocusHere();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,16 +158,16 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
const ImGuiInputTextFlags inputFlags = ImGuiInputTextFlags.EnterReturnsTrue
|
const ImGuiInputTextFlags inputFlags = ImGuiInputTextFlags.EnterReturnsTrue
|
||||||
| ImGuiInputTextFlags.CallbackAlways
|
| ImGuiInputTextFlags.CallbackAlways
|
||||||
| ImGuiInputTextFlags.CallbackHistory;
|
| ImGuiInputTextFlags.CallbackHistory;
|
||||||
if (ImGui.InputText("##chat2-input", ref this._chat, 500, inputFlags, this.Callback)) {
|
if (ImGui.InputText("##chat2-input", ref this.Chat, 500, inputFlags, this.Callback)) {
|
||||||
if (!string.IsNullOrWhiteSpace(this._chat)) {
|
if (!string.IsNullOrWhiteSpace(this.Chat)) {
|
||||||
var trimmed = this._chat.Trim();
|
var trimmed = this.Chat.Trim();
|
||||||
this.AddBacklog(trimmed);
|
this.AddBacklog(trimmed);
|
||||||
this._inputBacklogIdx = -1;
|
this._inputBacklogIdx = -1;
|
||||||
|
|
||||||
this.Ui.Plugin.Common.Functions.Chat.SendMessage(trimmed);
|
this.Ui.Plugin.Common.Functions.Chat.SendMessage(trimmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._chat = string.Empty;
|
this.Chat = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputColour != null) {
|
if (inputColour != null) {
|
||||||
@@ -175,9 +180,9 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
private unsafe int Callback(ImGuiInputTextCallbackData* data) {
|
private unsafe int Callback(ImGuiInputTextCallbackData* data) {
|
||||||
var ptr = new ImGuiInputTextCallbackDataPtr(data);
|
var ptr = new ImGuiInputTextCallbackDataPtr(data);
|
||||||
|
|
||||||
if (this._activate) {
|
if (this.Activate) {
|
||||||
this._activate = false;
|
this.Activate = false;
|
||||||
data->CursorPos = this._chat.Length;
|
data->CursorPos = this.Chat.Length;
|
||||||
data->SelectionStart = data->SelectionEnd = data->CursorPos;
|
data->SelectionStart = data->SelectionEnd = data->CursorPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,8 +198,8 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
case -1:
|
case -1:
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(this._chat)) {
|
if (!string.IsNullOrWhiteSpace(this.Chat)) {
|
||||||
this.AddBacklog(this._chat);
|
this.AddBacklog(this.Chat);
|
||||||
offset = 1;
|
offset = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,9 +234,9 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawChunks(IReadOnlyList<Chunk> chunks) {
|
internal void DrawChunks(IReadOnlyList<Chunk> chunks, PayloadHandler? handler = null) {
|
||||||
for (var i = 0; i < chunks.Count; i++) {
|
for (var i = 0; i < chunks.Count; i++) {
|
||||||
this.DrawChunk(chunks[i]);
|
this.DrawChunk(chunks[i], handler);
|
||||||
|
|
||||||
if (i < chunks.Count - 1) {
|
if (i < chunks.Count - 1) {
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
@@ -239,7 +244,7 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawChunk(Chunk chunk) {
|
private void DrawChunk(Chunk chunk, PayloadHandler? handler = null) {
|
||||||
if (chunk is IconChunk icon && this._fontIcon != null) {
|
if (chunk is IconChunk icon && this._fontIcon != null) {
|
||||||
var bounds = IconUtil.GetBounds((byte) icon.Icon);
|
var bounds = IconUtil.GetBounds((byte) icon.Icon);
|
||||||
if (bounds != null) {
|
if (bounds != null) {
|
||||||
@@ -251,6 +256,7 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
var uv0 = new Vector2(bounds.Value.X, bounds.Value.Y - 2) / texSize;
|
var uv0 = new Vector2(bounds.Value.X, bounds.Value.Y - 2) / texSize;
|
||||||
var uv1 = new Vector2(bounds.Value.X + bounds.Value.Z, bounds.Value.Y - 2 + bounds.Value.W) / texSize;
|
var uv1 = new Vector2(bounds.Value.X + bounds.Value.Z, bounds.Value.Y - 2 + bounds.Value.W) / texSize;
|
||||||
ImGui.Image(this._fontIcon.ImGuiHandle, size, uv0, uv1);
|
ImGui.Image(this._fontIcon.ImGuiHandle, size, uv0, uv1);
|
||||||
|
ImGuiUtil.PostPayload(chunk.Link, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -277,7 +283,7 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
ImGui.PushFont(this.Ui.ItalicFont.Value);
|
ImGui.PushFont(this.Ui.ItalicFont.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiUtil.WrapText(text.Content);
|
ImGuiUtil.WrapText(text.Content, chunk.Link, handler);
|
||||||
|
|
||||||
if (text.Italic && this.Ui.ItalicFont.HasValue) {
|
if (text.Italic && this.Ui.ItalicFont.HasValue) {
|
||||||
ImGui.PopFont();
|
ImGui.PopFont();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ internal sealed class Settings : IUiComponent {
|
|||||||
private bool _visible;
|
private bool _visible;
|
||||||
|
|
||||||
private bool _hideChat;
|
private bool _hideChat;
|
||||||
|
private bool _nativeItemTooltips;
|
||||||
private float _fontSize;
|
private float _fontSize;
|
||||||
private Dictionary<ChatType, uint> _chatColours = new();
|
private Dictionary<ChatType, uint> _chatColours = new();
|
||||||
private List<Tab> _tabs = new();
|
private List<Tab> _tabs = new();
|
||||||
@@ -34,6 +35,7 @@ internal sealed class Settings : IUiComponent {
|
|||||||
private void Initialise() {
|
private void Initialise() {
|
||||||
var config = this.Ui.Plugin.Config;
|
var config = this.Ui.Plugin.Config;
|
||||||
this._hideChat = config.HideChat;
|
this._hideChat = config.HideChat;
|
||||||
|
this._nativeItemTooltips = config.NativeItemTooltips;
|
||||||
this._fontSize = config.FontSize;
|
this._fontSize = config.FontSize;
|
||||||
this._chatColours = config.ChatColours.ToDictionary(entry => entry.Key, entry => entry.Value);
|
this._chatColours = config.ChatColours.ToDictionary(entry => entry.Key, entry => entry.Value);
|
||||||
this._tabs = config.Tabs.Select(tab => tab.Clone()).ToList();
|
this._tabs = config.Tabs.Select(tab => tab.Clone()).ToList();
|
||||||
@@ -60,6 +62,7 @@ internal sealed class Settings : IUiComponent {
|
|||||||
- ImGui.CalcTextSize("A").Y;
|
- ImGui.CalcTextSize("A").Y;
|
||||||
if (ImGui.BeginChild("##chat2-settings", new Vector2(-1, height))) {
|
if (ImGui.BeginChild("##chat2-settings", new Vector2(-1, height))) {
|
||||||
ImGui.Checkbox("Hide chat", ref this._hideChat);
|
ImGui.Checkbox("Hide chat", ref this._hideChat);
|
||||||
|
ImGui.Checkbox("Show native item tooltips", ref this._nativeItemTooltips);
|
||||||
ImGui.DragFloat("Font size", ref this._fontSize, .5f, 12f, 36f);
|
ImGui.DragFloat("Font size", ref this._fontSize, .5f, 12f, 36f);
|
||||||
|
|
||||||
if (ImGui.TreeNodeEx("Chat colours")) {
|
if (ImGui.TreeNodeEx("Chat colours")) {
|
||||||
@@ -163,6 +166,7 @@ internal sealed class Settings : IUiComponent {
|
|||||||
var fontSizeChanged = Math.Abs(this._fontSize - this.Ui.Plugin.Config.FontSize) > float.Epsilon;
|
var fontSizeChanged = Math.Abs(this._fontSize - this.Ui.Plugin.Config.FontSize) > float.Epsilon;
|
||||||
|
|
||||||
config.HideChat = this._hideChat;
|
config.HideChat = this._hideChat;
|
||||||
|
config.NativeItemTooltips = this._nativeItemTooltips;
|
||||||
config.FontSize = this._fontSize;
|
config.FontSize = this._fontSize;
|
||||||
config.ChatColours = this._chatColours;
|
config.ChatColours = this._chatColours;
|
||||||
config.Tabs = this._tabs;
|
config.Tabs = this._tabs;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using ChatTwo.Code;
|
using ChatTwo.Code;
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
using Dalamud.Logging;
|
|
||||||
|
|
||||||
namespace ChatTwo.Util;
|
namespace ChatTwo.Util;
|
||||||
|
|
||||||
@@ -23,13 +22,7 @@ internal static class ChunkUtil {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginLog.Log("");
|
|
||||||
foreach (var payload in msg.Payloads) {
|
foreach (var payload in msg.Payloads) {
|
||||||
PluginLog.Log(payload.Type.ToString());
|
|
||||||
if (payload.Type == PayloadType.Unknown) {
|
|
||||||
PluginLog.Log(payload.Encode().Select(b => b.ToString("x2")).Aggregate(string.Concat));
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (payload.Type) {
|
switch (payload.Type) {
|
||||||
case PayloadType.EmphasisItalic:
|
case PayloadType.EmphasisItalic:
|
||||||
var newStatus = ((EmphasisItalicPayload) payload).IsEnabled;
|
var newStatus = ((EmphasisItalicPayload) payload).IsEnabled;
|
||||||
@@ -75,7 +68,7 @@ internal static class ChunkUtil {
|
|||||||
if (rawPayload.Data[1] == 0x13) {
|
if (rawPayload.Data[1] == 0x13) {
|
||||||
foreground.Pop();
|
foreground.Pop();
|
||||||
glow.Pop();
|
glow.Pop();
|
||||||
} else if (rawPayload == RawPayload.LinkTerminator) {
|
} else if (Equals(rawPayload, RawPayload.LinkTerminator)) {
|
||||||
link = null;
|
link = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,39 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
namespace ChatTwo.Util;
|
namespace ChatTwo.Util;
|
||||||
|
|
||||||
internal static class ImGuiUtil {
|
internal static class ImGuiUtil {
|
||||||
internal static unsafe void WrapText(string csText) {
|
private static readonly ImGuiMouseButton[] Buttons = {
|
||||||
|
ImGuiMouseButton.Left,
|
||||||
|
ImGuiMouseButton.Middle,
|
||||||
|
ImGuiMouseButton.Right,
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static void PostPayload(Payload? payload, PayloadHandler? handler) {
|
||||||
|
if (payload != null && ImGui.IsItemHovered()) {
|
||||||
|
ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
|
||||||
|
handler?.Hover(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload == null || handler == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var button in Buttons) {
|
||||||
|
if (ImGui.IsItemClicked(button)) {
|
||||||
|
handler.Click(payload, button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static unsafe void WrapText(string csText, Payload? payload, PayloadHandler? handler) {
|
||||||
|
void Text(byte* text, byte* textEnd) {
|
||||||
|
ImGuiNative.igTextUnformatted(text, textEnd);
|
||||||
|
PostPayload(payload, handler);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var part in csText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)) {
|
foreach (var part in csText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)) {
|
||||||
var bytes = Encoding.UTF8.GetBytes(part);
|
var bytes = Encoding.UTF8.GetBytes(part);
|
||||||
fixed (byte* rawText = bytes) {
|
fixed (byte* rawText = bytes) {
|
||||||
@@ -23,7 +52,7 @@ internal static class ImGuiUtil {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiNative.igTextUnformatted(text, endPrevLine);
|
Text(text, endPrevLine);
|
||||||
|
|
||||||
widthLeft = ImGui.GetContentRegionAvail().X;
|
widthLeft = ImGui.GetContentRegionAvail().X;
|
||||||
while (endPrevLine < textEnd) {
|
while (endPrevLine < textEnd) {
|
||||||
@@ -37,7 +66,7 @@ internal static class ImGuiUtil {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiNative.igTextUnformatted(text, endPrevLine);
|
Text(text, endPrevLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user