def create(self, *args, **kwargs):
        ''' '''
        if pm.control(self.windowName, exists=True):
            pm.deleteUI(self.windowName)
        if pm.control(self.dockName, exists=True):
            pm.deleteUI(self.dockName)

        if self.dockable:
            self.mainWindow = pm.window(self.windowName,
                                        t=self.windowName,
                                        menuBar=self.menuBar)
        else:
            self.mainWindow = pm.window(self.windowName,
                                        t=self.windowName,
                                        widthHeight=[self.width, self.height],
                                        menuBar=self.menuBar,
                                        rtf=self.rtf,
                                        mnb=self.mnb,
                                        mxb=self.mxb,
                                        s=self.sizeable)

        if self.menuBar:
            pm.menu(l='Help', helpMenu=True)
            pm.menuItem(l='blog.leocov.com',
                        command=lambda *args: webbrowser.open(
                            'http://blog.leocov.com', new=2))
            pm.menu(l='Tools')
            pm.menuItem(l='Make Shelf Icon',
                        command=lambda *args: shelf.makeShelfButton(
                            self.windowName, self.shelfCommand, self.icon, self
                            .annotation))
Exemple #2
0
def start():

    if pm.window('wBatchTools', ex=1):
        pm.deleteUI('wBatchTools')

    DOCK_NAME = 'BT_DOCK'
    LYT_NAME = 'BT_LYT_NAME'
    WIN_NAME = 'wBatchTools'
    AREA = 'left'

    app = BatchTools(mayaMainWindow)
    app.show()
    app.postLoad()

    # dock window
    if pm.dockControl(DOCK_NAME, ex=1):
        pm.deleteUI(DOCK_NAME)
    dockLayout = pm.paneLayout(LYT_NAME,
                               configuration='single',
                               parent=WIN_NAME,
                               width=500,
                               height=500)
    pm.dockControl(DOCK_NAME,
                   aa=['left', 'right'],
                   a=AREA,
                   floating=0,
                   content=dockLayout,
                   l='Batch tools')
    pm.control(WIN_NAME, e=True, parent=dockLayout)
    if pm.dockControl(DOCK_NAME, ex=1):
        pm.control(WIN_NAME, e=1, p=dockLayout)
        pm.dockControl(DOCK_NAME, e=1, a=AREA, fl=0)
        pm.dockControl(DOCK_NAME, e=1, vis=1)
        pm.dockControl(DOCK_NAME, e=1, w=500)
Exemple #3
0
    def browse_path(self, ctrl, button=False, *args, **kwargs):
        '''
        '''
        if button:
            path = lcPath.Path.browsePathTextField(
                ctrl, '', 'Choose an Image Editor Application', mode=1)
            if path and os.path.isfile(path):
                if 'photoshop' in ctrl:
                    pm.optionVar(sv=['PhotoshopDir', path])
                if 'image' in ctrl:
                    pm.optionVar(sv=['EditImageDir', path])
        else:

            path = pm.textField('lcPrefs_photosohp', query=True, text=True)
            if path and os.path.isfile(path):
                pm.optionVar(sv=['PhotoshopDir', path])

            path = pm.textField('lcPrefs_image', query=True, text=True)
            if path and os.path.isfile(path):
                pm.optionVar(sv=['EditImageDir', path])

        if self.hintCtrl:
            if pm.optionVar(query='EditImageDir') and pm.optionVar(
                    query='PhotoshopDir'):
                pm.control(self.hintCtrl, edit=True, visible=False)
Exemple #4
0
 def create_temp_panel(self):
     # create panel for playblast
     self.viewport = pm.modelPanel(tearOff=True)
     pm.setFocus(self.viewport)
     pm.control(self.viewport, edit=True, w=self.output_dimentions[0])
     pm.control(self.viewport, edit=True, h=self.output_dimentions[1])
     pm.lookThru(self.current_camera)
Exemple #5
0
def hidePanel():
    """Refreshs the main panel."""
    widget_instance = getPanel()

    if widget_instance:
        panel_name = widget_instance.objectName()
        maya_panel_name = "maya_%s" % panel_name
        pm.control(maya_panel_name, edit=True, visible=False)
Exemple #6
0
    def disperse(self, *args):
        """Called when the disperse button is pressed"""
        if self.sourceObj == None or self.targetObjs == None:
            pm.confirmDialog(t='Error', b=['OK'],
                m='Please make sure source and targets are selected.')
            return

        # get copy number
        copyNum = self.copyNum.getValue()
        copyNum = min(copyNum, len(self.vertIndexList))

        # get rotation
        rotationMode = self.rotationModeRC.getSelect()
        rotationMode = pm.control(rotationMode, q=True, fpn=True)
        if rotationMode == self.rotBtnRand:
            origRot = pm.xform(self.sourceObj, ro=True, q=True)
            rotRange = self.rotationRange.getValue()

        # get scale
        scaleMode = self.scaleModeRC.getSelect()
        scaleMode = pm.control(scaleMode, q=True, fpn=True)
        if scaleMode == self.scaleBtnRand:
            scaleRange = self.scaleRange.getValue()

        # make copies
        randVertIndexList = random.sample(self.vertIndexList, copyNum)
        for i in randVertIndexList:
            newObj = pm.duplicate(self.sourceObj, n='%s_copy'%self.sourceObj)
            # decide which target the random vert index falls on
            vertSum = 0
            targetIndex = 0
            targetVertIndex = 0
            for j, k in enumerate(self.targetVertNumList):
                vertSum += k
                if i + 1 <= vertSum:
                    targetIndex = j
                    targetVertIndex = i - (vertSum - k)
                    break
            # apply scale
            if scaleMode == self.scaleBtnRand:
                randScale = random.uniform(scaleRange[0], scaleRange[1])
                pm.xform(newObj, s=(randScale,randScale,randScale))
            # apply rotation
            if rotationMode == self.rotBtnAlign: # normal constraint
                pm.normalConstraint(self.targetObjs[targetIndex], newObj, aim=(0,0,1), u=(0,1,0))
            elif rotationMode == self.rotBtnRand:
                newRotX = random.uniform(origRot[0]-rotRange[0]/2,origRot[0]+rotRange[0]/2)
                newRotY = random.uniform(origRot[1]-rotRange[1]/2,origRot[1]+rotRange[1]/2)
                newRotZ = random.uniform(origRot[2]-rotRange[2]/2,origRot[2]+rotRange[2]/2)
                pm.xform(newObj, ro=(newRotX,newRotY,newRotZ))
            rotatePivot = pm.xform(newObj, rp=True, q=True)
            newPos = pm.pointPosition('%s.vtx[%d]'%(self.targetObjs[targetIndex],targetVertIndex))
            posOffset = [newPos[0]-rotatePivot[0], newPos[1]-rotatePivot[1], newPos[2]-rotatePivot[2]]
            pm.xform(newObj, t=posOffset)
            # remove constraint after translation
            if rotationMode == self.rotBtnAlign:
                pm.delete(newObj, cn=True)
Exemple #7
0
def showUi(name):
    """Maya is dumb. UI objects can be either controls or windows.
    Throw spaghetti at the wall and see what sticks"""
    try:
        pmc.control(name, e=True, vis=True)
    except:
        pass
    try:
        pmc.window(name, e=True, vis=True)
    except:
        pass
Exemple #8
0
    def create(self, *args, **kwargs):
        ''' '''
        if pm.control(self.windowName, exists=True):
            pm.deleteUI(self.windowName)
        if pm.control(self.dockName, exists=True):
            pm.deleteUI(self.dockName)

        if self.dockable:
            self.mainWindow = pm.window(self.windowName, t=self.windowName)
        else:
            self.mainWindow = pm.window(self.windowName, t=self.windowName, widthHeight=[self.width, self.height],
                                        rtf=self.rtf, mnb=self.mnb, mxb=self.mxb, s=self.sizeable, **self.kwargs)

        if self.menuBar:
            self.menuBarLayout = pm.menuBarLayout(self.prefix + '_menuBarLayout')
            #### Help menu
            pm.menu(self.prefix + '_help', l='Help', helpMenu=True)
            pm.menuItem(parent=self.prefix + '_help', l='Online Help', image='help.png',
                        command=lambda *args: webbrowser.open('http://lct.leocov.com/help', new=2))
            pm.menuItem(parent=self.prefix + '_help', l='Contact / Bug Report',
                        image=os.path.join(self.srcPath, 'icons', 'lc_bug.png'),
                        command=lambda *args: self.bug_report_window())
            errorLogMenuItem = pm.menuItem(parent=self.prefix + '_help', l='Send Error Logs',
                                           checkBox=self.global_cfg.get('g_send_errors'),
                                           annotation="Automatically send error logs to the developer",
                                           command=lambda *args: self.global_cfg.set('g_send_errors',
                                                                                     pm.menuItem(errorLogMenuItem,
                                                                                                 q=True,
                                                                                                 checkBox=True)))
            updateMenuItem = pm.menuItem(parent=self.prefix + '_help', l='Update', enable=False, image='',
                                         command=lambda *args: lcUpdate.Update.lct_auto_update(confirmDiag=True))
            pm.menuItem(parent=self.prefix + '_help', l='About', image='channelBox.png',
                        command=lambda *args: self.about())
            #### Options menu
            pm.menu(self.prefix + '_options', l='Options')
            sceneSettingsMenuItem = pm.menuItem(parent=self.prefix + '_options', l="Use scene settings node",
                                                checkBox=self.global_cfg.get('g_scene_settings'),
                                                annotation="Store tool settings in a scene node. This applies to all scenes.",
                                                command=lambda *args: self.global_cfg.set('g_scene_settings',
                                                                                          pm.menuItem(
                                                                                              sceneSettingsMenuItem,
                                                                                              q=True, checkBox=True)))
            pm.menuItem(parent=self.prefix + '_options', l='Reset {0}'.format(self.windowName), image='airField.svg',
                        command=lambda *args: self.lct_cfg.reset_tool_config(self.windowName))
            # pm.menuItem(parent = self.prefix+'_options', l='Make Shelf Icon', command=lambda *args: lcShelf.Shelf.makeShelfButton(self.windowName, self.shelfCommand, self.icon, self.annotation) )

            # get the current toolset version and release codes
            release, version = lcUpdate.Update.update_get_current_version()
            if release:
                # check if there is a new version on the server and get it
                updatePath = lcUpdate.Update.update_get_new_version(version=version, release=release)
                if updatePath:
                    pm.menuItem(updateMenuItem, edit=True, l='Update Available', enable=True,
                                image='activeSelectedAnimLayer.png')
