Maya undo chunk examples

# -*- coding: utf-8 -*-
##  Copyright 2019 Trevor van Hoof and Jan Pijpers.
##  Licensed under the Apache License, Version 2.0
##  Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers
##  See the license file attached or on https://www.janpijpers.com/script-licenses/

'''
Name: mayaUndoExample
Description:

two undo examples
one on how to use the undo stack as decorator function

and as inside function
'''

from maya import cmds
import traceback
import pymel.core as pm

def undo( function ):
    '''
        This is a function decorator.
        you can use it by writing @undo one line obove any function.
        before the function gets called an undo chunk is started.
        when the function ends it gets closed.
        Be carefull, if you call the function in itself (recursively) it will break the undo stack.
    :param function:
    :return:
    '''
    def funcCall(*args,**kwargs):

        result = None 
        try:
            ## here we open the undo chunk and we give it the name of the fuction
            cmds.undoInfo( openChunk= True, chunkname = function.__name__ )
            result = function( *args,**kwargs )
        except Exception as e:
            ## If we have an error we will print the stack of the error
            print traceback.format_exc()
            ## we also make sure the maya ui shows an error.
            pm.displayError( "## Error, see script editor: %s"%e )
        finally:
            ## we always need to close the chunk at the end else we corrupt the stack.
            cmds.undoInfo( closeChunk = True )
        return result
    return funcCall 



@undo
def simpleExampleWithDecorator():
    '''
        So here we have the decorator defined above the function definition.
        So before this function is called, an undo chunk is created and closed after the function has finished.
    :return:
    '''
    for i in xrange( 10 ):
        loc = cmds.createNode( "spaceLocator"  )
        cmds.xform(loc, translation=(i,i,i))
simpleExampleWithDecorator()


def undoInFunction( ):

    ## its recomended to always use a try and except with an undo chunk else you need to restart maya when it fails.
    ## here we open the undo chunk and we give it the name of the fuction
    cmds.undoInfo(openChunk=True, chunkname="Example")

    try:
        for i in xrange(10):
            loc = cmds.createNode("spaceLocator")
            cmds.xform(loc, translation=(i, i, i) )
    except Exception as e:
        ## If we have an error we will print the stack of the error
        print traceback.format_exc()
        ## we also make sure the maya ui shows an error.
        pm.displayError("## Error, see script editor: %s" % e)
    finally:
        cmds.undoInfo(openChunk=True, chunkname="Example")

undoInFunction()

Show QT widget UI hierarchy

# -*- coding: utf-8 -*-
##  Copyright 2019 Trevor van Hoof and Jan Pijpers.
##  Licensed under the Apache License, Version 2.0
##  Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers
##  See the license file attached or on https://www.janpijpers.com/script-licenses/

'''
Name: showQtWidgetHierarchy
Description:

In maya you sometimes want to hack the UI.
Seeng as the UI is made with QT you can hack into it by finding the right node and or widget name.

To make this process easier you can run this script and it will show you the entire hierarchy and return it as a dict

'''


import json

import sys
from PySide.QtGui import * ## pip install PySide

def widgets_recursive(d, widget = None, doPrint =False ):
    if not widget:
        for widget in QApplication.topLevelWidgets():
            get_widget(widget, d, 0, doPrint)
    else:
        get_widget(widget, d, 0, doPrint)
                
def get_widget(w,d, depth = 0, doPrint=False):
    '''
        Recursively searches through all widgets down the tree and prints if desired.
    :param w: the widget to search from
    :param d: the dictionary to add it to
    :param depth: current depth we are at
    :param doPrint: if we need to print
    :return:
    '''
    n = w.objectName()
    n = n if n else str(w)
    if doPrint: print "\t"*depth, n
    newD = {}
    for widget in w.children():
        get_widget(widget, newD, depth +1 )
    d[n] = newD

def get_widget_from_name(name):
    for widget in QApplication.allWidgets():
        try:
            if name in widget.objectName() :
                return widget
        except:
            pass
    return None 

if __name__ =="__main__":

    ## Remove this block if you are running this in maya or something.
    ## Here we make a simple QWindow with a layout and button.
    app = QApplication(sys.argv)
    wid = QWidget()
    wid.setObjectName("myWindow")
    button = QPushButton()
    button.setObjectName("This is my button, there are many like it but this one is mine.")
    lay = QHBoxLayout()
    lay.addWidget(button)
    wid.setLayout(lay)
    wid.show()


    ## Create a simpe dict to hold all the data in the ned.
    widgetHierarchyDict = {}

    ## if you have no idea where to start. Just leave the topWidget argument to None
    ## But if you are in a QT based aplication like Maya you can also start from a widget you know the name of to speed
    ## up the process
    widgetObjectName = None ## "graphEditor1Window"
    topWidget = get_widget_from_name(widgetObjectName)


    ## Recurse over all widgets and store all the information in the provided dict.
    widgets_recursive(widgetHierarchyDict, topWidget)

    ## Print it with json so its nice and clear.
    print json.dumps(widgetHierarchyDict, sort_keys=True, indent = 2 )