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