Merge pull request #62413 from willnationsdev/gdres-inspector
Script-class-aware Inspector & related controls.
This commit is contained in:
commit
469eb3dfd7
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue