godot_data_editor/item_tree.gd
2017-08-03 18:19:22 +02:00

286 lines
8.5 KiB
GDScript

# Item Tree
tool
extends Control
var dummy_root = null
onready var tree = get_node("Panel/VBox/Tree") # The item tree
onready var class_context_menu = get_node("ClassContextMenu") # Context menu when right clicking on a class
onready var instance_context_menu = get_node("InstanceContextMenu") # Context menu when right clicking on an instance
onready var filter_control = get_node("Panel/VBox/Margin/HBoxContainer/Filter")
var item_manager = null # Item Manager, used to load, modify and save items
var tree_roots = {} # Holds a copy of all tree roots, i.e. classes, accessible by class name
var tree_elements = {} # Reference to all tree elements, accessible by ["_roots"][item_class] (for the roots) and [item_class][id] for the items
signal on_delete_pressed # Emitted when item is deleted
signal on_rename_pressed # Emitted when item is renamed
signal on_duplicate_pressed # Emitted when item is duplicated
signal on_new_item_pressed # Emitted when new item is created
signal on_open # Emitted when item is opened in OS
signal on_item_selected(item, is_leaf) # Emitted when a tree item is selected, carries the item and wheter or not it is a leaf element
var last_selected = null # Reference to last selected item
var last_selected_id = "" # Name/id of last selected item
var last_selected_class = "" # Name/id of last selected class
var plugin_config
var filter = ""
# Load the tree when ready
func _ready():
# test = EditorPlugin.new()
tree.set_hide_root(true)
tree.set_select_mode(Tree.SELECT_SINGLE)
tree.set_allow_rmb_select(true)
load_tree()
func load_tree(is_reload = false):
plugin_config = ConfigFile.new()
plugin_config.load("res://addons/godot_data_editor/plugin.cfg")
self.item_manager = Globals.get("item_manager")
tree_elements = {}
tree_roots = {}
#filter_control.set_text("")
#filter = ""
last_selected_id = ""
last_selected_class = ""
last_selected = null
var tree_element_to_be_selected = null
# Store the class and name of the last selected item, in case the tree is reloaded
last_selected = tree.get_selected()
if last_selected:
if last_selected.has_meta("item"):
if last_selected.get_meta("item").get("_id"):
self.last_selected_id = last_selected.get_meta("item")._id
else:
self.last_selected_id = null
self.last_selected_class = last_selected.get_meta("class")
#print(last_selected_id)
#print(last_selected_class)
tree.clear()
# Create the roots for each item class, e.g. actors, monsters, crystals...
dummy_root = tree.create_item()
tree_elements["_roots"] = {}
var classes = item_manager.class_names
for item_class in classes:
var root = create_item_root(item_class)
tree_elements["_roots"][item_class] = root
pass
# Populate the list with items
classes.sort()
for item_class in classes:
tree_elements[item_class] = {}
var ids = item_manager.items[item_class].keys()
ids.sort()
for id in ids:
var item = item_manager.get_item(item_class, id)
if filter == "" or id.find(filter) != -1:
var tree_item = add_leaf(item, false)
pass
pass
if last_selected_id:
tree_element_to_be_selected = get_tree_item(last_selected_class, last_selected_id)
elif last_selected_class:
tree_element_to_be_selected = get_tree_item(last_selected_class)
elif tree.get_root().get_children():
tree_element_to_be_selected = tree.get_root().get_children()
else:
tree_element_to_be_selected = null # No elements to be selected
last_selected
# Handle filter
if tree_element_to_be_selected and not filter_control.has_focus():
tree.grab_focus()
tree_element_to_be_selected.select(0)
func create_item_root(item_class):
var tree_item = tree.create_item(dummy_root)
tree_item.set_selectable(0, true)
tree_item.set_icon(0, load(plugin_config.get_value("custom", "class_directory") + "/" + item_class + ".png"))
tree_item.set_text(0, item_class.capitalize())
tree_item.set_meta("class", item_class)
tree_roots[item_class] = tree_item
return tree_item
func select_first_element():
var first_element = tree.get_root().get_children()
if first_element:
first_element.select(0)
first_element = first_element.get_children()
last_selected = first_element.get_meta("item")
last_selected_id = last_selected._id
last_selected_class = last_selected._class
return last_selected
# Creates a new tree item, optionally with an existing item
func add_leaf(item, update_order):
var id = item._id
var item_class = item._class
var tree_item = tree.create_item(tree_roots[item_class])
set_tree_item_label_text(item, tree_item)
tree_item.set_selectable(0, true)
tree_item.set_meta("class", item_class)
tree_item.set_meta("item", item)
tree_elements[item_class][id] = tree_item
# Don't order the tree in the beginning as the ids will already be sorted
if update_order:
# Move the items which come before in the alphabet to the top
var elements_name_array = tree_elements[item_class].keys()
elements_name_array.sort()
tree_item.move_to_top()
var to_be_reordered = []
for element_name in elements_name_array:
if str(id) > str(element_name) or str(id) == str(element_name):
to_be_reordered.append(element_name)
else:
break
pass
to_be_reordered.invert()
for element_name in to_be_reordered:
tree_elements[item_class][element_name].move_to_top()
pass
tree_item.select(0)
return tree_item
func set_tree_item_label_text(item, tree_item = null):
if tree_item == null:
tree_item = get_tree_item(item._class, item._id)
if item._dirty or not item._persistent:
tree_item.set_text(0, " " + item._display_name + " (*)")
tree_item.set_custom_color(0, Color(1, 0.5, 0.5))
else:
tree_item.set_text(0, " " + item._display_name)
tree_item.set_custom_color(0, Color(0.7, 0.7, 0.7))
func get_selected_item_root():
var selected = tree.get_selected()
if selected.has_meta("item"):
return selected.get_parent()
else:
return selected
# A tree element in the tree was selected (either class or item)
func _on_Tree_cell_selected():
emit_signal("on_item_selected", get_selected_item(), get_selected_class())
func get_selected_item():
var selected = tree.get_selected()
if selected.has_meta("item"):
return selected.get_meta("item")
else:
return null
func get_selected_class():
return tree.get_selected().get_meta("class")
func get_tree_item(item_class, id = ""):
if id != "":
if tree_elements.has(item_class) and tree_elements[item_class].has(id):
return tree_elements[item_class][id]
else:
return null
else:
if tree_elements["_roots"].has(item_class):
return tree_elements["_roots"][item_class]
else:
return null
# Sets the selection to a specific tree item
func select_item(item):
if tree_elements.has(item._class) and tree_elements[item._class].has(item._id):
tree_elements[item._class][item._id].select(0)
# Sets the selection to a specific class
func select_class(item_class):
if tree_elements["_roots"].has(item_class):
tree_elements["_roots"][item_class].select(0)
func _on_Filter_text_changed( text ):
self.filter = text
load_tree()
# Right click context menu on leafs
# 0 = Add | 1 = Rename | 2 = Delete | 3 = Duplicate | 4 = Open
func _on_InstanceContextMenu_item_pressed(index):
if index == 0:
emit_signal("on_new_item_pressed")
elif index == 1:
emit_signal("on_rename_pressed")
elif index == 2:
emit_signal("on_delete_pressed")
elif index == 3:
emit_signal("on_duplicate_pressed")
elif index == 4:
emit_signal("on_open")
###########################################################
# CLASS CONTEXT MENU #
###########################################################
func _on_ClassContextMenu_about_to_show():
class_context_menu.set_item_text(0, tr("Add") + " " + get_selected_class().capitalize())
func _on_InstanceContextMenu_about_to_show():
pass
# Right click context menu on class branch
# 0 = Add | 1 = Delete Class
func _on_ClassContextMenu_item_pressed(index):
if index == 0:
emit_signal("on_new_item_pressed")
elif index == 1:
emit_signal("on_delete_pressed")
elif index == 2:
emit_signal("on_rename_pressed")
func _on_Tree_item_rmb_selected(pos):
var is_leaf = get_selected_item() != null
if is_leaf:
instance_context_menu.set_pos(get_global_mouse_pos())
instance_context_menu.popup()
else:
class_context_menu.set_pos(get_global_mouse_pos())
class_context_menu.popup()
func _on_DeleteItemDialog_confirmed():
var selected_item = get_selected_item()
if selected_item != null:
item_manager.delete_item(selected_item)
load_tree()
#TODO: Proper memory management?