Add IconSource

This commit is contained in:
Soreepeong 2024-02-26 01:21:45 +09:00
parent 7aba15ef5b
commit 3a6aa13c3b
13 changed files with 506 additions and 119 deletions

View file

@ -1,5 +1,4 @@
using System.Threading;
using System.Threading.Tasks;
using Dalamud.Interface.Internal.Notifications;
@ -57,8 +56,10 @@ public interface IActiveNotification : INotification
/// <inheritdoc cref="INotification.Type"/>
new NotificationType Type { get; set; }
/// <inheritdoc cref="INotification.IconCreator"/>
new Func<Task<object>>? IconCreator { get; set; }
/// <summary>Gets or sets the icon source.</summary>
/// <remarks>Setting a new value to this property does not change the icon. Use <see cref="UpdateIcon"/> to do so.
/// </remarks>
new INotificationIconSource? IconSource { get; set; }
/// <inheritdoc cref="INotification.Expiry"/>
new DateTime Expiry { get; set; }
@ -91,13 +92,13 @@ public interface IActiveNotification : INotification
/// <summary>Updates the notification data.</summary>
/// <remarks>
/// Call <see cref="UpdateIcon"/> to update the icon using the new <see cref="INotification.IconCreator"/>.
/// Call <see cref="UpdateIcon"/> to update the icon using the new <see cref="INotification.IconSource"/>.
/// If <see cref="IsDismissed"/> is <c>true</c>, then this function is a no-op.
/// </remarks>
/// <param name="newNotification">The new notification entry.</param>
void Update(INotification newNotification);
/// <summary>Loads the icon again using <see cref="INotification.IconCreator"/>.</summary>
/// <summary>Loads the icon again using <see cref="INotification.IconSource"/>.</summary>
/// <remarks>If <see cref="IsDismissed"/> is <c>true</c>, then this function is a no-op.</remarks>
void UpdateIcon();

View file

@ -1,7 +1,4 @@
using System.Threading.Tasks;
using Dalamud.Game.Text;
using Dalamud.Interface.Internal;
using Dalamud.Interface.ImGuiNotification.IconSource;
using Dalamud.Interface.Internal.Notifications;
namespace Dalamud.Interface.ImGuiNotification;
@ -18,18 +15,17 @@ public interface INotification
/// <summary>Gets the type of the notification.</summary>
NotificationType Type { get; }
/// <summary>Gets the icon creator function for the notification.<br />
/// Currently <see cref="IDalamudTextureWrap"/>, <see cref="SeIconChar"/>, and <see cref="FontAwesomeIcon"/> types
/// are accepted.</summary>
/// <remarks>
/// The icon created by the task returned will be owned by Dalamud,
/// i.e. it will be <see cref="IDisposable.Dispose"/>d automatically as needed.<br />
/// If <c>null</c> is supplied for this property or <see cref="Task.IsCompletedSuccessfully"/> of the returned task
/// is <c>false</c>, then the corresponding icon with <see cref="Type"/> will be used.<br />
/// Use <see cref="Task.FromResult{TResult}"/> if you have an instance of <see cref="IDalamudTextureWrap"/> that you
/// can transfer ownership to Dalamud and is available for use right away.
/// <summary>Gets the icon source.</summary>
/// <remarks>The following icon sources are currently available.<br />
/// <ul>
/// <li><see cref="SeIconCharIconSource"/></li>
/// <li><see cref="FontAwesomeIconIconSource"/></li>
/// <li><see cref="TextureWrapTaskIconSource"/></li>
/// <li><see cref="GamePathIconSource"/></li>
/// <li><see cref="FilePathIconSource"/></li>
/// </ul>
/// </remarks>
Func<Task<object>>? IconCreator { get; }
INotificationIconSource? IconSource { get; }
/// <summary>Gets the expiry.</summary>
/// <remarks>Set to <see cref="DateTime.MaxValue"/> to make the notification not have an expiry time

View file

@ -0,0 +1,20 @@
namespace Dalamud.Interface.ImGuiNotification;
/// <summary>Icon source for <see cref="INotification"/>.</summary>
/// <remarks>Plugins should NOT implement this interface.</remarks>
public interface INotificationIconSource : ICloneable, IDisposable
{
/// <summary>The internal interface.</summary>
internal interface IInternal : INotificationIconSource
{
/// <summary>Materializes the icon resource.</summary>
/// <returns>The materialized resource.</returns>
INotificationMaterializedIcon Materialize();
}
/// <inheritdoc cref="ICloneable.Clone"/>
new INotificationIconSource Clone();
/// <inheritdoc/>
object ICloneable.Clone() => this.Clone();
}

View file

@ -0,0 +1,18 @@
using System.Numerics;
using Dalamud.Plugin.Internal.Types;
namespace Dalamud.Interface.ImGuiNotification;
/// <summary>
/// Represents a materialized icon.
/// </summary>
internal interface INotificationMaterializedIcon : IDisposable
{
/// <summary>Draws the icon.</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="color">The foreground color.</param>
/// <param name="initiatorPlugin">The initiator plugin.</param>
void DrawIcon(Vector2 minCoord, Vector2 maxCoord, Vector4 color, LocalPlugin? initiatorPlugin);
}

View file

@ -0,0 +1,50 @@
using System.IO;
using System.Numerics;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal;
using Dalamud.Plugin.Internal.Types;
namespace Dalamud.Interface.ImGuiNotification.IconSource;
/// <summary>Represents the use of a texture from a file as the icon of a notification.</summary>
/// <remarks>If there was no texture loaded for any reason, the plugin icon will be displayed instead.</remarks>
public readonly struct FilePathIconSource : INotificationIconSource.IInternal
{
/// <summary>The path to a .tex file inside the game resources.</summary>
public readonly string FilePath;
/// <summary>Initializes a new instance of the <see cref="FilePathIconSource"/> struct.</summary>
/// <param name="filePath">The path to a .tex file inside the game resources.</param>
public FilePathIconSource(string filePath) => this.FilePath = filePath;
/// <inheritdoc/>
public INotificationIconSource Clone() => this;
/// <inheritdoc/>
void IDisposable.Dispose()
{
}
/// <inheritdoc/>
INotificationMaterializedIcon INotificationIconSource.IInternal.Materialize() =>
new MaterializedIcon(this.FilePath);
private sealed class MaterializedIcon : INotificationMaterializedIcon
{
private readonly FileInfo fileInfo;
public MaterializedIcon(string filePath) => this.fileInfo = new(filePath);
public void Dispose()
{
}
public void DrawIcon(Vector2 minCoord, Vector2 maxCoord, Vector4 color, LocalPlugin? initiatorPlugin) =>
NotificationUtilities.DrawTexture(
Service<TextureManager>.Get().GetTextureFromFile(this.fileInfo),
minCoord,
maxCoord,
initiatorPlugin);
}
}

View file

@ -0,0 +1,62 @@
using System.Numerics;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Plugin.Internal.Types;
using ImGuiNET;
namespace Dalamud.Interface.ImGuiNotification.IconSource;
/// <summary>Represents the use of <see cref="FontAwesomeIcon"/> as the icon of a notification.</summary>
public readonly struct FontAwesomeIconIconSource : INotificationIconSource.IInternal
{
/// <summary>The icon character.</summary>
public readonly FontAwesomeIcon Char;
/// <summary>Initializes a new instance of the <see cref="FontAwesomeIconIconSource"/> struct.</summary>
/// <param name="c">The character.</param>
public FontAwesomeIconIconSource(FontAwesomeIcon c) => this.Char = c;
/// <inheritdoc/>
public INotificationIconSource Clone() => this;
/// <inheritdoc/>
void IDisposable.Dispose()
{
}
/// <inheritdoc/>
INotificationMaterializedIcon INotificationIconSource.IInternal.Materialize() => new MaterializedIcon(this.Char);
/// <summary>Draws the icon.</summary>
/// <param name="iconString">The icon string.</param>
/// <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="color">The foreground color.</param>
internal static void DrawIconStatic(string iconString, Vector2 minCoord, Vector2 maxCoord, Vector4 color)
{
using (Service<NotificationManager>.Get().IconFontAwesomeFontHandle.Push())
{
var size = ImGui.CalcTextSize(iconString);
var pos = ((minCoord + maxCoord) - size) / 2;
ImGui.SetCursorPos(pos);
ImGui.PushStyleColor(ImGuiCol.Text, color);
ImGui.TextUnformatted(iconString);
ImGui.PopStyleColor();
}
}
private sealed class MaterializedIcon : INotificationMaterializedIcon
{
private readonly string iconString;
public MaterializedIcon(FontAwesomeIcon c) => this.iconString = c.ToIconString();
public void Dispose()
{
}
public void DrawIcon(Vector2 minCoord, Vector2 maxCoord, Vector4 color, LocalPlugin? initiatorPlugin) =>
DrawIconStatic(this.iconString, minCoord, maxCoord, color);
}
}

