1
0
mirror of synced 2025-01-22 11:33:46 +01:00

feat: Added more granular font settings

Fixes #1260
This commit is contained in:
WerWolv 2025-01-18 23:34:43 +01:00
parent 3129d6e8fd
commit 117eb1e2a7
37 changed files with 878 additions and 590 deletions

View File

@ -753,10 +753,8 @@ namespace hex {
const std::vector<Font>& getFonts(); const std::vector<Font>& getFonts();
void setFontSize(float size); std::map<UnlocalizedString, ImFont*>& getFontDefinitions();
void setFontAtlas(ImFontAtlas *fontAtlas);
void setFonts(ImFont *bold, ImFont *italic);
} }
GlyphRange glyph(const char *glyph); GlyphRange glyph(const char *glyph);
@ -769,20 +767,8 @@ namespace hex {
constexpr static float DefaultFontSize = 13.0; constexpr static float DefaultFontSize = 13.0;
ImFont* Bold(); void registerFont(const UnlocalizedString &fontName);
ImFont* Italic(); ImFont* getFont(const UnlocalizedString &fontName);
/**
* @brief Gets the current font size
* @return The current font size
*/
float getFontSize();
/**
* @brief Gets the current font atlas
* @return Current font atlas
*/
ImFontAtlas* getFontAtlas();
} }

View File

@ -223,6 +223,8 @@ namespace hex {
log::error("Failed to load setting [{} / {}]: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what()); log::error("Failed to load setting [{} / {}]: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
} }
}); });
runOnChangeHandlers(unlocalizedCategory, unlocalizedName, getSetting(unlocalizedCategory, unlocalizedName, entry->widget->store()));
} }
return entry->widget.get(); return entry->widget.get();

View File

@ -1010,6 +1010,10 @@ namespace hex {
s_italicFont = italic; s_italicFont = italic;
} }
static AutoReset<std::map<UnlocalizedString, ImFont*>> s_fontDefinitions;
std::map<UnlocalizedString, ImFont*>& getFontDefinitions() {
return *s_fontDefinitions;
}
} }
@ -1082,6 +1086,14 @@ namespace hex {
return impl::s_fontAtlas; return impl::s_fontAtlas;
} }
void registerFont(const UnlocalizedString &fontName) {
(*impl::s_fontDefinitions)[fontName] = nullptr;
}
ImFont* getFont(const UnlocalizedString &fontName) {
return (*impl::s_fontDefinitions)[fontName];
}
ImFont* Bold() { ImFont* Bold() {
return impl::s_boldFont; return impl::s_boldFont;
} }

View File

