diff --git a/Dalamud/Interface/ImGuiNotification/EventArgs/INotificationClickArgs.cs b/Dalamud/Interface/ImGuiNotification/EventArgs/INotificationClickArgs.cs
new file mode 100644
index 000000000..b85a96004
--- /dev/null
+++ b/Dalamud/Interface/ImGuiNotification/EventArgs/INotificationClickArgs.cs
@@ -0,0 +1,9 @@
+namespace Dalamud.Interface.ImGuiNotification.EventArgs;
+
+/// Arguments for use with .
+/// Not to be implemented by plugins.
+public interface INotificationClickArgs
+{
+ /// Gets the notification being clicked.
+ IActiveNotification Notification { get; }
+}
diff --git a/Dalamud/Interface/ImGuiNotification/EventArgs/INotificationDismissArgs.cs b/Dalamud/Interface/ImGuiNotification/EventArgs/INotificationDismissArgs.cs
new file mode 100644
index 000000000..7f664efa1
--- /dev/null
+++ b/Dalamud/Interface/ImGuiNotification/EventArgs/INotificationDismissArgs.cs
@@ -0,0 +1,12 @@
+namespace Dalamud.Interface.ImGuiNotification.EventArgs;
+
+/// Arguments for use with .
+/// Not to be implemented by plugins.
+public interface INotificationDismissArgs
+{
+ /// Gets the notification being dismissed.
+ IActiveNotification Notification { get; }
+
+ /// Gets the dismiss reason.
+ NotificationDismissReason Reason { get; }
+}
diff --git a/Dalamud/Interface/ImGuiNotification/EventArgs/INotificationDrawArgs.cs b/Dalamud/Interface/ImGuiNotification/EventArgs/INotificationDrawArgs.cs
new file mode 100644
index 000000000..221f769e0
--- /dev/null
+++ b/Dalamud/Interface/ImGuiNotification/EventArgs/INotificationDrawArgs.cs
@@ -0,0 +1,19 @@
+using System.Numerics;
+
+namespace Dalamud.Interface.ImGuiNotification.EventArgs;
+
+/// Arguments for use with .
+/// Not to be implemented by plugins.
+public interface INotificationDrawArgs
+{
+ /// Gets the notification being drawn.
+ IActiveNotification Notification { get; }
+
+ /// Gets the top left coordinates of the area being drawn.
+ Vector2 MinCoord { get; }
+
+ /// Gets the bottom right coordinates of the area being drawn.
+ /// Note that can be , in which case there is no
+ /// vertical limits to the drawing region.
+ Vector2 MaxCoord { get; }
+}
diff --git a/Dalamud/Interface/ImGuiNotification/IActiveNotification.cs b/Dalamud/Interface/ImGuiNotification/IActiveNotification.cs
index 340c052cd..c3ea2b9de 100644
--- a/Dalamud/Interface/ImGuiNotification/IActiveNotification.cs
+++ b/Dalamud/Interface/ImGuiNotification/IActiveNotification.cs
@@ -1,49 +1,48 @@
using System.Threading;
+using Dalamud.Interface.ImGuiNotification.EventArgs;
using Dalamud.Interface.Internal;
namespace Dalamud.Interface.ImGuiNotification;
/// Represents an active notification.
+/// Not to be implemented by plugins.
public interface IActiveNotification : INotification
{
/// The counter for field.
private static long idCounter;
/// Invoked upon dismissing the notification.
- /// The event callback will not be called,
- /// if a user interacts with the notification after the plugin is unloaded.
- event NotificationDismissedDelegate Dismiss;
+ /// The event callback will not be called, if it gets dismissed after plugin unload.
+ event Action Dismiss;
/// Invoked upon clicking on the notification.
- ///
- /// Note that this function may be called even after has been invoked.
- /// Refer to .
- ///
- event Action Click;
+ /// Note that this function may be called even after has been invoked.
+ event Action Click;
/// Invoked upon drawing the action bar of the notification.
- ///
- /// Note that this function may be called even after has been invoked.
- /// Refer to .
- ///
- event Action DrawActions;
+ /// Note that this function may be called even after has been invoked.
+ event Action DrawActions;
/// Gets the ID of this notification.
+ /// This value does not change.
long Id { get; }
/// Gets the time of creating this notification.
+ /// This value does not change.
DateTime CreatedAt { get; }
/// Gets the effective expiry time.
/// Contains if the notification does not expire.
+ /// This value will change depending on property changes and user interactions.
DateTime EffectiveExpiry { get; }
- /// Gets a value indicating whether the notification has been dismissed.
+ /// Gets the reason how this notification got dismissed. null if not dismissed.
/// This includes when the hide animation is being played.
- bool IsDismissed { get; }
+ NotificationDismissReason? DismissReason { get; }
/// Dismisses this notification.
+ /// If the notification has already been dismissed, this function does nothing.
void DismissNow();
/// Extends this notifiation.
@@ -57,8 +56,8 @@ public interface IActiveNotification : INotification
///
/// 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.
- /// If is true, then calling this function will simply dispose the passed
- /// without actually updating the icon.
+ /// If is not null, then calling this function will simply dispose the
+ /// passed without actually updating the icon.
///
void SetIconTexture(IDalamudTextureWrap? textureWrap);
diff --git a/Dalamud/Interface/ImGuiNotification/INotification.cs b/Dalamud/Interface/ImGuiNotification/INotification.cs
index e6861726f..2bc8e751c 100644
--- a/Dalamud/Interface/ImGuiNotification/INotification.cs
+++ b/Dalamud/Interface/ImGuiNotification/INotification.cs
@@ -4,6 +4,7 @@ using Dalamud.Plugin.Services;
namespace Dalamud.Interface.ImGuiNotification;
/// Represents a notification.
+/// Not to be implemented by plugins.
public interface INotification
{
/// Gets or sets the content body of the notification.
diff --git a/Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.EventArgs.cs b/Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.EventArgs.cs
new file mode 100644
index 000000000..428d9103f
--- /dev/null
+++ b/Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.EventArgs.cs
@@ -0,0 +1,87 @@
+using System.Numerics;
+
+using Dalamud.Interface.ImGuiNotification.EventArgs;
+
+namespace Dalamud.Interface.ImGuiNotification.Internal;
+
+/// Represents an active notification.
+internal sealed partial class ActiveNotification : INotificationDismissArgs
+{
+ ///
+ public event Action? Dismiss;
+
+ ///
+ IActiveNotification INotificationDismissArgs.Notification => this;
+
+ ///
+ NotificationDismissReason INotificationDismissArgs.Reason =>
+ this.DismissReason
+ ?? throw new InvalidOperationException("DismissReason must be set before using INotificationDismissArgs");
+
+ private void InvokeDismiss()
+ {
+ try
+ {
+ this.Dismiss?.Invoke(this);
+ }
+ catch (Exception e)
+ {
+ this.LogEventInvokeError(e, $"{nameof(this.Dismiss)} error");
+ }
+ }
+}
+
+/// Represents an active notification.
+internal sealed partial class ActiveNotification : INotificationClickArgs
+{
+ ///
+ public event Action? Click;
+
+ ///
+ IActiveNotification INotificationClickArgs.Notification => this;
+
+ private void InvokeClick()
+ {
+ try
+ {
+ this.Click?.Invoke(this);
+ }
+ catch (Exception e)
+ {
+ this.LogEventInvokeError(e, $"{nameof(this.Click)} error");
+ }
+ }
+}
+
+/// Represents an active notification.
+internal sealed partial class ActiveNotification : INotificationDrawArgs
+{
+ private Vector2 drawActionArgMinCoord;
+ private Vector2 drawActionArgMaxCoord;
+
+ ///
+ public event Action? DrawActions;
+
+ ///
+ IActiveNotification INotificationDrawArgs.Notification => this;
+
+ ///
+ Vector2 INotificationDrawArgs.MinCoord => this.drawActionArgMinCoord;
+
+ ///
+ Vector2 INotificationDrawArgs.MaxCoord => this.drawActionArgMaxCoord;
+
+ private void InvokeDrawActions(Vector2 minCoord, Vector2 maxCoord)
+ {
+ this.drawActionArgMinCoord = minCoord;
+ this.drawActionArgMaxCoord = maxCoord;
+ try
+ {
+ this.DrawActions?.Invoke(this);
+ }
+ catch (Exception e)
+ {
+ this.LogEventInvokeError(e, $"{nameof(this.DrawActions)} error; event registration cancelled");
+ }
+ }
+}
diff --git a/Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.ImGui.cs b/Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.ImGui.cs
index 99b924923..60e8e28e6 100644
--- a/Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.ImGui.cs
+++ b/Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.ImGui.cs
@@ -2,7 +2,6 @@ using System.Numerics;
using Dalamud.Interface.Internal;
using Dalamud.Interface.Utility;
-using Dalamud.Utility;
using ImGuiNET;
@@ -83,7 +82,7 @@ internal sealed partial class ActiveNotification
this.EffectiveExpiry = this.CalculateEffectiveExpiry(ref warrantsExtension);
- if (!this.IsDismissed && DateTime.Now > this.EffectiveExpiry)
+ if (DateTime.Now > this.EffectiveExpiry)
this.DismissNow(NotificationDismissReason.Timeout);
if (this.ExtensionDurationSinceLastInterest > TimeSpan.Zero && warrantsExtension)
@@ -121,7 +120,7 @@ internal sealed partial class ActiveNotification
if (ImGui.IsMouseClicked(ImGuiMouseButton.Left)
|| ImGui.IsMouseClicked(ImGuiMouseButton.Right)
|| ImGui.IsMouseClicked(ImGuiMouseButton.Middle))
- this.Click.InvokeSafely(this);
+ this.InvokeClick();
}
}
@@ -419,22 +418,16 @@ internal sealed partial class ActiveNotification
ImGui.PopTextWrapPos();
if (this.DrawActions is not null)
{
- ImGui.SetCursorPosY(ImGui.GetCursorPosY() + NotificationConstants.ScaledComponentGap);
- try
- {
- this.DrawActions.Invoke(this);
- }
- catch
- {
- // ignore
- }
+ this.InvokeDrawActions(
+ minCoord with { Y = ImGui.GetCursorPosY() + NotificationConstants.ScaledComponentGap },
+ new(minCoord.X + width, float.MaxValue));
}
}
private void DrawExpiryBar(DateTime effectiveExpiry, bool warrantsExtension)
{
float barL, barR;
- if (this.IsDismissed)
+ if (this.DismissReason is not null)
{
var v = this.hideEasing.IsDone ? 0f : 1f - (float)this.hideEasing.Value;
var midpoint = (this.prevProgressL + this.prevProgressR) / 2f;
diff --git a/Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.cs b/Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.cs
index 357752f6e..475ae7e68 100644
--- a/Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.cs
+++ b/Dalamud/Interface/ImGuiNotification/Internal/ActiveNotification.cs
@@ -1,16 +1,15 @@
-using System.Numerics;
using System.Runtime.Loader;
using System.Threading;
using Dalamud.Interface.Animation;
using Dalamud.Interface.Animation.EasingFunctions;
-using Dalamud.Interface.Colors;
using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Plugin.Internal.Types;
using Dalamud.Utility;
using Serilog;
+using Serilog.Events;
namespace Dalamud.Interface.ImGuiNotification.Internal;
@@ -71,15 +70,6 @@ internal sealed partial class ActiveNotification : IActiveNotification
this.progressEasing.Start();
}
- ///
- public event NotificationDismissedDelegate? Dismiss;
-
- ///
- public event Action? Click;
-
- ///
- public event Action? DrawActions;
-
///
public long Id { get; } = IActiveNotification.CreateNewId();
@@ -90,60 +80,35 @@ internal sealed partial class ActiveNotification : IActiveNotification
public string Content
{
get => this.underlyingNotification.Content;
- set
- {
- if (this.IsDismissed)
- return;
- this.underlyingNotification.Content = value;
- }
+ set => this.underlyingNotification.Content = value;
}
///
public string? Title
{
get => this.underlyingNotification.Title;
- set
- {
- if (this.IsDismissed)
- return;
- this.underlyingNotification.Title = value;
- }
+ set => this.underlyingNotification.Title = value;
}
///
public string? MinimizedText
{
get => this.underlyingNotification.MinimizedText;
- set
- {
- if (this.IsDismissed)
- return;
- this.underlyingNotification.MinimizedText = value;
- }
+ set => this.underlyingNotification.MinimizedText = value;
}
///
public NotificationType Type
{
get => this.underlyingNotification.Type;
- set
- {
- if (this.IsDismissed)
- return;
- this.underlyingNotification.Type = value;
- }
+ set => this.underlyingNotification.Type = value;
}
///
public INotificationIcon? Icon
{
get => this.underlyingNotification.Icon;
- set
- {
- if (this.IsDismissed)
- return;
- this.underlyingNotification.Icon = value;
- }
+ set => this.underlyingNotification.Icon = value;
}
///
@@ -152,7 +117,7 @@ internal sealed partial class ActiveNotification : IActiveNotification
get => this.underlyingNotification.HardExpiry;
set
{
- if (this.underlyingNotification.HardExpiry == value || this.IsDismissed)
+ if (this.underlyingNotification.HardExpiry == value)
return;
this.underlyingNotification.HardExpiry = value;
this.lastInterestTime = DateTime.Now;
@@ -165,8 +130,6 @@ internal sealed partial class ActiveNotification : IActiveNotification
get => this.underlyingNotification.InitialDuration;
set
{
- if (this.IsDismissed)
- return;
this.underlyingNotification.InitialDuration = value;
this.lastInterestTime = DateTime.Now;
}
@@ -178,8 +141,6 @@ internal sealed partial class ActiveNotification : IActiveNotification
get => this.underlyingNotification.ExtensionDurationSinceLastInterest;
set
{
- if (this.IsDismissed)
- return;
this.underlyingNotification.ExtensionDurationSinceLastInterest = value;
this.lastInterestTime = DateTime.Now;
}
@@ -188,57 +149,37 @@ internal sealed partial class ActiveNotification : IActiveNotification
///
public DateTime EffectiveExpiry { get; private set; }
+ ///
+ public NotificationDismissReason? DismissReason { get; private set; }
+
///
public bool ShowIndeterminateIfNoExpiry
{
get => this.underlyingNotification.ShowIndeterminateIfNoExpiry;
- set
- {
- if (this.IsDismissed)
- return;
- this.underlyingNotification.ShowIndeterminateIfNoExpiry = value;
- }
+ set => this.underlyingNotification.ShowIndeterminateIfNoExpiry = value;
}
///
public bool Minimized
{
get => this.newMinimized ?? this.underlyingNotification.Minimized;
- set
- {
- if (this.IsDismissed)
- return;
- this.newMinimized = value;
- }
+ set => this.newMinimized = value;
}
///
public bool UserDismissable
{
get => this.underlyingNotification.UserDismissable;
- set
- {
- if (this.IsDismissed)
- return;
- this.underlyingNotification.UserDismissable = value;
- }
+ set => this.underlyingNotification.UserDismissable = value;
}
///
public float Progress
{
get => this.newProgress ?? this.underlyingNotification.Progress;
- set
- {
- if (this.IsDismissed)
- return;
- this.newProgress = value;
- }
+ set => this.newProgress = value;
}
- ///
- public bool IsDismissed => this.hideEasing.IsRunning;
-
/// Gets the eased progress.
private float ProgressEased
{
@@ -271,20 +212,12 @@ internal sealed partial class ActiveNotification : IActiveNotification
/// The reason of dismissal.
public void DismissNow(NotificationDismissReason reason)
{
- if (this.hideEasing.IsRunning)
+ if (this.DismissReason is not null)
return;
+ this.DismissReason = reason;
this.hideEasing.Start();
- try
- {
- this.Dismiss?.Invoke(this, reason);
- }
- catch (Exception e)
- {
- Log.Error(
- e,
- $"{nameof(this.Dismiss)} error; notification is owned by {this.initiatorPlugin?.Name ?? NotificationConstants.DefaultInitiator}");
- }
+ this.InvokeDismiss();
}
///
@@ -298,7 +231,7 @@ internal sealed partial class ActiveNotification : IActiveNotification
///
public void SetIconTexture(IDalamudTextureWrap? textureWrap)
{
- if (this.IsDismissed)
+ if (this.DismissReason is not null)
{
textureWrap?.Dispose();
return;
@@ -408,4 +341,9 @@ internal sealed partial class ActiveNotification : IActiveNotification
this.DrawActions = null;
this.initiatorPlugin = null;
}
+
+ private void LogEventInvokeError(Exception exception, string message) =>
+ Log.Error(
+ exception,
+ $"[{nameof(ActiveNotification)}:{this.initiatorPlugin?.Name ?? NotificationConstants.DefaultInitiator}] {message}");
}
diff --git a/Dalamud/Interface/ImGuiNotification/Internal/NotificationIcon/GamePathNotificationIcon.cs b/Dalamud/Interface/ImGuiNotification/Internal/NotificationIcon/GamePathNotificationIcon.cs
index c1db8820c..e0699e1b6 100644
--- a/Dalamud/Interface/ImGuiNotification/Internal/NotificationIcon/GamePathNotificationIcon.cs
+++ b/Dalamud/Interface/ImGuiNotification/Internal/NotificationIcon/GamePathNotificationIcon.cs
@@ -15,7 +15,7 @@ internal class GamePathNotificationIcon : INotificationIcon
/// The path to a .tex file inside the game resources.
/// Use to get the game path from icon IDs.
public GamePathNotificationIcon(string gamePath) => this.gamePath = gamePath;
-
+
///
public bool DrawIcon(Vector2 minCoord, Vector2 maxCoord, Vector4 color) =>
NotificationUtilities.DrawIconFrom(
diff --git a/Dalamud/Interface/ImGuiNotification/Internal/NotificationManager.cs b/Dalamud/Interface/ImGuiNotification/Internal/NotificationManager.cs
index 5ee9fed3e..973e93c72 100644
--- a/Dalamud/Interface/ImGuiNotification/Internal/NotificationManager.cs
+++ b/Dalamud/Interface/ImGuiNotification/Internal/NotificationManager.cs
@@ -137,7 +137,7 @@ internal class NotificationManagerPluginScoped : INotificationManager, IServiceT
{
var an = this.notificationManagerService.AddNotification(notification, this.localPlugin);
_ = this.notifications.TryAdd(an, 0);
- an.Dismiss += (a, unused) => this.notifications.TryRemove(an, out _);
+ an.Dismiss += a => this.notifications.TryRemove(a.Notification, out _);
return an;
}
diff --git a/Dalamud/Interface/ImGuiNotification/NotificationDismissedDelegate.cs b/Dalamud/Interface/ImGuiNotification/NotificationDismissedDelegate.cs
deleted file mode 100644
index 09d6fd818..000000000
--- a/Dalamud/Interface/ImGuiNotification/NotificationDismissedDelegate.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Dalamud.Interface.ImGuiNotification;
-
-/// Delegate representing the dismissal of an active notification.
-/// The notification being dismissed.
-/// The reason of dismissal.
-public delegate void NotificationDismissedDelegate(
- IActiveNotification notification,
- NotificationDismissReason dismissReason);
diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs
index 6c94a2273..d51f18216 100644
--- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs
+++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs
@@ -219,7 +219,7 @@ internal class ImGuiWidget : IDataWindowWidget
Task.Run(
async () =>
{
- for (var i = 0; i <= 10 && !n.IsDismissed; i++)
+ for (var i = 0; i <= 10 && !n.DismissReason.HasValue; i++)
{
await Task.Delay(500);
n.Progress = i / 10f;
@@ -230,7 +230,7 @@ internal class ImGuiWidget : IDataWindowWidget
Task.Run(
async () =>
{
- for (var i = 0; i <= 10 && !n.IsDismissed; i++)
+ for (var i = 0; i <= 10 && !n.DismissReason.HasValue; i++)
{
await Task.Delay(500);
n.Progress = i / 10f;
@@ -257,16 +257,17 @@ internal class ImGuiWidget : IDataWindowWidget
if (ImGui.Button("Update"))
{
NewRandom(out title, out type, out progress);
- an.Title = title;
- an.Type = type;
- an.Progress = progress;
+ an.Notification.Title = title;
+ an.Notification.Type = type;
+ an.Notification.Progress = progress;
}
ImGui.SameLine();
if (ImGui.Button("Dismiss"))
- an.DismissNow();
+ an.Notification.DismissNow();
ImGui.SameLine();
+ ImGui.SetNextItemWidth(an.MaxCoord.X - ImGui.GetCursorPosX());
ImGui.InputText("##input", ref testString, 255);
};
}
diff --git a/Dalamud/Interface/UiBuilder.cs b/Dalamud/Interface/UiBuilder.cs
index 3a90d52c1..2053d9354 100644
--- a/Dalamud/Interface/UiBuilder.cs
+++ b/Dalamud/Interface/UiBuilder.cs
@@ -583,7 +583,7 @@ public sealed class UiBuilder : IDisposable
},
this.localPlugin);
_ = this.notifications.TryAdd(an, 0);
- an.Dismiss += (a, unused) => this.notifications.TryRemove(an, out _);
+ an.Dismiss += a => this.notifications.TryRemove(a.Notification, out _);
}
///