imnodes icon indicating copy to clipboard operation
imnodes copied to clipboard

Node with title bar gets expanded infinitely

Open tim-tim707 opened this issue 6 months ago • 2 comments

I'm trying to make the default examples work. Here is my main loop:

void main_loop(App &app) {
    ImGui::Begin("node editor");
    ImNodes::BeginNodeEditor();

    const int hardcoded_node_id = 1;

    ImNodes::BeginNode(hardcoded_node_id + 1);

    ImNodes::BeginNodeTitleBar();
    ImGui::TextUnformatted("node");
    ImNodes::EndNodeTitleBar();

    ImNodes::EndNode();

    ImNodes::EndNodeEditor();
    ImGui::End();
}
// Elsewhere:
    while (glfwWindowShouldClose(window) != GLFW_TRUE) {
        glfwPollEvents();
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();

        main_loop(app);

        ImGui::Render();
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        glfwSwapBuffers(window);
    }

For some reason, the node rectangle gets expanded every loop by the padding value at

ImNodes::EndNode(); -> node.Rect.Expand(node.LayoutStyle.Padding); -> Rect gets 8 pixel added to Max.x every loop (but not Max.y)

I don't really understand why it is doing this. Should I create a context and destroy it every frame ? I'm not doing it for ImGui and the examples do not seem to do it as well.

ImGui version 1.19.1 imnodes from branch master commit b2ec254

tim-tim707 avatar Aug 10 '25 16:08 tim-tim707

Seems that this works properly:

    ImGui::Begin("node editor");
    ImNodes::BeginNodeEditor();

    ImNodes::BeginNode(1);

    ImNodes::BeginNodeTitleBar();
    ImGui::TextUnformatted("node");
    ImNodes::EndNodeTitleBar();

    ImNodes::BeginOutputAttribute(2);
    ImGui::TextUnformatted("output pin");
    ImNodes::EndOutputAttribute();

    ImNodes::EndNode();

    ImNodes::EndNodeEditor();
    ImGui::End();

But this does not (expand infinitely):

    ImGui::Begin("node editor");
    ImNodes::BeginNodeEditor();

    ImNodes::BeginNode(1);

    ImNodes::BeginNodeTitleBar();
    ImGui::TextUnformatted("node");
    ImNodes::EndNodeTitleBar();

    // Removed the BeginOutputAttribute and EndOutputAttribute calls

    ImNodes::EndNode();

    ImNodes::EndNodeEditor();
    ImGui::End();

tim-tim707 avatar Aug 12 '25 20:08 tim-tim707

I experienced something similar. I found that if I don't layout any widgets or attributes after EndNodeTitleBar() that the width increases by 8 pixels on ever layout frame.

My solution (workaround) was to emit an ImGui::Dummy(0,0) between the EndNodeTitleBar() and EndNode() calls.

donovan-TGC avatar Aug 29 '25 23:08 donovan-TGC

I believe the root cause is in the GetNodeTitleRect function: ` inline ImRect GetNodeTitleRect(const ImNodeData& node) { // 1. Get the rectangle occupied by the title bar's content (e.g., text), // and expand it slightly by adding padding. ImRect expanded_title_rect = node.TitleBarContentRect; expanded_title_rect.Expand(node.LayoutStyle.Padding);

// 2. Calculate and return the new title bar rectangle.
return ImRect(
    expanded_title_rect.Min,
    expanded_title_rect.Min + ImVec2(node.Rect.GetWidth(), 0.f) +
        ImVec2(0.f, expanded_title_rect.GetHeight()));

}` The problem is: This implementation creates a feedback loop. The layout inside the title bar expands to fit the node's width, but the node's width is also being recalculated based on the content's width. As a result, if the function is called repeatedly, the node's width keeps growing.


I changed it to ignore the content's width for sizing and only use its height, like this: ` inline ImRect GetNodeTitleRect(const ImNodeData& node) { // Get the rectangle for the content. ImRect expanded_title_rect = node.TitleBarContentRect; // Add vertical padding. expanded_title_rect.Expand(node.LayoutStyle.Padding);

// Calculate and return the new title bar rectangle.
return ImRect(
    // Use the content's top-left for the top-left coordinate.
    expanded_title_rect.Min,
    // The width (X) ignores the content's width and always uses the node's current width.
    // The height (Y) uses the content's height to allow for collapsing/expanding.
    expanded_title_rect.Min + ImVec2(node.Rect.GetWidth(), expanded_title_rect.GetHeight())
);

} `

gbbnfhb avatar Dec 20 '25 03:12 gbbnfhb

This leads to another question: where is the node's width originally determined? Tracing this back reveals a different potential issue with the following function inline ImRect GetItemRect() { return ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); } While this appears harmless, it's important to note that this function returns the rect of the immediately preceding ImGui item, not necessarily the rect of the entire node.

gbbnfhb avatar Dec 20 '25 03:12 gbbnfhb