ocornut/imgui

Menus API work

ocornut opened this issue · 68 comments

Discussion for an upcoming menu api (still being designed).
If you have ideas or references of menu being implemented in imgui systems please post here!

Some thoughts:

  • Menu items typically contains a label, an optional checkmark, an optional local shortcut, an optional global shorcut, an optional link to a submenu, an optional Icon. Menus will be created and developed in a way analogous to the existing patterns in ImGui. API needs to be terse for the common case.
  • We should be able to use most types of widgets within a menu. Menu specialize for "menu items" but other widgets should be usable. We should be able to pack sliders or images into a menu.
  • We need "menu bars" as the common way to layout menus. Menu bars can be inside individual windows but we need to provide an easy way to have a "top of the screen" menu bar. Also provide easy way to hide menus.
  • We want popups menu. They are likely spawned from an event (e.g. clicking a button). This is posing a small problem: if a menu appears upon reacting to an event, we need to design a coding pattern that will allow the menu to stay on after the event has happened.
  • Support local keyboard shortcuts, We can use Windows syntax of using & (e.g. "&Save") for convenience.
  • 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.
  • Menu navigation may requires ImGui to support more thorough keyboard navigation (currently we only handle TAB and Shift+TAB for navigation).
  • Menus needs to scroll if they can't fit in screen.
  • Menus needs to position themselves nicely when opened from a parent menu.
  • Search in menus like OSX does?

To mimic similar existing api, the "default" could be something like this:

IMGUI_API bool MenuBegin(const char* label, flags);
IMGUI_API bool Item(const char* label, const char* shortcut = "", bool enabled = true, bool selected = false);
IMGUI_API bool Item(const char* label, const char* shortcut, bool enabled, bool* p_selected);

Using overload of Item(), Not considering extra parameters to MenuBegin yet.

if (ImGui::BeginMenu("&File"))
{
    if (ImGui::Item("&New", "CTRL+N")) {}
    if (ImGui::Item("&Open..", "CTRL+O")) {}
    if (ImGui::Item("&Save", "CTRL+S") {}
    if (ImGui::Item("Save &As..")) {}
    ImGui::Separator();
    if (ImGui::BeginMenu("Recent Files"))
    {
        // iterate items..
        // e.g. if (ImGui::Item("&1. filename.txt")) {}
        ImGui::EndMenu();
    }
    ImGui::Separator();
    if (ImGui::Item("Quit", "CTRL+W")) {}
    ImGui::EndMenu();
}

But something along those lines.
We could potentially store the activated item and have an api to query it back before the end of a menu or later (it would match the char* the user passed), which would allow to write the "execution" code later. If this ends up a useful pattern we can pass around a parameter (id, pointer, etc.) to make the execution code shorter to write. But it make sense to focus on immediate execution as the common case since this is analogous to everything else in ImGui.

The order of parameters makes it a bit tricky if we want to add a printf-format style version of the function, but I imagine this is rather rare (e.g. for filenames in a Recent Files you may want to embed a local shortcut). I don't have a solution I am happy with for that.

I would imagine that Popup menu can work in a similar way:

ImGui::BeginPopupMenu();
if (ImGui::Item("Foo")) {}
ImGui::EndMenu();

Yes, but you'd need to keep track of the menu lifetime somehow. Pseudo-code:

static bool popup_is_active = false;
if (ImGui::Button("click me"))
    popup_is_active = true;

if (ImGui::BeginPopupMenu(&popup_is_active))
{
    if (ImGui::Item("Foo")) {}
    ImGui::EndMenu();
}

ImGui would keep track of the menu being active. Clicking outside the menu or pressing Escape would deactivate it.

Or better?

if (ImGui::Button("clickme"))
   ImGui::OpenPopupMenu("popup_id");

if (ImGui::BeginPopupMenu("popup_id"))
{
    if (ImGui::Item("Foo")) {}
    ImGui::EndMenu();
}

Except ID can be string / idx / pointer the same way ImGui::TreeNode() allows for all three. Then within a tree we can test for right-click over a node and start a popup that would run for this specific node.

How would it work for mouse? Something like this?

if (ImGui::IsRmbDown())
{
  if (ImGui::BeginPopupMenu("popup_id"))
  {
    if (ImGui::Item("Foo")) {}
    ImGui::EndMenu();
  }
}

I think this is quite common because you may not press an actual control to bring up a Popup menu.

Hum.. I think I like approach 1 better even if I don't have any strong opinions about it.

Under the above scheme it would be somethng like

if (!ImGui::IsAnyItemActive() && ImGui::IsMouseClicked(2))
{
    ImGui::OpenPopup("foobar");
}
if (ImGui::BeginPopup("foobar"))
{
   ...
}

Which leaves a chance for another item to be active or another more specialized menu to run. Note how the Begin() test is outside of the mouse test block.

With the Open/Begin scheme maybe Begin is a misleading word. It is more analogous to TreeNode() which tests a state (is the tree node open). Or if we keep the bool on the user side as in the first example of my previous post, then we become more analogous to Begin() so it is clearer but the common case requires a little more work. So to reiterate:

static bool menu_opened = false;
if (!ImGui::IsAnyItemActive() && ImGui::IsMouseClicked(2))
{
    menu_opened = true;
}
if (ImGui::BeginPopup(&menu_opened))
{
   ...
}

Alright. That makes sense.

Add to that: as a user I would like to be able to right-click on any tree node and have popup with a "Copy" button that allows copying the entire node contents to the clipboard (the logging api allows to do that easily). I think it'd be a sensible default in many cases.

Now, ideally I don't want to user to have to add the popup code after every TreeNode call. The user can create their own replacement helper for TreeNode() that does both. Or we can have a dedicated functionality just for this case were TreeNode can automatically spawn a popup with a "Copy" function when right-clicking. Or we can have a system where the user can push a callback to provide a default popup menu. Either way it would need to allow the user code to ignore that menu and create their own. Not sure how to approach that exactly but it is solvable. I guess this is more of a feature of the general/tree API rather than specific to menus.

FYI i tested and added a demo of the idea of creating popup menus with the existing API.

popup

static bool popup_open = false;
static int selected_fish = -1;
const char* fishes[] = { "Bream", "Mackerel", "Pollock", "Tilefish" };
if (ImGui::Button("Select.."))
{
    popup_open = true;
    ImGui::SetNextWindowPos(ImGui::GetMousePos());
}
ImGui::SameLine();
ImGui::Text(selected_fish == -1 ? "<None>" : fishes[selected_fish]);
if (popup_open)
{
    ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
    ImGui::Begin("##Popup", &popup_open, ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize);
    if (!ImGui::IsWindowFocused())
        popup_open = false;
    for (size_t i = 0; i < IM_ARRAYSIZE(fishes); i++)
        if (ImGui::Selectable(fishes[i], false))
        {
            selected_fish = i;
            popup_open = false;
        }
    ImGui::End();
    ImGui::PopStyleVar();
}

There's a few problems but it works. I hope by the next version I'll be able to turn that into a 2nd class citizen (with shorter API, automatic positioning, clipping within screen, perhaps ALT+letter shortcuts).

Some of the most immediate problems with this:

  • The Begin() call is long.
  • Won't position elegantly if size is too big.
  • Creating a tooltip (within the popup window or elsewhere, e.g. hovering another window that has code to create a tooltip) will unfocus and remove the popup.

I added a simple BeginPopup() / EndPopup() API to wrap the pattern above.

static bool popup_open = false;
static int selected_fish = -1;
const char* fishes[] = { "Bream", "Mackerel", "Pollock", "Tilefish" };
if (ImGui::Button("Select.."))
    popup_open = true;
ImGui::SameLine();
ImGui::Text(selected_fish == -1 ? "<None>" : fishes[selected_fish]);

if (popup_open)
{
    ImGui::BeginPopup(&popup_open))
    for (size_t i = 0; i < IM_ARRAYSIZE(fishes); i++)
        if (ImGui::Selectable(fishes[i], false))
        {
            selected_fish = i;
            popup_open = false;
        }
    ImGui::EndPopup();
}

I tweaked that enough that BeginPopup() / EndPopup() is pretty much usable now.
You can fill the menu with
if (Selectable("Item.."))

You won't get icons/shortcuts/submenus expected in a normal menu yet.
EDIT Of course you can repro those with custom code, but may not be worth it, better add the features in core ImGui.

Nice! Will check this out as soon as I have time.

I think there is a bug here 😄
bug

Hmm strange is your style modified?

OK yeah it happens if WindowPadding.x < AutoFitPadding.x
EDIT fixed

Oh, okay. I just wanted to post all my style settings. These are the two you mentioned:

style.WindowPadding                         = ImVec2(2, 2);
style.FramePadding                          = ImVec2(2, 1);

It's not actually new it's a bug in Selectable() but the auto-resizing windows shows it clearly.
I'll patch the new release before it gets noticed :)

The repro is:

ImGuI::GetStyle().WindowPadding.x = 7;
ImGuI::GetStyle().AutoFitPadding.x = 8;
        ImGui::Begin("Test", NULL, ImGuiWindowFlags_AlwaysAutoResize);
        ImGui::Selectable("Hello");
        ImGui::End();

Pushed a fix! Let me know if that works for you :) I deleted 1.37 and will republish it.

I haven't investigated this but is it possible to use submenus with this approach also?

Not really yet, it's not really a proper menu API. You can do sub popups on click but that wouldn't be super user friendly. We want sub-menu hover, automatic positioning and alignment, etc.
(Coincidentally I was just working using popups right now!)

Cool :) I will wait a bit then with removing my native (as in platform specific) popups until you have it in.

FYI working on popup menus at the moment. The popup system in general (not particularly menus) is rapidly descending into a black hole of weird details: ordering, focusing, positioning things. Need some to reorganise that. I may have to change the BeginPopup() API to take a string identifier instead of a bool to allow ImGui to manage lifestime and stacks of popups better, and have a mode where activating an item automatically closes a popup.

After reworking that we can have version 0 of submenu.

menus

selected

Then need shortcuts and disable items.
For "disabled items" I would like to make it a ImGui-wide feature that you can disable a block. In disabled mode text will be grey and interaction disabled, etc. I received this request. Perhaps I'll just code in the "disabled" option for menu items first before extending it to every widget.

Aligning menu items with label + shortcut + checkmark requires some form of simple columning which can eventually feed back into column system v2.

Work in progress, works much better now, previous version had lots of small problems. Not committed yet, unsure about some of the API yet. I would like "menus" to be as not special as possible, they are generic windows and generic widgets essentially so you can mix and match stuff, but there's still some inconsistency with the handling of those popups.

popup_menus2

I'm also not sure about how to parse the shortcuts yet (because ImGui doesn't really know about keys on the system, such as "F4"). I may ignore the problem for now and make shortcuts display only for the first version.

Working on menu bars. Also here showing widgets that aren't regular menu items.

menus

This has become a deep rabbit hole, I must have spent 20+ hours on it so far and it's not done yet (I'd never had expected it to take that long. Unexpected issues keeps exploding)

wow thats a lot of hours, but I think it looks good so far!

I rewrote it 3 times. The thing is, it's working now but I'm not so happy with it at the moment. It is hard to pinpoint but the fact that fixing the bugs I am having with popups isn't trivial is not a good sign. So I have to keep massaging the code.

It's usable in the branch but i'm not totally sure of the API yet and the current behavior for normal menus (non-popup) isn't correct. They should start opening on click and have the popup-like behavior of inhibit other interactions, which is the next thing I'll do. Along with a few remaining fixes. First version will probably not have functional global nor local shortcuts. If you are feeling adventure you can try the branch.

I am looking forward to be able to use it, waiting for a release since I am updating https://github.com/Extrawurst/cimgui in bulk then. (finally a patreon too now^^)

It's near usable. I need to rework the way menu closes (sub-menu currently don't close anymore when you are hovering an item that isn't a sub-menu, which is incorrect, and need to introduce a delay to decrease cases of accidentally closing a menu when moving fast to a sub-menu. Fix a few bugs (the first-level menu from a menubar can't be moved when it's too big to fit on screen, it need to be resized smaller). After that need to use it a little more for real use and perhaps it'll be a good v1.0 menu.

Thanks Stephan and everyone helping with Patreon! Much much appreciated.

I saw the introduction of a buttonActive style enum, is it possible to introduce a general API to tag a following call to any button Method disableing that particular button (no click event can be triggered and it is slightly alterd in appearance) ? do you plan on doing this ?

It will be added as a generic feature (see #211 ) probably gradually and starting with the most common widgets aka buttons. For situation when it is more common to have disabled items like MenuItem() there will be an optional bool to disable the widget which will be a shortcut to the disabling feature, similar to how TextColored() just does PushCol/Text/PopCol

Something like but hopefully with a better name (disabled=true is a confusing thing)

PushDisabled(true)
PopDisabled()

We can add shortcut for common cases as when you want a single disabled Button.

Here's a more complete todo list toward first release of menu:

  • (DONE-ish) fix closing menus, try to add opening/closing timers
  • (DONE-ish) make a "fullscreen" menubar helper (create a temporary window at 0,0 with just enough room for the menubar + perhaps add an option to animate show/hide when mouse gets toward the top of the screen)
  • (DONE-ish) fix positioning issues with menus that are too big to fit on screen (first-level menu of a menubar shouldn't be moved)
  • (DONE) fix the inconsistencies with laying out widgets in a menu bar so allow laying any sort of item (need a simplified version of what will become #97 )

That sounds great! did not see #211 yet, i like it!

Can't wait to get my hands on the menus! This it what my pathetic menu looks like right now ^^:
2015-05-20 15_26_20-unecht - hello world sample

Almost done.

  • Added a "fullscreen menubar" (ImGui::BeginMainMenuBar / ImGui::EndMainMenuBar

menubar main

    if (ImGui::BeginMainMenuBar())
    {
        if (ImGui::BeginMenu("File"))
        {
            ShowExampleMenuFile();
            ImGui::EndMenu();
        }
        if (ImGui::BeginMenu("Edit"))
        {
            if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
            if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {}  // Disabled item
            ImGui::Separator();
            if (ImGui::MenuItem("Cut", "CTRL+X")) {}
            if (ImGui::MenuItem("Copy", "CTRL+C")) {}
            if (ImGui::MenuItem("Paste", "CTRL+V")) {}
            ImGui::EndMenu();
        }
        ImGui::EndMainMenuBar();
    }
  • Added "Disabled" menu items
  • Various fixes to allow other widgets in menu-bar. Bit of an overcrowded example here, it may not be frequently useful but it is more consistent that you are able to do this sort of things:

menubar widget

  • And five millions other fixes with tricky popups behaviors, sizing, positioning.

The main missing thing for v1 is to finish handling sub-menu closure/opening with a timer (sub-menu currently never close unless you open another sub-menu at the same level, or click outside).

That looks great! So you want to close a submenu when the cursor is not hovering over it (or its submenus) for a certain time ? or whats the plan ?

Basically what Windows does.

Menu A contains menus B1 and B2, and menu-item B3.
When B2 is opened and the user move back to A then hovers B3, B2 should close after a short-time.
Currently it only closes B2 when opening another menus/popup (e.g.: hovering B1) or clicking outside the menus. That sound evident and you may be wondering what it isn't already done (it worked previously) but the way the state is held and rebuilt every frame makes everything a little trickier than expected. It'll work soon.

The timer is also necessary to reduce "false positive" opening. In lots of situation when you hover fast from menu to menu the user actually hover other items for a short period, that needs to be ignored:

menus timer

PS: You can start using the branch already if you want to replace your menus. Note that I had to break the BegniPopup() API. Let me know if anything is even slightly unclear and I'll improve the documentation arccordingly.

regarding the closing I would not go the timer route: I just checked on my osx machine and they have a timer for opening a submenu that make it take a fraction of a second to open a submenu but leaving the submenu and stop hovering the item that opens the submenu closes the sub in an instant. feels natural to me and i would argue the necessity of even the opening timer.

regarding the usage of the branch: how far away is a v1 release? and how stable is the api now? i rather wait a couple of days and catch up with a 1.39 release of cimgui once you are finished instead of also branching the menu api.

BTW. I really like the route amazon took with their submenu/dropdown: http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown

I was hoping to release 1.39 including menus within a week (I will travel from June 4th so it'll be better to get that out before that, although I'll still be programming while away I'm expecting the first few days to be no-signal). The reason I'm asking if that I'll need a few people using the API before I can declare it is stable and in a releasable state.. chicken and egg.

Excellent link, thank you. Will try that!

Please expose the "next timer due" value somewhere in the api, so it's easy to schedule a refresh in idle/event driven re-drawing scenarios. If you will take the time to do that, also include the text cursor timer as well (one just needs the min of the two).

I have implemented amazon-dropbox like behaviour in d009a85

Done some tuning and settled on vertically extending the triangle a little past the menu (the extra vertical distance grows linearly with horizontal distance, caped to 30 pixels) + limited height to 100 pixels above and 100 pixels below. You can get a few "negative" but I made it possible to still click on the underlying item to activate it, which Amazon doesn't allow and I think it works ok.

It also works with right-to-left menus.

So there's no timer! I suppose the best way would be to leave it as it and see if anybody notice or complain.

The distance are hard-coded which I think makes sense in this context, but perhaps they should be expressed as multiples of the font size.

EDIT Moving the right edge of the triangle further when getting too close may be an improvement, will try out a few more things later.

Mouse cursor missing from the screenshot but imagine it to be at the tip of the triangle:
menus triangle

Remaining todo (may not be in 1.39)

  • You can't click and hold on a menu in a menu-bar, navigate the menu and activate an item on release (mouse held the entire time). You need to first click-release to open the menu and click to activate an item. This differs from what Windows does. That may bother some users.
  • Missing support for local and global shortcuts.

Considering merging in trunk to increase the number of testers now :)

@ocornut looks good to me although i don't geht todo#1, merge it and I will try it ;)

Todo#1 on windows you can click mouse (and hold it) on "File", hover to "Save" and release the mouse button. Currently in ImGui you have to click "File", then release the mouse once before you can activate "Save", so you can't do that in a single press-release sequence.

All menus in Windows seems to strictly react on "mouse release", so you can click-hold on "Save" then move the mouse to "Save As" and release the button, and "Save As" will be activated. This is inconsistent most other widgets, but it also allows to perform the action above.

My problem with it is that since I allow different sort of widgets in menus, and allows menu items in regular windows, I don't know how to handle those inconsistencies.

Committed a batch of fixes I had planned, may just merge now.

Merged in trunk! Living the life!
149 commits since 1.38, I should probably not add new stuff to 1.39. Testers wanted :)

Great news I will update cimgui right away!

works great. i am impressed, feels very responsive. awesome!

menus-api

Well after roughly converting my menus to the new API, I think the only thing I am missing is a way to identify a Popup using BeginPopup and OpenPopup without the need of a string but with a integer-id.

In what context do you need that?

Maybe it isn't clear, but the string id you pass is hashed along with the current id stack like every other widget. So if you are already in a loop where you uniquely identified say, your button via a PushId/PopId covering the loop, the popup identifier will include that and be unique.

That said, I can add OpenPopup/BeginPopup variants that takes pointers or integer (the same way PushID or TreeNode have those variants) but it may be unnecessary pollution?

The downside of this approach compared to the previous one where the user was storing a boolean is that OpenPopup/BeginPopup needs to be called at the same ID level. In case where the user wants to call OpenPopup in a very different location than BeginPopup then a workaround is to store your own bool and set it to true at the "other" location, then call OpenPopup based on this bool just before BeginPopup. I'll have to figure out if I can provide a more convenient way of doing that but that would require ignoring the ID stack.

Let me know if those explanation makes anything better and how I could improve the documentation. :)

Well I was not even aware of the problem when OpenPopup is called at a completly different id-stack-position. I was thinking the string is the unique id by itself. That is a nice solution, but one has to be careful with the OpenPopup-situation, is it throwing/asserting when one OpenPupup's at a wrong place?

I also found that some widgets inside of a popup close the popup implicitly (like selectable) and others like button don't so that i had to call CloseCurrentPopup manually, is that intended ?

It isn't asserting because it has no way to do so, there is no "wrong place", they will just be different popups. The possible confusion is that Begin() uses "absolute" name whereas BeginChild() uses "relative" name for identifying the window.
BeginPopup() function like if you were creating a child but perhaps that is not obvious. Do I really want to give the users responsibility of assigning unique names across their program?
If it was called BeginChildPopup() it would be more obvious.

Side-stepping: that reminds me that I haven't thoroughly tested cases of the users calling OpenPopup without BeginPopup (shouldn't be a problem but I'll need to test it better to make sure).

About implicit closing: MenuItem and Selectable close a popup automatically.

  • Perhaps I should add Button() to that list.
  • Or add a setting to configure that per widget or per widget categories. It doesn't make sense to close the popup if you adjusted a slider or clicked a checkbox, so perhaps it should only be default for pressable like MenuItem+Selectable+Button ?

I am not sure what the right rout is here.
Maybe even the checkable (checkmark menuitem in the example) should not close implicitly if buttons don't aswell.
its a hard decision. but maybe an option would make sense to disable implicit closing completely ? i am not sure...

I made Button() close popups but I am not sure about this.
Notice the + / - buttons in the float input box. It made sense that those didn't close the popup, so I made them so but using parameters that aren't exposed. So it is visibly inconsistent.

menus button closes popup

Also a ListBox inside a popup would close the popup when clicked on because it uses selectable, for that alone we'd like an option in a stack ?

Implicit closing, at least by default, is desirable to make the most common case terse (aka using a lot of MenuItem).

greate , thanks

is it possible to add icons to the menu items ?

No icon yet, we don't have a very practical and easy way of passing texture+uv. But you can use Image(), SameLine(), MenuItem() if you can bother.

emoon commented

Great work on this! :)

I am adding helpers to facilitate creating popups out of nowhere and following a common pattern. Suggested via a request from @bkaradzic

The helpers are currently as following:

bool ImGui::BeginPopupOnItemClicked(const char* str_id, int mouse_button = 1)
{
    if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(mouse_button))
        ImGui::OpenPopup(str_id);
    return ImGui::BeginPopup(str_id);
}

bool ImGui::BeginPopupOnWindowClicked(const char* str_id = "window_context", bool in_empty_space_only = false, int mouse_button = 1)
{
    if (ImGui::IsMouseHoveringWindow() && ImGui::IsMouseClicked(mouse_button))
        if (!in_empty_space_only || !ImGui::IsAnyItemHovered())
            ImGui::OpenPopup(str_id);
    return ImGui::BeginPopup(str_id);
}

Which you can use like that:

if (ImGui::BeginPopupOnWindowClicked())
{
    if (ImGui::Selectable("Clear")) ClearLog();
    ImGui::EndPopup();
}

However I don't like those function names! Any ideas?

  • I think it is correct that they start with BeginPopup*()
  • The word "contextual menu" would be more appropriate, but they are not actually "menu" but popups in the general sense which you can fill with menu items. ImGui uses BeginMenu to actually create a submenu. So there might be a slight confusion with the naming.

BeginPopupContextItem() / BeginPopupContextWindow() ?

BeginItemContextPopup() / BeginWindowContextPopup() ?

How about the lack of symetry with OpenPopup/BeginPopup, since those function do both?

I've been testing this for last few days and so far everything works perfectly, great job! Something that would be useful is a way to know whether there is any menu or popup currently open to allow ignoring mouse clicks in the void area which are only meant to close all currently open menu/popups - right now such clicks can (depending on the application) cause unwanted non-gui interactions because WantCaptureMouse is false

