ImGui::TreeNodeGetOpen() doesn't handle default-open nodes correctly, reports false until they're interacted with #9569

Open
opened 2026-10-01 13:28:17 +00:00 by adalisk-emikhaylov · 14 comments
adalisk-emikhaylov commented 2026-10-01 13:28:17 +00:00 (Migrated from github.com)

Version/Branch of Dear ImGui:

Version 1.92.0, Branch: docking (adfa5364c)

Back-ends:

imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp

Compiler, OS:

Linux + GCC

Full config/build information:

Dear ImGui 1.92.0 (19200)
--------------------------------

sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=202002
define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS
define: __linux__
define: __GNUC__=11
define: IMGUI_HAS_VIEWPORT
define: IMGUI_HAS_DOCK
--------------------------------

io.BackendPlatformName: imgui_impl_glfw (3306)
io.BackendRendererName: imgui_impl_opengl3
io.ConfigFlags: 0x00000400
 ViewportsEnable
io.ConfigViewportsNoDecoration
io.ConfigNavCaptureKeyboard
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x00001C1E
 HasMouseCursors
 HasSetMousePos
 PlatformHasViewports
 HasMouseHoveredViewport
 RendererHasVtxOffset
 RendererHasTextures
 RendererHasViewports
--------------------------------

io.Fonts: 9 fonts, Flags: 0x00000000, TexSize: 512,256
io.Fonts->FontLoaderName: FreeType
io.DisplaySize: 3840.00,2081.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------

style.WindowPadding: 12.00,12.00
style.WindowBorderSize: 1.00
style.FramePadding: 6.00,7.00
style.FrameRounding: 7.00
style.FrameBorderSize: 1.00
style.ItemSpacing: 12.00,9.00
style.ItemInnerSpacing: 6.00,6.00

Details:

My Issue/Question:

We're using ImGui::TreeNodeGetOpen() to check open-ness of tree nodes, but our nodes have flag ImGuiTreeNodeFlags_DefaultOpen set.

When this flag is present, TreeNodeGetOpen incorrectly reports false for those nodes until they're interacted with for the first time. After the first click, the value becomes correct (remains false after the first click, then toggles on each click).

We're able to work around this by accessing StateStorage directly and when this node is missing from it, treat it as open.

One way to fix this is to give TreeNodeGetOpen a parameter for the default value, like , bool default_open = false that it returns if the node wasn't interacted with yet.

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

ImGui::Begin("foo");

ImGui::CollapsingHeader("A");
ImGui::CollapsingHeader("B", ImGuiTreeNodeFlags_DefaultOpen);

ImGui::Text("A: %s", ImGui::TreeNodeGetOpen(ImGui::GetID("A")) ? "true" : "false");
ImGui::Text("B: %s", ImGui::TreeNodeGetOpen(ImGui::GetID("B")) ? "true" : "false");

ImGui::End();

Notice how it initially says A: false B: false, even though B is actually open. After you click on it at least once, B: becomes correct.

### Version/Branch of Dear ImGui: Version 1.92.0, Branch: docking (adfa5364c) ### Back-ends: imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp ### Compiler, OS: Linux + GCC ### Full config/build information: ```cpp Dear ImGui 1.92.0 (19200) -------------------------------- sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20 define: __cplusplus=202002 define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS define: __linux__ define: __GNUC__=11 define: IMGUI_HAS_VIEWPORT define: IMGUI_HAS_DOCK -------------------------------- io.BackendPlatformName: imgui_impl_glfw (3306) io.BackendRendererName: imgui_impl_opengl3 io.ConfigFlags: 0x00000400 ViewportsEnable io.ConfigViewportsNoDecoration io.ConfigNavCaptureKeyboard io.ConfigInputTextCursorBlink io.ConfigWindowsResizeFromEdges io.ConfigMemoryCompactTimer = 60.0 io.BackendFlags: 0x00001C1E HasMouseCursors HasSetMousePos PlatformHasViewports HasMouseHoveredViewport RendererHasVtxOffset RendererHasTextures RendererHasViewports -------------------------------- io.Fonts: 9 fonts, Flags: 0x00000000, TexSize: 512,256 io.Fonts->FontLoaderName: FreeType io.DisplaySize: 3840.00,2081.00 io.DisplayFramebufferScale: 1.00,1.00 -------------------------------- style.WindowPadding: 12.00,12.00 style.WindowBorderSize: 1.00 style.FramePadding: 6.00,7.00 style.FrameRounding: 7.00 style.FrameBorderSize: 1.00 style.ItemSpacing: 12.00,9.00 style.ItemInnerSpacing: 6.00,6.00 ``` ### Details: **My Issue/Question:** We're using `ImGui::TreeNodeGetOpen()` to check open-ness of tree nodes, but our nodes have flag `ImGuiTreeNodeFlags_DefaultOpen` set. When this flag is present, `TreeNodeGetOpen` incorrectly reports false for those nodes until they're interacted with for the first time. After the first click, the value becomes correct (remains false after the first click, then toggles on each click). We're able to work around this by accessing `StateStorage` directly and when this node is missing from it, treat it as open. One way to fix this is to give `TreeNodeGetOpen` a parameter for the default value, like `, bool default_open = false` that it returns if the node wasn't interacted with yet. ### Screenshots/Video: _No response_ ### Minimal, Complete and Verifiable Example code: ```cpp ImGui::Begin("foo"); ImGui::CollapsingHeader("A"); ImGui::CollapsingHeader("B", ImGuiTreeNodeFlags_DefaultOpen); ImGui::Text("A: %s", ImGui::TreeNodeGetOpen(ImGui::GetID("A")) ? "true" : "false"); ImGui::Text("B: %s", ImGui::TreeNodeGetOpen(ImGui::GetID("B")) ? "true" : "false"); ImGui::End(); ``` Notice how it initially says `A: false` `B: false`, even though B is actually open. After you click on it at least once, `B:` becomes correct.
ocornut commented 2026-10-01 15:02:28 +00:00 (Migrated from github.com)