Exemple #9
0
def lcBake_convert_lightmap(bakeSetListDropdown, cameraListDropdown, *args, **kwargs):
  ''' '''
  numItems = bakeSetListDropdown.getNumberOfItems()
  if numItems > 0:
    currentBakeSet = bakeSetListDropdown.getValue()
    if currentBakeSet:
      currentCamera = cameraListDropdown.getValue()
      outputDirectory = pm.textField(prefix+'_textField_texture_path', query=True, text=True)      
      if os.path.exists(outputDirectory):
        shadows = pm.checkBox(prefix+'_checkBox_shadows', query=True, value=True)
        
        if pm.control('bakeWindow', exists = True):
          pm.deleteUI('bakeWindow')          
        bakeWindow = pm.window('bakeWindow', t='Batch Bake', widthHeight=[100, 100], rtf=True, mnb=False, mxb=False, s=False)
        pm.columnLayout()
        pm.text(l='')
        pm.text(l='')
        pm.text(l='          Bake In Progress          ')
        pm.text(l='                  ......        ')
        pm.text(l='')
        pm.text(l='')
        bakeWindow.show()
        pm.refresh()
        #pm.pause(seconds=10)
        
        convertString = bake.convertLightmap(currentBakeSet, currentCamera, outputDirectory, shadows)
        
        print('Convert Command: {0}'.format(convertString) )
                
        pm.deleteUI('bakeWindow')    
        
        pm.select(clear=True)
      else:
        pm.warning('Path not found: {0}'.format(outputDirectory) )
Exemple #10
0
def _build_workspace_control_ui(widget_id):
    """
    Embed a Shotgun app panel widget into the calling Maya workspace control.

    :param widget_id: Unique string identifier naming the Qt widget at the root of the Shotgun app panel.
                      This Qt widget is assumed to be child of Maya main window.
                      Its name can be used in standard Maya commands to reparent it under a Maya panel.
    """

    import pymel.core as pm

    # In the context of this function, setParent() returns the calling workspace control.
    workspace_control = pm.setParent(query=True)

    # Reparent the Shotgun app panel widget under the workspace control.
    pm.control(widget_id, edit=True, parent=workspace_control)
Exemple #11
0
 def relaunch_all_open_tools(cls, *args, **kwargs):
     '''
     '''
     toolList = cls.buildPublishList(inline=False)
     for tool in toolList:
         toolName = tool[0]
         if pm.control(toolName, exists=True):
             cls.exec_tool(toolName)
Exemple #12
0
 def create(self, *args, **kwargs):
   ''' '''
   if pm.control(self.windowName, exists = True):
     pm.deleteUI(self.windowName)
   if pm.control(self.dockName, exists = True):
     pm.deleteUI(self.dockName)
     
   if self.dockable:
     self.mainWindow = pm.window(self.windowName, t=self.windowName, menuBar=self.menuBar)
   else:
     self.mainWindow = pm.window(self.windowName, t=self.windowName, widthHeight=[self.width, self.height], menuBar=self.menuBar, rtf=self.rtf, mnb=self.mnb, mxb=self.mxb, s=self.sizeable)
   
   if self.menuBar:
     pm.menu(l='Help', helpMenu=True)
     pm.menuItem(l='blog.leocov.com', command=lambda *args: webbrowser.open('http://blog.leocov.com', new=2) )
     pm.menu(l='Tools')
     pm.menuItem(l='Make Shelf Icon', command=lambda *args: shelf.makeShelfButton(self.windowName, self.shelfCommand, self.icon, self.annotation) )
Exemple #13
0
def lcBake_convert_lightmap(bakeSetListDropdown, cameraListDropdown, *args,
                            **kwargs):
    ''' '''
    global lct_cfg
    global prefix
    global defaultString
    global defaultPath

    sel = pm.ls(sl=True)

    numItems = bakeSetListDropdown.getNumberOfItems()
    if numItems > 0:
        currentBakeSet = bakeSetListDropdown.getValue()
        if currentBakeSet != defaultString:
            currentCamera = cameraListDropdown.getValue()
            outputDirectory = pm.textField(prefix + '_textField_texture_path',
                                           query=True,
                                           text=True)
            if os.path.exists(outputDirectory) or pm.PyNode(
                    currentBakeSet).nodeType() == 'vertexBakeSet':
                shadows = pm.checkBox(prefix + '_checkBox_shadows',
                                      query=True,
                                      value=True)

                if pm.control('bakeWindow', exists=True):
                    pm.deleteUI('bakeWindow')
                bakeWindow = pm.window('bakeWindow',
                                       t='Batch Bake',
                                       widthHeight=[100, 100],
                                       rtf=True,
                                       mnb=False,
                                       mxb=False,
                                       s=False)
                pm.columnLayout()
                pm.text(l='')
                pm.text(l='')
                pm.text(l='          Bake In Progress          ')
                pm.text(l='                  ......        ')
                pm.text(l='')
                pm.text(l='')
                bakeWindow.show()
                pm.refresh()

                if pm.PyNode(currentBakeSet).nodeType() == 'vertexBakeSet':
                    outputDirectory = 'None'

                convertString = lcBake.Bake.convertLightmap(
                    currentBakeSet, currentCamera, outputDirectory, shadows)

                sys.stdout.write('Convert Command: {0}'.format(convertString))

                pm.deleteUI('bakeWindow')

                pm.select(sel, replace=True)
            else:
                pm.warning('Path not found: {0}'.format(outputDirectory))
                pm.setFocus(prefix + '_textField_texture_path')
Exemple #14
0
 def close_all_open_tools(cls, silent=True, *args, **kwargs):
     '''
     '''
     toolList = cls.buildPublishList(inline=False)
     for tool in toolList:
         toolName = tool[0]
         if pm.control(toolName, exists=True):
             pm.deleteUI(toolName)
     if not silent:
         cls.lc_print('Closing all tools', mode='warning')
Exemple #15
0
def getPanel():
    """Gets the main panel."""
    # make a unique id for the app widget based off of the panel id
    widget_id = "panel_%s" % CALLBACK_OWNER

    if pm.control(widget_id, query=1, exists=1):
        # Find the panel widget for later use.
        for widget in QtWidgets.QApplication.allWidgets():
            if widget.objectName() == widget_id:
                return widget
    return None
Exemple #16
0
    def bug_report_window(self):
        ''' '''
        windowName = 'bugWindow'

        w = 400
        h = 330

        if pm.control(windowName, exists=True):
            pm.deleteUI(windowName)

        bug_window = pm.window(windowName, t="Bug Report / Contact", widthHeight=[w, h], rtf=False, mnb=False,
                               mxb=False, s=False, toolbox=True)

        pm.columnLayout(w=w, cw=w, cal='center')
        wM = (w - 30)
        pm.rowColumnLayout(nc=3, cw=([1, 15], [2, wM], [3, 15]))
        pm.text(l='', w=15)

        pm.columnLayout(w=wM, cw=wM, cal='center')

        pm.text(l='Message or Bug:', w=wM, h=30, al='left', font='boldLabelFont')
        message_text = pm.scrollField(w=wM, wordWrap=True)

        pm.text(l='Email Address (Optional, if you want a reply):', w=wM, h=30, al='left', font='boldLabelFont')
        email_address = pm.textField(w=wM)

        pm.setParent('..')

        pm.text(l='', w=15)

        pm.setParent('..')

        pm.separator(style='none', h=12, w=wM)

        cwA = 10
        cwB = (w / 2) - (1.5 * cwA)
        pm.rowColumnLayout(nc=5, cw=([1, cwA], [2, cwB], [3, cwA], [4, cwB], [5, cwA]))
        pm.text(l='', w=cwA)
        pm.button('bug_send', l='Send', w=cwB, h=25, command=lambda *args: self.bug_report_send(windowName,
                                                                                                pm.textField(
                                                                                                    email_address,
                                                                                                    query=True,
                                                                                                    text=True),
                                                                                                pm.scrollField(
                                                                                                    message_text,
                                                                                                    query=True,
                                                                                                    text=True)))
        pm.text(l='', w=cwA)
        pm.button('bug_cancel', l='Cancel', w=cwB, h=25, command=lambda *args: pm.deleteUI(windowName))
        pm.text(l='', w=cwA)

        bug_window.show()
        pm.window(bug_window, edit=True, h=h, w=(w + 2))
def rtb_toggle_select_mode(*args, **kwargs):
    if pm.control(prefix + '_symbolButton_select_mode', exists=True):
        componentMode = pm.selectMode(query=True, component=True)
        if not componentMode:
            pm.selectMode(component=True)
            pm.symbolButton(prefix + '_symbolButton_select_mode',
                            edit=True,
                            image='selectByComponent.png')
        else:
            pm.selectMode(object=True)
            pm.symbolButton(prefix + '_symbolButton_select_mode',
                            edit=True,
                            image='selectByObject.png')
