Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shortcuts API #456

Open
3 of 7 tasks
ocornut opened this issue Dec 25, 2015 · 70 comments
Open
3 of 7 tasks

Shortcuts API #456

ocornut opened this issue Dec 25, 2015 · 70 comments

Comments

@ocornut
Copy link
Owner

ocornut commented Dec 25, 2015

Writing down notes about implementing a shortcut system. I have started using menus more extensively in my own applications, and the lack of support for shortcuts has become a little annoying.

Without shortcuts the user is required to duplicate code to handle menu items and shortcuts for a same action. Consider that MenuItem() can takes both a "checked" and "enabled" parameter which may need to be fetch/computed from your application state, duplicating that code can be pretty annoying and ImGui strive to reduce redundancy so it's quite a flaw to have to do that.

menus

In the old Menus API #126 thread I said we'd need;

Support local keyboard shortcuts, We can use Windows syntax of using & (e.g. "&Save") for convenience.

And

Support general "global" shortcuts (e.g. "CTRL+S"). As a design goal of ImGui we want to avoid code and state duplication, so I'd like the ImGui system to handle shortcuts for the user. It will be optional but likely available by default. So the program can have a single entry point for "Save" whether it is activated via clicking in the menu or via pressing the shortcut. The way it would work is that when a global shortcut scheme is activated, the menu functions always notify the user code to develop its content so ImGui can parse and execute the shortcuts as they are declared, but the actual menu is not layed out nor rendered. The shortcut scheme can be disabled on a per-menu/window/global basis. In particular, procedurally generated menus that may have infinite depth will need to be able to disable the global shortcut scheme. In its "closed" state, the system has to be as lightweight as if the user were testing a bunch of shortcuts themselves. The scope of shortcuts can be dependent on factor such as if the parent window is focused so they aren't always "global". The user should also be able to display the label for a shortcut in the menu without letting ImGui handle the shortcut itself.

So here is a rough list of what I think we need. Unfortunately some of those will need the user to update their ImGui integration to provide the necessary inputs, but there won't be any breakage.

PART A, for regular shortcuts (typically global shortcuts, but they can be local to a window)

EDIT Not needed!
- [ ] We are going to need translated characters, aka the "A" in "CTRL+A" or "ALT+A" is a translated character. So the end-user application needs to feed those inputs probably via io.AddInputCharacter() and this isn't really a problem for ImGui to solve. However, and that's very surprising, retrieve this information under Windows is NOT straightforward. The WM_CHAR message isn't sent when ALT or CTRL are pressed. WM_SYSCHAR is only sent when ALT is pressed. No CHAR messages are sent when CTRL is pressed. By adding this in a Windows message handler I seem to be able to retrieve those characters.

    case WM_KEYDOWN:
    case WM_SYSKEYDOWN:
            if (GetKeyState(VK_CONTROL) & 0x8000)
            {
                BYTE keys[256];
                memset(keys, 0, sizeof(keys));
                keys[VK_SHIFT] = (GetKeyState(VK_SHIFT) & 0x8000) ? 0x80 : 0;
                WCHAR buf[4];
                const int scancode = (lParam >> 16) & 0x1ff;
                const int buf_sz = ToUnicodeEx(wParam, scancode, keys, buf, 4, 0, NULL);
                for (int n = 0; n < buf_sz; n++)
                    io.AddInputCharacters(buf[n]);
            }
            return 1;

It is a little scary but appears to work. End-user would need a similar mechanism which is rather annoying. For Windows messages user can copy demo code if they are pointed to it. GLFW has been patched in the 3.1 branch to support the ALT key but not the CTRL key yet (would be nice if it does so), what that means is that support for those inputs won't be widespread in most applications soon and it is only likely to be widely available in GLFW when 3.2 ships (also means that support for CTRL key would better be pushed in GLFW before they release 3.2!). Or user can freely do their own cheap conversions if they don't care about funky localisation things.

I'd be curious to know whether GLFW 3.1 gives you character inputs in ImGui_ImplGlfw_CharCallback when ALT or CTRL are pressed on MacOS, Linux, etc. See following rely for instructions on how to perform the test. If you can do a test let me know which version of GLFW you are using. Thanks!

  • Need to add all non-printable to the ImGuiKey_ enum: functions keys, insert, keypad stuff.. Unfortunately I didn't add those initially, my bad :( (Been thinking about adding a "Tester" to the demo code that helps you verify your ImGui integration, test things like clipping rectangle, texture changes, all sort of inputs. So this tester could list the keys and make sure you can input them.)
  • We are going to need to parse shortcuts string efficiently. Encoding should fit in 32-bits (e.g. 16-bit value, 1 bit to select translated character or key, 3 bits modifiers, 2 bits scope: window, window-and-parent, global). Maybe just parsing on the spot (hardcoded stricmp for prefixes such as "CTRL+") is simpler and faster but we need some sort of fast handling of all the named keys that aren't character (e..g F5, HOME, etc.) so this may make the encoding slower. Also figure out a syntax to specify shortcut scope, or this may be not in the string but rather specified in the callee function. If parsing is slow, perhaps hash/FNV1a the string and cache parsed result as a single u32 stored in a ImGuiStorage which is a contiguous sorted map, touching O(N log N) 8-bytes entries. Either way both are rather easy to try.
  • Function that checks if an encoded shortcut is pressed. May or not be merged with the parsing function. Trivial.
  • Menus need to be able to run in a mode where nothing renders but the global shortcuts are still processed. As per my old comment above, this may be optional and not the default, and the user needs to be able to disable the feature to allow for recursive menu. Perhaps the feature not spreading to sub-menu automatically would make more sense?

PART B (for & ALT-style local shortcuts, lesser priority)

  • Menus needs to process the & ALT-style local shortcuts. The behavior little different from the other shortcuts and may imply keyboard controllable menu, at least support for the Enter key.
  • We are going to need be able to parse and render the "&Save" syntax for & ALT-style local shortcuts. The text size calculation and text renderer will need a flag to support this feature. For size calculation, we can treat & as zero-width. For rendering, we need to query the width of the next character and draw an underscore below the baseline. We might or not need to handle inhibition with the \ character to be able to render regular & in this mode. All that would be normally easy BUT one problem is that CalcTextSizeA() is often a major bottleneck in very large UI and thus we can't afford to make it slower so those feature would have to be designed accordingly and will need to alter the low-level text rendering API. (Unrelated to this we want to allow centered and right text alignment on a per-line basis and this would have an effect on the text rendering API as well).
  • How about adding support for shortcuts to regular widgets like Buttons? Problem with & ALT-style is that it may have a small overhead with text-processing. But may be a nice default and thus we may design the feature expecting it to be always on. For CTRL-style shortcut, probably best to avoid encoding them in a label and just accept that the user can do their own shortcut checking aka
    if (ImGui::Button("Refresh") || ImGui::IsShortcutPressed("F5") { .. }.

That's it for now. Those are merely notes for myself. If there are

@emoon
Copy link
Contributor

emoon commented Dec 25, 2015

I tested this (in the opengl_example) on Mac and added a printf() in KeyCallback function and I got there everytime when pressing some key and holding ctrl, alt or command.

@ocornut
Copy link
Owner Author

ocornut commented Dec 25, 2015

Sorry my request wasn't clear, the problem is with the CharCallback not the KeyCallback.

To enable CharCallback with modifiers in GLFW 3.1 you need change
glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
to
glfwSetCharModsCallback(window, ImGui_ImplGlfw_CharCallback);
And add the extra integer to the ImGui_ImplGlfw_CharCallback function.
It isn't done in the default ImGui example because this function was introduced in 3.1 which is not in some package repos.

@emoon
Copy link
Contributor

emoon commented Dec 25, 2015

Did the changes and Alt seems to work just fine. Ctrl seems to work in some cases but not in others.

@ocornut
Copy link
Owner Author

ocornut commented Dec 25, 2015

Any specific pattern with CTRL working vs not working?
Do simple things like Ctrl+A, Ctrl+Shift+A, Ctrl+Alt+A works? Are the broken cases on specifc keys?

Thanks for looking, this is really helpful. This stupid app-side input problem has been the number one barrier for adding shortcuts so I am eager to solve it. I submitted a GLFW tentative patch for Windows but have no way to look into Mac right now.

For this specific use of shortcuts frankly I don't mind too much if some weird keys don't work seeing it is an application-side problem that can be fully solved later, I just would like basic support to work for most users.

@emoon
Copy link
Contributor

emoon commented Dec 25, 2015

So it seems Ctrl+A-Z doesn't work but 0-9 and other non A-Z keys (like /= etc) works fine.

Alt seems to work on all keys. Ctrl+Alt-.... behaves the same as Ctrl- only

@ocornut
Copy link
Owner Author

ocornut commented Dec 25, 2015

Thank you, very useful. Taking it to glfw.

@emoon
Copy link
Contributor

emoon commented Dec 25, 2015

np :)

@ocornut
Copy link
Owner Author

ocornut commented Dec 27, 2015

The first point in the list appears to be the most problematic. It looks like I may just need to redesign the IO API, which was desirable anyway, to switch to an event-registration system so e.g. have a AddKeyPress the same way we have a AddInputCharacter and the user may pass a optional stringified localized key name along with keypress.

