diff --git a/MareSynchronos/MareConfiguration/Configurations/PlayerPerformanceConfig.cs b/MareSynchronos/MareConfiguration/Configurations/PlayerPerformanceConfig.cs index 6b45ac7..74ab455 100644 --- a/MareSynchronos/MareConfiguration/Configurations/PlayerPerformanceConfig.cs +++ b/MareSynchronos/MareConfiguration/Configurations/PlayerPerformanceConfig.cs @@ -8,9 +8,10 @@ public class PlayerPerformanceConfig : IMareConfiguration public bool AutoPausePlayersExceedingThresholds { get; set; } = true; public bool NotifyAutoPauseDirectPairs { get; set; } = true; public bool NotifyAutoPauseGroupPairs { get; set; } = true; + public bool ShowSelfAnalysisWarnings { get; set; } = true; public int VRAMSizeAutoPauseThresholdMiB { get; set; } = 500; public int TrisAutoPauseThresholdThousands { get; set; } = 400; public bool IgnoreDirectPairs { get; set; } = true; public TextureShrinkMode TextureShrinkMode { get; set; } = TextureShrinkMode.Default; public bool TextureShrinkDeleteOriginal { get; set; } = false; -} \ No newline at end of file +} diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj index d403e3f..0b7986d 100644 --- a/MareSynchronos/MareSynchronos.csproj +++ b/MareSynchronos/MareSynchronos.csproj @@ -3,7 +3,7 @@ UmbraSync UmbraSync - 0.1.9.6 + 0.1.9.9 diff --git a/MareSynchronos/Services/AutoDetect/NearbyDiscoveryService.cs b/MareSynchronos/Services/AutoDetect/NearbyDiscoveryService.cs index 6baa786..ed73905 100644 --- a/MareSynchronos/Services/AutoDetect/NearbyDiscoveryService.cs +++ b/MareSynchronos/Services/AutoDetect/NearbyDiscoveryService.cs @@ -8,6 +8,7 @@ using MareSynchronos.WebAPI.AutoDetect; using Dalamud.Plugin.Services; using System.Numerics; using System.Linq; +using System.Collections.Generic; using MareSynchronos.Utils; namespace MareSynchronos.Services.AutoDetect; @@ -35,6 +36,8 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber private bool _lastAutoDetectState; private DateTime _lastHeartbeat = DateTime.MinValue; private static readonly TimeSpan HeartbeatInterval = TimeSpan.FromSeconds(75); + private readonly object _entriesLock = new(); + private List _lastEntries = []; public NearbyDiscoveryService(ILogger logger, MareMediator mediator, MareConfigService config, DiscoveryConfigProvider configProvider, DalamudUtilService dalamudUtilService, @@ -134,6 +137,22 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber return Task.CompletedTask; } + public List SnapshotEntries() + { + lock (_entriesLock) + { + return _lastEntries.ToList(); + } + } + + private void UpdateSnapshot(List entries) + { + lock (_entriesLock) + { + _lastEntries = entries.ToList(); + } + } + private static void CancelAndDispose(ref CancellationTokenSource? cts) { if (cts == null) return; @@ -443,6 +462,7 @@ public class NearbyDiscoveryService : IHostedService, IMediatorSubscriber _logger.LogDebug("Nearby: well-known not available or disabled; running in local-only mode"); } } + UpdateSnapshot(entries); _mediator.Publish(new DiscoveryListUpdated(entries)); var delayMs = Math.Max(1000, _configProvider.MinQueryIntervalMs); diff --git a/MareSynchronos/Services/CharacterAnalyzer.cs b/MareSynchronos/Services/CharacterAnalyzer.cs index 65b2cbd..6352890 100644 --- a/MareSynchronos/Services/CharacterAnalyzer.cs +++ b/MareSynchronos/Services/CharacterAnalyzer.cs @@ -4,6 +4,7 @@ using Lumina.Data.Files; using MareSynchronos.API.Data; using MareSynchronos.API.Data.Enum; using MareSynchronos.FileCache; +using MareSynchronos.MareConfiguration; using MareSynchronos.MareConfiguration.Models; using MareSynchronos.Services.Mediator; using MareSynchronos.UI; @@ -29,8 +30,9 @@ public sealed class CharacterAnalyzer : DisposableMediatorSubscriberBase private const long NotificationTriangleThreshold = 150_000; private bool _sizeWarningShown; private bool _triangleWarningShown; + private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; - public CharacterAnalyzer(ILogger logger, MareMediator mediator, FileCacheManager fileCacheManager, XivDataAnalyzer modelAnalyzer) + public CharacterAnalyzer(ILogger logger, MareMediator mediator, FileCacheManager fileCacheManager, XivDataAnalyzer modelAnalyzer, PlayerPerformanceConfigService playerPerformanceConfigService) : base(logger, mediator) { Mediator.Subscribe(this, (msg) => @@ -41,6 +43,7 @@ public sealed class CharacterAnalyzer : DisposableMediatorSubscriberBase }); _fileCacheManager = fileCacheManager; _xivDataAnalyzer = modelAnalyzer; + _playerPerformanceConfigService = playerPerformanceConfigService; } public int CurrentFile { get; internal set; } @@ -313,6 +316,12 @@ public sealed class CharacterAnalyzer : DisposableMediatorSubscriberBase return; } + if (!_playerPerformanceConfigService.Current.ShowSelfAnalysisWarnings) + { + ResetThresholdFlagsIfNeeded(summary); + return; + } + bool sizeExceeded = summary.TotalCompressedSize >= NotificationSizeThreshold; bool trianglesExceeded = summary.TotalTriangles >= NotificationTriangleThreshold; List exceededReasons = new(); diff --git a/MareSynchronos/UI/AutoDetectUi.cs b/MareSynchronos/UI/AutoDetectUi.cs index f58ef79..e926e96 100644 --- a/MareSynchronos/UI/AutoDetectUi.cs +++ b/MareSynchronos/UI/AutoDetectUi.cs @@ -24,14 +24,16 @@ public class AutoDetectUi : WindowMediatorSubscriberBase private readonly MareConfigService _configService; private readonly DalamudUtilService _dalamud; private readonly AutoDetectRequestService _requestService; + private readonly NearbyDiscoveryService _discoveryService; private readonly NearbyPendingService _pendingService; private readonly PairManager _pairManager; - private List _entries = new(); + private List _entries; private readonly HashSet _acceptInFlight = new(StringComparer.Ordinal); public AutoDetectUi(ILogger logger, MareMediator mediator, MareConfigService configService, DalamudUtilService dalamudUtilService, AutoDetectRequestService requestService, NearbyPendingService pendingService, PairManager pairManager, + NearbyDiscoveryService discoveryService, PerformanceCollectorService performanceCollectorService) : base(logger, mediator, "AutoDetect", performanceCollectorService) { @@ -40,6 +42,9 @@ public class AutoDetectUi : WindowMediatorSubscriberBase _requestService = requestService; _pendingService = pendingService; _pairManager = pairManager; + _discoveryService = discoveryService; + Mediator.Subscribe(this, OnDiscoveryUpdated); + _entries = _discoveryService.SnapshotEntries(); Flags |= ImGuiWindowFlags.NoScrollbar; SizeConstraints = new WindowSizeConstraints() @@ -214,61 +219,102 @@ public class AutoDetectUi : WindowMediatorSubscriberBase ImGuiHelpers.ScaledDummy(6); - // Table header - if (ImGui.BeginTable("autodetect-nearby", 5, ImGuiTableFlags.SizingStretchProp)) - { - ImGui.TableSetupColumn("Name"); - ImGui.TableSetupColumn("World"); - ImGui.TableSetupColumn("Distance"); - ImGui.TableSetupColumn("Status"); - ImGui.TableSetupColumn("Action"); - ImGui.TableHeadersRow(); + var sourceEntries = _entries.Count > 0 ? _entries : _discoveryService.SnapshotEntries(); + var orderedEntries = sourceEntries + .OrderBy(e => float.IsNaN(e.Distance) ? float.MaxValue : e.Distance) + .ToList(); - var data = _entries.Count > 0 ? _entries.Where(e => e.IsMatch).ToList() : new List(); - foreach (var e in data) + if (orderedEntries.Count == 0) + { + UiSharedService.ColorTextWrapped("Aucune présence UmbraSync détectée à proximité pour le moment.", ImGuiColors.DalamudGrey3); + return; + } + + if (!ImGui.BeginTable("autodetect-nearby", 5, ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.RowBg)) + { + return; + } + + ImGui.TableSetupColumn("Nom"); + ImGui.TableSetupColumn("Monde"); + ImGui.TableSetupColumn("Distance"); + ImGui.TableSetupColumn("Statut"); + ImGui.TableSetupColumn("Action"); + ImGui.TableHeadersRow(); + + for (int i = 0; i < orderedEntries.Count; i++) + { + var entry = orderedEntries[i]; + bool isMatch = entry.IsMatch; + bool alreadyPaired = IsAlreadyPairedByUidOrAlias(entry); + bool overDistance = !float.IsNaN(entry.Distance) && entry.Distance > maxDist; + bool canRequest = isMatch && entry.AcceptPairRequests && !string.IsNullOrEmpty(entry.Token) && !alreadyPaired; + + string displayName = entry.DisplayName ?? entry.Name; + string worldName = entry.WorldId == 0 + ? "-" + : (_dalamud.WorldData.Value.TryGetValue(entry.WorldId, out var mappedWorld) ? mappedWorld : entry.WorldId.ToString(CultureInfo.InvariantCulture)); + string distanceText = float.IsNaN(entry.Distance) ? "-" : $"{entry.Distance:0.0} m"; + + string status = alreadyPaired + ? "Déjà appairé" + : overDistance + ? $"Hors portée (> {maxDist} m)" + : !isMatch + ? "Umbra non activé" + : !entry.AcceptPairRequests + ? "Invitations refusées" + : string.IsNullOrEmpty(entry.Token) + ? "Indisponible" + : "Disponible"; + + ImGui.TableNextColumn(); + ImGui.TextUnformatted(displayName); + + ImGui.TableNextColumn(); + ImGui.TextUnformatted(worldName); + + ImGui.TableNextColumn(); + ImGui.TextUnformatted(distanceText); + + ImGui.TableNextColumn(); + ImGui.TextUnformatted(status); + + ImGui.TableNextColumn(); + using (ImRaii.PushId(i)) { - ImGui.TableNextColumn(); - ImGui.TextUnformatted(e.Name); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(e.WorldId == 0 ? "-" : (_dalamud.WorldData.Value.TryGetValue(e.WorldId, out var w) ? w : e.WorldId.ToString())); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(float.IsNaN(e.Distance) ? "-" : $"{e.Distance:0.0} m"); - ImGui.TableNextColumn(); - bool alreadyPaired = IsAlreadyPairedByUidOrAlias(e); - string status = alreadyPaired ? "Paired" : (string.IsNullOrEmpty(e.Token) ? "Requests disabled" : "On Umbra"); - ImGui.TextUnformatted(status); - ImGui.TableNextColumn(); - using (ImRaii.Disabled(alreadyPaired || string.IsNullOrEmpty(e.Token))) + if (canRequest && !overDistance) { - if (alreadyPaired) + if (ImGui.Button("Envoyer invitation")) { - ImGui.Button($"Already sync##{e.Name}"); + _ = _requestService.SendRequestAsync(entry.Token!, entry.Uid, entry.DisplayName); } - else if (string.IsNullOrEmpty(e.Token)) + UiSharedService.AttachToolTip("Envoie une demande d'appairage via AutoDetect."); + } + else + { + string reason = alreadyPaired + ? "Vous êtes déjà appairé avec ce joueur." + : overDistance + ? $"Ce joueur est au-delà de la distance maximale configurée ({maxDist} m)." + : !isMatch + ? "Ce joueur n'utilise pas UmbraSync ou ne s'est pas rendu détectable." + : !entry.AcceptPairRequests + ? "Ce joueur a désactivé la réception automatique des invitations." + : string.IsNullOrEmpty(entry.Token) + ? "Impossible d'obtenir un jeton d'invitation pour ce joueur." + : string.Empty; + + ImGui.TextDisabled(status); + if (!string.IsNullOrEmpty(reason)) { - ImGui.Button($"Requests disabled##{e.Name}"); - } - else if (ImGui.Button($"Send request##{e.Name}")) - { - _ = _requestService.SendRequestAsync(e.Token!, e.Uid, e.DisplayName); + UiSharedService.AttachToolTip(reason); } } } - - ImGui.EndTable(); } - } - public override void OnOpen() - { - base.OnOpen(); - Mediator.Subscribe(this, OnDiscoveryUpdated); - } - - public override void OnClose() - { - Mediator.Unsubscribe(this); - base.OnClose(); + ImGui.EndTable(); } private void OnDiscoveryUpdated(Services.Mediator.DiscoveryListUpdated msg) diff --git a/MareSynchronos/UI/CompactUI.cs b/MareSynchronos/UI/CompactUI.cs index 5ad5319..3ab7c67 100644 --- a/MareSynchronos/UI/CompactUI.cs +++ b/MareSynchronos/UI/CompactUI.cs @@ -76,7 +76,7 @@ public class CompactUi : WindowMediatorSubscriberBase private CompactUiSection _activeSection = CompactUiSection.VisiblePairs; private const float SidebarWidth = 42f; private const float SidebarIconSize = 22f; - private const float ContentFontScale = 0.92f; + private const float ContentFontScale = UiSharedService.ContentFontScale; private static readonly Vector4 SidebarButtonColor = new(0.08f, 0.08f, 0.10f, 0.92f); private static readonly Vector4 SidebarButtonHoverColor = new(0.12f, 0.12f, 0.16f, 0.95f); private static readonly Vector4 SidebarButtonActiveColor = new(0.16f, 0.16f, 0.22f, 0.95f); @@ -186,7 +186,7 @@ public class CompactUi : WindowMediatorSubscriberBase ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y - 1f * ImGuiHelpers.GlobalScale + ImGui.GetStyle().ItemSpacing.Y); var sidebarWidth = ImGuiHelpers.ScaledVector2(SidebarWidth, 0).X; - ImGui.SetWindowFontScale(ContentFontScale); + using var fontScale = UiSharedService.PushFontScale(ContentFontScale); ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ImGui.GetStyle().FramePadding * ContentFontScale); ImGui.BeginChild("compact-sidebar", new Vector2(sidebarWidth, 0), false, ImGuiWindowFlags.NoScrollbar); @@ -232,7 +232,6 @@ public class CompactUi : WindowMediatorSubscriberBase } ImGui.PopStyleVar(); - ImGui.SetWindowFontScale(1f); } public override void OnClose() @@ -735,7 +734,6 @@ if (showNearby && pendingInvites > 0) } else { - var visibleUsers = visibleUsersSource.Select(c => new DrawUserPair("Visible" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager)).ToList(); var onlineUsers = nonVisibleUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired() && (u.IsOnline || u.UserPair!.OwnPermissions.IsPaused())) .Select(c => new DrawUserPair("Online" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager, _serverManager)) .ToList(); @@ -750,7 +748,7 @@ if (showNearby && pendingInvites > 0) drawVisibleExtras = () => DrawNearbyCard(entriesForExtras); } - _pairGroupsUi.Draw(visibleUsers, onlineUsers, offlineUsers, drawVisibleExtras); + _pairGroupsUi.Draw(Array.Empty().ToList(), onlineUsers, offlineUsers, drawVisibleExtras); } ImGui.EndChild(); @@ -1289,7 +1287,7 @@ if (showNearby && pendingInvites > 0) } var originalPos = ImGui.GetCursorPos(); - ImGui.SetWindowFontScale(1.5f); + UiSharedService.SetFontScale(1.5f); Vector2 buttonSize = Vector2.Zero; float spacingX = ImGui.GetStyle().ItemSpacing.X; @@ -1307,7 +1305,7 @@ if (showNearby && pendingInvites > 0) } ImGui.SetCursorPos(originalPos); - ImGui.SetWindowFontScale(1f); + UiSharedService.SetFontScale(1f); float referenceHeight = buttonSize.Y > 0f ? buttonSize.Y : ImGui.GetFrameHeight(); ImGui.SetCursorPosY(originalPos.Y + referenceHeight / 2f - uidTextSize.Y / 2f - spacingX / 2f); diff --git a/MareSynchronos/UI/Components/DrawGroupPair.cs b/MareSynchronos/UI/Components/DrawGroupPair.cs index dc96bfb..ec15593 100644 --- a/MareSynchronos/UI/Components/DrawGroupPair.cs +++ b/MareSynchronos/UI/Components/DrawGroupPair.cs @@ -201,7 +201,7 @@ public class DrawGroupPair : DrawPairBase var individualVFXDisabled = (_pair.UserPair?.OwnPermissions.IsDisableVFX() ?? false) || (_pair.UserPair?.OtherPermissions.IsDisableVFX() ?? false); bool showShared = _charaDataManager.SharedWithYouData.TryGetValue(_pair.UserData, out var sharedData); - bool showInfo = (individualAnimDisabled || individualSoundsDisabled || animDisabled || soundsDisabled); + bool showInfo = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled || animDisabled || soundsDisabled || vfxDisabled); bool showPlus = _pair.UserPair == null && _pair.IsOnline; bool showBars = (userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) || !_pair.IsPaused; bool showPause = true; @@ -267,7 +267,7 @@ public class DrawGroupPair : DrawPairBase if (showInfo && infoIconWidth > 0f) { ImGui.SetCursorPosY(textPosY); - if (individualAnimDisabled || individualSoundsDisabled) + if (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled) { ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudYellow); _uiSharedService.IconText(permIcon); diff --git a/MareSynchronos/UI/Components/GroupPanel.cs b/MareSynchronos/UI/Components/GroupPanel.cs index 4a2ae22..a8b6d90 100644 --- a/MareSynchronos/UI/Components/GroupPanel.cs +++ b/MareSynchronos/UI/Components/GroupPanel.cs @@ -91,6 +91,7 @@ internal sealed class GroupPanel public void DrawSyncshells() { + using var fontScale = UiSharedService.PushFontScale(UiSharedService.ContentFontScale); using (ImRaii.PushId("addsyncshell")) DrawAddSyncshell(); using (ImRaii.PushId("syncshelllist")) DrawSyncshellList(); _mainUi.TransferPartHeight = ImGui.GetCursorPosY(); @@ -613,7 +614,7 @@ internal sealed class GroupPanel ImGui.Separator(); } ImGui.Unindent(20); - }, background: new Vector4(0.15f, 0.15f, 0.20f, 0.94f), border: new Vector4(0f, 0f, 0f, 0.78f), stretchWidth: true); + }, stretchWidth: true); ImGuiHelpers.ScaledDummy(4f); } diff --git a/MareSynchronos/UI/Components/PairGroupsUi.cs b/MareSynchronos/UI/Components/PairGroupsUi.cs index 7bb296c..fd4293b 100644 --- a/MareSynchronos/UI/Components/PairGroupsUi.cs +++ b/MareSynchronos/UI/Components/PairGroupsUi.cs @@ -198,10 +198,7 @@ public class PairGroupsUi private void DrawUserPairs(List tagsWithPairsInThem, List allUsers, IEnumerable visibleUsers, IEnumerable onlineUsers, IEnumerable offlineUsers, Action? drawVisibleExtras) { - if (_mareConfig.Current.ShowVisibleUsersSeparately) - { - using (ImRaii.PushId("$group-VisibleCustomTag")) DrawCategory(TagHandler.CustomVisibleTag, visibleUsers, allUsers, drawExtraContent: drawVisibleExtras); - } + // Visible section intentionally omitted for Individual Pairs view. foreach (var tag in tagsWithPairsInThem) { if (_mareConfig.Current.ShowOfflineUsersSeparately) diff --git a/MareSynchronos/UI/IntroUI.cs b/MareSynchronos/UI/IntroUI.cs index 726fe66..bba67c1 100644 --- a/MareSynchronos/UI/IntroUI.cs +++ b/MareSynchronos/UI/IntroUI.cs @@ -144,12 +144,12 @@ public partial class IntroUi : WindowMediatorSubscriberBase } ImGui.Separator(); - ImGui.SetWindowFontScale(1.5f); + UiSharedService.SetFontScale(1.5f); string readThis = "MERCI DE LIRE ATTENTIVEMENT"; Vector2 textSize = ImGui.CalcTextSize(readThis); ImGui.SetCursorPosX(ImGui.GetWindowSize().X / 2 - textSize.X / 2); UiSharedService.ColorText(readThis, UiSharedService.AccentColor); - ImGui.SetWindowFontScale(1.0f); + UiSharedService.SetFontScale(1.0f); ImGui.Separator(); UiSharedService.TextWrapped(""" Pour utiliser les services UmbraSync, vous devez être âgé de plus de 18 ans, où plus de 21 ans dans certaines juridictions. diff --git a/MareSynchronos/UI/SettingsUi.cs b/MareSynchronos/UI/SettingsUi.cs index 88f503a..29d3241 100644 --- a/MareSynchronos/UI/SettingsUi.cs +++ b/MareSynchronos/UI/SettingsUi.cs @@ -534,9 +534,9 @@ public class SettingsUi : WindowMediatorSubscriberBase }, globalChatTypeIdx); _uiShared.DrawHelpText("FFXIV chat channel to output chat messages on."); - ImGui.SetWindowFontScale(0.6f); + UiSharedService.SetFontScale(0.6f); _uiShared.BigText("\"Chat 2\" Plugin Integration"); - ImGui.SetWindowFontScale(1.0f); + UiSharedService.SetFontScale(1.0f); var extraChatTags = _configService.Current.ExtraChatTags; if (ImGui.Checkbox("Tag messages as ExtraChat", ref extraChatTags)) @@ -577,9 +577,9 @@ public class SettingsUi : WindowMediatorSubscriberBase if (shellEnabled) shellName = $"[{shellNumber}] {shellName}"; - ImGui.SetWindowFontScale(0.6f); + UiSharedService.SetFontScale(0.6f); _uiShared.BigText(shellName); - ImGui.SetWindowFontScale(1.0f); + UiSharedService.SetFontScale(1.0f); using var pushIndent = ImRaii.PushIndent(); @@ -1333,6 +1333,14 @@ public class SettingsUi : WindowMediatorSubscriberBase _uiShared.BigText("Global Configuration"); + bool showSelfAnalysisWarnings = _playerPerformanceConfigService.Current.ShowSelfAnalysisWarnings; + if (ImGui.Checkbox("Display self-analysis warnings", ref showSelfAnalysisWarnings)) + { + _playerPerformanceConfigService.Current.ShowSelfAnalysisWarnings = showSelfAnalysisWarnings; + _playerPerformanceConfigService.Save(); + } + _uiShared.DrawHelpText("Disable to suppress UmbraSync chat warnings when your character exceeds the self-analysis thresholds."); + bool alwaysShrinkTextures = _playerPerformanceConfigService.Current.TextureShrinkMode == TextureShrinkMode.Always; bool deleteOriginalTextures = _playerPerformanceConfigService.Current.TextureShrinkDeleteOriginal; diff --git a/MareSynchronos/UI/UISharedService.cs b/MareSynchronos/UI/UISharedService.cs index f9a9ea6..9f37058 100644 --- a/MareSynchronos/UI/UISharedService.cs +++ b/MareSynchronos/UI/UISharedService.cs @@ -21,6 +21,7 @@ using MareSynchronos.Services.ServerConfiguration; using MareSynchronos.WebAPI; using Microsoft.Extensions.Logging; using System; +using System.Collections.Generic; using System.Numerics; using System.Runtime.InteropServices; using System.Text; @@ -37,6 +38,8 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse; + public const float ContentFontScale = 0.92f; + 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; @@ -60,6 +63,8 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase private readonly Dictionary _selectedComboItems = new(StringComparer.Ordinal); private readonly ServerConfigurationManager _serverConfigurationManager; private bool _cacheDirectoryHasOtherFilesThanCache = false; + private static readonly Stack _fontScaleStack = new(); + private static float _currentWindowFontScale = 1f; private bool _cacheDirectoryIsValidPath = true; @@ -217,6 +222,37 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase public static bool CtrlPressed() => (GetKeyState(0xA2) & 0x8000) != 0 || (GetKeyState(0xA3) & 0x8000) != 0; + public static IDisposable PushFontScale(float scale) + { + var previous = _currentWindowFontScale; + _fontScaleStack.Push(previous); + if (Math.Abs(previous - scale) > float.Epsilon) + { + SetFontScale(scale); + } + + return new FontScaleScope(); + } + + private sealed class FontScaleScope : IDisposable + { + public void Dispose() + { + if (_fontScaleStack.Count == 0) return; + var previous = _fontScaleStack.Pop(); + if (Math.Abs(previous - _currentWindowFontScale) > float.Epsilon) + { + SetFontScale(previous); + } + } + } + + public static void SetFontScale(float scale) + { + ImGui.SetWindowFontScale(scale); + _currentWindowFontScale = scale; + } + public static void DrawGrouped(Action imguiDrawAction, float rounding = 5f, float? expectedWidth = null, bool drawBorder = true) { var cursorPos = ImGui.GetCursorPos(); @@ -894,9 +930,9 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase if (intro) { - ImGui.SetWindowFontScale(0.8f); + SetFontScale(0.8f); BigText("Mandatory Plugins"); - ImGui.SetWindowFontScale(1.0f); + SetFontScale(1.0f); } else { @@ -917,9 +953,9 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase if (intro) { - ImGui.SetWindowFontScale(0.8f); + SetFontScale(0.8f); BigText("Optional Addons"); - ImGui.SetWindowFontScale(1.0f); + SetFontScale(1.0f); UiSharedService.TextWrapped("These addons are not required for basic operation, but without them you may not see others as intended."); } else