From 23dde40c6fdc7194e42c2cf53c155b418c603762 Mon Sep 17 00:00:00 2001 From: Christian Fillion Date: Mon, 4 Aug 2025 22:56:43 -0400 Subject: [PATCH 1/2] decouple line height from the font size --- imgui.cpp | 37 ++++++------ imgui.h | 1 + imgui_draw.cpp | 7 ++- imgui_internal.h | 3 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 97 ++++++++++++++++++-------------- misc/freetype/imgui_freetype.cpp | 4 +- 7 files changed, 82 insertions(+), 69 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index bc4da78eee57..28267feadf00 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4027,7 +4027,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) Initialized = false; Font = NULL; FontBaked = NULL; - FontSize = FontSizeBase = FontBakedScale = CurrentDpiScale = 0.0f; + FontSize = FontSizeBase = FontBakedScale = FontLineHeight = CurrentDpiScale = 0.0f; FontRasterizerDensity = 1.0f; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); if (shared_font_atlas == NULL) @@ -5990,10 +5990,9 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex text_display_end = text_end; ImFont* font = g.Font; - const float font_size = g.FontSize; if (text == text_display_end) - return ImVec2(0.0f, font_size); - ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); + return ImVec2(0.0f, g.FontLineHeight); + ImVec2 text_size = font->CalcTextSizeA(g.FontSize, FLT_MAX, wrap_width, text, text_display_end, NULL); // Round // FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out. @@ -7470,8 +7469,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size. window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x); window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; - window->TitleBarHeight = (flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : g.FontSize + g.Style.FramePadding.y * 2.0f; - window->MenuBarHeight = (flags & ImGuiWindowFlags_MenuBar) ? window->DC.MenuBarOffset.y + g.FontSize + g.Style.FramePadding.y * 2.0f : 0.0f; + window->TitleBarHeight = (flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : g.FontLineHeight + g.Style.FramePadding.y * 2.0f; + window->MenuBarHeight = (flags & ImGuiWindowFlags_MenuBar) ? window->DC.MenuBarOffset.y + g.FontLineHeight + g.Style.FramePadding.y * 2.0f : 0.0f; window->FontRefSize = g.FontSize; // Lock this to discourage calling window->CalcFontSize() outside of current window. // Depending on condition we use previous or current window size to compare against contents size to decide if a scrollbar should be visible. @@ -7604,9 +7603,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Large values tend to lead to variety of artifacts and are not recommended. window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; - // For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts. + // For windows with title bar or menu bar, we clamp to FrameHeight(LineHeight + FramePadding.y * 2.0f) to completely hide artifacts. //if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar)) - // window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f); + // window->WindowRounding = ImMin(window->WindowRounding, g.FontLineHeight + style.FramePadding.y * 2.0f); // Apply window focus (new and reactivated windows are moved to front) bool want_focus = false; @@ -8775,8 +8774,8 @@ void ImGui::UpdateFontsNewFrame() g.Font = font; g.FontSizeBase = g.Style.FontSizeBase; g.FontSize = 0.0f; - ImFontStackData font_stack_data = { font, g.Style.FontSizeBase, g.Style.FontSizeBase }; // <--- Will restore FontSize - SetCurrentFont(font_stack_data.Font, font_stack_data.FontSizeBeforeScaling, 0.0f); // <--- but use 0.0f to enable scale + ImFontStackData font_stack_data = { font, g.Style.FontSizeBase, g.Style.FontSizeBase }; // <--- Will restore FontSize + SetCurrentFont(font_stack_data.Font, font_stack_data.FontSizeBeforeScaling, 0.0f); // <--- but use 0.0f to enable scale g.FontStack.push_back(font_stack_data); IM_ASSERT(g.Font->IsLoaded()); } @@ -8908,6 +8907,7 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) g.Font->CurrentRasterizerDensity = g.FontRasterizerDensity; g.FontSize = final_size; g.FontBaked = (g.Font != NULL && window != NULL) ? g.Font->GetFontBaked(final_size) : NULL; + g.FontLineHeight = g.FontBaked ? g.FontBaked->LineHeight : g.FontSize; g.FontBakedScale = (g.Font != NULL && window != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f; g.DrawListSharedData.FontSize = g.FontSize; g.DrawListSharedData.FontScale = g.FontBakedScale; @@ -11402,25 +11402,25 @@ ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) float ImGui::GetTextLineHeight() { ImGuiContext& g = *GImGui; - return g.FontSize; + return g.FontLineHeight; } float ImGui::GetTextLineHeightWithSpacing() { ImGuiContext& g = *GImGui; - return g.FontSize + g.Style.ItemSpacing.y; + return g.FontLineHeight + g.Style.ItemSpacing.y; } float ImGui::GetFrameHeight() { ImGuiContext& g = *GImGui; - return g.FontSize + g.Style.FramePadding.y * 2.0f; + return g.FontLineHeight + g.Style.FramePadding.y * 2.0f; } float ImGui::GetFrameHeightWithSpacing() { ImGuiContext& g = *GImGui; - return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; + return g.FontLineHeight + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; } ImVec2 ImGui::GetContentRegionAvail() @@ -16695,8 +16695,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) { char buf[32]; ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); - float font_size = GetFontSize(); - draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); + draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(g.FontSize, g.FontLineHeight), IM_COL32(200, 100, 100, 255)); draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf); } } @@ -17079,7 +17078,7 @@ void ImGui::DebugNodeFont(ImFont* font) baked->FindGlyph((ImWchar)base); const int surface_sqrt = (int)ImSqrt((float)baked->MetricsTotalSurface); - Text("Ascent: %f, Descent: %f, Ascent-Descent: %f", baked->Ascent, baked->Descent, baked->Ascent - baked->Descent); + Text("Ascent: %f, Descent: %f, Ascent-Descent: %f, LineHeight: %f", baked->Ascent, baked->Descent, baked->Ascent - baked->Descent, baked->LineHeight); Text("Texture Area: about %d px ~%dx%d px", baked->MetricsTotalSurface, surface_sqrt, surface_sqrt); for (int src_n = 0; src_n < font->Sources.Size; src_n++) { @@ -17424,7 +17423,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) { ImGuiContext& g = *GImGui; if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0) - SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 12.0f), ImGuiCond_FirstUseEver); + SetNextWindowSize(ImVec2(0.0f, GetTextLineHeight() * 12.0f), ImGuiCond_FirstUseEver); if (!Begin("Dear ImGui Debug Log", p_open) || GetCurrentWindow()->BeginCount > 1) { End(); @@ -17751,7 +17750,7 @@ void ImGui::ShowIDStackToolWindow(bool* p_open) { ImGuiContext& g = *GImGui; if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0) - SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 8.0f), ImGuiCond_FirstUseEver); + SetNextWindowSize(ImVec2(0.0f, GetTextLineHeight() * 8.0f), ImGuiCond_FirstUseEver); if (!Begin("Dear ImGui ID Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1) { End(); diff --git a/imgui.h b/imgui.h index 6b35f84032a3..94c422f23a22 100644 --- a/imgui.h +++ b/imgui.h @@ -3757,6 +3757,7 @@ struct ImFontBaked // [Internal] Members: Cold float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) + float LineHeight; // 4 // out // Vertical distance between two baselines unsigned int MetricsTotalSurface:26;// 3 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) unsigned int WantDestroy:1; // 0 // // Queued for destroy unsigned int LoadNoFallback:1; // 0 // // Disable loading fallback in lower-level calls. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c4dd43a524a4..1a45d5303f5f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4617,6 +4617,7 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout); baked->Descent = ImFloor(unscaled_descent * scale_for_layout); + baked->LineHeight = baked->Size; } return true; } @@ -5061,7 +5062,7 @@ void ImFontBaked::ClearOutputData() IndexAdvanceX.clear(); IndexLookup.clear(); FallbackGlyphIndex = -1; - Ascent = Descent = 0.0f; + Ascent = Descent = LineHeight = 0.0f; MetricsTotalSurface = 0; } @@ -5461,8 +5462,8 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons if (!text_end) text_end = text_begin + ImStrlen(text_begin); // FIXME-OPT: Need to avoid this. - const float line_height = size; ImFontBaked* baked = GetFontBaked(size); + const float line_height = baked->LineHeight; const float scale = size / baked->Size; ImVec2 text_size = ImVec2(0, 0); @@ -5592,9 +5593,9 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im if (!text_end) text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. - const float line_height = size; ImFontBaked* baked = GetFontBaked(size); + const float line_height = baked->LineHeight; const float scale = size / baked->Size; const float origin_x = x; const bool word_wrap_enabled = (wrap_width > 0.0f); diff --git a/imgui_internal.h b/imgui_internal.h index 3085648ddeeb..2afc48bc381e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2149,8 +2149,9 @@ struct ImGuiContext ImVector FontAtlases; // List of font atlases used by the context (generally only contains g.IO.Fonts aka the main font atlas) ImFont* Font; // Currently bound font. (== FontStack.back().Font) ImFontBaked* FontBaked; // Currently bound font at currently bound size. (== Font->GetFontBaked(FontSize)) - float FontSize; // Currently bound font size == line height (== FontSizeBase + externals scales applied in the UpdateCurrentFontSize() function). + float FontSize; // Currently bound font size (== FontSizeBase + externals scales applied in the UpdateCurrentFontSize() function). float FontSizeBase; // Font size before scaling == style.FontSizeBase == value passed to PushFont() when specified. + float FontLineHeight; // Currently bound font's line height (+ externals scales applied in the UpdateCurrentFontSize() function). float FontBakedScale; // == FontBaked->Size / FontSize. Scale factor over baked size. Rarely used nowadays, very often == 1.0f. float FontRasterizerDensity; // Current font density. Used by all calls to GetFontBaked(). float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 8824534e7510..bb3746b1ebc7 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3075,7 +3075,7 @@ float ImGui::TableGetHeaderRowHeight() // In your custom header row you may omit this all together and just call TableNextRow() without a height... ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - float row_height = g.FontSize; + float row_height = g.FontLineHeight; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) if (IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) if ((table->Columns[column_n].Flags & ImGuiTableColumnFlags_NoHeaderLabel) == 0) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4a64b2c21559..8de01d0b935e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -447,7 +447,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // Render ImU32 text_col = GetColorU32(ImGuiCol_Text); - RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, g.FontSize * 0.5f), text_col); + RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize * 0.5f, g.FontLineHeight * 0.5f), text_col); RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), text_begin, text_end, false); } @@ -888,9 +888,12 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + const float size = g.FontSize; + const ImVec2 pos_aligned(pos.x, pos.y + (g.FontLineHeight - size) * 0.5f); + const ImRect bb(pos_aligned, pos_aligned + ImVec2(size, size)); + // Tweak 1: Shrink hit-testing area if button covers an abnormally large proportion of the visible region. That's in order to facilitate moving the window away. (#3825) // This may better be applied as a general hit-rect reduction mechanism for all widgets to ensure the area to move window is always accessible? - const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize)); ImRect bb_interact = bb; const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea(); if (area_to_visible_ratio < 1.5f) @@ -925,7 +928,9 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize)); + const float size = g.FontSize; + const ImVec2 pos_aligned(pos.x, pos.y + (g.FontLineHeight - size) * 0.5f); + const ImRect bb(pos_aligned, pos_aligned + ImVec2(size, size)); bool is_clipped = !ItemAdd(bb, id); bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None); @@ -1405,7 +1410,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over const ImGuiStyle& style = g.Style; ImVec2 pos = window->DC.CursorPos; - ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y * 2.0f); + ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontLineHeight + style.FramePadding.y * 2.0f); ImRect bb(pos, pos + size); ItemSize(size, style.FramePadding.y); if (!ItemAdd(bb, 0)) @@ -1462,7 +1467,7 @@ void ImGui::Bullet() ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; - const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), g.FontSize); + const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontLineHeight + style.FramePadding.y * 2), g.FontLineHeight); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height)); ItemSize(bb); if (!ItemAdd(bb, 0)) @@ -1596,7 +1601,7 @@ void ImGui::NewLine() if (window->DC.CurrLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height. ItemSize(ImVec2(0, 0)); else - ItemSize(ImVec2(0.0f, g.FontSize)); + ItemSize(ImVec2(0.0f, g.FontLineHeight)); window->DC.LayoutType = backup_layout_type; } @@ -1607,7 +1612,7 @@ void ImGui::AlignTextToFramePadding() return; ImGuiContext& g = *GImGui; - window->DC.CurrLineSize.y = ImMax(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y * 2); + window->DC.CurrLineSize.y = ImMax(window->DC.CurrLineSize.y, g.FontLineHeight + g.Style.FramePadding.y * 2); window->DC.CurrLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, g.Style.FramePadding.y); } @@ -1893,7 +1898,7 @@ static float CalcMaxPopupHeightFromItemCount(int items_count) ImGuiContext& g = *GImGui; if (items_count <= 0) return FLT_MAX; - return (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2); + return (g.FontLineHeight + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2); } bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags) @@ -1945,7 +1950,10 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF ImU32 text_col = GetColorU32(ImGuiCol_Text); window->DrawList->AddRectFilled(ImVec2(value_x2, bb.Min.y), bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight); if (value_x2 + arrow_size - style.FramePadding.x <= bb.Max.x) - RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f); + { + const float extra = style.FramePadding.y + (g.FontLineHeight - g.FontSize) * 0.5f; + RenderArrow(window->DrawList, ImVec2(value_x2 + extra, bb.Min.y + extra), text_col, ImGuiDir_Down, 1.0f); + } } RenderFrameBorder(bb.Min, bb.Max, style.FrameRounding); @@ -3964,10 +3972,9 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end, const char** remaining, ImVec2* out_offset, bool stop_on_new_line) { ImGuiContext& g = *ctx; - //ImFont* font = g.Font; ImFontBaked* baked = g.FontBaked; - const float line_height = g.FontSize; - const float scale = line_height / baked->Size; + const float line_height = g.FontLineHeight; + const float scale = g.FontSize / baked->Size; ImVec2 text_size = ImVec2(0, 0); float line_width = 0.0f; @@ -4536,7 +4543,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ BeginGroup(); const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y * 2.0f); // Arbitrary default of 8 lines high for multi-line + const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontLineHeight * 8.0f : label_size.y) + style.FramePadding.y * 2.0f); // Arbitrary default of 8 lines high for multi-line const ImVec2 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y); const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); @@ -4780,7 +4787,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Edit in progress const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->Scroll.x; - const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f)); + const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontLineHeight * 0.5f)); if (select_all) { @@ -4887,7 +4894,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { IM_ASSERT(state != NULL); - const int row_count_per_page = ImMax((int)((inner_size.y - style.FramePadding.y) / g.FontSize), 1); + const int row_count_per_page = ImMax((int)((inner_size.y - style.FramePadding.y) / g.FontLineHeight), 1); state->Stb->row_count_per_page = row_count_per_page; const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); @@ -4914,10 +4921,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // FIXME-OSX: Missing support for Alt(option)+Right/Left = go to end of line, or next line if already in end of line. if (IsKeyPressed(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } else if (IsKeyPressed(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } - else if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } - else if (IsKeyPressed(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } - else if (IsKeyPressed(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.FontSize; } - else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; } + else if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontLineHeight, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); } + else if (IsKeyPressed(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontLineHeight, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } + else if (IsKeyPressed(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.FontLineHeight; } + else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontLineHeight; } else if (IsKeyPressed(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); } else if (IsKeyPressed(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut) @@ -5302,16 +5309,16 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Calculate 2d position by finding the beginning of the line and measuring distance cursor_offset.x = InputTextCalcTextSize(&g, ImStrbol(cursor_ptr, text_begin), cursor_ptr).x; - cursor_offset.y = cursor_line_no * g.FontSize; + cursor_offset.y = cursor_line_no * g.FontLineHeight; if (selmin_line_no >= 0) { select_start_offset.x = InputTextCalcTextSize(&g, ImStrbol(selmin_ptr, text_begin), selmin_ptr).x; - select_start_offset.y = selmin_line_no * g.FontSize; + select_start_offset.y = selmin_line_no * g.FontLineHeight; } // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224) if (is_multiline) - text_size = ImVec2(inner_size.x, line_count * g.FontSize); + text_size = ImVec2(inner_size.x, line_count * g.FontLineHeight); } // Scroll @@ -5336,8 +5343,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline) { // Test if cursor is vertically visible - if (cursor_offset.y - g.FontSize < scroll_y) - scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize); + if (cursor_offset.y - g.FontLineHeight < scroll_y) + scroll_y = ImMax(0.0f, cursor_offset.y - g.FontLineHeight); else if (cursor_offset.y - (inner_size.y - style.FramePadding.y * 2.0f) >= scroll_y) scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f; const float scroll_max_y = ImMax((text_size.y + style.FramePadding.y * 2.0f) - inner_size.y, 0.0f); @@ -5362,7 +5369,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll; for (const char* p = text_selected_begin; p < text_selected_end; ) { - if (rect_pos.y > clip_rect.w + g.FontSize) + if (rect_pos.y > clip_rect.w + g.FontLineHeight) break; if (rect_pos.y < clip_rect.y) { @@ -5373,13 +5380,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { ImVec2 rect_size = InputTextCalcTextSize(&g, p, text_selected_end, &p, NULL, true); if (rect_size.x <= 0.0f) rect_size.x = IM_TRUNC(g.FontBaked->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines - ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn)); + ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontLineHeight), rect_pos + ImVec2(rect_size.x, bg_offy_dn)); rect.ClipWith(clip_rect); if (rect.Overlaps(clip_rect)) draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color); rect_pos.x = draw_pos.x - draw_scroll.x; } - rect_pos.y += g.FontSize; + rect_pos.y += g.FontLineHeight; } } @@ -5397,7 +5404,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->CursorAnim += io.DeltaTime; bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll); - ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); + ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontLineHeight + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f); // FIXME-DPI: Cursor thickness (#7031) @@ -5409,8 +5416,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImGuiPlatformImeData* ime_data = &g.PlatformImeData; // (this is a public struct, passed to io.Platform_SetImeDataFn() handler) ime_data->WantVisible = true; ime_data->WantTextInput = true; - ime_data->InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); - ime_data->InputLineHeight = g.FontSize; + ime_data->InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontLineHeight); + ime_data->InputLineHeight = g.FontLineHeight; ime_data->ViewportId = window->Viewport->ID; } } @@ -5419,7 +5426,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Render text only (no selection, no cursor) if (is_multiline) - text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width + text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontLineHeight); // We don't need width else if (!is_displaying_hint && g.ActiveId == id) buf_display_end = buf_display + state->TextLen; else if (!is_displaying_hint) @@ -6329,7 +6336,7 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags Separator(); } - ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2); + ImVec2 sz(g.FontLineHeight * 3 + g.Style.FramePadding.y * 2, g.FontLineHeight * 3 + g.Style.FramePadding.y * 2); ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); ImGuiColorEditFlags flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_AlphaMask_; @@ -6656,7 +6663,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const float text_width = g.FontSize + label_size.x + padding.x * 2; // Include collapsing arrow // We vertically grow up to current line height up the typical widget height. - const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2); + const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontLineHeight + style.FramePadding.y * 2), label_size.y + padding.y * 2); const bool span_all_columns = (flags & ImGuiTreeNodeFlags_SpanAllColumns) != 0 && (g.CurrentTable != NULL); const bool span_all_columns_label = (flags & ImGuiTreeNodeFlags_LabelSpanAllColumns) != 0 && (g.CurrentTable != NULL); ImRect frame_bb; @@ -6866,9 +6873,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (span_all_columns && !span_all_columns_label) TablePopBackgroundChannel(); if (flags & ImGuiTreeNodeFlags_Bullet) - RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontLineHeight * 0.5f), text_col); else if (!is_leaf) - RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f); + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + (g.FontLineHeight - g.FontSize) * 0.5f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f); else // Leaf without bullet, left-adjusted text text_pos.x -= text_offset_x - padding.x; if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) @@ -6888,15 +6895,15 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (span_all_columns && !span_all_columns_label) TablePopBackgroundChannel(); if (flags & ImGuiTreeNodeFlags_Bullet) - RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontLineHeight * 0.5f), text_col); else if (!is_leaf) - RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f); + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + ((g.FontLineHeight - g.FontSize) * 0.5f) + (g.FontSize * 0.15f)), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f); if (g.LogEnabled) LogSetNextTextDecoration(">", NULL); } if (draw_tree_lines) - TreeNodeDrawLineToChildNode(ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.5f)); + TreeNodeDrawLineToChildNode(ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontLineHeight * 0.5f)); // Label if (display_frame) @@ -9085,13 +9092,14 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) float checkmark_w = IM_TRUNC(g.FontSize * 1.20f); float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); + float extra_y = (g.FontLineHeight - g.FontSize) * 0.5f; ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); LogSetNextTextDecoration("", ">"); RenderText(text_pos, label); if (icon_w > 0.0f) RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); - RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); + RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, extra_y), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); } if (!enabled) EndDisabled(); @@ -9306,7 +9314,10 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut PopStyleColor(); } if (selected) - RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f); + { + const float extra_y = (g.FontLineHeight - g.FontSize) * 0.5f; + RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, extra_y + g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f); + } } } IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); @@ -9434,7 +9445,7 @@ bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags) ImGuiID id = window->GetID(str_id); ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id); - ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2); + ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, window->DC.CursorPos.y + g.FontLineHeight + g.Style.FramePadding.y * 2); tab_bar->ID = id; tab_bar->SeparatorMinX = tab_bar_bb.Min.x - IM_TRUNC(window->WindowPadding.x * 0.5f); tab_bar->SeparatorMaxX = tab_bar_bb.Max.x + IM_TRUNC(window->WindowPadding.x * 0.5f); @@ -10037,7 +10048,7 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - const ImVec2 arrow_button_size(g.FontSize - 2.0f, g.FontSize + g.Style.FramePadding.y * 2.0f); + const ImVec2 arrow_button_size(g.FontSize - 2.0f, g.FontLineHeight + g.Style.FramePadding.y * 2.0f); const float scrolling_buttons_width = arrow_button_size.x * 2.0f; const ImVec2 backup_cursor_pos = window->DC.CursorPos; @@ -10101,7 +10112,7 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) ImGuiWindow* window = g.CurrentWindow; // We use g.Style.FramePadding.y to match the square ArrowButton size - const float tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y; + const float tab_list_popup_button_width = g.FontLineHeight + g.Style.FramePadding.y; const ImVec2 backup_cursor_pos = window->DC.CursorPos; window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x - g.Style.FramePadding.y, tab_bar->BarRect.Min.y); tab_bar->BarRect.Min.x += tab_list_popup_button_width; diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index cbbde767c0ff..3f1738f77fd2 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -455,9 +455,9 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s // Read metrics FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; const float scale = 1.0f / rasterizer_density; - baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). + baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). baked->Descent = (float)FT_CEIL(metrics.descender) * scale; // The extents below the baseline in pixels (typically negative). - //LineSpacing = (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. + baked->LineHeight = baked->Size; // (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. //LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * scale; // The spacing in pixels between one row's descent and the next row's ascent. //MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * scale; // This field gives the maximum horizontal cursor advance for all glyphs in the font. } From e8ce4fadb08df7028914e88f2e9e63152fa83cb7 Mon Sep 17 00:00:00 2001 From: Christian Fillion Date: Sun, 3 Aug 2025 00:06:55 -0400 Subject: [PATCH 2/2] make font size be the em square's size when ImFontCfg::SizePixels is <= 0.0f --- imgui_draw.cpp | 4 ++-- misc/freetype/imgui_freetype.cpp | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 1a45d5303f5f..e946feb4a6da 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4574,7 +4574,7 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* if (src->MergeMode && src->SizePixels == 0.0f) src->SizePixels = ref_size; - if (src->SizePixels >= 0.0f) + if (src->SizePixels > 0.0f) bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f); else bd_font_data->ScaleFactor = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f); @@ -4617,7 +4617,7 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout); baked->Descent = ImFloor(unscaled_descent * scale_for_layout); - baked->LineHeight = baked->Size; + baked->LineHeight = src->SizePixels > 0.0f ? baked->Size : baked->Ascent - baked->Descent; } return true; } diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 3f1738f77fd2..cfe2fb5cdff5 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -442,7 +442,7 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s // (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL) const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity; FT_Size_RequestRec req; - req.type = (bd_font_data->UserFlags & ImGuiFreeTypeLoaderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM; + req.type = src->SizePixels <= 0.0f ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM; req.width = 0; req.height = (uint32_t)(size * 64 * rasterizer_density); req.horiResolution = 0; @@ -455,10 +455,9 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s // Read metrics FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; const float scale = 1.0f / rasterizer_density; - baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). - baked->Descent = (float)FT_CEIL(metrics.descender) * scale; // The extents below the baseline in pixels (typically negative). - baked->LineHeight = baked->Size; // (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. - //LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * scale; // The spacing in pixels between one row's descent and the next row's ascent. + baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). + baked->Descent = (float)(metrics.descender >> 6) * scale; // The extents below the baseline in pixels (typically negative). + baked->LineHeight = src->SizePixels > 0.0f ? baked->Size : baked->Ascent - baked->Descent; // metrics.height also includes the font's suggested line gap //MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * scale; // This field gives the maximum horizontal cursor advance for all glyphs in the font. } return true;