mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-14 20:54:16 +01:00
Implement FontChooserDialog (#1637)
* Implement FontChooserDialog * Minor fixes * Fixes 2 * Add Reset default font button * Add failsafe * reduce uninteresting exception message * Add remarks to use AttachExtraGlyphsForDalamudLanguage * Support advanced font configuration options * fixes * Shift ui elements * more fixes * Add To(Localized)String for IFontSpec * Untie GlobalFontScale from default font size * Layout fixes * Make UiBuilder.DefaultFontSize point to user configured value * Update example for NewDelegateFontHandle * Font interfaces: write notes on not intended for plugins to implement * Update default gamma to 1.7 to match closer to prev behavior (1.4**2) * Fix console window layout
This commit is contained in:
parent
3b3823d4e6
commit
34daa73612
31 changed files with 2478 additions and 81 deletions
|
|
@ -5,6 +5,7 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
using Dalamud.Game.Text;
|
using Dalamud.Game.Text;
|
||||||
|
using Dalamud.Interface.FontIdentifier;
|
||||||
using Dalamud.Interface.Internal.Windows.PluginInstaller;
|
using Dalamud.Interface.Internal.Windows.PluginInstaller;
|
||||||
using Dalamud.Interface.Style;
|
using Dalamud.Interface.Style;
|
||||||
using Dalamud.IoC.Internal;
|
using Dalamud.IoC.Internal;
|
||||||
|
|
@ -145,7 +146,13 @@ internal sealed class DalamudConfiguration : IServiceType, IDisposable
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether to use AXIS fonts from the game.
|
/// Gets or sets a value indicating whether to use AXIS fonts from the game.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseAxisFontsFromGame { get; set; } = false;
|
[Obsolete($"See {nameof(DefaultFontSpec)}")]
|
||||||
|
public bool UseAxisFontsFromGame { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default font spec.
|
||||||
|
/// </summary>
|
||||||
|
public IFontSpec? DefaultFontSpec { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the gamma value to apply for Dalamud fonts. Do not use.
|
/// Gets or sets the gamma value to apply for Dalamud fonts. Do not use.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
using Dalamud.Storage.Assets;
|
||||||
|
|
||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.FontIdentifier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a font from Dalamud assets.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DalamudAssetFontAndFamilyId : IFontFamilyId, IFontId
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DalamudAssetFontAndFamilyId"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="asset">The font asset.</param>
|
||||||
|
public DalamudAssetFontAndFamilyId(DalamudAsset asset)
|
||||||
|
{
|
||||||
|
if (asset.GetPurpose() != DalamudAssetPurpose.Font)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(asset), asset, "The specified asset is not a font asset.");
|
||||||
|
this.Asset = asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the font asset.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty]
|
||||||
|
public DalamudAsset Asset { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public string EnglishName => $"Dalamud: {this.Asset}";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public IReadOnlyDictionary<string, string>? LocaleNames => null;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public IReadOnlyList<IFontId> Fonts => new List<IFontId> { this }.AsReadOnly();
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public IFontFamilyId Family => this;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public int Weight => (int)DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_NORMAL;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public int Stretch => (int)DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_NORMAL;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public int Style => (int)DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_NORMAL;
|
||||||
|
|
||||||
|
public static bool operator ==(DalamudAssetFontAndFamilyId? left, DalamudAssetFontAndFamilyId? right) =>
|
||||||
|
Equals(left, right);
|
||||||
|
|
||||||
|
public static bool operator !=(DalamudAssetFontAndFamilyId? left, DalamudAssetFontAndFamilyId? right) =>
|
||||||
|
!Equals(left, right);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool Equals(object? obj) => obj is DalamudAssetFontAndFamilyId other && this.Equals(other);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override int GetHashCode() => (int)this.Asset;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString() => $"{nameof(DalamudAssetFontAndFamilyId)}:{this.Asset}";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int FindBestMatch(int weight, int stretch, int style) => 0;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ImFontPtr AddToBuildToolkit(IFontAtlasBuildToolkitPreBuild tk, in SafeFontConfig config) =>
|
||||||
|
tk.AddDalamudAssetFont(this.Asset, config);
|
||||||
|
|
||||||
|
private bool Equals(DalamudAssetFontAndFamilyId other) => this.Asset == other.Asset;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
|
||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.FontIdentifier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the default Dalamud font.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DalamudDefaultFontAndFamilyId : IFontId, IFontFamilyId
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The shared instance of <see cref="DalamudDefaultFontAndFamilyId"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DalamudDefaultFontAndFamilyId Instance = new();
|
||||||
|
|
||||||
|
private DalamudDefaultFontAndFamilyId()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public string EnglishName => "(Default)";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public IReadOnlyDictionary<string, string>? LocaleNames => null;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public IFontFamilyId Family => this;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public int Weight => (int)DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_NORMAL;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public int Stretch => (int)DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_NORMAL;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public int Style => (int)DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_NORMAL;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public IReadOnlyList<IFontId> Fonts => new List<IFontId> { this }.AsReadOnly();
|
||||||
|
|
||||||
|
public static bool operator ==(DalamudDefaultFontAndFamilyId? left, DalamudDefaultFontAndFamilyId? right) =>
|
||||||
|
left is null == right is null;
|
||||||
|
|
||||||
|
public static bool operator !=(DalamudDefaultFontAndFamilyId? left, DalamudDefaultFontAndFamilyId? right) =>
|
||||||
|
left is null != right is null;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool Equals(object? obj) => obj is DalamudDefaultFontAndFamilyId;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override int GetHashCode() => 12345678;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString() => nameof(DalamudDefaultFontAndFamilyId);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ImFontPtr AddToBuildToolkit(IFontAtlasBuildToolkitPreBuild tk, in SafeFontConfig config)
|
||||||
|
=> tk.AddDalamudDefaultFont(config.SizePx, config.GlyphRanges);
|
||||||
|
// TODO: mergeFont
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int FindBestMatch(int weight, int stretch, int style) => 0;
|
||||||
|
}
|
||||||
81
Dalamud/Interface/FontIdentifier/GameFontAndFamilyId.cs
Normal file
81
Dalamud/Interface/FontIdentifier/GameFontAndFamilyId.cs
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Dalamud.Interface.GameFonts;
|
||||||
|
using Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
|
||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.FontIdentifier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a font from the game.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class GameFontAndFamilyId : IFontId, IFontFamilyId
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GameFontAndFamilyId"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="family">The game font family.</param>
|
||||||
|
public GameFontAndFamilyId(GameFontFamily family) => this.GameFontFamily = family;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the game font family.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty]
|
||||||
|
public GameFontFamily GameFontFamily { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public string EnglishName => $"Game: {Enum.GetName(this.GameFontFamily) ?? throw new NotSupportedException()}";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public IReadOnlyDictionary<string, string>? LocaleNames => null;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public IFontFamilyId Family => this;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public int Weight => (int)DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_NORMAL;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public int Stretch => (int)DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_NORMAL;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public int Style => (int)DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_NORMAL;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public IReadOnlyList<IFontId> Fonts => new List<IFontId> { this }.AsReadOnly();
|
||||||
|
|
||||||
|
public static bool operator ==(GameFontAndFamilyId? left, GameFontAndFamilyId? right) => Equals(left, right);
|
||||||
|
|
||||||
|
public static bool operator !=(GameFontAndFamilyId? left, GameFontAndFamilyId? right) => !Equals(left, right);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool Equals(object? obj) =>
|
||||||
|
ReferenceEquals(this, obj) || (obj is GameFontAndFamilyId other && this.Equals(other));
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override int GetHashCode() => (int)this.GameFontFamily;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int FindBestMatch(int weight, int stretch, int style) => 0;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString() => $"{nameof(GameFontAndFamilyId)}:{this.GameFontFamily}";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ImFontPtr AddToBuildToolkit(IFontAtlasBuildToolkitPreBuild tk, in SafeFontConfig config) =>
|
||||||
|
tk.AddGameGlyphs(new(this.GameFontFamily, config.SizePx), config.GlyphRanges, config.MergeFont);
|
||||||
|
|
||||||
|
private bool Equals(GameFontAndFamilyId other) => this.GameFontFamily == other.GameFontFamily;
|
||||||
|
}
|
||||||
102
Dalamud/Interface/FontIdentifier/IFontFamilyId.cs
Normal file
102
Dalamud/Interface/FontIdentifier/IFontFamilyId.cs
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Dalamud.Interface.GameFonts;
|
||||||
|
using Dalamud.Utility;
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.FontIdentifier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a font family identifier.<br />
|
||||||
|
/// Not intended for plugins to implement.
|
||||||
|
/// </summary>
|
||||||
|
public interface IFontFamilyId : IObjectWithLocalizableName
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of fonts under this family.
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
IReadOnlyList<IFontId> Fonts { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the index of the font inside <see cref="Fonts"/> that best matches the given parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="weight">The weight of the font.</param>
|
||||||
|
/// <param name="stretch">The stretch of the font.</param>
|
||||||
|
/// <param name="style">The style of the font.</param>
|
||||||
|
/// <returns>The index of the font. Guaranteed to be a valid index.</returns>
|
||||||
|
int FindBestMatch(int weight, int stretch, int style);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of Dalamud-provided fonts.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The list of fonts.</returns>
|
||||||
|
public static List<IFontFamilyId> ListDalamudFonts() =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
new DalamudAssetFontAndFamilyId(DalamudAsset.NotoSansJpMedium),
|
||||||
|
new DalamudAssetFontAndFamilyId(DalamudAsset.InconsolataRegular),
|
||||||
|
new DalamudAssetFontAndFamilyId(DalamudAsset.FontAwesomeFreeSolid),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of Game-provided fonts.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The list of fonts.</returns>
|
||||||
|
public static List<IFontFamilyId> ListGameFonts() => new()
|
||||||
|
{
|
||||||
|
new GameFontAndFamilyId(GameFontFamily.Axis),
|
||||||
|
new GameFontAndFamilyId(GameFontFamily.Jupiter),
|
||||||
|
new GameFontAndFamilyId(GameFontFamily.JupiterNumeric),
|
||||||
|
new GameFontAndFamilyId(GameFontFamily.Meidinger),
|
||||||
|
new GameFontAndFamilyId(GameFontFamily.MiedingerMid),
|
||||||
|
new GameFontAndFamilyId(GameFontFamily.TrumpGothic),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of System-provided fonts.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="refresh">If <c>true</c>, try to refresh the list.</param>
|
||||||
|
/// <returns>The list of fonts.</returns>
|
||||||
|
public static unsafe List<IFontFamilyId> ListSystemFonts(bool refresh)
|
||||||
|
{
|
||||||
|
using var dwf = default(ComPtr<IDWriteFactory>);
|
||||||
|
fixed (Guid* piid = &IID.IID_IDWriteFactory)
|
||||||
|
{
|
||||||
|
DirectX.DWriteCreateFactory(
|
||||||
|
DWRITE_FACTORY_TYPE.DWRITE_FACTORY_TYPE_SHARED,
|
||||||
|
piid,
|
||||||
|
(IUnknown**)dwf.GetAddressOf()).ThrowOnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
using var sfc = default(ComPtr<IDWriteFontCollection>);
|
||||||
|
dwf.Get()->GetSystemFontCollection(sfc.GetAddressOf(), refresh).ThrowOnError();
|
||||||
|
|
||||||
|
var count = (int)sfc.Get()->GetFontFamilyCount();
|
||||||
|
var result = new List<IFontFamilyId>(count);
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
using var ff = default(ComPtr<IDWriteFontFamily>);
|
||||||
|
if (sfc.Get()->GetFontFamily((uint)i, ff.GetAddressOf()).FAILED)
|
||||||
|
{
|
||||||
|
// Ignore errors, if any
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result.Add(SystemFontFamilyId.FromDWriteFamily(ff));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
Dalamud/Interface/FontIdentifier/IFontId.cs
Normal file
40
Dalamud/Interface/FontIdentifier/IFontId.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
using Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
|
||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.FontIdentifier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a font identifier.<br />
|
||||||
|
/// Not intended for plugins to implement.
|
||||||
|
/// </summary>
|
||||||
|
public interface IFontId : IObjectWithLocalizableName
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the associated font family.
|
||||||
|
/// </summary>
|
||||||
|
IFontFamilyId Family { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the font weight, ranging from 1 to 999.
|
||||||
|
/// </summary>
|
||||||
|
int Weight { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the font stretch, ranging from 1 to 9.
|
||||||
|
/// </summary>
|
||||||
|
int Stretch { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the font style. Treat as an opaque value.
|
||||||
|
/// </summary>
|
||||||
|
int Style { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds this font to the given font build toolkit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tk">The font build toolkit.</param>
|
||||||
|
/// <param name="config">The font configuration. Some parameters may be ignored.</param>
|
||||||
|
/// <returns>The added font.</returns>
|
||||||
|
ImFontPtr AddToBuildToolkit(IFontAtlasBuildToolkitPreBuild tk, in SafeFontConfig config);
|
||||||
|
}
|
||||||
50
Dalamud/Interface/FontIdentifier/IFontSpec.cs
Normal file
50
Dalamud/Interface/FontIdentifier/IFontSpec.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
using Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
|
||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.FontIdentifier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a user's choice of font(s).<br />
|
||||||
|
/// Not intended for plugins to implement.
|
||||||
|
/// </summary>
|
||||||
|
public interface IFontSpec
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the font size in pixels.
|
||||||
|
/// </summary>
|
||||||
|
float SizePx { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the font size in points.
|
||||||
|
/// </summary>
|
||||||
|
float SizePt { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the line height in pixels.
|
||||||
|
/// </summary>
|
||||||
|
float LineHeightPx { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a font handle corresponding to this font specification.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="atlas">The atlas to bind this font handle to.</param>
|
||||||
|
/// <param name="callback">Optional callback to be called after creating the font handle.</param>
|
||||||
|
/// <returns>The new font handle.</returns>
|
||||||
|
IFontHandle CreateFontHandle(IFontAtlas atlas, FontAtlasBuildStepDelegate? callback = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds this font to the given font build toolkit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tk">The font build toolkit.</param>
|
||||||
|
/// <param name="mergeFont">The font to merge to.</param>
|
||||||
|
/// <returns>The added font.</returns>
|
||||||
|
ImFontPtr AddToBuildToolkit(IFontAtlasBuildToolkitPreBuild tk, ImFontPtr mergeFont = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents this font specification, preferrably in the requested locale.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="localeCode">The locale code. Must be in lowercase(invariant).</param>
|
||||||
|
/// <returns>The value.</returns>
|
||||||
|
string ToLocalizedString(string localeCode);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Dalamud.Utility;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.FontIdentifier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an object with localizable names.
|
||||||
|
/// </summary>
|
||||||
|
public interface IObjectWithLocalizableName
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name, preferrably in English.
|
||||||
|
/// </summary>
|
||||||
|
string EnglishName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the names per locales.
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlyDictionary<string, string>? LocaleNames { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name in the requested locale if available; otherwise, <see cref="EnglishName"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="localeCode">The locale code. Must be in lowercase(invariant).</param>
|
||||||
|
/// <returns>The value.</returns>
|
||||||
|
string GetLocalizedName(string localeCode)
|
||||||
|
{
|
||||||
|
if (this.LocaleNames is null)
|
||||||
|
return this.EnglishName;
|
||||||
|
if (this.LocaleNames.TryGetValue(localeCode, out var v))
|
||||||
|
return v;
|
||||||
|
foreach (var (a, b) in this.LocaleNames)
|
||||||
|
{
|
||||||
|
if (a.StartsWith(localeCode))
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.EnglishName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resolves all names per locales.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fn">The names.</param>
|
||||||
|
/// <returns>A new dictionary mapping from locale code to localized names.</returns>
|
||||||
|
internal static unsafe IReadOnlyDictionary<string, string> GetLocaleNames(IDWriteLocalizedStrings* fn)
|
||||||
|
{
|
||||||
|
var count = fn->GetCount();
|
||||||
|
var maxStrLen = 0u;
|
||||||
|
for (var i = 0u; i < count; i++)
|
||||||
|
{
|
||||||
|
var length = 0u;
|
||||||
|
fn->GetStringLength(i, &length).ThrowOnError();
|
||||||
|
maxStrLen = Math.Max(maxStrLen, length);
|
||||||
|
fn->GetLocaleNameLength(i, &length).ThrowOnError();
|
||||||
|
maxStrLen = Math.Max(maxStrLen, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
maxStrLen++;
|
||||||
|
var buf = stackalloc char[(int)maxStrLen];
|
||||||
|
var result = new Dictionary<string, string>((int)count);
|
||||||
|
for (var i = 0u; i < count; i++)
|
||||||
|
{
|
||||||
|
fn->GetLocaleName(i, (ushort*)buf, maxStrLen).ThrowOnError();
|
||||||
|
var key = new string(buf);
|
||||||
|
fn->GetString(i, (ushort*)buf, maxStrLen).ThrowOnError();
|
||||||
|
var value = new string(buf);
|
||||||
|
result[key.ToLowerInvariant()] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
155
Dalamud/Interface/FontIdentifier/SingleFontSpec.cs
Normal file
155
Dalamud/Interface/FontIdentifier/SingleFontSpec.cs
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
using Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
|
|
||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.FontIdentifier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a user's choice of a single font.
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage(
|
||||||
|
"StyleCop.CSharp.OrderingRules",
|
||||||
|
"SA1206:Declaration keywords should follow order",
|
||||||
|
Justification = "public required")]
|
||||||
|
public record SingleFontSpec : IFontSpec
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the font id.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty]
|
||||||
|
public required IFontId FontId { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonProperty]
|
||||||
|
public float SizePx { get; init; } = 16;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public float SizePt
|
||||||
|
{
|
||||||
|
get => (this.SizePx * 3) / 4;
|
||||||
|
init => this.SizePx = (value * 4) / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public float LineHeightPx => MathF.Round(this.SizePx * this.LineHeight);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the line height ratio to the font size.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty]
|
||||||
|
public float LineHeight { get; init; } = 1f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the glyph offset in pixels.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty]
|
||||||
|
public Vector2 GlyphOffset { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the letter spacing in pixels.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty]
|
||||||
|
public float LetterSpacing { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the glyph ranges.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty]
|
||||||
|
public ushort[]? GlyphRanges { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public string ToLocalizedString(string localeCode)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(this.FontId.Family.GetLocalizedName(localeCode));
|
||||||
|
sb.Append($"({this.FontId.GetLocalizedName(localeCode)}, {this.SizePt}pt");
|
||||||
|
if (Math.Abs(this.LineHeight - 1f) > 0.000001f)
|
||||||
|
sb.Append($", LH={this.LineHeight:0.##}");
|
||||||
|
if (this.GlyphOffset != default)
|
||||||
|
sb.Append($", O={this.GlyphOffset.X:0.##},{this.GlyphOffset.Y:0.##}");
|
||||||
|
if (this.LetterSpacing != 0f)
|
||||||
|
sb.Append($", LS={this.LetterSpacing:0.##}");
|
||||||
|
sb.Append(')');
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString() => this.ToLocalizedString("en");
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IFontHandle CreateFontHandle(IFontAtlas atlas, FontAtlasBuildStepDelegate? callback = null) =>
|
||||||
|
atlas.NewDelegateFontHandle(tk =>
|
||||||
|
{
|
||||||
|
tk.OnPreBuild(e => e.Font = this.AddToBuildToolkit(e));
|
||||||
|
callback?.Invoke(tk);
|
||||||
|
});
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ImFontPtr AddToBuildToolkit(IFontAtlasBuildToolkitPreBuild tk, ImFontPtr mergeFont = default)
|
||||||
|
{
|
||||||
|
var font = this.FontId.AddToBuildToolkit(
|
||||||
|
tk,
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
SizePx = this.SizePx,
|
||||||
|
GlyphRanges = this.GlyphRanges,
|
||||||
|
MergeFont = mergeFont,
|
||||||
|
});
|
||||||
|
|
||||||
|
tk.RegisterPostBuild(
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
var roundUnit = tk.IsGlobalScaleIgnored(font) ? 1 : 1 / tk.Scale;
|
||||||
|
var newAscent = MathF.Round((font.Ascent * this.LineHeight) / roundUnit) * roundUnit;
|
||||||
|
var newFontSize = MathF.Round((font.FontSize * this.LineHeight) / roundUnit) * roundUnit;
|
||||||
|
var shiftDown = MathF.Round((newFontSize - font.FontSize) / 2f / roundUnit) * roundUnit;
|
||||||
|
|
||||||
|
font.Ascent = newAscent;
|
||||||
|
font.FontSize = newFontSize;
|
||||||
|
font.Descent = newFontSize - font.Ascent;
|
||||||
|
|
||||||
|
var lookup = new BitArray(ushort.MaxValue + 1, this.GlyphRanges is null);
|
||||||
|
if (this.GlyphRanges is not null)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < this.GlyphRanges.Length && this.GlyphRanges[i] != 0; i += 2)
|
||||||
|
{
|
||||||
|
var to = (int)this.GlyphRanges[i + 1];
|
||||||
|
for (var j = this.GlyphRanges[i]; j <= to; j++)
|
||||||
|
lookup[j] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `/ roundUnit` = `* scale`
|
||||||
|
var dax = MathF.Round(this.LetterSpacing / roundUnit / roundUnit) * roundUnit;
|
||||||
|
var dxy0 = this.GlyphOffset / roundUnit;
|
||||||
|
|
||||||
|
dxy0 /= roundUnit;
|
||||||
|
dxy0.X = MathF.Round(dxy0.X);
|
||||||
|
dxy0.Y = MathF.Round(dxy0.Y);
|
||||||
|
dxy0 *= roundUnit;
|
||||||
|
|
||||||
|
dxy0.Y += shiftDown;
|
||||||
|
var dxy = new Vector4(dxy0, dxy0.X, dxy0.Y);
|
||||||
|
foreach (ref var glyphReal in font.GlyphsWrapped().DataSpan)
|
||||||
|
{
|
||||||
|
if (!lookup[glyphReal.Codepoint])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
glyphReal.XY += dxy;
|
||||||
|
glyphReal.AdvanceX += dax;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
}
|
||||||
181
Dalamud/Interface/FontIdentifier/SystemFontFamilyId.cs
Normal file
181
Dalamud/Interface/FontIdentifier/SystemFontFamilyId.cs
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using Dalamud.Utility;
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.FontIdentifier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a font from system.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class SystemFontFamilyId : IFontFamilyId
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
private IReadOnlyList<IFontId>? fontsLazy;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SystemFontFamilyId"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="englishName">The font name in English.</param>
|
||||||
|
/// <param name="localeNames">The localized font name for display purposes.</param>
|
||||||
|
[JsonConstructor]
|
||||||
|
internal SystemFontFamilyId(string englishName, IReadOnlyDictionary<string, string> localeNames)
|
||||||
|
{
|
||||||
|
this.EnglishName = englishName;
|
||||||
|
this.LocaleNames = localeNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SystemFontFamilyId"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="localeNames">The localized font name for display purposes.</param>
|
||||||
|
internal SystemFontFamilyId(IReadOnlyDictionary<string, string> localeNames)
|
||||||
|
{
|
||||||
|
if (localeNames.TryGetValue("en-us", out var name))
|
||||||
|
this.EnglishName = name;
|
||||||
|
else if (localeNames.TryGetValue("en", out name))
|
||||||
|
this.EnglishName = name;
|
||||||
|
else
|
||||||
|
this.EnglishName = localeNames.Values.First();
|
||||||
|
this.LocaleNames = localeNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonProperty]
|
||||||
|
public string EnglishName { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonProperty]
|
||||||
|
public IReadOnlyDictionary<string, string>? LocaleNames { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonIgnore]
|
||||||
|
public IReadOnlyList<IFontId> Fonts => this.fontsLazy ??= this.GetFonts();
|
||||||
|
|
||||||
|
public static bool operator ==(SystemFontFamilyId? left, SystemFontFamilyId? right) => Equals(left, right);
|
||||||
|
|
||||||
|
public static bool operator !=(SystemFontFamilyId? left, SystemFontFamilyId? right) => !Equals(left, right);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int FindBestMatch(int weight, int stretch, int style)
|
||||||
|
{
|
||||||
|
using var matchingFont = default(ComPtr<IDWriteFont>);
|
||||||
|
|
||||||
|
var candidates = this.Fonts.ToList();
|
||||||
|
var minGap = int.MaxValue;
|
||||||
|
foreach (var c in candidates)
|
||||||
|
minGap = Math.Min(minGap, Math.Abs(c.Weight - weight));
|
||||||
|
candidates.RemoveAll(c => Math.Abs(c.Weight - weight) != minGap);
|
||||||
|
|
||||||
|
minGap = int.MaxValue;
|
||||||
|
foreach (var c in candidates)
|
||||||
|
minGap = Math.Min(minGap, Math.Abs(c.Stretch - stretch));
|
||||||
|
candidates.RemoveAll(c => Math.Abs(c.Stretch - stretch) != minGap);
|
||||||
|
|
||||||
|
if (candidates.Any(x => x.Style == style))
|
||||||
|
candidates.RemoveAll(x => x.Style != style);
|
||||||
|
else if (candidates.Any(x => x.Style == (int)DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_NORMAL))
|
||||||
|
candidates.RemoveAll(x => x.Style != (int)DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_NORMAL);
|
||||||
|
|
||||||
|
if (!candidates.Any())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < this.Fonts.Count; i++)
|
||||||
|
{
|
||||||
|
if (Equals(this.Fonts[i], candidates[0]))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString() => $"{nameof(SystemFontFamilyId)}:{this.EnglishName}";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool Equals(object? obj) =>
|
||||||
|
ReferenceEquals(this, obj) || (obj is SystemFontFamilyId other && this.Equals(other));
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override int GetHashCode() => this.EnglishName.GetHashCode();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new instance of <see cref="SystemFontFamilyId"/> from an <see cref="IDWriteFontFamily"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="family">The family.</param>
|
||||||
|
/// <returns>The new instance.</returns>
|
||||||
|
internal static unsafe SystemFontFamilyId FromDWriteFamily(ComPtr<IDWriteFontFamily> family)
|
||||||
|
{
|
||||||
|
using var fn = default(ComPtr<IDWriteLocalizedStrings>);
|
||||||
|
family.Get()->GetFamilyNames(fn.GetAddressOf()).ThrowOnError();
|
||||||
|
return new(IObjectWithLocalizableName.GetLocaleNames(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe IReadOnlyList<IFontId> GetFonts()
|
||||||
|
{
|
||||||
|
using var dwf = default(ComPtr<IDWriteFactory>);
|
||||||
|
fixed (Guid* piid = &IID.IID_IDWriteFactory)
|
||||||
|
{
|
||||||
|
DirectX.DWriteCreateFactory(
|
||||||
|
DWRITE_FACTORY_TYPE.DWRITE_FACTORY_TYPE_SHARED,
|
||||||
|
piid,
|
||||||
|
(IUnknown**)dwf.GetAddressOf()).ThrowOnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
using var sfc = default(ComPtr<IDWriteFontCollection>);
|
||||||
|
dwf.Get()->GetSystemFontCollection(sfc.GetAddressOf(), false).ThrowOnError();
|
||||||
|
|
||||||
|
var familyIndex = 0u;
|
||||||
|
BOOL exists = false;
|
||||||
|
fixed (void* pName = this.EnglishName)
|
||||||
|
sfc.Get()->FindFamilyName((ushort*)pName, &familyIndex, &exists).ThrowOnError();
|
||||||
|
if (!exists)
|
||||||
|
throw new FileNotFoundException($"Font \"{this.EnglishName}\" not found.");
|
||||||
|
|
||||||
|
using var family = default(ComPtr<IDWriteFontFamily>);
|
||||||
|
sfc.Get()->GetFontFamily(familyIndex, family.GetAddressOf()).ThrowOnError();
|
||||||
|
|
||||||
|
var fontCount = (int)family.Get()->GetFontCount();
|
||||||
|
var fonts = new List<IFontId>(fontCount);
|
||||||
|
for (var i = 0; i < fontCount; i++)
|
||||||
|
{
|
||||||
|
using var font = default(ComPtr<IDWriteFont>);
|
||||||
|
if (family.Get()->GetFont((uint)i, font.GetAddressOf()).FAILED)
|
||||||
|
{
|
||||||
|
// Ignore errors, if any
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font.Get()->GetSimulations() != DWRITE_FONT_SIMULATIONS.DWRITE_FONT_SIMULATIONS_NONE)
|
||||||
|
{
|
||||||
|
// No simulation support
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fonts.Add(new SystemFontId(this, font));
|
||||||
|
}
|
||||||
|
|
||||||
|
fonts.Sort(
|
||||||
|
(a, b) =>
|
||||||
|
{
|
||||||
|
var comp = a.Weight.CompareTo(b.Weight);
|
||||||
|
if (comp != 0)
|
||||||
|
return comp;
|
||||||
|
|
||||||
|
comp = a.Stretch.CompareTo(b.Stretch);
|
||||||
|
if (comp != 0)
|
||||||
|
return comp;
|
||||||
|
|
||||||
|
return a.Style.CompareTo(b.Style);
|
||||||
|
});
|
||||||
|
return fonts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Equals(SystemFontFamilyId other) => this.EnglishName == other.EnglishName;
|
||||||
|
}
|
||||||
163
Dalamud/Interface/FontIdentifier/SystemFontId.cs
Normal file
163
Dalamud/Interface/FontIdentifier/SystemFontId.cs
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
using Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
using Dalamud.Utility;
|
||||||
|
|
||||||
|
using ImGuiNET;
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
|
namespace Dalamud.Interface.FontIdentifier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a font installed in the system.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class SystemFontId : IFontId
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SystemFontId"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="family">The parent font family.</param>
|
||||||
|
/// <param name="font">The font.</param>
|
||||||
|
internal unsafe SystemFontId(SystemFontFamilyId family, ComPtr<IDWriteFont> font)
|
||||||
|
{
|
||||||
|
this.Family = family;
|
||||||
|
this.Weight = (int)font.Get()->GetWeight();
|
||||||
|
this.Stretch = (int)font.Get()->GetStretch();
|
||||||
|
this.Style = (int)font.Get()->GetStyle();
|
||||||
|
|
||||||
|
using var fn = default(ComPtr<IDWriteLocalizedStrings>);
|
||||||
|
font.Get()->GetFaceNames(fn.GetAddressOf()).ThrowOnError();
|
||||||
|
this.LocaleNames = IObjectWithLocalizableName.GetLocaleNames(fn);
|
||||||
|
if (this.LocaleNames.TryGetValue("en-us", out var name))
|
||||||
|
this.EnglishName = name;
|
||||||
|
else if (this.LocaleNames.TryGetValue("en", out name))
|
||||||
|
this.EnglishName = name;
|
||||||
|
else
|
||||||
|
this.EnglishName = this.LocaleNames.Values.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
private SystemFontId(string englishName, IReadOnlyDictionary<string, string> localeNames, IFontFamilyId family)
|
||||||
|
{
|
||||||
|
this.EnglishName = englishName;
|
||||||
|
this.LocaleNames = localeNames;
|
||||||
|
this.Family = family;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonProperty]
|
||||||
|
public string EnglishName { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonProperty]
|
||||||
|
public IReadOnlyDictionary<string, string>? LocaleNames { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonProperty]
|
||||||
|
public IFontFamilyId Family { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonProperty]
|
||||||
|
public int Weight { get; init; } = (int)DWRITE_FONT_WEIGHT.DWRITE_FONT_WEIGHT_NORMAL;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonProperty]
|
||||||
|
public int Stretch { get; init; } = (int)DWRITE_FONT_STRETCH.DWRITE_FONT_STRETCH_NORMAL;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
[JsonProperty]
|
||||||
|
public int Style { get; init; } = (int)DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_NORMAL;
|
||||||
|
|
||||||
|
public static bool operator ==(SystemFontId? left, SystemFontId? right) => Equals(left, right);
|
||||||
|
|
||||||
|
public static bool operator !=(SystemFontId? left, SystemFontId? right) => !Equals(left, right);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool Equals(object? obj) =>
|
||||||
|
ReferenceEquals(this, obj) || (obj is SystemFontId other && this.Equals(other));
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override int GetHashCode() => HashCode.Combine(this.Family, this.Weight, this.Stretch, this.Style);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString() =>
|
||||||
|
$"{nameof(SystemFontId)}:{this.Weight}:{this.Stretch}:{this.Style}:{this.Family}";
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ImFontPtr AddToBuildToolkit(IFontAtlasBuildToolkitPreBuild tk, in SafeFontConfig config)
|
||||||
|
{
|
||||||
|
var (path, index) = this.GetFileAndIndex();
|
||||||
|
return tk.AddFontFromFile(path, config with { FontNo = index });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the file containing this font, and the font index within.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The path and index.</returns>
|
||||||
|
public unsafe (string Path, int Index) GetFileAndIndex()
|
||||||
|
{
|
||||||
|
using var dwf = default(ComPtr<IDWriteFactory>);
|
||||||
|
fixed (Guid* piid = &IID.IID_IDWriteFactory)
|
||||||
|
{
|
||||||
|
DirectX.DWriteCreateFactory(
|
||||||
|
DWRITE_FACTORY_TYPE.DWRITE_FACTORY_TYPE_SHARED,
|
||||||
|
piid,
|
||||||
|
(IUnknown**)dwf.GetAddressOf()).ThrowOnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
using var sfc = default(ComPtr<IDWriteFontCollection>);
|
||||||
|
dwf.Get()->GetSystemFontCollection(sfc.GetAddressOf(), false).ThrowOnError();
|
||||||
|
|
||||||
|
var familyIndex = 0u;
|
||||||
|
BOOL exists = false;
|
||||||
|
fixed (void* name = this.Family.EnglishName)
|
||||||
|
sfc.Get()->FindFamilyName((ushort*)name, &familyIndex, &exists).ThrowOnError();
|
||||||
|
if (!exists)
|
||||||
|
throw new FileNotFoundException($"Font \"{this.Family.EnglishName}\" not found.");
|
||||||
|
|
||||||
|
using var family = default(ComPtr<IDWriteFontFamily>);
|
||||||
|
sfc.Get()->GetFontFamily(familyIndex, family.GetAddressOf()).ThrowOnError();
|
||||||
|
|
||||||
|
using var font = default(ComPtr<IDWriteFont>);
|
||||||
|
family.Get()->GetFirstMatchingFont(
|
||||||
|
(DWRITE_FONT_WEIGHT)this.Weight,
|
||||||
|
(DWRITE_FONT_STRETCH)this.Stretch,
|
||||||
|
(DWRITE_FONT_STYLE)this.Style,
|
||||||
|
font.GetAddressOf()).ThrowOnError();
|
||||||
|
|
||||||
|
using var fface = default(ComPtr<IDWriteFontFace>);
|
||||||
|
font.Get()->CreateFontFace(fface.GetAddressOf()).ThrowOnError();
|
||||||
|
var fileCount = 0;
|
||||||
|
fface.Get()->GetFiles((uint*)&fileCount, null).ThrowOnError();
|
||||||
|
if (fileCount != 1)
|
||||||
|
throw new NotSupportedException();
|
||||||
|
|
||||||
|
using var ffile = default(ComPtr<IDWriteFontFile>);
|
||||||
|
fface.Get()->GetFiles((uint*)&fileCount, ffile.GetAddressOf()).ThrowOnError();
|
||||||
|
void* refKey;
|
||||||
|
var refKeySize = 0u;
|
||||||
|
ffile.Get()->GetReferenceKey(&refKey, &refKeySize).ThrowOnError();
|
||||||
|
|
||||||
|
using var floader = default(ComPtr<IDWriteFontFileLoader>);
|
||||||
|
ffile.Get()->GetLoader(floader.GetAddressOf()).ThrowOnError();
|
||||||
|
|
||||||
|
using var flocal = default(ComPtr<IDWriteLocalFontFileLoader>);
|
||||||
|
floader.As(&flocal).ThrowOnError();
|
||||||
|
|
||||||
|
var pathSize = 0u;
|
||||||
|
flocal.Get()->GetFilePathLengthFromKey(refKey, refKeySize, &pathSize).ThrowOnError();
|
||||||
|
|
||||||
|
var path = stackalloc char[(int)pathSize + 1];
|
||||||
|
flocal.Get()->GetFilePathFromKey(refKey, refKeySize, (ushort*)path, pathSize + 1).ThrowOnError();
|
||||||
|
return (new(path, 0, (int)pathSize), (int)fface.Get()->GetIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Equals(SystemFontId other) => this.Family.Equals(other.Family) && this.Weight == other.Weight &&
|
||||||
|
this.Stretch == other.Stretch && this.Style == other.Style;
|
||||||
|
}
|
||||||
1117
Dalamud/Interface/ImGuiFontChooserDialog/SingleFontChooserDialog.cs
Normal file
1117
Dalamud/Interface/ImGuiFontChooserDialog/SingleFontChooserDialog.cs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -705,13 +705,13 @@ internal class InterfaceManager : IDisposable, IServiceType
|
||||||
using (this.dalamudAtlas.SuppressAutoRebuild())
|
using (this.dalamudAtlas.SuppressAutoRebuild())
|
||||||
{
|
{
|
||||||
this.DefaultFontHandle = (FontHandle)this.dalamudAtlas.NewDelegateFontHandle(
|
this.DefaultFontHandle = (FontHandle)this.dalamudAtlas.NewDelegateFontHandle(
|
||||||
e => e.OnPreBuild(tk => tk.AddDalamudDefaultFont(DefaultFontSizePx)));
|
e => e.OnPreBuild(tk => tk.AddDalamudDefaultFont(-1)));
|
||||||
this.IconFontHandle = (FontHandle)this.dalamudAtlas.NewDelegateFontHandle(
|
this.IconFontHandle = (FontHandle)this.dalamudAtlas.NewDelegateFontHandle(
|
||||||
e => e.OnPreBuild(
|
e => e.OnPreBuild(
|
||||||
tk => tk.AddFontAwesomeIconFont(
|
tk => tk.AddFontAwesomeIconFont(
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
SizePx = DefaultFontSizePx,
|
SizePx = Service<FontAtlasFactory>.Get().DefaultFontSpec.SizePx,
|
||||||
GlyphMinAdvanceX = DefaultFontSizePx,
|
GlyphMinAdvanceX = DefaultFontSizePx,
|
||||||
GlyphMaxAdvanceX = DefaultFontSizePx,
|
GlyphMaxAdvanceX = DefaultFontSizePx,
|
||||||
})));
|
})));
|
||||||
|
|
@ -719,7 +719,10 @@ internal class InterfaceManager : IDisposable, IServiceType
|
||||||
e => e.OnPreBuild(
|
e => e.OnPreBuild(
|
||||||
tk => tk.AddDalamudAssetFont(
|
tk => tk.AddDalamudAssetFont(
|
||||||
DalamudAsset.InconsolataRegular,
|
DalamudAsset.InconsolataRegular,
|
||||||
new() { SizePx = DefaultFontSizePx })));
|
new()
|
||||||
|
{
|
||||||
|
SizePx = Service<FontAtlasFactory>.Get().DefaultFontSpec.SizePx,
|
||||||
|
})));
|
||||||
this.dalamudAtlas.BuildStepChange += e => e.OnPostBuild(
|
this.dalamudAtlas.BuildStepChange += e => e.OnPostBuild(
|
||||||
tk =>
|
tk =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,10 @@ internal class ConsoleWindow : Window, IDisposable
|
||||||
ImGui.TextColored(ImGuiColors.DalamudRed, regexErrorString);
|
ImGui.TextColored(ImGuiColors.DalamudRed, regexErrorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.BeginChild("scrolling", new Vector2(0, ImGui.GetFrameHeightWithSpacing() - 55 * ImGuiHelpers.GlobalScale), false, ImGuiWindowFlags.AlwaysHorizontalScrollbar | ImGuiWindowFlags.AlwaysVerticalScrollbar);
|
var sendButtonSize = ImGui.CalcTextSize("Send") +
|
||||||
|
((new Vector2(16, 0) + (ImGui.GetStyle().FramePadding * 2)) * ImGuiHelpers.GlobalScale);
|
||||||
|
var scrollingHeight = ImGui.GetContentRegionAvail().Y - sendButtonSize.Y;
|
||||||
|
ImGui.BeginChild("scrolling", new Vector2(0, scrollingHeight), false, ImGuiWindowFlags.AlwaysHorizontalScrollbar | ImGuiWindowFlags.AlwaysVerticalScrollbar);
|
||||||
|
|
||||||
if (this.clearLog) this.Clear();
|
if (this.clearLog) this.Clear();
|
||||||
|
|
||||||
|
|
@ -173,9 +176,10 @@ internal class ConsoleWindow : Window, IDisposable
|
||||||
var childDrawList = ImGui.GetWindowDrawList();
|
var childDrawList = ImGui.GetWindowDrawList();
|
||||||
var childSize = ImGui.GetWindowSize();
|
var childSize = ImGui.GetWindowSize();
|
||||||
|
|
||||||
var cursorDiv = ImGuiHelpers.GlobalScale * 93;
|
var cursorDiv = ImGui.CalcTextSize("00:00:00.000 ").X;
|
||||||
var cursorLogLevel = ImGuiHelpers.GlobalScale * 100;
|
var cursorLogLevel = ImGui.CalcTextSize("00:00:00.000 | ").X;
|
||||||
var cursorLogLine = ImGuiHelpers.GlobalScale * 135;
|
var dividerOffset = ImGui.CalcTextSize("00:00:00.000 | AAA ").X + (ImGui.CalcTextSize(" ").X / 2);
|
||||||
|
var cursorLogLine = ImGui.CalcTextSize("00:00:00.000 | AAA | ").X;
|
||||||
|
|
||||||
lock (this.renderLock)
|
lock (this.renderLock)
|
||||||
{
|
{
|
||||||
|
|
@ -242,8 +246,7 @@ internal class ConsoleWindow : Window, IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw dividing line
|
// Draw dividing line
|
||||||
var offset = ImGuiHelpers.GlobalScale * 127;
|
childDrawList.AddLine(new Vector2(childPos.X + dividerOffset, childPos.Y), new Vector2(childPos.X + dividerOffset, childPos.Y + childSize.Y), 0x4FFFFFFF, 1.0f);
|
||||||
childDrawList.AddLine(new Vector2(childPos.X + offset, childPos.Y), new Vector2(childPos.X + offset, childPos.Y + childSize.Y), 0x4FFFFFFF, 1.0f);
|
|
||||||
|
|
||||||
ImGui.EndChild();
|
ImGui.EndChild();
|
||||||
|
|
||||||
|
|
@ -261,7 +264,7 @@ internal class ConsoleWindow : Window, IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X - (80.0f * ImGuiHelpers.GlobalScale) - (ImGui.GetStyle().ItemSpacing.X * ImGuiHelpers.GlobalScale));
|
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X - sendButtonSize.X - (ImGui.GetStyle().ItemSpacing.X * ImGuiHelpers.GlobalScale));
|
||||||
|
|
||||||
var getFocus = false;
|
var getFocus = false;
|
||||||
unsafe
|
unsafe
|
||||||
|
|
@ -280,7 +283,7 @@ internal class ConsoleWindow : Window, IDisposable
|
||||||
|
|
||||||
if (hadColor) ImGui.PopStyleColor();
|
if (hadColor) ImGui.PopStyleColor();
|
||||||
|
|
||||||
if (ImGui.Button("Send", ImGuiHelpers.ScaledVector2(80.0f, 23.0f)))
|
if (ImGui.Button("Send", sendButtonSize))
|
||||||
{
|
{
|
||||||
this.ProcessCommand();
|
this.ProcessCommand();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ using System.Numerics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using Dalamud.Game;
|
||||||
|
using Dalamud.Interface.FontIdentifier;
|
||||||
using Dalamud.Interface.GameFonts;
|
using Dalamud.Interface.GameFonts;
|
||||||
|
using Dalamud.Interface.ImGuiFontChooserDialog;
|
||||||
using Dalamud.Interface.ManagedFontAtlas;
|
using Dalamud.Interface.ManagedFontAtlas;
|
||||||
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
|
@ -24,6 +27,8 @@ internal class GamePrebakedFontsTestWidget : IDataWindowWidget, IDisposable
|
||||||
{
|
{
|
||||||
private ImVectorWrapper<byte> testStringBuffer;
|
private ImVectorWrapper<byte> testStringBuffer;
|
||||||
private IFontAtlas? privateAtlas;
|
private IFontAtlas? privateAtlas;
|
||||||
|
private SingleFontSpec fontSpec = new() { FontId = DalamudDefaultFontAndFamilyId.Instance };
|
||||||
|
private IFontHandle? fontDialogHandle;
|
||||||
private IReadOnlyDictionary<GameFontFamily, (GameFontStyle Size, Lazy<IFontHandle> Handle)[]>? fontHandles;
|
private IReadOnlyDictionary<GameFontFamily, (GameFontStyle Size, Lazy<IFontHandle> Handle)[]>? fontHandles;
|
||||||
private bool useGlobalScale;
|
private bool useGlobalScale;
|
||||||
private bool useWordWrap;
|
private bool useWordWrap;
|
||||||
|
|
@ -111,13 +116,52 @@ internal class GamePrebakedFontsTestWidget : IDataWindowWidget, IDisposable
|
||||||
if (ImGui.Button("Test Lock"))
|
if (ImGui.Button("Test Lock"))
|
||||||
Task.Run(this.TestLock);
|
Task.Run(this.TestLock);
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Choose Editor Font"))
|
||||||
|
{
|
||||||
|
var fcd = new SingleFontChooserDialog(
|
||||||
|
Service<FontAtlasFactory>.Get().CreateFontAtlas(
|
||||||
|
$"{nameof(GamePrebakedFontsTestWidget)}:EditorFont",
|
||||||
|
FontAtlasAutoRebuildMode.Async));
|
||||||
|
fcd.SelectedFont = this.fontSpec;
|
||||||
|
fcd.IgnorePreviewGlobalScale = !this.useGlobalScale;
|
||||||
|
Service<InterfaceManager>.Get().Draw += fcd.Draw;
|
||||||
|
fcd.ResultTask.ContinueWith(
|
||||||
|
r => Service<Framework>.Get().RunOnFrameworkThread(
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
Service<InterfaceManager>.Get().Draw -= fcd.Draw;
|
||||||
|
fcd.Dispose();
|
||||||
|
|
||||||
|
_ = r.Exception;
|
||||||
|
if (!r.IsCompletedSuccessfully)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.fontSpec = r.Result;
|
||||||
|
Log.Information("Selected font: {font}", this.fontSpec);
|
||||||
|
this.fontDialogHandle?.Dispose();
|
||||||
|
this.fontDialogHandle = null;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.privateAtlas ??=
|
||||||
|
Service<FontAtlasFactory>.Get().CreateFontAtlas(
|
||||||
|
nameof(GamePrebakedFontsTestWidget),
|
||||||
|
FontAtlasAutoRebuildMode.Async,
|
||||||
|
this.useGlobalScale);
|
||||||
|
this.fontDialogHandle ??= this.fontSpec.CreateFontHandle(this.privateAtlas);
|
||||||
|
|
||||||
fixed (byte* labelPtr = "Test Input"u8)
|
fixed (byte* labelPtr = "Test Input"u8)
|
||||||
|
{
|
||||||
|
if (!this.useGlobalScale)
|
||||||
|
ImGuiNative.igSetWindowFontScale(1 / ImGuiHelpers.GlobalScale);
|
||||||
|
using (this.fontDialogHandle.Push())
|
||||||
{
|
{
|
||||||
if (ImGuiNative.igInputTextMultiline(
|
if (ImGuiNative.igInputTextMultiline(
|
||||||
labelPtr,
|
labelPtr,
|
||||||
this.testStringBuffer.Data,
|
this.testStringBuffer.Data,
|
||||||
(uint)this.testStringBuffer.Capacity,
|
(uint)this.testStringBuffer.Capacity,
|
||||||
new(ImGui.GetContentRegionAvail().X, 32 * ImGuiHelpers.GlobalScale),
|
new(ImGui.GetContentRegionAvail().X, ImGui.GetTextLineHeight() * 3),
|
||||||
0,
|
0,
|
||||||
null,
|
null,
|
||||||
null) != 0)
|
null) != 0)
|
||||||
|
|
@ -136,11 +180,10 @@ internal class GamePrebakedFontsTestWidget : IDataWindowWidget, IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.privateAtlas ??=
|
if (!this.useGlobalScale)
|
||||||
Service<FontAtlasFactory>.Get().CreateFontAtlas(
|
ImGuiNative.igSetWindowFontScale(1);
|
||||||
nameof(GamePrebakedFontsTestWidget),
|
}
|
||||||
FontAtlasAutoRebuildMode.Async,
|
|
||||||
this.useGlobalScale);
|
|
||||||
this.fontHandles ??=
|
this.fontHandles ??=
|
||||||
Enum.GetValues<GameFontFamilyAndSize>()
|
Enum.GetValues<GameFontFamilyAndSize>()
|
||||||
.Where(x => x.GetAttribute<GameFontFamilyAndSizeAttribute>() is not null)
|
.Where(x => x.GetAttribute<GameFontFamilyAndSizeAttribute>() is not null)
|
||||||
|
|
@ -227,6 +270,8 @@ internal class GamePrebakedFontsTestWidget : IDataWindowWidget, IDisposable
|
||||||
this.fontHandles?.Values.SelectMany(x => x.Where(y => y.Handle.IsValueCreated).Select(y => y.Handle.Value))
|
this.fontHandles?.Values.SelectMany(x => x.Where(y => y.Handle.IsValueCreated).Select(y => y.Handle.Value))
|
||||||
.AggregateToDisposable().Dispose();
|
.AggregateToDisposable().Dispose();
|
||||||
this.fontHandles = null;
|
this.fontHandles = null;
|
||||||
|
this.fontDialogHandle?.Dispose();
|
||||||
|
this.fontDialogHandle = null;
|
||||||
this.privateAtlas?.Dispose();
|
this.privateAtlas?.Dispose();
|
||||||
this.privateAtlas = null;
|
this.privateAtlas = null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,11 @@ internal class SettingsWindow : Window
|
||||||
var interfaceManager = Service<InterfaceManager>.Get();
|
var interfaceManager = Service<InterfaceManager>.Get();
|
||||||
var fontAtlasFactory = Service<FontAtlasFactory>.Get();
|
var fontAtlasFactory = Service<FontAtlasFactory>.Get();
|
||||||
|
|
||||||
var rebuildFont = fontAtlasFactory.UseAxis != configuration.UseAxisFontsFromGame;
|
var rebuildFont = !Equals(fontAtlasFactory.DefaultFontSpec, configuration.DefaultFontSpec);
|
||||||
rebuildFont |= !Equals(ImGui.GetIO().FontGlobalScale, configuration.GlobalUiScale);
|
rebuildFont |= !Equals(ImGui.GetIO().FontGlobalScale, configuration.GlobalUiScale);
|
||||||
|
|
||||||
ImGui.GetIO().FontGlobalScale = configuration.GlobalUiScale;
|
ImGui.GetIO().FontGlobalScale = configuration.GlobalUiScale;
|
||||||
fontAtlasFactory.UseAxisOverride = null;
|
fontAtlasFactory.DefaultFontSpecOverride = null;
|
||||||
|
|
||||||
if (rebuildFont)
|
if (rebuildFont)
|
||||||
interfaceManager.RebuildFonts();
|
interfaceManager.RebuildFonts();
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,14 @@ using System.Text;
|
||||||
|
|
||||||
using CheapLoc;
|
using CheapLoc;
|
||||||
using Dalamud.Configuration.Internal;
|
using Dalamud.Configuration.Internal;
|
||||||
|
using Dalamud.Game;
|
||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
|
using Dalamud.Interface.FontIdentifier;
|
||||||
|
using Dalamud.Interface.GameFonts;
|
||||||
|
using Dalamud.Interface.ImGuiFontChooserDialog;
|
||||||
using Dalamud.Interface.Internal.Windows.PluginInstaller;
|
using Dalamud.Interface.Internal.Windows.PluginInstaller;
|
||||||
using Dalamud.Interface.Internal.Windows.Settings.Widgets;
|
using Dalamud.Interface.Internal.Windows.Settings.Widgets;
|
||||||
|
using Dalamud.Interface.ManagedFontAtlas;
|
||||||
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
|
|
@ -21,31 +26,19 @@ public class SettingsTabLook : SettingsTab
|
||||||
{
|
{
|
||||||
private static readonly (string, float)[] GlobalUiScalePresets =
|
private static readonly (string, float)[] GlobalUiScalePresets =
|
||||||
{
|
{
|
||||||
("9.6pt##DalamudSettingsGlobalUiScaleReset96", 9.6f / InterfaceManager.DefaultFontSizePt),
|
("80%##DalamudSettingsGlobalUiScaleReset96", 0.8f),
|
||||||
("12pt##DalamudSettingsGlobalUiScaleReset12", 12f / InterfaceManager.DefaultFontSizePt),
|
("100%##DalamudSettingsGlobalUiScaleReset12", 1f),
|
||||||
("14pt##DalamudSettingsGlobalUiScaleReset14", 14f / InterfaceManager.DefaultFontSizePt),
|
("117%##DalamudSettingsGlobalUiScaleReset14", 14 / 12f),
|
||||||
("18pt##DalamudSettingsGlobalUiScaleReset18", 18f / InterfaceManager.DefaultFontSizePt),
|
("150%##DalamudSettingsGlobalUiScaleReset18", 1.5f),
|
||||||
("24pt##DalamudSettingsGlobalUiScaleReset24", 24f / InterfaceManager.DefaultFontSizePt),
|
("200%##DalamudSettingsGlobalUiScaleReset24", 2f),
|
||||||
("36pt##DalamudSettingsGlobalUiScaleReset36", 36f / InterfaceManager.DefaultFontSizePt),
|
("300%##DalamudSettingsGlobalUiScaleReset36", 3f),
|
||||||
};
|
};
|
||||||
|
|
||||||
private float globalUiScale;
|
private float globalUiScale;
|
||||||
|
private IFontSpec defaultFontSpec = null!;
|
||||||
|
|
||||||
public override SettingsEntry[] Entries { get; } =
|
public override SettingsEntry[] Entries { get; } =
|
||||||
{
|
{
|
||||||
new GapSettingsEntry(5),
|
|
||||||
|
|
||||||
new SettingsEntry<bool>(
|
|
||||||
Loc.Localize("DalamudSettingToggleAxisFonts", "Use AXIS fonts as default Dalamud font"),
|
|
||||||
Loc.Localize("DalamudSettingToggleUiAxisFontsHint", "Use AXIS fonts (the game's main UI fonts) as default Dalamud font."),
|
|
||||||
c => c.UseAxisFontsFromGame,
|
|
||||||
(v, c) => c.UseAxisFontsFromGame = v,
|
|
||||||
v =>
|
|
||||||
{
|
|
||||||
Service<FontAtlasFactory>.Get().UseAxisOverride = v;
|
|
||||||
Service<InterfaceManager>.Get().RebuildFonts();
|
|
||||||
}),
|
|
||||||
|
|
||||||
new GapSettingsEntry(5, true),
|
new GapSettingsEntry(5, true),
|
||||||
|
|
||||||
new ButtonSettingsEntry(
|
new ButtonSettingsEntry(
|
||||||
|
|
@ -178,10 +171,10 @@ public class SettingsTabLook : SettingsTab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var globalUiScaleInPt = 12f * this.globalUiScale;
|
var globalUiScaleInPct = 100f * this.globalUiScale;
|
||||||
if (ImGui.DragFloat("##DalamudSettingsGlobalUiScaleDrag", ref globalUiScaleInPt, 0.1f, 9.6f, 36f, "%.1fpt", ImGuiSliderFlags.AlwaysClamp))
|
if (ImGui.DragFloat("##DalamudSettingsGlobalUiScaleDrag", ref globalUiScaleInPct, 1f, 80f, 300f, "%.0f%%", ImGuiSliderFlags.AlwaysClamp))
|
||||||
{
|
{
|
||||||
this.globalUiScale = globalUiScaleInPt / 12f;
|
this.globalUiScale = globalUiScaleInPct / 100f;
|
||||||
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
|
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
|
||||||
interfaceManager.RebuildFonts();
|
interfaceManager.RebuildFonts();
|
||||||
}
|
}
|
||||||
|
|
@ -201,12 +194,53 @@ public class SettingsTabLook : SettingsTab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(5);
|
||||||
|
|
||||||
|
if (ImGui.Button(Loc.Localize("DalamudSettingChooseDefaultFont", "Choose Default Font")))
|
||||||
|
{
|
||||||
|
var faf = Service<FontAtlasFactory>.Get();
|
||||||
|
var fcd = new SingleFontChooserDialog(
|
||||||
|
faf.CreateFontAtlas($"{nameof(SettingsTabLook)}:Default", FontAtlasAutoRebuildMode.Async));
|
||||||
|
fcd.SelectedFont = (SingleFontSpec)this.defaultFontSpec;
|
||||||
|
fcd.FontFamilyExcludeFilter = x => x is DalamudDefaultFontAndFamilyId;
|
||||||
|
interfaceManager.Draw += fcd.Draw;
|
||||||
|
fcd.ResultTask.ContinueWith(
|
||||||
|
r => Service<Framework>.Get().RunOnFrameworkThread(
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
interfaceManager.Draw -= fcd.Draw;
|
||||||
|
fcd.Dispose();
|
||||||
|
|
||||||
|
_ = r.Exception;
|
||||||
|
if (!r.IsCompletedSuccessfully)
|
||||||
|
return;
|
||||||
|
|
||||||
|
faf.DefaultFontSpecOverride = this.defaultFontSpec = r.Result;
|
||||||
|
interfaceManager.RebuildFonts();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
using (interfaceManager.MonoFontHandle?.Push())
|
||||||
|
{
|
||||||
|
if (ImGui.Button(Loc.Localize("DalamudSettingResetDefaultFont", "Reset Default Font")))
|
||||||
|
{
|
||||||
|
var faf = Service<FontAtlasFactory>.Get();
|
||||||
|
faf.DefaultFontSpecOverride =
|
||||||
|
this.defaultFontSpec =
|
||||||
|
new SingleFontSpec { FontId = new GameFontAndFamilyId(GameFontFamily.Axis) };
|
||||||
|
interfaceManager.RebuildFonts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
base.Draw();
|
base.Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Load()
|
public override void Load()
|
||||||
{
|
{
|
||||||
this.globalUiScale = Service<DalamudConfiguration>.Get().GlobalUiScale;
|
this.globalUiScale = Service<DalamudConfiguration>.Get().GlobalUiScale;
|
||||||
|
this.defaultFontSpec = Service<FontAtlasFactory>.Get().DefaultFontSpec;
|
||||||
|
|
||||||
base.Load();
|
base.Load();
|
||||||
}
|
}
|
||||||
|
|
@ -214,6 +248,7 @@ public class SettingsTabLook : SettingsTab
|
||||||
public override void Save()
|
public override void Save()
|
||||||
{
|
{
|
||||||
Service<DalamudConfiguration>.Get().GlobalUiScale = this.globalUiScale;
|
Service<DalamudConfiguration>.Get().GlobalUiScale = this.globalUiScale;
|
||||||
|
Service<DalamudConfiguration>.Get().DefaultFontSpec = this.defaultFontSpec;
|
||||||
|
|
||||||
base.Save();
|
base.Save();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ using ImGuiNET;
|
||||||
namespace Dalamud.Interface.ManagedFontAtlas;
|
namespace Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wrapper for <see cref="ImFontAtlasPtr"/>.
|
/// Wrapper for <see cref="ImFontAtlasPtr"/>.<br />
|
||||||
|
/// Not intended for plugins to implement.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFontAtlas : IDisposable
|
public interface IFontAtlas : IDisposable
|
||||||
{
|
{
|
||||||
|
|
@ -93,11 +94,15 @@ public interface IFontAtlas : IDisposable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="buildStepDelegate">Callback for <see cref="IFontAtlas.BuildStepChange"/>.</param>
|
/// <param name="buildStepDelegate">Callback for <see cref="IFontAtlas.BuildStepChange"/>.</param>
|
||||||
/// <returns>Handle to a font that may or may not be ready yet.</returns>
|
/// <returns>Handle to a font that may or may not be ready yet.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// Consider calling <see cref="IFontAtlasBuildToolkitPreBuild.AttachExtraGlyphsForDalamudLanguage"/> to support
|
||||||
|
/// glyphs that are not supplied by the game by default; this mostly affects Chinese and Korean language users.
|
||||||
|
/// </remarks>
|
||||||
/// <example>
|
/// <example>
|
||||||
/// <b>On initialization</b>:
|
/// <b>On initialization</b>:
|
||||||
/// <code>
|
/// <code>
|
||||||
/// this.fontHandle = atlas.NewDelegateFontHandle(e => e.OnPreBuild(tk => {
|
/// this.fontHandle = atlas.NewDelegateFontHandle(e => e.OnPreBuild(tk => {
|
||||||
/// var config = new SafeFontConfig { SizePx = 16 };
|
/// var config = new SafeFontConfig { SizePx = UiBuilder.DefaultFontSizePx };
|
||||||
/// config.MergeFont = tk.AddFontFromFile(@"C:\Windows\Fonts\comic.ttf", config);
|
/// config.MergeFont = tk.AddFontFromFile(@"C:\Windows\Fonts\comic.ttf", config);
|
||||||
/// tk.AddGameSymbol(config);
|
/// tk.AddGameSymbol(config);
|
||||||
/// tk.AddExtraGlyphsForDalamudLanguage(config);
|
/// tk.AddExtraGlyphsForDalamudLanguage(config);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ using ImGuiNET;
|
||||||
namespace Dalamud.Interface.ManagedFontAtlas;
|
namespace Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Common stuff for <see cref="IFontAtlasBuildToolkitPreBuild"/> and <see cref="IFontAtlasBuildToolkitPostBuild"/>.
|
/// Common stuff for <see cref="IFontAtlasBuildToolkitPreBuild"/> and <see cref="IFontAtlasBuildToolkitPostBuild"/>.<br />
|
||||||
|
/// Not intended for plugins to implement.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFontAtlasBuildToolkit
|
public interface IFontAtlasBuildToolkit
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@ using ImGuiNET;
|
||||||
namespace Dalamud.Interface.ManagedFontAtlas;
|
namespace Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Toolkit for use when the build state is <see cref="FontAtlasBuildStep.PostBuild"/>.
|
/// Toolkit for use when the build state is <see cref="FontAtlasBuildStep.PostBuild"/>.<br />
|
||||||
|
/// Not intended for plugins to implement.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFontAtlasBuildToolkitPostBuild : IFontAtlasBuildToolkit
|
public interface IFontAtlasBuildToolkitPostBuild : IFontAtlasBuildToolkit
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using Dalamud.Interface.FontIdentifier;
|
||||||
using Dalamud.Interface.GameFonts;
|
using Dalamud.Interface.GameFonts;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
|
||||||
|
|
@ -10,6 +11,7 @@ namespace Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Toolkit for use when the build state is <see cref="FontAtlasBuildStep.PreBuild"/>.<br />
|
/// Toolkit for use when the build state is <see cref="FontAtlasBuildStep.PreBuild"/>.<br />
|
||||||
|
/// Not intended for plugins to implement.<br />
|
||||||
/// <br />
|
/// <br />
|
||||||
/// After <see cref="FontAtlasBuildStepDelegate"/> returns,
|
/// After <see cref="FontAtlasBuildStepDelegate"/> returns,
|
||||||
/// either <see cref="IFontAtlasBuildToolkit.Font"/> must be set,
|
/// either <see cref="IFontAtlasBuildToolkit.Font"/> must be set,
|
||||||
|
|
@ -52,6 +54,12 @@ public interface IFontAtlasBuildToolkitPreBuild : IFontAtlasBuildToolkit
|
||||||
/// <returns>True if ignored.</returns>
|
/// <returns>True if ignored.</returns>
|
||||||
bool IsGlobalScaleIgnored(ImFontPtr fontPtr);
|
bool IsGlobalScaleIgnored(ImFontPtr fontPtr);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a function to be run after build.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action">The action to run.</param>
|
||||||
|
void RegisterPostBuild(Action action);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a font from memory region allocated using <see cref="ImGuiHelpers.AllocateMemory"/>.<br />
|
/// Adds a font from memory region allocated using <see cref="ImGuiHelpers.AllocateMemory"/>.<br />
|
||||||
/// <b>It WILL crash if you try to use a memory pointer allocated in some other way.</b><br />
|
/// <b>It WILL crash if you try to use a memory pointer allocated in some other way.</b><br />
|
||||||
|
|
@ -134,7 +142,12 @@ public interface IFontAtlasBuildToolkitPreBuild : IFontAtlasBuildToolkit
|
||||||
/// As this involves adding multiple fonts, calling this function will set <see cref="IFontAtlasBuildToolkit.Font"/>
|
/// As this involves adding multiple fonts, calling this function will set <see cref="IFontAtlasBuildToolkit.Font"/>
|
||||||
/// as the return value of this function, if it was empty before.
|
/// as the return value of this function, if it was empty before.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sizePx">Font size in pixels.</param>
|
/// <param name="sizePx">
|
||||||
|
/// Font size in pixels.
|
||||||
|
/// If a negative value is supplied,
|
||||||
|
/// (<see cref="UiBuilder.DefaultFontSpec"/>.<see cref="IFontSpec.SizePx"/> * <paramref name="sizePx"/>) will be
|
||||||
|
/// used as the font size. Specify -1 to use the default font size.
|
||||||
|
/// </param>
|
||||||
/// <param name="glyphRanges">The glyph ranges. Use <see cref="FontAtlasBuildToolkitUtilities"/>.ToGlyphRange to build.</param>
|
/// <param name="glyphRanges">The glyph ranges. Use <see cref="FontAtlasBuildToolkitUtilities"/>.ToGlyphRange to build.</param>
|
||||||
/// <returns>A font returned from <see cref="ImFontAtlasPtr.AddFont"/>.</returns>
|
/// <returns>A font returned from <see cref="ImFontAtlasPtr.AddFont"/>.</returns>
|
||||||
ImFontPtr AddDalamudDefaultFont(float sizePx, ushort[]? glyphRanges = null);
|
ImFontPtr AddDalamudDefaultFont(float sizePx, ushort[]? glyphRanges = null);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@ using ImGuiNET;
|
||||||
namespace Dalamud.Interface.ManagedFontAtlas;
|
namespace Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a reference counting handle for fonts.
|
/// Represents a reference counting handle for fonts.<br />
|
||||||
|
/// Not intended for plugins to implement.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFontHandle : IDisposable
|
public interface IFontHandle : IDisposable
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ namespace Dalamud.Interface.ManagedFontAtlas;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The wrapper for <see cref="ImFontPtr"/>, guaranteeing that the associated data will be available as long as
|
/// The wrapper for <see cref="ImFontPtr"/>, guaranteeing that the associated data will be available as long as
|
||||||
/// this struct is not disposed.
|
/// this struct is not disposed.<br />
|
||||||
|
/// Not intended for plugins to implement.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ILockedImFont : IDisposable
|
public interface ILockedImFont : IDisposable
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Runtime.InteropServices;
|
||||||
using System.Text.Unicode;
|
using System.Text.Unicode;
|
||||||
|
|
||||||
using Dalamud.Configuration.Internal;
|
using Dalamud.Configuration.Internal;
|
||||||
|
using Dalamud.Interface.FontIdentifier;
|
||||||
using Dalamud.Interface.GameFonts;
|
using Dalamud.Interface.GameFonts;
|
||||||
using Dalamud.Interface.Internal;
|
using Dalamud.Interface.Internal;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
|
@ -42,6 +43,7 @@ internal sealed partial class FontAtlasFactory
|
||||||
private readonly GamePrebakedFontHandle.HandleSubstance gameFontHandleSubstance;
|
private readonly GamePrebakedFontHandle.HandleSubstance gameFontHandleSubstance;
|
||||||
private readonly FontAtlasFactory factory;
|
private readonly FontAtlasFactory factory;
|
||||||
private readonly FontAtlasBuiltData data;
|
private readonly FontAtlasBuiltData data;
|
||||||
|
private readonly List<Action> registeredPostBuildActions = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BuildToolkit"/> class.
|
/// Initializes a new instance of the <see cref="BuildToolkit"/> class.
|
||||||
|
|
@ -163,6 +165,9 @@ internal sealed partial class FontAtlasFactory
|
||||||
public int StoreTexture(IDalamudTextureWrap textureWrap, bool disposeOnError) =>
|
public int StoreTexture(IDalamudTextureWrap textureWrap, bool disposeOnError) =>
|
||||||
this.data.AddNewTexture(textureWrap, disposeOnError);
|
this.data.AddNewTexture(textureWrap, disposeOnError);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void RegisterPostBuild(Action action) => this.registeredPostBuildActions.Add(action);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public unsafe ImFontPtr AddFontFromImGuiHeapAllocatedMemory(
|
public unsafe ImFontPtr AddFontFromImGuiHeapAllocatedMemory(
|
||||||
void* dataPointer,
|
void* dataPointer,
|
||||||
|
|
@ -314,19 +319,33 @@ internal sealed partial class FontAtlasFactory
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ImFontPtr AddDalamudDefaultFont(float sizePx, ushort[]? glyphRanges)
|
public ImFontPtr AddDalamudDefaultFont(float sizePx, ushort[]? glyphRanges)
|
||||||
{
|
{
|
||||||
ImFontPtr font;
|
ImFontPtr font = default;
|
||||||
glyphRanges ??= this.factory.DefaultGlyphRanges;
|
glyphRanges ??= this.factory.DefaultGlyphRanges;
|
||||||
if (this.factory.UseAxis)
|
|
||||||
|
var dfid = this.factory.DefaultFontSpec;
|
||||||
|
if (sizePx < 0f)
|
||||||
|
sizePx *= -dfid.SizePx;
|
||||||
|
|
||||||
|
if (dfid is SingleFontSpec sfs)
|
||||||
{
|
{
|
||||||
font = this.AddGameGlyphs(new(GameFontFamily.Axis, sizePx), glyphRanges, default);
|
if (sfs.FontId is DalamudDefaultFontAndFamilyId)
|
||||||
|
{
|
||||||
|
// invalid; calling sfs.AddToBuildToolkit calls this function, causing infinite recursion
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
font = this.AddDalamudAssetFont(
|
sfs = sfs with { SizePx = sizePx };
|
||||||
DalamudAsset.NotoSansJpMedium,
|
font = sfs.AddToBuildToolkit(this);
|
||||||
new() { SizePx = sizePx, GlyphRanges = glyphRanges });
|
if (sfs.FontId is not GameFontAndFamilyId { GameFontFamily: GameFontFamily.Axis })
|
||||||
this.AddGameSymbol(new() { SizePx = sizePx, MergeFont = font });
|
this.AddGameSymbol(new() { SizePx = sizePx, MergeFont = font });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font.IsNull())
|
||||||
|
{
|
||||||
|
// fall back to AXIS fonts
|
||||||
|
font = this.AddGameGlyphs(new(GameFontFamily.Axis, sizePx), glyphRanges, default);
|
||||||
|
}
|
||||||
|
|
||||||
this.AttachExtraGlyphsForDalamudLanguage(new() { SizePx = sizePx, MergeFont = font });
|
this.AttachExtraGlyphsForDalamudLanguage(new() { SizePx = sizePx, MergeFont = font });
|
||||||
if (this.Font.IsNull())
|
if (this.Font.IsNull())
|
||||||
|
|
@ -531,6 +550,13 @@ internal sealed partial class FontAtlasFactory
|
||||||
substance.OnPostBuild(this);
|
substance.OnPostBuild(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PostBuildCallbacks()
|
||||||
|
{
|
||||||
|
foreach (var ac in this.registeredPostBuildActions)
|
||||||
|
ac.InvokeSafely();
|
||||||
|
this.registeredPostBuildActions.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe void UploadTextures()
|
public unsafe void UploadTextures()
|
||||||
{
|
{
|
||||||
var buf = Array.Empty<byte>();
|
var buf = Array.Empty<byte>();
|
||||||
|
|
|
||||||
|
|
@ -658,7 +658,7 @@ internal sealed partial class FontAtlasFactory
|
||||||
toolkit = res.CreateToolkit(this.factory, isAsync);
|
toolkit = res.CreateToolkit(this.factory, isAsync);
|
||||||
|
|
||||||
// PreBuildSubstances deals with toolkit.Add... function family. Do this first.
|
// PreBuildSubstances deals with toolkit.Add... function family. Do this first.
|
||||||
var defaultFont = toolkit.AddDalamudDefaultFont(InterfaceManager.DefaultFontSizePx, null);
|
var defaultFont = toolkit.AddDalamudDefaultFont(-1, null);
|
||||||
|
|
||||||
this.BuildStepChange?.Invoke(toolkit);
|
this.BuildStepChange?.Invoke(toolkit);
|
||||||
toolkit.PreBuildSubstances();
|
toolkit.PreBuildSubstances();
|
||||||
|
|
@ -679,6 +679,7 @@ internal sealed partial class FontAtlasFactory
|
||||||
|
|
||||||
toolkit.PostBuild();
|
toolkit.PostBuild();
|
||||||
toolkit.PostBuildSubstances();
|
toolkit.PostBuildSubstances();
|
||||||
|
toolkit.PostBuildCallbacks();
|
||||||
this.BuildStepChange?.Invoke(toolkit);
|
this.BuildStepChange?.Invoke(toolkit);
|
||||||
|
|
||||||
foreach (var font in toolkit.Fonts)
|
foreach (var font in toolkit.Fonts)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
||||||
using Dalamud.Configuration.Internal;
|
using Dalamud.Configuration.Internal;
|
||||||
using Dalamud.Data;
|
using Dalamud.Data;
|
||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
|
using Dalamud.Interface.FontIdentifier;
|
||||||
using Dalamud.Interface.GameFonts;
|
using Dalamud.Interface.GameFonts;
|
||||||
using Dalamud.Interface.Internal;
|
using Dalamud.Interface.Internal;
|
||||||
using Dalamud.Storage.Assets;
|
using Dalamud.Storage.Assets;
|
||||||
|
|
@ -108,14 +109,29 @@ internal sealed partial class FontAtlasFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether to override configuration for UseAxis.
|
/// Gets or sets a value indicating whether to override configuration for <see cref="DefaultFontSpec"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? UseAxisOverride { get; set; } = null;
|
public IFontSpec? DefaultFontSpecOverride { get; set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether to use AXIS fonts.
|
/// Gets the default font ID.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseAxis => this.UseAxisOverride ?? Service<DalamudConfiguration>.Get().UseAxisFontsFromGame;
|
public IFontSpec DefaultFontSpec =>
|
||||||
|
this.DefaultFontSpecOverride
|
||||||
|
?? Service<DalamudConfiguration>.Get().DefaultFontSpec
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
?? (Service<DalamudConfiguration>.Get().UseAxisFontsFromGame
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
? new()
|
||||||
|
{
|
||||||
|
FontId = new GameFontAndFamilyId(GameFontFamily.Axis),
|
||||||
|
SizePx = InterfaceManager.DefaultFontSizePx,
|
||||||
|
}
|
||||||
|
: new SingleFontSpec
|
||||||
|
{
|
||||||
|
FontId = new DalamudAssetFontAndFamilyId(DalamudAsset.NotoSansJpMedium),
|
||||||
|
SizePx = InterfaceManager.DefaultFontSizePx + 1,
|
||||||
|
});
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the service instance of <see cref="Framework"/>.
|
/// Gets the service instance of <see cref="Framework"/>.
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ public struct SafeFontConfig
|
||||||
this.PixelSnapH = true;
|
this.PixelSnapH = true;
|
||||||
this.GlyphMaxAdvanceX = float.MaxValue;
|
this.GlyphMaxAdvanceX = float.MaxValue;
|
||||||
this.RasterizerMultiply = 1f;
|
this.RasterizerMultiply = 1f;
|
||||||
this.RasterizerGamma = 1.4f;
|
this.RasterizerGamma = 1.7f;
|
||||||
this.EllipsisChar = unchecked((char)-1);
|
this.EllipsisChar = unchecked((char)-1);
|
||||||
this.Raw.FontDataOwnedByAtlas = 1;
|
this.Raw.FontDataOwnedByAtlas = 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using Dalamud.Game;
|
||||||
using Dalamud.Game.ClientState;
|
using Dalamud.Game.ClientState;
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.Game.Gui;
|
using Dalamud.Game.Gui;
|
||||||
|
using Dalamud.Interface.FontIdentifier;
|
||||||
using Dalamud.Interface.GameFonts;
|
using Dalamud.Interface.GameFonts;
|
||||||
using Dalamud.Interface.Internal;
|
using Dalamud.Interface.Internal;
|
||||||
using Dalamud.Interface.Internal.ManagedAsserts;
|
using Dalamud.Interface.Internal.ManagedAsserts;
|
||||||
|
|
@ -173,12 +174,12 @@ public sealed class UiBuilder : IDisposable
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the default Dalamud font size in points.
|
/// Gets the default Dalamud font size in points.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static float DefaultFontSizePt => InterfaceManager.DefaultFontSizePt;
|
public static float DefaultFontSizePt => Service<FontAtlasFactory>.Get().DefaultFontSpec.SizePt;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the default Dalamud font size in pixels.
|
/// Gets the default Dalamud font size in pixels.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static float DefaultFontSizePx => InterfaceManager.DefaultFontSizePx;
|
public static float DefaultFontSizePx => Service<FontAtlasFactory>.Get().DefaultFontSpec.SizePx;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the default Dalamud font - supporting all game languages and icons.<br />
|
/// Gets the default Dalamud font - supporting all game languages and icons.<br />
|
||||||
|
|
@ -198,6 +199,11 @@ public sealed class UiBuilder : IDisposable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ImFontPtr MonoFont => InterfaceManager.MonoFont;
|
public static ImFontPtr MonoFont => InterfaceManager.MonoFont;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the default font specifications.
|
||||||
|
/// </summary>
|
||||||
|
public IFontSpec DefaultFontSpec => Service<FontAtlasFactory>.Get().DefaultFontSpec;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the handle to the default Dalamud font - supporting all game languages and icons.
|
/// Gets the handle to the default Dalamud font - supporting all game languages and icons.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
using System.Text.Unicode;
|
using System.Text.Unicode;
|
||||||
|
|
||||||
using Dalamud.Configuration.Internal;
|
using Dalamud.Configuration.Internal;
|
||||||
|
|
@ -544,6 +545,24 @@ public static class ImGuiHelpers
|
||||||
font.NativePtr->Used4kPagesMap[pageIndex >> 3] |= unchecked((byte)(1 << (pageIndex & 7)));
|
font.NativePtr->Used4kPagesMap[pageIndex >> 3] |= unchecked((byte)(1 << (pageIndex & 7)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the text for a text input, during the callback.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The callback data.</param>
|
||||||
|
/// <param name="s">The new text.</param>
|
||||||
|
internal static unsafe void SetTextFromCallback(ImGuiInputTextCallbackData* data, string s)
|
||||||
|
{
|
||||||
|
if (data->BufTextLen != 0)
|
||||||
|
ImGuiNative.ImGuiInputTextCallbackData_DeleteChars(data, 0, data->BufTextLen);
|
||||||
|
|
||||||
|
var len = Encoding.UTF8.GetByteCount(s);
|
||||||
|
var buf = len < 1024 ? stackalloc byte[len] : new byte[len];
|
||||||
|
Encoding.UTF8.GetBytes(s, buf);
|
||||||
|
fixed (byte* pBuf = buf)
|
||||||
|
ImGuiNative.ImGuiInputTextCallbackData_InsertChars(data, 0, pBuf, pBuf + len);
|
||||||
|
ImGuiNative.ImGuiInputTextCallbackData_SelectAll(data);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the corresponding ImGui viewport ID for the given window handle.
|
/// Finds the corresponding ImGui viewport ID for the given window handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -97,4 +97,76 @@ internal static class ArrayExtensions
|
||||||
/// <returns><paramref name="array"/> casted as a <see cref="IReadOnlyCollection{T}"/> if it is one; otherwise the result of <see cref="Enumerable.ToArray{TSource}"/>.</returns>
|
/// <returns><paramref name="array"/> casted as a <see cref="IReadOnlyCollection{T}"/> if it is one; otherwise the result of <see cref="Enumerable.ToArray{TSource}"/>.</returns>
|
||||||
public static IReadOnlyCollection<T> AsReadOnlyCollection<T>(this IEnumerable<T> array) =>
|
public static IReadOnlyCollection<T> AsReadOnlyCollection<T>(this IEnumerable<T> array) =>
|
||||||
array as IReadOnlyCollection<T> ?? array.ToArray();
|
array as IReadOnlyCollection<T> ?? array.ToArray();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="List{T}.FindIndex(System.Predicate{T})"/>
|
||||||
|
public static int FindIndex<T>(this IReadOnlyList<T> list, Predicate<T> match)
|
||||||
|
=> list.FindIndex(0, list.Count, match);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="List{T}.FindIndex(int,System.Predicate{T})"/>
|
||||||
|
public static int FindIndex<T>(this IReadOnlyList<T> list, int startIndex, Predicate<T> match)
|
||||||
|
=> list.FindIndex(startIndex, list.Count - startIndex, match);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="List{T}.FindIndex(int,int,System.Predicate{T})"/>
|
||||||
|
public static int FindIndex<T>(this IReadOnlyList<T> list, int startIndex, int count, Predicate<T> match)
|
||||||
|
{
|
||||||
|
if ((uint)startIndex > (uint)list.Count)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(startIndex), startIndex, null);
|
||||||
|
|
||||||
|
if (count < 0 || startIndex > list.Count - count)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(count), count, null);
|
||||||
|
|
||||||
|
if (match == null)
|
||||||
|
throw new ArgumentNullException(nameof(match));
|
||||||
|
|
||||||
|
var endIndex = startIndex + count;
|
||||||
|
for (var i = startIndex; i < endIndex; i++)
|
||||||
|
{
|
||||||
|
if (match(list[i])) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="List{T}.FindLastIndex(System.Predicate{T})"/>
|
||||||
|
public static int FindLastIndex<T>(this IReadOnlyList<T> list, Predicate<T> match)
|
||||||
|
=> list.FindLastIndex(list.Count - 1, list.Count, match);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="List{T}.FindLastIndex(int,System.Predicate{T})"/>
|
||||||
|
public static int FindLastIndex<T>(this IReadOnlyList<T> list, int startIndex, Predicate<T> match)
|
||||||
|
=> list.FindLastIndex(startIndex, startIndex + 1, match);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="List{T}.FindLastIndex(int,int,System.Predicate{T})"/>
|
||||||
|
public static int FindLastIndex<T>(this IReadOnlyList<T> list, int startIndex, int count, Predicate<T> match)
|
||||||
|
{
|
||||||
|
if (match == null)
|
||||||
|
throw new ArgumentNullException(nameof(match));
|
||||||
|
|
||||||
|
if (list.Count == 0)
|
||||||
|
{
|
||||||
|
// Special case for 0 length List
|
||||||
|
if (startIndex != -1)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(startIndex), startIndex, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Make sure we're not out of range
|
||||||
|
if ((uint)startIndex >= (uint)list.Count)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(startIndex), startIndex, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
|
||||||
|
if (count < 0 || startIndex - count + 1 < 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(count), count, null);
|
||||||
|
|
||||||
|
var endIndex = startIndex - count;
|
||||||
|
for (var i = startIndex; i > endIndex; i--)
|
||||||
|
{
|
||||||
|
if (match(list[i]))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,9 @@ using Dalamud.Logging.Internal;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
using Lumina.Excel.GeneratedSheets;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
using Windows.Win32.Storage.FileSystem;
|
using Windows.Win32.Storage.FileSystem;
|
||||||
|
|
||||||
namespace Dalamud.Utility;
|
namespace Dalamud.Utility;
|
||||||
|
|
@ -684,6 +687,16 @@ public static class Util
|
||||||
return names.ElementAt(rng.Next(0, names.Count() - 1)).Singular.RawString;
|
return names.ElementAt(rng.Next(0, names.Count() - 1)).Singular.RawString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws a corresponding exception if <see cref="HRESULT.FAILED"/> is true.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hr">The result value.</param>
|
||||||
|
internal static void ThrowOnError(this HRESULT hr)
|
||||||
|
{
|
||||||
|
if (hr.FAILED)
|
||||||
|
Marshal.ThrowExceptionForHR(hr.Value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Print formatted GameObject Information to ImGui.
|
/// Print formatted GameObject Information to ImGui.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue