Skip to content

Commit

Permalink
Use IImmediateTexture for notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
Critical-Impact committed Jul 2, 2024
1 parent 52c71a4 commit 1b3dd81
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 184 deletions.
60 changes: 6 additions & 54 deletions Dalamud/Interface/ImGuiNotification/IActiveNotification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace Dalamud.Interface.ImGuiNotification;

using Textures;

/// <summary>Represents an active notification.</summary>
/// <remarks>Not to be implemented by plugins.</remarks>
public interface IActiveNotification : INotification
Expand Down Expand Up @@ -52,63 +54,13 @@ public interface IActiveNotification : INotification
/// <remarks>This does not override <see cref="INotification.HardExpiry"/>.</remarks>
void ExtendBy(TimeSpan extension);

/// <summary>Sets the icon from <see cref="IDalamudTextureWrap"/>, overriding the icon.</summary>
/// <param name="textureWrap">The new texture wrap to use, or null to clear and revert back to the icon specified
/// <summary>Sets the icon from <see cref="ISharedImmediateTexture"/>, overriding the icon.</summary>
/// <param name="sharedImmediateTexture">The new shared immediate texture to use, or null to clear and revert back to the icon specified
/// from <see cref="INotification.Icon"/>.</param>
/// <remarks>
/// <para>The texture passed will be disposed when the notification is dismissed or a new different texture is set
/// via another call to this function or overwriting the property. You do not have to dispose it yourself.</para>
/// <para>If <see cref="DismissReason"/> is not <c>null</c>, then calling this function will simply dispose the
/// passed <paramref name="textureWrap"/> without actually updating the icon.</para>
/// </remarks>
void SetIconTexture(IDalamudTextureWrap? textureWrap);

/// <summary>Sets the icon from <see cref="IDalamudTextureWrap"/>, overriding the icon, once the given task
/// completes.</summary>
/// <param name="textureWrapTask">The task that will result in a new texture wrap to use, or null to clear and
/// revert back to the icon specified from <see cref="INotification.Icon"/>.</param>
/// <remarks>
/// <para>The texture resulted from the passed <see cref="Task{TResult}"/> will be disposed when the notification
/// is dismissed or a new different texture is set via another call to this function over overwriting the property.
/// You do not have to dispose the resulted instance of <see cref="IDalamudTextureWrap"/> yourself.</para>
/// <para>If the task fails for any reason, the exception will be silently ignored and the icon specified from
/// <see cref="INotification.Icon"/> will be used instead.</para>
/// <para>If <see cref="DismissReason"/> is not <c>null</c>, then calling this function will simply dispose the
/// result of the passed <paramref name="textureWrapTask"/> without actually updating the icon.</para>
/// </remarks>
void SetIconTexture(Task<IDalamudTextureWrap?>? textureWrapTask);

/// <summary>Sets the icon from <see cref="IDalamudTextureWrap"/>, overriding the icon.</summary>
/// <param name="textureWrap">The new texture wrap to use, or null to clear and revert back to the icon specified
/// from <see cref="INotification.Icon"/>.</param>
/// <param name="leaveOpen">Whether to keep the passed <paramref name="textureWrap"/> not disposed.</param>
/// <remarks>
/// <para>If <paramref name="leaveOpen"/> is <c>false</c>, the texture passed will be disposed when the
/// notification is dismissed or a new different texture is set via another call to this function. You do not have
/// to dispose it yourself.</para>
/// <para>If <see cref="DismissReason"/> is not <c>null</c> and <paramref name="leaveOpen"/> is <c>false</c>, then
/// calling this function will simply dispose the passed <paramref name="textureWrap"/> without actually updating
/// the icon.</para>
/// </remarks>
void SetIconTexture(IDalamudTextureWrap? textureWrap, bool leaveOpen);

/// <summary>Sets the icon from <see cref="IDalamudTextureWrap"/>, overriding the icon, once the given task
/// completes.</summary>
/// <param name="textureWrapTask">The task that will result in a new texture wrap to use, or null to clear and
/// revert back to the icon specified from <see cref="INotification.Icon"/>.</param>
/// <param name="leaveOpen">Whether to keep the result from the passed <paramref name="textureWrapTask"/> not
/// disposed.</param>
/// <remarks>
/// <para>If <paramref name="leaveOpen"/> is <c>false</c>, the texture resulted from the passed
/// <see cref="Task{TResult}"/> will be disposed when the notification is dismissed or a new different texture is
/// set via another call to this function. You do not have to dispose the resulted instance of
/// <see cref="IDalamudTextureWrap"/> yourself.</para>
/// <para>If the task fails for any reason, the exception will be silently ignored and the icon specified from
/// <see cref="INotification.Icon"/> will be used instead.</para>
/// <para>If <see cref="DismissReason"/> is not <c>null</c>, then calling this function will simply dispose the
/// result of the passed <paramref name="textureWrapTask"/> without actually updating the icon.</para>
/// <para>If you need to provide a IDalamudTextureWrap that you will be responsible for disposing of, wrap it with <see cref="ForwardingSharedImmediateTexture"/>.</para>
/// </remarks>
void SetIconTexture(Task<IDalamudTextureWrap?>? textureWrapTask, bool leaveOpen);
void SetIconTexture(ISharedImmediateTexture? sharedImmediateTexture);

/// <summary>Generates a new value to use for <see cref="Id"/>.</summary>
/// <returns>The new value.</returns>
Expand Down
20 changes: 5 additions & 15 deletions Dalamud/Interface/ImGuiNotification/INotification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

namespace Dalamud.Interface.ImGuiNotification;

using Textures;

/// <summary>Represents a notification.</summary>
/// <remarks>Not to be implemented by plugins.</remarks>
public interface INotification
Expand All @@ -29,28 +31,16 @@ public interface INotification
/// <summary>Gets or sets a texture wrap that will be used in place of <see cref="Icon"/> if set.</summary>
/// <remarks>
/// <para>A texture wrap set via this property will <b>NOT</b> be disposed when the notification is dismissed.
/// Use <see cref="IActiveNotification.SetIconTexture(IDalamudTextureWrap?)"/> or
/// <see cref="IActiveNotification.SetIconTexture(Task{IDalamudTextureWrap?}?)"/> to use a texture, after calling
/// Use <see cref="IActiveNotification.SetIconTexture(ISharedImmediateTexture?)"/> or
/// <see cref="IActiveNotification.SetIconTexture(Task{ISharedImmediateTexture?}?)"/> to use a texture, after calling
/// <see cref="INotificationManager.AddNotification"/>. Call either of those functions with <c>null</c> to revert
/// the effective icon back to this property.</para>
/// <para>This property and <see cref="IconTextureTask"/> are bound together. If the task is not <c>null</c> but
/// <see cref="Task.IsCompletedSuccessfully"/> is <c>false</c> (because the task is still in progress or faulted,)
/// the property will return <c>null</c>. Setting this property will set <see cref="IconTextureTask"/> to a new
/// completed <see cref="Task{TResult}"/> with the new value as its result.</para>
/// </remarks>
public IDalamudTextureWrap? IconTexture { get; set; }

/// <summary>Gets or sets a task that results in a texture wrap that will be used in place of <see cref="Icon"/> if
/// available.</summary>
/// <remarks>
/// <para>A texture wrap set via this property will <b>NOT</b> be disposed when the notification is dismissed.
/// Use <see cref="IActiveNotification.SetIconTexture(IDalamudTextureWrap?)"/> or
/// <see cref="IActiveNotification.SetIconTexture(Task{IDalamudTextureWrap?}?)"/> to use a texture, after calling
/// <see cref="INotificationManager.AddNotification"/>. Call either of those functions with <c>null</c> to revert
/// the effective icon back to this property.</para>
/// <para>This property and <see cref="IconTexture"/> are bound together.</para>
/// </remarks>
Task<IDalamudTextureWrap?>? IconTextureTask { get; set; }
public ISharedImmediateTexture? IconTexture { get; set; }

/// <summary>Gets or sets the hard expiry.</summary>
/// <remarks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ private void DrawIcon(Vector2 minCoord, Vector2 size)
var maxCoord = minCoord + size;
var iconColor = this.Type.ToColor();

