sebastian

> 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.

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:


PyNode classes now derive their methods from both MEL and the API  
( aka. maya.cmds and maya.OpenMaya, respectivelly ).  If you're   
familiar with Maya's API, you know that there is a distinct separation  
between objects and their abilities.  There are fundamental object  
types such as MObject and MDagPath that represent the object itself,  
and there are "function sets", which are classes that, once  
instantiated with a given fundamental object, provide it with special  
abilities.  ( Because I am a huge nerd, I like to the think of the   
function sets as robotic "mechs" and the fundamental objects as  
"spirits" or "ghosts" that inhabit them, like in *Ghost in the Shell* ).

For simplicity, pymel does away with this distinction: a PyNode  
instance is the equivalent of an activated API function set;  the  
necessary fundamental API objects are determined behind the scenes at  
instantiation.  You can access these by using the special methods  
__apimobject__, __apihandle__, __apimdagpath__, __apimplug__, and  
__apimfn__.  ( Be aware that this is still considered internal magic,  
and the names of these methods are subject to change ):

     >>> p = PyNode('perspShape')
     >>> p.__apimfn__() # doctest: +ELLIPSIS
     <maya.OpenMaya.MFnCamera; proxy of <Swig Object of type  
'MFnCamera *' at ...> >
     >>> p.__apimdagpath__() # doctest: +ELLIPSIS
     <maya.OpenMaya.MDagPath; proxy of <Swig Object of type 'MDagPath  
*' at ...> >
     >>> a = p.focalLength
     >>> a
     Attribute(u'perspShape.focalLength')
     >>> a.__apimplug__() # doctest: +ELLIPSIS
     <maya.OpenMaya.MPlug; proxy of <Swig Object of type 'MPlug *'  
at ...> >

As you can probably see, these methods are enormously useful when  
prototyping API plugins.

-chad



>
>
> >


--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/python_inside_maya
-~----------~----~----~----~------~----~------~--~---

Reply via email to