Browse Source

Change UndoRedo to use Callables

kobewi 2 years ago
parent
commit
b3997191d8
4 changed files with 61 additions and 151 deletions
  1. 48 112
      core/object/undo_redo.cpp
  2. 5 29
      core/object/undo_redo.h
  3. 6 8
      doc/classes/UndoRedo.xml
  4. 2 2
      editor/editor_undo_redo_manager.cpp

+ 48 - 112
core/object/undo_redo.cpp

@@ -126,27 +126,28 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
 	force_keep_in_merge_ends = false;
 }
 
-void UndoRedo::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
-	ERR_FAIL_COND(p_object == nullptr);
+void UndoRedo::add_do_method(const Callable &p_callable) {
+	ERR_FAIL_COND(p_callable.is_null());
 	ERR_FAIL_COND(action_level <= 0);
 	ERR_FAIL_COND((current_action + 1) >= actions.size());
+
+	Object *object = p_callable.get_object();
+	ERR_FAIL_NULL(object);
+
 	Operation do_op;
-	do_op.object = p_object->get_instance_id();
-	if (Object::cast_to<RefCounted>(p_object)) {
-		do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
+	do_op.callable = p_callable;
+	do_op.object = p_callable.get_object_id();
+	if (Object::cast_to<RefCounted>(object)) {
+		do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(object));
 	}
-
 	do_op.type = Operation::TYPE_METHOD;
-	do_op.name = p_method;
+	do_op.name = p_callable.get_method();
 
-	for (int i = 0; i < p_argcount; i++) {
-		do_op.args.push_back(*p_args[i]);
-	}
 	actions.write[current_action + 1].do_ops.push_back(do_op);
 }
 
-void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
-	ERR_FAIL_COND(p_object == nullptr);
+void UndoRedo::add_undo_method(const Callable &p_callable) {
+	ERR_FAIL_COND(p_callable.is_null());
 	ERR_FAIL_COND(action_level <= 0);
 	ERR_FAIL_COND((current_action + 1) >= actions.size());
 
@@ -155,19 +156,19 @@ void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, co
 		return;
 	}
 
+	Object *object = p_callable.get_object();
+	ERR_FAIL_NULL(object);
+
 	Operation undo_op;
-	undo_op.object = p_object->get_instance_id();
-	if (Object::cast_to<RefCounted>(p_object)) {
-		undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
+	undo_op.callable = p_callable;
+	undo_op.object = p_callable.get_object_id();
+	if (Object::cast_to<RefCounted>(object)) {
+		undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(object));
 	}
-
 	undo_op.type = Operation::TYPE_METHOD;
 	undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
-	undo_op.name = p_method;
+	undo_op.name = p_callable.get_method();
 
-	for (int i = 0; i < p_argcount; i++) {
-		undo_op.args.push_back(*p_args[i]);
-	}
 	actions.write[current_action + 1].undo_ops.push_back(undo_op);
 }
 
@@ -183,7 +184,7 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c
 
 	do_op.type = Operation::TYPE_PROPERTY;
 	do_op.name = p_property;
-	do_op.args.push_back(p_value);
+	do_op.value = p_value;
 	actions.write[current_action + 1].do_ops.push_back(do_op);
 }
 
@@ -206,7 +207,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.push_back(p_value);
+	undo_op.value = p_value;
 	actions.write[current_action + 1].undo_ops.push_back(undo_op);
 }
 
@@ -312,33 +313,42 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
 
 		switch (op.type) {
 			case Operation::TYPE_METHOD: {
-				int argc = op.args.size();
-				Vector<const Variant *> argptrs;
-				argptrs.resize(argc);
-
-				for (int i = 0; i < argc; i++) {
-					argptrs.write[i] = &op.args[i];
-				}
-
 				Callable::CallError ce;
-				obj->callp(op.name, (const Variant **)argptrs.ptr(), argc, ce);
+				Variant ret;
+				op.callable.callp(nullptr, 0, ret, ce);
 				if (ce.error != Callable::CallError::CALL_OK) {
-					ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce));
+					ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, nullptr, 0, ce));
 				}
 #ifdef TOOLS_ENABLED
 				Resource *res = Object::cast_to<Resource>(obj);
 				if (res) {
 					res->set_edited(true);
 				}