@ -296,6 +296,23 @@ namespace hex {
} }
void Window::frameBegin() { void Window::frameBegin() {
// Create font textures if necessary
{
const auto &fontDefinitions = ImHexApi::Fonts::impl::getFontDefinitions();
auto &currentFont = ImGui::GetIO().Fonts;
for (const auto &[name, font] : fontDefinitions) {
// If the texture for this atlas has been built already, don't do it again
if (font->ContainerAtlas->TexID != 0)
continue;
currentFont = font->ContainerAtlas;
ImGui_ImplOpenGL3_CreateFontsTexture();
}
// Make the first font in the list the default UI font
currentFont = fontDefinitions.begin()->second->ContainerAtlas;
}
// Start new ImGui Frame // Start new ImGui Frame
ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
@ -1060,17 +1077,8 @@ namespace hex {
void Window::initImGui() { void Window::initImGui() {
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
auto fonts = ImHexApi::Fonts::getFontAtlas();
if (fonts == nullptr) {
fonts = IM_NEW(ImFontAtlas)();
fonts->AddFontDefault();
fonts->Build();
}
// Initialize ImGui and all other ImGui extensions // Initialize ImGui and all other ImGui extensions
GImGui = ImGui::CreateContext(fonts); GImGui = ImGui::CreateContext();
GImPlot = ImPlot::CreateContext(); GImPlot = ImPlot::CreateContext();
ImPlot3D::GImPlot3D = ImPlot3D::CreateContext(); ImPlot3D::GImPlot3D = ImPlot3D::CreateContext();
GImNodes = ImNodes::CreateContext(); GImNodes = ImNodes::CreateContext();
@ -1105,7 +1113,6 @@ namespace hex {
auto scale = ImHexApi::System::getGlobalScale(); auto scale = ImHexApi::System::getGlobalScale();
style.ScaleAllSizes(scale); style.ScaleAllSizes(scale);
io.DisplayFramebufferScale = ImVec2(scale, scale); io.DisplayFramebufferScale = ImVec2(scale, scale);
io.Fonts->SetTexID(fonts->TexID);
style.WindowMenuButtonPosition = ImGuiDir_None; style.WindowMenuButtonPosition = ImGuiDir_None;
style.IndentSpacing = 10.0F; style.IndentSpacing = 10.0F;

View File

@ -448,17 +448,6 @@
"hex.builtin.setting.folders.add_folder": "Neuer Ordner hinzufügen", "hex.builtin.setting.folders.add_folder": "Neuer Ordner hinzufügen",
"hex.builtin.setting.folders.description": "Gib zusätzliche Orderpfade an, in welchen Pattern, Scripts, Yara Rules und anderes gesucht wird", "hex.builtin.setting.folders.description": "Gib zusätzliche Orderpfade an, in welchen Pattern, Scripts, Yara Rules und anderes gesucht wird",
"hex.builtin.setting.folders.remove_folder": "Ausgewählter Ordner von Liste entfernen", "hex.builtin.setting.folders.remove_folder": "Ausgewählter Ordner von Liste entfernen",
"hex.builtin.setting.font": "Schriftart",
"hex.builtin.setting.font.custom_font": "Schriftart",
"hex.builtin.setting.font.custom_font_info": "Die folgenden Einstellungen sind nur verfügbar wenn eine benutzerdefinierte Schriftart ausgewählt ist.",
"hex.builtin.setting.font.font_antialias": "Schrift Anti-Aliasing",
"hex.builtin.setting.font.font_bold": "Fett",
"hex.builtin.setting.font.font_italic": "Kursiv",
"hex.builtin.setting.font.font_path": "Eigene Schriftart",
"hex.builtin.setting.font.font_size": "Schriftgrösse",
"hex.builtin.setting.font.font_size.tooltip": "Die Schriftgrösse kann nur mit einer benutzerdefinierten Schriftart geändert werden.\n\nDer Grund dafür ist, dass die Standard Schriftart von ImHex eine Bitmap Schriftart ist, welche nicht skaliert werden kann.",
"hex.builtin.setting.font.glyphs": "Glyphen",
"hex.builtin.setting.font.load_all_unicode_chars": "Alle Unicode Zeichen laden",
"hex.builtin.setting.general": "Allgemein", "hex.builtin.setting.general": "Allgemein",
"hex.builtin.setting.general.auto_backup_time": "Periodisches Projekt Backup", "hex.builtin.setting.general.auto_backup_time": "Periodisches Projekt Backup",
"hex.builtin.setting.general.auto_backup_time.format.extended": "Alle {0}min {1}s", "hex.builtin.setting.general.auto_backup_time.format.extended": "Alle {0}min {1}s",

View File

@ -460,17 +460,6 @@
"hex.builtin.setting.folders.add_folder": "Add new folder", "hex.builtin.setting.folders.add_folder": "Add new folder",
"hex.builtin.setting.folders.description": "Specify additional search paths for patterns, scripts, Yara rules and more", "hex.builtin.setting.folders.description": "Specify additional search paths for patterns, scripts, Yara rules and more",
"hex.builtin.setting.folders.remove_folder": "Remove currently selected folder from list", "hex.builtin.setting.folders.remove_folder": "Remove currently selected folder from list",
"hex.builtin.setting.font": "Font",
"hex.builtin.setting.font.glyphs": "Glyphs",
"hex.builtin.setting.font.custom_font": "Custom Font",
"hex.builtin.setting.font.custom_font_info": "The following settings are only available when a custom font has been selected.",
"hex.builtin.setting.font.font_bold": "Bold",
"hex.builtin.setting.font.font_italic": "Italic",
"hex.builtin.setting.font.font_antialias": "Antialiasing",
"hex.builtin.setting.font.font_path": "Font",
"hex.builtin.setting.font.pixel_perfect_default_font": "Use a Pixel-Perfect default font",
"hex.builtin.setting.font.font_size": "Font Size",
"hex.builtin.setting.font.font_size.tooltip": "The font size can only be adjusted when a custom font has been selected above.\n\nThis is because ImHex uses a pixel-perfect bitmap font by default. Scaling it by any non-integer factor will only cause it to become blurry.",
"hex.builtin.setting.general": "General", "hex.builtin.setting.general": "General",
"hex.builtin.setting.general.patterns": "Patterns", "hex.builtin.setting.general.patterns": "Patterns",
"hex.builtin.setting.general.network": "Network", "hex.builtin.setting.general.network": "Network",
@ -487,7 +476,6 @@
"hex.builtin.setting.general.show_tips": "Show tips on startup", "hex.builtin.setting.general.show_tips": "Show tips on startup",
"hex.builtin.setting.general.sync_pattern_source": "Sync pattern source code between providers", "hex.builtin.setting.general.sync_pattern_source": "Sync pattern source code between providers",
"hex.builtin.setting.general.upload_crash_logs": "Upload crash reports", "hex.builtin.setting.general.upload_crash_logs": "Upload crash reports",
"hex.builtin.setting.font.load_all_unicode_chars": "Load all unicode characters",
"hex.builtin.setting.hex_editor": "Hex Editor", "hex.builtin.setting.hex_editor": "Hex Editor",
"hex.builtin.setting.hex_editor.byte_padding": "Extra byte cell padding", "hex.builtin.setting.hex_editor.byte_padding": "Extra byte cell padding",
"hex.builtin.setting.hex_editor.bytes_per_row": "Bytes per row", "hex.builtin.setting.hex_editor.bytes_per_row": "Bytes per row",

View File

@ -447,17 +447,6 @@
"hex.builtin.setting.folders.add_folder": "Añadir nueva carpeta", "hex.builtin.setting.folders.add_folder": "Añadir nueva carpeta",
"hex.builtin.setting.folders.description": "Especifica rutas de búsqueda adicionales para patterns, scripts, Yara Rules y más", "hex.builtin.setting.folders.description": "Especifica rutas de búsqueda adicionales para patterns, scripts, Yara Rules y más",
"hex.builtin.setting.folders.remove_folder": "Eliminar la carpeta seleccionada de la lista", "hex.builtin.setting.folders.remove_folder": "Eliminar la carpeta seleccionada de la lista",
"hex.builtin.setting.font": "Fuente",
"hex.builtin.setting.font.custom_font": "",
"hex.builtin.setting.font.custom_font_info": "",
"hex.builtin.setting.font.font_antialias": "",
"hex.builtin.setting.font.font_bold": "",
"hex.builtin.setting.font.font_italic": "",
"hex.builtin.setting.font.font_path": "Ruta de Fuente Personalizada",
"hex.builtin.setting.font.font_size": "Tamaño de Fuente",
"hex.builtin.setting.font.font_size.tooltip": "El tamaño de la fuente de letra puede únicamente ajustarse cuando arriba se ha seleccionado una fuente personalizada.\n\nEsto se debe a que ImHex usa una fuente de mapa de bits pixel-perfect por defecto. Escalarla por un factor no entero sólamente causará que se vuelva borrosa.",
"hex.builtin.setting.font.glyphs": "",
"hex.builtin.setting.font.load_all_unicode_chars": "Cargar todos los caracteres unicode",
"hex.builtin.setting.general": "General", "hex.builtin.setting.general": "General",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.auto_backup_time.format.extended": "",

View File

@ -440,16 +440,6 @@
"hex.builtin.setting.folders.add_folder": "Új mappa hozzáadása", "hex.builtin.setting.folders.add_folder": "Új mappa hozzáadása",
"hex.builtin.setting.folders.description": "Adj meg további keresési útvonalakat mintákhoz, szkriptekhez, Yara szabályokhoz és egyebekhez", "hex.builtin.setting.folders.description": "Adj meg további keresési útvonalakat mintákhoz, szkriptekhez, Yara szabályokhoz és egyebekhez",
"hex.builtin.setting.folders.remove_folder": "A kijelölt mappa eltávolítása a listáról", "hex.builtin.setting.folders.remove_folder": "A kijelölt mappa eltávolítása a listáról",
"hex.builtin.setting.font": "Betűtípus",
"hex.builtin.setting.font.glyphs": "Szimbólumok",
"hex.builtin.setting.font.custom_font": "Saját betűtípus",
"hex.builtin.setting.font.custom_font_info": "Az alábbi beállítások csak egyéni betűtípusok esetén érhetők el.",
"hex.builtin.setting.font.font_bold": "Félkövér",
"hex.builtin.setting.font.font_italic": "Dőlt",
"hex.builtin.setting.font.font_antialias": "Élsimítás",
"hex.builtin.setting.font.font_path": "Egyéni betűtípus útvonal",
"hex.builtin.setting.font.font_size": "Betűméret",
"hex.builtin.setting.font.font_size.tooltip": "A betűméretet csak akkor lehet módosítani, ha egy egyéni betűtípus van kiválasztva.",
"hex.builtin.setting.general": "Általános", "hex.builtin.setting.general": "Általános",
"hex.builtin.setting.general.patterns": "Sablonok", "hex.builtin.setting.general.patterns": "Sablonok",
"hex.builtin.setting.general.network": "Hálózat", "hex.builtin.setting.general.network": "Hálózat",
@ -463,7 +453,6 @@
"hex.builtin.setting.general.show_tips": "Tippek mutatása indításkor", "hex.builtin.setting.general.show_tips": "Tippek mutatása indításkor",
"hex.builtin.setting.general.sync_pattern_source": "Sablon kód szinkronizálása források között", "hex.builtin.setting.general.sync_pattern_source": "Sablon kód szinkronizálása források között",
"hex.builtin.setting.general.upload_crash_logs": "Hibajelentések feltöltése", "hex.builtin.setting.general.upload_crash_logs": "Hibajelentések feltöltése",
"hex.builtin.setting.font.load_all_unicode_chars": "Minden Unicode karakter betöltése",
"hex.builtin.setting.hex_editor": "Hex szerkesztő", "hex.builtin.setting.hex_editor": "Hex szerkesztő",
"hex.builtin.setting.hex_editor.byte_padding": "Extra bájt cella kitöltés", "hex.builtin.setting.hex_editor.byte_padding": "Extra bájt cella kitöltés",
"hex.builtin.setting.hex_editor.bytes_per_row": "Bájtok soronként", "hex.builtin.setting.hex_editor.bytes_per_row": "Bájtok soronként",

View File

@ -447,17 +447,6 @@
"hex.builtin.setting.folders.add_folder": "", "hex.builtin.setting.folders.add_folder": "",
"hex.builtin.setting.folders.description": "", "hex.builtin.setting.folders.description": "",
"hex.builtin.setting.folders.remove_folder": "", "hex.builtin.setting.folders.remove_folder": "",
"hex.builtin.setting.font": "",
"hex.builtin.setting.font.custom_font": "",
"hex.builtin.setting.font.custom_font_info": "",
"hex.builtin.setting.font.font_antialias": "",
"hex.builtin.setting.font.font_bold": "",
"hex.builtin.setting.font.font_italic": "",
"hex.builtin.setting.font.font_path": "",
"hex.builtin.setting.font.font_size": "",
"hex.builtin.setting.font.font_size.tooltip": "",
"hex.builtin.setting.font.glyphs": "",
"hex.builtin.setting.font.load_all_unicode_chars": "",
"hex.builtin.setting.general": "Generali", "hex.builtin.setting.general": "Generali",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.auto_backup_time.format.extended": "",

View File

@ -447,17 +447,6 @@
"hex.builtin.setting.folders.add_folder": "フォルダを追加…", "hex.builtin.setting.folders.add_folder": "フォルダを追加…",
"hex.builtin.setting.folders.description": "パターン、スクリプト、ルールなどのための検索パスを指定して追加できます。", "hex.builtin.setting.folders.description": "パターン、スクリプト、ルールなどのための検索パスを指定して追加できます。",
"hex.builtin.setting.folders.remove_folder": "選択中のフォルダをリストから消去", "hex.builtin.setting.folders.remove_folder": "選択中のフォルダをリストから消去",
"hex.builtin.setting.font": "フォント",
"hex.builtin.setting.font.custom_font": "",
"hex.builtin.setting.font.custom_font_info": "",
"hex.builtin.setting.font.font_antialias": "",
"hex.builtin.setting.font.font_bold": "",
"hex.builtin.setting.font.font_italic": "",
"hex.builtin.setting.font.font_path": "フォントファイルのパス",
"hex.builtin.setting.font.font_size": "フォントサイズ",
"hex.builtin.setting.font.font_size.tooltip": "",
"hex.builtin.setting.font.glyphs": "",
"hex.builtin.setting.font.load_all_unicode_chars": "",
"hex.builtin.setting.general": "基本", "hex.builtin.setting.general": "基本",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.auto_backup_time.format.extended": "",

View File

@ -447,17 +447,6 @@
"hex.builtin.setting.folders.add_folder": "새 폴더 추가", "hex.builtin.setting.folders.add_folder": "새 폴더 추가",
"hex.builtin.setting.folders.description": "패턴, 스크립트, YARA 규칙 등에 대한 추가 검색 경로를 지정합니다", "hex.builtin.setting.folders.description": "패턴, 스크립트, YARA 규칙 등에 대한 추가 검색 경로를 지정합니다",
"hex.builtin.setting.folders.remove_folder": "목록에서 현재 선택된 폴더 제거", "hex.builtin.setting.folders.remove_folder": "목록에서 현재 선택된 폴더 제거",
"hex.builtin.setting.font": "글꼴",
"hex.builtin.setting.font.custom_font": "사용자 정의 글꼴",
"hex.builtin.setting.font.custom_font_info": "",
"hex.builtin.setting.font.font_antialias": "안티에일리어싱",
"hex.builtin.setting.font.font_bold": "굵게",
"hex.builtin.setting.font.font_italic": "기울임꼴",
"hex.builtin.setting.font.font_path": "사용자 정의 글꼴 경로",
"hex.builtin.setting.font.font_size": "글꼴 크기",
"hex.builtin.setting.font.font_size.tooltip": "글꼴 크기는 위에서 사용자 지정 글꼴을 선택한 경우에만 조정할 수 있습니다.\n\n이는 ImHex가 기본적으로 픽셀 완벽한 비트맵 글꼴을 사용하기 때문입니다. 정수가 아닌 계수로 크기를 조정하면 글꼴이 흐릿해질 뿐입니다.",
"hex.builtin.setting.font.glyphs": "글리프",
"hex.builtin.setting.font.load_all_unicode_chars": "모든 유니코드 문자 불러오기",
"hex.builtin.setting.general": "일반", "hex.builtin.setting.general": "일반",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.auto_backup_time.format.extended": "",

View File

@ -447,17 +447,6 @@
"hex.builtin.setting.folders.add_folder": "Adicionar nova pasta", "hex.builtin.setting.folders.add_folder": "Adicionar nova pasta",
"hex.builtin.setting.folders.description": "Especifique caminhos de pesquisa adicionais para padrões, scripts, regras Yara e muito mais", "hex.builtin.setting.folders.description": "Especifique caminhos de pesquisa adicionais para padrões, scripts, regras Yara e muito mais",
"hex.builtin.setting.folders.remove_folder": "Remover a pasta atualmente selecionada da lista", "hex.builtin.setting.folders.remove_folder": "Remover a pasta atualmente selecionada da lista",
"hex.builtin.setting.font": "Fonte",
"hex.builtin.setting.font.custom_font": "",
"hex.builtin.setting.font.custom_font_info": "",
"hex.builtin.setting.font.font_antialias": "",
"hex.builtin.setting.font.font_bold": "",
"hex.builtin.setting.font.font_italic": "",
"hex.builtin.setting.font.font_path": "Caminho da Fonte Customizada",
"hex.builtin.setting.font.font_size": "Tamanho da Fonte",
"hex.builtin.setting.font.font_size.tooltip": "",
"hex.builtin.setting.font.glyphs": "",
"hex.builtin.setting.font.load_all_unicode_chars": "",
"hex.builtin.setting.general": "General", "hex.builtin.setting.general": "General",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.auto_backup_time.format.extended": "",

View File

@ -500,18 +500,6 @@
"hex.builtin.setting.folders.add_folder": "添加新的目录", "hex.builtin.setting.folders.add_folder": "添加新的目录",
"hex.builtin.setting.folders.description": "为模式、脚本和规则等指定额外的搜索路径", "hex.builtin.setting.folders.description": "为模式、脚本和规则等指定额外的搜索路径",
"hex.builtin.setting.folders.remove_folder": "从列表中移除当前目录", "hex.builtin.setting.folders.remove_folder": "从列表中移除当前目录",
"hex.builtin.setting.font": "字体",
"hex.builtin.setting.font.custom_font": "自定义字体",
"hex.builtin.setting.font.custom_font_info": "仅当选择自定义字体时,以下设置才可用。",
"hex.builtin.setting.font.font_antialias": "抗锯齿",
"hex.builtin.setting.font.font_bold": "粗体",
"hex.builtin.setting.font.font_italic": "斜体",
"hex.builtin.setting.font.font_path": "自定义字体路径",
"hex.builtin.setting.font.font_size": "字体大小",
"hex.builtin.setting.font.font_size.tooltip": "仅当选择了自定义字体时才能调整字体大小。\n\n这是因为 ImHex 默认使用像素完美的位图字体,用任何非整数因子缩放它只会导致它变得模糊。",
"hex.builtin.setting.font.glyphs": "字形",
"hex.builtin.setting.font.load_all_unicode_chars": "加载所有 Unicode 字符",
"hex.builtin.setting.font.pixel_perfect_default_font": "使用Pixel-Perfect默认字体",
"hex.builtin.setting.general": "通用", "hex.builtin.setting.general": "通用",
"hex.builtin.setting.general.auto_backup_time": "定期备份项目", "hex.builtin.setting.general.auto_backup_time": "定期备份项目",
"hex.builtin.setting.general.auto_backup_time.format.extended": "每 {0}分 {1}秒", "hex.builtin.setting.general.auto_backup_time.format.extended": "每 {0}分 {1}秒",

View File

@ -447,17 +447,6 @@
"hex.builtin.setting.folders.add_folder": "新增資料夾", "hex.builtin.setting.folders.add_folder": "新增資料夾",
"hex.builtin.setting.folders.description": "Specify additional search paths for patterns, scripts, Yara rules and more", "hex.builtin.setting.folders.description": "Specify additional search paths for patterns, scripts, Yara rules and more",
"hex.builtin.setting.folders.remove_folder": "從列表中移除目前選擇的資料夾", "hex.builtin.setting.folders.remove_folder": "從列表中移除目前選擇的資料夾",
"hex.builtin.setting.font": "字體",
"hex.builtin.setting.font.custom_font": "",
"hex.builtin.setting.font.custom_font_info": "",
"hex.builtin.setting.font.font_antialias": "",
"hex.builtin.setting.font.font_bold": "",
"hex.builtin.setting.font.font_italic": "",
"hex.builtin.setting.font.font_path": "自訂字型路徑",
"hex.builtin.setting.font.font_size": "字體大小",
"hex.builtin.setting.font.font_size.tooltip": "需要在上方選擇自訂字型後才能調整字體大小。\n\n因為 ImHex 預設使用像素完美點陣圖字型,若以任何非整數的倍率放大,將使其模糊。",
"hex.builtin.setting.font.glyphs": "",
"hex.builtin.setting.font.load_all_unicode_chars": "載入所有 unicode 字元",
"hex.builtin.setting.general": "一般", "hex.builtin.setting.general": "一般",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.auto_backup_time.format.extended": "",

View File

@ -19,6 +19,7 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <utility> #include <utility>
#include <romfs/romfs.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@ -650,98 +651,6 @@ namespace hex::plugin::builtin {
i32 m_currIndex = 0; i32 m_currIndex = 0;
}; };
class FontFilePicker : public ContentRegistry::Settings::Widgets::FilePicker {
public:
bool draw(const std::string &name) override {
bool changed = false;
const auto &fonts = hex::getFonts();
const bool pixelPerfectFont = ContentRegistry::Settings::read<bool>("hex.builtin.setting.font", "hex.builtin.setting.font.pixel_perfect_default_font", true);
bool customFont = false;
std::string pathPreview = "";
if (m_path.empty() && pixelPerfectFont) {
pathPreview = "Pixel-Perfect Default Font (Proggy Clean)";
} else if (m_path.empty() && !pixelPerfectFont) {
pathPreview = "Smooth Default Font (JetbrainsMono)";
} else if (fonts.contains(m_path)) {
pathPreview = fonts.at(m_path);
} else {
pathPreview = wolv::util::toUTF8String(m_path.filename());
customFont = true;
}
bool pixelPerfectFontSelected = false;
if (ImGui::BeginCombo(name.c_str(), pathPreview.c_str())) {
if (ImGui::Selectable("Pixel-Perfect Default Font (Proggy Clean)", m_path.empty() && pixelPerfectFont)) {
m_path.clear();
changed = true;
pixelPerfectFontSelected = true;
}
if (ImGui::Selectable("Smooth Default Font (JetbrainsMono)", m_path.empty() && !pixelPerfectFont)) {
m_path.clear();
changed = true;
}
if (ImGui::Selectable("Custom Font", customFont)) {
changed = fs::openFileBrowser(fs::DialogMode::Open, { { "TTF Font", "ttf" }, { "OTF Font", "otf" } }, [this](const std::fs::path &path) {
m_path = path;
});
}
for (const auto &[path, fontName] : fonts) {
if (ImGui::Selectable(limitStringLength(fontName, 50).c_str(), m_path == path)) {
m_path = path;
changed = true;
}
ImGui::SetItemTooltip("%s", fontName.c_str());
}
ImGui::EndCombo();
}
if (changed) {
m_pixelPerfectFont = pixelPerfectFontSelected;
}
return changed;
}
bool isPixelPerfectFontSelected() const {
return m_pixelPerfectFont;
}
private:
bool m_pixelPerfectFont = false;
};
class SliderPoints : public ContentRegistry::Settings::Widgets::SliderFloat {
public:
SliderPoints(float defaultValue, float min, float max) : SliderFloat(defaultValue, min, max) { }
bool draw(const std::string &name) override {
float value = pixelsToPoints(m_value);
float min = pixelsToPoints(m_min);
float max = pixelsToPoints(m_max);
auto changed = ImGui::SliderFloat(name.c_str(), &value, min, max, "%.0f pt");
m_value = pointsToPixels(value);
return changed;
}
private:
static float pixelsToPoints(float pixels) {
return pixels * (72_scaled / 96.0F);
}
static float pointsToPixels(float points) {
return points / (72_scaled / 96.0F);
}
};
bool getDefaultBorderlessWindowMode() { bool getDefaultBorderlessWindowMode() {
bool result; bool result;
@ -919,47 +828,6 @@ namespace hex::plugin::builtin {
"none"); "none");
} }
/* Fonts */
{
const auto scaleWarningHandler = [](auto&) {
s_showScalingWarning = ContentRegistry::Settings::read<bool>("hex.builtin.setting.font", "hex.builtin.setting.font.pixel_perfect_default_font", true);
};
ContentRegistry::Settings::onChange("hex.builtin.setting.font", "hex.builtin.setting.font.pixel_perfect_default_font", scaleWarningHandler);
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.font", "hex.builtin.setting.font.glyphs", "hex.builtin.setting.font.load_all_unicode_chars", false)
.requiresRestart();
auto customFontPathSetting = ContentRegistry::Settings::add<FontFilePicker>("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_path")
.requiresRestart()
.setChangedCallback([scaleWarningHandler](Widgets::Widget &widget) {
scaleWarningHandler(widget);
auto &fontPicker = static_cast<FontFilePicker&>(widget);
ContentRegistry::Settings::write<bool>("hex.builtin.setting.font", "hex.builtin.setting.font.pixel_perfect_default_font", fontPicker.isPixelPerfectFontSelected());
});
const auto fontCustomizationEnabled = [customFontPathSetting ] {
auto &fontPicker = static_cast<FontFilePicker&>(customFontPathSetting.getWidget());
return !fontPicker.isPixelPerfectFontSelected();
};
ContentRegistry::Settings::add<Widgets::Label>("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.custom_font_info");
ContentRegistry::Settings::add<SliderPoints>("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_size", 16, 2, 100)
.requiresRestart()
.setEnabledCallback(fontCustomizationEnabled);
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_bold", false)
.requiresRestart()
.setEnabledCallback(fontCustomizationEnabled);
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_italic", false)
.requiresRestart()
.setEnabledCallback(fontCustomizationEnabled);
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.font", "hex.builtin.setting.font.custom_font", "hex.builtin.setting.font.font_antialias", true)
.requiresRestart()
.setEnabledCallback(fontCustomizationEnabled);
}
/* Folders */ /* Folders */
{ {
ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.folders", "hex.builtin.setting.folders.description"); ContentRegistry::Settings::setCategoryDescription("hex.builtin.setting.folders", "hex.builtin.setting.folders.description");

View File

@ -32,6 +32,7 @@
#include <wolv/utils/lock.hpp> #include <wolv/utils/lock.hpp>
#include <content/global_actions.hpp> #include <content/global_actions.hpp>
#include <fonts/fonts.hpp>
#include <ui/menu_items.hpp> #include <ui/menu_items.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@ -338,7 +339,11 @@ namespace hex::plugin::builtin {
if (name.contains(textEditorView) || name.contains(consoleView)) if (name.contains(textEditorView) || name.contains(consoleView))
m_focusedSubWindowName = name; m_focusedSubWindowName = name;
} }
ImGui::PushFont(fonts::CodeEditor());
m_textEditor.Render("hex.builtin.view.pattern_editor.name"_lang, textEditorSize, false); m_textEditor.Render("hex.builtin.view.pattern_editor.name"_lang, textEditorSize, false);
ImGui::PopFont();
m_textEditorHoverBox = ImRect(windowPosition,windowPosition+textEditorSize); m_textEditorHoverBox = ImRect(windowPosition,windowPosition+textEditorSize);
m_consoleHoverBox = ImRect(ImVec2(windowPosition.x,windowPosition.y+textEditorSize.y),windowPosition+availableSize); m_consoleHoverBox = ImRect(ImVec2(windowPosition.x,windowPosition.y+textEditorSize.y),windowPosition+availableSize);
TextEditor::FindReplaceHandler *findReplaceHandler = m_textEditor.GetFindReplaceHandler(); TextEditor::FindReplaceHandler *findReplaceHandler = m_textEditor.GetFindReplaceHandler();
@ -1073,7 +1078,10 @@ namespace hex::plugin::builtin {
m_consoleNeedsUpdate = false; m_consoleNeedsUpdate = false;
} }
ImGui::PushFont(fonts::CodeEditor());
m_consoleEditor.Render("##console", size, true); m_consoleEditor.Render("##console", size, true);
ImGui::PopFont();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetStyle().FramePadding.y + 1_scaled); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetStyle().FramePadding.y + 1_scaled);
} }

