Beispiel #1
0
class ui(MayaQWidgetDockableMixin, QtWidgets.QDialog):

    valueChanged = QtCore.Signal(int)

    def __init__(self, parent=None):
        super(ui, self).__init__(parent)

        self.filter = "Lips Rigger Configuration .lips (*.lips)"

        self.create()

    def create(self):

        self.setWindowTitle("Lips Rigger")
        self.setWindowFlags(QtCore.Qt.Window)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, 1)

        self.create_controls()
        self.create_layout()
        self.create_connections()

    def create_controls(self):

        # Geometry input controls
        self.geometryInput_group = QtWidgets.QGroupBox("Geometry Input")
        self.edgedge_loop_label = QtWidgets.QLabel("Edge Loop:")
        self.edge_loop = QtWidgets.QLineEdit()
        self.edge_loop_button = QtWidgets.QPushButton("<<")
        self.up_vertex_label = QtWidgets.QLabel("Upper Vertex:")
        self.up_vertex = QtWidgets.QLineEdit()
        self.up_vertex_button = QtWidgets.QPushButton("<<")
        self.low_vertex_label = QtWidgets.QLabel("Lower Vertex:")
        self.low_vertex = QtWidgets.QLineEdit()
        self.low_vertex_button = QtWidgets.QPushButton("<<")

        # Name prefix
        self.prefix_group = QtWidgets.QGroupBox("Name Prefix")
        self.name_prefix = QtWidgets.QLineEdit()
        self.name_prefix.setText("lips")

        # control extension
        self.control_group = QtWidgets.QGroupBox("Control Name Extension")
        self.control_name = QtWidgets.QLineEdit()
        self.control_name.setText("ctl")

        # joints
        self.joints_group = QtWidgets.QGroupBox("Joints")
        self.head_joint_label = QtWidgets.QLabel("Head or Upper Lip Joint:")
        self.head_joint = QtWidgets.QLineEdit()
        self.head_joint_button = QtWidgets.QPushButton("<<")
        self.jaw_joint_label = QtWidgets.QLabel("Jaw or Lower Lip Joint:")
        self.jaw_joint = QtWidgets.QLineEdit()
        self.jaw_joint_button = QtWidgets.QPushButton("<<")

        # Lips Controls
        self.control_ref_group = QtWidgets.QGroupBox(
            "Lips Base Controls (Optional. Required for Shifter Game tools)")
        self.upper_lip_ctl_label = QtWidgets.QLabel("Upper Lip Control:")
        self.upper_lip_ctl = QtWidgets.QLineEdit()
        self.upper_lip_ctl_button = QtWidgets.QPushButton("<<")
        self.lower_lip_ctl_label = QtWidgets.QLabel("Lower Lip Control:")
        self.lower_lip_ctl = QtWidgets.QLineEdit()
        self.lower_lip_ctl_button = QtWidgets.QPushButton("<<")

        # Topological Autoskin
        self.topoSkin_group = QtWidgets.QGroupBox("Skin")
        self.rigid_loops_label = QtWidgets.QLabel("Rigid Loops:")
        self.rigid_loops = QtWidgets.QSpinBox()
        self.rigid_loops.setRange(0, 30)
        self.rigid_loops.setSingleStep(1)
        self.rigid_loops.setValue(5)
        self.falloff_loops_label = QtWidgets.QLabel("Falloff Loops:")
        self.falloff_loops = QtWidgets.QSpinBox()
        self.falloff_loops.setRange(0, 30)
        self.falloff_loops.setSingleStep(1)
        self.falloff_loops.setValue(8)

        self.do_skin = QtWidgets.QCheckBox(
            'Compute Topological Autoskin')
        self.do_skin.setChecked(True)

        # Options
        self.options_group = QtWidgets.QGroupBox("Options")
        self.thickness_label = QtWidgets.QLabel("Lips Thickness:")
        self.thickness = QtWidgets.QDoubleSpinBox()
        self.thickness.setRange(0, 10)
        self.thickness.setSingleStep(.01)
        self.thickness.setValue(.03)
        self.parent_label = QtWidgets.QLabel("Static Rig Parent:")
        self.parent_node = QtWidgets.QLineEdit()
        self.parent_button = QtWidgets.QPushButton("<<")
        # Build button
        self.build_button = QtWidgets.QPushButton("Build Lips Rig")
        self.import_button = QtWidgets.QPushButton("Import Config from json")
        self.export_button = QtWidgets.QPushButton("Export Config to json")

    def create_layout(self):

        # Edge Loop Layout
        edgedge_loop_layout = QtWidgets.QHBoxLayout()
        edgedge_loop_layout.setContentsMargins(1, 1, 1, 1)
        edgedge_loop_layout.addWidget(self.edgedge_loop_label)
        edgedge_loop_layout.addWidget(self.edge_loop)
        edgedge_loop_layout.addWidget(self.edge_loop_button)

        # Outer Edge Loop Layout
        up_vertex_layout = QtWidgets.QHBoxLayout()
        up_vertex_layout.setContentsMargins(1, 1, 1, 1)
        up_vertex_layout.addWidget(self.up_vertex_label)
        up_vertex_layout.addWidget(self.up_vertex)
        up_vertex_layout.addWidget(self.up_vertex_button)

        # inner Edge Loop Layout
        low_vertex_layout = QtWidgets.QHBoxLayout()
        low_vertex_layout.setContentsMargins(1, 1, 1, 1)
        low_vertex_layout.addWidget(self.low_vertex_label)
        low_vertex_layout.addWidget(self.low_vertex)
        low_vertex_layout.addWidget(self.low_vertex_button)

        # Geometry Input Layout
        geometryInput_layout = QtWidgets.QVBoxLayout()
        geometryInput_layout.setContentsMargins(6, 1, 6, 2)
        geometryInput_layout.addLayout(edgedge_loop_layout)
        geometryInput_layout.addLayout(up_vertex_layout)
        geometryInput_layout.addLayout(low_vertex_layout)
        self.geometryInput_group.setLayout(geometryInput_layout)

        # joints Layout
        head_joint_layout = QtWidgets.QHBoxLayout()
        head_joint_layout.addWidget(self.head_joint_label)
        head_joint_layout.addWidget(self.head_joint)
        head_joint_layout.addWidget(self.head_joint_button)

        jaw_joint_layout = QtWidgets.QHBoxLayout()
        jaw_joint_layout.addWidget(self.jaw_joint_label)
        jaw_joint_layout.addWidget(self.jaw_joint)
        jaw_joint_layout.addWidget(self.jaw_joint_button)

        joints_layout = QtWidgets.QVBoxLayout()
        joints_layout.setContentsMargins(6, 4, 6, 4)
        joints_layout.addLayout(head_joint_layout)
        joints_layout.addLayout(jaw_joint_layout)
        self.joints_group.setLayout(joints_layout)

        # control Layout
        upper_lip_ctl_layout = QtWidgets.QHBoxLayout()
        upper_lip_ctl_layout.addWidget(self.upper_lip_ctl_label)
        upper_lip_ctl_layout.addWidget(self.upper_lip_ctl)
        upper_lip_ctl_layout.addWidget(self.upper_lip_ctl_button)

        lower_lip_ctl_layout = QtWidgets.QHBoxLayout()
        lower_lip_ctl_layout.addWidget(self.lower_lip_ctl_label)
        lower_lip_ctl_layout.addWidget(self.lower_lip_ctl)
        lower_lip_ctl_layout.addWidget(self.lower_lip_ctl_button)

        control_ref_layout = QtWidgets.QVBoxLayout()
        control_ref_layout.setContentsMargins(6, 4, 6, 4)
        control_ref_layout.addLayout(upper_lip_ctl_layout)
        control_ref_layout.addLayout(lower_lip_ctl_layout)
        self.control_ref_group.setLayout(control_ref_layout)

        # topological autoskin Layout
        skinLoops_layout = QtWidgets.QGridLayout()
        skinLoops_layout.addWidget(self.rigid_loops_label, 0, 0)
        skinLoops_layout.addWidget(self.falloff_loops_label, 0, 1)
        skinLoops_layout.addWidget(self.rigid_loops, 1, 0)
        skinLoops_layout.addWidget(self.falloff_loops, 1, 1)

        topoSkin_layout = QtWidgets.QVBoxLayout()
        topoSkin_layout.setContentsMargins(6, 4, 6, 4)
        topoSkin_layout.addWidget(self.do_skin,
                                  alignment=QtCore.Qt.Alignment())
        topoSkin_layout.addLayout(skinLoops_layout)
        topoSkin_layout.addLayout(head_joint_layout)
        topoSkin_layout.addLayout(jaw_joint_layout)
        self.topoSkin_group.setLayout(topoSkin_layout)

        # Options Layout
        lipThickness_layout = QtWidgets.QHBoxLayout()
        lipThickness_layout.addWidget(self.thickness_label)
        lipThickness_layout.addWidget(self.thickness)
        parent_layout = QtWidgets.QHBoxLayout()
        parent_layout.addWidget(self.parent_label)
        parent_layout.addWidget(self.parent_node)
        parent_layout.addWidget(self.parent_button)
        options_layout = QtWidgets.QVBoxLayout()
        options_layout.setContentsMargins(6, 1, 6, 2)
        options_layout.addLayout(lipThickness_layout)
        # options_layout.addLayout(offset_layout)
        options_layout.addLayout(parent_layout)
        self.options_group.setLayout(options_layout)

        # Name prefix
        name_prefix_layout = QtWidgets.QHBoxLayout()
        name_prefix_layout.setContentsMargins(1, 1, 1, 1)
        name_prefix_layout.addWidget(self.name_prefix)
        self.prefix_group.setLayout(name_prefix_layout)

        # Control Name Extension
        controlExtension_layout = QtWidgets.QHBoxLayout()
        controlExtension_layout.setContentsMargins(1, 1, 1, 1)
        controlExtension_layout.addWidget(self.control_name)
        self.control_group.setLayout(controlExtension_layout)

        # Main Layout
        main_layout = QtWidgets.QVBoxLayout()
        main_layout.setContentsMargins(6, 6, 6, 6)
        main_layout.addWidget(self.prefix_group)
        main_layout.addWidget(self.control_group)
        main_layout.addWidget(self.geometryInput_group)
        main_layout.addWidget(self.options_group)
        main_layout.addWidget(self.joints_group)
        main_layout.addWidget(self.control_ref_group)
        main_layout.addWidget(self.topoSkin_group)
        main_layout.addWidget(self.build_button)
        main_layout.addWidget(self.import_button)
        main_layout.addWidget(self.export_button)

        self.setLayout(main_layout)

    def create_connections(self):
        self.edge_loop_button.clicked.connect(
            partial(self.populate_edge_loop, self.edge_loop)
        )
        self.up_vertex_button.clicked.connect(
            partial(self.populate_element, self.up_vertex, "vertex")
        )
        self.low_vertex_button.clicked.connect(
            partial(self.populate_element, self.low_vertex, "vertex")
        )
        self.parent_button.clicked.connect(
            partial(self.populate_element, self.parent_node)
        )
        self.head_joint_button.clicked.connect(
            partial(self.populate_element, self.head_joint, "joint")
        )
        self.jaw_joint_button.clicked.connect(
            partial(self.populate_element, self.jaw_joint, "joint")
        )
        self.upper_lip_ctl_button.clicked.connect(
            partial(self.populate_element, self.upper_lip_ctl)
        )
        self.lower_lip_ctl_button.clicked.connect(
            partial(self.populate_element, self.lower_lip_ctl)
        )
        self.build_button.clicked.connect(self.build_rig)
        self.import_button.clicked.connect(self.import_settings)
        self.export_button.clicked.connect(self.export_settings)

    # SLOTS ##########################################################

    # TODO: create a checker to ensure that the vertex selected are part of
    # the main edgelopp
    def populate_element(self, lEdit, oType="transform"):
        if oType == "joint":
            oTypeInst = pm.nodetypes.Joint
        elif oType == "vertex":
            oTypeInst = pm.MeshVertex
        else:
            oTypeInst = pm.nodetypes.Transform

        oSel = pm.selected()
        if oSel:
            if isinstance(oSel[0], oTypeInst):
                lEdit.setText(oSel[0].name())
            else:
                pm.displayWarning(
                    "The selected element is not a valid %s" % oType)
        else:
            pm.displayWarning("Please select first one %s." % oType)

    def populate_edge_loop(self, lineEdit):
        lineEdit.setText(lib.get_edge_loop_from_selection())

    def build_rig(self):
        rig(**lib.get_settings_from_widget(self))

    def export_settings(self):
        data_string = json.dumps(
            lib.get_settings_from_widget(self), indent=4, sort_keys=True
        )

        file_path = lib.get_file_path(self.filter, "save")
        if not file_path:
            return

        with open(file_path, "w") as f:
            f.write(data_string)

    def import_settings(self):
        file_path = lib.get_file_path(self.filter, "open")
        if not file_path:
            return

        lib.import_settings_from_file(file_path, self)
Beispiel #2
0
class componentMainSettings(QtWidgets.QDialog, guide.helperSlots):
    valueChanged = QtCore.Signal(int)

    def __init__(self, parent=None):
        super(componentMainSettings, self).__init__()
        # the inspectSettings function set the current selection to the
        # component root before open the settings dialog
        self.root = pm.selected()[0]

        self.mainSettingsTab = mainSettingsTab()

        self.create_controls()
        self.populate_controls()
        self.create_layout()
        self.create_connections()

        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)

    def create_controls(self):
        """
        Create the controls for the component base

        """
        self.tabs = QtWidgets.QTabWidget()
        self.tabs.setObjectName("settings_tab")

        # Close Button
        self.close_button = QtWidgets.QPushButton("Close")

    def populate_controls(self):
        """Populate Controls attribute values

        Populate the controls values from the custom attributes
        of the component.

        """
        # populate tab
        self.tabs.insertTab(0, self.mainSettingsTab, "Main Settings")

        # populate main settings
        self.mainSettingsTab.name_lineEdit.setText(
            self.root.attr("comp_name").get())
        sideSet = ["C", "L", "R"]
        sideIndex = sideSet.index(self.root.attr("comp_side").get())
        self.mainSettingsTab.side_comboBox.setCurrentIndex(sideIndex)
        self.mainSettingsTab.componentIndex_spinBox.setValue(
            self.root.attr("comp_index").get())
        if self.root.attr("useIndex").get():
            self.mainSettingsTab.useJointIndex_checkBox.setCheckState(
                QtCore.Qt.Checked)
        else:
            self.mainSettingsTab.useJointIndex_checkBox.setCheckState(
                QtCore.Qt.Unchecked)
        self.mainSettingsTab.parentJointIndex_spinBox.setValue(
            self.root.attr("parentJointIndex").get())
        self.mainSettingsTab.host_lineEdit.setText(
            self.root.attr("ui_host").get())
        self.mainSettingsTab.subGroup_lineEdit.setText(
            self.root.attr("ctlGrp").get())

    def create_layout(self):
        """
        Create the layout for the component base settings

        """
        return

    def create_connections(self):
        """
        Create the slots connections to the controls functions

        """
        self.close_button.clicked.connect(self.close_settings)

        self.mainSettingsTab.name_lineEdit.editingFinished.connect(
            self.updateComponentName)
        self.mainSettingsTab.side_comboBox.currentIndexChanged.connect(
            self.updateComponentName)
        self.mainSettingsTab.componentIndex_spinBox.valueChanged.connect(
            self.updateComponentName)
        self.mainSettingsTab.useJointIndex_checkBox.stateChanged.connect(
            partial(self.updateCheck,
                    self.mainSettingsTab.useJointIndex_checkBox, "useIndex"))
        self.mainSettingsTab.parentJointIndex_spinBox.valueChanged.connect(
            partial(self.updateSpinBox,
                    self.mainSettingsTab.parentJointIndex_spinBox,
                    "parentJointIndex"))
        self.mainSettingsTab.host_pushButton.clicked.connect(
            partial(self.updateHostUI, self.mainSettingsTab.host_lineEdit,
                    "ui_host"))
        self.mainSettingsTab.subGroup_lineEdit.editingFinished.connect(
            partial(self.updateLineEdit,
                    self.mainSettingsTab.subGroup_lineEdit, "ctlGrp"))
Beispiel #3
0
class crankTool(MayaQWidgetDockableMixin, QtWidgets.QDialog):

    """Crank shot sculpt main window

    """

    valueChanged = QtCore.Signal(int)
    wi_to_destroy = []

    def __init__(self, parent=None):
        self.toolName = "Crank"
        super(crankTool, self).__init__(parent)
        self.crankUIWInst = crankUIW()

        self.__proxyModel = QtCore.QSortFilterProxyModel(self)
        self.crankUIWInst.layers_listView.setModel(self.__proxyModel)

        self.setup_crankWindow()
        self.create_layout()
        self.create_connections()
        self._refreshList()

        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)

    def setup_crankWindow(self):
        """Setup the window
        """
        self.setObjectName(self.toolName)
        self.setWindowFlags(QtCore.Qt.Window)
        self.setWindowTitle("Crank: Shot Sculpting")
        self.resize(266, 445)

    def create_layout(self):
        """Create the layout
        """
        self.crank_layout = QtWidgets.QVBoxLayout()
        self.crank_layout.addWidget(self.crankUIWInst)
        self.crank_layout.setContentsMargins(3, 3, 3, 3)

        self.setLayout(self.crank_layout)

    def setSourceModel(self, model):
        """Set the source model for the listview

        Args:
            model (Qt model): QtCore.QSortFilterProxyModel
        """
        self.__proxyModel.setSourceModel(model)

    ###########################
    # Helper functions
    ###########################

    def _refreshList(self):
        """Refresh listview content
        """
        model = QtGui.QStandardItemModel(self)
        for c_node in list_crank_layer_nodes():
            model.appendRow(QtGui.QStandardItem(c_node))
        self.setSourceModel(model)

    def _getSelectedListIndexes(self):
        """Get the selected layer index from the list view

        Returns:
            dagNode list: The selected layers list
        """
        layers = []
        for x in self.crankUIWInst.layers_listView.selectedIndexes():
            try:
                layers.append(pm.PyNode(x.data()))

            except pm.MayaNodeError:
                pm.displayWarning("{}  can't be find.".format(x.data()))
                return False
        return layers

    def select_layer_node(self):
        """Select the layer node from the list index
        """
        layers = self._getSelectedListIndexes()
        pm.select(layers)

    def create_layer(self):
        """Create a new layer and update the window list
        """
        create_layer(pm.selected())
        self._refreshList()

    def add_frame_sculpt(self):
        """Add a new fram sculpt
        """
        anim = self.crankUIWInst.keyframe_checkBox.isChecked()
        ei = self.crankUIWInst.easeIn_spinBox.value()
        eo = self.crankUIWInst.easeOut_spinBox.value()
        pre = self.crankUIWInst.preHold_spinBox.value()
        pos = self.crankUIWInst.postHold_spinBox.value()
        for layer_node in self._getSelectedListIndexes():
            add_frame_sculpt(layer_node, anim=anim, keyf=[ei, pre, pos, eo])

        self.select_members()

    def edit_frame_sculpt(self):
        """Edit fram sculpt
        """
        if edit_sculpt_frame():
            self.select_members()

    def edit_layer_off(self):
        """Turn off the layer edit status
        """
        for layer_node in self._getSelectedListIndexes():
            edit_layer_off(layer_node)

    def edit_all_off(self):
        """Turn off all the layers edit status
        """
        edit_all_off()

    ###########################
    # "right click context menu for layers"
    ###########################

    def _layer_menu(self, QPos):
        """Create the layers rightclick menu

        Args:
            QPos (QPos): Position

        Returns:
            None: None
        """
        lyr_widget = self.crankUIWInst.layers_listView
        currentSelection = lyr_widget.selectedIndexes()
        if currentSelection is None:
            return
        self.lyr_menu = QtWidgets.QMenu()
        parentPosition = lyr_widget.mapToGlobal(QtCore.QPoint(0, 0))
        menu_item_01 = self.lyr_menu.addAction("Select Members")
        self.lyr_menu.addSeparator()
        menu_item_02 = self.lyr_menu.addAction("Selected Layer Edit OFF")
        menu_item_03 = self.lyr_menu.addAction("All Layers Edit OFF")
        self.lyr_menu.addSeparator()

        menu_item_01.triggered.connect(self.select_members)
        menu_item_02.triggered.connect(self.edit_layer_off)
        menu_item_03.triggered.connect(self.edit_all_off)

        self.lyr_menu.move(parentPosition + QPos)
        self.lyr_menu.show()

    def select_members(self):
        """Select the members of a given layer
        """
        layers = self._getSelectedListIndexes()
        pm.select(get_layer_affected_elements(layers))

    ###########################
    # create connections SIGNALS
    ###########################
    def create_connections(self):
        """Create connections
        """
        self.crankUIWInst.search_lineEdit.textChanged.connect(
            self.filterChanged)
        self.crankUIWInst.refresh_pushButton.clicked.connect(
            self._refreshList)
        self.crankUIWInst.createLayer_pushButton.clicked.connect(
            self.create_layer)
        self.crankUIWInst.addFrame_pushButton.clicked.connect(
            self.add_frame_sculpt)
        self.crankUIWInst.editFrame_pushButton.clicked.connect(
            self.edit_frame_sculpt)

        selModel = self.crankUIWInst.layers_listView.selectionModel()
        selModel.selectionChanged.connect(self.select_layer_node)

        # connect menu
        self.crankUIWInst.layers_listView.setContextMenuPolicy(
            QtCore.Qt.CustomContextMenu)
        self.crankUIWInst.layers_listView.customContextMenuRequested.connect(
            self._layer_menu)

    #############
    # SLOTS
    #############
    def filterChanged(self, filter):
        """Filter out the elements in the list view

        """
        regExp = QtCore.QRegExp(filter,
                                QtCore.Qt.CaseSensitive,
                                QtCore.QRegExp.Wildcard
                                )
        self.__proxyModel.setFilterRegExp(regExp)
Beispiel #4
0
class lipRigUI(MayaQWidgetDockableMixin, QtWidgets.QDialog):

    valueChanged = QtCore.Signal(int)

    def __init__(self, parent=None):
        super(lipRigUI, self).__init__(parent)
        self.create()

    def create(self):

        self.setWindowTitle("Rigbits: Lips Rigger")
        self.setWindowFlags(QtCore.Qt.Window)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, 1)

        self.create_controls()
        self.create_layout()
        self.create_connections()

    def create_controls(self):

        # Geometry input controls
        self.geometryInput_group = QtWidgets.QGroupBox("Geometry Input")
        self.edgeloop_label = QtWidgets.QLabel("Edge Loop:")
        self.edgeloop_lineEdit = QtWidgets.QLineEdit()
        self.edgeloop_button = QtWidgets.QPushButton("<<")
        self.upVertex_label = QtWidgets.QLabel("Upper Vertex:")
        self.upVertex_lineEdit = QtWidgets.QLineEdit()
        self.upVertex_button = QtWidgets.QPushButton("<<")
        self.lowVertex_label = QtWidgets.QLabel("Lower Vertex:")
        self.lowVertex_lineEdit = QtWidgets.QLineEdit()
        self.lowVertex_button = QtWidgets.QPushButton("<<")

        # Name prefix
        self.prefix_group = QtWidgets.QGroupBox("Name Prefix")
        self.prefix_lineEdit = QtWidgets.QLineEdit()
        self.prefix_lineEdit.setText("lips")

        # control extension
        self.control_group = QtWidgets.QGroupBox("Control Name Extension")
        self.control_lineEdit = QtWidgets.QLineEdit()
        self.control_lineEdit.setText("ctl")

        # joints
        self.joints_group = QtWidgets.QGroupBox("Joints")
        self.headJnt_label = QtWidgets.QLabel("Head or Upper Lip Joint:")
        self.headJnt_lineEdit = QtWidgets.QLineEdit()
        self.headJnt_button = QtWidgets.QPushButton("<<")
        self.jawJnt_label = QtWidgets.QLabel("Jaw or Lower Lip Joint:")
        self.jawJnt_lineEdit = QtWidgets.QLineEdit()
        self.jawJnt_button = QtWidgets.QPushButton("<<")

        # Topological Autoskin
        self.topoSkin_group = QtWidgets.QGroupBox("Skin")
        self.rigidLoops_label = QtWidgets.QLabel("Rigid Loops:")
        self.rigidLoops_value = QtWidgets.QSpinBox()
        self.rigidLoops_value.setRange(0, 30)
        self.rigidLoops_value.setSingleStep(1)
        self.rigidLoops_value.setValue(5)
        self.falloffLoops_label = QtWidgets.QLabel("Falloff Loops:")
        self.falloffLoops_value = QtWidgets.QSpinBox()
        self.falloffLoops_value.setRange(0, 30)
        self.falloffLoops_value.setSingleStep(1)
        self.falloffLoops_value.setValue(8)

        self.topSkin_check = QtWidgets.QCheckBox(
            'Compute Topological Autoskin')
        self.topSkin_check.setChecked(True)

        # Options
        self.options_group = QtWidgets.QGroupBox("Options")
        self.lipThickness_label = QtWidgets.QLabel("Lips Thickness:")
        self.lipThickness_value = QtWidgets.QDoubleSpinBox()
        self.lipThickness_value.setRange(0, 10)
        self.lipThickness_value.setSingleStep(.01)
        self.lipThickness_value.setValue(.03)
        self.parent_label = QtWidgets.QLabel("Static Rig Parent:")
        self.parent_lineEdit = QtWidgets.QLineEdit()
        self.parent_button = QtWidgets.QPushButton("<<")
        # Build button
        self.build_button = QtWidgets.QPushButton("Build Lips Rig")
        self.export_button = QtWidgets.QPushButton("Export Config to json")

    def create_layout(self):

        # Edge Loop Layout
        edgeloop_layout = QtWidgets.QHBoxLayout()
        edgeloop_layout.setContentsMargins(1, 1, 1, 1)
        edgeloop_layout.addWidget(self.edgeloop_label)
        edgeloop_layout.addWidget(self.edgeloop_lineEdit)
        edgeloop_layout.addWidget(self.edgeloop_button)

        # Outer Edge Loop Layout
        upVertex_layout = QtWidgets.QHBoxLayout()
        upVertex_layout.setContentsMargins(1, 1, 1, 1)
        upVertex_layout.addWidget(self.upVertex_label)
        upVertex_layout.addWidget(self.upVertex_lineEdit)
        upVertex_layout.addWidget(self.upVertex_button)

        # inner Edge Loop Layout
        lowVertex_layout = QtWidgets.QHBoxLayout()
        lowVertex_layout.setContentsMargins(1, 1, 1, 1)
        lowVertex_layout.addWidget(self.lowVertex_label)
        lowVertex_layout.addWidget(self.lowVertex_lineEdit)
        lowVertex_layout.addWidget(self.lowVertex_button)

        # Geometry Input Layout
        geometryInput_layout = QtWidgets.QVBoxLayout()
        geometryInput_layout.setContentsMargins(6, 1, 6, 2)
        geometryInput_layout.addLayout(edgeloop_layout)
        geometryInput_layout.addLayout(upVertex_layout)
        geometryInput_layout.addLayout(lowVertex_layout)
        self.geometryInput_group.setLayout(geometryInput_layout)

        # joints Layout
        headJnt_layout = QtWidgets.QHBoxLayout()
        headJnt_layout.addWidget(self.headJnt_label)
        headJnt_layout.addWidget(self.headJnt_lineEdit)
        headJnt_layout.addWidget(self.headJnt_button)

        jawJnt_layout = QtWidgets.QHBoxLayout()
        jawJnt_layout.addWidget(self.jawJnt_label)
        jawJnt_layout.addWidget(self.jawJnt_lineEdit)
        jawJnt_layout.addWidget(self.jawJnt_button)

        joints_layout = QtWidgets.QVBoxLayout()
        joints_layout.setContentsMargins(6, 4, 6, 4)
        joints_layout.addLayout(headJnt_layout)
        joints_layout.addLayout(jawJnt_layout)
        self.joints_group.setLayout(joints_layout)

        # topological autoskin Layout
        skinLoops_layout = QtWidgets.QGridLayout()
        skinLoops_layout.addWidget(self.rigidLoops_label, 0, 0)
        skinLoops_layout.addWidget(self.falloffLoops_label, 0, 1)
        skinLoops_layout.addWidget(self.rigidLoops_value, 1, 0)
        skinLoops_layout.addWidget(self.falloffLoops_value, 1, 1)

        topoSkin_layout = QtWidgets.QVBoxLayout()
        topoSkin_layout.setContentsMargins(6, 4, 6, 4)
        topoSkin_layout.addWidget(self.topSkin_check,
                                  alignment=QtCore.Qt.Alignment())
        topoSkin_layout.addLayout(skinLoops_layout)
        topoSkin_layout.addLayout(headJnt_layout)
        topoSkin_layout.addLayout(jawJnt_layout)
        self.topoSkin_group.setLayout(topoSkin_layout)

        # Options Layout
        lipThickness_layout = QtWidgets.QHBoxLayout()
        lipThickness_layout.addWidget(self.lipThickness_label)
        lipThickness_layout.addWidget(self.lipThickness_value)
        parent_layout = QtWidgets.QHBoxLayout()
        parent_layout.addWidget(self.parent_label)
        parent_layout.addWidget(self.parent_lineEdit)
        parent_layout.addWidget(self.parent_button)
        options_layout = QtWidgets.QVBoxLayout()
        options_layout.setContentsMargins(6, 1, 6, 2)
        options_layout.addLayout(lipThickness_layout)
        # options_layout.addLayout(offset_layout)
        options_layout.addLayout(parent_layout)
        self.options_group.setLayout(options_layout)

        # Name prefix
        namePrefix_layout = QtWidgets.QHBoxLayout()
        namePrefix_layout.setContentsMargins(1, 1, 1, 1)
        namePrefix_layout.addWidget(self.prefix_lineEdit)
        self.prefix_group.setLayout(namePrefix_layout)

        # Control Name Extension
        controlExtension_layout = QtWidgets.QHBoxLayout()
        controlExtension_layout.setContentsMargins(1, 1, 1, 1)
        controlExtension_layout.addWidget(self.control_lineEdit)
        self.control_group.setLayout(controlExtension_layout)

        # Main Layout
        main_layout = QtWidgets.QVBoxLayout()
        main_layout.setContentsMargins(6, 6, 6, 6)
        main_layout.addWidget(self.prefix_group)
        main_layout.addWidget(self.control_group)
        main_layout.addWidget(self.geometryInput_group)
        main_layout.addWidget(self.options_group)
        main_layout.addWidget(self.joints_group)
        main_layout.addWidget(self.topoSkin_group)
        main_layout.addWidget(self.build_button)
        main_layout.addWidget(self.export_button)

        self.setLayout(main_layout)

    def create_connections(self):
        self.edgeloop_button.clicked.connect(
            partial(self.populate_edgeloop, self.edgeloop_lineEdit))
        self.upVertex_button.clicked.connect(
            partial(self.populate_element, self.upVertex_lineEdit, "vertex"))
        self.lowVertex_button.clicked.connect(
            partial(self.populate_element, self.lowVertex_lineEdit, "vertex"))

        self.parent_button.clicked.connect(
            partial(self.populate_element, self.parent_lineEdit))

        self.headJnt_button.clicked.connect(
            partial(self.populate_element, self.headJnt_lineEdit, "joint"))
        self.jawJnt_button.clicked.connect(
            partial(self.populate_element, self.jawJnt_lineEdit, "joint"))

        self.build_button.clicked.connect(self.buildRig)
        self.export_button.clicked.connect(self.exportDict)

    # SLOTS ##########################################################

    # TODO: create a checker to ensure that the vertex selected are part of
    # the main edgelopp
    def populate_element(self, lEdit, oType="transform"):
        if oType == "joint":
            oTypeInst = pm.nodetypes.Joint
        elif oType == "vertex":
            oTypeInst = pm.MeshVertex
        else:
            oTypeInst = pm.nodetypes.Transform

        oSel = pm.selected()
        if oSel:
            if isinstance(oSel[0], oTypeInst):
                lEdit.setText(oSel[0].name())
            else:
                pm.displayWarning("The selected element is not a valid %s" %
                                  oType)
        else:
            pm.displayWarning("Please select first one %s." % oType)

    def populate_edgeloop(self, lineEdit):
        oSel = pm.selected(fl=1)
        if oSel:
            edgeList = ""
            separator = ""
            for e in oSel:
                if isinstance(e, pm.MeshEdge):
                    if edgeList:
                        separator = ","
                    edgeList = edgeList + separator + str(e)
            if not edgeList:
                pm.displayWarning("Please select first the edge loop.")
            elif len(edgeList.split(",")) < 4:
                pm.displayWarning("The minimun edge count is 4")
            else:
                lineEdit.setText(edgeList)

        else:
            pm.displayWarning("Please select first the edge loop.")

    def populateDict(self):
        self.buildDict = {}
        self.buildDict["lips"] = [
            self.edgeloop_lineEdit.text(),
            self.upVertex_lineEdit.text(),
            self.lowVertex_lineEdit.text(),
            self.prefix_lineEdit.text(),
            self.lipThickness_value.value(),
            self.topSkin_check.isChecked(),
            self.rigidLoops_value.value(),
            self.falloffLoops_value.value(),
            self.headJnt_lineEdit.text(),
            self.jawJnt_lineEdit.text(),
            self.parent_lineEdit.text(),
            self.control_lineEdit.text()
        ]

    def buildRig(self):
        self.populateDict()
        lipsRig(*self.buildDict["lips"])

    def exportDict(self):
        self.populateDict()

        data_string = json.dumps(self.buildDict, indent=4, sort_keys=True)
        filePath = pm.fileDialog2(
            fileMode=0,
            fileFilter='Lips Rigger Configuration .lips (*%s)' % ".lips")
        if not filePath:
            return
        if not isinstance(filePath, basestring):
            filePath = filePath[0]
        f = open(filePath, 'w')
        f.write(data_string)
        f.close()
Beispiel #5
0
class componentMainSettings(QtWidgets.QDialog, guide.helperSlots):
    valueChanged = QtCore.Signal(int)

    def __init__(self, parent=None):
        super(componentMainSettings, self).__init__()
        # the inspectSettings function set the current selection to the
        # component root before open the settings dialog
        self.root = pm.selected()[0]

        self.mainSettingsTab = mainSettingsTab()
        if self.root.hasAttr("jointNamesDescription"):
            self.jointNameDescriptor = jointNameDescriptor()

        self.create_controls()
        self.populate_controls()
        self.create_layout()
        self.create_connections()

        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)

    def create_controls(self):
        """
        Create the controls for the component base

        """
        self.tabs = QtWidgets.QTabWidget()
        self.tabs.setObjectName("settings_tab")

        # Close Button
        self.close_button = QtWidgets.QPushButton("Close")

    def populate_controls(self):
        """Populate Controls attribute values

        Populate the controls values from the custom attributes
        of the component.

        """
        # populate tab
        self.tabs.insertTab(0, self.mainSettingsTab, "Main Settings")

        # populate main settings
        self.mainSettingsTab.name_lineEdit.setText(
            self.root.attr("comp_name").get())
        sideSet = ["C", "L", "R"]
        sideIndex = sideSet.index(self.root.attr("comp_side").get())
        self.mainSettingsTab.side_comboBox.setCurrentIndex(sideIndex)
        self.mainSettingsTab.componentIndex_spinBox.setValue(
            self.root.attr("comp_index").get())
        if self.root.attr("useIndex").get():
            self.mainSettingsTab.useJointIndex_checkBox.setCheckState(
                QtCore.Qt.Checked)
        else:
            self.mainSettingsTab.useJointIndex_checkBox.setCheckState(
                QtCore.Qt.Unchecked)
        self.mainSettingsTab.parentJointIndex_spinBox.setValue(
            self.root.attr("parentJointIndex").get())
        self.mainSettingsTab.host_lineEdit.setText(
            self.root.attr("ui_host").get())
        self.mainSettingsTab.subGroup_lineEdit.setText(
            self.root.attr("ctlGrp").get())
        self.mainSettingsTab.joint_offset_x_doubleSpinBox.setValue(
            self.root.attr("joint_rot_offset_x").get())
        self.mainSettingsTab.joint_offset_y_doubleSpinBox.setValue(
            self.root.attr("joint_rot_offset_y").get())
        self.mainSettingsTab.joint_offset_z_doubleSpinBox.setValue(
            self.root.attr("joint_rot_offset_z").get())

        # testing adding custom color per component
        self.mainSettingsTab.overrideColors_checkBox.setCheckState(
            QtCore.Qt.Checked if self.root.Override_Color.get()
            else QtCore.Qt.Unchecked)

        self.mainSettingsTab.useRGB_checkBox.setCheckState(
            QtCore.Qt.Checked if self.root.Use_RGB_Color.get()
            else QtCore.Qt.Unchecked)

        tab = self.mainSettingsTab

        index_widgets = ((tab.color_fk_spinBox,
                          tab.color_fk_label,
                          "color_fk"),
                         (tab.color_ik_spinBox,
                          tab.color_ik_label,
                          "color_ik"))

        rgb_widgets = ((tab.RGB_fk_pushButton, tab.RGB_fk_slider, "RGB_fk"),
                       (tab.RGB_ik_pushButton, tab.RGB_ik_slider, "RGB_ik"))

        for spinBox, label, source_attr in index_widgets:
            color_index = self.root.attr(source_attr).get()
            spinBox.setValue(color_index)
            self.updateWidgetStyleSheet(
                label, [i / 255.0 for i in MAYA_OVERRIDE_COLOR[color_index]])

        for button, slider, source_attr in rgb_widgets:
            self.updateRgbColorWidgets(
                button, self.root.attr(source_attr).get(), slider)

        # forceing the size of the color buttons/label to keep ui clean
        for widget in tuple(i[0] for i in rgb_widgets) + tuple(
                i[1] for i in index_widgets):
            widget.setFixedSize(pyqt.dpi_scale(30), pyqt.dpi_scale(20))

        self.toggleRgbIndexWidgets(tab.useRGB_checkBox,
                                   (w for i in index_widgets for w in i[:2]),
                                   (w for i in rgb_widgets for w in i[:2]),
                                   "Use_RGB_Color",
                                   tab.useRGB_checkBox.checkState())

        self.refresh_controls()

        # joint names tab
        if self.root.hasAttr("jointNamesDescription"):
            self.tabs.insertTab(
                2, self.jointNameDescriptor, "Joints Description Names")

    def refresh_controls(self):
        joint_names = [name.strip() for name in
                       self.root.attr("joint_names").get().split(",")]
        if any(joint_names):
            summary = "<b>({0} set)</b>".format(sum(map(bool, joint_names)))
        else:
            summary = "(None)"
        self.mainSettingsTab.jointNames_label.setText("Joint Names " + summary)

    def create_layout(self):
        """
        Create the layout for the component base settings

        """
        return

    def create_connections(self):
        """
        Create the slots connections to the controls functions

        """
        self.close_button.clicked.connect(self.close_settings)

        self.mainSettingsTab.name_lineEdit.editingFinished.connect(
            self.updateComponentName)
        self.mainSettingsTab.side_comboBox.currentIndexChanged.connect(
            self.updateComponentName)
        self.mainSettingsTab.componentIndex_spinBox.valueChanged.connect(
            self.updateComponentName)
        self.mainSettingsTab.useJointIndex_checkBox.stateChanged.connect(
            partial(self.updateCheck,
                    self.mainSettingsTab.useJointIndex_checkBox,
                    "useIndex"))
        self.mainSettingsTab.parentJointIndex_spinBox.valueChanged.connect(
            partial(self.updateSpinBox,
                    self.mainSettingsTab.parentJointIndex_spinBox,
                    "parentJointIndex"))
        self.mainSettingsTab.host_pushButton.clicked.connect(
            partial(self.updateHostUI,
                    self.mainSettingsTab.host_lineEdit,
                    "ui_host"))
        self.mainSettingsTab.subGroup_lineEdit.editingFinished.connect(
            partial(self.updateLineEdit,
                    self.mainSettingsTab.subGroup_lineEdit,
                    "ctlGrp"))
        self.mainSettingsTab.jointNames_pushButton.clicked.connect(
            self.joint_names_dialog)

        self.mainSettingsTab.joint_offset_x_doubleSpinBox.valueChanged.connect(
            partial(self.updateSpinBox,
                    self.mainSettingsTab.joint_offset_x_doubleSpinBox,
                    "joint_rot_offset_x"))
        self.mainSettingsTab.joint_offset_y_doubleSpinBox.valueChanged.connect(
            partial(self.updateSpinBox,
                    self.mainSettingsTab.joint_offset_y_doubleSpinBox,
                    "joint_rot_offset_y"))
        self.mainSettingsTab.joint_offset_z_doubleSpinBox.valueChanged.connect(
            partial(self.updateSpinBox,
                    self.mainSettingsTab.joint_offset_z_doubleSpinBox,
                    "joint_rot_offset_z"))

        tab = self.mainSettingsTab

        index_widgets = ((tab.color_fk_spinBox,
                          tab.color_fk_label,
                          "color_fk"),
                         (tab.color_ik_spinBox,
                          tab.color_ik_label,
                          "color_ik"))

        rgb_widgets = ((tab.RGB_fk_pushButton, tab.RGB_fk_slider, "RGB_fk"),
                       (tab.RGB_ik_pushButton, tab.RGB_ik_slider, "RGB_ik"))

        for spinBox, label, source_attr in index_widgets:
            spinBox.valueChanged.connect(
                partial(self.updateIndexColorWidgets,
                        spinBox,
                        source_attr,
                        label))

        for button, slider, source_attr in rgb_widgets:
            button.clicked.connect(
                partial(self.rgbColorEditor, button, source_attr, slider))
            slider.valueChanged.connect(
                partial(self.rgbSliderValueChanged, button, source_attr))

        tab.useRGB_checkBox.stateChanged.connect(
            partial(self.toggleRgbIndexWidgets,
                    tab.useRGB_checkBox,
                    tuple(w for i in index_widgets for w in i[:2]),
                    tuple(w for i in rgb_widgets for w in i[:2]),
                    "Use_RGB_Color"))

        tab.overrideColors_checkBox.stateChanged.connect(
            partial(self.updateCheck,
                    tab.overrideColors_checkBox,
                    "Override_Color"))

    def joint_names_dialog(self):
        dialog = JointNames(self.root, self)
        dialog.setWindowTitle(self.windowTitle())
        dialog.attributeChanged.connect(self.refresh_controls)
        dialog.show()
Beispiel #6
0
class JointNames(QtWidgets.QDialog, jnui.Ui_Form):
    attributeChanged = QtCore.Signal()

    def __init__(self, root, parent=None):
        super(JointNames, self).__init__(parent)
        self.root = root

        self.setupUi(self)

        self.populate_controls()
        self.apply_names()
        self.create_connections()

    def populate_controls(self):
        jointNames = self.root.attr("joint_names").get().split(",")
        if jointNames[-1]:
            jointNames.append("")

        self.jointNamesList.clearContents()
        self.jointNamesList.setRowCount(0)

        for i, name in enumerate(jointNames):
            self.jointNamesList.insertRow(i)
            item = QtWidgets.QTableWidgetItem(name.strip())
            self.jointNamesList.setItem(i, 0, item)

    def create_connections(self):
        self.jointNamesList.cellChanged.connect(self.update_name)
        self.jointNamesList.itemActivated.connect(self.jointNamesList.editItem)

        self.add_pushButton.clicked.connect(self.add)
        self.remove_pushButton.clicked.connect(self.remove)
        self.removeAll_pushButton.clicked.connect(self.remove_all)

        self.moveUp_pushButton.clicked.connect(lambda: self.move(-1))
        self.moveDown_pushButton.clicked.connect(lambda: self.move(1))

    def apply_names(self):
        jointNames = []
        for i in range(self.jointNamesList.rowCount()):
            item = self.jointNamesList.item(i, 0)
            jointNames.append(item.text())

        value = ",".join(jointNames[0:-1])
        self.root.attr("joint_names").set(value)

        self.jointNamesList.setVerticalHeaderLabels(
            [str(i) for i in range(len(jointNames))])

        self.attributeChanged.emit()

    def add(self):
        row = max(0, self.jointNamesList.currentRow() or 0)
        self.jointNamesList.insertRow(row)
        item = QtWidgets.QTableWidgetItem("")
        self.jointNamesList.setItem(row, 0, item)
        self.jointNamesList.setCurrentCell(row, 0)
        self.apply_names()

    def remove(self):
        row = self.jointNamesList.currentRow()
        if row + 1 < self.jointNamesList.rowCount() > 1:
            self.jointNamesList.removeRow(row)
            self.apply_names()
            self.jointNamesList.setCurrentCell(row, 0)

    def remove_all(self):
        self.jointNamesList.clearContents()
        self.jointNamesList.setRowCount(0)
        self.jointNamesList.insertRow(0)
        self.jointNamesList.setItem(0, 0, QtWidgets.QTableWidgetItem(""))
        self.jointNamesList.setCurrentCell(0, 0)
        self.apply_names()

    def move(self, step):
        row = self.jointNamesList.currentRow()
        if row + step < 0:
            return
        item1 = self.jointNamesList.item(row, 0).text()
        item2 = self.jointNamesList.item(row + step, 0).text()
        self.jointNamesList.item(row, 0).setText(item2)
        self.jointNamesList.item(row + step, 0).setText(item1)
        self.jointNamesList.setCurrentCell(row + step, 0)

    def update_name(self, row, column):
        item = self.jointNamesList.item(row, column)
        if row == self.jointNamesList.rowCount() - 1 and item.text():
            self.jointNamesList.insertRow(row + 1)
            self.jointNamesList.setItem(
                row + 1, 0, QtWidgets.QTableWidgetItem(""))
        self.apply_names()
        self.jointNamesList.setCurrentCell(row + 1, 0)
        self.jointNamesList.editItem(self.jointNamesList.currentItem())

    def keyPressEvent(self):
        pass