Good to hear it's working well for you. Note that I may still change the name of the 3 functions I added yesterday (currently BeginPopupContextItem / BeginPopupContextWindow / BeginPopupContextVoid).

I'll look into what you're mentioning. I think the bug should be that WantCaptureMouse should always be true automatically when a popup is active, so you don't have to check that yourself.

@thevaber : should be fixed now. When you close a popup or menu by clicking in void WantCaptureMouse will be kept high as long as the button isn't released.

I am now seeing that the input inhibition performed by popups/menus doesn't match what Windows is doing with menus. Windows only inhibits inputs for things under the popup for the same window, but other windows aren't affected. I wonder if I should work toward that.

The reason it relates to WantCaptureMouse is that with the fix above if you have a menu open it might feels unreactive if you click on the void to, say, move your game 3d camera and it doesn't work on the first click, you need to release and click. However having popups/menus open and trying to close them isn't such a common thing and it should be understandable to the user why they need to click once to close the popups/menus before they can interact with your game.

The difference between an operating system with a desktop and imgui "void" in your game app is that you never actually have void, that space is likely used by the rest of your app and if you are using inputs to interact with that space then we are left with nowhere to click on to close a popup without triggering something.

Thanks for the fix! Indeed, for some applications this behavior might not be desirable, while for some it is nearly essential.

My use case is a painting application - think photoshop, you have a brush tool selected and you start doing something in menus - then you change your mind, and click outside the menu to get rid of it, likely on the canvas - and you don't want that to actually paint anything. In photoshop (and other similar software I tried) this is the case, no painting is done on such mouse clicks (until the mouse button is released and clicked again), but clicking anywhere other than the canvas works exactly as Windows OS does it, like you described (ignoring clicks to the same window). But for some other applications, even clicking the "void" (well, non-imgui area) should actually do something.

I see some applications solving this by having a rather short timer for closing the menu when it's not hovered, thus not requiring a mouse click to close the menu at all, though that seems not exactly ideal either, it feels quite cumbersome.. So I'm guessing that this void click behavior will probably need to be configurable, or perhaps use another WantCaptureMouse-like variable (something like WantCaptureMouseVoid, which anyone can choose to ignore or OR it with WantCaptureMouse)?

Yes that would make sense. I'll wait until actual feedback come to get the "other" behavior before adding something. Menus are still new. Also don't hesitate to post screenshots if you're done something cool that you can share!

for me clicking in void to close the popup and ignoring that click WantCaptureMouse=true feels natural. +1 for keeping it that way.

I am going to release that as 1.40 (skipping 1.39 because the changelist is very huge already) in a few hours. Hopefully we won't find a bug that would require to change all the API the next day.

Closing this topic for now. Bug fixes and additions such as shortcuts, e.g. can be handled in a separate topic.