Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/editor/run/editor_run_bar.cpp
9903 views
1
/**************************************************************************/
2
/* editor_run_bar.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "editor_run_bar.h"
32
33
#include "core/config/project_settings.h"
34
#include "editor/debugger/editor_debugger_node.h"
35
#include "editor/debugger/script_editor_debugger.h"
36
#include "editor/editor_node.h"
37
#include "editor/editor_string_names.h"
38
#include "editor/gui/editor_bottom_panel.h"
39
#include "editor/gui/editor_quick_open_dialog.h"
40
#include "editor/gui/editor_toaster.h"
41
#include "editor/run/editor_run_native.h"
42
#include "editor/settings/editor_command_palette.h"
43
#include "editor/settings/editor_settings.h"
44
#include "editor/settings/project_settings_editor.h"
45
#include "editor/themes/editor_scale.h"
46
#include "scene/gui/box_container.h"
47
#include "scene/gui/button.h"
48
#include "scene/gui/menu_button.h"
49
#include "scene/gui/panel_container.h"
50
51
#ifndef XR_DISABLED
52
#include "servers/xr_server.h"
53
#endif // XR_DISABLED
54
55
EditorRunBar *EditorRunBar::singleton = nullptr;
56
57
void EditorRunBar::_notification(int p_what) {
58
switch (p_what) {
59
case NOTIFICATION_POSTINITIALIZE: {
60
_reset_play_buttons();
61
} break;
62
63
case NOTIFICATION_READY: {
64
if (Engine::get_singleton()->is_recovery_mode_hint()) {
65
recovery_mode_show_dialog();
66
}
67
} break;
68
69
case NOTIFICATION_THEME_CHANGED: {
70
if (Engine::get_singleton()->is_recovery_mode_hint()) {
71
main_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadRecoveryMode"), EditorStringName(EditorStyles)));
72
recovery_mode_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("RecoveryModeButton"), EditorStringName(EditorStyles)));
73
recovery_mode_button->add_theme_style_override("hover", get_theme_stylebox(SNAME("RecoveryModeButton"), EditorStringName(EditorStyles)));
74
75
recovery_mode_button->set_button_icon(get_editor_theme_icon(SNAME("NodeWarning")));
76
recovery_mode_reload_button->set_button_icon(get_editor_theme_icon(SNAME("Reload")));
77
78
recovery_mode_button->begin_bulk_theme_override();
79
recovery_mode_button->add_theme_color_override("icon_normal_color", Color(0.3, 0.3, 0.3, 1));
80
recovery_mode_button->add_theme_color_override("icon_pressed_color", Color(0.4, 0.4, 0.4, 1));
81
recovery_mode_button->add_theme_color_override("icon_hover_color", Color(0.6, 0.6, 0.6, 1));
82
Color dark_color = get_theme_color("recovery_mode_text_color", EditorStringName(Editor));
83
recovery_mode_button->add_theme_color_override(SceneStringName(font_color), dark_color);
84
recovery_mode_button->add_theme_color_override("font_pressed_color", dark_color.lightened(0.2));
85
recovery_mode_button->add_theme_color_override("font_hover_color", dark_color.lightened(0.4));
86
recovery_mode_button->add_theme_color_override("font_hover_pressed_color", dark_color.lightened(0.2));
87
recovery_mode_button->end_bulk_theme_override();
88
89
return;
90
}
91
92
_update_play_buttons();
93
profiler_autostart_indicator->set_button_icon(get_editor_theme_icon(SNAME("ProfilerAutostartWarning")));
94
pause_button->set_button_icon(get_editor_theme_icon(SNAME("Pause")));
95
stop_button->set_button_icon(get_editor_theme_icon(SNAME("Stop")));
96
97
if (is_movie_maker_enabled()) {
98
main_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadMovieMode"), EditorStringName(EditorStyles)));
99
write_movie_button->set_theme_type_variation("RunBarButtonMovieMakerEnabled");
100
101
write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonPressed"), EditorStringName(EditorStyles)));
102
} else {
103
main_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadNormal"), EditorStringName(EditorStyles)));
104
write_movie_button->set_theme_type_variation("RunBarButtonMovieMakerDisabled");
105
106
write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonNormal"), EditorStringName(EditorStyles)));
107
}
108
109
write_movie_button->set_button_icon(get_editor_theme_icon(SNAME("MainMovieWrite")));
110
111
} break;
112
}
113
}
114
115
void EditorRunBar::_reset_play_buttons() {
116
if (Engine::get_singleton()->is_recovery_mode_hint()) {
117
return;
118
}
119
120
play_button->set_pressed(false);
121
play_button->set_button_icon(get_editor_theme_icon(SNAME("MainPlay")));
122
play_button->set_tooltip_text(TTRC("Play the project."));
123
124
play_scene_button->set_pressed(false);
125
play_scene_button->set_button_icon(get_editor_theme_icon(SNAME("PlayScene")));
126
play_scene_button->set_tooltip_text(TTRC("Play the edited scene."));
127
128
play_custom_scene_button->set_pressed(false);
129
play_custom_scene_button->set_button_icon(get_editor_theme_icon(SNAME("PlayCustom")));
130
play_custom_scene_button->set_tooltip_text(TTRC("Play a custom scene."));
131
}
132
133
void EditorRunBar::_update_play_buttons() {
134
if (Engine::get_singleton()->is_recovery_mode_hint()) {
135
return;
136
}
137
138
_reset_play_buttons();
139
if (!is_playing()) {
140
return;
141
}
142
143
Button *active_button = nullptr;
144
if (current_mode == RUN_CURRENT) {
145
active_button = play_scene_button;
146
} else if (current_mode == RUN_CUSTOM) {
147
active_button = play_custom_scene_button;
148
} else {
149
active_button = play_button;
150
}
151
152
if (active_button) {
153
active_button->set_pressed(true);
154
active_button->set_button_icon(get_editor_theme_icon(SNAME("Reload")));
155
active_button->set_tooltip_text(TTRC("Reload the played scene."));
156
}
157
}
158
159
void EditorRunBar::_movie_maker_item_pressed(int p_id) {
160
switch (p_id) {
161
case MOVIE_MAKER_TOGGLE: {
162
bool new_enabled = !is_movie_maker_enabled();
163
set_movie_maker_enabled(new_enabled);
164
write_movie_button->get_popup()->set_item_checked(0, new_enabled);
165
write_movie_button->set_pressed(new_enabled);
166
_write_movie_toggled(new_enabled);
167
break;
168
}
169
case MOVIE_MAKER_OPEN_SETTINGS:
170
ProjectSettingsEditor::get_singleton()->popup_project_settings(true);
171
ProjectSettingsEditor::get_singleton()->set_general_page("editor/movie_writer");
172
break;
173
}
174
}
175
176
void EditorRunBar::_write_movie_toggled(bool p_enabled) {
177
if (p_enabled) {
178
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadMovieMode"), EditorStringName(EditorStyles)));
179
write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonPressed"), EditorStringName(EditorStyles)));
180
} else {
181
add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("LaunchPadNormal"), EditorStringName(EditorStyles)));
182
write_movie_panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SNAME("MovieWriterButtonNormal"), EditorStringName(EditorStyles)));
183
}
184
}
185
186
Vector<String> EditorRunBar::_get_xr_mode_play_args(int p_xr_mode_id) {
187
Vector<String> play_args;
188
if (p_xr_mode_id == 0) {
189
// Play in regular mode, xr mode off.
190
play_args.push_back("--xr-mode");
191
play_args.push_back("off");
192
} else if (p_xr_mode_id == 1) {
193
// Play in xr mode.
194
play_args.push_back("--xr-mode");
195
play_args.push_back("on");
196
}
197
return play_args;
198
}
199
200
void EditorRunBar::_quick_run_selected(const String &p_file_path, int p_id) {
201
play_custom_scene(p_file_path, _get_xr_mode_play_args(p_id));
202
}
203
204
void EditorRunBar::_play_custom_pressed(int p_id) {
205
if (editor_run.get_status() == EditorRun::STATUS_STOP || current_mode != RunMode::RUN_CUSTOM) {
206
stop_playing();
207
208
EditorNode::get_singleton()->get_quick_open_dialog()->popup_dialog({ "PackedScene" }, callable_mp(this, &EditorRunBar::_quick_run_selected).bind(p_id));
209
play_custom_scene_button->set_pressed(false);
210
} else {
211
Vector<String> play_args = _get_xr_mode_play_args(p_id);
212
213
// Reload if already running a custom scene.
214
String last_custom_scene = run_custom_filename; // This is necessary to have a copy of the string.
215
play_custom_scene(last_custom_scene, play_args);
216
}
217
}
218
219
void EditorRunBar::_play_current_pressed(int p_id) {
220
Vector<String> play_args = _get_xr_mode_play_args(p_id);
221
222
if (editor_run.get_status() == EditorRun::STATUS_STOP || current_mode != RunMode::RUN_CURRENT) {
223
play_current_scene(false, play_args);
224
} else {
225
// Reload if already running the current scene.
226
play_current_scene(true, play_args);
227
}
228
}
229
230
void EditorRunBar::_run_scene(const String &p_scene_path, const Vector<String> &p_run_args) {
231
ERR_FAIL_COND_MSG(current_mode == RUN_CUSTOM && p_scene_path.is_empty(), "Attempting to run a custom scene with an empty path.");
232
233
if (editor_run.get_status() == EditorRun::STATUS_PLAY) {
234
return;
235
}
236
237
if (!EditorNode::get_singleton()->validate_custom_directory()) {
238
return;
239
}
240
241
_reset_play_buttons();
242
243
String write_movie_file;
244
if (is_movie_maker_enabled()) {
245
if (current_mode == RUN_CURRENT) {
246
Node *scene_root = nullptr;
247
if (p_scene_path.is_empty()) {
248
scene_root = get_tree()->get_edited_scene_root();
249
} else {
250
int scene_index = EditorNode::get_editor_data().get_edited_scene_from_path(p_scene_path);
251
if (scene_index >= 0) {
252
scene_root = EditorNode::get_editor_data().get_edited_scene_root(scene_index);
253
}
254
}
255
256
if (scene_root && scene_root->has_meta("movie_file")) {
257
// If the scene file has a movie_file metadata set, use this as file.
258
// Quick workaround if you want to have multiple scenes that write to
259
// multiple movies.
260
write_movie_file = scene_root->get_meta("movie_file");
261
}
262
}
263
264
if (write_movie_file.is_empty()) {
265
write_movie_file = GLOBAL_GET("editor/movie_writer/movie_file");
266
}
267
268
if (write_movie_file.is_empty()) {
269
// TODO: Provide options to directly resolve the issue with a custom dialog.
270
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"));
271
return;
272
}
273
}
274
275
String run_filename;
276
switch (current_mode) {
277
case RUN_CUSTOM: {
278
run_filename = ResourceUID::ensure_path(p_scene_path);
279
run_custom_filename = run_filename;
280
} break;
281
282
case RUN_CURRENT: {
283
if (!p_scene_path.is_empty()) {
284
run_filename = p_scene_path;
285
run_current_filename = run_filename;
286
break;
287
}
288
289
Node *scene_root = get_tree()->get_edited_scene_root();
290
if (!scene_root) {
291
EditorNode::get_singleton()->show_accept(TTR("There is no defined scene to run."), TTR("OK"));
292
return;
293
}
294
295
if (scene_root->get_scene_file_path().is_empty()) {
296
EditorNode::get_singleton()->save_before_run();
297
return;
298
}
299
300
run_filename = scene_root->get_scene_file_path();
301
run_current_filename = run_filename;
302
} break;
303
304
default: {
305
if (!EditorNode::get_singleton()->ensure_main_scene(false)) {
306
return;
307
}
308
309
run_filename = GLOBAL_GET("application/run/main_scene");
310
} break;
311
}
312
313
EditorNode::get_singleton()->try_autosave();
314
if (!EditorNode::get_singleton()->call_build()) {
315
return;
316
}
317
318
EditorDebuggerNode::get_singleton()->start();
319
Error error = editor_run.run(run_filename, write_movie_file, p_run_args);
320
if (error != OK) {
321
EditorDebuggerNode::get_singleton()->stop();
322
EditorNode::get_singleton()->show_accept(TTR("Could not start subprocess(es)!"), TTR("OK"));
323
return;
324
}
325
326
_update_play_buttons();
327
stop_button->set_disabled(false);
328
329
emit_signal(SNAME("play_pressed"));
330
}
331
332
void EditorRunBar::_run_native(const Ref<EditorExportPreset> &p_preset) {
333
EditorNode::get_singleton()->try_autosave();
334
335
if (run_native->is_deploy_debug_remote_enabled()) {
336
stop_playing();
337
338
if (!EditorNode::get_singleton()->call_build()) {
339
return; // Build failed.
340
}
341
342
EditorDebuggerNode::get_singleton()->start(p_preset->get_platform()->get_debug_protocol());
343
emit_signal(SNAME("play_pressed"));
344
editor_run.run_native_notify();
345
}
346
}
347
348
void EditorRunBar::_profiler_autostart_indicator_pressed() {
349
// Switch to the first profiler tab in the bottom panel.
350
EditorNode::get_singleton()->get_bottom_panel()->make_item_visible(EditorDebuggerNode::get_singleton(), true);
351
352
if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_profiler", false)) {
353
EditorDebuggerNode::get_singleton()->get_current_debugger()->switch_to_debugger(3);
354
} else if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_visual_profiler", false)) {
355
EditorDebuggerNode::get_singleton()->get_current_debugger()->switch_to_debugger(4);
356
} else {
357
// Switch to the network profiler tab.
358
EditorDebuggerNode::get_singleton()->get_current_debugger()->switch_to_debugger(8);
359
}
360
}
361
362
void EditorRunBar::recovery_mode_show_dialog() {
363
recovery_mode_popup->popup_centered();
364
}
365
366
void EditorRunBar::recovery_mode_reload_project() {
367
EditorNode::get_singleton()->trigger_menu_option(EditorNode::PROJECT_RELOAD_CURRENT_PROJECT, false);
368
}
369
370
void EditorRunBar::play_main_scene(bool p_from_native) {
371
if (Engine::get_singleton()->is_recovery_mode_hint()) {
372
EditorToaster::get_singleton()->popup_str(TTR("Recovery Mode is enabled. Disable it to run the project."), EditorToaster::SEVERITY_WARNING);
373
return;
374
}
375
376
if (p_from_native) {
377
run_native->resume_run_native();
378
} else {
379
stop_playing();
380
381
current_mode = RunMode::RUN_MAIN;
382
_run_scene();
383
}
384
}
385
386
void EditorRunBar::play_current_scene(bool p_reload, const Vector<String> &p_play_args) {
387
if (Engine::get_singleton()->is_recovery_mode_hint()) {
388
EditorToaster::get_singleton()->popup_str(TTR("Recovery Mode is enabled. Disable it to run the project."), EditorToaster::SEVERITY_WARNING);
389
return;
390
}
391
392
String last_current_scene = run_current_filename; // This is necessary to have a copy of the string.
393
394
EditorNode::get_singleton()->save_default_environment();
395
stop_playing();
396
397
current_mode = RunMode::RUN_CURRENT;
398
if (p_reload) {
399
_run_scene(last_current_scene, p_play_args);
400
} else {
401
_run_scene("", p_play_args);
402
}
403
}
404
405
void EditorRunBar::play_custom_scene(const String &p_custom, const Vector<String> &p_play_args) {
406
if (Engine::get_singleton()->is_recovery_mode_hint()) {
407
EditorToaster::get_singleton()->popup_str(TTR("Recovery Mode is enabled. Disable it to run the project."), EditorToaster::SEVERITY_WARNING);
408
return;
409
}
410
411
stop_playing();
412
413
current_mode = RunMode::RUN_CUSTOM;
414
_run_scene(p_custom, p_play_args);
415
}
416
417
void EditorRunBar::stop_playing() {
418
if (editor_run.get_status() == EditorRun::STATUS_STOP) {
419
return;
420
}
421
422
current_mode = RunMode::STOPPED;
423
editor_run.stop();
424
EditorDebuggerNode::get_singleton()->stop();
425
426
run_custom_filename.clear();
427
run_current_filename.clear();
428
stop_button->set_pressed(false);
429
stop_button->set_disabled(true);
430
_reset_play_buttons();
431
432
emit_signal(SNAME("stop_pressed"));
433
}
434
435
bool EditorRunBar::is_playing() const {
436
EditorRun::Status status = editor_run.get_status();
437
return (status == EditorRun::STATUS_PLAY || status == EditorRun::STATUS_PAUSED);
438
}
439
440
String EditorRunBar::get_playing_scene() const {
441
String run_filename = editor_run.get_running_scene();
442
if (run_filename.is_empty() && is_playing()) {
443
run_filename = GLOBAL_GET("application/run/main_scene"); // Must be the main scene then.
444
}
445
446
return run_filename;
447
}
448
449
Error EditorRunBar::start_native_device(int p_device_id) {
450
return run_native->start_run_native(p_device_id);
451
}
452
453
OS::ProcessID EditorRunBar::has_child_process(OS::ProcessID p_pid) const {
454
return editor_run.has_child_process(p_pid);
455
}
456
457
void EditorRunBar::stop_child_process(OS::ProcessID p_pid) {
458
if (!has_child_process(p_pid)) {
459
return;
460
}
461
462
editor_run.stop_child_process(p_pid);
463
if (!editor_run.get_child_process_count()) { // All children stopped. Closing.
464
stop_playing();
465
}
466
}
467
468
OS::ProcessID EditorRunBar::get_current_process() const {
469
return editor_run.get_current_process();
470
}
471
472
void EditorRunBar::set_movie_maker_enabled(bool p_enabled) {
473
movie_maker_enabled = p_enabled;
474
write_movie_button->get_popup()->set_item_checked(0, p_enabled);
475
}
476
477
bool EditorRunBar::is_movie_maker_enabled() const {
478
return movie_maker_enabled;
479
}
480
481
void EditorRunBar::update_profiler_autostart_indicator() {
482
bool profiler_active = EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_profiler", false);
483
bool visual_profiler_active = EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_visual_profiler", false);
484
bool network_profiler_active = EditorSettings::get_singleton()->get_project_metadata("debug_options", "autostart_network_profiler", false);
485
bool any_profiler_active = profiler_active | visual_profiler_active | network_profiler_active;
486
any_profiler_active &= !Engine::get_singleton()->is_recovery_mode_hint();
487
profiler_autostart_indicator->set_visible(any_profiler_active);
488
if (any_profiler_active) {
489
String tooltip = TTR("Autostart is enabled for the following profilers, which can have a performance impact:");
490
if (profiler_active) {
491
tooltip += "\n- " + TTR("Profiler");
492
}
493
if (visual_profiler_active) {
494
tooltip += "\n- " + TTR("Visual Profiler");
495
}
496
if (network_profiler_active) {
497
tooltip += "\n- " + TTR("Network Profiler");
498
}
499
tooltip += "\n\n" + TTR("Click to open the first profiler for which autostart is enabled.");
500
profiler_autostart_indicator->set_tooltip_text(tooltip);
501
}
502
}
503
504
HBoxContainer *EditorRunBar::get_buttons_container() {
505
return main_hbox;
506
}
507
508
void EditorRunBar::_bind_methods() {
509
ADD_SIGNAL(MethodInfo("play_pressed"));
510
ADD_SIGNAL(MethodInfo("stop_pressed"));
511
}
512
513
EditorRunBar::EditorRunBar() {
514
singleton = this;
515
516
outer_hbox = memnew(HBoxContainer);
517
add_child(outer_hbox);
518
519
// Use a button for the indicator since it comes with a background panel and pixel perfect centering of an icon.
520
profiler_autostart_indicator = memnew(Button);
521
profiler_autostart_indicator->set_tooltip_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
522
profiler_autostart_indicator->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
523
profiler_autostart_indicator->set_focus_mode(FOCUS_ACCESSIBILITY);
524
profiler_autostart_indicator->set_theme_type_variation("ProfilerAutostartIndicator");
525
profiler_autostart_indicator->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::_profiler_autostart_indicator_pressed));
526
outer_hbox->add_child(profiler_autostart_indicator);
527
update_profiler_autostart_indicator();
528
529
main_panel = memnew(PanelContainer);
530
outer_hbox->add_child(main_panel);
531
532
main_hbox = memnew(HBoxContainer);
533
main_panel->add_child(main_hbox);
534
535
if (Engine::get_singleton()->is_recovery_mode_hint()) {
536
recovery_mode_popup = memnew(AcceptDialog);
537
recovery_mode_popup->set_min_size(Size2(550, 70) * EDSCALE);
538
recovery_mode_popup->set_title(TTR("Recovery Mode"));
539
recovery_mode_popup->set_text(
540
TTR("Godot opened the project in Recovery Mode, which is a special mode that can help recover projects that crash the engine upon initialization. The following features have been temporarily disabled:") +
541
String::utf8("\n\n• ") + TTR("Tool scripts") +
542
String::utf8("\n• ") + TTR("Editor plugins") +
543
String::utf8("\n• ") + TTR("GDExtension addons") +
544
String::utf8("\n• ") + TTR("Automatic scene restoring") +
545
String::utf8("\n\n") + TTR("If the project cannot be opened outside of this mode, then it's very likely any of these components is preventing this project from launching. This mode is intended only for basic editing to troubleshoot such issues, and therefore it is not possible to run a project in this mode.") +
546
String::utf8("\n\n") + TTR("To disable Recovery Mode, reload the project by pressing the Reload button next to the Recovery Mode banner, or by reopening the project normally."));
547
recovery_mode_popup->set_autowrap(true);
548
add_child(recovery_mode_popup);
549
550
recovery_mode_reload_button = memnew(Button);
551
main_hbox->add_child(recovery_mode_reload_button);
552
recovery_mode_reload_button->set_theme_type_variation("RunBarButton");
553
recovery_mode_reload_button->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
554
recovery_mode_reload_button->set_tooltip_text(TTR("Disable recovery mode and reload the project."));
555
recovery_mode_reload_button->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::recovery_mode_reload_project));
556
557
recovery_mode_panel = memnew(PanelContainer);
558
main_hbox->add_child(recovery_mode_panel);
559
560
recovery_mode_button = memnew(Button);
561
recovery_mode_panel->add_child(recovery_mode_button);
562
recovery_mode_button->set_theme_type_variation("RunBarButton");
563
recovery_mode_button->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
564
recovery_mode_button->set_text(TTR("Recovery Mode"));
565
recovery_mode_button->set_tooltip_text(TTR("Recovery Mode is enabled. Click for more details."));
566
recovery_mode_button->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::recovery_mode_show_dialog));
567
568
return;
569
}
570
571
play_button = memnew(Button);
572
main_hbox->add_child(play_button);
573
play_button->set_theme_type_variation("RunBarButton");
574
play_button->set_toggle_mode(true);
575
play_button->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
576
play_button->set_tooltip_text(TTRC("Run the project's default scene."));
577
play_button->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::play_main_scene).bind(false));
578
579
ED_SHORTCUT_AND_COMMAND("editor/run_project", TTRC("Run Project"), Key::F5);
580
ED_SHORTCUT_OVERRIDE("editor/run_project", "macos", KeyModifierMask::META | Key::B);
581
play_button->set_shortcut(ED_GET_SHORTCUT("editor/run_project"));
582
583
pause_button = memnew(Button);
584
main_hbox->add_child(pause_button);
585
pause_button->set_theme_type_variation("RunBarButton");
586
pause_button->set_toggle_mode(true);
587
pause_button->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
588
pause_button->set_tooltip_text(TTRC("Pause the running project's execution for debugging."));
589
pause_button->set_disabled(true);
590
591
ED_SHORTCUT("editor/pause_running_project", TTRC("Pause Running Project"), Key::F7);
592
ED_SHORTCUT_OVERRIDE("editor/pause_running_project", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::Y);
593
pause_button->set_shortcut(ED_GET_SHORTCUT("editor/pause_running_project"));
594
595
stop_button = memnew(Button);
596
main_hbox->add_child(stop_button);
597
stop_button->set_theme_type_variation("RunBarButton");
598
stop_button->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
599
stop_button->set_tooltip_text(TTRC("Stop the currently running project."));
600
stop_button->set_disabled(true);
601
stop_button->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::stop_playing));
602
603
ED_SHORTCUT("editor/stop_running_project", TTRC("Stop Running Project"), Key::F8);
604
ED_SHORTCUT_OVERRIDE("editor/stop_running_project", "macos", KeyModifierMask::META | Key::PERIOD);
605
stop_button->set_shortcut(ED_GET_SHORTCUT("editor/stop_running_project"));
606
607
run_native = memnew(EditorRunNative);
608
main_hbox->add_child(run_native);
609
run_native->connect("native_run", callable_mp(this, &EditorRunBar::_run_native));
610
611
bool add_play_xr_mode_options = false;
612
#ifndef XR_DISABLED
613
if (XRServer::get_xr_mode() == XRServer::XRMODE_ON ||
614
(XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT && GLOBAL_GET("xr/openxr/enabled"))) {
615
// If OpenXR is enabled, we turn the `play_scene_button` and
616
// `play_custom_scene_button` into MenuButtons to provide the option to start a scene in
617
// either regular mode or XR mode.
618
add_play_xr_mode_options = true;
619
}
620
#endif // XR_DISABLED
621
622
if (add_play_xr_mode_options) {
623
MenuButton *menu_button = memnew(MenuButton);
624
PopupMenu *popup = menu_button->get_popup();
625
popup->add_item(TTRC("Run Scene in Regular Mode"), 0);
626
popup->add_item(TTRC("Run Scene in XR Mode"), 1);
627
popup->connect(SceneStringName(id_pressed), callable_mp(this, &EditorRunBar::_play_current_pressed));
628
play_scene_button = menu_button;
629
} else {
630
play_scene_button = memnew(Button);
631
play_scene_button->set_toggle_mode(true);
632
play_scene_button->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::_play_current_pressed).bind(-1));
633
}
634
main_hbox->add_child(play_scene_button);
635
play_scene_button->set_theme_type_variation("RunBarButton");
636
play_scene_button->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
637
play_scene_button->set_tooltip_text(TTRC("Run the currently edited scene."));
638
639
ED_SHORTCUT_AND_COMMAND("editor/run_current_scene", TTRC("Run Current Scene"), Key::F6);
640
ED_SHORTCUT_OVERRIDE("editor/run_current_scene", "macos", KeyModifierMask::META | Key::R);
641
play_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_current_scene"));
642
643
if (add_play_xr_mode_options) {
644
MenuButton *menu_button = memnew(MenuButton);
645
PopupMenu *popup = menu_button->get_popup();
646
popup->add_item(TTRC("Run in Regular Mode"), 0);
647
popup->add_item(TTRC("Run in XR Mode"), 1);
648
popup->connect(SceneStringName(id_pressed), callable_mp(this, &EditorRunBar::_play_custom_pressed));
649
play_custom_scene_button = menu_button;
650
} else {
651
play_custom_scene_button = memnew(Button);
652
play_custom_scene_button->set_toggle_mode(true);
653
play_custom_scene_button->connect(SceneStringName(pressed), callable_mp(this, &EditorRunBar::_play_custom_pressed).bind(-1));
654
}
655
main_hbox->add_child(play_custom_scene_button);
656
play_custom_scene_button->set_theme_type_variation("RunBarButton");
657
play_custom_scene_button->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
658
play_custom_scene_button->set_tooltip_text(TTRC("Run a specific scene."));
659
660
ED_SHORTCUT_AND_COMMAND("editor/run_specific_scene", TTRC("Run Specific Scene"), KeyModifierMask::CTRL | KeyModifierMask::SHIFT | Key::F5);
661
ED_SHORTCUT_OVERRIDE("editor/run_specific_scene", "macos", KeyModifierMask::META | KeyModifierMask::SHIFT | Key::R);
662
play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/run_specific_scene"));
663
664
write_movie_panel = memnew(PanelContainer);
665
main_hbox->add_child(write_movie_panel);
666
667
write_movie_button = memnew(MenuButton);
668
PopupMenu *write_movie_popup = write_movie_button->get_popup();
669
write_movie_popup->add_check_item(TTRC("Enable Movie Maker Mode"), MOVIE_MAKER_TOGGLE);
670
write_movie_popup->add_item(TTRC("Open Movie Maker Settings..."), MOVIE_MAKER_OPEN_SETTINGS);
671
write_movie_popup->connect(SceneStringName(id_pressed), callable_mp(this, &EditorRunBar::_movie_maker_item_pressed));
672
673
write_movie_panel->add_child(write_movie_button);
674
write_movie_button->set_theme_type_variation("RunBarButtonMovieMakerDisabled");
675
write_movie_button->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
676
write_movie_button->set_tooltip_text(TTRC("Enable Movie Maker mode.\nThe project will run at stable FPS and the visual and audio output will be recorded to a video file."));
677
write_movie_button->set_accessibility_name(TTRC("Enable Movie Maker Mode"));
678
}
679
680