123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504 |
- /**************************************************************************/
- /* editor_run_bar.cpp */
- /**************************************************************************/
- /* This file is part of: */
- /* GODOT ENGINE */
- /* https://godotengine.org */
- /**************************************************************************/
- /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
- /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
- /* */
- /* 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_run_bar.h"
- #include "core/config/project_settings.h"
- #include "editor/debugger/editor_debugger_node.h"
- #include "editor/debugger/script_editor_debugger.h"
- #include "editor/editor_command_palette.h"
- #include "editor/editor_node.h"
- #include "editor/editor_run_native.h"
- #include "editor/editor_settings.h"
- #include "editor/editor_string_names.h"
- #include "editor/gui/editor_bottom_panel.h"
- #include "editor/gui/editor_quick_open_dialog.h"
- #include "scene/gui/box_container.h"
- #include "scene/gui/button.h"
- #include "scene/gui/panel_container.h"
- EditorRunBar *EditorRunBar::singleton = nullptr;
- void EditorRunBar::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_POSTINITIALIZE: {
- _reset_play_buttons();
- } break;
- case NOTIFICATION_THEME_CHANGED: {
- _update_play_buttons();
- profiler_autostart_indicator->set_button_icon(get_editor_theme_icon(SNAME("ProfilerAutostartWarning")));
- pause_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
- stop_button->set_button_icon(get_editor_theme_icon(SNAME("Stop")));
- if (is_movie_maker_enabled()) {
- main_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadMovieMode"), EditorStringName(EditorStyles)));
- write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonPressed"), EditorStringName(EditorStyles)));
- } else {
- main_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadNormal"), EditorStringName(EditorStyles)));
- write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonNormal"), EditorStringName(EditorStyles)));
- }
- write_movie_button->set_button_icon(get_editor_theme_icon(SNAME("MainMovieWrite")));
- // This button behaves differently, so color it as such.
- write_movie_button->begin_bulk_theme_override();
- write_movie_button->add_theme_color_override("icon_normal_color", get_theme_color(SNAME("movie_writer_icon_normal"), EditorStringName(EditorStyles)));
- write_movie_button->add_theme_color_override("icon_pressed_color", get_theme_color(SNAME("movie_writer_icon_pressed"), EditorStringName(EditorStyles)));
- write_movie_button->add_theme_color_override("icon_hover_color", get_theme_color(SNAME("movie_writer_icon_hover"), EditorStringName(EditorStyles)));
- write_movie_button->add_theme_color_override("icon_hover_pressed_color", get_theme_color(SNAME("movie_writer_icon_hover_pressed"), EditorStringName(EditorStyles)));
- write_movie_button->end_bulk_theme_override();
- } break;
- }
- }
- void EditorRunBar::_reset_play_buttons() {
- play_button->set_pressed(false);
- play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
- play_button->set_tooltip_text(TTR("Play the project."));
- play_scene_button->set_pressed(false);
- play_scene_button->set_button_icon(get_editor_theme_icon(SNAME("PlayScene")));
- play_scene_button->set_tooltip_text(TTR("Play the edited scene."));
- play_custom_scene_button->set_pressed(false);
- play_custom_scene_button->set_button_icon(get_editor_theme_icon(SNAME("PlayCustom")));
- play_custom_scene_button->set_tooltip_text(TTR("Play a custom scene."));
- }
- void EditorRunBar::_update_play_buttons() {
- _reset_play_buttons();
- if (!is_playing()) {
- return;
- }
- Button *active_button = nullptr;
- if (current_mode == RUN_CURRENT) {
- active_button = play_scene_button;
- } else if (current_mode == RUN_CUSTOM) {
- active_button = play_custom_scene_button;
- } else {
- active_button = play_button;
- }
- if (active_button) {
- active_button->set_pressed(true);
- active_button->set_button_icon(get_editor_theme_icon(SNAME("Reload")));
- active_button->set_tooltip_text(TTR("Reload the played scene."));
- }
- }
- void EditorRunBar::_write_movie_toggled(bool p_enabled) {
- if (p_enabled) {
- add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadMovieMode"), EditorStringName(EditorStyles)));
- write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonPressed"), EditorStringName(EditorStyles)));
- } else {
- add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadNormal"), EditorStringName(EditorStyles)));
- write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonNormal"), EditorStringName(EditorStyles)));
- }
- }
- void EditorRunBar::_quick_run_selected(const String &p_file_path) {
- play_custom_scene(p_file_path);
- }
- void EditorRunBar::_play_custom_pressed() {
- if (editor_run.get_status() == EditorRun::STATUS_STOP || current_mode != RunMode::RUN_CUSTOM) {
- stop_playing();
- EditorNode::get_singleton()->get_quick_open_dialog()->popup_dialog({ "PackedScene" }, callable_mp(this, &EditorRunBar::_quick_run_selected));
- play_custom_scene_button->set_pressed(false);
- } else {
- // Reload if already running a custom scene.
- String last_custom_scene = run_custom_filename; // This is necessary to have a copy of the string.
- play_custom_scene(last_custom_scene);
- }
- }
- void EditorRunBar::_play_current_pressed() {
- if (editor_run.get_status() == EditorRun::STATUS_STOP || current_mode != RunMode::RUN_CURRENT) {
- play_current_scene();
- } else {
- // Reload if already running the current scene.
- play_current_scene(true);
- }
- }
- void EditorRunBar::_run_scene(const String &p_scene_path) {
- ERR_FAIL_COND_MSG(current_mode == RUN_CUSTOM && p_scene_path.is_empty(), "Attempting to run a custom scene with an empty path.");
- if (editor_run.get_status() == EditorRun::STATUS_PLAY) {
- return;
- }
- _reset_play_buttons();
- String write_movie_file;
- if (is_movie_maker_enabled()) {
- if (current_mode == RUN_CURRENT) {
- Node *scene_root = nullptr;
- if (p_scene_path.is_empty()) {
- scene_root = get_tree()->get_edited_scene_root();
- } else {
- int scene_index = EditorNode::get_editor_data().get_edited_scene_from_path(p_scene_path);
- if (scene_index >= 0) {
- scene_root = EditorNode::get_editor_data().get_edited_scene_root(scene_index);
- }
- }
- if (scene_root && scene_root->has_meta("movie_file")) {
- // If the scene file has a movie_file metadata set, use this as file.
- // Quick workaround if you want to have multiple scenes that write to
- // multiple movies.
- write_movie_file = scene_root->get_meta("movie_file");
- }
- }
- if (write_movie_file.is_empty()) {
- write_movie_file = GLOBAL_GET("editor/movie_writer/movie_file");
- }
- if (write_movie_file.is_empty()) {
- // TODO: Provide options to directly resolve the issue with a custom dialog.
- EditorNode::get_singleton()->show_accept(TTR("Movie Maker mode is enabled, but no movie file path has been specified.\nA default movie file path can be specified in the project settings under the Editor > Movie Writer category.\nAlternatively, for running single scenes, a `movie_file` string metadata can be added to the root node,\nspecifying the path to a movie file that will be used when recording that scene."), TTR("OK"));
- return;
- }
- }
- String run_filename;
- switch (current_mode) {
- case RUN_CUSTOM: {
- run_filename = p_scene_path;
- run_custom_filename = run_filename;
- } break;
- case RUN_CURRENT: {
- if (!p_scene_path.is_empty()) {
- run_filename = p_scene_path;
- run_current_filename = run_filename;
- break;
- }
- Node *scene_root = get_tree()->get_edited_scene_root();
- if (!scene_root) {
- EditorNode::get_singleton()->show_accept(TTR("There is no defined scene to run."), TTR("OK"));
- return;
- }
- if (scene_root->get_scene_file_path().is_empty()) {
- EditorNode::get_singleton()->save_before_run();
- return;
- }
- run_filename = scene_root->get_scene_file_path();
- run_current_filename = run_filename;
- } break;
- default: {
- if (!EditorNode::get_singleton()->ensure_main_scene(false)) {
- return;
- }
- run_filename = GLOBAL_GET("application/run/main_scene");
- } break;
- }
- EditorNode::get_singleton()->try_autosave();
- if (!EditorNode::get_singleton()->call_build()) {
- return;
- }
- EditorDebuggerNode::get_singleton()->start();
- Error error = editor_run.run(run_filename, write_movie_file);
- if (error != OK) {
- EditorDebuggerNode::get_singleton()->stop();
- EditorNode::get_singleton()->show_accept(TTR("Could not start subprocess(es)!"), TTR("OK"));
- return;
- }
- _update_play_buttons();
- stop_button->set_disabled(false);
- emit_signal(SNAME("play_pressed"));
- }
- void EditorRunBar::_run_native(const Ref<EditorExportPreset> &p_preset) {
- EditorNode::get_singleton()->try_autosave();
- if (run_native->is_deploy_debug_remote_enabled()) {
- stop_playing();
- if (!EditorNode::get_singleton()->call_build()) {
- return; // Build failed.
- }
- EditorDebuggerNode::get_singleton()->start(p_preset->get_platform()->get_debug_protocol());
- emit_signal(SNAME("play_pressed"));
- editor_run.run_native_notify();
- }
- }
- void EditorRunBar::_profiler_autostart_indicator_pressed() {
- // Switch to the first profiler tab in the bottom panel.
- EditorNode::get_singleton()->get_bottom_panel()->make_item_visible(EditorDebuggerNode::get_singleton(), true);
- if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_profiler", false)) {
- EditorDebuggerNode::get_singleton()->get_current_debugger()->switch_to_debugger(3);
- } else if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_visual_profiler", false)) {
- EditorDebuggerNode::get_singleton()->get_current_debugger()->switch_to_debugger(4);
- } else {
- // Switch to the network profiler tab.
- EditorDebuggerNode::get_singleton()->get_current_debugger()->switch_to_debugger(8);
- }
- }
- void EditorRunBar::play_main_scene(bool p_from_native) {
- if (p_from_native) {
- run_native->resume_run_native();
- } else {
- stop_playing();
- current_mode = RunMode::RUN_MAIN;
- _run_scene();
- }
- }
- void EditorRunBar::play_current_scene(bool p_reload) {
- String last_current_scene = run_current_filename; // This is necessary to have a copy of the string.
- EditorNode::get_singleton()->save_default_environment();
- stop_playing();
- current_mode = RunMode::RUN_CURRENT;
- if (p_reload) {
- _run_scene(last_current_scene);
- } else {
- _run_scene();
- }
- }
- void EditorRunBar::play_custom_scene(const String &p_custom) {
- stop_playing();
- current_mode = RunMode::RUN_CUSTOM;
- _run_scene(p_custom);
- }
- void EditorRunBar::stop_playing() {
- if (editor_run.get_status() == EditorRun::STATUS_STOP) {
- return;
- }
- current_mode = RunMode::STOPPED;
- editor_run.stop();
- EditorDebuggerNode::get_singleton()->stop();
- run_custom_filename.clear();
- run_current_filename.clear();
- stop_button->set_pressed(false);
- stop_button->set_disabled(true);
- _reset_play_buttons();
- emit_signal(SNAME("stop_pressed"));
- }
- bool EditorRunBar::is_playing() const {
- EditorRun::Status status = editor_run.get_status();
- return (status == EditorRun::STATUS_PLAY || status == EditorRun::STATUS_PAUSED);
- }
- String EditorRunBar::get_playing_scene() const {
- String run_filename = editor_run.get_running_scene();
- if (run_filename.is_empty() && is_playing()) {
- run_filename = GLOBAL_GET("application/run/main_scene"); // Must be the main scene then.
- }
- return run_filename;
- }
- Error EditorRunBar::start_native_device(int p_device_id) {
- return run_native->start_run_native(p_device_id);
- }
- OS::ProcessID EditorRunBar::has_child_process(OS::ProcessID p_pid) const {
- return editor_run.has_child_process(p_pid);
- }
- void EditorRunBar::stop_child_process(OS::ProcessID p_pid) {
- if (!has_child_process(p_pid)) {
- return;
- }
- editor_run.stop_child_process(p_pid);
- if (!editor_run.get_child_process_count()) { // All children stopped. Closing.
- stop_playing();
- }
- }
- OS::ProcessID EditorRunBar::get_current_process() const {
- return editor_run.get_current_process();
- }
- void EditorRunBar::set_movie_maker_enabled(bool p_enabled) {
- write_movie_button->set_pressed(p_enabled);
- }
- bool EditorRunBar::is_movie_maker_enabled() const {
- return write_movie_button->is_pressed();
- }
- void EditorRunBar::update_profiler_autostart_indicator() {
- bool profiler_active = EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_profiler", false);
- bool visual_profiler_active = EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_visual_profiler", false);
- bool network_profiler_active = EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_network_profiler", false);
- bool any_profiler_active = profiler_active | visual_profiler_active | network_profiler_active;
- profiler_autostart_indicator->set_visible(any_profiler_active);
- if (any_profiler_active) {
- String tooltip = TTR("Autostart is enabled for the following profilers, which can have a performance impact:");
- if (profiler_active) {
- tooltip += "\n- " + TTR("Profiler");
- }
- if (visual_profiler_active) {
- tooltip += "\n- " + TTR("Visual Profiler");
- }
- if (network_profiler_active) {
- tooltip += "\n- " + TTR("Network Profiler");
- }
- tooltip += "\n\n" + TTR("Click to open the first profiler for which autostart is enabled.");
- profiler_autostart_indicator->set_tooltip_text(tooltip);
- }
- }
- HBoxContainer *EditorRunBar::get_buttons_container() {
- return main_hbox;
- }
- void EditorRunBar::_bind_methods() {
- ADD_SIGNAL(MethodInfo("play_pressed"));
- ADD_SIGNAL(MethodInfo("stop_pressed"));
- }
- EditorRunBar::EditorRunBar() {
- singleton = this;
- outer_hbox = memnew(HBoxContainer);
- add_child(outer_hbox);
- // Use a button for the indicator since it comes with a background panel and pixel perfect centering of an icon.
- profiler_autostart_indicator = memnew(Button);
- profiler_autostart_indicator->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- profiler_autostart_indicator->set_focus_mode(FOCUS_NONE);
- profiler_autostart_indicator->set_theme_type_variation("ProfilerAutostartIndicator");
- profiler_autostart_indicator->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::_profiler_autostart_indicator_pressed));
- outer_hbox->add_child(profiler_autostart_indicator);
- update_profiler_autostart_indicator();
- main_panel = memnew(PanelContainer);
- outer_hbox->add_child(main_panel);
- main_hbox = memnew(HBoxContainer);
- main_panel->add_child(main_hbox);
- play_button = memnew(Button);
- main_hbox->add_child(play_button);
- play_button->set_theme_type_variation("RunBarButton");
- play_button->set_toggle_mode(true);
- play_button->set_focus_mode(Control::FOCUS_NONE);
- play_button->set_tooltip_text(TTRC("Run the project's default scene."));
- play_button->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::play_main_scene).bind(false));
- ED_SHORTCUT_AND_COMMAND("editor/run_project", TTRC("Run Project"), Key::F5);
- ED_SHORTCUT_OVERRIDE("editor/run_project", "macos", KeyModifierMask::META | Key::B);
- play_button->set_shortcut(ED_GET_SHORTCUT("editor/run_project"));
- pause_button = memnew(Button);
- main_hbox->add_child(pause_button);
- pause_button->set_theme_type_variation("RunBarButton");
- pause_button->set_toggle_mode(true);
- pause_button->set_focus_mode(Control::FOCUS_NONE);
- pause_button->set_tooltip_text(TTRC("Pause the running project's execution for debugging."));
- pause_button->set_disabled(true);
- ED_SHORTCUT("editor/pause_running_project", TTRC("Pause Running Project"), Key::F7);
- ED_SHORTCUT_OVERRIDE("editor/pause_running_project", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::Y);
- pause_button->set_shortcut(ED_GET_SHORTCUT("editor/pause_running_project"));
- stop_button = memnew(Button);
- main_hbox->add_child(stop_button);
- stop_button->set_theme_type_variation("RunBarButton");
- stop_button->set_focus_mode(Control::FOCUS_NONE);
- stop_button->set_tooltip_text(TTRC("Stop the currently running project."));
- stop_button->set_disabled(true);
- stop_button->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::stop_playing));
- ED_SHORTCUT("editor/stop_running_project", TTRC("Stop Running Project"), Key::F8);
- ED_SHORTCUT_OVERRIDE("editor/stop_running_project", "macos", KeyModifierMask::META | Key::PERIOD);
- stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop_running_project"));
- run_native = memnew(EditorRunNative);
- main_hbox->add_child(run_native);
- run_native->connect("native_run", callable_mp(this, &EditorRunBar::_run_native));
- play_scene_button = memnew(Button);
- main_hbox->add_child(play_scene_button);
- play_scene_button->set_theme_type_variation("RunBarButton");
- play_scene_button->set_toggle_mode(true);
- play_scene_button->set_focus_mode(Control::FOCUS_NONE);
- play_scene_button->set_tooltip_text(TTRC("Run the currently edited scene."));
- play_scene_button->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::_play_current_pressed));
- ED_SHORTCUT_AND_COMMAND("editor/run_current_scene", TTRC("Run Current Scene"), Key::F6);
- ED_SHORTCUT_OVERRIDE("editor/run_current_scene", "macos", KeyModifierMask::META | Key::R);
- play_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_current_scene"));
- play_custom_scene_button = memnew(Button);
- main_hbox->add_child(play_custom_scene_button);
- play_custom_scene_button->set_theme_type_variation("RunBarButton");
- play_custom_scene_button->set_toggle_mode(true);
- play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE);
- play_custom_scene_button->set_tooltip_text(TTRC("Run a specific scene."));
- play_custom_scene_button->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::_play_custom_pressed));
- ED_SHORTCUT_AND_COMMAND("editor/run_specific_scene", TTRC("Run Specific Scene"), KeyModifierMask::CTRL | KeyModifierMask::SHIFT | Key::F5);
- ED_SHORTCUT_OVERRIDE("editor/run_specific_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R);
- play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_specific_scene"));
- write_movie_panel = memnew(PanelContainer);
- main_hbox->add_child(write_movie_panel);
- write_movie_button = memnew(Button);
- write_movie_panel->add_child(write_movie_button);
- write_movie_button->set_theme_type_variation("RunBarButton");
- write_movie_button->set_toggle_mode(true);
- write_movie_button->set_pressed(false);
- write_movie_button->set_focus_mode(Control::FOCUS_NONE);
- write_movie_button->set_tooltip_text(TTR("Enable Movie Maker mode.\nThe project will run at stable FPS and the visual and audio output will be recorded to a video file."));
- write_movie_button->connect(SceneStringName(toggled), callable_mp(this, &EditorRunBar::_write_movie_toggled));
- }
|