Exemple #18
0
def dockPanel(panel):
    """
    Put the widget to the Maya's dock.

    Args:
        panel: the widget to put
    """
    # Retrieve the panel name.
    panel_name = panel.objectName()

    # Create a Maya panel name.
    maya_panel_name = "maya_%s" % panel_name

    # Create a new Maya window.
    maya_window = pm.window()

    # Add a layout to the Maya window.
    maya_layout = pm.formLayout(parent=maya_window)

    # Reparent the panel under the Maya window layout.
    pm.control(panel_name, edit=True, parent=maya_layout)

    attachForm = [(panel_name, 'top', 1), (panel_name, 'left', 1),
                  (panel_name, 'bottom', 1), (panel_name, 'right', 1)]

    # Keep the panel sides aligned with the Maya window layout sides.
    pm.formLayout(maya_layout, edit=True, attachForm=attachForm)

    # Dock the Maya window into a new tab of Maya Channel Box dock area.
    pm.dockControl(maya_panel_name,
                   area="left",
                   content=maya_window,
                   label=PANEL_NAME)

    # Once Maya will have completed its UI update and be idle,
    # raise (with "r=True") the new dock tab to the top.
    maya.utils.executeDeferred("import maya.cmds as cmds\n"
                               "cmds.dockControl('%s', edit=True, r=True)" %
                               maya_panel_name)
Exemple #19
0
def createPanel():
    """Create the main panel."""
    widget_instance = getPanel()

    if widget_instance:
        panel_name = widget_instance.objectName()
        maya_panel_name = "maya_%s" % panel_name
        pm.control(maya_panel_name,
                   edit=True,
                   visible=(not widget_instance.isVisible()))
        return

    # parent the UI to the main maya window
    parent = getDialogParent()
    widget_instance = WalterWidget(parent)
    widget_instance.setParent(parent)

    widget_id = "panel_%s" % CALLBACK_OWNER
    # set its name - this means that it can also be found via the maya API
    widget_instance.setObjectName(widget_id)

    # Dock the panel into a new Maya panel in the active Maya window.
    dockPanel(widget_instance)
Exemple #20
0
    def update_unpack_files(cls,
                            scriptPath,
                            updatePath,
                            updateWindow='lct_update',
                            *args,
                            **kwargs):
        '''
            unpack zip files and copy to script path
        '''
        # settings
        global_cfg = lcConfiguration.GlobalSettingsDictionary(verbose=False)

        if pm.control(updateWindow, exists=True):
            pm.deleteUI(updateWindow)

        try:
            folderName = 'lct'
            fileDownload = urllib.urlretrieve(
                updatePath, os.path.join(scriptPath, 'lct_update.zip'))[0]

            # upgrade lct files
            if os.path.exists(os.path.join(
                    scriptPath, folderName)):  # if the original exists
                if os.path.exists(
                        os.path.join(scriptPath, folderName +
                                     '_backup')):  # if the backup exists
                    shutil.rmtree(
                        os.path.join(scriptPath, folderName +
                                     '_backup'))  # remove the backup
                # make a new backup
                os.renames(os.path.join(scriptPath, folderName),
                           os.path.join(scriptPath, folderName + '_backup'))

            # unzip new files
            with zipfile.ZipFile(fileDownload) as zf:
                zf.extractall(scriptPath)

            os.remove(fileDownload)

            global_cfg.set('g_first_launch', True)

            lcUtility.Utility.relaunch_all_open_tools()

            msg = 'Update Succeeded'
            log = "{}\n\n{}".format(lcUtility.SystemInfo().get_text(), msg)
            logger = lcUtility.LogManager('lct updated', log)
            logger.SendLog()

        except:
            lcUtility.Utility.lc_print_exception(message='Update Failed')
Exemple #21
0
def dockGui(GuiClass, name=None, replace=False):
    """Return a dockable ui of the given type.
    Possibly one that already exists if it exists and replace arg is false."""
    ctrlName = name + "WorkspaceControl"
    if not replace and pmc.control(name, q=True, ex=True):
        # in this case, just find the controls/windows - show and return
        showUi(name)
        showUi(ctrlName)

        return getChildWin(name)

    deleteUi(name)
    deleteUi(ctrlName)

    return makeNewDockGui(GuiClass, name=name)
def lcBake_convert_lightmap(bakeSetListDropdown, cameraListDropdown, *args,
                            **kwargs):
    ''' '''
    numItems = bakeSetListDropdown.getNumberOfItems()
    if numItems > 0:
        currentBakeSet = bakeSetListDropdown.getValue()
        if currentBakeSet:
            currentCamera = cameraListDropdown.getValue()
            outputDirectory = pm.textField(prefix + '_textField_texture_path',
                                           query=True,
                                           text=True)
            if os.path.exists(outputDirectory):
                shadows = pm.checkBox(prefix + '_checkBox_shadows',
                                      query=True,
                                      value=True)

                if pm.control('bakeWindow', exists=True):
                    pm.deleteUI('bakeWindow')
                bakeWindow = pm.window('bakeWindow',
                                       t='Batch Bake',
                                       widthHeight=[100, 100],
                                       rtf=True,
                                       mnb=False,
                                       mxb=False,
                                       s=False)
                pm.columnLayout()
                pm.text(l='')
                pm.text(l='')
                pm.text(l='          Bake In Progress          ')
                pm.text(l='                  ......        ')
                pm.text(l='')
                pm.text(l='')
                bakeWindow.show()
                pm.refresh()
                #pm.pause(seconds=10)

                convertString = bake.convertLightmap(currentBakeSet,
                                                     currentCamera,
                                                     outputDirectory, shadows)

                print('Convert Command: {0}'.format(convertString))

                pm.deleteUI('bakeWindow')

                pm.select(clear=True)
            else:
                pm.warning('Path not found: {0}'.format(outputDirectory))
Exemple #23
0
    def about(self, *args, **kwargs):
        ''' '''
        now = datetime.datetime.now()
        year = now.year
        release, version = lcUpdate.Update.update_get_current_version()
        aboutName = 'lct_about'

        w = 220
        h = 243

        if pm.control(aboutName, exists=True):
            pm.deleteUI(aboutName)

        aboutWindow = pm.window(aboutName, t="LEOCOV Toolbox - About", widthHeight=[w, h], rtf=False, mnb=False,
                                mxb=False, s=False, toolbox=True)

        pm.columnLayout(w=w, cw=w, cal='center')
        pm.text(l='', al='center', w=w)
        pm.text(l='LEOCOV Toolbox', al='center', w=w)
        pm.text(l='', al='center', w=w)
        pm.text(l='Release: {}'.format(release), al='center', w=w)
        pm.text(l='Version: {}'.format(version), al='center', w=w)
        pm.text(l='', al='center', w=w)
        pm.button(l='License', al='center', w=w,
                  command=lambda *args: webbrowser.open('http://lct.leocov.com/license', new=2))
        pm.button(l='Privacy Policy', al='center', w=w,
                  command=lambda *args: webbrowser.open('http://lct.leocov.com/privacy', new=2))
        pm.button(l='Release Notes', w=w,
                  command=lambda *args: webbrowser.open('http://lct.leocov.com/release_notes', new=2))
        pm.button(l='First Launch Window', al='center', w=w,
                  command=lambda *args: UI.lcToolbox_first_launch_window(force_show=True))

        pm.text(l='', al='center', w=w)
        pm.text(l='Leonardo Covarrubias - {} {}'.format("Copyright", year), al='center', w=w)
        pm.text(l='', al='center', w=w)

        pm.rowColumnLayout(nc=3, cw=([1, 60], [2, 100], [3, 60]))
        pm.text(l='', al='center', w=50)
        pm.button('about_close', l='Close', w=100, h=25, command=lambda *args: pm.deleteUI(aboutWindow))
        pm.text(l='', al='center', w=50)

        aboutWindow.show()
        pm.window(aboutWindow, edit=True, h=h, w=(w + 2))
    def initUI(self):
        if pm.control(self.WINDOW_NAME, query = True, exists = True): return

        self.window = pm.window(self.WINDOW_NAME, title = "Align Pivot", mxb = False, width = 300, height = 220)
        self.window.setWidthHeight([300,220])
        self.layout = pm.formLayout(nd=100)

        with pm.formLayout(nd = 100) as form:
            self.align_move = pm.checkBox(label = "Align Move Pivot", value = True)
            self.align_scale = pm.checkBox(label = "Align Scale Pivot", value = False)
            form.hDistribute()
            form.attachForm(str(self.align_move), "left", 10)
        self.fixbox = pm.checkBox(label = "Additional Fixing", value = False)
        self.align_button = pm.button(label = "Align", command = self.align)
        self.sep = pm.separator(style = "in")
        self.reset_move = pm.button(label = "Reset Move Pivot", command = self.resetMove)
        self.reset_scale = pm.button(label = "Reset Scale Pivot", command = self.resetScale)

        self.layout.vDistribute(1,1,1.5,0.5,1,1)
        self.layout.attachForm(str(self.fixbox), "left", 12)

        self.window.show()
Exemple #25
0
def uvmp_snapshot_execute(*args, **kwargs):
    '''
    takes the snapshot and opens it in photoshop, deletes the popup window if necessary
    '''

    texDim = [
        pm.intField(prefix + '_snapshot_width', q=True, v=True),
        pm.intField(prefix + '_snapshot_height', q=True, v=True)
    ]
    path = pm.workspace(q=True, rd=True)
    fileName = prefix + '_temp_uvsnapshot.tga'
    snapShotFile = os.path.join(path, fileName)
    lcTexture.TextureEditor().uvSnapshot(
        snapShotFile, texDim[0], texDim[1],
        bool(pm.menuItem(prefix + '_checkBox_antiAlias', q=True, cb=True)))

    if pm.menuItem(prefix + '_checkBox_openPS', q=True, cb=True):
        lcPath.Path.openImage(snapShotFile)
    else:
        lcUtility.Utility.lc_print(
            'Created UV Snapshot: {}'.format(snapShotFile))

    if pm.control(prefix + '_Snapshot', exists=True):
        pm.deleteUI(prefix + '_Snapshot')
