Merge pull request #6188 from TheHX/undo-redo

Implemented UndoRedo mergeable modes
This commit is contained in:
Rémi Verschelde 2016-08-29 19:04:42 +02:00 committed by GitHub
commit e51d59ed98
8 changed files with 81 additions and 34 deletions

View file

@ -52,26 +52,46 @@ void UndoRedo::_discard_redo() {
} }
void UndoRedo::create_action(const String& p_name,MergeMode p_mode) {
void UndoRedo::create_action(const String& p_name,bool p_mergeable) {
if (action_level==0) { if (action_level==0) {
_discard_redo(); _discard_redo();
if (p_mergeable && actions.size() && actions[actions.size()-1].name==p_name) {
//old will replace new (it's mergeable after all) // Check if the merge operation is valid
// should check references though! if (p_mode!=MERGE_DISABLE && actions.size() && actions[actions.size()-1].name==p_name) {
current_action=actions.size()-2; current_action=actions.size()-2;
actions[current_action+1].do_ops.clear();
//actions[current_action+1].undo_ops.clear(); - no, this is kept if (p_mode==MERGE_ENDS) {
merging=true;
// Clear all do ops from last action, and delete all object references
List<Operation>::Element *E=actions[current_action+1].do_ops.front();
while (E) {
if (E->get().type==Operation::TYPE_REFERENCE) {
Object *obj=ObjectDB::get_instance(E->get().object);
if (obj)
memdelete(obj);
}
E=E->next();
actions[current_action+1].do_ops.pop_front();
}
}
merge_mode=p_mode;
} else { } else {
Action new_action; Action new_action;
new_action.name=p_name; new_action.name=p_name;
actions.push_back(new_action); actions.push_back(new_action);
merging=false;
merge_mode=MERGE_DISABLE;
} }
} }
@ -102,8 +122,10 @@ void UndoRedo::add_undo_method(Object *p_object,const String& p_method,VARIANT_A
VARIANT_ARGPTRS VARIANT_ARGPTRS
ERR_FAIL_COND(action_level<=0); ERR_FAIL_COND(action_level<=0);
ERR_FAIL_COND((current_action+1)>=actions.size()); ERR_FAIL_COND((current_action+1)>=actions.size());
if (merging)
return; //- no undo if merging // No undo if the merge mode is MERGE_ENDS
if (merge_mode==MERGE_ENDS)
return;
Operation undo_op; Operation undo_op;
undo_op.object=p_object->get_instance_ID(); undo_op.object=p_object->get_instance_ID();
@ -139,6 +161,10 @@ void UndoRedo::add_undo_property(Object *p_object,const String& p_property,const
ERR_FAIL_COND(action_level<=0); ERR_FAIL_COND(action_level<=0);
ERR_FAIL_COND((current_action+1)>=actions.size()); ERR_FAIL_COND((current_action+1)>=actions.size());
// No undo if the merge mode is MERGE_ENDS
if (merge_mode==MERGE_ENDS)
return;
Operation undo_op; Operation undo_op;
undo_op.object=p_object->get_instance_ID(); undo_op.object=p_object->get_instance_ID();
if (p_object->cast_to<Resource>()) if (p_object->cast_to<Resource>())
@ -167,6 +193,11 @@ void UndoRedo::add_undo_reference(Object *p_object) {
ERR_FAIL_COND(action_level<=0); ERR_FAIL_COND(action_level<=0);
ERR_FAIL_COND((current_action+1)>=actions.size()); ERR_FAIL_COND((current_action+1)>=actions.size());
// No undo if the merge mode is MERGE_ENDS
if (merge_mode==MERGE_ENDS)
return;
Operation undo_op; Operation undo_op;
undo_op.object=p_object->get_instance_ID(); undo_op.object=p_object->get_instance_ID();
if (p_object->cast_to<Resource>()) if (p_object->cast_to<Resource>())
@ -352,7 +383,7 @@ UndoRedo::UndoRedo() {
action_level=0; action_level=0;
current_action=-1; current_action=-1;
max_steps=-1; max_steps=-1;
merging=true; merge_mode=MERGE_DISABLE;
callback=NULL; callback=NULL;
callback_ud=NULL; callback_ud=NULL;
@ -448,7 +479,7 @@ Variant UndoRedo::_add_undo_method(const Variant** p_args, int p_argcount, Varia
void UndoRedo::_bind_methods() { void UndoRedo::_bind_methods() {
ObjectTypeDB::bind_method(_MD("create_action","name","mergeable"),&UndoRedo::create_action, DEFVAL(false) ); ObjectTypeDB::bind_method(_MD("create_action","name","merge_mode"),&UndoRedo::create_action, DEFVAL(MERGE_DISABLE) );
ObjectTypeDB::bind_method(_MD("commit_action"),&UndoRedo::commit_action); ObjectTypeDB::bind_method(_MD("commit_action"),&UndoRedo::commit_action);
//ObjectTypeDB::bind_method(_MD("add_do_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_do_method); //ObjectTypeDB::bind_method(_MD("add_do_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_do_method);
@ -489,4 +520,8 @@ void UndoRedo::_bind_methods() {
ObjectTypeDB::bind_method(_MD("clear_history"),&UndoRedo::clear_history); ObjectTypeDB::bind_method(_MD("clear_history"),&UndoRedo::clear_history);
ObjectTypeDB::bind_method(_MD("get_current_action_name"),&UndoRedo::get_current_action_name); ObjectTypeDB::bind_method(_MD("get_current_action_name"),&UndoRedo::get_current_action_name);
ObjectTypeDB::bind_method(_MD("get_version"),&UndoRedo::get_version); ObjectTypeDB::bind_method(_MD("get_version"),&UndoRedo::get_version);
BIND_CONSTANT(MERGE_DISABLE);
BIND_CONSTANT(MERGE_ENDS);
BIND_CONSTANT(MERGE_ALL);
} }

View file

@ -41,6 +41,12 @@ class UndoRedo : public Object {
OBJ_SAVE_TYPE( UndoRedo ); OBJ_SAVE_TYPE( UndoRedo );
public: public:
enum MergeMode {
MERGE_DISABLE,
MERGE_ENDS,
MERGE_ALL
};
typedef void (*CommitNotifyCallback)(void *p_ud,const String& p_name); typedef void (*CommitNotifyCallback)(void *p_ud,const String& p_name);
Variant _add_do_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error); Variant _add_do_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
Variant _add_undo_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error); Variant _add_undo_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
@ -76,7 +82,7 @@ private:
int current_action; int current_action;
int action_level; int action_level;
int max_steps; int max_steps;
bool merging; MergeMode merge_mode;
uint64_t version; uint64_t version;
void _pop_history_tail(); void _pop_history_tail();
@ -98,7 +104,7 @@ protected:
public: public:
void create_action(const String& p_name="",bool p_mergeable=false); void create_action(const String& p_name="",MergeMode p_mode=MERGE_DISABLE);
void add_do_method(Object *p_object,const String& p_method,VARIANT_ARG_LIST); void add_do_method(Object *p_object,const String& p_method,VARIANT_ARG_LIST);
void add_undo_method(Object *p_object,const String& p_method,VARIANT_ARG_LIST); void add_undo_method(Object *p_object,const String& p_method,VARIANT_ARG_LIST);
@ -128,4 +134,6 @@ public:
~UndoRedo(); ~UndoRedo();
}; };
VARIANT_ENUM_CAST( UndoRedo::MergeMode );
#endif // UNDO_REDO_H #endif // UNDO_REDO_H

View file

@ -316,7 +316,7 @@ public:
int existing = animation->track_find_key(track,new_time,true); int existing = animation->track_find_key(track,new_time,true);
setting=true; setting=true;
undo_redo->create_action(TTR("Move Add Key"),false); undo_redo->create_action(TTR("Move Add Key"),UndoRedo::MERGE_ENDS);
Variant val = animation->track_get_key_value(track,key); Variant val = animation->track_get_key_value(track,key);
float trans = animation->track_get_key_transition(track,key); float trans = animation->track_get_key_transition(track,key);
@ -344,7 +344,7 @@ public:
float val = p_value; float val = p_value;
float prev_val = animation->track_get_key_transition(track,key); float prev_val = animation->track_get_key_transition(track,key);
setting=true; setting=true;
undo_redo->create_action(TTR("Anim Change Transition"),true); undo_redo->create_action(TTR("Anim Change Transition"),UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(animation.ptr(),"track_set_key_transition",track,key,val); undo_redo->add_do_method(animation.ptr(),"track_set_key_transition",track,key,val);
undo_redo->add_undo_method(animation.ptr(),"track_set_key_transition",track,key,prev_val); undo_redo->add_undo_method(animation.ptr(),"track_set_key_transition",track,key,prev_val);
undo_redo->add_do_method(this,"_update_obj",animation); undo_redo->add_do_method(this,"_update_obj",animation);
@ -387,7 +387,7 @@ public:
} }
setting=true; setting=true;
undo_redo->create_action(TTR("Anim Change Value"),true); undo_redo->create_action(TTR("Anim Change Value"),UndoRedo::MERGE_ENDS);
Variant prev = animation->track_get_key_value(track,key); Variant prev = animation->track_get_key_value(track,key);
undo_redo->add_do_method(animation.ptr(),"track_set_key_value",track,key,value); undo_redo->add_do_method(animation.ptr(),"track_set_key_value",track,key,value);
undo_redo->add_undo_method(animation.ptr(),"track_set_key_value",track,key,prev); undo_redo->add_undo_method(animation.ptr(),"track_set_key_value",track,key,prev);
@ -463,7 +463,11 @@ public:
} }
} }
undo_redo->create_action(TTR("Anim Change Call"),mergeable); if (mergeable)
undo_redo->create_action(TTR("Anim Change Call"),UndoRedo::MERGE_ENDS);
else
undo_redo->create_action(TTR("Anim Change Call"));
Variant prev = animation->track_get_key_value(track,key); Variant prev = animation->track_get_key_value(track,key);
setting=true; setting=true;
undo_redo->add_do_method(animation.ptr(),"track_set_key_value",track,key,d_new); undo_redo->add_do_method(animation.ptr(),"track_set_key_value",track,key,d_new);
@ -1715,9 +1719,9 @@ void AnimationKeyEditor::_curve_transition_changed(float p_what) {
if (selection.size()==0) if (selection.size()==0)
return; return;
if (selection.size()==1) if (selection.size()==1)
undo_redo->create_action(TTR("Edit Node Curve"),true); undo_redo->create_action(TTR("Edit Node Curve"),UndoRedo::MERGE_ENDS);
else else
undo_redo->create_action(TTR("Edit Selection Curve"),true); undo_redo->create_action(TTR("Edit Selection Curve"),UndoRedo::MERGE_ENDS);
for(Map<SelectedKey,KeyInfo>::Element *E=selection.front();E;E=E->next()) { for(Map<SelectedKey,KeyInfo>::Element *E=selection.front();E;E=E->next()) {

View file

@ -648,7 +648,7 @@ void CanvasItemEditor::_key_move(const Vector2& p_dir, bool p_snap, KeyMoveMODE
if (editor_selection->get_selected_node_list().empty()) if (editor_selection->get_selected_node_list().empty())
return; return;
undo_redo->create_action(TTR("Move Action"),true); undo_redo->create_action(TTR("Move Action"),UndoRedo::MERGE_ENDS);
List<Node*> &selection = editor_selection->get_selected_node_list(); List<Node*> &selection = editor_selection->get_selected_node_list();

View file

@ -84,7 +84,7 @@ void ColorRampEditorPlugin::_ramp_changed() {
if (old_offsets.size()!=new_offsets.size()) if (old_offsets.size()!=new_offsets.size())
ur->create_action(TTR("Add/Remove Color Ramp Point")); ur->create_action(TTR("Add/Remove Color Ramp Point"));
else else
ur->create_action(TTR("Modify Color Ramp"),true); ur->create_action(TTR("Modify Color Ramp"),UndoRedo::MERGE_ENDS);
ur->add_do_method(this,"undo_redo_color_ramp",new_offsets,new_colors); ur->add_do_method(this,"undo_redo_color_ramp",new_offsets,new_colors);
ur->add_undo_method(this,"undo_redo_color_ramp",old_offsets,old_colors); ur->add_undo_method(this,"undo_redo_color_ramp",old_offsets,old_colors);
ur->commit_action(); ur->commit_action();

View file

@ -675,7 +675,7 @@ GraphCurveMapEdit::GraphCurveMapEdit(){
void ShaderGraphView::_scalar_const_changed(double p_value,int p_id) { void ShaderGraphView::_scalar_const_changed(double p_value,int p_id) {
UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change Scalar Constant"),true); ur->create_action(TTR("Change Scalar Constant"),UndoRedo::MERGE_ENDS);
ur->add_do_method(graph.ptr(),"scalar_const_node_set_value",type,p_id,p_value); ur->add_do_method(graph.ptr(),"scalar_const_node_set_value",type,p_id,p_value);
ur->add_undo_method(graph.ptr(),"scalar_const_node_set_value",type,p_id,graph->scalar_const_node_get_value(type,p_id)); ur->add_undo_method(graph.ptr(),"scalar_const_node_set_value",type,p_id,graph->scalar_const_node_get_value(type,p_id));
ur->add_do_method(this,"_update_graph"); ur->add_do_method(this,"_update_graph");
@ -693,7 +693,7 @@ void ShaderGraphView::_vec_const_changed(double p_value, int p_id,Array p_arr){
} }
UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change Vec Constant"),true); ur->create_action(TTR("Change Vec Constant"),UndoRedo::MERGE_ENDS);
ur->add_do_method(graph.ptr(),"vec_const_node_set_value",type,p_id,val); ur->add_do_method(graph.ptr(),"vec_const_node_set_value",type,p_id,val);
ur->add_undo_method(graph.ptr(),"vec_const_node_set_value",type,p_id,graph->vec_const_node_get_value(type,p_id)); ur->add_undo_method(graph.ptr(),"vec_const_node_set_value",type,p_id,graph->vec_const_node_get_value(type,p_id));
ur->add_do_method(this,"_update_graph"); ur->add_do_method(this,"_update_graph");
@ -706,7 +706,7 @@ void ShaderGraphView::_vec_const_changed(double p_value, int p_id,Array p_arr){
void ShaderGraphView::_rgb_const_changed(const Color& p_color, int p_id){ void ShaderGraphView::_rgb_const_changed(const Color& p_color, int p_id){
UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change RGB Constant"),true); ur->create_action(TTR("Change RGB Constant"),UndoRedo::MERGE_ENDS);
ur->add_do_method(graph.ptr(),"rgb_const_node_set_value",type,p_id,p_color); ur->add_do_method(graph.ptr(),"rgb_const_node_set_value",type,p_id,p_color);
ur->add_undo_method(graph.ptr(),"rgb_const_node_set_value",type,p_id,graph->rgb_const_node_get_value(type,p_id)); ur->add_undo_method(graph.ptr(),"rgb_const_node_set_value",type,p_id,graph->rgb_const_node_get_value(type,p_id));
ur->add_do_method(this,"_update_graph"); ur->add_do_method(this,"_update_graph");
@ -807,7 +807,7 @@ void ShaderGraphView::_vec_func_changed(int p_func, int p_id){
void ShaderGraphView::_scalar_input_changed(double p_value,int p_id){ void ShaderGraphView::_scalar_input_changed(double p_value,int p_id){
UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change Scalar Uniform"),true); ur->create_action(TTR("Change Scalar Uniform"),UndoRedo::MERGE_ENDS);
ur->add_do_method(graph.ptr(),"scalar_input_node_set_value",type,p_id,p_value); ur->add_do_method(graph.ptr(),"scalar_input_node_set_value",type,p_id,p_value);
ur->add_undo_method(graph.ptr(),"scalar_input_node_set_value",type,p_id,graph->scalar_input_node_get_value(type,p_id)); ur->add_undo_method(graph.ptr(),"scalar_input_node_set_value",type,p_id,graph->scalar_input_node_get_value(type,p_id));
ur->add_do_method(this,"_update_graph"); ur->add_do_method(this,"_update_graph");
@ -825,7 +825,7 @@ void ShaderGraphView::_vec_input_changed(double p_value, int p_id,Array p_arr){
} }
UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change Vec Uniform"),true); ur->create_action(TTR("Change Vec Uniform"),UndoRedo::MERGE_ENDS);
ur->add_do_method(graph.ptr(),"vec_input_node_set_value",type,p_id,val); ur->add_do_method(graph.ptr(),"vec_input_node_set_value",type,p_id,val);
ur->add_undo_method(graph.ptr(),"vec_input_node_set_value",type,p_id,graph->vec_input_node_get_value(type,p_id)); ur->add_undo_method(graph.ptr(),"vec_input_node_set_value",type,p_id,graph->vec_input_node_get_value(type,p_id));
ur->add_do_method(this,"_update_graph"); ur->add_do_method(this,"_update_graph");
@ -863,7 +863,7 @@ void ShaderGraphView::_rgb_input_changed(const Color& p_color, int p_id){
UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change RGB Uniform"),true); ur->create_action(TTR("Change RGB Uniform"),UndoRedo::MERGE_ENDS);
ur->add_do_method(graph.ptr(),"rgb_input_node_set_value",type,p_id,p_color); ur->add_do_method(graph.ptr(),"rgb_input_node_set_value",type,p_id,p_color);
ur->add_undo_method(graph.ptr(),"rgb_input_node_set_value",type,p_id,graph->rgb_input_node_get_value(type,p_id)); ur->add_undo_method(graph.ptr(),"rgb_input_node_set_value",type,p_id,graph->rgb_input_node_get_value(type,p_id));
ur->add_do_method(this,"_update_graph"); ur->add_do_method(this,"_update_graph");
@ -963,7 +963,7 @@ void ShaderGraphView::_comment_edited(int p_id,Node* p_button) {
UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
TextEdit *te=p_button->cast_to<TextEdit>(); TextEdit *te=p_button->cast_to<TextEdit>();
ur->create_action(TTR("Change Comment"),true); ur->create_action(TTR("Change Comment"),UndoRedo::MERGE_ENDS);
ur->add_do_method(graph.ptr(),"comment_node_set_text",type,p_id,te->get_text()); ur->add_do_method(graph.ptr(),"comment_node_set_text",type,p_id,te->get_text());
ur->add_undo_method(graph.ptr(),"comment_node_set_text",type,p_id,graph->comment_node_get_text(type,p_id)); ur->add_undo_method(graph.ptr(),"comment_node_set_text",type,p_id,graph->comment_node_get_text(type,p_id));
ur->add_do_method(this,"_update_graph"); ur->add_do_method(this,"_update_graph");
@ -1005,7 +1005,7 @@ void ShaderGraphView::_color_ramp_changed(int p_id,Node* p_ramp) {
if (old_offsets.size()!=new_offsets.size()) if (old_offsets.size()!=new_offsets.size())
ur->create_action(TTR("Add/Remove to Color Ramp")); ur->create_action(TTR("Add/Remove to Color Ramp"));
else else
ur->create_action(TTR("Modify Color Ramp"),true); ur->create_action(TTR("Modify Color Ramp"),UndoRedo::MERGE_ENDS);
ur->add_do_method(graph.ptr(),"color_ramp_node_set_ramp",type,p_id,new_colors,new_offsets); ur->add_do_method(graph.ptr(),"color_ramp_node_set_ramp",type,p_id,new_colors,new_offsets);
ur->add_undo_method(graph.ptr(),"color_ramp_node_set_ramp",type,p_id,old_colors,old_offsets); ur->add_undo_method(graph.ptr(),"color_ramp_node_set_ramp",type,p_id,old_colors,old_offsets);
@ -1041,7 +1041,7 @@ void ShaderGraphView::_curve_changed(int p_id,Node* p_curve) {
if (old_points.size()!=new_points.size()) if (old_points.size()!=new_points.size())
ur->create_action(TTR("Add/Remove to Curve Map")); ur->create_action(TTR("Add/Remove to Curve Map"));
else else
ur->create_action(TTR("Modify Curve Map"),true); ur->create_action(TTR("Modify Curve Map"),UndoRedo::MERGE_ENDS);
ur->add_do_method(graph.ptr(),"curve_map_node_set_points",type,p_id,new_points); ur->add_do_method(graph.ptr(),"curve_map_node_set_points",type,p_id,new_points);
ur->add_undo_method(graph.ptr(),"curve_map_node_set_points",type,p_id,old_points); ur->add_undo_method(graph.ptr(),"curve_map_node_set_points",type,p_id,old_points);

View file

@ -524,7 +524,7 @@ void SpriteFramesEditor::_animation_fps_changed(double p_value) {
if (updating) if (updating)
return; return;
undo_redo->create_action(TTR("Change Animation FPS"),true); undo_redo->create_action(TTR("Change Animation FPS"),UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(frames,"set_animation_speed",edited_anim,p_value); undo_redo->add_do_method(frames,"set_animation_speed",edited_anim,p_value);
undo_redo->add_undo_method(frames,"set_animation_speed",edited_anim,frames->get_animation_speed(edited_anim)); undo_redo->add_undo_method(frames,"set_animation_speed",edited_anim,frames->get_animation_speed(edited_anim));
undo_redo->add_do_method(this,"_update_library",true); undo_redo->add_do_method(this,"_update_library",true);

View file

@ -3738,7 +3738,7 @@ void PropertyEditor::_edit_set(const String& p_name, const Variant& p_value) {
} else { } else {
undo_redo->create_action(TTR("Set")+" "+p_name,true); undo_redo->create_action(TTR("Set")+" "+p_name,UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(obj,p_name,p_value); undo_redo->add_do_property(obj,p_name,p_value);
undo_redo->add_undo_property(obj,p_name,obj->get(p_name)); undo_redo->add_undo_property(obj,p_name,obj->get(p_name));
undo_redo->add_do_method(this,"_changed_callback",obj,p_name); undo_redo->add_do_method(this,"_changed_callback",obj,p_name);