Browse Source

Merge branch 'master' into docking

# Conflicts:
#	docs/CHANGELOG.txt
ocornut 2 years ago
parent
commit
38cfe22b8b
8 changed files with 97 additions and 91 deletions
  1. 66 57
      docs/CHANGELOG.txt
  2. 9 9
      imgui.cpp
  3. 3 3
      imgui.h
  4. 1 1
      imgui_demo.cpp
  5. 1 1
      imgui_draw.cpp
  6. 3 3
      imgui_internal.h
  7. 1 1
      imgui_tables.cpp
  8. 13 16
      imgui_widgets.cpp

+ 66 - 57
docs/CHANGELOG.txt

@@ -98,6 +98,15 @@ Other changes:
   Note that Linux/Mac still have inconsistent support for multi-viewports. If you want to help see https://github.com/ocornut/imgui/issues/2117.
 
 
+-----------------------------------------------------------------------
+ VERSION 1.89.1 WIP (In Progress)
+-----------------------------------------------------------------------
+
+- Inputs: fixed moving a window or drag and dropping from preventing input-owner-unaware code
+  from accessing keys. (#5888, #4921, #456)
+- Inputs: fixed moving a window or drag and dropping from capturing mods. (#5888, #4921, #456)
+
+
 -----------------------------------------------------------------------
  VERSION 1.89 (Released 2022-11-15)
 -----------------------------------------------------------------------
@@ -106,63 +115,63 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v
 
 Breaking changes:
 
- - Layout: Obsoleted using SetCursorPos()/SetCursorScreenPos() to extend parent window/cell boundaries. (#5548)
-   This relates to when moving the cursor position beyond current boundaries WITHOUT submitting an item.
-   - Previously this would make the window content size ~200x200:
-       Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End();
-   - Instead, please submit an item:
-       Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End();
-   - Alternative:
-       Begin(...) + Dummy(ImVec2(200,200)) + End();
-   Content size is now only extended when submitting an item.
-   With '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will now be detected and assert.
-   Without '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will silently be fixed until we obsolete it.
-   (This incorrect pattern has been mentioned or suggested in: #4510, #3355, #1760, #1490, #4152, #150,
-    threads have been amended to refer to this issue).
- - Renamed and merged keyboard modifiers key enums and flags into a same set:  (#4921, #456)
-    - ImGuiKey_ModCtrl  and ImGuiModFlags_Ctrl  -> ImGuiMod_Ctrl
-    - ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift
-    - ImGuiKey_ModAlt   and ImGuiModFlags_Alt   -> ImGuiMod_Alt
-    - ImGuiKey_ModSuper and ImGuiModFlags_Super -> ImGuiMod_Super
-   Kept inline redirection enums (will obsolete).
-   This change simplifies a few things, reduces confusion, and will facilitate upcoming
-   shortcut/input ownership apis.
-   - The ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends.
-   - The ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api,
-     only by third-party extensions. They were however subject to a recent rename
-     (ImGuiKeyModFlags_XXX -> ImGuiModFlags_XXX) and we are exceptionally commenting out
-     the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion
-     and because they were not meant to be used anyway.
- - Removed io.NavInputs[] and ImGuiNavInput enum that were used to feed gamepad inputs.
-   Basically 1.87 already obsoleted them from the backend's point of view, but internally
-   our navigation code still used this array and enum, so they were still present.
-   Not anymore! (#4921, #4858, #787, #1599, #323)
-   Transition guide:
-    - Official backends from 1.87+                  -> no issue.
-    - Official backends from 1.60 to 1.86           -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need updating!
-    - Custom backends not writing to io.NavInputs[] -> no issue.
-    - Custom backends writing to io.NavInputs[]     -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need fixing!
-    - TL;DR: Backends should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values instead of filling io.NavInput[].
-   The ImGuiNavInput enum was essentially 1.60's attempt to combine keyboard and gamepad inputs with named
-   semantic, but the additional indirection and copy added complexity and got in the way of other
-   incoming work. User's code (other than backends) should not be affected, unless you have custom
-   widgets intercepting navigation events via the named enums (in which case you can upgrade your code).
- - DragInt()/SliderInt(): Removed runtime patching of invalid "%f"/"%.0f" types of format strings.
-   This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details.
- - Changed signature of ImageButton() function: (#5533, #4471, #2464, #1390)
-   - Added 'const char* str_id' parameter + removed 'int frame_padding = -1' parameter.
-   - Old signature: bool ImageButton(ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), int frame_padding = -1, ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));
-     - used the ImTextureID value to create an ID. This was inconsistent with other functions, led to ID conflicts, and caused problems with engines using transient ImTextureID values.
-     - had a FramePadding override which was inconsistent with other functions and made the already-long signature even longer.
-   - New signature: bool ImageButton(const char* str_id, ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));
-     - requires an explicit identifier. You may still use e.g. PushID() calls and then pass an empty identifier.
-     - always uses style.FramePadding for padding, to be consistent with other buttons. You may use PushStyleVar() to alter this.
-   - As always we are keeping a redirection function available (will obsolete later).
- - Removed the bizarre legacy default argument for 'TreePush(const void* ptr = NULL)'. (#1057)
-   Must always pass a pointer value explicitly, NULL/nullptr is ok but require cast, e.g. TreePush((void*)nullptr);
-   If you used TreePush() replace with TreePush((void*)NULL);
- - Removed support for 1.42-era IMGUI_DISABLE_INCLUDE_IMCONFIG_H / IMGUI_INCLUDE_IMCONFIG_H. (#255)
-   They only made sense before we could use IMGUI_USER_CONFIG.
+- Layout: Obsoleted using SetCursorPos()/SetCursorScreenPos() to extend parent window/cell boundaries. (#5548)
+  This relates to when moving the cursor position beyond current boundaries WITHOUT submitting an item.
+  - Previously this would make the window content size ~200x200:
+      Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End();
+  - Instead, please submit an item:
+      Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End();
+  - Alternative:
+      Begin(...) + Dummy(ImVec2(200,200)) + End();
+  Content size is now only extended when submitting an item.
+  With '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will now be detected and assert.
+  Without '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will silently be fixed until we obsolete it.
+  (This incorrect pattern has been mentioned or suggested in: #4510, #3355, #1760, #1490, #4152, #150,
+   threads have been amended to refer to this issue).
+- Renamed and merged keyboard modifiers key enums and flags into a same set:  (#4921, #456)
+   - ImGuiKey_ModCtrl  and ImGuiModFlags_Ctrl  -> ImGuiMod_Ctrl
+   - ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift
+   - ImGuiKey_ModAlt   and ImGuiModFlags_Alt   -> ImGuiMod_Alt
+   - ImGuiKey_ModSuper and ImGuiModFlags_Super -> ImGuiMod_Super
+  Kept inline redirection enums (will obsolete).
+  This change simplifies a few things, reduces confusion, and will facilitate upcoming
+  shortcut/input ownership apis.
+  - The ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends.
+  - The ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api,
+    only by third-party extensions. They were however subject to a recent rename
+    (ImGuiKeyModFlags_XXX -> ImGuiModFlags_XXX) and we are exceptionally commenting out
+    the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion
+    and because they were not meant to be used anyway.
+- Removed io.NavInputs[] and ImGuiNavInput enum that were used to feed gamepad inputs.
+  Basically 1.87 already obsoleted them from the backend's point of view, but internally
+  our navigation code still used this array and enum, so they were still present.
+  Not anymore! (#4921, #4858, #787, #1599, #323)
+  Transition guide:
+   - Official backends from 1.87+                  -> no issue.
+   - Official backends from 1.60 to 1.86           -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need updating!
+   - Custom backends not writing to io.NavInputs[] -> no issue.
+   - Custom backends writing to io.NavInputs[]     -> will build and convert gamepad inputs, unless IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Need fixing!
+   - TL;DR: Backends should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values instead of filling io.NavInput[].
+  The ImGuiNavInput enum was essentially 1.60's attempt to combine keyboard and gamepad inputs with named
+  semantic, but the additional indirection and copy added complexity and got in the way of other
+  incoming work. User's code (other than backends) should not be affected, unless you have custom
+  widgets intercepting navigation events via the named enums (in which case you can upgrade your code).
+- DragInt()/SliderInt(): Removed runtime patching of invalid "%f"/"%.0f" types of format strings.
+  This was obsoleted in 1.61 (May 2018). See 1.61 changelog for details.
+- Changed signature of ImageButton() function: (#5533, #4471, #2464, #1390)
+  - Added 'const char* str_id' parameter + removed 'int frame_padding = -1' parameter.
+  - Old signature: bool ImageButton(ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), int frame_padding = -1, ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));
+    - used the ImTextureID value to create an ID. This was inconsistent with other functions, led to ID conflicts, and caused problems with engines using transient ImTextureID values.
+    - had a FramePadding override which was inconsistent with other functions and made the already-long signature even longer.
+  - New signature: bool ImageButton(const char* str_id, ImTextureID tex_id, ImVec2 size, ImVec2 uv0 = ImVec2(0,0), ImVec2 uv1 = ImVec2(1,1), ImVec4 bg_col = ImVec4(0,0,0,0), ImVec4 tint_col = ImVec4(1,1,1,1));
+    - requires an explicit identifier. You may still use e.g. PushID() calls and then pass an empty identifier.
+    - always uses style.FramePadding for padding, to be consistent with other buttons. You may use PushStyleVar() to alter this.
+  - As always we are keeping a redirection function available (will obsolete later).
+- Removed the bizarre legacy default argument for 'TreePush(const void* ptr = NULL)'. (#1057)
+  Must always pass a pointer value explicitly, NULL/nullptr is ok but require cast, e.g. TreePush((void*)nullptr);
+  If you used TreePush() replace with TreePush((void*)NULL);
+- Removed support for 1.42-era IMGUI_DISABLE_INCLUDE_IMCONFIG_H / IMGUI_INCLUDE_IMCONFIG_H. (#255)
+  They only made sense before we could use IMGUI_USER_CONFIG.
 
 
 Other Changes:

+ 9 - 9
imgui.cpp

@@ -1,4 +1,4 @@
-// dear imgui, v1.89
+// dear imgui, v1.90 WIP
 // (main code and documentation)
 
 // Help:
@@ -8643,13 +8643,13 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord)
             return routing_data;
     }
 
-    // Add
-    ImGuiKeyRoutingIndex idx = (ImGuiKeyRoutingIndex)rt->Entries.Size;
+    // Add to linked-list
+    ImGuiKeyRoutingIndex routing_data_idx = (ImGuiKeyRoutingIndex)rt->Entries.Size;
     rt->Entries.push_back(ImGuiKeyRoutingData());
-    routing_data = &rt->Entries[idx];
+    routing_data = &rt->Entries[routing_data_idx];
     routing_data->Mods = (ImU16)mods;
     routing_data->NextEntryIndex = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; // Setup linked list
-    rt->Index[key - ImGuiKey_NamedKey_BEGIN] = idx;
+    rt->Index[key - ImGuiKey_NamedKey_BEGIN] = routing_data_idx;
     return routing_data;
 }
 
@@ -9150,8 +9150,8 @@ ImGuiID ImGui::GetKeyOwner(ImGuiKey key)
     ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);
     ImGuiID owner_id = owner_data->OwnerCurr;
 
-    if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId)
-        if ((key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super)
+    if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any)
+        if (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END)
             return ImGuiKeyOwner_None;
 
     return owner_id;
@@ -9167,8 +9167,8 @@ bool ImGui::TestKeyOwner(ImGuiKey key, ImGuiID owner_id)
         return true;
 
     ImGuiContext& g = *GImGui;
-    if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId)
-        if ((key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super)
+    if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any)
+        if (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END)
             return false;
 
     ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);

+ 3 - 3
imgui.h

@@ -1,4 +1,4 @@
-// dear imgui, v1.89
+// dear imgui, v1.89.1 WIP
 // (headers)
 
 // Help:
@@ -22,8 +22,8 @@
 
 // Library Version
 // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345')
-#define IMGUI_VERSION               "1.89"
-#define IMGUI_VERSION_NUM           18900
+#define IMGUI_VERSION               "1.89.1 WIP"
+#define IMGUI_VERSION_NUM           18902
 #define IMGUI_HAS_TABLE
 #define IMGUI_HAS_VIEWPORT          // Viewport WIP branch
 #define IMGUI_HAS_DOCK              // Docking WIP branch

+ 1 - 1
imgui_demo.cpp

@@ -1,4 +1,4 @@
-// dear imgui, v1.89
+// dear imgui, v1.89.1 WIP
 // (demo code)
 
 // Help:

+ 1 - 1
imgui_draw.cpp

@@ -1,4 +1,4 @@
-// dear imgui, v1.89
+// dear imgui, v1.89.1 WIP
 // (drawing and font code)
 
 /*

+ 3 - 3
imgui_internal.h

@@ -1,4 +1,4 @@
-// dear imgui, v1.89
+// dear imgui, v1.89.1 WIP
 // (internal structures/api)
 
 // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
@@ -1304,8 +1304,8 @@ typedef ImS16 ImGuiKeyRoutingIndex;
 struct ImGuiKeyRoutingData
 {
     ImGuiKeyRoutingIndex            NextEntryIndex;
-    ImU16                           Mods;
-    ImU8                            RoutingNextScore;               // Lower is better (0: perfect score)
+    ImU16                           Mods;               // Technically we'd only need 4 bits but for simplify we store ImGuiMod_ values which need 16 bits.
+    ImU8                            RoutingNextScore;   // Lower is better (0: perfect score)
     ImGuiID                         RoutingCurr;
     ImGuiID                         RoutingNext;
 

+ 1 - 1
imgui_tables.cpp

@@ -1,4 +1,4 @@
-// dear imgui, v1.89
+// dear imgui, v1.89.1 WIP
 // (tables and columns code)
 
 /*

+ 13 - 16
imgui_widgets.cpp

@@ -1,4 +1,4 @@
-// dear imgui, v1.89
+// dear imgui, v1.89.1 WIP
 // (widgets code)
 
 /*
@@ -4107,14 +4107,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
     }
     if (g.ActiveId == id)
     {
-        // Declare our inputs
+        // Declare some inputs, the other are registered and polled via Shortcut() routing system.
         if (user_clicked)
             SetKeyOwner(ImGuiKey_MouseLeft, id);
         g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
         if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory))
             g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
-        SetKeyOwner(ImGuiKey_Escape, id);
-        SetKeyOwner(ImGuiKey_NavGamepadCancel, id);
         SetKeyOwner(ImGuiKey_Home, id);
         SetKeyOwner(ImGuiKey_End, id);
         if (is_multiline)
@@ -4123,9 +4121,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
             SetKeyOwner(ImGuiKey_PageDown, id);
         }
         if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character.
-        {
             SetKeyOwner(ImGuiKey_Tab, id);
-        }
     }
 
     // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function)
@@ -4298,22 +4294,23 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
         const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl;                     // OS X style: Text editing cursor movement using Alt instead of Ctrl
         const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt;  // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
 
-        // Using Shortcut() with ImGuiInputFlags_RouteFocused flag to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: formet would be handled by InputText)
+        // Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: formet would be handled by InputText)
         // Otherwise we could simply assume that we own the keys as we are active.
-        const ImGuiInputFlags shortcut_flags = ImGuiInputFlags_RouteFocused | ImGuiInputFlags_Repeat;
-        const bool is_cut   = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_X, id, shortcut_flags) || Shortcut(ImGuiMod_Shift | ImGuiKey_Delete, id, shortcut_flags)) && !is_readonly && !is_password && (!is_multiline || state->HasSelection());
-        const bool is_copy  = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_C, id, shortcut_flags & ~ImGuiInputFlags_Repeat) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_Insert, id, shortcut_flags & ~ImGuiInputFlags_Repeat))  && !is_password && (!is_multiline || state->HasSelection());
-        const bool is_paste = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_V, id, shortcut_flags) || Shortcut(ImGuiMod_Shift | ImGuiKey_Insert, id, shortcut_flags)) && !is_readonly;
-        const bool is_undo  = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Z, id, shortcut_flags)) && !is_readonly && is_undoable;
-        const bool is_redo =  (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Y, id, shortcut_flags) || (is_osx && Shortcut(ImGuiMod_Shortcut | ImGuiMod_Shift | ImGuiKey_Z, id, shortcut_flags))) && !is_readonly && is_undoable;
-        const bool is_select_all = Shortcut(ImGuiMod_Shortcut | ImGuiKey_A, id, shortcut_flags & ~ImGuiInputFlags_Repeat);
+        const ImGuiInputFlags f_repeat = ImGuiInputFlags_Repeat;
+        const bool is_cut   = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_X, id, f_repeat) || Shortcut(ImGuiMod_Shift | ImGuiKey_Delete, id, f_repeat)) && !is_readonly && !is_password && (!is_multiline || state->HasSelection());
+        const bool is_copy  = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_C, id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_Insert, id))  && !is_password && (!is_multiline || state->HasSelection());
+        const bool is_paste = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_V, id, f_repeat) || Shortcut(ImGuiMod_Shift | ImGuiKey_Insert, id, f_repeat)) && !is_readonly;
+        const bool is_undo  = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Z, id, f_repeat)) && !is_readonly && is_undoable;
+        const bool is_redo =  (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Y, id, f_repeat) || (is_osx && Shortcut(ImGuiMod_Shortcut | ImGuiMod_Shift | ImGuiKey_Z, id, f_repeat))) && !is_readonly && is_undoable;
+        const bool is_select_all = Shortcut(ImGuiMod_Shortcut | ImGuiKey_A, id);
 
         // We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful.
         const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
         const bool is_enter_pressed = IsKeyPressed(ImGuiKey_Enter, true) || IsKeyPressed(ImGuiKey_KeypadEnter, true);
         const bool is_gamepad_validate = nav_gamepad_active && (IsKeyPressed(ImGuiKey_NavGamepadActivate, false) || IsKeyPressed(ImGuiKey_NavGamepadInput, false));
-        const bool is_cancel = Shortcut(ImGuiKey_Escape, id, shortcut_flags) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadCancel, false));
+        const bool is_cancel = Shortcut(ImGuiKey_Escape, id, f_repeat) || (nav_gamepad_active && Shortcut(ImGuiKey_NavGamepadCancel, id, f_repeat));
 
+        // FIXME: Should use more Shortcut() and reduce IsKeyPressed()+SetKeyOwner(), but requires modifiers combination to be taken account of.
         if (IsKeyPressed(ImGuiKey_LeftArrow))                        { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
         else if (IsKeyPressed(ImGuiKey_RightArrow))                  { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
         else if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline)     { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
@@ -6335,7 +6332,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
     // We use NoHoldingActiveID on menus so user can click and _hold_ on a menu then drag to browse child entries
     ImGuiButtonFlags button_flags = 0;
     if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; }
-    if (flags & ImGuiSelectableFlags_NoSetKeyOwner)   { button_flags |= ImGuiButtonFlags_NoSetKeyOwner; }
+    if (flags & ImGuiSelectableFlags_NoSetKeyOwner)     { button_flags |= ImGuiButtonFlags_NoSetKeyOwner; }
     if (flags & ImGuiSelectableFlags_SelectOnClick)     { button_flags |= ImGuiButtonFlags_PressedOnClick; }
     if (flags & ImGuiSelectableFlags_SelectOnRelease)   { button_flags |= ImGuiButtonFlags_PressedOnRelease; }
     if (flags & ImGuiSelectableFlags_AllowDoubleClick)  { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; }