Exemple #26
0
def get_active_camera():
    """
    Return the active camera.
    Thanks to Nohra Seif for the snippet!
    """
    # seems that $gMainPane contain the name of the main window pane layout holding the panels.
    main_pane = mel.eval('string $test = $gMainPane;')
    if main_pane != "":
        # get the layout's immediate children
        main_pane_ctrls = pymel.paneLayout(main_pane, q=True, childArray=True)
        for i in range(len(main_pane_ctrls)):
            # panel containing the specified control
            panel_name = pymel.getPanel(containing=main_pane_ctrls[i])
            if "" != panel_name:
                # Return the type of the specified panel.
                if ("modelPanel" == pymel.getPanel(typeOf=panel_name)):
                    # Return whether the control can actually be seen by the user, isObscured for invisible
                    if not (pymel.control(main_pane_ctrls[i], q=True, isObscured=True)):
                        model_editor = pymel.modelPanel(panel_name, q=True, modelEditor=True)
                        if model_editor:
                            # If this view is already active, let's continue to use it.
                            if pymel.modelEditor(model_editor, q=True, activeView=True):
                                # get the camera in the current modelPanel
                                return pymel.PyNode(pymel.modelPanel(model_editor, q=True, camera=True))
Exemple #27
0
 def disableRandParam(self, param):
     pm.control(param, edit=True, enable=False)
Exemple #28
0
 def enableRandParam(self, param):
     pm.control(param, edit=True, enable=True)
Exemple #29
0
    def __init__(self):

        if pm.window("Baker", ex=True):
            pm.deleteUI("Baker")
        win = pm.window("Baker", wh=(620, 580), tlb=True, t="redshift baker")
        pm.rowLayout(w=420, nc=2, cw=((1, 200), (2, 400)))

        pm.columnLayout(w=200)

        pm.text(label="material directory", w=200)
        self.mat_folder = pm.textField(tx=Default.material_dir, w=200)
        pm.text(label="output directory", w=200)
        self.out_folder = pm.textField(tx=Default.output_dir, w=200)
        pm.text(label="material name pattern")
        self.pattern = pm.textField(tx=Default.name_pattern, w=200)
        self.size = pm.intSliderGrp(cw3=[30, 50, 110],
                                    ct3=["left", "left", "lfet"],
                                    label="size",
                                    field=True,
                                    v=Default.size,
                                    max=8192)
        pm.button(label="import meshes", c=multiImport, w=200)
        pm.button(label="check names", c=checkNames, w=200)
        pm.button(label="create uv", w=200, c=applyUV)
        pm.button(label="render settings",
                  w=200,
                  c=lambda *args: preferences("redshiftOptions"))
        pm.button(label="AO shader settings",
                  w=200,
                  c=lambda *args: preferences("ao_texture", "ao_material"))
        pm.button(label="shadow shader settings",
                  w=200,
                  c=lambda *args: preferences("shadow_material"))
        pm.button(label="remove empty png", w=200, c=self.cleanEmptyFiles)
        self.format = pm.optionMenu(w=200)
        pm.menuItem(label='obj')
        pm.menuItem(label='fbx')
        pm.menuItem(label='dae')
        self.default_mat = pm.checkBox(label="default material for ID", v=True)
        self.auto_levels = pm.checkBox(label="auto levels for shadows",
                                       v=False)
        self.ignore_exist = pm.checkBox(label="ignore existence", v=True)
        self.shadow = pm.checkBox(label="bake shadows", v=True)
        self.ao = pm.checkBox(label="bake ambient occlusion", v=True)

        pm.button(label="bake id", w=200, c=self.renderID)
        pm.button(label="bake mesh", w=200, c=self.renderMesh)
        pm.button(label="bake AO and shadow", w=200, c=self.renderAO)
        pm.button(label="create material", w=200, c=self.renderMaterial)

        pm.text(l="materials", w=200)
        for color in Default.materials:
            pm.button(label=color,
                      w=200,
                      c=functools.partial(applyMaterial, color))

        pm.setParent(u=True)

        column = pm.columnLayout(w=400)
        self.progress = pm.progressBar(w=400)
        self.out_field = QTextEdit()
        self.out_field.setFixedSize(400, 500)
        self.out_field.setObjectName("baker_out")
        pm.control("baker_out", e=True, p=column)
        self.settings()
        win.show()
def dock_panel(engine, shotgun_panel, title):
   

    # Retrieve the Shotgun app panel name.
    shotgun_panel_name = shotgun_panel.objectName()

    # Create a Maya panel name.
    maya_panel_name = MAYA_PANEL_PREFIX + shotgun_panel_name

    # Use the proper Maya panel docking method according to the Maya version.
    if mel.eval("getApplicationVersionAsFloat()") < 2017:

        import pymel.core as pm

        # When the Maya panel already exists, it can be deleted safely since its embedded
        # Shotgun app panel has already been reparented under Maya main window.
        if pm.control(maya_panel_name, query=True, exists=True):
            engine.logger.debug("Deleting existing Maya panel %s.", maya_panel_name)
            pm.deleteUI(maya_panel_name)

        # Create a new Maya window.
        maya_window = pm.window()
        engine.logger.debug("Created Maya window %s.", maya_window)

        # Add a layout to the Maya window.
        maya_layout = pm.formLayout(parent=maya_window)
        engine.logger.debug("Created Maya layout %s.", maya_layout)

        # Reparent the Shotgun app panel under the Maya window layout.
        engine.logger.debug(
            "Reparenting Shotgun app panel %s under Maya layout %s.",
            shotgun_panel_name,
            maya_layout,
        )
        pm.control(shotgun_panel_name, edit=True, parent=maya_layout)

        # Keep the Shotgun app panel sides aligned with the Maya window layout sides.
        pm.formLayout(
            maya_layout,
            edit=True,
            attachForm=[
                (shotgun_panel_name, "top", 1),
                (shotgun_panel_name, "left", 1),
                (shotgun_panel_name, "bottom", 1),
                (shotgun_panel_name, "right", 1),
            ],
        )

        # Dock the Maya window into a new tab of Maya Channel Box dock area.
        engine.logger.debug("Creating Maya panel %s.", maya_panel_name)
        pm.dockControl(maya_panel_name, area="right", content=maya_window, label=title)

        # Since Maya does not give us any hints when a panel is being closed,
        # install an event filter on Maya dock control to monitor its close event
        # in order to gracefully close and delete the Shotgun app panel widget.
        # Some obscure issues relating to UI refresh are also resolved by the event filter.
        panel_util.install_event_filter_by_name(maya_panel_name, shotgun_panel_name)

        # Once Maya will have completed its UI update and be idle,
        # raise (with "r=True") the new dock tab to the top.
        maya.utils.executeDeferred(
            "import maya.cmds as cmds\n"
            "cmds.dockControl('%s', edit=True, r=True)" % maya_panel_name
        )

    else:  # Maya 2017 and later

        import uuid

        # When the current Maya workspace contains our Maya panel workspace control,
        # embed the Shotgun app panel into this workspace control.
        # This can happen when the engine has just been started and the Shotgun app panel is
        # displayed for the first time around, or when the user reinvokes a displayed panel.
        if cmds.workspaceControl(maya_panel_name, exists=True):

            engine.logger.debug("Restoring Maya workspace panel %s.", maya_panel_name)

            # Set the Maya default parent to be our Maya panel workspace control.
            cmds.setParent(maya_panel_name)

            # Embed the Shotgun app panel into the Maya panel workspace control.
            build_workspace_control_ui(shotgun_panel_name)

            if cmds.control(maya_panel_name, query=True, isObscured=True):
                # When the panel is not visible, raise it to the top of its workspace area.
                engine.logger.debug("Raising workspace panel %s.", maya_panel_name)
                cmds.workspaceControl(maya_panel_name, edit=True, r=True)
            else:
                # When the panel is visible, use a workaround to force Maya 2017 to refresh the panel size.
                # We encased this workaround in a try/except since we cannot be sure
                # that it will still work without errors in future versions of Maya.
                try:
                    engine.logger.debug(
                        "Forcing Maya to refresh workspace panel %s size.",
                        maya_panel_name,
                    )

                    # Create a new empty workspace control tab.
                    name = cmds.workspaceControl(
                        uuid.uuid4().hex,
                        tabToControl=(maya_panel_name, -1),  # -1 to append a new tab
                        uiScript="",
                        r=True,
                    )  # raise at the top of its workspace area
                    # Delete the empty workspace control.
                    cmds.deleteUI(name)
                    # Delete the empty workspace control state that was created
                    # when deleting the empty workspace control.
                    cmds.workspaceControlState(name, remove=True)
                except:
                    engine.logger.debug(
                        "Cannot force Maya to refresh workspace panel %s size.",
                        maya_panel_name,
                    )

            return maya_panel_name

        # Retrieve the Channel Box dock area, with error reporting turned off.
        # This MEL function is declared in Maya startup script file UIComponents.mel.
        # It returns an empty string when a dock area cannot be found, but Maya will
        # retrieve the Channel Box dock area even when it is not shown in the current workspace.
        dock_area = mel.eval(
            'getUIComponentDockControl("Channel Box / Layer Editor", false)'
        )
        engine.logger.debug("Retrieved Maya dock area %s.", dock_area)

        # This UI script will be called to build the UI of the new dock tab.
        # It will embed the Shotgun app panel into a Maya workspace control.
        # Since Maya 2017 expects this script to be passed in as a string,
        # not as a function pointer, it must retrieve the current module in order
        # to call function build_workspace_control_ui() that actually builds the UI.
        # Note that this script will be saved automatically with the workspace control state
        # in the Maya layout preference file when the user quits Maya, and will be executed
        # automatically when Maya is restarted later by the user.
        ui_script = (
            "import sys\n"
            "import maya.api.OpenMaya\n"
            "import maya.utils\n"
            "for m in sys.modules:\n"
            "    if 'tk_maya.panel_generation' in m:\n"
            "        try:\n"
            "            sys.modules[m].build_workspace_control_ui('%(panel_name)s')\n"
            "        except Exception, e:\n"
            "            msg = 'Shotgun: Cannot restore %(panel_name)s: %%s' %% e\n"
            "            fct = maya.api.OpenMaya.MGlobal.displayError\n"
            "            maya.utils.executeInMainThreadWithResult(fct, msg)\n"
            "        break\n"
            "else:\n"
            "    msg = 'Shotgun: Cannot restore %(panel_name)s: Shotgun is not currently running'\n"
            "    fct = maya.api.OpenMaya.MGlobal.displayError\n"
            "    maya.utils.executeInMainThreadWithResult(fct, msg)\n"
            % {"panel_name": shotgun_panel_name}
        )

        # Dock the Shotgun app panel into a new workspace control in the active Maya workspace.
        engine.logger.debug("Creating Maya workspace panel %s.", maya_panel_name)

        kwargs = {
            "uiScript": ui_script,
            "retain": False,  # delete the dock tab when it is closed
            "label": title,
            "r": True,
        }  # raise at the top of its workspace area

        # When we are in a Maya workspace where the Channel Box dock area can be found,
        # dock the Shotgun app panel into a new tab of this Channel Box dock area
        # since the user was used to this behaviour in previous versions of Maya.
        # When we are in a Maya workspace where the Channel Box dock area can not be found,
        # let Maya embed the Shotgun app panel into a floating workspace control window.
        kwargs["tabToControl"] = (dock_area, -1)  # -1 to append a new tab

        cmds.workspaceControl(maya_panel_name, **kwargs)

    return maya_panel_name
