ImStrv: Step 2 - change ImStrv typedef to struct, perform all other logic conversion.

Squashed commits (initially a commit from rokups + many rework by ocornut. keeping them separate commits made rebasing unnecessarily tricking so merged from 2024/02)
ImStrv: many fixes (see details), added imconfig class extension example, added natvis description.
ImStrv: rework toward ensuring End is always set to constant can be compile time calculated
ImStrv: using length(), fix ambiguous empty() function, fix altered behaviors, removed unused operators.
ImStrv: various tweaks and fixes. removed ImGuiTextRange from ImGuiTextFilter, fix test engine hooks, removed constructor only used twice.
This commit is contained in:
ocornut
2020-08-24 11:37:01 +03:00
committed by ocornut
parent 327ae2b2e2
commit 9a1c0ce98c
9 changed files with 551 additions and 426 deletions

View File

@@ -156,30 +156,24 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin,
// - BulletTextV()
//-------------------------------------------------------------------------
void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
void ImGui::TextEx(ImStrv text, ImGuiTextFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return;
ImGuiContext& g = *GImGui;
// Accept null ranges
if (text == text_end)
text = text_end = "";
// Calculate length
const char* text_begin = text;
if (text_end == NULL)
text_end = text + ImStrlen(text); // FIXME-OPT
const char* text_begin = text.Begin;
const char* text_end = text.End;
const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
const float wrap_pos_x = window->DC.TextWrapPos;
const bool wrap_enabled = (wrap_pos_x >= 0.0f);
if (text_end - text <= 2000 || wrap_enabled)
if (text_end - text_begin <= 2000 || wrap_enabled)
{
// Common case
const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f;
const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width);
const ImVec2 text_size = CalcTextSize(text, false, wrap_width);
ImRect bb(text_pos, text_pos + text_size);
ItemSize(text_size, 0.0f);
@@ -187,7 +181,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
return;
// Render (we don't hide text after ## in this end-user function)
RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width);
RenderTextWrapped(bb.Min, text, wrap_width);
}
else
{
@@ -196,7 +190,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
// - From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled.
// - We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line.
// - We use memchr(), pay attention that well optimized versions of those str/mem functions are much faster than a casually written loop.
const char* line = text;
const char* line = text_begin;
const float line_height = GetTextLineHeight();
ImVec2 text_size(0, 0);
@@ -235,7 +229,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
if (!line_end)
line_end = text_end;
text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x);
RenderText(pos, line, line_end, false);
RenderText(pos, ImStrv(line, line_end), false);
line = line_end + 1;
line_rect.Min.y += line_height;
line_rect.Max.y += line_height;
@@ -264,9 +258,9 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
}
}
void ImGui::TextUnformatted(const char* text, const char* text_end)
void ImGui::TextUnformatted(ImStrv text)
{
TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
TextEx(text, ImGuiTextFlags_NoWidthForLargeClippedText);
}
void ImGui::Text(const char* fmt, ...)
@@ -283,9 +277,9 @@ void ImGui::TextV(const char* fmt, va_list args)
if (window->SkipItems)
return;
const char* text, *text_end;
ImFormatStringToTempBufferV(&text, &text_end, fmt, args);
TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
ImStrv text;
ImFormatStringToTempBufferV(&text, fmt, args);
TextEx(text, ImGuiTextFlags_NoWidthForLargeClippedText);
}
void ImGui::TextColored(const ImVec4& col, const char* fmt, ...)
@@ -355,9 +349,9 @@ void ImGui::TextAlignedV(float align_x, float size_x, const char* fmt, va_list a
if (window->SkipItems)
return;
const char* text, *text_end;
ImFormatStringToTempBufferV(&text, &text_end, fmt, args);
const ImVec2 text_size = CalcTextSize(text, text_end);
ImStrv text;
ImFormatStringToTempBufferV(&text, fmt, args);
const ImVec2 text_size = CalcTextSize(text);
size_x = CalcItemSize(ImVec2(size_x, 0.0f), 0.0f, text_size.y).x;
ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
@@ -367,7 +361,7 @@ void ImGui::TextAlignedV(float align_x, float size_x, const char* fmt, va_list a
window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, pos.x + text_size.x);
if (align_x > 0.0f && text_size.x < size_x)
pos.x += ImTrunc((size_x - text_size.x) * align_x);
RenderTextEllipsis(window->DrawList, pos, pos_max, pos_max.x, text, text_end, &text_size);
RenderTextEllipsis(window->DrawList, pos, pos_max, pos_max.x, text, &text_size);
const ImVec2 backup_max_pos = window->DC.CursorMaxPos;
ItemSize(size);
@@ -375,7 +369,7 @@ void ImGui::TextAlignedV(float align_x, float size_x, const char* fmt, va_list a
window->DC.CursorMaxPos.x = backup_max_pos.x; // Cancel out extending content size because right-aligned text would otherwise mess it up.
if (size_x < text_size.x && IsItemHovered(ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_ForTooltip))
SetTooltip("%.*s", (int)(text_end - text), text);
SetTooltip("%.*s", (int)(text.End - text.Begin), text.Begin);
}
void ImGui::LabelText(ImStrv label, const char* fmt, ...)
@@ -397,11 +391,10 @@ void ImGui::LabelTextV(ImStrv label, const char* fmt, va_list args)
const ImGuiStyle& style = g.Style;
const float w = CalcItemWidth();
const char* value_text_begin, *value_text_end;
ImFormatStringToTempBufferV(&value_text_begin, &value_text_end, fmt, args);
const ImVec2 value_size = CalcTextSize(value_text_begin, value_text_end, false);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
ImStrv value_text;
ImFormatStringToTempBufferV(&value_text, fmt, args);
const ImVec2 value_size = CalcTextSize(value_text, false);
const ImVec2 label_size = CalcTextSize(label, true);
const ImVec2 pos = window->DC.CursorPos;
const ImRect value_bb(pos, pos + ImVec2(w, value_size.y + style.FramePadding.y * 2));
const ImRect total_bb(pos, pos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), ImMax(value_size.y, label_size.y) + style.FramePadding.y * 2));
@@ -410,7 +403,7 @@ void ImGui::LabelTextV(ImStrv label, const char* fmt, va_list args)
return;
// Render
RenderTextClipped(value_bb.Min + style.FramePadding, value_bb.Max, value_text_begin, value_text_end, &value_size, ImVec2(0.0f, 0.0f));
RenderTextClipped(value_bb.Min + style.FramePadding, value_bb.Max, value_text, &value_size, ImVec2(0.0f, 0.0f));
if (label_size.x > 0.0f)
RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label);
}
@@ -433,9 +426,9 @@ void ImGui::BulletTextV(const char* fmt, va_list args)
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const char* text_begin, *text_end;
ImFormatStringToTempBufferV(&text_begin, &text_end, fmt, args);
const ImVec2 label_size = CalcTextSize(text_begin, text_end, false);
ImStrv text;
ImFormatStringToTempBufferV(&text, fmt, args);
const ImVec2 label_size = CalcTextSize(text, false);
const ImVec2 total_size = ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y); // Empty text doesn't add padding
ImVec2 pos = window->DC.CursorPos;
pos.y += window->DC.CurrLineTextBaseOffset;
@@ -447,7 +440,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);
RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), text_begin, text_end, false);
RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f), text, false);
}
//-------------------------------------------------------------------------
@@ -772,7 +765,7 @@ bool ImGui::ButtonEx(ImStrv label, const ImVec2& size_arg, ImGuiButtonFlags flag
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, true);
ImVec2 pos = window->DC.CursorPos;
if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
@@ -794,7 +787,7 @@ bool ImGui::ButtonEx(ImStrv label, const ImVec2& size_arg, ImGuiButtonFlags flag
if (g.LogEnabled)
LogSetNextTextDecoration("[", "]");
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, &label_size, style.ButtonTextAlign, &bb);
// Automatically close popups
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
@@ -1217,7 +1210,7 @@ bool ImGui::Checkbox(ImStrv label, bool* v)
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, true);
const float square_sz = GetFrameHeight();
const ImVec2 pos = window->DC.CursorPos;
@@ -1339,7 +1332,7 @@ bool ImGui::RadioButton(ImStrv label, bool active)
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, true);
const float square_sz = GetFrameHeight();
const ImVec2 pos = window->DC.CursorPos;
@@ -1436,7 +1429,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, ImStrv overlay)
// Default displaying the fraction as percentage string, but user can override it
// Don't display text for indeterminate bars by default
char overlay_buf[32];
if (!is_indeterminate || overlay != NULL)
if (!is_indeterminate || overlay)
{
if (!overlay)
{
@@ -1444,11 +1437,11 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, ImStrv overlay)
overlay = overlay_buf;
}
ImVec2 overlay_size = CalcTextSize(overlay, NULL);
ImVec2 overlay_size = CalcTextSize(overlay);
if (overlay_size.x > 0.0f)
{
float text_x = is_indeterminate ? (bb.Min.x + bb.Max.x - overlay_size.x) * 0.5f : ImLerp(bb.Min.x, bb.Max.x, fill_n1) + style.ItemSpacing.x;
RenderTextClipped(ImVec2(ImClamp(text_x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb);
RenderTextClipped(ImVec2(ImClamp(text_x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, &overlay_size, ImVec2(0.0f, 0.5f), &bb);
}
}
}
@@ -1491,7 +1484,7 @@ bool ImGui::TextLink(ImStrv label)
const char* label_end = FindRenderedTextEnd(label);
ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
ImVec2 size = CalcTextSize(label, label_end, true);
ImVec2 size = CalcTextSize(label.Begin, label_end, true);
ImRect bb(pos, pos + size);
ItemSize(size, 0.0f);
if (!ItemAdd(bb, id))
@@ -1525,7 +1518,7 @@ bool ImGui::TextLink(ImStrv label)
window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf)); // FIXME-TEXT: Underline mode // FIXME-DPI
PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf));
RenderText(bb.Min, label, label_end);
RenderText(bb.Min, label.Begin, label_end);
PopStyleColor();
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
@@ -1535,12 +1528,17 @@ bool ImGui::TextLink(ImStrv label)
bool ImGui::TextLinkOpenURL(ImStrv label, ImStrv url)
{
ImGuiContext& g = *GImGui;
if (url == NULL)
url = label;
bool pressed = TextLink(label);
label.End = FindRenderedTextEnd(label.Begin);
if (!url)
url = label;
if (pressed && g.PlatformIO.Platform_OpenInShellFn != NULL)
g.PlatformIO.Platform_OpenInShellFn(&g, url);
SetItemTooltip(LocalizeGetMsg(ImGuiLocKey_OpenLink_s), url); // It is more reassuring for user to _always_ display URL when we same as label
{
ImStrv url_zt;
ImFormatStringToTempBuffer(&url_zt, "%.*s", (int)url.length(), url.Begin);
g.PlatformIO.Platform_OpenInShellFn(&g, url_zt.Begin);
}
SetItemTooltip(LocalizeGetMsg(ImGuiLocKey_OpenLink_s), (int)url.length(), url.Begin); // It is more reassuring for user to _always_ display URL when we same as label
if (BeginPopupContextItem())
{
if (MenuItem(LocalizeGetMsg(ImGuiLocKey_CopyLink)))
@@ -1695,13 +1693,13 @@ void ImGui::Separator()
SeparatorEx(flags, 1.0f);
}
void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w)
void ImGui::SeparatorTextEx(ImGuiID id, ImStrv label, float extra_w)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStyle& style = g.Style;
const ImVec2 label_size = CalcTextSize(label, label_end, false);
const ImVec2 label_size = CalcTextSize(label, false);
const ImVec2 pos = window->DC.CursorPos;
const ImVec2 padding = style.SeparatorTextPadding;
@@ -1734,7 +1732,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, 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_size);
}
else
{
@@ -1757,7 +1755,7 @@ void ImGui::SeparatorText(ImStrv label)
// - because of this we probably can't turn 'const char* label' into 'const char* fmt, ...'
// Otherwise, we can decide that users wanting to drag this would layout a dedicated drag-item,
// and then we can turn this into a format function.
SeparatorTextEx(0, label, FindRenderedTextEnd(label), 0.0f);
SeparatorTextEx(0, ImStrv(label.Begin, FindRenderedTextEnd(label)), 0.0f);
}
// Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise.
@@ -1912,8 +1910,8 @@ bool ImGui::BeginCombo(ImStrv label, ImStrv preview_value, ImGuiComboFlags flags
IM_ASSERT((flags & (ImGuiComboFlags_NoPreview | (ImGuiComboFlags)ImGuiComboFlags_CustomPreview)) == 0);
const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight();
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const float preview_width = ((flags & ImGuiComboFlags_WidthFitPreview) && (preview_value != NULL)) ? CalcTextSize(preview_value, NULL, true).x : 0.0f;
const ImVec2 label_size = CalcTextSize(label, true);
const float preview_width = ((flags & ImGuiComboFlags_WidthFitPreview) && (preview_value != NULL)) ? CalcTextSize(preview_value, true).x : 0.0f;
const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : ((flags & ImGuiComboFlags_WidthFitPreview) ? (arrow_size + preview_width + style.FramePadding.x * 2.0f) : CalcItemWidth());
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
const ImRect total_bb(bb.Min, bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@@ -1952,16 +1950,15 @@ bool ImGui::BeginCombo(ImStrv label, ImStrv preview_value, ImGuiComboFlags flags
if (flags & ImGuiComboFlags_CustomPreview)
{
g.ComboPreviewData.PreviewRect = ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y);
IM_ASSERT(preview_value == NULL || preview_value[0] == 0);
preview_value = NULL;
IM_ASSERT(!preview_value);
}
// Render preview and label
if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview))
if (!preview_value.empty() && !(flags & ImGuiComboFlags_NoPreview))
{
if (g.LogEnabled)
LogSetNextTextDecoration("{", "}");
RenderTextClipped(bb.Min + style.FramePadding, ImVec2(value_x2, bb.Max.y), preview_value, NULL, NULL);
RenderTextClipped(bb.Min + style.FramePadding, ImVec2(value_x2, bb.Max.y), preview_value, NULL);
}
if (label_size.x > 0)
RenderText(ImVec2(bb.Max.x + style.ItemInnerSpacing.x, bb.Min.y + style.FramePadding.y), label);
@@ -2666,7 +2663,7 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v
// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional.
// Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.
bool ImGui::DragScalar(ImStrv label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, ImStrv format, ImGuiSliderFlags flags)
bool ImGui::DragScalar(ImStrv label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, ImStrv format_p, ImGuiSliderFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -2677,7 +2674,7 @@ bool ImGui::DragScalar(ImStrv label, ImGuiDataType data_type, void* p_data, floa
const ImGuiID id = window->GetID(label);
const float w = CalcItemWidth();
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, true);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@@ -2686,8 +2683,14 @@ bool ImGui::DragScalar(ImStrv label, ImGuiDataType data_type, void* p_data, floa
if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0))
return false;
// FIXME-IMSTR
char format_0[64]; // format may not end with \0
const char* format = format_0;
IM_ASSERT(format_p.End - format_p.Begin < IM_ARRAYSIZE(format_0));
ImStrncpy(format_0, format_p, IM_ARRAYSIZE(format_0));
// Default format string when passing NULL
if (format == NULL)
if (!format_p)
format = DataTypeGetInfo(data_type)->PrintFmt;
const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags);
@@ -2756,7 +2759,7 @@ bool ImGui::DragScalar(ImStrv label, ImGuiDataType data_type, void* p_data, floa
const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);
if (g.LogEnabled)
LogSetNextTextDecoration("{", "}");
RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
RenderTextClipped(frame_bb.Min, frame_bb.Max, ImStrv(value_buf, value_buf_end), NULL, ImVec2(0.5f, 0.5f));
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
@@ -2789,11 +2792,11 @@ bool ImGui::DragScalarN(ImStrv label, ImGuiDataType data_type, void* p_data, int
}
PopID();
const char* label_end = FindRenderedTextEnd(label);
if (label != label_end)
label.End = FindRenderedTextEnd(label);
if (label.Begin != label.End)
{
SameLine(0, g.Style.ItemInnerSpacing.x);
TextEx(label, label_end);
TextEx(label);
}
EndGroup();
@@ -2846,7 +2849,8 @@ bool ImGui::DragFloatRange2(ImStrv label, float* v_current_min, float* v_current
PopItemWidth();
SameLine(0, g.Style.ItemInnerSpacing.x);
TextEx(label, FindRenderedTextEnd(label));
label.End = FindRenderedTextEnd(label);
TextEx(label);
EndGroup();
PopID();
@@ -2900,7 +2904,8 @@ bool ImGui::DragIntRange2(ImStrv label, int* v_current_min, int* v_current_max,
PopItemWidth();
SameLine(0, g.Style.ItemInnerSpacing.x);
TextEx(label, FindRenderedTextEnd(label));
label.End = FindRenderedTextEnd(label);
TextEx(label);
EndGroup();
PopID();
@@ -3270,7 +3275,7 @@ bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type
// Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a slider, they are all required.
// Read code of e.g. SliderFloat(), SliderInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.
bool ImGui::SliderScalar(ImStrv label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, ImStrv format, ImGuiSliderFlags flags)
bool ImGui::SliderScalar(ImStrv label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, ImStrv format_p, ImGuiSliderFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -3281,7 +3286,7 @@ bool ImGui::SliderScalar(ImStrv label, ImGuiDataType data_type, void* p_data, co
const ImGuiID id = window->GetID(label);
const float w = CalcItemWidth();
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, true);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@@ -3290,8 +3295,13 @@ bool ImGui::SliderScalar(ImStrv label, ImGuiDataType data_type, void* p_data, co
if (!ItemAdd(total_bb, id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0))
return false;
// FIXME-IMSTR
char format_0[64]; // format may not end with \0
const char* format = format_0;
IM_ASSERT(format_p.End - format_p.Begin < IM_ARRAYSIZE(format_0));
// Default format string when passing NULL
if (format == NULL)
if (!format_p)
format = DataTypeGetInfo(data_type)->PrintFmt;
const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags);
@@ -3347,7 +3357,7 @@ bool ImGui::SliderScalar(ImStrv label, ImGuiDataType data_type, void* p_data, co
const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);
if (g.LogEnabled)
LogSetNextTextDecoration("{", "}");
RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
RenderTextClipped(frame_bb.Min, frame_bb.Max, ImStrv(value_buf, value_buf_end), NULL, ImVec2(0.5f, 0.5f));
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
@@ -3381,11 +3391,11 @@ bool ImGui::SliderScalarN(ImStrv label, ImGuiDataType data_type, void* v, int co
}
PopID();
const char* label_end = FindRenderedTextEnd(label);
if (label != label_end)
label.End = FindRenderedTextEnd(label);
if (label.Begin != label.End)
{
SameLine(0, g.Style.ItemInnerSpacing.x);
TextEx(label, label_end);
TextEx(label);
}
EndGroup();
@@ -3414,7 +3424,7 @@ bool ImGui::SliderFloat4(ImStrv label, float v[4], float v_min, float v_max, ImS
bool ImGui::SliderAngle(ImStrv label, float* v_rad, float v_degrees_min, float v_degrees_max, ImStrv format, ImGuiSliderFlags flags)
{
if (format == NULL)
if (!format)
format = "%.0f deg";
float v_deg = (*v_rad) * 360.0f / (2 * IM_PI);
bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, flags);
@@ -3443,7 +3453,7 @@ bool ImGui::SliderInt4(ImStrv label, int v[4], int v_min, int v_max, ImStrv form
return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format, flags);
}
bool ImGui::VSliderScalar(ImStrv label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, ImStrv format, ImGuiSliderFlags flags)
bool ImGui::VSliderScalar(ImStrv label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, ImStrv format_p, ImGuiSliderFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -3453,7 +3463,7 @@ bool ImGui::VSliderScalar(ImStrv label, const ImVec2& size, ImGuiDataType data_t
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, true);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@@ -3461,8 +3471,13 @@ bool ImGui::VSliderScalar(ImStrv label, const ImVec2& size, ImGuiDataType data_t
if (!ItemAdd(frame_bb, id))
return false;
// FIXME-IMSTR
char format_0[64]; // format may not end with \0
const char* format = format_0;
IM_ASSERT(format_p.End - format_p.Begin < IM_ARRAYSIZE(format_0));
// Default format string when passing NULL
if (format == NULL)
if (!format_p)
format = DataTypeGetInfo(data_type)->PrintFmt;
const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags);
@@ -3496,7 +3511,7 @@ bool ImGui::VSliderScalar(ImStrv label, const ImVec2& size, ImGuiDataType data_t
// For the vertical slider we allow centered text to overlap the frame padding
char value_buf[64];
const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);
RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f));
RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, ImStrv(value_buf, value_buf_end), NULL, ImVec2(0.5f, 0.0f));
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
@@ -3738,7 +3753,7 @@ void ImGui::SetNextItemRefVal(ImGuiDataType data_type, void* p_data)
// Note: p_data, p_step, p_step_fast are _pointers_ to a memory address holding the data. For an Input widget, p_step and p_step_fast are optional.
// Read code of e.g. InputFloat(), InputInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly.
bool ImGui::InputScalar(ImStrv label, ImGuiDataType data_type, void* p_data, const void* p_step, const void* p_step_fast, ImStrv format, ImGuiInputTextFlags flags)
bool ImGui::InputScalar(ImStrv label, ImGuiDataType data_type, void* p_data, const void* p_step, const void* p_step_fast, ImStrv format_p, ImGuiInputTextFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -3748,7 +3763,13 @@ bool ImGui::InputScalar(ImStrv label, ImGuiDataType data_type, void* p_data, con
ImGuiStyle& style = g.Style;
IM_ASSERT((flags & ImGuiInputTextFlags_EnterReturnsTrue) == 0); // Not supported by InputScalar(). Please open an issue if you this would be useful to you. Otherwise use IsItemDeactivatedAfterEdit()!
if (format == NULL)
// FIXME-IMSTR
char format_0[64]; // format may not end with \0
const char* format = format_0;
IM_ASSERT(format_p.End - format_p.Begin < IM_ARRAYSIZE(format_0));
ImStrncpy(format_0, format_p, IM_ARRAYSIZE(format_0));
if (!format_p)
format = DataTypeGetInfo(data_type)->PrintFmt;
void* p_data_default = (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasRefVal) ? &g.NextItemData.RefVal : &g.DataTypeZeroValue;
@@ -3803,11 +3824,11 @@ bool ImGui::InputScalar(ImStrv label, ImGuiDataType data_type, void* p_data, con
if (flags & ImGuiInputTextFlags_ReadOnly)
EndDisabled();
const char* label_end = FindRenderedTextEnd(label);
if (label != label_end)
label.End = FindRenderedTextEnd(label);
if (label.Begin != label.End)
{
SameLine(0, style.ItemInnerSpacing.x);
TextEx(label, label_end);
TextEx(label);
}
style.FramePadding = backup_frame_padding;
@@ -3846,11 +3867,11 @@ bool ImGui::InputScalarN(ImStrv label, ImGuiDataType data_type, void* p_data, in
}
PopID();
const char* label_end = FindRenderedTextEnd(label);
if (label != label_end)
label.End = FindRenderedTextEnd(label);
if (label.Begin != label.End)
{
SameLine(0.0f, g.Style.ItemInnerSpacing.x);
TextEx(label, label_end);
TextEx(label);
}
EndGroup();
@@ -4290,10 +4311,10 @@ void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count)
BufTextLen -= bytes_count;
}
void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end)
void ImGuiInputTextCallbackData::InsertChars(int pos, ImStrv new_text)
{
// Accept null ranges
if (new_text == new_text_end)
if (new_text.Begin == new_text.End)
return;
ImGuiContext& g = *Ctx;
@@ -4302,7 +4323,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
// Grow internal buffer if needed
const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0;
const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)ImStrlen(new_text);
const int new_text_len = (int)new_text.length();
if (new_text_len + BufTextLen + 1 > obj->TextA.Size && (Flags & ImGuiInputTextFlags_ReadOnly) == 0)
{
if (!is_resizable)
@@ -4318,7 +4339,8 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
if (BufTextLen != pos)
memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos));
memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char));
if (new_text_len > 0)
memcpy(Buf + pos, new_text.Begin, (size_t)new_text_len * sizeof(char));
Buf[BufTextLen + new_text_len] = '\0';
if (CursorPos >= pos)
@@ -4636,7 +4658,7 @@ bool ImGui::InputTextEx(ImStrv label, ImStrv hint, char* buf, int buf_size, cons
if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope (including the scrollbar)
BeginGroup();
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, 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 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y);
@@ -4868,7 +4890,7 @@ bool ImGui::InputTextEx(ImStrv label, ImStrv hint, char* buf, int buf_size, cons
// Select the buffer to render.
const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state;
bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
bool is_displaying_hint = (!hint.empty() && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
// Password pushes a temporary font with only a fallback glyph
if (is_password && !is_displaying_hint)
@@ -5133,16 +5155,16 @@ bool ImGui::InputTextEx(ImStrv label, ImStrv hint, char* buf, int buf_size, cons
}
else if (is_paste)
{
if (const char* clipboard = GetClipboardText())
if (ImStrv clipboard = GetClipboardText())
{
// Filter pasted buffer
const int clipboard_len = (int)ImStrlen(clipboard);
const int clipboard_len = (int)clipboard.length();
ImVector<char> clipboard_filtered;
clipboard_filtered.reserve(clipboard_len + 1);
for (const char* s = clipboard; *s != 0; )
for (const char* s = clipboard.Begin; *s != 0; )
{
unsigned int c;
int in_len = ImTextCharFromUtf8(&c, s, NULL);
int in_len = ImTextCharFromUtf8(&c, s, clipboard.End);
s += in_len;
if (!InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, true))
continue;
@@ -5365,7 +5387,7 @@ bool ImGui::InputTextEx(ImStrv label, ImStrv hint, char* buf, int buf_size, cons
// Display hint when contents is empty
// At this point we need to handle the possibility that a callback could have modified the underlying buffer (#8368)
const bool new_is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
const bool new_is_displaying_hint = (!hint.empty() && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
if (new_is_displaying_hint != is_displaying_hint)
{
if (is_password && !is_displaying_hint)
@@ -5376,8 +5398,8 @@ bool ImGui::InputTextEx(ImStrv label, ImStrv hint, char* buf, int buf_size, cons
}
if (is_displaying_hint)
{
buf_display = hint;
buf_display_end = hint + ImStrlen(hint);
buf_display = hint.Begin;
buf_display_end = hint.End;
}
else
{
@@ -5523,8 +5545,7 @@ bool ImGui::InputTextEx(ImStrv label, ImStrv hint, char* buf, int buf_size, cons
g.Font->RenderText(draw_window->DrawList, g.FontSize,
draw_pos - draw_scroll + ImVec2(0.0f, line_visible_n0 * g.FontSize),
text_col, clip_rect.AsVec4(),
line_index->get_line_begin(buf_display, line_visible_n0),
line_index->get_line_end(buf_display, line_visible_n1 - 1),
ImStrv(line_index->get_line_begin(buf_display, line_visible_n0), line_index->get_line_end(buf_display, line_visible_n1 - 1)),
wrap_width, ImDrawTextFlags_WrapKeepBlanks);
// Render blinking cursor
@@ -5579,7 +5600,7 @@ bool ImGui::InputTextEx(ImStrv label, ImStrv hint, char* buf, int buf_size, cons
if (g.LogEnabled && (!is_password || is_displaying_hint))
{
LogSetNextTextDecoration("{", "}");
LogRenderedText(&draw_pos, buf_display, buf_display_end);
LogRenderedText(&draw_pos, ImStrv(buf_display, buf_display_end));
}
if (label_size.x > 0)
@@ -5694,7 +5715,6 @@ bool ImGui::ColorEdit4(ImStrv label, float col[4], ImGuiColorEditFlags flags)
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const float square_sz = GetFrameHeight();
const char* label_display_end = FindRenderedTextEnd(label);
float w_full = CalcItemWidth();
g.NextItemData.ClearFlags();
@@ -5703,6 +5723,7 @@ bool ImGui::ColorEdit4(ImStrv label, float col[4], ImGuiColorEditFlags flags)
const bool set_current_color_edit_id = (g.ColorEditCurrentID == 0);
if (set_current_color_edit_id)
g.ColorEditCurrentID = window->IDStack.back();
label.End = FindRenderedTextEnd(label);
// If we're not showing any slider there's no point in doing any HSV conversions
const ImGuiColorEditFlags flags_untouched = flags;
@@ -5849,9 +5870,9 @@ bool ImGui::ColorEdit4(ImStrv label, float col[4], ImGuiColorEditFlags flags)
if (g.CurrentWindow->BeginCount == 1)
{
picker_active_window = g.CurrentWindow;
if (label != label_display_end)
if (label.Begin != label.End)
{
TextEx(label, label_display_end);
TextEx(label);
Spacing();
}
ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar;
@@ -5863,13 +5884,13 @@ bool ImGui::ColorEdit4(ImStrv label, float col[4], ImGuiColorEditFlags flags)
}
}
if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel))
if (label.Begin != label.End && !(flags & ImGuiColorEditFlags_NoLabel))
{
// Position not necessarily next to last submitted button (e.g. if style.ColorButtonPosition == ImGuiDir_Left),
// but we need to use SameLine() to setup baseline correctly. Might want to refactor SameLine() to simplify this.
SameLine(0.0f, style.ItemInnerSpacing.x);
window->DC.CursorPos.x = pos.x + ((flags & ImGuiColorEditFlags_NoInputs) ? w_button : w_full + style.ItemInnerSpacing.x);
TextEx(label, label_display_end);
TextEx(label);
}
// Convert back
@@ -6116,11 +6137,11 @@ bool ImGui::ColorPicker4(ImStrv label, float col[4], ImGuiColorEditFlags flags,
if (!(flags & ImGuiColorEditFlags_NoLabel))
{
const char* label_display_end = FindRenderedTextEnd(label);
if (label != label_display_end)
if (label.Begin != label_display_end)
{
if ((flags & ImGuiColorEditFlags_NoSidePreview))
SameLine(0, style.ItemInnerSpacing.x);
TextEx(label, label_display_end);
TextEx(ImStrv(label.Begin, label_display_end));
}
}
@@ -6438,10 +6459,10 @@ void ImGui::ColorTooltip(ImStrv text, const float* col, ImGuiColorEditFlags flag
if (!BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None))
return;
const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text;
if (text_end > text)
text.End = FindRenderedTextEnd(text);
if (text.Begin != text.End)
{
TextEx(text, text_end);
TextEx(text);
Separator();
}
@@ -6603,7 +6624,7 @@ bool ImGui::TreeNode(ImStrv label)
if (window->SkipItems)
return false;
ImGuiID id = window->GetID(label);
return TreeNodeBehavior(id, ImGuiTreeNodeFlags_None, label, NULL);
return TreeNodeBehavior(id, ImGuiTreeNodeFlags_None, label);
}
bool ImGui::TreeNodeV(ImStrv str_id, const char* fmt, va_list args)
@@ -6622,7 +6643,7 @@ bool ImGui::TreeNodeEx(ImStrv label, ImGuiTreeNodeFlags flags)
if (window->SkipItems)
return false;
ImGuiID id = window->GetID(label);
return TreeNodeBehavior(id, flags, label, NULL);
return TreeNodeBehavior(id, flags, label);
}
bool ImGui::TreeNodeEx(ImStrv str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
@@ -6650,9 +6671,9 @@ bool ImGui::TreeNodeExV(ImStrv str_id, ImGuiTreeNodeFlags flags, const char* fmt
return false;
ImGuiID id = window->GetID(str_id);
const char* label, *label_end;
ImFormatStringToTempBufferV(&label, &label_end, fmt, args);
return TreeNodeBehavior(id, flags, label, label_end);
ImStrv label;
ImFormatStringToTempBufferV(&label, fmt, args);
return TreeNodeBehavior(id, flags, label);
}
bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
@@ -6662,9 +6683,9 @@ bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char
return false;
ImGuiID id = window->GetID(ptr_id);
const char* label, *label_end;
ImFormatStringToTempBufferV(&label, &label_end, fmt, args);
return TreeNodeBehavior(id, flags, label, label_end);
ImStrv label;
ImFormatStringToTempBufferV(&label, fmt, args);
return TreeNodeBehavior(id, flags, label);
}
bool ImGui::TreeNodeGetOpen(ImGuiID storage_id)
@@ -6752,7 +6773,7 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1)
}
// When using public API, currently 'id == storage_id' is always true, but we separate the values to facilitate advanced user code doing storage queries outside of UI loop.
bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end)
bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, ImStrv label)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -6762,10 +6783,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
const ImGuiStyle& style = g.Style;
const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0;
const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y));
if (!label_end)
label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false);
label.End = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, false);
const float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapsing arrow width + Spacing
const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
@@ -7016,9 +7035,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// Label
if (display_frame)
RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size);
RenderTextClipped(text_pos, frame_bb.Max, label, &label_size);
else
RenderText(text_pos, label, label_end, false);
RenderText(text_pos, label, false);
if (span_all_columns_label)
TablePopBackgroundChannel();
@@ -7245,7 +7264,7 @@ bool ImGui::Selectable(ImStrv label, bool selected, ImGuiSelectableFlags flags,
// Submit label or explicit size to ItemSize(), whereas ItemAdd() will submit a larger/spanning rectangle.
ImGuiID id = window->GetID(label);
ImVec2 label_size = CalcTextSize(label, NULL, true);
ImVec2 label_size = CalcTextSize(label, true);
ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
ImVec2 pos = window->DC.CursorPos;
pos.y += window->DC.CurrLineTextBaseOffset;
@@ -7400,7 +7419,7 @@ bool ImGui::Selectable(ImStrv label, bool selected, ImGuiSelectableFlags flags,
// Text stays at the submission position. Alignment/clipping extents ignore SpanAllColumns.
if (is_visible)
RenderTextClipped(pos, ImVec2(ImMin(pos.x + size.x, window->WorkRect.Max.x), pos.y + size.y), label, NULL, &label_size, style.SelectableTextAlign, &bb);
RenderTextClipped(pos, ImVec2(ImMin(pos.x + size.x, window->WorkRect.Max.x), pos.y + size.y), label, &label_size, style.SelectableTextAlign, &bb);
// Automatically close popups
if (pressed && !auto_selected && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups))
@@ -8573,7 +8592,7 @@ bool ImGui::BeginListBox(ImStrv label, const ImVec2& size_arg)
const ImGuiStyle& style = g.Style;
const ImGuiID id = GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, true);
// Size default to hold ~7.25 items.
// Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
@@ -8692,7 +8711,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, ImStrv label, float (*values_getter)(
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, true);
const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0f);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
@@ -8788,7 +8807,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, ImStrv label, float (*values_getter)(
// Text overlay
if (overlay_text)
RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f, 0.0f));
RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, ImVec2(0.5f, 0.0f));
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
@@ -8844,17 +8863,17 @@ void ImGui::PlotHistogram(ImStrv label, float (*values_getter)(void* data, int i
void ImGui::Value(ImStrv prefix, bool b)
{
Text("%s: %s", prefix, (b ? "true" : "false"));
Text("%.*s: %s", (int)prefix.length(), prefix.Begin, (b ? "true" : "false"));
}
void ImGui::Value(ImStrv prefix, int v)
{
Text("%s: %d", prefix, v);
Text("%.*s: %d", (int)prefix.length(), prefix.Begin, v);
}
void ImGui::Value(ImStrv prefix, unsigned int v)
{
Text("%s: %d", prefix, v);
Text("%.*s: %d", (int)prefix.length(), prefix.Begin, v);
}
void ImGui::Value(ImStrv prefix, float v, ImStrv float_format)
@@ -8862,12 +8881,12 @@ void ImGui::Value(ImStrv prefix, float v, ImStrv float_format)
if (float_format)
{
char fmt[64];
ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format);
Text(fmt, prefix, v);
ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%.*s: %.*s", (int)float_format.length(), float_format.Begin);
Text(fmt, (int)prefix.length(), prefix.Begin, v);
}
else
{
Text("%s: %.3f", prefix, v);
Text("%.*s: %.3f", (int)prefix.length(), prefix.Begin, v);
}
}
@@ -9156,7 +9175,7 @@ bool ImGui::BeginMenuEx(ImStrv label, ImStrv icon, bool enabled)
// Tag menu as used. Next time BeginMenu() with same ID is called it will append to existing menu
g.MenusIdSubmittedThisFrame.push_back(id);
ImVec2 label_size = CalcTextSize(label, NULL, true);
ImVec2 label_size = CalcTextSize(label, true);
// Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without always being a Child window)
// This is only done for items for the menu set and not the full parent window.
@@ -9198,7 +9217,7 @@ bool ImGui::BeginMenuEx(ImStrv label, ImStrv icon, bool enabled)
// (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f.
// Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.)
popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;
float icon_w = !icon.empty() ? CalcTextSize(icon, NULL).x : 0.0f;
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);
@@ -9368,7 +9387,7 @@ bool ImGui::MenuItemEx(ImStrv label, ImStrv icon, ImStrv shortcut, bool selected
ImGuiContext& g = *GImGui;
ImGuiStyle& style = g.Style;
ImVec2 pos = window->DC.CursorPos;
ImVec2 label_size = CalcTextSize(label, NULL, true);
ImVec2 label_size = CalcTextSize(label, true);
// See BeginMenuEx() for comments about this.
const bool menuset_is_open = IsRootOfOpenMenuSet();
@@ -9404,8 +9423,8 @@ bool ImGui::MenuItemEx(ImStrv label, ImStrv icon, ImStrv shortcut, bool selected
// Menu item inside a vertical menu
// (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f.
// Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.)
float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;
float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f;
float icon_w = !icon.empty() ? CalcTextSize(icon).x : 0.0f;
float shortcut_w = !shortcut.empty() ? CalcTextSize(shortcut).x : 0.0f;
float checkmark_w = IM_TRUNC(g.FontSize * 1.20f);
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame
float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
@@ -9419,7 +9438,7 @@ bool ImGui::MenuItemEx(ImStrv label, ImStrv icon, ImStrv shortcut, bool selected
{
PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]);
LogSetNextTextDecoration("(", ")");
RenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL, false);
RenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, false);
PopStyleColor();
}
if (selected)
@@ -10401,6 +10420,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, ImStrv label, bool* p_open, ImGui
tab_bar->LastTabItemIdx = (ImS16)tab_bar->Tabs.index_from_ptr(tab);
// Calculate tab contents size
label.End = FindRenderedTextEnd(label);
ImVec2 size = TabItemCalcSize(label, (p_open != NULL) || (flags & ImGuiTabItemFlags_UnsavedDocument));
tab->RequestedWidth = -1.0f;
if (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasWidth)
@@ -10426,7 +10446,9 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, ImStrv label, bool* p_open, ImGui
else
{
tab->NameOffset = (ImS32)tab_bar->TabsNames.size();
tab_bar->TabsNames.append(label, label + ImStrlen(label) + 1);
tab_bar->TabsNames.append(label);
char zero_c = 0;
tab_bar->TabsNames.append(ImStrv(&zero_c, &zero_c + 1));
}
// Update selected tab
@@ -10586,7 +10608,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, ImStrv label, bool* p_open, ImGui
// FIXME: We may want disabled tab to still display the tooltip?
if (text_clipped && g.HoveredId == id && !held)
if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip))
SetItemTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label);
SetItemTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label.Begin), label.Begin);
}
// Restore main window position so user can draw there
@@ -10619,7 +10641,7 @@ void ImGui::SetTabItemClosed(ImStrv label)
ImVec2 ImGui::TabItemCalcSize(ImStrv label, bool has_close_button_or_unsaved_marker)
{
ImGuiContext& g = *GImGui;
ImVec2 label_size = CalcTextSize(label, NULL, true);
ImVec2 label_size = CalcTextSize(label, true);
ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0f);
if (has_close_button_or_unsaved_marker)
size.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle.
@@ -10664,7 +10686,7 @@ void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabI
void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, ImStrv label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible, bool* out_just_closed, bool* out_text_clipped)
{
ImGuiContext& g = *GImGui;
ImVec2 label_size = CalcTextSize(label, NULL, true);
ImVec2 label_size = CalcTextSize(label);
if (out_just_closed)
*out_just_closed = false;
@@ -10749,7 +10771,7 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
}
}
LogSetNextTextDecoration("/", "\\");
RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, ellipsis_max_x, label, NULL, &label_size);
RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, ellipsis_max_x, label, &label_size);
#if 0
if (!is_contents_visible)