-
 #endif
 
 				if (method_callback) {
-					method_callback(method_callback_ud, obj, op.name, (const Variant **)argptrs.ptr(), argc);
+					Vector<Variant> binds;
+					if (op.callable.is_custom()) {
+						CallableCustomBind *ccb = dynamic_cast<CallableCustomBind *>(op.callable.get_custom());
+						if (ccb) {
+							binds = ccb->get_binds();
+						}
+					}
+
+					if (binds.is_empty()) {
+						method_callback(method_callback_ud, obj, op.name, nullptr, 0);
+					} else {
+						const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * binds.size());
+						for (int i = 0; i < binds.size(); i++) {
+							args[i] = (const Variant *)&binds[i];
+						}
+
+						method_callback(method_callback_ud, obj, op.name, args, binds.size());
+					}
 				}
 			} break;
 			case Operation::TYPE_PROPERTY: {
-				obj->set(op.name, op.args[0]);
+				obj->set(op.name, op.value);
 #ifdef TOOLS_ENABLED
 				Resource *res = Object::cast_to<Resource>(obj);
 				if (res) {
@@ -346,7 +356,7 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
 				}
 #endif
 				if (property_callback) {
-					property_callback(prop_callback_ud, obj, op.name, op.args[0]);
+					property_callback(prop_callback_ud, obj, op.name, op.value);
 				}
 			} break;
 			case Operation::TYPE_REFERENCE: {
@@ -444,87 +454,13 @@ UndoRedo::~UndoRedo() {
 	clear_history();
 }
 
-void UndoRedo::_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 UndoRedo::_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 UndoRedo::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE));
 	ClassDB::bind_method(D_METHOD("commit_action", "execute"), &UndoRedo::commit_action, DEFVAL(true));
 	ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::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", &UndoRedo::_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", &UndoRedo::_add_undo_method, mi, varray(), false);
-	}
-
+	ClassDB::bind_method(D_METHOD("add_do_method", "callable"), &UndoRedo::add_do_method);
+	ClassDB::bind_method(D_METHOD("add_undo_method", "callable"), &UndoRedo::add_undo_method);
 	ClassDB::bind_method(D_METHOD("add_do_property", "object", "property", "value"), &UndoRedo::add_do_property);
 	ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &UndoRedo::add_undo_property);
 	ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &UndoRedo::add_do_reference);

+ 5 - 29
core/object/undo_redo.h

@@ -46,8 +46,6 @@ public:
 	};
 
 	typedef void (*CommitNotifyCallback)(void *p_ud, const String &p_name);
-	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);
 
 	typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount);
 	typedef void (*PropertyNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value);
@@ -58,14 +56,14 @@ private:
 			TYPE_METHOD,
 			TYPE_PROPERTY,
 			TYPE_REFERENCE
-		};
+		} type;
 
-		Type type;
 		bool force_keep_in_merge_ends;
 		Ref<RefCounted> ref;
 		ObjectID object;
 		StringName name;
-		Vector<Variant> args;
+		Callable callable;
+		Variant value;
 
 		void delete_reference();
 	};
@@ -106,30 +104,8 @@ protected:
 public:
 	void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE);
 
-	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 Callable &p_callable);
+	void add_undo_method(const Callable &p_callable);
 	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);

+ 6 - 8
doc/classes/UndoRedo.xml

@@ -62,12 +62,11 @@
 	<tutorials>
 	</tutorials>
 	<methods>
-		<method name="add_do_method" qualifiers="vararg">
+		<method name="add_do_method">
 			<return type="void" />
-			<param index="0" name="object" type="Object" />
-			<param index="1" name="method" type="StringName" />
+			<param index="0" name="callable" type="Callable" />
 			<description>
-				Register a [param method] that will be called when the action is committed.
+				Register a [Callable] that will be called when the action is committed.
 			</description>
 		</method>
 		<method name="add_do_property">
@@ -86,12 +85,11 @@
 				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">
+		<method name="add_undo_method">
 			<return type="void" />
-			<param index="0" name="object" type="Object" />
-			<param index="1" name="method" type="StringName" />
+			<param index="0" name="callable" type="Callable" />
 			<description>
-				Register a [param method] that will be called when the action is undone.
+				Register a [Callable] that will be called when the action is undone.
 			</description>
 		</method>
 		<method name="add_undo_property">

+ 2 - 2
editor/editor_undo_redo_manager.cpp

@@ -131,12 +131,12 @@ void EditorUndoRedoManager::create_action(const String &p_name, UndoRedo::MergeM
 
 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);
+	undo_redo->add_do_method(Callable(p_object, p_method).bindp(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);
+	undo_redo->add_undo_method(Callable(p_object, p_method).bindp(p_args, p_argcount));
 }
 
 void EditorUndoRedoManager::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {