diff --git a/imgui.h b/imgui.h index add91e829af3..e7ed8dae9bbd 100644 --- a/imgui.h +++ b/imgui.h @@ -4087,6 +4087,9 @@ struct ImFont #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS float Scale; // 4 // in // Legacy base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() #endif + // Optional pair kerning. Extra advance in pixels at 'size'. NULL = advance only (no extra cost). + float (*KerningFn)(ImFont* font, ImWchar left, ImWchar right, float size, void* user); + void* KerningUserData; // Methods IMGUI_API ImFont(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 162f00193ad8..9d5c5f0c7a0d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -5696,6 +5696,7 @@ ImVec2 ImFontCalcTextSizeEx(ImFont* font, float size, float max_width, float wra ImVec2 text_size = ImVec2(0, 0); float line_width = 0.0f; + ImWchar prev_c = 0; const bool word_wrap_enabled = (wrap_width > 0.0f); const char* word_wrap_eol = NULL; @@ -5716,6 +5717,7 @@ ImVec2 ImFontCalcTextSizeEx(ImFont* font, float size, float max_width, float wra text_size.x = line_width; text_size.y += line_height; line_width = 0.0f; + prev_c = 0; s = ImTextCalcWordWrapNextLineStart(s, text_end, flags); // Wrapping skips upcoming blanks if (flags & ImDrawTextFlags_StopOnNewLine) break; @@ -5737,6 +5739,7 @@ ImVec2 ImFontCalcTextSizeEx(ImFont* font, float size, float max_width, float wra text_size.x = ImMax(text_size.x, line_width); text_size.y += line_height; line_width = 0.0f; + prev_c = 0; if (flags & ImDrawTextFlags_StopOnNewLine) break; continue; @@ -5749,6 +5752,8 @@ ImVec2 ImFontCalcTextSizeEx(ImFont* font, float size, float max_width, float wra if (char_width < 0.0f) char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c); char_width *= scale; + if (prev_c && font->KerningFn) + char_width += font->KerningFn(font, prev_c, (ImWchar)c, size, font->KerningUserData); if (line_width + char_width >= max_width) { @@ -5757,6 +5762,7 @@ ImVec2 ImFontCalcTextSizeEx(ImFont* font, float size, float max_width, float wra } line_width += char_width; + prev_c = (ImWchar)c; } if (text_size.x < line_width) @@ -5900,6 +5906,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im const ImU32 col_untinted = col | ~IM_COL32_A_MASK; const char* word_wrap_eol = NULL; + ImWchar prev_c = 0; while (s < text_end) { @@ -5913,6 +5920,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im { x = origin_x; y += line_height; + prev_c = 0; if (y > clip_rect.w) break; // break out of main loop word_wrap_eol = NULL; @@ -5934,6 +5942,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im { x = origin_x; y += line_height; + prev_c = 0; if (y > clip_rect.w) break; // break out of main loop continue; @@ -5946,6 +5955,8 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im //if (glyph == NULL) // continue; + if (prev_c && KerningFn) + x += KerningFn(this, prev_c, (ImWchar)c, size, KerningUserData); float char_width = glyph->AdvanceX * scale; if (glyph->Visible) { @@ -5988,6 +5999,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im if (y1 >= y2) { x += char_width; + prev_c = (ImWchar)c; continue; } } @@ -6010,6 +6022,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im } } x += char_width; + prev_c = (ImWchar)c; } // Edge case: calling RenderText() with unloaded glyphs triggering texture change. It doesn't happen via ImGui:: calls because CalcTextSize() is always used.