cherry-pick ImGui code

from LTVA1/furnace

localization work
This commit is contained in:
tildearrow 2024-05-27 17:31:20 -05:00
parent 972346d22d
commit 5f16edd0df
6 changed files with 587 additions and 71 deletions

View file

@ -1046,7 +1046,7 @@ static const float DOCKING_TRANSPARENT_PAYLOAD_ALPHA = 0.50f; // For u
static void SetCurrentWindow(ImGuiWindow* window);
static void FindHoveredWindow();
static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags);
static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags, const char* displayedName = NULL);
static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window);
static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
@ -1219,6 +1219,8 @@ ImGuiStyle::ImGuiStyle()
CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
DoFrameShadingForMultilineText = false;
// Behaviors
HoverStationaryDelay = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary.
HoverDelayShort = 0.15f; // Delay for IsItemHovered(ImGuiHoveredFlags_DelayShort). Usually used along with HoverStationaryDelay.
@ -3341,6 +3343,17 @@ const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
return text_display_end;
}
const char* FindRenderedTextEndNoHashHide(const char* text, const char* text_end)
{
const char* text_display_end = text;
if (!text_end)
text_end = (const char*)-1;
while (text_display_end < text_end && *text_display_end != '\0')
text_display_end++;
return text_display_end;
}
// Internal ImGui functions to render text
// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
@ -3363,7 +3376,14 @@ void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool
if (text != text_display_end)
{
window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
if (hide_text_after_hash)
{
window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
}
else
{
window->DrawList->AddTextNoHashHide(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
}
if (g.LogEnabled)
LogRenderedText(&pos, text, text_display_end);
}
@ -3385,6 +3405,22 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end
}
}
void ImGui::RenderTextWrappedNoHashHide(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (!text_end)
text_end = text + strlen(text); // FIXME-OPT
if (text != text_end)
{
window->DrawList->AddTextNoHashHide(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
if (g.LogEnabled)
LogRenderedText(&pos, text, text_end);
}
}
// Default clip_rect uses (pos_min,pos_max)
// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
// FIXME-OPT: Since we have or calculate text_size we could coarse clip whole block immediately, especally for text above draw_list->DrawList.
@ -3433,6 +3469,21 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons
LogRenderedText(&pos_min, text, text_display_end);
}
void ImGui::RenderTextClippedNoHashHide(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
{
// Do not hide anything after a '##' string
const char* text_display_end = text_end;
const int text_len = (int)(text_display_end - text);
if (text_len == 0)
return;
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect);
if (g.LogEnabled)
LogRenderedText(&pos_min, text, text_display_end);
}
// 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 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.
@ -3843,12 +3894,23 @@ void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type)
//-----------------------------------------------------------------------------
// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods
ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NULL)
ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name, const char* displayedName) : DrawListInst(NULL)
{
memset(this, 0, sizeof(*this));
Ctx = ctx;
Name = ImStrdup(name);
NameBufLen = (int)strlen(name) + 1;
if(displayedName != NULL)
{
DisplayedName = ImStrdup(displayedName);
}
else
{
DisplayedName = NULL;
}
ID = ImHashStr(name);
IDStack.push_back(ID);
ViewportAllowPlatformMonitorExtend = -1;
@ -3879,6 +3941,7 @@ ImGuiWindow::~ImGuiWindow()
{
IM_ASSERT(DrawList == &DrawListInst);
IM_DELETE(Name);
IM_DELETE(DisplayedName);
ColumnsStorage.clear_destruct();
}
@ -5731,6 +5794,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b
if (!border)
g.Style.ChildBorderSize = 0.0f;
bool ret = Begin(temp_window_name, NULL, flags);
g.Style.ChildBorderSize = backup_border_size;
ImGuiWindow* child_window = g.CurrentWindow;
@ -5930,12 +5994,12 @@ static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* s
}
}
static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags, const char* displayedName)
{
// Create window the first time
//IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags);
ImGuiContext& g = *GImGui;
ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name, displayedName);
window->Flags = flags;
g.WindowsById.SetVoidPtr(window->ID, window);
@ -6651,7 +6715,7 @@ ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)
// You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file.
// - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned.
// - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed.
bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags, const char* displayedName)
{
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
@ -6663,7 +6727,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
ImGuiWindow* window = FindWindowByName(name);
const bool window_just_created = (window == NULL);
if (window_just_created)
window = CreateNewWindow(name, flags);
window = CreateNewWindow(name, flags, displayedName);
// Automatically disable manual moving/resizing when NoInputs is set
if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
@ -6869,6 +6933,22 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->NameBufLen = (int)buf_len;
}
if(window->DisplayedName)
{
if(strcmp(displayedName, window->DisplayedName) != 0)
{
// WAHAHAHAHA
// you wrote free() instead of IM_DELETE() and broke portability HAHAHA
IM_DELETE(window->DisplayedName);
window->DisplayedName = ImStrdup(displayedName);
}
}
if(window->DisplayedName == NULL && displayedName != NULL)
{
window->DisplayedName = ImStrdup(displayedName);
}
// UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
// Update contents size from last frame for auto-fitting (or use explicit size)
@ -7420,7 +7500,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Title bar
if (!(flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive)
RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), name, p_open);
RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), displayedName == NULL ? name : displayedName, p_open);
// Clear hit test shape every frame
window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0;
@ -14183,8 +14263,14 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
void ImGui::LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count)
{
ImGuiContext& g = *GImGui;
for (int n = 0; n < count; n++)
g.LocalizationTable[entries[n].Key] = entries[n].Text;
if (GImGui != NULL)
{
for (int n = 0; n < count; n++)
{
g.LocalizationTable[entries[n].Key] = entries[n].Text;
}
}
}
@ -16891,7 +16977,7 @@ bool ImGui::DockNodeBeginAmendTabBar(ImGuiDockNode* node)
return false;
if (node->MergedFlags & ImGuiDockNodeFlags_KeepAliveOnly)
return false;
Begin(node->HostWindow->Name);
Begin(node->HostWindow->Name); //this is to be edited
PushOverrideID(node->ID);
bool ret = BeginTabBarEx(node->TabBar, node->TabBar->BarRect, node->TabBar->Flags, node);
IM_UNUSED(ret);
@ -17094,7 +17180,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
// Note that TabItemEx() calls TabBarCalcTabID() so our tab item ID will ignore the current ID stack (rightly so)
bool tab_open = true;
TabItemEx(tab_bar, window->Name, window->HasCloseButton ? &tab_open : NULL, tab_item_flags, window);
TabItemEx(tab_bar, window->DisplayedName == NULL ? window->Name : window->DisplayedName, window->HasCloseButton ? &tab_open : NULL, tab_item_flags, window);
if (!tab_open)
node->WantCloseTabId = window->TabId;
if (tab_bar->VisibleTabId == window->TabId)
@ -17551,7 +17637,7 @@ static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDock
if (!tab_bar_rect.Contains(tab_bb))
overlay_draw_lists[overlay_n]->PushClipRect(tab_bar_rect.Min, tab_bar_rect.Max);
TabItemBackground(overlay_draw_lists[overlay_n], tab_bb, tab_flags, overlay_col_tabs);
TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, g.Style.FramePadding, payload_window->Name, 0, 0, false, NULL, NULL);
TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, g.Style.FramePadding, payload_window->DisplayedName == NULL ? payload_window->Name : payload_window->DisplayedName, 0, 0, false, NULL, NULL);
if (!tab_bar_rect.Contains(tab_bb))
overlay_draw_lists[overlay_n]->PopClipRect();
}

