mirror of
https://github.com/ocornut/imgui.git
synced 2026-11-10 08:25:54 +01:00
Merge 626b0fbb01862a8a8e7b893367df5a5addea2ed5 into 1f3ee75ee40c7f224714cd6896f152a902e81652
This commit is contained in:
commit
382b18164b
@ -96,6 +96,15 @@ 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.
|
||||
- Misc: added misc/text_select/ extension using the hook above: mouse selection
|
||||
(click/drag, word, line, block), highlight, and Ctrl+C/Cmd+C copy of any drawn text.
|
||||
Ctrl+A/Cmd+A selects the selection's container, widening on each press (table ->
|
||||
window -> parent window). Keys are configurable with `TextSelectSetCopyShortcut()`
|
||||
and `TextSelectSetSelectAllShortcut()`.
|
||||
- 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.
|
||||
|
||||
2
imgui.h
2
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()
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -975,6 +975,8 @@ struct IMGUI_API ImDrawListSharedData
|
||||
ImVector<ImVec2> TempBuffer; // Temporary write buffer
|
||||
ImVector<ImDrawList*> 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.
|
||||
|
||||
@ -16,6 +16,10 @@ misc/freetype/
|
||||
Font atlas builder/rasterizer using FreeType instead of stb_truetype.
|
||||
Benefit from better FreeType rasterization, in particular for small fonts.
|
||||
|
||||
misc/text_select/
|
||||
Text selection extension: select and copy any text Dear ImGui draws, by screen position,
|
||||
without changes to widget code. Relies on ImDrawListSharedData::TextHook.
|
||||
|
||||
misc/single_file/
|
||||
Single-file header stub.
|
||||
We use this to validate compiling all *.cpp files in a same compilation unit.
|
||||
|
||||
1487
misc/text_select/imgui_text_select.cpp
Normal file
1487
misc/text_select/imgui_text_select.cpp
Normal file
File diff suppressed because it is too large
Load Diff
97
misc/text_select/imgui_text_select.h
Normal file
97
misc/text_select/imgui_text_select.h
Normal file
@ -0,0 +1,97 @@
|
||||
// dear imgui: text selection extension
|
||||
// Select and copy any text Dear ImGui draws, by screen position, without changing how widgets render it.
|
||||
// - Click where no widget takes the click to set the anchor (a caret shows at the nearest glyph edge), then
|
||||
// Shift+Click or drag to set the other end. Double-Click selects a word, Double-Click+drag extends by words,
|
||||
// Shift+Double-Click extends the selection to include the whole word. Triple-Click selects the line (all text on
|
||||
// that line of the window), Triple-Click+drag extends by lines, Shift+Triple-Click extends to the whole line.
|
||||
// - Shift+Alt+Click, or Shift+Alt held while dragging, selects a block: the glyphs inside the rectangle spanned
|
||||
// by the two ends, copied as one line per row.
|
||||
// - Both ends stay inside the container the anchor was set in: its window and, when set in a table, that table. Dragging
|
||||
// past the container's edge scrolls it, faster the longer the mouse stays out, and extends the selection to the
|
||||
// nearest point inside it. A table's frozen rows and columns come before its scrolling ones.
|
||||
// - Every glyph of the container drawn between the two ends in reading order is highlighted, with bookend markers on
|
||||
// the first and last selected glyphs. Child windows inside the container take part only when they overlap the
|
||||
// rectangle spanned by the two ends (selecting in one of two side-by-side children leaves the other out).
|
||||
// - A word is a run of word characters, or a run of delimiter characters (see TextSelectSetWordDelimiters()).
|
||||
// - Ctrl+C (Cmd+C on macOS) or Ctrl+Insert (see TextSelectSetCopyShortcut()) copies the selection in reading order: lines from top to bottom,
|
||||
// fragments on a line from left to right, wide gaps (e.g. table columns) as tabs, soft-wrapped lines joined by a space
|
||||
// (or as given to TextSelectMarkSoftWrap()). The container's rows and columns scrolled out of view are submitted for
|
||||
// that one frame (through ImGuiListClipper and tables' box-select unclip support) and copied; hidden columns are not.
|
||||
// - Ctrl+A (Cmd+A on macOS), with a caret or selection in the hovered or focused window, selects everything in its
|
||||
// container; each further press widens it: a table to its window, a child window to its parent, up to the root.
|
||||
// TextSelectSetSelectAllShortcut() changes or disables the key.
|
||||
// - Escape, or a click on a widget other than the container's scrollbars, clears the selection.
|
||||
// - When io.ConfigWindowsMoveFromTitleBarOnly is off, a click on background farther than the width of an 'M' (in the
|
||||
// text's font) from any text on its line clears the selection and a drag there moves the window; closer, it selects.
|
||||
// - A click on a widget's text stays the widget's click. On a TreeNode or a row-spanning Selectable, dragging it past
|
||||
// the drag threshold turns it into a selection instead, unless the widget already used the drag (edited a value,
|
||||
// started a drag and drop). Any other widget starts a selection only with Alt held.
|
||||
// Requires ImDrawListSharedData::TextHook, which ImDrawList::AddText() calls before emitting glyphs.
|
||||
// Opt-out: PushItemFlag(ImGuiItemFlags_NoTextSelect, true) for text, TextSelectPushDisabledRegion() for an area.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
#ifndef IMGUI_TEXT_SELECT_FLASH_DURATION
|
||||
#define IMGUI_TEXT_SELECT_FLASH_DURATION 0.20f // Seconds the highlight takes to fade back from opaque after a copy
|
||||
#endif
|
||||
|
||||
#ifndef IMGUI_TEXT_SELECT_DEFAULT_DELIMITERS
|
||||
#define IMGUI_TEXT_SELECT_DEFAULT_DELIMITERS "'\"`|:,()[]{}<>"
|
||||
#endif
|
||||
|
||||
struct ImGuiTextSelectCopyLine
|
||||
{
|
||||
ImVec2 Pos; // Screen position of the line's first copied glyph
|
||||
bool Visible; // The first glyph was inside its clip rectangle (not scrolled out of view)
|
||||
const char* Text; // Points into the full copied text
|
||||
const char* TextEnd;
|
||||
};
|
||||
|
||||
// Called after a copy has set the clipboard, instead of the built-in feedback (the highlight flashes opaque and
|
||||
// fades back over IMGUI_TEXT_SELECT_FLASH_DURATION). Pointers are valid only during the call.
|
||||
typedef void (*ImGuiTextSelectCopyFeedbackCallback)(const char* text, const ImGuiTextSelectCopyLine* lines, int lines_count, void* user_data);
|
||||
|
||||
namespace ImGui
|
||||
{
|
||||
// Installs into the current context. Safe to call every frame. The state is freed with the context.
|
||||
void TextSelectInstall();
|
||||
void TextSelectSetEnabled(bool enabled);
|
||||
void TextSelectSetCopyFeedbackCallback(ImGuiTextSelectCopyFeedbackCallback callback, void* user_data);
|
||||
// ASCII characters that end a word, besides blanks. Other characters, including all non-ASCII, are word characters.
|
||||
void TextSelectSetWordDelimiters(const char* delimiters);
|
||||
// Default ImGuiMod_Ctrl | ImGuiKey_C and ImGuiMod_Ctrl | ImGuiKey_Insert. Any chord copies; 0 disables it. With
|
||||
// io.ConfigMacOSXBehaviors ImGuiMod_Ctrl is Cmd and ImGuiMod_Super is Ctrl, so the Ctrl+Insert key is
|
||||
// ImGuiMod_Super | ImGuiKey_Insert there.
|
||||
void TextSelectSetCopyShortcut(ImGuiKeyChord key_chord, ImGuiKeyChord alt_key_chord = 0, ImGuiKeyChord alt_key_chord2 = 0);
|
||||
// Default ImGuiMod_Ctrl | ImGuiKey_A (Cmd+A on macOS with io.ConfigMacOSXBehaviors). Either chord selects; 0 disables
|
||||
// it, e.g. (ImGuiMod_Ctrl | ImGuiKey_A, ImGuiMod_Super | ImGuiKey_A) also accepts the other modifier.
|
||||
void TextSelectSetSelectAllShortcut(ImGuiKeyChord key_chord, ImGuiKeyChord alt_key_chord = 0);
|
||||
|
||||
// Text drawn in between is ignored (as ImGuiItemFlags_NoTextSelect), and clicks on that stretch of the current
|
||||
// window, from the cursor at Push to the cursor at Pop, do not set the anchor.
|
||||
void TextSelectPushDisabledRegion();
|
||||
void TextSelectPopDisabledRegion();
|
||||
|
||||
// The next text drawn in the current window copies as this text, once, when any of its glyphs is selected.
|
||||
// E.g. the full value of a text drawn truncated. Only needed while TextSelectIsCopying(). NULL clears it, e.g. after
|
||||
// drawing in case nothing reached AddText() (a truncation down to just the ellipsis character).
|
||||
void TextSelectSetNextCopyText(const char* text, const char* text_end = NULL);
|
||||
// Treats a rectangle as one selectable unit with the given copy text, e.g. for text drawn with
|
||||
// ImGuiItemFlags_NoTextSelect or without AddText() (animated digits). Highlights it when selected.
|
||||
void TextSelectAddText(const ImVec2& p_min, const ImVec2& p_max, const char* text, const char* text_end = NULL);
|
||||
|
||||
// The next text drawn in the current window continues the previous line (a soft wrap done by the caller):
|
||||
// copies join the two with join (a static string, "" for a word cut in two) instead of a newline.
|
||||
void TextSelectMarkSoftWrap(const char* join = " ");
|
||||
// Selects everything in the current window and its child windows, e.g. from a "Select all" menu item.
|
||||
void TextSelectSelectAll();
|
||||
// Selects the text inside a rectangle of the current window and copies it on the next frame, with the usual copy
|
||||
// feedback, e.g. from a click handler. copy_text, when given, is what reaches the clipboard instead.
|
||||
void TextSelectSelectAndCopy(const ImVec2& p_min, const ImVec2& p_max, const char* copy_text = NULL, const char* copy_text_end = NULL);
|
||||
|
||||
bool TextSelectHasSelection(bool current_window_only = false); // current_window_only: in the current window's root
|
||||
bool TextSelectIsCopying(); // True during the frame whose text is being collected for a copy
|
||||
void TextSelectClear();
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user