Beispiel #7
0
class eyeRigUI(MayaQWidgetDockableMixin, QtWidgets.QDialog):

    valueChanged = QtCore.Signal(int)

    def __init__(self, parent=None):
        super(eyeRigUI, self).__init__(parent)
        self.create()

    def create(self):

        self.setWindowTitle("Rigbits: Eye Rigger")
        self.setWindowFlags(QtCore.Qt.Window)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, 1)

        self.create_controls()
        self.create_layout()
        self.create_connections()

    def create_controls(self):

        # Geometry input controls
        self.geometryInput_group = QtWidgets.QGroupBox("Geometry Input")
        self.eyeball_label = QtWidgets.QLabel("Eyeball:")
        self.eyeball_lineEdit = QtWidgets.QLineEdit()
        self.eyeball_button = QtWidgets.QPushButton("<<")
        self.edgeloop_label = QtWidgets.QLabel("Edge Loop:")
        self.edgeloop_lineEdit = QtWidgets.QLineEdit()
        self.edgeloop_button = QtWidgets.QPushButton("<<")

        # Manual corners
        self.manualCorners_group = QtWidgets.QGroupBox("Custom Eye Corners")
        self.manualCorners_check = QtWidgets.QCheckBox(
            "Set Manual Vertex Corners")
        self.manualCorners_check.setChecked(False)
        self.intCorner_label = QtWidgets.QLabel("Internal Corner")
        self.intCorner_lineEdit = QtWidgets.QLineEdit()
        self.intCorner_button = QtWidgets.QPushButton("<<")
        self.extCorner_label = QtWidgets.QLabel("External Corner")
        self.extCorner_lineEdit = QtWidgets.QLineEdit()
        self.extCorner_button = QtWidgets.QPushButton("<<")

        # Blink heigh slider
        self.blinkHeigh_group = QtWidgets.QGroupBox("Blink High")
        self.blinkHeight_value = QtWidgets.QSpinBox()
        self.blinkHeight_value.setRange(0, 100)
        self.blinkHeight_value.setSingleStep(10)
        self.blinkHeight_value.setValue(20)
        self.blinkHeight_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.blinkHeight_slider.setRange(0, 100)
        self.blinkHeight_slider.setSingleStep(
            self.blinkHeight_slider.maximum() / 10.0)
        self.blinkHeight_slider.setValue(20)

        # Name prefix
        self.prefix_group = QtWidgets.QGroupBox("Name Prefix")
        self.prefix_lineEdit = QtWidgets.QLineEdit()
        self.prefix_lineEdit.setText("eye")
        self.control_group = QtWidgets.QGroupBox("Control Name Extension")
        self.control_lineEdit = QtWidgets.QLineEdit()
        self.control_lineEdit.setText("ctl")

        # joints
        self.joints_group = QtWidgets.QGroupBox("Joints")
        self.headJnt_label = QtWidgets.QLabel("Head or Eye area Joint:")
        self.headJnt_lineEdit = QtWidgets.QLineEdit()
        self.headJnt_button = QtWidgets.QPushButton("<<")

        # Topological Autoskin
        self.topoSkin_group = QtWidgets.QGroupBox("Skin")
        self.rigidLoops_label = QtWidgets.QLabel("Rigid Loops:")
        self.rigidLoops_value = QtWidgets.QSpinBox()
        self.rigidLoops_value.setRange(0, 30)
        self.rigidLoops_value.setSingleStep(1)
        self.rigidLoops_value.setValue(2)
        self.falloffLoops_label = QtWidgets.QLabel("Falloff Loops:")
        self.falloffLoops_value = QtWidgets.QSpinBox()
        self.falloffLoops_value.setRange(0, 30)
        self.falloffLoops_value.setSingleStep(1)
        self.falloffLoops_value.setValue(4)

        self.topSkin_check = QtWidgets.QCheckBox(
            'Compute Topological Autoskin')
        self.topSkin_check.setChecked(True)

        # Options
        self.options_group = QtWidgets.QGroupBox("Options")
        self.parent_label = QtWidgets.QLabel("Rig Parent:")
        self.parent_lineEdit = QtWidgets.QLineEdit()
        self.parent_button = QtWidgets.QPushButton("<<")
        self.ctlShapeOffset_label = QtWidgets.QLabel("Controls Offset:")
        self.ctlShapeOffset_value = QtWidgets.QDoubleSpinBox()
        self.ctlShapeOffset_value.setRange(0, 10)
        self.ctlShapeOffset_value.setSingleStep(.05)
        self.ctlShapeOffset_value.setValue(.05)
        self.sideRange_check = QtWidgets.QCheckBox(
            "Use Z axis for wide calculation (i.e: Horse and fish side eyes)")
        self.sideRange_check.setChecked(False)

        self.ctlGrp_label = QtWidgets.QLabel("Controls Group:")
        self.ctlGrp_lineEdit = QtWidgets.QLineEdit()
        self.ctlGrp_button = QtWidgets.QPushButton("<<")

        self.deformersGrp_label = QtWidgets.QLabel("Deformers Group:")
        self.deformersGrp_lineEdit = QtWidgets.QLineEdit()
        self.deformersGrp_button = QtWidgets.QPushButton("<<")

        # Build button
        self.build_button = QtWidgets.QPushButton("Build Eye Rig")
        self.export_button = QtWidgets.QPushButton("Export Config to json")

    def create_layout(self):

        # Eyeball Layout
        eyeball_layout = QtWidgets.QHBoxLayout()
        eyeball_layout.setContentsMargins(1, 1, 1, 1)
        eyeball_layout.addWidget(self.eyeball_label)
        eyeball_layout.addWidget(self.eyeball_lineEdit)
        eyeball_layout.addWidget(self.eyeball_button)

        # Edge Loop Layout
        edgeloop_layout = QtWidgets.QHBoxLayout()
        edgeloop_layout.setContentsMargins(1, 1, 1, 1)
        edgeloop_layout.addWidget(self.edgeloop_label)
        edgeloop_layout.addWidget(self.edgeloop_lineEdit)
        edgeloop_layout.addWidget(self.edgeloop_button)

        # Geometry Input Layout
        geometryInput_layout = QtWidgets.QVBoxLayout()
        geometryInput_layout.setContentsMargins(6, 1, 6, 2)
        geometryInput_layout.addLayout(eyeball_layout)
        geometryInput_layout.addLayout(edgeloop_layout)
        self.geometryInput_group.setLayout(geometryInput_layout)

        # Blink High Layout
        blinkHeight_layout = QtWidgets.QHBoxLayout()
        blinkHeight_layout.setContentsMargins(1, 1, 1, 1)
        blinkHeight_layout.addWidget(self.blinkHeight_value)
        blinkHeight_layout.addWidget(self.blinkHeight_slider)
        self.blinkHeigh_group.setLayout(blinkHeight_layout)

        # joints Layout
        headJnt_layout = QtWidgets.QHBoxLayout()
        headJnt_layout.addWidget(self.headJnt_label)
        headJnt_layout.addWidget(self.headJnt_lineEdit)
        headJnt_layout.addWidget(self.headJnt_button)

        joints_layout = QtWidgets.QVBoxLayout()
        joints_layout.setContentsMargins(6, 4, 6, 4)
        joints_layout.addLayout(headJnt_layout)
        self.joints_group.setLayout(joints_layout)

        # topological autoskin Layout
        skinLoops_layout = QtWidgets.QGridLayout()
        skinLoops_layout.addWidget(self.rigidLoops_label, 0, 0)
        skinLoops_layout.addWidget(self.falloffLoops_label, 0, 1)
        skinLoops_layout.addWidget(self.rigidLoops_value, 1, 0)
        skinLoops_layout.addWidget(self.falloffLoops_value, 1, 1)

        topoSkin_layout = QtWidgets.QVBoxLayout()
        topoSkin_layout.setContentsMargins(6, 4, 6, 4)
        topoSkin_layout.addWidget(self.topSkin_check, alignment=0)
        topoSkin_layout.addLayout(skinLoops_layout)
        self.topoSkin_group.setLayout(topoSkin_layout)

        # Manual Corners Layout
        intCorner_layout = QtWidgets.QHBoxLayout()
        intCorner_layout.addWidget(self.intCorner_label)
        intCorner_layout.addWidget(self.intCorner_lineEdit)
        intCorner_layout.addWidget(self.intCorner_button)

        extCorner_layout = QtWidgets.QHBoxLayout()
        extCorner_layout.addWidget(self.extCorner_label)
        extCorner_layout.addWidget(self.extCorner_lineEdit)
        extCorner_layout.addWidget(self.extCorner_button)

        manualCorners_layout = QtWidgets.QVBoxLayout()
        manualCorners_layout.setContentsMargins(6, 4, 6, 4)
        manualCorners_layout.addWidget(self.manualCorners_check, alignment=0)
        manualCorners_layout.addLayout(intCorner_layout)
        manualCorners_layout.addLayout(extCorner_layout)
        self.manualCorners_group.setLayout(manualCorners_layout)

        # Options Layout
        parent_layout = QtWidgets.QHBoxLayout()
        parent_layout.addWidget(self.parent_label)
        parent_layout.addWidget(self.parent_lineEdit)
        parent_layout.addWidget(self.parent_button)
        offset_layout = QtWidgets.QHBoxLayout()
        offset_layout.addWidget(self.ctlShapeOffset_label)
        offset_layout.addWidget(self.ctlShapeOffset_value)
        ctlGrp_layout = QtWidgets.QHBoxLayout()
        ctlGrp_layout.addWidget(self.ctlGrp_label)
        ctlGrp_layout.addWidget(self.ctlGrp_lineEdit)
        ctlGrp_layout.addWidget(self.ctlGrp_button)
        deformersGrp_layout = QtWidgets.QHBoxLayout()
        deformersGrp_layout.addWidget(self.deformersGrp_label)
        deformersGrp_layout.addWidget(self.deformersGrp_lineEdit)
        deformersGrp_layout.addWidget(self.deformersGrp_button)

        options_layout = QtWidgets.QVBoxLayout()
        options_layout.setContentsMargins(6, 1, 6, 2)
        options_layout.addLayout(parent_layout)
        options_layout.addLayout(offset_layout)
        options_layout.addWidget(self.blinkHeigh_group)
        options_layout.addWidget(self.sideRange_check)
        options_layout.addLayout(ctlGrp_layout)
        options_layout.addLayout(deformersGrp_layout)
        self.options_group.setLayout(options_layout)

        # Name prefix
        namePrefix_layout = QtWidgets.QVBoxLayout()
        namePrefix_layout.setContentsMargins(1, 1, 1, 1)
        namePrefix_layout.addWidget(self.prefix_lineEdit)
        self.prefix_group.setLayout(namePrefix_layout)

        # Name prefix
        controlExtension_layout = QtWidgets.QVBoxLayout()
        controlExtension_layout.setContentsMargins(1, 1, 1, 1)
        controlExtension_layout.addWidget(self.control_lineEdit)
        self.control_group.setLayout(controlExtension_layout)

        # Main Layout
        main_layout = QtWidgets.QVBoxLayout()
        main_layout.setContentsMargins(6, 6, 6, 6)
        main_layout.addWidget(self.prefix_group)
        main_layout.addWidget(self.control_group)
        main_layout.addWidget(self.geometryInput_group)
        main_layout.addWidget(self.manualCorners_group)
        main_layout.addWidget(self.options_group)
        main_layout.addWidget(self.joints_group)
        main_layout.addWidget(self.topoSkin_group)
        main_layout.addWidget(self.build_button)
        main_layout.addWidget(self.export_button)

        self.setLayout(main_layout)

    def create_connections(self):
        self.blinkHeight_value.valueChanged[int].connect(
            self.blinkHeight_slider.setValue)
        self.blinkHeight_slider.valueChanged[int].connect(
            self.blinkHeight_value.setValue)

        self.eyeball_button.clicked.connect(partial(self.populate_object,
                                                    self.eyeball_lineEdit))
        self.parent_button.clicked.connect(partial(self.populate_object,
                                                   self.parent_lineEdit))
        self.headJnt_button.clicked.connect(partial(self.populate_object,
                                                    self.headJnt_lineEdit,
                                                    1))

        self.edgeloop_button.clicked.connect(self.populate_edgeloop)

        self.build_button.clicked.connect(self.buildRig)
        self.export_button.clicked.connect(self.exportDict)

        self.intCorner_button.clicked.connect(partial(self.populate_element,
                                                      self.intCorner_lineEdit,
                                                      "vertex"))
        self.extCorner_button.clicked.connect(partial(self.populate_element,
                                                      self.extCorner_lineEdit,
                                                      "vertex"))

        self.ctlGrp_button.clicked.connect(partial(self.populate_element,
                                                   self.ctlGrp_lineEdit,
                                                   "objectSet"))
        self.deformersGrp_button.clicked.connect(partial(
            self.populate_element, self.deformersGrp_lineEdit, "objectSet"))

    # SLOTS ##########################################################
    def populate_element(self, lEdit, oType="transform"):
        if oType == "joint":
            oTypeInst = pm.nodetypes.Joint
        elif oType == "vertex":
            oTypeInst = pm.MeshVertex
        elif oType == "objectSet":
            oTypeInst = pm.nodetypes.ObjectSet
        else:
            oTypeInst = pm.nodetypes.Transform

        oSel = pm.selected()
        if oSel:
            if isinstance(oSel[0], oTypeInst):
                lEdit.setText(oSel[0].name())
            else:
                pm.displayWarning(
                    "The selected element is not a valid %s" % oType)
        else:
            pm.displayWarning("Please select first one %s." % oType)

    def populate_object(self, lEdit, oType=None):
        if oType == 1:
            oType = pm.nodetypes.Joint
        else:
            oType = pm.nodetypes.Transform

        oSel = pm.selected()
        if oSel:
            if isinstance(oSel[0], oType):
                lEdit.setText(oSel[0].name())
            else:
                pm.displayWarning("The selected element is not a valid object")
        else:
            pm.displayWarning("Please select first the  object.")

    def populate_edgeloop(self):
        oSel = pm.selected(fl=1)
        if oSel:
            edgeList = ""
            separator = ""
            for e in oSel:
                if isinstance(e, pm.MeshEdge):
                    if edgeList:
                        separator = ","
                    edgeList = edgeList + separator + str(e)
            if not edgeList:
                pm.displayWarning("Please select first the eyelid edge loop.")
            elif len(edgeList.split(",")) < 4:
                pm.displayWarning("The minimun edge count is 4")
            else:
                self.edgeloop_lineEdit.setText(edgeList)

        else:
            pm.displayWarning("Please select first the eyelid edge loop.")

    def populateDict(self):
        self.buildDict = {}
        blinkH = float(self.blinkHeight_value.value()) / 100.0
        self.buildDict["eye"] = [self.eyeball_lineEdit.text(),
                                 self.edgeloop_lineEdit.text(),
                                 blinkH,
                                 self.prefix_lineEdit.text(),
                                 self.ctlShapeOffset_value.value(),
                                 self.rigidLoops_value.value(),
                                 self.falloffLoops_value.value(),
                                 self.headJnt_lineEdit.text(),
                                 self.topSkin_check.isChecked(),
                                 self.parent_lineEdit.text(),
                                 self.control_lineEdit.text(),
                                 self.sideRange_check.isChecked(),
                                 self.manualCorners_check.isChecked(),
                                 self.intCorner_lineEdit.text(),
                                 self.extCorner_lineEdit.text(),
                                 self.ctlGrp_lineEdit.text(),
                                 self.deformersGrp_lineEdit.text()]

    def buildRig(self):
        self.populateDict()
        eyeRig(*self.buildDict["eye"])

    def exportDict(self):
        self.populateDict()

        data_string = json.dumps(self.buildDict, indent=4, sort_keys=True)
        filePath = pm.fileDialog2(
            dialogStyle=2,
            fileMode=0,
            fileFilter='Eyes Rigger Configuration .eyes (*%s)' % ".eyes")
        if not filePath:
            return
        if not isinstance(filePath, basestring):
            filePath = filePath[0]
        f = open(filePath, 'w')
        f.write(data_string)
        f.close()
Beispiel #8
0
class componentMainSettings(QtWidgets.QDialog, guide.helperSlots):
    valueChanged = QtCore.Signal(int)

    def __init__(self, parent=None):
        super(componentMainSettings, self).__init__()
        # the inspectSettings function set the current selection to the
        # component root before open the settings dialog
        self.root = pm.selected()[0]

        self.mainSettingsTab = mainSettingsTab()

        self.create_controls()
        self.populate_controls()
        self.create_layout()
        self.create_connections()

        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)

    def create_controls(self):
        """
        Create the controls for the component base

        """
        self.tabs = QtWidgets.QTabWidget()
        self.tabs.setObjectName("settings_tab")

        # Close Button
        self.close_button = QtWidgets.QPushButton("Close")

    def populate_controls(self):
        """Populate Controls attribute values

        Populate the controls values from the custom attributes
        of the component.

        """
        # populate tab
        self.tabs.insertTab(0, self.mainSettingsTab, "Main Settings")

        # populate main settings
        self.mainSettingsTab.name_lineEdit.setText(
            self.root.attr("comp_name").get())
        sideSet = ["C", "L", "R"]
        sideIndex = sideSet.index(self.root.attr("comp_side").get())
        self.mainSettingsTab.side_comboBox.setCurrentIndex(sideIndex)
        self.mainSettingsTab.componentIndex_spinBox.setValue(
            self.root.attr("comp_index").get())
        if self.root.attr("useIndex").get():
            self.mainSettingsTab.useJointIndex_checkBox.setCheckState(
                QtCore.Qt.Checked)
        else:
            self.mainSettingsTab.useJointIndex_checkBox.setCheckState(
                QtCore.Qt.Unchecked)
        self.mainSettingsTab.parentJointIndex_spinBox.setValue(
            self.root.attr("parentJointIndex").get())
        self.mainSettingsTab.host_lineEdit.setText(
            self.root.attr("ui_host").get())
        self.mainSettingsTab.subGroup_lineEdit.setText(
            self.root.attr("ctlGrp").get())
        self.mainSettingsTab.joint_offset_x_doubleSpinBox.setValue(
            self.root.attr("joint_rot_offset_x").get())
        self.mainSettingsTab.joint_offset_y_doubleSpinBox.setValue(
            self.root.attr("joint_rot_offset_y").get())
        self.mainSettingsTab.joint_offset_z_doubleSpinBox.setValue(
            self.root.attr("joint_rot_offset_z").get())

        self.refresh_controls()

    def refresh_controls(self):
        joint_names = [
            name.strip()
            for name in self.root.attr("joint_names").get().split(",")
        ]
        if any(joint_names):
            summary = "<b>({0} set)</b>".format(sum(map(bool, joint_names)))
        else:
            summary = "(None)"
        self.mainSettingsTab.jointNames_label.setText("Joint Names " + summary)

    def create_layout(self):
        """
        Create the layout for the component base settings

        """
        return

    def create_connections(self):
        """
        Create the slots connections to the controls functions

        """
        self.close_button.clicked.connect(self.close_settings)

        self.mainSettingsTab.name_lineEdit.editingFinished.connect(
            self.updateComponentName)
        self.mainSettingsTab.side_comboBox.currentIndexChanged.connect(
            self.updateComponentName)
        self.mainSettingsTab.componentIndex_spinBox.valueChanged.connect(
            self.updateComponentName)
        self.mainSettingsTab.useJointIndex_checkBox.stateChanged.connect(
            partial(self.updateCheck,
                    self.mainSettingsTab.useJointIndex_checkBox, "useIndex"))
        self.mainSettingsTab.parentJointIndex_spinBox.valueChanged.connect(
            partial(self.updateSpinBox,
                    self.mainSettingsTab.parentJointIndex_spinBox,
                    "parentJointIndex"))
        self.mainSettingsTab.host_pushButton.clicked.connect(
            partial(self.updateHostUI, self.mainSettingsTab.host_lineEdit,
                    "ui_host"))
        self.mainSettingsTab.subGroup_lineEdit.editingFinished.connect(
            partial(self.updateLineEdit,
                    self.mainSettingsTab.subGroup_lineEdit, "ctlGrp"))
        self.mainSettingsTab.jointNames_pushButton.clicked.connect(
            self.joint_names_dialog)

        self.mainSettingsTab.joint_offset_x_doubleSpinBox.valueChanged.connect(
            partial(self.updateSpinBox,
                    self.mainSettingsTab.joint_offset_x_doubleSpinBox,
                    "joint_rot_offset_x"))
        self.mainSettingsTab.joint_offset_y_doubleSpinBox.valueChanged.connect(
            partial(self.updateSpinBox,
                    self.mainSettingsTab.joint_offset_y_doubleSpinBox,
                    "joint_rot_offset_y"))
        self.mainSettingsTab.joint_offset_z_doubleSpinBox.valueChanged.connect(
            partial(self.updateSpinBox,
                    self.mainSettingsTab.joint_offset_z_doubleSpinBox,
                    "joint_rot_offset_z"))

    def joint_names_dialog(self):
        dialog = JointNames(self.root, self)
        dialog.setWindowTitle(self.windowTitle())
        dialog.attributeChanged.connect(self.refresh_controls)
        dialog.show()
Beispiel #9
0
class valueBox(QtWidgets.QDoubleSpinBox):
    """Custom QDoubleSpinBox

    Custom SpinBox with Houdini Style draggers, :obj:`draggers`.
    Middle Click to display a bunch of draggers to change value by
    adding different delta values

    Extends:
        QtWidgets.QDoubleSpinBox
    """
    valueIncremented = QtCore.Signal(object)

    def __init__(self,
                 labelText="",
                 type="float",
                 buttons=False,
                 decimals=3,
                 draggerSteps=FLOAT_SLIDER_DRAG_STEPS,
                 *args,
                 **kwargs):
        """
        :param type: Choose if create a float or int spinBox,
            defaults to "float"
        :type type: str, optional
        :param buttons: Show or hidden right up/Down Buttons, defaults to False
        :type buttons: bool, optional
        :param decimals: Number of decimals if type is "float", defaults to 3
        :type decimals: int, optional
        :param *args: [description]
        :type *args: [type]
        :param **kwargs: [description]
        :type **kwargs: [type]
        """
        super(valueBox, self).__init__(*args, **kwargs)
        self.labelFont = QtGui.QFont('Serif', 10, QtGui.QFont.Bold)
        self.labelText = labelText
        self.draggerSteps = copy(draggerSteps)
        self.isFloat = type == "float"
        if not self.isFloat:
            self.setDecimals(0)
        else:
            self.setDecimals(decimals)
        if not buttons:
            self.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        self.setStyleSheet(getSliderStyleSheet("sliderStyleSheetA"))
        self.lineEdit().installEventFilter(self)
        self.installEventFilter(self)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.draggers = None
        self.setRange(FLOAT_RANGE_MIN, FLOAT_RANGE_MAX)

    def paintEvent(self, event):
        super(valueBox, self).paintEvent(event)
        p = QtGui.QPainter()
        p.begin(self)
        p.setPen(Colors.DarkGray)
        p.setFont(self.labelFont)
        p.drawText(self.rect(), QtCore.Qt.AlignCenter, self.labelText)
        p.end()

    def wheelEvent(self, event):
        if not self.hasFocus():
            event.ignore()
        else:
            super(valueBox, self).wheelEvent(event)

    def onValueIncremented(self, step):
        self.valueIncremented.emit(step)
        val = self.value() + step
        self.setValue(val)

    def eventFilter(self, object, event):
        if event.type() == QtCore.QEvent.MouseButtonPress:
            if event.button() == QtCore.Qt.MiddleButton:
                if self.draggers is None:
                    self.draggers = draggers(self,
                                             self.isFloat,
                                             draggerSteps=self.draggerSteps)
                    self.draggers.increment.connect(self.onValueIncremented)
                self.draggers.show()
                if self.isFloat:
                    self.draggers.move(
                        self.mapToGlobal(
                            QtCore.QPoint(
                                event.pos().x() - 1,
                                event.pos().y() - self.draggers.height() / 2)))
                else:
                    self.draggers.move(
                        self.mapToGlobal(
                            QtCore.QPoint(
                                event.pos().x() - 1,
                                event.pos().y()
                                - self.draggers.height()
                                + 15)))
        return False

    def update(self):
        self.setStyleSheet(getSliderStyleSheet("sliderStyleSheetA"))
        super(valueBox, self).update()
Beispiel #10
0
class pyf_Slider(QtWidgets.QWidget):
    """Custom Slider that encapsulates a :obj:`slider` or a :obj:`DoubleSlider`
    and a :obj:`valueBox` linked together

    Signals:
        :valueChanged: Signal emitted when slider or valueBox value changes,
        int/float
    """
    valueChanged = QtCore.Signal(object)
    sliderPressed = QtCore.Signal()
    sliderReleased = QtCore.Signal()

    def __init__(self,
                 parent,
                 Type="float",
                 style=0,
                 name=None,
                 sliderRange=(-100.0, 100.0),
                 defaultValue=0.0,
                 draggerSteps=FLOAT_SLIDER_DRAG_STEPS,
                 *args):
        """
        :param parent: Parent Widget
        :type parent: QtWidgets.QWidget
        :param type: Choose if create a float or int Slider, defaults
            to "float"
        :type type: str, optional
        :param style: Choose looking style, 0 is a full colored xsi style
            slider, and 1 is a normal colored slider, defaults to 0
        :type style: number, optional
        :param name: Name to display in a label, if None no label created,
            defaults to None
        :type name: [type], optional
        :param *args: [description]
        :type *args: [type]
        """
        super(pyf_Slider, self).__init__(parent=parent, *args)
        self.parent = parent
        self.setLayout(QtWidgets.QHBoxLayout())
        self.input = valueBox(type=Type)
        self.input.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        self.input.valueIncremented.connect(self.incrementValue)
        self.input.setValue(defaultValue)
        self.type = Type

        if self.type in ATTR_SLIDER_TYPES:
            self.sld = DoubleSlider(self,
                                    defaultValue=defaultValue,
                                    sliderRange=sliderRange,
                                    draggerSteps=draggerSteps)
        if self.type == "int":
            self.sld = slider(self, sliderRange=sliderRange)
        self.sld.valueIncremented.connect(self.incrementValue)

        self.input.setRange(sliderRange[0], sliderRange[1])

        self.layout().setContentsMargins(0, 0, 0, 0)
        self.input.setContentsMargins(0, 0, 0, 0)
        self.sld.setContentsMargins(0, 0, 0, 0)
        self.label = None
        if name:
            self.label = QtWidgets.QLabel(name + "  ")
            self.layout().addWidget(self.label)
        self.layout().addWidget(self.input)
        self.layout().addWidget(self.sld)
        h = 17
        self.input.setMinimumWidth(50)
        self.input.setMaximumWidth(50)
        self.setMaximumHeight(h)
        self.setMinimumHeight(h)
        self.sld.setMaximumHeight(h)
        self.sld.setMinimumHeight(h)
        self.input.setMaximumHeight(h)
        self.input.setMinimumHeight(h)
        self.styleSheetType = style
        if self.styleSheetType == 0:
            self.layout().setSpacing(0)
            self.sld.setStyleSheet(getSliderStyleSheet("sliderStyleSheetA"))
        elif self.styleSheetType == 1:
            self.sld.setStyleSheet(getSliderStyleSheet("sliderStyleSheetB"))

        self.sld.valueChanged.connect(self.sliderValueChanged)
        self.sld.sliderPressed.connect(self.signalSliderPressed)
        self.sld.sliderReleased.connect(self.signalSliderReleased)
        self.input.valueChanged.connect(self.valBoxValueChanged)

        self._value = 0.0

    def signalSliderPressed(self):
        self.sliderPressed.emit()

    def signalSliderReleased(self):
        self.sliderReleased.emit()

    def sliderValueChanged(self, x):

        outValue = mapRangeUnclamped(x,
                                     float(self.sld.minimum()),
                                     float(self.sld.maximum()),
                                     self.input.minimum(),
                                     self.input.maximum())
        self.input.blockSignals(True)
        self.input.setValue(outValue)
        self.input.blockSignals(False)
        self.valueChanged.emit(outValue)

    def valBoxValueChanged(self, x):
        val = self.input.value()

        sv = mapRangeUnclamped(val,
                               self.input.minimum(),
                               self.input.maximum(),
                               self.sld.minimum(),
                               self.sld.maximum())
        self.sld.blockSignals(True)
        self.sld.setValue(int(sv))
        self.sld.blockSignals(False)
        self.valueChanged.emit(x)

    def update(self):
        if self.styleSheetType == 0:
            self.layout().setSpacing(0)
            self.sld.setStyleSheet(getSliderStyleSheet("sliderStyleSheetA"))
        elif self.styleSheetType == 1:
            self.sld.setStyleSheet(getSliderStyleSheet("sliderStyleSheetB"))
        super(pyf_Slider, self).update()

    @property
    def _value_range(self):
        return self.maximum - self.minimum

    @property
    def minimum(self):
        return self.input.minimum()

    @property
    def maximum(self):
        return self.input.maximum()

    def value(self):
        self._value = self.input.value()
        if self.type == "int":
            self._value = int(self._value)
        return self._value

    def incrementValue(self, delta):
        if delta == 0.0:
            return
        old = self.input.value()
        new = old + delta
        self.input.setValue(new)
        self.valueChanged.emit(new)

    def setValue(self, value):
        self.input.setValue(value)
        self._value = self.input.value()
        self.valueChanged.emit(self.value())
        self.valBoxValueChanged(0)

    def setMinimum(self, value):
        self.input.setMinimum(value)
        self.sld.setMinimum(value)
        pass

    def setMaximum(self, value):
        self.input.setMaximum(value)
        self.sld.setMaximum(value)
        # pass

    def getRange(self):
        return [self.input.minimum(), self.input.maximum()]

    def setRange(self, min, max):
        """Sets the range for the input value, real max and min range

        :param min: Minimum Value
        :type min: float/int
        :param max: Maximum Value
        :type max: float/int
        """
        # self.setMinimum(min)
        # self.setMaximum(max)
        self.input.setRange(min, max)
        self.sld.setRange(min, max)

    def setDisplayMinimun(self, value):
        """Sets the Minimum value for display options, real min value don't
        touched, if current value is less than this display value,Widget
        automatically recalculates minDisplay

        :param value: New Display MinValue
        :type value: float/int
        """
        # self._dispMin = value
        # self.sld.setMinimum(value)
        pass

    def setDisplayMaximum(self, value):
        """Sets the Maximum value for display options, real max value don't
        touched, if current value is bigger than this display value,Widget
        automatically recalculates maxDisplay

        :param value: New Display MaxValue
        :type value: float/int
        """
        # self._dispMax = value
        # self.sld.setMaximum(value)
        pass

    def setDecimals(self, decimals):
        self.input.setDecimals(decimals)
        # if type != "int":
        #     self.sld.setDecimals(decimals)

    def setSingleStep(self, step):
        self.input.setSingleStep(step)

    def hideLabel(self):
        """Hides Name label
        """
        if self.label:
            self.label.hide()

    def showLabel(self):
        """Shows Name label
        """
        if self.label:
            self.label.show()

    def hideSlider(self):
        """Hides Slider
        """
        self.sld.hide()

    def showSlider(self):
        """Show Slider
        """
        self.sld.show()
Beispiel #11
0
class DoubleSlider(slider):
    doubleValueChanged = QtCore.Signal(float)

    def __init__(self, parent=None,
                 sliderRange=(-100.0, 100.0),
                 defaultValue=0.0,
                 dencity=1000000,
                 draggerSteps=FLOAT_SLIDER_DRAG_STEPS):
        super(DoubleSlider, self).__init__(parent,
                                           draggerSteps=draggerSteps,
                                           sliderRange=sliderRange)
        self.isFloat = True
        self._dencity = abs(dencity)
        self.setOrientation(QtCore.Qt.Horizontal)

        self.defaultValue = defaultValue

        # set internal int slider range (dencity)
        self.setMinimum(0)
        self.setMaximum(self._dencity)

        # set out range
        self.valueChanged.connect(self.onInternalValueChanged)
        self.valueIncremented.connect(self.onValueIncremented)
        self.setMappedValue(self.defaultValue, True)

    def setRange(self, min_val, max_val):
        # implement a dummny setRange to avoid integer interpolation in
        # the slider
        # NOTE: not 100% sure why this should be override
        pass

    def onValueIncremented(self, step):
        # convert step value to slider internal space
        sliderInternalRange = (self.minimum(), self.maximum())
        sliderDistance = max(sliderInternalRange) - min(sliderInternalRange)
        valueDistance = max(self.sliderRange) - min(self.sliderRange)
        factor = sliderDistance / valueDistance
        unMappedStep = step * factor

        currentInternalValue = self.value()
        newUnmappedValue = currentInternalValue + unMappedStep
        self.setValue(newUnmappedValue)

    def mappedValue(self):
        return self.mapValue(self.value())

    def setMappedValue(self, value, blockSignals=False):
        # convert mapped value to slider internal integer
        internalValue = self.unMapValue(value)

        if blockSignals:
            self.blockSignals(True)

        self.setValue(internalValue)

        if self.signalsBlocked() and blockSignals:
            self.blockSignals(False)

    def mapValue(self, inValue):
        # convert slider int value to slider float range value
        return mapRangeUnclamped(inValue,
                                 self.minimum(),
                                 self.maximum(),
                                 self.sliderRange[0],
                                 self.sliderRange[1])

    def unMapValue(self, outValue):
        # convert mapped float value to slider integer
        return int(mapRangeUnclamped(outValue,
                                     self.sliderRange[0],
                                     self.sliderRange[1],
                                     self.minimum(),
                                     self.maximum()))

    def onInternalValueChanged(self, x):
        mappedValue = self.mapValue(x)
        self.doubleValueChanged.emit(mappedValue)
Beispiel #12
0
class slider(QtWidgets.QSlider):
    """Customized Int QSlider

    Re implements QSlider adding a few enhancements

    Modifiers:
        :Left/Mid:  Click to move handle
        :Ctrl:  and drag to move handle half velocity
        :Shift:  and drag to move handle quarter velocity
        :Ctrl+Shift:  and drag to move handle eighth velocity

    Extends:
        QtWidgets.QSlider
    """
    editingFinished = QtCore.Signal()
    valueIncremented = QtCore.Signal(object)
    floatValueChanged = QtCore.Signal(object)

    def __init__(self, parent=None,
                 draggerSteps=INT_SLIDER_DRAG_STEPS,
                 sliderRange=[-100, 100],
                 *args,
                 **kwargs):
        super(slider, self).__init__(parent, **kwargs)
        self.sliderRange = sliderRange
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.setOrientation(QtCore.Qt.Horizontal)
        self.draggerSteps = draggerSteps
        self.isFloat = False
        self.deltaValue = 0
        self.startDragpos = QtCore.QPointF()
        self.realStartDragpos = QtCore.QPointF()
        self.LeftButton = QtCore.Qt.LeftButton
        self.MidButton = QtCore.Qt.MidButton
        self.draggers = None
        # if SessionDescriptor().software == "maya":
        self.LeftButton = QtCore.Qt.MidButton
        self.MidButton = QtCore.Qt.LeftButton
        self.defaultValue = 0

        self.setRange(self.sliderRange[0], self.sliderRange[1])

    def mousePressEvent(self, event):
        self.prevValue = self.value()
        self.startDragpos = event.pos()

        emodif = event.modifiers()
        modif = [QtCore.Qt.ControlModifier,
                 QtCore.Qt.ShiftModifier,
                 QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier]

        if event.button() == QtCore.Qt.MidButton:
            if self.draggers is None:
                self.draggers = draggers(self,
                                         self.isFloat,
                                         draggerSteps=self.draggerSteps)
                self.draggers.increment.connect(self.valueIncremented.emit)
            self.draggers.show()
            if self.isFloat:
                self.draggers.move(
                    self.mapToGlobal(
                        QtCore.QPoint(
                            event.pos().x() - 1,
                            event.pos().y() - self.draggers.height() / 2)))
            else:
                self.draggers.move(
                    self.mapToGlobal(
                        QtCore.QPoint(
                            event.pos().x() - 1,
                            event.pos().y() - (self.draggers.height()
                                               - self.draggers.height()
                                               / 6))))

        elif event.button() == self.LeftButton and emodif not in modif:
            butts = QtCore.Qt.MouseButtons(self.MidButton)
            nevent = QtGui.QMouseEvent(event.type(), event.pos(),
                                       self.MidButton, butts,
                                       event.modifiers())
            super(slider, self).mousePressEvent(nevent)

        elif emodif in modif:
            st_slider = QtWidgets.QStyleOptionSlider()
            st_slider.initFrom(self)
            st_slider.orientation = self.orientation()
            available = self.style().pixelMetric(
                QtWidgets.QStyle.PM_SliderSpaceAvailable,
                st_slider, self)
            xloc = QtWidgets.QStyle.sliderPositionFromValue(
                self.minimum(),
                self.maximum(),
                super(slider, self).value(),
                available)
            butts = QtCore.Qt.MouseButtons(self.MidButton)
            newPos = QtCore.QPointF()
            newPos.setX(xloc)
            nevent = QtGui.QMouseEvent(event.type(), newPos,
                                       self.MidButton, butts,
                                       event.modifiers())
            self.startDragpos = newPos
            self.realStartDragpos = event.pos()
            super(slider, self).mousePressEvent(nevent)
            self.deltaValue = self.value() - self.prevValue
            self.setValue(self.prevValue)
        else:
            super(slider, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        deltaX = event.pos().x() - self.realStartDragpos.x()
        deltaY = event.pos().y() - self.realStartDragpos.y()
        newPos = QtCore.QPointF()

        modif = [QtCore.Qt.ControlModifier,
                 QtCore.Qt.ShiftModifier,
                 QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier]
        modif_ctl_shift = QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier

        if event.modifiers() in modif:
            if event.modifiers() == QtCore.Qt.ControlModifier:
                newPos.setX(self.startDragpos.x() + deltaX / 2)
                newPos.setY(self.startDragpos.y() + deltaY / 2)
            elif event.modifiers() == QtCore.Qt.ShiftModifier:
                newPos.setX(self.startDragpos.x() + deltaX / 4)
                newPos.setY(self.startDragpos.y() + deltaY / 4)
            elif event.modifiers() == modif_ctl_shift:
                newPos.setX(self.startDragpos.x() + deltaX / 8)
                newPos.setY(self.startDragpos.y() + deltaY / 8)
            nevent = QtGui.QMouseEvent(event.type(), newPos,
                                       event.button(), event.buttons(),
                                       event.modifiers())
            super(slider, self).mouseMoveEvent(nevent)
            self.setValue(self.value() - self.deltaValue)
        else:
            super(slider, self).mouseMoveEvent(event)

    def wheelEvent(self, event):
        if not self.hasFocus():
            event.ignore()
        else:
            super(slider, self).wheelEvent(event)

    def keyPressEvent(self, event):
        p = self.mapFromGlobal(QtGui.QCursor.pos())
        self.startDragpos = p
        self.realStartDragpos = p
        self.deltaValue = 0
        super(slider, self).keyPressEvent(event)
Beispiel #13
0
class draggers(QtWidgets.QWidget):
    """PopUp Draggers Houdini Style

    Custom Widget that holds a bunch of :obj:`inputDragger` to drag values
    when midClick over field type input widget, Right Drag increments value,
    Left Drag decreases Value
    """

    increment = QtCore.Signal(object)

    def __init__(self,
                 parent=None,
                 isFloat=True,
                 draggerSteps=FLOAT_SLIDER_DRAG_STEPS):
        super(draggers, self).__init__(parent)
        self.initialPos = None
        self.setLayout(QtWidgets.QVBoxLayout())
        self.layout().setSpacing(0)
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.setWindowFlags(QtCore.Qt.Popup)
        self.activeDrag = None
        self.lastDeltaX = 0
        self.drags = []
        steps = copy(draggerSteps)
        if not isFloat:
            # if int, cut steps less than 1.0
            steps = list(filter(lambda x: abs(x) >= 1.0, steps))
        for i in steps:
            drag = inputDragger(self, i)
            self.drags.append(drag)
            self.layout().addWidget(drag)
        self.installEventFilter(self)

    def eventFilter(self, object, event):
        if event.type() == QtCore.QEvent.MouseMove:
            if self.activeDrag:
                modifiers = event.modifiers()
                self.activeDrag.setStyleSheet(
                    getSliderStyleSheet("draggerstyleSheetHover"))
                if self.initialPos is None:
                    self.initialPos = event.globalPos()
                deltaX = event.globalPos().x() - self.initialPos.x()
                self._changeDirection = clamp(deltaX - self.lastDeltaX,
                                              -1.0,
                                              1.0)

                if self._changeDirection != 0:
                    v = self._changeDirection * self.activeDrag._factor

                    if modifiers == QtCore.Qt.NoModifier and deltaX % 4 == 0:
                        self.increment.emit(v)
                    modif = [QtCore.Qt.ShiftModifier,
                             QtCore.Qt.ControlModifier]
                    if modifiers in modif and deltaX % 8 == 0:
                        self.increment.emit(v)
                    modif = QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier
                    if modifiers == modif and deltaX % 32 == 0:
                        self.increment.emit(v)

                self.lastDeltaX = deltaX

        if event.type() == QtCore.QEvent.MouseButtonRelease:
            self.hide()
            self.lastDeltaX = 0
            del(self)
        return False
Beispiel #14
0
class softTweakManager(MayaQWidgetDockableMixin, QtWidgets.QDialog):

    valueChanged = QtCore.Signal(int)

    def __init__(self, parent=None):
        self.toolName = "softTweakManager"
        super(softTweakManager, self).__init__(parent)
        self.stUIInst = softTweakManagerUI()

        self.__proxyModel = QtCore.QSortFilterProxyModel(self)
        self.stUIInst.softTweak_listView.setModel(self.__proxyModel)

        self.setup_softTweakManagerrWindow()
        self.create_layout()
        self.create_connections()
        self._refreshList()

        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
        self.installEventFilter(self)

    def keyPressEvent(self, event):
        if not event.key() == QtCore.Qt.Key_Escape:
            super(softTweakManager, self).keyPressEvent(event)

    def setup_softTweakManagerrWindow(self):

        self.setObjectName(self.toolName)
        self.setWindowFlags(QtCore.Qt.Window)
        self.setWindowTitle("Animbits: SoftTweak Manager")
        self.resize(400, 600)

    def create_layout(self):

        self.stm_layout = QtWidgets.QVBoxLayout()
        self.stm_layout.addWidget(self.stUIInst)

        self.setLayout(self.stm_layout)

    def setSourceModel(self, model):
        self.__proxyModel.setSourceModel(model)

    ####################
    # Helper functions
    ####################

    # export selected softTweaker configuration from selected on the list
    def _exportSelectedConfigurationFromList(self):
        softMods = None
        exportConfiguration(softMods)
        return

    # export all the softTweaks in the list
    def _exportAllFromList(self):
        softMods = None
        exportConfiguration(softMods)
        return

    def _refreshList(self):
        model = QtGui.QStandardItemModel(self)
        is_asset = self.stUIInst.isAsset_checkBox.isChecked()
        for t_node in _listSoftModTweaks(is_asset):
            model.appendRow(QtGui.QStandardItem(t_node.name()))
        self.setSourceModel(model)

    def _getSelectedListIndexes(self):
        softMods = []
        for x in self.stUIInst.softTweak_listView.selectedIndexes():
            try:
                softMods.append(pm.PyNode(x.data()))

            except pm.MayaNodeError:
                pm.displayWarning("{}  can't be find.".format(x.data()))
                return False
        return softMods

    ###########################
    # create connections SIGNALS
    ###########################
    def create_connections(self):
        self.stUIInst.search_lineEdit.textChanged.connect(self.filterChanged)
        self.stUIInst.refresh_pushButton.clicked.connect(self.refreshList)
        self.stUIInst.addObjectToTweak_pushButton.clicked.connect(self.addObj)
        self.stUIInst.removeObjFromTweak_pushButton.clicked.connect(
            self.removeObj)
        self.stUIInst.auto_pushButton.clicked.connect(self.autoTweak)
        self.stUIInst.setParent_pushButton.clicked.connect(self.setTweakParent)
        self.stUIInst.setCtrlGrp_pushButton.clicked.connect(self.setCtlGrp)
        self.stUIInst.newTweak_pushButton.clicked.connect(self.newTweak)
        self.stUIInst.delete_pushButton.clicked.connect(self.deleteTweak)
        self.stUIInst.selectObjectsFromTweak_pushButton.clicked.connect(
            self.selectectAffected)
        self.stUIInst.selectCtlBase_pushButton.clicked.connect(
            self.selectBaseCtl)
        self.stUIInst.selectCtl_pushButton.clicked.connect(self.selectCtl)

        self.stUIInst.isAsset_checkBox.clicked.connect(self._refreshList)

        # actions
        self.stUIInst.exportSelected_action.triggered.connect(
            self.exportSelection)
        self.stUIInst.exportAll_action.triggered.connect(self.exportAll)
        self.stUIInst.import_action.triggered.connect(self.importConfiguration)

        # Misc
        self.stUIInst.name_lineEdit.textChanged.connect(
            self.name_text_changed)
        self.stUIInst.customExt_lineEdit.textChanged.connect(
            self.nameExt_text_changed)
        self.stUIInst.customExt_checkBox.toggled.connect(
            self.stUIInst.customExt_lineEdit.setEnabled)

    #############
    # SLOTS
    #############
    @staticmethod
    def _validate_name(name):
        # check and correct bad formating
        return string.removeInvalidCharacter(name)

    def name_text_changed(self):
        name = self._validate_name(self.stUIInst.name_lineEdit.text())
        self.stUIInst.name_lineEdit.setText(name)

    def nameExt_text_changed(self):
        name = self._validate_name(self.stUIInst.customExt_lineEdit.text())
        self.stUIInst.customExt_lineEdit.setText(name)

    def filterChanged(self, filter):
        regExp = QtCore.QRegExp(filter,
                                QtCore.Qt.CaseSensitive,
                                QtCore.QRegExp.Wildcard
                                )
        self.__proxyModel.setFilterRegExp(regExp)

    # FILE MENU COMMANDS
    # export from list ui
    def exportSelection(self):
        softMods = self._getSelectedListIndexes()
        exportConfiguration(softMods)

    def exportAll(self):
        is_asset = self.stUIInst.isAsset_checkBox.isChecked()
        softMods = _listSoftModTweaks(is_asset)
        exportConfiguration(softMods)

    # import configuration
    def importConfiguration(self):
        # import the configuration
        importConfigurationFromFile()
        # refresh UI list
        self.refreshList()

    # UI BUTTONS
    # refresh the softTweakers list
    def refreshList(self):
        self._refreshList()

    def _addRemoveObj(self, add=True):
        softMods = self._getSelectedListIndexes()
        _addRemoveSoftMode(softMods, pm.selected(), add)

    def addObj(self):
        self._addRemoveObj()

    def removeObj(self):
        self._addRemoveObj(False)

    def _populate_object(self, lEdit, oType=True):
        if oType:
            testInstance = pm.nodetypes.Transform
        else:
            testInstance = pm.nodetypes.ObjectSet

        oSel = pm.selected()
        if oSel:
            if isinstance(oSel[0], testInstance):
                lEdit.setText(oSel[0].name())
            else:
                pm.displayWarning("The selected element is not a valid object")
        else:
            pm.displayWarning("Please select first the element to add.")

    def setCtlGrp(self):
        self._populate_object(self.stUIInst.ctlGrp_lineEdit, False)

    def setTweakParent(self):
        self._populate_object(self.stUIInst.parent_lineEdit)

    def _getIsAssetNameExtSize(self):
        size = self.stUIInst.size_doubleSpinBox.value()
        if self.stUIInst.customExt_checkBox.isChecked():
            nameExt = self.stUIInst.customExt_lineEdit.text()
        else:
            nameExt = "softMod"
        is_asset = self.stUIInst.isAsset_checkBox.isChecked()
        return is_asset, nameExt, size

    def autoTweak(self):
        is_asset, nameExt, size = self._getIsAssetNameExtSize()
        createAutoSoftTweak(size, nameExt, is_asset)
        self._refreshList()

    def newTweak(self):
        name = self.stUIInst.name_lineEdit.text()
        if not name:
            pm.displayWarning("please define the name before create "
                              "the softTweak.")
            return
        grp = self.stUIInst.ctlGrp_lineEdit.text()
        parent = self.stUIInst.parent_lineEdit.text()
        if parent:
            try:
                p = pm.PyNode(parent)
                trans = p.getMatrix(worldSpace=True)

            except pm.MayaNodeError:
                pm.displayWarning("{} is not a valid parent or doesn't "
                                  "exist".format(parent))
                return
        else:
            trans = datatypes.Matrix()
        try:
            oSel = [x for x in pm.selected()
                    if x.getShape().type()
                    in ["mesh", "nurbsSurface"]]
        except pm.MayaNodeError:
            pm.displayError("Some objects on the current selection are "
                            "not valid. Please review the selection")
            return

        is_asset, nameExt, size = self._getIsAssetNameExtSize()
        createSoftTweak(name,
                        targets=oSel,
                        parent=parent,
                        t=trans,
                        grp=grp,
                        size=size,
                        nameExt=nameExt,
                        is_asset=is_asset)
        self._refreshList()
        pm.select(oSel, r=True)

    # delete the selected tweaks and the relative controls
    # What happen if the controls have more child objects?
    # like tweaks under tweaks
    def deleteTweak(self):
        option = pm.confirmDialog(title='Delete Tweak,',
                                  message='Are you sure?',
                                  button=['Delete', 'Cancel'],
                                  defaultButton='Delete',
                                  cancelButton='Cancel',
                                  dismissString='Cancel')
        if option == "Delete":
            softMods = self._getSelectedListIndexes()
            objs = _getPluggetObj(softMods, "ctlRoot")
            pm.delete(softMods)
            pm.delete(objs)
            self._refreshList()

    def selectectAffected(self):
        softMods = self._getSelectedListIndexes()
        aObj = _getAffectedObjects(softMods)
        pm.select(aObj, r=True)

    def selectBaseCtl(self):
        softMods = self._getSelectedListIndexes()
        objs = _getPluggetObj(softMods, "ctlBase")
        pm.select(objs, r=True)

    def selectCtl(self):
        softMods = self._getSelectedListIndexes()
        objs = _getPluggetObj(softMods, "ctlTweak")
        pm.select(objs, r=True)
Beispiel #15
0
class AbstractAnimationTransfer(QtWidgets.QDialog):
    """Abstract animation transfer class"""

    try:
        valueChanged = QtCore.Signal(int)
    except Exception:
        valueChanged = pyqt.pyqtSignal()

    def __init__(self):
        # type: () -> None

        self.comboObj = None               # type: widgets.toggleCombo
        self.comboItems = []               # type: list[str]
        self.model = None                  # type: pm.nodetypes.Transform
        self.uihost = None                 # type: str
        self.switchedAttrShortName = None  # type: str

    def createUI(self, parent=None):
        # type: (QtWidgets.QObject) -> None

        super(AbstractAnimationTransfer, self).__init__(parent)

        self.setWindowTitle("Space Transfer")
        self.setWindowFlags(QtCore.Qt.Tool)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, 1)

        self.create_controls()
        self.create_layout()
        self.create_connections()

    def create_controls(self):
        # type: () -> None

        self.groupBox = QtWidgets.QGroupBox()

        # must be implemented in each specialized classes
        self.setGroupBoxTitle()

        self.onlyKeyframes_check = QtWidgets.QCheckBox('Only Keyframe Frames')
        self.onlyKeyframes_check.setChecked(True)
        self.startFrame_label = QtWidgets.QLabel("Start")
        self.startFrame_value = QtWidgets.QSpinBox()
        self.startFrame_value = QtWidgets.QSpinBox()
        self.startFrame_value.setMinimum(-999999)
        self.startFrame_value.setMaximum(999999)
        self.endFrame_label = QtWidgets.QLabel("End")
        self.endFrame_value = QtWidgets.QSpinBox()
        self.endFrame_value.setMinimum(-999999)
        self.endFrame_value.setMaximum(999999)
        self.populateRange(True)
        self.allFrames_button = QtWidgets.QPushButton("All Frames")
        self.timeSliderFrames_button = QtWidgets.QPushButton(
            "Time Slider Frames")

        self.comboBoxSpaces = QtWidgets.QComboBox()
        self.comboBoxSpaces.addItems(self.comboItems)
        if self.comboObj is not None:
            self.comboBoxSpaces.setCurrentIndex(self.comboObj.currentIndex())

        self.spaceTransfer_button = QtWidgets.QPushButton("Space Transfer")

    def create_layout(self):
        # type: () -> None

        frames_layout = QtWidgets.QHBoxLayout()
        frames_layout.setContentsMargins(1, 1, 1, 1)
        frames_layout.addWidget(self.startFrame_label)
        frames_layout.addWidget(self.startFrame_value)
        frames_layout.addWidget(self.endFrame_label)
        frames_layout.addWidget(self.endFrame_value)

        framesSetter_layout = QtWidgets.QHBoxLayout()
        framesSetter_layout.setContentsMargins(1, 1, 1, 1)
        framesSetter_layout.addWidget(self.allFrames_button)
        framesSetter_layout.addWidget(self.timeSliderFrames_button)

        paremeter_layout = QtWidgets.QVBoxLayout(self.groupBox)
        paremeter_layout.setContentsMargins(6, 5, 6, 5)
        paremeter_layout.addWidget(self.onlyKeyframes_check)
        paremeter_layout.addLayout(frames_layout)
        paremeter_layout.addLayout(framesSetter_layout)
        paremeter_layout.addWidget(self.comboBoxSpaces)
        paremeter_layout.addWidget(self.spaceTransfer_button)

        spaceTransfer_layout = QtWidgets.QVBoxLayout()
        spaceTransfer_layout.addWidget(self.groupBox)

        self.setLayout(spaceTransfer_layout)

    def create_connections(self):
        # type: () -> None

        self.spaceTransfer_button.clicked.connect(self.doItByUI)
        self.allFrames_button.clicked.connect(
            partial(self.populateRange, False))
        self.timeSliderFrames_button.clicked.connect(
            partial(self.populateRange, True))

    # SLOTS ##########################################################

    def populateRange(self, timeSlider=False):
        # type: (bool) -> None
        if timeSlider:
            start = pm.playbackOptions(q=True, min=True)
            end = pm.playbackOptions(q=True, max=True)
        else:
            start = pm.playbackOptions(q=True, ast=True)
            end = pm.playbackOptions(q=True, aet=True)
        self.startFrame_value.setValue(start)
        self.endFrame_value.setValue(end)

    def setComboBoxItemsFormComboObj(self, combo):
        # type: (widegts.toggleCombo) -> None

        del self.comboItems[:]
        for i in range(combo.count() - 1):
            self.comboItems.append(combo.itemText(i))

    def setComboBoxItemsFormList(self, comboList):
        # type: (list[str]) -> None

        del self.comboItems[:]
        for i in range(len(comboList)):
            self.comboItems.append(comboList[i])

    # ----------------------------------------------------------------

    def setGroupBoxTitle(self):
        # type: (str) -> None
        # raise NotImplementedError("must implement transfer
        # in each specialized class")
        pass

    def setComboObj(self, combo):
        # type: (widgets.toggleCombo) -> None
        self.comboObj = combo

    def setModel(self, model):
        # type: (pm.nodetypes.Transform) -> None
        self.model = model
        self.nameSpace = getNamespace(self.model)

    def setUiHost(self, uihost):
        # type: (str) -> None
        self.uihost = uihost

    def setSwitchedAttrShortName(self, attr):
        # type: (str) -> None
        self.switchedAttrShortName = attr

    def getHostName(self):
        # type: () -> str
        return ":".join([self.nameSpace, self.uihost])

    def getWorldMatrices(self, start, end, val_src_nodes):
        # type: (int, int, List[pm.nodetypes.Transform]) ->
        # List[List[pm.datatypes.Matrix]]
        """ returns matrice List[frame][controller number]."""

        res = []
        for x in range(start, end + 1):
            tmp = []
            for n in val_src_nodes:
                tmp.append(pm.getAttr(n + '.worldMatrix', time=x))

            res.append(tmp)

        return res

    def transfer(self, startFrame, endFrame, onlyKeyframes, *args, **kwargs):
        # type: (int, int, bool, *str, **str) -> None
        raise NotImplementedError("must be implemented in each "
                                  "specialized class")

    def doItByUI(self):
        # type: () -> None

        # gather settings from UI
        startFrame = self.startFrame_value.value()
        endFrame = self.endFrame_value.value()
        onlyKeyframes = self.onlyKeyframes_check.isChecked()

        # main body
        self.transfer(startFrame, endFrame, onlyKeyframes)

        # set the new space value in the synoptic combobox
        if self.comboObj is not None:
            self.comboObj.setCurrentIndex(self.comboBoxSpaces.currentIndex())

        for c in pyqt.maya_main_window().children():
            if isinstance(c, AbstractAnimationTransfer):
                c.deleteLater()

    def gather_tangent_informations(self, nodes, channels, startFrame, endFrame):
        # type: (List[pm.nodetypes.Transform], List[str], int, int) -> List[Dict[str, List[str]]]
        """Returns tangent informations, containing ' '."""

        res = []

        for node in nodes:
            tangents = {}
            for attr in channels:

                opts = {
                    "query": True,
                    "attribute": attr
                }
                in_tangents = []
                out_tangents = []

                for i in range(startFrame, endFrame):
                    opts.update({"time": (i, )})
                    in_tangents.append(pm.keyTangent(node, inTangentType=True, **opts))
                    out_tangents.append(pm.keyTangent(node, outTangentType=True, **opts))

                tangents[attr] = [in_tangents, out_tangents]

            res.append(tangents)

        return res

    def restore_tangent_information(self, nodes, infos, startFrame, endFrame):
        # type: (List[pm.nodetypes.Transform], List[Dict[str, List[str]]], int, int) -> None

        for node, info in zip(nodes, infos):

            for attr, tangents in info.iteritems():

                in_val = tangents[0]
                out_val = tangents[1]

                for i in range(len(in_val)):
                    opts = {
                        "edit": True,
                        "attribute": attr,
                        # "index": (i, )
                    }

                    for i in range(startFrame, endFrame):
                        try:
                            if not in_val[i]:
                                continue
                        except:
                            continue

                        opts.update({"time": (i, )})
                        pm.keyTangent(node, inTangentType=in_val[i][0], **opts)
                        pm.keyTangent(node, outTangentType=out_val[i][0], **opts)

    @utils.one_undo
    @utils.viewport_off
    def bakeAnimation(self,
                      switch_attr_name,
                      val_src_nodes,
                      key_src_nodes,
                      key_dst_nodes,
                      startFrame,
                      endFrame,
                      onlyKeyframes=True,
                      restoreTangents=True,
                      channels=["tx", "ty", "tz", "rx", "ry", "rz", "sx", "sy", "sz"]):
        # type: (str, List[pm.nodetypes.Transform],
        # List[pm.nodetypes.Transform],
        # List[pm.nodetypes.Transform], int, int, bool) -> None

        # Temporaly turn off cycle check to avoid misleading cycle message
        # on Maya 2016.  With Maya 2016.5 and 2017 the cycle warning doesn't
        # show up
        if versions.current() < 201650:
            pm.cycleCheck(e=False)
            pm.displayWarning("Maya version older than: 2016.5: "
                              "CycleCheck temporal turn OFF")

        channels = ["tx", "ty", "tz", "rx", "ry", "rz", "sx", "sy", "sz"]
        worldMatrixList = self.getWorldMatrices(startFrame,
                                                endFrame,
                                                val_src_nodes)

        keyframes = pm.keyframe(key_src_nodes, at=["t", "r", "s"], q=True)
        keyframeList = list(set(keyframes))
        keyframeList.sort()

        # store source transform values and key tangents
        worldMatrixList = self.getWorldMatrices(startFrame, endFrame, val_src_nodes)

        if restoreTangents:
            tangents = self.gather_tangent_informations(key_src_nodes, channels, startFrame, endFrame)

        # delete animation in the space switch channel and destination ctrls
        pm.cutKey(key_dst_nodes, at=channels, time=(startFrame, endFrame))
        pm.cutKey(switch_attr_name, time=(startFrame, endFrame))

        for i, x in enumerate(range(startFrame, endFrame + 1)):

            if onlyKeyframes and x not in keyframeList:
                continue

            pm.currentTime(x)

            # set the new space in the channel
            self.changeAttrToBoundValue()

            # bake the stored transforms to the cotrols
            for j, n in enumerate(key_dst_nodes):
                n.setMatrix(worldMatrixList[i][j], worldSpace=True)

            pm.setKeyframe(key_dst_nodes, at=channels)

        if restoreTangents:
            self.restore_tangent_information(key_dst_nodes, tangents, startFrame, endFrame)

        if versions.current() < 201650:
            pm.cycleCheck(e=True)
            pm.displayWarning("CycleCheck turned back ON")
