Skip to content

Commit

Permalink
Merge pull request godotengine#53713 from groud/add_force_keep_on_und…
Browse files Browse the repository at this point in the history
…o_redo_merge_ends
  • Loading branch information
akien-mga authored Oct 12, 2021
2 parents d5409e3 + 1be0086 commit 480fc31
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 13 deletions.
59 changes: 47 additions & 12 deletions core/object/undo_redo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#include "core/io/resource.h"
#include "core/os/os.h"
#include "core/templates/local_vector.h"

void UndoRedo::_discard_redo() {
if (current_action == actions.size() - 1) {
Expand Down Expand Up @@ -85,38 +86,52 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
current_action = actions.size() - 2;

if (p_mode == MERGE_ENDS) {
// Clear all do ops from last action, and delete all object references
List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front();
// Clear all do ops from last action if they are not forced kept
LocalVector<List<Operation>::Element *> to_remove;
for (List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front(); E; E = E->next()) {
if (!E->get().force_keep_in_merge_ends) {
to_remove.push_back(E);
}
}

while (E) {
for (unsigned int i = 0; i < to_remove.size(); i++) {
List<Operation>::Element *E = to_remove[i];
// Delete all object references
if (E->get().type == Operation::TYPE_REFERENCE) {
Object *obj = ObjectDB::get_instance(E->get().object);

if (obj) {
memdelete(obj);
}
}

E = E->next();
actions.write[current_action + 1].do_ops.pop_front();
String s = "removed " + E->get().name + ": ";
for (int j = 0; j < VARIANT_ARG_MAX; j++) {
if (E->get().args[j].get_type() == Variant::NIL) {
break;
}
s += String(E->get().args[j]);
}
print_line(s);
E->erase();
}
}

actions.write[actions.size() - 1].last_tick = ticks;

merge_mode = p_mode;
merging = true;
} else {
Action new_action;
new_action.name = p_name;
new_action.last_tick = ticks;
actions.push_back(new_action);

merge_mode = MERGE_DISABLE;
}

merge_mode = p_mode;
}

action_level++;

force_keep_in_merge_ends = false;
}

void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) {
Expand Down Expand Up @@ -146,7 +161,7 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR
ERR_FAIL_COND((current_action + 1) >= actions.size());

// No undo if the merge mode is MERGE_ENDS
if (merge_mode == MERGE_ENDS) {
if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) {
return;
}

Expand All @@ -157,6 +172,7 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR
}

undo_op.type = Operation::TYPE_METHOD;
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
undo_op.name = p_method;

for (int i = 0; i < VARIANT_ARG_MAX; i++) {
Expand Down Expand Up @@ -187,7 +203,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property,
ERR_FAIL_COND((current_action + 1) >= actions.size());

// No undo if the merge mode is MERGE_ENDS
if (merge_mode == MERGE_ENDS) {
if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) {
return;
}

Expand All @@ -198,6 +214,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property,
}

undo_op.type = Operation::TYPE_PROPERTY;
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
undo_op.name = p_property;
undo_op.args[0] = p_value;
actions.write[current_action + 1].undo_ops.push_back(undo_op);
Expand All @@ -223,7 +240,7 @@ void UndoRedo::add_undo_reference(Object *p_object) {
ERR_FAIL_COND((current_action + 1) >= actions.size());

// No undo if the merge mode is MERGE_ENDS
if (merge_mode == MERGE_ENDS) {
if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) {
return;
}

Expand All @@ -234,9 +251,24 @@ void UndoRedo::add_undo_reference(Object *p_object) {
}

undo_op.type = Operation::TYPE_REFERENCE;
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}

void UndoRedo::start_force_keep_in_merge_ends() {
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());

force_keep_in_merge_ends = true;
}

void UndoRedo::end_force_keep_in_merge_ends() {
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());

force_keep_in_merge_ends = false;
}

void UndoRedo::_pop_history_tail() {
_discard_redo();

Expand Down Expand Up @@ -538,6 +570,9 @@ void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &UndoRedo::add_do_reference);
ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &UndoRedo::add_undo_reference);

ClassDB::bind_method(D_METHOD("start_force_keep_in_merge_ends"), &UndoRedo::start_force_keep_in_merge_ends);
ClassDB::bind_method(D_METHOD("end_force_keep_in_merge_ends"), &UndoRedo::end_force_keep_in_merge_ends);

ClassDB::bind_method(D_METHOD("get_history_count"), &UndoRedo::get_history_count);
ClassDB::bind_method(D_METHOD("get_current_action"), &UndoRedo::get_current_action);
ClassDB::bind_method(D_METHOD("get_action_name", "id"), &UndoRedo::get_action_name);
Expand Down
5 changes: 5 additions & 0 deletions core/object/undo_redo.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class UndoRedo : public Object {
};

Type type;
bool force_keep_in_merge_ends;
Ref<RefCounted> ref;
ObjectID object;
StringName name;
Expand All @@ -76,6 +77,7 @@ class UndoRedo : public Object {

Vector<Action> actions;
int current_action = -1;
bool force_keep_in_merge_ends = false;
int action_level = 0;
MergeMode merge_mode = MERGE_DISABLE;
bool merging = false;
Expand Down Expand Up @@ -109,6 +111,9 @@ class UndoRedo : public Object {
void add_do_reference(Object *p_object);
void add_undo_reference(Object *p_object);

void start_force_keep_in_merge_ends();
void end_force_keep_in_merge_ends();

bool is_committing_action() const;
void commit_action(bool p_execute = true);

Expand Down
14 changes: 13 additions & 1 deletion doc/classes/UndoRedo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@
The way actions are merged is dictated by the [code]merge_mode[/code] argument. See [enum MergeMode] for details.
</description>
</method>
<method name="end_force_keep_in_merge_ends">
<return type="void" />
<description>
Stops marking operations as to be processed even if the action gets merged with another in the [constant MERGE_ENDS] mode. See [method start_force_keep_in_merge_ends].
</description>
</method>
<method name="get_action_name">
<return type="String" />
<argument index="0" name="id" type="int" />
Expand Down Expand Up @@ -190,6 +196,12 @@
Redo the last action.
</description>
</method>
<method name="start_force_keep_in_merge_ends">
<return type="void" />
<description>
Marks the next "do" and "undo" operations to be processed even if the action gets merged with another in the [constant MERGE_ENDS] mode. Return to normal operation using [method end_force_keep_in_merge_ends].
</description>
</method>
<method name="undo">
<return type="bool" />
<description>
Expand All @@ -209,7 +221,7 @@
Makes "do"/"undo" operations stay in separate actions.
</constant>
<constant name="MERGE_ENDS" value="1" enum="MergeMode">
Makes so that the action's "do" operation is from the first action created and the "undo" operation is from the last subsequent action with the same name.
Makes so that the action's "undo" operations are from the first action created and the "do" operations are from the last subsequent action with the same name.
</constant>
<constant name="MERGE_ALL" value="2" enum="MergeMode">
Makes subsequent actions with the same name be merged into one.
Expand Down

0 comments on commit 480fc31

Please sign in to comment.