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

ImGui::Selectable with nested components #2184

Open
kbirk opened this issue Nov 13, 2018 · 6 comments
Open

ImGui::Selectable with nested components #2184

kbirk opened this issue Nov 13, 2018 · 6 comments
Labels
label/id and id stack implicit identifiers, pushid(), id stack

Comments

@kbirk
Copy link

kbirk commented Nov 13, 2018

Is there a way to get ImGui::Selectable behavior but have the component be comprised of several other nested components?

For example:

image

Where each ImGui::Selectable is contains an ImGui::Image and two ImGui::Text calls but acts as a single "selectable" item.

@ocornut
Copy link
Owner

ocornut commented Nov 15, 2018

You may call Selectable() first which a non-visible label ("##title") and specify a custom size, and then draw your stuff over it. You'll need to know the size ahead and call the imgui_internal.h text drawing functions that handle clipping.

@christophe-f8
Copy link

Sorry to revive an old post, but I run into the same issue and I more or less managed to make it work so I thought some people might want to know the following.

As stated above, using a non-visible label in Selectable, then drawing images/texts work, but the selectable label MUST be unique, otherwise only the first item can be selected. Here is a short example:

int i = 0;
for (std::vector<std::string>::iterator it = m_items.begin(); it != m_items.end(); ++it) {
    std::string itemid = "##" + std::to_string(i);
    if (ImGui::Selectable(itemid.c_str(), i == m_selectedItem)) {
        m_selectedItem = i;
    }
    ImGui::SameLine();
    ImGui::Text("Item: ");
    ImGui::SameLine();
    ImGui::Text((*it).c_str());
    i++;
}

This only displays texts (or image/buttons/...) on the same line. To draw on separate lines you indeed need to move the cursor and set the clipping manually.

@ocornut
Copy link
Owner

ocornut commented Jun 18, 2019

As stated above, using a non-visible label in Selectable, then drawing images/texts work, but the selectable label MUST be unique, otherwise only the first item can be selected. Here is a short example:

You can also use PushID(), this is all explained in the FAQ
"Why are multiple widgets reacting when I interact with a single one? How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack..."

@ocornut ocornut added the label/id and id stack implicit identifiers, pushid(), id stack label Apr 6, 2020
@bootzin
Copy link

bootzin commented Jan 7, 2021

Sorry to revive this issue again, but I'm having a problem where if I specify the width of the selectable it stops being drawn above the items that I want, but if I don't specify it overflows into the next item.. Is there a better way to make images selectable?

@dicroce
Copy link

dicroce commented Mar 22, 2022

Here is an example I got working. Creates a custom Selectable with 2 stacked text fields and a clickable button to the side that opens a modal dialog.

` auto pos = ImGui::GetCursorPos();

// selectable list
for (int n = 0; n < 10; n++)
{
    ImGui::PushID(n);

    char buf[32];
    sprintf(buf, "##Object %d", n);

    ImGui::SetCursorPos(ImVec2(pos.x, pos.y));
    if (ImGui::Selectable(buf, n == selected, 0, ImVec2(width, 50))) {
        selected = n;
    }
    ImGui::SetItemAllowOverlap();

    ImGui::SetCursorPos(ImVec2(pos.x, pos.y));
    ImGui::Text("foo");

    ImGui::SetCursorPos(ImVec2(pos.x + 30, pos.y+5));
    if(ImGui::Button("do thing", ImVec2(70, 30)))
    {
        ImGui::OpenPopup("Setup?");
        selected = n;
        printf("SETUP CLICKED %d\n", n);
    }

    if (ImGui::BeginPopupModal("Setup?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
    {
        ImGuiContext& g = *GImGui;
        ImGuiWindow* window = g.CurrentWindow;
        ImVec2 pos_before = window->DC.CursorPos;

        ImGui::Text("Setup Popup");
        if (ImGui::Button("OK", ImVec2(120, 0))) { printf("OK PRESSED!\n"); ImGui::CloseCurrentPopup(); }
        ImGui::EndPopup();
    }

    ImGui::SetCursorPos(ImVec2(pos.x, pos.y+20));
    ImGui::Text("bar");

    pos.y += 55;

    ImGui::PopID();
}

`

@Displee
Copy link

Displee commented Jan 21, 2024

I know this is an old one, but the above looks a bit too complicated, here's my solution (I use imgui Java bindings):

    fun selectableButton(label: String, selected: Boolean, width: Float, height: Float, onSelect: (() -> Unit)? = null, content: (() -> Unit)? = null) {
        val cursorPosX = ImGui.getCursorPosX()
        if (ImGui.selectable(label, selected, ImGuiSelectableFlags.None, width, height)) {
            onSelect?.invoke()
        }
        ImGui.sameLine()
        val afterCursorPosX = ImGui.getCursorPosX()
        ImGui.setCursorPosX(cursorPosX)
        content?.invoke()
        ImGui.sameLine()
        ImGui.setCursorPosX(afterCursorPosX)
    }

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

6 participants