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

How to correctly use IDs ? #719

Closed
victorlevasseur opened this issue Jun 29, 2016 · 10 comments
Closed

How to correctly use IDs ? #719

victorlevasseur opened this issue Jun 29, 2016 · 10 comments
Labels
label/id and id stack implicit identifiers, pushid(), id stack

Comments

@victorlevasseur
Copy link

victorlevasseur commented Jun 29, 2016

Hi,

Here is my code :

ImGui::SetNextWindowPosCenter();
    ImGui::SetNextWindowSize(ImVec2(350, 200));
    ImGui::Begin("YAPG - Main menu");
        //Level selection
        static char levelName[512] = "level.xml";
        ImGui::InputText("", levelName, 512);
        ImGui::SameLine();
        if(ImGui::Button("Play !"))
        {
            getStateEngine().pauseAndStartState
                <level::LevelState, std::string, resources::AllResourcesManagers&, settings::SettingsManager&, sfg::SFGUI&, sfg::Desktop&>(
                std::string(levelName), m_resourcesManager, m_settingsManager, m_sfgui, m_desktop
            );
        }

        //Level editor
        if(ImGui::Button("Level editor"))
        {
            getStateEngine().pauseAndStartState
                <editor::LevelEditorState, resources::AllResourcesManagers&, settings::SettingsManager&, sfg::SFGUI&, sfg::Desktop&>(
                m_resourcesManager, m_settingsManager, m_sfgui, m_desktop
            );
        }

        //Settings
        if(ImGui::Button("Settings..."))
        {
            ImGui::OpenPopup("Settings");
        }

        //Settings popup
        ImGui::SetNextWindowSize(ImVec2(350, 400));
        if(ImGui::BeginPopupModal("Settings"))
        {
            if(ImGui::CollapsingHeader("Keyboard settings"))
            {
                ImGui::Indent();
                for(std::size_t i = 0; i < 4; ++i)
                {
                    std::string label = "Player " + std::to_string(i + 1);
                    if(ImGui::CollapsingHeader(label.data()))
                    {
                        ImGui::Text("Left key: ");
                        ImGui::SameLine();
                        if(ImGui::Button(m_playersKeys[i][0]))
                        {
                            m_selectedKeyButton = m_playersKeys[i][0];
                        }

                        ImGui::Text("Right key: ");
                        ImGui::SameLine();
                        if(ImGui::Button(m_playersKeys[i][1]))
                        {
                            m_selectedKeyButton = m_playersKeys[i][1];
                        }

                        ImGui::Text("Jump key: ");
                        ImGui::SameLine();
                        if(ImGui::Button(m_playersKeys[i][2]))
                        {
                            m_selectedKeyButton = m_playersKeys[i][2];
                        }
                    }
                }
                ImGui::Unindent();
            }

            if(ImGui::Button("Close"))
            {
                ImGui::CloseCurrentPopup();
            }
            ImGui::EndPopup();
        }

        //About
        if(ImGui::Button("About..."))
        {

        }

        //Quit button
        if(ImGui::Button("Exit"))
        {
            getStateEngine().stopStateAndUnpause();
        }
    ImGui::End();

As you can see, I have a "for" loop, so I probably need to use PushID and PopID. However, I don't know where to put them. I tried all the possible combinations but it always resulted in buttons randomly acting like others (for exemple : the jump key button of the third player launch the level editor as the "Editor" button only should do !).

So, how do the IDs work ?

@ocornut
Copy link
Owner

ocornut commented Jun 29, 2016

Have you read the FAQ?
What have you tried with PushID/PopID ?

@ratchetfreak
Copy link

ratchetfreak commented Jun 29, 2016

In the faq in imgui.cpp quite literally says what you should do:

for (int i = 0; i < 100; i++)
{
     PushID(i);

     //...

     PopID();
}

@victorlevasseur
Copy link
Author

Obviously yes. Like I said, I tried all the possible combinations. For instance :

ImGui::SetNextWindowPosCenter();
    ImGui::SetNextWindowSize(ImVec2(350, 200));
    ImGui::Begin("YAPG - Main menu");
        //Level selection
        static char levelName[512] = "level.xml";
        ImGui::InputText("", levelName, 512);
        ImGui::SameLine();
        if(ImGui::Button("Play !"))
        {
            getStateEngine().pauseAndStartState
                <level::LevelState, std::string, resources::AllResourcesManagers&, settings::SettingsManager&, sfg::SFGUI&, sfg::Desktop&>(
                std::string(levelName), m_resourcesManager, m_settingsManager, m_sfgui, m_desktop
            );
        }

        //Level editor
        if(ImGui::Button("Level editor"))
        {
            getStateEngine().pauseAndStartState
                <editor::LevelEditorState, resources::AllResourcesManagers&, settings::SettingsManager&, sfg::SFGUI&, sfg::Desktop&>(
                m_resourcesManager, m_settingsManager, m_sfgui, m_desktop
            );
        }

        //Settings
        if(ImGui::Button("Settings..."))
        {
            ImGui::OpenPopup("Settings");
        }

        //Settings popup
        ImGui::SetNextWindowSize(ImVec2(350, 400));
        if(ImGui::BeginPopupModal("Settings"))
        {
            ImGui::PushID("keyboard_settings"); //Just to be sure !
            if(ImGui::CollapsingHeader("Keyboard settings"))
            {
                ImGui::Indent();
                for(std::size_t i = 0; i < 4; ++i)
                {
                    std::string label = "Player " + std::to_string(i + 1);
                    ImGui::PushID(i);
                    if(ImGui::CollapsingHeader(label.data()))
                    {
                        ImGui::Text("Left key: ");
                        ImGui::SameLine();
                        if(ImGui::Button(m_playersKeys[i][0]))
                        {
                            m_selectedKeyButton = m_playersKeys[i][0];
                        }

                        ImGui::Text("Right key: ");
                        ImGui::SameLine();
                        if(ImGui::Button(m_playersKeys[i][1]))
                        {
                            m_selectedKeyButton = m_playersKeys[i][1];
                        }

                        ImGui::Text("Jump key: ");
                        ImGui::SameLine();
                        if(ImGui::Button(m_playersKeys[i][2]))
                        {
                            m_selectedKeyButton = m_playersKeys[i][2];
                        }
                    }
                    ImGui::PopID();
                }
                ImGui::Unindent();
            }

            if(ImGui::Button("Close"))
            {
                ImGui::CloseCurrentPopup();
            }
            ImGui::PopID();
            ImGui::EndPopup();
        }

        //About
        if(ImGui::Button("About..."))
        {

        }

        //Quit button
        if(ImGui::Button("Exit"))
        {
            getStateEngine().stopStateAndUnpause();
        }
    ImGui::End();

Still give random bad click actions. :(

@ocornut
Copy link
Owner

ocornut commented Jun 29, 2016

This should work, I can't see why it wouldn't. You are perhaps doing something else wrong in the code.
Perhaps try to reduce the code into a mini-repro that I can use here first.

(Never tell yourself "I tried all the possible combinations." it is most often a wrong statement.)

@victorlevasseur
Copy link
Author

Ok, at least I use them correctly :). I'll take another look at my code. ;)

(Great lib by the way 👍 )

@ocornut
Copy link
Owner

ocornut commented Jun 29, 2016

Maybe you are handling m_selectedKeyButton in your code. Add printf or log output in the Button() scopes if you want to make sure they aren't called twice.

@ratchetfreak
Copy link

Do you change the contents of m_playersKeys? If so I would suggest using a "###id" postfix to make sure that's not the issue:

            char[128] labelBuffer;
            for(std::size_t i = 0; i < 4; ++i)
            {
                std::string label = "Player " + std::to_string(i + 1);
                ImGui::PushID(i);
                if(ImGui::CollapsingHeader(label.data()))
                {
                    ImGui::Text("Left key: ");
                    ImGui::SameLine();
                    sprintf(labelBuffer, "%s###left", m_playersKeys[i][0]);
                    if(ImGui::Button(labelBuffer))
                    {
                        m_selectedKeyButton = m_playersKeys[i][0];
                    }

                    ImGui::Text("Right key: ");
                    ImGui::SameLine();
                    sprintf(labelBuffer, "%s###right", m_playersKeys[i][1]);
                    if(ImGui::Button(labelBuffer))
                    {
                        m_selectedKeyButton = m_playersKeys[i][1];
                    }

                    ImGui::Text("Jump key: ");
                    ImGui::SameLine();
                    sprintf(labelBuffer, "%s###jump", m_playersKeys[i][2]);
                    if(ImGui::Button(labelBuffer))
                    {
                        m_selectedKeyButton = m_playersKeys[i][2];
                    }
                }
                ImGui::PopID();
            }

@ocornut
Copy link
Owner

ocornut commented Jun 29, 2016

Good point (and hence why posting a screenshot of the context is always helpful).
If your playersKey contains the same string it'll conflict.
You can fix it as pointed above or by using PushId/PopId.

Typically your code could you loop over an array of keys to set,

const char* keys_names[] = { "Left", "Right", "Jump");
for (int key_i = 0; key_i < ARRAYSIZE(keys_names); key_i++)
{
   ImGui::PushID(n);
   ImGuI::Text("%s key: ", keys_names[key_i]);
   ImGui::SameLine();
   if (ImGui::Button(m_playersKeys[i][key_i])
   {
      ...
   }
   ImGui::PopID();
}

@ocornut ocornut closed this as completed Jul 1, 2016
@victorlevasseur
Copy link
Author

Thanks for your help, it works now :)

@tankorsmash
Copy link

imgui/imgui.cpp

Line 637 in 9d6b2b0

Q: Why are multiple widgets reacting when I interact with a single one?
Here's an updated link to that FAQ question with all the info about PushID/PopID

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
label/id and id stack implicit identifiers, pushid(), id stack
Projects
None yet
Development

No branches or pull requests

4 participants