Make custom types more subtle and more useful

Implements #6067 (aaronfranke's idea)
Fixes #26980
This commit is contained in:
Bojidar Marinov 2019-07-19 22:21:30 +03:00
parent 22c843b0c4
commit 4f72178868
No known key found for this signature in database
GPG key ID: 4B0FD31949AD430D
6 changed files with 104 additions and 31 deletions

View file

@ -1274,12 +1274,7 @@ void AnimationTrackEdit::_notification(int p_what) {
}
text_color.a *= 0.7;
} else if (node) {
Ref<Texture> icon;
if (has_icon(node->get_class(), "EditorIcons")) {
icon = get_icon(node->get_class(), "EditorIcons");
} else {
icon = get_icon("Node", "EditorIcons");
}
Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(node, "Node");
draw_texture(icon, Point2(ofs, int(get_size().height - icon->get_height()) / 2));
icon_cache = icon;
@ -3500,9 +3495,7 @@ void AnimationTrackEditor::_update_tracks() {
if (root && root->has_node(base_path)) {
Node *n = root->get_node(base_path);
if (n) {
if (has_icon(n->get_class(), "EditorIcons")) {
icon = get_icon(n->get_class(), "EditorIcons");
}
icon = EditorNode::get_singleton()->get_object_icon(n, "Node");
name = n->get_name();
tooltip = root->get_path_to(n);
}

View file

@ -499,7 +499,6 @@ Object *EditorData::instance_custom_type(const String &p_type, const String &p_i
for (int i = 0; i < get_custom_types()[p_inherits].size(); i++) {
if (get_custom_types()[p_inherits][i].name == p_type) {
Ref<Texture> icon = get_custom_types()[p_inherits][i].icon;
Ref<Script> script = get_custom_types()[p_inherits][i].script;
Object *ob = ClassDB::instance(p_inherits);
@ -508,8 +507,6 @@ Object *EditorData::instance_custom_type(const String &p_type, const String &p_i
ob->call("set_name", p_type);
}
ob->set_script(script.get_ref_ptr());
if (icon.is_valid())
ob->set_meta("_editor_icon", icon);
return ob;
}
}

View file

@ -3488,6 +3488,69 @@ void EditorNode::stop_child_process() {
_menu_option_confirm(RUN_STOP, false);
}
Ref<Script> EditorNode::get_object_custom_type_base(const Object *p_object) const {
ERR_FAIL_COND_V(!p_object, NULL);
Ref<Script> script = p_object->get_script();
if (script.is_valid()) {
// Uncommenting would break things! Consider adding a parameter if you need it.
// StringName name = EditorNode::get_editor_data().script_class_get_name(base_script->get_path());
// if (name != StringName())
// return name;
// should probably be deprecated in 4.x
StringName base = script->get_instance_base_type();
if (base != StringName() && EditorNode::get_editor_data().get_custom_types().has(base)) {
const Vector<EditorData::CustomType> &types = EditorNode::get_editor_data().get_custom_types()[base];
Ref<Script> base_script = script;
while (base_script.is_valid()) {
for (int i = 0; i < types.size(); ++i) {
if (types[i].script == base_script) {
return types[i].script;
}
}
base_script = base_script->get_base_script();
}
}
}
return NULL;
}
StringName EditorNode::get_object_custom_type_name(const Object *p_object) const {
ERR_FAIL_COND_V(!p_object, StringName());
Ref<Script> script = p_object->get_script();
if (script.is_null() && p_object->is_class("Script")) {
script = p_object;
}
if (script.is_valid()) {
Ref<Script> base_script = script;
while (base_script.is_valid()) {
StringName name = EditorNode::get_editor_data().script_class_get_name(base_script->get_path());
if (name != StringName())
return name;
// should probably be deprecated in 4.x
StringName base = base_script->get_instance_base_type();
if (base != StringName() && EditorNode::get_editor_data().get_custom_types().has(base)) {
const Vector<EditorData::CustomType> &types = EditorNode::get_editor_data().get_custom_types()[base];
for (int i = 0; i < types.size(); ++i) {
if (types[i].script == base_script) {
return types[i].name;
}
}
}
base_script = base_script->get_base_script();
}
}
return StringName();
}
Ref<Texture> EditorNode::get_object_icon(const Object *p_object, const String &p_fallback) const {
ERR_FAIL_COND_V(!p_object || !gui_base, NULL);
@ -3497,23 +3560,24 @@ Ref<Texture> EditorNode::get_object_icon(const Object *p_object, const String &p
}
if (script.is_valid()) {
StringName name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
if (icon_path.length())
return ResourceLoader::load(icon_path);
Ref<Script> base_script = script;
while (base_script.is_valid()) {
StringName name = EditorNode::get_editor_data().script_class_get_name(base_script->get_path());
String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
if (icon_path.length())
return ResourceLoader::load(icon_path);
// should probably be deprecated in 4.x
StringName base = script->get_instance_base_type();
if (base != StringName()) {
const Map<String, Vector<EditorData::CustomType> > &p_map = EditorNode::get_editor_data().get_custom_types();
for (const Map<String, Vector<EditorData::CustomType> >::Element *E = p_map.front(); E; E = E->next()) {
const Vector<EditorData::CustomType> &ct = E->value();
for (int i = 0; i < ct.size(); ++i) {
if (ct[i].name == base && ct[i].icon.is_valid()) {
return ct[i].icon;
// should probably be deprecated in 4.x
StringName base = base_script->get_instance_base_type();
if (base != StringName() && EditorNode::get_editor_data().get_custom_types().has(base)) {
const Vector<EditorData::CustomType> &types = EditorNode::get_editor_data().get_custom_types()[base];
for (int i = 0; i < types.size(); ++i) {
if (types[i].script == base_script && types[i].icon.is_valid()) {
return types[i].icon;
}
}
}
base_script = base_script->get_base_script();
}
}

View file

@ -776,6 +776,8 @@ public:
void stop_child_process();
Ref<Theme> get_editor_theme() const { return theme; }
Ref<Script> get_object_custom_type_base(const Object *p_object) const;
StringName get_object_custom_type_name(const Object *p_object) const;
Ref<Texture> get_object_icon(const Object *p_object, const String &p_fallback = "Object") const;
Ref<Texture> get_class_icon(const String &p_class, const String &p_fallback = "Object") const;

View file

@ -466,8 +466,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *n = Object::cast_to<Node>(selection[i]);
Ref<Script> existing = n->get_script();
if (existing.is_valid()) {
const RefPtr empty;
Ref<Script> empty = EditorNode::get_singleton()->get_object_custom_type_base(n);
if (existing != empty) {
editor_data->get_undo_redo().add_do_method(n, "set_script", empty);
editor_data->get_undo_redo().add_undo_method(n, "set_script", existing);
}
@ -2329,6 +2329,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->clear();
Ref<Script> existing_script;
bool exisiting_script_removable = true;
if (selection.size() == 1) {
Node *selected = selection[0];
@ -2348,6 +2349,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->add_separator();
existing_script = selected->get_script();
if (EditorNode::get_singleton()->get_object_custom_type_base(selected) == existing_script) {
exisiting_script_removable = false;
}
}
if (profile_allow_script_editing) {
@ -2359,7 +2364,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->add_icon_shortcut(get_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_ATTACH_SCRIPT);
}
}
if (selection.size() > 1 || existing_script.is_valid()) {
if (selection.size() > 1 || (existing_script.is_valid() && exisiting_script_removable)) {
menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT);
}
menu->add_separator();

View file

@ -212,13 +212,19 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
Color accent = get_color("accent_color", "Editor");
Ref<Script> script = p_node->get_script();
if (!script.is_null()) {
if (!script.is_null() && EditorNode::get_singleton()->get_object_custom_type_base(p_node) != script) {
//has script
item->add_button(0, get_icon("Script", "EditorIcons"), BUTTON_SCRIPT);
} else {
//has no script
//has no script (or script is a custom type)
item->set_custom_color(0, get_color("disabled_font_color", "Editor"));
item->set_selectable(0, false);
if (!script.is_null()) { // make sure to mark the script if a custom type
item->add_button(0, get_icon("Script", "EditorIcons"), BUTTON_SCRIPT);
item->set_button_disabled(0, item->get_button_count(0) - 1, true);
}
accent.a *= 0.7;
}
@ -284,7 +290,10 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
item->add_button(0, get_icon("InstanceOptions", "EditorIcons"), BUTTON_SUBSCENE, false, TTR("Open in Editor"));
item->set_tooltip(0, TTR("Instance:") + " " + p_node->get_filename() + "\n" + TTR("Type:") + " " + p_node->get_class());
} else {
item->set_tooltip(0, String(p_node->get_name()) + "\n" + TTR("Type:") + " " + p_node->get_class());
StringName type = EditorNode::get_singleton()->get_object_custom_type_name(p_node);
if (type == StringName())
type = p_node->get_class();
item->set_tooltip(0, String(p_node->get_name()) + "\n" + TTR("Type:") + " " + type);
}
if (can_open_instance && undo_redo) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes
@ -295,6 +304,9 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
Ref<Script> script = p_node->get_script();
if (!script.is_null()) {
item->add_button(0, get_icon("Script", "EditorIcons"), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path());
if (EditorNode::get_singleton()->get_object_custom_type_base(p_node) == script) {
item->set_button_color(0, item->get_button_count(0) - 1, Color(1, 1, 1, 0.5));
}
}
if (p_node->is_class("CanvasItem")) {