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())
{