Exemple #31
0
    def show_panel(self, panel_id, title, bundle, widget_class, *args,
                   **kwargs):
        """
        Docks an app widget in a maya panel.

        :param panel_id: Unique identifier for the panel, as obtained by register_panel().
        :param title: The title of the panel
        :param bundle: The app, engine or framework object that is associated with this window
        :param widget_class: The class of the UI to be constructed. This must derive from QWidget.

        Additional parameters specified will be passed through to the widget_class constructor.

        :returns: the created widget_class instance
        """
        from tank.platform.qt import QtCore, QtGui

        tk_maya = self.import_module("tk_maya")

        self.logger.debug("Begin showing panel %s", panel_id)

        # The general approach below is as follows:
        #
        # 1. First create our qt tk app widget using QT.
        #    parent it to the Maya main window to give it
        #    a well established parent. If the widget already
        #    exists, don't create it again, just retrieve its
        #    handle.
        #
        # 2. Now dock our QT control in a new panel tab of
        #    Maya Channel Box dock area. We use the
        #    Qt object name property to do the bind.
        #
        # 3. Lastly, since our widgets won't get notified about
        #    when the parent dock is closed (and sometimes when it
        #    needs redrawing), attach some QT event watchers to it
        #
        # Note: It is possible that the close event and some of the
        #       refresh doesn't propagate down to the widget because
        #       of a misaligned parenting: The tk widget exists inside
        #       the pane layout but is still parented to the main
        #       Maya window. It's possible that by setting up the parenting
        #       explicitly, the missing signals we have to compensate for
        #       may start to work. I tried a bunch of stuff but couldn't get
        #       it to work and instead resorted to the event watcher setup.

        # make a unique id for the app widget based off of the panel id
        widget_id = tk_maya.panel_generation.SHOTGUN_APP_PANEL_PREFIX + panel_id

        if pm.control(widget_id, query=1, exists=1):
            self.logger.debug("Reparent existing toolkit widget %s.",
                              widget_id)
            # Find the Shotgun app panel widget for later use.
            for widget in QtGui.QApplication.allWidgets():
                if widget.objectName() == widget_id:
                    widget_instance = widget
                    # Reparent the Shotgun app panel widget under Maya main window
                    # to prevent it from being deleted with the existing Maya panel.
                    self.logger.debug(
                        "Reparenting widget %s under Maya main window.",
                        widget_id)
                    parent = self._get_dialog_parent()
                    widget_instance.setParent(parent)
                    # The Shotgun app panel was retrieved from under an existing Maya panel.
                    break
        else:
            self.logger.debug("Create toolkit widget %s", widget_id)
            # parent the UI to the main maya window
            parent = self._get_dialog_parent()
            widget_instance = widget_class(*args, **kwargs)
            widget_instance.setParent(parent)
            # set its name - this means that it can also be found via the maya API
            widget_instance.setObjectName(widget_id)
            self.logger.debug("Created widget %s: %s", widget_id,
                              widget_instance)
            # apply external stylesheet
            self._apply_external_styleshet(bundle, widget_instance)
            # The Shotgun app panel was just created.

        # Dock the Shotgun app panel into a new Maya panel in the active Maya window.
        maya_panel_name = tk_maya.panel_generation.dock_panel(
            self, widget_instance, title)

        # Add the new panel to the dictionary of Maya panels that have been created by the engine.
        # The panel entry has a Maya panel name key and an app widget instance value.
        # Note that the panel entry will not be removed from the dictionary when the panel is
        # later deleted since the added complexity of updating the dictionary from our panel
        # close callback is outweighed by the limited length of the dictionary that will never
        # be longer than the number of apps configured to be runnable by the engine.
        self._maya_panel_dict[maya_panel_name] = widget_instance

        return widget_instance
Exemple #32
0
        # Loop through the list of opened Tank dialogs.
        for dialog in opened_dialog_list:
            dialog_window_title = dialog.windowTitle()
            try:
                # Close the dialog and let its close callback remove it from the original dialog list.
                self.logger.debug("Closing dialog %s.", dialog_window_title)
                dialog.close()
            except Exception, exception:
                self.logger.error("Cannot close dialog %s: %s",
                                  dialog_window_title, exception)

        # Loop through the dictionary of Maya panels that have been created by the engine.
        for (maya_panel_name,
             widget_instance) in self._maya_panel_dict.iteritems():
            # Make sure the Maya panel is still opened.
            if pm.control(maya_panel_name, query=True, exists=True):
                try:
                    # Reparent the Shotgun app panel widget under Maya main window
                    # to prevent it from being deleted with the existing Maya panel.
                    self.logger.debug(
                        "Reparenting widget %s under Maya main window.",
                        widget_instance.objectName())
                    parent = self._get_dialog_parent()
                    widget_instance.setParent(parent)
                    # The Maya panel can now be deleted safely.
                    self.logger.debug("Deleting Maya panel %s.",
                                      maya_panel_name)
                    pm.deleteUI(maya_panel_name)
                except Exception, exception:
                    self.logger.error("Cannot delete Maya panel %s: %s",
                                      maya_panel_name, exception)
