feat: add system font selection

This commit is contained in:
Anna
2022-02-04 23:00:16 -05:00
parent 38cdb98f2d
commit 45c7d85e33
13 changed files with 280 additions and 19 deletions
+8
View File
@@ -48,6 +48,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.5"/> <PackageReference Include="DalamudPackager" Version="2.1.5"/>
<PackageReference Include="System.Drawing.Common" Version="6.0.0"/>
<PackageReference Include="Vanara.PInvoke.Gdi32" Version="3.3.15"/>
<PackageReference Include="XivCommon" Version="5.0.0"/> <PackageReference Include="XivCommon" Version="5.0.0"/>
</ItemGroup> </ItemGroup>
@@ -55,6 +57,12 @@
<EmbeddedResource Include="fonts\NotoSans-Italic.ttf"/> <EmbeddedResource Include="fonts\NotoSans-Italic.ttf"/>
<EmbeddedResource Include="fonts\NotoSans-Regular.ttf"/> <EmbeddedResource Include="fonts\NotoSans-Regular.ttf"/>
<EmbeddedResource Include="fonts\NotoSansJP-Regular.otf"/> <EmbeddedResource Include="fonts\NotoSansJP-Regular.otf"/>
<EmbeddedResource Include="fonts\NotoSerif-Italic.ttf"/>
<EmbeddedResource Include="fonts\NotoSerif-Regular.ttf"/>
<EmbeddedResource Include="fonts\OpenSans-Italic.ttf"/>
<EmbeddedResource Include="fonts\OpenSans-Regular.ttf"/>
<EmbeddedResource Include="fonts\Roboto-Italic.ttf"/>
<EmbeddedResource Include="fonts\Roboto-Regular.ttf"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+7
View File
@@ -1,5 +1,6 @@
using ChatTwo.Code; using ChatTwo.Code;
using ChatTwo.Resources; using ChatTwo.Resources;
using ChatTwo.Ui;
using Dalamud.Configuration; using Dalamud.Configuration;
namespace ChatTwo; namespace ChatTwo;
@@ -18,7 +19,11 @@ internal class Configuration : IPluginConfiguration {
public bool CanMove = true; public bool CanMove = true;
public bool CanResize = true; public bool CanResize = true;
public bool ShowTitleBar; public bool ShowTitleBar;
public float FontSize = 17f; public float FontSize = 17f;
public string GlobalFont = Fonts.GlobalFonts[0].Name;
public string JapaneseFont = Fonts.JapaneseFonts[0].Item1;
public float WindowAlpha = 1f; public float WindowAlpha = 1f;
public Dictionary<ChatType, uint> ChatColours = new(); public Dictionary<ChatType, uint> ChatColours = new();
public List<Tab> Tabs = new(); public List<Tab> Tabs = new();
@@ -35,6 +40,8 @@ internal class Configuration : IPluginConfiguration {
this.CanResize = other.CanResize; this.CanResize = other.CanResize;
this.ShowTitleBar = other.ShowTitleBar; this.ShowTitleBar = other.ShowTitleBar;
this.FontSize = other.FontSize; this.FontSize = other.FontSize;
this.GlobalFont = other.GlobalFont;
this.JapaneseFont = other.JapaneseFont;
this.WindowAlpha = other.WindowAlpha; this.WindowAlpha = other.WindowAlpha;
this.ChatColours = other.ChatColours.ToDictionary(entry => entry.Key, entry => entry.Value); this.ChatColours = other.ChatColours.ToDictionary(entry => entry.Key, entry => entry.Value);
this.Tabs = other.Tabs.Select(t => t.Clone()).ToList(); this.Tabs = other.Tabs.Select(t => t.Clone()).ToList();
+66 -17
View File
@@ -79,23 +79,7 @@ internal sealed class PluginUi : IDisposable {
builder.AddText("←→↑↓《》■※☀★★☆♥♡ヅツッシ☀☁☂℃℉°♀♂♠♣♦♣♧®©™€$£♯♭♪✓√◎◆◇♦■□〇●△▽▼▲‹›≤≥<«“”─\~Œœ"); builder.AddText("←→↑↓《》■※☀★★☆♥♡ヅツッシ☀☁☂℃℉°♀♂♠♣♦♣♧®©™€$£♯♭♪✓√◎◆◇♦■□〇●△▽▼▲‹›≤≥<«“”─\~Œœ");
builder.BuildRanges(out this._ranges); builder.BuildRanges(out this._ranges);
var regular = this.GetResource("ChatTwo.fonts.NotoSans-Regular.ttf"); this.SetUpUserFonts();
this._regularFont = (
GCHandle.Alloc(regular, GCHandleType.Pinned),
regular.Length
);
var italic = this.GetResource("ChatTwo.fonts.NotoSans-Italic.ttf");
this._italicFont = (
GCHandle.Alloc(italic, GCHandleType.Pinned),
italic.Length
);
var jp = this.GetResource("ChatTwo.fonts.NotoSansJP-Regular.otf");
this._jpFont = (
GCHandle.Alloc(jp, GCHandleType.Pinned),
jp.Length
);
var gameSym = File.ReadAllBytes(Path.Combine(this.Plugin.Interface.DalamudAssetDirectory.FullName, "UIRes", "gamesym.ttf")); var gameSym = File.ReadAllBytes(Path.Combine(this.Plugin.Interface.DalamudAssetDirectory.FullName, "UIRes", "gamesym.ttf"));
this._gameSymFont = ( this._gameSymFont = (
@@ -132,6 +116,69 @@ internal sealed class PluginUi : IDisposable {
this._fontCfgMerge.Destroy(); this._fontCfgMerge.Destroy();
} }
private void SetUpUserFonts() {
FontData? fontData = null;
if (this.Plugin.Config.GlobalFont.StartsWith(Fonts.IncludedIndicator)) {
var globalFont = Fonts.GlobalFonts.FirstOrDefault(font => font.Name == this.Plugin.Config.GlobalFont);
if (globalFont != null) {
fontData = new FontData(this.GetResource(globalFont.ResourcePath), this.GetResource(globalFont.ResourcePathItalic));
}
} else {
fontData = Fonts.GetFont(this.Plugin.Config.GlobalFont, true);
}
if (fontData == null) {
PluginLog.Warning("global fallback");
var globalFont = Fonts.GlobalFonts[0];
fontData = new FontData(this.GetResource(globalFont.ResourcePath), this.GetResource(globalFont.ResourcePathItalic));
}
if (this._regularFont.Item1.IsAllocated) {
this._regularFont.Item1.Free();
}
if (this._italicFont.Item1.IsAllocated) {
this._italicFont.Item1.Free();
}
this._regularFont = (
GCHandle.Alloc(fontData.Regular, GCHandleType.Pinned),
fontData.Regular.Length
);
this._italicFont = (
GCHandle.Alloc(fontData.Italic, GCHandleType.Pinned),
fontData.Italic.Length
);
FontData? jpFontData = null;
if (this.Plugin.Config.JapaneseFont.StartsWith(Fonts.IncludedIndicator)) {
var jpFont = Fonts.JapaneseFonts.FirstOrDefault(item => item.Item1 == this.Plugin.Config.JapaneseFont);
if (jpFont != default) {
jpFontData = new FontData(this.GetResource(jpFont.Item2), Array.Empty<byte>());
}
}
// else {
// jpFontData = Fonts.GetFont(this.Plugin.Config.JapaneseFont, false, CharacterSet.SHIFTJIS_CHARSET);
// PluginLog.Log($"data.Regular.Length: {jpFontData?.Regular.Length}");
// }
if (jpFontData == null) {
PluginLog.Warning("jp fallback");
var jpFont = Fonts.JapaneseFonts[0];
jpFontData = new FontData(this.GetResource(jpFont.Item2), Array.Empty<byte>());
}
if (this._jpFont.Item1.IsAllocated) {
this._jpFont.Item1.Free();
}
this._jpFont = (
GCHandle.Alloc(jpFontData.Regular, GCHandleType.Pinned),
jpFontData.Regular.Length
);
}
private void Draw() { private void Draw() {
this.DefaultText = ImGui.GetStyle().Colors[(int) ImGuiCol.Text]; this.DefaultText = ImGui.GetStyle().Colors[(int) ImGuiCol.Text];
@@ -165,6 +212,8 @@ internal sealed class PluginUi : IDisposable {
this.RegularFont = null; this.RegularFont = null;
this.ItalicFont = null; this.ItalicFont = null;
this.SetUpUserFonts();
// load regular noto sans and merge in jp + game icons // load regular noto sans and merge in jp + game icons
this.RegularFont = ImGui.GetIO().Fonts.AddFontFromMemoryTTF( this.RegularFont = ImGui.GetIO().Fonts.AddFontFromMemoryTTF(
this._regularFont.Item1.AddrOfPinnedObject(), this._regularFont.Item1.AddrOfPinnedObject(),
+119
View File
@@ -0,0 +1,119 @@
using System.Drawing;
using Vanara.PInvoke;
namespace ChatTwo.Ui;
internal static class Fonts {
internal const string IncludedIndicator = "Chat 2: ";
internal static readonly Font[] GlobalFonts = {
new(
$"{IncludedIndicator}Noto Sans",
"ChatTwo.fonts.NotoSans-Regular.ttf",
"ChatTwo.fonts.NotoSans-Italic.ttf"
),
new(
$"{IncludedIndicator}Noto Serif",
"ChatTwo.fonts.NotoSerif-Regular.ttf",
"ChatTwo.fonts.NotoSerif-Italic.ttf"
),
new(
$"{IncludedIndicator}Open Sans",
"ChatTwo.fonts.OpenSans-Regular.ttf",
"ChatTwo.fonts.OpenSans-Italic.ttf"
),
new(
$"{IncludedIndicator}Roboto",
"ChatTwo.fonts.Roboto-Regular.ttf",
"ChatTwo.fonts.Roboto-Italic.ttf"
),
};
internal static readonly (string, string)[] JapaneseFonts = {
($"{IncludedIndicator}Noto Sans JP", "ChatTwo.fonts.NotoSansJP-Regular.otf"),
// ($"{IncludedIndicator}Noto Serif JP", "ChatTwo.fonts.NotoSerifJP-Regular.otf"),
};
internal static List<string> GetJpFonts() {
var fonts = new List<string>();
using var g = Graphics.FromImage(new Bitmap(1, 1));
foreach (var (lpelfe, _, fontType) in Gdi32.EnumFontFamiliesEx(g.GetHdc(), CharacterSet.SHIFTJIS_CHARSET)) {
var name = lpelfe.elfEnumLogfontEx.elfLogFont.lfFaceName;
if (name.StartsWith("@")) {
continue;
}
fonts.Add(name);
}
return fonts;
}
internal static unsafe FontData? GetFont(string name, bool withItalic, CharacterSet charset = CharacterSet.ANSI_CHARSET) {
var regularFont = Gdi32.CreateFontIndirect(new LOGFONT {
lfFaceName = name,
lfItalic = false,
lfCharSet = charset,
lfOutPrecision = LogFontOutputPrecision.OUT_TT_ONLY_PRECIS,
});
using var g = Graphics.FromImage(new Bitmap(1, 1));
var hdc = g.GetHdc();
byte[]? GetFontData(HGDIOBJ obj) {
Gdi32.SelectObject(hdc, obj);
var size = Gdi32.GetFontData(hdc, pvBuffer: IntPtr.Zero);
var data = new byte[size];
fixed (byte* p = data) {
var res = Gdi32.GetFontData(hdc, pvBuffer: (IntPtr) p, cjBuffer: size);
Gdi32.DeleteObject(obj);
if (res == Gdi32.GDI_ERROR) {
return null;
}
}
return data;
}
var regular = GetFontData(regularFont);
var italic = Array.Empty<byte>();
if (withItalic) {
var italicFont = Gdi32.CreateFontIndirect(new LOGFONT {
lfFaceName = name,
lfItalic = true,
lfCharSet = charset,
lfOutPrecision = LogFontOutputPrecision.OUT_TT_ONLY_PRECIS,
});
italic = GetFontData(italicFont);
}
if (regular == null || italic == null) {
return null;
}
return new FontData(regular, italic);
}
}
internal sealed class FontData {
internal byte[] Regular { get; }
internal byte[] Italic { get; }
internal FontData(byte[] regular, byte[] italic) {
this.Regular = regular;
this.Italic = italic;
}
}
internal sealed class Font {
internal string Name { get; }
internal string ResourcePath { get; }
internal string ResourcePathItalic { get; }
internal Font(string name, string resourcePath, string resourcePathItalic) {
this.Name = name;
this.ResourcePath = resourcePath;
this.ResourcePathItalic = resourcePathItalic;
}
}
+3 -1
View File
@@ -123,6 +123,8 @@ internal sealed class Settings : IUiComponent {
var config = this.Ui.Plugin.Config; var config = this.Ui.Plugin.Config;
var hideChatChanged = this.Mutable.HideChat != this.Ui.Plugin.Config.HideChat; var hideChatChanged = this.Mutable.HideChat != this.Ui.Plugin.Config.HideChat;
var fontChanged = this.Mutable.GlobalFont != this.Ui.Plugin.Config.GlobalFont
|| this.Mutable.JapaneseFont != this.Ui.Plugin.Config.JapaneseFont;
var fontSizeChanged = Math.Abs(this.Mutable.FontSize - this.Ui.Plugin.Config.FontSize) > 0.001; var fontSizeChanged = Math.Abs(this.Mutable.FontSize - this.Ui.Plugin.Config.FontSize) > 0.001;
config.UpdateFrom(this.Mutable); config.UpdateFrom(this.Mutable);
@@ -131,7 +133,7 @@ internal sealed class Settings : IUiComponent {
this.Ui.Plugin.Store.FilterAllTabs(false); this.Ui.Plugin.Store.FilterAllTabs(false);
if (fontSizeChanged) { if (fontChanged || fontSizeChanged) {
this.Ui.Plugin.Interface.UiBuilder.RebuildFonts(); this.Ui.Plugin.Interface.UiBuilder.RebuildFonts();
} }
+77 -1
View File
@@ -1,4 +1,6 @@
using ChatTwo.Resources; using System.Drawing;
using System.Drawing.Text;
using ChatTwo.Resources;
using ChatTwo.Util; using ChatTwo.Util;
using ImGuiNET; using ImGuiNET;
@@ -6,14 +8,32 @@ namespace ChatTwo.Ui.SettingsTabs;
internal sealed class Display : ISettingsTab { internal sealed class Display : ISettingsTab {
private Configuration Mutable { get; } private Configuration Mutable { get; }
private List<FontFamily> Fonts { get; } = new();
private List<string> JpFonts { get; set; } = new();
public string Name => Language.Options_Display_Tab + "###tabs-display"; public string Name => Language.Options_Display_Tab + "###tabs-display";
internal Display(Configuration mutable) { internal Display(Configuration mutable) {
this.Mutable = mutable; this.Mutable = mutable;
this.UpdateFonts();
}
private void UpdateFonts() {
this.Fonts.Clear();
var fonts = new InstalledFontCollection();
foreach (var font in fonts.Families) {
this.Fonts.Add(font);
}
this.JpFonts = Ui.Fonts.GetJpFonts();
} }
public void Draw() { public void Draw() {
if (ImGui.IsWindowAppearing()) {
this.UpdateFonts();
}
ImGuiUtil.OptionCheckbox(ref this.Mutable.HideChat, Language.Options_HideChat_Name, Language.Options_HideChat_Description); ImGuiUtil.OptionCheckbox(ref this.Mutable.HideChat, Language.Options_HideChat_Name, Language.Options_HideChat_Description);
ImGuiUtil.OptionCheckbox(ref this.Mutable.HideDuringCutscenes, Language.Options_HideDuringCutscenes_Name, Language.Options_HideDuringCutscenes_Description); ImGuiUtil.OptionCheckbox(ref this.Mutable.HideDuringCutscenes, Language.Options_HideDuringCutscenes_Name, Language.Options_HideDuringCutscenes_Description);
ImGuiUtil.OptionCheckbox(ref this.Mutable.NativeItemTooltips, Language.Options_NativeItemTooltips_Name, Language.Options_NativeItemTooltips_Description); ImGuiUtil.OptionCheckbox(ref this.Mutable.NativeItemTooltips, Language.Options_NativeItemTooltips_Name, Language.Options_NativeItemTooltips_Description);
@@ -28,6 +48,62 @@ internal sealed class Display : ISettingsTab {
ImGuiUtil.OptionCheckbox(ref this.Mutable.ShowNoviceNetwork, Language.Options_ShowNoviceNetwork_Name, Language.Options_ShowNoviceNetwork_Description); ImGuiUtil.OptionCheckbox(ref this.Mutable.ShowNoviceNetwork, Language.Options_ShowNoviceNetwork_Name, Language.Options_ShowNoviceNetwork_Description);
if (ImGui.BeginCombo("Font", this.Mutable.GlobalFont)) {
foreach (var font in Ui.Fonts.GlobalFonts) {
if (ImGui.Selectable(font.Name, this.Mutable.GlobalFont == font.Name)) {
this.Mutable.GlobalFont = font.Name;
}
if (ImGui.IsWindowAppearing() && this.Mutable.GlobalFont == font.Name) {
ImGui.SetScrollHereY(0.5f);
}
}
ImGui.Separator();
foreach (var family in this.Fonts) {
if (!family.IsStyleAvailable(FontStyle.Italic)) {
continue;
}
if (ImGui.Selectable(family.Name, this.Mutable.GlobalFont == family.Name)) {
this.Mutable.GlobalFont = family.Name;
}
if (ImGui.IsWindowAppearing() && this.Mutable.GlobalFont == family.Name) {
ImGui.SetScrollHereY(0.5f);
}
}
ImGui.EndCombo();
}
if (ImGui.BeginCombo("Japanese font", this.Mutable.JapaneseFont)) {
foreach (var (name, _) in Ui.Fonts.JapaneseFonts) {
if (ImGui.Selectable(name, this.Mutable.JapaneseFont == name)) {
this.Mutable.JapaneseFont = name;
}
if (ImGui.IsWindowAppearing() && this.Mutable.JapaneseFont == name) {
ImGui.SetScrollHereY(0.5f);
}
}
// ImGui.Separator();
//
// foreach (var family in this.JpFonts) {
// if (ImGui.Selectable(family, this.Mutable.JapaneseFont == family)) {
// this.Mutable.JapaneseFont = family;
// }
//
// if (ImGui.IsWindowAppearing() && this.Mutable.JapaneseFont == family) {
// ImGui.SetScrollHereY(0.5f);
// }
// }
ImGui.EndCombo();
}
ImGui.DragFloat(Language.Options_FontSize_Name, ref this.Mutable.FontSize, .0125f, 12f, 36f, $"{this.Mutable.FontSize:N1}"); ImGui.DragFloat(Language.Options_FontSize_Name, ref this.Mutable.FontSize, .0125f, 12f, 36f, $"{this.Mutable.FontSize:N1}");
if (ImGui.DragFloat(Language.Options_WindowOpacity_Name, ref this.Mutable.WindowAlpha, .0025f, 0f, 1f, $"{this.Mutable.WindowAlpha * 100f:N2}%%")) { if (ImGui.DragFloat(Language.Options_WindowOpacity_Name, ref this.Mutable.WindowAlpha, .0025f, 0f, 1f, $"{this.Mutable.WindowAlpha * 100f:N2}%%")) {
switch (this.Mutable.WindowAlpha) { switch (this.Mutable.WindowAlpha) {
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.