View file

@ -0,0 +1,51 @@
using System.Numerics;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal;
using Dalamud.Plugin.Internal.Types;
using Dalamud.Plugin.Services;
namespace Dalamud.Interface.ImGuiNotification.IconSource;
/// <summary>Represents the use of a game-shipped texture as the icon of a notification.</summary>
/// <remarks>If there was no texture loaded for any reason, the plugin icon will be displayed instead.</remarks>
public readonly struct GamePathIconSource : INotificationIconSource.IInternal
{
/// <summary>The path to a .tex file inside the game resources.</summary>
public readonly string GamePath;
/// <summary>Initializes a new instance of the <see cref="GamePathIconSource"/> struct.</summary>
/// <param name="gamePath">The path to a .tex file inside the game resources.</param>
/// <remarks>Use <see cref="ITextureProvider.GetIconPath"/> to get the game path from icon IDs.</remarks>
public GamePathIconSource(string gamePath) => this.GamePath = gamePath;
/// <inheritdoc/>
public INotificationIconSource Clone() => this;
/// <inheritdoc/>
void IDisposable.Dispose()
{
}
/// <inheritdoc/>
INotificationMaterializedIcon INotificationIconSource.IInternal.Materialize() =>
new MaterializedIcon(this.GamePath);
private sealed class MaterializedIcon : INotificationMaterializedIcon
{
private readonly string gamePath;
public MaterializedIcon(string gamePath) => this.gamePath = gamePath;
public void Dispose()
{
}
public void DrawIcon(Vector2 minCoord, Vector2 maxCoord, Vector4 color, LocalPlugin? initiatorPlugin) =>
NotificationUtilities.DrawTexture(
Service<TextureManager>.Get().GetTextureFromGame(this.gamePath),
minCoord,
maxCoord,
initiatorPlugin);
}
}

View file

@ -0,0 +1,55 @@
using System.Numerics;
using Dalamud.Game.Text;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Plugin.Internal.Types;
using ImGuiNET;
namespace Dalamud.Interface.ImGuiNotification.IconSource;
/// <summary>Represents the use of <see cref="SeIconChar"/> as the icon of a notification.</summary>
public readonly struct SeIconCharIconSource : INotificationIconSource.IInternal
{
/// <summary>The icon character.</summary>
public readonly SeIconChar Char;
/// <summary>Initializes a new instance of the <see cref="SeIconCharIconSource"/> struct.</summary>
/// <param name="c">The character.</param>
public SeIconCharIconSource(SeIconChar c) => this.Char = c;
/// <inheritdoc/>
public INotificationIconSource Clone() => this;
/// <inheritdoc/>
void IDisposable.Dispose()
{
}
/// <inheritdoc/>
INotificationMaterializedIcon INotificationIconSource.IInternal.Materialize() => new MaterializedIcon(this.Char);
private sealed class MaterializedIcon : INotificationMaterializedIcon
{
private readonly string iconString;
public MaterializedIcon(SeIconChar c) => this.iconString = c.ToIconString();
public void Dispose()
{
}
public void DrawIcon(Vector2 minCoord, Vector2 maxCoord, Vector4 color, LocalPlugin? initiatorPlugin)
{
using (Service<NotificationManager>.Get().IconAxisFontHandle.Push())
{
var size = ImGui.CalcTextSize(this.iconString);
var pos = ((minCoord + maxCoord) - size) / 2;
ImGui.SetCursorPos(pos);
ImGui.PushStyleColor(ImGuiCol.Text, color);
ImGui.TextUnformatted(this.iconString);
ImGui.PopStyleColor();
}
}
}
}