May or not need to break compatibility with the user-glue code, very obviously if I can avoid it I'll try very hard to avoid it. I always liked how ImGui took this nice shortcut of taking a sample of input state because it makes initial integration with all sort of libraries easier, but we also need a way out of that.

@emoon
Copy link
Contributor

emoon commented Dec 28, 2015

Yeah that sounds. Good also something I have been thinking about for a while (sorry for being a bit of topic) is the versioning of the lib. Something I have started to come to like is "Semantic Versioning" http://semver.org I kinda like this approach as it's clear when breaking changes comes that may cause issue. This would of course break the current versioning and it's of course up to you to use or not but may be something to consider.

@zhiayang
Copy link

Sorry to jump on like this, but would it be possible to allow for more flexibility in the shortcut modifier? On OS X it's quite annoying whenever an application doesn't implement Cmd+A/S/V/N/X shortcuts, and chooses to go with Ctrl+whatever.

I already maintain a local patchjob of ImGui::InputTextEx that handles the OS X shortcut style and text editing behaviour (rather, I just #ifdef it away and include a copied version from a header file). It would be great if the new global shortcut system could allow a little leeway in not hardcoding for Ctrl so much?

Just a suggestion, of course.

@ocornut
Copy link
Owner Author

ocornut commented Dec 31, 2015

How do you think it would work? I don't know enough about Mac experience to design that. My idea is that the user would pass in strings to the api, e.g. "CTRL+S". Then it could be the responsibility of user code to pass in "CMD+S" there? Or an optional/default behavior would be to allow to remap CTRL to CMD by default? (both for key testing and display).

Is the Command key a wholly different key? Does typical third API feed it as an modifier? GLFW has GLFW_KEY_LEFT_SUPER/GLFW_KEY_RIGHT_SUPER keys for the Command key and a keyboard modifier GLFW_MOD_SUPER so that's all ok. Is Super a good terminology that can adapt to both Command and Windows key?

EDIT SDL2 has KMOD_GUI/KMOD_LGUI/KMOD_RGUI so I'll assume other API are supporting this as a modifiers keys as well.

Also - you could post your InputTextEx() mod for reference?

@emoon
Copy link
Contributor

emoon commented Dec 31, 2015

So the way I have done that in the past is like this:

https://github.com/emoon/rocket/blob/master/ogl_editor/src/Menu.c?ts=4#L26

EMGUI_KEY_COMMAND, EMGUI_KEY_CTRL

First part is the modifier on Mac and the other is on Windows/Linux. The thing is that while the Windows key isn't used that much on Windows actually for shortcuts inside programs that is certainly the case on Mac.

@zhiayang
Copy link

Ah, thanks for responding. I've changed a number of things actually:

  1. Command key for shortcuts. In theory it should work on windows (if ENABLE_OSX_TEXT_EDITING is defined to be 0)
  2. Double click selects a word instead of everything (this is the behaviour on OS X)
  3. Movement by word in OS X is done with the ALT key instead of the control key, I put a couple of #if guards in there to handle it as well.

(3) is done a bit hackily, since I'm not too familiar with the code, I did a move left word, select word right.

I know that these changes work on OS X, but since I don't have a windows machine to test on (and I'm not sure the rest of my code would work), I can only guarantee my changes to work... "in theory". It's all compile time checks too, so no performance hit either.

I also added a KeyCmd member in the ImGuiIO struct, which is basically the same as KeyAlt and the others. It's updated in the backend input event function as well.

Here's the diff: https://gist.github.com/zhiayang/5764aacd621ebbed6f0b
(um... i have a habit of changing the whitespace, so in case the diff is too unreadable there's the whole function below. terribly sorry)

Here's my edited version: https://gist.github.com/zhiayang/27b3f032a054e503484a

@ocornut
Copy link
Owner Author

ocornut commented Jan 2, 2016

On InputTextEx( ) for Mac: regardless of the shortcut API above we should probably merge those three into master, add the KeyCmd member. They could be a runtime settings (for slightly better build coverage) and set the default differently based on __APPLE__ define. If someone wants to try making a clean version of that I'll merge else I'll give it a go sometimes.

For shortcuts, we could require the user to pass in different strings per os for apps caring about portability in this manner (not all imgui apps will do), but that would make user code more bulky. Or support a syntax like "CTRL|CMD+S", simple but a little weird. Or have a system where by default "CTRL+S" gets translated to "CMD+S" on Mac ("Mac" defined via a runtime flag again) BUT with a mechanism to enforce actual CTRL when desired, aka a different identifier for CTRL on Mac, e.g. "XCTRL". Or Control key stays "CTRL" and we have a different short identifier meaning "CTRL|CMD"., I don't know how to name that.

CTRL = Ctrl (Windows), Cmd (Mac)
XCTRL = Ctrl (Windows), Ctrl (Mac)
CMD = Cmd (Windows, nearly never used), Cmd (mac)

With R/L variants "LCTRL", "RCTRL".
Looking at Daniel's table it looks like the majority of occurrences of CTRL are to be CMD on Mac, but not all of them.

@zhiayang
Copy link

zhiayang commented Jan 2, 2016

I'll have a go at a proper pull request for this, it shouldn't take long. A few things to clarify though:

  1. Cmd/Ctrl should be a runtime setting defaulting based on __APPLE__. Does this bool go in ImGuiIO, or is somewhere else more appropriate?
  2. Should the double click text behaviour change as well? Would it always select by word when double clicking, or would this also be OS dependent? If the latter, should it be governed by the same setting as (1) (eg. OSXAlikeBehaviour) or separate, eg. TextShortcutsUseCmdKey and DoubleClickSelectsWord?
  3. I'm assuming KeyCmd would be present in the ImGuiIO struct regardless of OS? Should it then be named something more agnostic, like KeySuper or KeyGui? If the answer to the first question is "no", then ignore all this.
  4. In a similar vein to (3), should there be new enum members for LSuper and RSuper in the ImGuiKey_ enum? And should the backends set this by default when handling events? Should these be set for Windows systems as well? (Actually idk if Windows passes down such keypresses to applications)
  5. I've made a change to stb_textedit as well, where it calls different functions (is_word_boundary) based on whether it's next word forward or backward; this puts it in line with OS X behaviour, where the cursor sticks to the end of the word (before the space) if going forward, and sticks to the beginning of the word (after the space) if going backward. Linux does this too, only Windows (as usual) puts the cursor after the space, regardless of direction. Should this be merged as a local change (just a couple of lines), as a pull request to STB itself, or not at all?
  6. Finally, is the current implementation of doubleclick word select (ie. move cursor to previous word, hold shift, move cursor to next word) satisfactory? I could look into properly moving the cursor, if needed.

EDIT:
7. Actually, I think multiples selection in lists or something that's done with Ctrl also needs to be handled. I'll look into it.

Thanks for sticking around I suppose, hope to hear your opinions on this. Should make for a more fluid and comfortable experience for OS X users, at least.

@ocornut
Copy link
Owner Author

ocornut commented Jan 5, 2016

Late answer and happy new year :)

I'll have a go at a proper pull request for this, it shouldn't take long. A few things to clarify though:

Cmd/Ctrl should be a runtime setting defaulting based on APPLE. Does this bool go in ImGuiIO, or is somewhere else more appropriate?

I'll have to think a little further about that but for now you can put it in ImGuiIO. Down the line I expect user controllable behaviors for variety of things (eg: slider/drag behavior). Probably just keeping things in IO would just be simpler, but for some behavior it might make sense to Push/Pop the value and then perhaps the ImGuiStyle or another structure may feel more suited. For now let's not worry about that.

Should the double click text behaviour change as well? Would it always select by word when double clicking, or would this also be OS dependent? If the latter, should it be governed by the same setting as (1) (eg. OSXAlikeBehaviour) or separate, eg. TextShortcutsUseCmdKey and DoubleClickSelectsWord?

I suggest to make a different bool. Eg: InputTextShortcutsUsesSuperKey, InputTextDoubleClickSelectsWord.

I'm assuming KeyCmd would be present in the ImGuiIO struct regardless of OS? Should it then be named something more agnostic, like KeySuper or KeyGui? If the answer to the first question is "no", then ignore all this.

Yes, easier to always have in the structure regardless of OS. Let's call it KeySuper because glfw is the cool active thing in town for (with a comment mentioning it maps to Cmd/Windows key). People don't really use the Windows key ar all because it is awkward to use.

In a similar vein to (3), should there be new enum members for LSuper and RSuper in the ImGuiKey_ enum? And should the backends set this by default when handling events?

Yes, yes.

Should these be set for Windows systems as well? (Actually idk if Windows passes down such keypresses to applications)

I don't know either. I wouldn't bother setting them unless it looks trivial. If you don't have access to a Windows machine I'll do some basic tests but not worry if there's a hurdle.

I've made a change to stb_textedit as well, where it calls different functions (is_word_boundary) based on whether it's next word forward or backward; this puts it in line with OS X behaviour, where the cursor sticks to the end of the word (before the space) if going forward, and sticks to the beginning of the word (after the space) if going backward. Linux does this too, only Windows (as usual) puts the cursor after the space, regardless of direction. Should this be merged as a local change (just a couple of lines), as a pull request to STB itself, or not at all?

