diff --git a/CMakeLists.txt b/CMakeLists.txt index 8665e4f..ab59981 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(kte) include(GNUInstallDirs) set(CMAKE_CXX_STANDARD 17) -set(KTE_VERSION "1.3.0") +set(KTE_VERSION "1.3.1") # Default to terminal-only build to avoid SDL/OpenGL dependency by default. # Enable with -DBUILD_GUI=ON when SDL2/OpenGL/Freetype are available. diff --git a/Command.cc b/Command.cc index 6f543d5..d8e8923 100644 --- a/Command.cc +++ b/Command.cc @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "Command.h" @@ -18,6 +19,8 @@ #include "syntax/CppHighlighter.h" #ifdef KTE_BUILD_GUI #include "GUITheme.h" +#include "fonts/FontRegistry.h" +#include "imgui.h" #endif @@ -984,6 +987,117 @@ cmd_theme_set_by_name(CommandContext &ctx) #endif +// Font set by name (GUI) +#ifdef KTE_BUILD_GUI +static bool +cmd_font_set_by_name(const CommandContext &ctx) +{ + using namespace kte::Fonts; + std::string name = ctx.arg; + // trim + auto ltrim = [](std::string &s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { + return !std::isspace(ch); + })); + }; + auto rtrim = [](std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { + return !std::isspace(ch); + }).base(), s.end()); + }; + ltrim(name); + rtrim(name); + std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) { + return (char) std::tolower(c); + }); + if (name.empty()) { + ctx.editor.SetStatus("font: missing name"); + return true; + } + + auto ® = FontRegistry::Instance(); + if (!reg.HasFont(name)) { + ctx.editor.SetStatus("font: unknown name"); + return true; + } + + float size = reg.CurrentFontSize(); + if (size <= 0.0f) { + // Fallback to current ImGui font size if available + size = ImGui::GetFontSize(); + if (size <= 0.0f) + size = 16.0f; + } + reg.RequestLoadFont(name, size); + ctx.editor.SetStatus(std::string("Font: ") + name + " (" + std::to_string((int) std::round(size)) + ")"); + return true; +} +#else +static bool +cmd_font_set_by_name(CommandContext &ctx) +{ + (void) ctx; + return true; +} +#endif + + +// Font size set (GUI) +#ifdef KTE_BUILD_GUI +static bool +cmd_font_set_size(const CommandContext &ctx) +{ + using namespace kte::Fonts; + std::string a = ctx.arg; + auto ltrim = [](std::string &s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { + return !std::isspace(ch); + })); + }; + auto rtrim = [](std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { + return !std::isspace(ch); + }).base(), s.end()); + }; + ltrim(a); + rtrim(a); + if (a.empty()) { + ctx.editor.SetStatus("font-size: missing value"); + return true; + } + char *endp = nullptr; + float size = strtof(a.c_str(), &endp); + if (endp == a.c_str() || !std::isfinite(size)) { + ctx.editor.SetStatus("font-size: expected number"); + return true; + } + // Clamp to a reasonable range + if (size < 6.0f) + size = 6.0f; + if (size > 96.0f) + size = 96.0f; + + auto ® = FontRegistry::Instance(); + std::string name = reg.CurrentFontName(); + if (name.empty()) + name = "default"; + if (!reg.HasFont(name)) + name = "default"; + + reg.RequestLoadFont(name, size); + ctx.editor.SetStatus(std::string("Font size: ") + std::to_string((int) std::round(size))); + return true; +} +#else +static bool +cmd_font_set_size(CommandContext &ctx) +{ + (void) ctx; + return true; +} +#endif + + // Background set command (GUI) #ifdef KTE_BUILD_GUI static bool @@ -3781,6 +3895,14 @@ InstallDefaultCommands() CommandRegistry::Register({ CommandId::ThemeSetByName, "theme", "Set GUI theme by name", cmd_theme_set_by_name, true }); + // Font by name (public) + CommandRegistry::Register({ + CommandId::FontSetByName, "font", "Set GUI font by name", cmd_font_set_by_name, true + }); + // Font size (public) + CommandRegistry::Register({ + CommandId::FontSetSize, "font-size", "Set GUI font size (pixels)", cmd_font_set_size, true + }); // Background light/dark (public) CommandRegistry::Register({ CommandId::BackgroundSet, "background", "Set GUI background light|dark", cmd_background_set, true diff --git a/Command.h b/Command.h index dba5cad..0d8f912 100644 --- a/Command.h +++ b/Command.h @@ -97,6 +97,8 @@ enum class CommandId { ThemeSetByName, // Font by name (GUI) FontSetByName, + // Font size (GUI) + FontSetSize, // Background mode (GUI) BackgroundSet, // Syntax highlighting diff --git a/GUIFrontend.cc b/GUIFrontend.cc index ce0ee64..01f69bb 100644 --- a/GUIFrontend.cc +++ b/GUIFrontend.cc @@ -17,6 +17,7 @@ #include "GUIConfig.h" #include "GUITheme.h" #include "fonts/Font.h" // embedded default font (DefaultFont) +#include "fonts/FontRegistry.h" #include "syntax/HighlighterRegistry.h" #include "syntax/NullHighlighter.h" @@ -196,8 +197,19 @@ GUIFrontend::Init(Editor &ed) } #endif - // Initialize GUI font from embedded default (use configured size or compiled default) - LoadGuiFont_(nullptr, (float) cfg.font_size); + // Install embedded fonts into registry and load configured font + kte::Fonts::InstallDefaultFonts(); + // Initialize font atlas using configured font name and size; fallback to embedded default helper + if (!kte::Fonts::FontRegistry::Instance().LoadFont(cfg.font, (float) cfg.font_size)) { + LoadGuiFont_(nullptr, (float) cfg.font_size); + // Record defaults in registry so subsequent size changes have a base + kte::Fonts::FontRegistry::Instance().RequestLoadFont("default", (float) cfg.font_size); + std::string n; + float s = 0.0f; + if (kte::Fonts::FontRegistry::Instance().ConsumePendingFontRequest(n, s)) { + kte::Fonts::FontRegistry::Instance().LoadFont(n, s); + } + } return true; } @@ -226,6 +238,20 @@ GUIFrontend::Step(Editor &ed, bool &running) input_.ProcessSDLEvent(e); } + // Apply pending font change before starting a new frame + { + std::string fname; + float fsize = 0.0f; + if (kte::Fonts::FontRegistry::Instance().ConsumePendingFontRequest(fname, fsize)) { + if (!fname.empty() && fsize > 0.0f) { + kte::Fonts::FontRegistry::Instance().LoadFont(fname, fsize); + // Recreate backend font texture + ImGui_ImplOpenGL3_DestroyFontsTexture(); + ImGui_ImplOpenGL3_CreateFontsTexture(); + } + } + } + // Start a new ImGui frame BEFORE processing commands so dimensions are correct ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplSDL2_NewFrame(window_); diff --git a/GUIInputHandler.cc b/GUIInputHandler.cc index f4802cf..71a69c0 100644 --- a/GUIInputHandler.cc +++ b/GUIInputHandler.cc @@ -573,8 +573,6 @@ GUIInputHandler::ProcessSDLEvent(const SDL_Event &e) if (produced && mi.hasCommand) { // Attach universal-argument count if present, then clear the state if (uarg_active_ &&mi - - . id != CommandId::UArgStatus @@ -582,13 +580,15 @@ GUIInputHandler::ProcessSDLEvent(const SDL_Event &e) { int count = 0; if (!uarg_had_digits_ && !uarg_negative_) { + // No explicit digits: use current value (default 4 or 4^n) count = (uarg_value_ > 0) ? uarg_value_ : 4; } else { count = uarg_value_; if (uarg_negative_) count = -count; } - mi.count = count; + mi.count = count; + // Clear universal-argument state after applying it uarg_active_ = false; uarg_collecting_ = false; uarg_negative_ = false; diff --git a/docs/ke.md b/docs/ke.md index 8e12fbe..50fc2a8 100644 --- a/docs/ke.md +++ b/docs/ke.md @@ -77,5 +77,4 @@ k-command mode can be exited with ESC or C-g. The find operation is an incremental search. The up or left arrow keys will go to the previous result, while the down or right arrow keys -will go to the next result. Unfortunately, the search starts from the -top of the file each time. This is a known bug. +will go to the next result. \ No newline at end of file diff --git a/docs/kge.1 b/docs/kge.1 index c6303bf..e08f8b7 100644 --- a/docs/kge.1 +++ b/docs/kge.1 @@ -252,9 +252,6 @@ Open using the terminal frontend from kge: (project keybinding manual) .br Project homepage: https://github.com/wntrmute/kte -.SH BUGS -Report issues on the project tracker. Some behaviors are inherited from -ke and may evolve over time; see the manual for notes. .SH AUTHORS Kyle (wntrmute) and contributors. .SH COPYRIGHT diff --git a/docs/kte.1 b/docs/kte.1 index 327b7c9..2ad3982 100644 --- a/docs/kte.1 +++ b/docs/kte.1 @@ -279,9 +279,6 @@ Force GUI frontend (if available): (project keybinding manual) .br Project homepage: https://github.com/wntrmute/kte -.SH BUGS -Incremental search currently restarts from the top on each invocation; see -\(lqKnown behavior\(rq in the ke manual. Report issues on the project tracker. .SH AUTHORS Kyle (wntrmute) and contributors. .SH COPYRIGHT diff --git a/fonts/FontRegistry.h b/fonts/FontRegistry.h index f864a7b..ba6c3c5 100644 --- a/fonts/FontRegistry.h +++ b/fonts/FontRegistry.h @@ -39,10 +39,16 @@ public: // Convenience: load a font by name and size - bool LoadFont(const std::string &name, const float size) const + bool LoadFont(const std::string &name, const float size) { if (auto *font = Get(name)) { font->Load(size); + // Track current selection + { + std::lock_guard lock(mutex_); + current_name_ = name; + current_size_ = size; + } return true; } return false; @@ -80,6 +86,21 @@ public: return fonts_.count(name) > 0; } + + // Current font name/size as last successfully loaded via LoadFont() + std::string CurrentFontName() const + { + std::lock_guard lock(mutex_); + return current_name_; + } + + + float CurrentFontSize() const + { + std::lock_guard lock(mutex_); + return current_size_; + } + private: FontRegistry() = default; @@ -90,6 +111,10 @@ private: bool has_pending_ = false; std::string pending_name_; float pending_size_ = 0.0f; + + // Track last applied font + std::string current_name_; + float current_size_ = 0.0f; };