diff --git a/Dalamud/Interface/Windowing/Window.cs b/Dalamud/Interface/Windowing/Window.cs index 8dc517cb2..e4ff699ed 100644 --- a/Dalamud/Interface/Windowing/Window.cs +++ b/Dalamud/Interface/Windowing/Window.cs @@ -32,6 +32,9 @@ namespace Dalamud.Interface.Windowing; /// public abstract class Window { + private const float FadeInOutTime = 1f; + private const float FadeInOutStep = 0.09f; + private static readonly ModuleLog Log = new("WindowSystem"); private static bool wasEscPressedLastFrame = false; @@ -48,6 +51,12 @@ public abstract class Window private PresetModel.PresetWindow? presetWindow; private bool presetDirty = false; + private float fadeInTimer = 1f; + private float fadeOutTimer = 0f; + private IDrawListTextureWrap? fadeOutTexture = null; + private Vector2 fadeOutSize = Vector2.Zero; + private Vector2 fadeOutOrigin = Vector2.Zero; + /// /// Initializes a new instance of the class. /// @@ -89,6 +98,11 @@ public abstract class Window /// Enable the built-in "additional options" menu on the title bar. /// UseAdditionalOptions = 1 << 2, + + /// + /// Do not draw non-critical animations. + /// + IsReducedMotion = 1 << 3, } /// @@ -316,6 +330,7 @@ public abstract class Window internal void DrawInternal(WindowDrawFlags internalDrawFlags, WindowSystemPersistence? persistence) { this.PreOpenCheck(); + var isReducedMotion = internalDrawFlags.HasFlag(WindowDrawFlags.IsReducedMotion); if (!this.IsOpen) { @@ -330,9 +345,35 @@ public abstract class Window UIGlobals.PlaySoundEffect(this.OnCloseSfxId); } + if (this.fadeOutTexture != null) + { + this.fadeOutTimer -= FadeInOutStep; + if (this.fadeOutTimer <= 0f) + { + this.fadeOutTexture.Dispose(); + this.fadeOutTexture = null; + } + else + { + var dl = ImGui.GetBackgroundDrawList(); + dl.AddImage( + this.fadeOutTexture.ImGuiHandle, + this.fadeOutOrigin, + this.fadeOutOrigin + this.fadeOutSize, + Vector2.Zero, + Vector2.One, + ImGui.ColorConvertFloat4ToU32(new(1f, 1f, 1f, Math.Clamp(this.fadeOutTimer / FadeInOutTime, 0f, 1f)))); + } + } + + this.fadeInTimer = !isReducedMotion ? 0f : FadeInOutTime; return; } + this.fadeInTimer += FadeInOutStep; + if (this.fadeInTimer > FadeInOutTime) + this.fadeInTimer = FadeInOutTime; + this.Update(); if (!this.DrawConditions()) return; @@ -546,8 +587,19 @@ public abstract class Window } } + this.fadeOutSize = ImGui.GetWindowSize(); + this.fadeOutOrigin = ImGui.GetWindowPos(); + ImGui.End(); + if (!this.internalIsOpen && this.fadeOutTexture == null && !isReducedMotion) + { + this.fadeOutTexture = Service.Get().CreateDrawListTexture( + "WindowFadeOutTexture"); + this.fadeOutTexture.ResizeAndDrawWindow(this.WindowName, Vector2.One); + this.fadeOutTimer = FadeInOutTime; + } + if (printWindow) { var tex = Service.Get().CreateDrawListTexture( @@ -567,7 +619,7 @@ public abstract class Window ImGui.PopID(); } - private void ApplyConditionals() + private unsafe void ApplyConditionals() { if (this.Position.HasValue) { @@ -594,15 +646,18 @@ public abstract class Window ImGui.SetNextWindowSizeConstraints(this.SizeConstraints.Value.MinimumSize * ImGuiHelpers.GlobalScale, this.SizeConstraints.Value.MaximumSize * ImGuiHelpers.GlobalScale); } - if (this.BgAlpha.HasValue) + var maxBgAlpha = this.internalAlpha ?? this.BgAlpha; + var fadeInAlpha = this.fadeInTimer / FadeInOutTime; + if (fadeInAlpha < 1f) { - ImGui.SetNextWindowBgAlpha(this.BgAlpha.Value); + maxBgAlpha = maxBgAlpha.HasValue ? + Math.Clamp(maxBgAlpha.Value * fadeInAlpha, 0f, 1f) : + (*ImGui.GetStyleColorVec4(ImGuiCol.WindowBg)).W * fadeInAlpha; } - // Manually set alpha takes precedence, if devs don't want that, they should turn it off - if (this.internalAlpha.HasValue) + if (maxBgAlpha.HasValue) { - ImGui.SetNextWindowBgAlpha(this.internalAlpha.Value); + ImGui.SetNextWindowBgAlpha(maxBgAlpha.Value); } } diff --git a/Dalamud/Interface/Windowing/WindowSystem.cs b/Dalamud/Interface/Windowing/WindowSystem.cs index f79eea025..ccdc2b44c 100644 --- a/Dalamud/Interface/Windowing/WindowSystem.cs +++ b/Dalamud/Interface/Windowing/WindowSystem.cs @@ -119,6 +119,9 @@ public class WindowSystem if (config?.IsFocusManagementEnabled ?? false) flags |= Window.WindowDrawFlags.UseFocusManagement; + if (config?.ReduceMotions ?? false) + flags |= Window.WindowDrawFlags.IsReducedMotion; + // Shallow clone the list of windows so that we can edit it without modifying it while the loop is iterating foreach (var window in this.windows.ToArray()) {