IFontAtlas API9 compat: support reading GameFontHandle.ImFont during UiBuilder.After/BuildFonts

This commit is contained in:
Soreepeong 2024-01-21 00:15:12 +09:00
parent 11c1b4658b
commit dd5cbdfd5d
8 changed files with 148 additions and 22 deletions

View file

@ -1,6 +1,8 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Interface.ManagedFontAtlas.Internals;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Utility;
using ImGuiNET; using ImGuiNET;
@ -11,6 +13,20 @@ namespace Dalamud.Interface.ManagedFontAtlas;
/// </summary> /// </summary>
public interface IFontAtlasBuildToolkit public interface IFontAtlasBuildToolkit
{ {
/// <summary>
/// Functionalities for compatibility behavior.<br />
/// </summary>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
internal interface IApi9Compat : IFontAtlasBuildToolkit
{
/// <summary>
/// Invokes <paramref name="action"/>, temporarily applying <see cref="IFontHandleSubstance"/>s.<br />
/// </summary>
/// <param name="action">The action to invoke.</param>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public void FromUiBuilderObsoleteEventHandlers(Action action);
}
/// <summary> /// <summary>
/// Gets or sets the font relevant to the call. /// Gets or sets the font relevant to the call.
/// </summary> /// </summary>

View file

@ -4,6 +4,7 @@ using System.Linq;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using Dalamud.Logging.Internal; using Dalamud.Logging.Internal;
using Dalamud.Utility;
using ImGuiNET; using ImGuiNET;
@ -144,6 +145,14 @@ internal class DelegateFontHandle : IFontHandle.IInternal
/// <inheritdoc/> /// <inheritdoc/>
public IFontHandleManager Manager { get; } public IFontHandleManager Manager { get; }
/// <inheritdoc/>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public IFontAtlasBuildToolkitPreBuild? PreBuildToolkitForApi9Compat { get; set; }
/// <inheritdoc/>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public bool CreateFontOnAccess { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public void Dispose() public void Dispose()
{ {

View file

@ -30,7 +30,7 @@ internal sealed partial class FontAtlasFactory
/// Implementations for <see cref="IFontAtlasBuildToolkitPreBuild"/> and /// Implementations for <see cref="IFontAtlasBuildToolkitPreBuild"/> and
/// <see cref="IFontAtlasBuildToolkitPostBuild"/>. /// <see cref="IFontAtlasBuildToolkitPostBuild"/>.
/// </summary> /// </summary>
private class BuildToolkit : IFontAtlasBuildToolkitPreBuild, IFontAtlasBuildToolkitPostBuild, IDisposable private class BuildToolkit : IFontAtlasBuildToolkit.IApi9Compat, IFontAtlasBuildToolkitPreBuild, IFontAtlasBuildToolkitPostBuild, IDisposable
{ {
private static readonly ushort FontAwesomeIconMin = private static readonly ushort FontAwesomeIconMin =
(ushort)Enum.GetValues<FontAwesomeIcon>().Where(x => x > 0).Min(); (ushort)Enum.GetValues<FontAwesomeIcon>().Where(x => x > 0).Min();
@ -107,6 +107,34 @@ internal sealed partial class FontAtlasFactory
/// <inheritdoc/> /// <inheritdoc/>
public void DisposeWithAtlas(Action action) => this.data.Garbage.Add(action); public void DisposeWithAtlas(Action action) => this.data.Garbage.Add(action);
/// <inheritdoc/>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public void FromUiBuilderObsoleteEventHandlers(Action action)
{
var previousSubstances = new IFontHandleSubstance[this.data.Substances.Count];
for (var i = 0; i < previousSubstances.Length; i++)
{
previousSubstances[i] = this.data.Substances[i].Manager.Substance;
this.data.Substances[i].Manager.Substance = this.data.Substances[i];
this.data.Substances[i].CreateFontOnAccess = true;
this.data.Substances[i].PreBuildToolkitForApi9Compat = this;
}
try
{
action();
}
finally
{
for (var i = 0; i < previousSubstances.Length; i++)
{
this.data.Substances[i].Manager.Substance = previousSubstances[i];
this.data.Substances[i].CreateFontOnAccess = false;
this.data.Substances[i].PreBuildToolkitForApi9Compat = null;
}
}
}
/// <inheritdoc/> /// <inheritdoc/>
public ImFontPtr IgnoreGlobalScale(ImFontPtr fontPtr) public ImFontPtr IgnoreGlobalScale(ImFontPtr fontPtr)
{ {

View file

@ -230,6 +230,14 @@ internal class GamePrebakedFontHandle : IFontHandle.IInternal
/// <inheritdoc/> /// <inheritdoc/>
public IFontHandleManager Manager => this.handleManager; public IFontHandleManager Manager => this.handleManager;
/// <inheritdoc/>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public IFontAtlasBuildToolkitPreBuild? PreBuildToolkitForApi9Compat { get; set; }
/// <inheritdoc/>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public bool CreateFontOnAccess { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public void Dispose() public void Dispose()
{ {
@ -285,11 +293,27 @@ internal class GamePrebakedFontHandle : IFontHandle.IInternal
} }
} }
// Use this on API 10.
// /// <inheritdoc/>
// public ImFontPtr GetFontPtr(IFontHandle handle) =>
// handle is GamePrebakedFontHandle ggfh
// ? this.fonts.GetValueOrDefault(ggfh.FontStyle)?.FullRangeFont ?? default
// : default;
/// <inheritdoc/> /// <inheritdoc/>
public ImFontPtr GetFontPtr(IFontHandle handle) => [Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
handle is GamePrebakedFontHandle ggfh public ImFontPtr GetFontPtr(IFontHandle handle)
? this.fonts.GetValueOrDefault(ggfh.FontStyle)?.FullRangeFont ?? default {
: default; if (handle is not GamePrebakedFontHandle ggfh)
return default;
if (this.fonts.GetValueOrDefault(ggfh.FontStyle)?.FullRangeFont is { } font)
return font;
if (!this.CreateFontOnAccess)
return default;
if (this.PreBuildToolkitForApi9Compat is not { } tk)
return default;
return this.GetOrCreateFont(ggfh.FontStyle, tk);
}
/// <inheritdoc/> /// <inheritdoc/>
public Exception? GetBuildException(IFontHandle handle) => public Exception? GetBuildException(IFontHandle handle) =>

View file

@ -1,4 +1,6 @@
using ImGuiNET; using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.ManagedFontAtlas.Internals; namespace Dalamud.Interface.ManagedFontAtlas.Internals;
@ -12,6 +14,19 @@ internal interface IFontHandleSubstance : IDisposable
/// </summary> /// </summary>
IFontHandleManager Manager { get; } IFontHandleManager Manager { get; }
/// <summary>
/// Gets or sets the relevant <see cref="IFontAtlasBuildToolkitPreBuild"/> for this.
/// </summary>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
IFontAtlasBuildToolkitPreBuild? PreBuildToolkitForApi9Compat { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to create a new instance of <see cref="ImGuiNET.ImFontPtr"/> on first
/// access, for compatibility with API 9.
/// </summary>
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
bool CreateFontOnAccess { get; set; }
/// <summary> /// <summary>
/// Gets the font. /// Gets the font.
/// </summary> /// </summary>

View file

@ -104,6 +104,7 @@ public sealed class UiBuilder : IDisposable
/// pointers inside this handler. /// pointers inside this handler.
/// </summary> /// </summary>
[Obsolete($"Use {nameof(this.FontAtlas)} instead.", false)] [Obsolete($"Use {nameof(this.FontAtlas)} instead.", false)]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public event Action? BuildFonts; public event Action? BuildFonts;
/// <summary> /// <summary>
@ -113,6 +114,7 @@ public sealed class UiBuilder : IDisposable
/// pointers inside this handler. /// pointers inside this handler.
/// </summary> /// </summary>
[Obsolete($"Use {nameof(this.FontAtlas)} instead.", false)] [Obsolete($"Use {nameof(this.FontAtlas)} instead.", false)]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public event Action? AfterBuildFonts; public event Action? AfterBuildFonts;
/// <summary> /// <summary>
@ -423,6 +425,7 @@ public sealed class UiBuilder : IDisposable
/// <param name="style">Font to get.</param> /// <param name="style">Font to get.</param>
/// <returns>Handle to the game font which may or may not be available for use yet.</returns> /// <returns>Handle to the game font which may or may not be available for use yet.</returns>
[Obsolete($"Use {nameof(this.FontAtlas)}.{nameof(IFontAtlas.NewGameFontHandle)} instead.", false)] [Obsolete($"Use {nameof(this.FontAtlas)}.{nameof(IFontAtlas.NewGameFontHandle)} instead.", false)]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public GameFontHandle GetGameFontHandle(GameFontStyle style) => new( public GameFontHandle GetGameFontHandle(GameFontStyle style) => new(
(IFontHandle.IInternal)this.FontAtlas.NewGameFontHandle(style), (IFontHandle.IInternal)this.FontAtlas.NewGameFontHandle(style),
Service<FontAtlasFactory>.Get()); Service<FontAtlasFactory>.Get());
@ -620,28 +623,37 @@ public sealed class UiBuilder : IDisposable
this.hitchDetector.Stop(); this.hitchDetector.Stop();
} }
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
private unsafe void PrivateAtlasOnBuildStepChange(IFontAtlasBuildToolkit e) private unsafe void PrivateAtlasOnBuildStepChange(IFontAtlasBuildToolkit e)
{ {
if (e.IsAsyncBuildOperation) if (e.IsAsyncBuildOperation)
return; return;
e.OnPreBuild( if (this.BuildFonts is not null)
_ => {
{ e.OnPreBuild(
var prev = ImGui.GetIO().NativePtr->Fonts; _ =>
ImGui.GetIO().NativePtr->Fonts = e.NewImAtlas.NativePtr; {
this.BuildFonts?.InvokeSafely(); var prev = ImGui.GetIO().NativePtr->Fonts;
ImGui.GetIO().NativePtr->Fonts = prev; ImGui.GetIO().NativePtr->Fonts = e.NewImAtlas.NativePtr;
}); ((IFontAtlasBuildToolkit.IApi9Compat)e)
.FromUiBuilderObsoleteEventHandlers(() => this.BuildFonts?.InvokeSafely());
ImGui.GetIO().NativePtr->Fonts = prev;
});
}
e.OnPostBuild( if (this.AfterBuildFonts is not null)
_ => {
{ e.OnPostBuild(
var prev = ImGui.GetIO().NativePtr->Fonts; _ =>
ImGui.GetIO().NativePtr->Fonts = e.NewImAtlas.NativePtr; {
this.AfterBuildFonts?.InvokeSafely(); var prev = ImGui.GetIO().NativePtr->Fonts;
ImGui.GetIO().NativePtr->Fonts = prev; ImGui.GetIO().NativePtr->Fonts = e.NewImAtlas.NativePtr;
}); ((IFontAtlasBuildToolkit.IApi9Compat)e)
.FromUiBuilderObsoleteEventHandlers(() => this.AfterBuildFonts?.InvokeSafely());
ImGui.GetIO().NativePtr->Fonts = prev;
});
}
} }
private void OnResizeBuffers() private void OnResizeBuffers()

View file

@ -1,6 +1,8 @@
using System.Reflection; using System.Reflection;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using Dalamud.Utility;
using Serilog; using Serilog;
using Serilog.Events; using Serilog.Events;
@ -14,6 +16,7 @@ namespace Dalamud.Logging;
/// move over as soon as reasonably possible for performance reasons. /// move over as soon as reasonably possible for performance reasons.
/// </remarks> /// </remarks>
[Obsolete("Static PluginLog will be removed in API 10. Developers should use IPluginLog.")] [Obsolete("Static PluginLog will be removed in API 10. Developers should use IPluginLog.")]
[Api10ToDo(Api10ToDoAttribute.DeleteCompatBehavior)]
public static class PluginLog public static class PluginLog
{ {
#region "Log" prefixed Serilog style methods #region "Log" prefixed Serilog style methods

View file

@ -0,0 +1,19 @@
namespace Dalamud.Utility;
/// <summary>
/// Utility class for marking something to be changed for API 10, for ease of lookup.
/// </summary>
[AttributeUsage(AttributeTargets.All, Inherited = false)]
internal sealed class Api10ToDoAttribute : Attribute
{
/// <summary>
/// Marks that this exists purely for making API 9 plugins work.
/// </summary>
public const string DeleteCompatBehavior = "Delete. This is for making API 9 plugins work.";
/// <summary>
/// Initializes a new instance of the <see cref="Api10ToDoAttribute"/> class.
/// </summary>
/// <param name="what">The explanation.</param>
public Api10ToDoAttribute(string what) => _ = what;
}