mirror of
https://github.com/ocornut/imgui.git
synced 2026-11-06 06:25:54 +01:00
TextSelect: Ctrl+A selects the selection's container, widening on each press; copy and select-all keys are configurable chords (TextSelectSetCopyShortcut(), TextSelectSetSelectAllShortcut()).
This commit is contained in:
parent
f70c1bc285
commit
7fb069997b
@ -102,6 +102,9 @@ Other Changes:
|
||||
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.
|
||||
|
||||
@ -55,6 +55,8 @@ struct ImGuiTextSelectState
|
||||
bool Enabled = true;
|
||||
ImGuiTextSelectCopyFeedbackCallback CopyFeedback = NULL;
|
||||
void* CopyFeedbackUserData = NULL;
|
||||
ImGuiKeyChord SelectAllChords[2] = { ImGuiMod_Ctrl | ImGuiKey_A, 0 };
|
||||
ImGuiKeyChord CopyChords[2] = { ImGuiMod_Ctrl | ImGuiKey_C, ImGuiMod_Ctrl | ImGuiKey_Insert };
|
||||
double FlashStartTime = -1.0; // Built-in copy feedback: the highlight turns opaque and fades back
|
||||
bool Delimiters[128] = {};
|
||||
|
||||
@ -855,6 +857,39 @@ static const ImGuiTextSelectRange* TextSelectExtendContainer(ImGuiTextSelectStat
|
||||
return (st->Dragging && has_anchor) ? &st->Anchor : NULL;
|
||||
}
|
||||
|
||||
// Selects all of the anchor's container; when a previous call already did, widens it first: a table to its window, a
|
||||
// child window to its parent. A drag is clamped to its container, so only this leaves the anchor at -far_away.
|
||||
static void TextSelectSelectAllInContainer(ImGuiTextSelectState* st)
|
||||
{
|
||||
const float far_away = 1e8f;
|
||||
ImGuiTextSelectRange c = st->Anchor;
|
||||
if (c.Begin.x == -far_away && st->Focus.End.x == far_away && !c.MenuBar)
|
||||
{
|
||||
if (c.TableId != 0)
|
||||
{
|
||||
c.TableId = 0;
|
||||
}
|
||||
else if (c.Window != c.Window->RootWindow && c.Window->ParentWindow != NULL)
|
||||
{
|
||||
c.Window = c.Window->ParentWindow;
|
||||
c.WindowId = c.Window->ID;
|
||||
}
|
||||
}
|
||||
c.Begin = c.End = ImVec2(-far_away, -far_away);
|
||||
st->Anchor = c;
|
||||
c.Begin = c.End = ImVec2(far_away, far_away);
|
||||
st->Focus = c;
|
||||
st->Block = false;
|
||||
}
|
||||
|
||||
static ImGuiKey TextSelectChordPressed(const ImGuiKeyChord (&chords)[2])
|
||||
{
|
||||
for (ImGuiKeyChord chord : chords)
|
||||
if (chord != 0 && ImGui::IsKeyChordPressed(chord))
|
||||
return (ImGuiKey)(chord & ~ImGuiMod_Mask_);
|
||||
return ImGuiKey_None;
|
||||
}
|
||||
|
||||
static void TextSelectNewFrame(ImGuiContext* ctx, ImGuiContextHook* hook)
|
||||
{
|
||||
ImGuiTextSelectState* st = (ImGuiTextSelectState*)hook->UserData;
|
||||
@ -912,6 +947,19 @@ static void TextSelectNewFrame(ImGuiContext* ctx, ImGuiContextHook* hook)
|
||||
st->ProbeTextDistEm = FLT_MAX;
|
||||
st->ProbeGlyphItemId = 0;
|
||||
|
||||
const ImGuiKey select_all_key = TextSelectChordPressed(st->SelectAllChords);
|
||||
if (select_all_key != ImGuiKey_None && st->RootWindow != NULL && !io.WantTextInput)
|
||||
{
|
||||
const bool owns_window = (g.HoveredWindow != NULL && g.HoveredWindow->RootWindow == st->RootWindow) || (g.NavWindow != NULL && g.NavWindow->RootWindow == st->RootWindow);
|
||||
if (owns_window)
|
||||
{
|
||||
TextSelectSelectAllInContainer(st);
|
||||
TextSelectResolve(st);
|
||||
// Nobody else acts on this select-all key press
|
||||
ImGui::SetKeyOwner(select_all_key, ImGuiKeyOwner_Any, ImGuiInputFlags_LockThisFrame);
|
||||
}
|
||||
}
|
||||
|
||||
if (st->CopyRequested)
|
||||
{
|
||||
st->CopyRequested = false;
|
||||
@ -922,7 +970,8 @@ static void TextSelectNewFrame(ImGuiContext* ctx, ImGuiContextHook* hook)
|
||||
}
|
||||
}
|
||||
st->RequestedCopyText.clear();
|
||||
if (!(io.KeyCtrl || io.KeySuper) || !(ImGui::IsKeyPressed(ImGuiKey_C, false) || ImGui::IsKeyPressed(ImGuiKey_Insert, false)))
|
||||
const ImGuiKey copy_key = TextSelectChordPressed(st->CopyChords);
|
||||
if (copy_key == ImGuiKey_None)
|
||||
return;
|
||||
if (!st->Active)
|
||||
{
|
||||
@ -936,8 +985,7 @@ static void TextSelectNewFrame(ImGuiContext* ctx, ImGuiContextHook* hook)
|
||||
{
|
||||
TextSelectBeginCopy(st);
|
||||
// Nobody else acts on this copy key press
|
||||
ImGui::SetKeyOwner(ImGuiKey_C, ImGuiKeyOwner_Any, ImGuiInputFlags_LockThisFrame);
|
||||
ImGui::SetKeyOwner(ImGuiKey_Insert, ImGuiKeyOwner_Any, ImGuiInputFlags_LockThisFrame);
|
||||
ImGui::SetKeyOwner(copy_key, ImGuiKeyOwner_Any, ImGuiInputFlags_LockThisFrame);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1226,6 +1274,24 @@ void ImGui::TextSelectSetCopyFeedbackCallback(ImGuiTextSelectCopyFeedbackCallbac
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui::TextSelectSetCopyShortcut(ImGuiKeyChord key_chord, ImGuiKeyChord alt_key_chord)
|
||||
{
|
||||
if (ImGuiTextSelectState* st = TextSelectGetState())
|
||||
{
|
||||
st->CopyChords[0] = key_chord;
|
||||
st->CopyChords[1] = alt_key_chord;
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui::TextSelectSetSelectAllShortcut(ImGuiKeyChord key_chord, ImGuiKeyChord alt_key_chord)
|
||||
{
|
||||
if (ImGuiTextSelectState* st = TextSelectGetState())
|
||||
{
|
||||
st->SelectAllChords[0] = key_chord;
|
||||
st->SelectAllChords[1] = alt_key_chord;
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui::TextSelectSetWordDelimiters(const char* delimiters)
|
||||
{
|
||||
if (ImGuiTextSelectState* st = TextSelectGetState())
|
||||
|
||||
@ -13,10 +13,13 @@
|
||||
// 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 copies the selection in reading order: lines from top to bottom,
|
||||
// - 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.
|
||||
@ -58,6 +61,11 @@ namespace ImGui
|
||||
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_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.
|
||||
// Default ImGuiMod_Ctrl | ImGuiKey_C and ImGuiMod_Ctrl | ImGuiKey_Insert. Either chord copies; 0 disables it.
|
||||
void TextSelectSetCopyShortcut(ImGuiKeyChord key_chord, ImGuiKeyChord alt_key_chord = 0);
|
||||
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.
|
||||
@ -75,7 +83,7 @@ namespace ImGui
|
||||
// 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. on Ctrl+A in a text view).
|
||||
// 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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user