View file

@ -338,7 +338,7 @@ namespace ImGui
// BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function
// returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.]
// - Note that the bottom of window stack always contains a window called "Debug".
IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0);
IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0, const char* displayedName = NULL);
IMGUI_API void End();
// Child Windows
@ -496,6 +496,7 @@ namespace ImGui
// Widgets: Text
IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text.
IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // formatted text
IMGUI_API void TextNoHashHide(const char* fmt, ...) IM_FMTARGS(1); // formatted text
IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1);
IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor();
IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args) IM_FMTLIST(2);
@ -1080,6 +1081,8 @@ enum ImGuiInputTextFlags_
ImGuiInputTextFlags_CallbackEdit = 1 << 19, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)
ImGuiInputTextFlags_EscapeClearsAll = 1 << 20, // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert)
ImGuiInputTextFlags_WordWrapping = 1 << 21, //https://github.com/MladoniSzabi/QuestSystem/commit/2c1f8bba6ecaa53a642ea469d49f19e94adc0029
// Obsolete names
//ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior
};
@ -1143,6 +1146,8 @@ enum ImGuiSelectableFlags_
ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text
ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one
ImGuiSelectableFlags_NoHashTextHide = 1 << 5, // do not hide text after `##`
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiSelectableFlags_AllowItemOverlap = ImGuiSelectableFlags_AllowOverlap, // Renamed in 1.89.7
#endif
@ -2020,6 +2025,8 @@ struct ImGuiStyle
float CircleTessellationMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
ImVec4 Colors[ImGuiCol_COUNT];
bool DoFrameShadingForMultilineText; // Toggle FrameShading for multiline text input field
// Behaviors
// (It is possible to modify those fields mid-frame if specific behavior need it, unlike e.g. configuration fields in ImGuiIO)
float HoverStationaryDelay; // Delay for IsItemHovered(ImGuiHoveredFlags_Stationary). Time required to consider mouse stationary.
@ -2808,6 +2815,8 @@ struct ImDrawList
IMGUI_API void AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments);
IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL);
IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL);
IMGUI_API void AddTextNoHashHide(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL);
IMGUI_API void AddTextNoHashHide(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL);
IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness);
IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col);
IMGUI_API void AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); // Cubic Bezier (4 control points)