View File

@ -33,7 +33,6 @@ namespace hex::plugin::builtin {
try { try {
auto defaultValue = widget->store(); auto defaultValue = widget->store();
widget->load(ContentRegistry::Settings::impl::getSetting(unlocalizedCategory, unlocalizedName, defaultValue)); widget->load(ContentRegistry::Settings::impl::getSetting(unlocalizedCategory, unlocalizedName, defaultValue));
widget->onChanged();
} catch (const std::exception &e) { } catch (const std::exception &e) {
log::error("Failed to load setting [{} / {}]: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what()); log::error("Failed to load setting [{} / {}]: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
} }

View File

@ -9,6 +9,7 @@ add_imhex_plugin(
source/library_fonts.cpp source/library_fonts.cpp
source/font_loader.cpp source/font_loader.cpp
source/fonts.cpp source/fonts.cpp
source/font_settings.cpp
INCLUDES INCLUDES
include include
LIBRARY_PLUGIN LIBRARY_PLUGIN

View File

@ -0,0 +1,253 @@
#pragma once
#include <imgui.h>
#include <imgui_internal.h>
#include <imgui_freetype.h>
#include <memory>
#include <list>
#include <hex/api/event_manager.hpp>
#include <hex/api/task_manager.hpp>
#include <romfs/romfs.hpp>
#include <wolv/io/file.hpp>
namespace hex::fonts {
class Font {
public:
Font() = default;
float getDescent() const {
return m_font->Descent;
}
private:
explicit Font(ImFont *font) : m_font(font) { }
private:
friend class FontAtlas;
ImFont *m_font;
};
class FontAtlas {
public:
FontAtlas() : m_fontAtlas(IM_NEW(ImFontAtlas)) {
enableUnicodeCharacters(false);
// Set the default configuration for the font atlas
m_config.OversampleH = m_config.OversampleV = 1;
m_config.PixelSnapH = true;
m_config.MergeMode = false;
// Make sure the font atlas doesn't get too large, otherwise weaker GPUs might reject it
m_fontAtlas->Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;
m_fontAtlas->TexDesiredWidth = 4096;
}
FontAtlas(const FontAtlas &) = delete;
FontAtlas &operator=(const FontAtlas &) = delete;
FontAtlas(FontAtlas &&other) noexcept {
this->m_fontAtlas = other.m_fontAtlas;
other.m_fontAtlas = nullptr;
this->m_fontSizes = std::move(other.m_fontSizes);
this->m_config = other.m_config;
this->m_glyphRange = std::move(other.m_glyphRange);
this->m_fontData = std::move(other.m_fontData);
}
FontAtlas &operator=(FontAtlas &&other) noexcept {
this->m_fontAtlas = other.m_fontAtlas;
other.m_fontAtlas = nullptr;
this->m_fontSizes = std::move(other.m_fontSizes);
this->m_config = other.m_config;
this->m_glyphRange = std::move(other.m_glyphRange);
this->m_fontData = std::move(other.m_fontData);
return *this;
}
~FontAtlas() {
if (m_fontAtlas != nullptr)
IM_DELETE(m_fontAtlas);
}
Font addDefaultFont() {
ImFontConfig config = m_config;
config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Monochrome | ImGuiFreeTypeBuilderFlags_MonoHinting;
config.SizePixels = std::floor(getAdjustedFontSize(ImHexApi::System::getGlobalScale() * 13.0F));
auto font = m_fontAtlas->AddFontDefault(&config);
m_fontSizes.emplace_back(false, config.SizePixels);
m_config.MergeMode = true;
return Font(font);
}
Font addFontFromMemory(const std::vector<u8> &fontData, float fontSize, bool scalable, ImVec2 offset, const ImVector<ImWchar> &glyphRange = {}) {
auto &storedFontData = m_fontData.emplace_back(fontData);
ImFontConfig config = m_config;
config.FontDataOwnedByAtlas = false;
config.GlyphOffset = { offset.x, offset.y };
auto font = m_fontAtlas->AddFontFromMemoryTTF(storedFontData.data(), int(storedFontData.size()), getAdjustedFontSize(fontSize), &config, !glyphRange.empty() ? glyphRange.Data : m_glyphRange.Data);
m_fontSizes.emplace_back(scalable, fontSize);
m_config.MergeMode = true;
return Font(font);
}
Font addFontFromRomFs(const std::fs::path &path, float fontSize, bool scalable, ImVec2 offset, const ImVector<ImWchar> &glyphRange = {}) {
auto data = romfs::get(path).span<u8>();
return addFontFromMemory({ data.begin(), data.end() }, fontSize, scalable, offset, glyphRange);
}
Font addFontFromFile(const std::fs::path &path, float fontSize, bool scalable, ImVec2 offset, const ImVector<ImWchar> &glyphRange = {}) {
wolv::io::File file(path, wolv::io::File::Mode::Read);
auto data = file.readVector();
return addFontFromMemory(data, fontSize, scalable, offset, glyphRange);
}
void setBold(bool enabled) {
if (enabled)
m_config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Bold;
else
m_config.FontBuilderFlags &= ~ImGuiFreeTypeBuilderFlags_Bold;
}
void setItalic(bool enabled) {
if (enabled)
m_config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Oblique;
else
m_config.FontBuilderFlags &= ~ImGuiFreeTypeBuilderFlags_Oblique;
}
void setAntiAliasing(bool enabled) {
if (enabled)
m_config.FontBuilderFlags &= ~ImGuiFreeTypeBuilderFlags_Monochrome | ImGuiFreeTypeBuilderFlags_MonoHinting;
else
m_config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Monochrome | ImGuiFreeTypeBuilderFlags_MonoHinting;
}
void enableUnicodeCharacters(bool enabled) {
ImFontGlyphRangesBuilder glyphRangesBuilder;
{
constexpr static std::array<ImWchar, 3> controlCodeRange = { 0x0001, 0x001F, 0 };
constexpr static std::array<ImWchar, 3> extendedAsciiRange = { 0x007F, 0x00FF, 0 };
constexpr static std::array<ImWchar, 3> latinExtendedARange = { 0x0100, 0x017F, 0 };
glyphRangesBuilder.AddRanges(controlCodeRange.data());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesDefault());
glyphRangesBuilder.AddRanges(extendedAsciiRange.data());
glyphRangesBuilder.AddRanges(latinExtendedARange.data());
}
if (enabled) {
constexpr static std::array<ImWchar, 3> fullRange = { 0x0180, 0xFFEF, 0 };
glyphRangesBuilder.AddRanges(fullRange.data());
} else {
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesJapanese());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesChineseFull());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesCyrillic());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesKorean());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesThai());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesVietnamese());
glyphRangesBuilder.AddText("⌘⌥⌃⇧⏎⇥⌫⇪");
}
m_glyphRange.clear();
glyphRangesBuilder.BuildRanges(&m_glyphRange);
}
bool build() const {
return m_fontAtlas->Build();
}
[[nodiscard]] ImFontAtlas* getAtlas() {
auto result = m_fontAtlas;
return result;
}
float calculateFontDescend(const ImHexApi::Fonts::Font &font, float fontSize) const {
auto atlas = std::make_unique<ImFontAtlas>();
auto cfg = m_config;
// Calculate the expected font size
auto size = fontSize;
if (font.defaultSize.has_value())
size = font.defaultSize.value() * std::max(1.0F, std::floor(ImHexApi::System::getGlobalScale()));
else
size = std::max(1.0F, std::floor(size / ImHexApi::Fonts::DefaultFontSize)) * ImHexApi::Fonts::DefaultFontSize;
cfg.MergeMode = false;
cfg.SizePixels = size;
cfg.FontDataOwnedByAtlas = false;
// Construct a range that only contains the first glyph of the font
ImVector<ImWchar> queryRange;
{
auto firstGlyph = font.glyphRanges.empty() ? m_glyphRange.front() : font.glyphRanges.front().begin;
queryRange.push_back(firstGlyph);
queryRange.push_back(firstGlyph);
}
queryRange.push_back(0x00);
// Build the font atlas with the query range
auto newFont = atlas->AddFontFromMemoryTTF(const_cast<u8 *>(font.fontData.data()), int(font.fontData.size()), 0, &cfg, queryRange.Data);
atlas->Build();
return newFont->Descent;
}
void reset() {
/*IM_DELETE(m_fontAtlas);
m_fontAtlas = IM_NEW(ImFontAtlas);*/
m_fontData.clear();
m_config.MergeMode = false;
}
void updateFontScaling(float newScaling) {
for (int i = 0; i < m_fontAtlas->ConfigData.size(); i += 1) {
const auto &[scalable, fontSize] = m_fontSizes[i];
auto &configData = m_fontAtlas->ConfigData[i];
if (!scalable) {
configData.SizePixels = fontSize * std::floor(newScaling);
} else {
configData.SizePixels = fontSize * newScaling;
}
}
}
float getAdjustedFontSize(float fontSize) const {
// Since macOS reports half the framebuffer size that's actually available,
// we'll multiply all font sizes by that and then divide the global font scale
// by the same amount to get super crisp font rendering.
return fontSize * hex::ImHexApi::System::getBackingScaleFactor();
}
private:
ImFontAtlas* m_fontAtlas;
std::vector<std::pair<bool, float>> m_fontSizes;
ImFontConfig m_config;
ImVector<ImWchar> m_glyphRange;
std::list<std::vector<u8>> m_fontData;
};
}