if (NotificationUtilities.DrawIconFrom(minCoord, maxCoord, this.IconTextureTask))
if (NotificationUtilities.DrawIconFrom(minCoord, maxCoord, this.IconTexture))
return;

if (this.Icon?.DrawIcon(minCoord, maxCoord, iconColor) is true)
Expand Down
73 changes: 6 additions & 67 deletions Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

namespace Dalamud.Interface.ImGuiNotification.Internal;

using Textures;

/// <summary>Represents an active notification.</summary>
internal sealed partial class ActiveNotification : IActiveNotification
{
Expand All @@ -23,9 +25,6 @@ internal sealed partial class ActiveNotification : IActiveNotification
private readonly Easing progressEasing;
private readonly Easing expandoEasing;

/// <summary>Whether to call <see cref="IDisposable.Dispose"/> on <see cref="DisposeInternal"/>.</summary>
private bool hasIconTextureOwnership;

/// <summary>Gets the time of starting to count the timer for the expiration.</summary>
private DateTime lastInterestTime;

Expand Down Expand Up @@ -119,31 +118,10 @@ public INotificationIcon? Icon
}

/// <inheritdoc/>
public IDalamudTextureWrap? IconTexture
public ISharedImmediateTexture? IconTexture
{
get => this.underlyingNotification.IconTexture;
set => this.IconTextureTask = value is null ? null : Task.FromResult(value);
}

/// <inheritdoc/>
public Task<IDalamudTextureWrap?>? IconTextureTask
{
get => this.underlyingNotification.IconTextureTask;
set
{
// Do nothing if the value did not change.
if (this.underlyingNotification.IconTextureTask == value)
return;

if (this.hasIconTextureOwnership)
{
_ = this.underlyingNotification.IconTextureTask?.ToContentDisposedTask(true);
this.underlyingNotification.IconTextureTask = null;
this.hasIconTextureOwnership = false;
}

this.underlyingNotification.IconTextureTask = value;
}
set => this.underlyingNotification.IconTexture = value;
}

/// <inheritdoc/>
Expand Down Expand Up @@ -266,36 +244,9 @@ public void ExtendBy(TimeSpan extension)
}

/// <inheritdoc/>
public void SetIconTexture(IDalamudTextureWrap? textureWrap) =>
this.SetIconTexture(textureWrap, false);

/// <inheritdoc/>
public void SetIconTexture(IDalamudTextureWrap? textureWrap, bool leaveOpen) =>
this.SetIconTexture(textureWrap is null ? null : Task.FromResult(textureWrap), leaveOpen);

/// <inheritdoc/>
public void SetIconTexture(Task<IDalamudTextureWrap?>? textureWrapTask) =>
this.SetIconTexture(textureWrapTask, false);

/// <inheritdoc/>
public void SetIconTexture(Task<IDalamudTextureWrap?>? textureWrapTask, bool leaveOpen)
public void SetIconTexture(ISharedImmediateTexture? sharedImmediateTexture)
{
// If we're requested to replace the texture with the same texture, do nothing.
if (this.underlyingNotification.IconTextureTask == textureWrapTask)
return;

if (this.DismissReason is not null)
{
if (!leaveOpen)
textureWrapTask?.ToContentDisposedTask(true);
return;
}

if (this.hasIconTextureOwnership)
_ = this.underlyingNotification.IconTextureTask?.ToContentDisposedTask(true);

this.hasIconTextureOwnership = !leaveOpen;
this.underlyingNotification.IconTextureTask = textureWrapTask;
this.underlyingNotification.IconTexture = sharedImmediateTexture;
}

/// <summary>Removes non-Dalamud invocation targets from events.</summary>
Expand All @@ -317,11 +268,6 @@ internal void RemoveNonDalamudInvocations()
if (this.Icon is { } previousIcon && !IsOwnedByDalamud(previousIcon.GetType()))
this.Icon = null;

// Clear the texture if we don't have the ownership.
// The texture probably was owned by the plugin being unloaded in such case.
if (!this.hasIconTextureOwnership)
this.IconTextureTask = null;

this.isInitiatorUnloaded = true;
this.UserDismissable = true;
this.ExtensionDurationSinceLastInterest = NotificationConstants.DefaultDuration;
Expand Down Expand Up @@ -400,13 +346,6 @@ internal bool UpdateOrDisposeInternal()
/// <summary>Clears the resources associated with this instance of <see cref="ActiveNotification"/>.</summary>
internal void DisposeInternal()
{
if (this.hasIconTextureOwnership)
{
_ = this.underlyingNotification.IconTextureTask?.ToContentDisposedTask(true);
this.underlyingNotification.IconTextureTask = null;
this.hasIconTextureOwnership = false;
}

this.Dismiss = null;
this.Click = null;
this.DrawActions = null;
Expand Down
11 changes: 3 additions & 8 deletions Dalamud/Interface/ImGuiNotification/Notification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

namespace Dalamud.Interface.ImGuiNotification;

using Textures;

/// <summary>Represents a blueprint for a notification.</summary>
public sealed record Notification : INotification
{
Expand All @@ -30,14 +32,7 @@ public sealed record Notification : INotification
public INotificationIcon? Icon { get; set; }

/// <inheritdoc/>
public IDalamudTextureWrap? IconTexture
{
get => this.IconTextureTask?.IsCompletedSuccessfully is true ? this.IconTextureTask.Result : null;
set => this.IconTextureTask = value is null ? null : Task.FromResult(value);
}

/// <inheritdoc/>
public Task<IDalamudTextureWrap?>? IconTextureTask { get; set; }
public ISharedImmediateTexture? IconTexture { get; set; }

/// <inheritdoc/>
public DateTime HardExpiry { get; set; } = DateTime.MaxValue;
Expand Down
25 changes: 15 additions & 10 deletions Dalamud/Interface/ImGuiNotification/NotificationUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

namespace Dalamud.Interface.ImGuiNotification;

using Textures;

/// <summary>Utilities for implementing stuff under <see cref="ImGuiNotification"/>.</summary>
public static class NotificationUtilities
{
Expand Down Expand Up @@ -78,6 +80,19 @@ internal static unsafe bool DrawIconFrom(
return true;
}

/// <summary>Draws an icon from an instance of <see cref="ISharedImmediateTexture"/>.</summary>
/// <param name="minCoord">The coordinates of the top left of the icon area.</param>
/// <param name="maxCoord">The coordinates of the bottom right of the icon area.</param>
/// <param name="texture">The texture.</param>
/// <returns><c>true</c> if anything has been drawn.</returns>
internal static bool DrawIconFrom(Vector2 minCoord, Vector2 maxCoord, ISharedImmediateTexture? texture)
{
if (texture is null)
return false;

return DrawIconFrom(minCoord, maxCoord, texture.GetWrapOrEmpty());
}

/// <summary>Draws an icon from an instance of <see cref="IDalamudTextureWrap"/>.</summary>
/// <param name="minCoord">The coordinates of the top left of the icon area.</param>
/// <param name="maxCoord">The coordinates of the bottom right of the icon area.</param>
Expand Down Expand Up @@ -105,16 +120,6 @@ internal static bool DrawIconFrom(Vector2 minCoord, Vector2 maxCoord, IDalamudTe
}
}

/// <summary>Draws an icon from an instance of <see cref="Task{TResult}"/> that results in an
/// <see cref="IDalamudTextureWrap"/>.</summary>
/// <param name="minCoord">The coordinates of the top left of the icon area.</param>
/// <param name="maxCoord">The coordinates of the bottom right of the icon area.</param>
/// <param name="textureTask">The task that results in a texture.</param>
/// <returns><c>true</c> if anything has been drawn.</returns>
/// <remarks>Exceptions from the task will be treated as if no texture is provided.</remarks>
internal static bool DrawIconFrom(Vector2 minCoord, Vector2 maxCoord, Task<IDalamudTextureWrap?>? textureTask) =>
textureTask?.IsCompletedSuccessfully is true && DrawIconFrom(minCoord, maxCoord, textureTask.Result);

/// <summary>Draws an icon from an instance of <see cref="LocalPlugin"/>.</summary>
/// <param name="minCoord">The coordinates of the top left of the icon area.</param>
/// <param name="maxCoord">The coordinates of the bottom right of the icon area.</param>
Expand Down
Loading

0 comments on commit 1b3dd81

Please sign in to comment.