Imgui: Can not open modal popup from menu / Issue with ID stack

Created on 14 Sep 2015  路  15Comments  路  Source: ocornut/imgui

This works:

 if (ImGui::Button("Import asset"))
 {
    ImGui::OpenPopup("ImportAssetDialog");
 }
 if (ImGui::BeginPopupModal("ImportAssetDialog"))
 {
    ImGui::Text("test");
 }

This does not:

 if (ImGui::MenuItem("Import asset"))
 {
    ImGui::OpenPopup("ImportAssetDialog");
 }
 if (ImGui::BeginPopupModal("ImportAssetDialog"))
 {
    ImGui::Text("test");
 }

This happens

imgui_popup_error

labeid and id stack popups

Most helpful comment

The exact code I use is complicated, therefore I did not paste it here. However I tried to find the simplest code to reproduce the problem, here it is:

        ImGui::NewFrame();

        if (ImGui::BeginMainMenuBar())
        {
            if (ImGui::BeginMenu("menu"))
            {
                if (ImGui::MenuItem("menu item"))
                {
                    ImGui::OpenPopup("popup");
                }
                if (ImGui::BeginPopupModal("popup"))
                {
                    ImGui::Text("Lorem ipsum");
                }
                ImGui::EndMenu();
            }
            ImGui::EndMainMenuBar();
        }

        ImGui::Render();

Just to be sure I tried to place BeginPopupModal from the example in every possible place, nothing works.

The only solution I found is this, however I hope there is something better:

        ImGui::NewFrame();

        bool b = false;
        if (ImGui::BeginMainMenuBar())
        {
            if (ImGui::BeginMenu("menu"))
            {
                if (ImGui::MenuItem("menu item"))
                {
                    b = true;
                }
                ImGui::EndMenu();
            }
            ImGui::EndMainMenuBar();
        }

        if (b)
        {
            ImGui::OpenPopup("popup");
        }

        if (ImGui::BeginPopupModal("popup"))
        {
            ImGui::Text("Lorem ipsum");
            ImGui::EndPopup();
        }

        ImGui::Render();

I've pulled the source code of ImGui yesterday.

All 15 comments

Is that exactly the code you are actually using/testing with ?

Popup Identifiers have to be part of the ID stack to clear ambiguity and allows a same popup to work from different items sources. So your calls OpenPopup() and BeginPopupModal() have to be in the same level of the ID stack. I imagine your MenuItem() is inside a BeginMenu/EndMenu pair in your code and that adds to the popup stack?

Now there is another problem here is that MenuItem() will close your current popup as well.

