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

Improve TreeItem API and allow to move nodes #46773

Merged
merged 1 commit into from
May 18, 2021

Conversation

trollodel
Copy link
Contributor

@trollodel trollodel commented Mar 7, 2021

Partially fixes godotengine/godot-proposals#2088
Fixes #19796 by renaming get_children to get_first_child, as suggested in #19796 and in #16863 3 times.

This PR adds:

  • Some getters to reduce the number of manual iteration over the tree.
  • Tree get_tree().
  • get_first_child to replace get_children.
  • TreeItem.create_child.
  • A pointer to the previous item to speed up get_prev() (the old code still exists but now is an edge case).
  • move_before and move_after for moving items (see below), and remove move_to_top and move_to_bottom as they are not necessary anymore.

The new move_* methods allows moving items over the tree and (unlikely the current system), allow reparent and even moving the item and its children to another tree.
Those methods move self before (or after) the specified item. For me, this is the simplest (and less error-prone) approach, but I'm open to suggestions.

An example of cross-tree move

Move

@tool
extends Control

@onready var root: TreeItem = $Tree.create_item()
@onready var level1: TreeItem = $Tree.create_item()
@onready var level2: TreeItem = level1.create_child()

func _ready():
    root.set_text(0, "Root")
    level1.set_text(0, "Level 1")
    level2.set_text(0, "Level 2")
    
    $Tree2.create_item()
    var dummy: TreeItem = $Tree2.create_item()
    await get_tree().create_timer(3.0).timeout
    level1.move_after(dummy)
    dummy.free()

@Calinou Calinou added this to the 4.0 milestone Mar 7, 2021
@trollodel trollodel force-pushed the TreeItem+ branch 2 times, most recently from 90e5f6b to a200e8c Compare March 8, 2021 17:22
@trollodel trollodel marked this pull request as ready for review March 8, 2021 17:40
@trollodel trollodel requested review from a team as code owners March 8, 2021 17:40
Copy link
Member

@groud groud left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good to me. My only worry would be about making sure that TreeItems are always freed correctly, but it' seems that there is no way to make them orphan (without a tree).
So I guess it should be fine.

@groud groud self-requested a review March 9, 2021 15:59
Copy link
Member

@groud groud left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think get_first_sibling and get_last_sibling should be remove.

Sorry for the double review I messed up the first one (you cannot edit the review status)

scene/gui/tree.cpp Outdated Show resolved Hide resolved
scene/gui/tree.cpp Show resolved Hide resolved
Copy link
Member

@groud groud left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks overral good to me.

My only concern would be the efficiency get_child_count/get_index/etc... TreeItem might benefit of using an internal array of pointers to all its children, that would avoid the need to iterate over all children every time. Those pointers would need to be updated, but I don't think it's a big deal since TreeItem is internal anyway.

@trollodel trollodel force-pushed the TreeItem+ branch 2 times, most recently from 2e480da to d946cdc Compare March 12, 2021 13:53
@trollodel
Copy link
Contributor Author

TreeItem might benefit of using an internal array of pointers to all its children, that would avoid the need to iterate over all children every time.

Implemented. Now when you call get_child, get_child_count and get_children, children are cached (the first time it iterates over all the children to construct the cache). And the cache is updated efficiently when adding and removing nodes.
But, the cache is not populated until a call to the methods listed above is done, so the cache is not populated if it is not necessary.

Copy link
Member

@groud groud left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a rebase but looks good to me overall.

doc/classes/TreeItem.xml Outdated Show resolved Hide resolved
doc/classes/TreeItem.xml Outdated Show resolved Hide resolved
doc/classes/TreeItem.xml Outdated Show resolved Hide resolved
doc/classes/TreeItem.xml Outdated Show resolved Hide resolved
doc/classes/TreeItem.xml Outdated Show resolved Hide resolved
doc/classes/TreeItem.xml Outdated Show resolved Hide resolved
doc/classes/TreeItem.xml Outdated Show resolved Hide resolved
doc/classes/TreeItem.xml Outdated Show resolved Hide resolved
doc/classes/TreeItem.xml Outdated Show resolved Hide resolved
@akien-mga akien-mga merged commit 95bb720 into godotengine:master May 18, 2021
@akien-mga
Copy link
Member

Thanks!

@trollodel
Copy link
Contributor Author

I don't think this PR is enough to close godotengine/godot-proposals#2088. It is missing some feature listed there, like drag 'n' drop.
Also, should it be added in #16863?

@akien-mga
Copy link
Member

I don't think this PR is enough to close godotengine/godot-proposals#2088. It is missing some feature listed there, like drag 'n' drop.

Reopened, but note that it was closed because you used a keyword that triggers closure:
Screenshot_20210518_112245

See https://docs.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword

Also, should it be added in #16863?

What should be added? This list is mostly TODOs, not an exhaustive overview of renames that did happen (there's a lot more than what the list includes).

@trollodel
Copy link
Contributor Author

Reopened, but note that it was closed because you used a keyword that triggers closure

Thanks for reopening. I thought GH is smarter 😕.

This list is mostly TODOs, not an exhaustive overview of renames that did happen (there's a lot more than what the list includes).

Oh, ok. It's not important to me, especially if it not a tracker of all breaking changes.

@trollodel trollodel deleted the TreeItem+ branch May 18, 2021 09:40
@CsloudX
Copy link

CsloudX commented Nov 26, 2021

I think it should be add_child and move_child like node's method.
LOOK:

|-TreeRoot
  |-NodeA
    |-Child
  |-NodeB

How can I move Child to as a NodeB's child by move_before and move_after, like this:

|-TreeRoot
  |-NodeA
  |-NodeB
    |-Child

@trollodel
Copy link
Contributor Author

@CsloudX you can add a dummy item to NodeB, move_after Child to the dummy and then remove the dummy.
It's a workaround through, so it makes sense to have a way to handle that case. I'm a bit worried about performance of an add_node style method that appends the item to the end, especially when you have several items.
I'm not a maintainer, but can you open a proposal about this?

@CsloudX
Copy link

CsloudX commented Nov 28, 2021

@trollodel Thanks

@NoodleSushi
Copy link

Is it possible to backport this feature to Godot 3?

@Calinou
Copy link
Member

Calinou commented Jul 8, 2022

Is it possible to backport this feature to Godot 3?

This PR includes many compatibility-breaking changes, and therefore can't be backported as-is to Godot 3.x.

Feel free to work on a backport of the backwards-compatible features yourself, still.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make the Tree control node more usable TreeItem.get_children() iteration is non-intuitive
6 participants