From 34af65a1b5800f364bcf271de0021232dad188a2 Mon Sep 17 00:00:00 2001 From: Marius PvW Date: Wed, 4 Nov 2026 10:24:44 -0500 Subject: [PATCH] Core: added ImDrawListSharedData::TextHook called by AddText(), and ImGuiItemFlags_NoTextSelect, to allow implementing text selection externally. --- docs/CHANGELOG.txt | 4 ++++ imgui.h | 2 ++ imgui_draw.cpp | 2 ++ imgui_internal.h | 2 ++ 4 files changed, 10 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b5b7ecbaa..9cfe4cef7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -96,6 +96,10 @@ Other Changes: - Multi-Select: - Fixed `ImGuiSelectionBasicStorage::GetNextSelectedItem()` reading one past the end of storage when trailing items are unselected (#9604) [@MilosLord] +- Text: added `ImDrawListSharedData::TextHook` (internal), called by `ImDrawList::AddText()` + with the font, position, clip rectangle and string of every text run before its glyphs + are emitted, and `ImGuiItemFlags_NoTextSelect` to let such a hook skip items. Enables + text selection/copy of any displayed text without changes to widget code. - ImVec2: added a check for cases where a custom `IM_VEC2_CLASS_EXTRA` macro adds an extra `operator=` to ImVec2. This isn't supported but should not be needed as you should have a constructor to convert from your type to ImVec2. diff --git a/imgui.h b/imgui.h index 5634b552f..f7ef3357e 100644 --- a/imgui.h +++ b/imgui.h @@ -1330,6 +1330,8 @@ enum ImGuiItemFlags_ // - If you use MixedMode and the simplest solution is to ensure LiveEdit is off but widgets where this applies. //--------------------------------------------------------------------------------- ImGuiItemFlags_MixedValue = 1 << 9, // false // [BETA] Represent a mixed/indeterminate value. Replace value label with "-" and apply edits on validation. + + ImGuiItemFlags_NoTextSelect = 1 << 10, // false // Text drawn while set is ignored by text selection implemented via ImDrawListSharedData::TextHook: not highlighted, not copied, and a click on it does not start a selection. }; // Flags for ImGui::InputText() diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 79c493e76..9210cb6e9 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2977,6 +2977,8 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z); clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w); } + if (_Data->TextHook != NULL) + _Data->TextHook(this, font, font_size, pos, clip_rect, text_begin, text_end, wrap_width, _Data->TextHookUserData); font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, (cpu_fine_clip_rect != NULL) ? ImDrawTextFlags_CpuFineClip : ImDrawTextFlags_None); } diff --git a/imgui_internal.h b/imgui_internal.h index 321cb0933..d09d5fc00 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -975,6 +975,8 @@ struct IMGUI_API ImDrawListSharedData ImVector TempBuffer; // Temporary write buffer ImVector DrawLists; // All draw lists associated to this ImDrawListSharedData ImGuiContext* Context; // [OPTIONAL] Link to Dear ImGui context. 99% of ImDrawList/ImFontAtlas can function without an ImGui context, but this facilitate handling one legacy edge case. + void (*TextHook)(ImDrawList* draw_list, ImFont* font, float font_size, const ImVec2& pos, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, void* user_data); // [OPTIONAL] Called by AddText() before the glyphs are emitted: anything it draws ends up underneath the text. text_end may be NULL. + void* TextHookUserData; // Lookup tables ImVec2 ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle.