diff --git a/doc/classes/EditorUndoRedoManager.xml b/doc/classes/EditorUndoRedoManager.xml
index 6a66a35ce87..09293302817 100644
--- a/doc/classes/EditorUndoRedoManager.xml
+++ b/doc/classes/EditorUndoRedoManager.xml
@@ -96,11 +96,13 @@
+
Create a new action. After this is called, do all your calls to [method add_do_method], [method add_undo_method], [method add_do_property], and [method add_undo_property], then commit the action with [method commit_action].
The way actions are merged is dictated by the [param merge_mode] argument. See [enum UndoRedo.MergeMode] for details.
If [param custom_context] object is provided, it will be used for deducing target history (instead of using the first operation).
The way undo operation are ordered in actions is dictated by [param backward_undo_ops]. When [param backward_undo_ops] is [code]false[/code] undo option are ordered in the same order they were added. Which means the first operation to be added will be the first to be undone.
+ If [param mark_unsaved] is [code]false[/code], the action will not mark the history as unsaved. This is useful for example for actions that change a selection, or a setting that will be saved automatically. Otherwise, this should be left to [code]true[/code] if the action requires saving by the user or if it can cause data loss when left unsaved.
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index a55fe2098e8..0b2d0280899 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -4661,7 +4661,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
_edit_request_change(object, p_name);
emit_signal(_prop_edited, p_name);
} else {
- undo_redo->create_action(vformat(TTR("Set %s"), p_name), UndoRedo::MERGE_ENDS);
+ undo_redo->create_action(vformat(TTR("Set %s"), p_name), UndoRedo::MERGE_ENDS, nullptr, false, mark_unsaved);
undo_redo->add_do_property(object, p_name, p_value);
bool valid = false;
Variant value = object->get(p_name, &valid);
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 183c18c3afb..a0da16593a3 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -603,6 +603,7 @@ class EditorInspector : public ScrollContainer {
bool keying = false;
bool wide_editors = false;
bool deletable_properties = false;
+ bool mark_unsaved = true;
float refresh_countdown;
bool update_tree_pending = false;
@@ -703,6 +704,7 @@ public:
void set_keying(bool p_active);
void set_read_only(bool p_read_only);
+ void set_mark_unsaved(bool p_mark) { mark_unsaved = p_mark; }
EditorPropertyNameProcessor::Style get_property_name_style() const;
void set_property_name_style(EditorPropertyNameProcessor::Style p_style);
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index 016d2d5b314..01c0e2b5689 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -915,6 +915,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
inspector = memnew(SectionedInspector);
inspector->get_inspector()->set_use_filter(true);
+ inspector->get_inspector()->set_mark_unsaved(false);
inspector->register_search_box(search_box);
inspector->register_advanced_toggle(advanced_switch);
inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL);
diff --git a/editor/editor_undo_redo_manager.compat.inc b/editor/editor_undo_redo_manager.compat.inc
new file mode 100644
index 00000000000..b44762e3111
--- /dev/null
+++ b/editor/editor_undo_redo_manager.compat.inc
@@ -0,0 +1,41 @@
+/**************************************************************************/
+/* editor_undo_redo_manager.compat.inc */
+/**************************************************************************/
+/* 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. */
+/**************************************************************************/
+
+#ifndef DISABLE_DEPRECATED
+
+void EditorUndoRedoManager::_create_action_bind_compat_106121(const String &p_name, UndoRedo::MergeMode p_mode, Object *p_custom_context, bool p_backward_undo_ops) {
+ create_action(p_name, p_mode, p_custom_context, p_backward_undo_ops, true);
+}
+
+void EditorUndoRedoManager::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("create_action", "name", "merge_mode", "custom_context", "backward_undo_ops"), &EditorUndoRedoManager::_create_action_bind_compat_106121, DEFVAL(UndoRedo::MERGE_DISABLE), DEFVAL((Object *)nullptr), DEFVAL(false));
+}
+
+#endif
diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp
index a278de0884b..2737d4d4b2e 100644
--- a/editor/editor_undo_redo_manager.cpp
+++ b/editor/editor_undo_redo_manager.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "editor_undo_redo_manager.h"
+#include "editor_undo_redo_manager.compat.inc"
#include "core/io/resource.h"
#include "core/os/os.h"
@@ -125,7 +126,7 @@ void EditorUndoRedoManager::force_fixed_history() {
forced_history = true;
}
-void EditorUndoRedoManager::create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode, bool p_backward_undo_ops) {
+void EditorUndoRedoManager::create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode, bool p_backward_undo_ops, bool p_mark_unsaved) {
if (pending_action.history_id != INVALID_HISTORY) {
// Nested action.
p_history_id = pending_action.history_id;
@@ -134,6 +135,7 @@ void EditorUndoRedoManager::create_action_for_history(const String &p_name, int
pending_action.timestamp = OS::get_singleton()->get_unix_time();
pending_action.merge_mode = p_mode;
pending_action.backward_undo_ops = p_backward_undo_ops;
+ pending_action.mark_unsaved = p_mark_unsaved;
}
if (p_history_id != INVALID_HISTORY) {
@@ -143,8 +145,8 @@ void EditorUndoRedoManager::create_action_for_history(const String &p_name, int
}
}
-void EditorUndoRedoManager::create_action(const String &p_name, UndoRedo::MergeMode p_mode, Object *p_custom_context, bool p_backward_undo_ops) {
- create_action_for_history(p_name, INVALID_HISTORY, p_mode, p_backward_undo_ops);
+void EditorUndoRedoManager::create_action(const String &p_name, UndoRedo::MergeMode p_mode, Object *p_custom_context, bool p_backward_undo_ops, bool p_mark_unsaved) {
+ create_action_for_history(p_name, INVALID_HISTORY, p_mode, p_backward_undo_ops, p_mark_unsaved);
if (p_custom_context) {
// This assigns history to pending action.
@@ -380,7 +382,26 @@ void EditorUndoRedoManager::set_history_as_unsaved(int p_id) {
bool EditorUndoRedoManager::is_history_unsaved(int p_id) {
History &history = get_or_create_history(p_id);
- return history.undo_redo->get_version() != history.saved_version;
+
+ int version_difference = history.undo_redo->get_version() - history.saved_version;
+ if (version_difference > 0) {
+ List::Element *E = history.undo_stack.back();
+ for (int i = 0; i < version_difference; i++) {
+ if (E->get().mark_unsaved) {
+ return true;
+ }
+ E = E->prev();
+ }
+ } else if (version_difference < 0) {
+ List::Element *E = history.redo_stack.back();
+ for (int i = 0; i > version_difference; i--) {
+ if (E->get().mark_unsaved) {
+ return true;
+ }
+ E = E->prev();
+ }
+ }
+ return false;
}
bool EditorUndoRedoManager::has_undo() {
@@ -492,7 +513,7 @@ EditorUndoRedoManager::History *EditorUndoRedoManager::_get_newest_undo() {
}
void EditorUndoRedoManager::_bind_methods() {
- ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode", "custom_context", "backward_undo_ops"), &EditorUndoRedoManager::create_action, DEFVAL(UndoRedo::MERGE_DISABLE), DEFVAL((Object *)nullptr), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode", "custom_context", "backward_undo_ops", "mark_unsaved"), &EditorUndoRedoManager::create_action, DEFVAL(UndoRedo::MERGE_DISABLE), DEFVAL((Object *)nullptr), DEFVAL(false), DEFVAL(true));
ClassDB::bind_method(D_METHOD("commit_action", "execute"), &EditorUndoRedoManager::commit_action, DEFVAL(true));
ClassDB::bind_method(D_METHOD("is_committing_action"), &EditorUndoRedoManager::is_committing_action);
ClassDB::bind_method(D_METHOD("force_fixed_history"), &EditorUndoRedoManager::force_fixed_history);
diff --git a/editor/editor_undo_redo_manager.h b/editor/editor_undo_redo_manager.h
index 4b90a65e1b6..a67b900a041 100644
--- a/editor/editor_undo_redo_manager.h
+++ b/editor/editor_undo_redo_manager.h
@@ -51,6 +51,7 @@ public:
String action_name;
UndoRedo::MergeMode merge_mode = UndoRedo::MERGE_DISABLE;
bool backward_undo_ops = false;
+ bool mark_unsaved = true;
};
struct History {
@@ -73,6 +74,11 @@ private:
protected:
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ void _create_action_bind_compat_106121(const String &p_name = "", UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE, Object *p_custom_context = nullptr, bool p_backward_undo_ops = false);
+ static void _bind_compatibility_methods();
+#endif
+
public:
History &get_or_create_history(int p_idx);
UndoRedo *get_history_undo_redo(int p_idx) const;
@@ -80,8 +86,8 @@ public:
History &get_history_for_object(Object *p_object);
void force_fixed_history();
- void create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE, bool p_backward_undo_ops = false);
- void create_action(const String &p_name = "", UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE, Object *p_custom_context = nullptr, bool p_backward_undo_ops = false);
+ void create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE, bool p_backward_undo_ops = false, bool p_mark_unsaved = true);
+ void create_action(const String &p_name = "", UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE, Object *p_custom_context = nullptr, bool p_backward_undo_ops = false, bool p_mark_unsaved = true);
void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index 5846fe7ee66..09c321aa9d9 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -1521,10 +1521,11 @@ ProjectExportDialog::ProjectExportDialog() {
// Main preset parameters.
parameters = memnew(EditorInspector);
- sections->add_child(parameters);
- parameters->set_name(TTR("Options"));
+ parameters->set_name(TTRC("Options"));
+ parameters->set_mark_unsaved(false);
parameters->set_v_size_flags(Control::SIZE_EXPAND_FILL);
parameters->set_use_doc_hints(true);
+ sections->add_child(parameters);
parameters->connect("property_edited", callable_mp(this, &ProjectExportDialog::_update_parameters));
EditorExport::get_singleton()->connect("export_presets_updated", callable_mp(this, &ProjectExportDialog::_force_update_current_preset_parameters));
diff --git a/editor/plugins/tiles/tile_map_layer_editor.cpp b/editor/plugins/tiles/tile_map_layer_editor.cpp
index 972bf5aaa18..4fd11c2966d 100644
--- a/editor/plugins/tiles/tile_map_layer_editor.cpp
+++ b/editor/plugins/tiles/tile_map_layer_editor.cpp
@@ -1313,7 +1313,7 @@ void TileMapLayerEditorTilesPlugin::_stop_dragging() {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (drag_type) {
case DRAG_TYPE_SELECT: {
- undo_redo->create_action_for_history(TTR("Change selection"), EditorNode::get_editor_data().get_current_edited_scene_history_id());
+ undo_redo->create_action_for_history(TTR("Change selection"), EditorNode::get_editor_data().get_current_edited_scene_history_id(), UndoRedo::MERGE_DISABLE, false, false);
undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
if (!Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 0671684e0ec..6f0976e140f 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -718,6 +718,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
general_settings_inspector->register_search_box(search_box);
general_settings_inspector->register_advanced_toggle(advanced);
general_settings_inspector->get_inspector()->set_use_filter(true);
+ general_settings_inspector->get_inspector()->set_mark_unsaved(false);
general_settings_inspector->get_inspector()->connect("property_selected", callable_mp(this, &ProjectSettingsEditor::_setting_selected));
general_settings_inspector->get_inspector()->connect("property_edited", callable_mp(this, &ProjectSettingsEditor::_setting_edited));
general_settings_inspector->get_inspector()->connect("restart_requested", callable_mp(this, &ProjectSettingsEditor::_editor_restart_request));
diff --git a/misc/extension_api_validation/4.4-stable.expected b/misc/extension_api_validation/4.4-stable.expected
index 3265e1b8c73..33e335ff502 100644
--- a/misc/extension_api_validation/4.4-stable.expected
+++ b/misc/extension_api_validation/4.4-stable.expected
@@ -104,3 +104,10 @@ GH-105570
Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/texture_create_from_extension/arguments': size changed value in new API, from 9 to 10.
Argument added; p_mipmaps. Compatibility method registered.
+
+GH-106121
+--------
+Validate extension JSON: Error: Field 'classes/EditorUndoRedoManager/methods/create_action/arguments': size changed value in new API, from 4 to 5.
+Validate extension JSON: Error: Field 'classes/EditorUndoRedoManager/methods/create_action/arguments': size changed value in new API, from 3 to 5.
+
+New argument added. Compatibility method registered.