chore: housekeeping — linter & formatter setup
Add .prettierrc.json, .markdownlint.json, .yamllint.yaml, .gitattributes Run CSharpier, Prettier and markdownlint across the entire codebase. No logic changes — formatting, using order and line endings only.
This commit is contained in:
@@ -7,7 +7,6 @@ using Lumina.Excel;
|
||||
using Lumina.Text.Payloads;
|
||||
using Lumina.Text.ReadOnly;
|
||||
using Pidgin;
|
||||
|
||||
using static Pidgin.Parser;
|
||||
using static Pidgin.Parser<char>;
|
||||
|
||||
@@ -26,14 +25,18 @@ internal static class AutoTranslate
|
||||
|
||||
private static Parser<char, (string name, Maybe<IEnumerable<ISelectorPart>> selector)> Parser()
|
||||
{
|
||||
var sheetName = Any
|
||||
.AtLeastOnceUntil(Lookahead(Char('[').IgnoreResult().Or(End)))
|
||||
var sheetName = Any.AtLeastOnceUntil(Lookahead(Char('[').IgnoreResult().Or(End)))
|
||||
.Select(string.Concat)
|
||||
.Labelled("sheetName");
|
||||
var numPair = Map(ISelectorPart (first, second) =>
|
||||
new IndexRange(uint.Parse(string.Concat(first)), uint.Parse(string.Concat(second))),
|
||||
var numPair = Map(
|
||||
ISelectorPart (first, second) =>
|
||||
new IndexRange(
|
||||
uint.Parse(string.Concat(first)),
|
||||
uint.Parse(string.Concat(second))
|
||||
),
|
||||
Digit.AtLeastOnce().Before(Char('-')),
|
||||
Digit.AtLeastOnce())
|
||||
Digit.AtLeastOnce()
|
||||
)
|
||||
.Labelled("numPair");
|
||||
var singleRow = Digit
|
||||
.AtLeastOnce()
|
||||
@@ -43,14 +46,11 @@ internal static class AutoTranslate
|
||||
.Then(Digit.AtLeastOnce())
|
||||
.Select(string.Concat)
|
||||
.Select(ISelectorPart (num) => new ColumnSpecifier(uint.Parse(num)));
|
||||
var noun = String("noun")
|
||||
.Select(ISelectorPart (_) => new NounMarker());
|
||||
var noun = String("noun").Select(ISelectorPart (_) => new NounMarker());
|
||||
var selectorItems = OneOf(Try(numPair), singleRow, column, noun)
|
||||
.Separated(Char(','))
|
||||
.Labelled("selectorItems");
|
||||
var selector = selectorItems
|
||||
.Between(Char('['), Char(']'))
|
||||
.Labelled("selector");
|
||||
var selector = selectorItems.Between(Char('['), Char(']')).Labelled("selector");
|
||||
return Map((name, sel) => (name, sel), sheetName, selector.Optional());
|
||||
}
|
||||
|
||||
@@ -90,7 +90,16 @@ internal static class AutoTranslate
|
||||
var list = new List<AutoTranslateEntry>();
|
||||
foreach (var row in Sheets.CompletionSheet)
|
||||
{
|
||||
var lookup = string.Concat(row.LookupTable.Select(p => p.Type == ReadOnlySePayloadType.Text ? Encoding.UTF8.GetString(p.Body.Span) : p.MacroCode == MacroCode.Num && p.TryGetExpression(out var num) && num.TryGetInt(out var val) ? val.ToString(CultureInfo.InvariantCulture) : ",,,unexpected macro code,,,"));
|
||||
var lookup = string.Concat(
|
||||
row.LookupTable.Select(p =>
|
||||
p.Type == ReadOnlySePayloadType.Text ? Encoding.UTF8.GetString(p.Body.Span)
|
||||
: p.MacroCode == MacroCode.Num
|
||||
&& p.TryGetExpression(out var num)
|
||||
&& num.TryGetInt(out var val)
|
||||
? val.ToString(CultureInfo.InvariantCulture)
|
||||
: ",,,unexpected macro code,,,"
|
||||
)
|
||||
);
|
||||
try
|
||||
{
|
||||
if (lookup is not ("" or "@"))
|
||||
@@ -114,7 +123,7 @@ internal static class AutoTranslate
|
||||
case IndexRange range:
|
||||
{
|
||||
var start = (int)range.Start;
|
||||
var end = (int)(range.End + 1);
|
||||
var end = (int)(range.End + 1);
|
||||
rows.Add(start..end);
|
||||
break;
|
||||
}
|
||||
@@ -158,7 +167,14 @@ internal static class AutoTranslate
|
||||
var rawName = rowParser.ReadStringColumn(col);
|
||||
if (!rawName.IsEmpty)
|
||||
{
|
||||
list.Add(new AutoTranslateEntry(row.Group, (uint)i, rawName.ToString(), string.Empty));
|
||||
list.Add(
|
||||
new AutoTranslateEntry(
|
||||
row.Group,
|
||||
(uint)i,
|
||||
rawName.ToString(),
|
||||
string.Empty
|
||||
)
|
||||
);
|
||||
|
||||
if (shouldAdd)
|
||||
ValidEntries.Add((row.Group, (uint)i));
|
||||
@@ -172,7 +188,14 @@ internal static class AutoTranslate
|
||||
if (row.Text.IsEmpty)
|
||||
continue;
|
||||
|
||||
list.Add(new AutoTranslateEntry(row.Group, row.RowId, row.Text.ToString(), row.GroupTitle.ToString()));
|
||||
list.Add(
|
||||
new AutoTranslateEntry(
|
||||
row.Group,
|
||||
row.RowId,
|
||||
row.Text.ToString(),
|
||||
row.GroupTitle.ToString()
|
||||
)
|
||||
);
|
||||
|
||||
if (shouldAdd)
|
||||
ValidEntries.Add((row.Group, row.RowId));
|
||||
@@ -220,16 +243,16 @@ internal static class AutoTranslate
|
||||
|
||||
if (sort)
|
||||
{
|
||||
return wholeMatches.OrderBy(entry => entry.Text, StringComparer.OrdinalIgnoreCase)
|
||||
.Concat(prefixMatches.OrderBy(entry => entry.Text, StringComparer.OrdinalIgnoreCase))
|
||||
return wholeMatches
|
||||
.OrderBy(entry => entry.Text, StringComparer.OrdinalIgnoreCase)
|
||||
.Concat(
|
||||
prefixMatches.OrderBy(entry => entry.Text, StringComparer.OrdinalIgnoreCase)
|
||||
)
|
||||
.Concat(otherMatches.OrderBy(entry => entry.Text, StringComparer.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return wholeMatches
|
||||
.Concat(prefixMatches)
|
||||
.Concat(otherMatches)
|
||||
.ToList();
|
||||
return wholeMatches.Concat(prefixMatches).Concat(otherMatches).ToList();
|
||||
}
|
||||
|
||||
internal static void ReplaceWithPayload(ref byte[] bytes)
|
||||
@@ -255,7 +278,11 @@ internal static class AutoTranslate
|
||||
|
||||
var tag = Encoding.UTF8.GetString(bytes[start..(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 (
|
||||
parts.Length == 2
|
||||
&& uint.TryParse(parts[0], out var group)
|
||||
&& uint.TryParse(parts[1], out var key)
|
||||
)
|
||||
{
|
||||
bool isValid;
|
||||
lock (EntriesLock)
|
||||
@@ -267,7 +294,13 @@ internal static class AutoTranslate
|
||||
bytes = new byte[oldBytes.Length + lengthDiff];
|
||||
Array.Copy(oldBytes, bytes, start);
|
||||
Array.Copy(payload, 0, bytes, start, payload.Length);
|
||||
Array.Copy(oldBytes, i + 1, bytes, start + payload.Length, oldBytes.Length - (i + 1));
|
||||
Array.Copy(
|
||||
oldBytes,
|
||||
i + 1,
|
||||
bytes,
|
||||
start + payload.Length,
|
||||
oldBytes.Length - (i + 1)
|
||||
);
|
||||
|
||||
i += lengthDiff;
|
||||
}
|
||||
@@ -278,7 +311,10 @@ internal static class AutoTranslate
|
||||
// Pure managed comparison via Span avoids the msvcrt.dll P/Invoke,
|
||||
// which is fragile under Wine and triggered an extra managed-to-
|
||||
// unmanaged copy per check.
|
||||
if (i + search.Length < bytes.Length && bytes.AsSpan(i, search.Length).SequenceEqual(search))
|
||||
if (
|
||||
i + search.Length < bytes.Length
|
||||
&& bytes.AsSpan(i, search.Length).SequenceEqual(search)
|
||||
)
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
@@ -309,7 +345,11 @@ internal static class AutoTranslate
|
||||
|
||||
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 (
|
||||
parts.Length == 2
|
||||
&& uint.TryParse(parts[0], out var group)
|
||||
&& uint.TryParse(parts[1], out var key)
|
||||
)
|
||||
{
|
||||
bool isValid;
|
||||
lock (EntriesLock)
|
||||
@@ -317,7 +357,9 @@ internal static class AutoTranslate
|
||||
if (!isValid)
|
||||
return false;
|
||||
|
||||
var evaluated = Plugin.Evaluator.Evaluate(new ReadOnlySeString(CreateFixedTranslation(group, key))).ToString();
|
||||
var evaluated = Plugin
|
||||
.Evaluator.Evaluate(new ReadOnlySeString(CreateFixedTranslation(group, key)))
|
||||
.ToString();
|
||||
if (!evaluated.StartsWith('/'))
|
||||
return false;
|
||||
|
||||
@@ -332,8 +374,8 @@ internal static class AutoTranslate
|
||||
private static byte[] CreateFixedTranslation(uint group, uint key)
|
||||
{
|
||||
using var rssb = new RentedSeStringBuilder();
|
||||
return rssb.Builder
|
||||
.BeginMacro(MacroCode.Fixed)
|
||||
return rssb
|
||||
.Builder.BeginMacro(MacroCode.Fixed)
|
||||
.AppendUIntExpression(group - 1)
|
||||
.AppendUIntExpression(key)
|
||||
.EndMacro()
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using HellionChat.Code;
|
||||
using System.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using System.Text;
|
||||
using HellionChat.Code;
|
||||
using Lumina.Text.Payloads;
|
||||
|
||||
using PayloadType = Dalamud.Game.Text.SeStringHandling.PayloadType;
|
||||
|
||||
namespace HellionChat.Util;
|
||||
@@ -248,7 +247,11 @@ internal static class ChunkUtil
|
||||
// return chunks;
|
||||
// }
|
||||
|
||||
internal static IEnumerable<Chunk> ToChunks(SeString msg, ChunkSource source, ChatType? defaultColour)
|
||||
internal static IEnumerable<Chunk> ToChunks(
|
||||
SeString msg,
|
||||
ChunkSource source,
|
||||
ChatType? defaultColour
|
||||
)
|
||||
{
|
||||
var chunks = new List<Chunk>();
|
||||
|
||||
@@ -259,13 +262,15 @@ internal static class ChunkUtil
|
||||
|
||||
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,
|
||||
});
|
||||
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.Payloads)
|
||||
@@ -273,18 +278,18 @@ internal static class ChunkUtil
|
||||
switch (payload.Type)
|
||||
{
|
||||
case PayloadType.EmphasisItalic:
|
||||
var newStatus = ((EmphasisItalicPayload) payload).IsEnabled;
|
||||
var newStatus = ((EmphasisItalicPayload)payload).IsEnabled;
|
||||
italic = newStatus;
|
||||
break;
|
||||
case PayloadType.UIForeground:
|
||||
var foregroundPayload = (UIForegroundPayload) payload;
|
||||
var foregroundPayload = (UIForegroundPayload)payload;
|
||||
if (foregroundPayload.IsEnabled)
|
||||
foreground.Push(foregroundPayload.UIColor.Value.Dark);
|
||||
else if (foreground.Count > 0)
|
||||
foreground.Pop();
|
||||
break;
|
||||
case PayloadType.UIGlow:
|
||||
var glowPayload = (UIGlowPayload) payload;
|
||||
var glowPayload = (UIGlowPayload)payload;
|
||||
if (glowPayload.IsEnabled)
|
||||
glow.Push(glowPayload.UIColor.Value.Light);
|
||||
else if (glow.Count > 0)
|
||||
@@ -292,12 +297,12 @@ internal static class ChunkUtil
|
||||
break;
|
||||
case PayloadType.AutoTranslateText:
|
||||
chunks.Add(new IconChunk(source, payload, BitmapFontIcon.AutoTranslateBegin));
|
||||
var autoText = ((AutoTranslatePayload) payload).Text;
|
||||
var autoText = ((AutoTranslatePayload)payload).Text;
|
||||
Append(autoText.Substring(2, autoText.Length - 4));
|
||||
chunks.Add(new IconChunk(source, link, BitmapFontIcon.AutoTranslateEnd));
|
||||
break;
|
||||
case PayloadType.Icon:
|
||||
chunks.Add(new IconChunk(source, link, ((IconPayload) payload).Icon));
|
||||
chunks.Add(new IconChunk(source, link, ((IconPayload)payload).Icon));
|
||||
break;
|
||||
case PayloadType.MapLink:
|
||||
case PayloadType.Quest:
|
||||
@@ -311,7 +316,7 @@ internal static class ChunkUtil
|
||||
link = payload;
|
||||
break;
|
||||
case PayloadType.Unknown:
|
||||
var rawPayload = (RawPayload) payload;
|
||||
var rawPayload = (RawPayload)payload;
|
||||
var colorPayload = ColorPayload.From(rawPayload.Data);
|
||||
if (colorPayload != null)
|
||||
{
|
||||
@@ -333,20 +338,36 @@ internal static class ChunkUtil
|
||||
{
|
||||
glow.Pop();
|
||||
}
|
||||
else if (rawPayload.Data.Length > 6 && rawPayload.Data[2] == 0x05 && rawPayload.Data[3] == 0xF6)
|
||||
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]);
|
||||
var (r, g, b) = (
|
||||
rawPayload.Data[4],
|
||||
rawPayload.Data[5],
|
||||
rawPayload.Data[6]
|
||||
);
|
||||
glow.Push(ColourUtil.ComponentsToRgba(r, g, b));
|
||||
}
|
||||
}
|
||||
else if (rawPayload.Data.Length > 7 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x0A)
|
||||
else if (
|
||||
rawPayload.Data.Length > 7
|
||||
&& rawPayload.Data[1] == 0x27
|
||||
&& rawPayload.Data[3] == 0x0A
|
||||
)
|
||||
{
|
||||
// pf payload
|
||||
var reader = new BinaryReader(new MemoryStream(rawPayload.Data[4..]));
|
||||
var id = GetInteger(reader);
|
||||
link = new PartyFinderPayload(id);
|
||||
}
|
||||
else if (rawPayload.Data.Length > 5 && rawPayload.Data[1] == 0x27 && rawPayload.Data[3] == 0x06)
|
||||
else if (
|
||||
rawPayload.Data.Length > 5
|
||||
&& rawPayload.Data[1] == 0x27
|
||||
&& rawPayload.Data[3] == 0x06
|
||||
)
|
||||
{
|
||||
// achievement payload
|
||||
var reader = new BinaryReader(new MemoryStream(rawPayload.Data[4..]));
|
||||
@@ -452,18 +473,29 @@ internal static class ChunkUtil
|
||||
return payload.World.RowId == senderWorld;
|
||||
}
|
||||
|
||||
internal static readonly RawPayload PeriodicRecruitmentLink = new([0x02, 0x27, 0x07, 0x08, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03]);
|
||||
internal static readonly RawPayload PeriodicRecruitmentLink = new([
|
||||
0x02,
|
||||
0x27,
|
||||
0x07,
|
||||
0x08,
|
||||
0x01,
|
||||
0x01,
|
||||
0x01,
|
||||
0xFF,
|
||||
0x01,
|
||||
0x03,
|
||||
]);
|
||||
|
||||
private static uint GetInteger(BinaryReader input)
|
||||
{
|
||||
var num1 = (uint) input.ReadByte();
|
||||
var num1 = (uint)input.ReadByte();
|
||||
if (num1 < 208U)
|
||||
return num1 - 1U;
|
||||
|
||||
var num2 = (uint) ((int) num1 + 1 & 15);
|
||||
var num2 = (uint)((int)num1 + 1 & 15);
|
||||
var numArray = new byte[4];
|
||||
for (var index = 3; index >= 0; --index)
|
||||
numArray[index] = (num2 & 1 << index) == 0L ? (byte) 0 : input.ReadByte();
|
||||
numArray[index] = (num2 & 1 << index) == 0L ? (byte)0 : input.ReadByte();
|
||||
|
||||
return BitConverter.ToUInt32(numArray, 0);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@ using System.Numerics;
|
||||
|
||||
namespace HellionChat.Util;
|
||||
|
||||
internal static class ColourUtil {
|
||||
internal static class ColourUtil
|
||||
{
|
||||
private static (byte r, byte g, byte b) RgbaToRgbComponents(uint rgba)
|
||||
{
|
||||
var r = (byte) ((rgba & 0xFF000000) >> 24);
|
||||
var g = (byte) ((rgba & 0xFF0000) >> 16);
|
||||
var b = (byte) ((rgba & 0xFF00) >> 8);
|
||||
var r = (byte)((rgba & 0xFF000000) >> 24);
|
||||
var g = (byte)((rgba & 0xFF0000) >> 16);
|
||||
var b = (byte)((rgba & 0xFF00) >> 8);
|
||||
return (r, g, b);
|
||||
}
|
||||
|
||||
@@ -17,26 +18,28 @@ internal static class ColourUtil {
|
||||
internal static Vector3 RgbaToVector3(uint rgba)
|
||||
{
|
||||
var (r, g, b) = RgbaToRgbComponents(rgba);
|
||||
return new Vector3((float) r / 255, (float) g / 255, (float) b / 255);
|
||||
return new Vector3((float)r / 255, (float)g / 255, (float)b / 255);
|
||||
}
|
||||
|
||||
internal static uint Vector3ToRgba(Vector3 col)
|
||||
{
|
||||
return ComponentsToRgba(
|
||||
(byte) Math.Round(col.X * 255),
|
||||
(byte) Math.Round(col.Y * 255),
|
||||
(byte) Math.Round(col.Z * 255)
|
||||
(byte)Math.Round(col.X * 255),
|
||||
(byte)Math.Round(col.Y * 255),
|
||||
(byte)Math.Round(col.Z * 255)
|
||||
);
|
||||
}
|
||||
|
||||
internal static uint Vector4ToAbgr(Vector4 col)
|
||||
{
|
||||
return RgbaToAbgr(ComponentsToRgba(
|
||||
(byte) Math.Round(col.X * 255),
|
||||
(byte) Math.Round(col.Y * 255),
|
||||
(byte) Math.Round(col.Z * 255),
|
||||
(byte) Math.Round(col.W * 255)
|
||||
));
|
||||
return RgbaToAbgr(
|
||||
ComponentsToRgba(
|
||||
(byte)Math.Round(col.X * 255),
|
||||
(byte)Math.Round(col.Y * 255),
|
||||
(byte)Math.Round(col.Z * 255),
|
||||
(byte)Math.Round(col.W * 255)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static unsafe uint ArgbToRgba(uint x)
|
||||
@@ -46,21 +49,21 @@ internal static class ColourUtil {
|
||||
return x;
|
||||
}
|
||||
|
||||
internal static uint ComponentsToRgba(byte red, byte green, byte blue, byte alpha = 0xFF)
|
||||
=> alpha | (uint) (red << 24) | (uint) (green << 16) | (uint) (blue << 8);
|
||||
internal static uint ComponentsToRgba(byte red, byte green, byte blue, byte alpha = 0xFF) =>
|
||||
alpha | (uint)(red << 24) | (uint)(green << 16) | (uint)(blue << 8);
|
||||
|
||||
internal static uint AdjustBrightness(uint abgr, float factor)
|
||||
{
|
||||
var a = (byte) ((abgr & 0xFF000000) >> 24);
|
||||
var b = (byte) ((abgr & 0x00FF0000) >> 16);
|
||||
var g = (byte) ((abgr & 0x0000FF00) >> 8);
|
||||
var r = (byte) (abgr & 0x000000FF);
|
||||
var a = (byte)((abgr & 0xFF000000) >> 24);
|
||||
var b = (byte)((abgr & 0x00FF0000) >> 16);
|
||||
var g = (byte)((abgr & 0x0000FF00) >> 8);
|
||||
var r = (byte)(abgr & 0x000000FF);
|
||||
|
||||
var nr = (byte) Math.Clamp(r * factor, 0f, 255f);
|
||||
var ng = (byte) Math.Clamp(g * factor, 0f, 255f);
|
||||
var nb = (byte) Math.Clamp(b * factor, 0f, 255f);
|
||||
var nr = (byte)Math.Clamp(r * factor, 0f, 255f);
|
||||
var ng = (byte)Math.Clamp(g * factor, 0f, 255f);
|
||||
var nb = (byte)Math.Clamp(b * factor, 0f, 255f);
|
||||
|
||||
return ((uint) a << 24) | ((uint) nb << 16) | ((uint) ng << 8) | nr;
|
||||
return ((uint)a << 24) | ((uint)nb << 16) | ((uint)ng << 8) | nr;
|
||||
}
|
||||
|
||||
public static uint HexToRgba(string hex)
|
||||
@@ -68,13 +71,22 @@ internal static class ColourUtil {
|
||||
ArgumentNullException.ThrowIfNull(hex);
|
||||
var s = hex.StartsWith('#') ? hex[1..] : hex;
|
||||
if (s.Length != 6 && s.Length != 8)
|
||||
throw new FormatException($"Hex colour must be 6 or 8 hex digits, got {s.Length}: '{hex}'");
|
||||
throw new FormatException(
|
||||
$"Hex colour must be 6 or 8 hex digits, got {s.Length}: '{hex}'"
|
||||
);
|
||||
|
||||
if (!uint.TryParse(s, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out var value))
|
||||
if (
|
||||
!uint.TryParse(
|
||||
s,
|
||||
System.Globalization.NumberStyles.HexNumber,
|
||||
System.Globalization.CultureInfo.InvariantCulture,
|
||||
out var value
|
||||
)
|
||||
)
|
||||
throw new FormatException($"Hex colour '{hex}' is not a valid hexadecimal value");
|
||||
|
||||
if (s.Length == 6)
|
||||
value = (value << 8) | 0xFFu; // RRGGBB → RRGGBBFF
|
||||
value = (value << 8) | 0xFFu; // RRGGBB → RRGGBBFF
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
+122
-24
@@ -1,13 +1,13 @@
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using HellionChat.Resources;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using Dalamud.Utility;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using HellionChat.Resources;
|
||||
|
||||
namespace HellionChat.Util;
|
||||
|
||||
@@ -18,9 +18,46 @@ public static class DateWidget
|
||||
private static readonly DateTime Sample = DateTime.UnixEpoch;
|
||||
|
||||
private static readonly Vector4 Transparent = new(1, 1, 1, 0);
|
||||
private static readonly string[] DayNames = [Language.DateWidget_Day_Sun, Language.DateWidget_Day_Mon, Language.DateWidget_Day_Tue, Language.DateWidget_Day_Wed, Language.DateWidget_Day_Thu, Language.DateWidget_Day_Fri, Language.DateWidget_Day_Sat];
|
||||
private static readonly string[] MonthNames = [Language.DateWidget_Month_January, Language.DateWidget_Month_February, Language.DateWidget_Month_March, Language.DateWidget_Month_April, Language.DateWidget_Month_May, Language.DateWidget_Month_June, Language.DateWidget_Month_July, Language.DateWidget_Month_August, Language.DateWidget_Month_September, Language.DateWidget_Month_October, Language.DateWidget_Month_November, Language.DateWidget_Month_December];
|
||||
private static readonly int[] NumDaysPerMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
private static readonly string[] DayNames =
|
||||
[
|
||||
Language.DateWidget_Day_Sun,
|
||||
Language.DateWidget_Day_Mon,
|
||||
Language.DateWidget_Day_Tue,
|
||||
Language.DateWidget_Day_Wed,
|
||||
Language.DateWidget_Day_Thu,
|
||||
Language.DateWidget_Day_Fri,
|
||||
Language.DateWidget_Day_Sat,
|
||||
];
|
||||
private static readonly string[] MonthNames =
|
||||
[
|
||||
Language.DateWidget_Month_January,
|
||||
Language.DateWidget_Month_February,
|
||||
Language.DateWidget_Month_March,
|
||||
Language.DateWidget_Month_April,
|
||||
Language.DateWidget_Month_May,
|
||||
Language.DateWidget_Month_June,
|
||||
Language.DateWidget_Month_July,
|
||||
Language.DateWidget_Month_August,
|
||||
Language.DateWidget_Month_September,
|
||||
Language.DateWidget_Month_October,
|
||||
Language.DateWidget_Month_November,
|
||||
Language.DateWidget_Month_December,
|
||||
];
|
||||
private static readonly int[] NumDaysPerMonth =
|
||||
[
|
||||
31,
|
||||
28,
|
||||
31,
|
||||
30,
|
||||
31,
|
||||
30,
|
||||
31,
|
||||
31,
|
||||
30,
|
||||
31,
|
||||
30,
|
||||
31,
|
||||
];
|
||||
|
||||
private static float LongestMonthWidth;
|
||||
private static readonly float[] MonthWidths = new float[12];
|
||||
@@ -33,12 +70,14 @@ public static class DateWidget
|
||||
if (minimal > currentMin)
|
||||
{
|
||||
currentMin = minimal;
|
||||
Plugin.Notification.AddNotification(new Notification
|
||||
{
|
||||
Content = Language.DateWidget_InvalidDate.Format(minimal.ToShortDateString()),
|
||||
Type = NotificationType.Warning,
|
||||
Minimized = false,
|
||||
});
|
||||
Plugin.Notification.AddNotification(
|
||||
new Notification
|
||||
{
|
||||
Content = Language.DateWidget_InvalidDate.Format(minimal.ToShortDateString()),
|
||||
Type = NotificationType.Warning,
|
||||
Minimized = false,
|
||||
}
|
||||
);
|
||||
needsRefresh = true;
|
||||
}
|
||||
else if (currentMin > currentMax)
|
||||
@@ -50,15 +89,41 @@ public static class DateWidget
|
||||
return needsRefresh;
|
||||
}
|
||||
|
||||
public static void DatePickerWithInput(string label, int id, ref string dateString, ref DateTime date, string format, bool sameLine = false, bool closeWhenMouseLeavesIt = true)
|
||||
public static void DatePickerWithInput(
|
||||
string label,
|
||||
int id,
|
||||
ref string dateString,
|
||||
ref DateTime date,
|
||||
string format,
|
||||
bool sameLine = false,
|
||||
bool closeWhenMouseLeavesIt = true
|
||||
)
|
||||
{
|
||||
if (sameLine)
|
||||
ImGui.SameLine();
|
||||
|
||||
ImGui.SetNextItemWidth(ImGui.CalcTextSize(Sample.ToString(format)).X + ImGui.GetStyle().ItemInnerSpacing.X * 2);
|
||||
if (ImGui.InputTextWithHint($"##{label}Input", format.ToUpper(), ref dateString, 32, ImGuiInputTextFlags.CallbackCompletion))
|
||||
ImGui.SetNextItemWidth(
|
||||
ImGui.CalcTextSize(Sample.ToString(format)).X + ImGui.GetStyle().ItemInnerSpacing.X * 2
|
||||
);
|
||||
if (
|
||||
ImGui.InputTextWithHint(
|
||||
$"##{label}Input",
|
||||
format.ToUpper(),
|
||||
ref dateString,
|
||||
32,
|
||||
ImGuiInputTextFlags.CallbackCompletion
|
||||
)
|
||||
)
|
||||
{
|
||||
if (DateTime.TryParseExact(dateString, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out var tmp))
|
||||
if (
|
||||
DateTime.TryParseExact(
|
||||
dateString,
|
||||
format,
|
||||
CultureInfo.InvariantCulture,
|
||||
DateTimeStyles.None,
|
||||
out var tmp
|
||||
)
|
||||
)
|
||||
date = tmp;
|
||||
}
|
||||
|
||||
@@ -72,7 +137,13 @@ public static class DateWidget
|
||||
dateString = date.ToString(format);
|
||||
}
|
||||
|
||||
private static bool DatePicker(string label, ref DateTime dateOut, bool closeWhenMouseLeavesIt, string leftArrow = "", string rightArrow = "")
|
||||
private static bool DatePicker(
|
||||
string label,
|
||||
ref DateTime dateOut,
|
||||
bool closeWhenMouseLeavesIt,
|
||||
string leftArrow = "",
|
||||
string rightArrow = ""
|
||||
)
|
||||
{
|
||||
using var mono = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
if (LongestMonthWidth == 0.0f)
|
||||
@@ -96,12 +167,22 @@ public static class DateWidget
|
||||
|
||||
var labelSize = ImGui.CalcTextSize(label, true, 0);
|
||||
|
||||
var widthRequiredByCalendar = (2.0f * arrowLeftWidth) + (2.0f * arrowRightWidth) + LongestMonthWidth + ImGui.CalcTextSize("9999").X + (120.0f * ImGuiHelpers.GlobalScale);
|
||||
var popupHeight = ((labelSize.Y + (2 * style.ItemSpacing.Y)) * HeightInItems) + (style.FramePadding.Y * 3);
|
||||
var widthRequiredByCalendar =
|
||||
(2.0f * arrowLeftWidth)
|
||||
+ (2.0f * arrowRightWidth)
|
||||
+ LongestMonthWidth
|
||||
+ ImGui.CalcTextSize("9999").X
|
||||
+ (120.0f * ImGuiHelpers.GlobalScale);
|
||||
var popupHeight =
|
||||
((labelSize.Y + (2 * style.ItemSpacing.Y)) * HeightInItems)
|
||||
+ (style.FramePadding.Y * 3);
|
||||
|
||||
var valueChanged = false;
|
||||
ImGui.SetNextWindowSize(new Vector2(widthRequiredByCalendar, widthRequiredByCalendar));
|
||||
ImGui.SetNextWindowSizeConstraints(new Vector2(widthRequiredByCalendar, popupHeight + 40), new Vector2(widthRequiredByCalendar, popupHeight + 40));
|
||||
ImGui.SetNextWindowSizeConstraints(
|
||||
new Vector2(widthRequiredByCalendar, popupHeight + 40),
|
||||
new Vector2(widthRequiredByCalendar, popupHeight + 40)
|
||||
);
|
||||
|
||||
using var popupItem = ImRaii.ContextPopupItem(label, ImGuiPopupFlags.None);
|
||||
if (!popupItem.Success)
|
||||
@@ -156,7 +237,12 @@ public static class DateWidget
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine(ImGui.GetWindowWidth() - yearPartWidth - style.WindowPadding.X - style.ItemSpacing.X * 4.0f);
|
||||
ImGui.SameLine(
|
||||
ImGui.GetWindowWidth()
|
||||
- yearPartWidth
|
||||
- style.WindowPadding.X
|
||||
- style.ItemSpacing.X * 4.0f
|
||||
);
|
||||
|
||||
using (ImRaii.PushId(1235))
|
||||
{
|
||||
@@ -189,7 +275,10 @@ public static class DateWidget
|
||||
maxDayOfCurMonth = 29;
|
||||
}
|
||||
|
||||
using var buttonHovered = ImRaii.PushColor(ImGuiCol.ButtonHovered, ImGuiColors.DalamudOrange);
|
||||
using var buttonHovered = ImRaii.PushColor(
|
||||
ImGuiCol.ButtonHovered,
|
||||
ImGuiColors.DalamudOrange
|
||||
);
|
||||
using var buttonActive = ImRaii.PushColor(ImGuiCol.ButtonActive, ImGuiColors.DalamudYellow);
|
||||
|
||||
ImGui.Separator();
|
||||
@@ -201,7 +290,11 @@ public static class DateWidget
|
||||
{
|
||||
using (ImRaii.Group())
|
||||
{
|
||||
using var textColor = ImRaii.PushColor(ImGuiCol.Text, CalculateTextColor(), dw == 0);
|
||||
using var textColor = ImRaii.PushColor(
|
||||
ImGuiCol.Text,
|
||||
CalculateTextColor(),
|
||||
dw == 0
|
||||
);
|
||||
|
||||
ImGui.Text($"{(dw == 0 ? "" : " ")}{DayNames[dw]}");
|
||||
if (dw == 0)
|
||||
@@ -253,7 +346,12 @@ public static class DateWidget
|
||||
size.X += 2.0f * distance;
|
||||
size.Y += 2.0f * distance;
|
||||
var mousePos = ImGui.GetIO().MousePos;
|
||||
if (mousePos.X < pos.X || mousePos.Y < pos.Y || mousePos.X > pos.X + size.X || mousePos.Y > pos.Y + size.Y)
|
||||
if (
|
||||
mousePos.X < pos.X
|
||||
|| mousePos.Y < pos.Y
|
||||
|| mousePos.X > pos.X + size.X
|
||||
|| mousePos.Y > pos.Y + size.Y
|
||||
)
|
||||
mustCloseCombo = true;
|
||||
}
|
||||
|
||||
@@ -270,4 +368,4 @@ public static class DateWidget
|
||||
var l = (textColor.X + textColor.Y + textColor.Z) * 0.33334f;
|
||||
return new Vector4(l * 2.0f > 1 ? 1 : l * 2.0f, l * .5f, l * .5f, textColor.W);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,11 @@ public class ColorPayload
|
||||
case 0xE9:
|
||||
var param = stream.ReadByte();
|
||||
if (param == -1)
|
||||
throw new ArgumentException("Encountered premature end of input (unexpected EOF).", nameof(stream));
|
||||
var globalValue = (uint) GlobalParametersCache.GetValue(param - 2);
|
||||
throw new ArgumentException(
|
||||
"Encountered premature end of input (unexpected EOF).",
|
||||
nameof(stream)
|
||||
);
|
||||
var globalValue = (uint)GlobalParametersCache.GetValue(param - 2);
|
||||
payload.Enabled = true;
|
||||
payload.UnshiftedColor = globalValue;
|
||||
payload.Color = ColourUtil.ArgbToRgba(globalValue);
|
||||
@@ -40,10 +43,16 @@ public class ColorPayload
|
||||
return v switch
|
||||
{
|
||||
// ReSharper disable once LocalizableElement
|
||||
-1 => throw new ArgumentException("Encountered premature end of input (unexpected EOF).", nameof(v)),
|
||||
-1 => throw new ArgumentException(
|
||||
"Encountered premature end of input (unexpected EOF).",
|
||||
nameof(v)
|
||||
),
|
||||
// ReSharper disable once LocalizableElement
|
||||
0 => throw new ArgumentException("Encountered premature end of input (unexpected null character).", nameof(v)),
|
||||
_ => (uint)v << shift
|
||||
0 => throw new ArgumentException(
|
||||
"Encountered premature end of input (unexpected null character).",
|
||||
nameof(v)
|
||||
),
|
||||
_ => (uint)v << shift,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -54,9 +63,12 @@ public class ColorPayload
|
||||
else
|
||||
argbValue |= 0xff000000u;
|
||||
|
||||
if( (typeByte & 4) != 0 ) argbValue |= ShiftAndThrowIfZero( stream.ReadByte(), 16 );
|
||||
if( (typeByte & 2) != 0 ) argbValue |= ShiftAndThrowIfZero( stream.ReadByte(), 8 );
|
||||
if( (typeByte & 1) != 0 ) argbValue |= ShiftAndThrowIfZero( stream.ReadByte(), 0 );
|
||||
if ((typeByte & 4) != 0)
|
||||
argbValue |= ShiftAndThrowIfZero(stream.ReadByte(), 16);
|
||||
if ((typeByte & 2) != 0)
|
||||
argbValue |= ShiftAndThrowIfZero(stream.ReadByte(), 8);
|
||||
if ((typeByte & 1) != 0)
|
||||
argbValue |= ShiftAndThrowIfZero(stream.ReadByte(), 0);
|
||||
|
||||
payload.Enabled = true;
|
||||
payload.Color = ColourUtil.ArgbToRgba(argbValue);
|
||||
@@ -66,4 +78,4 @@ public class ColorPayload
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ public static class GlobalParametersCache
|
||||
public static unsafe void Refresh()
|
||||
{
|
||||
if (!ThreadSafety.IsMainThread)
|
||||
throw new InvalidOperationException("GlobalParametersCache.Refresh must be called on the main thread.");
|
||||
throw new InvalidOperationException(
|
||||
"GlobalParametersCache.Refresh must be called on the main thread."
|
||||
);
|
||||
|
||||
var rtm = RaptureTextModule.Instance();
|
||||
if (rtm is null)
|
||||
@@ -48,4 +50,4 @@ public static class GlobalParametersCache
|
||||
Cache[(int)i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,8 @@ public readonly unsafe ref struct GfdFileView
|
||||
private ref readonly GfdHeader Header => ref MemoryMarshal.AsRef<GfdHeader>(Span);
|
||||
|
||||
/// <summary>Gets the entries.</summary>
|
||||
private ReadOnlySpan<GfdEntry> Entries => MemoryMarshal.Cast<byte, GfdEntry>(Span[sizeof(GfdHeader)..]);
|
||||
private ReadOnlySpan<GfdEntry> Entries =>
|
||||
MemoryMarshal.Cast<byte, GfdEntry>(Span[sizeof(GfdHeader)..]);
|
||||
|
||||
/// <summary>Attempts to get an entry.</summary>
|
||||
/// <param name="iconId">The icon ID.</param>
|
||||
@@ -153,8 +154,6 @@ public readonly unsafe ref struct GfdFileView
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal static class IconUtil
|
||||
{
|
||||
private static byte[]? GfdFile;
|
||||
@@ -164,8 +163,11 @@ internal static class IconUtil
|
||||
{
|
||||
if (GfdFile is null)
|
||||
{
|
||||
var file = Plugin.DataManager.GetFile("common/font/gfdata.gfd")
|
||||
?? throw new FileNotFoundException("Failed to load common/font/gfdata.gfd from the game data.");
|
||||
var file =
|
||||
Plugin.DataManager.GetFile("common/font/gfdata.gfd")
|
||||
?? throw new FileNotFoundException(
|
||||
"Failed to load common/font/gfdata.gfd from the game data."
|
||||
);
|
||||
GfdFile = file.Data;
|
||||
}
|
||||
return new GfdFileView(GfdFile);
|
||||
|
||||
+126
-28
@@ -1,9 +1,7 @@
|
||||
using System.Buffers;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using HellionChat.Code;
|
||||
using HellionChat.GameFunctions.Types;
|
||||
using HellionChat.Resources;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Game.ClientState.Keys;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Interface;
|
||||
@@ -13,7 +11,9 @@ using Dalamud.Interface.ImGuiFontChooserDialog;
|
||||
using Dalamud.Interface.Style;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using HellionChat.Code;
|
||||
using HellionChat.GameFunctions.Types;
|
||||
using HellionChat.Resources;
|
||||
|
||||
namespace HellionChat.Util;
|
||||
|
||||
@@ -30,7 +30,7 @@ internal static class ImGuiUtil
|
||||
[
|
||||
ImGuiMouseButton.Left,
|
||||
ImGuiMouseButton.Middle,
|
||||
ImGuiMouseButton.Right
|
||||
ImGuiMouseButton.Right,
|
||||
];
|
||||
|
||||
private static Payload? Hovered;
|
||||
@@ -66,7 +66,13 @@ internal static class ImGuiUtil
|
||||
// ever feeds in a degenerate input.
|
||||
private const int MaxLineByteCount = 16 * 1024;
|
||||
|
||||
internal static void WrapText(string csText, Chunk chunk, PayloadHandler? handler, Vector4 defaultText, float lineWidth)
|
||||
internal static void WrapText(
|
||||
string csText,
|
||||
Chunk chunk,
|
||||
PayloadHandler? handler,
|
||||
Vector4 defaultText,
|
||||
float lineWidth
|
||||
)
|
||||
{
|
||||
if (csText.Length == 0)
|
||||
return;
|
||||
@@ -111,7 +117,13 @@ internal static class ImGuiUtil
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void WrapEncodedLine(ReadOnlySpan<byte> bytes, Chunk chunk, PayloadHandler? handler, Vector4 defaultText, float lineWidth)
|
||||
private static unsafe void WrapEncodedLine(
|
||||
ReadOnlySpan<byte> bytes,
|
||||
Chunk chunk,
|
||||
PayloadHandler? handler,
|
||||
Vector4 defaultText,
|
||||
float lineWidth
|
||||
)
|
||||
{
|
||||
var byteCount = bytes.Length;
|
||||
if (byteCount == 0)
|
||||
@@ -187,13 +199,21 @@ internal static class ImGuiUtil
|
||||
ImGuiHelpers.GlobalScale,
|
||||
basePtr + start,
|
||||
basePtr + end,
|
||||
width);
|
||||
width
|
||||
);
|
||||
if (result == null)
|
||||
return -1;
|
||||
return (int)(result - basePtr);
|
||||
}
|
||||
|
||||
private static unsafe void DrawText(byte* basePtr, int start, int end, Chunk chunk, PayloadHandler? handler, Vector4 defaultText)
|
||||
private static unsafe void DrawText(
|
||||
byte* basePtr,
|
||||
int start,
|
||||
int end,
|
||||
Chunk chunk,
|
||||
PayloadHandler? handler,
|
||||
Vector4 defaultText
|
||||
)
|
||||
{
|
||||
var oldPos = ImGui.GetCursorScreenPos();
|
||||
|
||||
@@ -209,10 +229,14 @@ internal static class ImGuiUtil
|
||||
{
|
||||
defaultText.W = 0.25f;
|
||||
var actualCol = ColourUtil.Vector4ToAbgr(defaultText);
|
||||
ImGui.GetWindowDrawList().AddRectFilled(oldPos, oldPos + ImGui.GetItemRectSize(), actualCol);
|
||||
ImGui
|
||||
.GetWindowDrawList()
|
||||
.AddRectFilled(oldPos, oldPos + ImGui.GetItemRectSize(), actualCol);
|
||||
|
||||
foreach (var (boundsStart, boundsSize) in PayloadBounds)
|
||||
ImGui.GetWindowDrawList().AddRectFilled(boundsStart, boundsStart + boundsSize, actualCol);
|
||||
ImGui
|
||||
.GetWindowDrawList()
|
||||
.AddRectFilled(boundsStart, boundsStart + boundsSize, actualCol);
|
||||
|
||||
PayloadBounds.Clear();
|
||||
}
|
||||
@@ -230,7 +254,12 @@ internal static class ImGuiUtil
|
||||
return end;
|
||||
}
|
||||
|
||||
internal static bool IconButton(FontAwesomeIcon icon, string? id = null, string? tooltip = null, int width = 0)
|
||||
internal static bool IconButton(
|
||||
FontAwesomeIcon icon,
|
||||
string? id = null,
|
||||
string? tooltip = null,
|
||||
int width = 0
|
||||
)
|
||||
{
|
||||
var label = icon.ToIconString();
|
||||
if (id != null)
|
||||
@@ -246,7 +275,10 @@ internal static class ImGuiUtil
|
||||
ret = ImGui.Button(label, size);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tooltip) && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||
if (
|
||||
!string.IsNullOrEmpty(tooltip)
|
||||
&& ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)
|
||||
)
|
||||
Tooltip(tooltip);
|
||||
|
||||
return ret;
|
||||
@@ -264,7 +296,7 @@ internal static class ImGuiUtil
|
||||
internal static void HelpText(string text)
|
||||
{
|
||||
using (ImRaii.TextWrapPos(0.0f))
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, ImGui.GetStyle().Colors[(int) ImGuiCol.TextDisabled]))
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, ImGui.GetStyle().Colors[(int)ImGuiCol.TextDisabled]))
|
||||
ImGui.TextUnformatted(text);
|
||||
}
|
||||
|
||||
@@ -275,7 +307,7 @@ internal static class ImGuiUtil
|
||||
internal static void HelpMarker(string description)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, ImGui.GetStyle().Colors[(int) ImGuiCol.TextDisabled]))
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, ImGui.GetStyle().Colors[(int)ImGuiCol.TextDisabled]))
|
||||
ImGui.TextUnformatted("(?)");
|
||||
|
||||
// AllowWhenDisabled — ohne das Flag liefert IsItemHovered bei
|
||||
@@ -296,25 +328,48 @@ internal static class ImGuiUtil
|
||||
var dalamudOrange = style.BuiltInColors?.DalamudOrange;
|
||||
|
||||
using (ImRaii.TextWrapPos(wrap ? 0.0f : ImGui.GetFontSize() * 35.0f))
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, dalamudOrange ?? Vector4.Zero, dalamudOrange != null))
|
||||
using (
|
||||
ImRaii.PushColor(ImGuiCol.Text, dalamudOrange ?? Vector4.Zero, dalamudOrange != null)
|
||||
)
|
||||
ImGui.TextUnformatted(text);
|
||||
}
|
||||
|
||||
internal static ImRaii.ComboDisposable BeginComboVertical(string label, string previewValue, ImGuiComboFlags flags = ImGuiComboFlags.None)
|
||||
internal static ImRaii.ComboDisposable BeginComboVertical(
|
||||
string label,
|
||||
string previewValue,
|
||||
ImGuiComboFlags flags = ImGuiComboFlags.None
|
||||
)
|
||||
{
|
||||
ImGui.TextUnformatted(label);
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
return ImRaii.Combo($"##{label}", previewValue, flags);
|
||||
}
|
||||
|
||||
internal static bool DragFloatVertical(string label, ref float value, float vSpeed = 1.0f, float vMin = float.MinValue, float vMax = float.MaxValue, string? format = null, ImGuiSliderFlags flags = ImGuiSliderFlags.None)
|
||||
internal static bool DragFloatVertical(
|
||||
string label,
|
||||
ref float value,
|
||||
float vSpeed = 1.0f,
|
||||
float vMin = float.MinValue,
|
||||
float vMax = float.MaxValue,
|
||||
string? format = null,
|
||||
ImGuiSliderFlags flags = ImGuiSliderFlags.None
|
||||
)
|
||||
{
|
||||
ImGui.TextUnformatted(label);
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
return ImGui.DragFloat($"##{label}", ref value, vSpeed, vMin, vMax, format, flags);
|
||||
}
|
||||
|
||||
internal static bool DragFloatVertical(string label, string description, ref float value, float vSpeed = 1.0f, float vMin = float.MinValue, float vMax = float.MaxValue, string? format = null, ImGuiSliderFlags flags = ImGuiSliderFlags.None)
|
||||
internal static bool DragFloatVertical(
|
||||
string label,
|
||||
string description,
|
||||
ref float value,
|
||||
float vSpeed = 1.0f,
|
||||
float vMin = float.MinValue,
|
||||
float vMax = float.MaxValue,
|
||||
string? format = null,
|
||||
ImGuiSliderFlags flags = ImGuiSliderFlags.None
|
||||
)
|
||||
{
|
||||
ImGui.TextUnformatted(label);
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
@@ -324,7 +379,14 @@ internal static class ImGuiUtil
|
||||
return r;
|
||||
}
|
||||
|
||||
internal static bool InputIntVertical(string label, string description, ref int value, int step = 1, int stepFast = 100, ImGuiInputTextFlags flags = ImGuiInputTextFlags.None)
|
||||
internal static bool InputIntVertical(
|
||||
string label,
|
||||
string description,
|
||||
ref int value,
|
||||
int step = 1,
|
||||
int stepFast = 100,
|
||||
ImGuiInputTextFlags flags = ImGuiInputTextFlags.None
|
||||
)
|
||||
{
|
||||
ImGui.TextUnformatted(label);
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
@@ -341,7 +403,14 @@ internal static class ImGuiUtil
|
||||
ImGui.TextUnformatted(tooltip);
|
||||
}
|
||||
|
||||
public static SingleFontChooserDialog? FontChooser(string label, SingleFontSpec font, bool checkbox, ref bool checkboxValue, Predicate<IFontFamilyId>? exclusion = null, string? preview = null)
|
||||
public static SingleFontChooserDialog? FontChooser(
|
||||
string label,
|
||||
SingleFontSpec font,
|
||||
bool checkbox,
|
||||
ref bool checkboxValue,
|
||||
Predicate<IFontFamilyId>? exclusion = null,
|
||||
string? preview = null
|
||||
)
|
||||
{
|
||||
using var id = ImRaii.PushId(label);
|
||||
|
||||
@@ -360,7 +429,7 @@ internal static class ImGuiUtil
|
||||
if (!ImGui.Button($"{buttonText}##{label}"))
|
||||
return null;
|
||||
|
||||
var chooser = SingleFontChooserDialog.CreateAuto((UiBuilder) Plugin.Interface.UiBuilder);
|
||||
var chooser = SingleFontChooserDialog.CreateAuto((UiBuilder)Plugin.Interface.UiBuilder);
|
||||
chooser.SelectedFont = font;
|
||||
if (exclusion is not null)
|
||||
chooser.FontFamilyExcludeFilter = exclusion;
|
||||
@@ -445,7 +514,19 @@ internal static class ImGuiUtil
|
||||
|
||||
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)
|
||||
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 (!vk.TryToImGui(out var imKey) || !ImGui.IsKeyPressed(imKey))
|
||||
@@ -466,7 +547,15 @@ internal static class ImGuiUtil
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawArrows(ref int selected, int min, int max, float spacing, int id = 0, string? tooltipLeft = null, string? tooltipRight = null)
|
||||
public static void DrawArrows(
|
||||
ref int selected,
|
||||
int min,
|
||||
int max,
|
||||
float spacing,
|
||||
int id = 0,
|
||||
string? tooltipLeft = null,
|
||||
string? tooltipRight = null
|
||||
)
|
||||
{
|
||||
// Prevents changing values from triggering EndDisable
|
||||
var isMin = selected == min;
|
||||
@@ -486,7 +575,7 @@ internal static class ImGuiUtil
|
||||
|
||||
using (ImRaii.Disabled(isMax))
|
||||
{
|
||||
if (IconButton(FontAwesomeIcon.ArrowRight, id+1.ToString()))
|
||||
if (IconButton(FontAwesomeIcon.ArrowRight, id + 1.ToString()))
|
||||
selected++;
|
||||
}
|
||||
|
||||
@@ -503,7 +592,9 @@ internal static class ImGuiUtil
|
||||
public static void CenterText(string text, float indent = 0.0f)
|
||||
{
|
||||
indent *= ImGuiHelpers.GlobalScale;
|
||||
ImGui.SameLine(((ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize(text).X) * 0.5f) + indent);
|
||||
ImGui.SameLine(
|
||||
((ImGui.GetContentRegionAvail().X - ImGui.CalcTextSize(text).X) * 0.5f) + indent
|
||||
);
|
||||
ImGui.TextUnformatted(text);
|
||||
}
|
||||
|
||||
@@ -624,7 +715,10 @@ internal static class ImGuiUtil
|
||||
return result != 0 || key == VirtualKey.NO_KEY;
|
||||
}
|
||||
|
||||
public static void ChannelSelector(string headerText, Dictionary<ChatType, (ChatSource Source, ChatSource Target)> chatCodes)
|
||||
public static void ChannelSelector(
|
||||
string headerText,
|
||||
Dictionary<ChatType, (ChatSource Source, ChatSource Target)> chatCodes
|
||||
)
|
||||
{
|
||||
var spacing = 3.0f * ImGuiHelpers.GlobalScale;
|
||||
|
||||
@@ -710,7 +804,11 @@ internal static class ImGuiUtil
|
||||
}
|
||||
}
|
||||
|
||||
public static void ExtraChatSelector(string headerText, ref bool all, HashSet<Guid> extraChatChannels)
|
||||
public static void ExtraChatSelector(
|
||||
string headerText,
|
||||
ref bool all,
|
||||
HashSet<Guid> extraChatChannels
|
||||
)
|
||||
{
|
||||
if (Plugin.ExtraChat.ChannelNames.Count <= 0)
|
||||
return;
|
||||
|
||||
@@ -25,10 +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()
|
||||
=> $"X: {X} Y: {Y} Width: {Width} Height: {Height}";
|
||||
public override string ToString() => $"X: {X} Y: {Y} Width: {Width} Height: {Height}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -43,7 +43,9 @@ public static class MathUtil
|
||||
// overlap on both axes. The previous nested ValueInRange approach
|
||||
// used strict inequalities at both ends, which dropped identical
|
||||
// rectangles and shared-edge cases as false negatives.
|
||||
return a.X < b.X + b.Width && a.X + a.Width > b.X &&
|
||||
a.Y < b.Y + b.Height && a.Y + a.Height > b.Y;
|
||||
return a.X < b.X + b.Width
|
||||
&& a.X + a.Width > b.X
|
||||
&& a.Y < b.Y + b.Height
|
||||
&& a.Y + a.Height > b.Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,25 +15,33 @@ public static class MemoryUtil
|
||||
if (address == nint.Zero)
|
||||
throw new ArgumentException("Memory address cannot be zero.", nameof(address));
|
||||
if (length <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), length, "Length must be positive.");
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(length),
|
||||
length,
|
||||
"Length must be positive."
|
||||
);
|
||||
if (length > MaxDumpLength)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), length, $"Length exceeds the {MaxDumpLength}-byte safety cap.");
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(length),
|
||||
length,
|
||||
$"Length exceeds the {MaxDumpLength}-byte safety cap."
|
||||
);
|
||||
|
||||
var ptr = (byte*)address;
|
||||
var str = new StringBuilder("\n");
|
||||
for(var i = 0; i < length; i++)
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
str.Append($"{ptr![i]:X02}");
|
||||
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
if ((i+1) % 16 == 0)
|
||||
if ((i + 1) % 16 == 0)
|
||||
str.Append('\n');
|
||||
else if ((i+1) % 4 == 0)
|
||||
else if ((i + 1) % 4 == 0)
|
||||
str.Append(' ');
|
||||
}
|
||||
|
||||
Plugin.Log.Information(str.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace HellionChat.Util;
|
||||
|
||||
internal class PartyFinderPayload : Payload
|
||||
{
|
||||
public override PayloadType Type => (PayloadType) 0x50;
|
||||
public override PayloadType Type => (PayloadType)0x50;
|
||||
|
||||
internal uint Id { get; }
|
||||
|
||||
@@ -26,7 +26,7 @@ internal class PartyFinderPayload : Payload
|
||||
|
||||
internal class AchievementPayload : Payload
|
||||
{
|
||||
public override PayloadType Type => (PayloadType) 0x51;
|
||||
public override PayloadType Type => (PayloadType)0x51;
|
||||
|
||||
internal uint Id { get; }
|
||||
|
||||
@@ -46,10 +46,9 @@ internal class AchievementPayload : Payload
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class UriPayload(Uri uri) : Payload
|
||||
{
|
||||
public override PayloadType Type => (PayloadType) 0x52;
|
||||
public override PayloadType Type => (PayloadType)0x52;
|
||||
|
||||
public Uri Uri { get; } = uri;
|
||||
|
||||
@@ -92,7 +91,7 @@ internal class UriPayload(Uri uri) : Payload
|
||||
|
||||
internal class EmotePayload : Payload
|
||||
{
|
||||
public override PayloadType Type => (PayloadType) 0x53;
|
||||
public override PayloadType Type => (PayloadType)0x53;
|
||||
|
||||
public string Code = string.Empty;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface.Utility;
|
||||
using System.Collections;
|
||||
using System.Numerics;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using System.Collections;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
|
||||
namespace HellionChat.Util;
|
||||
@@ -15,7 +15,6 @@ public static class SearchSelector
|
||||
private static string PrevSearchId = null!;
|
||||
private static Type PrevSearchType = null!;
|
||||
|
||||
|
||||
public record SelectorOptions
|
||||
{
|
||||
public Func<string, string> FormatRow { get; init; } = row => row.ToString();
|
||||
@@ -25,14 +24,18 @@ public static class SearchSelector
|
||||
public Vector2? Size { get; init; } = null;
|
||||
}
|
||||
|
||||
public record SelectorPopupOptions: SelectorOptions
|
||||
public record SelectorPopupOptions : SelectorOptions
|
||||
{
|
||||
public ImGuiPopupFlags PopupFlags { get; init; } = ImGuiPopupFlags.None;
|
||||
public bool CloseOnSelection { get; init; } = false;
|
||||
public Func<string, bool> IsSelected { get; init; } = _ => false;
|
||||
}
|
||||
|
||||
private static void SearchInput(string id, IEnumerable<string> filteredSheet, Func<string, string, bool> searchPredicate)
|
||||
private static void SearchInput(
|
||||
string id,
|
||||
IEnumerable<string> filteredSheet,
|
||||
Func<string, string, bool> searchPredicate
|
||||
)
|
||||
{
|
||||
if (ImGui.IsWindowAppearing() && ImGui.IsWindowFocused() && !ImGui.IsAnyItemActive())
|
||||
{
|
||||
@@ -51,13 +54,28 @@ public static class SearchSelector
|
||||
ImGui.SetKeyboardFocusHere(0);
|
||||
}
|
||||
|
||||
if (ImGui.InputTextWithHint("##ExcelSheetSearch", "Search", ref SheetSearchText, 128, ImGuiInputTextFlags.AutoSelectAll))
|
||||
if (
|
||||
ImGui.InputTextWithHint(
|
||||
"##ExcelSheetSearch",
|
||||
"Search",
|
||||
ref SheetSearchText,
|
||||
128,
|
||||
ImGuiInputTextFlags.AutoSelectAll
|
||||
)
|
||||
)
|
||||
FilteredSearchSheet = null;
|
||||
|
||||
FilteredSearchSheet ??= filteredSheet.Where(s => searchPredicate(s, SheetSearchText)).ToArray();
|
||||
FilteredSearchSheet ??= filteredSheet
|
||||
.Where(s => searchPredicate(s, SheetSearchText))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static bool SelectorPopup(string id, out string selected, SelectorPopupOptions? options = null, bool close = false)
|
||||
public static bool SelectorPopup(
|
||||
string id,
|
||||
out string selected,
|
||||
SelectorPopupOptions? options = null,
|
||||
bool close = false
|
||||
)
|
||||
{
|
||||
options ??= new SelectorPopupOptions();
|
||||
var sheet = options.FilteredSheet;
|
||||
@@ -71,14 +89,26 @@ public static class SearchSelector
|
||||
if (!popup.Success)
|
||||
return false;
|
||||
|
||||
SearchInput(id, sheet, options.SearchPredicate ?? ((row, s) => options.FormatRow(row).Contains(s, StringComparison.CurrentCultureIgnoreCase)));
|
||||
SearchInput(
|
||||
id,
|
||||
sheet,
|
||||
options.SearchPredicate
|
||||
?? (
|
||||
(row, s) =>
|
||||
options
|
||||
.FormatRow(row)
|
||||
.Contains(s, StringComparison.CurrentCultureIgnoreCase)
|
||||
)
|
||||
);
|
||||
|
||||
using var child = ImRaii.Child("SearchList", Vector2.Zero, true);
|
||||
if (!child.Success)
|
||||
return false;
|
||||
|
||||
var ret = false;
|
||||
var drawSelectable = options.DrawSelectable ?? ((row, selected) => ImGui.Selectable(options.FormatRow(row), selected));
|
||||
var drawSelectable =
|
||||
options.DrawSelectable
|
||||
?? ((row, selected) => ImGui.Selectable(options.FormatRow(row), selected));
|
||||
using (var clipper = new ListClipper(FilteredSearchSheet!.Length))
|
||||
{
|
||||
foreach (var i in clipper.Rows)
|
||||
@@ -139,7 +169,10 @@ public unsafe class ListClipper : IEnumerable<(int, int)>, IDisposable
|
||||
{
|
||||
get
|
||||
{
|
||||
var cols = (ItemRemainder == 0 || CurrentRows != DisplayEnd || CurrentRow != DisplayEnd - 1) ? CurrentColumns : ItemRemainder;
|
||||
var cols =
|
||||
(ItemRemainder == 0 || CurrentRows != DisplayEnd || CurrentRow != DisplayEnd - 1)
|
||||
? CurrentColumns
|
||||
: ItemRemainder;
|
||||
for (var j = 0; j < cols; j++)
|
||||
yield return j;
|
||||
}
|
||||
@@ -155,7 +188,8 @@ public unsafe class ListClipper : IEnumerable<(int, int)>, IDisposable
|
||||
Clipper.Begin(CurrentRows, itemHeight);
|
||||
}
|
||||
|
||||
public IEnumerator<(int, int)> GetEnumerator() => (from i in Rows from j in Columns select (i, j)).GetEnumerator();
|
||||
public IEnumerator<(int, int)> GetEnumerator() =>
|
||||
(from i in Rows from j in Columns select (i, j)).GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@ internal static class StringUtil
|
||||
// "0.#" keeps the rounded fractional digit (1.5 GB stays "1.5GB"); "N0"
|
||||
// would truncate it back to integer. InvariantCulture pins the decimal
|
||||
// separator to '.' so a German locale doesn't render "1,5GB".
|
||||
return (Math.Sign(byteCount) * num).ToString("0.#", CultureInfo.InvariantCulture) + suf[place];
|
||||
return (Math.Sign(byteCount) * num).ToString("0.#", CultureInfo.InvariantCulture)
|
||||
+ suf[place];
|
||||
}
|
||||
|
||||
// Returns the text unchanged when it already fits the width budget,
|
||||
|
||||
+137
-125
@@ -20,149 +20,161 @@ public static class TabsUtil
|
||||
// events (loot, crafting, gathering, NPC dialogue, PF pings) move to
|
||||
// the System tab where they belong — keeps the General view focused
|
||||
// on actual conversation in the immediate surroundings.
|
||||
public static Tab VanillaGeneral => new()
|
||||
{
|
||||
Name = Language.Tabs_Presets_General,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
public static Tab VanillaGeneral =>
|
||||
new()
|
||||
{
|
||||
[ChatType.Say] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Yell] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Shout] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
}
|
||||
};
|
||||
Name = Language.Tabs_Presets_General,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
{
|
||||
[ChatType.Say] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Yell] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Shout] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
};
|
||||
|
||||
public static Tab VanillaEvent => new()
|
||||
{
|
||||
Name = Language.Tabs_Presets_Event,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)> { [ChatType.NpcDialogue] = (ChatSourceExt.All, ChatSourceExt.All), },
|
||||
};
|
||||
|
||||
public static Tab VanillaTellExclusive => new()
|
||||
{
|
||||
Name = Language.Tabs_Presets_Tell,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
public static Tab VanillaEvent =>
|
||||
new()
|
||||
{
|
||||
[ChatType.TellIncoming] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.TellOutgoing] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
Channel = InputChannel.Tell,
|
||||
AllSenderMessages = true,
|
||||
};
|
||||
Name = Language.Tabs_Presets_Event,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
{
|
||||
[ChatType.NpcDialogue] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
};
|
||||
|
||||
public static Tab VanillaTellExclusive =>
|
||||
new()
|
||||
{
|
||||
Name = Language.Tabs_Presets_Tell,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
{
|
||||
[ChatType.TellIncoming] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.TellOutgoing] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
Channel = InputChannel.Tell,
|
||||
AllSenderMessages = true,
|
||||
};
|
||||
|
||||
// Hellion default-tab presets used by the v10 wipe migration. Names are
|
||||
// kept in HellionStrings (EN+DE) instead of Language.* so the upstream
|
||||
// resource files stay untouched. Channel selections cover the channels
|
||||
// a typical Eorzea raider uses without forcing the user to hand-tick
|
||||
// each box on first start.
|
||||
public static Tab HellionFreeCompany => new()
|
||||
{
|
||||
Name = HellionStrings.Tabs_Presets_FreeCompany,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
public static Tab HellionFreeCompany =>
|
||||
new()
|
||||
{
|
||||
[ChatType.FreeCompany] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.FreeCompanyAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
Channel = InputChannel.FreeCompany,
|
||||
};
|
||||
Name = HellionStrings.Tabs_Presets_FreeCompany,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
{
|
||||
[ChatType.FreeCompany] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.FreeCompanyAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
Channel = InputChannel.FreeCompany,
|
||||
};
|
||||
|
||||
public static Tab HellionParty => new()
|
||||
{
|
||||
Name = HellionStrings.Tabs_Presets_Party,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
public static Tab HellionParty =>
|
||||
new()
|
||||
{
|
||||
[ChatType.Party] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossParty] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Alliance] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PvpTeam] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PvpTeamAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.LootNotice] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.LootRoll] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
// No automatic input-channel switch; the Gruppe tab is a read
|
||||
// surface that pulls in Party, CrossParty, Alliance and PvpTeam
|
||||
// together. Auto-routing /party into this tab would surprise the
|
||||
// user when they actually wanted /alliance or /pvpteam.
|
||||
};
|
||||
Name = HellionStrings.Tabs_Presets_Party,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
{
|
||||
[ChatType.Party] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossParty] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Alliance] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PvpTeam] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PvpTeamAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.LootNotice] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.LootRoll] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
// No automatic input-channel switch; the Gruppe tab is a read
|
||||
// surface that pulls in Party, CrossParty, Alliance and PvpTeam
|
||||
// together. Auto-routing /party into this tab would surprise the
|
||||
// user when they actually wanted /alliance or /pvpteam.
|
||||
};
|
||||
|
||||
public static Tab HellionBeginner => new()
|
||||
{
|
||||
Name = HellionStrings.Tabs_Presets_Beginner,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
public static Tab HellionBeginner =>
|
||||
new()
|
||||
{
|
||||
[ChatType.NoviceNetwork] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.NoviceNetworkSystem] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
Channel = InputChannel.NoviceNetwork,
|
||||
};
|
||||
Name = HellionStrings.Tabs_Presets_Beginner,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
{
|
||||
[ChatType.NoviceNetwork] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.NoviceNetworkSystem] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
Channel = InputChannel.NoviceNetwork,
|
||||
};
|
||||
|
||||
public static Tab HellionSystem => new()
|
||||
{
|
||||
Name = HellionStrings.Tabs_Presets_System,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
public static Tab HellionSystem =>
|
||||
new()
|
||||
{
|
||||
// Plain system noise
|
||||
[ChatType.Debug] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Urgent] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Notice] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.System] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Error] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Echo] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.GatheringSystem] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.NoviceNetworkSystem] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.BattleSystem] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
// Login / logout / announcement noise
|
||||
[ChatType.NpcAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.FreeCompanyAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PvpTeamAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.RetainerSale] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PeriodicRecruitmentNotification] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
// Gameplay-event streams (moved out of General in v1.0.0)
|
||||
[ChatType.NpcDialogue] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.LootNotice] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.LootRoll] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Crafting] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Gathering] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
// Misc
|
||||
[ChatType.Progress] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.RandomNumber] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Orchestrion] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.MessageBook] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Alarm] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Sign] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.GlamourNotifications] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
};
|
||||
Name = HellionStrings.Tabs_Presets_System,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
{
|
||||
// Plain system noise
|
||||
[ChatType.Debug] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Urgent] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Notice] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.System] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Error] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Echo] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.GatheringSystem] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.NoviceNetworkSystem] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.BattleSystem] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
// Login / logout / announcement noise
|
||||
[ChatType.NpcAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.FreeCompanyAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PvpTeamAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.RetainerSale] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.PeriodicRecruitmentNotification] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
// Gameplay-event streams (moved out of General in v1.0.0)
|
||||
[ChatType.NpcDialogue] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.LootNotice] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.LootRoll] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Crafting] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Gathering] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
// Misc
|
||||
[ChatType.Progress] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.RandomNumber] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Orchestrion] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.MessageBook] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Alarm] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Sign] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.GlamourNotifications] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
};
|
||||
|
||||
public static Tab HellionLinkshell => new()
|
||||
{
|
||||
Name = HellionStrings.Tabs_Presets_Linkshell,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
public static Tab HellionLinkshell =>
|
||||
new()
|
||||
{
|
||||
[ChatType.Linkshell1] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell2] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell3] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell4] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell5] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell6] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell7] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell8] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell1] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell2] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell3] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell4] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell5] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell6] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell7] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell8] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
};
|
||||
Name = HellionStrings.Tabs_Presets_Linkshell,
|
||||
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
|
||||
{
|
||||
[ChatType.Linkshell1] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell2] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell3] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell4] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell5] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell6] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell7] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Linkshell8] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell1] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell2] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell3] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell4] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell5] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell6] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell7] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.CrossLinkshell8] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
},
|
||||
};
|
||||
|
||||
public static Dictionary<ChatType, (ChatSource, ChatSource)> MostlyPlayer => new()
|
||||
{
|
||||
public static Dictionary<ChatType, (ChatSource, ChatSource)> MostlyPlayer =>
|
||||
new()
|
||||
{
|
||||
// Special
|
||||
[ChatType.Debug] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.Urgent] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
@@ -208,5 +220,5 @@ public static class TabsUtil
|
||||
[ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.RandomNumber] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
[ChatType.MessageBook] = (ChatSourceExt.All, ChatSourceExt.All),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,12 +19,13 @@ public static class Tokenizer
|
||||
UrlString,
|
||||
StringValue,
|
||||
Leftover,
|
||||
SequenceTerminator
|
||||
SequenceTerminator,
|
||||
}
|
||||
|
||||
public class Token(TokenType tokenType, string value)
|
||||
{
|
||||
public Token(TokenType tokenType) : this(tokenType, string.Empty) { }
|
||||
public Token(TokenType tokenType)
|
||||
: this(tokenType, string.Empty) { }
|
||||
|
||||
public TokenType TokenType { get; } = tokenType;
|
||||
public string Value { get; } = value;
|
||||
@@ -49,7 +50,7 @@ public static class Tokenizer
|
||||
new TokenDefinition(TokenType.OpenParenthesis, "\\(", 1),
|
||||
new TokenDefinition(TokenType.UrlString, UrlRegex, 1),
|
||||
new TokenDefinition(TokenType.StringValue, "\\p{IsBasicLatin}", 2),
|
||||
new TokenDefinition(TokenType.Leftover, ".", 3)
|
||||
new TokenDefinition(TokenType.Leftover, ".", 3),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -57,7 +58,8 @@ public static class Tokenizer
|
||||
{
|
||||
var tokenMatches = FindTokenMatches(lqlText);
|
||||
|
||||
var groupedByIndex = tokenMatches.GroupBy(x => x.StartIndex)
|
||||
var groupedByIndex = tokenMatches
|
||||
.GroupBy(x => x.StartIndex)
|
||||
.OrderBy(x => x.Key)
|
||||
.ToList();
|
||||
|
||||
@@ -97,7 +99,7 @@ public static class Tokenizer
|
||||
{
|
||||
Type = returnsToken;
|
||||
Precedence = precedence;
|
||||
Regex = new Regex(regexPattern, RegexOptions.IgnoreCase|RegexOptions.Compiled);
|
||||
Regex = new Regex(regexPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
}
|
||||
|
||||
public TokenDefinition(TokenType returnsToken, Regex regex, int precedence)
|
||||
@@ -110,7 +112,7 @@ public static class Tokenizer
|
||||
public IEnumerable<TokenMatch> FindMatches(string inputString)
|
||||
{
|
||||
var matches = Regex.Matches(inputString);
|
||||
for(var i = 0; i < matches.Count; i++)
|
||||
for (var i = 0; i < matches.Count; i++)
|
||||
{
|
||||
yield return new TokenMatch
|
||||
{
|
||||
@@ -118,7 +120,7 @@ public static class Tokenizer
|
||||
EndIndex = matches[i].Index + matches[i].Length,
|
||||
TokenType = Type,
|
||||
Value = matches[i].Value,
|
||||
Precedence = Precedence
|
||||
Precedence = Precedence,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -149,4 +151,4 @@ public static class Tokenizer
|
||||
@"(?<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,5 @@
|
||||
using HellionChat.Resources;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using HellionChat.Resources;
|
||||
|
||||
namespace HellionChat.Util;
|
||||
|
||||
@@ -7,7 +7,14 @@ public static class WrapperUtil
|
||||
{
|
||||
public static void AddNotification(string content, NotificationType type, bool minimized = true)
|
||||
{
|
||||
Plugin.Notification.AddNotification(new Notification { Content = content, Type = type, Minimized = minimized });
|
||||
Plugin.Notification.AddNotification(
|
||||
new Notification
|
||||
{
|
||||
Content = content,
|
||||
Type = type,
|
||||
Minimized = minimized,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static void TryOpenUri(Uri uri)
|
||||
@@ -23,4 +30,4 @@ public static class WrapperUtil
|
||||
AddNotification(Language.Context_OpenInBrowserError, NotificationType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user