One way to fix this is to give TreeNodeGetOpen a parameter for the default value, like , bool default_open = false that it returns if the node wasn't interacted with yet.

I was not sure what was the proper design and solution for this.
This is the evident answer but I didn't like this solution much, and wondered if _ImGuiTreeNodeFlags_DefaultOpen shouldn't simply store the state.

> One way to fix this is to give TreeNodeGetOpen a parameter for the default value, like , bool default_open = false that it returns if the node wasn't interacted with yet. I was not sure what was the proper design and solution for this. This is the evident answer but I didn't like this solution much, and wondered if `_ImGuiTreeNodeFlags_DefaultOpen` shouldn't simply store the state.
ocornut commented 2026-10-01 15:02:28 +00:00 (Migrated from github.com)

One way to fix this is to give TreeNodeGetOpen a parameter for the default value, like , bool default_open = false that it returns if the node wasn't interacted with yet.

I was not sure what was the proper design and solution for this.
This is the evident answer but I didn't like this solution much, and wondered if _ImGuiTreeNodeFlags_DefaultOpen shouldn't simply store the state.

> One way to fix this is to give TreeNodeGetOpen a parameter for the default value, like , bool default_open = false that it returns if the node wasn't interacted with yet. I was not sure what was the proper design and solution for this. This is the evident answer but I didn't like this solution much, and wondered if `_ImGuiTreeNodeFlags_DefaultOpen` shouldn't simply store the state.
ocornut commented 2026-10-01 15:02:28 +00:00 (Migrated from github.com)

One way to fix this is to give TreeNodeGetOpen a parameter for the default value, like , bool default_open = false that it returns if the node wasn't interacted with yet.

I was not sure what was the proper design and solution for this.
This is the evident answer but I didn't like this solution much, and wondered if _ImGuiTreeNodeFlags_DefaultOpen shouldn't simply store the state.

> One way to fix this is to give TreeNodeGetOpen a parameter for the default value, like , bool default_open = false that it returns if the node wasn't interacted with yet. I was not sure what was the proper design and solution for this. This is the evident answer but I didn't like this solution much, and wondered if `_ImGuiTreeNodeFlags_DefaultOpen` shouldn't simply store the state.
adalisk-emikhaylov commented 2026-10-01 17:26:39 +00:00 (Migrated from github.com)

You mean DefaultOpen would write to the state as soon as it appears? I think I like the parameter more, because it would give the correct result for the first frame if called before the tree node.

You mean `DefaultOpen` would write to the state as soon as it appears? I think I like the parameter more, because it would give the correct result for the first frame if called before the tree node.
adalisk-emikhaylov commented 2026-10-01 17:26:39 +00:00 (Migrated from github.com)

You mean DefaultOpen would write to the state as soon as it appears? I think I like the parameter more, because it would give the correct result for the first frame if called before the tree node.

You mean `DefaultOpen` would write to the state as soon as it appears? I think I like the parameter more, because it would give the correct result for the first frame if called before the tree node.
adalisk-emikhaylov commented 2026-10-01 17:26:39 +00:00 (Migrated from github.com)

You mean DefaultOpen would write to the state as soon as it appears? I think I like the parameter more, because it would give the correct result for the first frame if called before the tree node.

You mean `DefaultOpen` would write to the state as soon as it appears? I think I like the parameter more, because it would give the correct result for the first frame if called before the tree node.
ocornut commented 2026-10-02 09:59:55 +00:00 (Migrated from github.com)

We're using ImGui::TreeNodeGetOpen() to check open-ness of tree nodes

As a side note, would you be kind to explain how/you are using this data?
I was hesitant to provide this API as-is (vs a more generic API) and interested to hear about your usage.

> We're using ImGui::TreeNodeGetOpen() to check open-ness of tree nodes As a side note, would you be kind to explain how/you are using this data? I was hesitant to provide this API as-is (vs a more generic API) and interested to hear about your usage.
ocornut commented 2026-10-02 09:59:55 +00:00 (Migrated from github.com)

We're using ImGui::TreeNodeGetOpen() to check open-ness of tree nodes

As a side note, would you be kind to explain how/you are using this data?
I was hesitant to provide this API as-is (vs a more generic API) and interested to hear about your usage.

