diff --git a/core/global_constants.cpp b/core/global_constants.cpp index 6281e563950a..25a3cd1ac70e 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -552,6 +552,7 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NO_INSTANCE_STATE); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_VARIABLE); + BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NIL_IS_VARIANT); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_DEFAULT); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_DEFAULT_INTL); diff --git a/core/script_language.cpp b/core/script_language.cpp index 38a970f3c63b..e1a9536d79c5 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -469,7 +469,7 @@ void PlaceHolderScriptInstance::update(const List &p_properties, c StringName n = E->get().name; new_values.insert(n); - if (!values.has(n) || values[n].get_type() != E->get().type) { + if (!values.has(n) || (values[n].get_type() != E->get().type && !(E->get().usage & PROPERTY_USAGE_NIL_IS_VARIANT))) { if (p_values.has(n)) { values[n] = p_values[n]; } diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 9a28a0d08527..66c549b28b00 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1411,6 +1411,9 @@ The property is a script variable which should be serialized and saved in the scene file. + + The property stores a variable of type [Variant]. Used with type flag [code]TYPE_NIL[/code]. + Default usage (storage, editor and network). diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index eee610e9a8f5..adbdeea35f37 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -30,6 +30,7 @@ #include "editor_properties.h" +#include "core/io/marshalls.h" #include "editor/editor_resource_preview.h" #include "editor/filesystem_dock.h" #include "editor_node.h" @@ -48,6 +49,101 @@ EditorPropertyNil::EditorPropertyNil() { add_child(label); } +///////////////////// GENERIC ///////////////////////// + +void EditorPropertyGeneric::update_property() { + Object *object = get_edited_object(); + StringName edited_prop = get_edited_property(); + Variant value = object->get(edited_prop); + Variant::Type value_type = value.get_type(); + + // remove previous controls + while (hbox->get_child_count() > 0) { + Node *child = hbox->get_child(0); + child->queue_delete(); + hbox->remove_child(child); + } + + EditorProperty *prop = nullptr; + if (value_type == Variant::NIL) { + prop = memnew(EditorPropertyNil); + } else if (value_type == Variant::OBJECT && Object::cast_to(value)) { + EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID); + editor->setup("Object"); + prop = editor; + } else { + prop = EditorInspector::instantiate_property_editor(nullptr, value_type, "", PROPERTY_HINT_NONE, "", 0); + } + + prop->set_object_and_property(object, edited_prop); + prop->set_name_split_ratio(0.0); + prop->set_selectable(false); + prop->connect("property_changed", callable_mp(this, &EditorPropertyGeneric::_property_changed)); + prop->connect("object_id_selected", callable_mp(this, &EditorPropertyGeneric::_object_id_selected)); + prop->set_h_size_flags(SIZE_EXPAND_FILL); + + hbox->add_child(prop); + + Button *edit_button = memnew(Button); + edit_button->set_icon(get_theme_icon("Edit", "EditorIcons")); + edit_button->connect("pressed", callable_mp(this, &EditorPropertyGeneric::_change_type), varray(edit_button)); + hbox->add_child(edit_button); + + prop->update_property(); +} + +void EditorPropertyGeneric::_property_changed(const String &p_prop, Variant p_value, const String &p_name, bool changing) { + emit_changed(get_edited_property(), p_value, p_name, changing); +} + +void EditorPropertyGeneric::_object_id_selected(const String &p_property, ObjectID p_id) { + emit_signal("object_id_selected", p_property, p_id); +} + +void EditorPropertyGeneric::_change_type(Object *p_button) { + Button *button = Object::cast_to