This appears to me like an 'evil hack' ( which is how I rarely annotate my code to workaround things ;) ) - and such a hack should not be the basis of a whole undo framework.
What happens with your internal queue if the user flushes undo ? ( alternatively maya flushes it when creating a reference, or when unloading it, or removing it ). To me it appears the index on the garbage node would stay as it was, as well as your internal queue. Perhaps you can register a callback that will always be triggered in such cases, so you can react to it.
When the user changes scenes, you will loose your previous garbage node, and have to create a new one.
What happens if I trigger one undoable pymel API command, that internally calls 10 more undoable commands ( and we could go on like it ).
Just to get this node work right one has to do whole lots of work and catch many special cases - all this could possibly break in yet another unforseen situation.
What do you think about the flagged issues ?
sebastianThis appears to me like an 'evil hack' ( which is how I rarely annotate my code to workaround things ;) ) - and such a hack should not be the basis of a whole undo framework.
What happens with your internal queue if the user flushes undo ? ( alternatively maya flushes it when creating a reference, or when unloading it, or removing it ). To me it appears the index on the garbage node would stay as it was, as well as your internal queue. Perhaps you can register a callback that will always be triggered in such cases, so you can react to it.i just looked up the code, and it does not use the index, but merely moves undoItems between the undo and redo stack:def _attrChanged(self, msg, plug, otherPlug, data):if self.cb_enabled \and (msg & _api.MNodeMessage.kAttributeSet != 0) \and (plug == self.cmdCountAttr):if _api.MGlobal.isUndoing():cmdObj = self.undo_queue.pop()cmdObj.undoIt()self.redo_queue.append(cmdObj)elif _api.MGlobal.isRedoing():cmdObj = self.redo_queue.pop()cmdObj.redoIt()self.undo_queue.append(cmdObj)
When the user changes scenes, you will loose your previous garbage node, and have to create a new one.undo does not span scenes anyway, so this should not be an issue, right?
What happens if I trigger one undoable pymel API command, that internally calls 10 more undoable commands ( and we could go on like it ).undoable pymel API commands are atomic -- they never call anything but pure api.
Just to get this node work right one has to do whole lots of work and catch many special cases - all this could possibly break in yet another unforseen situation.What do you think about the flagged issues ?it ain't pretty, but it works. there may end up being special cases to address, but so far we have not hit any. the benefits you get from adding the API as an option for pymel to delegate to FAR outweigh the unaesthetic nature of this undo solution. in the end, these API calls are *additional* methods that you can use if you want, or not. the docstrings on each method tell you whether it is derived from MEL or from API, and if from API, if it is undoable. the most important and complex methods still derive from maya.cmds: things like setAttr, addAttr.
the flushing of maya undo i'll have to look into. not sure if there's an API callback for that....we've been using this new API/MEL hybrid pymel for about 3-4 months now and the TDs here, including myself, are loving the hybridization. it feels less like a prototype now and more like something that ties into maya at a core level : because that's exactly what it does :) . it's awesome for prototyping plugins too, as you can get API classes for any PyNode. From the new docs:
Yes, but Method A sets tx, ty and tz of a transform - that is 3 calls to the API , but just one call to MethodA. The way it works now with that node, it would 3 operations onto the stack, requireing it to be undone 3 times ( instead of one ).
Your explanation does not alleviate my concern - which is acutally a major flaw in the whole concept of using a garbage node.
In fact you would have to store these 3 commands in an individual list that can be undone at once. This is impossible with a garbage node putting every attribute change onto maya's undo stack. Even if you would track your stack depth to be able to internally track your 3 commands as one, maya's undo queue will still be contaminated with 2 additional do-nothing commands.
This shows that having a node respond to every API call ( that should be undoable ) cannot work the way undo has to work.