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

Open specific tree node programmatically #5423

Closed
RandyGaul opened this issue Jun 26, 2022 · 5 comments
Closed

Open specific tree node programmatically #5423

RandyGaul opened this issue Jun 26, 2022 · 5 comments
Labels
label/id and id stack implicit identifiers, pushid(), id stack tree tree nodes

Comments

@RandyGaul
Copy link
Contributor

RandyGaul commented Jun 26, 2022

Version/Branch of Dear ImGui:
Version: Dear ImGui 1.84 WIP (18313)
Branch : master

My Issue/Question:

When using tree nodes is it possible to expand a specific tree node arbitrarily? I'm implementing undo/redo for my UI, and after navigating around and undo-ing the last edit, I'd like to expand any tree nodes to the item edited, but am struggling to figure out how to expand anything beyond the next item with SetNextItemOpen.

@rokups
Copy link
Contributor

rokups commented Jun 27, 2022

Use ImGui::SetNextItemOpen() before tree node you want to open/close.

@ocornut ocornut added tree tree nodes label/id and id stack implicit identifiers, pushid(), id stack labels Jun 27, 2022
@ocornut
Copy link
Owner

ocornut commented Jun 27, 2022

Assuming you can calculate your ID, the internal way to manipulate tree node state would be via e.g (yet non existing function):

void ImGui::SetItemStateOpen(ImGuiID id, bool open)
{
    ImGuiContext& g = *GImGui;
    ImGuiWindow* window = g.CurrentWindow;
    ImGuiStorage* storage = window->DC.StateStorage;
    storage->SetInt(id, open ? 1 : 0);
}

Effectively TreeNode() simply calls storage->SetInt() directly.

For "reading", internally TreeNode() calls TreeNodeBehaviorIsOpen() which does two things: handle SetNextItemOpen() + read from that same storage (without creating an entry if unnecessary). Perhaps we can refactor some of that to provide two symmetrical function to work with the storage.

Then the problem you have if to come up with the ID of each node leading to the path of your newly selected object.
The recap is:
https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system

We have an unpushed/unpublished function called GetIDFromPath() which is a helper which among other things can be used to do e.g.

  • GetIDFromPath("//windowname/treenode1/treenode2") return ID that's the hash of "windownametreenode1treenode2". Leading // ignore current ID stack top, subsequent / separators are ignored.
  • GetIDFromPath("treenode1/treenode2") // if called from the root of Window "windowname" that's the same.
  • GetIDFromPath("/treenode1/treenode2") // if called from anywhere in Window "windowname" that's the same.

However, even if you suggested "how to expand anything beyond the next item with SetNextItemOpen." my intuition is that given your problem set if would be much easier if you actually used SetNextItemOpen()`

OnSelectNode(MyNode* node)
{
   // search 'node' in your hierarchy
   // store in a vector e.g. std::vector<MyNode*> SelectPathToNode the "path" to that object in your hierarchy, using pointer to your objects (or identifier of your object
}

OnTreeDisplay()
{
    // before rendering a node
    if (!SelectPathToNode.empty() && depth < SelectPathToNode.size() && SelectPathToNode[depth] == node)
       ImGui::SetNextItemOpen(true);
}

@RandyGaul
Copy link
Contributor Author

RandyGaul commented Jun 27, 2022

Thanks Ocornut, that makes sense. From a user perspective the assumption is that Dear ImGui stores the tree structure somewhere, and that it would be silly to duplicate the structure in user code. However, since there's merely a concatenation of hashes the explicit tree is lost.

Do you think it would be a good idea to cache the tree structure in memory within Dear ImGui? Then an API could be implemented to open/close a node and all its parents. For example, the parent can be stored with a small amount of memory along with the 0/1 int state within ImGuiStorage. The structure could be easily traversed to set states to 1 along the parent chain. The user can get the hashed id of a node with GetItemID, correct? Then perhaps a function such as OpenTreeNodeAndParents(id) or CloseTreeNodeAndParents(id) could be implemented.

I do not think crawling the string path and hashing them would be the way to go, like GetIDFromPath. It feels a bit backwards and complicated.

However, even if you suggested "how to expand anything beyond the next item with SetNextItemOpen." my intuition is that given your problem set if would be much easier if you actually used SetNextItemOpen()`

Yes, implementing this on the user side is totally possible if the tree structure is stored/traversed. Though, sometimes the tree API is used in code without maintaining an explicit tree structure (i.e. just a stack, much like the hash'd id stack), and so the user is in the same problem space that Dear ImGui is. Though, I think in this case Dear ImGui might be in a simpler position to tackle this stuff.

I can experiment with an implementation if you're open to the possibility or discussion of a PR, assuming I've understood the problem context well enough.

@ocornut
Copy link
Owner

ocornut commented Jun 28, 2022

From a user perspective the assumption is that Dear ImGui stores the tree structure somewhere

But it does not.

Do you think it would be a good idea to cache the tree structure in memory within Dear ImGui?

No it wouldn't be a good idea at all.

Though, sometimes the tree API is used in code without maintaining an explicit tree structure (i.e. just a stack, much like the hash'd id stack), and so the user is in the same problem space that Dear ImGui is.

Surely you must have a way to identify a sort of "path" to your items.

I can experiment with an implementation if you're open to the possibility or discussion of a PR, assuming I've understood the problem context well enough.

I'm pretty sure it'll be more natural and easier to do on your end but feel free to experiment and see what yo ufind.

@RandyGaul
Copy link
Contributor Author

Ah I see, I ran an experiment and realized ImGui has no clue what the tree structure could possibly be until it's actually run. So even if the structure were to be cached, looking it up as a user would be pretty weird as you'd have to specify a lot of keys for lookup, which starts to look like the "path" anyways.

We can close this, thanks a lot for the discussion though Ocornut!

ocornut added a commit that referenced this issue Jun 28, 2022
ocornut added a commit that referenced this issue Oct 15, 2024
…TreeNodeBehaviorIsOpen() (#4814, #5423, #282, #2958, #924)

+ Removed obsolete header checks for IMGUI_DISABLE_METRICS_WINDOW.
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 tree tree nodes
Projects
None yet
Development

No branches or pull requests

3 participants