View file

@ -0,0 +1,59 @@
using System.Numerics;
using System.Threading.Tasks;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal;
using Dalamud.Plugin.Internal.Types;
using Dalamud.Utility;
namespace Dalamud.Interface.ImGuiNotification.IconSource;
/// <summary>Represents the use of future <see cref="IDalamudTextureWrap"/> as the icon of a notification.</summary>
/// <remarks>If there was no texture loaded for any reason, the plugin icon will be displayed instead.</remarks>
public readonly struct TextureWrapTaskIconSource : INotificationIconSource.IInternal
{
/// <summary>The function that returns a task resulting in a new instance of <see cref="IDalamudTextureWrap"/>.
/// </summary>
/// <remarks>Dalamud will take ownership of the result. Do not call <see cref="IDisposable.Dispose"/>.</remarks>
public readonly Func<Task<IDalamudTextureWrap?>?>? TextureWrapTaskFunc;
/// <summary>Gets the default materialized icon, for the purpose of displaying the plugin icon.</summary>
internal static readonly INotificationMaterializedIcon DefaultMaterializedIcon = new MaterializedIcon(null);
/// <summary>Initializes a new instance of the <see cref="TextureWrapTaskIconSource"/> struct.</summary>
/// <param name="taskFunc">The function.</param>
public TextureWrapTaskIconSource(Func<Task<IDalamudTextureWrap?>?>? taskFunc) =>
this.TextureWrapTaskFunc = taskFunc;
/// <inheritdoc/>
public INotificationIconSource Clone() => this;
/// <inheritdoc/>
void IDisposable.Dispose()
{
}
/// <inheritdoc/>
INotificationMaterializedIcon INotificationIconSource.IInternal.Materialize() =>
new MaterializedIcon(this.TextureWrapTaskFunc);
private sealed class MaterializedIcon : INotificationMaterializedIcon
{
private Task<IDalamudTextureWrap>? task;
public MaterializedIcon(Func<Task<IDalamudTextureWrap?>?>? taskFunc) => this.task = taskFunc?.Invoke();
public void Dispose()
{
this.task?.ToContentDisposedTask(true);
this.task = null;
}
public void DrawIcon(Vector2 minCoord, Vector2 maxCoord, Vector4 color, LocalPlugin? initiatorPlugin) =>
NotificationUtilities.DrawTexture(
this.task?.IsCompletedSuccessfully is true ? this.task.Result : null,
minCoord,
maxCoord,
initiatorPlugin);
}
}

View file

@ -1,25 +1,21 @@
using System.Numerics;
using System.Runtime.Loader;
using System.Threading.Tasks;
using Dalamud.Game.Text;
using Dalamud.Interface.Animation;
using Dalamud.Interface.Animation.EasingFunctions;
using Dalamud.Interface.Colors;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.Windows;
using Dalamud.Interface.ManagedFontAtlas;
using Dalamud.Interface.ImGuiNotification.IconSource;
using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Utility;
using Dalamud.Plugin.Internal.Types;
using Dalamud.Storage.Assets;
using Dalamud.Utility;
using ImGuiNET;
using Serilog;
namespace Dalamud.Interface.Internal.Notifications;
namespace Dalamud.Interface.ImGuiNotification.Internal;
/// <summary>Represents an active notification.</summary>
internal sealed class ActiveNotification : IActiveNotification, IDisposable
@ -115,15 +111,15 @@ internal sealed class ActiveNotification : IActiveNotification, IDisposable
}
}
/// <inheritdoc cref="IActiveNotification.IconCreator"/>
public Func<Task<object>>? IconCreator
/// <inheritdoc cref="IActiveNotification.IconSource"/>
public INotificationIconSource? IconSource
{
get => this.underlyingNotification.IconCreator;
get => this.underlyingNotification.IconSource;
set
{
if (this.IsDismissed)
return;
this.underlyingNotification.IconCreator = value;
this.underlyingNotification.IconSource = value;
}
}
@ -192,7 +188,7 @@ internal sealed class ActiveNotification : IActiveNotification, IDisposable
public LocalPlugin? InitiatorPlugin { get; set; }
/// <summary>Gets or sets the icon of this notification.</summary>
public Task<object>? IconTask { get; set; }
public INotificationMaterializedIcon? MaterializedIcon { get; set; }
/// <summary>Gets the eased progress.</summary>
private float ProgressEased
@ -255,7 +251,7 @@ internal sealed class ActiveNotification : IActiveNotification, IDisposable
public void Dispose()
{
this.ClearIconTask();
this.underlyingNotification.IconCreator = null;
this.underlyingNotification.IconSource = null;
this.Dismiss = null;
this.Click = null;
this.DrawActions = null;
@ -487,7 +483,7 @@ internal sealed class ActiveNotification : IActiveNotification, IDisposable
this.Content = newNotification.Content;
this.Title = newNotification.Title;
this.Type = newNotification.Type;
this.IconCreator = newNotification.IconCreator;
this.IconSource = newNotification.IconSource;
this.Expiry = newNotification.Expiry;
this.Interactible = newNotification.Interactible;
this.HoverExtendDuration = newNotification.HoverExtendDuration;
@ -500,7 +496,7 @@ internal sealed class ActiveNotification : IActiveNotification, IDisposable
if (this.IsDismissed)
return;
this.ClearIconTask();
this.IconTask = this.IconCreator?.Invoke();
this.MaterializedIcon = (this.IconSource as INotificationIconSource.IInternal)?.Materialize();
}
/// <summary>Removes non-Dalamud invocation targets from events.</summary>
@ -546,20 +542,14 @@ internal sealed class ActiveNotification : IActiveNotification, IDisposable
private void ClearIconTask()
{
_ = this.IconTask?.ContinueWith(
r =>
{
if (r.IsCompletedSuccessfully && r.Result is IDisposable d)
d.Dispose();
});
this.IconTask = null;
this.MaterializedIcon?.Dispose();
this.MaterializedIcon = null;
}
private void DrawNotificationMainWindowContent(NotificationManager notificationManager, float width)
{
var basePos = ImGui.GetCursorPos();
this.DrawIcon(
notificationManager,
basePos,
basePos + new Vector2(NotificationConstants.ScaledIconSize));
basePos.X += NotificationConstants.ScaledIconSize + NotificationConstants.ScaledWindowPadding;
@ -633,84 +623,26 @@ internal sealed class ActiveNotification : IActiveNotification, IDisposable
ImGui.PopClipRect();
}
private void DrawIcon(NotificationManager notificationManager, Vector2 minCoord, Vector2 maxCoord)
private void DrawIcon(Vector2 minCoord, Vector2 maxCoord)
{
string? iconString = null;
IFontHandle? fontHandle = null;
IDalamudTextureWrap? iconTexture = null;
switch (this.IconTask?.IsCompletedSuccessfully is true ? this.IconTask.Result : null)
if (this.MaterializedIcon is not null)
{
case IDalamudTextureWrap wrap:
iconTexture = wrap;
break;
case SeIconChar icon:
iconString = string.Empty + (char)icon;
fontHandle = notificationManager.IconAxisFontHandle;
break;
case FontAwesomeIcon icon:
iconString = icon.ToIconString();
fontHandle = notificationManager.IconFontAwesomeFontHandle;
break;
default:
iconString = this.DefaultIconString;
fontHandle = notificationManager.IconFontAwesomeFontHandle;
break;
this.MaterializedIcon.DrawIcon(minCoord, maxCoord, this.DefaultIconColor, this.InitiatorPlugin);
return;
}
if (string.IsNullOrWhiteSpace(iconString))
var defaultIconString = this.DefaultIconString;
if (!string.IsNullOrWhiteSpace(defaultIconString))
{
var dam = Service<DalamudAssetManager>.Get();
if (this.InitiatorPlugin is null)
{
iconTexture = dam.GetDalamudTextureWrap(DalamudAsset.LogoSmall);
}
else
{
if (!Service<PluginImageCache>.Get().TryGetIcon(
this.InitiatorPlugin,
this.InitiatorPlugin.Manifest,
this.InitiatorPlugin.IsThirdParty,
out iconTexture) || iconTexture is null)
{
iconTexture = this.InitiatorPlugin switch
{
{ IsDev: true } => dam.GetDalamudTextureWrap(DalamudAsset.DevPluginIcon),
{ IsThirdParty: true } => dam.GetDalamudTextureWrap(DalamudAsset.ThirdInstalledIcon),
_ => dam.GetDalamudTextureWrap(DalamudAsset.InstalledIcon),
};
}
}
FontAwesomeIconIconSource.DrawIconStatic(defaultIconString, minCoord, maxCoord, this.DefaultIconColor);
return;
}
if (iconTexture is not null)
{
var size = iconTexture.Size;
if (size.X > maxCoord.X - minCoord.X)
size *= (maxCoord.X - minCoord.X) / size.X;
if (size.Y > maxCoord.Y - minCoord.Y)
size *= (maxCoord.Y - minCoord.Y) / size.Y;
var pos = ((minCoord + maxCoord) - size) / 2;
ImGui.SetCursorPos(pos);
ImGui.Image(iconTexture.ImGuiHandle, size);
}
else
{
// Just making it extremely sure
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
if (fontHandle is null || iconString is null)
// ReSharper disable once HeuristicUnreachableCode
return;
using (fontHandle.Push())
{
var size = ImGui.CalcTextSize(iconString);
var pos = ((minCoord + maxCoord) - size) / 2;
ImGui.SetCursorPos(pos);
ImGui.PushStyleColor(ImGuiCol.Text, this.DefaultIconColor);
ImGui.TextUnformatted(iconString);
ImGui.PopStyleColor();
}
}
TextureWrapTaskIconSource.DefaultMaterializedIcon.DrawIcon(
minCoord,
maxCoord,
this.DefaultIconColor,
this.InitiatorPlugin);
}
private void DrawTitle(Vector2 minCoord, Vector2 maxCoord)

