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

[Godot 4] Typed arrays support, Enable packed arrays, Workaround for read-only collections & some small fixes. #6

Merged
merged 18 commits into from
Apr 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 47 additions & 14 deletions addons/dictionary_inspector/elements/array_property_editor.gd
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ var header_node


func add_all_items(collection):
last_type_v = typeof(collection[-1])
for i in collection.size():
add_child(create_item_container(i))
if !collection.is_empty():
last_type_v = typeof(collection[-1])
for i in collection.size():
add_child(create_item_container(i))


func can_drop_data(position, data):
Expand All @@ -24,23 +25,55 @@ func drop_data(position, data):
_on_add_button_pressed()
update_variant(stored_collection.size() - 1, load(x), false)


func create_item_container(index_in_collection):
var c = init_prop_container.duplicate()
var index = DictionaryInspectorArrayIndex.new(index_in_collection)
index.connect("drop_received", _on_item_moved.bind(c))
c.add_child(index)
c.add_child(create_type_switcher(typeof(stored_collection[index_in_collection]), c, false))
c.add_child(create_item_control_for_type(typeof(stored_collection[index_in_collection]), stored_collection[index_in_collection], c, false))
if !stored_collection.is_empty():
var c = init_prop_container.duplicate()
var index = DictionaryInspectorArrayIndex.new(index_in_collection)
index.connect("drop_received", _on_item_moved.bind(c))
c.add_child(index)
c.add_child(create_type_switcher(typeof(stored_collection[index_in_collection]), c, false))
c.add_child(create_item_control_for_type(typeof(stored_collection[index_in_collection]), stored_collection[index_in_collection], c, false))

return c
return c

func update_variant(key, value, is_rename = false):
var is_typed = stored_collection.is_typed()
# workaround for arrays apparently sometimes being readonly to EditorPlugins
# basically just reassign the collection back and forth
if stored_collection.is_read_only():
var arr = [] + stored_collection
# for some reason arrays set one too small key index, but correct key index if value is dictionary
# so if dictionary member, the array key index is correct, so rather just set the index instead of appending
if typeof(value) == TYPE_DICTIONARY:
arr[key] = value
else:
arr.append(value)
stored_collection = arr if !is_typed else Array(arr, stored_collection.get_typed_builtin(), stored_collection.get_typed_class_name(), stored_collection.get_typed_script())
else:
if (is_typed):
var arr_t = stored_collection.get_typed_builtin()
if typeof(value) != arr_t:
# try to cast the value to the array type
# needed when assigning to typed arrays, because for example Slider inherited controls
# have value as float and engine prints error (the value seems to be still inserted and automatically cast to type of array)
stored_collection[key] = convert(value, arr_t)
else:
stored_collection[key] = value
emit_signal("value_changed", stored_collection)

func _on_property_control_type_changed(type, control, container, is_key = false):
var key = get_container_index(container)
if type == 0:
_on_item_deleted(control)
return
# check type just in case, even if have deactivated all other items in the menu
if stored_collection.is_typed() && type != 0:
type = stored_collection.get_typed_builtin()
var i = control.get_type_dict_index(type)
print("This is a typed Array of type ", control.typenames.keys()[i], " only!")
control.select(i)
control.text = ""
else:
if type == 0:
_on_item_deleted(container)
return

var value = get_default_for_type(type)
var new_editor = create_item_control_for_type(type, value, container, is_key)
Expand Down
24 changes: 19 additions & 5 deletions addons/dictionary_inspector/elements/base_property_editor.gd
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,11 @@ func create_add_button():


func add_all_items(collection):
for x in collection:
add_child(create_item_container(x))
if !collection.is_empty():
for x in collection:
add_child(create_item_container(x))
else:
add_child(create_item_container(0))


func create_item_container(k):
Expand Down Expand Up @@ -142,7 +145,7 @@ func create_item_control_for_type(type, initial_value, container, is_key) -> Con

