1 /* 2 Copyright © 2020,2022 Inochi2D Project 3 Distributed under the 2-Clause BSD License, see LICENSE file. 4 */ 5 module creator.actions.parameter; 6 7 import creator.core.actionstack; 8 import creator.actions; 9 import creator.actions.binding; 10 import creator; 11 import inochi2d; 12 import std.format; 13 import i18n; 14 15 /** 16 Action to add parameter to active puppet. 17 */ 18 class ParameterAddRemoveAction(bool added = true) : Action { 19 public: 20 Parameter self; 21 Driver[] drivers; 22 Parameter[]* parentList; 23 24 this(Parameter self, Parameter[]* parentList) { 25 this.self = self; 26 this.parentList = parentList; 27 28 // Find drivers 29 foreach(ref driver; incActivePuppet().getDrivers()) { 30 if (SimplePhysics sf = cast(SimplePhysics)driver) { 31 if (sf.param !is null && sf.param.uuid == self.uuid) { 32 drivers ~= driver; 33 } 34 } 35 } 36 37 // Empty drivers 38 foreach(ref driver; drivers) { 39 if (SimplePhysics sf = cast(SimplePhysics)driver) { 40 sf.param = null; 41 } 42 } 43 } 44 45 /** 46 Rollback 47 */ 48 void rollback() { 49 if (!added) 50 incActivePuppet().parameters ~= self; 51 else 52 incActivePuppet().removeParameter(self); 53 54 // Re-apply drivers 55 foreach(ref driver; drivers) { 56 if (SimplePhysics sf = cast(SimplePhysics)driver) { 57 sf.param = self; 58 } 59 } 60 } 61 62 /** 63 Redo 64 */ 65 void redo() { 66 if (added) 67 incActivePuppet().parameters ~= self; 68 else 69 incActivePuppet().removeParameter(self); 70 71 // Empty drivers 72 foreach(ref driver; drivers) { 73 if (SimplePhysics sf = cast(SimplePhysics)driver) { 74 sf.param = null; 75 } 76 } 77 } 78 79 /** 80 Describe the action 81 */ 82 string describe() { 83 if (added) 84 return _("Added parameter %s").format(self.name); 85 else 86 return _("Removed parameter %s").format(self.name); 87 } 88 89 /** 90 Describe the action 91 */ 92 string describeUndo() { 93 if (added) 94 return _("Parameter %s was removed").format(self.name); 95 else 96 return _("Parameter %s was added").format(self.name); 97 } 98 99 /** 100 Gets name of this action 101 */ 102 string getName() { 103 return this.stringof; 104 } 105 106 bool merge(Action other) { return false; } 107 bool canMerge(Action other) { return false; } 108 } 109 110 alias ParameterAddAction = ParameterAddRemoveAction!true; 111 alias ParameterRemoveAction = ParameterAddRemoveAction!false; 112 113 114 /** 115 Action to remove parameter from active puppet. 116 */ 117 class ParameterValueChangeAction(T) : LazyBoundAction { 118 public: 119 alias TSelf = typeof(this); 120 string name; 121 Parameter self; 122 T oldValue; 123 T newValue; 124 T* valuePtr; 125 126 this(string name, Parameter self, T oldValue, T newValue, T* valuePtr) { 127 this.name = name; 128 this.self = self; 129 this.oldValue = oldValue; 130 this.newValue = newValue; 131 this.valuePtr = valuePtr; 132 } 133 134 this(string name, Parameter self, T* valuePtr, void delegate() update = null) { 135 this.name = name; 136 this.self = self; 137 this.valuePtr = valuePtr; 138 this.oldValue = *valuePtr; 139 if (update !is null) { 140 update(); 141 updateNewState(); 142 } 143 } 144 145 void updateNewState() { 146 this.newValue = *valuePtr; 147 } 148 149 /** 150 Rollback 151 */ 152 void rollback() { 153 *valuePtr = oldValue; 154 } 155 156 /** 157 Redo 158 */ 159 void redo() { 160 *valuePtr = newValue; 161 } 162 163 /** 164 Describe the action 165 */ 166 string describe() { 167 if (name == "axis points") 168 return _("%s->%s changed").format(self.name, name); 169 else 170 return _("%s->%s changed to %s").format(self.name, name, newValue); 171 } 172 173 /** 174 Describe the action 175 */ 176 string describeUndo() { 177 if (name == "axis points") 178 return _("%s->%s change cancelled").format(self.name, name); 179 else 180 return _("%s->%s changed from %s").format(self.name, name, oldValue); 181 } 182 183 /** 184 Gets name of this action 185 */ 186 string getName() { 187 return name; 188 } 189 190 /** 191 Merge 192 */ 193 bool merge(Action other) { 194 if (this.canMerge(other)) { 195 this.newValue = (cast(TSelf)other).newValue; 196 return true; 197 } 198 return false; 199 } 200 201 /** 202 Gets whether this node can merge with an other 203 */ 204 bool canMerge(Action other) { 205 TSelf otherChange = cast(TSelf) other; 206 return (otherChange !is null && this.name == otherChange.name); 207 } 208 } 209 210 /** 211 Base class for actions to change multiple bindings of the same parameter at once. 212 */ 213 class AbstractParameterChangeBindingsAction(VarArg...) : GroupAction, LazyBoundAction { 214 public: 215 alias TSelf = typeof(this); 216 string name; 217 Parameter self; 218 219 this(string name, Parameter self, ParameterBinding[] bindings, Action function(ParameterBinding, VarArg) bindingActionMapper, VarArg args) { 220 super([]); 221 this.name = name; 222 this.self = self; 223 foreach (binding; (bindings !is null)? bindings: self.bindings) { 224 Action action = bindingActionMapper(binding, args); 225 if (action !is null) 226 addAction(action); 227 } 228 } 229 230 override 231 void updateNewState() { 232 foreach (action; actions) { 233 LazyBoundAction lazyAction = cast(LazyBoundAction)action; 234 if (lazyAction !is null) 235 lazyAction.updateNewState(); 236 } 237 } 238 239 /** 240 Describe the action 241 */ 242 override 243 string describe() { 244 return _("%s->%s changed").format(self.name, name); 245 } 246 247 /** 248 Describe the action 249 */ 250 override 251 string describeUndo() { 252 return _("%s->%s change cancelled").format(self.name, name); 253 } 254 255 /** 256 Gets name of this action 257 */ 258 override 259 string getName() { 260 return name; 261 } 262 } 263 264 265 /** 266 Actions to add bindings to parameter at once. 267 */ 268 269 Action BindingAddMapper(ParameterBinding binding, Parameter parent) { 270 return new ParameterBindingAddAction(parent, binding); 271 } 272 class ParameterAddBindingsAction : AbstractParameterChangeBindingsAction!(Parameter) { 273 this(string name, Parameter self, ParameterBinding[] bindings) { 274 super(name, self, bindings, &BindingAddMapper, self); 275 } 276 } 277 278 279 /** 280 Actions to remove bindings from parameter at once. 281 */ 282 283 Action BindingRemoveMapper(ParameterBinding binding, Parameter parent) { 284 return new ParameterBindingRemoveAction(parent, binding); 285 } 286 class ParameterRemoveBindingsAction : AbstractParameterChangeBindingsAction!(Parameter) { 287 this(string name, Parameter self, ParameterBinding[] bindings) { 288 super(name, self, bindings, &BindingRemoveMapper, self); 289 } 290 } 291 292 293 /** 294 Actions to change all binding values at once. 295 */ 296 297 Action BindingChangeMapper(ParameterBinding binding) { 298 if (auto typedBinding = cast(ParameterBindingImpl!float)binding) { 299 return new ParameterBindingAllValueChangeAction!(float)(typedBinding.getName(), typedBinding); 300 } else if (auto typedBinding = cast(ParameterBindingImpl!Deformation)binding) { 301 return new ParameterBindingAllValueChangeAction!(Deformation)(typedBinding.getName(), typedBinding); 302 } else { 303 return null; 304 } 305 } 306 class ParameterChangeBindingsAction : AbstractParameterChangeBindingsAction!() { 307 this(string name, Parameter self, ParameterBinding[] bindings) { 308 super(name, self, bindings, &BindingChangeMapper); 309 } 310 } 311 312 313 /** 314 Actions to change binding value of specified keypoints at once. 315 */ 316 317 Action BindingValueChangeMapper(ParameterBinding binding, int pointx, int pointy) { 318 if (auto typedBinding = cast(ParameterBindingImpl!float)binding) { 319 return new ParameterBindingValueChangeAction!(float)(typedBinding.getName(), typedBinding, pointx, pointy); 320 } else if (auto typedBinding = cast(ParameterBindingImpl!Deformation)binding) { 321 return new ParameterBindingValueChangeAction!(Deformation)(typedBinding.getName(), typedBinding, pointx, pointy); 322 } else { 323 return null; 324 } 325 } 326 class ParameterChangeBindingsValueAction : AbstractParameterChangeBindingsAction!(int, int) { 327 this(string name, Parameter self, ParameterBinding[] bindings, int pointx, int pointy) { 328 super(name, self, bindings, &BindingValueChangeMapper, pointx, pointy); 329 } 330 }