View file

@ -0,0 +1,63 @@
using System.Numerics;
using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal.Windows;
using Dalamud.Plugin.Internal.Types;
using Dalamud.Storage.Assets;
using ImGuiNET;
namespace Dalamud.Interface.ImGuiNotification.Internal;
/// <summary>
/// Utilities for implementing stuff under <see cref="ImGuiNotification"/>.
/// </summary>
internal static class NotificationUtilities
{
/// <summary>
/// Draws the given texture, or the icon of the plugin if texture is <c>null</c>.
/// </summary>
/// <param name="texture">The texture.</param>
/// <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="initiatorPlugin">The initiator plugin.</param>
public static void DrawTexture(
IDalamudTextureWrap? texture,
Vector2 minCoord,
Vector2 maxCoord,
LocalPlugin? initiatorPlugin)
{
if (texture is null)
{
var dam = Service<DalamudAssetManager>.Get();
if (initiatorPlugin is null)
{
texture = dam.GetDalamudTextureWrap(DalamudAsset.LogoSmall);
}
else
{
if (!Service<PluginImageCache>.Get().TryGetIcon(
initiatorPlugin,
initiatorPlugin.Manifest,
initiatorPlugin.IsThirdParty,
out texture) || texture is null)
{
texture = initiatorPlugin switch
{
{ IsDev: true } => dam.GetDalamudTextureWrap(DalamudAsset.DevPluginIcon),
{ IsThirdParty: true } => dam.GetDalamudTextureWrap(DalamudAsset.ThirdInstalledIcon),
_ => dam.GetDalamudTextureWrap(DalamudAsset.InstalledIcon),
};
}
}
}
var size = texture.Size;
if (size.X > maxCoord.X - minCoord.X)
size *= (maxCoord.X - minCoord.X) / size.X;
if (size.Y > maxCoord.Y - minCoord.Y)
size *= (maxCoord.Y - minCoord.Y) / size.Y;
ImGui.SetCursorPos(((minCoord + maxCoord) - size) / 2);
ImGui.Image(texture.ImGuiHandle, size);
}
}

View file

@ -1,5 +1,3 @@
using System.Threading.Tasks;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.Notifications;
@ -20,7 +18,7 @@ public sealed record Notification : INotification
public NotificationType Type { get; set; } = NotificationType.None;
/// <inheritdoc/>
public Func<Task<object>>? IconCreator { get; set; }
public INotificationIconSource? IconSource { get; set; }
/// <inheritdoc/>
public DateTime Expiry { get; set; } = DateTime.Now + NotificationConstants.DefaultDisplayDuration;

View file

@ -1,8 +1,13 @@
using System.Threading.Tasks;
using System.Linq;
using System.Threading.Tasks;
using Dalamud.Game.Text;
using Dalamud.Interface.ImGuiNotification.IconSource;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Windowing;
using Dalamud.Storage.Assets;
using Dalamud.Utility;
using ImGuiNET;
@ -66,6 +71,41 @@ internal class ImGuiWidget : IDataWindowWidget
NotificationTemplate.TypeTitles,
NotificationTemplate.TypeTitles.Length);
ImGui.Combo(
"Icon Source##iconSourceCombo",
ref this.notificationTemplate.IconSourceInt,
NotificationTemplate.IconSourceTitles,
NotificationTemplate.IconSourceTitles.Length);
switch (this.notificationTemplate.IconSourceInt)
{
case 1:
case 2:
ImGui.InputText(
"Icon Text##iconSourceText",
ref this.notificationTemplate.IconSourceText,
255);
break;
case 3:
ImGui.Combo(
"Icon Source##iconSourceAssetCombo",
ref this.notificationTemplate.IconSourceAssetInt,
NotificationTemplate.AssetSources,
NotificationTemplate.AssetSources.Length);
break;
case 4:
ImGui.InputText(
"Game Path##iconSourceText",
ref this.notificationTemplate.IconSourceText,
255);
break;
case 5:
ImGui.InputText(
"File Path##iconSourceText",
ref this.notificationTemplate.IconSourceText,
255);
break;
}
ImGui.Combo(
"Duration",
ref this.notificationTemplate.DurationInt,
@ -114,6 +154,26 @@ internal class ImGuiWidget : IDataWindowWidget
4 => -1f,
_ => 0.5f,
},
IconSource = this.notificationTemplate.IconSourceInt switch
{
1 => new SeIconCharIconSource(
(SeIconChar)(this.notificationTemplate.IconSourceText.Length == 0
? 0
: this.notificationTemplate.IconSourceText[0])),
2 => new FontAwesomeIconIconSource(
(FontAwesomeIcon)(this.notificationTemplate.IconSourceText.Length == 0
? 0
: this.notificationTemplate.IconSourceText[0])),
3 => new TextureWrapTaskIconSource(
() =>
Service<DalamudAssetManager>.Get().GetDalamudTextureWrapAsync(
Enum.Parse<DalamudAsset>(
NotificationTemplate.AssetSources[
this.notificationTemplate.IconSourceAssetInt]))),
4 => new GamePathIconSource(this.notificationTemplate.IconSourceText),
5 => new FilePathIconSource(this.notificationTemplate.IconSourceText),
_ => null,
},
});
switch (this.notificationTemplate.ProgressMode)
{
@ -205,6 +265,22 @@ internal class ImGuiWidget : IDataWindowWidget
private struct NotificationTemplate
{
public static readonly string[] IconSourceTitles =
{
"None (use Type)",
"SeIconChar",
"FontAwesomeIcon",
"TextureWrapTask from DalamudAssets",
"GamePath",
"FilePath",
};
public static readonly string[] AssetSources =
Enum.GetValues<DalamudAsset>()
.Where(x => x.GetAttribute<DalamudAssetAttribute>()?.Purpose is DalamudAssetPurpose.TextureFromPng)
.Select(Enum.GetName)
.ToArray();
public static readonly string[] ProgressModeTitles =
{
"Default",
@ -243,6 +319,9 @@ internal class ImGuiWidget : IDataWindowWidget
public string Content;
public bool ManualTitle;
public string Title;
public int IconSourceInt;
public string IconSourceText;
public int IconSourceAssetInt;
public bool ManualType;
public int TypeInt;
public int DurationInt;
@ -256,6 +335,9 @@ internal class ImGuiWidget : IDataWindowWidget
this.Content = string.Empty;
this.ManualTitle = false;
this.Title = string.Empty;
this.IconSourceInt = 0;
this.IconSourceText = "ui/icon/000000/000004_hr1.tex";
this.IconSourceAssetInt = 0;
this.ManualType = false;
this.TypeInt = (int)NotificationType.None;
this.DurationInt = 2;