Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add per-scene UndoRedo #59564

Merged
merged 1 commit into from
Aug 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/classes/EditorPlugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
118 changes: 118 additions & 0 deletions doc/classes/EditorUndoRedoManager.xml
Original file line number Diff line number Diff line change
@@ -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>
3 changes: 2 additions & 1 deletion editor/animation_bezier_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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;
}

Expand Down
5 changes: 3 additions & 2 deletions editor/animation_bezier_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "animation_track_editor.h"
#include "core/templates/rb_set.h"

class EditorUndoRedoManager;
class ViewPanner;

class AnimationBezierTrackEdit : public Control {
Expand All @@ -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;
Expand Down Expand Up @@ -180,7 +181,7 @@ class AnimationBezierTrackEdit : public Control {
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could maybe be const Ref<T> &?

Copy link
Member Author

@KoBeWi KoBeWi May 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually planning to remove all the set_undo_redo() methods and just access it directly from the EditorNode singleton (similar to #57306), just not sure if it's better to do it after this PR or before. If done before it might make this PR even bigger, but if done after, this PR will add code that will need to be removed later.

void set_timeline(AnimationTimelineEdit *p_timeline);
void set_editor(AnimationTrackEditor *p_editor);
void set_root(Node *p_root);
Expand Down
19 changes: 12 additions & 7 deletions editor/animation_track_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -680,7 +681,7 @@ class AnimationTrackKeyEdit : public Object {
}
}

UndoRedo *undo_redo = nullptr;
Ref<EditorUndoRedoManager> undo_redo;
Ref<Animation> animation;
int track = -1;
float key_ofs = 0;
Expand Down Expand Up @@ -1374,7 +1375,7 @@ class AnimationMultiTrackKeyEdit : public Object {

bool use_fps = false;

UndoRedo *undo_redo = nullptr;
Ref<EditorUndoRedoManager> undo_redo;

void notify_change() {
notify_property_list_changed();
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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.
Expand Down
12 changes: 6 additions & 6 deletions editor/animation_track_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -112,7 +112,7 @@ class AnimationTimelineEdit : public Range {
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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -234,12 +234,12 @@ class AnimationTrackEdit : public Control {
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);
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions editor/animation_track_editor_plugins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
7 changes: 4 additions & 3 deletions editor/array_property_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions editor/connections_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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();
Expand Down
6 changes: 3 additions & 3 deletions editor/connections_dialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -48,6 +47,7 @@
#include "scene/gui/tree.h"

class ConnectDialogBinds;
class EditorUndoRedoManager;

class ConnectDialog : public ConfirmationDialog {
GDCLASS(ConnectDialog, ConfirmationDialog);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -225,7 +225,7 @@ class ConnectionsDock : public VBoxContainer {
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();

Expand Down
Loading