TYPE_OBJECT, TYPE_NIL,\
TYPE_DICTIONARY, TYPE_ARRAY,\
TYPE_PACKED_BYTE_ARRAY, TYPE_PACKED_COLOR_ARRAY,\
TYPE_PACKED_BYTE_ARRAY, TYPE_PACKED_COLOR_ARRAY, TYPE_PACKED_STRING_ARRAY,\
TYPE_PACKED_FLOAT32_ARRAY, TYPE_PACKED_FLOAT64_ARRAY,\
TYPE_PACKED_INT32_ARRAY, TYPE_PACKED_INT64_ARRAY,\
TYPE_PACKED_VECTOR2_ARRAY, TYPE_PACKED_VECTOR3_ARRAY:
Expand Down Expand Up @@ -239,9 +242,15 @@ func connect_control(control, type, container, is_key):


func create_type_switcher(type, container, is_key) -> TypeOptionButton:
var result = TypeOptionButton.new()
var result
if typeof(stored_collection) == TYPE_ARRAY && stored_collection.is_typed():
result = TypeOptionButton.new(stored_collection.get_typed_builtin())
else:
result = TypeOptionButton.new()

result._on_item_selected.call_deferred(type)
result.get_popup().id_pressed.connect(_on_property_control_type_changed.bind(result, container, is_key))
result.call_deferred("_on_item_selected", result.get_type_dict_index(type))
result.get_popup().connect("index_pressed", _on_property_control_type_changed_parse_type.bind(result, container, is_key), CONNECT_DEFERRED)

return result

Expand Down Expand Up @@ -269,3 +278,8 @@ func _on_property_control_value_changed(value, control, container, is_rename = f

func _on_property_control_type_changed(type, control, container, is_key = false):
pass

func _on_property_control_type_changed_parse_type(type, control, container, is_key = false):
var typenames = control.typenames
type = typenames[typenames.keys()[type]]
_on_property_control_type_changed(type, control, container, is_key)
9 changes: 6 additions & 3 deletions addons/dictionary_inspector/elements/dict_property_editor.gd
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ func toggle_property_editable(container):
children[3].queue_free()
children[5].queue_free()


func update_variant(key, value, is_rename = false):
if is_rename:
if (typeof(value) != typeof(key) || value != key):
Expand All @@ -85,7 +84,7 @@ func update_variant(key, value, is_rename = false):
keys_by_index = stored_collection.keys()

else:
stored_collection[key] = value
stored_collection[key] = value

emit_signal("value_changed", stored_collection)

Expand All @@ -96,7 +95,11 @@ func _on_add_button_pressed():

var new_key = get_default_for_type(last_type_k, true)
var new_value = get_default_for_type(last_type_v)
stored_collection[new_key] = new_value

if stored_collection.is_empty():
stored_collection = { new_key: new_value }
else:
stored_collection[new_key] = new_value
keys_by_index = stored_collection.keys()

var new_node = create_item_container(keys_by_index.size() - 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const array_to_element_type = {
TYPE_PACKED_COLOR_ARRAY : TYPE_COLOR,
}

func get_array_type(arr):
if typeof(arr) == TYPE_ARRAY && arr.is_typed():
return arr.get_typed_builtin()
else:
return last_type_v

func add_all_items(collection):
last_type_v = array_to_element_type.get(typeof(collection), TYPE_FLOAT)
Expand Down Expand Up @@ -41,19 +46,22 @@ func create_add_button():
func create_item_container(index_in_collection):
var c = init_prop_container.duplicate()
c.add_child(DictionaryInspectorArrayIndex.new(index_in_collection))
c.get_child(0).connect("drop_received", _on_item_moved.bind(c))
c.add_child(create_item_control_for_type(last_type_v, stored_collection[index_in_collection], c, false))
c.get_child(0).connect("drop_received", _on_item_moved.bind(c), CONNECT_DEFERRED)

var type = get_array_type(stored_collection)
c.add_child(create_item_control_for_type(type, stored_collection[index_in_collection], c, false))

var delete_button = Button.new()
delete_button.icon = get_theme_icon("Remove", "EditorIcons")
delete_button.connect("pressed", _on_item_deleted.bind(c))
delete_button.connect("pressed", _on_item_deleted.bind(c), CONNECT_DEFERRED)
c.add_child(delete_button)

return c


func _on_add_button_pressed():
var new_value = get_default_for_type(last_type_v)
var type = get_array_type(stored_collection)
var new_value = get_default_for_type(type)
if stored_collection.size() > 0 && (
last_type_v == TYPE_OBJECT || stored_collection[-1] is Object
):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,56 @@
@tool
extends Button

# just copy these here for now to have easier access
const typenames = {
&"Remove" : 0,
&"bool" : TYPE_BOOL,
&"int" : TYPE_INT,
&"float" : TYPE_FLOAT,
&"String" : TYPE_STRING,
&"Vector2" : TYPE_VECTOR2,
&"Vector2i" : TYPE_VECTOR2I,
&"Rect2" : TYPE_RECT2,
&"Rect2i" : TYPE_RECT2I,
&"Vector3" : TYPE_VECTOR3,
&"Vector3i" : TYPE_VECTOR3I,
&"Transform2D" : TYPE_TRANSFORM2D,
&"Vector4" : TYPE_VECTOR4,
&"Vector4i" : TYPE_VECTOR4I,
&"Plane" : TYPE_PLANE,
&"Quaternion" : TYPE_QUATERNION,
&"AABB" : TYPE_AABB,
&"Basis" : TYPE_BASIS,
&"Transform3D" : TYPE_TRANSFORM3D,
&"Projection" : TYPE_PROJECTION,
&"Color" : TYPE_COLOR,
&"StringName" : TYPE_STRING_NAME,
&"NodePath" : TYPE_NODE_PATH,
# &"RID" : TYPE_RID,
&"Object" : TYPE_OBJECT,
# &"Callable" : TYPE_CALLABLE,
# &"Signal" : TYPE_SIGNAL,
&"Dictionary" : TYPE_DICTIONARY,
&"Array" : TYPE_ARRAY,
&"PackedByteArray" : TYPE_PACKED_BYTE_ARRAY,
&"PackedInt32Array" : TYPE_PACKED_INT32_ARRAY,
&"PackedInt64Array" : TYPE_PACKED_INT64_ARRAY,
&"PackedFloat32Array" : TYPE_PACKED_FLOAT32_ARRAY,
&"PackedFloat64Array" : TYPE_PACKED_FLOAT64_ARRAY,
&"PackedStringArray" : TYPE_PACKED_STRING_ARRAY,
&"PackedVector2Array" : TYPE_PACKED_VECTOR2_ARRAY,
&"PackedVector3Array" : TYPE_PACKED_VECTOR3_ARRAY,
&"PackedColorArray" : TYPE_PACKED_COLOR_ARRAY,
}

func get_type_dict_index(type):
var i = 0
var typekeys = typenames.keys()
for key in typekeys:
if (typenames[key] == type):
return i
i += 1

signal value_changed(new_value)
signal bottom_control_available(control)

Expand Down Expand Up @@ -101,12 +151,13 @@ func get_recursion_style():

func _on_value_changed(value):
if value != null && !value is Object:
text = "%s (size %s)" % [
text = "%s (%ssize %s)" % [
(
"Dictionary" if value is Dictionary else
"Array" if value is Array else
"PackedArray"
),
str(typenames.keys()[get_type_dict_index(value.get_typed_builtin())]) + ", " if value is Array && value.is_typed() else "",
value.size(),
]
stored_collection = value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,70 @@ extends OptionButton

const typenames = {
&"Remove" : 0,
&"bool" : 1,
&"int" : 2,
&"float" : 3,
&"String" : 4,
&"Vector2" : 5,
&"Vector2i" : 6,
&"Rect2" : 7,
&"Rect2i" : 8,
&"Vector3" : 9,
&"Vector3i" : 10,
&"Transform2D" : 11,
&"Vector4" : 12,
&"Vector4i" : 13,
&"Plane" : 14,
&"Quaternion" : 15,
&"AABB" : 16,
&"Basis" : 17,
&"Transform3D" : 18,
&"Projection" : 19,
&"Color" : 20,
&"StringName" : 21,
&"NodePath" : 22,
# &"---​" : 23,
&"Object" : 24,
# &"---​​" : 25,
# &"---​​​" : 26,
&"Dictionary" : 27,
&"Array" : 28,
&"PackedByteArray" : 29,
&"PackedInt32Array" : 30,
&"PackedInt64Array" : 31,
&"PackedFloat32Array" : 32,
&"PackedFloat64Array" : 33,
&"PackedStringArray" : 34,
&"PackedVector2Array" : 35,
&"PackedVector3Array" : 36,
&"PackedColorArray" : 37,
&"bool" : TYPE_BOOL,
&"int" : TYPE_INT,
&"float" : TYPE_FLOAT,
&"String" : TYPE_STRING,
&"Vector2" : TYPE_VECTOR2,
&"Vector2i" : TYPE_VECTOR2I,
&"Rect2" : TYPE_RECT2,
&"Rect2i" : TYPE_RECT2I,
&"Vector3" : TYPE_VECTOR3,
&"Vector3i" : TYPE_VECTOR3I,
&"Transform2D" : TYPE_TRANSFORM2D,
&"Vector4" : TYPE_VECTOR4,
&"Vector4i" : TYPE_VECTOR4I,
&"Plane" : TYPE_PLANE,
&"Quaternion" : TYPE_QUATERNION,
&"AABB" : TYPE_AABB,
&"Basis" : TYPE_BASIS,
&"Transform3D" : TYPE_TRANSFORM3D,
&"Projection" : TYPE_PROJECTION,
&"Color" : TYPE_COLOR,
&"StringName" : TYPE_STRING_NAME,
&"NodePath" : TYPE_NODE_PATH,
# &"RID" : TYPE_RID,
&"Object" : TYPE_OBJECT,
# &"Callable" : TYPE_CALLABLE,
# &"Signal" : TYPE_SIGNAL,
&"Dictionary" : TYPE_DICTIONARY,
&"Array" : TYPE_ARRAY,
&"PackedByteArray" : TYPE_PACKED_BYTE_ARRAY,
&"PackedInt32Array" : TYPE_PACKED_INT32_ARRAY,
&"PackedInt64Array" : TYPE_PACKED_INT64_ARRAY,
&"PackedFloat32Array" : TYPE_PACKED_FLOAT32_ARRAY,
&"PackedFloat64Array" : TYPE_PACKED_FLOAT64_ARRAY,
&"PackedStringArray" : TYPE_PACKED_STRING_ARRAY,
&"PackedVector2Array" : TYPE_PACKED_VECTOR2_ARRAY,
&"PackedVector3Array" : TYPE_PACKED_VECTOR3_ARRAY,
&"PackedColorArray" : TYPE_PACKED_COLOR_ARRAY,
}

func get_type_dict_index(type):
var i = 0
var typekeys = typenames.keys()
for key in typekeys:
if (typenames[key] == type):
return i
i += 1

@export var custom_icons : Array[Texture] = []

var _type

func _init(type = null):
_type = type

func _ready():
if custom_icons == null || custom_icons.size() == 0:
var i = 0
for x in typenames:
add_type_icon_item(x)
if _type:
if typenames[x] != _type:
set_item_disabled(i, true)
i += 1
set_item_disabled(0, false)

else:
for i in custom_icons.size():
Expand All @@ -61,7 +79,6 @@ func _ready():
# connect("item_selected", _on_item_selected)
get_popup().id_pressed.connect(_on_item_selected)


func add_type_icon_item(typename):
var icon = null
if has_theme_icon(typename, "EditorIcons"):
Expand Down
Loading