summaryrefslogtreecommitdiff
path: root/editor/editor_node.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/editor_node.cpp')
-rw-r--r--editor/editor_node.cpp131
1 files changed, 92 insertions, 39 deletions
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index c59c7de603..9b0ac305d1 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -582,9 +582,10 @@ void EditorNode::_notification(int p_what) {
opening_prev = false;
}
+ bool unsaved_cache_changed = false;
if (unsaved_cache != (saved_version != editor_data.get_undo_redo().get_version())) {
unsaved_cache = (saved_version != editor_data.get_undo_redo().get_version());
- _update_title();
+ unsaved_cache_changed = true;
}
if (last_checked_version != editor_data.get_undo_redo().get_version()) {
@@ -615,6 +616,10 @@ void EditorNode::_notification(int p_what) {
ResourceImporterTexture::get_singleton()->update_imports();
+ if (settings_changed || unsaved_cache_changed) {
+ _update_title();
+ }
+
if (settings_changed) {
_update_from_settings();
settings_changed = false;
@@ -876,7 +881,7 @@ void EditorNode::_resources_changed(const Vector<String> &p_resources) {
int rc = p_resources.size();
for (int i = 0; i < rc; i++) {
- Ref<Resource> res(ResourceCache::get(p_resources.get(i)));
+ Ref<Resource> res = ResourceCache::get_ref(p_resources.get(i));
if (res.is_null()) {
continue;
}
@@ -968,21 +973,14 @@ void EditorNode::_fs_changed() {
ERR_PRINT(vformat("Cannot export project with preset \"%s\" due to configuration errors:\n%s", preset_name, config_error));
err = missing_templates ? ERR_FILE_NOT_FOUND : ERR_UNCONFIGURED;
} else {
+ platform->clear_messages();
err = platform->export_project(export_preset, export_defer.debug, export_path);
}
}
- switch (err) {
- case OK:
- break;
- case ERR_FILE_NOT_FOUND:
- export_error = vformat("Project export failed for preset \"%s\". The export template appears to be missing.", preset_name);
- break;
- case ERR_FILE_BAD_PATH:
- export_error = vformat("Project export failed for preset \"%s\". The target path \"%s\" appears to be invalid.", preset_name, export_path);
- break;
- default:
- export_error = vformat("Project export failed with error code %d for preset \"%s\".", (int)err, preset_name);
- break;
+ if (err != OK) {
+ export_error = vformat("Project export for preset \"%s\" failed.", preset_name);
+ } else if (platform->get_worst_message_type() >= EditorExportPlatform::EXPORT_MESSAGE_WARNING) {
+ export_error = vformat("Project export for preset \"%s\" completed with errors.", preset_name);
}
}
}
@@ -1013,8 +1011,8 @@ void EditorNode::_resources_reimported(const Vector<String> &p_resources) {
continue;
}
// Reload normally.
- Resource *resource = ResourceCache::get(p_resources[i]);
- if (resource) {
+ Ref<Resource> resource = ResourceCache::get_ref(p_resources[i]);
+ if (resource.is_valid()) {
resource->reload_from_file();
}
}
@@ -1727,7 +1725,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
// We must update it, but also let the previous scene state go, as
// old version still work for referencing changes in instantiated or inherited scenes.
- sdata = Ref<PackedScene>(Object::cast_to<PackedScene>(ResourceCache::get(p_file)));
+ sdata = ResourceCache::get_ref(p_file);
if (sdata.is_valid()) {
sdata->recreate_state();
} else {
@@ -1799,6 +1797,10 @@ void EditorNode::save_scene_list(Vector<String> p_scene_filenames) {
void EditorNode::restart_editor() {
exiting = true;
+ if (editor_run.get_status() != EditorRun::STATUS_STOP) {
+ editor_run.stop();
+ }
+
String to_reopen;
if (get_tree()->get_edited_scene_root()) {
to_reopen = get_tree()->get_edited_scene_root()->get_scene_file_path();
@@ -2345,6 +2347,20 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
return;
}
+ String write_movie_file;
+ if (write_movie_button->is_pressed()) {
+ if (p_current && get_tree()->get_edited_scene_root() && get_tree()->get_edited_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 = get_tree()->get_edited_scene_root()->get_meta("movie_file");
+ } else {
+ write_movie_file = GLOBAL_GET("editor/movie_writer/movie_file");
+ }
+ if (write_movie_file == String()) {
+ 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_path' 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;
+ }
+ }
+
play_button->set_pressed(false);
play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
play_scene_button->set_pressed(false);
@@ -2408,7 +2424,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
}
EditorDebuggerNode::get_singleton()->start();
- Error error = editor_run.run(run_filename);
+ Error error = editor_run.run(run_filename, write_movie_file);
if (error != OK) {
EditorDebuggerNode::get_singleton()->stop();
show_accept(TTR("Could not start subprocess(es)!"), TTR("OK"));
@@ -2791,6 +2807,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case RUN_SETTINGS: {
project_settings_editor->popup_project_settings();
} break;
+ case RUN_WRITE_MOVIE: {
+ _update_write_movie_icon();
+ } break;
case FILE_INSTALL_ANDROID_SOURCE: {
if (p_confirmed) {
export_template_manager->install_android_template();
@@ -3306,33 +3325,39 @@ void EditorNode::_update_addon_config() {
}
void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled, bool p_config_changed) {
- ERR_FAIL_COND(p_enabled && addon_name_to_plugin.has(p_addon));
- ERR_FAIL_COND(!p_enabled && !addon_name_to_plugin.has(p_addon));
+ String addon_path = p_addon;
+
+ if (!addon_path.begins_with("res://")) {
+ addon_path = "res://addons/" + addon_path + "/plugin.cfg";
+ }
+
+ ERR_FAIL_COND(p_enabled && addon_name_to_plugin.has(addon_path));
+ ERR_FAIL_COND(!p_enabled && !addon_name_to_plugin.has(addon_path));
if (!p_enabled) {
- EditorPlugin *addon = addon_name_to_plugin[p_addon];
+ EditorPlugin *addon = addon_name_to_plugin[addon_path];
remove_editor_plugin(addon, p_config_changed);
memdelete(addon);
- addon_name_to_plugin.erase(p_addon);
+ addon_name_to_plugin.erase(addon_path);
_update_addon_config();
return;
}
Ref<ConfigFile> cf;
cf.instantiate();
- if (!DirAccess::exists(p_addon.get_base_dir())) {
- _remove_plugin_from_enabled(p_addon);
- WARN_PRINT("Addon '" + p_addon + "' failed to load. No directory found. Removing from enabled plugins.");
+ if (!DirAccess::exists(addon_path.get_base_dir())) {
+ _remove_plugin_from_enabled(addon_path);
+ WARN_PRINT("Addon '" + addon_path + "' failed to load. No directory found. Removing from enabled plugins.");
return;
}
- Error err = cf->load(p_addon);
+ Error err = cf->load(addon_path);
if (err != OK) {
- show_warning(vformat(TTR("Unable to enable addon plugin at: '%s' parsing of config failed."), p_addon));
+ show_warning(vformat(TTR("Unable to enable addon plugin at: '%s' parsing of config failed."), addon_path));
return;
}
if (!cf->has_section_key("plugin", "script")) {
- show_warning(vformat(TTR("Unable to find script field for addon plugin at: '%s'."), p_addon));
+ show_warning(vformat(TTR("Unable to find script field for addon plugin at: '%s'."), addon_path));
return;
}
@@ -3341,7 +3366,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
// Only try to load the script if it has a name. Else, the plugin has no init script.
if (script_path.length() > 0) {
- script_path = p_addon.get_base_dir().plus_file(script_path);
+ script_path = addon_path.get_base_dir().plus_file(script_path);
script = ResourceLoader::load(script_path);
if (script.is_null()) {
@@ -3351,8 +3376,8 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
// Errors in the script cause the base_type to be an empty StringName.
if (script->get_instance_base_type() == StringName()) {
- show_warning(vformat(TTR("Unable to load addon script from path: '%s'. This might be due to a code error in that script.\nDisabling the addon at '%s' to prevent further errors."), script_path, p_addon));
- _remove_plugin_from_enabled(p_addon);
+ show_warning(vformat(TTR("Unable to load addon script from path: '%s'. This might be due to a code error in that script.\nDisabling the addon at '%s' to prevent further errors."), script_path, addon_path));
+ _remove_plugin_from_enabled(addon_path);
return;
}
@@ -3370,14 +3395,18 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
EditorPlugin *ep = memnew(EditorPlugin);
ep->set_script(script);
- addon_name_to_plugin[p_addon] = ep;
+ addon_name_to_plugin[addon_path] = ep;
add_editor_plugin(ep, p_config_changed);
_update_addon_config();
}
bool EditorNode::is_addon_plugin_enabled(const String &p_addon) const {
- return addon_name_to_plugin.has(p_addon);
+ if (p_addon.begins_with("res://")) {
+ return addon_name_to_plugin.has(p_addon);
+ }
+
+ return addon_name_to_plugin.has("res://addons/" + p_addon + "/plugin.cfg");
}
void EditorNode::_remove_edited_scene(bool p_change_tab) {
@@ -3688,7 +3717,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
if (ResourceCache::has(lpath)) {
// Used from somewhere else? No problem! Update state and replace sdata.
- Ref<PackedScene> ps = Ref<PackedScene>(Object::cast_to<PackedScene>(ResourceCache::get(lpath)));
+ Ref<PackedScene> ps = ResourceCache::get_ref(lpath);
if (ps.is_valid()) {
ps->replace_state(sdata->get_state());
ps->set_last_modified_time(sdata->get_last_modified_time());
@@ -4870,7 +4899,7 @@ bool EditorNode::has_scenes_in_session() {
bool EditorNode::ensure_main_scene(bool p_from_native) {
pick_main_scene->set_meta("from_native", p_from_native); // Whether from play button or native run.
- String main_scene = GLOBAL_DEF("application/run/main_scene", "");
+ String main_scene = GLOBAL_DEF_BASIC("application/run/main_scene", "");
if (main_scene.is_empty()) {
current_menu_option = -1;
@@ -4936,12 +4965,20 @@ bool EditorNode::is_run_playing() const {
String EditorNode::get_run_playing_scene() const {
String run_filename = editor_run.get_running_scene();
if (run_filename.is_empty() && is_run_playing()) {
- run_filename = GLOBAL_DEF("application/run/main_scene", ""); // Must be the main scene then.
+ run_filename = GLOBAL_DEF_BASIC("application/run/main_scene", ""); // Must be the main scene then.
}
return run_filename;
}
+void EditorNode::_update_write_movie_icon() {
+ if (write_movie_button->is_pressed()) {
+ write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWriteEnabled"), SNAME("EditorIcons")));
+ } else {
+ write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWrite"), SNAME("EditorIcons")));
+ }
+}
+
void EditorNode::_immediate_dialog_confirmed() {
immediate_dialog_confirmed = true;
}
@@ -6109,8 +6146,8 @@ EditorNode::EditorNode() {
EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "Script,MeshLibrary");
EDITOR_DEF("interface/inspector/default_color_picker_mode", 0);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW", PROPERTY_USAGE_DEFAULT));
- EDITOR_DEF("interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_VHS_CIRCLE);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle", PROPERTY_USAGE_DEFAULT));
+ EDITOR_DEF("interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_OKHSL_CIRCLE);
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle", PROPERTY_USAGE_DEFAULT));
ED_SHORTCUT("canvas_item_editor/pan_view", TTR("Pan View"), Key::SPACE);
@@ -6697,6 +6734,23 @@ EditorNode::EditorNode() {
ED_SHORTCUT_OVERRIDE("editor/play_custom_scene", "macos", KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::R);
play_custom_scene_button->set_shortcut(ED_GET_SHORTCUT("editor/play_custom_scene"));
+ write_movie_button = memnew(Button);
+ write_movie_button->set_flat(true);
+ write_movie_button->set_toggle_mode(true);
+ play_hb->add_child(write_movie_button);
+ write_movie_button->set_pressed(false);
+ write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWrite"), SNAME("EditorIcons")));
+ write_movie_button->set_focus_mode(Control::FOCUS_NONE);
+ write_movie_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(RUN_WRITE_MOVIE));
+ write_movie_button->set_tooltip(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."));
+ // Restore these values to something more useful so it ignores the theme
+ write_movie_button->add_theme_color_override("icon_normal_color", Color(1, 1, 1, 0.4));
+ write_movie_button->add_theme_color_override("icon_pressed_color", Color(1, 1, 1, 1));
+ write_movie_button->add_theme_color_override("icon_hover_color", Color(1.2, 1.2, 1.2, 0.4));
+ write_movie_button->add_theme_color_override("icon_hover_pressed_color", Color(1.2, 1.2, 1.2, 1));
+ write_movie_button->add_theme_color_override("icon_focus_color", Color(1, 1, 1, 1));
+ write_movie_button->add_theme_color_override("icon_disabled_color", Color(1, 1, 1, 0.4));
+
HBoxContainer *right_menu_hb = memnew(HBoxContainer);
menu_hb->add_child(right_menu_hb);
@@ -7047,7 +7101,6 @@ EditorNode::EditorNode() {
add_editor_plugin(VersionControlEditorPlugin::get_singleton());
add_editor_plugin(memnew(ShaderEditorPlugin));
add_editor_plugin(memnew(ShaderFileEditorPlugin));
- add_editor_plugin(memnew(VisualShaderEditorPlugin));
add_editor_plugin(memnew(Camera3DEditorPlugin));
add_editor_plugin(memnew(ThemeEditorPlugin));