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

Refactor Object metadata #59452

Merged
merged 1 commit into from
Mar 25, 2022
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
70 changes: 49 additions & 21 deletions core/object/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,12 +416,22 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid
}
return;

} else if (p_name == CoreStringNames::get_singleton()->_meta) {
metadata = p_value.duplicate();
if (r_valid) {
*r_valid = true;
} else {
OrderedHashMap<StringName, Variant>::Element *E = metadata_properties.getptr(p_name);
if (E) {
E->get() = p_value;
if (r_valid) {
*r_valid = true;
}
return;
} else if (p_name.operator String().begins_with("metadata/")) {
// Must exist, otherwise duplicate() will not work.
set_meta(p_name.operator String().replace_first("metadata/", ""), p_value);
if (r_valid) {
*r_valid = true;
}
return;
}
return;
}

// Something inside the object... :|
Expand Down Expand Up @@ -496,9 +506,12 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
*r_valid = true;
}
return ret;
}

const OrderedHashMap<StringName, Variant>::Element *E = metadata_properties.getptr(p_name);

} else if (p_name == CoreStringNames::get_singleton()->_meta) {
ret = metadata;
if (E) {
ret = E->get();
if (r_valid) {
*r_valid = true;
}
Expand Down Expand Up @@ -648,13 +661,20 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
if (!is_class("Script")) { // can still be set, but this is for user-friendliness
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT));
}
if (!metadata.is_empty()) {
p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
}

if (script_instance && !p_reversed) {
p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
}

for (OrderedHashMap<StringName, Variant>::ConstElement K = metadata.front(); K; K = K.next()) {
PropertyInfo pi = PropertyInfo(K.value().get_type(), "metadata/" + K.key().operator String());
if (K.value().get_type() == Variant::OBJECT) {
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
pi.hint_string = "Resource";
}
p_list->push_back(pi);
}
}

void Object::_validate_property(PropertyInfo &property) const {
Expand Down Expand Up @@ -915,11 +935,23 @@ bool Object::has_meta(const StringName &p_name) const {

void Object::set_meta(const StringName &p_name, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
metadata.erase(p_name);
if (metadata.has(p_name)) {
metadata.erase(p_name);
metadata_properties.erase("metadata/" + p_name.operator String());
notify_property_list_changed();
}
return;
}

metadata[p_name] = p_value;
OrderedHashMap<StringName, Variant>::Element E = metadata.find(p_name);
if (E) {
E.value() = p_value;
} else {
ERR_FAIL_COND(!p_name.operator String().is_valid_identifier());
E = metadata.insert(p_name, p_value);
metadata_properties["metadata/" + p_name.operator String()] = E;
notify_property_list_changed();
}
}

Variant Object::get_meta(const StringName &p_name) const {
Expand All @@ -928,7 +960,7 @@ Variant Object::get_meta(const StringName &p_name) const {
}

void Object::remove_meta(const StringName &p_name) {
metadata.erase(p_name);
set_meta(p_name, Variant());
}

Array Object::_get_property_list_bind() const {
Expand All @@ -954,20 +986,16 @@ Array Object::_get_method_list_bind() const {
Vector<StringName> Object::_get_meta_list_bind() const {
Vector<StringName> _metaret;

List<Variant> keys;
metadata.get_key_list(&keys);
for (const Variant &E : keys) {
_metaret.push_back(E);
for (OrderedHashMap<StringName, Variant>::ConstElement K = metadata.front(); K; K = K.next()) {
_metaret.push_back(K.key());
}

return _metaret;
}

void Object::get_meta_list(List<StringName> *p_list) const {
List<Variant> keys;
metadata.get_key_list(&keys);
for (const Variant &E : keys) {
p_list->push_back(E);
for (OrderedHashMap<StringName, Variant>::ConstElement K = metadata.front(); K; K = K.next()) {
p_list->push_back(K.key());
}
}

Expand Down
4 changes: 3 additions & 1 deletion core/object/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
#include "core/templates/map.h"
#include "core/templates/ordered_hash_map.h"
#include "core/templates/safe_refcount.h"
#include "core/templates/set.h"
#include "core/templates/vmap.h"
Expand Down Expand Up @@ -530,7 +531,8 @@ class Object {
#endif
ScriptInstance *script_instance = nullptr;
Variant script; // Reference does not exist yet, store it in a Variant.
Dictionary metadata;
OrderedHashMap<StringName, Variant> metadata;
HashMap<StringName, OrderedHashMap<StringName, Variant>::Element> metadata_properties;
mutable StringName _class_name;
mutable const StringName *_class_ptr = nullptr;

Expand Down
6 changes: 2 additions & 4 deletions core/variant/variant_construct.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,14 +543,12 @@ class VariantConstructNoArgsNil {
class VariantConstructNoArgsObject {
public:
static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
VariantInternal::clear(&r_ret);
VariantInternal::object_assign_null(&r_ret);
r_ret = (Object *)nullptr; // Must construct a TYPE_OBJECT containing nullptr.
r_error.error = Callable::CallError::CALL_OK;
}

static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
VariantInternal::clear(r_ret);
VariantInternal::object_assign_null(r_ret);
*r_ret = (Object *)nullptr; // Must construct a TYPE_OBJECT containing nullptr.
}
static void ptr_construct(void *base, const void **p_args) {
PtrConstruct<Object *>::construct(nullptr, base);
Expand Down
104 changes: 101 additions & 3 deletions editor/editor_inspector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "multi_node_edit.h"
#include "scene/gui/center_container.h"
#include "scene/property_utils.h"
#include "scene/resources/packed_scene.h"

Expand Down Expand Up @@ -2506,7 +2507,7 @@ void EditorInspector::update_tree() {
List<PropertyInfo>::Element *N = E_property->next();
bool valid = true;
while (N) {
if (N->get().usage & PROPERTY_USAGE_EDITOR && (!restrict_to_basic || (N->get().usage & PROPERTY_USAGE_EDITOR_BASIC_SETTING))) {
if (!N->get().name.begins_with("metadata/_") && N->get().usage & PROPERTY_USAGE_EDITOR && (!restrict_to_basic || (N->get().usage & PROPERTY_USAGE_EDITOR_BASIC_SETTING))) {
break;
}
if (N->get().usage & PROPERTY_USAGE_CATEGORY) {
Expand Down Expand Up @@ -2580,7 +2581,7 @@ void EditorInspector::update_tree() {

continue;

} else if (!(p.usage & PROPERTY_USAGE_EDITOR) || _is_property_disabled_by_feature_profile(p.name) || (restrict_to_basic && !(p.usage & PROPERTY_USAGE_EDITOR_BASIC_SETTING))) {
} else if (p.name.begins_with("metadata/_") || !(p.usage & PROPERTY_USAGE_EDITOR) || _is_property_disabled_by_feature_profile(p.name) || (restrict_to_basic && !(p.usage & PROPERTY_USAGE_EDITOR_BASIC_SETTING))) {
// Ignore properties that are not supposed to be in the inspector.
continue;
}
Expand Down Expand Up @@ -2915,7 +2916,7 @@ void EditorInspector::update_tree() {
ep->set_checked(checked);
ep->set_keying(keying);
ep->set_read_only(property_read_only);
ep->set_deletable(deletable_properties);
ep->set_deletable(deletable_properties || p.name.begins_with("metadata/"));
}

current_vbox->add_child(F.property_editor);
Expand Down Expand Up @@ -2956,6 +2957,15 @@ void EditorInspector::update_tree() {
}
}

if (!hide_metadata) {
Button *add_md = memnew(Button);
add_md->set_text(TTR("Add Metadata"));
add_md->set_focus_mode(Control::FOCUS_NONE);
add_md->set_icon(get_theme_icon("Add", "EditorIcons"));
add_md->connect("pressed", callable_mp(this, &EditorInspector::_show_add_meta_dialog));
main_vbox->add_child(add_md);
}

// Get the lists of to add at the end.
for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
ped->parse_end(object);
Expand Down Expand Up @@ -3055,6 +3065,11 @@ void EditorInspector::set_hide_script(bool p_hide) {
update_tree();
}

void EditorInspector::set_hide_metadata(bool p_hide) {
hide_metadata = p_hide;
update_tree();
}

void EditorInspector::set_use_filter(bool p_use) {
use_filter = p_use;
update_tree();
Expand Down Expand Up @@ -3323,6 +3338,14 @@ void EditorInspector::_property_deleted(const String &p_path) {
return;
}

if (p_path.begins_with("metadata/")) {
String name = p_path.replace_first("metadata/", "");
undo_redo->create_action(vformat(TTR("Remove metadata %s"), name));
undo_redo->add_do_method(object, "remove_meta", name);
undo_redo->add_undo_method(object, "set_meta", name, object->get_meta(name));
undo_redo->commit_action();
}

emit_signal(SNAME("property_deleted"), p_path);
}

Expand Down Expand Up @@ -3650,6 +3673,81 @@ Variant EditorInspector::get_property_clipboard() const {
return property_clipboard;
}

void EditorInspector::_add_meta_confirm() {
String name = add_meta_name->get_text();

object->editor_set_section_unfold("metadata", true); // Ensure metadata is unfolded when adding a new metadata.

Variant defval;
Callable::CallError ce;
Variant::construct(Variant::Type(add_meta_type->get_selected_id()), defval, nullptr, 0, ce);
undo_redo->create_action(vformat(TTR("Add metadata %s"), name));
undo_redo->add_do_method(object, "set_meta", name, defval);
undo_redo->add_undo_method(object, "remove_meta", name);
undo_redo->commit_action();
}

void EditorInspector::_check_meta_name(String name) {
String error;

if (name == "") {
error = TTR("Metadata can't be empty.");
} else if (!name.is_valid_identifier()) {
error = TTR("Invalid metadata identifier.");
} else if (object->has_meta(name)) {
error = TTR("Metadata already exists.");
}

if (error != "") {
add_meta_error->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
add_meta_error->set_text(error);
add_meta_dialog->get_ok_button()->set_disabled(true);
} else {
add_meta_error->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
add_meta_error->set_text(TTR("Metadata name is valid."));
add_meta_dialog->get_ok_button()->set_disabled(false);
}
}

void EditorInspector::_show_add_meta_dialog() {
if (!add_meta_dialog) {
add_meta_dialog = memnew(ConfirmationDialog);
add_meta_dialog->set_title(TTR("Add Metadata Property"));
VBoxContainer *vbc = memnew(VBoxContainer);
add_meta_dialog->add_child(vbc);
HBoxContainer *hbc = memnew(HBoxContainer);
vbc->add_child(hbc);
hbc->add_child(memnew(Label(TTR("Name:"))));
add_meta_name = memnew(LineEdit);
add_meta_name->set_custom_minimum_size(Size2(200 * EDSCALE, 1));
hbc->add_child(add_meta_name);
hbc->add_child(memnew(Label(TTR("Type:"))));
add_meta_type = memnew(OptionButton);
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
if (i == Variant::NIL || i == Variant::RID || i == Variant::CALLABLE || i == Variant::SIGNAL) {
continue; //not editable by inspector.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
continue; //not editable by inspector.
continue; // Not editable by inspector.

}
String type = i == Variant::OBJECT ? String("Resource") : Variant::get_type_name(Variant::Type(i));

add_meta_type->add_icon_item(get_theme_icon(type, "EditorIcons"), type, i);
}
hbc->add_child(add_meta_type);
add_meta_dialog->get_ok_button()->set_text(TTR("Add"));
add_child(add_meta_dialog);
add_meta_dialog->register_text_enter(add_meta_name);
add_meta_dialog->connect("confirmed", callable_mp(this, &EditorInspector::_add_meta_confirm));
add_meta_error = memnew(Label);
vbc->add_child(add_meta_error);

add_meta_name->connect("text_changed", callable_mp(this, &EditorInspector::_check_meta_name));
}

add_meta_dialog->popup_centered();
add_meta_name->set_text("");
_check_meta_name("");
add_meta_name->grab_focus();
}

void EditorInspector::_bind_methods() {
ClassDB::bind_method("_edit_request_change", &EditorInspector::_edit_request_change);

Expand Down
12 changes: 12 additions & 0 deletions editor/editor_inspector.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/scroll_container.h"
#include "scene/gui/texture_rect.h"
Expand Down Expand Up @@ -445,6 +446,7 @@ class EditorInspector : public ScrollContainer {
LineEdit *search_box;
bool show_categories = false;
bool hide_script = true;
bool hide_metadata = true;
bool use_doc_hints = false;
bool capitalize_paths = true;
bool use_filter = false;
Expand Down Expand Up @@ -511,6 +513,15 @@ class EditorInspector : public ScrollContainer {

void _update_inspector_bg();

ConfirmationDialog *add_meta_dialog = nullptr;
LineEdit *add_meta_name = nullptr;
OptionButton *add_meta_type = nullptr;
Label *add_meta_error = nullptr;

void _add_meta_confirm();
void _show_add_meta_dialog();
void _check_meta_name(String name);

protected:
static void _bind_methods();
void _notification(int p_what);
Expand Down Expand Up @@ -541,6 +552,7 @@ class EditorInspector : public ScrollContainer {
void set_show_categories(bool p_show);
void set_use_doc_hints(bool p_enable);
void set_hide_script(bool p_hide);
void set_hide_metadata(bool p_hide);

void set_use_filter(bool p_use);
void register_text_enter(Node *p_line_edit);
Expand Down
1 change: 1 addition & 0 deletions editor/inspector_dock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL);
inspector->set_use_doc_hints(true);
inspector->set_hide_script(false);
inspector->set_hide_metadata(false);
inspector->set_enable_capitalize_paths(bool(EDITOR_GET("interface/inspector/capitalize_properties")));
inspector->set_use_folding(!bool(EDITOR_GET("interface/inspector/disable_folding")));
inspector->register_text_enter(search);
Expand Down
3 changes: 3 additions & 0 deletions scene/gui/dialogs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ void AcceptDialog::_notification(int p_what) {
}

void AcceptDialog::_text_submitted(const String &p_text) {
if (get_ok_button() && get_ok_button()->is_disabled()) {
return; // Do not allow submission if OK button is disabled.
}
_ok_pressed();
}

Expand Down
Loading