From c58ff1728961939ac909f2d667439e57e1612158 Mon Sep 17 00:00:00 2001 From: Daniel Dada Date: Wed, 17 Dec 2025 03:06:24 +0300 Subject: [PATCH] feat: font selector --- src/gui/font_loader.cpp | 98 +++++++++++++++++++++++++++++++++++++ src/gui/font_loader.hpp | 3 +- src/gui/settings_window.cpp | 35 +++++++++++-- src/gui/settings_window.hpp | 4 ++ 4 files changed, 136 insertions(+), 4 deletions(-) diff --git a/src/gui/font_loader.cpp b/src/gui/font_loader.cpp index bc8782a..fa5b780 100644 --- a/src/gui/font_loader.cpp +++ b/src/gui/font_loader.cpp @@ -226,3 +226,101 @@ void font_loader::pop_font() { ImGui::PopFont(); } + +std::vector font_loader::get_system_fonts() +{ + std::vector fonts; + +#if defined(_WIN32) + auto enumerate_registry_fonts = [&fonts](HKEY root_key, const char* subkey) + { + HKEY hKey; + if (RegOpenKeyExA(root_key, subkey, 0, KEY_READ, &hKey) != ERROR_SUCCESS) + return; + + char value_name[512]; + DWORD value_name_size; + DWORD index = 0; + + while (true) + { + value_name_size = sizeof(value_name); + LONG result = RegEnumValueA(hKey, index++, value_name, &value_name_size, nullptr, nullptr, nullptr, nullptr); + + if (result != ERROR_SUCCESS) + break; + + std::string font_name = value_name; + size_t pos = font_name.find(" ("); + if (pos != std::string::npos) + font_name = font_name.substr(0, pos); + + if (std::find(fonts.begin(), fonts.end(), font_name) == fonts.end()) + fonts.push_back(font_name); + } + + RegCloseKey(hKey); + }; + + enumerate_registry_fonts(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"); + enumerate_registry_fonts(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"); + +#elif defined(__APPLE__) + CTFontCollectionRef collection = CTFontCollectionCreateFromAvailableFonts(nullptr); + if (collection) + { + CFArrayRef fontDescriptors = CTFontCollectionCreateMatchingFontDescriptors(collection); + CFRelease(collection); + + if (fontDescriptors) + { + CFIndex count = CFArrayGetCount(fontDescriptors); + for (CFIndex i = 0; i < count; i++) + { + CTFontDescriptorRef descriptor = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fontDescriptors, i); + CFStringRef fontName = (CFStringRef)CTFontDescriptorCopyAttribute(descriptor, kCTFontDisplayNameAttribute); + + if (fontName) + { + char buffer[256]; + if (CFStringGetCString(fontName, buffer, sizeof(buffer), kCFStringEncodingUTF8)) + { + std::string font_name = buffer; + if (std::find(fonts.begin(), fonts.end(), font_name) == fonts.end()) + fonts.push_back(font_name); + } + CFRelease(fontName); + } + } + CFRelease(fontDescriptors); + } + } + +#else + FcInit(); + FcPattern* pattern = FcPatternCreate(); + FcObjectSet* os = FcObjectSetBuild(FC_FAMILY, nullptr); + FcFontSet* fs = FcFontList(nullptr, pattern, os); + + if (fs) + { + for (int i = 0; i < fs->nfont; i++) + { + FcChar8* family = nullptr; + if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch) + { + std::string font_name = reinterpret_cast(family); + if (std::find(fonts.begin(), fonts.end(), font_name) == fonts.end()) + fonts.push_back(font_name); + } + } + FcFontSetDestroy(fs); + } + + FcObjectSetDestroy(os); + FcPatternDestroy(pattern); +#endif + + std::sort(fonts.begin(), fonts.end()); + return fonts; +} diff --git a/src/gui/font_loader.hpp b/src/gui/font_loader.hpp index 3559f8e..326c1e4 100644 --- a/src/gui/font_loader.hpp +++ b/src/gui/font_loader.hpp @@ -10,10 +10,11 @@ class font_loader public: font_loader() = default; - // Loads system font by name and returns an ImFont* or nullptr. ImFont* load_font(const char* font_name, float size_px); void push_default_font(); void pop_font(); + + std::vector get_system_fonts(); private: std::string find_font_path(const char* font_name); diff --git a/src/gui/settings_window.cpp b/src/gui/settings_window.cpp index 7e4a8c7..698dade 100644 --- a/src/gui/settings_window.cpp +++ b/src/gui/settings_window.cpp @@ -6,11 +6,15 @@ #include settings_window::settings_window() - : m_font_size(14) + : m_font_size(14), m_selected_font_idx(0) { m_default_theme[0] = '\0'; m_palettes_path[0] = '\0'; m_font[0] = '\0'; + + font_loader loader; + m_available_fonts = loader.get_system_fonts(); + load_settings(); } @@ -51,10 +55,25 @@ void settings_window::render() ImGui::Text("Font:"); ImGui::SameLine(); ImGui::SetNextItemWidth(300.0f); - ImGui::InputText("##font", m_font, sizeof(m_font)); + if (ImGui::BeginCombo("##font", m_font)) + { + for (int i = 0; i < static_cast(m_available_fonts.size()); i++) + { + bool is_selected = (i == m_selected_font_idx); + if (ImGui::Selectable(m_available_fonts[i].c_str(), is_selected)) + { + m_selected_font_idx = i; + strncpy(m_font, m_available_fonts[i].c_str(), sizeof(m_font) - 1); + m_font[sizeof(m_font) - 1] = '\0'; + } + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Font"); + ImGui::SetTooltip("Select font for the application"); } ImGui::Spacing(); @@ -134,6 +153,16 @@ void settings_window::load_settings() strncpy(m_font, font.c_str(), sizeof(m_font) - 1); m_font[sizeof(m_font) - 1] = '\0'; + m_selected_font_idx = 0; + for (int i = 0; i < static_cast(m_available_fonts.size()); i++) + { + if (m_available_fonts[i] == font) + { + m_selected_font_idx = i; + break; + } + } + m_font_size = cfg.font_size(); m_error_message = ""; diff --git a/src/gui/settings_window.hpp b/src/gui/settings_window.hpp index bb73c8a..48ee2d8 100644 --- a/src/gui/settings_window.hpp +++ b/src/gui/settings_window.hpp @@ -2,6 +2,7 @@ #define CLRSYNC_GUI_SETTINGS_WINDOW_HPP #include +#include class settings_window { @@ -24,6 +25,9 @@ private: char m_font[128]; int m_font_size; + std::vector m_available_fonts; + int m_selected_font_idx; + std::string m_error_message; };