View File

@ -0,0 +1,59 @@
#pragma once
#include <hex/api/content_registry.hpp>
namespace hex::fonts {
class FontFilePicker : public ContentRegistry::Settings::Widgets::FilePicker {
public:
bool draw(const std::string &name) override;
bool isPixelPerfectFontSelected() const;
const std::string& getSelectedFontName() const;
void load(const nlohmann::json& data) override;
nlohmann::json store() override;
private:
bool updateSelectedFontName();
private:
std::string m_selectedFontName;
bool m_pixelPerfectFont = false;
};
class SliderPoints : public ContentRegistry::Settings::Widgets::SliderFloat {
public:
SliderPoints(float defaultValue, float min, float max) : SliderFloat(defaultValue, min, max) { }
bool draw(const std::string &name) override;
};
class FontSelector : public ContentRegistry::Settings::Widgets::Widget {
public:
FontSelector() : m_fontSize(16, 2, 100), m_bold(false), m_italic(false), m_antiAliased(true) { }
bool draw(const std::string &name) override;
nlohmann::json store() override;
void load(const nlohmann::json& data) override;
[[nodiscard]] const std::fs::path& getFontPath() const;
[[nodiscard]] bool isPixelPerfectFont() const;
[[nodiscard]] float getFontSize() const;
[[nodiscard]] bool isBold() const;
[[nodiscard]] bool isItalic() const;
[[nodiscard]] bool isAntiAliased() const;
private:
bool drawPopup();
private:
FontFilePicker m_fontFilePicker;
SliderPoints m_fontSize;
ContentRegistry::Settings::Widgets::Checkbox m_bold, m_italic, m_antiAliased;
};
ContentRegistry::Settings::Widgets::Widget::Interface& addFontSettingsWidget(UnlocalizedString name);
}

