- Check auto translation for commands and execute them instead of sending
- Plugin commands trigger the command helper window now - Fix auto translation with empty text appearing - Switch up all dalamud payload usage to ROSS if possible - Prepare 7.5 changes - Cleanup
This commit is contained in:
@@ -3,13 +3,12 @@ using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Utility;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Text.Payloads;
|
||||
using Lumina.Text.ReadOnly;
|
||||
using Pidgin;
|
||||
|
||||
using static Pidgin.Parser;
|
||||
using static Pidgin.Parser<char>;
|
||||
|
||||
@@ -157,6 +156,9 @@ internal static class AutoTranslate
|
||||
}
|
||||
else if (lookup is not "@")
|
||||
{
|
||||
if (row.Text.IsEmpty)
|
||||
continue;
|
||||
|
||||
list.Add(new AutoTranslateEntry(row.Group, row.RowId, row.Text.ToString(), row.GroupTitle.ToString()));
|
||||
|
||||
if (shouldAdd)
|
||||
@@ -242,9 +244,7 @@ internal static class AutoTranslate
|
||||
var parts = tag[4..^1].Split(',', 2);
|
||||
if (parts.Length == 2 && uint.TryParse(parts[0], out var group) && uint.TryParse(parts[1], out var key))
|
||||
{
|
||||
var payload = ValidEntries.Contains((group, key))
|
||||
? new AutoTranslatePayload(group, key).Encode()
|
||||
: [];
|
||||
var payload = ValidEntries.Contains((group, key)) ? CreateFixedTranslation(group, key) : [];
|
||||
|
||||
var oldBytes = bytes.ToArray();
|
||||
var lengthDiff = payload.Length - (i - start);
|
||||
@@ -263,56 +263,83 @@ internal static class AutoTranslate
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool StartsWithCommand(ref byte[] bytes)
|
||||
{
|
||||
var search = "<at:"u8;
|
||||
if (bytes.Length <= search.Length)
|
||||
return false;
|
||||
|
||||
// populate the list of valid entries
|
||||
if (ValidEntries.Count == 0)
|
||||
AllEntries();
|
||||
|
||||
for (var i = 0; i < search.Length; i++)
|
||||
{
|
||||
if (bytes[i] != search[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
if (bytes[i] != '>')
|
||||
continue;
|
||||
|
||||
var tag = Encoding.UTF8.GetString(bytes[..(i + 1)]);
|
||||
var parts = tag[4..^1].Split(',', 2);
|
||||
if (parts.Length == 2 && uint.TryParse(parts[0], out var group) && uint.TryParse(parts[1], out var key))
|
||||
{
|
||||
if (!ValidEntries.Contains((group, key)))
|
||||
return false;
|
||||
|
||||
var evaluated = Plugin.Evaluator.Evaluate(new ReadOnlySeString(CreateFixedTranslation(group, key))).ToString();
|
||||
if (!evaluated.StartsWith('/'))
|
||||
return false;
|
||||
|
||||
bytes = Encoding.UTF8.GetBytes(evaluated);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static byte[] CreateFixedTranslation(uint group, uint key)
|
||||
{
|
||||
using var rssb = new RentedSeStringBuilder();
|
||||
return rssb.Builder
|
||||
.BeginMacro(MacroCode.Fixed)
|
||||
.AppendUIntExpression(group - 1)
|
||||
.AppendUIntExpression(key)
|
||||
.EndMacro()
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
internal interface ISelectorPart { }
|
||||
|
||||
internal class SingleRow : ISelectorPart
|
||||
internal class SingleRow(uint row) : ISelectorPart
|
||||
{
|
||||
public uint Row { get; }
|
||||
|
||||
public SingleRow(uint row)
|
||||
{
|
||||
Row = row;
|
||||
}
|
||||
public uint Row { get; } = row;
|
||||
}
|
||||
|
||||
internal class IndexRange : ISelectorPart
|
||||
internal class IndexRange(uint start, uint end) : ISelectorPart
|
||||
{
|
||||
public uint Start { get; }
|
||||
public uint End { get; }
|
||||
|
||||
public IndexRange(uint start, uint end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
}
|
||||
public uint Start { get; } = start;
|
||||
public uint End { get; } = end;
|
||||
}
|
||||
|
||||
internal class NounMarker : ISelectorPart { }
|
||||
|
||||
internal class ColumnSpecifier : ISelectorPart
|
||||
internal class ColumnSpecifier(uint column) : ISelectorPart
|
||||
{
|
||||
public uint Column { get; }
|
||||
|
||||
public ColumnSpecifier(uint column)
|
||||
{
|
||||
Column = column;
|
||||
}
|
||||
public uint Column { get; } = column;
|
||||
}
|
||||
|
||||
internal class AutoTranslateEntry
|
||||
internal class AutoTranslateEntry(uint group, uint row, string str, string title)
|
||||
{
|
||||
internal uint Group { get; }
|
||||
internal uint Row { get; }
|
||||
internal string Text { get; }
|
||||
internal string Title { get; }
|
||||
|
||||
public AutoTranslateEntry(uint group, uint row, string str, string title)
|
||||
{
|
||||
Group = group;
|
||||
Row = row;
|
||||
Text = str;
|
||||
Title = title;
|
||||
}
|
||||
internal uint Group { get; } = group;
|
||||
internal uint Row { get; } = row;
|
||||
internal string Text { get; } = str;
|
||||
internal string Title { get; } = title;
|
||||
}
|
||||
|
||||
+277
-12
@@ -1,8 +1,11 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using ChatTwo.Code;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using System.Text;
|
||||
using Lumina.Text.Expressions;
|
||||
using Lumina.Text.Payloads;
|
||||
using Lumina.Text.ReadOnly;
|
||||
|
||||
using PayloadType = Dalamud.Game.Text.SeStringHandling.PayloadType;
|
||||
|
||||
@@ -10,6 +13,244 @@ namespace ChatTwo.Util;
|
||||
|
||||
internal static class ChunkUtil
|
||||
{
|
||||
// internal static IEnumerable<Chunk> ToChunks(ReadOnlySeString msg, ChunkSource source, ChatType? defaultColour)
|
||||
// {
|
||||
// var chunks = new List<Chunk>();
|
||||
//
|
||||
// var italic = false;
|
||||
// var foreground = new Stack<uint>();
|
||||
// var glow = new Stack<uint>();
|
||||
// Payload? link = null;
|
||||
//
|
||||
// void Append(string text)
|
||||
// {
|
||||
// chunks.Add(new TextChunk(source, link, text)
|
||||
// {
|
||||
// FallbackColour = defaultColour,
|
||||
// Foreground = foreground.Count > 0 ? foreground.Peek() : null,
|
||||
// Glow = glow.Count > 0 ? glow.Peek() : null,
|
||||
// Italic = italic,
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// foreach (var payload in msg)
|
||||
// {
|
||||
// if (payload.Type == ReadOnlySePayloadType.Text)
|
||||
// {
|
||||
// // We don't want to parse any null string
|
||||
// var str = payload.ToString();
|
||||
// var nulIndex = str.IndexOf('\0');
|
||||
// if (nulIndex > 0)
|
||||
// str = str[..nulIndex];
|
||||
// if (string.IsNullOrEmpty(str))
|
||||
// continue;
|
||||
//
|
||||
// Append(str);
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// switch (payload.MacroCode)
|
||||
// {
|
||||
// case MacroCode.Italic:
|
||||
// var newStatus = payload.TryGetExpression(out var expression) && expression.TryGetUInt(out var value) && value == 1;
|
||||
// italic = newStatus;
|
||||
// break;
|
||||
// case MacroCode.Color:
|
||||
// if (payload.TryGetExpression(out var eColor))
|
||||
// {
|
||||
// if (eColor.TryGetPlaceholderExpression(out var ph) && ph == (int)ExpressionType.StackColor)
|
||||
// {
|
||||
// if (foreground.Count > 0)
|
||||
// foreground.Pop();
|
||||
// }
|
||||
// else if (TryResolveUInt(eColor, out var eColorVal))
|
||||
// {
|
||||
// var color = ColourUtil.ArgbToRgba(eColorVal);
|
||||
//
|
||||
// if (color > 0)
|
||||
// foreground.Push(color);
|
||||
// else if (foreground.Count > 0) // Push the previous color as we don't want invisible text
|
||||
// foreground.Push(foreground.Peek());
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
// case MacroCode.EdgeColor:
|
||||
// if (payload.TryGetExpression(out eColor))
|
||||
// {
|
||||
// if (eColor.TryGetPlaceholderExpression(out var ph) && ph == (int)ExpressionType.StackColor)
|
||||
// {
|
||||
// if (glow.Count > 0)
|
||||
// glow.Pop();
|
||||
// }
|
||||
// else if (TryResolveUInt(eColor, out var eColorVal))
|
||||
// {
|
||||
// glow.Push(ColourUtil.ArgbToRgba(eColorVal));
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
// case MacroCode.ColorType:
|
||||
// if (!payload.TryGetExpression(out var eColorType) || !eColorType.TryGetUInt(out var eColorTypeVal))
|
||||
// {
|
||||
// if (foreground.Count > 0)
|
||||
// foreground.Pop();
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// if (eColorTypeVal == 0)
|
||||
// {
|
||||
// if (foreground.Count > 0)
|
||||
// foreground.Pop();
|
||||
// }
|
||||
// else if (Sheets.UIColorSheet.TryGetRow(eColorTypeVal, out var row))
|
||||
// {
|
||||
// foreground.Push(row.Dark);
|
||||
// }
|
||||
// break;
|
||||
// case MacroCode.EdgeColorType:
|
||||
// if (!payload.TryGetExpression(out var eEdgeColor) || !eEdgeColor.TryGetUInt(out var eEdgeColorVal))
|
||||
// {
|
||||
// if (glow.Count > 0)
|
||||
// glow.Pop();
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// if (eEdgeColorVal == 0)
|
||||
// {
|
||||
// if (glow.Count > 0)
|
||||
// glow.Pop();
|
||||
// }
|
||||
// else if (Sheets.UIColorSheet.TryGetRow(eEdgeColorVal, out var row))
|
||||
// {
|
||||
// glow.Push(row.Dark);
|
||||
// }
|
||||
// break;
|
||||
// case MacroCode.Fixed:
|
||||
// if (!payload.TryGetExpression(out var expr1, out var expr2))
|
||||
// break;
|
||||
//
|
||||
// if (expr1.TryGetUInt(out var group) && expr2.TryGetUInt(out var key))
|
||||
// {
|
||||
// chunks.Add(new IconChunk(source, null, BitmapFontIcon.AutoTranslateBegin));
|
||||
// using var rssb = new RentedSeStringBuilder();
|
||||
// var translatePayload = rssb.Builder
|
||||
// .BeginMacro(MacroCode.Fixed)
|
||||
// .AppendUIntExpression(group - 1)
|
||||
// .AppendUIntExpression(key)
|
||||
// .EndMacro()
|
||||
// .ToReadOnlySeString();
|
||||
//
|
||||
// Append(Plugin.Evaluator.Evaluate(translatePayload).ToString());
|
||||
// chunks.Add(new IconChunk(source, null, BitmapFontIcon.AutoTranslateEnd));
|
||||
// }
|
||||
// break;
|
||||
// case MacroCode.Icon:
|
||||
// if (payload.TryGetExpression(out var eIcon) && TryResolveInt(eIcon, out var iconVal))
|
||||
// chunks.Add(new IconChunk(source, link, (BitmapFontIcon)iconVal));
|
||||
// break;
|
||||
// case MacroCode.Link:
|
||||
// if (!payload.TryGetExpression(
|
||||
// out var linkTypeExpr1,
|
||||
// out var uintExpr2,
|
||||
// out var intExpr3,
|
||||
// out var intExpr4,
|
||||
// out var strExpr5))
|
||||
// break;
|
||||
//
|
||||
// if (!linkTypeExpr1.TryGetUInt(out var linkType))
|
||||
// break;
|
||||
//
|
||||
// switch ((LinkMacroPayloadType)linkType)
|
||||
// {
|
||||
// case LinkMacroPayloadType.Terminator:
|
||||
// link = null;
|
||||
// break;
|
||||
// case LinkMacroPayloadType.MapPosition:
|
||||
// if (!uintExpr2.TryGetUInt(out var ids))
|
||||
// break;
|
||||
//
|
||||
// if (!intExpr3.TryGetInt(out var rawX))
|
||||
// break;
|
||||
//
|
||||
// if (!intExpr4.TryGetInt(out var rawY))
|
||||
// break;
|
||||
//
|
||||
// var mapId = ids & 0xFF;
|
||||
// var territoryId = (ids >> 16) & 0xFF;
|
||||
// break;
|
||||
// case (LinkMacroPayloadType)Payload.EmbeddedInfoType.DalamudLink - 1:
|
||||
// if (!uintExpr2.TryGetUInt(out var commandId))
|
||||
// break;
|
||||
//
|
||||
// if (!intExpr3.TryGetInt(out var extra1))
|
||||
// break;
|
||||
//
|
||||
// if (!intExpr4.TryGetInt(out var extra2))
|
||||
// break;
|
||||
//
|
||||
// if (!strExpr5.TryGetString(out var extraStr))
|
||||
// break;
|
||||
// break;
|
||||
// case LinkMacroPayloadType.Quest:
|
||||
// if (!uintExpr2.TryGetUInt(out var questId))
|
||||
// break;
|
||||
// break;
|
||||
// case LinkMacroPayloadType.Status:
|
||||
// if (!uintExpr2.TryGetUInt(out var statusId))
|
||||
// break;
|
||||
// break;
|
||||
// case LinkMacroPayloadType.Item:
|
||||
// if (!uintExpr2.TryGetUInt(out var itemId))
|
||||
// break;
|
||||
// break;
|
||||
// case LinkMacroPayloadType.Character:
|
||||
// if (!uintExpr2.TryGetUInt(out var flags))
|
||||
// break;
|
||||
//
|
||||
// if (!intExpr3.TryGetUInt(out var worldId))
|
||||
// break;
|
||||
// break;
|
||||
// case LinkMacroPayloadType.PartyFinder:
|
||||
// if (!uintExpr2.TryGetUInt(out var listingId))
|
||||
// break;
|
||||
//
|
||||
// // intExpr3 is unused
|
||||
//
|
||||
// if (!intExpr4.TryGetUInt(out worldId))
|
||||
// break;
|
||||
// break;
|
||||
// case LinkMacroPayloadType.PartyFinderNotification:
|
||||
// // no expr used
|
||||
// break;
|
||||
// case LinkMacroPayloadType.Achievement:
|
||||
// if (!uintExpr2.TryGetUInt(out var achievementId))
|
||||
// break;
|
||||
// break;
|
||||
// }
|
||||
// break;
|
||||
// case MacroCode.NonBreakingSpace:
|
||||
// Append(" ");
|
||||
// break;
|
||||
// case PayloadType.Unknown:
|
||||
// var rawPayload = (RawPayload)payload;
|
||||
// else if (rawPayload.Data.Length > 1 && rawPayload.Data[1] == 0x14)
|
||||
// {
|
||||
// if (glow.Count > 0)
|
||||
// {
|
||||
// glow.Pop();
|
||||
// }
|
||||
// else if (rawPayload.Data.Length > 6 && rawPayload.Data[2] == 0x05 && rawPayload.Data[3] == 0xF6)
|
||||
// {
|
||||
// var (r, g, b) = (rawPayload.Data[4], rawPayload.Data[5], rawPayload.Data[6]);
|
||||
// glow.Push(ColourUtil.ComponentsToRgba(r, g, b));
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return chunks;
|
||||
// }
|
||||
|
||||
internal static IEnumerable<Chunk> ToChunks(SeString msg, ChunkSource source, ChatType? defaultColour)
|
||||
{
|
||||
var chunks = new List<Chunk>();
|
||||
@@ -176,22 +417,46 @@ internal static class ChunkUtil
|
||||
return BitConverter.ToUInt32(numArray, 0);
|
||||
}
|
||||
|
||||
public static unsafe void PrintMemoryArea(nint address, int length)
|
||||
private static bool TryResolveUInt(in ReadOnlySeExpressionSpan expression, out uint value)
|
||||
{
|
||||
var ptr = (byte*)address;
|
||||
var str = new StringBuilder("\n");
|
||||
for(var i = 0; i < length; i++)
|
||||
if (expression.TryGetUInt(out value))
|
||||
return true;
|
||||
|
||||
if (expression.TryGetParameterExpression(out var exprType, out var operand1))
|
||||
{
|
||||
str.Append($"{ptr![i]:X02}");
|
||||
if (!TryResolveUInt(operand1, out var paramIndex))
|
||||
return false;
|
||||
|
||||
if (i == 0)
|
||||
continue;
|
||||
if (paramIndex == 0)
|
||||
return false;
|
||||
|
||||
if ((i+1) % 16 == 0)
|
||||
str.Append('\n');
|
||||
else if ((i+1) % 4 == 0)
|
||||
str.Append(' ');
|
||||
paramIndex--;
|
||||
if ((ExpressionType)exprType == ExpressionType.GlobalNumber)
|
||||
{
|
||||
value = (uint) GlobalParametersCache.GetValue((int)paramIndex);
|
||||
return true;
|
||||
}
|
||||
// return (ExpressionType)exprType switch
|
||||
// {
|
||||
// // ExpressionType.LocalNumber => context.TryGetLNum((int)paramIndex, out value), // lnum
|
||||
// ExpressionType.GlobalNumber => (uint) GlobalParametersCache.GetValue((int)paramIndex), // gnum
|
||||
// _ => false, // gstr, lstr
|
||||
// };
|
||||
}
|
||||
Plugin.Log.Information(str.ToString());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool TryResolveInt(in ReadOnlySeExpressionSpan expression, out int value)
|
||||
{
|
||||
if (TryResolveUInt(expression, out var u32))
|
||||
{
|
||||
value = (int)u32;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Numerics;
|
||||
namespace ChatTwo.Util;
|
||||
|
||||
internal static class ColourUtil {
|
||||
internal static (byte r, byte g, byte b, byte a) RgbaToComponents(uint rgba)
|
||||
private static (byte r, byte g, byte b, byte a) RgbaToComponents(uint rgba)
|
||||
{
|
||||
var r = (byte) ((rgba & 0xFF000000) >> 24);
|
||||
var g = (byte) ((rgba & 0xFF0000) >> 16);
|
||||
|
||||
@@ -25,7 +25,7 @@ public static class DateWidget
|
||||
private static float LongestMonthWidth;
|
||||
private static readonly float[] MonthWidths = new float[12];
|
||||
|
||||
private static uint LastOpenComboID;
|
||||
private static uint LastOpenComboId;
|
||||
|
||||
public static bool Validate(DateTime minimal, ref DateTime currentMin, ref DateTime currentMax)
|
||||
{
|
||||
@@ -109,9 +109,9 @@ public static class DateWidget
|
||||
// reset date when user right-clicks the date chooser header when the dialog is open
|
||||
dateOut = DateTime.Now;
|
||||
}
|
||||
else if (LastOpenComboID != id)
|
||||
else if (LastOpenComboId != id)
|
||||
{
|
||||
LastOpenComboID = id;
|
||||
LastOpenComboId = id;
|
||||
if (dateOut.Year == 1)
|
||||
dateOut = DateTime.Now;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
public class ColorPayload
|
||||
{
|
||||
private const byte START_BYTE = 2;
|
||||
private const byte StartByte = 2;
|
||||
|
||||
public bool Enabled;
|
||||
public uint Color;
|
||||
@@ -11,7 +11,7 @@ public class ColorPayload
|
||||
public static ColorPayload? From(byte[] data)
|
||||
{
|
||||
using var stream = new MemoryStream(data);
|
||||
if (stream.ReadByte() != START_BYTE || stream.ReadByte() != 0x13)
|
||||
if (stream.ReadByte() != StartByte || stream.ReadByte() != 0x13)
|
||||
return null;
|
||||
|
||||
stream.ReadByte(); // skip the length byte;
|
||||
|
||||
+28
-120
@@ -183,13 +183,15 @@ internal static class ImGuiUtil
|
||||
if (id != null)
|
||||
label += $"##{id}";
|
||||
|
||||
Plugin.FontManager.FontAwesome.Push();
|
||||
var size = new Vector2(0, 0);
|
||||
if (width > 0)
|
||||
size.X = width - 2 * ImGui.GetStyle().CellPadding.X;
|
||||
bool ret;
|
||||
using (Plugin.FontManager.FontAwesome.Push())
|
||||
{
|
||||
var size = Vector2.Zero;
|
||||
if (width > 0)
|
||||
size.X = width - 2 * ImGui.GetStyle().CellPadding.X;
|
||||
|
||||
var ret = ImGui.Button(label, size);
|
||||
Plugin.FontManager.FontAwesome.Pop();
|
||||
ret = ImGui.Button(label, size);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tooltip) && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||
Tooltip(tooltip);
|
||||
@@ -200,7 +202,7 @@ internal static class ImGuiUtil
|
||||
internal static bool OptionCheckbox(ref bool value, string label, string? description = null)
|
||||
{
|
||||
var ret = ImGui.Checkbox(label, ref value);
|
||||
if (description != null)
|
||||
if (!string.IsNullOrEmpty(description))
|
||||
HelpText(description);
|
||||
|
||||
return ret;
|
||||
@@ -208,13 +210,9 @@ internal static class ImGuiUtil
|
||||
|
||||
internal static void HelpText(string text)
|
||||
{
|
||||
var colour = ImGui.GetStyle().Colors[(int) ImGuiCol.TextDisabled];
|
||||
|
||||
using (TextWrapPos())
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, colour))
|
||||
{
|
||||
using (ImRaii.TextWrapPos(0.0f))
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, ImGui.GetStyle().Colors[(int) ImGuiCol.TextDisabled]))
|
||||
ImGui.TextUnformatted(text);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void WarningText(string text, bool wrap = true)
|
||||
@@ -222,11 +220,9 @@ internal static class ImGuiUtil
|
||||
var style = StyleModel.GetConfiguredStyle() ?? StyleModel.GetFromCurrent();
|
||||
var dalamudOrange = style.BuiltInColors?.DalamudOrange;
|
||||
|
||||
using (TextWrapPos(wrap))
|
||||
using (ImRaii.TextWrapPos(wrap ? 0.0f : ImGui.GetFontSize() * 35.0f))
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, dalamudOrange ?? Vector4.Zero, dalamudOrange != null))
|
||||
{
|
||||
ImGui.TextUnformatted(text);
|
||||
}
|
||||
}
|
||||
|
||||
internal static ImRaii.IEndObject BeginComboVertical(string label, string previewValue, ImGuiComboFlags flags = ImGuiComboFlags.None)
|
||||
@@ -267,9 +263,7 @@ internal static class ImGuiUtil
|
||||
{
|
||||
using (ImRaii.Tooltip())
|
||||
using (ImRaii.TextWrapPos(ImGui.GetFontSize() * 35.0f))
|
||||
{
|
||||
ImGui.TextUnformatted(tooltip);
|
||||
}
|
||||
}
|
||||
|
||||
public static SingleFontChooserDialog? FontChooser(string label, SingleFontSpec font, bool checkbox, ref bool checkboxValue, Predicate<IFontFamilyId>? exclusion = null, string? preview = null)
|
||||
@@ -306,20 +300,18 @@ internal static class ImGuiUtil
|
||||
ImGui.TextUnformatted(label);
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
using var combo = ImRaii.Combo($"##{label}", $"{currentSize:###.##}pt");
|
||||
if (combo)
|
||||
{
|
||||
foreach (var size in FontManager.AxisFontSizeList)
|
||||
if (ImGui.Selectable($"{size:###.##}pt", currentSize.Equals(size)))
|
||||
currentSize = size;
|
||||
}
|
||||
if (!combo.Success)
|
||||
return;
|
||||
|
||||
foreach (var size in FontManager.AxisFontSizeList)
|
||||
if (ImGui.Selectable($"{size:###.##}pt", currentSize.Equals(size)))
|
||||
currentSize = size;
|
||||
}
|
||||
|
||||
public static bool Button(string id, FontAwesomeIcon icon, bool disabled)
|
||||
{
|
||||
using (ImRaii.Disabled(disabled))
|
||||
{
|
||||
return ImGuiComponents.IconButton(id, icon);
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool CtrlShiftButton(string label, string tooltip = "")
|
||||
@@ -330,30 +322,12 @@ internal static class ImGuiUtil
|
||||
using (ImRaii.Disabled(!ctrlShiftHeld))
|
||||
ret = ImGui.Button(label) && ctrlShiftHeld;
|
||||
|
||||
if (!string.IsNullOrEmpty(tooltip) && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||
if (tooltip.Length != 0 && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||
Tooltip(tooltip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal static bool CtrlShiftButtonColored(string label, string tooltip = "")
|
||||
{
|
||||
var ctrlShiftHeld = ImGui.GetIO() is { KeyCtrl: true, KeyShift: true };
|
||||
|
||||
var colorNormal = new Vector4(0.780f, 0.245f, 0.245f, 1.0f);
|
||||
var colorHovered = new Vector4(0.7f, 0.0f, 0.0f, 1.0f);
|
||||
using (ImRaii.PushColor(ImGuiCol.Button, colorNormal))
|
||||
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, colorHovered))
|
||||
{
|
||||
var ret = ImGui.Button(label) && ctrlShiftHeld;
|
||||
|
||||
if (!string.IsNullOrEmpty(tooltip) && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||
Tooltip(tooltip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void KeybindInput(string id, ref ConfigKeyBind? keybind)
|
||||
{
|
||||
var idUint = ImGui.GetID(id);
|
||||
@@ -394,19 +368,15 @@ internal static class ImGuiUtil
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var vk in Enum.GetValues(typeof(VirtualKey)).Cast<VirtualKey>())
|
||||
foreach (var vk in Enum.GetValues<VirtualKey>())
|
||||
{
|
||||
if (vk is VirtualKey.NO_KEY or VirtualKey.CONTROL or VirtualKey.LCONTROL or VirtualKey.RCONTROL or VirtualKey.SHIFT or VirtualKey.LSHIFT or VirtualKey.RSHIFT or VirtualKey.MENU or VirtualKey.LMENU or VirtualKey.RMENU)
|
||||
continue;
|
||||
|
||||
if (!TryToImGui(vk, out var imKey) || !ImGui.IsKeyPressed(imKey))
|
||||
if (!vk.TryToImGui(out var imKey) || !ImGui.IsKeyPressed(imKey))
|
||||
continue;
|
||||
|
||||
keybind = new ConfigKeyBind
|
||||
{
|
||||
Modifier = currentMods,
|
||||
Key = vk
|
||||
};
|
||||
keybind = new ConfigKeyBind { Modifier = currentMods, Key = vk };
|
||||
ImGui.GetStateStorage().SetBool(idUint, false);
|
||||
return;
|
||||
}
|
||||
@@ -442,6 +412,12 @@ internal static class ImGuiUtil
|
||||
}
|
||||
}
|
||||
|
||||
public static void WrappedTextWithColor(Vector4 color, string text)
|
||||
{
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, color))
|
||||
ImGui.TextWrapped(text);
|
||||
}
|
||||
|
||||
public static void CenterText(string text, float indent = 0.0f)
|
||||
{
|
||||
indent *= ImGuiHelpers.GlobalScale;
|
||||
@@ -566,63 +542,6 @@ internal static class ImGuiUtil
|
||||
return result != 0 || key == VirtualKey.NO_KEY;
|
||||
}
|
||||
|
||||
public struct EndUnconditionally(Action endAction, bool success) : ImRaii.IEndObject
|
||||
{
|
||||
public bool Success { get; } = success;
|
||||
|
||||
private bool Disposed { get; set; } = false;
|
||||
private Action EndAction { get; } = endAction;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!Disposed)
|
||||
{
|
||||
EndAction();
|
||||
Disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use end-function only on success.
|
||||
private struct EndConditionally(Action endAction, bool success) : ImRaii.IEndObject
|
||||
{
|
||||
public bool Success { get; } = success;
|
||||
|
||||
private bool Disposed { get; set; } = false;
|
||||
private Action EndAction { get; } = endAction;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Disposed)
|
||||
return;
|
||||
|
||||
if (Success)
|
||||
EndAction();
|
||||
|
||||
Disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static ImRaii.IEndObject TextWrapPos()
|
||||
{
|
||||
ImGui.PushTextWrapPos();
|
||||
return new EndUnconditionally(ImGui.PopTextWrapPos, true);
|
||||
}
|
||||
|
||||
public static ImRaii.IEndObject TextWrapPos(bool condition)
|
||||
{
|
||||
if (!condition)
|
||||
return new EndUnconditionally(Nop, false);
|
||||
|
||||
ImGui.PushTextWrapPos();
|
||||
return new EndUnconditionally(ImGui.PopTextWrapPos, true);
|
||||
}
|
||||
|
||||
public static ImRaii.IEndObject Menu(string label)
|
||||
{
|
||||
return new EndConditionally(ImGui.EndMenu, ImGui.BeginMenu(label));
|
||||
}
|
||||
|
||||
public static void ChannelSelector(string headerText, Dictionary<ChatType, ChatSource> chatCodes)
|
||||
{
|
||||
using var channelNode = ImRaii.TreeNode(headerText);
|
||||
@@ -696,15 +615,4 @@ internal static class ImGuiUtil
|
||||
extraChatChannels.Remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
public static void WrappedTextWithColor(Vector4 color, string text)
|
||||
{
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, color))
|
||||
{
|
||||
ImGui.TextWrapped(text);
|
||||
}
|
||||
}
|
||||
|
||||
// Used to avoid pops if condition is false for Push.
|
||||
private static void Nop() { }
|
||||
}
|
||||
|
||||
@@ -25,13 +25,10 @@ public static class MathUtil
|
||||
SizeY = Y + Height;
|
||||
}
|
||||
|
||||
public Rectangle(Vector2 pos, Vector2 size)
|
||||
: this((int) pos.X, (int) pos.Y, (int) size.X, (int) size.Y) { }
|
||||
public Rectangle(Vector2 pos, Vector2 size) : this((int) pos.X, (int) pos.Y, (int) size.X, (int) size.Y) { }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"X: {X} Y: {Y} Width: {Width} Height: {Height}";
|
||||
}
|
||||
=> $"X: {X} Y: {Y} Width: {Width} Height: {Height}";
|
||||
}
|
||||
|
||||
// From: https://stackoverflow.com/a/306379
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Text;
|
||||
|
||||
namespace ChatTwo.Util;
|
||||
|
||||
public static class MemoryUtil
|
||||
{
|
||||
public static unsafe void PrintMemoryArea(nint address, int length)
|
||||
{
|
||||
var ptr = (byte*)address;
|
||||
var str = new StringBuilder("\n");
|
||||
for(var i = 0; i < length; i++)
|
||||
{
|
||||
str.Append($"{ptr![i]:X02}");
|
||||
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
if ((i+1) % 16 == 0)
|
||||
str.Append('\n');
|
||||
else if ((i+1) % 4 == 0)
|
||||
str.Append(' ');
|
||||
}
|
||||
|
||||
Plugin.Log.Information(str.ToString());
|
||||
}
|
||||
}
|
||||
@@ -63,18 +63,18 @@ internal class UriPayload(Uri uri) : Payload
|
||||
/// <exception cref="UriFormatException">
|
||||
/// If the URI is invalid, or if the scheme is not supported.
|
||||
/// </exception>
|
||||
public static UriPayload ResolveURI(string rawURI)
|
||||
public static UriPayload ResolveUri(string rawUri)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rawURI);
|
||||
ArgumentNullException.ThrowIfNull(rawUri);
|
||||
|
||||
// Check for an expected scheme '://', if not add 'https://'
|
||||
if (ExpectedSchemes.Any(scheme => rawURI.StartsWith($"{scheme}://")))
|
||||
return new UriPayload(new Uri(rawURI));
|
||||
if (ExpectedSchemes.Any(scheme => rawUri.StartsWith($"{scheme}://")))
|
||||
return new UriPayload(new Uri(rawUri));
|
||||
|
||||
if (rawURI.Contains("://"))
|
||||
throw new UriFormatException($"Unsupported scheme in URL: {rawURI}");
|
||||
if (rawUri.Contains("://"))
|
||||
throw new UriFormatException($"Unsupported scheme in URL: {rawUri}");
|
||||
|
||||
return new UriPayload(new Uri($"{DefaultScheme}://{rawURI}"));
|
||||
return new UriPayload(new Uri($"{DefaultScheme}://{rawUri}"));
|
||||
}
|
||||
|
||||
protected override void DecodeImpl(BinaryReader reader, long endOfStream)
|
||||
|
||||
@@ -10,6 +10,7 @@ internal static class TabsUtil
|
||||
var channels = new Dictionary<ChatType, ChatSource>();
|
||||
foreach (var chatType in Enum.GetValues<ChatType>())
|
||||
channels[chatType] = ChatSourceExt.All;
|
||||
|
||||
return channels;
|
||||
}
|
||||
|
||||
@@ -76,7 +77,7 @@ internal static class TabsUtil
|
||||
[ChatType.MessageBook] = ChatSourceExt.All,
|
||||
[ChatType.Alarm] = ChatSourceExt.All,
|
||||
[ChatType.GlamourNotifications] = ChatSourceExt.All,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
internal static Tab VanillaEvent => new()
|
||||
|
||||
@@ -47,7 +47,7 @@ public static class Tokenizer
|
||||
new TokenDefinition(TokenType.Whitespace, "\\s", 1),
|
||||
new TokenDefinition(TokenType.Equals, "=", 1),
|
||||
new TokenDefinition(TokenType.OpenParenthesis, "\\(", 1),
|
||||
new TokenDefinition(TokenType.UrlString, URLRegex, 1),
|
||||
new TokenDefinition(TokenType.UrlString, UrlRegex, 1),
|
||||
new TokenDefinition(TokenType.StringValue, "\\p{IsBasicLatin}", 2),
|
||||
new TokenDefinition(TokenType.Leftover, ".", 3)
|
||||
];
|
||||
@@ -127,7 +127,7 @@ public static class Tokenizer
|
||||
private class TokenMatch
|
||||
{
|
||||
public TokenType TokenType { get; set; }
|
||||
public string Value { get; set; }
|
||||
public required string Value { get; set; }
|
||||
public int StartIndex { get; set; }
|
||||
public int EndIndex { get; set; }
|
||||
public int Precedence { get; set; }
|
||||
@@ -145,7 +145,7 @@ public static class Tokenizer
|
||||
/// It matches URLs with www. or https:// prefix, and also matches URLs
|
||||
/// without a prefix on specific TLDs.
|
||||
/// </summary>
|
||||
private static Regex URLRegex = new(
|
||||
private static readonly Regex UrlRegex = new(
|
||||
@"(?<URL>((https?:\/\/|www\.)[a-z0-9-]+(\.[a-z0-9-]+)*|([a-z0-9-]+(\.[a-z0-9-]+)*\.(com|net|org|co|io|app)))(:[\d]{1,5})?(\/[^\s]*)?)",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture
|
||||
);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using ChatTwo.Resources;
|
||||
using ChatTwo.Resources;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
|
||||
namespace ChatTwo.Util;
|
||||
@@ -11,7 +10,7 @@ public static class WrapperUtil
|
||||
Plugin.Notification.AddNotification(new Notification { Content = content, Type = type, Minimized = minimized });
|
||||
}
|
||||
|
||||
public static void TryOpenURI(Uri uri)
|
||||
public static void TryOpenUri(Uri uri)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -24,21 +23,4 @@ public static class WrapperUtil
|
||||
AddNotification(Language.Context_OpenInBrowserError, NotificationType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<(T Value, int Index)> WithIndex<T>(this IEnumerable<T> list)
|
||||
=> list.Select((x, i) => (x, i));
|
||||
|
||||
/// <summary> Return the first object fulfilling the predicate or null for structs.</summary>
|
||||
/// <param name="values"> The enumerable. </param>
|
||||
/// <param name="predicate"> The predicate. </param>
|
||||
/// <returns> The first object fulfilling the predicate, or a null-optional. </returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static T? FirstOrNull<T>(this IEnumerable<T> values, Func<T, bool> predicate) where T : struct
|
||||
{
|
||||
foreach(var val in values)
|
||||
if (predicate(val))
|
||||
return val;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user