diff --git a/LightlessSync/LightlessSync.csproj b/LightlessSync/LightlessSync.csproj
index fcbddb7..5ec5e78 100644
--- a/LightlessSync/LightlessSync.csproj
+++ b/LightlessSync/LightlessSync.csproj
@@ -31,7 +31,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -39,13 +39,13 @@
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs
index 2a962a6..cd758f5 100644
--- a/LightlessSync/UI/CompactUI.cs
+++ b/LightlessSync/UI/CompactUI.cs
@@ -629,8 +629,9 @@ public class CompactUi : WindowMediatorSubscriberBase
{
var seString = SeStringUtils.BuildFormattedPlayerName(uidText, vanityTextColor, vanityGlowColor);
var cursorPos = ImGui.GetCursorScreenPos();
- var fontPtr = ImGui.GetFont();
- SeStringUtils.RenderSeStringWithHitbox(seString, cursorPos, fontPtr, "uid-header");
+ var targetFontSize = ImGui.GetFontSize();
+ var font = ImGui.GetFont();
+ SeStringUtils.RenderSeStringWithHitbox(seString, cursorPos, targetFontSize ,font , "uid-header");
}
else
{
@@ -716,8 +717,9 @@ public class CompactUi : WindowMediatorSubscriberBase
{
var seString = SeStringUtils.BuildFormattedPlayerName(_apiController.UID, vanityTextColor, vanityGlowColor);
var cursorPos = ImGui.GetCursorScreenPos();
- var fontPtr = ImGui.GetFont();
- SeStringUtils.RenderSeStringWithHitbox(seString, cursorPos, fontPtr, "uid-footer");
+ var targetFontSize = ImGui.GetFontSize();
+ var font = ImGui.GetFont();
+ SeStringUtils.RenderSeStringWithHitbox(seString, cursorPos, targetFontSize, font, "uid-footer");
}
else
{
diff --git a/LightlessSync/UI/EditProfileUi.Group.cs b/LightlessSync/UI/EditProfileUi.Group.cs
index ee6a329..7b47ced 100644
--- a/LightlessSync/UI/EditProfileUi.Group.cs
+++ b/LightlessSync/UI/EditProfileUi.Group.cs
@@ -332,7 +332,7 @@ public partial class EditProfileUi
saveTooltip: "Apply the selected tags to this syncshell profile.",
submitAction: payload => SubmitGroupTagChanges(payload),
allowReorder: true,
- sortPayloadBeforeSubmit: true,
+ sortPayloadBeforeSubmit: false,
onPayloadPrepared: payload =>
{
_tagEditorSelection.Clear();
@@ -586,7 +586,7 @@ public partial class EditProfileUi
IsNsfw: null,
IsDisabled: null)).ConfigureAwait(false);
- _profileTagIds = payload.Length == 0 ? Array.Empty() : payload.ToArray();
+ _profileTagIds = payload.Length == 0 ? [] : [.. payload];
Mediator.Publish(new ClearProfileGroupDataMessage(_groupInfo.Group));
}
catch (Exception ex)
diff --git a/LightlessSync/UI/Handlers/IdDisplayHandler.cs b/LightlessSync/UI/Handlers/IdDisplayHandler.cs
index b31b145..74a6571 100644
--- a/LightlessSync/UI/Handlers/IdDisplayHandler.cs
+++ b/LightlessSync/UI/Handlers/IdDisplayHandler.cs
@@ -122,6 +122,7 @@ public class IdDisplayHandler
if (!string.Equals(_editEntry, pair.UserData.UID, StringComparison.Ordinal))
{
+ var targetFontSize = ImGui.GetFontSize();
var font = textIsUid ? UiBuilder.MonoFont : ImGui.GetFont();
var rowWidth = MathF.Max(editBoxWidth.Invoke(), 0f);
float rowRightLimit = 0f;
@@ -183,7 +184,7 @@ public class IdDisplayHandler
}
}
- SeStringUtils.RenderSeStringWithHitbox(seString, rowStart, font, pair.UserData.UID);
+ SeStringUtils.RenderSeStringWithHitbox(seString, rowStart, targetFontSize, font, pair.UserData.UID);
nameRectMin = ImGui.GetItemRectMin();
nameRectMax = ImGui.GetItemRectMax();
diff --git a/LightlessSync/UI/ZoneChatUi.cs b/LightlessSync/UI/ZoneChatUi.cs
index e7574e8..6944759 100644
--- a/LightlessSync/UI/ZoneChatUi.cs
+++ b/LightlessSync/UI/ZoneChatUi.cs
@@ -44,6 +44,8 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
private float _currentWindowOpacity = DefaultWindowOpacity;
private bool _isWindowPinned;
private bool _showRulesOverlay;
+ private bool _refocusChatInput;
+ private string? _refocusChatInputKey;
private string? _selectedChannelKey;
private bool _scrollToBottom = true;
@@ -308,46 +310,60 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
_draftMessages.TryGetValue(channel.Key, out var draft);
draft ??= string.Empty;
+ var style = ImGui.GetStyle();
+ var sendButtonWidth = 100f * ImGuiHelpers.GlobalScale;
+ var counterWidth = ImGui.CalcTextSize($"{MaxMessageLength}/{MaxMessageLength}").X;
+ var reservedWidth = sendButtonWidth + counterWidth + style.ItemSpacing.X * 2f;
+
+ ImGui.SetNextItemWidth(-reservedWidth);
+ var inputId = $"##chat-input-{channel.Key}";
+ if (_refocusChatInput && string.Equals(_refocusChatInputKey, channel.Key, StringComparison.Ordinal))
+ {
+ ImGui.SetKeyboardFocusHere();
+ _refocusChatInput = false;
+ _refocusChatInputKey = null;
+ }
+ ImGui.InputText(inputId, ref draft, MaxMessageLength);
+ var enterPressed = ImGui.IsItemFocused()
+ && (ImGui.IsKeyPressed(ImGuiKey.Enter) || ImGui.IsKeyPressed(ImGuiKey.KeypadEnter));
+ _draftMessages[channel.Key] = draft;
+
+ ImGui.SameLine();
+ ImGui.AlignTextToFramePadding();
+ ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3);
+ ImGui.TextUnformatted($"{draft.Length}/{MaxMessageLength}");
+ ImGui.PopStyleColor();
+
+ ImGui.SameLine();
+ var buttonScreenPos = ImGui.GetCursorScreenPos();
+ var rightEdgeScreen = ImGui.GetWindowPos().X + ImGui.GetWindowContentRegionMax().X;
+ var desiredButtonX = rightEdgeScreen - sendButtonWidth;
+ var minButtonX = buttonScreenPos.X + style.ItemSpacing.X;
+ var finalButtonX = MathF.Max(minButtonX, desiredButtonX);
+ ImGui.SetCursorScreenPos(new Vector2(finalButtonX, buttonScreenPos.Y));
+ var sendColor = UIColors.Get("LightlessPurpleDefault");
+ var sendHovered = UIColors.Get("LightlessPurple");
+ var sendActive = UIColors.Get("LightlessPurpleActive");
+ ImGui.PushStyleColor(ImGuiCol.Button, sendColor);
+ ImGui.PushStyleColor(ImGuiCol.ButtonHovered, sendHovered);
+ ImGui.PushStyleColor(ImGuiCol.ButtonActive, sendActive);
+ ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 6f * ImGuiHelpers.GlobalScale);
+ var sendClicked = false;
using (ImRaii.Disabled(!canSend))
{
- var style = ImGui.GetStyle();
- var sendButtonWidth = 100f * ImGuiHelpers.GlobalScale;
- var counterWidth = ImGui.CalcTextSize($"{MaxMessageLength}/{MaxMessageLength}").X;
- var reservedWidth = sendButtonWidth + counterWidth + style.ItemSpacing.X * 2f;
-
- ImGui.SetNextItemWidth(-reservedWidth);
- var inputId = $"##chat-input-{channel.Key}";
- var send = ImGui.InputText(inputId, ref draft, MaxMessageLength, ImGuiInputTextFlags.EnterReturnsTrue);
- _draftMessages[channel.Key] = draft;
-
- ImGui.SameLine();
- ImGui.AlignTextToFramePadding();
- ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3);
- ImGui.TextUnformatted($"{draft.Length}/{MaxMessageLength}");
- ImGui.PopStyleColor();
-
- ImGui.SameLine();
- var buttonScreenPos = ImGui.GetCursorScreenPos();
- var rightEdgeScreen = ImGui.GetWindowPos().X + ImGui.GetWindowContentRegionMax().X;
- var desiredButtonX = rightEdgeScreen - sendButtonWidth;
- var minButtonX = buttonScreenPos.X + style.ItemSpacing.X;
- var finalButtonX = MathF.Max(minButtonX, desiredButtonX);
- ImGui.SetCursorScreenPos(new Vector2(finalButtonX, buttonScreenPos.Y));
- var sendColor = UIColors.Get("LightlessPurpleDefault");
- var sendHovered = UIColors.Get("LightlessPurple");
- var sendActive = UIColors.Get("LightlessPurpleActive");
- ImGui.PushStyleColor(ImGuiCol.Button, sendColor);
- ImGui.PushStyleColor(ImGuiCol.ButtonHovered, sendHovered);
- ImGui.PushStyleColor(ImGuiCol.ButtonActive, sendActive);
- ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 6f * ImGuiHelpers.GlobalScale);
- if (_uiSharedService.IconTextButton(FontAwesomeIcon.PaperPlane, "Send", 100f * ImGuiHelpers.GlobalScale, center: true))
+ if (_uiSharedService.IconTextButton(FontAwesomeIcon.PaperPlane, $"Send##chat-send-{channel.Key}", 100f * ImGuiHelpers.GlobalScale, center: true))
{
- send = true;
+ sendClicked = true;
}
- ImGui.PopStyleVar();
- ImGui.PopStyleColor(3);
+ }
+ ImGui.PopStyleVar();
+ ImGui.PopStyleColor(3);
- if (send && TrySendDraft(channel, draft))
+ if (canSend && (enterPressed || sendClicked))
+ {
+ _refocusChatInput = true;
+ _refocusChatInputKey = channel.Key;
+ if (TrySendDraft(channel, draft))
{
_draftMessages[channel.Key] = string.Empty;
_scrollToBottom = true;
@@ -969,6 +985,12 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
_draftMessages.Remove(key);
}
}
+
+ if (_refocusChatInputKey is not null && !existingKeys.Contains(_refocusChatInputKey))
+ {
+ _refocusChatInputKey = null;
+ _refocusChatInput = false;
+ }
}
private void DrawConnectionControls()
diff --git a/LightlessSync/Utils/SeStringUtils.cs b/LightlessSync/Utils/SeStringUtils.cs
index 810cbe7..2188d91 100644
--- a/LightlessSync/Utils/SeStringUtils.cs
+++ b/LightlessSync/Utils/SeStringUtils.cs
@@ -559,17 +559,11 @@ public static class SeStringUtils
ImGui.Dummy(new Vector2(0f, textSize.Y));
}
+
public static Vector2 RenderSeStringWithHitbox(DalamudSeString seString, Vector2 position, ImFontPtr? font = null, string? id = null)
{
var drawList = ImGui.GetWindowDrawList();
var usedFont = font ?? UiBuilder.MonoFont;
- var drawParams = new SeStringDrawParams
- {
- Font = usedFont,
- Color = 0xFFFFFFFF,
- WrapWidth = float.MaxValue,
- TargetDrawList = drawList
- };
var textSize = ImGui.CalcTextSize(seString.TextValue);
if (textSize.Y <= 0f)
@@ -584,11 +578,17 @@ public static class SeStringUtils
var verticalOffset = MathF.Max((hitboxHeight - textSize.Y) * 0.5f, 0f);
var drawPos = new Vector2(position.X, position.Y + verticalOffset);
- ImGui.SetCursorScreenPos(drawPos);
+ var drawParams = new SeStringDrawParams
+ {
+ FontSize = usedFont.FontSize,
+ ScreenOffset = drawPos,
+ Font = usedFont,
+ Color = 0xFFFFFFFF,
+ WrapWidth = float.MaxValue,
+ TargetDrawList = drawList
+ };
- drawParams.ScreenOffset = drawPos;
- drawParams.Font = usedFont;
- drawParams.FontSize = usedFont.FontSize;
+ ImGui.SetCursorScreenPos(drawPos);
ImGuiHelpers.SeStringWrapped(seString.Encode(), drawParams);
@@ -614,6 +614,64 @@ public static class SeStringUtils
return new Vector2(textSize.X, hitboxHeight);
}
+ public static Vector2 RenderSeStringWithHitbox(DalamudSeString seString, Vector2 position, float? targetFontSize, ImFontPtr? font = null, string? id = null)
+ {
+ var drawList = ImGui.GetWindowDrawList();
+ var usedFont = font ?? ImGui.GetFont();
+
+ ImGui.PushFont(usedFont);
+ Vector2 rawSize;
+ float usedEffectiveSize;
+ try
+ {
+ usedEffectiveSize = ImGui.GetFontSize();
+ rawSize = ImGui.CalcTextSize(seString.TextValue);
+ }
+ finally
+ {
+ ImGui.PopFont();
+ }
+
+ var desiredSize = targetFontSize ?? usedEffectiveSize;
+ var scale = usedEffectiveSize > 0 ? (desiredSize / usedEffectiveSize) : 1f;
+
+ var textSize = rawSize * scale;
+
+ var style = ImGui.GetStyle();
+ var frameHeight = desiredSize + style.FramePadding.Y * 2f;
+ var hitboxHeight = MathF.Max(frameHeight, textSize.Y);
+ var verticalOffset = MathF.Max((hitboxHeight - textSize.Y) * 0.5f, 0f);
+
+ var drawPos = new Vector2(position.X, position.Y + verticalOffset);
+
+ var drawParams = new SeStringDrawParams
+ {
+ TargetDrawList = drawList,
+ ScreenOffset = drawPos,
+ Font = usedFont,
+ FontSize = desiredSize,
+ Color = 0xFFFFFFFF,
+ WrapWidth = float.MaxValue,
+ };
+
+ ImGui.SetCursorScreenPos(drawPos);
+ ImGuiHelpers.SeStringWrapped(seString.Encode(), drawParams);
+
+ ImGui.SetCursorScreenPos(position);
+ ImGui.PushID(id ?? Interlocked.Increment(ref _seStringHitboxCounter).ToString());
+
+ try
+ {
+ ImGui.InvisibleButton("##hitbox", new Vector2(textSize.X, hitboxHeight));
+ }
+ finally
+ {
+ ImGui.PopID();
+ }
+
+ return new Vector2(textSize.X, hitboxHeight);
+ }
+
public static Vector2 RenderIconWithHitbox(int iconId, Vector2 position, ImFontPtr? font = null, string? id = null)
{
var drawList = ImGui.GetWindowDrawList();
diff --git a/LightlessSync/packages.lock.json b/LightlessSync/packages.lock.json
index bf2bdfe..47b77e9 100644
--- a/LightlessSync/packages.lock.json
+++ b/LightlessSync/packages.lock.json
@@ -52,9 +52,9 @@
},
"Meziantou.Analyzer": {
"type": "Direct",
- "requested": "[2.0.212, )",
- "resolved": "2.0.212",
- "contentHash": "U91ktjjTRTccUs3Lk+hrLD9vW+2+lhnsOf4G1GpRSJi1pLn3uK5CU6wGP9Bmz1KlJs6Oz1GGoMhxQBoqQsmAuQ=="
+ "requested": "[2.0.264, )",
+ "resolved": "2.0.264",
+ "contentHash": "zRG13RDG446rZNdd/YjKRd4utpbjleRDUqNQSrX0etMnH8Rz9NBlXUpS5aR2ExoOokhNfkdOW8HpLzjLj5x0hQ=="
},
"Microsoft.AspNetCore.SignalR.Client": {
"type": "Direct",
@@ -108,35 +108,35 @@
},
"NReco.Logging.File": {
"type": "Direct",
- "requested": "[1.2.2, )",
- "resolved": "1.2.2",
- "contentHash": "UyUIkyDiHi2HAJlmEWqeKN9/FxTF0DPNdyatzMDMTXvUpgvqBFneJ2qDtZkXRJNG8eR6jU+KsbGeMmChgUdRUg==",
+ "requested": "[1.3.1, )",
+ "resolved": "1.3.1",
+ "contentHash": "4aFUEW1OFJsuKtg46dnqxZUyb37f9dzaWOXjUv2x/wzoHKovR9yqiMzXtCZt3+a9G78YCIAtSEz2g/GaNYbxSQ==",
"dependencies": {
- "Microsoft.Extensions.Logging": "8.0.1",
- "Microsoft.Extensions.Logging.Configuration": "8.0.1",
- "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
+ "Microsoft.Extensions.Logging": "10.0.0",
+ "Microsoft.Extensions.Logging.Configuration": "10.0.0",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "10.0.0"
}
},
"SixLabors.ImageSharp": {
"type": "Direct",
- "requested": "[3.1.11, )",
- "resolved": "3.1.11",
- "contentHash": "JfPLyigLthuE50yi6tMt7Amrenr/fA31t2CvJyhy/kQmfulIBAqo5T/YFUSRHtuYPXRSaUHygFeh6Qd933EoSw=="
+ "requested": "[3.1.12, )",
+ "resolved": "3.1.12",
+ "contentHash": "iAg6zifihXEFS/t7fiHhZBGAdCp3FavsF4i2ZIDp0JfeYeDVzvmlbY1CNhhIKimaIzrzSi5M/NBFcWvZT2rB/A=="
},
"SonarAnalyzer.CSharp": {
"type": "Direct",
- "requested": "[10.7.0.110445, )",
- "resolved": "10.7.0.110445",
- "contentHash": "U4v2LWopxADYkUv7Z5CX7ifKMdDVqHb7a1bzppIQnQi4WQR6z1Zi5rDkCHlVYGEd1U/WMz1IJCU8OmFZLJpVig=="
+ "requested": "[10.17.0.131074, )",
+ "resolved": "10.17.0.131074",
+ "contentHash": "N8agHzX1pK3Xv/fqMig/mHspPAmh/aKkGg7lUC1xfezAhFtPTuRqBjuyas622Tvy5jnsN5zCXJVclvNkfJJ4rQ=="
},
"System.IdentityModel.Tokens.Jwt": {
"type": "Direct",
- "requested": "[8.7.0, )",
- "resolved": "8.7.0",
- "contentHash": "8dKL3A9pVqYCJIXHd4H2epQqLxSvKeNxGonR0e5g89yMchyvsM/NLuB06otx29BicUd6+LUJZgNZmvYjjPsPGg==",
+ "requested": "[8.15.0, )",
+ "resolved": "8.15.0",
+ "contentHash": "dpodi7ixz6hxK8YCBYAWzm0IA8JYXoKcz0hbCbNifo519//rjUI0fBD8rfNr+IGqq+2gm4oQoXwHk09LX5SqqQ==",
"dependencies": {
- "Microsoft.IdentityModel.JsonWebTokens": "8.7.0",
- "Microsoft.IdentityModel.Tokens": "8.7.0"
+ "Microsoft.IdentityModel.JsonWebTokens": "8.15.0",
+ "Microsoft.IdentityModel.Tokens": "8.15.0"
}
},
"YamlDotNet": {
@@ -490,32 +490,32 @@
},
"Microsoft.IdentityModel.Abstractions": {
"type": "Transitive",
- "resolved": "8.7.0",
- "contentHash": "OQd5aVepYvh5evOmBMeAYjMIpEcTf1ZCBZaU7Nh/RlhhdXefjFDJeP1L2F2zeNT1unFr+wUu/h3Ac2Xb4BXU6w=="
+ "resolved": "8.15.0",
+ "contentHash": "e/DApa1GfxUqHSBHcpiQg8yaghKAvFVBQFcWh25jNoRobDZbduTUACY8bZ54eeGWXvimGmEDdF0zkS5Dq16XPQ=="
},
"Microsoft.IdentityModel.JsonWebTokens": {
"type": "Transitive",
- "resolved": "8.7.0",
- "contentHash": "uzsSAWhNhbrkWbQKBTE8QhzviU6sr3bJ1Bkv7gERlhswfSKOp7HsxTRLTPBpx/whQ/GRRHEwMg8leRIPbMrOgw==",
+ "resolved": "8.15.0",
+ "contentHash": "3513f5VzvOZy3ELd42wGnh1Q3e83tlGAuXFSNbENpgWYoAhLLzgFtd5PiaOPGAU0gqKhYGVzKavghLUGfX3HQg==",
"dependencies": {
- "Microsoft.IdentityModel.Tokens": "8.7.0"
+ "Microsoft.IdentityModel.Tokens": "8.15.0"
}
},
"Microsoft.IdentityModel.Logging": {
"type": "Transitive",
- "resolved": "8.7.0",
- "contentHash": "Bs0TznPAu+nxa9rAVHJ+j3CYECHJkT3tG8AyBfhFYlT5ldsDhoxFT7J+PKxJHLf+ayqWfvDZHHc4639W2FQCxA==",
+ "resolved": "8.15.0",
+ "contentHash": "1gJLjhy0LV2RQMJ9NGzi5Tnb2l+c37o8D8Lrk2mrvmb6OQHZ7XJstd/XxvncXgBpad4x9CGXdipbZzJJCXKyAg==",
"dependencies": {
- "Microsoft.IdentityModel.Abstractions": "8.7.0"
+ "Microsoft.IdentityModel.Abstractions": "8.15.0"
}
},
"Microsoft.IdentityModel.Tokens": {
"type": "Transitive",
- "resolved": "8.7.0",
- "contentHash": "5Z6voXjRXAnGklhmZd1mKz89UhcF5ZQQZaZc2iKrOuL4Li1UihG2vlJx8IbiFAOIxy/xdbsAm0A+WZEaH5fxng==",
+ "resolved": "8.15.0",
+ "contentHash": "zUE9ysJXBtXlHHRtcRK3Sp8NzdCI1z/BRDTXJQ2TvBoI0ENRtnufYIep0O5TSCJRJGDwwuLTUx+l/bEYZUxpCA==",
"dependencies": {
- "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
- "Microsoft.IdentityModel.Logging": "8.7.0"
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.0",
+ "Microsoft.IdentityModel.Logging": "8.15.0"
}
},
"Microsoft.NET.StringTools": {
@@ -619,7 +619,7 @@
"FlatSharp.Runtime": "[7.9.0, )",
"OtterGui": "[1.0.0, )",
"Penumbra.Api": "[5.13.0, )",
- "Penumbra.String": "[1.0.6, )"
+ "Penumbra.String": "[1.0.7, )"
}
},
"penumbra.string": {