View File

@ -0,0 +1,11 @@
#pragma once
#include <hex/api/imhex_api.hpp>
namespace hex::fonts {
const static auto Default = []{ return ImHexApi::Fonts::getFont("hex.fonts.font.default"); };
const static auto HexEditor = []{ return ImHexApi::Fonts::getFont("hex.fonts.font.hex_editor"); };
const static auto CodeEditor = []{ return ImHexApi::Fonts::getFont("hex.fonts.font.code_editor"); };
}

View File

@ -0,0 +1,18 @@
{
"code": "de-DE",
"country": "Germany",
"fallback": false,
"language": "German",
"translations": {
"hex.fonts.setting.font": "Schriftart",
"hex.fonts.setting.font.custom_font": "Schriftart",
"hex.fonts.setting.font.custom_font_info": "Die folgenden Einstellungen sind nur verfügbar wenn eine benutzerdefinierte Schriftart ausgewählt ist.",
"hex.fonts.setting.font.font_antialias": "Schrift Anti-Aliasing",
"hex.fonts.setting.font.font_bold": "Fett",
"hex.fonts.setting.font.font_italic": "Kursiv",
"hex.fonts.setting.font.font_path": "Schriftart",
"hex.fonts.setting.font.font_size": "Schriftgrösse",
"hex.fonts.setting.font.glyphs": "Glyphen",
"hex.fonts.setting.font.load_all_unicode_chars": "Alle Unicode Zeichen laden"
}
}

View File

@ -0,0 +1,21 @@
{
"code": "en-US",
"language": "English",
"country": "United States",
"fallback": true,
"translations": {
"hex.fonts.setting.font": "Font",
"hex.fonts.setting.font.glyphs": "Glyphs",
"hex.fonts.setting.font.custom_font": "Font",
"hex.fonts.setting.font.custom_font_info": "The following settings are only available when a custom font has been selected.",
"hex.fonts.setting.font.font_bold": "Bold",
"hex.fonts.setting.font.font_italic": "Italic",
"hex.fonts.setting.font.font_antialias": "Antialiasing",
"hex.fonts.setting.font.font_path": "Font",
"hex.fonts.setting.font.font_size": "Font Size",
"hex.fonts.setting.font.load_all_unicode_chars": "Load all unicode glyphs",
"hex.fonts.font.default": "General UI Font",
"hex.fonts.font.hex_editor": "Hex Editor Font",
"hex.fonts.font.code_editor": "Code Editor Font"
}
}

View File

@ -0,0 +1,17 @@
{
"code": "es_ES",
"country": "Spain",
"fallback": false,
"language": "Spanish",
"translations": {
"hex.fonts.setting.font": "Fuente",
"hex.fonts.setting.font.custom_font": "",
"hex.fonts.setting.font.font_antialias": "",
"hex.fonts.setting.font.font_bold": "",
"hex.fonts.setting.font.font_italic": "",
"hex.fonts.setting.font.font_path": "Fuente",
"hex.fonts.setting.font.font_size": "Tamaño de Fuente",
"hex.fonts.setting.font.glyphs": "",
"hex.fonts.setting.font.load_all_unicode_chars": "Cargar todos los caracteres unicode"
}
}

View File

@ -0,0 +1,17 @@
{
"code": "hu_HU",
"language": "Hungarian",
"country": "Hungary",
"fallback": false,
"translations": {
"hex.fonts.setting.font": "Betűtípus",
"hex.fonts.setting.font.glyphs": "Szimbólumok",
"hex.fonts.setting.font.custom_font": "Saját betűtípus",
"hex.fonts.setting.font.font_bold": "Félkövér",
"hex.fonts.setting.font.font_italic": "Dőlt",
"hex.fonts.setting.font.font_antialias": "Élsimítás",
"hex.fonts.setting.font.font_path": "Betűtípus",
"hex.fonts.setting.font.font_size": "Betűméret",
"hex.fonts.setting.font.load_all_unicode_chars": "Minden Unicode karakter betöltése"
}
}

View File

@ -0,0 +1,17 @@
{
"code": "it-IT",
"country": "Italy",
"fallback": false,
"language": "Italian",
"translations": {
"hex.fonts.setting.font": "",
"hex.fonts.setting.font.custom_font": "",
"hex.fonts.setting.font.font_antialias": "",
"hex.fonts.setting.font.font_bold": "",
"hex.fonts.setting.font.font_italic": "",
"hex.fonts.setting.font.font_path": "",
"hex.fonts.setting.font.font_size": "",
"hex.fonts.setting.font.glyphs": "",
"hex.fonts.setting.font.load_all_unicode_chars": ""
}
}

View File

@ -0,0 +1,17 @@
{
"code": "ja-JP",
"country": "Japan",
"fallback": false,
"language": "Japanese",
"translations": {
"hex.fonts.setting.font": "フォント",
"hex.fonts.setting.font.custom_font": "",
"hex.fonts.setting.font.font_antialias": "",
"hex.fonts.setting.font.font_bold": "",
"hex.fonts.setting.font.font_italic": "",
"hex.fonts.setting.font.font_path": "フォント",
"hex.fonts.setting.font.font_size": "フォントサイズ",
"hex.fonts.setting.font.glyphs": "",
"hex.fonts.setting.font.load_all_unicode_chars": ""
}
}

View File

@ -0,0 +1,17 @@
{
"code": "ko-KR",
"country": "Korea",
"fallback": false,
"language": "Korean",
"translations": {
"hex.fonts.setting.font": "글꼴",
"hex.fonts.setting.font.custom_font": "사용자 정의 글꼴",
"hex.fonts.setting.font.font_antialias": "안티에일리어싱",
"hex.fonts.setting.font.font_bold": "굵게",
"hex.fonts.setting.font.font_italic": "기울임꼴",
"hex.fonts.setting.font.font_path": "글꼴",
"hex.fonts.setting.font.font_size": "글꼴 크기",
"hex.fonts.setting.font.glyphs": "글리프",
"hex.fonts.setting.font.load_all_unicode_chars": "모든 유니코드 문자 불러오기"
}
}

View File

@ -0,0 +1,17 @@
{
"code": "pt-BR",
"country": "Brazil",
"fallback": false,
"language": "Portuguese",
"translations": {
"hex.fonts.setting.font": "Fonte",
"hex.fonts.setting.font.custom_font": "",
"hex.fonts.setting.font.font_antialias": "",
"hex.fonts.setting.font.font_bold": "",
"hex.fonts.setting.font.font_italic": "",
"hex.fonts.setting.font.font_path": "Fonte",
"hex.fonts.setting.font.font_size": "Tamanho da Fonte",
"hex.fonts.setting.font.glyphs": "",
"hex.fonts.setting.font.load_all_unicode_chars": ""
}
}

View File

@ -0,0 +1,17 @@
{
"code": "zh-CN",
"country": "China",
"fallback": false,
"language": "Chinese (Simplified)",
"translations": {
"hex.fonts.setting.font": "字体",
"hex.fonts.setting.font.custom_font": "自定义字体",
"hex.fonts.setting.font.font_antialias": "抗锯齿",
"hex.fonts.setting.font.font_bold": "粗体",
"hex.fonts.setting.font.font_italic": "斜体",
"hex.fonts.setting.font.font_path": "字体",
"hex.fonts.setting.font.font_size": "字体大小",
"hex.fonts.setting.font.glyphs": "字形",
"hex.fonts.setting.font.load_all_unicode_chars": "加载所有 Unicode 字符"
}
}

View File

@ -0,0 +1,18 @@
{
"code": "zh-TW",
"country": "Taiwan",
"fallback": false,
"language": "Chinese (Traditional)",
"translations": {
"hex.fonts.setting.font": "字體",
"hex.fonts.setting.font.custom_font": "",
"hex.fonts.setting.font.custom_font_info": "",
"hex.fonts.setting.font.font_antialias": "",
"hex.fonts.setting.font.font_bold": "",
"hex.fonts.setting.font.font_italic": "",
"hex.fonts.setting.font.font_path": "字體",
"hex.fonts.setting.font.font_size": "字體大小",
"hex.fonts.setting.font.glyphs": "",
"hex.fonts.setting.font.load_all_unicode_chars": "載入所有 unicode 字元"
}
}

View File

@ -1,326 +1,66 @@
#include <imgui.h> #include <imgui.h>
#include <imgui_internal.h> #include <imgui_internal.h>
#include <imgui_freetype.h>
#include <imgui_impl_opengl3.h>
#include <memory>
#include <list> #include <list>
#include <hex/api/imhex_api.hpp> #include <hex/api/imhex_api.hpp>
#include <hex/api/content_registry.hpp> #include <hex/api/content_registry.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <hex/helpers/fs.hpp> #include <hex/helpers/fs.hpp>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <hex/helpers/default_paths.hpp>
#include <romfs/romfs.hpp>
#include <wolv/io/file.hpp>
#include <wolv/utils/string.hpp> #include <wolv/utils/string.hpp>
#include <font_atlas.hpp>
namespace hex::fonts { namespace hex::fonts {
namespace { bool buildFontAtlas(FontAtlas *fontAtlas, std::fs::path fontPath, bool pixelPerfectFont, float fontSize, bool loadUnicodeCharacters, bool bold, bool italic, bool antialias) {
if (fontAtlas == nullptr) {
class Font { return false;
public:
Font() = default;
float getDescent() const {
return m_font->Descent;
} }
private: fontAtlas->reset();
explicit Font(ImFont *font) : m_font(font) { }
private:
friend class FontAtlas;
ImFont *m_font;
};
class FontAtlas {
public:
FontAtlas() : m_fontAtlas(IM_NEW(ImFontAtlas)) {
enableUnicodeCharacters(false);
// Set the default configuration for the font atlas
m_config.OversampleH = m_config.OversampleV = 1;
m_config.PixelSnapH = true;
m_config.MergeMode = false;
// Make sure the font atlas doesn't get too large, otherwise weaker GPUs might reject it
m_fontAtlas->Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;
m_fontAtlas->TexDesiredWidth = 4096;
}
~FontAtlas() {
IM_DELETE(m_fontAtlas);
}
Font addDefaultFont() {
ImFontConfig config = m_config;
config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Monochrome | ImGuiFreeTypeBuilderFlags_MonoHinting;
config.SizePixels = std::floor(getAdjustedFontSize(ImHexApi::System::getGlobalScale() * 13.0F));
auto font = m_fontAtlas->AddFontDefault(&config);
m_fontSizes.emplace_back(false, config.SizePixels);
m_config.MergeMode = true;
return Font(font);
}
Font addFontFromMemory(const std::vector<u8> &fontData, float fontSize, bool scalable, ImVec2 offset, const ImVector<ImWchar> &glyphRange = {}) {
auto &storedFontData = m_fontData.emplace_back(fontData);
ImFontConfig config = m_config;
config.FontDataOwnedByAtlas = false;
config.GlyphOffset = { offset.x, offset.y };
auto font = m_fontAtlas->AddFontFromMemoryTTF(storedFontData.data(), int(storedFontData.size()), getAdjustedFontSize(fontSize), &config, !glyphRange.empty() ? glyphRange.Data : m_glyphRange.Data);
m_fontSizes.emplace_back(scalable, fontSize);
m_config.MergeMode = true;
return Font(font);
}
Font addFontFromRomFs(const std::fs::path &path, float fontSize, bool scalable, ImVec2 offset, const ImVector<ImWchar> &glyphRange = {}) {
auto data = romfs::get(path).span<u8>();
return addFontFromMemory({ data.begin(), data.end() }, fontSize, scalable, offset, glyphRange);
}
Font addFontFromFile(const std::fs::path &path, float fontSize, bool scalable, ImVec2 offset, const ImVector<ImWchar> &glyphRange = {}) {
wolv::io::File file(path, wolv::io::File::Mode::Read);
auto data = file.readVector();
return addFontFromMemory(data, fontSize, scalable, offset, glyphRange);
}
void setBold(bool enabled) {
if (enabled)
m_config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Bold;
else
m_config.FontBuilderFlags &= ~ImGuiFreeTypeBuilderFlags_Bold;
}
void setItalic(bool enabled) {
if (enabled)
m_config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Oblique;
else
m_config.FontBuilderFlags &= ~ImGuiFreeTypeBuilderFlags_Oblique;
}
void setAntiAliasing(bool enabled) {
if (enabled)
m_config.FontBuilderFlags &= ~ImGuiFreeTypeBuilderFlags_Monochrome | ImGuiFreeTypeBuilderFlags_MonoHinting;
else
m_config.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_Monochrome | ImGuiFreeTypeBuilderFlags_MonoHinting;
}
void enableUnicodeCharacters(bool enabled) {
ImFontGlyphRangesBuilder glyphRangesBuilder;
{
constexpr static std::array<ImWchar, 3> controlCodeRange = { 0x0001, 0x001F, 0 };
constexpr static std::array<ImWchar, 3> extendedAsciiRange = { 0x007F, 0x00FF, 0 };
constexpr static std::array<ImWchar, 3> latinExtendedARange = { 0x0100, 0x017F, 0 };
glyphRangesBuilder.AddRanges(controlCodeRange.data());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesDefault());
glyphRangesBuilder.AddRanges(extendedAsciiRange.data());
glyphRangesBuilder.AddRanges(latinExtendedARange.data());
}
if (enabled) {
constexpr static std::array<ImWchar, 3> fullRange = { 0x0180, 0xFFEF, 0 };
glyphRangesBuilder.AddRanges(fullRange.data());
} else {
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesJapanese());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesChineseFull());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesCyrillic());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesKorean());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesThai());
glyphRangesBuilder.AddRanges(m_fontAtlas->GetGlyphRangesVietnamese());
glyphRangesBuilder.AddText("⌘⌥⌃⇧⏎⇥⌫⇪");
}
m_glyphRange.clear();
glyphRangesBuilder.BuildRanges(&m_glyphRange);
}
bool build() const {
return m_fontAtlas->Build();
}
[[nodiscard]] ImFontAtlas* getAtlas() {
auto result = m_fontAtlas;
return result;
}
float calculateFontDescend(const ImHexApi::Fonts::Font &font, float fontSize) const {
auto atlas = std::make_unique<ImFontAtlas>();
auto cfg = m_config;
// Calculate the expected font size
auto size = fontSize;
if (font.defaultSize.has_value())
size = font.defaultSize.value() * std::max(1.0F, std::floor(ImHexApi::Fonts::getFontSize() / ImHexApi::Fonts::DefaultFontSize));
else
size = std::max(1.0F, std::floor(size / ImHexApi::Fonts::DefaultFontSize)) * ImHexApi::Fonts::DefaultFontSize;
cfg.MergeMode = false;
cfg.SizePixels = size;
cfg.FontDataOwnedByAtlas = false;
// Construct a range that only contains the first glyph of the font
ImVector<ImWchar> queryRange;
{
auto firstGlyph = font.glyphRanges.empty() ? m_glyphRange.front() : font.glyphRanges.front().begin;
queryRange.push_back(firstGlyph);
queryRange.push_back(firstGlyph);
}
queryRange.push_back(0x00);
// Build the font atlas with the query range
auto newFont = atlas->AddFontFromMemoryTTF(const_cast<u8 *>(font.fontData.data()), int(font.fontData.size()), 0, &cfg, queryRange.Data);
atlas->Build();
return newFont->Descent;
}
void reset() {
IM_DELETE(m_fontAtlas);
m_fontAtlas = IM_NEW(ImFontAtlas);
m_fontData.clear();
m_config.MergeMode = false;
}
void updateFontScaling(float newScaling) {
for (int i = 0; i < m_fontAtlas->ConfigData.size(); i += 1) {
const auto &[scalable, fontSize] = m_fontSizes[i];
auto &configData = m_fontAtlas->ConfigData[i];
if (!scalable) {
configData.SizePixels = fontSize * std::floor(newScaling);
} else {
configData.SizePixels = fontSize * newScaling;
}
}
}
private:
float getAdjustedFontSize(float fontSize) const {
// Since macOS reports half the framebuffer size that's actually available,
// we'll multiply all font sizes by that and then divide the global font scale
// by the same amount to get super crisp font rendering.
return fontSize * hex::ImHexApi::System::getBackingScaleFactor();
}
private:
ImFontAtlas* m_fontAtlas;
std::vector<std::pair<bool, float>> m_fontSizes;
ImFontConfig m_config;
ImVector<ImWchar> m_glyphRange;
std::list<std::vector<u8>> m_fontData;
};
std::fs::path findCustomFontPath() {
// Find the custom font file specified in the settings
auto fontFile = ContentRegistry::Settings::read<std::fs::path>("hex.builtin.setting.font", "hex.builtin.setting.font.font_path", "");
if (!fontFile.empty()) {
if (!wolv::io::fs::exists(fontFile) || !wolv::io::fs::isRegularFile(fontFile)) {
log::warn("Custom font file {} not found! Falling back to default font.", wolv::util::toUTF8String(fontFile));
fontFile.clear();
}
log::info("Loading custom font from {}", wolv::util::toUTF8String(fontFile));
}
// If no custom font has been specified, search for a file called "font.ttf" in one of the resource folders
if (fontFile.empty()) {
for (const auto &dir : paths::Resources.read()) {
auto path = dir / "font.ttf";
if (wolv::io::fs::exists(path)) {
log::info("Loading custom font from {}", wolv::util::toUTF8String(path));
fontFile = path;
break;
}
}
}
return fontFile;
}
float getFontSize() {
const auto pixelPerfectFont = ContentRegistry::Settings::read<bool>("hex.builtin.setting.font", "hex.builtin.setting.font.pixel_perfect_default_font", true);
if (pixelPerfectFont)
return 13.0F * ImHexApi::System::getGlobalScale();
else
return float(ContentRegistry::Settings::read<int>("hex.builtin.setting.font", "hex.builtin.setting.font.font_size", 13)) * ImHexApi::System::getGlobalScale();
}
}
bool buildFontAtlasImpl(bool loadUnicodeCharacters) {
static FontAtlas fontAtlas;
fontAtlas.reset();
// Check if Unicode support is enabled in the settings and that the user doesn't use the No GPU version on Windows // Check if Unicode support is enabled in the settings and that the user doesn't use the No GPU version on Windows
// The Mesa3D software renderer on Windows identifies itself as "VMware, Inc." // The Mesa3D software renderer on Windows identifies itself as "VMware, Inc."
bool shouldLoadUnicode = bool shouldLoadUnicode =
ContentRegistry::Settings::read<bool>("hex.builtin.setting.font", "hex.builtin.setting.font.load_all_unicode_chars", false) && ContentRegistry::Settings::read<bool>("hex.fonts.setting.font", "hex.builtin.fonts.font.load_all_unicode_chars", false) &&
ImHexApi::System::getGPUVendor() != "VMware, Inc."; ImHexApi::System::getGPUVendor() != "VMware, Inc.";
if (!loadUnicodeCharacters) if (!loadUnicodeCharacters)
shouldLoadUnicode = false; shouldLoadUnicode = false;
fontAtlas.enableUnicodeCharacters(shouldLoadUnicode); fontAtlas->enableUnicodeCharacters(shouldLoadUnicode);
auto pixelPerfectFont = ContentRegistry::Settings::read<bool>("hex.builtin.setting.font", "hex.builtin.setting.font.pixel_perfect_default_font", true);
std::fs::path customFontPath;
// If a custom font is set in the settings, load the rest of the settings as well // If a custom font is set in the settings, load the rest of the settings as well
if (!pixelPerfectFont) { if (!pixelPerfectFont) {
fontAtlas.setBold(ContentRegistry::Settings::read<bool>("hex.builtin.setting.font", "hex.builtin.setting.font.font_bold", false)); fontAtlas->setBold(bold);
fontAtlas.setItalic(ContentRegistry::Settings::read<bool>("hex.builtin.setting.font", "hex.builtin.setting.font.font_italic", false)); fontAtlas->setItalic(italic);
fontAtlas.setAntiAliasing(ContentRegistry::Settings::read<bool>("hex.builtin.setting.font", "hex.builtin.setting.font.font_antialias", true)); fontAtlas->setAntiAliasing(antialias);
} else {
customFontPath = findCustomFontPath(); fontPath.clear();
} }
ImHexApi::Fonts::impl::setFontSize(getFontSize());
const auto fontSize = ImHexApi::Fonts::getFontSize();
// Try to load the custom font if one was set // Try to load the custom font if one was set
std::optional<Font> defaultFont; std::optional<Font> defaultFont;
if (!customFontPath.empty()) { if (!fontPath.empty()) {
defaultFont = fontAtlas.addFontFromFile(customFontPath, fontSize, true, ImVec2()); defaultFont = fontAtlas->addFontFromFile(fontPath, fontSize, true, ImVec2());
if (!fontAtlas.build()) { if (!fontAtlas->build()) {
log::error("Failed to load custom font '{}'! Falling back to default font", wolv::util::toUTF8String(customFontPath)); log::error("Failed to load custom font '{}'! Falling back to default font", wolv::util::toUTF8String(fontPath));
defaultFont.reset(); defaultFont.reset();
} }
} }
// If there's no custom font set, or it failed to load, fall back to the default font // If there's no custom font set, or it failed to load, fall back to the default font
if (!defaultFont.has_value()) { if (!defaultFont.has_value()) {
if (pixelPerfectFont) if (pixelPerfectFont) {
defaultFont = fontAtlas.addDefaultFont(); defaultFont = fontAtlas->addDefaultFont();
else fontSize = std::floor(fontAtlas->getAdjustedFontSize(ImHexApi::System::getGlobalScale() * 13.0F));
defaultFont = fontAtlas.addFontFromRomFs("fonts/JetBrainsMono.ttf", fontSize, true, ImVec2()); } else
defaultFont = fontAtlas->addFontFromRomFs("fonts/JetBrainsMono.ttf", fontSize, true, ImVec2());
if (!fontAtlas.build()) { if (!fontAtlas->build()) {
log::fatal("Failed to load default font!"); log::fatal("Failed to load default font!");
return false; return false;
} }
@ -345,48 +85,25 @@ namespace hex::fonts {
glyphRanges.push_back(glyphRange); glyphRanges.push_back(glyphRange);
// Calculate the glyph offset for the font // Calculate the glyph offset for the font
ImVec2 offset = { font.offset.x, font.offset.y - (defaultFont->getDescent() - fontAtlas.calculateFontDescend(font, fontSize)) }; const ImVec2 offset = { font.offset.x, font.offset.y - (defaultFont->getDescent() - fontAtlas->calculateFontDescend(font, fontSize)) };
// Load the font // Load the font
fontAtlas.addFontFromMemory(font.fontData, font.defaultSize.value_or(fontSize), !font.defaultSize.has_value(), offset, glyphRanges.back()); fontAtlas->addFontFromMemory(font.fontData, font.defaultSize.value_or(fontSize), !font.defaultSize.has_value(), offset, glyphRanges.back());
} }
} }
EventDPIChanged::subscribe([](float, float newScaling) {
fontAtlas.updateFontScaling(newScaling);
if (fontAtlas.build()) {
ImGui_ImplOpenGL3_DestroyFontsTexture();
ImGui_ImplOpenGL3_CreateFontsTexture();
ImHexApi::Fonts::impl::setFontAtlas(fontAtlas.getAtlas());
}
});
// Build the font atlas // Build the font atlas
const bool result = fontAtlas.build(); if (fontAtlas->build()) {
if (result) {
// Set the font atlas if the build was successful
ImHexApi::Fonts::impl::setFontAtlas(fontAtlas.getAtlas());
return true; return true;
} }
// If the build wasn't successful and Unicode characters are enabled, try again without them // If the build wasn't successful and Unicode characters are enabled, try again without them
// If they were disabled already, something went wrong, and we can't recover from it // If they were disabled already, something went wrong, and we can't recover from it
if (!shouldLoadUnicode) { if (!shouldLoadUnicode) {
// Reset Unicode loading and scaling factor settings back to default to make sure the user can still use the application
ContentRegistry::Settings::write<bool>("hex.builtin.setting.font", "hex.builtin.setting.font.load_all_unicode_chars", false);
ContentRegistry::Settings::write<float>("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling_factor", 1.0F);
ImHexApi::System::impl::setGlobalScale(1.0F);
return false; return false;
} else { } else {
return buildFontAtlasImpl(false); return buildFontAtlas(fontAtlas, fontPath, pixelPerfectFont, fontSize, false, bold, italic, antialias);
} }
} }
bool buildFontAtlas() {
return buildFontAtlasImpl(true);
}
} }

