| 
									
										
										
										
											2023-01-05 13:25:55 +01:00
										 |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*  editor_undo_redo_manager.cpp                                          */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /*                         This file is part of:                          */ | 
					
						
							|  |  |  | /*                             GODOT ENGINE                               */ | 
					
						
							|  |  |  | /*                        https://godotengine.org                         */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							|  |  |  | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | 
					
						
							|  |  |  | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | 
					
						
							|  |  |  | /*                                                                        */ | 
					
						
							|  |  |  | /* 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.                 */ | 
					
						
							|  |  |  | /**************************************************************************/ | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "editor_undo_redo_manager.h"
 | 
					
						
							| 
									
										
										
										
											2025-05-06 13:59:56 +02:00
										 |  |  | #include "editor_undo_redo_manager.compat.inc"
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "core/io/resource.h"
 | 
					
						
							|  |  |  | #include "core/os/os.h"
 | 
					
						
							| 
									
										
										
										
											2022-12-07 18:15:09 +01:00
										 |  |  | #include "editor/debugger/editor_debugger_inspector.h"
 | 
					
						
							| 
									
										
										
										
											2022-11-11 20:12:48 +01:00
										 |  |  | #include "editor/debugger/editor_debugger_node.h"
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | #include "editor/editor_log.h"
 | 
					
						
							|  |  |  | #include "editor/editor_node.h"
 | 
					
						
							|  |  |  | #include "scene/main/node.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-23 23:53:16 +01:00
										 |  |  | EditorUndoRedoManager *EditorUndoRedoManager::singleton = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | EditorUndoRedoManager::History &EditorUndoRedoManager::get_or_create_history(int p_idx) { | 
					
						
							|  |  |  | 	if (!history_map.has(p_idx)) { | 
					
						
							|  |  |  | 		History history; | 
					
						
							|  |  |  | 		history.undo_redo = memnew(UndoRedo); | 
					
						
							|  |  |  | 		history.id = p_idx; | 
					
						
							|  |  |  | 		history_map[p_idx] = history; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		EditorNode::get_singleton()->get_log()->register_undo_redo(history.undo_redo); | 
					
						
							|  |  |  | 		EditorDebuggerNode::get_singleton()->register_undo_redo(history.undo_redo); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return history_map[p_idx]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | UndoRedo *EditorUndoRedoManager::get_history_undo_redo(int p_idx) const { | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(!history_map.has(p_idx), nullptr); | 
					
						
							|  |  |  | 	return history_map[p_idx].undo_redo; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EditorUndoRedoManager::get_history_id_for_object(Object *p_object) const { | 
					
						
							|  |  |  | 	int history_id = INVALID_HISTORY; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-18 15:44:38 -03:00
										 |  |  | 	if (Object::cast_to<EditorDebuggerRemoteObjects>(p_object)) { | 
					
						
							| 
									
										
										
										
											2022-12-07 18:15:09 +01:00
										 |  |  | 		return REMOTE_HISTORY; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	if (Node *node = Object::cast_to<Node>(p_object)) { | 
					
						
							|  |  |  | 		Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (edited_scene && (node == edited_scene || edited_scene->is_ancestor_of(node))) { | 
					
						
							| 
									
										
										
										
											2023-08-11 15:55:47 +02:00
										 |  |  | 			int idx = EditorNode::get_editor_data().get_current_edited_scene_history_id(); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 			if (idx > 0) { | 
					
						
							|  |  |  | 				history_id = idx; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (Resource *res = Object::cast_to<Resource>(p_object)) { | 
					
						
							|  |  |  | 		if (res->is_built_in()) { | 
					
						
							|  |  |  | 			if (res->get_path().is_empty()) { | 
					
						
							| 
									
										
										
										
											2023-08-11 15:55:47 +02:00
										 |  |  | 				int idx = EditorNode::get_editor_data().get_current_edited_scene_history_id(); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 				if (idx > 0) { | 
					
						
							|  |  |  | 					history_id = idx; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2023-08-11 15:55:47 +02:00
										 |  |  | 				int idx = EditorNode::get_editor_data().get_scene_history_id_from_path(res->get_path().get_slice("::", 0)); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 				if (idx > 0) { | 
					
						
							|  |  |  | 					history_id = idx; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (history_id == INVALID_HISTORY) { | 
					
						
							|  |  |  | 		if (pending_action.history_id != INVALID_HISTORY) { | 
					
						
							|  |  |  | 			history_id = pending_action.history_id; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			history_id = GLOBAL_HISTORY; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return history_id; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EditorUndoRedoManager::History &EditorUndoRedoManager::get_history_for_object(Object *p_object) { | 
					
						
							| 
									
										
										
										
											2023-07-22 20:16:54 +02:00
										 |  |  | 	int history_id; | 
					
						
							|  |  |  | 	if (!forced_history) { | 
					
						
							|  |  |  | 		history_id = get_history_id_for_object(p_object); | 
					
						
							|  |  |  | 		ERR_FAIL_COND_V_MSG(pending_action.history_id != INVALID_HISTORY && history_id != pending_action.history_id, get_or_create_history(pending_action.history_id), vformat("UndoRedo history mismatch: expected %d, got %d.", pending_action.history_id, history_id)); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		history_id = pending_action.history_id; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	History &history = get_or_create_history(history_id); | 
					
						
							|  |  |  | 	if (pending_action.history_id == INVALID_HISTORY) { | 
					
						
							|  |  |  | 		pending_action.history_id = history_id; | 
					
						
							| 
									
										
										
										
											2023-06-02 23:03:39 +02:00
										 |  |  | 		history.undo_redo->create_action(pending_action.action_name, pending_action.merge_mode, pending_action.backward_undo_ops); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return history; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-22 20:16:54 +02:00
										 |  |  | void EditorUndoRedoManager::force_fixed_history() { | 
					
						
							|  |  |  | 	ERR_FAIL_COND_MSG(pending_action.history_id == INVALID_HISTORY, "The current action has no valid history assigned."); | 
					
						
							|  |  |  | 	forced_history = true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-06 13:59:56 +02:00
										 |  |  | void EditorUndoRedoManager::create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode, bool p_backward_undo_ops, bool p_mark_unsaved) { | 
					
						
							| 
									
										
										
										
											2022-10-28 02:54:55 +02:00
										 |  |  | 	if (pending_action.history_id != INVALID_HISTORY) { | 
					
						
							|  |  |  | 		// Nested action.
 | 
					
						
							|  |  |  | 		p_history_id = pending_action.history_id; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		pending_action.action_name = p_name; | 
					
						
							|  |  |  | 		pending_action.timestamp = OS::get_singleton()->get_unix_time(); | 
					
						
							|  |  |  | 		pending_action.merge_mode = p_mode; | 
					
						
							| 
									
										
										
										
											2023-06-02 23:03:39 +02:00
										 |  |  | 		pending_action.backward_undo_ops = p_backward_undo_ops; | 
					
						
							| 
									
										
										
										
											2025-05-06 13:59:56 +02:00
										 |  |  | 		pending_action.mark_unsaved = p_mark_unsaved; | 
					
						
							| 
									
										
										
										
											2022-10-28 02:54:55 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (p_history_id != INVALID_HISTORY) { | 
					
						
							|  |  |  | 		pending_action.history_id = p_history_id; | 
					
						
							|  |  |  | 		History &history = get_or_create_history(p_history_id); | 
					
						
							| 
									
										
										
										
											2023-06-02 23:03:39 +02:00
										 |  |  | 		history.undo_redo->create_action(pending_action.action_name, pending_action.merge_mode, pending_action.backward_undo_ops); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-06 13:59:56 +02:00
										 |  |  | void EditorUndoRedoManager::create_action(const String &p_name, UndoRedo::MergeMode p_mode, Object *p_custom_context, bool p_backward_undo_ops, bool p_mark_unsaved) { | 
					
						
							|  |  |  | 	create_action_for_history(p_name, INVALID_HISTORY, p_mode, p_backward_undo_ops, p_mark_unsaved); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (p_custom_context) { | 
					
						
							| 
									
										
										
										
											2022-09-13 19:35:25 +02:00
										 |  |  | 		// This assigns history to pending action.
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 		get_history_for_object(p_custom_context); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							| 
									
										
										
										
											2022-09-18 23:27:00 +02:00
										 |  |  | 	undo_redo->add_do_method(Callable(p_object, p_method).bindp(p_args, p_argcount)); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							| 
									
										
										
										
											2022-09-18 23:27:00 +02:00
										 |  |  | 	undo_redo->add_undo_method(Callable(p_object, p_method).bindp(p_args, p_argcount)); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditorUndoRedoManager::_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; | 
					
						
							| 
									
										
										
										
											2023-09-29 19:19:46 +03:00
										 |  |  | 		r_error.expected = 2; | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 		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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-28 14:44:23 -08:00
										 |  |  | 	if (!p_args[1]->is_string()) { | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 		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 EditorUndoRedoManager::_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; | 
					
						
							| 
									
										
										
										
											2023-09-29 19:19:46 +03:00
										 |  |  | 		r_error.expected = 2; | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 		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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-28 14:44:23 -08:00
										 |  |  | 	if (!p_args[1]->is_string()) { | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 		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 EditorUndoRedoManager::add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value) { | 
					
						
							|  |  |  | 	UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; | 
					
						
							|  |  |  | 	undo_redo->add_do_property(p_object, p_property, p_value); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditorUndoRedoManager::add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value) { | 
					
						
							|  |  |  | 	UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; | 
					
						
							|  |  |  | 	undo_redo->add_undo_property(p_object, p_property, p_value); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditorUndoRedoManager::add_do_reference(Object *p_object) { | 
					
						
							|  |  |  | 	UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; | 
					
						
							|  |  |  | 	undo_redo->add_do_reference(p_object); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditorUndoRedoManager::add_undo_reference(Object *p_object) { | 
					
						
							|  |  |  | 	UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo; | 
					
						
							|  |  |  | 	undo_redo->add_undo_reference(p_object); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditorUndoRedoManager::commit_action(bool p_execute) { | 
					
						
							| 
									
										
										
										
											2022-09-13 19:35:25 +02:00
										 |  |  | 	if (pending_action.history_id == INVALID_HISTORY) { | 
					
						
							|  |  |  | 		return; // Empty action, do nothing.
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-22 20:16:54 +02:00
										 |  |  | 	forced_history = false; | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	is_committing = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	History &history = get_or_create_history(pending_action.history_id); | 
					
						
							| 
									
										
										
										
											2023-11-06 23:55:14 +00:00
										 |  |  | 	bool merging = history.undo_redo->is_merging(); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	history.undo_redo->commit_action(p_execute); | 
					
						
							|  |  |  | 	history.redo_stack.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-28 02:54:55 +02:00
										 |  |  | 	if (history.undo_redo->get_action_level() > 0) { | 
					
						
							|  |  |  | 		// Nested action.
 | 
					
						
							|  |  |  | 		is_committing = false; | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-06 23:55:14 +00:00
										 |  |  | 	if (!merging) { | 
					
						
							|  |  |  | 		history.undo_stack.push_back(pending_action); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-24 15:47:55 +02:00
										 |  |  | 	if (history.id != GLOBAL_HISTORY) { | 
					
						
							|  |  |  | 		// Clear global redo, to avoid unexpected actions when redoing.
 | 
					
						
							|  |  |  | 		History &global = get_or_create_history(GLOBAL_HISTORY); | 
					
						
							|  |  |  | 		global.redo_stack.clear(); | 
					
						
							|  |  |  | 		global.undo_redo->discard_redo(); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// On global actions, clear redo of all scenes instead.
 | 
					
						
							|  |  |  | 		for (KeyValue<int, History> &E : history_map) { | 
					
						
							|  |  |  | 			if (E.key == GLOBAL_HISTORY) { | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			E.value.redo_stack.clear(); | 
					
						
							|  |  |  | 			E.value.undo_redo->discard_redo(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	pending_action = Action(); | 
					
						
							|  |  |  | 	is_committing = false; | 
					
						
							| 
									
										
										
										
											2022-08-27 13:52:06 +02:00
										 |  |  | 	emit_signal(SNAME("history_changed")); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool EditorUndoRedoManager::is_committing_action() const { | 
					
						
							|  |  |  | 	return is_committing; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool EditorUndoRedoManager::undo() { | 
					
						
							|  |  |  | 	if (!has_undo()) { | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 14:04:48 +01:00
										 |  |  | 	History *selected_history = _get_newest_undo(); | 
					
						
							|  |  |  | 	if (selected_history) { | 
					
						
							|  |  |  | 		return undo_history(selected_history->id); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-27 13:52:06 +02:00
										 |  |  | bool EditorUndoRedoManager::undo_history(int p_id) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(p_id == INVALID_HISTORY, false); | 
					
						
							|  |  |  | 	History &history = get_or_create_history(p_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Action action = history.undo_stack.back()->get(); | 
					
						
							|  |  |  | 	history.undo_stack.pop_back(); | 
					
						
							|  |  |  | 	history.redo_stack.push_back(action); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool success = history.undo_redo->undo(); | 
					
						
							|  |  |  | 	if (success) { | 
					
						
							|  |  |  | 		emit_signal(SNAME("version_changed")); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return success; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | bool EditorUndoRedoManager::redo() { | 
					
						
							|  |  |  | 	if (!has_redo()) { | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-27 13:52:06 +02:00
										 |  |  | 	int selected_history = INVALID_HISTORY; | 
					
						
							| 
									
										
										
										
											2025-04-10 11:21:05 -05:00
										 |  |  | 	double global_timestamp = Math::INF; | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Pick the history with lowest last action timestamp (either global or current scene).
 | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		History &history = get_or_create_history(GLOBAL_HISTORY); | 
					
						
							|  |  |  | 		if (!history.redo_stack.is_empty()) { | 
					
						
							| 
									
										
										
										
											2022-08-27 13:52:06 +02:00
										 |  |  | 			selected_history = history.id; | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 			global_timestamp = history.redo_stack.back()->get().timestamp; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-07 18:15:09 +01:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		History &history = get_or_create_history(REMOTE_HISTORY); | 
					
						
							|  |  |  | 		if (!history.redo_stack.is_empty() && history.redo_stack.back()->get().timestamp < global_timestamp) { | 
					
						
							|  |  |  | 			selected_history = history.id; | 
					
						
							|  |  |  | 			global_timestamp = history.redo_stack.back()->get().timestamp; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id()); | 
					
						
							|  |  |  | 		if (!history.redo_stack.is_empty() && history.redo_stack.back()->get().timestamp < global_timestamp) { | 
					
						
							| 
									
										
										
										
											2022-08-27 13:52:06 +02:00
										 |  |  | 			selected_history = history.id; | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-27 13:52:06 +02:00
										 |  |  | 	if (selected_history != INVALID_HISTORY) { | 
					
						
							|  |  |  | 		return redo_history(selected_history); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-27 13:52:06 +02:00
										 |  |  | bool EditorUndoRedoManager::redo_history(int p_id) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(p_id == INVALID_HISTORY, false); | 
					
						
							|  |  |  | 	History &history = get_or_create_history(p_id); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Action action = history.redo_stack.back()->get(); | 
					
						
							|  |  |  | 	history.redo_stack.pop_back(); | 
					
						
							|  |  |  | 	history.undo_stack.push_back(action); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool success = history.undo_redo->redo(); | 
					
						
							|  |  |  | 	if (success) { | 
					
						
							|  |  |  | 		emit_signal(SNAME("version_changed")); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return success; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | void EditorUndoRedoManager::set_history_as_saved(int p_id) { | 
					
						
							|  |  |  | 	History &history = get_or_create_history(p_id); | 
					
						
							|  |  |  | 	history.saved_version = history.undo_redo->get_version(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EditorUndoRedoManager::set_history_as_unsaved(int p_id) { | 
					
						
							|  |  |  | 	History &history = get_or_create_history(p_id); | 
					
						
							| 
									
										
										
										
											2025-05-15 18:03:05 +02:00
										 |  |  | 	history.saved_version = 0; | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool EditorUndoRedoManager::is_history_unsaved(int p_id) { | 
					
						
							|  |  |  | 	History &history = get_or_create_history(p_id); | 
					
						
							| 
									
										
										
										
											2025-05-15 18:03:05 +02:00
										 |  |  | 	if (history.saved_version == 0) { | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-05-06 13:59:56 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int version_difference = history.undo_redo->get_version() - history.saved_version; | 
					
						
							|  |  |  | 	if (version_difference > 0) { | 
					
						
							|  |  |  | 		List<Action>::Element *E = history.undo_stack.back(); | 
					
						
							|  |  |  | 		for (int i = 0; i < version_difference; i++) { | 
					
						
							| 
									
										
										
										
											2025-05-15 18:03:05 +02:00
										 |  |  | 			ERR_FAIL_NULL_V_MSG(E, false, "Inconsistent undo history."); | 
					
						
							| 
									
										
										
										
											2025-05-06 13:59:56 +02:00
										 |  |  | 			if (E->get().mark_unsaved) { | 
					
						
							|  |  |  | 				return true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			E = E->prev(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if (version_difference < 0) { | 
					
						
							|  |  |  | 		List<Action>::Element *E = history.redo_stack.back(); | 
					
						
							|  |  |  | 		for (int i = 0; i > version_difference; i--) { | 
					
						
							| 
									
										
										
										
											2025-05-15 18:03:05 +02:00
										 |  |  | 			ERR_FAIL_NULL_V_MSG(E, false, "Inconsistent redo history."); | 
					
						
							| 
									
										
										
										
											2025-05-06 13:59:56 +02:00
										 |  |  | 			if (E->get().mark_unsaved) { | 
					
						
							|  |  |  | 				return true; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			E = E->prev(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false; | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool EditorUndoRedoManager::has_undo() { | 
					
						
							|  |  |  | 	for (const KeyValue<int, History> &E : history_map) { | 
					
						
							| 
									
										
										
										
											2022-12-07 18:15:09 +01:00
										 |  |  | 		if ((E.key == GLOBAL_HISTORY || E.key == REMOTE_HISTORY || E.key == EditorNode::get_editor_data().get_current_edited_scene_history_id()) && !E.value.undo_stack.is_empty()) { | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool EditorUndoRedoManager::has_redo() { | 
					
						
							|  |  |  | 	for (const KeyValue<int, History> &E : history_map) { | 
					
						
							| 
									
										
										
										
											2022-12-07 18:15:09 +01:00
										 |  |  | 		if ((E.key == GLOBAL_HISTORY || E.key == REMOTE_HISTORY || E.key == EditorNode::get_editor_data().get_current_edited_scene_history_id()) && !E.value.redo_stack.is_empty()) { | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-05 17:42:37 +01:00
										 |  |  | bool EditorUndoRedoManager::has_history(int p_idx) const { | 
					
						
							|  |  |  | 	return history_map.has(p_idx); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 13:33:12 +02:00
										 |  |  | void EditorUndoRedoManager::clear_history(int p_idx, bool p_increase_version) { | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	if (p_idx != INVALID_HISTORY) { | 
					
						
							| 
									
										
										
										
											2022-12-07 18:15:09 +01:00
										 |  |  | 		History &history = get_or_create_history(p_idx); | 
					
						
							|  |  |  | 		history.undo_redo->clear_history(p_increase_version); | 
					
						
							|  |  |  | 		history.undo_stack.clear(); | 
					
						
							|  |  |  | 		history.redo_stack.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 		if (!p_increase_version) { | 
					
						
							|  |  |  | 			set_history_as_saved(p_idx); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-27 13:52:06 +02:00
										 |  |  | 		emit_signal(SNAME("history_changed")); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (const KeyValue<int, History> &E : history_map) { | 
					
						
							|  |  |  | 		E.value.undo_redo->clear_history(p_increase_version); | 
					
						
							|  |  |  | 		set_history_as_saved(E.key); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-27 13:52:06 +02:00
										 |  |  | 	emit_signal(SNAME("history_changed")); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String EditorUndoRedoManager::get_current_action_name() { | 
					
						
							|  |  |  | 	if (has_undo()) { | 
					
						
							| 
									
										
										
										
											2022-12-08 14:04:48 +01:00
										 |  |  | 		History *selected_history = _get_newest_undo(); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 		if (selected_history) { | 
					
						
							|  |  |  | 			return selected_history->undo_redo->get_current_action_name(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ""; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 14:04:48 +01:00
										 |  |  | int EditorUndoRedoManager::get_current_action_history_id() { | 
					
						
							|  |  |  | 	if (has_undo()) { | 
					
						
							|  |  |  | 		History *selected_history = _get_newest_undo(); | 
					
						
							|  |  |  | 		if (selected_history) { | 
					
						
							|  |  |  | 			return selected_history->id; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return INVALID_HISTORY; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | void EditorUndoRedoManager::discard_history(int p_idx, bool p_erase_from_map) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(!history_map.has(p_idx)); | 
					
						
							|  |  |  | 	History &history = history_map[p_idx]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (history.undo_redo) { | 
					
						
							|  |  |  | 		memdelete(history.undo_redo); | 
					
						
							|  |  |  | 		history.undo_redo = nullptr; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_erase_from_map) { | 
					
						
							|  |  |  | 		history_map.erase(p_idx); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 14:04:48 +01:00
										 |  |  | EditorUndoRedoManager::History *EditorUndoRedoManager::_get_newest_undo() { | 
					
						
							|  |  |  | 	History *selected_history = nullptr; | 
					
						
							|  |  |  | 	double global_timestamp = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Pick the history with greatest last action timestamp (either global or current scene).
 | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		History &history = get_or_create_history(GLOBAL_HISTORY); | 
					
						
							|  |  |  | 		if (!history.undo_stack.is_empty()) { | 
					
						
							|  |  |  | 			selected_history = &history; | 
					
						
							|  |  |  | 			global_timestamp = history.undo_stack.back()->get().timestamp; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		History &history = get_or_create_history(REMOTE_HISTORY); | 
					
						
							|  |  |  | 		if (!history.undo_stack.is_empty() && history.undo_stack.back()->get().timestamp > global_timestamp) { | 
					
						
							|  |  |  | 			selected_history = &history; | 
					
						
							|  |  |  | 			global_timestamp = history.undo_stack.back()->get().timestamp; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id()); | 
					
						
							|  |  |  | 		if (!history.undo_stack.is_empty() && history.undo_stack.back()->get().timestamp > global_timestamp) { | 
					
						
							|  |  |  | 			selected_history = &history; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return selected_history; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | void EditorUndoRedoManager::_bind_methods() { | 
					
						
							| 
									
										
										
										
											2025-05-06 13:59:56 +02:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode", "custom_context", "backward_undo_ops", "mark_unsaved"), &EditorUndoRedoManager::create_action, DEFVAL(UndoRedo::MERGE_DISABLE), DEFVAL((Object *)nullptr), DEFVAL(false), DEFVAL(true)); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("commit_action", "execute"), &EditorUndoRedoManager::commit_action, DEFVAL(true)); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("is_committing_action"), &EditorUndoRedoManager::is_committing_action); | 
					
						
							| 
									
										
										
										
											2023-07-22 20:16:54 +02:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("force_fixed_history"), &EditorUndoRedoManager::force_fixed_history); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		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", &EditorUndoRedoManager::_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", &EditorUndoRedoManager::_add_undo_method, mi, varray(), false); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("add_do_property", "object", "property", "value"), &EditorUndoRedoManager::add_do_property); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &EditorUndoRedoManager::add_undo_property); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &EditorUndoRedoManager::add_do_reference); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &EditorUndoRedoManager::add_undo_reference); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_object_history_id", "object"), &EditorUndoRedoManager::get_history_id_for_object); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_history_undo_redo", "id"), &EditorUndoRedoManager::get_history_undo_redo); | 
					
						
							| 
									
										
										
										
											2024-04-02 13:33:12 +02:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("clear_history", "id", "increase_version"), &EditorUndoRedoManager::clear_history, DEFVAL(INVALID_HISTORY), DEFVAL(true)); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-27 13:52:06 +02:00
										 |  |  | 	ADD_SIGNAL(MethodInfo("history_changed")); | 
					
						
							|  |  |  | 	ADD_SIGNAL(MethodInfo("version_changed")); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	BIND_ENUM_CONSTANT(GLOBAL_HISTORY); | 
					
						
							| 
									
										
										
										
											2022-12-07 18:15:09 +01:00
										 |  |  | 	BIND_ENUM_CONSTANT(REMOTE_HISTORY); | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | 	BIND_ENUM_CONSTANT(INVALID_HISTORY); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-23 23:53:16 +01:00
										 |  |  | EditorUndoRedoManager *EditorUndoRedoManager::get_singleton() { | 
					
						
							|  |  |  | 	return singleton; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | EditorUndoRedoManager::EditorUndoRedoManager() { | 
					
						
							|  |  |  | 	if (!singleton) { | 
					
						
							|  |  |  | 		singleton = this; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-25 18:06:46 +01:00
										 |  |  | EditorUndoRedoManager::~EditorUndoRedoManager() { | 
					
						
							|  |  |  | 	for (const KeyValue<int, History> &E : history_map) { | 
					
						
							|  |  |  | 		discard_history(E.key, false); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |