Skip to content

Commit 012d47b

Browse files
committed
Allow exporting variables of type Variant
1 parent 96cdbbe commit 012d47b

File tree

5 files changed

+127
-12
lines changed

5 files changed

+127
-12
lines changed

editor/editor_properties.cpp

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
#include "scene/resources/mesh.h"
5858
#include "scene/resources/visual_shader_nodes.h"
5959

60-
///////////////////// Nil /////////////////////////
60+
///////////////////// NIL /////////////////////////
6161

6262
void EditorPropertyNil::update_property() {
6363
}
@@ -68,6 +68,91 @@ EditorPropertyNil::EditorPropertyNil() {
6868
add_child(prop_label);
6969
}
7070

71+
//////////////////// VARIANT ///////////////////////
72+
73+
void EditorPropertyVariant::_change_type(int p_to_type) {
74+
new_type = Variant::Type(p_to_type);
75+
76+
Variant zero;
77+
Callable::CallError ce;
78+
Variant::construct(new_type, zero, nullptr, 0, ce);
79+
emit_changed(get_edited_property(), zero);
80+
}
81+
82+
void EditorPropertyVariant::_set_read_only(bool p_read_only) {
83+
change_type->set_disabled(p_read_only);
84+
if (sub_property) {
85+
sub_property->set_read_only(p_read_only);
86+
}
87+
}
88+
89+
void EditorPropertyVariant::_notification(int p_what) {
90+
if (p_what == NOTIFICATION_THEME_CHANGED) {
91+
change_type->set_button_icon(get_editor_theme_icon("Edit"));
92+
93+
PopupMenu *popup = change_type->get_popup();
94+
for (int i = 0; i < popup->get_item_count(); i++) {
95+
popup->set_item_icon(i, get_editor_theme_icon(Variant::get_type_name(Variant::Type(popup->get_item_id(i)))));
96+
}
97+
}
98+
}
99+
100+
void EditorPropertyVariant::update_property() {
101+
const Variant &value = get_edited_property_value();
102+
if (new_type == Variant::VARIANT_MAX) {
103+
new_type = value.get_type();
104+
}
105+
106+
if (new_type != current_type) {
107+
current_type = new_type;
108+
109+
if (sub_property) {
110+
memdelete(sub_property);
111+
sub_property = nullptr;
112+
}
113+
114+
if (current_type == Variant::OBJECT) {
115+
sub_property = EditorInspector::instantiate_property_editor(nullptr, current_type, "", PROPERTY_HINT_RESOURCE_TYPE, "Resource", PROPERTY_USAGE_NONE);
116+
} else {
117+
sub_property = EditorInspector::instantiate_property_editor(nullptr, current_type, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE);
118+
}
119+
ERR_FAIL_NULL(sub_property);
120+
121+
sub_property->set_object_and_property(get_edited_object(), get_edited_property());
122+
sub_property->set_name_split_ratio(0);
123+
sub_property->set_selectable(false);
124+
sub_property->set_use_folding(is_using_folding());
125+
sub_property->set_read_only(is_read_only());
126+
sub_property->set_h_size_flags(SIZE_EXPAND_FILL);
127+
sub_property->connect(SNAME("property_changed"), callable_mp((EditorProperty *)this, &EditorProperty::emit_changed));
128+
content->add_child(sub_property);
129+
content->move_child(sub_property, 0);
130+
sub_property->update_property();
131+
} else if (sub_property) {
132+
sub_property->update_property();
133+
}
134+
new_type = Variant::VARIANT_MAX;
135+
}
136+
137+
EditorPropertyVariant::EditorPropertyVariant() {
138+
content = memnew(HBoxContainer);
139+
add_child(content);
140+
141+
change_type = memnew(MenuButton);
142+
change_type->set_flat(false);
143+
144+
PopupMenu *popup = change_type->get_popup();
145+
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
146+
if (i == Variant::CALLABLE || i == Variant::SIGNAL || i == Variant::RID) {
147+
// These types can't be constructed or serialized properly, so skip them.
148+
continue;
149+
}
150+
popup->add_item(Variant::get_type_name(Variant::Type(i)), i);
151+
}
152+
popup->connect(SceneStringName(id_pressed), callable_mp(this, &EditorPropertyVariant::_change_type));
153+
content->add_child(change_type);
154+
}
155+
71156
///////////////////// TEXT /////////////////////////
72157

73158
void EditorPropertyText::_set_read_only(bool p_read_only) {
@@ -3510,8 +3595,11 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
35103595
switch (p_type) {
35113596
// atomic types
35123597
case Variant::NIL: {
3513-
EditorPropertyNil *editor = memnew(EditorPropertyNil);
3514-
return editor;
3598+
if (p_usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
3599+
return memnew(EditorPropertyVariant);
3600+
} else {
3601+
return memnew(EditorPropertyNil);
3602+
}
35153603
} break;
35163604
case Variant::BOOL: {
35173605
EditorPropertyCheck *editor = memnew(EditorPropertyCheck);

editor/editor_properties.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,27 @@ class EditorPropertyNil : public EditorProperty {
5555
EditorPropertyNil();
5656
};
5757

58+
class EditorPropertyVariant : public EditorProperty {
59+
GDCLASS(EditorPropertyVariant, EditorProperty);
60+
61+
HBoxContainer *content = nullptr;
62+
EditorProperty *sub_property = nullptr;
63+
MenuButton *change_type = nullptr;
64+
65+
Variant::Type current_type = Variant::VARIANT_MAX;
66+
Variant::Type new_type = Variant::VARIANT_MAX;
67+
68+
void _change_type(int p_to_type);
69+
70+
protected:
71+
virtual void _set_read_only(bool p_read_only) override;
72+
void _notification(int p_what);
73+
74+
public:
75+
virtual void update_property() override;
76+
EditorPropertyVariant();
77+
};
78+
5879
class EditorPropertyText : public EditorProperty {
5980
GDCLASS(EditorPropertyText, EditorProperty);
6081
LineEdit *text = nullptr;

editor/plugins/tiles/tile_set_editor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,7 @@ void TileSourceInspectorPlugin::_confirm_change_id() {
998998
}
999999

10001000
bool TileSourceInspectorPlugin::can_handle(Object *p_object) {
1001-
return p_object->is_class("TileSetAtlasSourceProxyObject") || p_object->is_class("TileSetScenesCollectionProxyObject");
1001+
return p_object && (p_object->is_class("TileSetAtlasSourceProxyObject") || p_object->is_class("TileSetScenesCollectionProxyObject"));
10021002
}
10031003

10041004
bool TileSourceInspectorPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {

modules/gdscript/gdscript_parser.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4533,14 +4533,9 @@ bool GDScriptParser::export_annotations(AnnotationNode *p_annotation, Node *p_ta
45334533
return false;
45344534
}
45354535

4536-
if (export_type.is_variant() || export_type.has_no_type()) {
4537-
if (is_dict) {
4538-
// Dictionary allowed to have a variant key/value.
4539-
export_type.kind = GDScriptParser::DataType::BUILTIN;
4540-
} else {
4541-
push_error(R"(Cannot use simple "@export" annotation because the type of the initialized value can't be inferred.)", p_annotation);
4542-
return false;
4543-
}
4536+
if (export_type.has_no_type()) {
4537+
push_error(R"(Cannot use simple "@export" annotation because the type of the initialized value can't be inferred.)", p_annotation);
4538+
return false;
45444539
}
45454540

45464541
switch (export_type.kind) {
@@ -4591,6 +4586,12 @@ bool GDScriptParser::export_annotations(AnnotationNode *p_annotation, Node *p_ta
45914586
variable->export_info.class_name = String(export_type.native_type).replace("::", ".");
45924587
}
45934588
} break;
4589+
case GDScriptParser::DataType::VARIANT: {
4590+
if (export_type.is_variant()) {
4591+
variable->export_info.type = Variant::NIL;
4592+
variable->export_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
4593+
}
4594+
} break;
45944595
default:
45954596
push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", p_annotation);
45964597
return false;

modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorPlugin.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ public partial class InspectorPlugin : EditorInspectorPlugin
1010
{
1111
public override bool _CanHandle(GodotObject godotObject)
1212
{
13+
if (godotObject == null)
14+
{
15+
return false;
16+
}
17+
1318
foreach (var script in EnumerateScripts(godotObject))
1419
{
1520
if (script is CSharpScript)

0 commit comments

Comments
 (0)