| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*  undo_redo.cpp                                                        */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							|  |  |  | /*                    http://www.godotengine.org                         */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2016-01-01 11:50:53 -02:00
										 |  |  | /* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* 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 "undo_redo.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::_discard_redo() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (current_action==actions.size()-1) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(int i=current_action+1;i<actions.size();i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (List<Operation>::Element *E=actions[i].do_ops.front();E;E=E->next()) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (E->get().type==Operation::TYPE_REFERENCE) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				Object *obj = ObjectDB::get_instance(E->get().object); | 
					
						
							|  |  |  | 				if (obj) | 
					
						
							|  |  |  | 					memdelete(obj); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		//ERASE do data
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	actions.resize(current_action+1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::create_action(const String& p_name,bool p_mergeable) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (action_level==0) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_discard_redo(); | 
					
						
							|  |  |  | 		if (p_mergeable && actions.size() && actions[actions.size()-1].name==p_name) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			//old will replace new (it's mergeable after all)
 | 
					
						
							|  |  |  | 			// should check references though!
 | 
					
						
							|  |  |  | 			current_action=actions.size()-2; | 
					
						
							|  |  |  | 			actions[current_action+1].do_ops.clear(); | 
					
						
							|  |  |  | 			//actions[current_action+1].undo_ops.clear(); - no, this is kept
 | 
					
						
							|  |  |  | 			merging=true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			Action new_action; | 
					
						
							|  |  |  | 			new_action.name=p_name; | 
					
						
							|  |  |  | 			actions.push_back(new_action); | 
					
						
							|  |  |  | 			merging=false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	action_level++; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::add_do_method(Object *p_object,const String& p_method,VARIANT_ARG_DECLARE) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	VARIANT_ARGPTRS | 
					
						
							|  |  |  | 	ERR_FAIL_COND(action_level<=0); | 
					
						
							|  |  |  | 	ERR_FAIL_COND((current_action+1)>=actions.size()); | 
					
						
							|  |  |  | 	Operation do_op; | 
					
						
							|  |  |  | 	do_op.object=p_object->get_instance_ID(); | 
					
						
							|  |  |  | 	if (p_object->cast_to<Resource>()) | 
					
						
							|  |  |  | 		do_op.resref=Ref<Resource>(p_object->cast_to<Resource>()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do_op.type=Operation::TYPE_METHOD; | 
					
						
							|  |  |  | 	do_op.name=p_method; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(int i=0;i<VARIANT_ARG_MAX;i++) { | 
					
						
							|  |  |  | 		do_op.args[i]=*argptr[i]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	actions[current_action+1].do_ops.push_back(do_op); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::add_undo_method(Object *p_object,const String& p_method,VARIANT_ARG_DECLARE) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	VARIANT_ARGPTRS | 
					
						
							|  |  |  | 	ERR_FAIL_COND(action_level<=0); | 
					
						
							|  |  |  | 	ERR_FAIL_COND((current_action+1)>=actions.size()); | 
					
						
							|  |  |  | 	if (merging) | 
					
						
							|  |  |  | 		return; //- no undo if merging
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Operation undo_op; | 
					
						
							|  |  |  | 	undo_op.object=p_object->get_instance_ID(); | 
					
						
							|  |  |  | 	if (p_object->cast_to<Resource>()) | 
					
						
							|  |  |  | 		undo_op.resref=Ref<Resource>(p_object->cast_to<Resource>()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	undo_op.type=Operation::TYPE_METHOD; | 
					
						
							|  |  |  | 	undo_op.name=p_method; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(int i=0;i<VARIANT_ARG_MAX;i++) { | 
					
						
							|  |  |  | 		undo_op.args[i]=*argptr[i]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	actions[current_action+1].undo_ops.push_back(undo_op); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | void UndoRedo::add_do_property(Object *p_object,const String& p_property,const Variant& p_value) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND(action_level<=0); | 
					
						
							|  |  |  | 	ERR_FAIL_COND((current_action+1)>=actions.size()); | 
					
						
							|  |  |  | 	Operation do_op; | 
					
						
							|  |  |  | 	do_op.object=p_object->get_instance_ID(); | 
					
						
							|  |  |  | 	if (p_object->cast_to<Resource>()) | 
					
						
							|  |  |  | 		do_op.resref=Ref<Resource>(p_object->cast_to<Resource>()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do_op.type=Operation::TYPE_PROPERTY; | 
					
						
							|  |  |  | 	do_op.name=p_property; | 
					
						
							|  |  |  | 	do_op.args[0]=p_value; | 
					
						
							|  |  |  | 	actions[current_action+1].do_ops.push_back(do_op); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | void UndoRedo::add_undo_property(Object *p_object,const String& p_property,const Variant& p_value) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND(action_level<=0); | 
					
						
							|  |  |  | 	ERR_FAIL_COND((current_action+1)>=actions.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Operation undo_op; | 
					
						
							|  |  |  | 	undo_op.object=p_object->get_instance_ID(); | 
					
						
							|  |  |  | 	if (p_object->cast_to<Resource>()) | 
					
						
							|  |  |  | 		undo_op.resref=Ref<Resource>(p_object->cast_to<Resource>()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	undo_op.type=Operation::TYPE_PROPERTY; | 
					
						
							|  |  |  | 	undo_op.name=p_property; | 
					
						
							|  |  |  | 	undo_op.args[0]=p_value; | 
					
						
							|  |  |  | 	actions[current_action+1].undo_ops.push_back(undo_op); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | void UndoRedo::add_do_reference(Object *p_object) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND(action_level<=0); | 
					
						
							|  |  |  | 	ERR_FAIL_COND((current_action+1)>=actions.size()); | 
					
						
							|  |  |  | 	Operation do_op; | 
					
						
							|  |  |  | 	do_op.object=p_object->get_instance_ID(); | 
					
						
							|  |  |  | 	if (p_object->cast_to<Resource>()) | 
					
						
							|  |  |  | 		do_op.resref=Ref<Resource>(p_object->cast_to<Resource>()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do_op.type=Operation::TYPE_REFERENCE; | 
					
						
							|  |  |  | 	actions[current_action+1].do_ops.push_back(do_op); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | void UndoRedo::add_undo_reference(Object *p_object) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND(action_level<=0); | 
					
						
							|  |  |  | 	ERR_FAIL_COND((current_action+1)>=actions.size()); | 
					
						
							|  |  |  | 	Operation undo_op; | 
					
						
							|  |  |  | 	undo_op.object=p_object->get_instance_ID(); | 
					
						
							|  |  |  | 	if (p_object->cast_to<Resource>()) | 
					
						
							|  |  |  | 		undo_op.resref=Ref<Resource>(p_object->cast_to<Resource>()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	undo_op.type=Operation::TYPE_REFERENCE; | 
					
						
							|  |  |  | 	actions[current_action+1].undo_ops.push_back(undo_op); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::_pop_history_tail() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_discard_redo(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!actions.size()) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (List<Operation>::Element *E=actions[0].undo_ops.front();E;E=E->next()) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (E->get().type==Operation::TYPE_REFERENCE) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Object *obj = ObjectDB::get_instance(E->get().object); | 
					
						
							|  |  |  | 			if (obj) | 
					
						
							|  |  |  | 				memdelete(obj); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	actions.remove(0); | 
					
						
							|  |  |  | 	current_action--; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::commit_action() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND(action_level<=0); | 
					
						
							|  |  |  | 	action_level--; | 
					
						
							|  |  |  | 	if (action_level>0) | 
					
						
							|  |  |  | 		return; //still nested
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	redo(); // perform action
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (max_steps>0 && actions.size()>max_steps) { | 
					
						
							|  |  |  | 		//clear early steps
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		while(actions.size() > max_steps) | 
					
						
							|  |  |  | 			_pop_history_tail(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (callback && actions.size()>0) { | 
					
						
							|  |  |  | 		callback(callback_ud,actions[actions.size()-1].name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::_process_operation_list(List<Operation>::Element *E) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (;E;E=E->next()) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Operation &op=E->get(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Object *obj = ObjectDB::get_instance(op.object); | 
					
						
							|  |  |  | 		if (!obj) { | 
					
						
							|  |  |  | 			//corruption
 | 
					
						
							|  |  |  | 			clear_history(); | 
					
						
							|  |  |  | 			ERR_FAIL_COND(!obj); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-05-11 21:36:29 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		switch(op.type) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			case Operation::TYPE_METHOD: { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 				obj->call(op.name,VARIANT_ARGS_FROM_ARRAY(op.args)); | 
					
						
							| 
									
										
										
										
											2015-05-11 21:36:29 -03:00
										 |  |  | #ifdef TOOLS_ENABLED
 | 
					
						
							|  |  |  | 				Resource* res = obj->cast_to<Resource>(); | 
					
						
							|  |  |  | 				if (res) | 
					
						
							|  |  |  | 					res->set_edited(true); | 
					
						
							| 
									
										
										
										
											2015-08-02 12:29:37 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-11 21:36:29 -03:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2015-08-02 12:29:37 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if (method_callback) { | 
					
						
							|  |  |  | 					method_callback(method_callbck_ud,obj,op.name,VARIANT_ARGS_FROM_ARRAY(op.args)); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 			} break; | 
					
						
							|  |  |  | 			case Operation::TYPE_PROPERTY: { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				obj->set(op.name,op.args[0]); | 
					
						
							| 
									
										
										
										
											2014-11-02 11:31:01 -03:00
										 |  |  | #ifdef TOOLS_ENABLED
 | 
					
						
							|  |  |  | 				Resource* res = obj->cast_to<Resource>(); | 
					
						
							|  |  |  | 				if (res) | 
					
						
							|  |  |  | 					res->set_edited(true); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2015-08-02 12:29:37 -03:00
										 |  |  | 				if (property_callback) { | 
					
						
							|  |  |  | 					property_callback(prop_callback_ud,obj,op.name,op.args[0]); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 			} break; | 
					
						
							|  |  |  | 			case Operation::TYPE_REFERENCE: { | 
					
						
							|  |  |  | 				//do nothing
 | 
					
						
							|  |  |  | 			} break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::redo() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND(action_level>0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((current_action+1)>=actions.size()) | 
					
						
							|  |  |  | 		return; //nothing to redo
 | 
					
						
							|  |  |  | 	current_action++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_process_operation_list(actions[current_action].do_ops.front()); | 
					
						
							|  |  |  | 	version++; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::undo() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND(action_level>0); | 
					
						
							|  |  |  | 	if (current_action<0) | 
					
						
							|  |  |  | 		return; //nothing to redo
 | 
					
						
							|  |  |  | 	_process_operation_list(actions[current_action].undo_ops.front()); | 
					
						
							|  |  |  | 	current_action--; | 
					
						
							| 
									
										
										
										
											2015-06-22 00:03:19 -03:00
										 |  |  | 	version--; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::clear_history() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND(action_level>0); | 
					
						
							|  |  |  | 	_discard_redo(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while(actions.size()) | 
					
						
							|  |  |  | 		_pop_history_tail(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-22 00:03:19 -03:00
										 |  |  | 	//version++;
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String UndoRedo::get_current_action_name() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(action_level>0,""); | 
					
						
							|  |  |  | 	if (current_action<0) | 
					
						
							|  |  |  | 		return ""; //nothing to redo
 | 
					
						
							|  |  |  | 	return actions[current_action].name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::set_max_steps(int p_max_steps) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	max_steps=p_max_steps; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int UndoRedo::get_max_steps() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return max_steps; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint64_t UndoRedo::get_version() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return version; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::set_commit_notify_callback(CommitNotifyCallback p_callback,void* p_ud) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	callback=p_callback; | 
					
						
							|  |  |  | 	callback_ud=p_ud; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-02 12:29:37 -03:00
										 |  |  | void UndoRedo::set_method_notify_callback(MethodNotifyCallback p_method_callback,void* p_ud) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	method_callback=p_method_callback; | 
					
						
							|  |  |  | 	method_callbck_ud=p_ud; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_callback,void* p_ud){ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	property_callback=p_property_callback; | 
					
						
							|  |  |  | 	prop_callback_ud=p_ud; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | UndoRedo::UndoRedo() { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-22 00:03:19 -03:00
										 |  |  | 	version=1; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	action_level=0; | 
					
						
							|  |  |  | 	current_action=-1; | 
					
						
							|  |  |  | 	max_steps=-1; | 
					
						
							|  |  |  | 	merging=true; | 
					
						
							|  |  |  | 	callback=NULL; | 
					
						
							|  |  |  | 	callback_ud=NULL; | 
					
						
							| 
									
										
										
										
											2015-08-02 12:29:37 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	method_callbck_ud=NULL; | 
					
						
							|  |  |  | 	prop_callback_ud=NULL; | 
					
						
							|  |  |  | 	method_callback=NULL; | 
					
						
							|  |  |  | 	property_callback=NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | UndoRedo::~UndoRedo() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	clear_history(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-21 21:55:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Variant UndoRedo::_add_do_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-22 23:44:13 -03:00
										 |  |  | 	if (p_argcount<2) { | 
					
						
							| 
									
										
										
										
											2015-06-21 21:55:47 +02:00
										 |  |  | 		r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; | 
					
						
							|  |  |  | 		r_error.argument=0; | 
					
						
							|  |  |  | 		return Variant(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_args[0]->get_type()!=Variant::OBJECT) { | 
					
						
							|  |  |  | 		r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; | 
					
						
							|  |  |  | 		r_error.argument=0; | 
					
						
							|  |  |  | 		r_error.expected=Variant::OBJECT; | 
					
						
							|  |  |  | 		return Variant(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_args[1]->get_type()!=Variant::STRING) { | 
					
						
							|  |  |  | 		r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; | 
					
						
							|  |  |  | 		r_error.argument=1; | 
					
						
							|  |  |  | 		r_error.expected=Variant::STRING; | 
					
						
							|  |  |  | 		return Variant(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	r_error.error=Variant::CallError::CALL_OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Object* object = *p_args[0]; | 
					
						
							|  |  |  | 	String method = *p_args[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Variant v[VARIANT_ARG_MAX]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(int i=0;i<MIN(VARIANT_ARG_MAX,p_argcount-2);++i) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		v[i]=*p_args[i+2]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	add_do_method(object,method,v[0],v[1],v[2],v[3],v[4]); | 
					
						
							|  |  |  | 	return Variant(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Variant UndoRedo::_add_undo_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-22 23:44:13 -03:00
										 |  |  | 	if (p_argcount<2) { | 
					
						
							| 
									
										
										
										
											2015-06-21 21:55:47 +02:00
										 |  |  | 		r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; | 
					
						
							|  |  |  | 		r_error.argument=0; | 
					
						
							|  |  |  | 		return Variant(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_args[0]->get_type()!=Variant::OBJECT) { | 
					
						
							|  |  |  | 		r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; | 
					
						
							|  |  |  | 		r_error.argument=0; | 
					
						
							|  |  |  | 		r_error.expected=Variant::OBJECT; | 
					
						
							|  |  |  | 		return Variant(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_args[1]->get_type()!=Variant::STRING) { | 
					
						
							|  |  |  | 		r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; | 
					
						
							|  |  |  | 		r_error.argument=1; | 
					
						
							|  |  |  | 		r_error.expected=Variant::STRING; | 
					
						
							|  |  |  | 		return Variant(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	r_error.error=Variant::CallError::CALL_OK; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Object* object = *p_args[0]; | 
					
						
							|  |  |  | 	String method = *p_args[1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Variant v[VARIANT_ARG_MAX]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(int i=0;i<MIN(VARIANT_ARG_MAX,p_argcount-2);++i) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		v[i]=*p_args[i+2]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	add_undo_method(object,method,v[0],v[1],v[2],v[3],v[4]); | 
					
						
							|  |  |  | 	return Variant(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UndoRedo::_bind_methods() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ObjectTypeDB::bind_method(_MD("create_action","name","mergeable"),&UndoRedo::create_action, DEFVAL(false) ); | 
					
						
							|  |  |  | 	ObjectTypeDB::bind_method(_MD("commit_action"),&UndoRedo::commit_action); | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 21:55:47 +02:00
										 |  |  | 	//ObjectTypeDB::bind_method(_MD("add_do_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_do_method);
 | 
					
						
							|  |  |  | 	//ObjectTypeDB::bind_method(_MD("add_undo_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_undo_method);
 | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 21:55:47 +02:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		MethodInfo mi; | 
					
						
							|  |  |  | 		mi.name="add_do_method"; | 
					
						
							|  |  |  | 		mi.arguments.push_back( PropertyInfo( Variant::OBJECT, "object")); | 
					
						
							|  |  |  | 		mi.arguments.push_back( PropertyInfo( Variant::STRING, "method")); | 
					
						
							|  |  |  | 		Vector<Variant> defargs; | 
					
						
							|  |  |  | 		for(int i=0;i<VARIANT_ARG_MAX;++i) { | 
					
						
							|  |  |  | 			mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i))); | 
					
						
							|  |  |  | 			defargs.push_back(Variant()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"add_do_method",&UndoRedo::_add_do_method,mi,defargs); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		MethodInfo mi; | 
					
						
							|  |  |  | 		mi.name="add_undo_method"; | 
					
						
							|  |  |  | 		mi.arguments.push_back( PropertyInfo( Variant::OBJECT, "object")); | 
					
						
							|  |  |  | 		mi.arguments.push_back( PropertyInfo( Variant::STRING, "method")); | 
					
						
							|  |  |  | 		Vector<Variant> defargs; | 
					
						
							|  |  |  | 		for(int i=0;i<VARIANT_ARG_MAX;++i) { | 
					
						
							|  |  |  | 			mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i))); | 
					
						
							|  |  |  | 			defargs.push_back(Variant()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"add_undo_method",&UndoRedo::_add_undo_method,mi,defargs); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 08:28:01 -03:00
										 |  |  | 	ObjectTypeDB::bind_method(_MD("add_do_property","object", "property", "value:Variant"),&UndoRedo::add_do_property); | 
					
						
							|  |  |  | 	ObjectTypeDB::bind_method(_MD("add_undo_property","object", "property", "value:Variant"),&UndoRedo::add_undo_property); | 
					
						
							| 
									
										
										
										
											2015-06-21 21:55:47 +02:00
										 |  |  | 	ObjectTypeDB::bind_method(_MD("add_do_reference","object"),&UndoRedo::add_do_reference); | 
					
						
							|  |  |  | 	ObjectTypeDB::bind_method(_MD("add_undo_reference","object"),&UndoRedo::add_undo_reference); | 
					
						
							| 
									
										
										
										
											2015-06-22 14:42:52 +02:00
										 |  |  | 	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_version"),&UndoRedo::get_version); | 
					
						
							| 
									
										
										
										
											2015-06-22 23:44:13 -03:00
										 |  |  | } |