diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 51229ac83..23093c963 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -76,6 +76,8 @@ Other changes: - The feature is unlikely to ever work properly when using a coarse clipper such as ImGuiListClipper. - TreeNode: fixed incorrect clipping of arrow/bullet when using ImGuiTreeNodeFlags_SpanAllColumns. +- Tabs: fixes small issues with how "..." ellipsis moved depending on visibility + of Close Button or Unsaved Document marker. (#8387) - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous diff --git a/imgui.cpp b/imgui.cpp index 0d882da04..0f7618edc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3691,18 +3691,18 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons } // Another overly complex function until we reorganize everything into a nice all-in-one helper. -// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display. +// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) from 'ellipsis_max_x' which may be beyond it. // This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. -void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) +void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) { ImGuiContext& g = *GImGui; if (text_end_full == NULL) text_end_full = FindRenderedTextEnd(text); const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f); - //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255)); - //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255)); - //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255)); + //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 6), IM_COL32(0, 0, 255, 255)); + //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y - 2), ImVec2(ellipsis_max_x, pos_max.y + 3), IM_COL32(0, 255, 0, 255)); + // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels. if (text_size.x > pos_max.x - pos_min.x) { @@ -3734,15 +3734,15 @@ 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)); + RenderTextClippedEx(draw_list, pos_min, pos_max, text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); + ImVec4 cpu_fine_clip_rect(pos_min.x, pos_min.y, pos_max.x, pos_max.y); ImVec2 ellipsis_pos = ImTrunc(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); + 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, &cpu_fine_clip_rect); } else { - RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f)); + RenderTextClippedEx(draw_list, pos_min, pos_max, text, text_end_full, &text_size, ImVec2(0.0f, 0.0f)); } if (g.LogEnabled) diff --git a/imgui_internal.h b/imgui_internal.h index 65de255f5..1d217553b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3424,7 +3424,7 @@ namespace ImGui IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); - IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); + IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders = true, float rounding = 0.0f); IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index b8b869301..077d54b14 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3275,7 +3275,7 @@ void ImGui::TableHeader(const char* label) // Render clipped label. Clipping here ensure that in the majority of situations, all our header cells will // be merged into a single draw call. //window->DrawList->AddCircleFilled(ImVec2(ellipsis_max, label_pos.y), 40, IM_COL32_WHITE); - RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, ellipsis_max, label, label_end, &label_size); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, label, label_end, &label_size); const bool text_clipped = label_size.x > (ellipsis_max - label_pos.x); if (text_clipped && hovered && g.ActiveId == 0) @@ -3427,7 +3427,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label ImRect clip_r(window->ClipRect.Min, window->ClipRect.Min + ImVec2(clip_width, clip_height)); int vtx_idx_begin = draw_list->_VtxCurrentIdx; PushStyleColor(ImGuiCol_Text, request->TextColor); - RenderTextEllipsis(draw_list, clip_r.Min, clip_r.Max, clip_r.Max.x, clip_r.Max.x, label_name, label_name_eol, &label_size); + RenderTextEllipsis(draw_list, clip_r.Min, clip_r.Max, clip_r.Max.x, label_name, label_name_eol, &label_size); PopStyleColor(); int vtx_idx_end = draw_list->_VtxCurrentIdx; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 52e6236b5..984bf5f06 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1690,7 +1690,7 @@ void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end window->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); if (g.LogEnabled) LogSetNextTextDecoration("---", NULL); - RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, bb.Max.x, label, label_end, &label_size); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, label, label_end, &label_size); } else { @@ -10467,12 +10467,11 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, // Render text label (with clipping + alpha gradient) + unsaved marker ImRect text_ellipsis_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y); - float text_pixel_clip_bb_max_x = text_ellipsis_clip_bb.Max.x; // Return clipped state ignoring the close button if (out_text_clipped) { - *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_pixel_clip_bb_max_x; + *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_ellipsis_clip_bb.Max.x; //draw_list->AddCircle(text_ellipsis_clip_bb.Min, 3.0f, *out_text_clipped ? IM_COL32(255, 0, 0, 255) : IM_COL32(0, 255, 0, 255)); } @@ -10518,15 +10517,22 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, // This is all rather complicated // (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position) // FIXME: if FramePadding is noticeably large, ellipsis_max_x will be wrong here (e.g. #3497), maybe for consistency that parameter of RenderTextEllipsis() shouldn't exist.. - float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb_max_x : bb.Max.x - 1.0f; + float ellipsis_max_x = text_ellipsis_clip_bb.Max.x; if (close_button_visible || unsaved_marker_visible) { - text_pixel_clip_bb_max_x -= close_button_visible ? (button_sz) : (button_sz * 0.80f); - text_ellipsis_clip_bb.Max.x -= unsaved_marker_visible ? (button_sz * 0.80f) : 0.0f; - ellipsis_max_x = text_pixel_clip_bb_max_x; + const bool visible_without_hover = unsaved_marker_visible || (is_contents_visible ? g.Style.TabCloseButtonMinWidthSelected : g.Style.TabCloseButtonMinWidthUnselected) < 0.0f; + if (visible_without_hover) + { + text_ellipsis_clip_bb.Max.x -= button_sz * 0.90f; + ellipsis_max_x -= button_sz * 0.90f; + } + else + { + text_ellipsis_clip_bb.Max.x -= button_sz * 1.00f; + } } LogSetNextTextDecoration("/", "\\"); - RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb_max_x, ellipsis_max_x, label, NULL, &label_size); + RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, ellipsis_max_x, label, NULL, &label_size); #if 0 if (!is_contents_visible)