Merge pull request #62413 from willnationsdev/gdres-inspector

Script-class-aware Inspector & related controls.
This commit is contained in:
Rémi Verschelde 2022-09-18 10:53:47 +02:00
commit 469eb3dfd7
2 changed files with 91 additions and 54 deletions

View File

@ -53,6 +53,7 @@ void EditorResourcePicker::_update_resource() {
if (edited_resource.is_valid() && edited_resource->get_path().is_resource_file()) { if (edited_resource.is_valid() && edited_resource->get_path().is_resource_file()) {
resource_path = edited_resource->get_path() + "\n"; resource_path = edited_resource->get_path() + "\n";
} }
String class_name = _get_resource_type(edited_resource);
if (preview_rect) { if (preview_rect) {
preview_rect->set_texture(Ref<Texture2D>()); preview_rect->set_texture(Ref<Texture2D>());
@ -64,16 +65,20 @@ void EditorResourcePicker::_update_resource() {
assign_button->set_text(TTR("<empty>")); assign_button->set_text(TTR("<empty>"));
assign_button->set_tooltip_text(""); assign_button->set_tooltip_text("");
} else { } else {
assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), "Object")); assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), SNAME("Object")));
if (!edited_resource->get_name().is_empty()) { if (!edited_resource->get_name().is_empty()) {
assign_button->set_text(edited_resource->get_name()); assign_button->set_text(edited_resource->get_name());
} else if (edited_resource->get_path().is_resource_file()) { } else if (edited_resource->get_path().is_resource_file()) {
assign_button->set_text(edited_resource->get_path().get_file()); assign_button->set_text(edited_resource->get_path().get_file());
} else { } else {
assign_button->set_text(edited_resource->get_class()); assign_button->set_text(class_name);
} }
assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + edited_resource->get_class());
if (edited_resource->get_path().is_resource_file()) {
resource_path = edited_resource->get_path() + "\n";
}
assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + class_name);
// Preview will override the above, so called at the end. // Preview will override the above, so called at the end.
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(edited_resource, this, "_update_resource_preview", edited_resource->get_instance_id()); EditorResourcePreview::get_singleton()->queue_edited_resource_preview(edited_resource, this, "_update_resource_preview", edited_resource->get_instance_id());
@ -134,16 +139,29 @@ void EditorResourcePicker::_file_selected(const String &p_path) {
if (!base_type.is_empty()) { if (!base_type.is_empty()) {
bool any_type_matches = false; bool any_type_matches = false;
String res_type = loaded_resource->get_class();
Ref<Script> res_script = loaded_resource->get_script();
bool is_global_class = false;
if (res_script.is_valid()) {
String script_type = EditorNode::get_editor_data().script_class_get_name(res_script->get_path());
if (!script_type.is_empty()) {
is_global_class = true;
res_type = script_type;
}
}
for (int i = 0; i < base_type.get_slice_count(","); i++) { for (int i = 0; i < base_type.get_slice_count(","); i++) {
String base = base_type.get_slice(",", i); String base = base_type.get_slice(",", i);
if (loaded_resource->is_class(base)) {
any_type_matches = true; any_type_matches = is_global_class ? EditorNode::get_editor_data().script_class_is_parent(res_type, base) : loaded_resource->is_class(base);
if (!any_type_matches) {
break; break;
} }
} }
if (!any_type_matches) { if (!any_type_matches) {
EditorNode::get_singleton()->show_warning(vformat(TTR("The selected resource (%s) does not match any type expected for this property (%s)."), loaded_resource->get_class(), base_type)); EditorNode::get_singleton()->show_warning(vformat(TTR("The selected resource (%s) does not match any type expected for this property (%s)."), res_type, base_type));
return; return;
} }
} }
@ -227,16 +245,19 @@ void EditorResourcePicker::_update_menu_items() {
// Add options to copy/paste resource. // Add options to copy/paste resource.
Ref<Resource> cb = EditorSettings::get_singleton()->get_resource_clipboard(); Ref<Resource> cb = EditorSettings::get_singleton()->get_resource_clipboard();
bool paste_valid = false; bool paste_valid = false;
if (is_editable()) { if (is_editable() && cb.is_valid()) {
if (cb.is_valid()) { if (base_type.is_empty()) {
if (base_type.is_empty()) { paste_valid = true;
paste_valid = true; } else {
} else { String res_type = _get_resource_type(cb);
for (int i = 0; i < base_type.get_slice_count(","); i++) {
if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) { for (int i = 0; i < base_type.get_slice_count(","); i++) {
paste_valid = true; String base = base_type.get_slice(",", i);
break;
} paste_valid = ClassDB::is_parent_class(res_type, base) || EditorNode::get_editor_data().script_class_is_parent(res_type, base);
if (!paste_valid) {
break;
} }
} }
} }
@ -281,6 +302,9 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
for (int i = 0; i < base_type.get_slice_count(","); i++) { for (int i = 0; i < base_type.get_slice_count(","); i++) {
String base = base_type.get_slice(",", i); String base = base_type.get_slice(",", i);
ResourceLoader::get_recognized_extensions_for_type(base, &extensions); ResourceLoader::get_recognized_extensions_for_type(base, &extensions);
if (ScriptServer::is_global_class(base)) {
ResourceLoader::get_recognized_extensions_for_type(ScriptServer::get_global_class_native_base(base), &extensions);
}
} }
HashSet<String> valid_extensions; HashSet<String> valid_extensions;
@ -408,13 +432,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
Variant obj; Variant obj;
if (ScriptServer::is_global_class(intype)) { if (ScriptServer::is_global_class(intype)) {
obj = ClassDB::instantiate(ScriptServer::get_global_class_native_base(intype)); obj = EditorNode::get_editor_data().script_class_instance(intype);
if (obj) {
Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(intype));
if (script.is_valid()) {
((Object *)obj)->set_script(script);
}
}
} else { } else {
obj = ClassDB::instantiate(intype); obj = ClassDB::instantiate(intype);
} }
@ -512,23 +530,40 @@ void EditorResourcePicker::_button_draw() {
void EditorResourcePicker::_button_input(const Ref<InputEvent> &p_event) { void EditorResourcePicker::_button_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event; Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) { if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
if (mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) { // Only attempt to update and show the menu if we have
// Only attempt to update and show the menu if we have // a valid resource or the Picker is editable, as
// a valid resource or the Picker is editable, as // there will otherwise be nothing to display.
// there will otherwise be nothing to display. if (edited_resource.is_valid() || is_editable()) {
if (edited_resource.is_valid() || is_editable()) { _update_menu_items();
_update_menu_items();
Vector2 pos = get_screen_position() + mb->get_position(); Vector2 pos = get_screen_position() + mb->get_position();
edit_menu->reset_size(); edit_menu->reset_size();
edit_menu->set_position(pos); edit_menu->set_position(pos);
edit_menu->popup(); edit_menu->popup();
}
} }
} }
} }
String EditorResourcePicker::_get_resource_type(const Ref<Resource> &p_resource) const {
if (p_resource.is_null()) {
return String();
}
String res_type = p_resource->get_class();
Ref<Script> res_script = p_resource->get_script();
if (res_script.is_null()) {
return res_type;
}
// TODO: Replace with EditorFileSystem when PR #60606 is merged to use cached resource type.
String script_type = EditorNode::get_editor_data().script_class_get_name(res_script->get_path());
if (!script_type.is_empty()) {
res_type = script_type;
}
return res_type;
}
void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const { void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const {
Vector<String> allowed_types = base_type.split(","); Vector<String> allowed_types = base_type.split(",");
int size = allowed_types.size(); int size = allowed_types.size();
@ -550,7 +585,9 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin
List<StringName> allowed_subtypes; List<StringName> allowed_subtypes;
List<StringName> inheriters; List<StringName> inheriters;
ClassDB::get_inheriters_from_class(base, &inheriters); if (!ScriptServer::is_global_class(base)) {
ClassDB::get_inheriters_from_class(base, &inheriters);
}
for (const StringName &subtype_name : inheriters) { for (const StringName &subtype_name : inheriters) {
p_vector->insert(subtype_name); p_vector->insert(subtype_name);
allowed_subtypes.push_back(subtype_name); allowed_subtypes.push_back(subtype_name);
@ -602,32 +639,29 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const {
} }
} else if (drag_data.has("type") && String(drag_data["type"]) == "resource") { } else if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
res = drag_data["resource"]; res = drag_data["resource"];
} else if (drag_data.has("type") && String(drag_data["type"]) == "files") {
Vector<String> files = drag_data["files"];
// TODO: Extract the typename of the dropped filepath's resource in a more performant way, without fully loading it.
if (files.size() == 1) {
String file = files[0];
res = ResourceLoader::load(file);
}
} }
HashSet<String> allowed_types; HashSet<String> allowed_types;
_get_allowed_types(true, &allowed_types); _get_allowed_types(true, &allowed_types);
if (res.is_valid() && _is_type_valid(res->get_class(), allowed_types)) { if (res.is_valid()) {
return true; String res_type = _get_resource_type(res);
}
if (res.is_valid() && res->get_script()) { if (_is_type_valid(res_type, allowed_types)) {
StringName custom_class = EditorNode::get_singleton()->get_object_custom_type_name(res->get_script());
if (_is_type_valid(custom_class, allowed_types)) {
return true; return true;
} }
}
if (drag_data.has("type") && String(drag_data["type"]) == "files") { StringName custom_class = EditorNode::get_singleton()->get_object_custom_type_name(res.ptr());
Vector<String> files = drag_data["files"]; if (_is_type_valid(custom_class, allowed_types)) {
return true;
if (files.size() == 1) {
String file = files[0];
String file_type = EditorFileSystem::get_singleton()->get_file_type(file);
if (!file_type.is_empty() && _is_type_valid(file_type, allowed_types)) {
return true;
}
} }
} }
@ -685,8 +719,10 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_
HashSet<String> allowed_types; HashSet<String> allowed_types;
_get_allowed_types(false, &allowed_types); _get_allowed_types(false, &allowed_types);
String res_type = _get_resource_type(dropped_resource);
// If the accepted dropped resource is from the extended list, it requires conversion. // If the accepted dropped resource is from the extended list, it requires conversion.
if (!_is_type_valid(dropped_resource->get_class(), allowed_types)) { if (!_is_type_valid(res_type, allowed_types)) {
for (const String &E : allowed_types) { for (const String &E : allowed_types) {
String at = E.strip_edges(); String at = E.strip_edges();

View File

@ -91,6 +91,7 @@ class EditorResourcePicker : public HBoxContainer {
void _button_draw(); void _button_draw();
void _button_input(const Ref<InputEvent> &p_event); void _button_input(const Ref<InputEvent> &p_event);
String _get_resource_type(const Ref<Resource> &p_resource) const;
void _get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const; void _get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const;
bool _is_drop_valid(const Dictionary &p_drag_data) const; bool _is_drop_valid(const Dictionary &p_drag_data) const;
bool _is_type_valid(const String p_type_name, HashSet<String> p_allowed_types) const; bool _is_type_valid(const String p_type_name, HashSet<String> p_allowed_types) const;