parent
3129d6e8fd
commit
117eb1e2a7
@ -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();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 ¤tFont = 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;
|
||||||
|
@ -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",
|
||||||
|
@ -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",
|
||||||
|
@ -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": "",
|
||||||
|
@ -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",
|
||||||
|
@ -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": "",
|
||||||
|
@ -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": "",
|
||||||
|
@ -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": "",
|
||||||
|
@ -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": "",
|
||||||
|
@ -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}秒",
|
||||||
|
@ -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": "",
|
||||||
|
@ -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");
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
253
plugins/fonts/include/font_atlas.hpp
Normal file
253
plugins/fonts/include/font_atlas.hpp
Normal 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
59
plugins/fonts/include/font_settings.hpp
Normal file
59
plugins/fonts/include/font_settings.hpp
Normal 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);
|
||||||
|
|
||||||
|
}
|
11
plugins/fonts/include/fonts/fonts.hpp
Normal file
11
plugins/fonts/include/fonts/fonts.hpp
Normal 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"); };
|
||||||
|
|
||||||
|
}
|
18
plugins/fonts/romfs/lang/de_DE.json
Normal file
18
plugins/fonts/romfs/lang/de_DE.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
21
plugins/fonts/romfs/lang/en_US.json
Normal file
21
plugins/fonts/romfs/lang/en_US.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
17
plugins/fonts/romfs/lang/es_ES.json
Normal file
17
plugins/fonts/romfs/lang/es_ES.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
17
plugins/fonts/romfs/lang/hu_HU.json
Normal file
17
plugins/fonts/romfs/lang/hu_HU.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
17
plugins/fonts/romfs/lang/it_IT.json
Normal file
17
plugins/fonts/romfs/lang/it_IT.json
Normal 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": ""
|
||||||
|
}
|
||||||
|
}
|
17
plugins/fonts/romfs/lang/ja_JP.json
Normal file
17
plugins/fonts/romfs/lang/ja_JP.json
Normal 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": ""
|
||||||
|
}
|
||||||
|
}
|
17
plugins/fonts/romfs/lang/ko_KR.json
Normal file
17
plugins/fonts/romfs/lang/ko_KR.json
Normal 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": "모든 유니코드 문자 불러오기"
|
||||||
|
}
|
||||||
|
}
|
17
plugins/fonts/romfs/lang/pt_BR.json
Normal file
17
plugins/fonts/romfs/lang/pt_BR.json
Normal 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": ""
|
||||||
|
}
|
||||||
|
}
|
17
plugins/fonts/romfs/lang/zh_CN.json
Normal file
17
plugins/fonts/romfs/lang/zh_CN.json
Normal 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 字符"
|
||||||
|
}
|
||||||
|
}
|
18
plugins/fonts/romfs/lang/zh_TW.json
Normal file
18
plugins/fonts/romfs/lang/zh_TW.json
Normal 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 字元"
|
||||||
|
}
|
||||||
|
}
|
@ -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:
|
|
||||||
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() {
|
fontAtlas->reset();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
206
plugins/fonts/source/font_settings.cpp
Normal file
206
plugins/fonts/source/font_settings.cpp
Normal 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
}
|
}
|
@ -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",
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user