- Prevent null string from being parsed
- cursor pos adjustment through preview
This commit is contained in:
+29
-17
@@ -49,10 +49,11 @@ public sealed class ChatLogWindow : Window
|
||||
}
|
||||
}
|
||||
|
||||
internal bool KeepFocusedThroughPreview;
|
||||
internal bool Activate;
|
||||
private int ActivatePos = -1;
|
||||
internal string Chat = string.Empty;
|
||||
private readonly IDalamudTextureWrap? FontIcon;
|
||||
internal readonly IDalamudTextureWrap? FontIcon;
|
||||
private readonly List<string> InputBacklog = [];
|
||||
private int InputBacklogIdx = -1;
|
||||
private int LastTab { get; set; }
|
||||
@@ -685,8 +686,11 @@ public sealed class ChatLogWindow : Window
|
||||
var push = inputColour != null;
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, push ? ColourUtil.RgbaToAbgr(inputColour!.Value) : 0, push))
|
||||
{
|
||||
if (Activate)
|
||||
if (Activate || KeepFocusedThroughPreview)
|
||||
{
|
||||
KeepFocusedThroughPreview = false;
|
||||
ImGui.SetKeyboardFocusHere();
|
||||
}
|
||||
|
||||
var chatCopy = Chat;
|
||||
|
||||
@@ -1397,6 +1401,11 @@ public sealed class ChatLogWindow : Window
|
||||
|
||||
var ptr = new ImGuiInputTextCallbackDataPtr(data);
|
||||
|
||||
// Set the cursor pos to the user selected
|
||||
if (Plugin.InputPreview.SelectedCursorPos != -1)
|
||||
ptr.CursorPos = Plugin.InputPreview.SelectedCursorPos;
|
||||
Plugin.InputPreview.SelectedCursorPos = -1;
|
||||
|
||||
CursorPos = ptr.CursorPos;
|
||||
if (data->EventFlag == ImGuiInputTextFlags.CallbackCompletion)
|
||||
{
|
||||
@@ -1529,21 +1538,7 @@ public sealed class ChatLogWindow : Window
|
||||
{
|
||||
if (chunk is IconChunk icon && FontIcon != null)
|
||||
{
|
||||
var bounds = IconUtil.GfdFileView.TryGetEntry((uint) icon.Icon, out var entry);
|
||||
if (!bounds)
|
||||
return;
|
||||
|
||||
var texSize = new Vector2(FontIcon.Width, FontIcon.Height);
|
||||
|
||||
var sizeRatio = Plugin.Config.FontSize / entry.Height;
|
||||
var size = new Vector2(entry.Width, entry.Height) * sizeRatio * ImGuiHelpers.GlobalScale;
|
||||
|
||||
var uv0 = new Vector2(entry.Left, entry.Top + 170) * 2 / texSize;
|
||||
var uv1 = new Vector2(entry.Left + entry.Width, entry.Top + entry.Height + 170) * 2 / texSize;
|
||||
|
||||
ImGui.Image(FontIcon.ImGuiHandle, size, uv0, uv1);
|
||||
ImGuiUtil.PostPayload(chunk, handler);
|
||||
|
||||
DrawIcon(chunk, icon, handler);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1621,6 +1616,23 @@ public sealed class ChatLogWindow : Window
|
||||
(useCustomItalicFont ? Plugin.FontManager.ItalicFont! : Plugin.FontManager.AxisItalic).Pop();
|
||||
}
|
||||
|
||||
internal void DrawIcon(Chunk chunk, IconChunk icon, PayloadHandler? handler)
|
||||
{
|
||||
if (!IconUtil.GfdFileView.TryGetEntry((uint) icon.Icon, out var entry))
|
||||
return;
|
||||
|
||||
var texSize = new Vector2(FontIcon!.Width, FontIcon.Height);
|
||||
|
||||
var sizeRatio = Plugin.Config.FontSize / entry.Height;
|
||||
var size = new Vector2(entry.Width, entry.Height) * sizeRatio * ImGuiHelpers.GlobalScale;
|
||||
|
||||
var uv0 = new Vector2(entry.Left, entry.Top + 170) * 2 / texSize;
|
||||
var uv1 = new Vector2(entry.Left + entry.Width, entry.Top + entry.Height + 170) * 2 / texSize;
|
||||
|
||||
ImGui.Image(FontIcon.ImGuiHandle, size, uv0, uv1);
|
||||
ImGuiUtil.PostPayload(chunk, handler);
|
||||
}
|
||||
|
||||
private string HashPlayer(string playerName, uint worldId)
|
||||
{
|
||||
var hashCode = $"{Salt}{playerName}{worldId}".GetHashCode();
|
||||
|
||||
+120
-2
@@ -1,10 +1,12 @@
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using ChatTwo.Code;
|
||||
using ChatTwo.Resources;
|
||||
using ChatTwo.Util;
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using ImGuiNET;
|
||||
@@ -20,6 +22,10 @@ public class InputPreview : Window
|
||||
private int LastLength;
|
||||
private Message? PreviewMessage;
|
||||
|
||||
private bool NextChunkIsAutoTranslate;
|
||||
private int CursorPosition;
|
||||
public int SelectedCursorPos = -1;
|
||||
|
||||
internal InputPreview(ChatLogWindow logWindow) : base("##chat2-inputpreview")
|
||||
{
|
||||
LogWindow = logWindow;
|
||||
@@ -85,7 +91,7 @@ public class InputPreview : Window
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero))
|
||||
{
|
||||
ImGui.TextUnformatted(Language.Options_Preview_Header);
|
||||
LogWindow.DrawChunks(PreviewMessage.Content);
|
||||
DrawChunksPreview(PreviewMessage.Content);
|
||||
}
|
||||
var after = ImGui.GetCursorPosY();
|
||||
ImGui.SetCursorPos(pos);
|
||||
@@ -112,8 +118,120 @@ public class InputPreview : Window
|
||||
ImGui.TextUnformatted(Language.Options_Preview_Header);
|
||||
|
||||
var handler = LogWindow.HandlerLender.Borrow();
|
||||
LogWindow.DrawChunks(PreviewMessage.Content, true, handler);
|
||||
DrawChunksPreview(PreviewMessage.Content, handler, unique: 10000);
|
||||
handler.Draw();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawChunksPreview(IReadOnlyList<Chunk> chunks, PayloadHandler? handler = null, float lineWidth = 0f, int unique = 0)
|
||||
{
|
||||
CursorPosition = 0;
|
||||
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
|
||||
for (var i = 0; i < chunks.Count; i++)
|
||||
{
|
||||
if (chunks[i] is TextChunk text && string.IsNullOrEmpty(text.Content))
|
||||
continue;
|
||||
|
||||
DrawChunkPreview(chunks[i], handler, lineWidth, unique);
|
||||
|
||||
if (i < chunks.Count - 1)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
}
|
||||
else if (chunks[i].Link is EmotePayload && Plugin.Config.ShowEmotes)
|
||||
{
|
||||
// Emote payloads seem to not automatically put newlines, which
|
||||
// is an issue when modern mode is disabled.
|
||||
ImGui.SameLine();
|
||||
// Use default ImGui behavior for newlines.
|
||||
ImGui.TextUnformatted("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawChunkPreview(Chunk chunk, PayloadHandler? handler = null, float lineWidth = 0f, int unique = 0)
|
||||
{
|
||||
if (chunk is IconChunk icon && LogWindow.FontIcon != null)
|
||||
{
|
||||
LogWindow.DrawIcon(chunk, icon, handler);
|
||||
if (icon.Icon != BitmapFontIcon.AutoTranslateBegin)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
NextChunkIsAutoTranslate = true;
|
||||
var key = (uint)typeof(AutoTranslatePayload).GetField("key", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(chunk.Link)!;
|
||||
var group = (uint)typeof(AutoTranslatePayload).GetField("group", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(chunk.Link)!;
|
||||
CursorPosition += $"<at:{key},{group}>".Length;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (chunk is not TextChunk text)
|
||||
return;
|
||||
|
||||
if (chunk.Link is EmotePayload emotePayload && Plugin.Config.ShowEmotes)
|
||||
{
|
||||
var emoteSize = ImGui.CalcTextSize("W");
|
||||
emoteSize = emoteSize with { Y = emoteSize.X } * 1.5f;
|
||||
|
||||
// TextWrap doesn't work for emotes, so we have to wrap them manually
|
||||
if (ImGui.GetContentRegionAvail().X < emoteSize.X)
|
||||
ImGui.NewLine();
|
||||
|
||||
// We only draw a dummy if it is still loading, in the case it failed we draw the actual name
|
||||
var image = EmoteCache.GetEmote(emotePayload.Code);
|
||||
if (image is { Failed: false })
|
||||
{
|
||||
if (image.IsLoaded)
|
||||
image.Draw(emoteSize);
|
||||
else
|
||||
ImGui.Dummy(emoteSize);
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip(emotePayload.Code);
|
||||
|
||||
CursorPosition += emotePayload.Code.Length;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (text.Link != null || NextChunkIsAutoTranslate)
|
||||
{
|
||||
NextChunkIsAutoTranslate = false;
|
||||
|
||||
if (text.Link is ItemPayload)
|
||||
CursorPosition += "<item>".Length;
|
||||
else if (text.Link is MapLinkPayload)
|
||||
CursorPosition += "<flag>".Length;
|
||||
else if (text.Link is EmotePayload emote)
|
||||
CursorPosition += emote.Code.Length;
|
||||
|
||||
ImGuiUtil.WrapText(text.Content, chunk, handler, LogWindow.DefaultText, lineWidth);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var letter in text.Content)
|
||||
{
|
||||
var letterSize = ImGui.CalcTextSize(letter.ToString());
|
||||
if (ImGui.GetContentRegionAvail().X < letterSize.X)
|
||||
ImGui.NewLine();
|
||||
|
||||
CursorPosition++;
|
||||
if (ImGui.Selectable($"{letter}##{CursorPosition + unique}", false, ImGuiSelectableFlags.None, letterSize))
|
||||
{
|
||||
SelectedCursorPos = CursorPosition;
|
||||
LogWindow.KeepFocusedThroughPreview = true;
|
||||
}
|
||||
ImGui.SameLine();
|
||||
}
|
||||
ImGui.NewLine();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ internal static class ChunkUtil
|
||||
glow.Pop();
|
||||
break;
|
||||
case PayloadType.AutoTranslateText:
|
||||
chunks.Add(new IconChunk(source, link, BitmapFontIcon.AutoTranslateBegin));
|
||||
chunks.Add(new IconChunk(source, payload, BitmapFontIcon.AutoTranslateBegin));
|
||||
var autoText = ((AutoTranslatePayload) payload).Text;
|
||||
Append(autoText.Substring(2, autoText.Length - 4));
|
||||
chunks.Add(new IconChunk(source, link, BitmapFontIcon.AutoTranslateEnd));
|
||||
@@ -121,7 +121,17 @@ internal static class ChunkUtil
|
||||
break;
|
||||
default:
|
||||
if (payload is ITextProvider textProvider)
|
||||
Append(textProvider.Text);
|
||||
{
|
||||
// We don't want to parse any null string
|
||||
var str = textProvider.Text;
|
||||
var nulIndex = str.IndexOf('\0');
|
||||
if (nulIndex > 0)
|
||||
str = str[..nulIndex];
|
||||
if (string.IsNullOrEmpty(str))
|
||||
break;
|
||||
|
||||
Append(str);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user