> We're using ImGui::TreeNodeGetOpen() to check open-ness of tree nodes As a side note, would you be kind to explain how/you are using this data? I was hesitant to provide this API as-is (vs a more generic API) and interested to hear about your usage.
ocornut commented 2026-10-02 09:59:55 +00:00 (Migrated from github.com)

We're using ImGui::TreeNodeGetOpen() to check open-ness of tree nodes

As a side note, would you be kind to explain how/you are using this data?
I was hesitant to provide this API as-is (vs a more generic API) and interested to hear about your usage.

> We're using ImGui::TreeNodeGetOpen() to check open-ness of tree nodes As a side note, would you be kind to explain how/you are using this data? I was hesitant to provide this API as-is (vs a more generic API) and interested to hear about your usage.
adalisk-emikhaylov commented 2026-10-07 09:21:39 +00:00 (Migrated from github.com)

We draw a scene tree view, and each node is selectable. There's a hotkey to select all visible nodes (visible = none of the parents are closed), or visible nodes in a certain range (clicking one, then shift-clicking another, like in file managers). Not the most intuitive behavior that hidden nodes are skipped, but I didn't write this code. 🙂

So when that hotkey is pressed, we loop over all nodes (which is separate from drawing them), and check their parents with ImGui::TreeNodeGetOpen() (or with direct state access now).

I guess we could merge the selection logic with drawing and do it all in one pass...

We draw a scene tree view, and each node is selectable. There's a hotkey to select all visible nodes (visible = none of the parents are closed), or visible nodes in a certain range (clicking one, then shift-clicking another, like in file managers). Not the most intuitive behavior that hidden nodes are skipped, but I didn't write this code. 🙂 So when that hotkey is pressed, we loop over all nodes (which is separate from drawing them), and check their parents with `ImGui::TreeNodeGetOpen()` (or with direct state access now). I guess we could merge the selection logic with drawing and do it all in one pass...
adalisk-emikhaylov commented 2026-10-07 09:21:39 +00:00 (Migrated from github.com)

We draw a scene tree view, and each node is selectable. There's a hotkey to select all visible nodes (visible = none of the parents are closed), or visible nodes in a certain range (clicking one, then shift-clicking another, like in file managers). Not the most intuitive behavior that hidden nodes are skipped, but I didn't write this code. 🙂

So when that hotkey is pressed, we loop over all nodes (which is separate from drawing them), and check their parents with ImGui::TreeNodeGetOpen() (or with direct state access now).

I guess we could merge the selection logic with drawing and do it all in one pass...

We draw a scene tree view, and each node is selectable. There's a hotkey to select all visible nodes (visible = none of the parents are closed), or visible nodes in a certain range (clicking one, then shift-clicking another, like in file managers). Not the most intuitive behavior that hidden nodes are skipped, but I didn't write this code. 🙂 So when that hotkey is pressed, we loop over all nodes (which is separate from drawing them), and check their parents with `ImGui::TreeNodeGetOpen()` (or with direct state access now). I guess we could merge the selection logic with drawing and do it all in one pass...
ocornut commented 2026-10-12 13:38:12 +00:00 (Migrated from github.com)

I'm hesitant between:

bool TreeNodeGetOpen(ImGuiID storage_id, bool default_open = true);
and
bool TreeNodeGetOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags = 0);

bool:

  • pro: easier to understand
  • pro: shorter to use
  • con: optional param default to true

flags:

  • pro: potentially bit more future proof.
  • pro: optional param default to 0 feels generally better IMHO.
I'm hesitant between: `bool TreeNodeGetOpen(ImGuiID storage_id, bool default_open = true);` and `bool TreeNodeGetOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags = 0);` bool: - pro: easier to understand - pro: shorter to use - con: optional param default to `true` flags: - pro: potentially bit more future proof. - pro: optional param default to 0 feels generally better IMHO.
ocornut commented 2026-10-12 13:38:12 +00:00 (Migrated from github.com)

I'm hesitant between:

bool TreeNodeGetOpen(ImGuiID storage_id, bool default_open = true);
and
bool TreeNodeGetOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags = 0);

bool:

  • pro: easier to understand
  • pro: shorter to use
  • con: optional param default to true

flags:

  • pro: potentially bit more future proof.
  • pro: optional param default to 0 feels generally better IMHO.
I'm hesitant between: `bool TreeNodeGetOpen(ImGuiID storage_id, bool default_open = true);` and `bool TreeNodeGetOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags = 0);` bool: - pro: easier to understand - pro: shorter to use - con: optional param default to `true` flags: - pro: potentially bit more future proof. - pro: optional param default to 0 feels generally better IMHO.
adalisk-emikhaylov commented 2026-10-17 12:56:27 +00:00 (Migrated from github.com)

Wouldn't it be bool default_open = false to match the default lack of ImGuiTreeNodeFlags_DefaultOpen?
I think I like the flags version a bit more, but both are ok.

Wouldn't it be `bool default_open = false` to match the default lack of `ImGuiTreeNodeFlags_DefaultOpen`? I think I like the flags version a bit more, but both are ok.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ocornut/imgui#9569
No description provided.