View file

@ -1620,6 +1620,17 @@ void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const Im
PathStroke(col, 0, thickness);
}
const char* FindTextEnd(const char* text, const char* text_end)
{
const char* text_display_end = text;
if (!text_end)
text_end = (const char*)-1;
while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
text_display_end++;
return text_display_end;
}
void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect)
{
if ((col & IM_COL32_A_MASK) == 0)
@ -1630,6 +1641,8 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos,
if (text_begin == text_end)
return;
text_end = FindTextEnd(text_begin, text_end); //hides everything after ##
// Pull default font/size from the shared ImDrawListSharedData instance
if (font == NULL)
font = _Data->Font;
@ -1654,6 +1667,42 @@ void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, c
AddText(NULL, 0.0f, pos, col, text_begin, text_end);
}
void ImDrawList::AddTextNoHashHide(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
if (text_end == NULL)
text_end = text_begin + strlen(text_begin);
if (text_begin == text_end)
return;
//text_end = FindTextEnd(text_begin, text_end); //hides everything after ##
// Pull default font/size from the shared ImDrawListSharedData instance
if (font == NULL)
font = _Data->Font;
if (font_size == 0.0f)
font_size = _Data->FontSize;
IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
ImVec4 clip_rect = _CmdHeader.ClipRect;
if (cpu_fine_clip_rect)
{
clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
}
font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
}
void ImDrawList::AddTextNoHashHide(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
{
AddTextNoHashHide(NULL, 0.0f, pos, col, text_begin, text_end);
}
void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col)
{
if ((col & IM_COL32_A_MASK) == 0)

View file

@ -941,6 +941,8 @@ enum ImGuiTextFlags_
{
ImGuiTextFlags_None = 0,
ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0,
ImGuiTextFlags_HideID = 1 << 1, //hide things after ##
};
enum ImGuiTooltipFlags_
@ -1109,6 +1111,7 @@ struct IMGUI_API ImGuiInputTextState
bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
bool Edited; // edited this frame
ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set.
float WordWrapWidth;
ImGuiInputTextState() { memset(this, 0, sizeof(*this)); }
void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); }
@ -1117,6 +1120,8 @@ struct IMGUI_API ImGuiInputTextState
int GetRedoAvailCount() const { return STB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; }
void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation
bool HasWordWrap() const { return WordWrapWidth > 0.0; }
// Cursor & Selection
void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking
void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); }
@ -2513,6 +2518,9 @@ struct IMGUI_API ImGuiWindow
{
ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent).
char* Name; // Window name, owned by the window.
char* DisplayedName; // Window name, displayed in docked mode.
ImGuiID ID; // == ImHashStr(Name)
ImGuiWindowFlags Flags, FlagsPreviousFrame; // See enum ImGuiWindowFlags_
ImGuiWindowClass WindowClass; // Advanced users only. Set with SetNextWindowClass()
@ -2638,7 +2646,7 @@ struct IMGUI_API ImGuiWindow
ImRect DockTabItemRect;
public:
ImGuiWindow(ImGuiContext* context, const char* name);
ImGuiWindow(ImGuiContext* context, const char* name, const char* displayedName = NULL);
~ImGuiWindow();
ImGuiID GetID(const char* str, const char* str_end = NULL);
@ -3445,7 +3453,9 @@ namespace ImGui
// NB: All position are in absolute pixels coordinates (we are never using window coordinates internally)
IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width);
IMGUI_API void RenderTextWrappedNoHashHide(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 RenderTextClippedNoHashHide(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 RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);
@ -3468,6 +3478,7 @@ namespace ImGui
// Widgets
IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0);
IMGUI_API void TextExNoHashHide(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0);
IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0);
IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0);

