diff --git a/MareSynchronos/MareConfiguration/Configurations/MareConfig.cs b/MareSynchronos/MareConfiguration/Configurations/MareConfig.cs index 0003b83..d999d60 100644 --- a/MareSynchronos/MareConfiguration/Configurations/MareConfig.cs +++ b/MareSynchronos/MareConfiguration/Configurations/MareConfig.cs @@ -86,6 +86,7 @@ public class MareConfig : IMareConfiguration public bool ExtraChatTags { get; set; } = false; public bool TypingIndicatorShowOnNameplates { get; set; } = true; public bool TypingIndicatorShowOnPartyList { get; set; } = true; + public TypingIndicatorBubbleSize TypingIndicatorBubbleSize { get; set; } = TypingIndicatorBubbleSize.Large; public bool MareAPI { get; set; } = true; } diff --git a/MareSynchronos/MareConfiguration/Models/TypingIndicatorBubbleSize.cs b/MareSynchronos/MareConfiguration/Models/TypingIndicatorBubbleSize.cs new file mode 100644 index 0000000..0c3c1ec --- /dev/null +++ b/MareSynchronos/MareConfiguration/Models/TypingIndicatorBubbleSize.cs @@ -0,0 +1,8 @@ +namespace MareSynchronos.MareConfiguration.Models; + +public enum TypingIndicatorBubbleSize +{ + Small, + Medium, + Large +} diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj index 1448877..bfaf3f1 100644 --- a/MareSynchronos/MareSynchronos.csproj +++ b/MareSynchronos/MareSynchronos.csproj @@ -3,7 +3,7 @@ UmbraSync UmbraSync - 0.1.9.2 + 0.1.9.4 diff --git a/MareSynchronos/Services/DalamudUtilService.cs b/MareSynchronos/Services/DalamudUtilService.cs index 70a480c..f21c179 100644 --- a/MareSynchronos/Services/DalamudUtilService.cs +++ b/MareSynchronos/Services/DalamudUtilService.cs @@ -20,6 +20,8 @@ using Microsoft.Extensions.Logging; using System.Numerics; using System.Runtime.CompilerServices; using System.Text; +using System; +using System.Collections.Generic; using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject; using DalamudGameObject = Dalamud.Game.ClientState.Objects.Types.IGameObject; @@ -52,6 +54,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber private readonly ILogger _logger; private readonly IObjectTable _objectTable; private readonly PerformanceCollectorService _performanceCollector; + private readonly Dictionary _conditionLookup = new(StringComparer.OrdinalIgnoreCase); private uint? _classJobId = 0; private DateTime _delayedFrameworkUpdateCheck = DateTime.UtcNow; private string _lastGlobalBlockPlayer = string.Empty; @@ -172,6 +175,20 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber public bool IsInCombatOrPerforming { get; private set; } = false; public bool HasModifiedGameFiles => _gameData.HasModifiedGameDataFiles; + public bool IsConditionActive(string flagName) + { + if (_conditionLookup.TryGetValue(flagName, out var cachedFlag)) + return _condition[cachedFlag]; + + if (Enum.TryParse(flagName, true, out var flag)) + { + _conditionLookup[flagName] = flag; + return _condition[flag]; + } + + return false; + } + public Lazy> WorldData { get; private set; } public Lazy> UiColors { get; private set; } public Lazy> TerritoryData { get; private set; } diff --git a/MareSynchronos/UI/ChangelogUi.cs b/MareSynchronos/UI/ChangelogUi.cs index ec908bb..3b679f0 100644 --- a/MareSynchronos/UI/ChangelogUi.cs +++ b/MareSynchronos/UI/ChangelogUi.cs @@ -169,6 +169,10 @@ public sealed class ChangelogUi : WindowMediatorSubscriberBase { return new List { + new(new Version(0, 1, 9, 3), "0.1.9.3", new List + { + new("Correctif de l'affichage de la bulle de frappe quand l'interface est à + de 100%."), + }), new(new Version(0, 1, 9, 2), "0.1.9.2", new List { new("Correctif de l'affichage de la bulle de frappe."), diff --git a/MareSynchronos/UI/CharaDataHubUi.GposeTogether.cs b/MareSynchronos/UI/CharaDataHubUi.GposeTogether.cs index f5c4059..4b89aa5 100644 --- a/MareSynchronos/UI/CharaDataHubUi.GposeTogether.cs +++ b/MareSynchronos/UI/CharaDataHubUi.GposeTogether.cs @@ -15,14 +15,14 @@ internal sealed partial class CharaDataHubUi if (!_charaDataManager.BrioAvailable) { ImGuiHelpers.ScaledDummy(5); - UiSharedService.DrawGroupedCenteredColorText("BRIO IS MANDATORY FOR GPOSE TOGETHER.", ImGuiColors.DalamudRed); + UiSharedService.DrawGroupedCenteredColorText("BRIO IS MANDATORY FOR GPOSE TOGETHER.", UiSharedService.AccentColor); ImGuiHelpers.ScaledDummy(5); } if (!_uiSharedService.ApiController.IsConnected) { ImGuiHelpers.ScaledDummy(5); - UiSharedService.DrawGroupedCenteredColorText("CANNOT USE GPOSE TOGETHER WHILE DISCONNECTED FROM THE SERVER.", ImGuiColors.DalamudRed); + UiSharedService.DrawGroupedCenteredColorText("CANNOT USE GPOSE TOGETHER WHILE DISCONNECTED FROM THE SERVER.", UiSharedService.AccentColor); ImGuiHelpers.ScaledDummy(5); } @@ -165,7 +165,7 @@ internal sealed partial class CharaDataHubUi UiSharedService.AttachToolTip(user.WorldDataDescriptor + UiSharedService.TooltipSeparator); ImGui.SameLine(); - _uiSharedService.IconText(FontAwesomeIcon.Map, sameMapAndServer.SameMap ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed); + _uiSharedService.IconText(FontAwesomeIcon.Map, sameMapAndServer.SameMap ? ImGuiColors.ParsedGreen : UiSharedService.AccentColor); if (ImGui.IsItemClicked(ImGuiMouseButton.Left) && user.WorldData != null) { _dalamudUtilService.SetMarkerAndOpenMap(new(user.WorldData.Value.PositionX, user.WorldData.Value.PositionY, user.WorldData.Value.PositionZ), user.Map); @@ -175,12 +175,12 @@ internal sealed partial class CharaDataHubUi + "Note: For GPose synchronization to work properly, you must be on the same map."); ImGui.SameLine(); - _uiSharedService.IconText(FontAwesomeIcon.Globe, sameMapAndServer.SameServer ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed); + _uiSharedService.IconText(FontAwesomeIcon.Globe, sameMapAndServer.SameServer ? ImGuiColors.ParsedGreen : UiSharedService.AccentColor); UiSharedService.AttachToolTip((sameMapAndServer.SameMap ? "You are on the same server." : "You are not on the same server.") + UiSharedService.TooltipSeparator + "Note: GPose synchronization is not dependent on the current server, but you will have to spawn a character for the other lobby users."); ImGui.SameLine(); - _uiSharedService.IconText(FontAwesomeIcon.Running, sameMapAndServer.SameEverything ? ImGuiColors.ParsedGreen : ImGuiColors.DalamudRed); + _uiSharedService.IconText(FontAwesomeIcon.Running, sameMapAndServer.SameEverything ? ImGuiColors.ParsedGreen : UiSharedService.AccentColor); UiSharedService.AttachToolTip(sameMapAndServer.SameEverything ? "You are in the same instanced area." : "You are not the same instanced area." + UiSharedService.TooltipSeparator + "Note: Users not in your instance, but on the same map, will be drawn as floating wisps." + Environment.NewLine + "Note: GPose synchronization is not dependent on the current instance, but you will have to spawn a character for the other lobby users."); @@ -217,7 +217,7 @@ internal sealed partial class CharaDataHubUi if (_uiSharedService.IsInGpose && user.Address == nint.Zero) { ImGui.SameLine(); - _uiSharedService.IconText(FontAwesomeIcon.ExclamationTriangle, ImGuiColors.DalamudRed); + _uiSharedService.IconText(FontAwesomeIcon.ExclamationTriangle, UiSharedService.AccentColor); UiSharedService.AttachToolTip("No valid character assigned for this user. Pose data will not be applied."); } } diff --git a/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs b/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs index 3cc29c2..121a3a1 100644 --- a/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs +++ b/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs @@ -45,7 +45,7 @@ internal sealed partial class CharaDataHubUi if (canUpdate) { ImGui.AlignTextToFramePadding(); - UiSharedService.ColorTextWrapped("Warning: You have unsaved changes!", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped("Warning: You have unsaved changes!", UiSharedService.AccentColor); ImGui.SameLine(); using (ImRaii.Disabled(_charaDataManager.CharaUpdateTask != null && !_charaDataManager.CharaUpdateTask.IsCompleted)) { @@ -216,7 +216,7 @@ internal sealed partial class CharaDataHubUi } else { - UiSharedService.ColorTextWrapped($"{dataDto.MissingFiles.DistinctBy(k => k.HashOrFileSwap).Count()} files to download this character data are missing on the server", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped($"{dataDto.MissingFiles.DistinctBy(k => k.HashOrFileSwap).Count()} files to download this character data are missing on the server", UiSharedService.AccentColor); ImGui.NewLine(); ImGui.SameLine(pos); if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowCircleUp, "Attempt to upload missing files and restore Character Data")) @@ -401,7 +401,7 @@ internal sealed partial class CharaDataHubUi else if (!_charaDataManager.BrioAvailable) { ImGuiHelpers.ScaledDummy(5); - UiSharedService.DrawGroupedCenteredColorText("To attach pose and world data Brio requires to be installed.", ImGuiColors.DalamudRed); + UiSharedService.DrawGroupedCenteredColorText("To attach pose and world data Brio requires to be installed.", UiSharedService.AccentColor); ImGuiHelpers.ScaledDummy(5); } @@ -685,7 +685,7 @@ internal sealed partial class CharaDataHubUi } else if (_charaDataManager.DataCreationTask != null && _charaDataManager.DataCreationTask.IsCompleted) { - var color = _charaDataManager.DataCreationTask.Result.Success ? ImGuiColors.HealerGreen : ImGuiColors.DalamudRed; + var color = _charaDataManager.DataCreationTask.Result.Success ? ImGuiColors.HealerGreen : UiSharedService.AccentColor; UiSharedService.ColorTextWrapped(_charaDataManager.DataCreationTask.Result.Output, color); } diff --git a/MareSynchronos/UI/CharaDataHubUi.cs b/MareSynchronos/UI/CharaDataHubUi.cs index 683d35f..48d5ecd 100644 --- a/MareSynchronos/UI/CharaDataHubUi.cs +++ b/MareSynchronos/UI/CharaDataHubUi.cs @@ -170,7 +170,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase if (!_charaDataManager.BrioAvailable) { ImGuiHelpers.ScaledDummy(3); - UiSharedService.DrawGroupedCenteredColorText("To utilize any features related to posing or spawning characters you require to have Brio installed.", ImGuiColors.DalamudRed); + UiSharedService.DrawGroupedCenteredColorText("To utilize any features related to posing or spawning characters you require to have Brio installed.", UiSharedService.AccentColor); UiSharedService.DistanceSeparator(); } @@ -194,7 +194,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase } if (_charaDataManager.DataApplicationTask != null) { - UiSharedService.ColorTextWrapped("WARNING: During the data application avoid interacting with this actor to prevent potential crashes.", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped("WARNING: During the data application avoid interacting with this actor to prevent potential crashes.", UiSharedService.AccentColor); ImGuiHelpers.ScaledDummy(5); ImGui.Separator(); } @@ -648,7 +648,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase } if ((_charaDataManager.DownloadMetaInfoTask?.IsCompleted ?? false) && !_charaDataManager.DownloadMetaInfoTask.Result.Success) { - UiSharedService.ColorTextWrapped(_charaDataManager.DownloadMetaInfoTask.Result.Result, ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped(_charaDataManager.DownloadMetaInfoTask.Result.Result, UiSharedService.AccentColor); } using (ImRaii.Disabled(_charaDataManager.LastDownloadedMetaInfo == null)) @@ -848,7 +848,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase if ((_charaDataManager.LoadedMcdfHeader?.IsFaulted ?? false) || (_charaDataManager.McdfApplicationTask?.IsFaulted ?? false)) { UiSharedService.ColorTextWrapped("Failure to read MCDF file. MCDF file is possibly corrupt. Re-export the MCDF file and try again.", - ImGuiColors.DalamudRed); + UiSharedService.AccentColor); UiSharedService.ColorTextWrapped("Note: if this is your MCDF, try redrawing yourself, wait and re-export the file. " + "If you received it from someone else have them do the same.", ImGuiColors.DalamudYellow); } diff --git a/MareSynchronos/UI/CompactUI.cs b/MareSynchronos/UI/CompactUI.cs index fbd78d0..92b4b2a 100644 --- a/MareSynchronos/UI/CompactUI.cs +++ b/MareSynchronos/UI/CompactUI.cs @@ -1,4 +1,4 @@ -using Dalamud.Bindings.ImGui; +using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.Utility; @@ -130,7 +130,15 @@ public class CompactUi : WindowMediatorSubscriberBase protected override void DrawInternal() { - UiSharedService.AccentColor = new Vector4(0.63f, 0.25f, 1f, 1f); + UiSharedService.AccentColor = new Vector4(0x8D / 255f, 0x37 / 255f, 0xC0 / 255f, 1f); + UiSharedService.AccentHoverColor = new Vector4(0x3A / 255f, 0x15 / 255f, 0x50 / 255f, 1f); + UiSharedService.AccentActiveColor = UiSharedService.AccentHoverColor; + var accent = UiSharedService.AccentColor; + using var titleBg = ImRaii.PushColor(ImGuiCol.TitleBg, accent); + using var titleBgActive = ImRaii.PushColor(ImGuiCol.TitleBgActive, accent); + using var titleBgCollapsed = ImRaii.PushColor(ImGuiCol.TitleBgCollapsed, accent); + using var buttonHover = ImRaii.PushColor(ImGuiCol.ButtonHovered, UiSharedService.AccentHoverColor); + using var buttonActive = ImRaii.PushColor(ImGuiCol.ButtonActive, UiSharedService.AccentActiveColor); ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y - 1f * ImGuiHelpers.GlobalScale + ImGui.GetStyle().ItemSpacing.Y); WindowContentWidth = UiSharedService.GetWindowContentRegionWidth(); if (!_apiController.IsCurrentVersion) @@ -142,10 +150,10 @@ public class CompactUi : WindowMediatorSubscriberBase var uidTextSize = ImGui.CalcTextSize(unsupported); ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X + ImGui.GetWindowContentRegionMin().X) / 2 - uidTextSize.X / 2); ImGui.AlignTextToFramePadding(); - ImGui.TextColored(ImGuiColors.DalamudRed, unsupported); + ImGui.TextColored(UiSharedService.AccentColor, unsupported); } UiSharedService.ColorTextWrapped($"Your UmbraSync installation is out of date, the current version is {ver.Major}.{ver.Minor}.{ver.Build}. " + - $"It is highly recommended to keep UmbraSync up to date. Open /xlplugins and update the plugin.", ImGuiColors.DalamudRed); + $"It is highly recommended to keep UmbraSync up to date. Open /xlplugins and update the plugin.", UiSharedService.AccentColor); } using (ImRaii.PushId("header")) DrawUIDHeader(); @@ -156,40 +164,59 @@ public class CompactUi : WindowMediatorSubscriberBase { var hasShownSyncShells = _showSyncShells; - ImGui.PushFont(UiBuilder.IconFont); + using (var hoverColor = ImRaii.PushColor(ImGuiCol.ButtonHovered, UiSharedService.AccentHoverColor)) + using (var activeColor = ImRaii.PushColor(ImGuiCol.ButtonActive, UiSharedService.AccentActiveColor)) + { if (!hasShownSyncShells) { - ImGui.PushStyleColor(ImGuiCol.Button, ImGui.GetStyle().Colors[(int)ImGuiCol.ButtonHovered]); + using var selectedColor = ImRaii.PushColor(ImGuiCol.Button, accent); + using (ImRaii.PushFont(UiBuilder.IconFont)) + { + if (ImGui.Button(FontAwesomeIcon.User.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale))) + { + _showSyncShells = false; + } + } } - if (ImGui.Button(FontAwesomeIcon.User.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale))) + else { - _showSyncShells = false; + using (ImRaii.PushFont(UiBuilder.IconFont)) + { + if (ImGui.Button(FontAwesomeIcon.User.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale))) + { + _showSyncShells = false; + } + } } - if (!hasShownSyncShells) - { - ImGui.PopStyleColor(); - } - ImGui.PopFont(); + UiSharedService.AttachToolTip("Individual pairs"); ImGui.SameLine(); - ImGui.PushFont(UiBuilder.IconFont); if (hasShownSyncShells) { - ImGui.PushStyleColor(ImGuiCol.Button, ImGui.GetStyle().Colors[(int)ImGuiCol.ButtonHovered]); + using var selectedColor = ImRaii.PushColor(ImGuiCol.Button, accent); + using (ImRaii.PushFont(UiBuilder.IconFont)) + { + if (ImGui.Button(FontAwesomeIcon.UserFriends.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale))) + { + _showSyncShells = true; + } + } } - if (ImGui.Button(FontAwesomeIcon.UserFriends.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale))) + else { - _showSyncShells = true; + using (ImRaii.PushFont(UiBuilder.IconFont)) + { + if (ImGui.Button(FontAwesomeIcon.UserFriends.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale))) + { + _showSyncShells = true; + } + } } - if (hasShownSyncShells) - { - ImGui.PopStyleColor(); - } - ImGui.PopFont(); UiSharedService.AttachToolTip("Syncshells"); + } DrawDefaultSyncSettings(); if (!hasShownSyncShells) @@ -271,9 +298,9 @@ public class CompactUi : WindowMediatorSubscriberBase bool vfxDisabled = _configService.Current.DefaultDisableVfx; bool showNearby = _configService.Current.EnableAutoDetectDiscovery; - var soundIcon = soundsDisabled ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeMute; - var animIcon = animsDisabled ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop; - var vfxIcon = vfxDisabled ? FontAwesomeIcon.Sun : FontAwesomeIcon.Circle; + var soundIcon = soundsDisabled ? FontAwesomeIcon.VolumeMute : FontAwesomeIcon.VolumeUp; + var animIcon = animsDisabled ? FontAwesomeIcon.WindowClose : FontAwesomeIcon.Running; + var vfxIcon = vfxDisabled ? FontAwesomeIcon.TimesCircle : FontAwesomeIcon.Sun; float spacing = ImGui.GetStyle().ItemSpacing.X; float audioWidth = _uiSharedService.GetIconTextButtonSize(soundIcon, soundLabel); @@ -337,12 +364,24 @@ public class CompactUi : WindowMediatorSubscriberBase ImGui.SameLine(0, spacingOverride); } + var colorsPushed = 0; + if (currentState) + { + ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0.95f, 0.35f, 0.35f, 1f)); + colorsPushed++; + } + if (_uiSharedService.IconTextButton(icon, label, width)) { var newState = !currentState; onToggle(newState); } + if (colorsPushed > 0) + { + ImGui.PopStyleColor(colorsPushed); + } + UiSharedService.AttachToolTip(tooltipProvider()); } @@ -648,7 +687,7 @@ public class CompactUi : WindowMediatorSubscriberBase else { ImGui.AlignTextToFramePadding(); - ImGui.TextColored(ImGuiColors.DalamudRed, "Not connected to any server"); + ImGui.TextColored(UiSharedService.AccentColor, "Not connected to any server"); } if (printShard) @@ -845,17 +884,17 @@ public class CompactUi : WindowMediatorSubscriberBase return _apiController.ServerState switch { ServerState.Connecting => ImGuiColors.DalamudYellow, - ServerState.Reconnecting => ImGuiColors.DalamudRed, - ServerState.Connected => new Vector4(0.63f, 0.25f, 1f, 1f), + ServerState.Reconnecting => UiSharedService.AccentColor, + ServerState.Connected => UiSharedService.AccentColor, ServerState.Disconnected => ImGuiColors.DalamudYellow, ServerState.Disconnecting => ImGuiColors.DalamudYellow, - ServerState.Unauthorized => ImGuiColors.DalamudRed, - ServerState.VersionMisMatch => ImGuiColors.DalamudRed, - ServerState.Offline => ImGuiColors.DalamudRed, + ServerState.Unauthorized => UiSharedService.AccentColor, + ServerState.VersionMisMatch => UiSharedService.AccentColor, + ServerState.Offline => UiSharedService.AccentColor, ServerState.RateLimited => ImGuiColors.DalamudYellow, ServerState.NoSecretKey => ImGuiColors.DalamudYellow, ServerState.MultiChara => ImGuiColors.DalamudYellow, - _ => ImGuiColors.DalamudRed + _ => UiSharedService.AccentColor }; } diff --git a/MareSynchronos/UI/Components/DrawGroupPair.cs b/MareSynchronos/UI/Components/DrawGroupPair.cs index 41c0a70..488aafb 100644 --- a/MareSynchronos/UI/Components/DrawGroupPair.cs +++ b/MareSynchronos/UI/Components/DrawGroupPair.cs @@ -201,7 +201,7 @@ public class DrawGroupPair : DrawPairBase if (individualSoundsDisabled) { var userSoundsText = "Sound sync disabled with " + _pair.UserData.AliasOrUID; - _uiSharedService.IconText(FontAwesomeIcon.VolumeOff); + _uiSharedService.IconText(FontAwesomeIcon.VolumeMute); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.TextUnformatted(userSoundsText); ImGui.NewLine(); @@ -212,7 +212,7 @@ public class DrawGroupPair : DrawPairBase if (individualAnimDisabled) { var userAnimText = "Animation sync disabled with " + _pair.UserData.AliasOrUID; - _uiSharedService.IconText(FontAwesomeIcon.Stop); + _uiSharedService.IconText(FontAwesomeIcon.WindowClose); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.TextUnformatted(userAnimText); ImGui.NewLine(); @@ -223,7 +223,7 @@ public class DrawGroupPair : DrawPairBase if (individualVFXDisabled) { var userVFXText = "VFX sync disabled with " + _pair.UserData.AliasOrUID; - _uiSharedService.IconText(FontAwesomeIcon.Circle); + _uiSharedService.IconText(FontAwesomeIcon.TimesCircle); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.TextUnformatted(userVFXText); ImGui.NewLine(); @@ -248,7 +248,7 @@ public class DrawGroupPair : DrawPairBase if (soundsDisabled) { var userSoundsText = "Sound sync disabled by " + _pair.UserData.AliasOrUID; - _uiSharedService.IconText(FontAwesomeIcon.VolumeOff); + _uiSharedService.IconText(FontAwesomeIcon.VolumeMute); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.TextUnformatted(userSoundsText); } @@ -256,7 +256,7 @@ public class DrawGroupPair : DrawPairBase if (animDisabled) { var userAnimText = "Animation sync disabled by " + _pair.UserData.AliasOrUID; - _uiSharedService.IconText(FontAwesomeIcon.Stop); + _uiSharedService.IconText(FontAwesomeIcon.WindowClose); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.TextUnformatted(userAnimText); } @@ -264,7 +264,7 @@ public class DrawGroupPair : DrawPairBase if (vfxDisabled) { var userVFXText = "VFX sync disabled by " + _pair.UserData.AliasOrUID; - _uiSharedService.IconText(FontAwesomeIcon.Circle); + _uiSharedService.IconText(FontAwesomeIcon.TimesCircle); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.TextUnformatted(userVFXText); } @@ -383,4 +383,4 @@ public class DrawGroupPair : DrawPairBase return pos - spacing; } -} \ No newline at end of file +} diff --git a/MareSynchronos/UI/Components/DrawUserPair.cs b/MareSynchronos/UI/Components/DrawUserPair.cs index 06e102c..f6e4b3c 100644 --- a/MareSynchronos/UI/Components/DrawUserPair.cs +++ b/MareSynchronos/UI/Components/DrawUserPair.cs @@ -54,7 +54,7 @@ public class DrawUserPair : DrawPairBase ImGui.SameLine(); ImGui.SetCursorPosY(textPosY); ImGui.PushFont(UiBuilder.IconFont); - UiSharedService.ColorText(FontAwesomeIcon.ArrowUp.ToIconString(), ImGuiColors.DalamudRed); + UiSharedService.ColorText(FontAwesomeIcon.ArrowUp.ToIconString(), UiSharedService.AccentColor); ImGui.PopFont(); UiSharedService.AttachToolTip(_pair.UserData.AliasOrUID + " has not added you back"); } @@ -163,7 +163,7 @@ public class DrawUserPair : DrawPairBase if (individualSoundsDisabled) { var userSoundsText = "Sound sync disabled with " + _pair.UserData.AliasOrUID; - _uiSharedService.IconText(FontAwesomeIcon.VolumeOff); + _uiSharedService.IconText(FontAwesomeIcon.VolumeMute); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.TextUnformatted(userSoundsText); ImGui.NewLine(); @@ -174,7 +174,7 @@ public class DrawUserPair : DrawPairBase if (individualAnimDisabled) { var userAnimText = "Animation sync disabled with " + _pair.UserData.AliasOrUID; - _uiSharedService.IconText(FontAwesomeIcon.Stop); + _uiSharedService.IconText(FontAwesomeIcon.WindowClose); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.TextUnformatted(userAnimText); ImGui.NewLine(); @@ -185,7 +185,7 @@ public class DrawUserPair : DrawPairBase if (individualVFXDisabled) { var userVFXText = "VFX sync disabled with " + _pair.UserData.AliasOrUID; - _uiSharedService.IconText(FontAwesomeIcon.Circle); + _uiSharedService.IconText(FontAwesomeIcon.TimesCircle); ImGui.SameLine(40 * ImGuiHelpers.GlobalScale); ImGui.TextUnformatted(userVFXText); ImGui.NewLine(); @@ -267,7 +267,7 @@ public class DrawUserPair : DrawPairBase var isDisableSounds = entry.UserPair!.OwnPermissions.IsDisableSounds(); string disableSoundsText = isDisableSounds ? "Enable sound sync" : "Disable sound sync"; - var disableSoundsIcon = isDisableSounds ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeMute; + var disableSoundsIcon = isDisableSounds ? FontAwesomeIcon.VolumeMute : FontAwesomeIcon.VolumeUp; if (_uiSharedService.IconTextButton(disableSoundsIcon, disableSoundsText)) { var permissions = entry.UserPair.OwnPermissions; @@ -278,7 +278,7 @@ public class DrawUserPair : DrawPairBase var isDisableAnims = entry.UserPair!.OwnPermissions.IsDisableAnimations(); string disableAnimsText = isDisableAnims ? "Enable animation sync" : "Disable animation sync"; - var disableAnimsIcon = isDisableAnims ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop; + var disableAnimsIcon = isDisableAnims ? FontAwesomeIcon.WindowClose : FontAwesomeIcon.Running; if (_uiSharedService.IconTextButton(disableAnimsIcon, disableAnimsText)) { var permissions = entry.UserPair.OwnPermissions; @@ -289,7 +289,7 @@ public class DrawUserPair : DrawPairBase var isDisableVFX = entry.UserPair!.OwnPermissions.IsDisableVFX(); string disableVFXText = isDisableVFX ? "Enable VFX sync" : "Disable VFX sync"; - var disableVFXIcon = isDisableVFX ? FontAwesomeIcon.Sun : FontAwesomeIcon.Circle; + var disableVFXIcon = isDisableVFX ? FontAwesomeIcon.TimesCircle : FontAwesomeIcon.Sun; if (_uiSharedService.IconTextButton(disableVFXIcon, disableVFXText)) { var permissions = entry.UserPair.OwnPermissions; diff --git a/MareSynchronos/UI/Components/GroupPanel.cs b/MareSynchronos/UI/Components/GroupPanel.cs index f63412f..07abb5b 100644 --- a/MareSynchronos/UI/Components/GroupPanel.cs +++ b/MareSynchronos/UI/Components/GroupPanel.cs @@ -627,12 +627,12 @@ internal sealed class GroupPanel bool showInfoIcon = !invitesEnabled || soundsDisabled || animDisabled || vfxDisabled || userSoundsDisabled || userAnimDisabled || userVFXDisabled; var lockedIcon = invitesEnabled ? FontAwesomeIcon.LockOpen : FontAwesomeIcon.Lock; - var animIcon = animDisabled ? FontAwesomeIcon.Stop : FontAwesomeIcon.Running; - var soundsIcon = soundsDisabled ? FontAwesomeIcon.VolumeOff : FontAwesomeIcon.VolumeUp; - var vfxIcon = vfxDisabled ? FontAwesomeIcon.Circle : FontAwesomeIcon.Sun; - var userAnimIcon = userAnimDisabled ? FontAwesomeIcon.Stop : FontAwesomeIcon.Running; - var userSoundsIcon = userSoundsDisabled ? FontAwesomeIcon.VolumeOff : FontAwesomeIcon.VolumeUp; - var userVFXIcon = userVFXDisabled ? FontAwesomeIcon.Circle : FontAwesomeIcon.Sun; + var animIcon = animDisabled ? FontAwesomeIcon.WindowClose : FontAwesomeIcon.Running; + var soundsIcon = soundsDisabled ? FontAwesomeIcon.VolumeMute : FontAwesomeIcon.VolumeUp; + var vfxIcon = vfxDisabled ? FontAwesomeIcon.TimesCircle : FontAwesomeIcon.Sun; + var userAnimIcon = userAnimDisabled ? FontAwesomeIcon.WindowClose : FontAwesomeIcon.Running; + var userSoundsIcon = userSoundsDisabled ? FontAwesomeIcon.VolumeMute : FontAwesomeIcon.VolumeUp; + var userVFXIcon = userVFXDisabled ? FontAwesomeIcon.TimesCircle : FontAwesomeIcon.Sun; var iconSize = UiSharedService.GetIconSize(infoIcon); var barbuttonSize = _uiShared.GetIconButtonSize(FontAwesomeIcon.Bars); diff --git a/MareSynchronos/UI/Components/Popup/ReportPopupHandler.cs b/MareSynchronos/UI/Components/Popup/ReportPopupHandler.cs index 659e5e0..6c08332 100644 --- a/MareSynchronos/UI/Components/Popup/ReportPopupHandler.cs +++ b/MareSynchronos/UI/Components/Popup/ReportPopupHandler.cs @@ -35,7 +35,7 @@ internal class ReportPopupHandler : IPopupHandler UiSharedService.TextWrapped($"Note: Sending a report will disable the offending profile globally.{Environment.NewLine}" + $"The report will be sent to the team of your currently connected server.{Environment.NewLine}" + $"Depending on the severity of the offense the users profile or account can be permanently disabled or banned."); - UiSharedService.ColorTextWrapped("Report spam and wrong reports will not be tolerated and can lead to permanent account suspension.", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped("Report spam and wrong reports will not be tolerated and can lead to permanent account suspension.", UiSharedService.AccentColor); UiSharedService.ColorTextWrapped("This is not for reporting misbehavior but solely for the actual profile. " + "Reports that are not solely for the profile will be ignored.", ImGuiColors.DalamudYellow); diff --git a/MareSynchronos/UI/DataAnalysisUi.cs b/MareSynchronos/UI/DataAnalysisUi.cs index 15add8f..fd2759e 100644 --- a/MareSynchronos/UI/DataAnalysisUi.cs +++ b/MareSynchronos/UI/DataAnalysisUi.cs @@ -285,7 +285,7 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase { UiSharedService.ColorText("WARNING BC7 CONVERSION:", ImGuiColors.DalamudYellow); ImGui.SameLine(); - UiSharedService.ColorText("Converting textures to BC7 is irreversible!", ImGuiColors.DalamudRed); + UiSharedService.ColorText("Converting textures to BC7 is irreversible!", UiSharedService.AccentColor); UiSharedService.ColorTextWrapped("- Converting textures to BC7 will reduce their size (compressed and uncompressed) drastically. It is recommended to be used for large (4k+) textures." + Environment.NewLine + "- Some textures, especially ones utilizing colorsets, might not be suited for BC7 conversion and might produce visual artifacts." + Environment.NewLine + "- Before converting textures, make sure to have the original files of the mod you are converting so you can reimport it in case of issues." + diff --git a/MareSynchronos/UI/EditProfileUi.cs b/MareSynchronos/UI/EditProfileUi.cs index 4f4f623..cd1f81f 100644 --- a/MareSynchronos/UI/EditProfileUi.cs +++ b/MareSynchronos/UI/EditProfileUi.cs @@ -12,6 +12,7 @@ using MareSynchronos.Services.ServerConfiguration; using MareSynchronos.Utils; using MareSynchronos.WebAPI; using Microsoft.Extensions.Logging; +using System.Numerics; namespace MareSynchronos.UI; @@ -65,12 +66,13 @@ public class EditProfileUi : WindowMediatorSubscriberBase protected override void DrawInternal() { _uiSharedService.BigText("Current Profile (as saved on server)"); + ImGuiHelpers.ScaledDummy(new Vector2(0f, ImGui.GetStyle().ItemSpacing.Y / 2)); var profile = _mareProfileManager.GetMareProfile(new UserData(_apiController.UID)); if (profile.IsFlagged) { - UiSharedService.ColorTextWrapped(profile.Description, ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped(profile.Description, UiSharedService.AccentColor); return; } @@ -87,13 +89,12 @@ public class EditProfileUi : WindowMediatorSubscriberBase _descriptionText = _profileDescription; } + var spacing = ImGui.GetStyle().ItemSpacing.X; if (_pfpTextureWrap != null) { ImGui.Image(_pfpTextureWrap.Handle, ImGuiHelpers.ScaledVector2(_pfpTextureWrap.Width, _pfpTextureWrap.Height)); + ImGuiHelpers.ScaledRelativeSameLine(256, spacing); } - - var spacing = ImGui.GetStyle().ItemSpacing.X; - ImGuiHelpers.ScaledRelativeSameLine(256, spacing); using (_uiSharedService.GameFont.Push()) { var descriptionTextSize = ImGui.CalcTextSize(profile.Description, hideTextAfterDoubleHash: false, 256f); @@ -157,7 +158,7 @@ public class EditProfileUi : WindowMediatorSubscriberBase UiSharedService.AttachToolTip("Clear your currently uploaded profile picture"); if (_showFileDialogError) { - UiSharedService.ColorTextWrapped("The profile picture must be a PNG file with a maximum height and width of 256px and 250KiB size", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped("The profile picture must be a PNG file with a maximum height and width of 256px and 250KiB size", UiSharedService.AccentColor); } var isNsfw = profile.IsNSFW; if (ImGui.Checkbox("Profile is NSFW", ref isNsfw)) @@ -217,4 +218,4 @@ public class EditProfileUi : WindowMediatorSubscriberBase base.Dispose(disposing); _pfpTextureWrap?.Dispose(); } -} \ No newline at end of file +} diff --git a/MareSynchronos/UI/EventViewerUI.cs b/MareSynchronos/UI/EventViewerUI.cs index 5ff52ee..1e19d51 100644 --- a/MareSynchronos/UI/EventViewerUI.cs +++ b/MareSynchronos/UI/EventViewerUI.cs @@ -175,7 +175,7 @@ internal class EventViewerUI : WindowMediatorSubscriberBase { EventSeverity.Informational => new Vector4(), EventSeverity.Warning => ImGuiColors.DalamudYellow, - EventSeverity.Error => ImGuiColors.DalamudRed, + EventSeverity.Error => UiSharedService.AccentColor, _ => new Vector4() }; diff --git a/MareSynchronos/UI/IntroUI.cs b/MareSynchronos/UI/IntroUI.cs index 0b64c1b..726fe66 100644 --- a/MareSynchronos/UI/IntroUI.cs +++ b/MareSynchronos/UI/IntroUI.cs @@ -69,17 +69,17 @@ public partial class IntroUi : WindowMediatorSubscriberBase return _uiShared.ApiController.ServerState switch { ServerState.Connecting => ImGuiColors.DalamudYellow, - ServerState.Reconnecting => ImGuiColors.DalamudRed, + ServerState.Reconnecting => UiSharedService.AccentColor, ServerState.Connected => ImGuiColors.HealerGreen, ServerState.Disconnected => ImGuiColors.DalamudYellow, ServerState.Disconnecting => ImGuiColors.DalamudYellow, - ServerState.Unauthorized => ImGuiColors.DalamudRed, - ServerState.VersionMisMatch => ImGuiColors.DalamudRed, - ServerState.Offline => ImGuiColors.DalamudRed, + ServerState.Unauthorized => UiSharedService.AccentColor, + ServerState.VersionMisMatch => UiSharedService.AccentColor, + ServerState.Offline => UiSharedService.AccentColor, ServerState.RateLimited => ImGuiColors.DalamudYellow, ServerState.NoSecretKey => ImGuiColors.DalamudYellow, ServerState.MultiChara => ImGuiColors.DalamudYellow, - _ => ImGuiColors.DalamudRed + _ => UiSharedService.AccentColor }; } @@ -140,46 +140,46 @@ public partial class IntroUi : WindowMediatorSubscriberBase { using (_uiShared.UidFont.Push()) { - ImGui.TextUnformatted("Agreement of Usage of Service"); + ImGui.TextUnformatted("Conditions d'utilisation"); } ImGui.Separator(); ImGui.SetWindowFontScale(1.5f); - string readThis = "READ THIS CAREFULLY"; + string readThis = "MERCI DE LIRE ATTENTIVEMENT"; Vector2 textSize = ImGui.CalcTextSize(readThis); ImGui.SetCursorPosX(ImGui.GetWindowSize().X / 2 - textSize.X / 2); - UiSharedService.ColorText(readThis, ImGuiColors.DalamudRed); + UiSharedService.ColorText(readThis, UiSharedService.AccentColor); ImGui.SetWindowFontScale(1.0f); ImGui.Separator(); UiSharedService.TextWrapped(""" - To use Umbra, you must be over the age of 18, or 21 in some jurisdictions. + Pour utiliser les services UmbraSync, vous devez être âgé de plus de 18 ans, où plus de 21 ans dans certaines juridictions. """); UiSharedService.TextWrapped(""" - All of the mod files currently active on your character as well as your current character state will be uploaded to the service you registered yourself at automatically. The plugin will exclusively upload the necessary mod files and not the whole mod. + Tout les mods actuellement actifs sur votre personnage et ses états associés seront automatiquement téléchargés vers le serveur UmbraSync auquel vous vous êtes inscrit.Il sera téléchargé exclusivement les fichiers nécessaires à la synchronisation et non l'intégralité du mod. """); UiSharedService.TextWrapped(""" - If you are on a data capped internet connection, higher fees due to data usage depending on the amount of downloaded and uploaded mod files might occur. Mod files will be compressed on up- and download to save on bandwidth usage. Due to varying up- and download speeds, changes in characters might not be visible immediately. Files present on the service that already represent your active mod files will not be uploaded again. + Si vous disposez d'une connexion Internet limitée, des frais supplémentaires peuvent s'appliquer en fonction du nombre de fichiers envoyés et reçus. Les fichiers seront compressés afin d'économiser la bande passante. En raison des variations de vitesse de débit, les sychronisations peuvent ne pas être visible immédiatement. """); UiSharedService.TextWrapped(""" - The mod files you are uploading are confidential and will not be distributed to parties other than the ones who are requesting the exact same mod files. Please think about who you are going to pair since it is unavoidable that they will receive and locally cache the necessary mod files that you have currently in use. Locally cached mod files will have arbitrary file names to discourage attempts at replicating the original mod. + Les fichiers téléchargés sont confidentiels et ne seront pas distribués à des solutions tierces où autres personnes. Uniquement les personnes avec qui vous êtes appairés demandent exactement les mêmes fichiers. Réfléchissez donc bien avec qui vous allez vous appairer. """); UiSharedService.TextWrapped(""" - The plugin creator tried their best to keep you secure. However, there is no guarantee for 100% security. Do not blindly pair your client with everyone. + Le gentil dev' a fait de son mieux pour assurer votre sécurité. Cependant le risque 0 n'existe pas. Ne vous appairez pas aveuglément avec n'importe qui. """); UiSharedService.TextWrapped(""" - Mod files that are saved on the service will remain on the service as long as there are requests for the files from clients. After a period of not being used, the mod files will be automatically deleted. + Après une periode d'inactivité, les mods enregistrés sur le serveur UmbraSync seront automatiquement supprimés. """); UiSharedService.TextWrapped(""" - Accounts that are inactive for ninety (90) days will be deleted for privacy reasons. + Les comptes inactifs pendant 90 jours seront supprimés pour des raisons de stockage et de confidentialité. """); UiSharedService.TextWrapped(""" - Umbra is operated from servers located in the European Union. You agree not to upload any content to the service that violates EU law; and more specifically, German law. + L'infrastructure Umbrasync est hebergé dans l'Union Européenne (Allemagne) et en Suisse. Vous acceptez alors de ne pas télécharger de contenu qui pourrait aller à l'encontre des législations de ces deux pays. """); UiSharedService.TextWrapped(""" - You may delete your account at any time from within the Settings panel of the plugin. Any mods unique to you will then be removed from the server within 14 days. + Vous pouvez supprimer votre compte à tout moment. Votre compte et toutes les données associées seront supprimés dans un délai de 14 jours. """); UiSharedService.TextWrapped(""" - This service is provided as-is. + Ce service est fourni tel quel. """); ImGui.Separator(); @@ -208,7 +208,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase if (!_uiShared.HasValidPenumbraModPath) { - UiSharedService.ColorTextWrapped("You do not have a valid Penumbra path set. Open Penumbra and set up a valid path for the mod directory.", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped("You do not have a valid Penumbra path set. Open Penumbra and set up a valid path for the mod directory.", UiSharedService.AccentColor); } else { @@ -330,11 +330,11 @@ public partial class IntroUi : WindowMediatorSubscriberBase ImGui.InputText("", ref _secretKey, 64); if (_secretKey.Length > 0 && _secretKey.Length != 64) { - UiSharedService.ColorTextWrapped("Your secret key must be exactly 64 characters long.", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped("Your secret key must be exactly 64 characters long.", UiSharedService.AccentColor); } else if (_secretKey.Length == 64 && !HexRegex().IsMatch(_secretKey)) { - UiSharedService.ColorTextWrapped("Your secret key can only contain ABCDEF and the numbers 0-9.", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped("Your secret key can only contain ABCDEF and the numbers 0-9.", UiSharedService.AccentColor); } else if (_secretKey.Length == 64) { diff --git a/MareSynchronos/UI/PopoutProfileUi.cs b/MareSynchronos/UI/PopoutProfileUi.cs index ea540ca..8bce2e6 100644 --- a/MareSynchronos/UI/PopoutProfileUi.cs +++ b/MareSynchronos/UI/PopoutProfileUi.cs @@ -113,7 +113,7 @@ public class PopoutProfileUi : WindowMediatorSubscriberBase UiSharedService.ColorText(note, ImGuiColors.DalamudGrey); } string status = _pair.IsVisible ? "Visible" : (_pair.IsOnline ? "Online" : "Offline"); - UiSharedService.ColorText(status, (_pair.IsVisible || _pair.IsOnline) ? ImGuiColors.HealerGreen : ImGuiColors.DalamudRed); + UiSharedService.ColorText(status, (_pair.IsVisible || _pair.IsOnline) ? ImGuiColors.HealerGreen : UiSharedService.AccentColor); if (_pair.IsVisible) { ImGui.SameLine(); diff --git a/MareSynchronos/UI/SettingsUi.cs b/MareSynchronos/UI/SettingsUi.cs index 5cada1e..08ebf05 100644 --- a/MareSynchronos/UI/SettingsUi.cs +++ b/MareSynchronos/UI/SettingsUi.cs @@ -657,7 +657,7 @@ public class SettingsUi : WindowMediatorSubscriberBase else if (_ipcProvider.MarePluginEnabled) UiSharedService.ColorTextWrapped("Umbra API inactive: Umbra plugin is loaded", ImGuiColors.DalamudYellow); else - UiSharedService.ColorTextWrapped("Umbra API inactive: Unknown reason", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped("Umbra API inactive: Unknown reason", UiSharedService.AccentColor); } } @@ -991,7 +991,7 @@ public class SettingsUi : WindowMediatorSubscriberBase } else if (_notesSuccessfullyApplied.HasValue && !_notesSuccessfullyApplied.Value) { - UiSharedService.ColorTextWrapped("Attempt to import notes from clipboard failed. Check formatting and try again", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped("Attempt to import notes from clipboard failed. Check formatting and try again", UiSharedService.AccentColor); } var openPopupOnAddition = _configService.Current.OpenPopupOnAdd; @@ -1122,6 +1122,29 @@ public class SettingsUi : WindowMediatorSubscriberBase } _uiShared.DrawHelpText("Ajoute une bulle '...' sur la plaque des paires en train d'écrire."); + using (ImRaii.Disabled(!typingIndicatorNameplates)) + { + using var indentTyping = ImRaii.PushIndent(); + var bubbleSize = _configService.Current.TypingIndicatorBubbleSize; + TypingIndicatorBubbleSize? selectedBubbleSize = _uiShared.DrawCombo("Taille de la bulle de frappe##typingBubbleSize", + Enum.GetValues(), + size => size switch + { + TypingIndicatorBubbleSize.Small => "Petite", + TypingIndicatorBubbleSize.Medium => "Moyenne", + TypingIndicatorBubbleSize.Large => "Grande", + _ => size.ToString() + }, + null, + bubbleSize); + + if (selectedBubbleSize.HasValue && selectedBubbleSize.Value != bubbleSize) + { + _configService.Current.TypingIndicatorBubbleSize = selectedBubbleSize.Value; + _configService.Save(); + } + } + if (ImGui.Checkbox("Tracer la frappe dans la liste de groupe", ref typingIndicatorPartyList)) { _configService.Current.TypingIndicatorShowOnPartyList = typingIndicatorPartyList; @@ -1318,7 +1341,7 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.SameLine(); using (ImRaii.PushColor(ImGuiCol.Text, UiSharedService.AccentColor, totalVramBytes < 2.0 * 1024.0 * 1024.0 * 1024.0)) using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, totalVramBytes >= 4.0 * 1024.0 * 1024.0 * 1024.0)) - using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed, totalVramBytes >= 6.0 * 1024.0 * 1024.0 * 1024.0)) + using (ImRaii.PushColor(ImGuiCol.Text, UiSharedService.AccentColor, totalVramBytes >= 6.0 * 1024.0 * 1024.0 * 1024.0)) ImGui.TextUnformatted($"{totalVramBytes / 1024.0 / 1024.0 / 1024.0:0.00} GiB"); ImGui.Separator(); @@ -1920,6 +1943,11 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.Separator(); if (ImGui.BeginTabBar("mainTabBar")) { + var accent = UiSharedService.AccentColor; + var accentColor = ImGui.ColorConvertFloat4ToU32(accent); + ImGui.PushStyleColor(ImGuiCol.TabActive, accentColor); + ImGui.PushStyleColor(ImGuiCol.TabHovered, accentColor); + if (ImGui.BeginTabItem("General")) { DrawGeneral(); @@ -1957,6 +1985,7 @@ public class SettingsUi : WindowMediatorSubscriberBase DrawAdvanced(); ImGui.EndTabItem(); } + ImGui.PopStyleColor(2); ImGui.EndTabBar(); } diff --git a/MareSynchronos/UI/StandaloneProfileUi.cs b/MareSynchronos/UI/StandaloneProfileUi.cs index 469ef19..810bf6e 100644 --- a/MareSynchronos/UI/StandaloneProfileUi.cs +++ b/MareSynchronos/UI/StandaloneProfileUi.cs @@ -111,7 +111,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase UiSharedService.ColorText(note, ImGuiColors.DalamudGrey); } string status = Pair.IsVisible ? "Visible" : (Pair.IsOnline ? "Online" : "Offline"); - UiSharedService.ColorText(status, (Pair.IsVisible || Pair.IsOnline) ? ImGuiColors.HealerGreen : ImGuiColors.DalamudRed); + UiSharedService.ColorText(status, (Pair.IsVisible || Pair.IsOnline) ? ImGuiColors.HealerGreen : UiSharedService.AccentColor); if (Pair.IsVisible) { ImGui.SameLine(); diff --git a/MareSynchronos/UI/SyncshellAdminUI.cs b/MareSynchronos/UI/SyncshellAdminUI.cs index cf87eb9..b72fe79 100644 --- a/MareSynchronos/UI/SyncshellAdminUI.cs +++ b/MareSynchronos/UI/SyncshellAdminUI.cs @@ -374,7 +374,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase ImGui.TextUnformatted("Sound Sync"); _uiSharedService.BooleanToColoredIcon(!isDisableSounds); ImGui.SameLine(230); - if (_uiSharedService.IconTextButton(isDisableSounds ? FontAwesomeIcon.VolumeUp : FontAwesomeIcon.VolumeMute, + if (_uiSharedService.IconTextButton(isDisableSounds ? FontAwesomeIcon.VolumeMute : FontAwesomeIcon.VolumeUp, isDisableSounds ? "Enable sound sync" : "Disable sound sync")) { perm.SetDisableSounds(!perm.IsDisableSounds()); @@ -385,7 +385,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase ImGui.TextUnformatted("Animation Sync"); _uiSharedService.BooleanToColoredIcon(!isDisableAnimations); ImGui.SameLine(230); - if (_uiSharedService.IconTextButton(isDisableAnimations ? FontAwesomeIcon.Running : FontAwesomeIcon.Stop, + if (_uiSharedService.IconTextButton(isDisableAnimations ? FontAwesomeIcon.WindowClose : FontAwesomeIcon.Running, isDisableAnimations ? "Enable animation sync" : "Disable animation sync")) { perm.SetDisableAnimations(!perm.IsDisableAnimations()); @@ -396,7 +396,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase ImGui.TextUnformatted("VFX Sync"); _uiSharedService.BooleanToColoredIcon(!isDisableVfx); ImGui.SameLine(230); - if (_uiSharedService.IconTextButton(isDisableVfx ? FontAwesomeIcon.Sun : FontAwesomeIcon.Circle, + if (_uiSharedService.IconTextButton(isDisableVfx ? FontAwesomeIcon.TimesCircle : FontAwesomeIcon.Sun, isDisableVfx ? "Enable VFX sync" : "Disable VFX sync")) { perm.SetDisableVFX(!perm.IsDisableVFX()); diff --git a/MareSynchronos/UI/TypingIndicatorOverlay.cs b/MareSynchronos/UI/TypingIndicatorOverlay.cs index 0f7bcaa..fef7edf 100644 --- a/MareSynchronos/UI/TypingIndicatorOverlay.cs +++ b/MareSynchronos/UI/TypingIndicatorOverlay.cs @@ -1,16 +1,19 @@ +using System; +using System.Collections.Generic; using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Utility; using Dalamud.Plugin.Services; +using MareSynchronos.API.Data; using MareSynchronos.MareConfiguration; +using MareSynchronos.MareConfiguration.Models; using MareSynchronos.PlayerData.Pairs; using MareSynchronos.Services; using MareSynchronos.Services.Mediator; -using Microsoft.Extensions.Logging; using MareSynchronos.WebAPI; -using MareSynchronos.API.Data; -using FFXIVClientStructs.Interop; +using Microsoft.Extensions.Logging; using Dalamud.Interface.Textures.TextureWraps; +using FFXIVClientStructs.Interop; using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -72,22 +75,23 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase var showParty = _configService.Current.TypingIndicatorShowOnPartyList; var showNameplates = _configService.Current.TypingIndicatorShowOnNameplates; + if (!showParty && !showNameplates) return; - var drawList = ImGui.GetWindowDrawList(); + var overlayDrawList = ImGui.GetWindowDrawList(); var activeTypers = _typingStateService.GetActiveTypers(TypingDisplayTime); var hasSelf = _typingStateService.TryGetSelfTyping(TypingDisplayTime, out var selfStart, out var selfLast); var now = DateTime.UtcNow; if (showParty) { - DrawPartyIndicators(drawList, activeTypers, hasSelf, now, selfStart, selfLast); + DrawPartyIndicators(overlayDrawList, activeTypers, hasSelf, now, selfStart, selfLast); } if (showNameplates) { - DrawNameplateIndicators(drawList, activeTypers, hasSelf, now, selfStart, selfLast); + DrawNameplateIndicators(ImGui.GetWindowDrawList(), activeTypers, hasSelf, now, selfStart, selfLast); } } @@ -169,7 +173,7 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase bool selfActive, DateTime now, DateTime selfStart, DateTime selfLast) { var iconWrap = _textureProvider.GetFromGameIcon(NameplateIconId).GetWrapOrEmpty(); - if (iconWrap == null) + if (iconWrap == null || iconWrap.Handle == IntPtr.Zero) return; if (selfActive @@ -178,12 +182,9 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase && (now - selfLast) <= TypingDisplayFade) { var selfId = GetEntityId(_clientState.LocalPlayer.Address); - if (selfId != 0) + if (selfId != 0 && !TryDrawNameplateBubble(drawList, iconWrap, selfId)) { - if (!DrawNameplateIcon(drawList, iconWrap, selfId)) - { - DrawWorldFallbackIcon(drawList, iconWrap, _clientState.LocalPlayer.Position); - } + DrawWorldFallbackIcon(drawList, iconWrap, _clientState.LocalPlayer.Position); } } @@ -202,11 +203,9 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase _logger.LogInformation("TypingIndicator: no pair found for {uid}, attempting fallback", uid); } - var drawnOnNameplate = objectId != uint.MaxValue && objectId != 0 && DrawNameplateIcon(drawList, iconWrap, objectId); - - if (drawnOnNameplate) + if (objectId != uint.MaxValue && objectId != 0 && TryDrawNameplateBubble(drawList, iconWrap, objectId)) { - _logger.LogTrace("TypingIndicator: drew nameplate icon for {uid} (objectId={objectId})", uid, objectId); + _logger.LogTrace("TypingIndicator: drew nameplate bubble for {uid} (objectId={objectId})", uid, objectId); continue; } @@ -228,8 +227,28 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase } } - private unsafe bool DrawNameplateIcon(ImDrawListPtr drawList, IDalamudTextureWrap textureWrap, uint objectId) + private Vector2 GetConfiguredBubbleSize(float scaleX, float scaleY, bool isNameplateVisible, TypingIndicatorBubbleSize? overrideSize = null) { + var sizeSetting = overrideSize ?? _configService.Current.TypingIndicatorBubbleSize; + var baseSize = sizeSetting switch + { + TypingIndicatorBubbleSize.Small when isNameplateVisible => 32f, + TypingIndicatorBubbleSize.Medium when isNameplateVisible => 44f, + TypingIndicatorBubbleSize.Large when isNameplateVisible => 56f, + TypingIndicatorBubbleSize.Small => 15f, + TypingIndicatorBubbleSize.Medium => 25f, + TypingIndicatorBubbleSize.Large => 35f, + _ => 35f, + }; + + return new Vector2(baseSize * scaleX, baseSize * scaleY); + } + + private unsafe bool TryDrawNameplateBubble(ImDrawListPtr drawList, IDalamudTextureWrap textureWrap, uint objectId) + { + if (textureWrap == null || textureWrap.Handle == IntPtr.Zero) + return false; + var framework = Framework.Instance(); if (framework == null) return false; @@ -238,6 +257,13 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase if (ui3D == null) return false; + var addonNamePlate = (AddonNamePlate*)_gameGui.GetAddonByName("NamePlate", 1).Address; + if (addonNamePlate == null) + return false; + + AddonNamePlate.NamePlateObject* namePlate = null; + float distance = 0f; + for (var i = 0; i < ui3D->NamePlateObjectInfoCount; i++) { var objectInfo = ui3D->NamePlateObjectInfoPointers[i]; @@ -247,47 +273,71 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase if (objectInfo.Value->GameObject->EntityId != objectId) continue; - var addonNamePlate = (AddonNamePlate*)_gameGui.GetAddonByName("NamePlate", 1).Address; - if (addonNamePlate == null) + if (objectInfo.Value->GameObject->YalmDistanceFromPlayerX > 35f) return false; - var npObject = &addonNamePlate->NamePlateObjectArray[objectInfo.Value->NamePlateIndex]; - if (npObject == null || npObject->RootComponentNode == null) - return false; + namePlate = &addonNamePlate->NamePlateObjectArray[objectInfo.Value->NamePlateIndex]; + distance = objectInfo.Value->GameObject->YalmDistanceFromPlayerX; + break; + } - var iconNode = npObject->RootComponentNode->Component->UldManager.NodeList[0]; - if (iconNode == null) - return false; + if (namePlate == null || namePlate->RootComponentNode == null) + return false; - var distance = objectInfo.Value->GameObject->YalmDistanceFromPlayerX; - var scaleX = npObject->RootComponentNode->AtkResNode.ScaleX; - var scaleY = npObject->RootComponentNode->AtkResNode.ScaleY; - var iconSize = new Vector2(40f * scaleX, 40f * scaleY); + var iconNode = namePlate->RootComponentNode->Component->UldManager.NodeList[0]; + if (iconNode == null) + return false; - var iconPos = new Vector2( - npObject->RootComponentNode->AtkResNode.X + iconNode->X + iconNode->Width, - npObject->RootComponentNode->AtkResNode.Y + iconNode->Y); + var scaleX = namePlate->RootComponentNode->AtkResNode.ScaleX; + var scaleY = namePlate->RootComponentNode->AtkResNode.ScaleY; + var iconVisible = iconNode->IsVisible(); + var sizeScaleFactor = 1f; + var scaleVector = new Vector2(scaleX, scaleY); + var rootPosition = new Vector2(namePlate->RootComponentNode->AtkResNode.X, namePlate->RootComponentNode->AtkResNode.Y); + var iconLocalPosition = new Vector2(iconNode->X, iconNode->Y) * scaleVector; + var iconDimensions = new Vector2(iconNode->Width, iconNode->Height) * scaleVector; - var iconOffset = new Vector2(distance / 1.5f, distance / 3f); + if (!iconVisible) + { + sizeScaleFactor = 2.5f; + var anchor = rootPosition + iconLocalPosition + new Vector2(iconDimensions.X * 0.5f, 0f); + + var distanceOffset = new Vector2(0f, -16f + distance) * scaleVector; if (iconNode->Height == 24) { - iconOffset.Y -= 8f; + distanceOffset.Y += 16f * scaleY; } + distanceOffset.Y += 64f * scaleY; - iconPos += iconOffset; - var extraScaleX = Math.Max(scaleX - 1f, 0f); - var extraScaleY = Math.Max(scaleY - 1f, 0f); - if (extraScaleX > 0f || extraScaleY > 0f) - { - iconPos -= new Vector2(extraScaleX * 14f, extraScaleY * 14f); - } + var referenceSize = GetConfiguredBubbleSize(scaleX * sizeScaleFactor, scaleY * sizeScaleFactor, false, TypingIndicatorBubbleSize.Small); + var manualOffset = new Vector2(referenceSize.X * 2.00f, referenceSize.Y * 2.00f); - drawList.AddImage(textureWrap.Handle, iconPos, iconPos + iconSize, Vector2.Zero, Vector2.One, + var iconSizeHidden = GetConfiguredBubbleSize(scaleX * sizeScaleFactor, scaleY * sizeScaleFactor, false); + var center = anchor + distanceOffset + manualOffset; + var topLeft = center - (iconSizeHidden / 2f); + + drawList.AddImage(textureWrap.Handle, topLeft, topLeft + iconSizeHidden, Vector2.Zero, Vector2.One, ImGui.ColorConvertFloat4ToU32(new Vector4(1f, 1f, 1f, 0.95f))); + return true; } - return false; + var iconPos = rootPosition + iconLocalPosition + new Vector2(iconDimensions.X, 0f); + + var iconOffset = new Vector2(distance / 1.5f, distance / 3.5f) * scaleVector; + if (iconNode->Height == 24) + { + iconOffset.Y -= 8f * scaleY; + } + + iconPos += iconOffset; + + var iconSize = GetConfiguredBubbleSize(scaleX * sizeScaleFactor, scaleY * sizeScaleFactor, true); + + drawList.AddImage(textureWrap.Handle, iconPos, iconPos + iconSize, Vector2.Zero, Vector2.One, + ImGui.ColorConvertFloat4ToU32(new Vector4(1f, 1f, 1f, 0.95f))); + + return true; } private void DrawWorldFallbackIcon(ImDrawListPtr drawList, IDalamudTextureWrap textureWrap, Vector3 worldPosition) @@ -296,7 +346,7 @@ public sealed class TypingIndicatorOverlay : WindowMediatorSubscriberBase if (!_gameGui.WorldToScreen(offsetPosition, out var screenPos)) return; - var iconSize = new Vector2(36f, 36f) * ImGuiHelpers.GlobalScale; + var iconSize = GetConfiguredBubbleSize(ImGuiHelpers.GlobalScale, ImGuiHelpers.GlobalScale, false); var iconPos = screenPos - (iconSize / 2f) - new Vector2(0f, iconSize.Y * 0.6f); drawList.AddImage(textureWrap.Handle, iconPos, iconPos + iconSize, Vector2.Zero, Vector2.One, ImGui.ColorConvertFloat4ToU32(new Vector4(1f, 1f, 1f, 0.95f))); diff --git a/MareSynchronos/UI/UISharedService.cs b/MareSynchronos/UI/UISharedService.cs index 7547fd7..73868ce 100644 --- a/MareSynchronos/UI/UISharedService.cs +++ b/MareSynchronos/UI/UISharedService.cs @@ -37,6 +37,8 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase ImGuiWindowFlags.NoScrollWithMouse; public static Vector4 AccentColor { get; set; } = ImGuiColors.DalamudViolet; + public static Vector4 AccentHoverColor { get; set; } = new Vector4(0x3A / 255f, 0x15 / 255f, 0x50 / 255f, 1f); + public static Vector4 AccentActiveColor { get; set; } = AccentHoverColor; public readonly FileDialogManager FileDialogManager; @@ -311,7 +313,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase } } - public static Vector4 GetBoolColor(bool input) => input ? AccentColor : ImGuiColors.DalamudRed; + public static Vector4 GetBoolColor(bool input) => input ? AccentColor : UiSharedService.AccentColor; public float GetIconTextButtonSize(FontAwesomeIcon icon, string text) { @@ -369,6 +371,8 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase Vector2 cursorScreenPos = ImGui.GetCursorScreenPos(); float x = vector.X + ImGui.GetStyle().FramePadding.X * 2f; float frameHeight = height ?? ImGui.GetFrameHeight(); + using var hoverColor = ImRaii.PushColor(ImGuiCol.ButtonHovered, AccentHoverColor); + using var activeColor = ImRaii.PushColor(ImGuiCol.ButtonActive, AccentActiveColor); bool result = ImGui.Button(string.Empty, new Vector2(x, frameHeight)); Vector2 pos = new Vector2(cursorScreenPos.X + ImGui.GetStyle().FramePadding.X, cursorScreenPos.Y + (height ?? ImGui.GetFrameHeight()) / 2f - (vector.Y / 2f)); @@ -379,13 +383,19 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase return result; } - private bool IconTextButtonInternal(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, float? width = null) + private bool IconTextButtonInternal(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, float? width = null, bool useAccentHover = true) { - int num = 0; + int colorsPushed = 0; if (defaultColor.HasValue) { ImGui.PushStyleColor(ImGuiCol.Button, defaultColor.Value); - num++; + colorsPushed++; + } + if (useAccentHover) + { + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, AccentHoverColor); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, AccentActiveColor); + colorsPushed += 2; } ImGui.PushID(text); @@ -405,9 +415,9 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase Vector2 pos2 = new Vector2(pos.X + vector.X + num2, cursorScreenPos.Y + ImGui.GetStyle().FramePadding.Y); windowDrawList.AddText(pos2, ImGui.GetColorU32(ImGuiCol.Text), text); ImGui.PopID(); - if (num > 0) + if (colorsPushed > 0) { - ImGui.PopStyleColor(num); + ImGui.PopStyleColor(colorsPushed); } return result; @@ -417,7 +427,8 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase { return IconTextButtonInternal(icon, text, isInPopup ? ColorHelpers.RgbaUintToVector4(ImGui.GetColorU32(ImGuiCol.PopupBg)) : null, - width <= 0 ? null : width); + width <= 0 ? null : width, + !isInPopup); } public static bool IsDirectoryWritable(string dirPath, bool throwIfFails = false) @@ -519,7 +530,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase public void BooleanToColoredIcon(bool value, bool inline = true) { using var colorgreen = ImRaii.PushColor(ImGuiCol.Text, AccentColor, value); - using var colorred = ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed, !value); + using var colorred = ImRaii.PushColor(ImGuiCol.Text, UiSharedService.AccentColor, !value); if (inline) ImGui.SameLine(); @@ -593,24 +604,24 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase if (_isPenumbraDirectory) { - ColorTextWrapped("Do not point the storage path directly to the Penumbra directory. If necessary, make a subfolder in it.", ImGuiColors.DalamudRed); + ColorTextWrapped("Do not point the storage path directly to the Penumbra directory. If necessary, make a subfolder in it.", UiSharedService.AccentColor); } else if (_isOneDrive) { - ColorTextWrapped("Do not point the storage path to a folder in OneDrive. Do not use OneDrive folders for any Mod related functionality.", ImGuiColors.DalamudRed); + ColorTextWrapped("Do not point the storage path to a folder in OneDrive. Do not use OneDrive folders for any Mod related functionality.", UiSharedService.AccentColor); } else if (!_isDirectoryWritable) { - ColorTextWrapped("The folder you selected does not exist or cannot be written to. Please provide a valid path.", ImGuiColors.DalamudRed); + ColorTextWrapped("The folder you selected does not exist or cannot be written to. Please provide a valid path.", UiSharedService.AccentColor); } else if (_cacheDirectoryHasOtherFilesThanCache) { - ColorTextWrapped("Your selected directory has files or directories inside that are not Umbra related. Use an empty directory or a previous storage directory only.", ImGuiColors.DalamudRed); + ColorTextWrapped("Your selected directory has files or directories inside that are not Umbra related. Use an empty directory or a previous storage directory only.", UiSharedService.AccentColor); } else if (!_cacheDirectoryIsValidPath) { ColorTextWrapped("Your selected directory contains illegal characters unreadable by FFXIV. " + - "Restrict yourself to latin letters (A-Z), underscores (_), dashes (-) and arabic numbers (0-9).", ImGuiColors.DalamudRed); + "Restrict yourself to latin letters (A-Z), underscores (_), dashes (-) and arabic numbers (0-9).", UiSharedService.AccentColor); } float maxCacheSize = (float)_configService.Current.MaxLocalCacheInGiB; @@ -849,7 +860,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase if (!_penumbraExists || !_glamourerExists) { - ImGui.TextColored(ImGuiColors.DalamudRed, "You need to install both Penumbra and Glamourer and keep them up to date to use Umbra."); + ImGui.TextColored(UiSharedService.AccentColor, "You need to install both Penumbra and Glamourer and keep them up to date to use Umbra."); return false; }