Exemple #33
0
    def show_panel(self, panel_id, title, bundle, widget_class, *args, **kwargs):
        """
        Docks an app widget in a maya panel.

        :param panel_id: Unique identifier for the panel, as obtained by register_panel().
        :param title: The title of the panel
        :param bundle: The app, engine or framework object that is associated with this window
        :param widget_class: The class of the UI to be constructed. This must derive from QWidget.

        Additional parameters specified will be passed through to the widget_class constructor.

        :returns: the created widget_class instance
        """
        from tank.platform.qt import QtCore, QtGui

        tk_maya = self.import_module("tk_maya")

        self.log_debug("Begin showing panel %s" % panel_id)

        # The general approach below is as follows:
        #
        # 1. First create our qt tk app widget using QT.
        #    parent it to the maya main window to give it
        #    a well established parent. If the widget already
        #    exists, don't create it again, just retrieve its
        #    handle
        #
        # 2. Now create a native maya window and layout and
        #    attach our QT control to this. For this, we use
        #    the QT objectname property to do the bind. Note that
        #    the window won't show in the UI, this is all just
        #    setting up the hiearchy.
        #
        # 3. If a panel already exists, delete it. The panel
        #    no longer has the tk widget inside it, since that is
        #    parented to the window that was just created
        #
        # 4. Create a new panel using the dockControl command and
        #    pass our maya window in as the object to dock.
        #
        # 5. Lastly, since our widgets won't get notified about
        #    when the parent dock is closed (and sometimes when it
        #    needs redrawing), attach some QT event watchers to it
        #
        #
        # Note: It is possible that the close event and some of the
        #       refresh doesn't propagate down to the widget because
        #       of a misaligned parenting: The tk widget exists inside
        #       the pane layout but is still parented to the main
        #       maya window. It's possible that by setting up the parenting
        #       explicitly, the missing signals we have to compensate for
        #       may start to work. I tried a bunch of stuff but couldn't get
        #       it to work and instead resorted to the event watcher setup.

        # make a unique id for the app widget based off of the panel id
        widget_id = "wdgt_%s" % panel_id

        # create a maya window and layout
        window = pm.window()
        self.log_debug("Created window: %s" % window)
        maya_layout = pm.formLayout(parent=window)
        self.log_debug("Created layout %s" % maya_layout)

        if pm.control(widget_id, query=1, exists=1):
            self.log_debug("Toolkit widget already exists. Reparenting it...")
            # find the widget for later use
            for widget in QtGui.QApplication.allWidgets():
                if widget.objectName() == widget_id:
                    widget_instance = widget
                    break

        else:
            self.log_debug("Toolkit widget does not exist - creating it...")
            # parent the UI to the main maya window
            parent = self._get_dialog_parent()
            widget_instance = widget_class(*args, **kwargs)
            widget_instance.setParent(parent)
            # set its name - this means that it can also be found via the maya API
            widget_instance.setObjectName(widget_id)
            self.log_debug("Created %s (Object Name '%s')" % (widget_instance, widget_id))
            # apply external stylesheet
            self._apply_external_styleshet(bundle, widget_instance)

        # now reparent the widget instance to the layout
        # we can now refer to the QT widget via the widget name
        self.log_debug("Parenting widget %s to temporary window %s..." % (widget_id, maya_layout))
        pm.control(widget_id, edit=True, parent=maya_layout)

        # now attach our widget in all four corners to the maya layout so that it fills
        # the entire panel space
        pm.formLayout(maya_layout,
                      edit=True,
                      attachForm=[(widget_id, 'top', 1),
                                  (widget_id, 'left', 1),
                                  (widget_id, 'bottom', 1),
                                  (widget_id, 'right', 1)] )

        if pm.control(panel_id, query=1, exists=1):
            # exists already - delete it
            self.log_debug("Panel exists. Deleting it.")
            pm.deleteUI(panel_id)

        # lastly, move the maya window into a dock
        pm.dockControl(panel_id, area="right", content=window, label=title)
        self.log_debug("Created panel %s" % panel_id)

        # Once Maya will have completed its UI update and be idle,
        # raise (with "r=True") the docked panel window to the top dock tab.
        maya.utils.executeDeferred("cmds.dockControl('%s', edit=True, r=True)" % panel_id)

        # just like nuke, maya doesn't give us any hints when a panel is being closed.
        # QT widgets contained within this panel are just unparented and the floating
        # around, taking up memory.
        #
        # the visibleChangeCommand callback offered by the dockControl command
        # doesn't seem to work
        #
        # instead, install a QT event watcher to track when the parent
        # is closed and make sure that the tk widget payload is closed and
        # deallocated at the same time.
        #
        # Also, there are some obscure issues relating to UI refresh. These are also
        # resolved by looking at the stream of event and force triggering refreshes at the
        # right locations
        #
        tk_maya.install_callbacks(panel_id, widget_id)

        return widget_instance
Exemple #34
0
def dock_panel(engine, shotgun_panel, title, new_panel):
    """
    Docks a Shotgun app panel into a new Maya panel in the active Maya window.

    In Maya 2016 and before, the panel is docked into a new tab of Maya Channel Box dock area.
    In Maya 2017 and after, the panel is docked into a new workspace area in the active Maya workspace.

    :param engine: :class:`MayaEngine` instance running in Maya.
    :param shotgun_panel: Qt widget at the root of the Shotgun app panel.
                          This Qt widget is assumed to be child of Maya main window.
                          Its name can be used in standard Maya commands to reparent it under a Maya panel.
    :param title: Title to give to the new dock tab.
    :param new_panel: True when the Shotgun app panel was just created by the calling function.
                      False when the Shotgun app panel was retrieved from under an existing Maya panel.
    :returns: Name of the newly created Maya panel.
    """

    # The imports are done here rather than at the module level to avoid spurious imports
    # when this module is reloaded in the context of a workspace control UI script.
    import maya.mel as mel

    # Retrieve the Shotgun app panel name.
    shotgun_panel_name = shotgun_panel.objectName()

    # Use the proper Maya panel docking method according to the Maya version.
    if mel.eval("getApplicationVersionAsFloat()") < 2017:

        import maya.utils
        import pymel.core as pm

        # Create a Maya panel name.
        maya_panel_name = "maya_%s" % shotgun_panel_name

        # When the Maya panel already exists, it can be deleted safely since its embedded
        # Shotgun app panel has already been reparented under Maya main window.
        if pm.control(maya_panel_name, query=True, exists=True):
            engine.log_debug("Deleting existing Maya panel %s." % maya_panel_name)
            pm.deleteUI(maya_panel_name)

        # Create a new Maya window.
        maya_window = pm.window()
        engine.log_debug("Created Maya window %s." % maya_window)

        # Add a layout to the Maya window.
        maya_layout = pm.formLayout(parent=maya_window)
        engine.log_debug("Created Maya layout %s." % maya_layout)

        # Reparent the Shotgun app panel under the Maya window layout.
        engine.log_debug("Reparenting Shotgun app panel %s under Maya layout %s." % (shotgun_panel_name, maya_layout))
        pm.control(shotgun_panel_name, edit=True, parent=maya_layout)

        # Keep the Shotgun app panel sides aligned with the Maya window layout sides.
        pm.formLayout(maya_layout,
                      edit=True,
                      attachForm=[(shotgun_panel_name, 'top', 1),
                                  (shotgun_panel_name, 'left', 1),
                                  (shotgun_panel_name, 'bottom', 1),
                                  (shotgun_panel_name, 'right', 1)]
        )

        # Dock the Maya window into a new tab of Maya Channel Box dock area.
        engine.log_debug("Creating Maya panel %s." % maya_panel_name)
        pm.dockControl(maya_panel_name, area="right", content=maya_window, label=title)

        # Since Maya does not give us any hints when a panel is being closed,
        # install an event filter on Maya dock control to monitor its close event
        # in order to gracefully close and delete the Shotgun app panel widget.
        # Some obscure issues relating to UI refresh are also resolved by the event filter.
        panel_util.install_event_filter_by_name(maya_panel_name, shotgun_panel_name)

        # Once Maya will have completed its UI update and be idle,
        # raise (with "r=True") the new dock tab to the top.
        maya.utils.executeDeferred("import maya.cmds as cmds\n" \
                                   "cmds.dockControl('%s', edit=True, r=True)" % maya_panel_name)

    else:  # Maya 2017 and later

        import maya.cmds as cmds

        # Create a Maya panel name.
        maya_panel_name = "maya_%s" % shotgun_panel_name

        # When the current Maya workspace contains our Maya panel workspace control,
        # embed the Shotgun app panel into this workspace control.
        # This can happen when the engine has just been started and the Shotgun app panel is
        # displayed for the first time around, or when the user reinvokes a displayed panel.
        if cmds.workspaceControl(maya_panel_name, exists=True) and \
           cmds.workspaceControl(maya_panel_name, query=True, visible=True):

            engine.log_debug("Restoring Maya workspace panel %s." % maya_panel_name)

            # Set the Maya default parent to be our Maya panel workspace control.
            cmds.setParent(maya_panel_name)

            # Embed the Shotgun app panel into the Maya panel workspace control.
            build_workspace_control_ui(shotgun_panel_name)

            return maya_panel_name

        # Retrieve the Channel Box dock area, with error reporting turned off.
        # This MEL function is declared in Maya startup script file UIComponents.mel.
        # It returns an empty string when a dock area cannot be found, but Maya will
        # retrieve the Channel Box dock area even when it is not shown in the current workspace.
        dock_area = mel.eval('getUIComponentDockControl("Channel Box / Layer Editor", false)')
        engine.log_debug("Retrieved Maya dock area %s." % dock_area)

        # This UI script will be called to build the UI of the new dock tab.
        # It will embed the Shotgun app panel into a Maya workspace control.
        # Since Maya 2017 expects this script to be passed in as a string,
        # not as a function pointer, it must retrieve the current module in order
        # to call function build_workspace_control_ui() that actually builds the UI.
        # Note that this script will be saved automatically with the workspace control state
        # in the Maya layout preference file when the user quits Maya, and will be executed
        # automatically when Maya is restarted later by the user.
        ui_script = "import sys\n" \
                    "import maya.api.OpenMaya\n" \
                    "import maya.utils\n" \
                    "for m in sys.modules:\n" \
                    "    if 'tk_maya.panel_generation' in m:\n" \
                    "        try:\n" \
                    "            sys.modules[m].build_workspace_control_ui('%(panel_name)s')\n" \
                    "        except Exception, e:\n" \
                    "            msg = 'Shotgun: Cannot restore %(panel_name)s: %%s' %% e\n" \
                    "            fct = maya.api.OpenMaya.MGlobal.displayError\n" \
                    "            maya.utils.executeInMainThreadWithResult(fct, msg)\n" \
                    "        break\n" \
                    "else:\n" \
                    "    msg = 'Shotgun: Cannot restore %(panel_name)s: Shotgun is not currently running'\n" \
                    "    fct = maya.api.OpenMaya.MGlobal.displayError\n" \
                    "    maya.utils.executeInMainThreadWithResult(fct, msg)\n" \
                    % {"panel_name": shotgun_panel_name}

        # Dock the Shotgun app panel into a new workspace control in the active Maya workspace.
        engine.log_debug("Creating Maya workspace panel %s." % maya_panel_name)

        kwargs = {"uiScript": ui_script,
                  "retain": False,  # delete the dock tab when it is closed
                  "label": title,
                  "r": True}  # raise at the top of its workspace area

        # When we are in a Maya workspace where the Channel Box dock area can be found,
        # dock the Shotgun app panel into a new tab of this Channel Box dock area
        # since the user was used to this behaviour in previous versions of Maya.
        # When we are in a Maya workspace where the Channel Box dock area can not be found,
        # let Maya embed the Shotgun app panel into a floating workspace control window.
        kwargs["tabToControl"] = (dock_area, -1)  # -1 to append a new tab

        cmds.workspaceControl(maya_panel_name, **kwargs)

    return maya_panel_name