View file

@ -122,7 +122,9 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1);
// For InputTextEx()
static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source);
static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, const bool stop_on_new_line = false, const float wrap_width = 0.0f, const bool keep_trailing_blanks = false);
static ImVec2 FindCharPosition(const ImWchar* text_begin, const ImWchar* char_position, const ImWchar* text_end, const float wrap_width);
static const ImWchar* CalcWordWrapPositionW(const ImFont* font, float scale, const ImWchar* text, const ImWchar* text_end, float wrap_width);
//-------------------------------------------------------------------------
// [SECTION] Widgets: Text, etc.
@ -159,6 +161,8 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
if (text_end == NULL)
text_end = text + strlen(text); // FIXME-OPT
text_end = FindRenderedTextEnd(text, text_end); //hides everything after ##
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);
@ -251,6 +255,116 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
}
}
void ImGui::TextExNoHashHide(const char* text, const char* text_end, 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 + strlen(text); // FIXME-OPT
//text_end = FindRenderedTextEnd(text, text_end); //hides everything after ##
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)
{
// 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);
ImRect bb(text_pos, text_pos + text_size);
ItemSize(text_size, 0.0f);
if (!ItemAdd(bb, 0))
return;
// Render (we don't hide text after ## in this end-user function)
RenderTextWrappedNoHashHide(bb.Min, text_begin, text_end, wrap_width);
}
else
{
// Long text!
// Perform manual coarse clipping to optimize for long multi-line text
// - 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 float line_height = GetTextLineHeight();
ImVec2 text_size(0, 0);
// Lines to skip (can't skip when logging text)
ImVec2 pos = text_pos;
if (!g.LogEnabled)
{
int lines_skippable = (int)((window->ClipRect.Min.y - text_pos.y) / line_height);
if (lines_skippable > 0)
{
int lines_skipped = 0;
while (line < text_end && lines_skipped < lines_skippable)
{
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
if (!line_end)
line_end = text_end;
if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)
text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end, false).x);
line = line_end + 1;
lines_skipped++;
}
pos.y += lines_skipped * line_height;
}
}
// Lines to render
if (line < text_end)
{
ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height));
while (line < text_end)
{
if (IsClippedEx(line_rect, 0))
break;
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
if (!line_end)
line_end = text_end;
text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end, false).x);
RenderText(pos, line, line_end, false);
line = line_end + 1;
line_rect.Min.y += line_height;
line_rect.Max.y += line_height;
pos.y += line_height;
}
// Count remaining lines
int lines_skipped = 0;
while (line < text_end)
{
const char* line_end = (const char*)memchr(line, '\n', text_end - line);
if (!line_end)
line_end = text_end;
if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)
text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end, false).x);
line = line_end + 1;
lines_skipped++;
}
pos.y += lines_skipped * line_height;
}
text_size.y = (pos - text_pos).y;
ImRect bb(text_pos, text_pos + text_size);
ItemSize(text_size, 0.0f);
ItemAdd(bb, 0);
}
}
void ImGui::TextUnformatted(const char* text, const char* text_end)
{
TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
@ -264,6 +378,22 @@ void ImGui::Text(const char* fmt, ...)
va_end(args);
}
void ImGui::TextNoHashHide(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return;
const char* text, *text_end;
ImFormatStringToTempBufferV(&text, &text_end, fmt, args);
TextExNoHashHide(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
va_end(args);
}
void ImGui::TextV(const char* fmt, va_list args)
{
ImGuiWindow* window = GetCurrentWindow();
@ -3668,7 +3798,188 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char**
return line_count;
}
static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)
static const ImWchar* CalcWordWrapPositionW(const ImFont* font, float scale, const ImWchar* text, const ImWchar* text_end, float wrap_width)
{
// Simple word-wrapping for English, not full-featured. Please submit failing cases!
// FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.)
// For references, possible wrap point marked with ^
// "aaa bbb, ccc,ddd. eee fff. ggg!"
// ^ ^ ^ ^ ^__ ^ ^
// List of hardcoded separators: .,;!?'"
// Skip extra blanks after a line returns (that includes not counting them in width computation)
// e.g. "Hello world" --> "Hello" "World"
// Cut words that cannot possibly fit within one line.
// e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
float line_width = 0.0f;
float word_width = 0.0f;
float blank_width = 0.0f;
wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
const ImWchar* word_end = text;
const ImWchar* prev_word_end = NULL;
bool inside_word = true;
const ImWchar* s = text;
while (s < text_end)
{
ImWchar c = (unsigned int)*s++;
if (c == 0)
break;
if (c < 32)
{
if (c == '\n')
{
line_width = word_width = blank_width = 0.0f;
inside_word = true;
continue;
}
if (c == '\r')
{
continue;
}
}
const float char_width = font->GetCharAdvance(c) * scale;
if (ImCharIsBlankW(c))
{
if (inside_word)
{
line_width += blank_width;
blank_width = 0.0f;
word_end = s - 1;
}
blank_width += char_width;
inside_word = false;
}
else
{
word_width += char_width;
if (inside_word)
{
word_end = s;
}
else
{
prev_word_end = word_end;
line_width += word_width + blank_width;
word_width = blank_width = 0.0f;
}
// Allow wrapping after punctuation.
inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"');
}
// We ignore blank width at the end of the line (they can be skipped)
if (line_width + word_width > wrap_width)
{
// Words that cannot possibly fit within an entire line will be cut anywhere.
if (word_width < wrap_width)
s = prev_word_end ? prev_word_end : word_end;
break;
}
}
return s;
}
static ImVec2 FindCharPosition(const ImWchar* text_begin, const ImWchar* char_position, const ImWchar* text_end, const float wrap_width)
{
ImGuiContext& g = *GImGui;
ImFont* font = g.Font;
const float line_height = g.FontSize;
const float scale = line_height / font->FontSize;
ImVec2 text_size = ImVec2(0, 0);
float line_width = 0.0f;
const bool word_wrap_enabled = (wrap_width > 0.0f);
const ImWchar* word_wrap_eol = NULL;
bool stop_on_new_line = false;
const ImWchar* s = text_begin;
while (s < text_end)
{
if (word_wrap_enabled)
{
if (!word_wrap_eol)
{
word_wrap_eol = CalcWordWrapPositionW(font, scale, s, text_end, wrap_width - line_width);
if (word_wrap_eol == s)
{
word_wrap_eol++;
}
}
if (s >= word_wrap_eol)
{
text_size.x = ImMax(text_size.x, line_width);
text_size.y += line_height;
line_width = 0.0f;
word_wrap_eol = NULL;
while (s < text_end)
{
unsigned int c = (unsigned int)(*s);
if(ImCharIsBlankW(c)) {
s++;
} else if(c == '\n'){
s++;
break;
} else { break; }
}
if(s >= char_position)
{
stop_on_new_line = true;
}
if (stop_on_new_line)
break;
continue;
}
}
if(s == char_position)
{
break;
}
unsigned int c = (unsigned int)(*s++);
if (c == '\n')
{
text_size.x = ImMax(text_size.x, line_width);
text_size.y += line_height;
line_width = 0.0f;
if (stop_on_new_line)
break;
continue;
}
if (c == '\r')
continue;
const float char_width = font->GetCharAdvance((ImWchar)c) * scale;
line_width += char_width;
}
if (text_size.x < line_width)
text_size.x = line_width;
return ImVec2(line_width, text_size.y + line_height);
}
static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset,const bool stop_on_new_line, const float word_wrap_width, const bool keep_trailing_blanks)
{
ImGuiContext& g = *ctx;
ImFont* font = g.Font;
@ -3678,9 +3989,52 @@ static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begi
ImVec2 text_size = ImVec2(0, 0);
float line_width = 0.0f;
const float wrap_width = word_wrap_width;
const bool word_wrap_enabled = (wrap_width > 0.0f);
const ImWchar* word_wrap_eol = NULL;
const ImWchar* s = text_begin;
while (s < text_end)
{
if (word_wrap_enabled)
{
if (!word_wrap_eol)
{
word_wrap_eol = CalcWordWrapPositionW(font, scale, s, text_end, wrap_width - line_width);
if (word_wrap_eol == s)
{
word_wrap_eol++;
}
}
if (s >= word_wrap_eol)
{
text_size.x = ImMax(text_size.x, line_width);
text_size.y += line_height;
line_width = 0.0f;
word_wrap_eol = NULL;
if(!keep_trailing_blanks)
{
while (s < text_end)
{
unsigned int c = (unsigned int)(*s);
if(ImCharIsBlankW(c)) {
s++;
} else if(c == '\n'){
s++;
break;
} else { break; }
}
}
if (stop_on_new_line)
break;
continue;
}
}
unsigned int c = (unsigned int)(*s++);
if (c == '\n')
{
@ -3726,7 +4080,7 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* ob
{
const ImWchar* text = obj->TextW.Data;
const ImWchar* text_remaining = NULL;
const ImVec2 size = InputTextCalcTextSizeW(obj->Ctx, text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true);
const ImVec2 size = InputTextCalcTextSizeW(obj->Ctx, text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true, obj->WordWrapWidth);
r->x0 = 0.0f;
r->x1 = size.x;
r->baseline_y_delta = size.y;
@ -4136,6 +4490,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
const ImRect total_bb(frame_bb.Min, frame_bb.Min + total_size);
const bool has_word_wrap = is_multiline && (flags & ImGuiInputTextFlags_WordWrapping) != 0;
const float word_wrap_width = has_word_wrap ? frame_size.x - style.FramePadding.x * 2.0f : 0.0f;
ImGuiWindow* draw_window = window;
ImVec2 inner_size = frame_size;
ImGuiItemStatusFlags item_status_flags = 0;
@ -4155,13 +4512,22 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug.
// FIXME-NAV: Pressing NavActivate will trigger general child activation right before triggering our own below. Harmless but bizarre.
PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
if(!style.DoFrameShadingForMultilineText)
{
PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
}
PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);
PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);
PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Ensure no clip rect so mouse hover can reach FramePadding edges
bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove);
PopStyleVar(3);
PopStyleColor();
if(!style.DoFrameShadingForMultilineText)
{
PopStyleColor();
}
if (!child_visible)
{
EndChild();
@ -4259,6 +4625,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
state->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863)
}
if(state)
{
state->WordWrapWidth = word_wrap_width;
}
const bool is_osx = io.ConfigMacOSXBehaviors;
if (g.ActiveId != id && init_make_active)
{
@ -4822,7 +5193,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
g.WantTextInputNextFrame = 1;
// Render frame
if (!is_multiline)
if (!is_multiline || (is_multiline && style.DoFrameShadingForMultilineText))
{
RenderNavHighlight(frame_bb, id);
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
@ -4860,63 +5231,35 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
// FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
const ImWchar* text_begin = state->TextW.Data;
const ImWchar* text_end = state->TextW.Data + ImStrlenW(state->TextW.Data);
ImVec2 cursor_offset, select_start_offset;
{
// Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions.
const ImWchar* searches_input_ptr[2] = { NULL, NULL };
int searches_result_line_no[2] = { -1000, -1000 };
int searches_remaining = 0;
if (render_cursor)
{
searches_input_ptr[0] = text_begin + state->Stb.cursor;
searches_result_line_no[0] = -1;
searches_remaining++;
// Find input local positions of 'cursor' (slot 0) and 'select_start' (slot 1) positions.
if(render_cursor) {
const ImWchar* cursor_ptr = text_begin + state->Stb.cursor;
ImVec2 cursor_pos = FindCharPosition(text_begin, cursor_ptr, text_end, word_wrap_width);
cursor_offset.x = cursor_pos.x;
cursor_offset.y = cursor_pos.y;
}
if (render_selection)
{
searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
searches_result_line_no[1] = -1;
searches_remaining++;
}
// Iterate all lines to find our line numbers
// In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.
searches_remaining += is_multiline ? 1 : 0;
int line_count = 0;
//for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) // FIXME-OPT: Could use this when wchar_t are 16-bit
for (const ImWchar* s = text_begin; *s != 0; s++)
if (*s == '\n')
{
line_count++;
if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; }
if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; }
}
line_count++;
if (searches_result_line_no[0] == -1)
searches_result_line_no[0] = line_count;
if (searches_result_line_no[1] == -1)
searches_result_line_no[1] = line_count;
// Calculate 2d position by finding the beginning of the line and measuring distance
cursor_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
cursor_offset.y = searches_result_line_no[0] * g.FontSize;
if (searches_result_line_no[1] >= 0)
{
select_start_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
select_start_offset.y = searches_result_line_no[1] * g.FontSize;
const ImWchar* selection_ptr = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
ImVec2 selection_pos = FindCharPosition(text_begin, selection_ptr, text_end, word_wrap_width);
select_start_offset.x = selection_pos.x;
select_start_offset.y = selection_pos.y;
}
// 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 = InputTextCalcTextSizeW(GImGui, text_begin, text_end, NULL, NULL, false, word_wrap_width);
}
// Scroll
if (render_cursor && state->CursorFollow)
{
// Horizontal scroll in chunks of quarter width
if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll))
if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll) && !has_word_wrap)
{
const float scroll_increment_x = inner_size.x * 0.25f;
const float visible_width = inner_size.x - style.FramePadding.x;
@ -4962,7 +5305,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
{
if (rect_pos.y > clip_rect.w + g.FontSize)
break;
if (rect_pos.y < clip_rect.y)
if (!has_word_wrap && rect_pos.y < clip_rect.y)
{
//p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p); // FIXME-OPT: Could use this when wchar_t are 16-bit
//p = p ? p + 1 : text_selected_end;
@ -4972,7 +5315,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
else
{
ImVec2 rect_size = InputTextCalcTextSizeW(&g, p, text_selected_end, &p, NULL, true);
float selection_word_wrap = has_word_wrap ? (word_wrap_width - ImMax(0.0f, rect_pos.x - draw_pos.x)) : 0.0f;
ImVec2 rect_size = InputTextCalcTextSizeW(&g, p, text_selected_end, &p, NULL, true, selection_word_wrap, false);
if (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->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));
rect.ClipWith(clip_rect);
@ -4988,7 +5332,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)
{
ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);
draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect);
draw_window->DrawList->AddTextNoHashHide(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, word_wrap_width, is_multiline ? NULL : &clip_rect);
}
// Draw blinking cursor
@ -5024,7 +5368,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)
{
ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);
draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect);
draw_window->DrawList->AddTextNoHashHide(g.Font, g.FontSize, draw_pos, col, buf_display, buf_display_end, word_wrap_width, is_multiline ? NULL : &clip_rect);
}
}
@ -6495,7 +6839,17 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
// 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;
if(flags & ImGuiSelectableFlags_NoHashTextHide)
{
label_size = CalcTextSize(label, NULL, false);
}
else
{
label_size = CalcTextSize(label, NULL, 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;
@ -6612,7 +6966,14 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
else if (span_all_columns && g.CurrentTable)
TablePopBackgroundChannel();
RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb);
if(flags & ImGuiSelectableFlags_NoHashTextHide)
{
RenderTextClippedNoHashHide(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb);
}
else
{
RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb);
}
// Automatically close popups
if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(g.LastItemData.InFlags & ImGuiItemFlags_SelectableDontClosePopup))
@ -8023,7 +8384,7 @@ ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar)
const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
{
if (tab->Window)
return tab->Window->Name;
return (tab->Window->DisplayedName ? tab->Window->DisplayedName : tab->Window->Name);
if (tab->NameOffset == -1)
return "N/A";
IM_ASSERT(tab->NameOffset < tab_bar->TabsNames.Buf.Size);
@ -8702,7 +9063,7 @@ ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button_or_unsave
ImVec2 ImGui::TabItemCalcSize(ImGuiWindow* window)
{
return TabItemCalcSize(window->Name, window->HasCloseButton || (window->Flags & ImGuiWindowFlags_UnsavedDocument));
return TabItemCalcSize((window->DisplayedName == NULL ? window->Name : window->DisplayedName), window->HasCloseButton || (window->Flags & ImGuiWindowFlags_UnsavedDocument));
}
void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col)

View file

@ -889,7 +889,7 @@ retry:
// [DEAR IMGUI]
// going down while being on the last line shouldn't bring us to that line end
if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
if (!str->HasWordWrap() && STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
break;
// now find character position down a row