From d28a164d8c02e16c0e6fb8fad23a97463f3560e2 Mon Sep 17 00:00:00 2001 From: Ottermandias <70807659+Ottermandias@users.noreply.github.com> Date: Tue, 5 Aug 2025 00:52:13 +0200 Subject: [PATCH] Add events for certain style changes from within Dalamud. (#2277) * Add events for certain style changes from within Dalamud. * Capture reset changes in events too. * Add non-static versions of events to IUiBuilder, add remarks about timing to events. * Move statics to InterfaceManager members and make plugin events local. --------- Co-authored-by: KazWolfe --- .../Interface/Internal/InterfaceManager.cs | 29 +++++++ .../Windows/Settings/SettingsWindow.cs | 13 ++- .../Windows/Settings/Tabs/SettingsTabLook.cs | 4 + .../Windows/StyleEditor/StyleEditorWindow.cs | 80 ++++++++++++------- Dalamud/Interface/UiBuilder.cs | 37 +++++++++ 5 files changed, 134 insertions(+), 29 deletions(-) diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index 60421960d..c096b428f 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -140,6 +140,23 @@ internal partial class InterfaceManager : IInternalDisposableService /// public event Action? AfterBuildFonts; + /// + /// Invoked when the default global scale used by ImGui has been changed through Dalamud. + /// + /// Fonts will generally not have finished rebuilding when this is invoked, so if you need to access the font you should subscribe to .ImFontChanged instead. + public event Action? DefaultGlobalScaleChanged; + + /// + /// Invoked when the default font used by ImGui has been changed through Dalamud. + /// + /// Fonts will generally not have finished rebuilding when this is invoked, so if you need to access the font you should subscribe to .ImFontChanged instead. + public event Action? DefaultFontChanged; + + /// + /// Invoked when either the currently chosen style in Dalamud or a style or color variable within the currently chosen style has been changed through Dalamud. + /// + public event Action? DefaultStyleChanged; + /// /// Gets the default ImGui font.
/// Accessing this static property outside of the main thread is dangerous and not supported. @@ -499,6 +516,18 @@ internal partial class InterfaceManager : IInternalDisposableService sizeof(uint)).ThrowOnFailure(); } + /// Safely invoke . + internal void InvokeGlobalScaleChanged() + => DefaultGlobalScaleChanged.InvokeSafely(); + + /// Safely invoke . + internal void InvokeFontChanged() + => DefaultFontChanged.InvokeSafely(); + + /// Safely invoke . + internal void InvokeStyleChanged() + => DefaultStyleChanged.InvokeSafely(); + private static InterfaceManager WhenFontsReady() { var im = Service.GetNullable(); diff --git a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs index 1b731ed16..75cbeb836 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs @@ -100,19 +100,30 @@ internal class SettingsWindow : Window var interfaceManager = Service.Get(); var fontAtlasFactory = Service.Get(); + var scaleChanged = !Equals(ImGui.GetIO().FontGlobalScale, configuration.GlobalUiScale); var rebuildFont = !Equals(fontAtlasFactory.DefaultFontSpec, configuration.DefaultFontSpec); - rebuildFont |= !Equals(ImGui.GetIO().FontGlobalScale, configuration.GlobalUiScale); + rebuildFont |= scaleChanged; ImGui.GetIO().FontGlobalScale = configuration.GlobalUiScale; + if (scaleChanged) + { + Service.Get().InvokeGlobalScaleChanged(); + } + fontAtlasFactory.DefaultFontSpecOverride = null; if (rebuildFont) + { interfaceManager.RebuildFonts(); + Service.Get().InvokeFontChanged(); + } foreach (var settingsTab in this.tabs) { if (settingsTab.IsOpen) + { settingsTab.OnClose(); + } settingsTab.IsOpen = false; } diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs index 6d1c76aae..b6aa11db4 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs @@ -198,6 +198,7 @@ public class SettingsTabLook : SettingsTab { ImGui.GetIO().FontGlobalScale = this.globalUiScale = scale; interfaceManager.RebuildFonts(); + Service.Get().InvokeGlobalScaleChanged(); } } @@ -221,6 +222,7 @@ public class SettingsTabLook : SettingsTab this.globalUiScale = globalUiScaleInPct / 100f; ImGui.GetIO().FontGlobalScale = this.globalUiScale; interfaceManager.RebuildFonts(); + Service.Get().InvokeGlobalScaleChanged(); } ImGui.TextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsGlobalUiScaleHint", "Scale text in all XIVLauncher UI elements - this is useful for 4K displays.")); @@ -261,6 +263,7 @@ public class SettingsTabLook : SettingsTab faf.DefaultFontSpecOverride = this.defaultFontSpec = r.Result; interfaceManager.RebuildFonts(); + Service.Get().InvokeFontChanged(); })); } @@ -275,6 +278,7 @@ public class SettingsTabLook : SettingsTab this.defaultFontSpec = new SingleFontSpec { FontId = new GameFontAndFamilyId(GameFontFamily.Axis) }; interfaceManager.RebuildFonts(); + Service.Get().InvokeFontChanged(); } } diff --git a/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs b/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs index a16f6b53b..679b95520 100644 --- a/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs +++ b/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs @@ -26,6 +26,7 @@ public class StyleEditorWindow : Window private int currentSel = 0; private string initialStyle = string.Empty; private bool didSave = false; + private bool anyChanges = false; private string renameText = string.Empty; private bool renameModalDrawing = false; @@ -65,6 +66,10 @@ public class StyleEditorWindow : Window var config = Service.Get(); var newStyle = config.SavedStyles.FirstOrDefault(x => x.Name == this.initialStyle); newStyle?.Apply(); + if (this.anyChanges) + { + Service.Get().InvokeStyleChanged(); + } } base.OnClose(); @@ -88,6 +93,7 @@ public class StyleEditorWindow : Window { var newStyle = config.SavedStyles[this.currentSel]; newStyle.Apply(); + this.Change(); appliedThisFrame = true; } @@ -102,6 +108,7 @@ public class StyleEditorWindow : Window this.currentSel = config.SavedStyles.Count - 1; newStyle.Apply(); + this.Change(); appliedThisFrame = true; config.QueueSave(); @@ -117,6 +124,7 @@ public class StyleEditorWindow : Window this.currentSel--; var newStyle = config.SavedStyles[this.currentSel]; newStyle.Apply(); + this.Change(); appliedThisFrame = true; config.SavedStyles.RemoveAt(this.currentSel + 1); @@ -181,6 +189,7 @@ public class StyleEditorWindow : Window config.SavedStyles.Add(newStyle); newStyle.Apply(); + this.Change(); appliedThisFrame = true; this.currentSel = config.SavedStyles.Count - 1; @@ -211,49 +220,52 @@ public class StyleEditorWindow : Window else if (ImGui.BeginTabBar("StyleEditorTabs"u8)) { var style = ImGui.GetStyle(); - + var changes = false; if (ImGui.BeginTabItem(Loc.Localize("StyleEditorVariables", "Variables"))) { if (ImGui.BeginChild($"ScrollingVars", ImGuiHelpers.ScaledVector2(0, -32), true, ImGuiWindowFlags.HorizontalScrollbar | ImGuiWindowFlags.NoBackground)) { ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 5); - ImGui.SliderFloat2("WindowPadding", ref style.WindowPadding, 0.0f, 20.0f, "%.0f"); - ImGui.SliderFloat2("FramePadding", ref style.FramePadding, 0.0f, 20.0f, "%.0f"); - ImGui.SliderFloat2("CellPadding", ref style.CellPadding, 0.0f, 20.0f, "%.0f"); - ImGui.SliderFloat2("ItemSpacing", ref style.ItemSpacing, 0.0f, 20.0f, "%.0f"); - ImGui.SliderFloat2("ItemInnerSpacing", ref style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); - ImGui.SliderFloat2("TouchExtraPadding", ref style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); - ImGui.SliderFloat("IndentSpacing"u8, ref style.IndentSpacing, 0.0f, 30.0f, "%.0f"u8); - ImGui.SliderFloat("ScrollbarSize"u8, ref style.ScrollbarSize, 1.0f, 20.0f, "%.0f"u8); - ImGui.SliderFloat("GrabMinSize"u8, ref style.GrabMinSize, 1.0f, 20.0f, "%.0f"u8); + changes |= ImGui.SliderFloat2("WindowPadding", ref style.WindowPadding, 0.0f, 20.0f, "%.0f"); + changes |= ImGui.SliderFloat2("FramePadding", ref style.FramePadding, 0.0f, 20.0f, "%.0f"); + changes |= ImGui.SliderFloat2("CellPadding", ref style.CellPadding, 0.0f, 20.0f, "%.0f"); + changes |= ImGui.SliderFloat2("ItemSpacing", ref style.ItemSpacing, 0.0f, 20.0f, "%.0f"); + changes |= ImGui.SliderFloat2("ItemInnerSpacing", ref style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); + changes |= ImGui.SliderFloat2("TouchExtraPadding", ref style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); + changes |= ImGui.SliderFloat("IndentSpacing"u8, ref style.IndentSpacing, 0.0f, 30.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("ScrollbarSize"u8, ref style.ScrollbarSize, 1.0f, 20.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("GrabMinSize"u8, ref style.GrabMinSize, 1.0f, 20.0f, "%.0f"u8); ImGui.Text("Borders"u8); - ImGui.SliderFloat("WindowBorderSize"u8, ref style.WindowBorderSize, 0.0f, 1.0f, "%.0f"u8); - ImGui.SliderFloat("ChildBorderSize"u8, ref style.ChildBorderSize, 0.0f, 1.0f, "%.0f"u8); - ImGui.SliderFloat("PopupBorderSize"u8, ref style.PopupBorderSize, 0.0f, 1.0f, "%.0f"u8); - ImGui.SliderFloat("FrameBorderSize"u8, ref style.FrameBorderSize, 0.0f, 1.0f, "%.0f"u8); - ImGui.SliderFloat("TabBorderSize"u8, ref style.TabBorderSize, 0.0f, 1.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("WindowBorderSize"u8, ref style.WindowBorderSize, 0.0f, 1.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("ChildBorderSize"u8, ref style.ChildBorderSize, 0.0f, 1.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("PopupBorderSize"u8, ref style.PopupBorderSize, 0.0f, 1.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("FrameBorderSize"u8, ref style.FrameBorderSize, 0.0f, 1.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("TabBorderSize"u8, ref style.TabBorderSize, 0.0f, 1.0f, "%.0f"u8); ImGui.Text("Rounding"u8); - ImGui.SliderFloat("WindowRounding"u8, ref style.WindowRounding, 0.0f, 12.0f, "%.0f"u8); - ImGui.SliderFloat("ChildRounding"u8, ref style.ChildRounding, 0.0f, 12.0f, "%.0f"u8); - ImGui.SliderFloat("FrameRounding"u8, ref style.FrameRounding, 0.0f, 12.0f, "%.0f"u8); - ImGui.SliderFloat("PopupRounding"u8, ref style.PopupRounding, 0.0f, 12.0f, "%.0f"u8); - ImGui.SliderFloat("ScrollbarRounding"u8, ref style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"u8); - ImGui.SliderFloat("GrabRounding"u8, ref style.GrabRounding, 0.0f, 12.0f, "%.0f"u8); - ImGui.SliderFloat("LogSliderDeadzone"u8, ref style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"u8); - ImGui.SliderFloat("TabRounding"u8, ref style.TabRounding, 0.0f, 12.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("WindowRounding"u8, ref style.WindowRounding, 0.0f, 12.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("ChildRounding"u8, ref style.ChildRounding, 0.0f, 12.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("FrameRounding"u8, ref style.FrameRounding, 0.0f, 12.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("PopupRounding"u8, ref style.PopupRounding, 0.0f, 12.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("ScrollbarRounding"u8, ref style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("GrabRounding"u8, ref style.GrabRounding, 0.0f, 12.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("LogSliderDeadzone"u8, ref style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"u8); + changes |= ImGui.SliderFloat("TabRounding"u8, ref style.TabRounding, 0.0f, 12.0f, "%.0f"u8); ImGui.Text("Alignment"u8); - ImGui.SliderFloat2("WindowTitleAlign", ref style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + changes |= ImGui.SliderFloat2("WindowTitleAlign", ref style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); var windowMenuButtonPosition = (int)style.WindowMenuButtonPosition + 1; if (ImGui.Combo("WindowMenuButtonPosition"u8, ref windowMenuButtonPosition, ["None", "Left", "Right"])) style.WindowMenuButtonPosition = (ImGuiDir)(windowMenuButtonPosition - 1); - ImGui.SliderFloat2("ButtonTextAlign", ref style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); + changes = true; + } + + changes |= ImGui.SliderFloat2("ButtonTextAlign", ref style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui.SameLine(); ImGuiComponents.HelpMarker("Alignment applies when a button is larger than its text content."); - ImGui.SliderFloat2("SelectableTextAlign", ref style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); + changes |= ImGui.SliderFloat2("SelectableTextAlign", ref style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui.SameLine(); ImGuiComponents.HelpMarker("Alignment applies when a selectable is larger than its text content."); - ImGui.SliderFloat2("DisplaySafeAreaPadding", ref style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); + changes |= ImGui.SliderFloat2("DisplaySafeAreaPadding", ref style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui.SameLine(); ImGuiComponents.HelpMarker( "Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); @@ -292,7 +304,7 @@ public class StyleEditorWindow : Window ImGui.PushID(imGuiCol.ToString()); - ImGui.ColorEdit4("##color", ref style.Colors[(int)imGuiCol], ImGuiColorEditFlags.AlphaBar | this.alphaFlags); + changes |= ImGui.ColorEdit4("##color", ref style.Colors[(int)imGuiCol], ImGuiColorEditFlags.AlphaBar | this.alphaFlags); ImGui.SameLine(0.0f, style.ItemInnerSpacing.X); ImGui.Text(imGuiCol.ToString()); @@ -319,6 +331,7 @@ public class StyleEditorWindow : Window { property.SetValue(workStyle.BuiltInColors, color); workStyle.BuiltInColors?.Apply(); + changes = true; } ImGui.SameLine(0.0f, style.ItemInnerSpacing.X); @@ -333,6 +346,11 @@ public class StyleEditorWindow : Window ImGui.EndTabItem(); } + if (changes) + { + this.Change(); + } + ImGui.EndTabBar(); } @@ -395,4 +413,10 @@ public class StyleEditorWindow : Window config.QueueSave(); } + + private void Change() + { + this.anyChanges = true; + Service.Get().InvokeStyleChanged(); + } } diff --git a/Dalamud/Interface/UiBuilder.cs b/Dalamud/Interface/UiBuilder.cs index 462c98100..b870e7a94 100644 --- a/Dalamud/Interface/UiBuilder.cs +++ b/Dalamud/Interface/UiBuilder.cs @@ -12,6 +12,7 @@ using Dalamud.Interface.FontIdentifier; using Dalamud.Interface.Internal; using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.ManagedFontAtlas.Internals; +using Dalamud.Plugin; using Dalamud.Plugin.Internal.Types; using Dalamud.Utility; using Serilog; @@ -57,6 +58,15 @@ public interface IUiBuilder ///
event Action? HideUi; + /// + event Action? DefaultGlobalScaleChanged; + + /// + event Action? DefaultFontChanged; + + /// + event Action? DefaultStyleChanged; + /// /// Gets the handle to the default Dalamud font - supporting all game languages and icons. /// @@ -287,6 +297,15 @@ public sealed class UiBuilder : IDisposable, IUiBuilder this.interfaceManager.ResizeBuffers += this.OnResizeBuffers; this.scopedFinalizer.Add(() => this.interfaceManager.ResizeBuffers -= this.OnResizeBuffers); + this.interfaceManager.DefaultStyleChanged += this.OnDefaultStyleChanged; + this.scopedFinalizer.Add(() => this.interfaceManager.DefaultStyleChanged -= this.OnDefaultStyleChanged); + + this.interfaceManager.DefaultGlobalScaleChanged += this.OnDefaultGlobalScaleChanged; + this.scopedFinalizer.Add(() => this.interfaceManager.DefaultGlobalScaleChanged -= this.OnDefaultGlobalScaleChanged); + + this.interfaceManager.DefaultFontChanged += this.OnDefaultFontChanged; + this.scopedFinalizer.Add(() => this.interfaceManager.DefaultFontChanged -= this.OnDefaultFontChanged); + this.FontAtlas = this.scopedFinalizer .Add( @@ -319,6 +338,15 @@ public sealed class UiBuilder : IDisposable, IUiBuilder /// public event Action? HideUi; + /// + public event Action? DefaultGlobalScaleChanged; + + /// + public event Action? DefaultFontChanged; + + /// + public event Action? DefaultStyleChanged; + /// /// Gets the default Dalamud font size in points. /// @@ -504,6 +532,15 @@ public sealed class UiBuilder : IDisposable, IUiBuilder /// public bool ShouldUseReducedMotion => Service.Get().ReduceMotions ?? false; + private void OnDefaultStyleChanged() + => this.DefaultStyleChanged.InvokeSafely(); + + private void OnDefaultGlobalScaleChanged() + => this.DefaultGlobalScaleChanged.InvokeSafely(); + + private void OnDefaultFontChanged() + => this.DefaultFontChanged.InvokeSafely(); + /// /// Gets or sets a value indicating whether statistics about UI draw time should be collected. ///