diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3f6fe80c6..eeed3a62e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -40,6 +40,7 @@ All changes: - Text: Fix clipping of single-character "..." ellipsis (U+2026 or U+0085) when font is scaled. Scaling wasn't taken into account, leading to ellipsis character straying slightly out of its expected boundaries. (#2775) +- Text: Tweaked rendering of three-dots "..." ellipsis variant. (#2775, #4269) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 6ffa4a8de..53f92e13b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3261,29 +3261,10 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con const float font_size = draw_list->_Data->FontSize; const float font_scale = font_size / font->FontSize; const char* text_end_ellipsis = NULL; - - ImWchar ellipsis_char = font->EllipsisChar; - int ellipsis_char_count = 1; - if (ellipsis_char == (ImWchar)-1) - { - ellipsis_char = font->DotChar; - ellipsis_char_count = 3; - } - const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char); - - float ellipsis_glyph_width = glyph->X1 * font_scale; // Width of the glyph with no padding on either side - float ellipsis_total_width = ellipsis_glyph_width; // Full width of entire ellipsis - - if (ellipsis_char_count > 1) - { - // Full ellipsis size without free spacing after it. - const float spacing_between_dots = 1.0f * font_scale; - ellipsis_glyph_width = (glyph->X1 - glyph->X0) * font_scale + spacing_between_dots; - ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots; - } + const float ellipsis_width = font->EllipsisWidth * font_scale; // We can now claim the space between pos_max.x and ellipsis_max.x - const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f); + const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f); float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x; if (text == text_end_ellipsis && text_end_ellipsis < text_end_full) { @@ -3300,13 +3281,10 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con // Render text, render ellipsis RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); - float ellipsis_x = pos_min.x + text_size_clipped_x; - if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x) - for (int i = 0; i < ellipsis_char_count; i++) - { - font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char); - ellipsis_x += ellipsis_glyph_width; - } + ImVec2 ellipsis_pos = ImFloor(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y)); + if (ellipsis_pos.x + ellipsis_width <= ellipsis_max_x) + for (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale) + font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar); } else { diff --git a/imgui.h b/imgui.h index d1e8260be..fea413403 100644 --- a/imgui.h +++ b/imgui.h @@ -2859,8 +2859,10 @@ struct ImFont const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. ImWchar FallbackChar; // 2 // out // = FFFD/'?' // Character used if a glyph isn't found. - ImWchar EllipsisChar; // 2 // out // = '...' // Character used for ellipsis rendering. - ImWchar DotChar; // 2 // out // = '.' // Character used for ellipsis rendering (if a single '...' character isn't found) + ImWchar EllipsisChar; // 2 // out // = '...'/'.'// Character used for ellipsis rendering. + short EllipsisCharCount; // 1 // out // 1 or 3 + float EllipsisWidth; // 4 // out // Width + float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 bool DirtyLookupTables; // 1 // out // float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f768cf213..43857a682 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3112,7 +3112,8 @@ ImFont::ImFont() FallbackAdvanceX = 0.0f; FallbackChar = (ImWchar)-1; EllipsisChar = (ImWchar)-1; - DotChar = (ImWchar)-1; + EllipsisWidth = EllipsisCharStep = 0.0f; + EllipsisCharCount = 0; FallbackGlyph = NULL; ContainerAtlas = NULL; ConfigData = NULL; @@ -3200,8 +3201,20 @@ void ImFont::BuildLookupTable() const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; if (EllipsisChar == (ImWchar)-1) EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars)); - if (DotChar == (ImWchar)-1) - DotChar = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars)); + const ImWchar dot_char = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars)); + if (EllipsisChar != (ImWchar)-1) + { + EllipsisCharCount = 1; + EllipsisWidth = EllipsisCharStep = FindGlyph(EllipsisChar)->X1; + } + else if (dot_char != (ImWchar)-1) + { + const ImFontGlyph* glyph = FindGlyph(dot_char); + EllipsisChar = dot_char; + EllipsisCharCount = 3; + EllipsisCharStep = (glyph->X1 - glyph->X0) + 1.0f; + EllipsisWidth = EllipsisCharStep * 3.0f - 1.0f; + } // Setup fallback character const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };