1 /**
2 Helper to manage undo/redo operations in the editor or custom tools.
3 
4 Copyright:
5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.  
6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)  
7 Copyright (c) 2017-2018 Godot-D contributors  
8 
9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License)
10 
11 
12 */
13 module godot.undoredo;
14 import std.meta : AliasSeq, staticIndexOf;
15 import std.traits : Unqual;
16 import godot.d.traits;
17 import godot.core;
18 import godot.c;
19 import godot.d.bind;
20 import godot.d.reference;
21 import godot.globalenums;
22 import godot.object;
23 import godot.classdb;
24 /**
25 Helper to manage undo/redo operations in the editor or custom tools.
26 
27 It works by registering methods and property changes inside "actions".
28 Common behavior is to create an action, then add do/undo calls to functions or property changes, then committing the action.
29 Here's an example on how to add an action to the Godot editor's own $(D UndoRedo), from a plugin:
30 
31 
32 var undo_redo = get_undo_redo() # Method of EditorPlugin.
33 
34 func do_something():
35     pass # Put your code here.
36 
37 func undo_something():
38     pass # Put here the code that reverts what's done by "do_something()".
39 
40 func _on_MyButton_pressed():
41     var node = get_node("MyNode2D")
42     undo_redo.create_action("Move the node")
43     undo_redo.add_do_method(self, "do_something")
44     undo_redo.add_undo_method(self, "undo_something")
45     undo_redo.add_do_property(node, "position", Vector2(100,100))
46     undo_redo.add_undo_property(node, "position", node.position)
47     undo_redo.commit_action()
48 
49 
50 $(D createAction), $(D addDoMethod), $(D addUndoMethod), $(D addDoProperty), $(D addUndoProperty), and $(D commitAction) should be called one after the other, like in the example. Not doing so could lead to crashes.
51 If you don't need to register a method, you can leave $(D addDoMethod) and $(D addUndoMethod) out; the same goes for properties. You can also register more than one method/property.
52 */
53 @GodotBaseClass struct UndoRedo
54 {
55 	package(godot) enum string _GODOT_internal_name = "UndoRedo";
56 public:
57 @nogc nothrow:
58 	union { /** */ godot_object _godot_object; /** */ GodotObject _GODOT_base; }
59 	alias _GODOT_base this;
60 	alias BaseClasses = AliasSeq!(typeof(_GODOT_base), typeof(_GODOT_base).BaseClasses);
61 	package(godot) __gshared bool _classBindingInitialized = false;
62 	package(godot) static struct GDNativeClassBinding
63 	{
64 		__gshared:
65 		@GodotName("add_do_method") GodotMethod!(void, GodotObject, String, GodotVarArgs) addDoMethod;
66 		@GodotName("add_do_property") GodotMethod!(void, GodotObject, String, Variant) addDoProperty;
67 		@GodotName("add_do_reference") GodotMethod!(void, GodotObject) addDoReference;
68 		@GodotName("add_undo_method") GodotMethod!(void, GodotObject, String, GodotVarArgs) addUndoMethod;
69 		@GodotName("add_undo_property") GodotMethod!(void, GodotObject, String, Variant) addUndoProperty;
70 		@GodotName("add_undo_reference") GodotMethod!(void, GodotObject) addUndoReference;
71 		@GodotName("clear_history") GodotMethod!(void, bool) clearHistory;
72 		@GodotName("commit_action") GodotMethod!(void) commitAction;
73 		@GodotName("create_action") GodotMethod!(void, String, long) createAction;
74 		@GodotName("get_current_action_name") GodotMethod!(String) getCurrentActionName;
75 		@GodotName("get_version") GodotMethod!(long) getVersion;
76 		@GodotName("has_redo") GodotMethod!(bool) hasRedo;
77 		@GodotName("has_undo") GodotMethod!(bool) hasUndo;
78 		@GodotName("is_commiting_action") GodotMethod!(bool) isCommitingAction;
79 		@GodotName("redo") GodotMethod!(bool) redo;
80 		@GodotName("undo") GodotMethod!(bool) undo;
81 	}
82 	/// 
83 	pragma(inline, true) bool opEquals(in UndoRedo other) const
84 	{ return _godot_object.ptr is other._godot_object.ptr; }
85 	/// 
86 	pragma(inline, true) typeof(null) opAssign(typeof(null) n)
87 	{ _godot_object.ptr = n; return null; }
88 	/// 
89 	pragma(inline, true) bool opEquals(typeof(null) n) const
90 	{ return _godot_object.ptr is n; }
91 	/// 
92 	size_t toHash() const @trusted { return cast(size_t)_godot_object.ptr; }
93 	mixin baseCasts;
94 	/// Construct a new instance of UndoRedo.
95 	/// Note: use `memnew!UndoRedo` instead.
96 	static UndoRedo _new()
97 	{
98 		static godot_class_constructor constructor;
99 		if(constructor is null) constructor = _godot_api.godot_get_class_constructor("UndoRedo");
100 		if(constructor is null) return typeof(this).init;
101 		return cast(UndoRedo)(constructor());
102 	}
103 	@disable new(size_t s);
104 	/// 
105 	enum MergeMode : int
106 	{
107 		/**
108 		Makes "do"/"undo" operations stay in separate actions.
109 		*/
110 		mergeDisable = 0,
111 		/**
112 		Makes so that the action's "do" operation is from the first action created and the "undo" operation is from the last subsequent action with the same name.
113 		*/
114 		mergeEnds = 1,
115 		/**
116 		Makes subsequent actions with the same name be merged into one.
117 		*/
118 		mergeAll = 2,
119 	}
120 	/// 
121 	enum Constants : int
122 	{
123 		mergeDisable = 0,
124 		mergeEnds = 1,
125 		mergeAll = 2,
126 	}
127 	/**
128 	Register a method that will be called when the action is committed.
129 	*/
130 	void addDoMethod(VarArgs...)(GodotObject object, in String method, VarArgs varArgs)
131 	{
132 		Array _GODOT_args = Array.make();
133 		_GODOT_args.append(object);
134 		_GODOT_args.append(method);
135 		foreach(vai, VA; VarArgs)
136 		{
137 			_GODOT_args.append(varArgs[vai]);
138 		}
139 		String _GODOT_method_name = String("add_do_method");
140 		this.callv(_GODOT_method_name, _GODOT_args);
141 	}
142 	/**
143 	Register a property value change for "do".
144 	*/
145 	void addDoProperty(VariantArg2)(GodotObject object, in String property, in VariantArg2 value)
146 	{
147 		checkClassBinding!(typeof(this))();
148 		ptrcall!(void)(GDNativeClassBinding.addDoProperty, _godot_object, object, property, value);
149 	}
150 	/**
151 	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.
152 	*/
153 	void addDoReference(GodotObject object)
154 	{
155 		checkClassBinding!(typeof(this))();
156 		ptrcall!(void)(GDNativeClassBinding.addDoReference, _godot_object, object);
157 	}
158 	/**
159 	Register a method that will be called when the action is undone.
160 	*/
161 	void addUndoMethod(VarArgs...)(GodotObject object, in String method, VarArgs varArgs)
162 	{
163 		Array _GODOT_args = Array.make();
164 		_GODOT_args.append(object);
165 		_GODOT_args.append(method);
166 		foreach(vai, VA; VarArgs)
167 		{
168 			_GODOT_args.append(varArgs[vai]);
169 		}
170 		String _GODOT_method_name = String("add_undo_method");
171 		this.callv(_GODOT_method_name, _GODOT_args);
172 	}
173 	/**
174 	Register a property value change for "undo".
175 	*/
176 	void addUndoProperty(VariantArg2)(GodotObject object, in String property, in VariantArg2 value)
177 	{
178 		checkClassBinding!(typeof(this))();
179 		ptrcall!(void)(GDNativeClassBinding.addUndoProperty, _godot_object, object, property, value);
180 	}
181 	/**
182 	Register a reference for "undo" that will be erased if the "undo" history is lost. This is useful mostly for nodes removed with the "do" call (not the "undo" call!).
183 	*/
184 	void addUndoReference(GodotObject object)
185 	{
186 		checkClassBinding!(typeof(this))();
187 		ptrcall!(void)(GDNativeClassBinding.addUndoReference, _godot_object, object);
188 	}
189 	/**
190 	Clear the undo/redo history and associated references.
191 	Passing `false` to `increase_version` will prevent the version number to be increased from this.
192 	*/
193 	void clearHistory(in bool increase_version = true)
194 	{
195 		checkClassBinding!(typeof(this))();
196 		ptrcall!(void)(GDNativeClassBinding.clearHistory, _godot_object, increase_version);
197 	}
198 	/**
199 	Commit the action. All "do" methods/properties are called/set when this function is called.
200 	*/
201 	void commitAction()
202 	{
203 		checkClassBinding!(typeof(this))();
204 		ptrcall!(void)(GDNativeClassBinding.commitAction, _godot_object);
205 	}
206 	/**
207 	Create a new action. After this is called, do all your calls to $(D addDoMethod), $(D addUndoMethod), $(D addDoProperty), and $(D addUndoProperty), then commit the action with $(D commitAction).
208 	The way actions are merged is dictated by the `merge_mode` argument. See $(D mergemode) for details.
209 	*/
210 	void createAction(in String name, in long merge_mode = 0)
211 	{
212 		checkClassBinding!(typeof(this))();
213 		ptrcall!(void)(GDNativeClassBinding.createAction, _godot_object, name, merge_mode);
214 	}
215 	/**
216 	Gets the name of the current action.
217 	*/
218 	String getCurrentActionName() const
219 	{
220 		checkClassBinding!(typeof(this))();
221 		return ptrcall!(String)(GDNativeClassBinding.getCurrentActionName, _godot_object);
222 	}
223 	/**
224 	Gets the version. Every time a new action is committed, the $(D UndoRedo)'s version number is increased automatically.
225 	This is useful mostly to check if something changed from a saved version.
226 	*/
227 	long getVersion() const
228 	{
229 		checkClassBinding!(typeof(this))();
230 		return ptrcall!(long)(GDNativeClassBinding.getVersion, _godot_object);
231 	}
232 	/**
233 	Returns `true` if a "redo" action is available.
234 	*/
235 	bool hasRedo()
236 	{
237 		checkClassBinding!(typeof(this))();
238 		return ptrcall!(bool)(GDNativeClassBinding.hasRedo, _godot_object);
239 	}
240 	/**
241 	Returns `true` if an "undo" action is available.
242 	*/
243 	bool hasUndo()
244 	{
245 		checkClassBinding!(typeof(this))();
246 		return ptrcall!(bool)(GDNativeClassBinding.hasUndo, _godot_object);
247 	}
248 	/**
249 	Returns `true` if the $(D UndoRedo) is currently committing the action, i.e. running its "do" method or property change (see $(D commitAction)).
250 	*/
251 	bool isCommitingAction() const
252 	{
253 		checkClassBinding!(typeof(this))();
254 		return ptrcall!(bool)(GDNativeClassBinding.isCommitingAction, _godot_object);
255 	}
256 	/**
257 	Redo the last action.
258 	*/
259 	bool redo()
260 	{
261 		checkClassBinding!(typeof(this))();
262 		return ptrcall!(bool)(GDNativeClassBinding.redo, _godot_object);
263 	}
264 	/**
265 	Undo the last action.
266 	*/
267 	bool undo()
268 	{
269 		checkClassBinding!(typeof(this))();
270 		return ptrcall!(bool)(GDNativeClassBinding.undo, _godot_object);
271 	}
272 }