Skip to content
Closed
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
1 change: 1 addition & 0 deletions core/global_constants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion core/script_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ void PlaceHolderScriptInstance::update(const List<PropertyInfo> &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];
}
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/@GlobalScope.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,9 @@
<constant name="PROPERTY_USAGE_SCRIPT_VARIABLE" value="8192" enum="PropertyUsageFlags">
The property is a script variable which should be serialized and saved in the scene file.
</constant>
<constant name="PROPERTY_USAGE_NIL_IS_VARIANT" value="524288" enum="PropertyUsageFlags">
The property stores a variable of type [Variant]. Used with type flag [code]TYPE_NIL[/code].
</constant>
<constant name="PROPERTY_USAGE_DEFAULT" value="7" enum="PropertyUsageFlags">
Default usage (storage, editor and network).
</constant>
Expand Down
105 changes: 103 additions & 2 deletions editor/editor_properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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<EncodedObjectAsID>(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<Button>(p_button);
Rect2 rect = button->get_global_rect();
change_type->set_as_minsize();
change_type->set_position(rect.position + rect.size - Vector2(change_type->get_contents_minimum_size().x, 0));
change_type->popup();
}

void EditorPropertyGeneric::_change_type_menu(int p_index) {
Object *object = get_edited_object();
StringName edited_prop = get_edited_property();
Variant value = object->get(edited_prop);
Variant::Type value_type = value.get_type();

Variant::Type new_value_type = Variant::Type(p_index);
if (new_value_type == value_type) {
return;
}

Callable::CallError ce;
Variant new_value = Variant::construct(new_value_type, nullptr, 0, ce);

emit_changed(edited_prop, new_value, "", true);
update_property();
}

EditorPropertyGeneric::EditorPropertyGeneric() {
hbox = memnew(HBoxContainer);
hbox->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(hbox);

change_type = memnew(PopupMenu);
add_child(change_type);
change_type->connect("id_pressed", callable_mp(this, &EditorPropertyGeneric::_change_type_menu));

for (int i = 0; i < Variant::VARIANT_MAX; i++) {
String type = Variant::get_type_name(Variant::Type(i));
change_type->add_item(type, i);
}
}

void EditorPropertyGeneric::_bind_methods() {
}

///////////////////// TEXT /////////////////////////

void EditorPropertyText::_text_entered(const String &p_string) {
Expand Down Expand Up @@ -3121,8 +3217,13 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ
switch (p_type) {
// atomic types
case Variant::NIL: {
EditorPropertyNil *editor = memnew(EditorPropertyNil);
add_property_editor(p_path, editor);
if (p_usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
EditorPropertyGeneric *editor = memnew(EditorPropertyGeneric);
add_property_editor(p_path, editor);
} else {
EditorPropertyNil *editor = memnew(EditorPropertyNil);
add_property_editor(p_path, editor);
}
} break;
case Variant::BOOL: {
EditorPropertyCheck *editor = memnew(EditorPropertyCheck);
Expand Down
19 changes: 18 additions & 1 deletion editor/editor_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,30 @@

class EditorPropertyNil : public EditorProperty {
GDCLASS(EditorPropertyNil, EditorProperty);
LineEdit *text;

public:
virtual void update_property();
EditorPropertyNil();
};

class EditorPropertyGeneric : public EditorProperty {
GDCLASS(EditorPropertyGeneric, EditorProperty);
HBoxContainer *hbox;
PopupMenu *change_type;

void _property_changed(const String &p_prop, Variant p_value, const String &p_name = String(), bool changing = false);
void _object_id_selected(const String &p_property, ObjectID p_id);
void _change_type(Object *p_button);
void _change_type_menu(int p_index);

protected:
static void _bind_methods();

public:
virtual void update_property();
EditorPropertyGeneric();
};

class EditorPropertyText : public EditorProperty {
GDCLASS(EditorPropertyText, EditorProperty);
LineEdit *text;
Expand Down
4 changes: 3 additions & 1 deletion modules/gdscript/gdscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,9 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) {

for (int i = 0; i < c->variables.size(); i++) {
if (c->variables[i]._export.type == Variant::NIL) {
continue;
if (!(c->variables[i]._export.usage & PROPERTY_USAGE_NIL_IS_VARIANT)) {
continue;
}
}

members_cache.push_back(c->variables[i]._export);
Expand Down
2 changes: 1 addition & 1 deletion modules/gdscript/gdscript_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1942,7 +1942,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
prop_info.name = name;
PropertyInfo export_info = p_class->variables[i]._export;

if (export_info.type != Variant::NIL) {
if (export_info.type != Variant::NIL || export_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
if (!minfo.data_type.has_type) {
prop_info.type = export_info.type;
prop_info.class_name = export_info.class_name;
Expand Down
8 changes: 6 additions & 2 deletions modules/gdscript/gdscript_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4604,7 +4604,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
} break;
}
}

} else if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "Variant") {
current_export.type = Variant::Type::NIL;
current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
current_export.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
tokenizer->advance();
} else {
parenthesis++;
Node *subexpr = _parse_and_reduce_expression(p_class, true, true);
Expand Down Expand Up @@ -4832,7 +4836,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
ClassNode::Member member;

bool autoexport = tokenizer->get_token(-1) == GDScriptTokenizer::TK_PR_EXPORT;
if (current_export.type != Variant::NIL) {
if (current_export.type != Variant::NIL || current_export.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
member._export = current_export;
current_export = PropertyInfo();
}
Expand Down