View File

@ -0,0 +1,206 @@
#include <font_settings.hpp>
#include <hex/api/content_registry.hpp>
#include <wolv/utils/string.hpp>
#include <hex/helpers/utils.hpp>
#include <imgui.h>
namespace hex::fonts {
constexpr static auto PixelPerfectName = "Pixel-Perfect Default Font (Proggy Clean)";
constexpr static auto SmoothName = "Smooth Default Font (JetbrainsMono)";
constexpr static auto CustomName = "Custom Font";
bool FontFilePicker::draw(const std::string &name) {
bool changed = false;
const bool pixelPerfectFont = isPixelPerfectFontSelected();
bool customFont = updateSelectedFontName();
if (ImGui::BeginCombo(name.c_str(), m_selectedFontName.c_str())) {
if (ImGui::Selectable(PixelPerfectName, m_path.empty() && pixelPerfectFont)) {
m_path.clear();
m_pixelPerfectFont = true;
changed = true;
}
if (ImGui::Selectable(SmoothName, m_path.empty() && !pixelPerfectFont)) {
m_path.clear();
m_pixelPerfectFont = false;
changed = true;
}
if (ImGui::Selectable(CustomName, customFont)) {
changed = fs::openFileBrowser(fs::DialogMode::Open, { { "TTF Font", "ttf" }, { "OTF Font", "otf" } }, [this](const std::fs::path &path) {
m_path = path;
m_pixelPerfectFont = false;
});
}
for (const auto &[path, fontName] : hex::getFonts()) {
if (ImGui::Selectable(limitStringLength(fontName, 50).c_str(), m_path == path)) {
m_path = path;
m_pixelPerfectFont = false;
changed = true;
}
ImGui::SetItemTooltip("%s", fontName.c_str());
}
ImGui::EndCombo();
}
return changed;
}
bool FontFilePicker::isPixelPerfectFontSelected() const {
return m_pixelPerfectFont;
}
const std::string& FontFilePicker::getSelectedFontName() const {
return m_selectedFontName;
}
void FontFilePicker::load(const nlohmann::json& data) {
FilePicker::load(data["path"]);
m_pixelPerfectFont = data["pixel_perfect_font"];
updateSelectedFontName();
}
nlohmann::json FontFilePicker::store() {
nlohmann::json data = nlohmann::json::object();
data["path"] = FilePicker::store();
data["pixel_perfect_font"] = m_pixelPerfectFont;
return data;
}
bool FontFilePicker::updateSelectedFontName() {
const auto &fonts = hex::getFonts();
bool customFont = false;
const bool pixelPerfectFont = isPixelPerfectFontSelected();
if (m_path.empty() && pixelPerfectFont) {
m_selectedFontName = PixelPerfectName;
} else if (m_path.empty() && !pixelPerfectFont) {
m_selectedFontName = SmoothName;
} else if (fonts.contains(m_path)) {
m_selectedFontName = fonts.at(m_path);
} else {
m_selectedFontName = wolv::util::toUTF8String(m_path.filename());
customFont = true;
}
return customFont;
}
static float pixelsToPoints(float pixels) {
return pixels * (72_scaled / 96.0F);
}
static float pointsToPixels(float points) {
return points / (72_scaled / 96.0F);
}
bool SliderPoints::draw(const std::string &name) {
float value = pixelsToPoints(m_value);
float min = pixelsToPoints(m_min);
float max = pixelsToPoints(m_max);
auto changed = ImGui::SliderFloat(name.c_str(), &value, min, max, "%.0f pt");
m_value = pointsToPixels(value);
return changed;
}
bool FontSelector::draw(const std::string &name) {
ImGui::PushID(name.c_str());
ON_SCOPE_EXIT { ImGui::PopID(); };
if (ImGui::Button(m_fontFilePicker.getSelectedFontName().c_str(), ImVec2(300_scaled, 0))) {
ImGui::OpenPopup("Fonts");
}
ImGui::SameLine();
ImGui::TextUnformatted(name.c_str());
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
return drawPopup();
}
nlohmann::json FontSelector::store() {
nlohmann::json json = nlohmann::json::object();
json["font_file"] = m_fontFilePicker.store();
json["font_size"] = m_fontSize.store();
json["bold"] = m_bold.store();
json["italic"] = m_italic.store();
json["antialiased"] = m_antiAliased.store();
return json;
}
void FontSelector::load(const nlohmann::json& data) {
m_fontFilePicker.load(data["font_file"]);
m_fontSize.load(data["font_size"]);
m_bold.load(data["bold"]);
m_italic.load(data["italic"]);
m_antiAliased.load(data["antialiased"]);
}
bool FontSelector::drawPopup() {
bool changed = false;
if (ImGui::BeginPopup("Fonts")) {
m_fontFilePicker.draw("hex.fonts.setting.font.custom_font"_lang);
ImGui::BeginDisabled(m_fontFilePicker.isPixelPerfectFontSelected());
{
m_fontSize.draw("hex.fonts.setting.font.font_size"_lang);
m_bold.draw("hex.fonts.setting.font.font_bold"_lang);
m_italic.draw("hex.fonts.setting.font.font_italic"_lang);
m_antiAliased.draw("hex.fonts.setting.font.font_antialias"_lang);
}
ImGui::EndDisabled();
ImGui::NewLine();
if (ImGui::Button("hex.ui.common.apply"_lang))
changed = true;
ImGui::EndPopup();
}
return changed;
}
[[nodiscard]] const std::fs::path& FontSelector::getFontPath() const {
return m_fontFilePicker.getPath();
}
[[nodiscard]] bool FontSelector::isPixelPerfectFont() const {
return m_fontFilePicker.isPixelPerfectFontSelected();
}
[[nodiscard]] float FontSelector::getFontSize() const {
return m_fontSize.getValue();
}
[[nodiscard]] bool FontSelector::isBold() const {
return m_bold.isChecked();
}
[[nodiscard]] bool FontSelector::isItalic() const {
return m_italic.isChecked();
}
[[nodiscard]] bool FontSelector::isAntiAliased() const {
return m_antiAliased.isChecked();
}
ContentRegistry::Settings::Widgets::Widget::Interface& addFontSettingsWidget(UnlocalizedString name) {
return ContentRegistry::Settings::add<FontSelector>("hex.fonts.setting.font", "hex.fonts.setting.font.custom_font", std::move(name));
}
}

