/*************************************************************************/ /* scene_tree_editor.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "scene_tree_editor.h" #include "core/message_queue.h" #include "core/print_string.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor_node.h" #include "scene/gui/label.h" #include "scene/main/viewport.h" #include "scene/resources/packed_scene.h" Node *SceneTreeEditor::get_scene_node() { ERR_FAIL_COND_V(!is_inside_tree(), NULL); return get_tree()->get_edited_scene_root(); } void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_id) { if (connect_to_script_mode) { return; //don't do anything in this mode } TreeItem *item = Object::cast_to(p_item); ERR_FAIL_COND(!item); NodePath np = item->get_metadata(0); Node *n = get_node(np); ERR_FAIL_COND(!n); if (p_id == BUTTON_SUBSCENE) { if (n == get_scene_node()) { if (n && n->get_scene_inherited_state().is_valid()) { emit_signal("open", n->get_scene_inherited_state()->get_path()); } } else { emit_signal("open", n->get_filename()); } } else if (p_id == BUTTON_SCRIPT) { RefPtr script = n->get_script(); if (!script.is_null()) emit_signal("open_script", script); } else if (p_id == BUTTON_VISIBILITY) { undo_redo->create_action(TTR("Toggle Visible")); _toggle_visible(n); List selection = editor_selection->get_selected_node_list(); if (selection.size() > 1 && selection.find(n) != NULL) { for (List::Element *E = selection.front(); E; E = E->next()) { Node *nv = E->get(); ERR_FAIL_COND(!nv); if (nv == n) { continue; } _toggle_visible(nv); } } undo_redo->commit_action(); } else if (p_id == BUTTON_LOCK) { undo_redo->create_action(TTR("Unlock Node")); if (n->is_class("CanvasItem") || n->is_class("Spatial")) { undo_redo->add_do_method(n, "remove_meta", "_edit_lock_"); undo_redo->add_undo_method(n, "set_meta", "_edit_lock_", true); undo_redo->add_do_method(this, "_update_tree", Variant()); undo_redo->add_undo_method(this, "_update_tree", Variant()); undo_redo->add_do_method(this, "emit_signal", "node_changed"); undo_redo->add_undo_method(this, "emit_signal", "node_changed"); } undo_redo->commit_action(); } else if (p_id == BUTTON_PIN) { if (n->is_class("AnimationPlayer")) { AnimationPlayerEditor::singleton->unpin(); _update_tree(); } } else if (p_id == BUTTON_GROUP) { undo_redo->create_action(TTR("Button Group")); if (n->is_class("CanvasItem") || n->is_class("Spatial")) { undo_redo->add_do_method(n, "remove_meta", "_edit_group_"); undo_redo->add_undo_method(n, "set_meta", "_edit_group_", true); undo_redo->add_do_method(this, "_update_tree", Variant()); undo_redo->add_undo_method(this, "_update_tree", Variant()); undo_redo->add_do_method(this, "emit_signal", "node_changed"); undo_redo->add_undo_method(this, "emit_signal", "node_changed"); } undo_redo->commit_action(); } else if (p_id == BUTTON_WARNING) { String config_err = n->get_configuration_warning(); if (config_err == String()) return; config_err = config_err.word_wrap(80); warning->set_text(config_err); warning->popup_centered_minsize(); } else if (p_id == BUTTON_SIGNALS) { editor_selection->clear(); editor_selection->add_node(n); set_selected(n); NodeDock::singleton->get_parent()->call("set_current_tab", NodeDock::singleton->get_index()); NodeDock::singleton->show_connections(); } else if (p_id == BUTTON_GROUPS) { editor_selection->clear(); editor_selection->add_node(n); set_selected(n); NodeDock::singleton->get_parent()->call("set_current_tab", NodeDock::singleton->get_index()); NodeDock::singleton->show_groups(); } } void SceneTreeEditor::_toggle_visible(Node *p_node) { if (p_node->has_method("is_visible") && p_node->has_method("set_visible")) { bool v = bool(p_node->call("is_visible")); undo_redo->add_do_method(p_node, "set_visible", !v); undo_redo->add_undo_method(p_node, "set_visible", v); } } bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { if (!p_node) return false; // only owned nodes are editable, since nodes can create their own (manually owned) child nodes, // which the editor needs not to know about. bool part_of_subscene = false; if (!display_foreign && p_node->get_owner() != get_scene_node() && p_node != get_scene_node()) { if ((show_enabled_subscene || can_open_instance) && p_node->get_owner() && (get_scene_node()->is_editable_instance(p_node->get_owner()))) { part_of_subscene = true; //allow } else { return false; } } else { part_of_subscene = p_node != get_scene_node() && get_scene_node()->get_scene_inherited_state().is_valid() && get_scene_node()->get_scene_inherited_state()->find_node_by_path(get_scene_node()->get_path_to(p_node)) >= 0; } TreeItem *item = tree->create_item(p_parent); item->set_text(0, p_node->get_name()); if (can_rename && !part_of_subscene /*(p_node->get_owner() == get_scene_node() || p_node==get_scene_node())*/) item->set_editable(0, true); item->set_selectable(0, true); if (can_rename) { #ifndef DISABLE_DEPRECATED if (p_node->has_meta("_editor_collapsed")) { //remove previous way of storing folding, which did not get along with scene inheritance and instancing if ((bool)p_node->get_meta("_editor_collapsed")) p_node->set_display_folded(true); p_node->set_meta("_editor_collapsed", Variant()); } #endif bool collapsed = p_node->is_displayed_folded(); if (collapsed) item->set_collapsed(true); } Ref icon = EditorNode::get_singleton()->get_object_icon(p_node, "Node"); item->set_icon(0, icon); item->set_metadata(0, p_node->get_path()); if (connect_to_script_mode) { Color accent = get_color("accent_color", "Editor"); if (!p_node->get_script().is_null()) { //has script item->add_button(0, get_icon("Script", "EditorIcons"), BUTTON_SCRIPT); } else { //has no script item->set_custom_color(0, get_color("disabled_font_color", "Editor")); item->set_selectable(0, false); accent.a *= 0.7; } if (marked.has(p_node)) { String node_name = p_node->get_name(); if (connecting_signal) { node_name += " " + TTR("(Connecting From)"); } item->set_text(0, node_name); item->set_custom_color(0, accent); } } else if (part_of_subscene) { if (valid_types.size() == 0) { item->set_custom_color(0, get_color("disabled_font_color", "Editor")); } } else if (marked.has(p_node)) { String node_name = p_node->get_name(); if (connecting_signal) { node_name += " " + TTR("(Connecting From)"); } item->set_text(0, node_name); item->set_selectable(0, marked_selectable); item->set_custom_color(0, get_color("accent_color", "Editor")); } else if (!marked_selectable && !marked_children_selectable) { Node *node = p_node; while (node) { if (marked.has(node)) { item->set_selectable(0, false); item->set_custom_color(0, get_color("error_color", "Editor")); break; } node = node->get_parent(); } } if (can_rename) { //should be can edit.. String warning = p_node->get_configuration_warning(); if (warning != String()) { item->add_button(0, get_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + p_node->get_configuration_warning()); } bool has_connections = p_node->has_persistent_signal_connections(); bool has_groups = p_node->has_persistent_groups(); if (has_connections && has_groups) { item->add_button(0, get_icon("SignalsAndGroups", "EditorIcons"), BUTTON_SIGNALS, false, TTR("Node has connection(s) and group(s).\nClick to show signals dock.")); } else if (has_connections) { item->add_button(0, get_icon("Signals", "EditorIcons"), BUTTON_SIGNALS, false, TTR("Node has connections.\nClick to show signals dock.")); } else if (has_groups) { item->add_button(0, get_icon("Groups", "EditorIcons"), BUTTON_GROUPS, false, TTR("Node is in group(s).\nClick to show groups dock.")); } } if (p_node == get_scene_node() && p_node->get_scene_inherited_state().is_valid()) { item->add_button(0, get_icon("InstanceOptions", "EditorIcons"), BUTTON_SUBSCENE, false, TTR("Open in Editor")); item->set_tooltip(0, TTR("Inherits:") + " " + p_node->get_scene_inherited_state()->get_path() + "\n" + TTR("Type:") + " " + p_node->get_class()); } else if (p_node != get_scene_node() && p_node->get_filename() != "" && can_open_instance) { 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()); } if (can_open_instance && undo_redo) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes if (!p_node->is_connected("script_changed", this, "_node_script_changed")) p_node->connect("script_changed", this, "_node_script_changed", varray(p_node)); if (!p_node->get_script().is_null()) { Ref