Add FontAwesome fixed width (#1737)

* Add FA-FW

* remove braces (ask of kizer)

* reuse iconfont glyphs

* use FAFS for initial font

---------

Co-authored-by: rootdarkarchon <root.darkarchon@outlook.com>
This commit is contained in:
rootdarkarchon 2024-04-14 23:19:27 +02:00 committed by GitHub
parent b8802f0609
commit e97d95dba8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 87 additions and 11 deletions

View file

@ -25,10 +25,15 @@ using Dalamud.Interface.Utility;
using Dalamud.Interface.Windowing;
using Dalamud.Utility;
using Dalamud.Utility.Timing;
using ImGuiNET;
using ImGuiScene;
using PInvoke;
using Serilog;
using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
@ -131,6 +136,13 @@ internal class InterfaceManager : IInternalDisposableService
public static ImFontPtr IconFont =>
WhenFontsReady().IconFontHandle!.LockUntilPostFrame().OrElse(ImGui.GetIO().FontDefault);
/// <summary>
/// Gets an included FontAwesome icon font with fixed width.
/// <strong>Accessing this static property outside of the main thread is dangerous and not supported.</strong>
/// </summary>
public static ImFontPtr IconFontFixedWidth =>
WhenFontsReady().IconFontFixedWidthHandle!.LockUntilPostFrame().OrElse(ImGui.GetIO().FontDefault);
/// <summary>
/// Gets an included monospaced font.<br />
/// <strong>Accessing this static property outside of the main thread is dangerous and not supported.</strong>
@ -148,6 +160,11 @@ internal class InterfaceManager : IInternalDisposableService
/// </summary>
public FontHandle? IconFontHandle { get; private set; }
/// <summary>
/// Gets the icon font handle with fixed width.
/// </summary>
public FontHandle? IconFontFixedWidthHandle { get; private set; }
/// <summary>
/// Gets the mono font handle.
/// </summary>
@ -402,7 +419,7 @@ internal class InterfaceManager : IInternalDisposableService
});
}
}
// no sampler for now because the ImGui implementation we copied doesn't allow for changing it
return new DalamudTextureWrap(new D3DTextureWrap(resView, width, height));
}
@ -498,7 +515,7 @@ internal class InterfaceManager : IInternalDisposableService
atlas.BuildTask.GetAwaiter().GetResult();
return im;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void RenderImGui(RawDX11Scene scene)
{
@ -732,6 +749,13 @@ internal class InterfaceManager : IInternalDisposableService
GlyphMinAdvanceX = DefaultFontSizePx,
GlyphMaxAdvanceX = DefaultFontSizePx,
})));
this.IconFontFixedWidthHandle = (FontHandle)this.dalamudAtlas.NewDelegateFontHandle(
e => e.OnPreBuild(tk => tk.AddDalamudAssetFont(
DalamudAsset.FontAwesomeFreeSolid,
new()
{
GlyphRanges = new ushort[] { 0x20 },
})));
this.MonoFontHandle = (FontHandle)this.dalamudAtlas.NewDelegateFontHandle(
e => e.OnPreBuild(
tk => tk.AddDalamudAssetFont(
@ -748,6 +772,13 @@ internal class InterfaceManager : IInternalDisposableService
tk.GetFont(this.DefaultFontHandle),
tk.GetFont(this.MonoFontHandle),
missingOnly: true);
// Fill missing glyphs in IconFontFixedWidth with IconFont and fit ratio
tk.CopyGlyphsAcrossFonts(
tk.GetFont(this.IconFontHandle),
tk.GetFont(this.IconFontFixedWidthHandle),
missingOnly: true);
tk.FitRatio(tk.GetFont(this.IconFontFixedWidthHandle));
});
this.DefaultFontHandle.ImFontChanged += (_, font) =>
{

View file

@ -1,4 +1,4 @@
using Dalamud.Interface.Internal;
using Dalamud.Interface.Internal;
using Dalamud.Utility;
using ImGuiNET;
@ -27,6 +27,13 @@ public interface IFontAtlasBuildToolkitPostBuild : IFontAtlasBuildToolkit
/// <returns>The texture index.</returns>
int StoreTexture(IDalamudTextureWrap textureWrap, bool disposeOnError);
/// <summary>
/// Fits a font to a fixed 1:1 ratio adjusting glyph positions horizontally and vertically to fit within font size boundaries.
/// </summary>
/// <param name="font">The font to fit.</param>
/// <param name="rebuildLookupTable">Whether to call target.BuildLookupTable().</param>
void FitRatio(ImFontPtr font, bool rebuildLookupTable = true);
/// <summary>
/// Copies glyphs across fonts, in a safer way.<br />
/// If the font does not belong to the current atlas, this function is a no-op.

View file

@ -1,4 +1,4 @@
using System.Buffers;
using System.Buffers;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@ -166,7 +166,7 @@ internal sealed partial class FontAtlasFactory
/// <inheritdoc/>
public int StoreTexture(IDalamudTextureWrap textureWrap, bool disposeOnError) =>
this.data.AddNewTexture(textureWrap, disposeOnError);
/// <inheritdoc/>
public void RegisterPostBuild(Action action) => this.registeredPostBuildActions.Add(action);
@ -391,12 +391,10 @@ internal sealed partial class FontAtlasFactory
});
case DalamudAsset.LodestoneGameSymbol when !this.factory.HasGameSymbolsFontFile:
{
return this.AddGameGlyphs(
new(GameFontFamily.Axis, fontConfig.SizePx),
fontConfig.GlyphRanges,
fontConfig.MergeFont);
}
default:
return this.factory.AddFont(
@ -858,5 +856,30 @@ internal sealed partial class FontAtlasFactory
}
}
}
/// <inheritdoc/>
public void FitRatio(ImFontPtr font, bool rebuildLookupTable = true)
{
var nsize = font.FontSize;
var glyphs = font.GlyphsWrapped();
foreach (ref var glyph in glyphs.DataSpan)
{
var ratio = 1f;
if (glyph.X1 - glyph.X0 > nsize)
ratio = Math.Max(ratio, (glyph.X1 - glyph.X0) / nsize);
if (glyph.Y1 - glyph.Y0 > nsize)
ratio = Math.Max(ratio, (glyph.Y1 - glyph.Y0) / nsize);
var w = MathF.Round((glyph.X1 - glyph.X0) / ratio, MidpointRounding.ToZero);
var h = MathF.Round((glyph.Y1 - glyph.Y0) / ratio, MidpointRounding.AwayFromZero);
glyph.X0 = MathF.Round((nsize - w) / 2f, MidpointRounding.ToZero);
glyph.Y0 = MathF.Round((nsize - h) / 2f, MidpointRounding.AwayFromZero);
glyph.X1 = glyph.X0 + w;
glyph.Y1 = glyph.Y0 + h;
glyph.AdvanceX = nsize;
}
if (rebuildLookupTable)
this.BuildLookupTable(font);
}
}
}

View file

@ -21,9 +21,13 @@ using Dalamud.Plugin;
using Dalamud.Plugin.Internal.Types;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using ImGuiNET;
using ImGuiScene;
using Serilog;
using SharpDX.Direct3D11;
namespace Dalamud.Interface;
@ -53,6 +57,7 @@ public sealed class UiBuilder : IDisposable
private IFontHandle? defaultFontHandle;
private IFontHandle? iconFontHandle;
private IFontHandle? monoFontHandle;
private IFontHandle? iconFontFixedWidthHandle;
/// <summary>
/// Initializes a new instance of the <see cref="UiBuilder"/> class and registers it.
@ -106,7 +111,7 @@ public sealed class UiBuilder : IDisposable
/// Event that is fired when the plugin should open its configuration interface.
/// </summary>
public event Action OpenConfigUi;
/// <summary>
/// Event that is fired when the plugin should open its main interface.
/// </summary>
@ -251,6 +256,16 @@ public sealed class UiBuilder : IDisposable
this.InterfaceManagerWithScene?.IconFontHandle
?? throw new InvalidOperationException("Scene is not yet ready.")));
/// <summary>
/// Gets the default Dalamud icon font based on FontAwesome 5 free solid with a fixed width and vertically centered glyphs.
/// </summary>
public IFontHandle IconFontFixedWidthHandle =>
this.iconFontFixedWidthHandle ??=
this.scopedFinalizer.Add(
new FontHandleWrapper(
this.InterfaceManagerWithScene?.IconFontFixedWidthHandle
?? throw new InvalidOperationException("Scene is not yet ready.")));
/// <summary>
/// Gets the default Dalamud monospaced font based on Inconsolata Regular.
/// </summary>
@ -266,7 +281,7 @@ public sealed class UiBuilder : IDisposable
/// new() { SizePx = UiBuilder.DefaultFontSizePx })));
/// </code>
/// </remarks>
public IFontHandle MonoFontHandle =>
public IFontHandle MonoFontHandle =>
this.monoFontHandle ??=
this.scopedFinalizer.Add(
new FontHandleWrapper(
@ -630,7 +645,7 @@ public sealed class UiBuilder : IDisposable
{
this.OpenConfigUi?.InvokeSafely();
}
/// <summary>
/// Open the registered configuration UI, if it exists.
/// </summary>
@ -838,5 +853,5 @@ public sealed class UiBuilder : IDisposable
private void WrappedOnImFontChanged(IFontHandle obj, ILockedImFont lockedFont) =>
this.ImFontChanged?.Invoke(obj, lockedFont);
}
}
}