View File

@ -4,16 +4,109 @@
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <romfs/romfs.hpp> #include <romfs/romfs.hpp>
#include <font_atlas.hpp>
#include <font_settings.hpp>
#include <imgui_impl_opengl3.h>
#include <fonts/fonts.hpp>
namespace hex::fonts { namespace hex::fonts {
void registerFonts(); void registerFonts();
bool buildFontAtlas(); bool buildFontAtlas(FontAtlas *fontAtlas, std::fs::path fontPath, bool pixelPerfectFont, float fontSize, bool loadUnicodeCharacters, bool bold, bool italic, bool antialias);
static AutoReset<std::map<ImFont*, FontAtlas>> s_fontAtlases;
void loadFont(const ContentRegistry::Settings::Widgets::Widget &widget, const UnlocalizedString &name, ImFont **font) {
const auto &settings = static_cast<const FontSelector&>(widget);
FontAtlas atlas;
const bool atlasBuilt = buildFontAtlas(
&atlas,
settings.getFontPath(),
settings.isPixelPerfectFont(),
settings.getFontSize(),
true,
settings.isBold(),
settings.isItalic(),
settings.isAntiAliased()
);
if (!atlasBuilt) {
buildFontAtlas(
&atlas,
"",
false,
settings.getFontSize(),
false,
settings.isBold(),
settings.isItalic(),
settings.isAntiAliased()
);
log::error("Failed to load font {}! Reverting back to default font!", name.get());
}
if (*font != nullptr) {
EventDPIChanged::unsubscribe(*font);
}
*font = atlas.getAtlas()->Fonts[0];
s_fontAtlases->insert_or_assign(*font, std::move(atlas));
(*s_fontAtlases)[*font] = std::move(atlas);
EventDPIChanged::subscribe(*font, [&atlas, font](float, float newScaling) {
atlas.updateFontScaling(newScaling);
if (atlas.build()) {
auto &io = ImGui::GetIO();
auto prevFont = io.Fonts;
{
io.Fonts = atlas.getAtlas();
ImGui_ImplOpenGL3_DestroyFontsTexture();
ImGui_ImplOpenGL3_CreateFontsTexture();
io.Fonts = prevFont;
}
*font = atlas.getAtlas()->Fonts[0];
}
});
}
bool setupFonts() {
ContentRegistry::Settings::add<ContentRegistry::Settings::Widgets::Checkbox>("hex.fonts.setting.font", "hex.fonts.setting.font.glyphs", "hex.fonts.setting.font.load_all_unicode_chars", false).requiresRestart();
for (auto &[name, font] : ImHexApi::Fonts::impl::getFontDefinitions()) {
auto &widget = addFontSettingsWidget(name)
.setChangedCallback([name, &font, firstLoad = true](auto &widget) mutable {
if (firstLoad) {
firstLoad = false;
return;
}
loadFont(widget, name, &font);
});
loadFont(widget.getWidget(), name, &font);
}
return true;
}
} }
IMHEX_LIBRARY_SETUP("Fonts") { IMHEX_LIBRARY_SETUP("Fonts") {
hex::log::debug("Using romfs: '{}'", romfs::name()); hex::log::debug("Using romfs: '{}'", romfs::name());
for (auto &path : romfs::list("lang"))
hex::ContentRegistry::Language::addLocalization(nlohmann::json::parse(romfs::get(path).string()));
hex::ImHexApi::System::addStartupTask("Loading fonts", true, hex::fonts::buildFontAtlas); hex::ImHexApi::Fonts::registerFont("hex.fonts.font.default");
hex::ImHexApi::Fonts::registerFont("hex.fonts.font.hex_editor");
hex::ImHexApi::Fonts::registerFont("hex.fonts.font.code_editor");
hex::ImHexApi::System::addStartupTask("Loading fonts", true, hex::fonts::setupFonts);
hex::fonts::registerFonts(); hex::fonts::registerFonts();
} }

View File

@ -7,6 +7,7 @@
"hex.ui.common.add": "Add", "hex.ui.common.add": "Add",
"hex.ui.common.address": "Address", "hex.ui.common.address": "Address",
"hex.ui.common.allow": "Allow", "hex.ui.common.allow": "Allow",
"hex.ui.common.apply": "Apply",
"hex.ui.common.begin": "Begin", "hex.ui.common.begin": "Begin",
"hex.ui.common.big": "Big", "hex.ui.common.big": "Big",
"hex.ui.common.big_endian": "Big Endian", "hex.ui.common.big_endian": "Big Endian",

View File

@ -12,6 +12,7 @@
#include <hex/providers/buffered_reader.hpp> #include <hex/providers/buffered_reader.hpp>
#include <algorithm> #include <algorithm>
#include <fonts/fonts.hpp>
namespace hex::ui { namespace hex::ui {
@ -1280,7 +1281,9 @@ namespace hex::ui {
if (tableSize.y <= 0) if (tableSize.y <= 0)
tableSize.y = height; tableSize.y = height;
ImGui::PushFont(fonts::HexEditor());
this->drawEditor(tableSize); this->drawEditor(tableSize);
ImGui::PopFont();
if (tableSize.y > 0) if (tableSize.y > 0)
this->drawFooter(footerSize); this->drawFooter(footerSize);

View File

@ -22,8 +22,6 @@ namespace hex::plugin::visualizers {
auto lastMonthDay = std::chrono::year_month_day_last(date.year(), date.month() / std::chrono::last); auto lastMonthDay = std::chrono::year_month_day_last(date.year(), date.month() / std::chrono::last);
auto firstWeekDay = std::chrono::weekday(std::chrono::year_month_day(date.year(), date.month(), std::chrono::day(1))); auto firstWeekDay = std::chrono::weekday(std::chrono::year_month_day(date.year(), date.month(), std::chrono::day(1)));
const auto scale = 1_scaled * (ImHexApi::Fonts::getFontSize() / ImHexApi::Fonts::DefaultFontSize);
// Draw calendar // Draw calendar
if (ImGui::BeginTable("##month_table", 2)) { if (ImGui::BeginTable("##month_table", 2)) {
ImGui::TableNextRow(); ImGui::TableNextRow();
@ -32,7 +30,7 @@ namespace hex::plugin::visualizers {
// Draw centered month name and year // Draw centered month name and year
ImGuiExt::TextFormattedCenteredHorizontal("{:%B %Y}", tm); ImGuiExt::TextFormattedCenteredHorizontal("{:%B %Y}", tm);
if (ImGui::BeginTable("##days_table", 7, ImGuiTableFlags_Borders | ImGuiTableFlags_NoHostExtendX, ImVec2(160, 120) * scale)) { if (ImGui::BeginTable("##days_table", 7, ImGuiTableFlags_Borders | ImGuiTableFlags_NoHostExtendX, scaled(ImVec2(160, 120)))) {
constexpr static auto ColumnFlags = ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoReorder | ImGuiTableColumnFlags_NoHide; constexpr static auto ColumnFlags = ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoReorder | ImGuiTableColumnFlags_NoHide;
ImGui::TableSetupColumn("M", ColumnFlags); ImGui::TableSetupColumn("M", ColumnFlags);
ImGui::TableSetupColumn("T", ColumnFlags); ImGui::TableSetupColumn("T", ColumnFlags);
@ -68,7 +66,7 @@ namespace hex::plugin::visualizers {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
// Draw analog clock // Draw analog clock
const auto size = ImVec2(120, 120) * scale; const auto size = scaled(ImVec2(120, 120));
if (ImGui::BeginChild("##clock", size + ImVec2(0, ImGui::GetTextLineHeightWithSpacing()))) { if (ImGui::BeginChild("##clock", size + ImVec2(0, ImGui::GetTextLineHeightWithSpacing()))) {
// Draw centered digital hour, minute and seconds // Draw centered digital hour, minute and seconds
ImGuiExt::TextFormattedCenteredHorizontal("{:%H:%M:%S}", tm); ImGuiExt::TextFormattedCenteredHorizontal("{:%H:%M:%S}", tm);