Ideally merged in STB itself with an additional flag. Sean probably won't merge soon but we can apply the patch locally.

Finally, is the current implementation of doubleclick word select (ie. move cursor to previous word, hold shift, move cursor to next word) satisfactory? I could look into properly moving the cursor, if needed.

Haven't looked yet, sorry.
Thanks for sticking around I suppose, hope to hear your opinions on this. Should make for a more fluid and comfortable experience for OS X users, at least.

Thanks for the help!

@ratchetfreak
Copy link

Instead of using the "&Save" syntax you could use "Save", VK_S, aka let the user pass in which indices you have to monitor in the keysDown array.

It does require that the user will also need to pass the correct index of which letter to highlight. Because you can't rely on any mapping between them. Then there is no overhead with text processing.

@ocornut
Copy link
Owner Author

ocornut commented Feb 11, 2016

That would add an extra parameter to every function which would be practically a no-no.
It would be bearable if we only used it for MenuItem but ideally we want local shortcuts for keyboard activation for all widgets (e.g. Button)

@ratchetfreak
Copy link

I'm tempted to say to change the string param to a special struct that includes all the data for the & alt menu (plus the label/ID stuff ofcourse).

Which also has a constructor taking a char* so it won't break existing code. Which can then do the bit of parsing needed for the "###ID" stuff and you may as well add the & parsing as well. Also it may be an option to use && to specify a literal & and &&& for the version where the & itself is the shortcut.

Though the viability of that struct may depend on how the ImStr experiment #494 turns out.

@emoon
Copy link
Contributor

emoon commented Mar 14, 2016

On a slightly related note something that would be nice is keyboard navigation of menus (excluding the actual shortcuts) but perhaps that belongs in a separate issue.

@ocornut
Copy link
Owner Author

ocornut commented Mar 14, 2016

Agree, it would make sense to aim for that support early on (there's a keyboard navigation task and menus could be worked on earlier). Tho up/down without alt+letter may feel incomplete?

On 13 Mar 2016, at 19:39, Daniel Collin notifications@github.com wrote:

On a slightly related note something that would be nice is keyboard navigation of menus (excluding the actual shortcuts) but perhaps that belongs in a separate issue.


Reply to this email directly or view it on GitHub.

@emoon
Copy link
Contributor

emoon commented Mar 14, 2016

I was thinking about popups in this case (at least on Mac if you have a popup and press arrow down you get keyboard focus and can navigate it with arrows and then enter to select an item)

But for regular menus that would be nice yes.

@ocornut
Copy link
Owner Author

ocornut commented Apr 14, 2016

So the simple solution to my problem with obtaining translated characters when ALT/CTRL is pressed to use with shortcuts, is instead to include printables like A-Z 0-9 in the ImGuiKey_ enum and work with key events.

Pros:

  • makes the remaining work of the shortcut API attainable :)
  • makes it a little easier to share ImGui code using keyboard in a portable way
  • don't need to break existing IO API (which would need to be reworked, but it can happen later)

Cons:

  • initial setup a little more length/annoying but we'll provide tables with all bindings supported by default.

@xaxxon
Copy link

xaxxon commented Aug 11, 2016

Is this the right thread to watch for things like cmd-a doing a select-all in a text box instead of ctrl-a on os x?

ocornut added a commit that referenced this issue May 23, 2024
…active. Made NavCalcPreferredRefPos() take account for remote activation. (#456)

Unsure why filter in ItemHandleShortcut(), will probably find out soon enough.
ocornut added a commit that referenced this issue May 23, 2024
…ow evaluation to SetShortcutRouting() for now. (#456)
@ocornut
Copy link
Owner Author

ocornut commented May 23, 2024

I have pushed a dozen more commits related to this topic, henceforth officially referred to as the Duke-Nukem-Forever™ of GitHub issues.

Now added public API:

// Inputs Utilities: Shortcut Testing & Routing
// - ImGuiKeyChord = a ImGuiKey + optional ImGuiMod_Alt/ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Super.
//       ImGuiKey_C                          // Accepted by functions taking ImGuiKey or ImGuiKeyChord arguments)
//       ImGuiMod_Ctrl | ImGuiKey_C          // Accepted by functions taking ImGuiKeyChord arguments)
//   only ImGuiMod_XXX values are legal to combine with an ImGuiKey. You CANNOT combine two ImGuiKey values.
// - The general idea is that several callers may register interest in a shortcut, and only one owner gets it.
//      Parent   -> call Shortcut(Ctrl+S)    // When Parent is focused, Parent gets the shortcut.
//        Child1 -> call Shortcut(Ctrl+S)    // When Child1 is focused, Child1 gets the shortcut (Child1 overrides Parent shortcuts)
//        Child2 -> no call                  // When Child2 is focused, Parent gets the shortcut.
//   The whole system is order independent, so if Child1 makes its calls before Parent, results will be identical.
//   This is an important property as it facilitate working with foreign code or larger codebase.
// - To understand the difference:
//   - IsKeyChordPressed() compares mods and call IsKeyPressed() -> function has no side-effect.
//   - Shortcut() submits a route, routes are resolved, if it currently can be routed it calls IsKeyChordPressed() -> function has (desirable) side-effects as it can prevents another call from getting the route.
// - Visualize registered routes in 'Metrics/Debugger->Inputs'.
bool      Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0);
void      SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0);
// Flags for Shortcut(), SetNextItemShortcut(),
// (and for upcoming extended versions of IsKeyPressed(), IsMouseClicked(), Shortcut(), SetKeyOwner(), SetItemKeyOwner() that are still in imgui_internal.h)
// Don't mistake with ImGuiInputTextFlags! (which is for ImGui::InputText() function)
enum ImGuiInputFlags_
{
    ImGuiInputFlags_None                    = 0,
    ImGuiInputFlags_Repeat                  = 1 << 0,   // Enable repeat. Return true on successive repeats. Default for legacy IsKeyPressed(). NOT Default for legacy IsMouseClicked(). MUST BE == 1.

    // Flags for Shortcut(), SetNextItemShortcut()
    // - Default policy is RouteFocused. Can select only 1 policy among all available.
    // - Priorities: GlobalHighest > Focused (if owner is active item) > GlobalOverFocused > Focused (if in focused window) > Global.
    ImGuiInputFlags_RouteFocused            = 1 << 12,  // Focus stack route (default): Accept inputs if window is in focus stack. Deep-most focused window takes inputs. ActiveId takes inputs over deep-most focused window.
    ImGuiInputFlags_RouteGlobal             = 1 << 13,  // Global route (normal priority): unless a focused window or active item registered the route) -> recommended Global priority.
    ImGuiInputFlags_RouteGlobalOverFocused  = 1 << 14,  // Global route (higher priority): unless an active item registered the route, e.g. CTRL+A registered by InputText will take priority over this).
    ImGuiInputFlags_RouteGlobalHighest      = 1 << 15,  // Global route (highest priority): unlikely you need to use that: will interfere with every active items, e.g. CTRL+A registered by InputText will be overridden by this)
    ImGuiInputFlags_RouteAlways             = 1 << 16,  // Do not register route, poll keys directly.
    ImGuiInputFlags_RouteUnlessBgFocused    = 1 << 17,  // Option: global routes will not be applied if underlying background/void is focused (== no Dear ImGui windows are focused). Useful for overlay applications.
    ImGuiInputFlags_RouteFromRootWindow     = 1 << 18,  // Option: route evaluated from the point of view of root window rather than current window.

    // Flags for SetNextItemShortcut()
    ImGuiInputFlags_Tooltip                 = 1 << 19,  // Automatically display a tooltip when hovering item.
};

Those seemingly innocuous functions have required months/years of yak-shaking and iterations. Much of the inputs system has transitioning to key-owner-awareness since 1.89 (november 2022)... with further iterations and long-time work on input routing (which I swear I must have rewritten 10 times).. untangled key handling (1.87 #4921)... related backend works for translated keys... decent macOS support (#2343 (comment))... remove nav activation/highlight without stealing focus/active id.... mod and keychord design, etc.

Not everything is in public API because I'm not sure of all the stuff, but those two are rather useful already:

Some typical use would be:

ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S);
ImGui::Button("Save");

By default it use the focus route, so here Ctrl+S will trigger button if parent window is focused, or one of its child.
Nested calls will react as generally desired, and regardless of call orders, so if a child window also claim Ctrl+S things will be resolved in favor of the child when the child is focused. The system also means that this plays nicely with widgets using their own shortcut, so with focus route if you try to use Ctrl+C it'll work when window is focused, but not when an InputText() using Ctrl+C is active, conversely using another shortcut can be made to work while the same InputText() is active.

But also note, e.g.

ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_RouteGlobal);
ImGui::Button("Save");

May be triggered when other windows are focused.

I currently offer an opt-in mouse-only (intentional) auto tooltip:

ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_Tooltip);
ImGui::Button("Save");

