diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml index 4836f48a57b..c1e28ffba34 100644 --- a/doc/classes/AcceptDialog.xml +++ b/doc/classes/AcceptDialog.xml @@ -61,6 +61,8 @@ Sets autowrapping for the text in the dialog. + + If [code]true[/code], the dialog is hidden when the OK button is pressed. You can set it to [code]false[/code] if you want to do e.g. input validation when receiving the [signal confirmed] signal, and handle hiding the dialog in your own logic. [b]Note:[/b] Some nodes derived from this class can have a different default value, and potentially their own built-in logic overriding this setting. For example [FileDialog] defaults to [code]false[/code], and has its own input validation code that is called when you press OK, which eventually hides the dialog if the input is valid. As such, this property can't be used in [FileDialog] to disable hiding the dialog when pressing OK. diff --git a/doc/classes/EditorFileSystemImportFormatSupportQuery.xml b/doc/classes/EditorFileSystemImportFormatSupportQuery.xml new file mode 100644 index 00000000000..8431a3a7ef2 --- /dev/null +++ b/doc/classes/EditorFileSystemImportFormatSupportQuery.xml @@ -0,0 +1,31 @@ + + + + Used to query and configure import format support. + + + This class is used to query and configure a certain import format. It is used in conjuntion with asset format import plugins. + + + + + + + + Return the file extensions supported. + + + + + + Return whether this importer is active. + + + + + + Query support. Return false if import must not continue. + + + + diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 44b16de0cfb..5e43c4a4cfa 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -553,9 +553,9 @@ Search path for project-specific script templates. Godot will search for script templates both in the editor-specific path and in this project-specific path. - + If [code]true[/code], Blender 3D scene files with the [code].blend[/code] extension will be imported by converting them to glTF 2.0. - This requires configuring a path to a Blender executable in the editor settings at [code]filesystem/import/blend/blender_path[/code]. Blender 3.0 or later is required. + This requires configuring a path to a Blender executable in the editor settings at [code]filesystem/import/blender/blender3_path[/code]. Blender 3.0 or later is required. If [code]true[/code], Autodesk FBX 3D scene files with the [code].fbx[/code] extension will be imported by converting them to glTF 2.0. diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index f3d9449c6cb..2b98a4b02ac 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -520,6 +520,45 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo return false; //nothing changed } +bool EditorFileSystem::_scan_import_support(Vector reimports) { + if (import_support_queries.size() == 0) { + return false; + } + Map import_support_test; + Vector import_support_tested; + import_support_tested.resize(import_support_queries.size()); + for (int i = 0; i < import_support_queries.size(); i++) { + import_support_tested.write[i] = false; + if (import_support_queries[i]->is_active()) { + Vector extensions = import_support_queries[i]->get_file_extensions(); + for (int j = 0; j < extensions.size(); j++) { + import_support_test.insert(extensions[j], i); + } + } + } + + if (import_support_test.size() == 0) { + return false; //well nothing to do + } + + for (int i = 0; i < reimports.size(); i++) { + Map::Element *E = import_support_test.find(reimports[i].get_extension()); + if (E) { + import_support_tested.write[E->get()] = true; + } + } + + for (int i = 0; i < import_support_tested.size(); i++) { + if (import_support_tested[i]) { + if (import_support_queries.write[i]->query()) { + return true; + } + } + } + + return false; +} + bool EditorFileSystem::_update_scan_actions() { sources_changed.clear(); @@ -612,7 +651,7 @@ bool EditorFileSystem::_update_scan_actions() { if (_scan_extensions()) { //needs editor restart //extensions also may provide filetypes to be imported, so they must run before importing - if (EditorNode::immediate_confirmation_dialog(TTR("Some extensions need the editor to restart to take effect."), first_scan ? TTR("Restart") : TTR("Save&Restart"), TTR("Continue"))) { + if (EditorNode::immediate_confirmation_dialog(TTR("Some extensions need the editor to restart to take effect."), first_scan ? TTR("Restart") : TTR("Save & Restart"), TTR("Continue"))) { if (!first_scan) { EditorNode::get_singleton()->save_all_scenes(); } @@ -621,7 +660,12 @@ bool EditorFileSystem::_update_scan_actions() { return true; } } + if (reimports.size()) { + if (_scan_import_support(reimports)) { + return true; + } + reimport_files(reimports); } else { //reimport files will update the uid cache file so if nothing was reimported, update it manually @@ -2274,6 +2318,7 @@ static void _scan_extensions_dir(EditorFileSystemDirectory *d, Set &exte bool EditorFileSystem::_scan_extensions() { EditorFileSystemDirectory *d = get_filesystem(); Set extensions; + _scan_extensions_dir(d, extensions); //verify against loaded extensions @@ -2374,6 +2419,14 @@ void EditorFileSystem::_update_extensions() { } } +void EditorFileSystem::add_import_format_support_query(Ref p_query) { + ERR_FAIL_COND(import_support_queries.find(p_query) != -1); + import_support_queries.push_back(p_query); +} +void EditorFileSystem::remove_import_format_support_query(Ref p_query) { + import_support_queries.erase(p_query); +} + EditorFileSystem::EditorFileSystem() { ResourceLoader::import = _resource_import; reimport_on_missing_imported_files = GLOBAL_DEF("editor/import/reimport_missing_imported_files", true); diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 0ec00940304..0ddac658391 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -109,6 +109,37 @@ public: ~EditorFileSystemDirectory(); }; +class EditorFileSystemImportFormatSupportQuery : public RefCounted { + GDCLASS(EditorFileSystemImportFormatSupportQuery, RefCounted); + +protected: + GDVIRTUAL0RC(bool, _is_active) + GDVIRTUAL0RC(Vector, _get_file_extensions) + GDVIRTUAL0RC(bool, _query) + static void _bind_methods() { + GDVIRTUAL_BIND(_is_active); + GDVIRTUAL_BIND(_get_file_extensions); + GDVIRTUAL_BIND(_query); + } + +public: + virtual bool is_active() const { + bool ret = false; + GDVIRTUAL_REQUIRED_CALL(_is_active, ret); + return ret; + } + virtual Vector get_file_extensions() const { + Vector ret; + GDVIRTUAL_REQUIRED_CALL(_get_file_extensions, ret); + return ret; + } + virtual bool query() { + bool ret = false; + GDVIRTUAL_REQUIRED_CALL(_query, ret); + return ret; + } +}; + class EditorFileSystem : public Node { GDCLASS(EditorFileSystem, Node); @@ -257,6 +288,9 @@ class EditorFileSystem : public Node { static ResourceUID::ID _resource_saver_get_resource_id_for_path(const String &p_path, bool p_generate); bool _scan_extensions(); + bool _scan_import_support(Vector reimports); + + Vector> import_support_queries; protected: void _notification(int p_what); @@ -289,6 +323,8 @@ public: static bool _should_skip_directory(const String &p_path); + void add_import_format_support_query(Ref p_query); + void remove_import_format_support_query(Ref p_query); EditorFileSystem(); ~EditorFileSystem(); }; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 25e3bc8d6a4..52f7366dd7e 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -3920,6 +3920,7 @@ void EditorNode::register_editor_types() { GDREGISTER_CLASS(EditorScriptPicker); GDREGISTER_ABSTRACT_CLASS(FileSystemDock); + GDREGISTER_VIRTUAL_CLASS(EditorFileSystemImportFormatSupportQuery); GDREGISTER_CLASS(EditorScenePostImport); GDREGISTER_CLASS(EditorCommandPalette); diff --git a/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml b/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml index 9c6c8e03c41..ca8eb9854f2 100644 --- a/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml +++ b/modules/gltf/doc_classes/EditorSceneFormatImporterBlend.xml @@ -5,8 +5,8 @@ Imports Blender scenes in the [code].blend[/code] file format through the glTF 2.0 3D import pipeline. This importer requires Blender to be installed by the user, so that it can be used to export the scene as glTF 2.0. - The location of the Blender binary is set via the [code]filesystem/import/blend/blender_path[/code] editor setting. - This importer is only used if [member ProjectSettings.filesystem/import/blend/enabled] is enabled, otherwise [code].blend[/code] files present in the project folder are not imported. + The location of the Blender binary is set via the [code]filesystem/import/blender/blender3_path[/code] editor setting. + This importer is only used if [member ProjectSettings.filesystem/import/blender/enabled] is enabled, otherwise [code].blend[/code] files present in the project folder are not imported. Blend import requires Blender 3.0. Internally, the EditorSceneFormatImporterBlend uses the Blender glTF "Use Original" mode to reference external textures. diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 2587c095e1d..e3f66412742 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -30,16 +30,25 @@ #include "editor_scene_importer_blend.h" -#if TOOLS_ENABLED +#ifdef TOOLS_ENABLED #include "../gltf_document.h" #include "../gltf_state.h" #include "core/config/project_settings.h" +#include "editor/editor_file_dialog.h" +#include "editor/editor_node.h" +#include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "main/main.h" #include "scene/main/node.h" #include "scene/resources/animation.h" +#ifdef WINDOWS_ENABLED +// Code by Pedro Estebanez (https://github.com/godotengine/godot/pull/59766) +#include +#endif + uint32_t EditorSceneFormatImporterBlend::get_import_flags() const { return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION; } @@ -169,7 +178,13 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ // Run script with configured Blender binary. - String blender_path = EDITOR_GET("filesystem/import/blend/blender_path"); + String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path"); + +#ifdef WINDOWS_ENABLED + blender_path = blender_path.plus_file("blender.exe"); +#else + blender_path = blender_path.plus_file("blender"); +#endif List args; args.push_back("--background"); @@ -252,4 +267,294 @@ void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, Li #undef ADD_OPTION_ENUM } +/////////////////////////// + +static bool _test_blender_path(const String &p_path, String *r_err = nullptr) { + String path = p_path; +#ifdef WINDOWS_ENABLED + path = path.plus_file("blender.exe"); +#else + path = path.plus_file("blender"); +#endif + +#if defined(OSX_ENABLED) + if (!FileAccess::exists(path)) { + path = path.plus_file("Blender"); + } +#endif + + if (!FileAccess::exists(path)) { + if (r_err) { + *r_err = TTR("Path does not contain a Blender installation."); + } + return false; + } + List args; + args.push_back("--version"); + String pipe; + Error err = OS::get_singleton()->execute(path, args, &pipe); + if (err != OK) { + if (r_err) { + *r_err = TTR("Can't excecute Blender binary."); + } + return false; + } + + if (pipe.find("Blender ") != 0) { + if (r_err) { + *r_err = vformat(TTR("Unexpected --version output from Blender binary at: %s"), path); + } + return false; + } + pipe = pipe.replace_first("Blender ", ""); + int pp = pipe.find("."); + if (pp == -1) { + if (r_err) { + *r_err = TTR("Path supplied lacks a Blender binary."); + } + return false; + } + String v = pipe.substr(0, pp); + int version = v.to_int(); + if (version < 3) { + if (r_err) { + *r_err = TTR("This Blender installation is too old for this importer (not 3.0+)."); + } + return false; + } + if (version > 3) { + if (r_err) { + *r_err = TTR("This Blender installation is too new for this importer (not 3.x)."); + } + return false; + } + + return true; +} + +bool EditorFileSystemImportFormatSupportQueryBlend::is_active() const { + bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled"); + + String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path"); + + if (blend_enabled && !_test_blender_path(blender_path)) { + // Intending to import Blender, but blend not configured. + return true; + } + + return false; +} +Vector EditorFileSystemImportFormatSupportQueryBlend::get_file_extensions() const { + Vector ret; + ret.push_back("blend"); + return ret; +} + +void EditorFileSystemImportFormatSupportQueryBlend::_validate_path(String p_path) { + String error; + bool success = false; + if (p_path == "") { + error = TTR("Path is empty."); + } else { + if (_test_blender_path(p_path, &error)) { + success = true; + if (auto_detected_path == p_path) { + error = TTR("Path to Blender installation is valid (Autodetected)."); + } else { + error = TTR("Path to Blender installation is valid."); + } + } + } + + path_status->set_text(error); + + if (success) { + path_status->add_theme_color_override("font_color", path_status->get_theme_color(SNAME("success_color"), SNAME("Editor"))); + configure_blender_dialog->get_ok_button()->set_disabled(false); + } else { + path_status->add_theme_color_override("font_color", path_status->get_theme_color(SNAME("error_color"), SNAME("Editor"))); + configure_blender_dialog->get_ok_button()->set_disabled(true); + } +} + +bool EditorFileSystemImportFormatSupportQueryBlend::_autodetect_path(String p_path) { + if (_test_blender_path(p_path)) { + auto_detected_path = p_path; + return true; + } + return false; +} + +void EditorFileSystemImportFormatSupportQueryBlend::_path_confirmed() { + confirmed = true; +} + +void EditorFileSystemImportFormatSupportQueryBlend::_select_install(String p_path) { + blender_path->set_text(p_path); + _validate_path(p_path); +} +void EditorFileSystemImportFormatSupportQueryBlend::_browse_install() { + if (blender_path->get_text() != String()) { + browse_dialog->set_current_dir(blender_path->get_text()); + } + + browse_dialog->popup_centered_ratio(); +} + +bool EditorFileSystemImportFormatSupportQueryBlend::query() { + if (!configure_blender_dialog) { + configure_blender_dialog = memnew(ConfirmationDialog); + configure_blender_dialog->set_title(TTR("Configure Blender Importer")); + configure_blender_dialog->set_flag(Window::FLAG_BORDERLESS, true); // Avoid closing accidentally . + configure_blender_dialog->set_close_on_escape(false); + + VBoxContainer *vb = memnew(VBoxContainer); + vb->add_child(memnew(Label(TTR("Blender 3.0+ is required to import '.blend' files.\nPlease provide a valid path to a Blender installation:")))); + + HBoxContainer *hb = memnew(HBoxContainer); + + blender_path = memnew(LineEdit); + blender_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hb->add_child(blender_path); + blender_path_browse = memnew(Button); + hb->add_child(blender_path_browse); + blender_path_browse->set_text(TTR("Browse")); + blender_path_browse->connect("pressed", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_browse_install)); + hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hb->set_custom_minimum_size(Size2(400 * EDSCALE, 0)); + + vb->add_child(hb); + + path_status = memnew(Label); + vb->add_child(path_status); + + configure_blender_dialog->add_child(vb); + + blender_path->connect("text_changed", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_validate_path)); + + EditorNode::get_singleton()->get_gui_base()->add_child(configure_blender_dialog); + + configure_blender_dialog->get_ok_button()->set_text(TTR("Confirm Path")); + configure_blender_dialog->get_cancel_button()->set_text(TTR("Disable '.blend' Import")); + configure_blender_dialog->get_cancel_button()->set_tooltip(TTR("Disables Blender '.blend' files import for this project. Can be re-enabled in Project Settings.")); + configure_blender_dialog->connect("confirmed", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_path_confirmed)); + + browse_dialog = memnew(EditorFileDialog); + browse_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + browse_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR); + browse_dialog->connect("dir_selected", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_select_install)); + + EditorNode::get_singleton()->get_gui_base()->add_child(browse_dialog); + } + + String path = EDITOR_GET("filesystem/import/blender/blender3_path"); + + if (path == "") { + // Autodetect + auto_detected_path = ""; + +#if defined(OSX_ENABLED) + + { + Vector mdfind_paths; + { + List mdfind_args; + mdfind_args.push_back("kMDItemCFBundleIdentifier=org.blenderfoundation.blender"); + + String output; + Error err = OS::get_singleton()->execute("mdfind", mdfind_args, &output); + if (err == OK) { + mdfind_paths = output.split("\n"); + } + } + + bool found = false; + for (const String &path : mdfind_paths) { + found = _autodetect_path(path.plus_file("Contents/MacOS")); + if (found) { + break; + } + } + if (!found) { + found = _autodetect_path("/opt/homebrew/bin"); + } + if (!found) { + found = _autodetect_path("/opt/local/bin"); + } + if (!found) { + found = _autodetect_path("/usr/local/bin"); + } + if (!found) { + found = _autodetect_path("/usr/local/opt"); + } + if (!found) { + found = _autodetect_path("/Applications/Blender.app/Contents/MacOS"); + } + } +#elif defined(WINDOWS_ENABLED) + { + char blender_opener_path[MAX_PATH]; + DWORD path_len = MAX_PATH; + HRESULT res = AssocQueryString(0, ASSOCSTR_EXECUTABLE, ".blend", "open", blender_opener_path, &path_len); + if (res == S_OK && _autodetect_path(String(blender_opener_path).get_base_dir())) { + // Good. + } else if (_autodetect_path("C:\\Program Files\\Blender Foundation")) { + // Good. + } else { + _autodetect_path("C:\\Program Files (x86)\\Blender Foundation"); + } + } + +#elif defined(UNIX_ENABLED) + if (_autodetect_path("/usr/bin")) { + // Good. + } else if (_autodetect_path("/usr/local/bin")) { + // Good + } else { + _autodetect_path("/opt/blender/bin"); + } +#endif + if (auto_detected_path != "") { + path = auto_detected_path; + } + } + + blender_path->set_text(path); + + _validate_path(path); + + configure_blender_dialog->popup_centered(); + confirmed = false; + + while (true) { + OS::get_singleton()->delay_usec(1); + DisplayServer::get_singleton()->process_events(); + Main::iteration(); + if (!configure_blender_dialog->is_visible() || confirmed) { + break; + } + } + + if (confirmed) { + // Can only confirm a valid path. + EditorSettings::get_singleton()->set("filesystem/import/blender/blender3_path", blender_path->get_text()); + EditorSettings::get_singleton()->save(); + } else { + // Disable Blender import + ProjectSettings::get_singleton()->set("filesystem/import/blender/enabled", false); + ProjectSettings::get_singleton()->save(); + + if (EditorNode::immediate_confirmation_dialog(TTR("Disabling '.blend' file import requires restarting the editor."), TTR("Save & Restart"), TTR("Restart"))) { + EditorNode::get_singleton()->save_all_scenes(); + } + EditorNode::get_singleton()->restart_editor(); + return true; + } + + return false; +} + +EditorFileSystemImportFormatSupportQueryBlend::EditorFileSystemImportFormatSupportQueryBlend() { +} + #endif // TOOLS_ENABLED diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h index 4bdf4c93a2f..bba0e01403d 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.h +++ b/modules/gltf/editor/editor_scene_importer_blend.h @@ -33,10 +33,12 @@ #ifdef TOOLS_ENABLED +#include "editor/editor_file_system.h" #include "editor/import/resource_importer_scene.h" class Animation; class Node; +class ConfirmationDialog; class EditorSceneFormatImporterBlend : public EditorSceneFormatImporter { GDCLASS(EditorSceneFormatImporterBlend, EditorSceneFormatImporter); @@ -70,6 +72,39 @@ public: const Map &p_options) override; }; +class LineEdit; +class Button; +class EditorFileDialog; +class Label; + +class EditorFileSystemImportFormatSupportQueryBlend : public EditorFileSystemImportFormatSupportQuery { + GDCLASS(EditorFileSystemImportFormatSupportQueryBlend, EditorFileSystemImportFormatSupportQuery); + + ConfirmationDialog *configure_blender_dialog; + LineEdit *blender_path; + Button *blender_path_browse; + EditorFileDialog *browse_dialog; + Label *path_status; + bool confirmed = false; + + String auto_detected_path; + void _validate_path(String p_path); + + bool _autodetect_path(String p_path); + + void _path_confirmed(); + + void _select_install(String p_path); + void _browse_install(); + +public: + virtual bool is_active() const override; + virtual Vector get_file_extensions() const override; + virtual bool query() override; + + EditorFileSystemImportFormatSupportQueryBlend(); +}; + #endif // TOOLS_ENABLED #endif // EDITOR_SCENE_IMPORTER_BLEND_H diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index 79b918dbc01..4166f925024 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -64,22 +64,19 @@ static void _editor_init() { // Blend to glTF importer. - bool blend_enabled = GLOBAL_GET("filesystem/import/blend/enabled"); + bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled"); // Defined here because EditorSettings doesn't exist in `register_gltf_types` yet. - String blender_path = EDITOR_DEF_RST("filesystem/import/blend/blender_path", ""); + EDITOR_DEF_RST("filesystem/import/blender/blender3_path", ""); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, - "filesystem/import/blend/blender_path", PROPERTY_HINT_GLOBAL_FILE)); + "filesystem/import/blender/blender3_path", PROPERTY_HINT_GLOBAL_DIR)); if (blend_enabled) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (blender_path.is_empty()) { - WARN_PRINT("Blend file import is enabled, but no Blender path is configured. Blend files will not be imported."); - } else if (!da->file_exists(blender_path)) { - WARN_PRINT("Blend file import is enabled, but the Blender path doesn't point to a valid Blender executable. Blend files will not be imported."); - } else { - Ref importer; - importer.instantiate(); - ResourceImporterScene::get_singleton()->add_importer(importer); - } + Ref importer; + importer.instantiate(); + ResourceImporterScene::get_singleton()->add_importer(importer); + + Ref blend_import_query; + blend_import_query.instantiate(); + EditorFileSystem::get_singleton()->add_import_format_support_query(blend_import_query); } // FBX to glTF importer. @@ -131,13 +128,14 @@ void register_gltf_types() { EditorPlugins::add_by_type(); // Project settings defined here so doctool finds them. - GLOBAL_DEF_RST("filesystem/import/blend/enabled", true); + GLOBAL_DEF_RST("filesystem/import/blender/enabled", true); GLOBAL_DEF_RST("filesystem/import/fbx/enabled", true); GDREGISTER_CLASS(EditorSceneFormatImporterBlend); GDREGISTER_CLASS(EditorSceneFormatImporterFBX); ClassDB::set_current_api(prev_api); EditorNode::add_init_callback(_editor_init); + #endif // TOOLS_ENABLED } diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index be57ca90844..0bb96a18a53 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -39,13 +39,13 @@ void AcceptDialog::_input_from_window(const Ref &p_event) { Ref key = p_event; - if (key.is_valid() && key->is_pressed() && key->get_keycode() == Key::ESCAPE) { + if (close_on_escape && key.is_valid() && key->is_pressed() && key->get_keycode() == Key::ESCAPE) { _cancel_pressed(); } } void AcceptDialog::_parent_focused() { - if (!is_exclusive()) { + if (close_on_escape && !is_exclusive()) { _cancel_pressed(); } } @@ -145,6 +145,14 @@ bool AcceptDialog::get_hide_on_ok() const { return hide_on_ok; } +void AcceptDialog::set_close_on_escape(bool p_hide) { + close_on_escape = p_hide; +} + +bool AcceptDialog::get_close_on_escape() const { + return close_on_escape; +} + void AcceptDialog::set_autowrap(bool p_autowrap) { label->set_autowrap_mode(p_autowrap ? Label::AUTOWRAP_WORD : Label::AUTOWRAP_OFF); } @@ -288,6 +296,8 @@ void AcceptDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("get_label"), &AcceptDialog::get_label); ClassDB::bind_method(D_METHOD("set_hide_on_ok", "enabled"), &AcceptDialog::set_hide_on_ok); ClassDB::bind_method(D_METHOD("get_hide_on_ok"), &AcceptDialog::get_hide_on_ok); + ClassDB::bind_method(D_METHOD("set_close_on_escape", "enabled"), &AcceptDialog::set_close_on_escape); + ClassDB::bind_method(D_METHOD("get_close_on_escape"), &AcceptDialog::get_close_on_escape); ClassDB::bind_method(D_METHOD("add_button", "text", "right", "action"), &AcceptDialog::add_button, DEFVAL(false), DEFVAL("")); ClassDB::bind_method(D_METHOD("add_cancel_button", "name"), &AcceptDialog::add_cancel_button); ClassDB::bind_method(D_METHOD("remove_button", "button"), &AcceptDialog::remove_button); @@ -304,6 +314,7 @@ void AcceptDialog::_bind_methods() { ADD_GROUP("Dialog", "dialog"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "dialog_text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_hide_on_ok"), "set_hide_on_ok", "get_hide_on_ok"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_close_on_escape"), "set_close_on_escape", "get_close_on_escape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_autowrap"), "set_autowrap", "has_autowrap"); } diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index 1365b1df24f..11c701b0d5f 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -50,6 +50,7 @@ class AcceptDialog : public Window { Label *label; Button *ok; bool hide_on_ok = true; + bool close_on_escape = true; void _custom_action(const String &p_action); void _update_child_rects(); @@ -87,6 +88,9 @@ public: void set_hide_on_ok(bool p_hide); bool get_hide_on_ok() const; + void set_close_on_escape(bool p_enable); + bool get_close_on_escape() const; + void set_text(String p_text); String get_text() const;