/*************************************************************************/ /* editor_debugger_node.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2022 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 "editor_debugger_node.h" #include "core/object/undo_redo.h" #include "editor/debugger/editor_debugger_tree.h" #include "editor/debugger/script_editor_debugger.h" #include "editor/editor_log.h" #include "editor/editor_node.h" #include "editor/plugins/editor_debugger_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" #include "scene/gui/menu_button.h" #include "scene/gui/tab_container.h" #include "scene/resources/packed_scene.h" template void _for_all(TabContainer *p_node, const Func &p_func) { for (int i = 0; i < p_node->get_tab_count(); i++) { ScriptEditorDebugger *dbg = Object::cast_to(p_node->get_tab_control(i)); ERR_FAIL_COND(!dbg); p_func(dbg); } } EditorDebuggerNode *EditorDebuggerNode::singleton = nullptr; EditorDebuggerNode::EditorDebuggerNode() { if (!singleton) { singleton = this; } add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), SNAME("EditorStyles"))->get_margin(SIDE_LEFT)); add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), SNAME("EditorStyles"))->get_margin(SIDE_RIGHT)); tabs = memnew(TabContainer); tabs->set_tabs_visible(false); tabs->connect("tab_changed", callable_mp(this, &EditorDebuggerNode::_debugger_changed)); add_child(tabs); Ref empty; empty.instantiate(); tabs->add_theme_style_override("panel", empty); auto_switch_remote_scene_tree = EDITOR_DEF("debugger/auto_switch_to_remote_scene_tree", false); _add_debugger(); // Remote scene tree remote_scene_tree = memnew(EditorDebuggerTree); remote_scene_tree->connect("object_selected", callable_mp(this, &EditorDebuggerNode::_remote_object_requested)); remote_scene_tree->connect("save_node", callable_mp(this, &EditorDebuggerNode::_save_node_requested)); remote_scene_tree->connect("button_clicked", callable_mp(this, &EditorDebuggerNode::_remote_tree_button_pressed)); SceneTreeDock::get_singleton()->add_remote_tree_editor(remote_scene_tree); SceneTreeDock::get_singleton()->connect("remote_tree_selected", callable_mp(this, &EditorDebuggerNode::request_remote_tree)); remote_scene_tree_timeout = EDITOR_DEF("debugger/remote_scene_tree_refresh_interval", 1.0); inspect_edited_object_timeout = EDITOR_DEF("debugger/remote_inspect_refresh_interval", 0.2); EditorNode *editor = EditorNode::get_singleton(); editor->get_pause_button()->connect("pressed", callable_mp(this, &EditorDebuggerNode::_paused)); } ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() { ScriptEditorDebugger *node = memnew(ScriptEditorDebugger); int id = tabs->get_tab_count(); node->connect("stop_requested", callable_mp(this, &EditorDebuggerNode::_debugger_wants_stop).bind(id)); node->connect("stopped", callable_mp(this, &EditorDebuggerNode::_debugger_stopped).bind(id)); node->connect("stack_frame_selected", callable_mp(this, &EditorDebuggerNode::_stack_frame_selected).bind(id)); node->connect("error_selected", callable_mp(this, &EditorDebuggerNode::_error_selected).bind(id)); node->connect("breakpoint_selected", callable_mp(this, &EditorDebuggerNode::_error_selected).bind(id)); node->connect("clear_execution", callable_mp(this, &EditorDebuggerNode::_clear_execution)); node->connect("breaked", callable_mp(this, &EditorDebuggerNode::_breaked).bind(id)); node->connect("remote_tree_updated", callable_mp(this, &EditorDebuggerNode::_remote_tree_updated).bind(id)); node->connect("remote_object_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_updated).bind(id)); node->connect("remote_object_property_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_property_updated).bind(id)); node->connect("remote_object_requested", callable_mp(this, &EditorDebuggerNode::_remote_object_requested).bind(id)); node->connect("errors_cleared", callable_mp(this, &EditorDebuggerNode::_update_errors)); if (tabs->get_tab_count() > 0) { get_debugger(0)->clear_style(); } tabs->add_child(node); node->set_name("Session " + itos(tabs->get_tab_count())); if (tabs->get_tab_count() > 1) { node->clear_style(); tabs->set_tabs_visible(true); tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("DebuggerPanel"), SNAME("EditorStyles"))); } if (!debugger_plugins.is_empty()) { for (Ref plugin : debugger_plugins) { plugin->create_session(node); } } return node; } void EditorDebuggerNode::_stack_frame_selected(int p_debugger) { const ScriptEditorDebugger *dbg = get_debugger(p_debugger); ERR_FAIL_COND(!dbg); if (dbg != get_current_debugger()) { return; } _text_editor_stack_goto(dbg); } void EditorDebuggerNode::_error_selected(const String &p_file, int p_line, int p_debugger) { Ref