But I would consider making it opt-out once I am done with working on tooltip priority system (#7570)


Amusingly, because this is the Duke-Nukem-Forever™ of GitHub issues, in spite of much progress, many elements discussed at the very top of this thread are still undone:

  • embedded & alt-style shortcuts (we are now much closer to it, but for perf reasons there are some niggles ahead still)
  • unopened/blind menus running shortcuts (i have proof of concept for it, so most of the big infrastructure permits it, but i would like to do further rework on menu system so this may not be in soon)
  • display translated shortcuts on e.g. macOS (easy but require some careful design)

For the few people who have been using Shortcut() with a global route specifier, I have pushed some renaming (b4f564c) prior to moving it back in public API.

IMPORTANT! IF and only IF you have been using key-owner-aware API or Shortcut() prior to today, please be mindful of the following badly breaking changes:

  • 55748cd Renamed ImGuiKeyOwner_None to ImGuiKeyOwner_NoOwner:
  • 900b290 Swapped two last default parameters of Shortcut().
  • 85513de Swapped two last default parameters for owner-aware versions of IsKeyPressed(), IsKeyChordPressed(), IsMouseClicked().

@GamingMinds-DanielC
Copy link
Contributor

I have not used the shortcut interface much so far and did not look at its implementation yet. The newly added public interface looks promising, but could use a few more policies. So just as a suggestion...

  • ImGuiInputFlags_RouteHovered: accept input if window is hovered (or any of its children, hovered children take priority if they also register this route), slightly lower priority than ImGuiInputFlags_RouteFocused
  • ImGuiInputFlags_RouteHoveredOverFocused: same as ImGuiInputFlags_RouteHovered, but slightly higher priority than ImGuiInputFlags_RouteFocused

If they were to be added, ImGuiInputFlags_RouteGlobal would be lower priority than ImGuiInputFlags_RouteHovered as well while ImGuiInputFlags_RouteGlobalOverFocused would also take priority over ImGuiInputFlags_RouteHovered and ImGuiInputFlags_RouteHoveredOverFocused.

Moving the mouse to a window where you want to send the next keypress without an additional click is pretty efficient. Some applications like f.e. Maya use this shortcut policy and (some of) our artists like it a lot. When I get around to overhauling the shortcut system in our tools someday, I will either implement this policy in a custom system or maybe use the new public one if it supports hover routes by then. There's no need to implement it just for me, but I think this might be useful for other users too and it should integrate nicely with the other policies.

Another shortcut feature that I find to be very useful would be keychord sequences. Visual Studio f.e. has sequences like Ctrl+K, Ctrl+K (you can either press Ctrl+K twice or hold down Ctrl and press K twice, both count) to toggle a bookmark. With sequences like this, complex applications with tons of shortcuts can group related actions into easier to remember final presses while not running out of keys to use. A complete sequence clears the history of presses (so a 3rd Ctrl+K would not toggle the bookmark again). Any press that is not part of an available sequence would also cancel the sequence and is consumed right away (instead of triggering another shortcut or beginning another sequence). Of course, a single Ctrl+K as a shortcut would then effectively disable any sequence beginning with that keychord (unless a different routing allows it), but that would be a user error.

I don't know if keychord sequences whould already be doable with some clever use of this interface or if they are feasible for an immediate mode interface at all, I will probably need to experiment a bit. So no concrete suggestion yet, just maybe something to keep in mind for the future.

@ocornut
Copy link
Owner Author

ocornut commented May 24, 2024

ImGuiInputFlags_RouteHovered: accept input if window is hovered (or any of its children, hovered children take priority if they also register this route), slightly lower priority than ImGuiInputFlags_RouteFocused
ImGuiInputFlags_RouteHoveredOverFocused: same as ImGuiInputFlags_RouteHovered, but slightly higher priority than ImGuiInputFlags_RouteFocused

It seems possible to implement by mimicking some of the logic.
Note for later:

  • Storing a g.HoverRoute[] similar to g.NavFocusRoute[] would be preferable. Although not strictly necessary because in the case of hover it can be inferred from g.HoveredWindow and its parents, storing a compact form once a frame would be more efficient.
  • Right now we can store up to 250 levels of nested windows for focus, that would likely mean a split between 125 levels for hover and 125 levels for focus, which is likely way large enough, but either way expanding score storage in ImGuiKeyRoutingData from U8 to U16 would fit within existing padding and not a problem.

Another shortcut feature that I find to be very useful would be keychord sequences. Visual Studio f.e. has sequences like Ctrl+K, Ctrl+K (you can either press Ctrl+K twice or hold down Ctrl and press K twice, both count) to toggle a bookmark.

I would like to implement that indeed, the idea would be to pack in upper bits of ImGuiKeyChord. I think we already manipulate enough state that it should be feasible, but I presume it won't be trivial.
I think both things are worth their own thread/issue as this one is already packed with history.

ocornut added a commit that referenced this issue May 24, 2024
ocornut added a commit that referenced this issue May 24, 2024
…gs_RouteGlobalOverActive, made ImGuiInputFlags_RouteGlobalOverFocused and ImGuiInputFlags_RouteGlobalOverActive flags. (#456)
@ocornut
Copy link
Owner Author

ocornut commented May 24, 2024

I am concerned about priorities between Hovered and Focused. Regardless of being lower or higher, mixing both types is going to be very misleading. It may requires app hygiene to not mix both together too much.

I have found a solution to slightly decrease the perceived complexity of this.

Reducing the number of route types (only 1 of those can be choosen)

ImGuiInputFlags_RouteActive             = 1 << 10,  // Route to active item only.
ImGuiInputFlags_RouteFocused            = 1 << 11,  // Route to windows in the focus stack (DEFAULT). Deep-most focused window takes inputs. Active item takes inputs over deep-most focused window.
ImGuiInputFlags_RouteGlobal             = 1 << 12,  // Global route (unless a focused window or active item registered the route).
ImGuiInputFlags_RouteAlways             = 1 << 13,  // Do not register route, poll keys directly.

And making others flags which may be combined:

ImGuiInputFlags_RouteGlobalOverFocused  = 1 << 14,  // Option: global route, higher priority than focused route (unless active item in focused route). automatically sets ImGuiInputFlags_RouteGlobal.
ImGuiInputFlags_RouteGlobalOverActive   = 1 << 15,  // Option: global route, higher priority than active item. Unlikely you need to use that: will interfere with every active items, e.g. CTRL+A registered by InputText will be overridden by this. May not be fully honored as user/internal code is likely to always assume they can access keys when active. Automatically sets ImGuiInputFlags_RouteGlobal.
ImGuiInputFlags_RouteUnlessBgFocused    = 1 << 16,  // Option: global route, will not be applied if underlying background/void is focused (== no Dear ImGui windows are focused). Useful for overlay applications.

Notice how ImGuiInputFlags_RouteGlobalHighest got renamed to ImGuiInputFlags_RouteGlobalOverActive: with this subtlety of making them combinable flags, it doesn't require the reader to understand by heart the global/respective priority order.

It also means if we want to add an Hovered route we will only need to add ImGuiInputFlags_RouteHovered (between Focused and Global) and possibly ImGuiInputFlags_RouteGlobalOverHovered.

@ocornut
Copy link
Owner Author

ocornut commented May 24, 2024

I renamed those:

// - Routing options
ImGuiInputFlags_RouteOverFocused        = 1 << 14,  // Option: global route: higher priority than focused route (unless active item in focused route).
ImGuiInputFlags_RouteOverActive         = 1 << 15,  // Option: global route: higher priority than active item. Unlikely you need to use that: will interfere with every active items, e.g. CTRL+A registered by InputText will be overridden by this. May not be fully honored as user/internal code is likely to always assume they can access keys when active.
ImGuiInputFlags_RouteUnlessBgFocused    = 1 << 16,  // Option: global route: will not be applied if underlying background/void is focused (== no Dear ImGui windows are focused). Useful for overlay applications.

Because I think we would to use them with hypothetical Hovered route.

ocornut added a commit that referenced this issue May 24, 2024
…tFlags_RouteOverFocused, ImGuiInputFlags_RouteGlobalOverActive -> ImGuiInputFlags_RouteOverActive in previsiion of using them with a Hovered route. (#456)
@rayzchen
Copy link

rayzchen commented Jun 4, 2024

I'm not quite sure I can follow the current progress of this issue, so I'm just going to simply ask: does ImGUI support keyboard shortcuts for MenuItems which run the same code as if they were clicked? (regardless of whether the menu is open or not)

@ocornut
Copy link
Owner Author

ocornut commented Jun 4, 2024

so I'm just going to simply ask: does ImGUI support keyboard shortcuts for MenuItems which run the same code as if they were clicked? (regardless of whether the menu is open or not)

No, it doesn't do that now. Currently the shortcut field of MenuItem() is displayed for not used for anything else.

However, I do have the working proof of concept for it (~30 lines patch), and it was fully in my mind with the recent work done. But it's not fully in as it requires quite some menu API design (opt-in, fallback for recursion, transitioning to use ImGuiKeyChord to reduce amount of parsing which involve transition to multiple signatures).

@ocornut
Copy link
Owner Author

ocornut commented Jun 4, 2024

However, I do have the working proof of concept for it (~30 lines patch), and it was fully in my mind with the recent work done. But it's not fully in as it requires quite some menu API design (opt-in, fallback for recursion, transitioning to use ImGuiKeyChord to reduce amount of parsing which involve transition to multiple signatures).

Specifically, my big remaining design issue is the following:

(1) I would like to change

BeginMenu(const char* label, bool enabled = true);

to

BeginMenu(const char* label, ImGuiMenuFlags flags = 0);`,

with flags, e.g.

// Flags for ImGui::BeginMenu()
enum ImGuiMenuFlags_
{
    ImGuiMenuFlags_None               = 0,
    ImGuiMenuFlags_Disabled           = 1 << 1,   // We skip using (1 << 0) to detect ABI/bindings possible issue with old BeginMenu(const char*, bool)
    ImGuiMenuFlags_ProcessShortcuts   = 1 << 2,
};

That part is not so problematic and has been a common transition pattern, the signatures can co-exist, and also the bool enabled flag of BeginMenu() is rarely used.

(2) However, the equivalent change for MenuItem() is more complicated.

bool MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true);  // return true when activated.
bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true);              // return true when activated + toggle (*p_selected) if p_selected != NULL

(2.A) It would make sense to change const char* shortcut to ImGuiKeyChord shortcut as it would reduce parsing cost, simplify translation of some key mods (on Mac).

(2.B) Out of experience bool parameters have always been an API issue. So ideally I would remove them and replace with MenuFlags, this is the perfect occasion to do so. However in the context of MenuItem() those value are frequently evaluated inline, e.g. MenuItem("Save", ..., m_Document->IsDirty()) and enforcing flags would make the API a lots more verbose to work with.
The presence of an alternative bool* p_selected API is also a convenience, for which requiring user to call if (IsItemToggledSelection()) { selected ^= 1; } is going to be tedious.

So I need to factor those things in and come up with a design that senseful, forward facing, while not breaking backward compatibility in an horrible manner.

ocornut added a commit that referenced this issue Jul 2, 2024
…named to ImGuiKeyChord and ImGuiMod_XXX in 1.89). (#4921, #456)
Ciachociech added a commit to Ciachociech/imgui that referenced this issue Jul 24, 2024
* Version 1.90.8

* Version 1.90.9 WIP

* Internals: renamed HoveredIdDisabled to HoveredIdIsDisabled for consistency.

* Examples: GLFW+Vulkan: handle swap chain resize even without Vulkan returning VK_SUBOPTIMAL_KHR (ocornut#7671)

* Examples: SDL+Vulkan: handle swap chain resize even without Vulkan returning VK_SUBOPTIMAL_KHR (ocornut#7671)

* Removed old nested structure: renaming ImGuiStorage::ImGuiStoragePair type to ImGuiStoragePair (simpler for many languages).

* Internals: made ImLowerBound() accessible in internals + take a span. + rearrange child/popup/tooltips section.

Because upcoming rework of ImGuiSelectionBasicStorage will want to do a lower bound on a span.

* IO: do not disable io.ConfigWindowsResizeFromEdges when ImGuiBackendFlags_HasMouseCursors is not set by backend.

Amend 42bf149

* Style: (Breaking) renamed ImGuiCol_TabActive -> ImGuiCol_TabSelected, ImGuiCol_TabUnfocused -> ImGuiCol_TabDimmed, ImGuiCol_TabUnfocusedActive -> ImGuiCol_TabDimmedSelected.

Amend ocornut#261, ocornut#351

* TabBar, Style: added ImGuiTabBarFlags_DrawSelectedOverline and ImGuiCol_TabSelectedOverline, ImGuiCol_TabDimmedSelectedOverline.

* Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceExtern. (ocornut#143)

Amend 0c6e260

* Drag and Drop: Fixes an issue when elapsing payload would be based on last payload frame instead of last drag source frame.

* Internals: added ImGuiContext::ContextName optionally used by debug log and to facilitate debugging.

* Drag and Drop: comments, debug log entries.

* Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceExtern assume a mouse button being pressed. (ocornut#143)

* Drag and Drop: (Breaking) renamed ImGuiDragDropFlags_SourceAutoExpirePayload to ImGuiDragDropFlags_PayloadAutoExpire. (ocornut#1725, ocornut#143)

* Drag and Drop: Added ImGuiDragDropFlags_PayloadNoCrossContext and ImGuiDragDropFlags_PayloadNoCrossProcess flags.

* Ignore .ini file with other suffixes.

* Fixed build warning.

* IO: added ClearInputMouse(). made ClearInputKeys() not clear mouse data. (ocornut#4921)

Amend 6aa408c

* IO: added ImGuiConfigFlags_NoKeyboard for consistency and convenience. (ocornut#4921)

# Conflicts:
#	imgui.h
#	imgui_demo.cpp

* Nav: CTRL+Tab overlay display context name if any.

* Internals: storing HoveredWindowBeforeClear for use by multi-context compositor drag and drop propagation.

# Conflicts:
#	imgui.cpp
#	imgui_internal.h

* (Breaking) Move ImGuiWindowFlags_NavFlattened to ImGuiChildFlags_NavFlattened. (ocornut#7687)

* Backends: SDL3: Follow SDL3 removal of keysym field in SDL_KeyboardEvent (ocornut#7729)

* Demo: Style Editor: clarify how _CalcCircleAutoSegmentCount() doesn't always get exact final segment count. (ocornut#7731)

* Backends: Vulkan: Remove Volk/ from volk.h #include directives (ocornut#7722, ocornut#6582, ocornut#4854)

* Metrics/Debugger: Browsing a Storage perform hover lookup on identifier.

* Viewports: Backported 'void* ImGuiViewport::PlatformHandle' from docking branch for use by backends.

* Backends: SDL3: Update for SDL_StartTextInput()/SDL_StopTextInput() API changes. (ocornut#7735)

* Examples: undo adding SDL3 example to Visual Studio sln.

* Backends: OSX: build fix. Amend 32f9dfc

* ImGuiStorage: tweak impl for BuildSortByKey().

* Inputs: fixed using Shortcut() or SetNextItemShortcut() within a disabled block bypassing the disabled state. (ocornut#7726)

* Tables: moved TableGetHoveredColumn() to public API. (ocornut#7715, ocornut#3740)

* Windows: BeginChild(): fixed a glitch when during a resize of a child window which is tightly close to the boundaries of its parent. (ocornut#7706)

* Nav: store NavJustMovedToIsTabbing + shuffle a few nav related fields.

(for usage by multi-select)

* Backends: OpenGL2, OpenGL3: ImGui_ImplOpenGL3_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL3_DestroyFontsTexture(). (ocornut#7748)

Analogous to change to Vulkan backend in 1.90.

* Backends: Win32: Fixed warning with old MinGW/GCC versions.

* Drags: added ImGuisliderFlags_WrapAround flag for DragInt(), DragFloat() etc. (ocornut#7749)

* Fix typo, rename ImGuisliderFlags_WrapAround flag to ImGuiSliderFlags_WrapAround. (ocornut#7752, ocornut#7749)

* Checkbox: minor tidying up to simplify work on multi-select branch.

* Backends: Allegro5: Correctly handle unstable bit in version checks (ocornut#7755)

* Backends: SDLRenderer3: Update for SDL_RenderGeometryRaw() API changes.

* Backends: SDL3: update for SDL_SetTextInputRect() -> SDL_SetTextInputArea() api change. (ocornut#7760, ocornut#7754)

* Examples: SDL3: Remove use of SDL_HINT_IME_NATIVE_UI.

* Disabled: Reworked 1.90.8 behavior of Begin() not inheriting current BeginDisabled() state. Only tooltip are clearing that state. (ocornut#211, ocornut#7640)

* imgui_freetype: fixed divide by zero while handling FT_PIXEL_MODE_BGRA glyphs. (ocornut#7267, ocornut#3369)

* IO: do not claim io.WantCaptureMouse=true on the mouse release frame of a button which was pressed over void.  (ocornut#1392)

* Version 1.90.9

* Version 1.91.0 WIP

* Backends: SDL3: Update for API changes: SDLK_x renames and SDLK_KP_x removals (ocornut#7761, ocornut#7762)

Also updated function signature in SDL2 backend to match and because it is expected we will use that data (as per ocornut#7672)

* Backends: SDL3: Updated comments (IME seems fixed in SDL3). Added SDL3 examples to Visual Studio solution.

* Debug Tools: Added IMGUI_DEBUG_LOG(), ImGui::DebugLog() in public API. (ocornut#5855)

* Debug Log: Added "Configure Outputs.." button. (ocornut#5855)

* Backends: SDL3: add default case to fix warnings. (ocornut#7763)

* Demo: changed style editor inline block to its own window.

* IO: added io.PlatformOpenInShellFn handler to open a link/folder/file in OS shell, added IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS. (ocornut#7660)

* (Breaking) IO, IME: renamed platform IME hook io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() and added explicit context.

* Commented out obsolete ImGuiModFlags and ImGuiModFlags_XXX values (renamed to ImGuiKeyChord and ImGuiMod_XXX in 1.89). (ocornut#4921, ocornut#456)

* Build fix for non Windows platforms.

* IO: disable default io.PlatformOpenInShellFn() implementation on iPhone, as compiler errors that system() is not available on iOS.

* Internals: added FontScale storage.

* Added TextLink(), TextLinkOpenURL() hyperlink widgets. (ocornut#7660)

* Internals: added FontScale storage (amend 0f63d3e).

* Backends: GLFW,SDL2: Added ioPlatformOpenInShellFn handler for web/Emscripten versions. (ocornut#7660)

* IO: amend PlatformOpenInShellFn specs to return a bool. (ocornut#7660)

Amend 8f36798

* Misc tweaks, comments.

* TreeNode: rename/rework ImGuiNavTreeNodeData system to be usable by more features. (ocornut#2920, ocornut#1131, ocornut#7553)

Reworked to it is easier during TreeNode code to request extra data to be stored.

* Fixed Unix version of PlatformOpenInShellFn_DefaultImpl. (ocornut#7772, ocornut#7660)

+ Enable on non-iPhone macOS builds

* DemosFix typo in help text in demo Tables/Borders (ocornut#7780)

The help text for flags had a "V" flag duplicated, this change corrects it to the missing "H" flag.

* Backends: Win32: fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN (ocornut#7768, ocornut#4858, ocornut#2622)

Amend 0755767

The `ImGui_ImplWin32_UpdateKeyModifiers()` function maps `ImGuiMod_Super` to `VK_APPS`, the "Application" key located between the Right Windows (Super) and Right Control keys on the keyboard, see https://conemu.github.io/en/AppsKey.html

This means that when using `ImGui::GetIO().KeySuper` to try to get the down state of the `VK_RWIN` or `VK_LWIN` keys, it'll always return FALSE when either of those keys are held down, and only return TRUE when `VK_APPS` is held down.

* Backends: GLFW+Emscripten: (Breaking) Renamed ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback() to ImGui_ImplGlfw_InstallEmscriptenCallbacks(), added GLFWwindow* parameter. (ocornut#7647, ocornut#7600)

+ Fixed Emscripten warning when using mouse wheel on some setups.

* Backends: GLFW+Emscripten: Added support for GLFW3 contrib port. (ocornut#7647)

* Backends: GLFW+Emscripten: Fixed build (ocornut#7647)

* Examples: SDL3+OpenGL: Update for API changes: SDL_GL_DeleteContext() renamed to SDL_GL_DestroyContext().

* Fix definition check (ocornut#7793)

* Backends: SDL3: Update for API changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (ocornut#7794)

* Backends: SDL3: fixed typo leading to PlatformHandleRaw not being set leading to SHOWNA path not working for multi-viewports.

* Internals: Added TreeNodeIsOpen() to facilitate discoverability. (ocornut#7553, ocornut#1131, ocornut#2958, ocornut#2079, ocornut#722)

* Added ImGuiDataType_Bool for convenience.

* Demo: Reworked "Property Editor" demo in a manner that more ressemble the tree data and struct description data that a real application would want to use.

* Added PushItemFlag(), PopItemFlag(), ImGuiItemFlags.

* (Breaking) Obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag()/PopItemFlag() with ImGuiItemFlags_ButtonRepeat.

* Added ImGuiItemFlags_AutoClosePopups as a replacement for internal's ImGuiItemFlags_SelectableDontClosePopup. (ocornut#1379, ocornut#1468, ocornut#2200, ocornut#4936, ocornut#5216, ocornut#7302, ocornut#7573)

* (Breaking) Renamed ImGuiSelectableFlags_DontClosePopups to ImGuiSelectableFlags_NoAutoClosePopups. (ocornut#1379, ocornut#1468, ocornut#2200, ocornut#4936, ocornut#5216, ocornut#7302, ocornut#7573)

* Obsoleted PushTabStop()/PopTabStop() in favor of using new PushItemFlag()/PopItemFlag() with ImGuiItemFlags_NoTabStop.

* Fixed pvs-studio warning.

* Demo: Property Editor: rearrange code + replace use of bool to proper ImGuiChildFlags.

Amend 46691d1

* Demo: Property Editor: add basic filter.

* Style: close button and collapse/window-menu button hover highlight made rectangular instead of round.

The reason they were round in the first place was to work better with rounded windows/frames.
However since the 4a81424 rework ocornut#6749 we can naturally use a tigher bounding box and it seems to work ok either way.

* Nav, Demo: comments.

* Clipper: added SeekCursorForItem() function, for use when using ImGuiListClipper::Begin(INT_MAX). (ocornut#1311)

Tagging ocornut#3609 just in case we made a mistake introducing a regression (but tests are passing and have been extended).

* TreeNode: Internals: facilitate dissociating item ID from storage ID (useful for 1861)

* Internals: rename recently added TreeNodeIsOpen() -> TreeNodeGetOpen(). (ocornut#7553, ocornut#1131, ocornut#2958, ocornut#2079, ocornut#722)

Amend ac7d6fb

* Backends: SDL3: Update for API changes: SDL_GetClipboardText() string ownership change. (ocornut#7801)

* MultiSelect: WIP range-select (ocornut#1861) (rebased six millions times)

* MultiSelect: Removed SelectableSpacing as I'm not sure it is of use for now (history insert)

* MultiSelect: Added IMGUI_HAS_MULTI_SELECT define. Fixed right-click toggling selection without clearing active id, could lead to MarkItemEdited() asserting. Fixed demo.

* MultiSelect: Demo sharing selection helper code. Fixed static analyzer warnings.

* MultiSelect: Renamed SetNextItemMultiSelectData() to SetNextItemSelectionUserData()

* MultiSelect: Transition to use FocusScope bits merged in master.

Preserve ability to shift+arrow into an item that is part of FocusScope but doesn't carry a selection without breaking selection.

* MultiSelect: Fix for TreeNode following merge of 011d475. Demo: basic test for tree nodes.

* MultiSelect: Fixed CTRL+A not testing focus scope id. Fixed CTRL+A not testing active id. Added demo code.

Comments.

* MultiSelect: Comments. Tweak demo.

* MultiSelect: Fix Selectable() ambiguous return value, clarify need to use IsItemToggledSelection().

* MultiSelect: Fix testing key mods from after the nav request (remove need to hold the mod longer)

* MultiSelect: Temporary fix/work-around for child/popup to not inherit MultiSelectEnabled flag, until we make mulit-select data stackable.

* MultiSelect: Fixed issue with Ctrl+click on TreeNode + amend demo to test drag and drop.

* MultiSelect: Demo: Add a simpler version.

* MultiSelect: Added ImGuiMultiSelectFlags_ClearOnEscape (unsure of best design), expose IsFocused for custom shortcuts.

* MultiSelect: Demo: Added pointer indirection and indent level.

This is to reduce noise for upcoming commits, ahead of adding a loop here.

* MultiSelect: Added ImGuiMultiSelectFlags_ClearOnClickWindowVoid. + Demo: showcase multiple selection scopes in same window.

* MultiSelect: Enter doesn't alter selection (unlike Space).

Fix for changes done in 5606.

* MultiSelect: Shallow tweaks/refactors.

Including moving IsFocused back internally for now.

* MultiSelect: Fixed needing to set RangeSrcPassedBy when not using clipper.

* MultiSelect: made SetNextItemSelectionData() optional to allow disjoint selection (e.g. with a CollapsingHeader between items). Amend demo.

* MultiSelect: Enter can alter selection if current item is not selected.

* MultiSelect: removed DragDropActive/preserve_existing_selection logic which seems unused + comments.

Can't find trace of early prototype for range-select but I couldn't find way to trigger this anymore. May be wrong. Will find out.

* MultiSelect: refactor before introducing persistant state pool and to facilitate adding recursion + debug log calls.

This is mostly the noisy/shallow stuff committed here, to get this out of the way.

* MultiSelect: (Breaking) Rename ImGuiMultiSelectData to ImGuiMultiSelectIO.

* MultiSelect: Demo tweak. Removed multi-scope from Advanced (too messy), made it a seperate mini-demo.

* MultiSelect: Internals rename of IO fields to avoid ambiguity with io/rw concepts + memset constructors, tweaks.

debug

* MultiSelect: (Breaking) Renamed 'RangeSrc -> 'RangeSrcItem', "RangeDst' -> 'RangeDstItem'

This is necessary to have consistent names in upcoming fields (NavIdItem etc.)

* MultiSelect: (Breaking) Renamed 'RangeValue' -> 'RangeSelected' + amend comments.

* MultiSelect: Remove ImGuiMultiSelectFlags_NoUnselect because I currently can't find use for this specific design.

And/or it seem partly broken.

* MultiSelect: Remove the need for using IsItemToggledSelection(). Update comments.

This is the simple version that past our tests. MultiSelectItemFooter() is in need of a cleanup.

* MultiSelect: Tidying up/simpllifying MultiSelectItemFooter().

Intended to be entirely a no-op, merely a transform of source code for simplification. But committing separatey from behavior change in previous change.

* MultiSelect: Clarify and better enforce lifetime of BeginMultiSelect() value.

* MultiSelect: Demo: first-draft of user-side deletion idioms.

(will need support from lib)

* MultiSelect: (Breaking) BeginMultiSelect() doesn't need two last params maintained by users. Moving some storage from user to core. Proper deletion demo.

* MultiSelect: Maintain NavIdSelected for user. Simplify deletion demo.

* MultiSelect: Further simplication of user code to support Deletion.

Provide standard RequestFocusItem storage.

* MultiSelect: Demo: Delete items from menu.

* MultiSelect: Fixed right-click handling in MultiSelectItemFooter() when not focused.

* MultiSelect: Cleanup unused comments/code.

* MultiSelect: (Breaking) Fix + Rename ImGuiMultiSelectFlags_NoMultiSelect to ImGuiMultiSelectFlags_SingleSelect as it seems easier to grasp.

Feature was broken by "Tidying up..." June 30 commit.

* MultiSelect: Comments, tweaks.

+ Alignment to reduce noise on next commit.

* MultiSelect: (Breaking) Use ImGuiSelectionUserData (= ImS64) instead of void* for selection user data.

Less confusing for most users, less casting.

* MultiSelect: move HasSelectionData to ImGuiItemFlags to facilitate copying around in standardized fieds.

Required/motivated to simplify support for ImGuiTreeNodeFlags_NavLeftJumpsBackHere (bc3c0ce) in this branch.

* MultiSelect: Tweak debug log to print decimal+hex values for item data.

Struggled to get standard PRIX64 to work on CI.

* MultiSelect: clear selection when leaving a scope with a nav directional request.

May need to clarify how to depends on actions being performed (e.g. click doesn't).
May become optional?

* MultiSelect: (Breaking) RequestSetRange's parameter are RangeFirstItem...RangeLastItem (which was always ordered unlike RangeSrcItem...RangeDstItme). Removed RangeDstItem. Removed RangeDirection.

* MultiSelect: Demo: rework ExampleSelection names to map better to typical user code + variety of Comments tweaks.

* MultiSelect: Demo: added simpler demo using Clipper. Clarify RangeSrcPassedBy doc.

* MultiSelect: (Breaking) Removed RangeSrcPassedBy in favor of favoring user to call IncludeByIndex(RangeSrcItem) which is easier/simpler to honor.

Especially as recent changes made it required to also update RangeSrcPassedBy after last clipper Step.
Should now be simpler.

* MultiSelect: Demo: rework ExampleSelection with an ExampleSelectionAdapter layer, allowing to share more code accross examples using different storage systems.

Not ideal way to showcase this demo but this is really more flexible.

* MultiSelect: Demo: Remove UserDataToIndex from ExampleSelectionAdapter.

Seems to make a better demo this way.

* MultiSelect: Demo: Make ExampleSelection use ImGuiID. More self-explanatory.

* MultiSelect: Demo: Deletion: Rework ApplyDeletionPreLoop to use adapter + fix PostLoop not using right value of RequestFocusItem.

Recovery made it transparent visually but user side selection would be empty for a frame before recovery.

* MultiSelect: Demo: Deletion: Various renames to clarify. Use adapter and item list in both ApplyDeletion functions.

This also minify the patch for an alternative/wip attmept at redesgining pre/post deletion logic. But turns out current attempt may be easier to grasp.

* Demo: Dual List Box: Added a dual list box (6648)

* MultiSelect: ImGuiMultiSelectIO's field are not used during loop anymore, stripping them out of comments.

* MultiSelect: moved RequestClear output so it'll match request list version better. Use Storage->RangeSrcItem in EndMultiSelect().

* MultiSelect: move shared logic to MultiSelectItemHeader().

No logic change AFAIK but added an indent level in MultiSelectItemHeader(). Logic changes will come in next commit.

* MultiSelect: Added ImGuiMultiSelectFlags_SelectOnClickRelease to allow dragging an unselected item without altering selection + update drag and drop demo.

* Demo: Assets Browser: Added assets browser demo.

* Demo: Assets Browser: store items, sorting, type overlay.

* MultiSelect: removed seemingly unnecessary block in BeginMultiSelect().

- EndIO.RangeSelected always set along with EndIO.RequestSetRange
- Trying to assert for the assignment making a difference when EndIO.RequestSetRange is already set couldn't find a case (tests passing).

* MultiSelect: clarified purpose and use of IsItemToggledSelection(). Added assert. Moved to multi-selection section of imgui.h.

* MultiSelect: added missing call on Shutdown(). Better reuse selection buffer.

* MultiSelect: (Breaking) io contains a ImVector<ImGuiSelectionRequest> list.

* MultiSelect: we don't need to ever write to EndIO.RangeSrcItem as this is not meant to be used.

* MultiSelect: added support for recovery in ErrorCheckEndWindowRecover().

* MultiSelect: use a single ImGuiMultiSelectIO buffer.

+ using local storage var in EndMultiSelect(), should be no-op.

* MultiSelect: simplify clearing ImGuiMultiSelectTempData.

* Demo: Assets Browser: add hit spacing, requierd for box-select patterns.

* MultiSelect: (breaking) renamed ImGuiMultiSelectFlags_ClearOnClickWindowVoid -> ImGuiMultiSelectFlags_ClearOnClickVoid. Added ImGuiMultiSelectFlags_ScopeWindow, ImGuiMultiSelectFlags_ScopeRect.

* MultiSelect: Box-Select: added support for ImGuiMultiSelectFlags_BoxSelect.

(v11)
FIXME: broken on clipping demo.

* MultiSelect: Box-Select: added scroll support.

* MultiSelect: Demo: rework and move selection adapter inside ExampleSelection.

* MultiSelect: added support for nested/stacked BeginMultiSelect().

Mimicking table logic, reusing amortized buffers.

* MultiSelect: remove ImGuiSelectionRequest/ImGuiMultiSelectIO details from public api to reduce confusion + comments.

* MultiSelect: move demo's ExampleSelection to main api as a convenient ImGuiSelectionBasicStorage for basic users.

* MultiSelect: reworked comments in imgui.h now that we have our own section.

* MultiSelect: Demo: Assets Browser: added deletion support. Store ID in selection. Moved QueueDeletion to local var to emphasis that this is a user extension.

* MultiSelect: Demo: Assets Browser: track scrolling target so we can roughly land on hovered item.

It's impossible to do this perfectly without some form of locking on item because as the hovered item X position changes it's easy to drift.

* MultiSelect: Box-Select: Fixed holes when using with clipper (in 1D list.)

Clipper accounts for Selectable() layout oddity as BoxSelect is sensitive to it.
Also tweaked scroll triggering region inward.
Rename ImGuiMultiSelectFlags_NoBoxSelectScroll to ImGuiMultiSelectFlags_BoxSelectNoScroll.
Fixed use with ImGuiMultiSelectFlags_SinglaSelect.

* MultiSelect: Box-Select: Added ImGuiMultiSelectFlags_BoxSelect2d support. Enabled in Asset Browser. Selectable() supports it.

* MultiSelect: Box-Select: Refactor into its own structure, designed for single-instance but closer to being reusable outside Multi-Select.

Kept same member names.

* MultiSelect: Box-Select: Refactor: Renames.

Split into two commits to facilite looking into previous one if needed.

* MultiSelect: Box-Select: Fixed scrolling on high framerates.

* MultiSelect: Box-Select: Further refactor to extra mode code away from multi-select function into box-select funcitons.

* MultiSelect: Fixed ImGuiSelectionBasicStorage::ApplyRequests() incorrectly maintaining selection size on SelectAll.

* MultiSelect: Comments + Assets Browser : Tweak colors.

* MultiSelect: Added ImGuiMultiSelectFlags_NoRangeSelect. Fixed ImGuiMultiSelectFlags_ScopeRect not querying proper window hover.

* MultiSelect: Box-Select: Fixed CTRL+drag from void clearing items.

* MultiSelect: Box-Select: Fixed initial drag from not claiming hovered id, preventing window behind to move for a frame.

* MultiSelect: Fixed ImGuiMultiSelectFlags_SelectOnClickRelease over tree node arrow.

* MultiSelect: (Breaking) merge ImGuiSelectionRequestType_Clear and ImGuiSelectionRequestType_SelectAll into ImGuiSelectionRequestType_SetAll., rename ImGuiSelectionRequest::RangeSelected to Selected.

The reasoning is that it makes it easier/faster to write an adhoc ImGuiMultiSelectIO handler (e.g. trying to apply multi-select to checkboxes)

* MultiSelect: Simplified ImGuiSelectionBasicStorage by using a single SetItemSelected() entry point.

* MultiSelect: Comments + tweaked location for widgets to test ImGuiItemFlags_IsMultiSelect to avoid misleading into thinking doing it before ItemAdd() is necessary.

* MultiSelect: Demo: make various child windows resizable, with synched heights for the dual list box demo.

* MultiSelect: added ImGuiMultiSelectFlags_NoAutoSelect, ImGuiMultiSelectFlags_NoAutoClear features + added Checkbox Demo

Refer to "widgets_multiselect_checkboxes" in imgui_test_suite.

* MultiSelect: Box-Select: fix preventing focus. amend determination of scope_hovered for decorated/non-child windows + avoid stealing NavId. (ocornut#7424)

* MultiSelect: Demo: use Shortcut().

Got rid of suggestion to move Delete signal processing to BeginMultiSelect(), seems unnecessary.

* RangeSelect/MultiSelect: (Breaking) Added current_selection_size to BeginMultiSelect().

Required for shortcut routing so we can e.g. have Escape be used to clear selection THEN to exit child window.

* MultiSelect: Box-Select: minor refactor, tidying up.

* MultiSelect: Box-Select: when dragging from void, first hit item sets NavId by simulating a press, so navigation can resume from that spot.

* MultiSelect: added GetMultiSelectState() + store LastSelectionSize as provided by user, convenient for quick debugging and testing.

* MultiSelect: Box-Select: fixed "when dragging from void" implementation messing with calling BeginMultiSelect() without a selection size.

* MultiSelect: (breaking) renamed ImGuiSelectionBasicStorage::AdapterData to UserData.

* MultiSelect: Box-Select: fixes for checkboxes support. Comments.

* MultiSelect: (breaking) renamed ImGuiMultiSelectFlags_BoxSelect -> ImGuiMultiSelectFlags_BoxSelect1d, ImGuiMultiSelectFlags_BoxSelect2d -> ImGuiMultiSelectFlags_BoxSelect.

ImGuiMultiSelectFlags_BoxSelect1d being an optimization it is the optional flag.

* MultiSelect: mark parent child window as navigable into, with highlight. Assume user will always submit interactive items.

* MultiSelect: (breaking) Added 'items_count' parameter to BeginMultiSelect(). Will enable extra features, and remove equivalent param from ImGuiSelectionBasicStorage::ApplyRequests(.

* MultiSelect: added ImGuiSelectionBasicStorage::GetStorageIdFromIndex() indirection to be easier on the reader.

Tempting to make it a virtual.

* MultiSelect: fixed ImGuiSelectionBasicStorage::Swap() helper.

* MultiSelect: added ImGuiSelectionExternalStorage helper. Simplify bool demo.

* MultiSelect: comments, header tweaks., simplication (some of it on wiki).

* MultiSelect: ImGuiSelectionBasicStorage: added GetNextSelectedItem() to abstract selection storage from user. Amend Assets Browser demo to handle drag and drop correctly.

* MultiSelect: ImGuiSelectionBasicStorage: rework to accept massive selections requests without flinching.

Batch modification + storage only keeps selected items.

* MultiSelect: ImGuiSelectionBasicStorage: simplify by removing compacting code (compacting may be opt-in?).

GetNextSelectedItem() wrapper gives us more flexibility to work on this kind of stuff now.

* MultiSelect: ImGuiSelectionBasicStorage: move function bodies to cpp file.

+ make ImGuiStorage::BuildSortByKey() less affected by msvc debug mode.

* Demo: Assets Browser: added a way to disable sorting and hide sorting options.

This is mostly designed to showcase that on very large sets (e.g. 1 million) most of the time is likely spent on sorting.

* MultiSelect: ImGuiSelectionBasicStorage: (breaking) rework GetNextSelectedItem() api to avoid ambiguity/failure when user uses a zero id.

* MultiSelect: provide RangeDirection to allow selection handler to handler backward shift+click.

* MultiSelect: ImGuiSelectionBasicStorage: added PreserveOrder, maintain implicit order data in storage.

Little tested but provided for completeness.

* MultiSelect: (breaking) renamed ImGuiMultiSelectFlags_BoxSelect -> ImGuiMultiSelectFlags_BoxSelect2d. Which include not assuming one flag imply the other.

Amend 2024/05/31 commit.

* MultiSelect: Shift+Tab doesn't enable Shift select on landing item.

* MultiSelect: added ImGuiMultiSelectFlags_NoAutoClearOnReselect + tweak flags comments. (ocornut#7424)

* MultiSelect: minor tidying up.

Checkbox() was reworked in master effectively fixing render clipping when culled by BoxSelect2d's UnclipMode.

* MultiSelect: added courtesy ImGuiMultiSelectFlags_NavWrapX flag so we can demo this until a nav api is designed.

* MultiSelect: Box-Select: uses SetActiveIdUsingAllKeyboardKeys() to avoid nav interference, much like most drag operations.

* MultiSelect: Box-Select: handle Esc to disable box-select.

This avoid remove a one-frame delay when finishing box-select, where Esc wouldn't be routed to selection but to child.

* MultiSelect: ImGuiSelectionBasicStorage: optimized for smaller insertion amounts in larger sets + fix caling batch select with same value.

* MultiSelect: Better document how TreeNode() is not trivially usable yet.

Will revert when the time is right.

* MultiSelect: added Changelog for the feature. Removed IMGUI_HAS_MULTI_SELECT.

* Demo: moved ExampleTreeNode, ExampleMemberInfo above in the demo file. Tidying up index.

+ change ExampleTreeNode::UID from ImGuiID to int to not suggest that the user ID needs to be of a certain type

* Demo: moved some fields inside a struct.

* Demo: moved menu bar code to its own function.

* MultiSelect: using ImGuiMultiSelectFlags_NoRangeSelect ensure never having to interpolate between two ImGuiSelectionUserData.

* Inputs: added SetItemKeyOwner(ImGuiKey key) in public API. (ocornut#456, ocornut#2637, ocornut#2620, ocornut#2891, ocornut#3370, ocornut#3724, ocornut#4828, ocornut#5108, ocornut#5242, ocornut#5641)

* Backends: SDL3: Update for API changes: SDL_GetGamepads() memory ownership change. (ocornut#7807)

* TabBar, Style: added style option for the size of the Tab-Bar Overline (ocornut#7804)

Amend 21bda2e.

* Added a comment hinting at how to set IMGUI_API for shared librairies on e.g. Linux, macOS (ocornut#7806)

* Demo: rework Property Editor.

* Nav: fixed c licking window decorations (e.g. resize borders) from losing focused item when within a child window using ImGuiChildFlags_NavFlattened.

In essence, using ImGuiFocusRequestFlags_RestoreFocusedChild here is a way to reduce changes caused by FocusWindow(), but it could be done more neatly.
See amended "nav_flattened" test.

* Demo: Property Editor: using ImGuiChildFlags_NavFlattened now that a bug is fixed. Fixed static analyzer.

* Backends: OpenGL3: Fixed unsupported option warning with apple clang (ocornut#7810)

* Internals, TreeNode: indent all render block into its own scope (aim is to add a is_visible test there later)

* Internals, TreeNode, Selectable: tweak span_all_columns paths for clarity.

* CollapsingHeader: left-side outer extend matches right-side one (moved left by one pixel)

Amend c3a348a

* Debug Log: fixed incorrect checkbox layout when partially clipped., doesn't parse 64-bits hex value as ImGuiID lookups.

* Groups, Tables: fixed EndGroup() failing to correctly capture current table occupied size. (ocornut#7543)

See "layout_group_endtable" test.

* MultiSelect: sequential SetRange merging not generally handled by box-select path, useful for others.

* MultiSelect: add internal MultiSelectAddSetAll() helper.

* MultiSelect: fixed an issue caused by previous commit.

Amend a285835. Breaks box-select.

---------

Co-authored-by: ocornut <omarcornut@gmail.com>
Co-authored-by: cfillion <cfillion@users.noreply.github.com>
Co-authored-by: Gary Geng <garygengxiao@gmail.com>
Co-authored-by: Martin Ejdestig <marejde@gmail.com>
Co-authored-by: Kevin Coghlan <mail@kevincoghlan.com>
Co-authored-by: Connor Clark <cjamcl@gmail.com>
Co-authored-by: Max Ortner <maxortner01@gmail.com>
Co-authored-by: Hugues Evrard <hevrard@users.noreply.github.com>
Co-authored-by: Aemony <10578344+Aemony@users.noreply.github.com>
Co-authored-by: Yan Pujante <ypujante@proton.me>
Co-authored-by: Cyao <94928179+cheyao@users.noreply.github.com>
Co-authored-by: wermi <32251376+wermipls@users.noreply.github.com>
Co-authored-by: Thomas Stehle <th.stehle@icloud.com>
@anthofoxo
Copy link

anthofoxo commented Aug 15, 2024

Wanted to leave a small comment on a workaround getting shortcuts in menu items. Since you typically want these global, you'll always want to test for the shortcut.

// Check global action at start of the frame
ImGuiKeyChord chord = ImGuiMod_Ctrl | ImGuiKey_O;
bool isRouted = ImGui::GetShortcutRoutingData(chord)->RoutingCurr != ImGuiKeyOwner_NoOwner;
if (!isRouted && ImGui::IsKeyChordPressed(chord)) {
    // Perform action
}

// Within a `BeginMenuBar` and `BeginMenu`
if (ImGui::MenuItem("Open", ImGui::GetKeyChordName(chord))) {
    // Perform action
}

GetShortcutRoutingData tells us the routing information for the chord. And if it isn't routed. We can perform our global action.

Note that calling SetNextItemShortcut for a MenuItem won't work unless the menu is actively open.

This method has worked nicely thus far for me. And still allows to set shortcuts for other items.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests