Dragging TreeItems within Tree control node

Godot Version

v4.2.1 Win64

Question

Hello everybody!
I’m trying to create something like a blueprint system for a game where you create vehicles, and to make it easier to group parts together I need to use a Tree control node, which works perfectly for this scenario, however, although I have the ability to rename the tree items I can’t reorder them which is very strange, considering the Tree control node has a DROP_MODE_FLAGS option, but no way to access what item index the mouse is hovering over and there seems to be nothing online for dragging things around except for entire control nodes, not TreeItems.

If anyone knows a way to drag and drop TreeItems to reorganise them within the Tree control node, that would be great!

Thank you for your time!

You will need to implement the drag and drop functionality yourself. I have implemented it in a project before, the code goes like this:

func _get_drag_data(_at_position: Vector2) -> Variant:
	var items := []
	var next: TreeItem = get_next_selected(null)
	var v := VBoxContainer.new()
	while next:
		if get_root() == next.get_parent():
			items.append(next)
			var l := Label.new()
			l.text = next.get_text(0)
			v.add_child(l)
		next = get_next_selected(next)
	set_drag_preview(v)
	return items

func _can_drop_data(at_position: Vector2, data: Variant) -> bool:
	drop_mode_flags = Tree.DROP_MODE_INBETWEEN
	var drop_section := get_drop_section_at_position(at_position)
	if drop_section == -100:
		return false
	var item := get_item_at_position(at_position)
	if item in data:
		return false
	return true

func _drop_data(at_position: Vector2, data: Variant) -> void:
	var drop_section := get_drop_section_at_position(at_position)
	var other_item := get_item_at_position(at_position)
	var sprite_groups := []
	for item in data:
		sprite_groups.append(item.get_meta("sprite_group"))
	if drop_section == -1:
		group_moved.emit(sprite_groups, other_item.get_index())
	else:
		group_moved.emit(sprite_groups, other_item.get_index() + 1)
	for i in data.size():
		var item := data[i] as TreeItem
		if drop_section == -1:
			item.move_before(other_item)
		elif drop_section == 1:
			if i == 0:
				item.move_after(other_item)
			else:
				item.move_after(data[i - 1])

There’s some extra stuff in there that’s project specific, like the signals and the metadata, you can just ignore that.