diff options
122 files changed, 1498 insertions, 642 deletions
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 5a1037aebe..fdd3807b69 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -532,7 +532,7 @@ </description> </method> <method name="get_undo_redo"> - <return type="UndoRedo" /> + <return type="EditorUndoRedoManager" /> <description> Gets the undo/redo object. Most actions in the editor can be undoable, so use this object to make sure this happens when it's worth it. </description> diff --git a/doc/classes/EditorUndoRedoManager.xml b/doc/classes/EditorUndoRedoManager.xml new file mode 100644 index 0000000000..1350e4487c --- /dev/null +++ b/doc/classes/EditorUndoRedoManager.xml @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="EditorUndoRedoManager" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Manages undo history of scenes opened in the editor. + </brief_description> + <description> + [EditorUndoRedoManager] is a manager for [UndoRedo] objects associated with edited scenes. Each scene has its own undo history and [EditorUndoRedoManager] ensures that each action performed in the editor gets associated with a proper scene. For actions not related to scenes ([ProjectSettings] edits, external resources, etc.), a separate global history is used. + The usage is mostly the same as [UndoRedo]. You create and commit actions and the manager automatically decides under-the-hood what scenes it belongs to. The scene is deduced based on the first operation in an action, using the object from the operation. The rules are as follows: + - If the object is a [Node], use the currently edited scene; + - If the object is a built-in resource, use the scene from its path; + - If the object is external resource or anything else, use global history. + This guessing can sometimes yield false results, so you can provide a custom context object when creating an action. + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_do_method" qualifiers="vararg"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <param index="1" name="method" type="StringName" /> + <description> + Register a method that will be called when the action is committed (i.e. the "do" action). + If this is the first operation, the [param object] will be used to deduce target undo history. + </description> + </method> + <method name="add_do_property"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <param index="1" name="property" type="StringName" /> + <param index="2" name="value" type="Variant" /> + <description> + Register a property value change for "do". + If this is the first operation, the [param object] will be used to deduce target undo history. + </description> + </method> + <method name="add_do_reference"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <description> + Register a reference for "do" that will be erased if the "do" history is lost. This is useful mostly for new nodes created for the "do" call. Do not use for resources. + </description> + </method> + <method name="add_undo_method" qualifiers="vararg"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <param index="1" name="method" type="StringName" /> + <description> + Register a method that will be called when the action is undone (i.e. the "undo" action). + If this is the first operation, the [param object] will be used to deduce target undo history. + </description> + </method> + <method name="add_undo_property"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <param index="1" name="property" type="StringName" /> + <param index="2" name="value" type="Variant" /> + <description> + Register a property value change for "undo". + If this is the first operation, the [param object] will be used to deduce target undo history. + </description> + </method> + <method name="add_undo_reference"> + <return type="void" /> + <param index="0" name="object" type="Object" /> + <description> + Register a reference for "undo" that will be erased if the "undo" history is lost. This is useful mostly for nodes removed with the "do" call (not the "undo" call!). + </description> + </method> + <method name="commit_action"> + <return type="void" /> + <param index="0" name="execute" type="bool" default="true" /> + <description> + Commit the action. If [param execute] is true (default), all "do" methods/properties are called/set when this function is called. + </description> + </method> + <method name="create_action"> + <return type="void" /> + <param index="0" name="name" type="String" /> + <param index="1" name="merge_mode" type="int" enum="UndoRedo.MergeMode" default="0" /> + <param index="2" name="custom_context" type="Object" default="null" /> + <description> + 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). + </description> + </method> + <method name="get_history_undo_redo" qualifiers="const"> + <return type="UndoRedo" /> + <param index="0" name="id" type="int" /> + <description> + Returns the [UndoRedo] object associated with the given history [param id]. + [param id] above [code]0[/code] are mapped to the opened scene tabs (but it doesn't match their order). [param id] of [code]0[/code] or lower have special meaning (see [enum SpecialHistory]). + Best used with [method get_object_history_id]. This method is only provided in case you need some more advanced methods of [UndoRedo] (but keep in mind that directly operating on the [UndoRedo] object might affect editor's stability). + </description> + </method> + <method name="get_object_history_id" qualifiers="const"> + <return type="int" /> + <param index="0" name="object" type="Object" /> + <description> + Returns the history ID deduced from the given [param object]. It can be used with [method get_history_undo_redo]. + </description> + </method> + <method name="is_committing_action" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if the [EditorUndoRedoManager] is currently committing the action, i.e. running its "do" method or property change (see [method commit_action]). + </description> + </method> + </methods> + <constants> + <constant name="GLOBAL_HISTORY" value="0" enum="SpecialHistory"> + Global history not associated with any scene, but with external resources etc. + </constant> + <constant name="INVALID_HISTORY" value="-99" enum="SpecialHistory"> + Invalid "null" history. It's a special value, not associated with any object. + </constant> + </constants> +</class> diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index e10ed7e976..11e46152ef 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/view_panner.h" #include "scene/resources/text_line.h" @@ -649,7 +650,7 @@ Size2 AnimationBezierTrackEdit::get_minimum_size() const { return Vector2(1, 1); } -void AnimationBezierTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) { +void AnimationBezierTrackEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { undo_redo = p_undo_redo; } diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h index 070a6589ad..3e94b4fa84 100644 --- a/editor/animation_bezier_editor.h +++ b/editor/animation_bezier_editor.h @@ -34,6 +34,7 @@ #include "animation_track_editor.h" #include "core/templates/rb_set.h" +class EditorUndoRedoManager; class ViewPanner; class AnimationBezierTrackEdit : public Control { @@ -48,7 +49,7 @@ class AnimationBezierTrackEdit : public Control { }; AnimationTimelineEdit *timeline = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Node *root = nullptr; Control *play_position = nullptr; //separate control used to draw so updates for only position changed are much faster float play_position_pos = 0; @@ -180,7 +181,7 @@ public: void set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only); virtual Size2 get_minimum_size() const override; - void set_undo_redo(UndoRedo *p_undo_redo); + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_timeline(AnimationTimelineEdit *p_timeline); void set_editor(AnimationTrackEditor *p_editor); void set_root(Node *p_root); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 5580d3d5b1..93666b55f1 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -35,6 +35,7 @@ #include "editor/animation_bezier_editor.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "scene/animation/animation_player.h" #include "scene/gui/separator.h" @@ -680,7 +681,7 @@ public: } } - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Ref<Animation> animation; int track = -1; float key_ofs = 0; @@ -1374,7 +1375,7 @@ public: bool use_fps = false; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void notify_change() { notify_property_list_changed(); @@ -1708,7 +1709,7 @@ Size2 AnimationTimelineEdit::get_minimum_size() const { return ms; } -void AnimationTimelineEdit::set_undo_redo(UndoRedo *p_undo_redo) { +void AnimationTimelineEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { undo_redo = p_undo_redo; } @@ -2507,10 +2508,14 @@ Size2 AnimationTrackEdit::get_minimum_size() const { return Vector2(1, max_h + separation); } -void AnimationTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) { +void AnimationTrackEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { undo_redo = p_undo_redo; } +Ref<EditorUndoRedoManager> AnimationTrackEdit::get_undo_redo() const { + return undo_redo; +} + void AnimationTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) { timeline = p_timeline; timeline->set_track_edit(this); @@ -6065,7 +6070,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { case EDIT_OPTIMIZE_ANIMATION_CONFIRM: { animation->optimize(optimize_linear_error->get_value(), optimize_angular_error->get_value(), optimize_max_angle->get_value()); _update_tracks(); - undo_redo->clear_history(); + undo_redo->clear_history(true, undo_redo->get_history_for_object(animation.ptr()).id); } break; case EDIT_CLEAN_UP_ANIMATION: { @@ -6133,7 +6138,7 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) { } } - undo_redo->clear_history(); + undo_redo->clear_history(true, undo_redo->get_history_for_object(animation.ptr()).id); _update_tracks(); } @@ -6303,7 +6308,7 @@ void AnimationTrackEditor::_pick_track_filter_input(const Ref<InputEvent> &p_ie) } AnimationTrackEditor::AnimationTrackEditor() { - undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo = EditorNode::get_undo_redo(); main_panel = memnew(PanelContainer); main_panel->set_focus_mode(FOCUS_ALL); // Allow panel to have focus so that shortcuts work as expected. diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index a785f5aec7..42238d8c72 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -78,7 +78,7 @@ class AnimationTimelineEdit : public Range { void _anim_loop_pressed(); void _play_position_draw(); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Rect2 hsize_rect; bool editing = false; @@ -112,7 +112,7 @@ public: void set_track_edit(AnimationTrackEdit *p_track_edit); void set_zoom(Range *p_zoom); Range *get_zoom() const { return zoom; } - void set_undo_redo(UndoRedo *p_undo_redo); + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_play_position(float p_pos); float get_play_position() const; @@ -153,7 +153,7 @@ class AnimationTrackEdit : public Control { }; AnimationTimelineEdit *timeline = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Popup *path_popup = nullptr; LineEdit *path = nullptr; Node *root = nullptr; @@ -234,12 +234,12 @@ public: Ref<Animation> get_animation() const; AnimationTimelineEdit *get_timeline() const { return timeline; } AnimationTrackEditor *get_editor() const { return editor; } - UndoRedo *get_undo_redo() const { return undo_redo; } + Ref<EditorUndoRedoManager> get_undo_redo() const; NodePath get_path() const; void set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only); virtual Size2 get_minimum_size() const override; - void set_undo_redo(UndoRedo *p_undo_redo); + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_timeline(AnimationTimelineEdit *p_timeline); void set_editor(AnimationTrackEditor *p_editor); void set_root(Node *p_root); @@ -334,7 +334,7 @@ class AnimationTrackEditor : public VBoxContainer { void _animation_track_remove_request(int p_track, Ref<Animation> p_from_animation); void _track_grab_focus(int p_track); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _update_scroll(double); void _update_step(double p_new_step); diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index cd40b53919..ab64aaa24d 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -33,6 +33,7 @@ #include "editor/audio_stream_preview.h" #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/2d/animated_sprite_2d.h" #include "scene/2d/sprite_2d.h" #include "scene/3d/sprite_3d.h" diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp index 58527ee4d1..ab0e801c88 100644 --- a/editor/array_property_edit.cpp +++ b/editor/array_property_edit.cpp @@ -32,6 +32,7 @@ #include "core/io/marshalls.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #define ITEMS_PER_PAGE 100 @@ -87,7 +88,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { return true; } - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Resize Array")); ur->add_do_method(this, "_set_size", newsize); ur->add_undo_method(this, "_set_size", size); @@ -134,7 +135,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { Callable::CallError ce; Variant new_value; Variant::construct(Variant::Type(type), new_value, nullptr, 0, ce); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Array Value Type")); ur->add_do_method(this, "_set_value", idx, new_value); @@ -150,7 +151,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { Variant arr = get_array(); Variant value = arr.get(idx); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Array Value")); ur->add_do_method(this, "_set_value", idx, p_value); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 6fdd9563fb..6c86b341da 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -34,6 +34,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "plugins/script_editor_plugin.h" @@ -924,6 +925,10 @@ void ConnectionsDock::_bind_methods() { ClassDB::bind_method("update_tree", &ConnectionsDock::update_tree); } +void ConnectionsDock::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void ConnectionsDock::set_node(Node *p_node) { selected_node = p_node; update_tree(); diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index d141d1a880..7e7192019b 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -31,7 +31,6 @@ #ifndef CONNECTIONS_DIALOG_H #define CONNECTIONS_DIALOG_H -#include "core/object/undo_redo.h" #include "editor/editor_inspector.h" #include "editor/scene_tree_editor.h" #include "scene/gui/button.h" @@ -48,6 +47,7 @@ #include "scene/gui/tree.h" class ConnectDialogBinds; +class EditorUndoRedoManager; class ConnectDialog : public ConfirmationDialog { GDCLASS(ConnectDialog, ConfirmationDialog); @@ -194,7 +194,7 @@ class ConnectionsDock : public VBoxContainer { Button *connect_button = nullptr; PopupMenu *signal_menu = nullptr; PopupMenu *slot_menu = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; LineEdit *search_box = nullptr; HashMap<StringName, HashMap<StringName, String>> descr_cache; @@ -225,7 +225,7 @@ protected: static void _bind_methods(); public: - void set_undoredo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_node(Node *p_node); void update_tree(); diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 472e53c0e8..9fd7fa578f 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -30,6 +30,7 @@ #include "editor_debugger_node.h" +#include "core/object/undo_redo.h" #include "editor/debugger/editor_debugger_tree.h" #include "editor/debugger/script_editor_debugger.h" #include "editor/editor_log.h" @@ -83,8 +84,6 @@ EditorDebuggerNode::EditorDebuggerNode() { inspect_edited_object_timeout = EDITOR_DEF("debugger/remote_inspect_refresh_interval", 0.2); EditorNode *editor = EditorNode::get_singleton(); - editor->get_undo_redo()->set_method_notify_callback(_method_changeds, this); - editor->get_undo_redo()->set_property_notify_callback(_property_changeds, this); editor->get_pause_button()->connect("pressed", callable_mp(this, &EditorDebuggerNode::_paused)); } @@ -181,6 +180,11 @@ void EditorDebuggerNode::_bind_methods() { ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::BOOL, "enabled"))); } +void EditorDebuggerNode::register_undo_redo(UndoRedo *p_undo_redo) { + p_undo_redo->set_method_notify_callback(_method_changeds, this); + p_undo_redo->set_property_notify_callback(_property_changeds, this); +} + EditorDebuggerRemoteObject *EditorDebuggerNode::get_inspected_remote_object() { return Object::cast_to<EditorDebuggerRemoteObject>(ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_current())); } diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h index 4c9ad49ac4..e79e60b180 100644 --- a/editor/debugger/editor_debugger_node.h +++ b/editor/debugger/editor_debugger_node.h @@ -41,6 +41,7 @@ class EditorDebuggerRemoteObject; class MenuButton; class ScriptEditorDebugger; class TabContainer; +class UndoRedo; class EditorDebuggerNode : public MarginContainer { GDCLASS(EditorDebuggerNode, MarginContainer); @@ -152,6 +153,7 @@ protected: public: static EditorDebuggerNode *get_singleton() { return singleton; } + void register_undo_redo(UndoRedo *p_undo_redo); ScriptEditorDebugger *get_current_debugger() const; ScriptEditorDebugger *get_default_debugger() const; diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp index 630265e268..f16c5402ad 100644 --- a/editor/dictionary_property_edit.cpp +++ b/editor/dictionary_property_edit.cpp @@ -30,6 +30,7 @@ #include "dictionary_property_edit.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" void DictionaryPropertyEdit::_notif_change() { notify_property_list_changed(); @@ -118,7 +119,7 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val int index = pn.substr(0, slash).to_int(); if (type == "key" && index < keys.size()) { const Variant &key = keys[index]; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Dictionary Key")); ur->add_do_method(this, "_set_key", key, p_value); @@ -130,7 +131,7 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val const Variant &key = keys[index]; if (dict.has(key)) { Variant value = dict[key]; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Dictionary Value")); ur->add_do_method(this, "_set_value", key, p_value); diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index b6d7bbc45f..f1add65b7c 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -38,6 +38,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "filesystem_dock.h" #include "scene/resources/font.h" #include "servers/audio_server.h" @@ -280,7 +281,7 @@ void EditorAudioBus::_name_changed(const String &p_new_name) { } updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); StringName current = AudioServer::get_singleton()->get_bus_name(get_index()); ur->create_action(TTR("Rename Audio Bus")); @@ -321,7 +322,7 @@ void EditorAudioBus::_volume_changed(float p_normalized) { slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db))); } - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Audio Bus Volume"), UndoRedo::MERGE_ENDS); ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), p_db); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), AudioServer::get_singleton()->get_bus_volume_db(get_index())); @@ -415,7 +416,7 @@ void EditorAudioBus::_hide_value_preview() { void EditorAudioBus::_solo_toggled() { updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Toggle Audio Bus Solo")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), solo->is_pressed()); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), AudioServer::get_singleton()->is_bus_solo(get_index())); @@ -429,7 +430,7 @@ void EditorAudioBus::_solo_toggled() { void EditorAudioBus::_mute_toggled() { updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Toggle Audio Bus Mute")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), mute->is_pressed()); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), AudioServer::get_singleton()->is_bus_mute(get_index())); @@ -443,7 +444,7 @@ void EditorAudioBus::_mute_toggled() { void EditorAudioBus::_bypass_toggled() { updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Toggle Audio Bus Bypass Effects")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), bypass->is_pressed()); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), AudioServer::get_singleton()->is_bus_bypassing_effects(get_index())); @@ -457,7 +458,7 @@ void EditorAudioBus::_bypass_toggled() { void EditorAudioBus::_send_selected(int p_which) { updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Select Audio Bus Send")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", get_index(), send->get_item_text(p_which)); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", get_index(), AudioServer::get_singleton()->get_bus_send(get_index())); @@ -507,7 +508,7 @@ void EditorAudioBus::_effect_edited() { int index = effect->get_metadata(0); updating_bus = true; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Select Audio Bus Send")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, effect->is_checked(0)); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index)); @@ -534,7 +535,7 @@ void EditorAudioBus::_effect_add(int p_which) { afxr->set_name(effect_options->get_item_text(p_which)); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Add Audio Bus Effect")); ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), afxr, -1); ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect_count(get_index())); @@ -688,7 +689,7 @@ void EditorAudioBus::drop_data_fw(const Point2 &p_point, const Variant &p_data, bool enabled = AudioServer::get_singleton()->is_bus_effect_enabled(bus, effect); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Move Bus Effect")); ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", bus, effect); ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(bus, effect), paste_at); @@ -730,7 +731,7 @@ void EditorAudioBus::_delete_effect_pressed(int p_option) { int index = item->get_metadata(0); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Delete Bus Effect")); ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), index); ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(get_index(), index), index); @@ -1063,7 +1064,7 @@ void EditorAudioBuses::_notification(int p_what) { } void EditorAudioBuses::_add_bus() { - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Add Audio Bus")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count() + 1); @@ -1095,7 +1096,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) { return; } - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Delete Audio Bus")); ur->add_do_method(AudioServer::get_singleton(), "remove_bus", index); @@ -1117,7 +1118,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) { void EditorAudioBuses::_duplicate_bus(int p_which) { int add_at_pos = p_which + 1; - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Duplicate Audio Bus")); ur->add_do_method(AudioServer::get_singleton(), "add_bus", add_at_pos); ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", add_at_pos, AudioServer::get_singleton()->get_bus_name(p_which) + " Copy"); @@ -1140,7 +1141,7 @@ void EditorAudioBuses::_reset_bus_volume(Object *p_which) { EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which); int index = bus->get_index(); - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Reset Bus Volume")); ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", index, 0.f); ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index)); @@ -1160,7 +1161,7 @@ void EditorAudioBuses::_request_drop_end() { } void EditorAudioBuses::_drop_at_index(int p_bus, int p_index) { - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Move Audio Bus")); ur->add_do_method(AudioServer::get_singleton(), "move_bus", p_bus, p_index); @@ -1219,7 +1220,7 @@ void EditorAudioBuses::_load_default_layout() { file->set_text(String(TTR("Layout:")) + " " + layout_path.get_file()); AudioServer::get_singleton()->set_bus_layout(state); _update_buses(); - EditorNode::get_singleton()->get_undo_redo()->clear_history(); + EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); call_deferred(SNAME("_select_layout")); } @@ -1235,7 +1236,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) { file->set_text(String(TTR("Layout:")) + " " + p_string.get_file()); AudioServer::get_singleton()->set_bus_layout(state); _update_buses(); - EditorNode::get_singleton()->get_undo_redo()->clear_history(); + EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); call_deferred(SNAME("_select_layout")); } else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) { @@ -1255,7 +1256,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) { edited_path = p_string; file->set_text(String(TTR("Layout:")) + " " + p_string.get_file()); _update_buses(); - EditorNode::get_singleton()->get_undo_redo()->clear_history(); + EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); call_deferred(SNAME("_select_layout")); } } @@ -1354,7 +1355,7 @@ void EditorAudioBuses::open_layout(const String &p_path) { file->set_text(p_path.get_file()); AudioServer::get_singleton()->set_bus_layout(state); _update_buses(); - EditorNode::get_singleton()->get_undo_redo()->clear_history(); + EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY); call_deferred(SNAME("_select_layout")); } diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index ee4955d0a0..120ac5b984 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -35,6 +35,7 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/filesystem_dock.h" #include "project_settings_editor.h" #include "scene/main/window.h" @@ -193,7 +194,7 @@ void EditorAutoloadSettings::_autoload_edited() { TreeItem *ti = tree->get_edited(); int column = tree->get_edited_column(); - UndoRedo *undo_redo = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); if (column == 0) { String name = ti->get_text(0); @@ -288,7 +289,7 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu String name = "autoload/" + ti->get_text(0); - UndoRedo *undo_redo = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); switch (p_button) { case BUTTON_OPEN: { @@ -713,7 +714,7 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant & orders.sort(); - UndoRedo *undo_redo = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Rearrange Autoloads")); @@ -757,7 +758,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_ name = "autoload/" + name; - UndoRedo *undo_redo = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Add Autoload")); // Singleton autoloads are represented with a leading "*" in their path. @@ -783,7 +784,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_ void EditorAutoloadSettings::autoload_remove(const String &p_name) { String name = "autoload/" + p_name; - UndoRedo *undo_redo = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); int order = ProjectSettings::get_singleton()->get_order(name); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 2d4945db14..64bdac1e77 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -35,6 +35,7 @@ #include "core/io/resource_loader.h" #include "editor/editor_node.h" #include "editor/editor_plugin.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/script_editor_plugin.h" #include "scene/resources/packed_scene.h" @@ -364,13 +365,13 @@ void EditorData::restore_editor_global_states() { void EditorData::paste_object_params(Object *p_object) { ERR_FAIL_NULL(p_object); - undo_redo.create_action(TTR("Paste Params")); + undo_redo_manager->create_action(TTR("Paste Params")); for (const PropertyData &E : clipboard) { String name = E.name; - undo_redo.add_do_property(p_object, name, E.value); - undo_redo.add_undo_property(p_object, name, p_object->get(name)); + undo_redo_manager->add_do_property(p_object, name, E.value); + undo_redo_manager->add_undo_property(p_object, name, p_object->get(name)); } - undo_redo.commit_action(); + undo_redo_manager->commit_action(); } bool EditorData::call_build() { @@ -383,8 +384,49 @@ bool EditorData::call_build() { return result; } -UndoRedo &EditorData::get_undo_redo() { - return undo_redo; +void EditorData::set_scene_as_saved(int p_idx) { + if (p_idx == -1) { + p_idx = current_edited_scene; + } + ERR_FAIL_INDEX(p_idx, edited_scene.size()); + + get_undo_redo()->set_history_as_saved(edited_scene[p_idx].history_id); +} + +bool EditorData::is_scene_changed(int p_idx) { + if (p_idx == -1) { + p_idx = current_edited_scene; + } + ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), false); + + uint64_t current_scene_version = get_undo_redo()->get_or_create_history(edited_scene[p_idx].history_id).undo_redo->get_version(); + bool is_changed = edited_scene[p_idx].last_checked_version != current_scene_version; + edited_scene.write[p_idx].last_checked_version = current_scene_version; + return is_changed; +} + +int EditorData::get_scene_history_id_from_path(const String &p_path) const { + for (const EditedScene &E : edited_scene) { + if (E.path == p_path) { + return E.history_id; + } + } + return 0; +} + +int EditorData::get_current_edited_scene_history_id() const { + if (current_edited_scene != -1) { + return edited_scene[current_edited_scene].history_id; + } + return 0; +} + +int EditorData::get_scene_history_id(int p_idx) const { + return edited_scene[p_idx].history_id; +} + +Ref<EditorUndoRedoManager> &EditorData::get_undo_redo() { + return undo_redo_manager; } void EditorData::add_undo_redo_inspector_hook_callback(Callable p_callable) { @@ -415,12 +457,12 @@ Callable EditorData::get_move_array_element_function(const StringName &p_class) } void EditorData::remove_editor_plugin(EditorPlugin *p_plugin) { - p_plugin->undo_redo = nullptr; + p_plugin->undo_redo = Ref<EditorUndoRedoManager>(); editor_plugins.erase(p_plugin); } void EditorData::add_editor_plugin(EditorPlugin *p_plugin) { - p_plugin->undo_redo = &undo_redo; + p_plugin->undo_redo = undo_redo_manager; editor_plugins.push_back(p_plugin); } @@ -505,8 +547,8 @@ int EditorData::add_edited_scene(int p_at_pos) { es.path = String(); es.file_modified_time = 0; es.history_current = -1; - es.version = 0; es.live_edit_root = NodePath(String("/root")); + es.history_id = last_created_scene++; if (p_at_pos == edited_scene.size()) { edited_scene.push_back(es); @@ -547,6 +589,7 @@ void EditorData::remove_scene(int p_idx) { ScriptEditor::get_singleton()->close_builtin_scripts_from_scene(edited_scene[p_idx].path); } + undo_redo_manager->discard_history(edited_scene[p_idx].history_id); edited_scene.remove_at(p_idx); } @@ -679,26 +722,10 @@ Vector<EditorData::EditedScene> EditorData::get_edited_scenes() const { return out_edited_scenes_list; } -void EditorData::set_edited_scene_version(uint64_t version, int p_scene_idx) { - ERR_FAIL_INDEX(current_edited_scene, edited_scene.size()); - if (p_scene_idx < 0) { - edited_scene.write[current_edited_scene].version = version; - } else { - ERR_FAIL_INDEX(p_scene_idx, edited_scene.size()); - edited_scene.write[p_scene_idx].version = version; - } -} - -uint64_t EditorData::get_scene_version(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), 0); - return edited_scene[p_idx].version; -} - void EditorData::set_scene_modified_time(int p_idx, uint64_t p_time) { if (p_idx == -1) { p_idx = current_edited_scene; } - ERR_FAIL_INDEX(p_idx, edited_scene.size()); edited_scene.write[p_idx].file_modified_time = p_time; @@ -991,6 +1018,7 @@ void EditorData::script_class_load_icon_paths() { EditorData::EditorData() { current_edited_scene = -1; + undo_redo_manager.instantiate(); script_class_load_icon_paths(); } diff --git a/editor/editor_data.h b/editor/editor_data.h index 351c63f4b9..655a62a9ae 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -31,12 +31,12 @@ #ifndef EDITOR_DATA_H #define EDITOR_DATA_H -#include "core/object/undo_redo.h" #include "core/templates/list.h" #include "scene/resources/texture.h" class ConfigFile; class EditorPlugin; +class EditorUndoRedoManager; /** * Stores the history of objects which have been selected for editing in the Editor & the Inspector. @@ -118,8 +118,9 @@ public: Vector<EditorSelectionHistory::HistoryElement> history_stored; int history_current = 0; Dictionary custom_state; - uint64_t version = 0; NodePath live_edit_root; + int history_id = 0; + uint64_t last_checked_version = 0; }; private: @@ -132,12 +133,13 @@ private: HashMap<String, Vector<CustomType>> custom_types; List<PropertyData> clipboard; - UndoRedo undo_redo; + Ref<EditorUndoRedoManager> undo_redo_manager; Vector<Callable> undo_redo_callbacks; HashMap<StringName, Callable> move_element_functions; Vector<EditedScene> edited_scene; - int current_edited_scene; + int current_edited_scene = -1; + int last_created_scene = 1; bool _find_updated_instances(Node *p_root, Node *p_node, HashSet<String> &checked_paths); @@ -166,7 +168,7 @@ public: int get_editor_plugin_count() const; EditorPlugin *get_editor_plugin(int p_idx); - UndoRedo &get_undo_redo(); + Ref<EditorUndoRedoManager> &get_undo_redo(); void add_undo_redo_inspector_hook_callback(Callable p_callable); // Callbacks should have this signature: void (Object* undo_redo, Object *modified_object, String property, Variant new_value) void remove_undo_redo_inspector_hook_callback(Callable p_callable); const Vector<Callable> get_undo_redo_inspector_hook_callback(); @@ -200,7 +202,6 @@ public: void set_scene_path(int p_idx, const String &p_path); Ref<Script> get_scene_root_script(int p_idx) const; void set_edited_scene_version(uint64_t version, int p_scene_idx = -1); - uint64_t get_scene_version(int p_idx) const; void set_scene_modified_time(int p_idx, uint64_t p_time); uint64_t get_scene_modified_time(int p_idx) const; void clear_edited_scenes(); @@ -210,6 +211,13 @@ public: void move_edited_scene_to_index(int p_idx); bool call_build(); + void set_scene_as_saved(int p_idx); + bool is_scene_changed(int p_idx); + + int get_scene_history_id_from_path(const String &p_path) const; + int get_current_edited_scene_history_id() const; + int get_scene_history_id(int p_idx) const; + void set_plugin_window_layout(Ref<ConfigFile> p_layout); void get_plugin_window_layout(Ref<ConfigFile> p_layout); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index e954f06f08..855f4b1366 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1701,7 +1701,7 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) { // Call the function. Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name()); if (move_function.is_valid()) { - Variant args[] = { (Object *)undo_redo, object, array_element_prefix, p_element_index, p_to_pos }; + Variant args[] = { undo_redo.ptr(), object, array_element_prefix, p_element_index, p_to_pos }; const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] }; Variant return_value; Callable::CallError call_error; @@ -1845,7 +1845,7 @@ void EditorInspectorArray::_clear_array() { // Call the function. Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name()); if (move_function.is_valid()) { - Variant args[] = { (Object *)undo_redo, object, array_element_prefix, i, -1 }; + Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 }; const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] }; Variant return_value; Callable::CallError call_error; @@ -1898,7 +1898,7 @@ void EditorInspectorArray::_resize_array(int p_size) { // Call the function. Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name()); if (move_function.is_valid()) { - Variant args[] = { (Object *)undo_redo, object, array_element_prefix, -1, -1 }; + Variant args[] = { undo_redo.ptr(), object, array_element_prefix, -1, -1 }; const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] }; Variant return_value; Callable::CallError call_error; @@ -1917,7 +1917,7 @@ void EditorInspectorArray::_resize_array(int p_size) { // Call the function. Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name()); if (move_function.is_valid()) { - Variant args[] = { (Object *)undo_redo, object, array_element_prefix, i, -1 }; + Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 }; const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] }; Variant return_value; Callable::CallError call_error; @@ -2240,7 +2240,7 @@ void EditorInspectorArray::_bind_methods() { ADD_SIGNAL(MethodInfo("page_change_request")); } -void EditorInspectorArray::set_undo_redo(UndoRedo *p_undo_redo) { +void EditorInspectorArray::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { undo_redo = p_undo_redo; } @@ -2502,7 +2502,7 @@ Button *EditorInspector::create_inspector_action_button(const String &p_text) { return button; } -void EditorInspector::set_undo_redo(UndoRedo *p_undo_redo) { +void EditorInspector::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { undo_redo = p_undo_redo; } @@ -3525,7 +3525,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo } } - if (!undo_redo || bool(object->call("_dont_undo_redo"))) { + if (!undo_redo.is_valid() || bool(object->call("_dont_undo_redo"))) { object->set(p_name, p_value); if (p_refresh_all) { _edit_request_change(object, ""); @@ -3568,7 +3568,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo } } - Variant v_undo_redo = (Object *)undo_redo; + Variant v_undo_redo = undo_redo; Variant v_object = object; Variant v_name = p_name; for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_undo_redo_inspector_hook_callback().size(); i++) { @@ -3744,7 +3744,7 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) { Node *node = Object::cast_to<Node>(object); ERR_FAIL_COND(!node); - if (undo_redo) { + if (undo_redo.is_valid()) { undo_redo->create_action(vformat(p_pinned ? TTR("Pinned %s") : TTR("Unpinned %s"), p_path)); undo_redo->add_do_method(node, "_set_property_pinned", p_path, p_pinned); undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned); @@ -4026,7 +4026,6 @@ void EditorInspector::_bind_methods() { EditorInspector::EditorInspector() { object = nullptr; - undo_redo = nullptr; main_vbox = memnew(VBoxContainer); main_vbox->set_h_size_flags(SIZE_EXPAND_FILL); main_vbox->add_theme_constant_override("separation", 0); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index baba9ec1f4..905e13b3a9 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -31,6 +31,7 @@ #ifndef EDITOR_INSPECTOR_H #define EDITOR_INSPECTOR_H +#include "editor/editor_undo_redo_manager.h" #include "editor_property_name_processor.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" @@ -42,8 +43,6 @@ #include "scene/gui/spin_box.h" #include "scene/gui/texture_rect.h" -class UndoRedo; - class EditorPropertyRevert { public: static bool get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value, bool p_check_class_default = true); @@ -313,7 +312,7 @@ public: class EditorInspectorArray : public EditorInspectorSection { GDCLASS(EditorInspectorArray, EditorInspectorSection); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; enum Mode { MODE_NONE, @@ -408,7 +407,7 @@ protected: static void _bind_methods(); public: - void set_undo_redo(UndoRedo *p_undo_redo); + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = ""); void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = ""); @@ -448,7 +447,7 @@ public: class EditorInspector : public ScrollContainer { GDCLASS(EditorInspector, ScrollContainer); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; enum { MAX_PLUGINS = 1024 }; @@ -562,7 +561,7 @@ public: static EditorProperty *instantiate_property_editor(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false); - void set_undo_redo(UndoRedo *p_undo_redo); + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); String get_selected_path() const; diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp index cd8150d235..0cf7f7df2a 100644 --- a/editor/editor_locale_dialog.cpp +++ b/editor/editor_locale_dialog.cpp @@ -33,6 +33,7 @@ #include "core/config/project_settings.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/check_button.h" #include "scene/gui/line_edit.h" #include "scene/gui/option_button.h" diff --git a/editor/editor_locale_dialog.h b/editor/editor_locale_dialog.h index 7a4828e83a..8ac642a038 100644 --- a/editor/editor_locale_dialog.h +++ b/editor/editor_locale_dialog.h @@ -40,7 +40,7 @@ class VBoxContainer; class LineEdit; class Tree; class OptionButton; -class UndoRedo; +class EditorUndoRedoManager; class EditorLocaleDialog : public ConfirmationDialog { GDCLASS(EditorLocaleDialog, ConfirmationDialog); @@ -63,7 +63,7 @@ class EditorLocaleDialog : public ConfirmationDialog { Tree *script_list = nullptr; Tree *cnt_list = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool locale_set = false; bool updating_lists = false; diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 8aa099ddff..dc03a1f270 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -224,6 +224,10 @@ void EditorLog::set_tool_button(Button *p_tool_button) { tool_button = p_tool_button; } +void EditorLog::register_undo_redo(UndoRedo *p_undo_redo) { + p_undo_redo->set_commit_notify_callback(_undo_redo_cbk, this); +} + void EditorLog::_undo_redo_cbk(void *p_self, const String &p_name) { EditorLog *self = static_cast<EditorLog *>(p_self); self->add_message(p_name, EditorLog::MSG_TYPE_EDITOR); @@ -458,8 +462,6 @@ EditorLog::EditorLog() { add_error_handler(&eh); current = Thread::get_caller_id(); - - EditorNode::get_undo_redo()->set_commit_notify_callback(_undo_redo_cbk, this); } void EditorLog::deinit() { diff --git a/editor/editor_log.h b/editor/editor_log.h index c225e6d8c5..3bdfd936c1 100644 --- a/editor/editor_log.h +++ b/editor/editor_log.h @@ -41,6 +41,8 @@ #include "scene/gui/texture_button.h" #include "scene/gui/texture_rect.h" +class UndoRedo; + class EditorLog : public HBoxContainer { GDCLASS(EditorLog, HBoxContainer); @@ -182,6 +184,7 @@ protected: public: void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD); void set_tool_button(Button *p_tool_button); + void register_undo_redo(UndoRedo *p_undo_redo); void deinit(); void clear(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 2941ae6695..ad0be0c35e 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -105,6 +105,7 @@ #include "editor/editor_themes.h" #include "editor/editor_toaster.h" #include "editor/editor_translation_parser.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/export/editor_export.h" #include "editor/export/export_template_manager.h" #include "editor/export/project_export.h" @@ -349,8 +350,7 @@ void EditorNode::_update_scene_tabs() { icon = EditorNode::get_singleton()->get_object_icon(type_node, "Node"); } - int current = editor_data.get_edited_scene(); - bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0; + bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i)); scene_tabs->add_tab(disambiguated_scene_names[i] + (unsaved ? "(*)" : ""), icon); if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) { @@ -597,15 +597,15 @@ 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()); - unsaved_cache_changed = true; + bool global_unsaved = get_undo_redo()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY); + bool scene_or_global_unsaved = global_unsaved || get_undo_redo()->is_history_unsaved(editor_data.get_current_edited_scene_history_id()); + if (unsaved_cache != scene_or_global_unsaved) { + unsaved_cache = scene_or_global_unsaved; + _update_title(); } - if (last_checked_version != editor_data.get_undo_redo().get_version()) { + if (editor_data.is_scene_changed(-1)) { _update_scene_tabs(); - last_checked_version = editor_data.get_undo_redo().get_version(); } // Update the animation frame of the update spinner. @@ -631,7 +631,7 @@ void EditorNode::_notification(int p_what) { ResourceImporterTexture::get_singleton()->update_imports(); - if (settings_changed || unsaved_cache_changed) { + if (settings_changed) { _update_title(); } @@ -1127,7 +1127,6 @@ void EditorNode::_reload_modified_scenes() { } } - get_undo_redo()->clear_history(false); set_current_scene(current_idx); _update_scene_tabs(); disk_changed->hide(); @@ -1681,6 +1680,8 @@ int EditorNode::_save_external_resources() { saved++; } + get_undo_redo()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY); + return saved; } @@ -1762,11 +1763,7 @@ void EditorNode::_save_scene(String p_file, int idx) { if (err == OK) { scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(p_file)); - if (idx < 0 || idx == editor_data.get_edited_scene()) { - set_current_version(editor_data.get_undo_redo().get_version()); - } else { - editor_data.set_edited_scene_version(0, idx); - } + editor_data.set_scene_as_saved(idx); editor_data.set_scene_modified_time(idx, FileAccess::get_modified_time(p_file)); editor_folding.save_scene_folding(scene, p_file); @@ -1858,12 +1855,9 @@ void EditorNode::_mark_unsaved_scenes() { } String path = node->get_scene_file_path(); - if (!(path.is_empty() || FileAccess::exists(path))) { - if (i == editor_data.get_edited_scene()) { - set_current_version(-1); - } else { - editor_data.set_edited_scene_version(-1, i); - } + if (!path.is_empty() && !FileAccess::exists(path)) { + // Mark scene tab as unsaved if the file is gone. + get_undo_redo()->set_history_as_unsaved(editor_data.get_scene_history_id(i)); } } @@ -2721,9 +2715,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) { log->add_message(TTR("Can't undo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR); } else { - String action = editor_data.get_undo_redo().get_current_action_name(); + String action = editor_data.get_undo_redo()->get_current_action_name(); - if (!editor_data.get_undo_redo().undo()) { + if (!editor_data.get_undo_redo()->undo()) { log->add_message(TTR("Nothing to undo."), EditorLog::MSG_TYPE_EDITOR); } else if (!action.is_empty()) { log->add_message(vformat(TTR("Undo: %s"), action), EditorLog::MSG_TYPE_EDITOR); @@ -2734,10 +2728,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) { log->add_message(TTR("Can't redo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR); } else { - if (!editor_data.get_undo_redo().redo()) { + if (!editor_data.get_undo_redo()->redo()) { log->add_message(TTR("Nothing to redo."), EditorLog::MSG_TYPE_EDITOR); } else { - String action = editor_data.get_undo_redo().get_current_action_name(); + String action = editor_data.get_undo_redo()->get_current_action_name(); log->add_message(vformat(TTR("Redo: %s"), action), EditorLog::MSG_TYPE_EDITOR); } } @@ -2772,7 +2766,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { ERR_PRINT("Failed to load scene"); } editor_data.move_edited_scene_to_index(cur_idx); - get_undo_redo()->clear_history(false); + get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id()); scene_tabs->set_current_tab(cur_idx); } break; @@ -3085,8 +3079,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) { if (!editor_data.get_edited_scene_root(i)) { continue; } - int current = editor_data.get_edited_scene(); - bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0; + bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i)); if (unsaved) { String scene_filename = editor_data.get_edited_scene_root(i)->get_scene_file_path(); if (p_valid_filename && scene_filename.length() == 0) { @@ -3193,9 +3186,9 @@ void EditorNode::_update_file_menu_opened() { file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty()); - const UndoRedo &undo_redo = editor_data.get_undo_redo(); - file_menu->set_item_disabled(file_menu->get_item_index(EDIT_UNDO), !undo_redo.has_undo()); - file_menu->set_item_disabled(file_menu->get_item_index(EDIT_REDO), !undo_redo.has_redo()); + Ref<EditorUndoRedoManager> undo_redo = editor_data.get_undo_redo(); + file_menu->set_item_disabled(file_menu->get_item_index(EDIT_UNDO), !undo_redo->has_undo()); + file_menu->set_item_disabled(file_menu->get_item_index(EDIT_REDO), !undo_redo->has_redo()); } void EditorNode::_update_file_menu_closed() { @@ -3451,7 +3444,6 @@ void EditorNode::_remove_edited_scene(bool p_change_tab) { _scene_tab_changed(new_index); } editor_data.remove_scene(old_index); - editor_data.get_undo_redo().clear_history(false); _update_title(); _update_scene_tabs(); } @@ -3507,7 +3499,6 @@ Dictionary EditorNode::_get_main_scene_state() { state["main_tab"] = _get_current_main_editor(); state["scene_tree_offset"] = SceneTreeDock::get_singleton()->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->get_value(); state["property_edit_offset"] = InspectorDock::get_inspector_singleton()->get_scroll_offset(); - state["saved_version"] = saved_version; state["node_filter"] = SceneTreeDock::get_singleton()->get_filter(); return state; } @@ -3567,11 +3558,6 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) { editor_data.notify_edited_scene_changed(); } -void EditorNode::set_current_version(uint64_t p_version) { - saved_version = p_version; - editor_data.set_edited_scene_version(p_version); -} - bool EditorNode::is_changing_scene() const { return changing_scene; } @@ -3591,7 +3577,7 @@ void EditorNode::set_current_scene(int p_idx) { editor_folding.load_scene_folding(editor_data.get_edited_scene_root(p_idx), editor_data.get_scene_path(p_idx)); } - call_deferred(SNAME("_clear_undo_history")); + get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(p_idx)); } changing_scene = true; @@ -3608,8 +3594,8 @@ void EditorNode::set_current_scene(int p_idx) { Node *new_scene = editor_data.get_edited_scene_root(); - if (Object::cast_to<Popup>(new_scene)) { - Object::cast_to<Popup>(new_scene)->show(); + if (Popup *p = Object::cast_to<Popup>(new_scene)) { + p->show(); } SceneTreeDock::get_singleton()->set_edited_scene(new_scene); @@ -3627,6 +3613,7 @@ void EditorNode::set_current_scene(int p_idx) { _edit_current(true); _update_title(); + _update_scene_tabs(); call_deferred(SNAME("_set_main_scene_state"), state, get_edited_scene()); // Do after everything else is done setting up. } @@ -3785,7 +3772,6 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b set_edited_scene(new_scene); _get_scene_metadata(p_scene); - saved_version = editor_data.get_undo_redo().get_version(); _update_title(); _update_scene_tabs(); _add_to_recent_scenes(lpath); @@ -3836,6 +3822,10 @@ void EditorNode::request_instantiate_scenes(const Vector<String> &p_files) { SceneTreeDock::get_singleton()->instantiate_scenes(p_files); } +Ref<EditorUndoRedoManager> &EditorNode::get_undo_redo() { + return singleton->editor_data.get_undo_redo(); +} + void EditorNode::_inherit_request(String p_file) { current_menu_option = FILE_NEW_INHERITED_SCENE; _dialog_action(p_file); @@ -3996,6 +3986,7 @@ void EditorNode::register_editor_types() { GDREGISTER_CLASS(EditorSpinSlider); GDREGISTER_CLASS(EditorResourcePicker); GDREGISTER_CLASS(EditorScriptPicker); + GDREGISTER_ABSTRACT_CLASS(EditorUndoRedoManager); GDREGISTER_ABSTRACT_CLASS(FileSystemDock); GDREGISTER_VIRTUAL_CLASS(EditorFileSystemImportFormatSupportQuery); @@ -5128,9 +5119,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) { return; } - bool unsaved = (p_tab == editor_data.get_edited_scene()) - ? saved_version != editor_data.get_undo_redo().get_version() - : editor_data.get_scene_version(p_tab) != 0; + bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(p_tab)); if (unsaved) { save_confirmation->set_ok_button_text(TTR("Save & Close")); save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene->get_scene_file_path().is_empty() ? scene->get_scene_file_path() : "unsaved scene")); @@ -5242,23 +5231,10 @@ void EditorNode::_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_p void EditorNode::_scene_tab_changed(int p_tab) { tab_preview_panel->hide(); - bool unsaved = (saved_version != editor_data.get_undo_redo().get_version()); - if (p_tab == editor_data.get_edited_scene()) { return; // Pointless. } - - uint64_t next_scene_version = editor_data.get_scene_version(p_tab); - - editor_data.get_undo_redo().create_action(TTR("Switch Scene Tab")); - editor_data.get_undo_redo().add_do_method(this, "set_current_version", unsaved ? saved_version : 0); - editor_data.get_undo_redo().add_do_method(this, "set_current_scene", p_tab); - editor_data.get_undo_redo().add_do_method(this, "set_current_version", next_scene_version == 0 ? editor_data.get_undo_redo().get_version() + 1 : next_scene_version); - - editor_data.get_undo_redo().add_undo_method(this, "set_current_version", next_scene_version); - editor_data.get_undo_redo().add_undo_method(this, "set_current_scene", editor_data.get_edited_scene()); - editor_data.get_undo_redo().add_undo_method(this, "set_current_version", saved_version); - editor_data.get_undo_redo().commit_action(); + set_current_scene(p_tab); } Button *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) { @@ -5644,7 +5620,7 @@ void EditorNode::reload_scene(const String &p_path) { if (scene_idx == -1) { if (get_edited_scene()) { // Scene is not open, so at it might be instantiated. We'll refresh the whole scene later. - editor_data.get_undo_redo().clear_history(); + editor_data.get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id()); } return; } @@ -5660,7 +5636,7 @@ void EditorNode::reload_scene(const String &p_path) { // Adjust index so tab is back a the previous position. editor_data.move_edited_scene_to_index(scene_idx); - get_undo_redo()->clear_history(); + get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(scene_idx)); // Recover the tab. scene_tabs->set_current_tab(current_tab); @@ -5844,7 +5820,6 @@ void EditorNode::_bind_methods() { ClassDB::bind_method("stop_child_process", &EditorNode::stop_child_process); ClassDB::bind_method("set_current_scene", &EditorNode::set_current_scene); - ClassDB::bind_method("set_current_version", &EditorNode::set_current_version); ClassDB::bind_method("_thumbnail_done", &EditorNode::_thumbnail_done); ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state); ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes); diff --git a/editor/editor_node.h b/editor/editor_node.h index f7a102b4c7..858e300ee5 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -72,6 +72,7 @@ class EditorRun; class EditorRunNative; class EditorSettingsDialog; class EditorToaster; +class EditorUndoRedoManager; class ExportTemplateManager; class FileDialog; class FileSystemDock; @@ -471,9 +472,6 @@ private: String open_navigate; String run_custom_filename; - uint64_t saved_version = 1; - uint64_t last_checked_version = 0; - DynamicFontImportSettings *fontdata_import_settings = nullptr; SceneImportSettings *scene_import_settings = nullptr; AudioStreamImportSettings *audio_stream_import_settings = nullptr; @@ -705,7 +703,7 @@ public: static EditorLog *get_log() { return singleton->log; } static EditorData &get_editor_data() { return singleton->editor_data; } static EditorFolding &get_editor_folding() { return singleton->editor_folding; } - static UndoRedo *get_undo_redo() { return &singleton->editor_data.get_undo_redo(); } + static Ref<EditorUndoRedoManager> &get_undo_redo(); static HBoxContainer *get_menu_hb() { return singleton->menu_hb; } static VSplitContainer *get_top_split() { return singleton->top_split; } @@ -789,7 +787,6 @@ public: bool is_scene_open(const String &p_path); - void set_current_version(uint64_t p_version); void set_current_scene(int p_idx); void setup_color_picker(ColorPicker *picker); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 400ad1ebac..3750674e2f 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -35,6 +35,7 @@ #include "editor/editor_paths.h" #include "editor/editor_resource_preview.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/export/editor_export.h" #include "editor/filesystem_dock.h" #include "editor/plugins/canvas_item_editor_plugin.h" @@ -885,7 +886,7 @@ void EditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("make_bottom_panel_item_visible", "item"), &EditorPlugin::make_bottom_panel_item_visible); ClassDB::bind_method(D_METHOD("hide_bottom_panel"), &EditorPlugin::hide_bottom_panel); - ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::_get_undo_redo); + ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::get_undo_redo); ClassDB::bind_method(D_METHOD("add_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::add_undo_redo_inspector_hook_callback); ClassDB::bind_method(D_METHOD("remove_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::remove_undo_redo_inspector_hook_callback); ClassDB::bind_method(D_METHOD("queue_save_layout"), &EditorPlugin::queue_save_layout); @@ -965,6 +966,10 @@ void EditorPlugin::_bind_methods() { BIND_ENUM_CONSTANT(DOCK_SLOT_MAX); } +Ref<EditorUndoRedoManager> EditorPlugin::get_undo_redo() { + return undo_redo; +} + EditorPluginCreateFunc EditorPlugins::creation_funcs[MAX_CREATE_FUNCS]; int EditorPlugins::creation_func_count = 0; diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 3f9d276b6a..e450dcc5c0 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -53,6 +53,7 @@ class EditorImportPlugin; class EditorExportPlugin; class EditorNode3DGizmoPlugin; class EditorResourcePreview; +class EditorUndoRedoManager; class EditorFileSystem; class EditorToolAddons; class EditorPaths; @@ -129,9 +130,7 @@ public: class EditorPlugin : public Node { GDCLASS(EditorPlugin, Node); friend class EditorData; - UndoRedo *undo_redo = nullptr; - - UndoRedo *_get_undo_redo() { return undo_redo; } + Ref<EditorUndoRedoManager> undo_redo; bool input_event_forwarding_always_enabled = false; bool force_draw_over_forwarding_enabled = false; @@ -144,7 +143,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - UndoRedo &get_undo_redo() { return *undo_redo; } + Ref<EditorUndoRedoManager> get_undo_redo(); void add_custom_type(const String &p_type, const String &p_base, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon); void remove_custom_type(const String &p_type); diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index 08ff63551f..67c602ad2d 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -40,6 +40,7 @@ #include "editor/editor_property_name_processor.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/margin_container.h" void EditorSettingsDialog::ok_pressed() { @@ -124,9 +125,9 @@ void EditorSettingsDialog::_notification(int p_what) { } break; case NOTIFICATION_READY: { - undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, nullptr); - undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, nullptr); - undo_redo->set_commit_notify_callback(_undo_redo_callback, this); + undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, nullptr); + undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, nullptr); + undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_commit_notify_callback(_undo_redo_callback, this); } break; case NOTIFICATION_ENTER_TREE: { @@ -680,7 +681,7 @@ void EditorSettingsDialog::_bind_methods() { EditorSettingsDialog::EditorSettingsDialog() { set_title(TTR("Editor Settings")); - undo_redo = memnew(UndoRedo); + undo_redo = EditorNode::get_undo_redo(); tabs = memnew(TabContainer); tabs->set_theme_type_variation("TabContainerOdd"); @@ -776,5 +777,4 @@ EditorSettingsDialog::EditorSettingsDialog() { } EditorSettingsDialog::~EditorSettingsDialog() { - memdelete(undo_redo); } diff --git a/editor/editor_settings_dialog.h b/editor/editor_settings_dialog.h index a1ea54c6fb..87ed6a77eb 100644 --- a/editor/editor_settings_dialog.h +++ b/editor/editor_settings_dialog.h @@ -40,6 +40,8 @@ #include "scene/gui/tab_container.h" #include "scene/gui/texture_rect.h" +class EditorUndoRedoManager; + class EditorSettingsDialog : public AcceptDialog { GDCLASS(EditorSettingsDialog, AcceptDialog); @@ -73,7 +75,7 @@ class EditorSettingsDialog : public AcceptDialog { Timer *timer = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; virtual void cancel_pressed() override; virtual void ok_pressed() override; diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp new file mode 100644 index 0000000000..eca2b3143b --- /dev/null +++ b/editor/editor_undo_redo_manager.cpp @@ -0,0 +1,442 @@ +/*************************************************************************/ +/* editor_undo_redo_manager.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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_undo_redo_manager.h" + +#include "core/io/resource.h" +#include "core/os/os.h" +#include "core/templates/local_vector.h" +#include "editor/editor_log.h" +#include "editor/editor_node.h" +#include "scene/main/node.h" + +EditorUndoRedoManager::History &EditorUndoRedoManager::get_or_create_history(int p_idx) { + if (!history_map.has(p_idx)) { + History history; + history.undo_redo = memnew(UndoRedo); + history.id = p_idx; + history_map[p_idx] = history; + + EditorNode::get_singleton()->get_log()->register_undo_redo(history.undo_redo); + EditorDebuggerNode::get_singleton()->register_undo_redo(history.undo_redo); + } + return history_map[p_idx]; +} + +UndoRedo *EditorUndoRedoManager::get_history_undo_redo(int p_idx) const { + ERR_FAIL_COND_V(!history_map.has(p_idx), nullptr); + return history_map[p_idx].undo_redo; +} + +int EditorUndoRedoManager::get_history_id_for_object(Object *p_object) const { + int history_id = INVALID_HISTORY; + + if (Node *node = Object::cast_to<Node>(p_object)) { + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); + + if (edited_scene && (node == edited_scene || edited_scene->is_ancestor_of(node))) { + int idx = EditorNode::get_singleton()->get_editor_data().get_current_edited_scene_history_id(); + if (idx > 0) { + history_id = idx; + } + } + } + + if (Resource *res = Object::cast_to<Resource>(p_object)) { + if (res->is_built_in()) { + if (res->get_path().is_empty()) { + int idx = EditorNode::get_singleton()->get_editor_data().get_current_edited_scene_history_id(); + if (idx > 0) { + history_id = idx; + } + } else { + int idx = EditorNode::get_singleton()->get_editor_data().get_scene_history_id_from_path(res->get_path().get_slice("::", 0)); + if (idx > 0) { + history_id = idx; + } + } + } + } + + if (history_id == INVALID_HISTORY) { + if (pending_action.history_id != INVALID_HISTORY) { + history_id = pending_action.history_id; + } else { + history_id = GLOBAL_HISTORY; + } + } + return history_id; +} + +EditorUndoRedoManager::History &EditorUndoRedoManager::get_history_for_object(Object *p_object) { + int history_id = get_history_id_for_object(p_object); + ERR_FAIL_COND_V_MSG(pending_action.history_id != INVALID_HISTORY && history_id != pending_action.history_id, get_or_create_history(pending_action.history_id), vformat("UndoRedo history mismatch: expected %d, got %d.", pending_action.history_id, history_id)); + + History &history = get_or_create_history(history_id); + if (pending_action.history_id == INVALID_HISTORY) { + pending_action.history_id = history_id; + history.undo_redo->create_action(pending_action.action_name, pending_action.merge_mode); + } + + return history; +} + +void EditorUndoRedoManager::create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode) { + pending_action.action_name = p_name; + pending_action.timestamp = OS::get_singleton()->get_unix_time(); + pending_action.merge_mode = p_mode; + + if (p_history_id != INVALID_HISTORY) { + pending_action.history_id = p_history_id; + History &history = get_or_create_history(p_history_id); + history.undo_redo->create_action(pending_action.action_name, pending_action.merge_mode); + } +} + +void EditorUndoRedoManager::create_action(const String &p_name, UndoRedo::MergeMode p_mode, Object *p_custom_context) { + create_action_for_history(p_name, INVALID_HISTORY, p_mode); + + if (p_custom_context) { + // This assigns context to pending action. + get_history_for_object(p_custom_context); + } +} + +void EditorUndoRedoManager::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_do_methodp(p_object, p_method, p_args, p_argcount); +} + +void EditorUndoRedoManager::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_undo_methodp(p_object, p_method, p_args, p_argcount); +} + +void EditorUndoRedoManager::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + if (p_argcount < 2) { + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = 0; + return; + } + + if (p_args[0]->get_type() != Variant::OBJECT) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + return; + } + + if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::STRING_NAME; + return; + } + + r_error.error = Callable::CallError::CALL_OK; + + Object *object = *p_args[0]; + StringName method = *p_args[1]; + + add_do_methodp(object, method, p_args + 2, p_argcount - 2); +} + +void EditorUndoRedoManager::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + if (p_argcount < 2) { + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_error.argument = 0; + return; + } + + if (p_args[0]->get_type() != Variant::OBJECT) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + return; + } + + if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::STRING_NAME; + return; + } + + r_error.error = Callable::CallError::CALL_OK; + + Object *object = *p_args[0]; + StringName method = *p_args[1]; + + add_undo_methodp(object, method, p_args + 2, p_argcount - 2); +} + +void EditorUndoRedoManager::add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_do_property(p_object, p_property, p_value); +} + +void EditorUndoRedoManager::add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_undo_property(p_object, p_property, p_value); +} + +void EditorUndoRedoManager::add_do_reference(Object *p_object) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_do_reference(p_object); +} + +void EditorUndoRedoManager::add_undo_reference(Object *p_object) { + UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; + undo_redo->add_undo_reference(p_object); +} + +void EditorUndoRedoManager::commit_action(bool p_execute) { + ERR_FAIL_COND(pending_action.history_id == INVALID_HISTORY); + is_committing = true; + + History &history = get_or_create_history(pending_action.history_id); + history.undo_redo->commit_action(p_execute); + history.redo_stack.clear(); + + if (!history.undo_stack.is_empty()) { + const Action &prev_action = history.undo_stack.back()->get(); + if (pending_action.merge_mode != UndoRedo::MERGE_DISABLE && pending_action.merge_mode == prev_action.merge_mode && pending_action.action_name == prev_action.action_name) { + // Discard action if it should be merged (UndoRedo handles merging internally). + pending_action = Action(); + is_committing = false; + return; + } + } + + history.undo_stack.push_back(pending_action); + pending_action = Action(); + is_committing = false; +} + +bool EditorUndoRedoManager::is_committing_action() const { + return is_committing; +} + +bool EditorUndoRedoManager::undo() { + if (!has_undo()) { + return false; + } + + History *selected_history = nullptr; + double global_timestamp = 0; + + // Pick the history with greatest last action timestamp (either global or current scene). + { + History &history = get_or_create_history(GLOBAL_HISTORY); + if (!history.undo_stack.is_empty()) { + selected_history = &history; + global_timestamp = history.undo_stack.back()->get().timestamp; + } + } + + { + History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id()); + if (!history.undo_stack.is_empty() && history.undo_stack.back()->get().timestamp > global_timestamp) { + selected_history = &history; + } + } + + if (selected_history) { + Action action = selected_history->undo_stack.back()->get(); + selected_history->undo_stack.pop_back(); + selected_history->redo_stack.push_back(action); + return selected_history->undo_redo->undo(); + } + return false; +} + +bool EditorUndoRedoManager::redo() { + if (!has_redo()) { + return false; + } + + History *selected_history = nullptr; + double global_timestamp = INFINITY; + + // Pick the history with lowest last action timestamp (either global or current scene). + { + History &history = get_or_create_history(GLOBAL_HISTORY); + if (!history.redo_stack.is_empty()) { + selected_history = &history; + global_timestamp = history.redo_stack.back()->get().timestamp; + } + } + + { + History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id()); + if (!history.redo_stack.is_empty() && history.redo_stack.back()->get().timestamp < global_timestamp) { + selected_history = &history; + } + } + + if (selected_history) { + Action action = selected_history->redo_stack.back()->get(); + selected_history->redo_stack.pop_back(); + selected_history->undo_stack.push_back(action); + return selected_history->undo_redo->redo(); + } + return false; +} + +void EditorUndoRedoManager::set_history_as_saved(int p_id) { + History &history = get_or_create_history(p_id); + history.saved_version = history.undo_redo->get_version(); +} + +void EditorUndoRedoManager::set_history_as_unsaved(int p_id) { + History &history = get_or_create_history(p_id); + history.saved_version = -1; +} + +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; +} + +bool EditorUndoRedoManager::has_undo() { + for (const KeyValue<int, History> &E : history_map) { + if ((E.key == GLOBAL_HISTORY || E.key == EditorNode::get_editor_data().get_current_edited_scene_history_id()) && !E.value.undo_stack.is_empty()) { + return true; + } + } + return false; +} + +bool EditorUndoRedoManager::has_redo() { + for (const KeyValue<int, History> &E : history_map) { + if ((E.key == GLOBAL_HISTORY || E.key == EditorNode::get_editor_data().get_current_edited_scene_history_id()) && !E.value.redo_stack.is_empty()) { + return true; + } + } + return false; +} + +void EditorUndoRedoManager::clear_history(bool p_increase_version, int p_idx) { + if (p_idx != INVALID_HISTORY) { + get_or_create_history(p_idx).undo_redo->clear_history(p_increase_version); + if (!p_increase_version) { + set_history_as_saved(p_idx); + } + return; + } + + for (const KeyValue<int, History> &E : history_map) { + E.value.undo_redo->clear_history(p_increase_version); + set_history_as_saved(E.key); + } +} + +String EditorUndoRedoManager::get_current_action_name() { + if (has_undo()) { + History *selected_history = nullptr; + double global_timestamp = 0; + + // Pick the history with greatest last action timestamp (either global or current scene). + { + History &history = get_or_create_history(GLOBAL_HISTORY); + if (!history.undo_stack.is_empty()) { + selected_history = &history; + global_timestamp = history.undo_stack.back()->get().timestamp; + } + } + + { + History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id()); + if (!history.undo_stack.is_empty() && history.undo_stack.back()->get().timestamp > global_timestamp) { + selected_history = &history; + } + } + + if (selected_history) { + return selected_history->undo_redo->get_current_action_name(); + } + } + return ""; +} + +void EditorUndoRedoManager::discard_history(int p_idx, bool p_erase_from_map) { + ERR_FAIL_COND(!history_map.has(p_idx)); + History &history = history_map[p_idx]; + + if (history.undo_redo) { + memdelete(history.undo_redo); + history.undo_redo = nullptr; + } + + if (p_erase_from_map) { + history_map.erase(p_idx); + } +} + +void EditorUndoRedoManager::_bind_methods() { + ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode", "custom_context"), &EditorUndoRedoManager::create_action, DEFVAL(UndoRedo::MERGE_DISABLE), DEFVAL((Object *)nullptr)); + 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); + + { + MethodInfo mi; + mi.name = "add_do_method"; + mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object")); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); + + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_do_method", &EditorUndoRedoManager::_add_do_method, mi, varray(), false); + } + + { + MethodInfo mi; + mi.name = "add_undo_method"; + mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object")); + mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method")); + + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_undo_method", &EditorUndoRedoManager::_add_undo_method, mi, varray(), false); + } + + ClassDB::bind_method(D_METHOD("add_do_property", "object", "property", "value"), &EditorUndoRedoManager::add_do_property); + ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &EditorUndoRedoManager::add_undo_property); + ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &EditorUndoRedoManager::add_do_reference); + ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &EditorUndoRedoManager::add_undo_reference); + + ClassDB::bind_method(D_METHOD("get_object_history_id", "object"), &EditorUndoRedoManager::get_history_id_for_object); + ClassDB::bind_method(D_METHOD("get_history_undo_redo", "id"), &EditorUndoRedoManager::get_history_undo_redo); + + BIND_ENUM_CONSTANT(GLOBAL_HISTORY); + BIND_ENUM_CONSTANT(INVALID_HISTORY); +} + +EditorUndoRedoManager::~EditorUndoRedoManager() { + for (const KeyValue<int, History> &E : history_map) { + discard_history(E.key, false); + } +} diff --git a/editor/editor_undo_redo_manager.h b/editor/editor_undo_redo_manager.h new file mode 100644 index 0000000000..c4d85daa22 --- /dev/null +++ b/editor/editor_undo_redo_manager.h @@ -0,0 +1,134 @@ +/*************************************************************************/ +/* editor_undo_redo_manager.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 EDITOR_UNDO_REDO_MANAGER_H +#define EDITOR_UNDO_REDO_MANAGER_H + +#include "core/object/class_db.h" +#include "core/object/ref_counted.h" +#include "core/object/undo_redo.h" + +class EditorUndoRedoManager : public RefCounted { + GDCLASS(EditorUndoRedoManager, RefCounted); + +public: + enum SpecialHistory { + GLOBAL_HISTORY = 0, + INVALID_HISTORY = -99, + }; + +private: + struct Action { + int history_id = INVALID_HISTORY; + double timestamp = 0; + String action_name; + UndoRedo::MergeMode merge_mode = UndoRedo::MERGE_DISABLE; + }; + + struct History { + int id = INVALID_HISTORY; + UndoRedo *undo_redo = nullptr; + uint64_t saved_version = 1; + List<Action> undo_stack; + List<Action> redo_stack; + }; + + HashMap<int, History> history_map; + Action pending_action; + + bool is_committing = false; + +protected: + static void _bind_methods(); + +public: + History &get_or_create_history(int p_idx); + UndoRedo *get_history_undo_redo(int p_idx) const; + int get_history_id_for_object(Object *p_object) const; + History &get_history_for_object(Object *p_object); + + void create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE); + void create_action(const String &p_name = "", UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE, Object *p_custom_context = nullptr); + + 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); + + template <typename... VarArgs> + void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + + add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + + template <typename... VarArgs> + void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + + add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + + void _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error); + void _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error); + + void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value); + void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value); + void add_do_reference(Object *p_object); + void add_undo_reference(Object *p_object); + + void commit_action(bool p_execute = true); + bool is_committing_action() const; + + bool undo(); + bool redo(); + void clear_history(bool p_increase_version = true, int p_idx = INVALID_HISTORY); + + void set_history_as_saved(int p_idx); + void set_history_as_unsaved(int p_idx); + bool is_history_unsaved(int p_idx); + bool has_undo(); + bool has_redo(); + + String get_current_action_name(); + + void discard_history(int p_idx, bool p_erase_from_map = true); + ~EditorUndoRedoManager(); +}; + +VARIANT_ENUM_CAST(EditorUndoRedoManager::SpecialHistory); + +#endif // EDITOR_UNDO_REDO_MANAGER_H diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index f16097f109..15add50fd4 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "editor/scene_tree_editor.h" #include "scene/gui/box_container.h" @@ -397,6 +398,10 @@ void GroupDialog::_notification(int p_what) { } } +void GroupDialog::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void GroupDialog::edit() { popup_centered(); @@ -696,6 +701,10 @@ void GroupsEditor::update_tree() { } } +void GroupsEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void GroupsEditor::set_current(Node *p_node) { node = p_node; update_tree(); diff --git a/editor/groups_editor.h b/editor/groups_editor.h index fec8913e31..8bbea4e652 100644 --- a/editor/groups_editor.h +++ b/editor/groups_editor.h @@ -31,7 +31,6 @@ #ifndef GROUPS_EDITOR_H #define GROUPS_EDITOR_H -#include "core/object/undo_redo.h" #include "editor/scene_tree_editor.h" #include "scene/gui/button.h" #include "scene/gui/dialogs.h" @@ -40,6 +39,8 @@ #include "scene/gui/popup.h" #include "scene/gui/tree.h" +class EditorUndoRedoManager; + class GroupDialog : public AcceptDialog { GDCLASS(GroupDialog, AcceptDialog); @@ -68,7 +69,7 @@ class GroupDialog : public AcceptDialog { String selected_group; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _group_selected(); @@ -103,7 +104,7 @@ public: }; void edit(); - void set_undo_redo(UndoRedo *p_undoredo) { undo_redo = p_undoredo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); GroupDialog(); }; @@ -119,7 +120,7 @@ class GroupsEditor : public VBoxContainer { Button *add = nullptr; Tree *tree = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void update_tree(); void _add_group(const String &p_group = ""); @@ -137,7 +138,7 @@ public: COPY_GROUP, }; - void set_undo_redo(UndoRedo *p_undoredo) { undo_redo = p_undoredo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_current(Node *p_node); GroupsEditor(); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 79d94246ad..1bcbd2fe00 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -178,7 +178,8 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) { } } - editor_data->get_undo_redo().clear_history(); + int history_id = editor_data->get_undo_redo()->get_history_for_object(current).id; + editor_data->get_undo_redo()->clear_history(true, history_id); EditorNode::get_singleton()->get_editor_plugins_over()->edit(nullptr); EditorNode::get_singleton()->get_editor_plugins_over()->edit(current); @@ -755,7 +756,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { inspector->set_property_name_style(EditorPropertyNameProcessor::get_default_inspector_style()); inspector->set_use_folding(!bool(EDITOR_GET("interface/inspector/disable_folding"))); inspector->register_text_enter(search); - inspector->set_undo_redo(&editor_data->get_undo_redo()); + inspector->set_undo_redo(editor_data->get_undo_redo()); inspector->set_use_filter(true); // TODO: check me diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp index e8fb80eb57..77a1700ebf 100644 --- a/editor/localization_editor.cpp +++ b/editor/localization_editor.cpp @@ -36,6 +36,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_translation_parser.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/filesystem_dock.h" #include "editor/pot_generator.h" #include "scene/gui/control.h" diff --git a/editor/localization_editor.h b/editor/localization_editor.h index 10ccdfdc13..ecac171fe3 100644 --- a/editor/localization_editor.h +++ b/editor/localization_editor.h @@ -56,7 +56,7 @@ class LocalizationEditor : public VBoxContainer { EditorFileDialog *pot_file_open_dialog = nullptr; EditorFileDialog *pot_generate_dialog = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool updating_translations = false; String localization_changed; diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp index a694b8d754..70cc54668d 100644 --- a/editor/multi_node_edit.cpp +++ b/editor/multi_node_edit.cpp @@ -32,6 +32,7 @@ #include "core/math/math_fieldwise.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" bool MultiNodeEdit::_set(const StringName &p_name, const Variant &p_value) { return _set_impl(p_name, p_value, ""); @@ -54,7 +55,7 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value, node_path_target = es->get_node(p_value); } - UndoRedo *ur = EditorNode::get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("MultiNode Set") + " " + String(name), UndoRedo::MERGE_ENDS); for (const NodePath &E : nodes) { diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp index 986370f537..55fa2f22dd 100644 --- a/editor/node_dock.cpp +++ b/editor/node_dock.cpp @@ -117,7 +117,7 @@ NodeDock::NodeDock() { groups_button->connect("pressed", callable_mp(this, &NodeDock::show_groups)); connections = memnew(ConnectionsDock); - connections->set_undoredo(EditorNode::get_undo_redo()); + connections->set_undo_redo(EditorNode::get_undo_redo()); add_child(connections); connections->set_v_size_flags(SIZE_EXPAND_FILL); connections->hide(); diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index a7d7c0145a..275859f528 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -36,6 +36,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/separator.h" bool AbstractPolygon2DEditor::Vertex::operator==(const AbstractPolygon2DEditor::Vertex &p_vertex) const { diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h index 696fd7b637..1fbbe67c8d 100644 --- a/editor/plugins/abstract_polygon_2d_editor.h +++ b/editor/plugins/abstract_polygon_2d_editor.h @@ -36,6 +36,7 @@ #include "scene/gui/box_container.h" class CanvasItemEditor; +class EditorUndoRedoManager; class AbstractPolygon2DEditor : public HBoxContainer { GDCLASS(AbstractPolygon2DEditor, HBoxContainer); @@ -99,7 +100,7 @@ protected: int mode = MODE_EDIT; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; virtual void _menu_option(int p_option); void _wip_changed(); diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index 32d97c65a9..2578099a9f 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_blend_tree.h" StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const { diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h index 9b06f3248f..125a3382fa 100644 --- a/editor/plugins/animation_blend_space_1d_editor.h +++ b/editor/plugins/animation_blend_space_1d_editor.h @@ -40,6 +40,8 @@ #include "scene/gui/separator.h" #include "scene/gui/tree.h" +class EditorUndoRedoManager; + class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin { GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin); @@ -76,7 +78,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin { bool updating = false; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; static AnimationNodeBlendSpace1DEditor *singleton; diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index dc764725dd..c0723cef87 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -39,6 +39,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_blend_tree.h" #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h index 26471df051..df2bcf254d 100644 --- a/editor/plugins/animation_blend_space_2d_editor.h +++ b/editor/plugins/animation_blend_space_2d_editor.h @@ -40,6 +40,8 @@ #include "scene/gui/separator.h" #include "scene/gui/tree.h" +class EditorUndoRedoManager; + class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin { GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin); @@ -82,7 +84,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin { bool updating; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; static AnimationNodeBlendSpace2DEditor *singleton; diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 79be2d04b3..e4f5576d66 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -39,6 +39,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" #include "scene/gui/panel.h" diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h index 18199676b8..af43da6197 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.h +++ b/editor/plugins/animation_blend_tree_editor_plugin.h @@ -41,6 +41,7 @@ class ProgressBar; class EditorFileDialog; +class EditorUndoRedoManager; class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin); @@ -54,7 +55,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { PanelContainer *error_panel = nullptr; Label *error_label = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; AcceptDialog *filter_dialog = nullptr; Tree *filters = nullptr; diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index c36ae1c521..f9e5aa799a 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -32,6 +32,7 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" void AnimationLibraryEditor::set_animation_player(Object *p_player) { player = p_player; @@ -92,7 +93,7 @@ void AnimationLibraryEditor::_add_library_validate(const String &p_name) { void AnimationLibraryEditor::_add_library_confirm() { if (adding_animation) { String anim_name = add_library_name->get_text(); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library); ERR_FAIL_COND(!al.is_valid()); @@ -109,7 +110,7 @@ void AnimationLibraryEditor::_add_library_confirm() { } else { String lib_name = add_library_name->get_text(); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); Ref<AnimationLibrary> al; al.instantiate(); @@ -203,7 +204,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { // TODO: should probably make all foreign animations assigned to this library // unique too. - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name)); undo_redo->add_do_method(player, "remove_animation_library", lib_name); undo_redo->add_do_method(player, "add_animation_library", lib_name, ald); @@ -272,7 +273,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { Ref<Animation> animd = anim->duplicate(); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Make Animation Unique: %s"), anim_name)); undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name); undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, animd); @@ -320,7 +321,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { name = p_path.get_file().get_basename() + " " + itos(attempt); } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), name)); undo_redo->add_do_method(player, "add_animation_library", name, al); @@ -358,7 +359,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { name = p_path.get_file().get_basename() + " " + itos(attempt); } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Load Animation into Library: %s"), name)); undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); @@ -374,7 +375,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { EditorNode::get_singleton()->save_resource_in_path(al, p_path); if (al->get_path() != prev_path) { // Save successful. - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Save Animation library to File: %s"), file_dialog_library)); undo_redo->add_do_method(al.ptr(), "set_path", al->get_path()); @@ -395,7 +396,7 @@ void AnimationLibraryEditor::_load_file(String p_path) { String prev_path = anim->get_path(); EditorNode::get_singleton()->save_resource_in_path(anim, p_path); if (anim->get_path() != prev_path) { // Save successful. - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Save Animation to File: %s"), file_dialog_animation)); undo_redo->add_do_method(anim.ptr(), "set_path", anim->get_path()); @@ -413,7 +414,7 @@ void AnimationLibraryEditor::_item_renamed() { String text = ti->get_text(0); String old_text = ti->get_metadata(0); bool restore_text = false; - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); if (String(text).contains("/") || String(text).contains(":") || String(text).contains(",") || String(text).contains("[")) { restore_text = true; @@ -527,7 +528,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int name = base_name + " (" + itos(attempt) + ")"; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), name)); undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); @@ -553,7 +554,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int file_dialog_library = lib_name; } break; case LIB_BUTTON_DELETE: { - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Remove Animation Library: %s"), lib_name)); undo_redo->add_do_method(player, "remove_animation_library", lib_name); undo_redo->add_undo_method(player, "add_animation_library", lib_name, al); @@ -594,7 +595,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int } break; case ANIM_BUTTON_DELETE: { - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Remove Animation from Library: %s"), anim_name)); undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name); undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 516079673d..f374f48fb2 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -1045,6 +1045,10 @@ void AnimationPlayerEditor::_update_name_dialog_library_dropdown() { } } +void AnimationPlayerEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void AnimationPlayerEditor::edit(AnimationPlayer *p_player) { if (player && pin->is_pressed()) { return; // Ignore, pinned. @@ -1925,7 +1929,7 @@ void AnimationPlayerEditorPlugin::_update_keying() { } void AnimationPlayerEditorPlugin::edit(Object *p_object) { - anim_editor->set_undo_redo(&get_undo_redo()); + anim_editor->set_undo_redo(get_undo_redo()); if (!p_object) { return; } diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 3b1de070fa..a37a9debef 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -41,6 +41,7 @@ #include "scene/gui/texture_button.h" #include "scene/gui/tree.h" +class EditorUndoRedoManager; class AnimationPlayerEditorPlugin; class AnimationPlayerEditor : public VBoxContainer { @@ -100,7 +101,7 @@ class AnimationPlayerEditor : public VBoxContainer { LineEdit *name = nullptr; OptionButton *library = nullptr; Label *name_title = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Ref<Texture2D> autoplay_icon; Ref<Texture2D> reset_icon; @@ -233,7 +234,7 @@ public: void ensure_visibility(); - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void edit(AnimationPlayer *p_player); void forward_force_draw_over_viewport(Control *p_overlay); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 473450b292..ef4ae3dca4 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -39,6 +39,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_blend_tree.h" #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h index 165940e639..fdd1af0f6d 100644 --- a/editor/plugins/animation_state_machine_editor.h +++ b/editor/plugins/animation_state_machine_editor.h @@ -40,6 +40,7 @@ #include "scene/gui/tree.h" class EditorFileDialog; +class EditorUndoRedoManager; class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { GDCLASS(AnimationNodeStateMachineEditor, AnimationTreeNodeEditorPlugin); @@ -76,7 +77,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin { bool updating = false; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; static AnimationNodeStateMachineEditor *singleton; diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp index 9e551ae0ed..d670197c53 100644 --- a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp +++ b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp @@ -31,6 +31,7 @@ #include "audio_stream_randomizer_editor_plugin.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" void AudioStreamRandomizerEditorPlugin::edit(Object *p_object) { } @@ -43,8 +44,8 @@ void AudioStreamRandomizerEditorPlugin::make_visible(bool p_visible) { } void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - ERR_FAIL_COND(!undo_redo); + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(undo_redo.is_null()); AudioStreamRandomizer *randomizer = Object::cast_to<AudioStreamRandomizer>(p_edited); if (!randomizer) { diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index fc70ace331..5682df845e 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -40,6 +40,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_toaster.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" @@ -3988,6 +3989,10 @@ void CanvasItemEditor::_selection_changed() { selected_from_canvas = false; } +void CanvasItemEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void CanvasItemEditor::edit(CanvasItem *p_canvas_item) { Array selection = editor_selection->get_selected_nodes(); if (selection.size() != 1 || Object::cast_to<Node>(selection[0]) != p_canvas_item) { @@ -5419,7 +5424,7 @@ CanvasItemEditor::CanvasItemEditor() { CanvasItemEditor *CanvasItemEditor::singleton = nullptr; void CanvasItemEditorPlugin::edit(Object *p_object) { - canvas_item_editor->set_undo_redo(&get_undo_redo()); + canvas_item_editor->set_undo_redo(EditorNode::get_undo_redo()); canvas_item_editor->edit(Object::cast_to<CanvasItem>(p_object)); } @@ -5572,34 +5577,34 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & Ref<Texture2D> texture = ResourceCache::get_ref(path); if (parent) { - editor_data->get_undo_redo().add_do_method(parent, "add_child", child, true); - editor_data->get_undo_redo().add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene()); - editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child); + editor_data->get_undo_redo()->add_do_method(parent, "add_child", child, true); + editor_data->get_undo_redo()->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene()); + editor_data->get_undo_redo()->add_do_reference(child); + editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", child); } else { // If no parent is selected, set as root node of the scene. - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", child); - editor_data->get_undo_redo().add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene()); - editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child); + editor_data->get_undo_redo()->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene()); + editor_data->get_undo_redo()->add_do_reference(child); + editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); } if (parent) { String new_name = parent->validate_child_name(child); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo().add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); } if (Object::cast_to<TouchScreenButton>(child) || Object::cast_to<TextureButton>(child)) { - editor_data->get_undo_redo().add_do_property(child, "texture_normal", texture); + editor_data->get_undo_redo()->add_do_property(child, "texture_normal", texture); } else { - editor_data->get_undo_redo().add_do_property(child, "texture", texture); + editor_data->get_undo_redo()->add_do_property(child, "texture", texture); } // make visible for certain node type if (Object::cast_to<Control>(child)) { Size2 texture_size = texture->get_size(); - editor_data->get_undo_redo().add_do_property(child, "rect_size", texture_size); + editor_data->get_undo_redo()->add_do_property(child, "rect_size", texture_size); } else if (Object::cast_to<Polygon2D>(child)) { Size2 texture_size = texture->get_size(); Vector<Vector2> list = { @@ -5608,7 +5613,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & Vector2(texture_size.width, texture_size.height), Vector2(0, texture_size.height) }; - editor_data->get_undo_redo().add_do_property(child, "polygon", list); + editor_data->get_undo_redo()->add_do_property(child, "polygon", list); } // Compute the global position @@ -5617,7 +5622,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & // there's nothing to be used as source position so snapping will work as absolute if enabled target_position = canvas_item_editor->snap_point(target_position); - editor_data->get_undo_redo().add_do_method(child, "set_global_position", target_position); + editor_data->get_undo_redo()->add_do_method(child, "set_global_position", target_position); } bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) { @@ -5642,15 +5647,15 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path)); - editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true); - editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", edited_scene); - editor_data->get_undo_redo().add_do_reference(instantiated_scene); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); + editor_data->get_undo_redo()->add_do_method(parent, "add_child", instantiated_scene, true); + editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_owner", edited_scene); + editor_data->get_undo_redo()->add_do_reference(instantiated_scene); + editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", instantiated_scene); String new_name = parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), path, new_name); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name)); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), path, new_name); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name)); CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instantiated_scene); if (instance_ci) { @@ -5664,7 +5669,7 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons // Preserve instance position of the original scene. target_pos += instance_ci->_edit_get_position(); - editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_position", target_pos); + editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_position", target_pos); } return true; @@ -5682,7 +5687,7 @@ void CanvasItemEditorViewport::_perform_drop_data() { Vector<String> error_files; - editor_data->get_undo_redo().create_action(TTR("Create Node")); + editor_data->get_undo_redo()->create_action(TTR("Create Node")); for (int i = 0; i < selected_files.size(); i++) { String path = selected_files[i]; @@ -5713,7 +5718,7 @@ void CanvasItemEditorViewport::_perform_drop_data() { } } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); if (error_files.size() > 0) { String files_str; diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 04fd819dec..2ca495e5d6 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -45,6 +45,7 @@ class EditorData; class CanvasItemEditorViewport; class ViewPanner; +class EditorUndoRedoManager; class CanvasItemEditorSelectedItem : public Object { GDCLASS(CanvasItemEditorSelectedItem, Object); @@ -400,7 +401,7 @@ private: void _prepare_grid_menu(); void _on_grid_menu_id_pressed(int p_id); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true); Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list); @@ -547,7 +548,7 @@ public: Tool get_current_tool() { return tool; } void set_current_tool(Tool p_tool); - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void edit(CanvasItem *p_canvas_item); void focus_selection(); diff --git a/editor/plugins/cast_2d_editor_plugin.cpp b/editor/plugins/cast_2d_editor_plugin.cpp index 18c38e7ab8..a8d255f997 100644 --- a/editor/plugins/cast_2d_editor_plugin.cpp +++ b/editor/plugins/cast_2d_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "canvas_item_editor_plugin.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/2d/ray_cast_2d.h" #include "scene/2d/shape_cast_2d.h" diff --git a/editor/plugins/cast_2d_editor_plugin.h b/editor/plugins/cast_2d_editor_plugin.h index d9c0cc4a06..85ff497bc7 100644 --- a/editor/plugins/cast_2d_editor_plugin.h +++ b/editor/plugins/cast_2d_editor_plugin.h @@ -35,11 +35,12 @@ #include "scene/2d/node_2d.h" class CanvasItemEditor; +class EditorUndoRedoManager; class Cast2DEditor : public Control { GDCLASS(Cast2DEditor, Control); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; CanvasItemEditor *canvas_item_editor = nullptr; Node2D *node; diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index af20064a8d..11992ad10e 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "canvas_item_editor_plugin.h" #include "core/os/keyboard.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/resources/capsule_shape_2d.h" #include "scene/resources/circle_shape_2d.h" #include "scene/resources/concave_polygon_shape_2d.h" diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h index f7de05ddd1..49e0820ae9 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.h +++ b/editor/plugins/collision_shape_2d_editor_plugin.h @@ -35,6 +35,7 @@ #include "scene/2d/collision_shape_2d.h" class CanvasItemEditor; +class EditorUndoRedoManager; class CollisionShape2DEditor : public Control { GDCLASS(CollisionShape2DEditor, Control); @@ -61,7 +62,7 @@ class CollisionShape2DEditor : public Control { Point2(1, -1), }; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; CanvasItemEditor *canvas_item_editor = nullptr; CollisionShape2D *node = nullptr; diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp index ff5d112956..2a12dc0e89 100644 --- a/editor/plugins/control_editor_plugin.cpp +++ b/editor/plugins/control_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/gui/separator.h" diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h index f1b9190a0b..584d05aab0 100644 --- a/editor/plugins/control_editor_plugin.h +++ b/editor/plugins/control_editor_plugin.h @@ -44,6 +44,8 @@ #include "scene/gui/separator.h" #include "scene/gui/texture_rect.h" +class EditorUndoRedoManager; + // Inspector controls. class ControlPositioningWarning : public MarginContainer { GDCLASS(ControlPositioningWarning, MarginContainer); @@ -203,7 +205,7 @@ public: class ControlEditorToolbar : public HBoxContainer { GDCLASS(ControlEditorToolbar, HBoxContainer); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; EditorSelection *editor_selection = nullptr; ControlEditorPopupButton *anchors_button = nullptr; diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index a7c3c32120..e20d298195 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "core/io/image_loader.h" #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/2d/cpu_particles_2d.h" #include "scene/gui/separator.h" #include "scene/resources/particles_material.h" diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h index cc59bc924f..06ca208463 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.h +++ b/editor/plugins/cpu_particles_2d_editor_plugin.h @@ -39,6 +39,7 @@ class EditorPlugin; class SpinBox; class EditorFileDialog; +class EditorUndoRedoManager; class CPUParticles2DEditorPlugin : public EditorPlugin { GDCLASS(CPUParticles2DEditorPlugin, EditorPlugin); @@ -70,7 +71,7 @@ class CPUParticles2DEditorPlugin : public EditorPlugin { String source_emission_file; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _file_selected(const String &p_file); void _menu_callback(int p_idx); void _generate_emission_mask(); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 8aeab684e3..013a9f10a4 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -139,14 +139,14 @@ void CurveEditor::gui_input(const Ref<InputEvent> &p_event) { if (!mb.is_pressed() && _dragging && mb.get_button_index() == MouseButton::LEFT) { _dragging = false; if (_has_undo_data) { - UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); - ur.create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent")); - ur.add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data()); - ur.add_undo_method(*_curve_ref, "_set_data", _undo_data); + ur->create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent")); + ur->add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data()); + ur->add_undo_method(*_curve_ref, "_set_data", _undo_data); // Note: this will trigger one more "changed" signal even if nothing changes, // but it's ok since it would have fired every frame during the drag anyways - ur.commit_action(); + ur->commit_action(); _has_undo_data = false; } @@ -301,13 +301,13 @@ void CurveEditor::on_preset_item_selected(int preset_id) { break; } - UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); - ur.create_action(TTR("Load Curve Preset")); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + ur->create_action(TTR("Load Curve Preset")); - ur.add_do_method(&curve, "_set_data", curve.get_data()); - ur.add_undo_method(&curve, "_set_data", previous_data); + ur->add_do_method(&curve, "_set_data", curve.get_data()); + ur->add_undo_method(&curve, "_set_data", previous_data); - ur.commit_action(); + ur->commit_action(); } void CurveEditor::_curve_changed() { @@ -435,8 +435,8 @@ CurveEditor::TangentIndex CurveEditor::get_tangent_at(Vector2 pos) const { void CurveEditor::add_point(Vector2 pos) { ERR_FAIL_COND(_curve_ref.is_null()); - UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); - ur.create_action(TTR("Remove Curve Point")); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + ur->create_action(TTR("Remove Curve Point")); Vector2 point_pos = get_world_pos(pos); if (point_pos.y < 0.0) { @@ -449,22 +449,22 @@ void CurveEditor::add_point(Vector2 pos) { int i = _curve_ref->add_point(point_pos); _curve_ref->remove_point(i); - ur.add_do_method(*_curve_ref, "add_point", point_pos); - ur.add_undo_method(*_curve_ref, "remove_point", i); + ur->add_do_method(*_curve_ref, "add_point", point_pos); + ur->add_undo_method(*_curve_ref, "remove_point", i); - ur.commit_action(); + ur->commit_action(); } void CurveEditor::remove_point(int index) { ERR_FAIL_COND(_curve_ref.is_null()); - UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); - ur.create_action(TTR("Remove Curve Point")); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + ur->create_action(TTR("Remove Curve Point")); Curve::Point p = _curve_ref->get_point(index); - ur.add_do_method(*_curve_ref, "remove_point", index); - ur.add_undo_method(*_curve_ref, "add_point", p.position, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode); + ur->add_do_method(*_curve_ref, "remove_point", index); + ur->add_undo_method(*_curve_ref, "add_point", p.position, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode); if (index == _selected_point) { set_selected_point(-1); @@ -474,14 +474,14 @@ void CurveEditor::remove_point(int index) { set_hover_point_index(-1); } - ur.commit_action(); + ur->commit_action(); } void CurveEditor::toggle_linear(TangentIndex tangent) { ERR_FAIL_COND(_curve_ref.is_null()); - UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo(); - ur.create_action(TTR("Toggle Curve Linear Tangent")); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + ur->create_action(TTR("Toggle Curve Linear Tangent")); if (tangent == TANGENT_NONE) { tangent = _selected_tangent; @@ -493,8 +493,8 @@ void CurveEditor::toggle_linear(TangentIndex tangent) { Curve::TangentMode prev_mode = _curve_ref->get_point_left_mode(_selected_point); Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR; - ur.add_do_method(*_curve_ref, "set_point_left_mode", _selected_point, mode); - ur.add_undo_method(*_curve_ref, "set_point_left_mode", _selected_point, prev_mode); + ur->add_do_method(*_curve_ref, "set_point_left_mode", _selected_point, mode); + ur->add_undo_method(*_curve_ref, "set_point_left_mode", _selected_point, prev_mode); } else { bool is_linear = _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR; @@ -502,11 +502,11 @@ void CurveEditor::toggle_linear(TangentIndex tangent) { Curve::TangentMode prev_mode = _curve_ref->get_point_right_mode(_selected_point); Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR; - ur.add_do_method(*_curve_ref, "set_point_right_mode", _selected_point, mode); - ur.add_undo_method(*_curve_ref, "set_point_right_mode", _selected_point, prev_mode); + ur->add_do_method(*_curve_ref, "set_point_right_mode", _selected_point, mode); + ur->add_undo_method(*_curve_ref, "set_point_right_mode", _selected_point, prev_mode); } - ur.commit_action(); + ur->commit_action(); } void CurveEditor::set_selected_point(int index) { diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index 8e6687c836..1487f8b7bc 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "core/io/image_loader.h" #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "scene/2d/cpu_particles_2d.h" #include "scene/gui/separator.h" @@ -111,7 +112,7 @@ void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) { cpu_particles->set_process_mode(particles->get_process_mode()); cpu_particles->set_z_index(particles->get_z_index()); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Convert to CPUParticles2D")); ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", particles, cpu_particles, true, false); ur->add_do_reference(cpu_particles); diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.h b/editor/plugins/gpu_particles_2d_editor_plugin.h index bf49a82166..0229b57c10 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.h +++ b/editor/plugins/gpu_particles_2d_editor_plugin.h @@ -38,6 +38,7 @@ #include "scene/gui/spin_box.h" class EditorFileDialog; +class EditorUndoRedoManager; class GPUParticles2DEditorPlugin : public EditorPlugin { GDCLASS(GPUParticles2DEditorPlugin, EditorPlugin); @@ -75,7 +76,7 @@ class GPUParticles2DEditorPlugin : public EditorPlugin { String source_emission_file; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _file_selected(const String &p_file); void _menu_callback(int p_idx); void _generate_visibility_rect(); diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index 6750f1aa9c..335efd6949 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "core/io/resource_loader.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/scene_tree_dock.h" #include "scene/3d/cpu_particles_3d.h" @@ -271,7 +272,7 @@ void GPUParticles3DEditor::_menu_option(int p_option) { cpu_particles->set_visible(node->is_visible()); cpu_particles->set_process_mode(node->get_process_mode()); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Convert to CPUParticles3D")); ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, cpu_particles, true, false); ur->add_do_reference(cpu_particles); @@ -321,7 +322,7 @@ void GPUParticles3DEditor::_generate_aabb() { node->set_emitting(false); } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Generate Visibility AABB")); ur->add_do_method(node, "set_visibility_aabb", rect); ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb()); diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp index 542aee879b..460178490e 100644 --- a/editor/plugins/gradient_editor_plugin.cpp +++ b/editor/plugins/gradient_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" Size2 GradientEditor::get_minimum_size() const { @@ -55,7 +56,7 @@ void GradientEditor::_gradient_changed() { void GradientEditor::_ramp_changed() { editing = true; - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Gradient Edited"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets()); undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors()); diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp index df45d6c290..6c463f71cf 100644 --- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp +++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/box_container.h" #include "scene/gui/flow_container.h" #include "scene/gui/separator.h" @@ -175,7 +176,7 @@ void GradientTexture2DEditorRect::_notification(int p_what) { } GradientTexture2DEditorRect::GradientTexture2DEditorRect() { - undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo = EditorNode::get_undo_redo(); checkerboard = memnew(TextureRect); checkerboard->set_stretch_mode(TextureRect::STRETCH_TILE); @@ -222,7 +223,7 @@ void GradientTexture2DEditor::_notification(int p_what) { } GradientTexture2DEditor::GradientTexture2DEditor() { - undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo = EditorNode::get_undo_redo(); HFlowContainer *toolbar = memnew(HFlowContainer); add_child(toolbar); diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.h b/editor/plugins/gradient_texture_2d_editor_plugin.h index 93c49b1e6f..9faf33152a 100644 --- a/editor/plugins/gradient_texture_2d_editor_plugin.h +++ b/editor/plugins/gradient_texture_2d_editor_plugin.h @@ -34,6 +34,8 @@ #include "editor/editor_plugin.h" #include "editor/editor_spin_slider.h" +class EditorUndoRedoManager; + class GradientTexture2DEditorRect : public Control { GDCLASS(GradientTexture2DEditorRect, Control); @@ -44,7 +46,7 @@ class GradientTexture2DEditorRect : public Control { }; Ref<GradientTexture2D> texture; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool snap_enabled = false; float snap_size = 0; @@ -74,7 +76,7 @@ class GradientTexture2DEditor : public VBoxContainer { GDCLASS(GradientTexture2DEditor, VBoxContainer); Ref<GradientTexture2D> texture; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Button *reverse_button = nullptr; Button *snap_button = nullptr; diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index 1b4d98fc3f..5d59f62f05 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/subviewport_container.h" #include "scene/resources/fog_material.h" #include "scene/resources/particles_material.h" @@ -261,10 +262,8 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) { } void EditorInspectorPluginMaterial::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - if (!undo_redo) { - return; - } + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(!undo_redo.is_valid()); // For BaseMaterial3D, if a roughness or metallic textures is being assigned to an empty slot, // set the respective metallic or roughness factor to 1.0 as a convenience feature diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 5fb885ad1f..7bd406b869 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" #include "scene/3d/collision_shape_3d.h" #include "scene/3d/navigation_region_3d.h" @@ -60,7 +61,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { switch (p_option) { case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY: { EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); List<Node *> selection = editor_selection->get_selected_node_list(); @@ -147,7 +148,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { Node *owner = get_tree()->get_edited_scene_root(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Create Trimesh Static Shape")); @@ -177,7 +178,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); if (simplify) { ur->create_action(TTR("Create Simplified Convex Shape")); @@ -217,7 +218,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Create Multiple Convex Shapes")); @@ -254,7 +255,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { Node *owner = get_tree()->get_edited_scene_root(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Create Navigation Mesh")); ur->add_do_method(node, "add_child", nmi, true); @@ -311,7 +312,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Unwrap UV2")); ur->add_do_method(node, "set_mesh", unwrapped_mesh); @@ -470,7 +471,7 @@ void MeshInstance3DEditor::_create_outline_mesh() { mi->set_mesh(mesho); Node *owner = get_tree()->get_edited_scene_root(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Create Outline")); diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index e8f143a637..8f1e6c9ec2 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -35,6 +35,7 @@ #include "core/math/geometry_3d.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "scene/3d/audio_listener_3d.h" #include "scene/3d/audio_stream_player_3d.h" @@ -1347,13 +1348,13 @@ void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i light->set_param(p_id == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore); } else if (p_id == 0) { - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Light Radius")); ur->add_do_method(light, "set_param", Light3D::PARAM_RANGE, light->get_param(Light3D::PARAM_RANGE)); ur->add_undo_method(light, "set_param", Light3D::PARAM_RANGE, p_restore); ur->commit_action(); } else if (p_id == 1) { - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Light Radius")); ur->add_do_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, light->get_param(Light3D::PARAM_SPOT_ANGLE)); ur->add_undo_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, p_restore); @@ -1571,7 +1572,7 @@ void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gi player->set_emission_angle(p_restore); } else { - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change AudioStreamPlayer3D Emission Angle")); ur->add_do_method(player, "set_emission_angle", player->get_emission_angle()); ur->add_undo_method(player, "set_emission_angle", p_restore); @@ -1814,7 +1815,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_ if (p_cancel) { camera->set("fov", p_restore); } else { - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Camera FOV")); ur->add_do_property(camera, "fov", camera->get_fov()); ur->add_undo_property(camera, "fov", p_restore); @@ -1825,7 +1826,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_ if (p_cancel) { camera->set("size", p_restore); } else { - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Camera Size")); ur->add_do_property(camera, "size", camera->get_size()); ur->add_undo_property(camera, "size", p_restore); @@ -2141,7 +2142,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Sphere Shape Radius")); ur->add_do_method(so.ptr(), "set_radius", so->get_radius()); ur->add_undo_method(so.ptr(), "set_radius", p_restore); @@ -2155,7 +2156,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Box Shape Size")); ur->add_do_method(bo.ptr(), "set_size", bo->get_size()); ur->add_undo_method(bo.ptr(), "set_size", p_restore); @@ -2169,7 +2170,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Box Shape Size")); ur->add_do_method(qo.ptr(), "set_size", qo->get_size()); ur->add_undo_method(qo.ptr(), "set_size", p_restore); @@ -2870,7 +2871,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Notifier AABB")); ur->add_do_method(notifier, "set_aabb", notifier->get_aabb()); ur->add_undo_method(notifier, "set_aabb", p_restore); @@ -3061,7 +3062,7 @@ void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Particles AABB")); ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb()); ur->add_undo_method(particles, "set_visibility_aabb", p_restore); @@ -3227,7 +3228,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo * return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Radius")); ur->add_do_method(sn, "set_radius", sn->call("get_radius")); ur->add_undo_method(sn, "set_radius", p_restore); @@ -3240,7 +3241,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo * return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Box Shape Extents")); ur->add_do_method(sn, "set_extents", sn->call("get_extents")); ur->add_undo_method(sn, "set_extents", p_restore); @@ -3499,7 +3500,7 @@ void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Probe Extents")); ur->add_do_method(probe, "set_extents", probe->get_extents()); ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset()); @@ -3651,7 +3652,7 @@ void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Decal Extents")); ur->add_do_method(decal, "set_extents", decal->get_extents()); ur->add_undo_method(decal, "set_extents", restore); @@ -3791,7 +3792,7 @@ void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Probe Extents")); ur->add_do_method(probe, "set_extents", probe->get_extents()); ur->add_undo_method(probe, "set_extents", restore); @@ -4406,7 +4407,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Sphere Shape Radius")); ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); ur->add_undo_method(ss.ptr(), "set_radius", p_restore); @@ -4420,7 +4421,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Box Shape Size")); ur->add_do_method(ss.ptr(), "set_size", ss->get_size()); ur->add_undo_method(ss.ptr(), "set_size", p_restore); @@ -4437,7 +4438,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (p_id == 0) { ur->create_action(TTR("Change Capsule Shape Radius")); ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); @@ -4462,7 +4463,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (p_id == 0) { ur->create_action(TTR("Change Cylinder Shape Radius")); ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); @@ -4487,7 +4488,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Separation Ray Shape Length")); ur->add_do_method(ss.ptr(), "set_length", ss->get_length()); ur->add_undo_method(ss.ptr(), "set_length", p_restore); @@ -5745,7 +5746,7 @@ void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Fog Volume Extents")); ur->add_do_method(sn, "set_extents", sn->call("get_extents")); ur->add_undo_method(sn, "set_extents", p_restore); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 6afc6798d0..2798f3d93e 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -4003,15 +4003,15 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path)); } - editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true); - editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene()); - editor_data->get_undo_redo().add_do_reference(instantiated_scene); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); + editor_data->get_undo_redo()->add_do_method(parent, "add_child", instantiated_scene, true); + editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene()); + editor_data->get_undo_redo()->add_do_reference(instantiated_scene); + editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", instantiated_scene); String new_name = parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); Node3D *node3d = Object::cast_to<Node3D>(instantiated_scene); if (node3d) { @@ -4024,7 +4024,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point)); global_transform.basis *= node3d->get_transform().basis; - editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_global_transform", global_transform); + editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_global_transform", global_transform); } return true; @@ -4035,15 +4035,15 @@ void Node3DEditorViewport::_perform_drop_data() { GeometryInstance3D *geometry_instance = Object::cast_to<GeometryInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target())); MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target())); if (mesh_instance && spatial_editor->get_preview_material_surface() != -1) { - editor_data->get_undo_redo().create_action(vformat(TTR("Set Surface %d Override Material"), spatial_editor->get_preview_material_surface())); - editor_data->get_undo_redo().add_do_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_material()); - editor_data->get_undo_redo().add_undo_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_reset_material()); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(vformat(TTR("Set Surface %d Override Material"), spatial_editor->get_preview_material_surface())); + editor_data->get_undo_redo()->add_do_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_material()); + editor_data->get_undo_redo()->add_undo_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_reset_material()); + editor_data->get_undo_redo()->commit_action(); } else if (geometry_instance) { - editor_data->get_undo_redo().create_action(TTR("Set Material Override")); - editor_data->get_undo_redo().add_do_method(geometry_instance, "set_material_override", spatial_editor->get_preview_material()); - editor_data->get_undo_redo().add_undo_method(geometry_instance, "set_material_override", spatial_editor->get_preview_reset_material()); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(TTR("Set Material Override")); + editor_data->get_undo_redo()->add_do_method(geometry_instance, "set_material_override", spatial_editor->get_preview_material()); + editor_data->get_undo_redo()->add_undo_method(geometry_instance, "set_material_override", spatial_editor->get_preview_reset_material()); + editor_data->get_undo_redo()->commit_action(); } _remove_preview_material(); @@ -4054,7 +4054,7 @@ void Node3DEditorViewport::_perform_drop_data() { Vector<String> error_files; - editor_data->get_undo_redo().create_action(TTR("Create Node")); + editor_data->get_undo_redo()->create_action(TTR("Create Node")); for (int i = 0; i < selected_files.size(); i++) { String path = selected_files[i]; @@ -4072,7 +4072,7 @@ void Node3DEditorViewport::_perform_drop_data() { } } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); if (error_files.size() > 0) { String files_str; @@ -7247,6 +7247,14 @@ Vector<int> Node3DEditor::get_subgizmo_selection() { return ret; } +void Node3DEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + +Ref<EditorUndoRedoManager> Node3DEditor::get_undo_redo() { + return undo_redo; +} + void Node3DEditor::add_control_to_menu_panel(Control *p_control) { context_menu_hbox->add_child(p_control); } diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 4469271a38..e0298ebd5f 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -53,6 +53,7 @@ class Node3DEditorViewport; class SubViewportContainer; class DirectionalLight3D; class WorldEnvironment; +class EditorUndoRedoManager; class ViewportRotationControl : public Control { GDCLASS(ViewportRotationControl, Control); @@ -201,7 +202,7 @@ private: EditorData *editor_data = nullptr; EditorSelection *editor_selection = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; CheckBox *preview_camera = nullptr; SubViewportContainer *subviewport_container = nullptr; @@ -682,7 +683,7 @@ private: HBoxContainer *context_menu_hbox = nullptr; void _generate_selection_boxes(); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; int camera_override_viewport_id; @@ -820,13 +821,13 @@ public: void select_gizmo_highlight_axis(int p_axis); void set_custom_camera(Node *p_camera) { custom_camera = p_camera; } - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } Dictionary get_state() const; void set_state(const Dictionary &p_state); Ref<Environment> get_viewport_environment() { return viewport_environment; } - UndoRedo *get_undo_redo() { return undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); + Ref<EditorUndoRedoManager> get_undo_redo(); void add_control_to_menu_panel(Control *p_control); void remove_control_from_menu_panel(Control *p_control); diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index fd331c4127..1d8a3f5c81 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -36,6 +36,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" void Path2DEditor::_notification(int p_what) { switch (p_what) { diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h index 720f5c090f..13eca79010 100644 --- a/editor/plugins/path_2d_editor_plugin.h +++ b/editor/plugins/path_2d_editor_plugin.h @@ -36,11 +36,12 @@ #include "scene/gui/separator.h" class CanvasItemEditor; +class EditorUndoRedoManager; class Path2DEditor : public HBoxContainer { GDCLASS(Path2DEditor, HBoxContainer); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; CanvasItemEditor *canvas_item_editor = nullptr; Panel *panel = nullptr; diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index 65b15a6001..084c0c2bb0 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -35,6 +35,7 @@ #include "core/os/keyboard.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" #include "scene/resources/curve.h" @@ -172,7 +173,7 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (!p_secondary) { if (p_cancel) { @@ -385,7 +386,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera } } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (closest_seg != -1) { //subdivide @@ -427,21 +428,21 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera // Find the offset and point index of the place to break up. // Also check for the control points. if (dist_to_p < click_dist) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Path Point")); ur->add_do_method(c.ptr(), "remove_point", i); ur->add_undo_method(c.ptr(), "add_point", c->get_point_position(i), c->get_point_in(i), c->get_point_out(i), i); ur->commit_action(); return EditorPlugin::AFTER_GUI_INPUT_STOP; } else if (dist_to_p_out < click_dist) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Out-Control Point")); ur->add_do_method(c.ptr(), "set_point_out", i, Vector3()); ur->add_undo_method(c.ptr(), "set_point_out", i, c->get_point_out(i)); ur->commit_action(); return EditorPlugin::AFTER_GUI_INPUT_STOP; } else if (dist_to_p_in < click_dist) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove In-Control Point")); ur->add_do_method(c.ptr(), "set_point_in", i, Vector3()); ur->add_undo_method(c.ptr(), "set_point_in", i, c->get_point_in(i)); @@ -520,7 +521,7 @@ void Path3DEditorPlugin::_close_curve() { if (c->get_point_position(0) == c->get_point_position(c->get_point_count() - 1)) { return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Close Curve")); ur->add_do_method(c.ptr(), "add_point", c->get_point_position(0), c->get_point_in(0), c->get_point_out(0), -1); ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count()); diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp index 83092f990f..2b3a5c3e23 100644 --- a/editor/plugins/polygon_3d_editor_plugin.cpp +++ b/editor/plugins/polygon_3d_editor_plugin.cpp @@ -38,6 +38,7 @@ #include "core/os/keyboard.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" #include "scene/3d/camera_3d.h" diff --git a/editor/plugins/polygon_3d_editor_plugin.h b/editor/plugins/polygon_3d_editor_plugin.h index e1e1261250..0eb02a39e2 100644 --- a/editor/plugins/polygon_3d_editor_plugin.h +++ b/editor/plugins/polygon_3d_editor_plugin.h @@ -37,11 +37,12 @@ #include "scene/resources/immediate_mesh.h" class CanvasItemEditor; +class EditorUndoRedoManager; class Polygon3DEditor : public HBoxContainer { GDCLASS(Polygon3DEditor, HBoxContainer); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; enum Mode { MODE_CREATE, MODE_EDIT, diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index 4e528ef066..201a3af539 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -234,6 +234,10 @@ void ResourcePreloaderEditor::_cell_button_pressed(Object *p_item, int p_column, } } +void ResourcePreloaderEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void ResourcePreloaderEditor::edit(ResourcePreloader *p_preloader) { preloader = p_preloader; @@ -387,7 +391,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() { } void ResourcePreloaderEditorPlugin::edit(Object *p_object) { - preloader_editor->set_undo_redo(&get_undo_redo()); + preloader_editor->set_undo_redo(EditorNode::get_undo_redo()); ResourcePreloader *s = Object::cast_to<ResourcePreloader>(p_object); if (!s) { return; diff --git a/editor/plugins/resource_preloader_editor_plugin.h b/editor/plugins/resource_preloader_editor_plugin.h index 96cef3de21..ef80283dae 100644 --- a/editor/plugins/resource_preloader_editor_plugin.h +++ b/editor/plugins/resource_preloader_editor_plugin.h @@ -37,6 +37,7 @@ #include "scene/main/resource_preloader.h" class EditorFileDialog; +class EditorUndoRedoManager; class ResourcePreloaderEditor : public PanelContainer { GDCLASS(ResourcePreloaderEditor, PanelContainer); @@ -66,7 +67,7 @@ class ResourcePreloaderEditor : public PanelContainer { void _cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button); void _item_edited(); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; @@ -78,7 +79,7 @@ protected: static void _bind_methods(); public: - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void edit(ResourcePreloader *p_preloader); ResourcePreloaderEditor(); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index c53ac59c11..de13c77e1a 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1408,8 +1408,6 @@ void ScriptEditor::_menu_option(int p_option) { es->set_editor(EditorNode::get_singleton()); es->_run(); - - EditorNode::get_undo_redo()->clear_history(); } break; case FILE_CLOSE: { if (current->is_unsaved()) { diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index 5a1505c232..3dc068a72a 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "canvas_item_editor_plugin.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/2d/mesh_instance_2d.h" #include "scene/gui/box_container.h" #include "thirdparty/misc/clipper.hpp" @@ -59,7 +60,7 @@ void Skeleton2DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Rest Pose to Bones")); for (int i = 0; i < node->get_bone_count(); i++) { Bone2D *bone = node->get_bone(i); @@ -75,7 +76,7 @@ void Skeleton2DEditor::_menu_option(int p_option) { err_dialog->popup_centered(); return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Create Rest Pose from Bones")); for (int i = 0; i < node->get_bone_count(); i++) { Bone2D *bone = node->get_bone(i); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 2263dd098c..1e4ef217f0 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "node_3d_editor_plugin.h" #include "scene/3d/collision_shape_3d.h" @@ -267,7 +268,7 @@ void Skeleton3DEditor::reset_pose(const bool p_all_bones) { return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS); if (p_all_bones) { for (int i = 0; i < bone_len; i++) { @@ -334,7 +335,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) { return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Bone Rest"), UndoRedo::MERGE_ENDS); if (p_all_bones) { for (int i = 0; i < bone_len; i++) { @@ -354,7 +355,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) { } void Skeleton3DEditor::create_physical_skeleton() { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ERR_FAIL_COND(!get_tree()); Node *owner = get_tree()->get_edited_scene_root(); @@ -587,7 +588,7 @@ void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_se Node *node = get_node_or_null(p_skeleton_path); Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node); ERR_FAIL_NULL(skeleton); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Bone Parentage")); // If the target is a child of ourselves, we move only *us* and not our children. if (skeleton->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) { @@ -1309,7 +1310,7 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c Skeleton3DEditor *se = Skeleton3DEditor::get_singleton(); Node3DEditor *ne = Node3DEditor::get_singleton(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Bone Transform")); if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || ne->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { for (int i = 0; i < p_ids.size(); i++) { diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index 9f610e1b7d..f51d4e60e8 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -40,6 +40,7 @@ #include "scene/resources/immediate_mesh.h" class EditorInspectorPluginSkeleton; +class EditorUndoRedoManager; class Joint; class PhysicalBone3D; class Skeleton3DEditorPlugin; @@ -63,7 +64,7 @@ class BoneTransformEditor : public VBoxContainer { Skeleton3D *skeleton = nullptr; // String property; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool toggle_enabled = false; bool updating = false; diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index 7d350fd46f..e45c907e86 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "core/math/geometry_2d.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "scene/2d/collision_polygon_2d.h" #include "scene/2d/light_occluder_2d.h" @@ -342,7 +343,7 @@ void Sprite2DEditor::_convert_to_mesh_2d_node() { MeshInstance2D *mesh_instance = memnew(MeshInstance2D); mesh_instance->set_mesh(mesh); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Convert to MeshInstance2D")); ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, mesh_instance, true, false); ur->add_do_reference(mesh_instance); @@ -400,7 +401,7 @@ void Sprite2DEditor::_convert_to_polygon_2d_node() { polygon_2d_instance->set_polygon(polygon); polygon_2d_instance->set_polygons(polys); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Convert to Polygon2D")); ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, polygon_2d_instance, true, false); ur->add_do_reference(polygon_2d_instance); @@ -422,7 +423,7 @@ void Sprite2DEditor::_create_collision_polygon_2d_node() { CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D); collision_polygon_2d_instance->set_polygon(outline); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Create CollisionPolygon2D Sibling")); ur->add_do_method(this, "_add_as_sibling_or_child", node, collision_polygon_2d_instance); ur->add_do_reference(collision_polygon_2d_instance); @@ -455,7 +456,7 @@ void Sprite2DEditor::_create_light_occluder_2d_node() { LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D); light_occluder_2d_instance->set_occluder_polygon(polygon); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Create LightOccluder2D Sibling")); ur->add_do_method(this, "_add_as_sibling_or_child", node, light_occluder_2d_instance); ur->add_do_reference(light_occluder_2d_instance); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index a39d24a167..205fed48b4 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -37,6 +37,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "scene/3d/sprite_3d.h" #include "scene/gui/center_container.h" @@ -1010,6 +1011,10 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) { } } +void SpriteFramesEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) { if (!frames->has_animation(edited_anim)) { return false; @@ -1471,7 +1476,7 @@ SpriteFramesEditor::SpriteFramesEditor() { } void SpriteFramesEditorPlugin::edit(Object *p_object) { - frames_editor->set_undo_redo(&get_undo_redo()); + frames_editor->set_undo_redo(get_undo_redo()); SpriteFrames *s; AnimatedSprite2D *animated_sprite = Object::cast_to<AnimatedSprite2D>(p_object); diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index 6352259b73..f2530b732f 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -45,6 +45,7 @@ #include "scene/gui/tree.h" class EditorFileDialog; +class EditorUndoRedoManager; class SpriteFramesEditor : public HSplitContainer { GDCLASS(SpriteFramesEditor, HSplitContainer); @@ -151,7 +152,7 @@ class SpriteFramesEditor : public HSplitContainer { bool updating; bool updating_split_settings = false; // Skip SpinBox/Range callback when setting value by code. - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; @@ -176,7 +177,7 @@ protected: static void _bind_methods(); public: - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void edit(SpriteFrames *p_frames); SpriteFramesEditor(); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 0bd8a8a484..772bae6544 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -36,6 +36,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/check_box.h" #include "scene/gui/separator.h" #include "scene/gui/view_panner.h" diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index a18c87f153..e3bbaf49fc 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -40,6 +40,7 @@ #include "scene/resources/texture.h" class ViewPanner; +class EditorUndoRedoManager; class TextureRegionEditor : public AcceptDialog { GDCLASS(TextureRegionEditor, AcceptDialog); @@ -68,7 +69,7 @@ class TextureRegionEditor : public AcceptDialog { VScrollBar *vscroll = nullptr; HScrollBar *hscroll = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Vector2 draw_ofs; float draw_zoom = 0.0; diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index bbc22c8622..af3959d47c 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_resource_picker.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/progress_dialog.h" #include "scene/gui/color_picker.h" @@ -796,7 +797,7 @@ void ThemeItemImportTree::_import_selected() { ProgressDialog::get_singleton()->end_task("import_theme_items"); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Import Theme Items")); ur->add_do_method(*edited_theme, "clear"); @@ -1494,7 +1495,7 @@ void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_colu String item_name = item->get_text(0); int data_type = item->get_parent()->get_metadata(0); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Theme Item")); ur->add_do_method(*edited_theme, "clear_theme_item", (Theme::DataType)data_type, item_name, edited_item_type); ur->add_undo_method(*edited_theme, "set_theme_item", (Theme::DataType)data_type, item_name, edited_item_type, edited_theme->get_theme_item((Theme::DataType)data_type, item_name, edited_item_type)); @@ -1513,7 +1514,7 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) { const String new_type = edit_add_type_value->get_text().strip_edges(); edit_add_type_value->clear(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Add Theme Type")); ur->add_do_method(*edited_theme, "add_type", new_type); @@ -1525,7 +1526,7 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) { } void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Create Theme Item")); switch (p_data_type) { @@ -1570,7 +1571,7 @@ void ThemeItemEditorDialog::_remove_theme_type(const String &p_theme_type) { Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Theme Type")); new_snapshot->remove_type(p_theme_type); @@ -1593,7 +1594,7 @@ void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type, Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Data Type Items From Theme")); new_snapshot->get_theme_item_list(p_data_type, p_item_type, &names); @@ -1622,7 +1623,7 @@ void ThemeItemEditorDialog::_remove_class_items() { Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Class Items From Theme")); for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { @@ -1658,7 +1659,7 @@ void ThemeItemEditorDialog::_remove_custom_items() { Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Custom Items From Theme")); for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { @@ -1694,7 +1695,7 @@ void ThemeItemEditorDialog::_remove_all_items() { Ref<Theme> old_snapshot = edited_theme->duplicate(); Ref<Theme> new_snapshot = edited_theme->duplicate(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove All Items From Theme")); for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { @@ -1798,7 +1799,7 @@ void ThemeItemEditorDialog::_confirm_edit_theme_item() { if (item_popup_mode == CREATE_THEME_ITEM) { _add_theme_item(edit_item_data_type, theme_item_name->get_text(), edited_item_type); } else if (item_popup_mode == RENAME_THEME_ITEM) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Rename Theme Item")); ur->add_do_method(*edited_theme, "rename_theme_item", edit_item_data_type, edit_item_old_name, theme_item_name->get_text(), edited_item_type); @@ -2824,7 +2825,7 @@ void ThemeTypeEditor::_add_default_type_items() { updating = false; - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Override All Default Theme Items")); ur->add_do_method(*edited_theme, "merge_with", new_snapshot); @@ -2844,7 +2845,7 @@ void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) { } String item_name = le->get_text().strip_edges(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Add Theme Item")); switch (p_data_type) { @@ -2889,7 +2890,7 @@ void ThemeTypeEditor::_item_add_lineedit_cbk(String p_value, int p_data_type, Co } void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Override Theme Item")); switch (p_data_type) { @@ -2928,7 +2929,7 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) { } void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Remove Theme Item")); switch (p_data_type) { @@ -3002,7 +3003,7 @@ void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name return; } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Rename Theme Item")); switch (p_data_type) { @@ -3058,7 +3059,7 @@ void ThemeTypeEditor::_item_rename_canceled(int p_data_type, String p_item_name, } void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Color Item in Theme"), UndoRedo::MERGE_ENDS); ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, p_value); ur->add_undo_method(*edited_theme, "set_color", p_item_name, edited_type, edited_theme->get_color(p_item_name, edited_type)); @@ -3066,7 +3067,7 @@ void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) { } void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Constant Item in Theme")); ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, p_value); ur->add_undo_method(*edited_theme, "set_constant", p_item_name, edited_type, edited_theme->get_constant(p_item_name, edited_type)); @@ -3074,7 +3075,7 @@ void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) } void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Font Size Item in Theme")); ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, p_value); ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type)); @@ -3086,7 +3087,7 @@ void ThemeTypeEditor::_edit_resource_item(Ref<Resource> p_resource, bool p_edit) } void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Font Item in Theme")); ur->add_do_method(*edited_theme, "set_font", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Font>()); @@ -3103,7 +3104,7 @@ void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) } void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Icon Item in Theme")); ur->add_do_method(*edited_theme, "set_icon", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Texture2D>()); @@ -3120,7 +3121,7 @@ void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_n } void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Stylebox Item in Theme")); ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<StyleBox>()); @@ -3163,7 +3164,7 @@ void ThemeTypeEditor::_on_pin_leader_button_pressed(Control *p_editor, String p_ stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource(); } - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Pin Stylebox")); ur->add_do_method(this, "_pin_leading_stylebox", p_item_name, stylebox); @@ -3196,7 +3197,7 @@ void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_ } void ThemeTypeEditor::_on_unpin_leader_button_pressed() { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Unpin Stylebox")); ur->add_do_method(this, "_unpin_leading_stylebox"); ur->add_undo_method(this, "_pin_leading_stylebox", leading_stylebox.item_name, leading_stylebox.stylebox); @@ -3265,7 +3266,7 @@ void ThemeTypeEditor::_update_stylebox_from_leading() { } void ThemeTypeEditor::_type_variation_changed(const String p_value) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Set Theme Type Variation")); if (p_value.is_empty()) { diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp index 3fe6778f48..de4f3f7989 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.cpp +++ b/editor/plugins/tiles/atlas_merging_dialog.cpp @@ -33,6 +33,7 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/control.h" #include "scene/gui/split_container.h" diff --git a/editor/plugins/tiles/atlas_merging_dialog.h b/editor/plugins/tiles/atlas_merging_dialog.h index c54e259594..c7e4635d16 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.h +++ b/editor/plugins/tiles/atlas_merging_dialog.h @@ -38,6 +38,7 @@ #include "scene/resources/tile_set.h" class EditorFileDialog; +class EditorUndoRedoManager; class AtlasMergingDialog : public ConfirmationDialog { GDCLASS(AtlasMergingDialog, ConfirmationDialog); @@ -49,7 +50,7 @@ private: LocalVector<HashMap<Vector2i, Vector2i>> merged_mapping; Ref<TileSet> tile_set; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; // Settings. int next_line_after_column = 30; diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index a00e1ed9e8..b44b6fcc53 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -38,6 +38,7 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" void TileDataEditor::_tile_set_changed_plan_update() { _tile_set_changed_update_needed = true; @@ -248,7 +249,14 @@ void GenericTilePolygonEditor::_zoom_changed() { } void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { - UndoRedo *undo_redo = use_undo_redo ? editor_undo_redo : memnew(UndoRedo); + Ref<EditorUndoRedoManager> undo_redo; + if (use_undo_redo) { + undo_redo = editor_undo_redo; + } else { + // This nice hack allows for discarding undo actions without making code too complex. + undo_redo.instantiate(); + } + switch (p_item_pressed) { case RESET_TO_DEFAULT_TILE: { undo_redo->create_action(TTR("Reset Polygons")); @@ -322,9 +330,6 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { default: break; } - if (!use_undo_redo) { - memdelete(undo_redo); - } } void GenericTilePolygonEditor::_grab_polygon_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_point_index) { @@ -409,7 +414,14 @@ void GenericTilePolygonEditor::_snap_to_half_pixel(Point2 &r_point) { } void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) { - UndoRedo *undo_redo = use_undo_redo ? editor_undo_redo : memnew(UndoRedo); + Ref<EditorUndoRedoManager> undo_redo; + if (use_undo_redo) { + undo_redo = editor_undo_redo; + } else { + // This nice hack allows for discarding undo actions without making code too complex. + undo_redo.instantiate(); + } + real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius"); hovered_polygon_index = -1; @@ -600,10 +612,6 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) } base_control->update(); - - if (!use_undo_redo) { - memdelete(undo_redo); - } } void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) { diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index f9b8948d0a..c1560138b2 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -39,6 +39,8 @@ #include "scene/gui/control.h" #include "scene/gui/label.h" +class EditorUndoRedoManager; + class TileDataEditor : public VBoxContainer { GDCLASS(TileDataEditor, VBoxContainer); @@ -93,7 +95,7 @@ private: bool multiple_polygon_mode = false; bool use_undo_redo = true; - UndoRedo *editor_undo_redo = nullptr; + Ref<EditorUndoRedoManager> editor_undo_redo; // UI int hovered_polygon_index = -1; @@ -214,7 +216,7 @@ private: protected: DummyObject *dummy_object = memnew(DummyObject); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; StringName type; String property; @@ -279,7 +281,7 @@ private: virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override; protected: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; virtual void _tile_set_changed() override; @@ -314,7 +316,7 @@ class TileDataCollisionEditor : public TileDataDefaultEditor { virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override; protected: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; virtual void _tile_set_changed() override; @@ -366,7 +368,7 @@ protected: void _notification(int p_what); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; public: virtual Control *get_toolbar() override { return toolbar; }; @@ -399,7 +401,7 @@ private: virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override; protected: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; virtual void _tile_set_changed() override; diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 1bf24a7393..3f355a1ed2 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/2d/camera_2d.h" @@ -3697,8 +3698,8 @@ void TileMapEditor::_update_layers_selection() { } void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - ERR_FAIL_COND(!undo_redo); + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(undo_redo.is_null()); TileMap *tile_map = Object::cast_to<TileMap>(p_edited); if (!tile_map) { diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h index 605fbe4823..9a47d8bbc4 100644 --- a/editor/plugins/tiles/tile_map_editor.h +++ b/editor/plugins/tiles/tile_map_editor.h @@ -47,7 +47,7 @@ #include "scene/gui/tab_bar.h" #include "scene/gui/tree.h" -class UndoRedo; +class EditorUndoRedoManager; class TileMapEditorPlugin : public Object { public: @@ -70,7 +70,7 @@ class TileMapEditorTilesPlugin : public TileMapEditorPlugin { GDCLASS(TileMapEditorTilesPlugin, TileMapEditorPlugin); private: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; ObjectID tile_map_id; int tile_map_layer = -1; virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override; @@ -223,7 +223,7 @@ class TileMapEditorTerrainsPlugin : public TileMapEditorPlugin { GDCLASS(TileMapEditorTerrainsPlugin, TileMapEditorPlugin); private: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; ObjectID tile_map_id; int tile_map_layer = -1; virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override; @@ -317,7 +317,7 @@ class TileMapEditor : public VBoxContainer { GDCLASS(TileMapEditor, VBoxContainer); private: - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool tileset_changed_needs_update = false; ObjectID tile_map_id; int tile_map_layer = -1; diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp index 12e1615484..9e4c29fa79 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, Object *p_item_list, MouseButton p_mouse_button_index) { if (p_mouse_button_index != MouseButton::RIGHT) { diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.h b/editor/plugins/tiles/tile_proxies_manager_dialog.h index 44de708898..511e442a10 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.h +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.h @@ -43,7 +43,7 @@ private: int commited_actions_count = 0; Ref<TileSet> tile_set; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; TileMapCell from; TileMapCell to; diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 6950f57a00..09722d3d65 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -2058,14 +2058,16 @@ void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what) } void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - ERR_FAIL_COND(!undo_redo); + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(!undo_redo.is_valid()); #define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property)); - undo_redo->start_force_keep_in_merge_ends(); AtlasTileProxyObject *tile_data_proxy = Object::cast_to<AtlasTileProxyObject>(p_edited); if (tile_data_proxy) { + UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(tile_data_proxy).undo_redo; + internal_undo_redo->start_force_keep_in_merge_ends(); + Vector<String> components = String(p_property).split("/", true, 2); if (components.size() == 2 && components[1] == "polygons_count") { int layer_index = components[0].trim_prefix("physics_layer_").to_int(); @@ -2088,6 +2090,7 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo } } } + internal_undo_redo->end_force_keep_in_merge_ends(); } TileSetAtlasSourceProxyObject *atlas_source_proxy = Object::cast_to<TileSetAtlasSourceProxyObject>(p_edited); @@ -2095,6 +2098,9 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo TileSetAtlasSource *atlas_source = atlas_source_proxy->get_edited(); ERR_FAIL_COND(!atlas_source); + UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(atlas_source).undo_redo; + internal_undo_redo->start_force_keep_in_merge_ends(); + PackedVector2Array arr; if (p_property == "texture") { arr = atlas_source->get_tiles_to_be_removed_on_change(p_new_value, atlas_source->get_margins(), atlas_source->get_separation(), atlas_source->get_texture_region_size()); @@ -2121,8 +2127,8 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo } } } + internal_undo_redo->end_force_keep_in_merge_ends(); } - undo_redo->end_force_keep_in_merge_ends(); #undef ADD_UNDO } diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h index 738fe1044d..badb702e29 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.h +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h @@ -114,7 +114,7 @@ private: TileSetAtlasSource *tile_set_atlas_source = nullptr; int tile_set_atlas_source_id = TileSet::INVALID_SOURCE; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool tile_set_changed_needs_update = false; diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 81804710b4..8d04dd3121 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -36,6 +36,7 @@ #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/box_container.h" #include "scene/gui/control.h" @@ -405,8 +406,8 @@ void TileSetEditor::_tab_changed(int p_tab_changed) { } void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - ERR_FAIL_COND(!undo_redo); + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(undo_redo.is_null()); TileSet *tile_set = Object::cast_to<TileSet>(p_edited); if (!tile_set) { @@ -586,8 +587,8 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_ } void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) { - UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo); - ERR_FAIL_COND(!undo_redo); + Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo); + ERR_FAIL_COND(undo_redo.is_null()); #define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property)); TileSet *tile_set = Object::cast_to<TileSet>(p_edited); diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h index c45240043e..3b9b80dac4 100644 --- a/editor/plugins/tiles/tile_set_editor.h +++ b/editor/plugins/tiles/tile_set_editor.h @@ -39,6 +39,8 @@ #include "tile_set_atlas_source_editor.h" #include "tile_set_scenes_collection_source_editor.h" +class EditorUndoRedoManager; + class TileSetEditor : public VBoxContainer { GDCLASS(TileSetEditor, VBoxContainer); @@ -58,7 +60,7 @@ private: TileSetAtlasSourceEditor *tile_set_atlas_source_editor = nullptr; TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h index 77a583e522..0284b45c0f 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h @@ -97,7 +97,7 @@ private: TileSetScenesCollectionSource *tile_set_scenes_collection_source = nullptr; int tile_set_source_id = -1; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; bool tile_set_scenes_collection_source_changed_needs_update = false; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index cf24095582..961f092650 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -40,6 +40,7 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/curve_editor_plugin.h" #include "editor/plugins/shader_editor_plugin.h" #include "scene/animation/animation_player.h" @@ -4063,7 +4064,7 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, bool type_changed = next_input_type != prev_input_type; - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Visual Shader Input Type Changed")); undo_redo->add_do_method(p_input.ptr(), "set_input_name", p_name); @@ -4132,7 +4133,7 @@ void VisualShaderEditor::_uniform_select_item(Ref<VisualShaderNodeUniformRef> p_ bool type_changed = p_uniform_ref->get_uniform_type_by_name(p_name) != p_uniform_ref->get_uniform_type_by_name(prev_name); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("UniformRef Name Changed")); undo_redo->add_do_method(p_uniform_ref.ptr(), "set_uniform_name", p_name); @@ -4176,7 +4177,7 @@ void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_var bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid(); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Varying Name Changed")); undo_redo->add_do_method(p_varying.ptr(), "set_varying_name", p_name); @@ -5668,7 +5669,7 @@ VisualShaderEditor::VisualShaderEditor() { _update_options_menu(); - undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo = EditorNode::get_undo_redo(); Ref<VisualShaderNodePluginDefault> default_plugin; default_plugin.instantiate(); @@ -5876,7 +5877,7 @@ public: return; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); updating = true; undo_redo->create_action(TTR("Edit Visual Property:") + " " + p_property, UndoRedo::MERGE_ENDS); @@ -6078,7 +6079,7 @@ void EditorPropertyVisualShaderMode::_option_selected(int p_which) { return; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Visual Shader Mode Changed")); //do is easy undo_redo->add_do_method(visual_shader.ptr(), "set_mode", p_which); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index b6a3b43754..ede6513b83 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -48,6 +48,7 @@ class TextEdit; class Tree; class VisualShaderEditor; +class EditorUndoRedoManager; class VisualShaderNodePlugin : public RefCounted { GDCLASS(VisualShaderNodePlugin, RefCounted); @@ -192,7 +193,7 @@ class VisualShaderEditor : public VBoxContainer { PanelContainer *error_panel = nullptr; Label *error_label = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; Point2 saved_node_pos; bool saved_node_pos_dirty = false; diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index ca5eeaa787..581315d512 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "servers/movie_writer/movie_writer.h" ProjectSettingsEditor *ProjectSettingsEditor::singleton = nullptr; @@ -566,7 +567,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { set_title(TTR("Project Settings (project.godot)")); ps = ProjectSettings::get_singleton(); - undo_redo = &p_data->get_undo_redo(); + undo_redo = p_data->get_undo_redo(); data = p_data; tab_container = memnew(TabContainer); @@ -625,7 +626,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { custom_properties->add_child(del_button); general_settings_inspector = memnew(SectionedInspector); - general_settings_inspector->get_inspector()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo()); + general_settings_inspector->get_inspector()->set_undo_redo(EditorNode::get_undo_redo()); general_settings_inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL); general_settings_inspector->register_search_box(search_box); general_settings_inspector->get_inspector()->set_use_filter(true); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index c2d2c2d8f4..040d992e40 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -32,7 +32,6 @@ #define PROJECT_SETTINGS_EDITOR_H #include "core/config/project_settings.h" -#include "core/object/undo_redo.h" #include "editor/action_map_editor.h" #include "editor/editor_autoload_settings.h" #include "editor/editor_data.h" @@ -43,6 +42,7 @@ #include "editor/shader_globals_editor.h" #include "scene/gui/tab_container.h" +class EditorUndoRedoManager; class FileSystemDock; class ProjectSettingsEditor : public AcceptDialog { @@ -77,7 +77,7 @@ class ProjectSettingsEditor : public AcceptDialog { ImportDefaultsEditor *import_defaults_editor = nullptr; EditorData *data = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; void _advanced_toggled(bool p_button_pressed); void _update_advanced(bool p_is_advanced); diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 665aca6a37..84923a94a2 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -38,6 +38,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_themes.h" +#include "editor/editor_undo_redo_manager.h" #include "modules/regex/regex.h" #include "plugins/script_editor_plugin.h" #include "scene/gui/control.h" @@ -45,7 +46,7 @@ #include "scene/gui/separator.h" #include "scene/gui/tab_container.h" -RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_undo_redo) { +RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoRedoManager> p_undo_redo) { scene_tree_editor = p_scene_tree_editor; undo_redo = p_undo_redo; preview_node = nullptr; @@ -581,7 +582,7 @@ void RenameDialog::rename() { // Forward recursive as opposed to the actual renaming. _iterate_scene(root_node, selected_node_list, &global_count); - if (undo_redo && !to_rename.is_empty()) { + if (undo_redo.is_valid() && !to_rename.is_empty()) { undo_redo->create_action(TTR("Batch Rename")); // Make sure to iterate reversed so that child nodes will find parents. diff --git a/editor/rename_dialog.h b/editor/rename_dialog.h index f3a850045e..dac73b13b8 100644 --- a/editor/rename_dialog.h +++ b/editor/rename_dialog.h @@ -34,7 +34,6 @@ #include "modules/modules_enabled.gen.h" // For regex. #ifdef MODULE_REGEX_ENABLED -#include "core/object/undo_redo.h" #include "editor/scene_tree_editor.h" #include "scene/gui/check_box.h" #include "scene/gui/check_button.h" @@ -43,6 +42,8 @@ #include "scene/gui/spin_box.h" #include "scene/gui/tab_container.h" +class EditorUndoRedoManager; + class RenameDialog : public ConfirmationDialog { GDCLASS(RenameDialog, ConfirmationDialog); @@ -63,7 +64,7 @@ class RenameDialog : public ConfirmationDialog { static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type); SceneTreeEditor *scene_tree_editor = nullptr; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; int global_count = 0; LineEdit *lne_search = nullptr; @@ -109,7 +110,7 @@ public: void reset(); void rename(); - RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_undo_redo = nullptr); + RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoRedoManager> p_undo_redo = Ref<EditorUndoRedoManager>()); ~RenameDialog() {} }; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index f0884a4a91..9f80119c35 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -222,28 +222,28 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N return; } - editor_data->get_undo_redo().create_action(TTR("Instance Scene(s)")); + editor_data->get_undo_redo()->create_action(TTR("Instance Scene(s)")); for (int i = 0; i < instances.size(); i++) { Node *instantiated_scene = instances[i]; - editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true); + editor_data->get_undo_redo()->add_do_method(parent, "add_child", instantiated_scene, true); if (p_pos >= 0) { - editor_data->get_undo_redo().add_do_method(parent, "move_child", instantiated_scene, p_pos + i); + editor_data->get_undo_redo()->add_do_method(parent, "move_child", instantiated_scene, p_pos + i); } - editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", edited_scene); - editor_data->get_undo_redo().add_do_method(editor_selection, "clear"); - editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", instantiated_scene); - editor_data->get_undo_redo().add_do_reference(instantiated_scene); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); + editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_owner", edited_scene); + editor_data->get_undo_redo()->add_do_method(editor_selection, "clear"); + editor_data->get_undo_redo()->add_do_method(editor_selection, "add_node", instantiated_scene); + editor_data->get_undo_redo()->add_do_reference(instantiated_scene); + editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", instantiated_scene); String new_name = parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), p_files[i], new_name); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name))); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), p_files[i], new_name); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name))); } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); _push_item(instances[instances.size() - 1]); for (int i = 0; i < instances.size(); i++) { emit_signal(SNAME("node_created"), instances[i]); @@ -265,7 +265,7 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) return; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Replace with Branch Scene")); Node *parent = base->get_parent(); @@ -530,23 +530,23 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { return; } - editor_data->get_undo_redo().create_action(TTR("Detach Script")); - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "push_item", (Script *)nullptr); + editor_data->get_undo_redo()->create_action(TTR("Detach Script"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "push_item", (Script *)nullptr); for (int i = 0; i < selection.size(); i++) { Node *n = Object::cast_to<Node>(selection[i]); Ref<Script> existing = n->get_script(); Ref<Script> empty = EditorNode::get_singleton()->get_object_custom_type_base(n); if (existing != empty) { - editor_data->get_undo_redo().add_do_method(n, "set_script", empty); - editor_data->get_undo_redo().add_undo_method(n, "set_script", existing); + editor_data->get_undo_redo()->add_do_method(n, "set_script", empty); + editor_data->get_undo_redo()->add_undo_method(n, "set_script", existing); } } - editor_data->get_undo_redo().add_do_method(this, "_update_script_button"); - editor_data->get_undo_redo().add_undo_method(this, "_update_script_button"); + editor_data->get_undo_redo()->add_do_method(this, "_update_script_button"); + editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button"); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); } break; case TOOL_MOVE_UP: case TOOL_MOVE_DOWN: { @@ -601,10 +601,10 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } if (selection.size() == 1) { - editor_data->get_undo_redo().create_action(TTR("Move Node In Parent")); + editor_data->get_undo_redo()->create_action(TTR("Move Node In Parent")); } if (selection.size() > 1) { - editor_data->get_undo_redo().create_action(TTR("Move Nodes In Parent")); + editor_data->get_undo_redo()->create_action(TTR("Move Nodes In Parent")); } for (int i = 0; i < selection.size(); i++) { @@ -617,11 +617,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { int bottom_node_pos = bottom_node->get_index(); int top_node_pos_next = top_node->get_index() + (MOVING_DOWN ? 1 : -1); - editor_data->get_undo_redo().add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next); - editor_data->get_undo_redo().add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos); + editor_data->get_undo_redo()->add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next); + editor_data->get_undo_redo()->add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos); } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); } break; case TOOL_DUPLICATE: { @@ -649,8 +649,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; } - editor_data->get_undo_redo().create_action(TTR("Duplicate Node(s)")); - editor_data->get_undo_redo().add_do_method(editor_selection, "clear"); + editor_data->get_undo_redo()->create_action(TTR("Duplicate Node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get()); + editor_data->get_undo_redo()->add_do_method(editor_selection, "clear"); Node *dupsingle = nullptr; @@ -675,28 +675,28 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { dup->set_name(parent->validate_child_name(dup)); - editor_data->get_undo_redo().add_do_method(add_below_node, "add_sibling", dup, true); + editor_data->get_undo_redo()->add_do_method(add_below_node, "add_sibling", dup, true); for (Node *F : owned) { if (!duplimap.has(F)) { continue; } Node *d = duplimap[F]; - editor_data->get_undo_redo().add_do_method(d, "set_owner", node->get_owner()); + editor_data->get_undo_redo()->add_do_method(d, "set_owner", node->get_owner()); } - editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", dup); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", dup); - editor_data->get_undo_redo().add_do_reference(dup); + editor_data->get_undo_redo()->add_do_method(editor_selection, "add_node", dup); + editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", dup); + editor_data->get_undo_redo()->add_do_reference(dup); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo().add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name()); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(dup->get_name()))); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name()); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(dup->get_name()))); add_below_node = dup; } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); if (dupsingle) { _push_item(dupsingle); @@ -765,29 +765,29 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { return; } - editor_data->get_undo_redo().create_action(TTR("Make node as Root")); - editor_data->get_undo_redo().add_do_method(node->get_parent(), "remove_child", node); - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", node); - editor_data->get_undo_redo().add_do_method(node, "add_child", root, true); - editor_data->get_undo_redo().add_do_method(node, "set_scene_file_path", root->get_scene_file_path()); - editor_data->get_undo_redo().add_do_method(root, "set_scene_file_path", String()); - editor_data->get_undo_redo().add_do_method(node, "set_owner", (Object *)nullptr); - editor_data->get_undo_redo().add_do_method(root, "set_owner", node); + editor_data->get_undo_redo()->create_action(TTR("Make node as Root")); + editor_data->get_undo_redo()->add_do_method(node->get_parent(), "remove_child", node); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", node); + editor_data->get_undo_redo()->add_do_method(node, "add_child", root, true); + editor_data->get_undo_redo()->add_do_method(node, "set_scene_file_path", root->get_scene_file_path()); + editor_data->get_undo_redo()->add_do_method(root, "set_scene_file_path", String()); + editor_data->get_undo_redo()->add_do_method(node, "set_owner", (Object *)nullptr); + editor_data->get_undo_redo()->add_do_method(root, "set_owner", node); _node_replace_owner(root, root, node, MODE_DO); - editor_data->get_undo_redo().add_undo_method(root, "set_scene_file_path", root->get_scene_file_path()); - editor_data->get_undo_redo().add_undo_method(node, "set_scene_file_path", String()); - editor_data->get_undo_redo().add_undo_method(node, "remove_child", root); - editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", root); - editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node, true); - editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, node->get_index()); - editor_data->get_undo_redo().add_undo_method(root, "set_owner", (Object *)nullptr); - editor_data->get_undo_redo().add_undo_method(node, "set_owner", root); + editor_data->get_undo_redo()->add_undo_method(root, "set_scene_file_path", root->get_scene_file_path()); + editor_data->get_undo_redo()->add_undo_method(node, "set_scene_file_path", String()); + editor_data->get_undo_redo()->add_undo_method(node, "remove_child", root); + editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", root); + editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "add_child", node, true); + editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "move_child", node, node->get_index()); + editor_data->get_undo_redo()->add_undo_method(root, "set_owner", (Object *)nullptr); + editor_data->get_undo_redo()->add_undo_method(node, "set_owner", root); _node_replace_owner(root, root, root, MODE_UNDO); - editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().add_undo_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree"); + editor_data->get_undo_redo()->add_undo_method(scene_tree, "update_tree"); + editor_data->get_undo_redo()->commit_action(); } break; case TOOL_MULTI_EDIT: { if (!profile_allow_editing) { @@ -1008,7 +1008,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Node *node = e->get(); if (node) { Node *root = EditorNode::get_singleton()->get_edited_scene(); - UndoRedo *undo_redo = &editor_data->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo(); if (!root) { break; } @@ -1071,7 +1071,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { List<Node *> selection = editor_selection->get_selected_node_list(); List<Node *>::Element *e = selection.front(); if (e) { - UndoRedo *undo_redo = &editor_data->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo(); Node *node = e->get(); bool enabled = node->is_unique_name_in_owner(); if (!enabled && get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(node->get_name())) != nullptr) { @@ -1160,19 +1160,19 @@ void SceneTreeDock::_property_selected(int p_idx) { } void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, Ref<Resource> p_res) { - editor_data->get_undo_redo().create_action(vformat(TTR("Set %s"), p_property)); - editor_data->get_undo_redo().add_do_property(p_node, p_property, p_res); - editor_data->get_undo_redo().add_undo_property(p_node, p_property, p_node->get(p_property)); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(vformat(TTR("Set %s"), p_property)); + editor_data->get_undo_redo()->add_do_property(p_node, p_property, p_res); + editor_data->get_undo_redo()->add_undo_property(p_node, p_property, p_node->get(p_property)); + editor_data->get_undo_redo()->commit_action(); } void SceneTreeDock::add_root_node(Node *p_node) { - editor_data->get_undo_redo().create_action(TTR("New Scene Root")); - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node); - editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().add_do_reference(p_node); - editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action_for_history(TTR("New Scene Root"), editor_data->get_current_edited_scene_history_id()); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node); + editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree"); + editor_data->get_undo_redo()->add_do_reference(p_node); + editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); + editor_data->get_undo_redo()->commit_action(); } void SceneTreeDock::_node_collapsed(Object *p_obj) { @@ -1334,7 +1334,7 @@ void SceneTreeDock::_notification(int p_what) { void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root, ReplaceOwnerMode p_mode) { if (p_node->get_owner() == p_base && p_node != p_root) { - UndoRedo *undo_redo = &editor_data->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo(); switch (p_mode) { case MODE_BIDI: { bool disable_unique = p_node->is_unique_name_in_owner() && p_root->get_node_or_null(UNIQUE_NODE_PREFIX + String(p_node->get_name())) != nullptr; @@ -1567,8 +1567,8 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath> Variant old_variant = p_base->get(propertyname); Variant updated_variant = old_variant; if (_check_node_path_recursive(p_base, updated_variant, p_renames)) { - editor_data->get_undo_redo().add_do_property(p_base, propertyname, updated_variant); - editor_data->get_undo_redo().add_undo_property(p_base, propertyname, old_variant); + editor_data->get_undo_redo()->add_do_property(p_base, propertyname, updated_variant); + editor_data->get_undo_redo()->add_undo_property(p_base, propertyname, old_variant); p_base->set(propertyname, updated_variant); } } @@ -1626,12 +1626,12 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath> ERR_FAIL_COND(!EI); //another bug } - editor_data->get_undo_redo().add_do_method(anim.ptr(), "remove_track", idx); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", idx, track_np); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i)); + editor_data->get_undo_redo()->add_do_method(anim.ptr(), "remove_track", idx); + editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx); + editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_path", idx, track_np); + editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i)); for (int j = 0; j < anim->track_get_key_count(i); j++) { - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j)); + editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j)); } ran.erase(i); //byebye channel @@ -1644,8 +1644,8 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath> if (new_path == track_np) { continue; //bleh } - editor_data->get_undo_redo().add_do_method(anim.ptr(), "track_set_path", i, new_path); - editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", i, track_np); + editor_data->get_undo_redo()->add_do_method(anim.ptr(), "track_set_path", i, new_path); + editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_path", i, track_np); } } } @@ -1779,7 +1779,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V // Sort by tree order, so re-adding is easy. p_nodes.sort_custom<Node::Comparator>(); - editor_data->get_undo_redo().create_action(TTR("Reparent Node")); + editor_data->get_undo_redo()->create_action(TTR("Reparent Node")); HashMap<Node *, NodePath> path_renames; Vector<StringName> former_names; @@ -1804,11 +1804,11 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V inc--; // If the child will generate a gap when moved, adjust. } - editor_data->get_undo_redo().add_do_method(node->get_parent(), "remove_child", node); - editor_data->get_undo_redo().add_do_method(new_parent, "add_child", node, true); + editor_data->get_undo_redo()->add_do_method(node->get_parent(), "remove_child", node); + editor_data->get_undo_redo()->add_do_method(new_parent, "add_child", node, true); if (p_position_in_parent >= 0) { - editor_data->get_undo_redo().add_do_method(new_parent, "move_child", node, p_position_in_parent + inc); + editor_data->get_undo_redo()->add_do_method(new_parent, "move_child", node, p_position_in_parent + inc); } EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); @@ -1838,29 +1838,29 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V } } - editor_data->get_undo_redo().add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).plus_file(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index()); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).plus_file(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index()); if (p_keep_global_xform) { if (Object::cast_to<Node2D>(node)) { - editor_data->get_undo_redo().add_do_method(node, "set_global_transform", Object::cast_to<Node2D>(node)->get_global_transform()); + editor_data->get_undo_redo()->add_do_method(node, "set_global_transform", Object::cast_to<Node2D>(node)->get_global_transform()); } if (Object::cast_to<Node3D>(node)) { - editor_data->get_undo_redo().add_do_method(node, "set_global_transform", Object::cast_to<Node3D>(node)->get_global_transform()); + editor_data->get_undo_redo()->add_do_method(node, "set_global_transform", Object::cast_to<Node3D>(node)->get_global_transform()); } if (Object::cast_to<Control>(node)) { - editor_data->get_undo_redo().add_do_method(node, "set_global_position", Object::cast_to<Control>(node)->get_global_position()); + editor_data->get_undo_redo()->add_do_method(node, "set_global_position", Object::cast_to<Control>(node)->get_global_position()); } } - editor_data->get_undo_redo().add_do_method(this, "_set_owners", edited_scene, owners); + editor_data->get_undo_redo()->add_do_method(this, "_set_owners", edited_scene, owners); if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) { - editor_data->get_undo_redo().add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node); + editor_data->get_undo_redo()->add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node); } - editor_data->get_undo_redo().add_undo_method(new_parent, "remove_child", node); - editor_data->get_undo_redo().add_undo_method(node, "set_name", former_names[ni]); + editor_data->get_undo_redo()->add_undo_method(new_parent, "remove_child", node); + editor_data->get_undo_redo()->add_undo_method(node, "set_name", former_names[ni]); inc++; } @@ -1878,29 +1878,29 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V int child_pos = node->get_index(); - editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node, true); - editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, child_pos); - editor_data->get_undo_redo().add_undo_method(this, "_set_owners", edited_scene, owners); + editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "add_child", node, true); + editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "move_child", node, child_pos); + editor_data->get_undo_redo()->add_undo_method(this, "_set_owners", edited_scene, owners); if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) { - editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node); + editor_data->get_undo_redo()->add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node); } if (p_keep_global_xform) { if (Object::cast_to<Node2D>(node)) { - editor_data->get_undo_redo().add_undo_method(node, "set_transform", Object::cast_to<Node2D>(node)->get_transform()); + editor_data->get_undo_redo()->add_undo_method(node, "set_transform", Object::cast_to<Node2D>(node)->get_transform()); } if (Object::cast_to<Node3D>(node)) { - editor_data->get_undo_redo().add_undo_method(node, "set_transform", Object::cast_to<Node3D>(node)->get_transform()); + editor_data->get_undo_redo()->add_undo_method(node, "set_transform", Object::cast_to<Node3D>(node)->get_transform()); } if (Object::cast_to<Control>(node)) { - editor_data->get_undo_redo().add_undo_method(node, "set_position", Object::cast_to<Control>(node)->get_position()); + editor_data->get_undo_redo()->add_undo_method(node, "set_position", Object::cast_to<Control>(node)->get_position()); } } } perform_node_renames(nullptr, &path_renames); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); } bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const { @@ -1956,30 +1956,30 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) { Node *node = selected.front()->get(); Ref<Script> existing = node->get_script(); - editor_data->get_undo_redo().create_action(TTR("Attach Script")); - editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "store_script_properties", node); - editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "store_script_properties", node); - editor_data->get_undo_redo().add_do_method(node, "set_script", p_script); - editor_data->get_undo_redo().add_undo_method(node, "set_script", existing); - editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", node); - editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", node); - editor_data->get_undo_redo().add_do_method(this, "_update_script_button"); - editor_data->get_undo_redo().add_undo_method(this, "_update_script_button"); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(TTR("Attach Script")); + editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", node); + editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", node); + editor_data->get_undo_redo()->add_do_method(node, "set_script", p_script); + editor_data->get_undo_redo()->add_undo_method(node, "set_script", existing); + editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", node); + editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", node); + editor_data->get_undo_redo()->add_do_method(this, "_update_script_button"); + editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button"); + editor_data->get_undo_redo()->commit_action(); } else { - editor_data->get_undo_redo().create_action(TTR("Attach Script")); - for (List<Node *>::Element *E = selected.front(); E; E = E->next()) { - Ref<Script> existing = E->get()->get_script(); - editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "store_script_properties", E->get()); - editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E->get()); - editor_data->get_undo_redo().add_do_method(E->get(), "set_script", p_script); - editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing); - editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E->get()); - editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E->get()); - editor_data->get_undo_redo().add_do_method(this, "_update_script_button"); - editor_data->get_undo_redo().add_undo_method(this, "_update_script_button"); + editor_data->get_undo_redo()->create_action(TTR("Attach Script")); + for (Node *E : selected) { + Ref<Script> existing = E->get_script(); + editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", E); + editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E); + editor_data->get_undo_redo()->add_do_method(E, "set_script", p_script); + editor_data->get_undo_redo()->add_undo_method(E, "set_script", existing); + editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E); + editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E); + editor_data->get_undo_redo()->add_do_method(this, "_update_script_button"); + editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button"); } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); } _push_item(p_script.operator->()); @@ -1993,10 +1993,10 @@ void SceneTreeDock::_shader_created(Ref<Shader> p_shader) { Ref<Shader> existing = selected_shader_material->get_shader(); - editor_data->get_undo_redo().create_action(TTR("Set Shader")); - editor_data->get_undo_redo().add_do_method(selected_shader_material.ptr(), "set_shader", p_shader); - editor_data->get_undo_redo().add_undo_method(selected_shader_material.ptr(), "set_shader", existing); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(TTR("Set Shader")); + editor_data->get_undo_redo()->add_do_method(selected_shader_material.ptr(), "set_shader", p_shader); + editor_data->get_undo_redo()->add_undo_method(selected_shader_material.ptr(), "set_shader", existing); + editor_data->get_undo_redo()->commit_action(); } void SceneTreeDock::_script_creation_closed() { @@ -2062,9 +2062,9 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { EditorNode::get_singleton()->get_editor_plugins_over()->make_visible(false); if (p_cut) { - editor_data->get_undo_redo().create_action(TTR("Cut Node(s)")); + editor_data->get_undo_redo()->create_action(TTR("Cut Node(s)")); } else { - editor_data->get_undo_redo().create_action(TTR("Remove Node(s)")); + editor_data->get_undo_redo()->create_action(TTR("Remove Node(s)")); } bool entire_scene = false; @@ -2076,11 +2076,11 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { } if (entire_scene) { - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); - editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", edited_scene); - editor_data->get_undo_redo().add_undo_method(edited_scene, "set_owner", edited_scene->get_owner()); - editor_data->get_undo_redo().add_undo_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().add_undo_reference(edited_scene); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); + editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", edited_scene); + editor_data->get_undo_redo()->add_undo_method(edited_scene, "set_owner", edited_scene->get_owner()); + editor_data->get_undo_redo()->add_undo_method(scene_tree, "update_tree"); + editor_data->get_undo_redo()->add_undo_reference(edited_scene); } else { remove_list.sort_custom<Node::Comparator>(); //sort nodes to keep positions @@ -2109,21 +2109,21 @@ void SceneTreeDock::_delete_confirm(bool p_cut) { owners.push_back(F); } - editor_data->get_undo_redo().add_do_method(n->get_parent(), "remove_child", n); - editor_data->get_undo_redo().add_undo_method(n->get_parent(), "add_child", n, true); - editor_data->get_undo_redo().add_undo_method(n->get_parent(), "move_child", n, n->get_index()); + editor_data->get_undo_redo()->add_do_method(n->get_parent(), "remove_child", n); + editor_data->get_undo_redo()->add_undo_method(n->get_parent(), "add_child", n, true); + editor_data->get_undo_redo()->add_undo_method(n->get_parent(), "move_child", n, n->get_index()); if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == n) { - editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", n); + editor_data->get_undo_redo()->add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", n); } - editor_data->get_undo_redo().add_undo_method(this, "_set_owners", edited_scene, owners); - editor_data->get_undo_redo().add_undo_reference(n); + editor_data->get_undo_redo()->add_undo_method(this, "_set_owners", edited_scene, owners); + editor_data->get_undo_redo()->add_undo_reference(n); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo().add_do_method(ed, "live_debug_remove_and_keep_node", edited_scene->get_path_to(n), n->get_instance_id()); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_restore_node", n->get_instance_id(), edited_scene->get_path_to(n->get_parent()), n->get_index()); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_remove_and_keep_node", edited_scene->get_path_to(n), n->get_instance_id()); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_restore_node", n->get_instance_id(), edited_scene->get_path_to(n->get_parent()), n->get_index()); } } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); // hack, force 2d editor viewport to refresh after deletion if (CanvasItemEditor *editor = CanvasItemEditor::get_singleton()) { @@ -2189,29 +2189,29 @@ void SceneTreeDock::_do_create(Node *p_parent) { Node *child = Object::cast_to<Node>(c); ERR_FAIL_COND(!child); - editor_data->get_undo_redo().create_action(TTR("Create Node")); + editor_data->get_undo_redo()->create_action(TTR("Create Node")); if (edited_scene) { - editor_data->get_undo_redo().add_do_method(p_parent, "add_child", child, true); - editor_data->get_undo_redo().add_do_method(child, "set_owner", edited_scene); - editor_data->get_undo_redo().add_do_method(editor_selection, "clear"); - editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", child); - editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(p_parent, "remove_child", child); + editor_data->get_undo_redo()->add_do_method(p_parent, "add_child", child, true); + editor_data->get_undo_redo()->add_do_method(child, "set_owner", edited_scene); + editor_data->get_undo_redo()->add_do_method(editor_selection, "clear"); + editor_data->get_undo_redo()->add_do_method(editor_selection, "add_node", child); + editor_data->get_undo_redo()->add_do_reference(child); + editor_data->get_undo_redo()->add_undo_method(p_parent, "remove_child", child); String new_name = p_parent->validate_child_name(child); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); - editor_data->get_undo_redo().add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name); - editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).plus_file(new_name))); + editor_data->get_undo_redo()->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name); + editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).plus_file(new_name))); } else { - editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", child); - editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); + editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child); + editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree"); + editor_data->get_undo_redo()->add_do_reference(child); + editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); } - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->commit_action(); _push_item(c); editor_selection->clear(); editor_selection->add_node(child); @@ -2258,8 +2258,8 @@ void SceneTreeDock::_create() { List<Node *> selection = editor_selection->get_selected_node_list(); ERR_FAIL_COND(selection.size() <= 0); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change type of node(s)")); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); + ur->create_action(TTR("Change type of node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get()); for (Node *n : selection) { ERR_FAIL_COND(!n); @@ -2392,7 +2392,7 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop } //p_remove_old was added to support undo if (p_remove_old) { - editor_data->get_undo_redo().clear_history(); + editor_data->get_undo_redo()->clear_history(); } newnode->set_name(newname); @@ -2606,16 +2606,16 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) { Ref<Script> scr = ResourceLoader::load(p_file); ERR_FAIL_COND(!scr.is_valid()); if (Node *n = get_node(p_to)) { - editor_data->get_undo_redo().create_action(TTR("Attach Script")); - editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "store_script_properties", n); - editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "store_script_properties", n); - editor_data->get_undo_redo().add_do_method(n, "set_script", scr); - editor_data->get_undo_redo().add_undo_method(n, "set_script", n->get_script()); - editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", n); - editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", n); - editor_data->get_undo_redo().add_do_method(this, "_update_script_button"); - editor_data->get_undo_redo().add_undo_method(this, "_update_script_button"); - editor_data->get_undo_redo().commit_action(); + editor_data->get_undo_redo()->create_action(TTR("Attach Script")); + editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", n); + editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", n); + editor_data->get_undo_redo()->add_do_method(n, "set_script", scr); + editor_data->get_undo_redo()->add_undo_method(n, "set_script", n->get_script()); + editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", n); + editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", n); + editor_data->get_undo_redo()->add_do_method(this, "_update_script_button"); + editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button"); + editor_data->get_undo_redo()->commit_action(); } } @@ -3063,9 +3063,9 @@ List<Node *> SceneTreeDock::paste_nodes() { owner = paste_parent; } - UndoRedo &ur = editor_data->get_undo_redo(); - ur.create_action(TTR("Paste Node(s)")); - ur.add_do_method(editor_selection, "clear"); + Ref<EditorUndoRedoManager> &ur = editor_data->get_undo_redo(); + ur->create_action(TTR("Paste Node(s)"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene()); + ur->add_do_method(editor_selection, "clear"); HashMap<Ref<Resource>, Ref<Resource>> resource_remap; String target_scene; @@ -3094,36 +3094,36 @@ List<Node *> SceneTreeDock::paste_nodes() { if (!paste_parent) { paste_parent = dup; owner = dup; - ur.add_do_method(EditorNode::get_singleton(), "set_edited_scene", dup); + ur->add_do_method(EditorNode::get_singleton(), "set_edited_scene", dup); } else { - ur.add_do_method(paste_parent, "add_child", dup, true); + ur->add_do_method(paste_parent, "add_child", dup, true); } for (KeyValue<const Node *, Node *> &E2 : duplimap) { Node *d = E2.value; if (d != dup) { - ur.add_do_method(d, "set_owner", owner); + ur->add_do_method(d, "set_owner", owner); } } if (dup != owner) { - ur.add_do_method(dup, "set_owner", owner); + ur->add_do_method(dup, "set_owner", owner); } - ur.add_do_method(editor_selection, "add_node", dup); + ur->add_do_method(editor_selection, "add_node", dup); if (dup == paste_parent) { - ur.add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); + ur->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr); } else { - ur.add_undo_method(paste_parent, "remove_child", dup); + ur->add_undo_method(paste_parent, "remove_child", dup); } - ur.add_do_reference(dup); + ur->add_do_reference(dup); if (node_clipboard.size() == 1) { - ur.add_do_method(EditorNode::get_singleton(), "push_item", dup); + ur->add_do_method(EditorNode::get_singleton(), "push_item", dup); } } - ur.commit_action(); + ur->commit_action(); return pasted_nodes; } @@ -3491,7 +3491,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed)); - scene_tree->set_undo_redo(&editor_data->get_undo_redo()); + scene_tree->set_undo_redo(editor_data->get_undo_redo()); scene_tree->set_editor_selection(editor_selection); create_dialog = memnew(CreateDialog); @@ -3501,7 +3501,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec create_dialog->connect("favorites_updated", callable_mp(this, &SceneTreeDock::_update_create_root_dialog)); #ifdef MODULE_REGEX_ENABLED - rename_dialog = memnew(RenameDialog(scene_tree, &editor_data->get_undo_redo())); + rename_dialog = memnew(RenameDialog(scene_tree, editor_data->get_undo_redo())); add_child(rename_dialog); #endif // MODULE_REGEX_ENABLED diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index ad83db9b60..5f1c0bd26d 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -35,6 +35,7 @@ #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/node_dock.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" @@ -365,7 +366,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { item->set_tooltip(0, tooltip); } - if (can_open_instance && undo_redo) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes + if (can_open_instance && undo_redo.is_valid()) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes if (!p_node->is_connected("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed))) { p_node->connect("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed).bind(p_node)); @@ -883,7 +884,7 @@ void SceneTreeEditor::_renamed() { return; } - if (!undo_redo) { + if (!undo_redo.is_valid()) { n->set_name(new_name); which->set_metadata(0, n->get_path()); emit_signal(SNAME("node_renamed")); @@ -927,6 +928,10 @@ String SceneTreeEditor::get_filter() const { return filter; } +void SceneTreeEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) { + undo_redo = p_undo_redo; +} + void SceneTreeEditor::set_display_foreign_nodes(bool p_display) { display_foreign = p_display; _update_tree(); @@ -1258,7 +1263,6 @@ void SceneTreeEditor::_bind_methods() { } SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_open_instance) { - undo_redo = nullptr; selected = nullptr; can_rename = p_can_rename; diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index 31772e55b5..0c13ad96cd 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -31,13 +31,14 @@ #ifndef SCENE_TREE_EDITOR_H #define SCENE_TREE_EDITOR_H -#include "core/object/undo_redo.h" #include "editor/editor_data.h" #include "editor/editor_settings.h" #include "scene/gui/button.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" +class EditorUndoRedoManager; + class SceneTreeEditor : public Control { GDCLASS(SceneTreeEditor, Control); @@ -98,7 +99,7 @@ class SceneTreeEditor : public Control { bool show_enabled_subscene = false; void _renamed(); - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; HashSet<Node *> marked; bool marked_selectable = false; @@ -139,7 +140,7 @@ public: void set_filter(const String &p_filter); String get_filter() const; - void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }; + void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo); void set_display_foreign_nodes(bool p_display); void set_marked(const HashSet<Node *> &p_marked, bool p_selectable = false, bool p_children_selectable = true); diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp index 1cd1b4ea00..9058596830 100644 --- a/editor/shader_globals_editor.cpp +++ b/editor/shader_globals_editor.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "servers/rendering/shader_language.h" static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = { @@ -85,7 +86,7 @@ protected: return false; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Set Shader Global Variable")); undo_redo->add_do_method(RS::get_singleton(), "global_shader_uniform_set", p_name, p_value); @@ -393,7 +394,7 @@ void ShaderGlobalsEditor::_variable_added() { return; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); Variant value = create_var(RS::GlobalShaderUniformType(variable_type->get_selected())); @@ -412,7 +413,7 @@ void ShaderGlobalsEditor::_variable_added() { } void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) { - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(TTR("Add Shader Global Uniform")); undo_redo->add_do_method(RS::get_singleton(), "global_shader_uniform_remove", p_variable); diff --git a/editor/shader_globals_editor.h b/editor/shader_globals_editor.h index d29052eaee..1e2f1dd828 100644 --- a/editor/shader_globals_editor.h +++ b/editor/shader_globals_editor.h @@ -31,7 +31,6 @@ #ifndef SHADER_GLOBALS_EDITOR_H #define SHADER_GLOBALS_EDITOR_H -#include "core/object/undo_redo.h" #include "editor/editor_autoload_settings.h" #include "editor/editor_data.h" #include "editor/editor_plugin_settings.h" diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp index 6442ff71fc..ba9b96db74 100644 --- a/modules/csg/editor/csg_gizmos.cpp +++ b/modules/csg/editor/csg_gizmos.cpp @@ -32,7 +32,9 @@ #ifdef TOOLS_ENABLED +#include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "scene/3d/camera_3d.h" @@ -215,7 +217,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Sphere Shape Radius")); ur->add_do_method(s, "set_radius", s->get_radius()); ur->add_undo_method(s, "set_radius", p_restore); @@ -229,7 +231,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Change Box Shape Size")); ur->add_do_method(s, "set_size", s->get_size()); ur->add_undo_method(s, "set_size", p_restore); @@ -247,7 +249,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (p_id == 0) { ur->create_action(TTR("Change Cylinder Radius")); ur->add_do_method(s, "set_radius", s->get_radius()); @@ -272,7 +274,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int return; } - UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); if (p_id == 0) { ur->create_action(TTR("Change Torus Inner Radius")); ur->add_do_method(s, "set_inner_radius", s->get_inner_radius()); diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp index 7471bae093..17f9832096 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.cpp +++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp @@ -37,6 +37,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "scene/3d/camera_3d.h" #include "scene/main/window.h" diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h index 3b29397502..a64dc4a80b 100644 --- a/modules/gridmap/editor/grid_map_editor_plugin.h +++ b/modules/gridmap/editor/grid_map_editor_plugin.h @@ -39,6 +39,7 @@ #include "scene/gui/slider.h" #include "scene/gui/spin_box.h" +class EditorUndoRedoManager; class Node3DEditorPlugin; class GridMapEditor : public VBoxContainer { @@ -62,7 +63,7 @@ class GridMapEditor : public VBoxContainer { DISPLAY_LIST }; - UndoRedo *undo_redo = nullptr; + Ref<EditorUndoRedoManager> undo_redo; InputAction input_action = INPUT_NONE; Panel *panel = nullptr; MenuButton *options = nullptr; diff --git a/modules/multiplayer/editor/replication_editor_plugin.cpp b/modules/multiplayer/editor/replication_editor_plugin.cpp index 50f1434ad8..f045018f25 100644 --- a/modules/multiplayer/editor/replication_editor_plugin.cpp +++ b/modules/multiplayer/editor/replication_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/inspector_dock.h" #include "editor/scene_tree_editor.h" #include "modules/multiplayer/multiplayer_synchronizer.h" @@ -139,7 +140,7 @@ void ReplicationEditor::_add_sync_property(String p_path) { return; } - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(TTR("Add property to synchronizer")); if (config.is_null()) { @@ -354,7 +355,7 @@ void ReplicationEditor::_tree_item_edited() { int column = tree->get_edited_column(); ERR_FAIL_COND(column < 1 || column > 2); const NodePath prop = ti->get_metadata(0); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); bool value = ti->is_checked(column); String method; if (column == 1) { @@ -394,7 +395,7 @@ void ReplicationEditor::_dialog_closed(bool p_confirmed) { int idx = config->property_get_index(prop); bool spawn = config->property_get_spawn(prop); bool sync = config->property_get_sync(prop); - UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Remove Property")); undo_redo->add_do_method(config.ptr(), "remove_property", prop); undo_redo->add_undo_method(config.ptr(), "add_property", prop, idx); diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp index 2c7d23a3c4..a5eb09f786 100644 --- a/modules/visual_script/editor/visual_script_editor.cpp +++ b/modules/visual_script/editor/visual_script_editor.cpp @@ -43,6 +43,7 @@ #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/gui/check_button.h" #include "scene/gui/graph_edit.h" #include "scene/gui/separator.h" @@ -74,7 +75,7 @@ class VisualScriptEditorSignalEdit : public Object { StringName sig; public: - UndoRedo *undo_redo; + Ref<EditorUndoRedoManager> undo_redo; Ref<VisualScript> script; protected: @@ -197,8 +198,6 @@ public: sig = p_sig; notify_property_list_changed(); } - - VisualScriptEditorSignalEdit() { undo_redo = nullptr; } }; class VisualScriptEditorVariableEdit : public Object { @@ -207,7 +206,7 @@ class VisualScriptEditorVariableEdit : public Object { StringName var; public: - UndoRedo *undo_redo; + Ref<EditorUndoRedoManager> undo_redo; Ref<VisualScript> script; protected: @@ -355,8 +354,6 @@ public: var = p_var; notify_property_list_changed(); } - - VisualScriptEditorVariableEdit() { undo_redo = nullptr; } }; static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h index 6b337e52f6..306f71ecf8 100644 --- a/modules/visual_script/editor/visual_script_editor.h +++ b/modules/visual_script/editor/visual_script_editor.h @@ -38,6 +38,7 @@ class GraphEdit; +class EditorUndoRedoManager; class VisualScriptEditorSignalEdit; class VisualScriptEditorVariableEdit; @@ -135,8 +136,7 @@ class VisualScriptEditor : public ScriptEditorBase { EditorProperty *default_property_editor = nullptr; Ref<VisualScriptEditedProperty> edited_default_property_holder; - UndoRedo *undo_redo = nullptr; - + Ref<EditorUndoRedoManager> undo_redo; Tree *members = nullptr; AcceptDialog *function_name_edit = nullptr; LineEdit *function_name_box = nullptr; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 1a7bf4c302..1af12a90f2 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -37,6 +37,7 @@ #ifdef TOOLS_ENABLED #include "editor/editor_node.h" +#include "editor/editor_undo_redo_manager.h" #include "scene/2d/skeleton_2d.h" void AnimatedValuesBackup::update_skeletons() { @@ -2046,7 +2047,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) { Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values(); old_values->restore(); - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); ur->create_action(TTR("Anim Apply Reset")); ur->add_do_method(new_values.ptr(), "restore"); ur->add_undo_method(old_values.ptr(), "restore"); |