Exemple #35
0
def dock_panel(engine, panel_id, widget_instance, title):
    """
    Docks a Shotgun app panel widget in a new panel tab of Maya Channel Box dock area.

    :param engine: :class:`MayaEngine` instance running in Maya.
    :param panel_id: Unique string identifier for the Shotgun app panel.
    :param widget_instance: Qt widget at the root of the Shotgun app panel.
                            This Qt widget is assumed to be child of Maya main window.
                            Its name can be used in standard Maya commands to reparent it under a Maya panel.
    :param title: Title to give to the new dock tab.
    """

    # The imports are done here rather than at the module level to avoid spurious imports
    # when this module is reloaded in the context of a workspace control UI script.
    import maya.mel as mel
    import maya.utils
    import pymel.core as pm

    # Retrieve the unique string identifier naming the Qt widget.
    widget_id = widget_instance.objectName()

    # Create the Maya panel name.
    maya_panel_id = "panel_%s" % panel_id

    # When the Maya panel already exists, it can be deleted safely since its embedded
    # Shotgun app panel widget has already been reparented under Maya main window.
    if pm.control(maya_panel_id, query=True, exists=True):
        engine.log_debug("Deleting existing Maya panel %s." % maya_panel_id)
        pm.deleteUI(maya_panel_id)

    # Use the proper Maya panel docking method according to the Maya version.
    if mel.eval("getApplicationVersionAsFloat()") < 2017:

        # Create a new Maya window.
        maya_window = pm.window()
        engine.log_debug("Created Maya window %s." % maya_window)

        # Add a layout to the Maya window.
        maya_layout = pm.formLayout(parent=maya_window)
        engine.log_debug("Created Maya layout %s." % maya_layout)

        # Reparent the Shotgun app panel widget under the Maya window layout.
        engine.log_debug("Reparenting Shotgun app panel widget %s under Maya layout %s." % (widget_id, maya_layout))
        pm.control(widget_id, edit=True, parent=maya_layout)

        # Keep the Shotgun app panel widget sides aligned with the Maya window layout sides.
        pm.formLayout(maya_layout,
                      edit=True,
                      attachForm=[(widget_id, 'top', 1),
                                  (widget_id, 'left', 1),
                                  (widget_id, 'bottom', 1),
                                  (widget_id, 'right', 1)]
        )

        # Dock the Maya window into a new tab of Maya Channel Box dock area.
        engine.log_debug("Creating Maya panel %s." % maya_panel_id)
        pm.dockControl(maya_panel_id, area="right", content=maya_window, label=title)

        # Once Maya will have completed its UI update and be idle,
        # raise (with "r=True") the new dock tab to the top.
        maya.utils.executeDeferred("cmds.dockControl('%s', edit=True, r=True)" % maya_panel_id)

    else:  # Maya 2017 and later

        # Delete any default workspace control state that might have been automatically
        # created by Maya when a previously existing Maya panel was closed and deleted.
        if pm.workspaceControlState(maya_panel_id, exists=True):
            engine.log_debug("Deleting existing Maya workspace panel state %s." % maya_panel_id)
            pm.workspaceControlState(maya_panel_id, remove=True)

        # Retrieve the Channel Box dock area, with error reporting turned off.
        # This MEL function is declared in Maya startup script file UIComponents.mel.
        # It returns an empty string when this dock area cannot be found in the active Maya workspace.
        dock_area = mel.eval('getUIComponentDockControl("Channel Box / Layer Editor", false)')
        engine.log_debug("Retrieved Maya dock area %s." % dock_area)

        # This UI script will be called to build the UI of the new dock tab.
        # It will embed the Shotgun app panel widget into a Maya workspace control.
        # Maya 2017 expects this script to be passed in as a string, not as a function pointer.
        # See function _build_workspace_control_ui() below for a commented version of this script.
        ui_script = "import pymel.core as pm\n" \
                    "workspace_control = pm.setParent(query=True)\n" \
                    "pm.control('%s', edit=True, parent=workspace_control)" \
                    % widget_id

        # The following UI script can be used for development and debugging purposes.
        # This script has to retrieve and import the current source file in order to call
        # function _build_workspace_control_ui() below to build the workspace control UI.
        # ui_script = "import imp\n" \
        #             "panel_generation = imp.load_source('%s', '%s')\n" \
        #             "panel_generation._build_workspace_control_ui('%s')" \
        #             % (__name__, __file__.replace(".pyc", ".py"), widget_id)

        # Give an initial width to the docked Shotgun app panel widget when first shown.
        # Otherwise, the workspace control would use the width of the currently displayed tab.
        size_hint = widget_instance.sizeHint()
        if size_hint.isValid():
            # Use the widget layout preferred size.
            widget_width = size_hint.width()
        else:
            # Since no size is recommended for the widget, use its current width.
            widget_width = widget_instance.width()
        engine.log_debug("Widget %s width: %s" % (widget_id, widget_width))

        # Dock the Shotgun app panel widget into a new tab of the Channel Box dock area.
        # When this dock area was not found in the active Maya workspace,
        # the Shotgun app panel widget is embedded into a floating workspace control window.
        # This floating workspace control can then be docked into an existing dock area by the user.
        engine.log_debug("Creating Maya workspace panel %s." % maya_panel_id)
        dock_tab = pm.workspaceControl(maya_panel_id,
                                       tabToControl=(dock_area, -1),  # -1 to append a new tab
                                       uiScript=ui_script,
                                       loadImmediately=True,
                                       retain=False,  # delete the dock tab when it is closed
                                       label=title,
                                       initialWidth=widget_width,
                                       minimumWidth=True,  # set the minimum width to the initial width
                                       r=True  # raise the new dock tab to the top
                   )

        # Now that the workspace dock tab has been created, let's update its UI script.
        # This updated script will be saved automatically with the workspace control state
        # in the Maya layout preference file when the user will choose to quit Maya,
        # and will be executed automatically when Maya is restarted later by the user.

        # The script will delete the empty workspace dock tab that Maya will recreate on startup
        # when the user previously chose to quit Maya while the panel was opened.
        deferred_script = "import maya.cmds as cmds\\n" \
                          "if cmds.workspaceControl('%(id)s', exists=True):\\n" \
                          "    cmds.deleteUI('%(id)s')" \
                          % {"id": maya_panel_id}

        # The previous script will need to be executed once Maya has completed its UI update and be idle.
        ui_script = "import maya.utils\n" \
                    "maya.utils.executeDeferred(\"%s\")\n" \
                    % deferred_script

        # Update the workspace dock tab UI script.
        pm.workspaceControl(maya_panel_id, edit=True, uiScript=ui_script)
Exemple #36
0
def delete_ui(name):
    if pm.control(name, exists=True):
        pm.deleteUI(name, ctl=1)
Exemple #37
0
def lcObj_offsetMultiple(mode='select', files=None, offset=[0,0,0], *args, **kwargs):
    '''
    select multiple external .obj files and offset them in worldspace
    '''
    # Select ###########################
    if mode=='select':
        path = pm.textField(prefix+'_textField_export_path', query=True, text=True)
        filter = "Wavefront Obj (*.obj)"
        files = pm.fileDialog2(ds=1, caption="Choose one or more Obj's to offset", dir=path, fileFilter=filter, fileMode=4)
        if files:
            lcObj_offsetMultiple(mode='window', files=files)
        else:
            lcUtility.Utility.lc_print("You didn't select anything . . .")

    # Window ###########################
    windowName = 'lcObj_offset_window'

    if mode=='window':
        if pm.control(windowName, exists = True):
            pm.deleteUI(windowName)

        w=200
        h=85
        offsetWindow = pm.window(windowName, t="lcObjTools - Obj Offset", widthHeight=[w+2,h], rtf=False, mnb=False, mxb=False, s=False, toolbox=True)
        pm.columnLayout()
        pm.text(l='Enter Obj Offset', w=w, h=25, al='center', font='boldLabelFont')
        a=(w/3)*0.2
        b=(w/3)-a
        pm.rowColumnLayout(nc=6, cw=([1,a], [2,b], [3,a], [4,b], [5,a], [6,b]) )
        pm.text(l='X', w=a, al='center', font='boldLabelFont')
        pm.floatField('o_x', w=b, v=0.0)
        pm.text(l='Y', w=a, al='center', font='boldLabelFont')
        pm.floatField('o_y', w=b, v=0.0)
        pm.text(l='Z', w=a, al='center', font='boldLabelFont')
        pm.floatField('o_z', w=b, v=0.0)
        pm.setParent('..')
        pm.separator(style='none', h=5)
        b=100
        a=(w-b)/2
        pm.rowColumnLayout(nc=3, cw=([1,a], [2,b], [3,a]) )
        pm.text(l='')
        pm.button(l='Offset', w=b, command=lambda *args: lcObj_offsetMultiple(mode='execute', files=files, offset=[pm.floatField('o_x',q=True,v=True), pm.floatField('o_y',q=True,v=True), pm.floatField('o_z',q=True,v=True)]) )
        pm.text(l='')

        offsetWindow.show()
        pm.window(offsetWindow, edit=True, wh=[w+2,h])

    # Execute ###########################
    if mode=='execute':
        i = 1
        for f in files:
            fileName, fileExtension = os.path.splitext(f)
            outputFile = '{}_Offset{}'.format(fileName, fileExtension)
            obj = lcGeometry.Obj(f, True, '[{} of {}]'.format(i, len(files)) )
            obj.edit_verts(offset)
            obj.write(outputFile)
            obj.flush()

            i=i+1
        if pm.control(windowName, exists = True):
            pm.deleteUI(windowName)
