Untitled

 avatar
unknown
plain_text
3 years ago
43 kB
5
Indexable
"""
deformUI.py

Author: Ehsan Hassani Moghaddam

"""
# python modules
import os
import sys
import logging

# Qt modules
from PySide2 import QtCore, QtWidgets
from itertools import groupby

logger = logging.getLogger(__name__)

# maya modules
import maya.cmds as mc
import maya.mel as mel

# iRig modules
from iRig.iRig_maya.lib import deformLib
from iRig.iRig_maya.lib import qtLib
from iRig.iRig_maya.lib import fileLib
reload(deformLib)

# CONSTANTS
SETTINGS_PATH = os.path.join(os.getenv("HOME"), 'deformUI.uiconfig')
JOBS_DIR = os.getenv('JOBS_DIR', 'Y:')
SUPPORTED_DEFORMERS = [
    'blendShape',
    'deltaMush',
    'shrinkWrap',
    'cluster',
    'ffd',
    'nonLinear',
    'cvWrap'
]


class UI(QtWidgets.QDialog):
    def __init__(self, title='deform UI', parent=qtLib.getMayaWindow()):
        self.closed = False
        # create window
        super(UI, self).__init__(parent=parent)
        self.setWindowTitle(title)
        self.setBaseSize(500, 500)

        # data about this asset
        self.job = os.getenv('TT_PROJCODE', 'ZZZ')
        self.asset_type = os.getenv('TT_ASSTYPE', 'Character')
        self.asset_name = os.getenv('TT_ENTNAME', 'test_asset')
        self.user = os.getenv('USERNAME', '')

        self.skinclusterPath = ''
        self.deformerPath = ''

        # skin/geo name list
        column_names = ['Geo Name', 'SkinCluster Name']
        self.skin_list = QtWidgets.QTableWidget(self)
        self.skin_list.setAlternatingRowColors(True)
        self.skin_list.setColumnCount(2)
        self.skin_list.setHorizontalHeaderLabels(column_names)
        self.skin_list.setAlternatingRowColors(True)
        self.skin_list.setColumnWidth(0, 263)
        self.skin_list.setColumnWidth(1, 265)

        # Stretch columns
        headers = self.skin_list.horizontalHeader()
        headers.setSectionResizeMode(QtWidgets.QHeaderView.Stretch)

        # Set no focus when selecting rows
        self.skin_list.setFocusPolicy(QtCore.Qt.NoFocus)

        # main layout - This part controls both tabs
        self.setLayout(QtWidgets.QVBoxLayout())
        self.layout().setContentsMargins(5, 5, 5, 5)
        self.layout().setSpacing(100)
        self.layout().setAlignment(QtCore.Qt.AlignTop)

        # tab frame (this will hold tabs inside it)
        self.mainTab = QtWidgets.QTabWidget()
        self.layout().addWidget(self.mainTab)

        # skincluster self.tab
        skincluster_tab = QtWidgets.QWidget(self.mainTab)
        self.mainTab.addTab(skincluster_tab, "SkinCluster")
        skincluster_tab_hl = QtWidgets.QHBoxLayout()
        skincluster_tab.setLayout(skincluster_tab_hl)
        skincluster_tab_hl.setContentsMargins(2, 2, 2, 2)

        # other deformers tab
        deformers_tab = QtWidgets.QWidget(self.mainTab)
        self.mainTab.addTab(deformers_tab, "Deformers")
        self.deformers_tab_hl = QtWidgets.QHBoxLayout()
        deformers_tab.setLayout(self.deformers_tab_hl)
        self.deformers_tab_hl.setContentsMargins(2, 2, 2, 2)

        # ======================================================================
        # populate skincluster tab
        expImp_gb, expImp_frame = qtLib.createGroupBox(skincluster_tab_hl, '')
        expImp_vb = qtLib.createHLayout(expImp_frame)

        expImp_lay = QtWidgets.QVBoxLayout()
        expImp_vb.layout().addLayout(expImp_lay)
        expImp_lay.layout().setContentsMargins(2, 2, 2, 2)
        expImp_lay.layout().setSpacing(5)
        expImp_lay.layout().setAlignment(QtCore.Qt.AlignCenter)

        path_lay = QtWidgets.QHBoxLayout()
        expImp_lay.layout().addLayout(path_lay)

        stay_lay = QtWidgets.QHBoxLayout()
        expImp_lay.layout().addLayout(stay_lay)
        stay_lay.layout().setAlignment(QtCore.Qt.AlignBottom)
        stay_label = QtWidgets.QLabel('Maintain Path From:')

        self.desktop_btn = QtWidgets.QRadioButton('Desktop')

        self.current_btn = QtWidgets.QRadioButton('Asset')
        #self.selected_btn.setChecked(True)

        self.genman_btn = QtWidgets.QRadioButton('Genman')

        stay_lay.layout().addWidget(stay_label)
        stay_lay.layout().addWidget(self.desktop_btn)
        stay_lay.layout().addWidget(self.current_btn)
        stay_lay.layout().addWidget(self.genman_btn)


        self.getPathToDesktop_btn = QtWidgets.QPushButton('Get Path to Desktop')
        path_lay.addWidget(self.getPathToDesktop_btn)
        self.getPathToDesktop_btn.clicked.connect(self.getPathToDesktop)

        self.getPathToCurrentAsset_btn = QtWidgets.QPushButton('Get Path To Current Asset')
        path_lay.addWidget(self.getPathToCurrentAsset_btn)
        self.getPathToCurrentAsset_btn.clicked.connect(self.getPathToCurrentAsset)

        self.getPathToLatestGenman_btn = QtWidgets.QPushButton('Get Path To Latest GenMan')
        path_lay.addWidget(self.getPathToLatestGenman_btn)
        self.getPathToLatestGenman_btn.clicked.connect(self.getPathToLatestGenman)

        self.skinclusterPath_le, skinclusterBrowse_bt = qtLib.createBrowseField(
            expImp_lay,
            label='Path:',
            labelWidth=50
        )

        # connect browse button to line edit
        skinclusterBrowse_bt.clicked.connect(lambda: qtLib.getExistingDir(
            self, self.skinclusterPath_le, self.skinclusterPath))

        # ======================================================================

        # add export / import buttons
        expImp_hl = QtWidgets.QHBoxLayout()
        expImp_lay.layout().addLayout(expImp_hl)
        expImp_hl.layout().setAlignment(QtCore.Qt.AlignBottom)

        # tab frame (this will hold tabs inside it)
        self.skinTab = QtWidgets.QTabWidget()
        expImp_hl.layout().addWidget(self.skinTab)

        # export tab
        export_skin_tab = QtWidgets.QWidget(self.skinTab)
        self.skinTab.addTab(export_skin_tab, "Export")
        self.export_skin_tab_hl = QtWidgets.QHBoxLayout()
        export_skin_tab.setLayout(self.export_skin_tab_hl)
        self.export_skin_tab_hl.setContentsMargins(2, 2, 2, 2)

        # import tab
        import_skin_tab = QtWidgets.QWidget(self.skinTab)
        self.skinTab.addTab(import_skin_tab, "Import")
        self.import_skin_tab_hl = QtWidgets.QHBoxLayout()
        import_skin_tab.setLayout(self.import_skin_tab_hl)
        self.import_skin_tab_hl.setContentsMargins(2, 2, 2, 2)

        top_btn_lay = QtWidgets.QHBoxLayout()
        expImp_lay.layout().addLayout(top_btn_lay)

        self.skinTab.currentChanged.connect(self.changeSkinMode)

        # launch the 2nd tab
        self.otherDeformUI()

        # restore UI settings
        self.mainTab.currentChanged.connect(self.changeMainTab)
        self.restoreUI()

        # grab all skins in scene
        self.allMode()
        self.changeMainTab()

    def changeMainTab(self):
        if self.mainTab.currentIndex() == 0:
            self.changeSkinMode()

        elif self.mainTab.currentIndex() == 1:
            self.changeDeformMode()

    def changeSkinMode(self):
        # if not in skincluster tab, don't do anything
        if self.mainTab.currentIndex() != 0:
            return

        # if in skincluster/export tab
        if self.skinTab.currentIndex() == 0:
            self.populateSkin(self.export_skin_tab_hl)
            self.loadSkinsFromScene()

        # if in skincluster/import tab
        elif self.skinTab.currentIndex() == 1:
            self.populateSkin(self.import_skin_tab_hl)
            self.loadSkinNodes()

    def changeDeformMode(self):
        # if not in deform tab, don't do anything
        if self.mainTab.currentIndex() != 1:
            return

        # if in deformer/export tab
        if self.deformTab.currentIndex() == 0:
            self.populateDeformer(self.export_tab_hl)
            self.loadDeformersFromScene()

        # if in deformer/import tab
        elif self.deformTab.currentIndex() == 1:
            self.populateDeformer(self.import_tab_hl)
            self.loadDeformersFromPath()

    def populateSkin(self, tab):
        self.clearLayout(tab)
        # populate export tab
        expImp_gb, expImp_frame = qtLib.createGroupBox(tab, '')
        expImp_vb = qtLib.createHLayout(expImp_frame)

        expImp_lay = QtWidgets.QVBoxLayout()
        expImp_vb.layout().addLayout(expImp_lay)
        expImp_lay.layout().setContentsMargins(2, 2, 2, 2)
        expImp_lay.layout().setSpacing(5)
        expImp_lay.layout().setAlignment(QtCore.Qt.AlignCenter)

        top_btn_lay = QtWidgets.QHBoxLayout()
        expImp_lay.layout().addLayout(top_btn_lay)

        self.refresh_btn = QtWidgets.QPushButton('Refresh List')
        top_btn_lay.layout().addWidget(self.refresh_btn)

        skin_rename_btn = QtWidgets.QPushButton('Fix Skin Names')
        top_btn_lay.layout().addWidget(skin_rename_btn)
        skin_rename_btn.clicked.connect(self.skinRename)

        self.loadSkinsFromScene()

        # add skin export list
        expImp_lay.layout().addWidget(self.skin_list)

        # add skin selection mode
        mode_lay = QtWidgets.QHBoxLayout()
        expImp_lay.layout().addLayout(mode_lay)
        mode_lay.layout().setAlignment(QtCore.Qt.AlignBottom)
        mode_label = QtWidgets.QLabel('Mode:')

        self.all_btn = QtWidgets.QRadioButton('All')

        self.selected_btn = QtWidgets.QRadioButton('Selected UI')
        self.selected_btn.setChecked(True)

        self.selected_scene_btn = QtWidgets.QRadioButton('Selected Scene')

        mode_lay.layout().addWidget(mode_label)
        mode_lay.layout().addWidget(self.all_btn)
        mode_lay.layout().addWidget(self.selected_btn)
        mode_lay.layout().addWidget(self.selected_scene_btn)

        expImp_btn_lay = QtWidgets.QHBoxLayout()
        expImp_lay.layout().addLayout(expImp_btn_lay)
        self.exp_skin_btn = QtWidgets.QPushButton('Export')
        self.imp_skin_btn = QtWidgets.QPushButton('Import')

        self.all_btn.clicked.connect(self.allMode)
        self.selected_btn.clicked.connect(self.selectedMode)
        self.selected_scene_btn.clicked.connect(self.selectedSceneMode)

        if self.skinTab.currentIndex() == 0:
            expImp_btn_lay.layout().addWidget(self.exp_skin_btn)
            self.exp_skin_btn.clicked.connect(self.exportSkin)
            self.refresh_btn.clicked.connect(self.loadSkinsFromScene)

            self.disable_export_button(
                self.skinclusterPath_le,
                self.exp_skin_btn)

        elif self.skinTab.currentIndex() == 1:
            expImp_btn_lay.layout().addWidget(self.imp_skin_btn)
            self.imp_skin_btn.clicked.connect(self.importSkin)
            self.refresh_btn.clicked.connect(self.loadSkinNodes)

        # do not allow export directly to G:/Rigging/Rigging_Assets/GenMan...
        self.skinclusterPath_le.textChanged.connect(
            lambda: self.disable_export_button(
                self.skinclusterPath_le,
                self.exp_skin_btn
            )
        )

    def otherDeformUI(self):
        """This function populates the 2nd tab with all the deformer export/import related content."""

        # create a frame inside the tab
        deformer_expImp_gb, deformer_expImp_frame = qtLib.createGroupBox(self.deformers_tab_hl, '')
        deformer_expImp_vb = qtLib.createHLayout(deformer_expImp_frame)

        deformer_expImp_lay = QtWidgets.QVBoxLayout()
        deformer_expImp_vb.layout().addLayout(deformer_expImp_lay)
        deformer_expImp_lay.layout().setContentsMargins(2, 2, 2, 2)
        deformer_expImp_lay.layout().setSpacing(5)
        deformer_expImp_lay.layout().setAlignment(QtCore.Qt.AlignCenter)

        deformer_top_btn_lay = QtWidgets.QHBoxLayout()
        deformer_expImp_lay.layout().addLayout(deformer_top_btn_lay)

        path_lay = QtWidgets.QHBoxLayout()
        deformer_expImp_lay.layout().addLayout(path_lay)

        stay_lay = QtWidgets.QHBoxLayout()
        deformer_expImp_lay.layout().addLayout(stay_lay)
        stay_lay.layout().setAlignment(QtCore.Qt.AlignBottom)
        stay_label = QtWidgets.QLabel('Maintain Path From:')

        self.deformer_desktop_btn = QtWidgets.QRadioButton('Desktop')

        self.deformer_current_btn = QtWidgets.QRadioButton('Asset')
        #self.selected_btn.setChecked(True)

        self.deformer_genman_btn = QtWidgets.QRadioButton('Genman')

        stay_lay.layout().addWidget(stay_label)
        stay_lay.layout().addWidget(self.deformer_desktop_btn)
        stay_lay.layout().addWidget(self.deformer_current_btn)
        stay_lay.layout().addWidget(self.deformer_genman_btn)

        # create 3 buttons: Get Path to Desktop, Get Path to Current Asset, Get Path to GenMan Files
        # 1st button: Get Path to Desktop
        self.deformer_getPathToDesktop_btn = QtWidgets.QPushButton('Get Path to Desktop')
        path_lay.addWidget(self.deformer_getPathToDesktop_btn)
        self.deformer_getPathToDesktop_btn.clicked.connect(self.getPathToDesktop)

        # 2nd button: Get Path to Current Asset
        self.deformer_getPathToCurrentAsset_btn = QtWidgets.QPushButton('Get Path To Current Asset')
        path_lay.addWidget(self.deformer_getPathToCurrentAsset_btn)
        self.deformer_getPathToCurrentAsset_btn.clicked.connect(self.getPathToCurrentAsset)

        # 3rd button: Get Path to Latest GenMan File
        self.deformer_getPathToLatestGenman_btn = QtWidgets.QPushButton('Get Path To Latest GenMan')
        path_lay.addWidget(self.deformer_getPathToLatestGenman_btn)
        self.deformer_getPathToLatestGenman_btn.clicked.connect(self.getPathToLatestGenman)

        # Add a check state to know which button is pressed
        self.deformerPath_le, deformerBrowse_bt = qtLib.createBrowseField(
            deformer_expImp_lay,
            label='Path:',
            txt='path to weights directory',
            labelWidth=50
        )

        # add export / import buttons
        expImp_hl = QtWidgets.QHBoxLayout()
        deformer_expImp_lay.layout().addLayout(expImp_hl)
        expImp_hl.layout().setAlignment(QtCore.Qt.AlignBottom)

        # tab frame (this will hold tabs inside it)
        self.deformTab = QtWidgets.QTabWidget()
        expImp_hl.layout().addWidget(self.deformTab)

        # export tab
        export_tab = QtWidgets.QWidget(self.deformTab)
        self.deformTab.addTab(export_tab, "Export")
        self.export_tab_hl = QtWidgets.QHBoxLayout()
        export_tab.setLayout(self.export_tab_hl)
        self.export_tab_hl.setContentsMargins(2, 2, 2, 2)

        # import tab
        import_tab = QtWidgets.QWidget(self.deformTab)
        self.deformTab.addTab(import_tab, "Import")
        self.import_tab_hl = QtWidgets.QHBoxLayout()
        import_tab.setLayout(self.import_tab_hl)
        self.import_tab_hl.setContentsMargins(2, 2, 2, 2)

        top_btn_lay = QtWidgets.QHBoxLayout()
        deformer_expImp_lay.layout().addLayout(top_btn_lay)

        self.changeDeformMode()
        self.deformTab.currentChanged.connect(self.changeDeformMode)

        # restore UI settings
        self.restoreUI()

        # grab all skins in scene
        self.allMode()

        deformerBrowse_bt.clicked.connect(
            lambda: qtLib.getExistingDir(
                self, self.deformerPath_le, self.deformerPath
            )
        )

        self.getPathToDesktop()

    def populateDeformer(self, tab):
        self.clearLayout(tab)
        # populate export tab
        expImp_gb, expImp_frame = qtLib.createGroupBox(tab, '')
        expImp_vb = qtLib.createHLayout(expImp_frame)

        expImp_lay = QtWidgets.QVBoxLayout()
        expImp_vb.layout().addLayout(expImp_lay)
        expImp_lay.layout().setContentsMargins(2, 2, 2, 2)
        expImp_lay.layout().setSpacing(5)
        expImp_lay.layout().setAlignment(QtCore.Qt.AlignCenter)

        top_btn_lay = QtWidgets.QHBoxLayout()
        expImp_lay.layout().addLayout(top_btn_lay)

        self.refresh_btn = QtWidgets.QPushButton('Refresh List')
        top_btn_lay.layout().addWidget(self.refresh_btn)

        # add skin export list
        self.column_names = ['Shape Name', 'Deformer Name']
        # add skin selection mode

        mode_label = QtWidgets.QLabel('Mode:')

        self.all_deformer_btn = QtWidgets.QRadioButton('All')

        self.selected_deformer_btn = QtWidgets.QRadioButton('Selected UI')
        self.selected_deformer_btn.setChecked(True)

        self.selected_scene_deformer_btn = QtWidgets.QRadioButton('Selected Scene')

        self.exp_deform_btn = QtWidgets.QPushButton('Export')
        self.imp_deform_btn = QtWidgets.QPushButton('Import')

        self.all_deformer_btn.clicked.connect(self.allDeformerMode)
        self.selected_deformer_btn.clicked.connect(self.selectedDefromerMode)
        self.selected_scene_deformer_btn.clicked.connect(self.selectedSceneMode)

        # export tab
        if self.deformTab.currentIndex() == 0:
            exp_column_names = ['Deformers']
            self.deformer_list = QtWidgets.QTableWidget(self)
            self.deformer_list.setAlternatingRowColors(True)
            self.deformer_list.setColumnCount(1)
            self.deformer_list.setHorizontalHeaderLabels(exp_column_names)
            self.deformer_list.setColumnWidth(0, 600)

            expHeaders = self.deformer_list.horizontalHeader()
            expHeaders.setSectionResizeMode(QtWidgets.QHeaderView.Stretch)

            # Set no focus when selecting rows
            self.deformer_list.setFocusPolicy(QtCore.Qt.NoFocus)

            expImp_lay.layout().addWidget(self.deformer_list)
            mode_lay = QtWidgets.QHBoxLayout()
            expImp_lay.layout().addLayout(mode_lay)
            mode_lay.layout().setAlignment(QtCore.Qt.AlignBottom)
            mode_lay.layout().addWidget(mode_label)
            mode_lay.layout().addWidget(self.all_deformer_btn)
            mode_lay.layout().addWidget(self.selected_deformer_btn)
            mode_lay.layout().addWidget(self.selected_scene_deformer_btn)
            expImp_btn_lay = QtWidgets.QHBoxLayout()
            expImp_lay.layout().addLayout(expImp_btn_lay)
            expImp_btn_lay.layout().addWidget(self.exp_deform_btn)

            self.refresh_btn.clicked.connect(self.loadDeformersFromScene)
            self.exp_deform_btn.clicked.connect(self.exportDeformer)

            self.disable_export_button(
                self.deformerPath_le,
                self.exp_deform_btn)

        # import tab
        elif self.deformTab.currentIndex() == 1:
            imp_column_names = ['Deformers']
            self.importDeformer_list = QtWidgets.QTableWidget(self)
            self.importDeformer_list.setAlternatingRowColors(True)
            self.importDeformer_list.setColumnCount(1)
            self.importDeformer_list.setHorizontalHeaderLabels(imp_column_names)
            self.importDeformer_list.setColumnWidth(0, 600)
            impHeaders = self.importDeformer_list.horizontalHeader()
            impHeaders.setSectionResizeMode(QtWidgets.QHeaderView.Stretch)

            # self.importDeformer_list.setMinimumWidth(180)
            # Set no focus when selecting rows
            self.importDeformer_list.setFocusPolicy(QtCore.Qt.NoFocus)
            expImp_lay.layout().addWidget(self.importDeformer_list)
            mode_lay = QtWidgets.QHBoxLayout()
            expImp_lay.layout().addLayout(mode_lay)
            mode_lay.layout().setAlignment(QtCore.Qt.AlignBottom)
            mode_lay.layout().addWidget(mode_label)
            mode_lay.layout().addWidget(self.all_deformer_btn)
            mode_lay.layout().addWidget(self.selected_deformer_btn)
            mode_lay.layout().addWidget(self.selected_scene_deformer_btn)
            expImp_btn_lay = QtWidgets.QHBoxLayout()
            expImp_lay.layout().addLayout(expImp_btn_lay)
            expImp_btn_lay.layout().addWidget(self.imp_deform_btn)

            self.refresh_btn.clicked.connect(self.loadDeformersFromPath)
            self.imp_deform_btn.clicked.connect(self.importDeformer)

        # do not allow export directly to G:/Rigging/Rigging_Assets/GenMan...
        self.deformerPath_le.textChanged.connect(
            lambda: self.disable_export_button(
                self.deformerPath_le,
                self.exp_deform_btn
            )
        )

    def clearLayout(self, layout):
        while layout.count():
            child = layout.takeAt(0)
            if child.widget():
                child.widget().deleteLater()

    def allMode(self):
        self.skin_list.setSelectionMode(QtWidgets.QAbstractItemView.ContiguousSelection)

    def allDeformerMode(self):
        self.deformer_list.setSelectionMode(QtWidgets.QAbstractItemView.ContiguousSelection)

    def selectedMode(self):
        self.skin_list.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)

    def selectedDefromerMode(self):
        self.deformer_list.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)

    def selectedSceneMode(self):
        self.skin_list.clearSelection()

    def selectedDeformerSceneMode(self):
        self.deformer_list.clearSelection()

    def skinRename(self):
        all_skins, skinned_geos = self.loadSkinsFromScene()
        for skin_name, geo_name in zip(all_skins, skinned_geos):
            mc.rename(skin_name, geo_name + '_Skn')
        self.loadSkinsFromScene()

    def loadSkinNodes(self):
        all_skins = []
        skinned_geos = []

        skin_path = self.skinclusterPath_le.text()

        if os.path.lexists(skin_path):
            for x in os.listdir(skin_path):
                if x.endswith('.json') or x.endswith('.wgt'):
                    skin_file = os.path.join(skin_path, x)
                    geo_skinned, skin_of_geos = self.importSkinData(skin_file)
                    all_skins.append(skin_of_geos)
                    skinned_geos.append(geo_skinned)

        skin_amount = len(all_skins)
        self.skin_list.setRowCount(skin_amount)
        self.skin_list.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.skin_list.verticalHeader().setVisible(False)

        for i, (skin_name, geo_name) in enumerate(zip(all_skins, skinned_geos)):
            skin_item = QtWidgets.QTableWidgetItem(skin_name)
            self.skin_list.setItem(i, 1, skin_item)
            skin_geo_item = QtWidgets.QTableWidgetItem(geo_name)
            self.skin_list.setItem(i, 0, skin_geo_item)

        self.skin_list.sortItems(0, QtCore.Qt.AscendingOrder)

    def importSkinData(self, filePath):
        if not os.path.lexists(filePath):
            return

        if filePath.endswith('.json'):
            skinData = fileLib.loadJson(filePath)

            # geting data
            geo = skinData['geometry']
            skin_name = skinData['skin_name']
        else:
            with open(filePath, 'r') as f:
                lines = [x for x in f]
                skinData = [list(group) for k,
                                            group in groupby(lines, lambda x: x == "\n")
                            if not k]
                # get geo
                geo = deformLib._lineToStr(skinData[0])
                # get skin
                skin_name = deformLib._lineToStr(skinData[1])

        return geo, skin_name

    def loadSkinsFromScene(self):
        skinned_geos = []
        all_skins = mc.ls(type='skinCluster')
        for skin in all_skins[:]:
            meshes = mc.skinCluster(skin, q=True, geometry=True)
            if not meshes:
                if skin in all_skins:
                    all_skins.remove(skin)
                continue
            mesh = meshes[0]
            if mc.nodeType(mesh) != 'mesh' and mc.nodeType(mesh) != 'nurbsSurface':
                if skin in all_skins:
                    all_skins.remove(skin)
                continue
            geo = mc.listRelatives(mesh, p=True)[0]
            skinned_geos.append(geo)

        skin_amount = len(all_skins)
        self.skin_list.setRowCount(skin_amount)
        self.skin_list.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.skin_list.verticalHeader().setVisible(False)

        for i, (skin_name, geo_name) in enumerate(zip(all_skins, skinned_geos)):
            skin_item = QtWidgets.QTableWidgetItem(skin_name)
            self.skin_list.setItem(i, 1, skin_item)
            skin_geo_item = QtWidgets.QTableWidgetItem(geo_name)
            self.skin_list.setItem(i, 0, skin_geo_item)

        return all_skins, skinned_geos

    def loadDeformersFromPath(self):
        deform_path = self.deformerPath_le.text()

        file_paths = []
        for root, directories, files in os.walk(deform_path):
            for filename in files:
                file_paths.append(filename)
        file_paths = [x.split('.json')[0] for x in file_paths if 'json' in x]

        deform_amount = len(file_paths)
        self.importDeformer_list.setRowCount(deform_amount)
        self.importDeformer_list.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.importDeformer_list.verticalHeader().setVisible(False)

        i = 0
        for node in file_paths:
            deformer_item = QtWidgets.QTableWidgetItem(node)
            self.importDeformer_list.setItem(i, 0, deformer_item)
            i += 1

        self.importDeformer_list.sortItems(0, QtCore.Qt.AscendingOrder)

    def importDeformerData(self, filePath):
        deform_geos = []
        deformer_of_path = []
        if not os.path.lexists(filePath):
            return

        deformer_node = os.path.splitext(os.path.basename(filePath))[0]

        deformer_data = fileLib.loadJson(path=filePath)
        for geo, weights in deformer_data.items():
            deform_geos.append(geo)
            deformer_of_path.append(weights)

        return deformer_node, deform_geos[0]

    def loadDeformersFromScene(self):
        """This function checks all the deformer sets in the scene and stores the
        shapes and the deformers in a dictionary called self.deformer_dict; Last
         it will call the self.displayAllDeformers() function to display the dict."""

        # to get all the shapes in the scene
        all_shapes = mc.ls(type=['mesh', 'nurbsSurface'])
        # create a dict and a list to collect all the deformers and the shapes
        deformerList = []
        for shape in all_shapes:
            transform = mc.listRelatives(shape, parent=True)[0]
            deformers = mc.findDeformers(transform, shape) or []
            deformers = [x for x in deformers if mc.nodeType(x) in SUPPORTED_DEFORMERS]
            deformerList.extend(deformers)

        deformerList = list(set(deformerList))
        deform_amount = len(deformerList)
        self.deformer_list.setRowCount(deform_amount)
        self.deformer_list.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.deformer_list.verticalHeader().setVisible(False)

        i = 0
        for node in deformerList:
            deformer_item = QtWidgets.QTableWidgetItem(node)
            self.deformer_list.setItem(i, 0, deformer_item)
            i += 1

        self.deformer_list.sortItems(0, QtCore.Qt.AscendingOrder)

    def getPathToCurrentAsset(self):
        task = os.getenv('TT_STEPCODE', 'rig')

        # Check if MAW Project because we source our skins from the hybrid script folder
        # This can be removed once MAW is finally over
        if self.job == 'MAW':
            build_folder = os.path.join(
                'hybrid_{}_script'.format(task),
                'build')
        else:
            build_folder = 'build'

        # find skin folder path
        skin_folder_path = os.path.join(
            JOBS_DIR,
            self.job,
            'assets',
            'type',
            self.asset_type,
            self.asset_name,
            'work',
            task,
            'Maya',
            self.user,
            build_folder,
            'data',
            'skincluster'
        )

        if not os.path.lexists(skin_folder_path):
            mc.warning('"{}" does not exist!'.format(skin_folder_path))

        if self.mainTab.currentIndex() == 0:
            self.skinclusterPath_le.setText(skin_folder_path)

        elif self.mainTab.currentIndex() == 1:
            skin_folder_path = skin_folder_path.replace('skincluster', 'deformer_weights')
            self.deformerPath_le.setText(skin_folder_path)

    def getPathToDesktop(self):
        home = os.getenv('USERPROFILE')
        if not home:
            home = os.path.dirname(os.getenv('Home'))
        desktopDir = os.path.join(home, 'Desktop')
        if sys.platform == 'win32' and not os.path.lexists(desktopDir):
            desktopDir = os.path.join(home, 'OneDrive', 'Desktop')

        if self.mainTab.currentIndex() == 0:
            self.skinclusterPath_le.setText(
                os.path.join(desktopDir, 'skincluster')
            )

        elif self.mainTab.currentIndex() == 1:
            self.deformerPath_le.setText(
                os.path.join(desktopDir, 'deformer_weights')
            )

        return desktopDir

    def getPathToLatestGenman(self):
        task = os.getenv('TT_STEPCODE', 'rig')

        # Current GenMan
        genMan = 'GenManB'

        # find GenMan skin folder path
        genman_folder_path = os.path.join(
            'G:\Rigging\Rigging_Assets',
            genMan,
            'Rig',
            'data',
            'skincluster'
        )

        if not os.path.lexists(genman_folder_path):
            mc.warning('"{}" does not exist! Check to see if the GenMan folders have changed position.'.format(genman_folder_path))

        if self.mainTab.currentIndex() == 0:
            self.skinclusterPath_le.setText(genman_folder_path)

        elif self.mainTab.currentIndex() == 1:
            genman_folder_path = genman_folder_path.replace('skincluster', 'deformer_weights')
            self.deformerPath_le.setText(genman_folder_path)

    def exportSkin(self):
        if self.all_btn.isChecked():
            skin_amount = self.skin_list.rowCount()
            skin_range = range(skin_amount)
            skins_to_export = []
            for num in skin_range:
                skins_to_export.append(self.skin_list.item(num, 0).text())
            mc.select(cl=True)
            for skin in skins_to_export:
                mc.select(skin, add=True)

            mc.select(skins_to_export)

        elif self.selected_btn.isChecked():
            skins_to_export = [self.skin_list.item(item.row(), 0).text() for item in
                               self.skin_list.selectionModel().selectedRows()]
            mc.select(skins_to_export)

        elif self.selected_scene_btn.isChecked():
            skins_to_export = mc.ls(sl=True)
            mc.select(skins_to_export)

        sel = mc.ls(sl=True)
        if not sel:
            logger.error('Please select a mesh transform node from the list or scene or change Mode!')
            return

        skinclusterPath = self.skinclusterPath_le.text()
        deformLib.exportSkin(mc.ls(sl=True), skinclusterPath)

    def exportDeformer(self):
        deformer_to_export = []

        if self.all_deformer_btn.isChecked():
            deformer_amount = self.deformer_list.rowCount()
            deformer_range = range(deformer_amount)
            deformer_to_export = []
            for num in deformer_range:
                deformer_to_export.append(self.deformer_list.item(num, 0).text())

        elif self.selected_deformer_btn.isChecked():
            deformer_to_export = [
                self.deformer_list.item(item.row(), 0).text()
                for item in self.deformer_list.selectionModel().selectedRows()
            ]

            # remove any deformers selected more than once
            deformer_to_export = list(dict.fromkeys(deformer_to_export))

        elif self.selected_scene_deformer_btn.isChecked():
            sel_nodes = mc.ls(sl=True)
            if sel_nodes:
                for sel in sel_nodes:
                    geos = mc.listRelatives(sel, shapes=True)
                    for geo in geos:  # Go through all shapes incase of cases like `*_GeoShapeDeformed` nodes
                        hist = mc.listHistory(geo, pdo=1, gl=1)
                        if not hist:
                            continue
                        for h in hist:
                            if mc.nodeType(h) not in SUPPORTED_DEFORMERS:
                                continue
                            deformer_to_export.append(h)
                        break  # Break out once a valid shape node found

        skinclusterPath = self.deformerPath_le.text()

        if not deformer_to_export:
            logger.error('Please select a mesh transform node from the list or scene or change Mode!')
            return
        # export every deformer in the scene
        for i in deformer_to_export:
            if mc.nodeType(i) == 'blendShape':
                continue
            j = i if ':' not in i else i.split(':')[1]
            deformLib.exportDeformerWgts(i, skinclusterPath + '/' + j + '.json')
            print 'Finished exporting the weight of ' + i

        for i in deformer_to_export:
            if mc.nodeType(i) != 'blendShape':
                continue
            j = i if ':' not in i else i.split(':')[1]
            deformLib.exportBlsWgts(i, skinclusterPath + '/' + j + '.json')
            print 'Finished exporting the weight of ' + i

    def importSkin(self):
        # This function runs all the importing of skinClusters for the DeformUI
        argument_node = []

        if self.all_btn.isChecked():
            skin_amount = self.skin_list.rowCount()
            skin_range = range(skin_amount)
            skins_to_export = []
            for num in skin_range:
                skins_to_export.append(self.skin_list.item(num, 0).text())
            argument_node = skins_to_export

        elif self.selected_btn.isChecked():
            # Selected UI Button
            # From the UI itself, this lists the selection within the UI
            # If nothing selected in the UI, nothing will be imported
            skins_to_import = [self.skin_list.item(item.row(), 0).text() for item in
                               self.skin_list.selectionModel().selectedRows()]
            argument_node = skins_to_import

        elif self.selected_scene_btn.isChecked():
            # Selected Scene
            # This selects only what the user has selected with the scene
            argument_node = (mc.ls(sl=True))

        if not argument_node:
            logger.error('Please select an item from the list or the scene!')
            return

        skinclusterPath = self.skinclusterPath_le.text()

        # Function that actually goes through the list and imports each skinCluster
        for obj in argument_node:
            deformLib.importSkin(skinclusterPath, obj)

    def importDeformer(self):
        deformerPath = self.deformerPath_le.text()
        deform_nodes = []
        if self.all_deformer_btn.isChecked():
            deformer_amount = self.importDeformer_list.rowCount()
            deformer_range = range(deformer_amount)
            deform_nodes = []
            for num in deformer_range:
                deform_nodes.append(self.importDeformer_list.item(num, 0).text())

        # import selected items in the UI
        elif self.selected_deformer_btn.isChecked():
            deform_nodes = [
                self.importDeformer_list.item(item.row(), 0).text()
                for item in self.importDeformer_list.selectionModel().selectedRows()
            ]

        # import selected items in Maya scene
        elif self.selected_scene_deformer_btn.isChecked():
            sel_nodes = mc.ls(sl=True)
            if sel_nodes:
                geos = mc.listRelatives(sel_nodes, shapes=True)
                for geo in geos:  # Go through all shapes incase of cases like `*_GeoShapeDeformed` nodes
                    hist = mc.listHistory(geo, pdo=1, gl=1)
                    if not hist:
                        continue
                    for h in hist:
                        if mc.nodeType(h) not in SUPPORTED_DEFORMERS:
                            continue
                        deform_nodes.append(h)
                    break  # Break out once a valid shape node found
                if not deform_nodes:
                    logger.error('Please make sure the Selected geo has deformer!')
                    return

        if not deform_nodes:
            logger.error('Please select a mesh transform node from the list or change Mode!')
            return

        for weight_file in os.listdir(deformerPath):

            for deform_node in deform_nodes:

                # this weight_file is not for this deform_node
                if deform_node not in weight_file:
                    continue

                # weight file
                filtered_weight = deformerPath + '/' + weight_file

                # try creating deformer if doesn't exist
                if not mc.objExists(deform_node):
                    deform_node = deformLib.create_deformer_from_json_data(filtered_weight)
                    if not deform_node:
                        logger.warning('Could not find or create deformer from path: {}'.format(filtered_weight))
                        continue

                # import blendShapes weights
                if mc.nodeType(deform_node) == 'blendShape':
                    deformLib.importBlsWgts(filtered_weight)

                # import all deformers weights except blendShapes
                else:
                    deformLib.importDeformerWgts(filtered_weight, deformer_name=deform_node)

                print 'Imported ' + filtered_weight


    def disable_export_button(self, le, btn):
        """
        This disables export button if user tries to export to G:/Rigging/Rigging_Assets/...
        """
        not_allowed_path = 'G:/Rigging/Rigging_Assets/Gen'
        given_path = le.text()
        given_path = given_path.replace('\\', '/')
        if given_path.startswith(not_allowed_path):
            btn.setEnabled(False)
            btn.setText("Can't export to Gen folder!")
        else:
            btn.setEnabled(True)
            btn.setText('Export')

    def closeEvent(self, *args, **kwargs):
        self.closed = True

        # settings path
        settings = QtCore.QSettings(SETTINGS_PATH, QtCore.QSettings.IniFormat)

        # window size and position
        settings.setValue("geometry", self.saveGeometry())

        # skincluster path
        settings.setValue("always", "None")
        settings.setValue("deformer_always", "None")

        if self.desktop_btn.isChecked():
            self.getPathToDesktop()
            settings.setValue("always", "Desktop")
        elif self.current_btn.isChecked():
            self.getPathToCurrentAsset()
            settings.setValue("always", "Asset")
        elif self.genman_btn.isChecked():
            self.getPathToLatestGenman()
            settings.setValue("always", "Genman")

        skinclusterPath = self.skinclusterPath_le.text()
        settings.setValue("skinclusterPath", skinclusterPath)

        # deformers path
        if self.deformer_desktop_btn.isChecked():
            self.getPathToDesktop()
            settings.setValue("deformer_always", "Desktop")
        elif self.deformer_current_btn.isChecked():
            self.getPathToCurrentAsset()
            settings.setValue("deformer_always", "Asset")
        elif self.deformer_genman_btn.isChecked():
            self.getPathToLatestGenman()
            settings.setValue("deformer_always", "Genman")

        deformerPath = self.deformerPath_le.text()
        settings.setValue("deformerPath", deformerPath)

    def restoreUI(self):
        """
        Restore UI size and position that if was last used
        :return: n/a
        """
        # self.closed = False
        if os.path.exists(SETTINGS_PATH):
            settings = QtCore.QSettings(SETTINGS_PATH, QtCore.QSettings.IniFormat)

            # window size and position
            self.restoreGeometry(settings.value("geometry"))

            # skinclusterPath
            self.skinclusterPath = settings.value("skinclusterPath")
            if not self.skinclusterPath:
                self.skinclusterPath = os.path.join(self.getPathToDesktop(), 'skincluster')
            self.skinclusterPath_le.setText(self.skinclusterPath)

            # deformerPath
            self.deformerPath = settings.value("deformerPath")
            if not self.deformerPath:
                self.deformerPath = os.path.join(self.getPathToDesktop(), 'deformer_weights')
            self.deformerPath_le.setText(self.deformerPath)


        if settings.value("always") == "Desktop":
            self.desktop_btn.setChecked(True)
        elif settings.value("always") == "Asset":
            self.current_btn.setChecked(True)
        elif settings.value("always") == "Genman":
            self.genman_btn.setChecked(True)

        if settings.value("deformer_always") == "Desktop":
            self.deformer_desktop_btn.setChecked(True)
        elif settings.value("deformer_always") == "Asset":
            self.deformer_current_btn.setChecked(True)
        elif settings.value("deformer_always") == "Genman":
            self.deformer_genman_btn.setChecked(True)


def launch():
    global deformUI_obj
    if 'deformUI_obj' in globals():
        if not deformUI_obj.closed:
            deformUI_obj.close()
        deformUI_obj.deleteLater()
        del globals()['deformUI_obj']
    deformUI_obj = UI()
    deformUI_obj.show()
Editor is loading...