Beispiel #16
0
class channelWrangler(MayaQWidgetDockableMixin, QtWidgets.QDialog):
    """Channel wrangler UI"""

    valueChanged = QtCore.Signal(int)

    def __init__(self, parent=None):
        self.toolName = "ChannelWranglerWindow"

        super(self.__class__, self).__init__(parent=parent)
        self.cwUIInst = cwUI()
        self.table = self.cwUIInst.channelMapping_tableWidget
        self.headerTable = self.table.horizontalHeader()
        # we try setSectionResizeMode for Pyside2 if attributeError
        # setResizeMode for PySide
        for i in [1, 4]:
            try:
                self.headerTable.setSectionResizeMode(
                    i, QtWidgets.QHeaderView.Stretch)
                self.headerTable.setSectionResizeMode(
                    0, QtWidgets.QHeaderView.ResizeToContents)
            except AttributeError:
                self.headerTable.setResizeMode(
                    i, QtWidgets.QHeaderView.Stretch)
                self.headerTable.setResizeMode(
                    0, QtWidgets.QHeaderView.ResizeToContents)

        self.setup_channelWranglerWindow()
        self.create_layout()
        self.create_connections()

        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
        self.installEventFilter(self)

    def keyPressEvent(self, event):
        if not event.key() == QtCore.Qt.Key_Escape:
            super(channelWrangler, self).keyPressEvent(event)

    def setup_channelWranglerWindow(self):
        self.mayaMainWindow = pyqt.maya_main_window()

        self.setObjectName(self.toolName)
        self.setWindowFlags(QtCore.Qt.Window)
        self.setWindowTitle("Channel Wrangler")
        self.resize(750, 525)

    def create_layout(self):

        self.cw_layout = QtWidgets.QVBoxLayout()
        self.cw_layout.addWidget(self.cwUIInst)

        self.setLayout(self.cw_layout)

    ###########################
    # create connections SIGNALS
    ###########################
    def create_connections(self):
        self.cwUIInst.channel_pushButton.clicked.connect(
            self.populateChannelLineEdit)
        self.cwUIInst.target_pushButton.clicked.connect(
            self.populateTargetLineEdit)
        self.cwUIInst.setRow_pushButton.clicked.connect(
            self.setRow)
        self.cwUIInst.setMultiChannel_pushButton.clicked.connect(
            self.setMultiChannel)
        self.cwUIInst.setMultiTarget_pushButton.clicked.connect(
            self.setMultiTarget)
        self.cwUIInst.clearAll_pushButton.clicked.connect(
            self.clearAllRows)
        self.cwUIInst.clearSelectedRows_pushButton.clicked.connect(
            self.clearSelectedRows)
        self.cwUIInst.setMoveOp_pushButton.clicked.connect(
            self.setMoveOperator)
        self.cwUIInst.setProxyOp_pushButton.clicked.connect(
            self.setProxyOperator)
        self.cwUIInst.export_pushButton.clicked.connect(
            self.exportConfig)
        self.cwUIInst.import_pushButton.clicked.connect(
            self.importConfig)
        self.cwUIInst.apply_pushButton.clicked.connect(
            self.applyChannelConfig)

    ##################
    # helper functions
    ##################

    def _setRowItem(self, rowPosition, itemIndex, itemContent):
        """Set the row item

        Args:
            rowPosition (Int): Row Index
            itemIndex (Int): Item Index
            itemContent (Str): Item content

        Returns:
            QTableWidgetItem: Item
        """
        item = QtWidgets.QTableWidgetItem(itemContent)
        self.table.setItem(rowPosition, itemIndex, item)
        return item

    def _setRowChannel(self, rowPosition, channel, source):
        """The source is set at the same time as the channel"""

        self._setRowItem(rowPosition, 0, str(rowPosition).zfill(3))
        self._setRowItem(rowPosition, 1, channel)
        self._setRowItem(rowPosition, 2, source)
        return

    def _setRowTarget(self, rowPosition, target):
        """Set the row target item

        Args:
            rowPosition (int): The row position index
            target (int): the target item index
        """
        self._setRowItem(rowPosition, 3, target)

    def _addNewRow(self, channel=None, source=None, target=None):
        """Add new row to the table

        Args:
            channel (str, optional): The channel to add to the table.
            source (str, optional): The source node that has the channel
                to move.
            target (str, optional): The destionation node for the channel.

        Returns:
            int: The row position index
        """
        rowPosition = self.table.rowCount()
        self.table.insertRow(rowPosition)
        if channel and source:
            self._setRowChannel(rowPosition, channel, source)
        if target:
            self._setRowTarget(rowPosition, target)

        # adding the operation combo box
        operation_comboBox = QtWidgets.QComboBox()
        operation_comboBox.setObjectName("operation")
        operation_comboBox.addItem("Move Channel")
        operation_comboBox.addItem("Proxy Channel")
        operation_comboBox.SizeAdjustPolicy(
            QtWidgets.QComboBox.AdjustToContentsOnFirstShow)
        self.table.setCellWidget(rowPosition, 4, operation_comboBox)
        return rowPosition

    def _getSelectedRowsIndex(self):
        """Return a list with the selected rows index

        Returns:
            List: Selected rows index list
        """
        index_list = []
        for model_index in self.table.selectionModel().selectedRows():
            index = QtCore.QPersistentModelIndex(model_index)
            index_list.append(index)

        return index_list

    def _buildConfigDict(self):
        """build the config dictionary from the UI data

        Returns:
            dic: The channel wrangler map configuration dictionary
        """
        configDict = {}
        mapList = []

        # this list will contain only the 3 main items list to avoid
        # duplicated rules
        checkDuplicatedList = []

        for i in range(self.table.rowCount()):
            checkItems = [self.table.item(i, x + 1).text() for x in range(3)]
            if checkItems not in checkDuplicatedList:
                checkDuplicatedList.append(checkItems)
                rowItems = checkItems + [self.table.cellWidget(
                                         i, 4).currentIndex()]
                mapList.append(rowItems)

        configDict["map"] = mapList
        mpIndex = self.cwUIInst.movePolicy_comboBox.currentIndex()
        configDict["movePolicy"] = ["merge", "index", "fullName"][mpIndex]
        pxyIndex = self.cwUIInst.proxyPolicy_comboBox.currentIndex()
        configDict["proxyPolicy"] = ["index", "fullName"][pxyIndex]
        return configDict

    ###########################
    # SLOTS
    ###########################
    # buttons
    def populateChannelLineEdit(self):
        oSel = pm.selected()
        if oSel:
            chan = attribute.getSelectedChannels(True)[0]
            self.cwUIInst.channel_lineEdit.setText(
                "{}.{}".format(oSel[0].name(), chan))

    def populateTargetLineEdit(self):
        oSel = pm.selected()
        if oSel:
            self.cwUIInst.target_lineEdit.setText(oSel[0].name())

    def setRow(self):
        """Sets a new row

        Sets a new row with the information on the channel and target lineEdit
        """
        fullChanName = self.cwUIInst.channel_lineEdit.text()
        if fullChanName:
            sourceName, chanName = fullChanName.split(".")
        targetName = self.cwUIInst.target_lineEdit.text()
        if fullChanName and targetName:
            # TODO: checker for the new rule, be sure is not duplicated
            self._addNewRow(chanName, sourceName, targetName)
        else:
            pm.displayWarning("Channel and target are not set properly")

    def setMultiChannel(self):
        """sets new rows from the selectec channels. 1 channel for each row"""
        oSel = pm.selected()
        if oSel:
            channels = attribute.getSelectedChannels(True)
            if not channels:
                channels = attribute.getSelectedObjectChannels(
                    oSel[0], True, True)
            for ch in channels:
                self._addNewRow(ch, oSel[0].name(), oSel[0].name())
        else:
            pm.displayWarning("To set the source, you need to select at  "
                              "one source object")

    def setMultiTarget(self):
        """set the target colum for the selected rows

        If only one object is selected will populate all the rows with the
        same object
        If there is more that one object selected, will iterate the selection
        adding one object to each row
        """
        oSel = pm.selected()
        index_list = self._getSelectedRowsIndex()

        if len(oSel) > 1:
            if index_list:
                for index, obj in zip(index_list, oSel):
                    self._setRowTarget(index.row(), obj.name())
        elif len(oSel) == 1:
            if index_list:
                for index in index_list:
                    self._setRowTarget(index.row(), oSel[0].name())
            else:
                for i in reversed(range(self.table.rowCount())):
                    self._setRowTarget(i, oSel[0].name())
        else:
            pm.displayWarning("To set the target, you need to select at less"
                              " one target object")

    def clearSelectedRows(self):
        """Clear selected rows from the table"""

        index_list = self._getSelectedRowsIndex()
        for index in index_list:
            self.table.removeRow(index.row())

    def clearAllRows(self):
        """Clear all the rows"""

        self.table.clear()
        for i in reversed(range(self.table.rowCount())):
            self.table.removeRow(i)

    def exportConfig(self):
        """Export channelWrangler configuration"""
        configDict = self._buildConfigDict()
        data_string = json.dumps(configDict, indent=4, sort_keys=True)
        filePath = pm.fileDialog2(
            fileMode=0,
            fileFilter='Channel Wrangler Configuration .cwc (*%s)' % ".cwc")
        if not filePath:
            return
        if not isinstance(filePath, string_types):
            filePath = filePath[0]
        f = open(filePath, 'w')
        f.write(data_string)
        f.close()

    def importConfig(self):
        """Import channel wrangler configuration"""

        # TODO: if import dict ask to add to the current
        # configuration or replace.
        filePath = pm.fileDialog2(
            fileMode=1,
            fileFilter='Channel Wrangler Configuration .cwc (*%s)' % ".cwc")
        if not filePath:
            return
        if not isinstance(filePath, string_types):
            filePath = filePath[0]
        configDict = json.load(open(filePath))
        # also ask for proxy and move policy if is not the same when we add to
        # the current list
        if self.table.rowCount():
            option = pm.confirmDialog(
                title='Channel Wrangler Configuration Import Style',
                message='Do you want to repace current configuration or'
                        ' add it?\n if add the move policy and proxy policy'
                        ' will not change',
                button=['Replace', 'Add', 'Cancel'],
                defaultButton='Reaplace',
                cancelButton='Cancel',
                dismissString='Cancel')
        else:
            option = "Replace"
        if option == "Replace":
            self.clearAllRows()
            # set move policy
            indexList = ["merge", "index", "fullName"]
            self.cwUIInst.movePolicy_comboBox.setCurrentIndex(
                indexList.index(configDict["movePolicy"]))

            # set proxy policy
            indexList = ["index", "fullName"]
            self.cwUIInst.proxyPolicy_comboBox.setCurrentIndex(
                indexList.index(configDict["proxyPolicy"]))

        for rule in configDict["map"]:
            row_pos = self._addNewRow(channel=rule[0],
                                      source=rule[1],
                                      target=rule[2])

            oCombo = self.table.cellWidget(row_pos, 4)
            oCombo.setCurrentIndex(rule[3])

    # apply the current configuration in the dialog
    def applyChannelConfig(self):
        with pm.UndoChunk():
            configDict = self._buildConfigDict()
            # TODO add checker to avoid error if the datas is not
            # found in the scene
            for rule in configDict["map"]:
                # proxy
                if rule[3]:
                    source = pm.PyNode("{}.{}".format(rule[1], rule[0]))
                    target = pm.PyNode(rule[2])
                    attribute.addProxyAttribute(source,
                                                target,
                                                configDict["proxyPolicy"])
                # move
                else:
                    source = pm.PyNode(rule[1])
                    target = pm.PyNode(rule[2])
                    attribute.moveChannel(rule[0],
                                          source,
                                          target,
                                          configDict["movePolicy"])

    def _setOperator(self, operator):
        """set the channel wrangle operator

        =====   ======================
        index   Operation
        =====   ======================
        0       Move the channel
        1       Create a proxy channel
        =====   ======================

        Args:
            operator (index): Operator to use
        """
        index_list = self._getSelectedRowsIndex()
        if index_list:
            for index in index_list:
                oCombo = self.table.cellWidget(index.row(), 4)
                oCombo.setCurrentIndex(operator)
        else:
            for i in reversed(range(self.table.rowCount())):
                oCombo = self.table.cellWidget(i, 4)
                oCombo.setCurrentIndex(operator)

    def setMoveOperator(self):
        """set the channel wrangler operator to Move
        """
        self._setOperator(0)

    def setProxyOperator(self):
        """set the channel wrangler operator to Proxy
        """
        self._setOperator(1)
Beispiel #17
0
class ui(MayaQWidgetDockableMixin, QtWidgets.QDialog):

    valueChanged = QtCore.Signal(int)

    def __init__(self, parent=None):
        super(ui, self).__init__(parent)

        # File type filter for settings.
        self.filter = "Eyes Rigger Configuration .eyes (*.eyes)"

        self.create()

    def create(self):

        self.setWindowTitle("Eye Rigger 2.0")
        self.setWindowFlags(QtCore.Qt.Window)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, 1)

        self.create_controls()
        self.create_layout()
        self.create_connections()

    def create_controls(self):

        # Geometry input controls
        self.geometryInput_group = QtWidgets.QGroupBox("Geometry Input")
        self.eyeball_label = QtWidgets.QLabel("Eyeball:")
        self.eyeMesh = QtWidgets.QLineEdit()
        self.eyeball_button = QtWidgets.QPushButton("<<")
        self.edgeloop_label = QtWidgets.QLabel("Edge Loop:")
        self.edgeLoop = QtWidgets.QLineEdit()
        self.edgeloop_button = QtWidgets.QPushButton("<<")
        # Manual corners
        self.manualCorners_group = QtWidgets.QGroupBox("Custom Eye Corners")
        self.customCorner = QtWidgets.QCheckBox("Set Manual Vertex Corners")
        self.customCorner.setChecked(False)
        self.intCorner_label = QtWidgets.QLabel("Internal Corner")
        self.intCorner = QtWidgets.QLineEdit()
        self.intCorner_button = QtWidgets.QPushButton("<<")
        self.extCorner_label = QtWidgets.QLabel("External Corner")
        self.extCorner = QtWidgets.QLineEdit()
        self.extCorner_button = QtWidgets.QPushButton("<<")

        # Blink heigh slider
        self.blinkHeight_group = QtWidgets.QGroupBox("Blink Height")
        self.blinkH = QtWidgets.QSpinBox()
        self.blinkH.setRange(0, 100)
        self.blinkH.setSingleStep(10)
        self.blinkH.setValue(20)
        self.blinkHeight_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
        self.blinkHeight_slider.setRange(0, 100)
        self.blinkHeight_slider.setSingleStep(
            self.blinkHeight_slider.maximum() / 10.0)
        self.blinkHeight_slider.setValue(20)

        # vTrack and hTrack
        self.tracking_group = QtWidgets.QGroupBox("Tracking")
        self.upperVTrack = QtWidgets.QDoubleSpinBox()
        self.upperVTrack.setValue(0.02)
        self.upperHTrack = QtWidgets.QDoubleSpinBox()
        self.upperHTrack.setValue(0.01)
        self.lowerVTrack = QtWidgets.QDoubleSpinBox()
        self.lowerVTrack.setValue(0.02)
        self.lowerHTrack = QtWidgets.QDoubleSpinBox()
        self.lowerHTrack.setValue(0.01)

        # Name prefix
        self.prefix_group = QtWidgets.QGroupBox("Name Prefix")
        self.namePrefix = QtWidgets.QLineEdit()
        self.namePrefix.setText("eye")
        self.control_group = QtWidgets.QGroupBox("Control Name Extension")
        self.ctlName = QtWidgets.QLineEdit()
        self.ctlName.setText("ctl")

        # joints
        self.joints_group = QtWidgets.QGroupBox("Joints")
        self.headJnt_label = QtWidgets.QLabel("Head or Eye area Joint:")
        self.headJnt = QtWidgets.QLineEdit()
        self.headJnt_button = QtWidgets.QPushButton("<<")
        self.everyNVertex_label = QtWidgets.QLabel(
            "Create Joint evey N number of Vertex:")
        self.everyNVertex = QtWidgets.QSpinBox()
        self.everyNVertex.setRange(0, 100)
        self.everyNVertex.setSingleStep(1)
        self.everyNVertex.setValue(1)

        # Topological Autoskin
        self.topoSkin_group = QtWidgets.QGroupBox("Skin")
        self.rigidLoops_label = QtWidgets.QLabel("Rigid Loops:")
        self.rigidLoops = QtWidgets.QSpinBox()
        self.rigidLoops.setRange(0, 30)
        self.rigidLoops.setSingleStep(1)
        self.rigidLoops.setValue(2)
        self.falloffLoops_label = QtWidgets.QLabel("Falloff Loops:")
        self.falloffLoops = QtWidgets.QSpinBox()
        self.falloffLoops.setRange(0, 30)
        self.falloffLoops.setSingleStep(1)
        self.falloffLoops.setValue(4)

        self.doSkin = QtWidgets.QCheckBox("Compute Topological Autoskin")
        self.doSkin.setChecked(True)

        # Options
        self.options_group = QtWidgets.QGroupBox("Options")
        self.parent_label = QtWidgets.QLabel("Rig Parent:")
        self.parent_node = QtWidgets.QLineEdit()
        self.parent_button = QtWidgets.QPushButton("<<")
        self.aim_controller_label = QtWidgets.QLabel("Aim Controller:")
        self.aim_controller = QtWidgets.QLineEdit()
        self.aim_controller_button = QtWidgets.QPushButton("<<")
        self.ctlShapeOffset_label = QtWidgets.QLabel("Controls Offset:")
        self.offset = QtWidgets.QDoubleSpinBox()
        self.offset.setRange(0, 10)
        self.offset.setSingleStep(0.05)
        self.offset.setValue(0.05)
        self.sideRange = QtWidgets.QCheckBox(
            "Use Z axis for wide calculation (i.e: Horse and fish side eyes)")
        self.sideRange.setChecked(False)

        self.ctlSet_label = QtWidgets.QLabel("Controls Set:")
        self.ctlSet = QtWidgets.QLineEdit()
        self.ctlSet_button = QtWidgets.QPushButton("<<")

        self.deformersSet_label = QtWidgets.QLabel("Deformers Set:")
        self.defSet = QtWidgets.QLineEdit()
        self.deformersSet_button = QtWidgets.QPushButton("<<")

        self.deformers_group_label = QtWidgets.QLabel("Static Rig Parent:")
        self.deformers_group = QtWidgets.QLineEdit()
        self.deformers_group_button = QtWidgets.QPushButton("<<")

        # Main buttons
        self.build_button = QtWidgets.QPushButton("Build Eye Rig")
        self.import_button = QtWidgets.QPushButton("Import Config from json")
        self.export_button = QtWidgets.QPushButton("Export Config to json")

    def create_layout(self):

        # Eyeball Layout
        eyeball_layout = QtWidgets.QHBoxLayout()
        eyeball_layout.setContentsMargins(1, 1, 1, 1)
        eyeball_layout.addWidget(self.eyeball_label)
        eyeball_layout.addWidget(self.eyeMesh)
        eyeball_layout.addWidget(self.eyeball_button)

        # Edge Loop Layout
        edgeloop_layout = QtWidgets.QHBoxLayout()
        edgeloop_layout.setContentsMargins(1, 1, 1, 1)
        edgeloop_layout.addWidget(self.edgeloop_label)
        edgeloop_layout.addWidget(self.edgeLoop)
        edgeloop_layout.addWidget(self.edgeloop_button)

        # Geometry Input Layout
        geometryInput_layout = QtWidgets.QVBoxLayout()
        geometryInput_layout.setContentsMargins(6, 1, 6, 2)
        geometryInput_layout.addLayout(eyeball_layout)
        geometryInput_layout.addLayout(edgeloop_layout)
        self.geometryInput_group.setLayout(geometryInput_layout)

        # Blink Height Layout
        blinkHeight_layout = QtWidgets.QHBoxLayout()
        blinkHeight_layout.setContentsMargins(1, 1, 1, 1)
        blinkHeight_layout.addWidget(self.blinkH)
        blinkHeight_layout.addWidget(self.blinkHeight_slider)
        self.blinkHeight_group.setLayout(blinkHeight_layout)

        # Tracking Layout
        tracking_layout = QtWidgets.QVBoxLayout()
        layout = QtWidgets.QHBoxLayout()
        layout.addWidget(QtWidgets.QLabel("Upper Vertical"))
        layout.addWidget(self.upperVTrack)
        layout.addWidget(QtWidgets.QLabel("Upper Horizontal"))
        layout.addWidget(self.upperHTrack)
        tracking_layout.addLayout(layout)
        layout = QtWidgets.QHBoxLayout()
        layout.addWidget(QtWidgets.QLabel("Lower Vertical"))
        layout.addWidget(self.lowerVTrack)
        layout.addWidget(QtWidgets.QLabel("Lower Horizontal"))
        layout.addWidget(self.lowerHTrack)
        tracking_layout.addLayout(layout)
        self.tracking_group.setLayout(tracking_layout)

        # joints Layout
        headJnt_layout = QtWidgets.QHBoxLayout()
        headJnt_layout.addWidget(self.headJnt_label)
        headJnt_layout.addWidget(self.headJnt)
        headJnt_layout.addWidget(self.headJnt_button)

        everyNVertex_layout = QtWidgets.QHBoxLayout()
        everyNVertex_layout.addWidget(self.everyNVertex_label)
        everyNVertex_layout.addWidget(self.everyNVertex)

        joints_layout = QtWidgets.QVBoxLayout()
        joints_layout.setContentsMargins(6, 4, 6, 4)
        joints_layout.addLayout(headJnt_layout)
        joints_layout.addLayout(everyNVertex_layout)
        self.joints_group.setLayout(joints_layout)

        # topological autoskin Layout
        skinLoops_layout = QtWidgets.QGridLayout()
        skinLoops_layout.addWidget(self.rigidLoops_label, 0, 0)
        skinLoops_layout.addWidget(self.falloffLoops_label, 0, 1)
        skinLoops_layout.addWidget(self.rigidLoops, 1, 0)
        skinLoops_layout.addWidget(self.falloffLoops, 1, 1)

        topoSkin_layout = QtWidgets.QVBoxLayout()
        topoSkin_layout.setContentsMargins(6, 4, 6, 4)
        topoSkin_layout.addWidget(self.doSkin, alignment=QtCore.Qt.Alignment())
        topoSkin_layout.addLayout(skinLoops_layout)
        self.topoSkin_group.setLayout(topoSkin_layout)

        # Manual Corners Layout
        intCorner_layout = QtWidgets.QHBoxLayout()
        intCorner_layout.addWidget(self.intCorner_label)
        intCorner_layout.addWidget(self.intCorner)
        intCorner_layout.addWidget(self.intCorner_button)

        extCorner_layout = QtWidgets.QHBoxLayout()
        extCorner_layout.addWidget(self.extCorner_label)
        extCorner_layout.addWidget(self.extCorner)
        extCorner_layout.addWidget(self.extCorner_button)

        manualCorners_layout = QtWidgets.QVBoxLayout()
        manualCorners_layout.setContentsMargins(6, 4, 6, 4)
        manualCorners_layout.addWidget(self.customCorner,
                                       alignment=QtCore.Qt.Alignment())
        manualCorners_layout.addLayout(intCorner_layout)
        manualCorners_layout.addLayout(extCorner_layout)
        self.manualCorners_group.setLayout(manualCorners_layout)

        # Options Layout
        parent_layout = QtWidgets.QHBoxLayout()
        parent_layout.addWidget(self.parent_label)
        parent_layout.addWidget(self.parent_node)
        parent_layout.addWidget(self.parent_button)
        parent_layout.addWidget(self.aim_controller_label)
        parent_layout.addWidget(self.aim_controller)
        parent_layout.addWidget(self.aim_controller_button)
        offset_layout = QtWidgets.QHBoxLayout()
        offset_layout.addWidget(self.ctlShapeOffset_label)
        offset_layout.addWidget(self.offset)
        ctlSet_layout = QtWidgets.QHBoxLayout()
        ctlSet_layout.addWidget(self.ctlSet_label)
        ctlSet_layout.addWidget(self.ctlSet)
        ctlSet_layout.addWidget(self.ctlSet_button)
        deformersGrp_layout = QtWidgets.QHBoxLayout()
        deformersGrp_layout.addWidget(self.deformersSet_label)
        deformersGrp_layout.addWidget(self.defSet)
        deformersGrp_layout.addWidget(self.deformersSet_button)
        deformersGrp_layout.addWidget(self.deformers_group_label)
        deformersGrp_layout.addWidget(self.deformers_group)
        deformersGrp_layout.addWidget(self.deformers_group_button)

        options_layout = QtWidgets.QVBoxLayout()
        options_layout.setContentsMargins(6, 1, 6, 2)
        options_layout.addLayout(parent_layout)
        options_layout.addLayout(offset_layout)
        options_layout.addWidget(self.blinkHeight_group)
        options_layout.addWidget(self.tracking_group)
        options_layout.addWidget(self.sideRange)
        options_layout.addLayout(ctlSet_layout)
        options_layout.addLayout(deformersGrp_layout)
        self.options_group.setLayout(options_layout)

        # Name prefix
        namePrefix_layout = QtWidgets.QVBoxLayout()
        namePrefix_layout.setContentsMargins(1, 1, 1, 1)
        namePrefix_layout.addWidget(self.namePrefix)
        self.prefix_group.setLayout(namePrefix_layout)

        # Name prefix
        controlExtension_layout = QtWidgets.QVBoxLayout()
        controlExtension_layout.setContentsMargins(1, 1, 1, 1)
        controlExtension_layout.addWidget(self.ctlName)
        self.control_group.setLayout(controlExtension_layout)

        # Main Layout
        main_layout = QtWidgets.QVBoxLayout()
        main_layout.setContentsMargins(6, 6, 6, 6)
        main_layout.addWidget(self.prefix_group)
        main_layout.addWidget(self.control_group)
        main_layout.addWidget(self.geometryInput_group)
        main_layout.addWidget(self.manualCorners_group)
        main_layout.addWidget(self.options_group)
        main_layout.addWidget(self.joints_group)
        main_layout.addWidget(self.topoSkin_group)
        main_layout.addWidget(self.build_button)
        main_layout.addWidget(self.import_button)
        main_layout.addWidget(self.export_button)

        self.setLayout(main_layout)

    def create_connections(self):
        self.blinkH.valueChanged[int].connect(self.blinkHeight_slider.setValue)
        self.blinkHeight_slider.valueChanged[int].connect(self.blinkH.setValue)

        self.eyeball_button.clicked.connect(
            partial(self.populate_object, self.eyeMesh))
        self.parent_button.clicked.connect(
            partial(self.populate_object, self.parent_node))
        self.aim_controller_button.clicked.connect(
            partial(self.populate_object, self.aim_controller))
        self.headJnt_button.clicked.connect(
            partial(self.populate_object, self.headJnt, 1))

        self.edgeloop_button.clicked.connect(self.populate_edgeloop)

        self.build_button.clicked.connect(self.build_rig)
        self.import_button.clicked.connect(self.import_settings)
        self.export_button.clicked.connect(self.export_settings)

        self.intCorner_button.clicked.connect(
            partial(self.populate_element, self.intCorner, "vertex"))
        self.extCorner_button.clicked.connect(
            partial(self.populate_element, self.extCorner, "vertex"))

        self.ctlSet_button.clicked.connect(
            partial(self.populate_element, self.ctlSet, "objectSet"))
        self.deformersSet_button.clicked.connect(
            partial(self.populate_element, self.defSet, "objectSet"))
        self.deformers_group_button.clicked.connect(
            partial(self.populate_element, self.deformers_group))

    # SLOTS ##########################################################
    def populate_element(self, lEdit, oType="transform"):
        if oType == "joint":
            oTypeInst = pm.nodetypes.Joint
        elif oType == "vertex":
            oTypeInst = pm.MeshVertex
        elif oType == "objectSet":
            oTypeInst = pm.nodetypes.ObjectSet
        else:
            oTypeInst = pm.nodetypes.Transform

        oSel = pm.selected()
        if oSel:
            if isinstance(oSel[0], oTypeInst):
                lEdit.setText(oSel[0].name())
            else:
                pm.displayWarning("The selected element is not a valid %s" %
                                  oType)
        else:
            pm.displayWarning("Please select first one %s." % oType)

    def populate_object(self, lEdit, oType=None):
        if oType == 1:
            oType = pm.nodetypes.Joint
        else:
            oType = pm.nodetypes.Transform

        oSel = pm.selected()
        if oSel:
            if isinstance(oSel[0], oType):
                lEdit.setText(oSel[0].name())
            else:
                pm.displayWarning("The selected element is not a valid object")
        else:
            pm.displayWarning("Please select first the  object.")

    def populate_edgeloop(self):
        self.edgeLoop.setText(lib.get_edge_loop_from_selection())

    def build_rig(self):
        eye_rigger.rig(**lib.get_settings_from_widget(self))

    def export_settings(self):
        data_string = json.dumps(lib.get_settings_from_widget(self),
                                 indent=4,
                                 sort_keys=True)

        file_path = lib.get_file_path(self.filter, "save")
        if not file_path:
            return

        with open(file_path, "w") as f:
            f.write(data_string)

    def import_settings(self):
        file_path = lib.get_file_path(self.filter, "open")
        if not file_path:
            return

        lib.import_settings_from_file(file_path, self)