Exemple #38
0
        opened_dialog_list = self.created_qt_dialogs[:]

        # Loop through the list of opened Tank dialogs.
        for dialog in opened_dialog_list:
            dialog_window_title = dialog.windowTitle()
            try:
                # Close the dialog and let its close callback remove it from the original dialog list.
                self.logger.debug("Closing dialog %s.", dialog_window_title)
                dialog.close()
            except Exception, exception:
                self.logger.error("Cannot close dialog %s: %s", dialog_window_title, exception)

        # Loop through the dictionary of Maya panels that have been created by the engine.
        for (maya_panel_name, widget_instance) in self._maya_panel_dict.iteritems():
            # Make sure the Maya panel is still opened.
            if pm.control(maya_panel_name, query=True, exists=True):
                try:
                    # Reparent the Shotgun app panel widget under Maya main window
                    # to prevent it from being deleted with the existing Maya panel.
                    self.logger.debug("Reparenting widget %s under Maya main window.",
                                   widget_instance.objectName())
                    parent = self._get_dialog_parent()
                    widget_instance.setParent(parent)
                    # The Maya panel can now be deleted safely.
                    self.logger.debug("Deleting Maya panel %s.", maya_panel_name)
                    pm.deleteUI(maya_panel_name)
                except Exception, exception:
                    self.logger.error("Cannot delete Maya panel %s: %s", maya_panel_name, exception)

        # Clear the dictionary of Maya panels now that they were deleted.
        self._maya_panel_dict = {}
Exemple #39
0
 def show_panel(self, panel_id, title, bundle, widget_class, *args, **kwargs):
     """
     Docks an app widget in a maya panel. 
     
     :param panel_id: Unique identifier for the panel, as obtained by register_panel().
     :param title: The title of the panel
     :param bundle: The app, engine or framework object that is associated with this window
     :param widget_class: The class of the UI to be constructed. This must derive from QWidget.
     
     Additional parameters specified will be passed through to the widget_class constructor.
     """
     from tank.platform.qt import QtCore, QtGui
     
     tk_maya = self.import_module("tk_maya")
     
     self.log_debug("Begin showing panel %s" % panel_id)                                    
     
     # The general approach below is as follows:
     #
     # 1. First create our qt tk app widget using QT.
     #    parent it to the maya main window to give it
     #    a well established parent. If the widget already
     #    exists, don't create it again, just retrieve its 
     #    handle
     #
     # 2. Now create a native maya window and layout and 
     #    attach our QT control to this. For this, we use
     #    the QT objectname property to do the bind. Note that
     #    the window won't show in the UI, this is all just 
     #    setting up the hiearchy.
     #    
     # 3. If a panel already exists, delete it. The panel 
     #    no longer has the tk widget inside it, since that is
     #    parented to the window that was just created
     #
     # 4. Create a new panel using the dockControl command and
     #    pass our maya window in as the object to dock.
     #
     # 5. Lastly, since our widgets won't get notified about 
     #    when the parent dock is closed (and sometimes when it
     #    needs redrawing), attach some QT event watchers to it
     #
     #
     # Note: It is possible that the close event and some of the 
     #       refresh doesn't propagate down to the widget because
     #       of a misaligned parenting: The tk widget exists inside
     #       the pane layout but is still parented to the main 
     #       maya window. It's possible that by setting up the parenting
     #       explicitly, the missing signals we have to compensate for 
     #       may start to work. I tried a bunch of stuff but couldn't get
     #       it to work and instead resorted to the event watcher setup. 
     
     # make a unique id for the app widget based off of the panel id
     widget_id = "wdgt_%s" % panel_id  
     
     # create a maya window and layout
     window = pm.window()
     self.log_debug("Created window: %s" % window)
     maya_layout = pm.formLayout(parent=window)
     self.log_debug("Created layout %s" % maya_layout)
     
     if pm.control(widget_id, query=1, exists=1):
         self.log_debug("Toolkit widget already exists. Reparenting it...")
         # find the widget for later use
         for widget in QtGui.QApplication.allWidgets():
             if widget.objectName() == widget_id:
                 widget_instance = widget
                 break
         
     else:
         self.log_debug("Toolkit widget does not exist - creating it...")
         # parent the UI to the main maya window
         parent = self._get_dialog_parent()            
         widget_instance = widget_class(*args, **kwargs)
         widget_instance.setParent(parent)
         # set its name - this means that it can also be found via the maya API
         widget_instance.setObjectName(widget_id)
         self.log_debug("Created %s (Object Name '%s')" % (widget_instance, widget_id))
         # apply external stylesheet
         self._apply_external_styleshet(bundle, widget_instance)
                   
     
     # now reparent the widget instance to the layout
     # we can now refer to the QT widget via the widget name
     self.log_debug("Parenting widget %s to temporary window %s..." % (widget_id, maya_layout))
     pm.control(widget_id, edit=True, parent=maya_layout)
     
     # now attach our widget in all four corners to the maya layout so that it fills 
     # the entire panel space
     pm.formLayout(maya_layout, 
                   edit=True, 
                   attachForm=[(widget_id, 'top', 1), 
                               (widget_id, 'left', 1), 
                               (widget_id, 'bottom', 1), 
                               (widget_id, 'right', 1)] )
     
     if pm.control(panel_id, query=1, exists=1):
         # exists already - delete it
         self.log_debug("Panel exists. Deleting it.")
         pm.deleteUI(panel_id)
                 
     # lastly, move the maya window into a dock
     pm.dockControl(panel_id, area="right", content=window, label=title)
     self.log_debug("Created panel %s" % panel_id)
 
     # just like nuke, maya doesn't give us any hints when a panel is being closed.
     # QT widgets contained within this panel are just unparented and the floating
     # around, taking up memory.
     #
     # the visibleChangeCommand callback offered by the dockControl command
     # doesn't seem to work
     #
     # instead, install a QT event watcher to track when the parent
     # is closed and make sure that the tk widget payload is closed and
     # deallocated at the same time.
     #
     # Also, there are some obscure issues relating to UI refresh. These are also
     # resolved by looking at the stream of event and force triggering refreshes at the 
     # right locations
     #  
     tk_maya.install_callbacks(panel_id, widget_id)
Exemple #40
0
    def show_panel(self, panel_id, title, bundle, widget_class, *args, **kwargs):
        """
        Docks an app widget in a maya panel.

        :param panel_id: Unique identifier for the panel, as obtained by register_panel().
        :param title: The title of the panel
        :param bundle: The app, engine or framework object that is associated with this window
        :param widget_class: The class of the UI to be constructed. This must derive from QWidget.

        Additional parameters specified will be passed through to the widget_class constructor.

        :returns: the created widget_class instance
        """
        from tank.platform.qt import QtCore, QtGui

        tk_maya = self.import_module("tk_maya")

        self.logger.debug("Begin showing panel %s", panel_id)

        # The general approach below is as follows:
        #
        # 1. First create our qt tk app widget using QT.
        #    parent it to the Maya main window to give it
        #    a well established parent. If the widget already
        #    exists, don't create it again, just retrieve its
        #    handle.
        #
        # 2. Now dock our QT control in a new panel tab of
        #    Maya Channel Box dock area. We use the
        #    Qt object name property to do the bind.
        #
        # 3. Lastly, since our widgets won't get notified about
        #    when the parent dock is closed (and sometimes when it
        #    needs redrawing), attach some QT event watchers to it
        #
        # Note: It is possible that the close event and some of the
        #       refresh doesn't propagate down to the widget because
        #       of a misaligned parenting: The tk widget exists inside
        #       the pane layout but is still parented to the main
        #       Maya window. It's possible that by setting up the parenting
        #       explicitly, the missing signals we have to compensate for
        #       may start to work. I tried a bunch of stuff but couldn't get
        #       it to work and instead resorted to the event watcher setup.

        # make a unique id for the app widget based off of the panel id
        widget_id = tk_maya.panel_generation.SHOTGUN_APP_PANEL_PREFIX + panel_id

        if pm.control(widget_id, query=1, exists=1):
            self.logger.debug("Reparent existing toolkit widget %s.", widget_id)
            # Find the Shotgun app panel widget for later use.
            for widget in QtGui.QApplication.allWidgets():
                if widget.objectName() == widget_id:
                    widget_instance = widget
                    # Reparent the Shotgun app panel widget under Maya main window
                    # to prevent it from being deleted with the existing Maya panel.
                    self.logger.debug("Reparenting widget %s under Maya main window.", widget_id)
                    parent = self._get_dialog_parent()
                    widget_instance.setParent(parent)
                    # The Shotgun app panel was retrieved from under an existing Maya panel.
                    break
        else:
            self.logger.debug("Create toolkit widget %s", widget_id)
            # parent the UI to the main maya window
            parent = self._get_dialog_parent()
            widget_instance = widget_class(*args, **kwargs)
            widget_instance.setParent(parent)
            # set its name - this means that it can also be found via the maya API
            widget_instance.setObjectName(widget_id)
            self.logger.debug("Created widget %s: %s", widget_id, widget_instance)
            # apply external stylesheet
            self._apply_external_styleshet(bundle, widget_instance)
            # The Shotgun app panel was just created.

        # Dock the Shotgun app panel into a new Maya panel in the active Maya window.
        maya_panel_name = tk_maya.panel_generation.dock_panel(self, widget_instance, title)

        # Add the new panel to the dictionary of Maya panels that have been created by the engine.
        # The panel entry has a Maya panel name key and an app widget instance value.
        # Note that the panel entry will not be removed from the dictionary when the panel is
        # later deleted since the added complexity of updating the dictionary from our panel
        # close callback is outweighed by the limited length of the dictionary that will never
        # be longer than the number of apps configured to be runnable by the engine.
        self._maya_panel_dict[maya_panel_name] = widget_instance

        return widget_instance