Chat changes for 2.0.3 (#134)
Co-authored-by: azyges <aaaaaa@aaa.aaa> Co-authored-by: cake <admin@cakeandbanana.nl> Reviewed-on: #134 Reviewed-by: defnotken <defnotken@noreply.git.lightless-sync.org>
This commit was merged in pull request #134.
This commit is contained in:
@@ -22,7 +22,6 @@ using LightlessSync.UI.Services;
|
||||
using LightlessSync.UI.Style;
|
||||
using LightlessSync.Utils;
|
||||
using Dalamud.Interface.Textures.TextureWraps;
|
||||
using OtterGui.Text;
|
||||
using LightlessSync.WebAPI;
|
||||
using LightlessSync.WebAPI.SignalR.Utils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -429,150 +428,182 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
||||
}
|
||||
else
|
||||
{
|
||||
var itemHeight = ImGui.GetTextLineHeightWithSpacing();
|
||||
using var clipper = ImUtf8.ListClipper(channel.Messages.Count, itemHeight);
|
||||
while (clipper.Step())
|
||||
var messageCount = channel.Messages.Count;
|
||||
var contentMaxX = ImGui.GetWindowContentRegionMax().X;
|
||||
var cursorStartX = ImGui.GetCursorPosX();
|
||||
var lineHeightWithSpacing = ImGui.GetTextLineHeightWithSpacing();
|
||||
var prefix = new float[messageCount + 1];
|
||||
var totalHeight = 0f;
|
||||
|
||||
for (var i = 0; i < messageCount; i++)
|
||||
{
|
||||
for (var i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
|
||||
var messageHeight = MeasureMessageHeight(channel, channel.Messages[i], showTimestamps, cursorStartX, contentMaxX, itemSpacing, ref pairSnapshot);
|
||||
if (messageHeight <= 0f)
|
||||
{
|
||||
var message = channel.Messages[i];
|
||||
ImGui.PushID(i);
|
||||
messageHeight = lineHeightWithSpacing;
|
||||
}
|
||||
|
||||
if (message.IsSystem)
|
||||
totalHeight += messageHeight;
|
||||
prefix[i + 1] = totalHeight;
|
||||
}
|
||||
|
||||
var scrollY = ImGui.GetScrollY();
|
||||
var windowHeight = ImGui.GetWindowHeight();
|
||||
var startIndex = Math.Max(0, UpperBound(prefix, scrollY) - 1);
|
||||
var endIndex = Math.Min(messageCount, LowerBound(prefix, scrollY + windowHeight));
|
||||
startIndex = Math.Max(0, startIndex - 2);
|
||||
endIndex = Math.Min(messageCount, endIndex + 2);
|
||||
|
||||
if (startIndex > 0)
|
||||
{
|
||||
ImGui.Dummy(new Vector2(1f, prefix[startIndex]));
|
||||
}
|
||||
|
||||
for (var i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
var message = channel.Messages[i];
|
||||
ImGui.PushID(i);
|
||||
|
||||
if (message.IsSystem)
|
||||
{
|
||||
DrawSystemEntry(message);
|
||||
ImGui.PopID();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (message.Payload is not { } payload)
|
||||
{
|
||||
ImGui.PopID();
|
||||
continue;
|
||||
}
|
||||
|
||||
var timestampText = string.Empty;
|
||||
if (showTimestamps)
|
||||
{
|
||||
timestampText = $"[{message.ReceivedAtUtc.ToLocalTime().ToString("HH:mm", CultureInfo.InvariantCulture)}] ";
|
||||
}
|
||||
var color = message.FromSelf ? UIColors.Get("LightlessBlue") : ImGuiColors.DalamudWhite;
|
||||
var showRoleIcons = false;
|
||||
var isOwner = false;
|
||||
var isModerator = false;
|
||||
var isPinned = false;
|
||||
|
||||
if (channel.Type == ChatChannelType.Group
|
||||
&& payload.Sender.Kind == ChatSenderKind.IdentifiedUser
|
||||
&& payload.Sender.User is not null)
|
||||
{
|
||||
pairSnapshot ??= _pairUiService.GetSnapshot();
|
||||
var groupId = channel.Descriptor.CustomKey;
|
||||
if (!string.IsNullOrWhiteSpace(groupId)
|
||||
&& pairSnapshot.GroupsByGid.TryGetValue(groupId, out var groupInfo))
|
||||
{
|
||||
DrawSystemEntry(message);
|
||||
ImGui.PopID();
|
||||
continue;
|
||||
var senderUid = payload.Sender.User.UID;
|
||||
isOwner = string.Equals(senderUid, groupInfo.OwnerUID, StringComparison.Ordinal);
|
||||
if (groupInfo.GroupPairUserInfos.TryGetValue(senderUid, out var info))
|
||||
{
|
||||
isModerator = info.IsModerator();
|
||||
isPinned = info.IsPinned();
|
||||
}
|
||||
}
|
||||
|
||||
if (message.Payload is not { } payload)
|
||||
showRoleIcons = isOwner || isModerator || isPinned;
|
||||
}
|
||||
|
||||
ImGui.BeginGroup();
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, color);
|
||||
if (showRoleIcons)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(timestampText))
|
||||
{
|
||||
ImGui.PopID();
|
||||
continue;
|
||||
ImGui.TextUnformatted(timestampText);
|
||||
ImGui.SameLine(0f, 0f);
|
||||
}
|
||||
|
||||
var timestampText = string.Empty;
|
||||
if (showTimestamps)
|
||||
var hasIcon = false;
|
||||
if (isModerator)
|
||||
{
|
||||
timestampText = $"[{message.ReceivedAtUtc.ToLocalTime().ToString("HH:mm", CultureInfo.InvariantCulture)}] ";
|
||||
}
|
||||
var color = message.FromSelf ? UIColors.Get("LightlessBlue") : ImGuiColors.DalamudWhite;
|
||||
var showRoleIcons = false;
|
||||
var isOwner = false;
|
||||
var isModerator = false;
|
||||
var isPinned = false;
|
||||
|
||||
if (channel.Type == ChatChannelType.Group
|
||||
&& payload.Sender.Kind == ChatSenderKind.IdentifiedUser
|
||||
&& payload.Sender.User is not null)
|
||||
{
|
||||
pairSnapshot ??= _pairUiService.GetSnapshot();
|
||||
var groupId = channel.Descriptor.CustomKey;
|
||||
if (!string.IsNullOrWhiteSpace(groupId)
|
||||
&& pairSnapshot.GroupsByGid.TryGetValue(groupId, out var groupInfo))
|
||||
{
|
||||
var senderUid = payload.Sender.User.UID;
|
||||
isOwner = string.Equals(senderUid, groupInfo.OwnerUID, StringComparison.Ordinal);
|
||||
if (groupInfo.GroupPairUserInfos.TryGetValue(senderUid, out var info))
|
||||
{
|
||||
isModerator = info.IsModerator();
|
||||
isPinned = info.IsPinned();
|
||||
}
|
||||
}
|
||||
|
||||
showRoleIcons = isOwner || isModerator || isPinned;
|
||||
_uiSharedService.IconText(FontAwesomeIcon.UserShield, UIColors.Get("LightlessPurple"));
|
||||
UiSharedService.AttachToolTip("Moderator");
|
||||
hasIcon = true;
|
||||
}
|
||||
|
||||
ImGui.BeginGroup();
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, color);
|
||||
if (showRoleIcons)
|
||||
if (isOwner)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(timestampText))
|
||||
{
|
||||
ImGui.TextUnformatted(timestampText);
|
||||
ImGui.SameLine(0f, 0f);
|
||||
}
|
||||
|
||||
var hasIcon = false;
|
||||
if (isModerator)
|
||||
{
|
||||
_uiSharedService.IconText(FontAwesomeIcon.UserShield, UIColors.Get("LightlessPurple"));
|
||||
UiSharedService.AttachToolTip("Moderator");
|
||||
hasIcon = true;
|
||||
}
|
||||
|
||||
if (isOwner)
|
||||
{
|
||||
if (hasIcon)
|
||||
{
|
||||
ImGui.SameLine(0f, itemSpacing);
|
||||
}
|
||||
|
||||
_uiSharedService.IconText(FontAwesomeIcon.Crown, UIColors.Get("LightlessYellow"));
|
||||
UiSharedService.AttachToolTip("Owner");
|
||||
hasIcon = true;
|
||||
}
|
||||
|
||||
if (isPinned)
|
||||
{
|
||||
if (hasIcon)
|
||||
{
|
||||
ImGui.SameLine(0f, itemSpacing);
|
||||
}
|
||||
|
||||
_uiSharedService.IconText(FontAwesomeIcon.Thumbtack, UIColors.Get("LightlessBlue"));
|
||||
UiSharedService.AttachToolTip("Pinned");
|
||||
hasIcon = true;
|
||||
}
|
||||
|
||||
if (hasIcon)
|
||||
{
|
||||
ImGui.SameLine(0f, itemSpacing);
|
||||
}
|
||||
|
||||
var messageStartX = ImGui.GetCursorPosX();
|
||||
DrawChatMessageWithEmotes($"{message.DisplayName}: ", payload.Message, messageStartX);
|
||||
_uiSharedService.IconText(FontAwesomeIcon.Crown, UIColors.Get("LightlessYellow"));
|
||||
UiSharedService.AttachToolTip("Owner");
|
||||
hasIcon = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var messageStartX = ImGui.GetCursorPosX();
|
||||
DrawChatMessageWithEmotes($"{timestampText}{message.DisplayName}: ", payload.Message, messageStartX);
|
||||
}
|
||||
ImGui.PopStyleColor();
|
||||
ImGui.EndGroup();
|
||||
|
||||
ImGui.SetNextWindowSizeConstraints(
|
||||
new Vector2(190f * ImGuiHelpers.GlobalScale, 0f),
|
||||
new Vector2(float.MaxValue, float.MaxValue));
|
||||
if (ImGui.BeginPopupContextItem($"chat_msg_ctx##{channel.Key}_{i}"))
|
||||
if (isPinned)
|
||||
{
|
||||
var contextLocalTimestamp = payload.SentAtUtc.ToLocalTime();
|
||||
var contextTimestampText = contextLocalTimestamp.ToString("yyyy-MM-dd HH:mm:ss 'UTC'z", CultureInfo.InvariantCulture);
|
||||
ImGui.TextDisabled(contextTimestampText);
|
||||
if (channel.Type == ChatChannelType.Group
|
||||
&& payload.Sender.Kind == ChatSenderKind.IdentifiedUser
|
||||
&& payload.Sender.User is not null)
|
||||
if (hasIcon)
|
||||
{
|
||||
var aliasOrUid = payload.Sender.User.AliasOrUID;
|
||||
if (!string.IsNullOrWhiteSpace(aliasOrUid)
|
||||
&& !string.Equals(message.DisplayName, aliasOrUid, StringComparison.Ordinal))
|
||||
{
|
||||
ImGui.TextDisabled(aliasOrUid);
|
||||
}
|
||||
}
|
||||
ImGui.Separator();
|
||||
|
||||
var actionIndex = 0;
|
||||
foreach (var action in GetContextMenuActions(channel, message))
|
||||
{
|
||||
DrawContextMenuAction(action, actionIndex++);
|
||||
ImGui.SameLine(0f, itemSpacing);
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
_uiSharedService.IconText(FontAwesomeIcon.Thumbtack, UIColors.Get("LightlessBlue"));
|
||||
UiSharedService.AttachToolTip("Pinned");
|
||||
hasIcon = true;
|
||||
}
|
||||
|
||||
ImGui.PopID();
|
||||
if (hasIcon)
|
||||
{
|
||||
ImGui.SameLine(0f, itemSpacing);
|
||||
}
|
||||
|
||||
var messageStartX = ImGui.GetCursorPosX();
|
||||
DrawChatMessageWithEmotes($"{message.DisplayName}: ", payload.Message, messageStartX);
|
||||
}
|
||||
else
|
||||
{
|
||||
var messageStartX = ImGui.GetCursorPosX();
|
||||
DrawChatMessageWithEmotes($"{timestampText}{message.DisplayName}: ", payload.Message, messageStartX);
|
||||
}
|
||||
ImGui.PopStyleColor();
|
||||
ImGui.EndGroup();
|
||||
|
||||
ImGui.SetNextWindowSizeConstraints(
|
||||
new Vector2(190f * ImGuiHelpers.GlobalScale, 0f),
|
||||
new Vector2(float.MaxValue, float.MaxValue));
|
||||
if (ImGui.BeginPopupContextItem($"chat_msg_ctx##{channel.Key}_{i}"))
|
||||
{
|
||||
var contextLocalTimestamp = payload.SentAtUtc.ToLocalTime();
|
||||
var contextTimestampText = contextLocalTimestamp.ToString("yyyy-MM-dd HH:mm:ss 'UTC'z", CultureInfo.InvariantCulture);
|
||||
ImGui.TextDisabled(contextTimestampText);
|
||||
if (channel.Type == ChatChannelType.Group
|
||||
&& payload.Sender.Kind == ChatSenderKind.IdentifiedUser
|
||||
&& payload.Sender.User is not null)
|
||||
{
|
||||
var aliasOrUid = payload.Sender.User.AliasOrUID;
|
||||
if (!string.IsNullOrWhiteSpace(aliasOrUid)
|
||||
&& !string.Equals(message.DisplayName, aliasOrUid, StringComparison.Ordinal))
|
||||
{
|
||||
ImGui.TextDisabled(aliasOrUid);
|
||||
}
|
||||
}
|
||||
ImGui.Separator();
|
||||
|
||||
var actionIndex = 0;
|
||||
foreach (var action in GetContextMenuActions(channel, message))
|
||||
{
|
||||
DrawContextMenuAction(action, actionIndex++);
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
var remainingHeight = totalHeight - prefix[endIndex];
|
||||
if (remainingHeight > 0f)
|
||||
{
|
||||
ImGui.Dummy(new Vector2(1f, remainingHeight));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -708,7 +739,20 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
||||
var clicked = false;
|
||||
if (texture is not null)
|
||||
{
|
||||
clicked = ImGui.ImageButton(texture.Handle, new Vector2(emoteSize));
|
||||
var buttonSize = new Vector2(itemWidth, itemHeight);
|
||||
clicked = ImGui.InvisibleButton("##emote_button", buttonSize);
|
||||
var drawList = ImGui.GetWindowDrawList();
|
||||
var itemMin = ImGui.GetItemRectMin();
|
||||
var itemMax = ImGui.GetItemRectMax();
|
||||
var bgColor = ImGui.IsItemActive()
|
||||
? ImGui.GetColorU32(ImGuiCol.ButtonActive)
|
||||
: ImGui.IsItemHovered()
|
||||
? ImGui.GetColorU32(ImGuiCol.ButtonHovered)
|
||||
: ImGui.GetColorU32(ImGuiCol.Button);
|
||||
drawList.AddRectFilled(itemMin, itemMax, bgColor, style.FrameRounding);
|
||||
var imageMin = itemMin + style.FramePadding;
|
||||
var imageMax = imageMin + new Vector2(emoteSize);
|
||||
drawList.AddImage(texture.Handle, imageMin, imageMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -878,7 +922,232 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
||||
|
||||
private static bool IsEmoteChar(char value)
|
||||
{
|
||||
return char.IsLetterOrDigit(value) || value == '_' || value == '-' || value == '!';
|
||||
return char.IsLetterOrDigit(value) || value == '_' || value == '-' || value == '!' || value == '(' || value == ')';
|
||||
}
|
||||
|
||||
private float MeasureMessageHeight(
|
||||
ChatChannelSnapshot channel,
|
||||
ChatMessageEntry message,
|
||||
bool showTimestamps,
|
||||
float cursorStartX,
|
||||
float contentMaxX,
|
||||
float itemSpacing,
|
||||
ref PairUiSnapshot? pairSnapshot)
|
||||
{
|
||||
if (message.IsSystem)
|
||||
{
|
||||
return MeasureSystemEntryHeight(message);
|
||||
}
|
||||
|
||||
if (message.Payload is not { } payload)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
var timestampText = string.Empty;
|
||||
if (showTimestamps)
|
||||
{
|
||||
timestampText = $"[{message.ReceivedAtUtc.ToLocalTime().ToString("HH:mm", CultureInfo.InvariantCulture)}] ";
|
||||
}
|
||||
|
||||
var showRoleIcons = false;
|
||||
var isOwner = false;
|
||||
var isModerator = false;
|
||||
var isPinned = false;
|
||||
|
||||
if (channel.Type == ChatChannelType.Group
|
||||
&& payload.Sender.Kind == ChatSenderKind.IdentifiedUser
|
||||
&& payload.Sender.User is not null)
|
||||
{
|
||||
pairSnapshot ??= _pairUiService.GetSnapshot();
|
||||
var groupId = channel.Descriptor.CustomKey;
|
||||
if (!string.IsNullOrWhiteSpace(groupId)
|
||||
&& pairSnapshot.GroupsByGid.TryGetValue(groupId, out var groupInfo))
|
||||
{
|
||||
var senderUid = payload.Sender.User.UID;
|
||||
isOwner = string.Equals(senderUid, groupInfo.OwnerUID, StringComparison.Ordinal);
|
||||
if (groupInfo.GroupPairUserInfos.TryGetValue(senderUid, out var info))
|
||||
{
|
||||
isModerator = info.IsModerator();
|
||||
isPinned = info.IsPinned();
|
||||
}
|
||||
}
|
||||
|
||||
showRoleIcons = isOwner || isModerator || isPinned;
|
||||
}
|
||||
|
||||
var lineStartX = cursorStartX;
|
||||
string prefix;
|
||||
if (showRoleIcons)
|
||||
{
|
||||
lineStartX += MeasureRolePrefixWidth(timestampText, isOwner, isModerator, isPinned, itemSpacing);
|
||||
prefix = $"{message.DisplayName}: ";
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix = $"{timestampText}{message.DisplayName}: ";
|
||||
}
|
||||
|
||||
var lines = MeasureChatMessageLines(prefix, payload.Message, lineStartX, contentMaxX);
|
||||
return Math.Max(1, lines) * ImGui.GetTextLineHeightWithSpacing();
|
||||
}
|
||||
|
||||
private int MeasureChatMessageLines(string prefix, string message, float lineStartX, float contentMaxX)
|
||||
{
|
||||
var segments = BuildChatSegments(prefix, message);
|
||||
if (segments.Count == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
var emoteWidth = ImGui.GetTextLineHeight();
|
||||
var availableWidth = Math.Max(1f, contentMaxX - lineStartX);
|
||||
var remainingWidth = availableWidth;
|
||||
var firstOnLine = true;
|
||||
var lines = 1;
|
||||
|
||||
foreach (var segment in segments)
|
||||
{
|
||||
if (segment.IsLineBreak)
|
||||
{
|
||||
lines++;
|
||||
firstOnLine = true;
|
||||
remainingWidth = availableWidth;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (segment.IsWhitespace && firstOnLine)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var segmentWidth = segment.IsEmote ? emoteWidth : ImGui.CalcTextSize(segment.Text).X;
|
||||
if (!firstOnLine)
|
||||
{
|
||||
if (segmentWidth > remainingWidth)
|
||||
{
|
||||
lines++;
|
||||
firstOnLine = true;
|
||||
remainingWidth = availableWidth;
|
||||
if (segment.IsWhitespace)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remainingWidth -= segmentWidth;
|
||||
firstOnLine = false;
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
private float MeasureRolePrefixWidth(string timestampText, bool isOwner, bool isModerator, bool isPinned, float itemSpacing)
|
||||
{
|
||||
var width = 0f;
|
||||
|
||||
if (!string.IsNullOrEmpty(timestampText))
|
||||
{
|
||||
width += ImGui.CalcTextSize(timestampText).X;
|
||||
}
|
||||
|
||||
var hasIcon = false;
|
||||
if (isModerator)
|
||||
{
|
||||
width += MeasureIconWidth(FontAwesomeIcon.UserShield);
|
||||
hasIcon = true;
|
||||
}
|
||||
|
||||
if (isOwner)
|
||||
{
|
||||
if (hasIcon)
|
||||
{
|
||||
width += itemSpacing;
|
||||
}
|
||||
|
||||
width += MeasureIconWidth(FontAwesomeIcon.Crown);
|
||||
hasIcon = true;
|
||||
}
|
||||
|
||||
if (isPinned)
|
||||
{
|
||||
if (hasIcon)
|
||||
{
|
||||
width += itemSpacing;
|
||||
}
|
||||
|
||||
width += MeasureIconWidth(FontAwesomeIcon.Thumbtack);
|
||||
hasIcon = true;
|
||||
}
|
||||
|
||||
if (hasIcon)
|
||||
{
|
||||
width += itemSpacing;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
private float MeasureIconWidth(FontAwesomeIcon icon)
|
||||
{
|
||||
using var font = _uiSharedService.IconFont.Push();
|
||||
return ImGui.CalcTextSize(icon.ToIconString()).X;
|
||||
}
|
||||
|
||||
private float MeasureSystemEntryHeight(ChatMessageEntry entry)
|
||||
{
|
||||
_ = entry;
|
||||
var spacing = ImGui.GetStyle().ItemSpacing.Y;
|
||||
var lineHeightWithSpacing = ImGui.GetTextLineHeightWithSpacing();
|
||||
var separatorHeight = Math.Max(1f, ImGuiHelpers.GlobalScale);
|
||||
|
||||
var height = spacing;
|
||||
height += lineHeightWithSpacing;
|
||||
height += spacing * 0.35f;
|
||||
height += separatorHeight;
|
||||
height += spacing;
|
||||
return height;
|
||||
}
|
||||
|
||||
private static int LowerBound(float[] values, float target)
|
||||
{
|
||||
var low = 0;
|
||||
var high = values.Length;
|
||||
while (low < high)
|
||||
{
|
||||
var mid = (low + high) / 2;
|
||||
if (values[mid] < target)
|
||||
{
|
||||
low = mid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
private static int UpperBound(float[] values, float target)
|
||||
{
|
||||
var low = 0;
|
||||
var high = values.Length;
|
||||
while (low < high)
|
||||
{
|
||||
var mid = (low + high) / 2;
|
||||
if (values[mid] <= target)
|
||||
{
|
||||
low = mid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
private void DrawEmoteTooltip(string name, IDalamudTextureWrap? texture)
|
||||
@@ -2092,6 +2361,17 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
|
||||
ImGui.SetTooltip("When enabled, your notes replace user names in syncshell chat.");
|
||||
}
|
||||
|
||||
var enableAnimatedEmotes = chatConfig.EnableAnimatedEmotes;
|
||||
if (ImGui.Checkbox("Enable animated emotes", ref enableAnimatedEmotes))
|
||||
{
|
||||
chatConfig.EnableAnimatedEmotes = enableAnimatedEmotes;
|
||||
_chatConfigService.Save();
|
||||
}
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
ImGui.SetTooltip("When disabled, emotes render as static images.");
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.TextUnformatted("Chat Visibility");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user