mirror of
https://github.com/Relintai/godot_data_editor.git
synced 2024-11-13 06:27:19 +01:00
479 lines
15 KiB
GDScript
479 lines
15 KiB
GDScript
tool
|
|
extends Panel
|
|
# This class represents an item control used to change the data values, e.g. the text boxes.
|
|
|
|
|
|
var load_icon = preload("icons/icon_load.png")
|
|
var multi_line_icon = preload("icons/icon_multi_line.png")
|
|
|
|
var property_name = ""
|
|
var type = TYPE_NIL
|
|
var hint = 0
|
|
var hint_array = []
|
|
var hint_text = ""
|
|
var number_of_hints = 0
|
|
var value = null # The value of the property
|
|
|
|
var has_delete_button = false
|
|
|
|
|
|
var control = null
|
|
var popup = null
|
|
var menu = null
|
|
var value_editor = []
|
|
|
|
|
|
var dialog = null
|
|
var object_type_line_edit = null
|
|
|
|
|
|
signal on_property_value_changed(property, value)
|
|
signal property_item_load_button_down(property_item)
|
|
signal custom_property_delete_requested(property_name)
|
|
|
|
# has_delete is used for custom properties
|
|
func initialize(property_name, type, value = null, hint = 0, hint_text = "", has_delete = false):
|
|
self.property_name = property_name
|
|
self.type = type
|
|
self.value = value
|
|
self.hint = hint
|
|
self.hint_text = hint_text
|
|
self.has_delete_button = has_delete
|
|
|
|
|
|
|
|
func _ready():
|
|
# Label describing property
|
|
var property_label = Label.new()
|
|
property_label.set_text(property_name.capitalize())
|
|
|
|
# Split property hints
|
|
self.hint_array = hint_text.split(",")
|
|
self.number_of_hints = hint_array.size()
|
|
|
|
##################################################
|
|
# For each type, one control is defined
|
|
##################################################
|
|
if type == TYPE_BOOL:
|
|
create_bool()
|
|
elif type == TYPE_INT or type == TYPE_REAL:
|
|
create_number()
|
|
elif type == TYPE_STRING:
|
|
create_string()
|
|
elif type == TYPE_COLOR:
|
|
create_color()
|
|
elif type == TYPE_NODE_PATH:
|
|
create_node_path()
|
|
elif type == TYPE_VECTOR2:
|
|
control = create_custom_editor_button(value);
|
|
create_custom_editor(2, 2, 10, ["x", "y"])
|
|
elif type == TYPE_VECTOR3:
|
|
control = create_custom_editor_button(value);
|
|
create_custom_editor(3, 3, 10, ["x", "y", "z"])
|
|
elif type == TYPE_RECT2:
|
|
control = create_custom_editor_button(value);
|
|
create_custom_editor(4, 4, 10, ["x", "y", "w", "h"])
|
|
elif type == TYPE_PLANE:
|
|
control = create_custom_editor_button(value);
|
|
create_custom_editor(4, 4, 10, ["x", "y", "z", "d"])
|
|
elif type == TYPE_QUAT:
|
|
control = create_custom_editor_button(value);
|
|
create_custom_editor(4, 4, 10, ["x", "y", "z", "w"])
|
|
elif type == TYPE_TRANSFORM:
|
|
control = create_custom_editor_button(value);
|
|
create_custom_editor(12, 4, 16, ["xx", "xy", "xz", "xo", "yx", "yy", "yz", "yo", "zx", "zy", "zz", "zo"])
|
|
elif type == TYPE_OBJECT or type == TYPE_IMAGE:
|
|
create_object_or_image()
|
|
else:
|
|
control = get_not_yet_supported()
|
|
|
|
control.set_h_size_flags(Control.SIZE_EXPAND_FILL)
|
|
control.set_margin(MARGIN_LEFT, 200)
|
|
control.set_custom_minimum_size(Vector2(get_parent().get_parent().get_parent().get_size().x - 270, 0))
|
|
add_child(property_label)
|
|
add_child(control)
|
|
|
|
if has_delete_button:
|
|
var delete_button = ToolButton.new()
|
|
delete_button.set_button_icon(preload("res://addons/DataEditor/icons/icon_remove.png"))
|
|
delete_button.set_h_size_flags(Control.SIZE_EXPAND)
|
|
delete_button.set_margin(MARGIN_LEFT, get_parent().get_parent().get_parent().get_size().x - 34 )
|
|
delete_button.set_custom_minimum_size(Vector2(28, 24))
|
|
delete_button.connect("button_down", self, "route_delete_request")
|
|
# delete_button.connect("button_down", self, "emit_signal", ["custom_property_delete_requested")
|
|
add_child(delete_button)
|
|
|
|
func route_delete_request():
|
|
emit_signal("custom_property_delete_requested")
|
|
|
|
func create_custom_editor_button(value):
|
|
var button = Button.new()
|
|
button.set_text(str(value))
|
|
button.connect("button_down", self, "open_custom_editor")
|
|
return button
|
|
|
|
func open_custom_editor():
|
|
menu.set_pos(get_global_mouse_pos())
|
|
menu.get_children()[1].grab_focus()
|
|
menu.popup()
|
|
|
|
|
|
##################################################
|
|
# All types
|
|
##################################################
|
|
|
|
func create_bool():
|
|
control = CheckBox.new()
|
|
control.set_text(str(value))
|
|
control.set_pressed(value)
|
|
control.connect("toggled", self, "set_checkbox_label", [])
|
|
control.connect("toggled", self, "property_value_changed", [])
|
|
|
|
func create_number():
|
|
if hint == PROPERTY_HINT_RANGE:
|
|
var control_min = -16777216
|
|
var control_max = 16777216
|
|
|
|
var control_step = 0
|
|
if type == TYPE_INT:
|
|
control_step = 1
|
|
else:
|
|
control_step = 0.00001
|
|
|
|
if number_of_hints >= 1:
|
|
if not hint_array[0].empty():
|
|
control_min = int(hint_array[0])
|
|
|
|
if number_of_hints >= 2:
|
|
if not hint_array[1].empty():
|
|
control_max = int(hint_array[1])
|
|
|
|
if number_of_hints >= 3:
|
|
if not hint_array[2].empty():
|
|
control_step = float(hint_array[2])
|
|
|
|
# TODO: This does not seem to be exposed in GDScript yet?
|
|
if number_of_hints >= 4 and hint_array[3] == "slider":
|
|
control = HSlider.new()
|
|
control.set_min(control_min)
|
|
control.set_max(control_max)
|
|
control.set_step(control_step)
|
|
control.set_value(value);
|
|
control.connect("value_changed", self, "property_value_changed", [])
|
|
#controlset_size(Size2(110,30)*EDSCALE);
|
|
else:
|
|
control = SpinBox.new()
|
|
control.set_min(control_min)
|
|
control.set_max(control_max)
|
|
control.set_step(control_step)
|
|
control.set_value(value)
|
|
control.connect("value_changed", self, "property_value_changed", [])
|
|
#set_size(Size2(70,35)*EDSCALE);
|
|
elif hint == PROPERTY_HINT_ENUM:
|
|
control = MenuButton.new()
|
|
for i in range(0, hint_array.size()):
|
|
control.get_popup().add_item(hint_array[i])
|
|
control.set_flat(false)
|
|
# control.set_pos(get_pos())
|
|
control.set_text(control.get_popup().get_item_text(value))
|
|
control.get_popup().connect("item_pressed", self, "int_enum_property_value_changed", [])
|
|
|
|
elif hint == PROPERTY_HINT_EXP_EASING:
|
|
control = get_not_yet_supported()
|
|
elif hint == PROPERTY_HINT_FLAGS:
|
|
control = get_not_yet_supported()
|
|
else:
|
|
control = SpinBox.new()
|
|
control.set_value(value);
|
|
if type == TYPE_REAL:
|
|
control.set_min(-16777216)
|
|
control.set_max(16777216)
|
|
control.set_step(0.00001)
|
|
else:
|
|
control.set_max(2147483647)
|
|
control.set_min(-2147483647)
|
|
control.set_step(1)
|
|
control.connect("value_changed", self, "property_value_changed", [])
|
|
#control = create_custom_editor_button(value);
|
|
#create_custom_editor(1, 1, 50, ["value"])
|
|
#custom_editor_value_applied()
|
|
|
|
func create_string():
|
|
if hint == PROPERTY_HINT_ENUM:
|
|
control = MenuButton.new()
|
|
for i in range(0, hint_array.size()):
|
|
control.get_popup().add_item(hint_array[i])
|
|
control.set_flat(false)
|
|
control.set_text(value)
|
|
control.get_popup().connect("item_pressed", self, "string_enum_property_value_changed", [])
|
|
elif hint == PROPERTY_HINT_MULTILINE_TEXT:
|
|
# RABRABRAB
|
|
control = HBoxContainer.new()
|
|
var line_edit = LineEdit.new()
|
|
line_edit.set_h_size_flags(SIZE_EXPAND_FILL)
|
|
var more_button = ToolButton.new()
|
|
more_button.set_button_icon(multi_line_icon)
|
|
line_edit.set_text(str(value))
|
|
control.add_child(line_edit)
|
|
control.add_child(more_button)
|
|
|
|
popup = Popup.new()
|
|
popup.set_size(Vector2(600, 400))
|
|
var text_edit = TextEdit.new()
|
|
text_edit.set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 0)
|
|
text_edit.set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 0)
|
|
text_edit.set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0)
|
|
text_edit.set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0)
|
|
add_child(popup)
|
|
popup.add_child(text_edit)
|
|
text_edit.set_text(str(value))
|
|
|
|
line_edit.connect("text_changed", self, "property_value_changed", [])
|
|
more_button.connect("button_down", popup, "popup_centered_minsize", [Vector2(800, 600)])
|
|
popup.connect("popup_hide", self, "text_edit_popup_closed", [])
|
|
else:
|
|
control = LineEdit.new()
|
|
control.set_text(str(value))
|
|
control.connect("text_changed", self, "property_value_changed", [])
|
|
|
|
func create_color():
|
|
control = ColorPickerButton.new()
|
|
# If, for some reason, the color is still (de)serialized wrongly, split the string
|
|
if typeof(value) == TYPE_STRING and value.find(","):
|
|
var split_color = value.split(",")
|
|
value = Color(split_color[0], split_color[1], split_color[2], split_color[3])
|
|
control.set_color(value)
|
|
control.connect("color_changed", self, "property_value_changed", [])
|
|
|
|
func create_node_path():
|
|
control = LineEdit.new()
|
|
control.set_text(value)
|
|
control.connect("text_changed", self, "property_value_changed", [])
|
|
|
|
|
|
# Adapted Port of property editor
|
|
func create_custom_editor(amount, columns, label_w, strings, read_only = false):
|
|
self.value_editor = []
|
|
self.menu = PopupMenu.new()
|
|
menu.connect("popup_hide", self, "custom_editor_value_applied")
|
|
var w = 80
|
|
var h = 20
|
|
var m = 10
|
|
var MAX_VALUE_EDITORS = 12
|
|
var value_label = []
|
|
for i in range(0, amount):
|
|
var line_edit = LineEdit.new()
|
|
line_edit.set_text(str(get_custom_editor_value(i)))
|
|
value_editor.append(line_edit)
|
|
menu.add_child(value_editor[i])
|
|
value_label.append(Label.new())
|
|
menu.add_child(value_label[i])
|
|
pass
|
|
|
|
var rows=((amount-1)/columns)+1
|
|
menu.set_size(Vector2( m*(1+columns)+(w+label_w)*columns, m*(1+rows)+h*rows ) );
|
|
for i in range(0, amount):
|
|
var c = i % columns;
|
|
var r = i / columns;
|
|
value_editor[i].show()
|
|
value_label[i].show()
|
|
if i < strings.size():
|
|
value_label[i].set_text(strings[i])
|
|
else:
|
|
value_label[i].set_text("")
|
|
|
|
value_editor[i].set_pos( Vector2( m+label_w+c*(w+m+label_w), m+r*(h+m) ))
|
|
value_editor[i].set_size( Vector2( w, h ) )
|
|
value_label[i].set_pos( Vector2( m+c*(w+m+label_w), m+r*(h+m) ) )
|
|
value_editor[i].set_editable(!read_only)
|
|
|
|
pass
|
|
|
|
add_child(menu)
|
|
|
|
|
|
func custom_editor_value_applied():
|
|
# TODO: Validate
|
|
var va = []
|
|
for line in value_editor:
|
|
var v = float(line.get_text())
|
|
va.append(v)
|
|
|
|
var value = null
|
|
if type == TYPE_VECTOR2:
|
|
value = Vector2(va[0], va[1])
|
|
if type == TYPE_VECTOR3:
|
|
value = Vector3(va[0], va[1], va[2])
|
|
if type == TYPE_RECT2:
|
|
value = Rect2(va[0], va[1], va[2], va[3])
|
|
if type == TYPE_PLANE:
|
|
value = Plane(va[0], va[1], va[2], va[3])
|
|
if type == TYPE_QUAT:
|
|
value = Quat(va[0], va[1], va[2], va[3])
|
|
if type == TYPE_TRANSFORM:
|
|
value = Transform(Vector3(va[0], va[1], va[2]), Vector3(va[4], va[5], va[6]), Vector3(va[8], va[9], va[10]), Vector3(va[3], va[7], va[11]))
|
|
|
|
if value != self.value:
|
|
self.value = value
|
|
emit_signal("on_property_value_changed", property_name, value)
|
|
control.set_text(str(value))
|
|
|
|
func get_custom_editor_value(index):
|
|
if type == TYPE_VECTOR2:
|
|
if index == 0: return value.x
|
|
else: return value.y
|
|
elif type == TYPE_VECTOR3:
|
|
if index == 0: return value.x
|
|
elif index == 1: return value.y
|
|
else: return value.z
|
|
elif type == TYPE_RECT2:
|
|
if index == 0: return value.pos.x
|
|
elif index == 1: return value.pos.y
|
|
elif index == 2: return value.size.x
|
|
else: return value.size.y
|
|
elif type == TYPE_QUAT:
|
|
if index == 0: return value.x
|
|
elif index == 1: return value.y
|
|
elif index == 2: return value.z
|
|
else: return value.w
|
|
elif type == TYPE_PLANE:
|
|
if index == 0: return value.x
|
|
elif index == 1: return value.y
|
|
elif index == 2: return value.z
|
|
else: return value.d
|
|
elif type == TYPE_TRANSFORM:
|
|
if index == 0: return value.basis.x.x
|
|
elif index == 1: return value.basis.x.y
|
|
elif index == 2: return value.basis.x.z
|
|
elif index == 3: return value.origin.x
|
|
elif index == 4: return value.basis.y.x
|
|
elif index == 5: return value.basis.y.y
|
|
elif index == 6: return value.basis.y.z
|
|
elif index == 7: return value.origin.y
|
|
elif index == 8: return value.basis.z.x
|
|
elif index == 9: return value.basis.z.y
|
|
elif index == 10: return value.basis.z.z
|
|
else: return value.origin.z
|
|
|
|
func create_object_or_image():
|
|
control = HBoxContainer.new()
|
|
object_type_line_edit = LineEdit.new()
|
|
object_type_line_edit.set_text(str(value))
|
|
object_type_line_edit.set_h_size_flags(SIZE_EXPAND_FILL)
|
|
object_type_line_edit.connect("text_changed", self, "property_value_changed", [])
|
|
if hint_text == "Texture" or type == TYPE_IMAGE:
|
|
var f = File.new()
|
|
if value != null and f.file_exists(value):
|
|
var texture = load(value)
|
|
var texture_frame = TextureFrame.new()
|
|
texture_frame.set_expand(true)
|
|
texture_frame.set_custom_minimum_size(Vector2(get_parent_area_size().y, get_parent_area_size().y))
|
|
texture_frame.set_texture(texture)
|
|
var texture_popup = Popup.new()
|
|
var texture_frame_full = TextureFrame.new()
|
|
texture_frame_full.set_texture(texture)
|
|
texture_popup.add_child(texture_frame_full)
|
|
texture_popup.set_size(texture.get_size())
|
|
# texture_frame.set_process_input(true)
|
|
# texture_frame.connect("input_event", self, "open_image", [])
|
|
control.add_child(texture_frame)
|
|
# control.add_child(texture_popup)
|
|
|
|
control.add_child(object_type_line_edit)
|
|
|
|
|
|
var load_button = ToolButton.new()
|
|
load_button.set_button_icon(load_icon)
|
|
control.add_child(load_button)
|
|
|
|
|
|
if Globals.get("debug_is_editor"):
|
|
dialog = EditorFileDialog.new()
|
|
dialog.set_access(EditorFileDialog.ACCESS_RESOURCES)
|
|
dialog.set_mode(EditorFileDialog.MODE_OPEN_FILE)
|
|
load_button.connect("button_down", dialog, "popup_centered_ratio")
|
|
|
|
var filter = ""
|
|
var resource_type = ""
|
|
var extension_array = []
|
|
|
|
if hint == PROPERTY_HINT_RESOURCE_TYPE:
|
|
resource_type = hint_text
|
|
extension_array = ResourceLoader.get_recognized_extensions_for_type(resource_type)
|
|
else:
|
|
extension_array = hint_array
|
|
|
|
for extension in extension_array:
|
|
# if filter.begins_with("."):
|
|
# filter = "*" + extension
|
|
# elif filter.begins_with("*"):
|
|
# filter = "*." + extension
|
|
# filter = filter + " ; " + extension.to_upper()
|
|
extension.replace("*", "").replace(".", "")
|
|
filter = "*." + extension + " ; " + extension.to_upper()
|
|
dialog.add_filter(filter)
|
|
pass
|
|
dialog.connect("file_selected", self, "fill_resource_name", [])
|
|
add_child(dialog)
|
|
|
|
|
|
#.add_icon_item(get_icon("Load","EditorIcons"), "Load")
|
|
|
|
|
|
|
|
func get_not_yet_supported():
|
|
var control = Label.new()
|
|
control.set_text(str("This type is not yet supported."))
|
|
return control
|
|
|
|
# TODO: That's all a bit too confusing...
|
|
func fill_resource_name(resource_path):
|
|
object_type_line_edit.set_text(resource_path)
|
|
property_value_changed(resource_path)
|
|
if hint_text == "Texture":
|
|
var texture = load(resource_path)
|
|
if texture:
|
|
control.get_child(0).set_texture(texture)
|
|
|
|
# Sets the label of the checkboxe's text to the value
|
|
func set_checkbox_label(value):
|
|
control.set_text(str(value))
|
|
|
|
func property_value_changed(value):
|
|
if type == TYPE_INT:
|
|
value = int(value)
|
|
if type == TYPE_REAL:
|
|
value = float(value)
|
|
if type == TYPE_COLOR:
|
|
value = Color(value)
|
|
if self.value != value:
|
|
self.value = value
|
|
emit_signal("on_property_value_changed", property_name, value)
|
|
|
|
|
|
func text_edit_popup_closed():
|
|
var text_edit = popup.get_child(0)
|
|
var value = text_edit.get_text()
|
|
if value and self.value != value:
|
|
self.value = value
|
|
emit_signal("on_property_value_changed", property_name, value)
|
|
control.get_child(0).set_text(value)
|
|
|
|
|
|
|
|
func int_enum_property_value_changed(value):
|
|
control.set_text(control.get_popup().get_item_text(value))
|
|
if self.value != value:
|
|
self.value = value
|
|
emit_signal("on_property_value_changed", property_name, value)
|
|
|
|
# Simply changes the text of the calling menu to the selected value if it's an enum
|
|
func string_enum_property_value_changed(value):
|
|
control.set_text(control.get_popup().get_item_text(value))
|
|
if str(self.value) != str(value):
|
|
self.value = value
|
|
emit_signal("on_property_value_changed", property_name, control.get_popup().get_item_text(value))
|
|
|
|
|
|
func open_image(texture):
|
|
pass |