If you understand those things you should be able to come up with a workaround very easily, it is likely that your real code is misplaced (you aren't pasting the full code here).

But I still would like to improve the situation here.

  • Clarify or improve the situation with MenuItem/Selectable closing their parent popup and how it affect ID and popups created there.
  • Perhaps be able to sort of "clear" the value at the top of the ID stack so those locations can refer to the same identifier. This would also be useful in the future to programmatically refer to widgets from outside their location.

The exact code I use is complicated, therefore I did not paste it here. However I tried to find the simplest code to reproduce the problem, here it is:

        ImGui::NewFrame();

        if (ImGui::BeginMainMenuBar())
        {
            if (ImGui::BeginMenu("menu"))
            {
                if (ImGui::MenuItem("menu item"))
                {
                    ImGui::OpenPopup("popup");
                }
                if (ImGui::BeginPopupModal("popup"))
                {
                    ImGui::Text("Lorem ipsum");
                }
                ImGui::EndMenu();
            }
            ImGui::EndMainMenuBar();
        }

        ImGui::Render();

Just to be sure I tried to place BeginPopupModal from the example in every possible place, nothing works.

The only solution I found is this, however I hope there is something better:

        ImGui::NewFrame();

        bool b = false;
        if (ImGui::BeginMainMenuBar())
        {
            if (ImGui::BeginMenu("menu"))
            {
                if (ImGui::MenuItem("menu item"))
                {
                    b = true;
                }
                ImGui::EndMenu();
            }
            ImGui::EndMainMenuBar();
        }

        if (b)
        {
            ImGui::OpenPopup("popup");
        }

        if (ImGui::BeginPopupModal("popup"))
        {
            ImGui::Text("Lorem ipsum");
            ImGui::EndPopup();
        }

        ImGui::Render();

I've pulled the source code of ImGui yesterday.

Your first example can't work anyway because the if (ImGui::BeginPopupModal("popup")) block is only called when the menu is being browsed. If it worked it would assert anyway because you aren't calling `EndPopup' anywhere.

The second example is correct and exactly what I have mentioned, the ID will match.

Now I think what would be desirable is to make this example work (currently it won't because the opened popup identifier will be "mainmenubar+popup" and the begin is on "popup", this why I was suggesting a way to alter how the popup is using - or not - the id stack.

        ImGui::NewFrame();

        bool b = false;
        if (ImGui::BeginMainMenuBar())
        {
            if (ImGui::BeginMenu("menu"))
            {
                if (ImGui::MenuItem("menu item"))
                   ImGui::OpenPopup("popup");
                ImGui::EndMenu();
            }
            ImGui::EndMainMenuBar();
        }

        if (ImGui::BeginPopupModal("popup"))
        {
            ImGui::Text("Lorem ipsum");
            ImGui::EndPopup();
        }

        ImGui::Render();

Now I understand why the first example does not work. Can there be some special way/flag in OpenPopup so that your example works?

For example:

 ImGui::OpenPopup("some_id", FlagPutInRoot)

 // somewhere else in root 
 if (ImGui::BeginPopupModal("popup"))
 {

Yes I would like to solve that but it would need to be solved in a generic manner not only for popup. I don't know how and when yet (considering there is a workaround for popups it isn't a top priority).

Ok, I will use the workaround until it's solved. Thank you.

Hello, I also encoutered this "problem". I have a humble idea, what if when label contains for example 4# at the begining like:
ImGui::Button("####I am a global label");
Then when generating ID it would just simply ignore the stack and use only inputed string for hashing. Of course that would mean that user must be more careful with them because of collisions. But it seems like relatively easy solution to me.
Of course I might be wrong, because of some internal structure or something....

This is probably a good solution to solve this specific problem (aside from the fact that the amount of # characters may start to be a little worrying). My concern is that it doesn't provide a clear solution to identifying _any_ widget without relying on global id, so it may be good for popup but not for other things. At this point my tendency is to sit on ideas until I can tackle a wider set of related problems all-together to avoid making too many short-term mistakes. So I'd be happy if you want to think about or discuss about identifiers in general and see where it can lead us.

Interestingly, for an hypothetical ActivateWidget() function, appending strings without any separator would work (syntactically we could allow a separator such as '/' to make them more readable) but we might still need a way to pass on chain of identifiers involving integers/pointers.

Aha, just wanted to say that took me a while to understand why the popups didnt work after a MenuItem() as well.
Got puzzled exactly like nem0 and found the same "solution".

I stumbled upon the same issue, I kind of understand why this is happening and I was wondering if we could find a temporary solution.

Would it be possible to open a modal popup using a variable?
I thought I could use the p_open argument in BeginPopupModal, but it doesn't work and neither using the variable as a condition to create the modal itself:

var openModal = false;

if ( ImGui::Button("open") )
    openModal = true;

if ( ImGui::BeginPopupModal("foo", &openModal) )
{
    ImGui::Text("Hello!");    
    if ( ImGui::Button("Ok") ) 
    { 
        ImGui::CloseCurrentPopup(); 
        openModal = false;
    }
    ImGui::EndPopup();
}

if ( openModal )
{
    ImGui::BeginPopupModal("foo");
    ImGui::Text("Hello!");    
    if ( ImGui::Button("Ok") ) 
    { 
        ImGui::CloseCurrentPopup(); 
        openModal = false;
    }
    ImGui::EndPopup();
}

I ended up going back using a Button which kind of works(parent popup stays open), however I can't close the parent popup when I close the modal, ideally I'd like to call ImGui::ClosePopup("parent-popup") but it's not accessible.

if ( ImGui::BeginPopupModal("foo") )
{
    ImGui::Text("Hello!");    
    if ( ImGui::Button("Ok") ) 
    { 
        ImGui::CloseCurrentPopup();                 // close modal
        ImGui::ClosePopup("parent-popup");   // close parent popup
    }
    ImGui::EndPopup();
}

I had a similar situation trying to write a Save File Menu Item. It opens up a modal popup for you to write the full path for the file to be saved(temporary until I figure out a good way to incorporate proper File Dialogs) and that ,if the file already exists ,in turn has to open up a stacked modal popup that asks for permission to overwrite.
The first modal is easy. The solution above with the bool flag toggle inside the MenuItem works fine. But that got a bit messy with bool flags too quickly due to dependencies. The first modal upon clicking Save has to either complete the action or wait for positive feedback from the second stacked modal.

Instead an enum with the states of this situation worked on the first try. Much cleaner and more straightforward.

In the case of MenuItems...if you've got many modals and possibly stacked as well, having an enum with the full flow in states for each different operation makes it easier to handle multiple modals code in the same scope with minimal variables. You basically have one variable for all the modals and the menu item they get triggered by for each operation without affecting the others.

I was about to open an issue regarding the same problem, good thing I've searched first.

My solution to this is to use a lambda. A function pointer can be set at any state (even inside a menu click) and in the end of your code you simply need to call it.

Not sure if this has perfomance issues I may be overlooking though, otherwise its pretty handy:

{

ImGui::NewFrame();

static void(*ShowPopup)() = []() {};

if (ImGui::BeginMainMenuBar())
{
    if (ImGui::BeginMenu("menu"))
    {
        if (ImGui::MenuItem("menu item"))
        {
            ShowPopup = []()
            {
                if (!ImGui::IsPopupOpen("popup"))
                    ImGui::OpenPopup("popup");

                if (ImGui::BeginPopupModal("popup"))
                {
                    ImGui::Text("Lorem ipsum");

                    if (ImGui::Button("Close", ImVec2(80, 0)))
                    {
                        ImGui::CloseCurrentPopup();
                        ShowPopup = []() {};
                    }
                    ImGui::EndPopup();
                }
            };
        }
        ImGui::EndMenu();
    }
    ImGui::EndMainMenuBar();
}

ShowPopup();

ImGui::Render();

}

I found a temporary solution to this bug for anyone waiting for a fix. Hopefully ocornut fixes it soon.

bool openpopuptemp = false;

//in render loop
if (ImGui::BeginMenu("Menu")){
        if (ImGui::MenuItem("Open Popup", NULL)) { 
            openpopuptemp = true;
        }
        ImGui::EndMenu();
}
if (openpopuptemp == true) {
        ImGui::OpenPopup("popup");
        openpopuptemp = false;
}
if (ImGui::BeginPopupModal("popup")){
            ImGui::Text("Lorem ipsum");
            ImGui::EndPopup();
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

mkanakis picture mkanakis  路  3Comments

Folling picture Folling  路  3Comments

GrammarLord picture GrammarLord  路  3Comments

bizehao picture bizehao  路  3Comments

SlNPacifist picture SlNPacifist  路  3Comments