Initial release: HSUI v1.0.0.0 - HUD replacement with configurable hotbars
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,401 @@
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using HSUI.Config;
|
||||
using HSUI.Config.Attributes;
|
||||
using HSUI.Helpers;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface.GameFonts;
|
||||
using Dalamud.Logging;
|
||||
using HSUI.Enums;
|
||||
using HSUI.Interface.Bars;
|
||||
|
||||
namespace HSUI.Interface.GeneralElements
|
||||
{
|
||||
public struct FontData
|
||||
{
|
||||
public string Name;
|
||||
public int Size;
|
||||
|
||||
public FontData(string name, int size)
|
||||
{
|
||||
Name = name;
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
|
||||
[Disableable(false)]
|
||||
[Section("Customization")]
|
||||
[SubSection("Fonts", 0)]
|
||||
public class FontsConfig : PluginConfigObject
|
||||
{
|
||||
public new static FontsConfig DefaultConfig() { return new FontsConfig(); }
|
||||
|
||||
public string FontsPath = "C:\\";
|
||||
[JsonIgnore] public string ValidatedFontsPath => ValidatePath(FontsPath);
|
||||
|
||||
public SortedList<string, FontData> Fonts = new SortedList<string, FontData>();
|
||||
public bool SupportChineseCharacters = false;
|
||||
public bool SupportKoreanCharacters = false;
|
||||
public bool SupportCyrillicCharacters = false;
|
||||
[JsonIgnore] public readonly Dictionary<string, string> GameFontMap = new Dictionary<string, string>()
|
||||
{
|
||||
{"Axis", "axis-ffxiv"},
|
||||
{"Jupiter", "jupiter-ffxiv"},
|
||||
{"JupiterNumeric", "jupiter-numeric-ffxiv"},
|
||||
{"MiedingerMid", "meidinger-ffxiv"},
|
||||
{"Meidinger", "meidinger-numberic-ffxiv"},
|
||||
{"TrumpGothic", "trumpgothic-ffxiv"},
|
||||
|
||||
};
|
||||
|
||||
[JsonIgnore] public static readonly List<string> DefaultFontsKeys = new List<string>() { "Expressway_18", "Expressway_14", "Expressway_12" };
|
||||
|
||||
[JsonIgnore] public static string DefaultBigFontKey => DefaultFontsKeys[0];
|
||||
[JsonIgnore] public static string DefaultMediumFontKey => DefaultFontsKeys[1];
|
||||
[JsonIgnore] public static string DefaultSmallFontKey => DefaultFontsKeys[2];
|
||||
|
||||
[JsonIgnore] private int _inputFont = 0;
|
||||
[JsonIgnore] private int _inputSize = 23;
|
||||
|
||||
[JsonIgnore] private string[] _fonts = null!;
|
||||
[JsonIgnore] private string[] _sizes = null!;
|
||||
|
||||
[JsonIgnore] private int _removingIndex = -1;
|
||||
[JsonIgnore] private int _applyingIndex = -1!;
|
||||
|
||||
[JsonIgnore] private FileDialogManager _fileDialogManager = new FileDialogManager();
|
||||
|
||||
public FontsConfig()
|
||||
{
|
||||
ReloadFonts();
|
||||
|
||||
// default fonts
|
||||
foreach (string key in DefaultFontsKeys)
|
||||
{
|
||||
if (!Fonts.ContainsKey(key))
|
||||
{
|
||||
string[] str = key.Split("_", StringSplitOptions.RemoveEmptyEntries);
|
||||
var defaultFont = new FontData(str[0], int.Parse(str[1]));
|
||||
Fonts.Add(key, defaultFont);
|
||||
}
|
||||
}
|
||||
|
||||
// sizes
|
||||
_sizes = new string[100];
|
||||
for (int i = 0; i < _sizes.Length; i++)
|
||||
{
|
||||
_sizes[i] = (i + 1).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsDefaultFont(string key)
|
||||
{
|
||||
return DefaultFontsKeys.Contains(key);
|
||||
}
|
||||
|
||||
private string ValidatePath(string path)
|
||||
{
|
||||
if (path.EndsWith("\\") || path.EndsWith("/"))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
return path + "\\";
|
||||
}
|
||||
|
||||
private string[] FontsFromPath(string path)
|
||||
{
|
||||
string[] fonts;
|
||||
try
|
||||
{
|
||||
fonts = Directory.GetFiles(path, "*.ttf");
|
||||
}
|
||||
catch
|
||||
{
|
||||
fonts = new string[0];
|
||||
}
|
||||
|
||||
for (int i = 0; i < fonts.Length; i++)
|
||||
{
|
||||
fonts[i] = fonts[i]
|
||||
.Replace(path, "")
|
||||
.Replace(".ttf", "")
|
||||
.Replace(".TTF", "");
|
||||
}
|
||||
|
||||
return fonts;
|
||||
}
|
||||
|
||||
private string[] FontsFromGame()
|
||||
{
|
||||
string[] gameFontArray = Enum.GetNames(typeof(GameFontFamily)).Skip(1).ToArray();
|
||||
string[] fonts = new string[gameFontArray.Length];
|
||||
|
||||
for (int i = 0; i < gameFontArray.Length; i++)
|
||||
{
|
||||
fonts[i] = GameFontMap[gameFontArray[i]];
|
||||
}
|
||||
|
||||
return fonts;
|
||||
}
|
||||
|
||||
private void ReloadFonts()
|
||||
{
|
||||
string defaultFontsPath = ValidatePath(FontsManager.Instance.DefaultFontsPath);
|
||||
string[] defaultFonts = FontsFromPath(defaultFontsPath);
|
||||
string[] gameFonts = FontsFromGame();
|
||||
string[] userFonts = FontsFromPath(ValidatedFontsPath);
|
||||
|
||||
_fonts = new string[defaultFonts.Length + gameFonts.Length + userFonts.Length];
|
||||
defaultFonts.CopyTo(_fonts, 0);
|
||||
gameFonts.CopyTo(_fonts, defaultFonts.Length);
|
||||
userFonts.CopyTo(_fonts, defaultFonts.Length + gameFonts.Length);
|
||||
}
|
||||
|
||||
private bool AddNewEntry(int font, int size)
|
||||
{
|
||||
if (font < 0 || font > _fonts.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size <= 0 || size > _sizes.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string fontName = _fonts[font];
|
||||
string key = fontName + "_" + size.ToString();
|
||||
|
||||
if (Fonts.ContainsKey(key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FontData fontData = new FontData(fontName, size);
|
||||
Fonts.Add(key, fontData);
|
||||
|
||||
FontsManager.Instance.BuildFonts();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SelectFolder()
|
||||
{
|
||||
Action<bool, string> callback = (finished, path) =>
|
||||
{
|
||||
if (finished && path.Length > 0)
|
||||
{
|
||||
FontsPath = path;
|
||||
ReloadFonts();
|
||||
}
|
||||
};
|
||||
|
||||
_fileDialogManager.OpenFolderDialog("Select Fonts Folder", callback);
|
||||
}
|
||||
|
||||
[ManualDraw]
|
||||
public bool Draw(ref bool changed)
|
||||
{
|
||||
ImGuiTableFlags flags =
|
||||
ImGuiTableFlags.RowBg |
|
||||
ImGuiTableFlags.Borders |
|
||||
ImGuiTableFlags.BordersOuter |
|
||||
ImGuiTableFlags.BordersInner |
|
||||
ImGuiTableFlags.ScrollY |
|
||||
ImGuiTableFlags.SizingFixedSame;
|
||||
|
||||
if (ImGui.BeginChild("Fonts", new Vector2(800, 500), false, ImGuiWindowFlags.NoSavedSettings | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse))
|
||||
{
|
||||
if (_fonts.Length == 0)
|
||||
{
|
||||
ImGuiHelper.Tab();
|
||||
ImGui.Text("Default font not found in \"%appdata%/Roaming/XIVLauncher/InstalledPlugins/HSUI/Media/Fonts/Expressway.ttf\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
if (ImGui.InputText("Path", ref FontsPath, 200, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
changed = true;
|
||||
ReloadFonts();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
if (ImGui.Button(FontAwesomeIcon.Folder.ToIconString(), new Vector2(0, 0)))
|
||||
{
|
||||
SelectFolder();
|
||||
}
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGuiHelper.Tab();
|
||||
ImGui.Combo("Font ##font", ref _inputFont, _fonts, 10);
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
if (ImGui.Button("\uf2f9", new Vector2(0, 0)))
|
||||
{
|
||||
ReloadFonts();
|
||||
}
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGuiHelper.Tab();
|
||||
ImGui.Combo("Size ##size", ref _inputSize, _sizes, 10);
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
if (ImGui.Button(FontAwesomeIcon.Plus.ToIconString(), new Vector2(0, 0)))
|
||||
{
|
||||
changed |= AddNewEntry(_inputFont, _inputSize + 1);
|
||||
}
|
||||
ImGui.PopFont();
|
||||
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
if (ImGui.BeginTable("table", 3, flags, new Vector2(326, 300)))
|
||||
{
|
||||
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthStretch, 0, 0);
|
||||
ImGui.TableSetupColumn("Size", ImGuiTableColumnFlags.WidthFixed, 0, 1);
|
||||
ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 0, 2);
|
||||
|
||||
ImGui.TableSetupScrollFreeze(0, 1);
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
for (int i = 0; i < Fonts.Count; i++)
|
||||
{
|
||||
var key = Fonts.Keys[i];
|
||||
var fontData = Fonts.Values[i];
|
||||
|
||||
ImGui.PushID(i.ToString());
|
||||
ImGui.TableNextRow(ImGuiTableRowFlags.None);
|
||||
|
||||
// icon
|
||||
if (ImGui.TableSetColumnIndex(0))
|
||||
{
|
||||
ImGui.Text(fontData.Name);
|
||||
}
|
||||
|
||||
// id
|
||||
if (ImGui.TableSetColumnIndex(1))
|
||||
{
|
||||
ImGui.Text(fontData.Size.ToString());
|
||||
}
|
||||
|
||||
// remove
|
||||
if (ImGui.TableSetColumnIndex(2))
|
||||
{
|
||||
ImGui.PushFont(UiBuilder.IconFont);
|
||||
ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero);
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonActive, Vector4.Zero);
|
||||
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, Vector4.Zero);
|
||||
|
||||
if (ImGui.Button(FontAwesomeIcon.ArrowAltCircleUp.ToIconString()))
|
||||
{
|
||||
_applyingIndex = i;
|
||||
}
|
||||
|
||||
if (!IsDefaultFont(key))
|
||||
{
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Button(FontAwesomeIcon.Trash.ToIconString()))
|
||||
{
|
||||
_removingIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
ImGui.PopStyleColor(3);
|
||||
}
|
||||
ImGui.PopID();
|
||||
}
|
||||
|
||||
ImGui.EndTable();
|
||||
}
|
||||
|
||||
ImGuiHelper.NewLineAndTab();
|
||||
if (ImGui.Checkbox("Support Chinese", ref SupportChineseCharacters))
|
||||
{
|
||||
changed = true;
|
||||
FontsManager.Instance.BuildFonts();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Checkbox("Support Korean", ref SupportKoreanCharacters))
|
||||
{
|
||||
changed = true;
|
||||
FontsManager.Instance.BuildFonts();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.Checkbox("Support Cyrillic", ref SupportCyrillicCharacters))
|
||||
{
|
||||
changed = true;
|
||||
FontsManager.Instance.BuildFonts();
|
||||
}
|
||||
}
|
||||
|
||||
// apply confirmation
|
||||
if (_applyingIndex >= 0)
|
||||
{
|
||||
string[] lines = new string[] { "Are you sure you want to apply this font", "to all labels using a font with the same size?" };
|
||||
var (didConfirm, didClose) = ImGuiHelper.DrawConfirmationModal("Apply to all labels?", lines);
|
||||
|
||||
if (didConfirm)
|
||||
{
|
||||
var (key, font) = Fonts.ElementAt(_applyingIndex);
|
||||
|
||||
List<LabelConfig> labelConfigs = ConfigurationManager.Instance.GetObjects<LabelConfig>();
|
||||
foreach (LabelConfig label in labelConfigs)
|
||||
{
|
||||
if (label.FontID != null && Fonts.TryGetValue(label.FontID, out FontData value))
|
||||
{
|
||||
if (font.Size == value.Size)
|
||||
{
|
||||
label.FontID = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changed = true;
|
||||
ConfigurationManager.Instance.SaveConfigurations(forced: true);
|
||||
}
|
||||
|
||||
if (didConfirm || didClose)
|
||||
{
|
||||
_applyingIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// delete confirmation
|
||||
if (_removingIndex >= 0)
|
||||
{
|
||||
string[] lines = new string[] { "Are you sure you want to remove this font?" };
|
||||
var (didConfirm, didClose) = ImGuiHelper.DrawConfirmationModal("Remove custom font?", lines);
|
||||
|
||||
if (didConfirm)
|
||||
{
|
||||
Fonts.RemoveAt(_removingIndex);
|
||||
FontsManager.Instance.BuildFonts();
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (didConfirm || didClose)
|
||||
{
|
||||
_removingIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
_fileDialogManager.Draw();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user