Ejemplo n.º 1
0
    def _setupFilterGroupBox(self, layout):
        filterGroupBox = QGroupBox(
            maya.stringTable['y_simpleSelector.kCollectionFilters'])
        font = QFont()
        font.setBold(True)
        filterGroupBox.setFont(font)
        filterGroupBox.setContentsMargins(0, utils.dpiScale(12), 0, 0)
        self.filtersGroupBoxLayout = Layout()
        self.filtersGroupBoxLayout.setVerticalSpacing(utils.dpiScale(2))

        self._setupFilterUI(self.filtersGroupBoxLayout)

        filterGroupBox.setLayout(self.filtersGroupBoxLayout)
        layout.addWidget(filterGroupBox)
Ejemplo n.º 2
0
    def _setupAddToCollectionGroupBox(self, layout):
        addToCollectionGroupBox = QGroupBox(
            maya.stringTable['y_staticCollection.kAddToCollection'])
        font = QFont()
        font.setBold(True)
        addToCollectionGroupBox.setFont(font)
        addToCollectionGroupBox.setContentsMargins(0, utils.dpiScale(12), 0, 0)
        self.addToCollectionGroupBoxLayout = propEdLayout.Layout()
        self.addToCollectionGroupBoxLayout.setVerticalSpacing(
            utils.dpiScale(2))

        self._setupStaticSelector()

        addToCollectionGroupBox.setLayout(self.addToCollectionGroupBoxLayout)
        layout.addWidget(addToCollectionGroupBox)
Ejemplo n.º 3
0
    def __init__(self, item, parent):
        super(Override, self).__init__(parent=parent)
        self.path = None
        self.attributeUI = None
        self.item = weakref.ref(item)

        layout = QVBoxLayout()
        layout.setObjectName('override_vertical_box_layout')
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(utils.dpiScale(2))
        self._setupMainOverrideGroupBox(layout)

        self.setLayout(layout)

        # Unwrap the layout into a pointer to be able to get the UI name.
        # We use fullName() to ensure a unique name is used
        layoutName = mui.MQtUtil.fullName(long(getCppPointer(layout)[0]))
        cmds.setParent(layoutName)

        self._uiLayout = cmds.columnLayout(adjustableColumn=True)

        self._dropBoxInit()

        if item.isUniqueOverride():
            self.target = QLabel(kAppliedToUnique % item.targetNodeName())
            self.target.setAlignment(Qt.AlignBottom | Qt.AlignCenter)
            layout.addWidget(self.target)
Ejemplo n.º 4
0
 def _hasChildrenAndLeftOfText(self, event, index):
     if self.model.hasChildren(index):
         indent = self.getIndent(index)
         leftOffset = indent + viewsUtils.dpiScale(23)
         if event.pos().x() < leftOffset:
             return True
     return False
Ejemplo n.º 5
0
class TitleFrame(Frame):
    """
    This class defines the frame for the FrameLayout
    """

    # Constants
    FRAME_HEIGHT = utils.dpiScale(28)

    # Signals
    clicked = Signal()

    def __init__(self, item, parent):
        super(TitleFrame, self).__init__(item, parent=parent)

        self.layout = QHBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.arrowAndTitle = CollapsibleArrowAndTitle(self.item(), self)
        self.layout.addWidget(self.arrowAndTitle)
        if self.item().data(renderSetupRoles.NODE_SHOULD_DISPLAY_NAME):
            self.name = NameLineEdit(self.item(), self)
            self.layout.addWidget(self.name)
            self.layout.addSpacing(utils.dpiScale(16))
        self.setLayout(self.layout)

    def paintEvent(self, e):
        """ Draws the disabled or enabled title frame background. """
        painter = QPainter(self)
        self._drawBackground(painter, e)

    def mousePressEvent(self, event):
        self.clicked.emit()
        return super(TitleFrame, self).mousePressEvent(event)
Ejemplo n.º 6
0
class StaticCollection(basicCollection.BasicCollection):
    """
        This class represents the property editor view of a static collection.
        A static selection is read-only and only contains a list of selected nodes.
    """

    # Constants
    LIST_BOX_HEIGHT = utils.dpiScale(100)

    def __init__(self, item, parent):
        super(StaticCollection, self).__init__(item, parent)
        self.addToCollectionGroupBoxLayout = None
        self.staticSelector = None

    def setupSelector(self, layout):
        self._setupAddToCollectionGroupBox(layout)

    def _setupStaticSelector(self):
        staticSelectionWidget = QWidget()
        staticSelectionLayout = QHBoxLayout()
        staticSelectionLayout.setContentsMargins(0, 0, 0, 0)
        staticSelectionLayout.setSpacing(utils.dpiScale(2))
        self.staticSelector = QListWidget()
        self.staticSelector.setFixedHeight(self.LIST_BOX_HEIGHT)
        staticSelectionLayout.addWidget(self.staticSelector)

        # Re-populate the static selection list view with the previously stored value
        staticSelections = self.item().model.getSelector().getStaticSelection()
        staticSelectionList = staticSelections.split(
        ) if staticSelections is not None else list()
        self.staticSelector.addItems(staticSelectionList)

        # Add the drag/drop buttons
        dragDropButtonLayout = QVBoxLayout()
        dragDropButtonLayout.setSpacing(utils.dpiScale(2))
        dragDropButtonLayout.setContentsMargins(0, 0, 0, 0)
        dragDropButtonWidget = QWidget()
        staticSelectionLayout.addWidget(dragDropButtonWidget)
        dragDropButtonWidget.setLayout(dragDropButtonLayout)
        staticSelectionWidget.setLayout(staticSelectionLayout)
        self.addToCollectionGroupBoxLayout.addRow("", staticSelectionWidget)

    def _setupAddToCollectionGroupBox(self, layout):
        addToCollectionGroupBox = QGroupBox(
            maya.stringTable['y_staticCollection.kAddToCollection'])
        font = QFont()
        font.setBold(True)
        addToCollectionGroupBox.setFont(font)
        addToCollectionGroupBox.setContentsMargins(0, utils.dpiScale(12), 0, 0)
        self.addToCollectionGroupBoxLayout = propEdLayout.Layout()
        self.addToCollectionGroupBoxLayout.setVerticalSpacing(
            utils.dpiScale(2))

        self._setupStaticSelector()

        addToCollectionGroupBox.setLayout(self.addToCollectionGroupBoxLayout)
        layout.addWidget(addToCollectionGroupBox)
Ejemplo n.º 7
0
    def _setupMainCollectionGroupBox(self, layout):
        mainGroupBox = QGroupBox()
        mainGroupBox.setContentsMargins(0, 0, 0, 0)
        mainGroupBoxLayout = propEdLayout.Layout()
        mainGroupBoxLayout.setVerticalSpacing(utils.dpiScale(2))

        self._setupCollectionPathName(mainGroupBoxLayout)

        mainGroupBox.setLayout(mainGroupBoxLayout)
        layout.addWidget(mainGroupBox)
Ejemplo n.º 8
0
    def _setupMainOverrideGroupBox(self, layout):
        mainGroupBox = QGroupBox()
        mainGroupBox.setContentsMargins(0, 0, 0, 0)
        mainGroupBoxLayout = Layout()
        mainGroupBoxLayout.setVerticalSpacing(utils.dpiScale(2))

        self._setupOverridePathName(mainGroupBoxLayout)

        mainGroupBox.setLayout(mainGroupBoxLayout)
        layout.addWidget(mainGroupBox)
Ejemplo n.º 9
0
    def setupSelector(self, layout):
        self._selectorGroupBox = QGroupBox(parent=self)
        self._selectorGroupBox.setContentsMargins(0, 0, 0, 0)
        self._selectorLayout = QVBoxLayout()
        self._selectorLayout.setContentsMargins(0, 0, 0, 0)
        self._selectorLayout.setSpacing(utils.dpiScale(2))
        self._selectorLayout.setObjectName('collection_selector_layout')
        self._selectorGroupBox.setLayout(self._selectorLayout)

        self._selectorUI.build(self._selectorLayout)

        layout.addWidget(self._selectorGroupBox)
Ejemplo n.º 10
0
    def __init__(self, item, parent):
        super(TitleFrame, self).__init__(item, parent=parent)

        self.layout = QHBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.arrowAndTitle = CollapsibleArrowAndTitle(self.item(), self)
        self.layout.addWidget(self.arrowAndTitle)
        if self.item().data(renderSetupRoles.NODE_SHOULD_DISPLAY_NAME):
            self.name = NameLineEdit(self.item(), self)
            self.layout.addWidget(self.name)
            self.layout.addSpacing(utils.dpiScale(16))
        self.setLayout(self.layout)
Ejemplo n.º 11
0
 def _setupSelectAllButton(self):
     selectAllButtonWidget = QWidget()
     selectAllButtonLayout = QHBoxLayout()
     selectAllButtonLayout.setContentsMargins(0, 0, 0, 0)
     selectAllButtonLayout.setSpacing(utils.dpiScale(2))
     selectAllButton = QPushButton(
         maya.stringTable['y_simpleSelector.kSelectAll'])
     selectAllButtonLayout.addStretch(1)
     selectAllButtonLayout.addWidget(selectAllButton)
     selectAllButtonLayout.addStretch(1)
     selectAllButtonLayout.addSpacing(self.EXPRESSION_BUTTON_WIDTH)
     selectAllButtonWidget.setLayout(selectAllButtonLayout)
     self.addToCollectionGroupBoxLayout.addRow("", selectAllButtonWidget)
Ejemplo n.º 12
0
    def _setupStaticSelector(self):
        staticSelectionWidget = QWidget()
        staticSelectionLayout = QHBoxLayout()
        staticSelectionLayout.setContentsMargins(0, 0, 0, 0)
        staticSelectionLayout.setSpacing(utils.dpiScale(2))
        self.staticSelector = CollectionStaticSelectionWidget(self._selector)
        self.staticSelector.setFixedHeight(self.LIST_BOX_HEIGHT)
        staticSelectionLayout.addWidget(self.staticSelector)

        # Add the drag/drop buttons
        dragDropButtonLayout = QVBoxLayout()
        dragDropButtonLayout.setSpacing(utils.dpiScale(2))
        dragDropButtonLayout.setContentsMargins(0, 0, 0, 0)
        addButton = QPushButton(maya.stringTable['y_simpleSelector.kAdd'])
        addButton.setToolTip(
            maya.stringTable['y_simpleSelector.kStaticAddTooltipStr'])
        addButton.setMinimumWidth(self.EXPRESSION_BUTTON_WIDTH)
        addButton.clicked.connect(self.staticSelector.addEntry)
        dragDropButtonLayout.addWidget(addButton)
        removeButton = QPushButton(
            maya.stringTable['y_simpleSelector.kRemove'])
        removeButton.setToolTip(
            maya.stringTable['y_simpleSelector.kStaticRemoveTooltipStr'])
        removeButton.setMinimumWidth(self.EXPRESSION_BUTTON_WIDTH)
        removeButton.clicked.connect(self.staticSelector.removeEntry)
        dragDropButtonLayout.addWidget(removeButton)
        dragDropButtonLayout.addStretch(1)
        selectButton = QPushButton(self.SELECT_STRING)
        selectButton.setToolTip(
            maya.stringTable['y_simpleSelector.kStaticSelectTooltipStr'])
        selectButton.setMinimumWidth(self.EXPRESSION_BUTTON_WIDTH)
        selectButton.clicked.connect(self.selectStaticEntries)
        dragDropButtonLayout.addWidget(selectButton)
        dragDropButtonWidget = QWidget()
        staticSelectionLayout.addWidget(dragDropButtonWidget)
        dragDropButtonWidget.setLayout(dragDropButtonLayout)
        staticSelectionWidget.setLayout(staticSelectionLayout)
        self.addToCollectionGroupBoxLayout.addRow("", staticSelectionWidget)
Ejemplo n.º 13
0
    def _setupStaticSelector(self):
        staticSelectionWidget = QWidget()
        staticSelectionLayout = QHBoxLayout()
        staticSelectionLayout.setContentsMargins(0, 0, 0, 0)
        staticSelectionLayout.setSpacing(utils.dpiScale(2))
        self.staticSelector = QListWidget()
        self.staticSelector.setFixedHeight(self.LIST_BOX_HEIGHT)
        staticSelectionLayout.addWidget(self.staticSelector)

        # Re-populate the static selection list view with the previously stored value
        staticSelections = self.item().model.getSelector().getStaticSelection()
        staticSelectionList = staticSelections.split(
        ) if staticSelections is not None else list()
        self.staticSelector.addItems(staticSelectionList)

        # Add the drag/drop buttons
        dragDropButtonLayout = QVBoxLayout()
        dragDropButtonLayout.setSpacing(utils.dpiScale(2))
        dragDropButtonLayout.setContentsMargins(0, 0, 0, 0)
        dragDropButtonWidget = QWidget()
        staticSelectionLayout.addWidget(dragDropButtonWidget)
        dragDropButtonWidget.setLayout(dragDropButtonLayout)
        staticSelectionWidget.setLayout(staticSelectionLayout)
        self.addToCollectionGroupBoxLayout.addRow("", staticSelectionWidget)
Ejemplo n.º 14
0
    def _setupExpression(self, expressionLabel, expressionChangedCB,
                         expressionFinishedCB):
        expressionWidget = QWidget()
        expressionLayout = QHBoxLayout()
        expressionLayout.setContentsMargins(0, 0, 0, 0)
        expressionLayout.setSpacing(utils.dpiScale(2))
        expressionWidget.setLayout(expressionLayout)
        expression = QLineEdit()
        tip = maya.stringTable['y_simpleSelector.kExpressionTooltipStr']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr1']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr2']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr3']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr4']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr5']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr6']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr7']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr8']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr9']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr10']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr11']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr12']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr13']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr14']
        expression.setToolTip(tip)

        expression.textChanged.connect(expressionChangedCB)

        # editingFinished is triggered for both enter key pressed and focused lost.
        expression.editingFinished.connect(expressionFinishedCB)
        expression.returnPressed.connect(lambda: expression.clearFocus())

        expression.setPlaceholderText(self.CREATE_EXPRESSION_STRING)
        expressionLayout.addWidget(expression)

        selectButton = QPushButton(self.SELECT_STRING)
        selectButton.setToolTip(
            maya.stringTable['y_simpleSelector.kExpressionSelectTooltipStr'])
        selectButton.setMinimumWidth(self.EXPRESSION_BUTTON_WIDTH)
        selectButton.clicked.connect(self.selectIncludeExpression)
        expressionLayout.addWidget(selectButton)

        self.addToCollectionGroupBoxLayout.addRow(expressionLabel,
                                                  expressionWidget)
        return expressionWidget, expression
Ejemplo n.º 15
0
    def _setupFilterUI(self, layout):
        filterUIWidget = QWidget()
        filterUILayout = QHBoxLayout()
        filterUILayout.setContentsMargins(0, 0, 0, 0)
        filterUILayout.setSpacing(utils.dpiScale(2))
        filterUIWidget.setLayout(filterUILayout)

        #setup and add the filter combo box.
        self.filterType = QComboBox()
        self.filterType.setSizeAdjustPolicy(
            QComboBox.AdjustToMinimumContentsLengthWithIcon)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(
            10)  # stronger than the spacer added below
        self.filterType.setSizePolicy(sizePolicy)
        self.filterType.setMinimumContentsLength(0)
        self.filterType.setMaximumWidth(200)
        self.filterType.setToolTip(
            maya.stringTable['y_simpleSelector.kFiltersToolTip'])

        for ftype in self._selector.getAvailableFilters():
            self.filterType.addItem(
                QIcon(RenderSetupDelegate.getFilterIcon(ftype)),
                selector.Filters.filterUIName(ftype), ftype)

        # get the current filter value and set the index of the combo box appropriately.
        filter = self._selector.getFilterType()
        self.filterType.currentIndexChanged[str].connect(
            self._filterTypeChanged)
        filterUILayout.addWidget(self.filterType)

        filterUILayout.addStretch()
        filterUILayout.addSpacing(4)

        self.customFilterEdit = CollectionFilterLineEdit()
        self.customFilterEdit.returnPressed.connect(
            lambda: self.customFilterEdit.clearFocus())
        self.customFilterEdit.setPlaceholderText(self.DRAG_DROP_FILTER_STRING)
        self.customFilterEdit.editingFinished.connect(self.customFilterEntered)
        showCustomFilter = (filter == selector.Filters.kCustom)

        layout.addRow("", filterUIWidget)
        layout.addRow(maya.stringTable['y_simpleSelector.kByTypeFilter'],
                      self.customFilterEdit)
Ejemplo n.º 16
0
 def data(self, role):
     if role == Qt.DisplayRole:
         return self.name
     elif role == Qt.EditRole:
         return self.name
     elif role == Qt.TextAlignmentRole:
         return Qt.AlignLeft | Qt.AlignVCenter
     elif role == Qt.TextColorRole:
         return QGuiApplication.palette().text().color()
     elif role == Qt.FontRole:
         return QApplication.font()
     elif role == Qt.SizeHintRole:
         return QSize(0, utils.dpiScale(ROW_HEIGHT))
     elif role == NODE_ACCEPTS_DRAG:
         return False
     elif role == NODE_ACTIVE_FRAME:
         return QColor(150, 150, 150)
     else:
         return super(ModelProxyItem, self).data(role)
Ejemplo n.º 17
0
    def __init__(self, item, parent):
        super(BasicCollection, self).__init__(parent=parent)
        # item is a weakref.
        self.item = item
        self.path = None

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(utils.dpiScale(2))
        layout.setObjectName('collection_vertical_box_layout')

        self._setupMainCollectionGroupBox(layout)
        self.setLayout(layout)
        # Unwrap the layout into a pointer to be able to get the UI name.
        # We use fullName() to ensure a unique name is used
        self._layoutName = mui.MQtUtil.fullName(
            long(getCppPointer(self.layout())[0]))

        self.preSelector()
        self.setupSelector(layout)
Ejemplo n.º 18
0
class Layout(QFormLayout):
    """
    This class implements a special form layout for the property editor in which the label column is of a specific size.
    """

    # Constants
    LABEL_COLUMN_WIDTH = utils.dpiScale(48)

    def __init__(self):
        super(Layout, self).__init__()
        self.setContentsMargins(0, 4, 0, 0)

    def _createLabel(self, v1):
        """ Returns a label with a specific size and right alignment. """
        label = v1
        # If v1 is not a label, it should be a string
        if not isinstance(v1, QLabel):
            label = QLabel(v1)
        label.setMinimumSize(self.LABEL_COLUMN_WIDTH, 0)
        label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        return label

    def insertRow(self, row, v1, v2=None):
        """ Inserts a row into the layout. If v2 is None, then there is no label specified. """
        if v2 == None:
            super(Layout, self).insertRow(row, v1)
        else:
            label = self._createLabel(v1)
            super(Layout, self).insertRow(row, label, v2)

    def addRow(self, v1, v2=None):
        """ Adds a row to the layout. If v2 is None, then there is no label specified. """
        if v2 == None:
            super(Layout, self).addRow(v1)
        else:
            label = self._createLabel(v1)
            super(Layout, self).addRow(label, v2)
Ejemplo n.º 19
0
class LookThroughWindow(MayaQWidgetDockableMixin, QWidget):
    """ This class implements the look through window. """

    # Constants
    STARTING_SIZE = QSize(viewsUtils.dpiScale(300), viewsUtils.dpiScale(300))
    PREFERRED_SIZE = STARTING_SIZE
    MINIMUM_SIZE = QSize(100, 100)
    WINDOW_STATE_PREFERENCE = 'lookThroughWindowState'

    def __init__(self, parent):
        super(LookThroughWindow, self).__init__(parent=None)
        self.editor = parent
        self.preferredSize = self.PREFERRED_SIZE

        self.setObjectName("lightEditorLookThroughWnd")
        self.resize(self.STARTING_SIZE)

        self.setAttribute(Qt.WA_DeleteOnClose, True)

        # Create the model panel
        cmds.setParent(self.objectName())
        cmds.paneLayout()

        lookThroughPanelLabel = "lightEditorLookThroughModelPanelLabel"
        previousLookThroughPanel = cmds.getPanel(
            withLabel=lookThroughPanelLabel)

        if previousLookThroughPanel != None:
            self.panel = previousLookThroughPanel
            cmds.modelPanel(self.panel, edit=True, parent=self.objectName())
        else:
            self.panel = cmds.modelPanel()
            cmds.modelPanel(self.panel, edit=True, label=lookThroughPanelLabel)

        # Enable smooth shading
        editor = cmds.modelPanel(self.panel, query=True, modelEditor=True)
        cmds.modelEditor(editor, edit=True, displayAppearance="smoothShaded")

        self.setParent(parent.parent())

    def __del__(self):
        pass

    def setSizeHint(self, size):
        self.preferredSize = size

    def sizeHint(self):
        return self.preferredSize

    def minimumSizeHint(self):
        return self.MINIMUM_SIZE

    def dockCloseEventTriggered(self):
        self.close()

    def closeEvent(self, event):
        self.editor.lookThroughWindow = None
        event.accept()

    def lookThroughLight(self, light):
        """ Opens a model panel with camera looking through the given light. """

        # Enable look through selected
        cmd = "lookThroughModelPanelClipped(\"" + light + "\", \"" + self.panel + "\", 0.001, 1000)"
        mel.eval(cmd)

        title = maya.stringTable['y_editor.kLookingThrough'] + light
        self.setWindowTitle(title)
Ejemplo n.º 20
0
class RenderSetupDelegate(baseDelegate.BaseDelegate):
    """
    This class provides customization of the appearance of items in the Model.
    """

    # Constants
    HIGHLIGHTED_FILL_OFFSET = 1
    INFO_COLOR = QColor(255, 0, 0)

    LEFT_NON_TEXT_OFFSET = utils.dpiScale(25.5)
    RIGHT_NON_TEXT_OFFSET = utils.dpiScale(6)

    DISABLED_IMAGE = baseDelegate.createPixmap(":/RS_disable.png")
    ISOLATE_IMAGE = baseDelegate.createPixmap(":/RS_isolate.png")
    INVALID_IMAGE = baseDelegate.createPixmap(":/RS_invalid.png")
    DISCLOSURE_IMAGE = baseDelegate.createPixmap(
        ":/RS_disclosure_triangle.png")

    # create a collection of pixmaps used for filters that can be looked up by filter type
    _kFilterIcons = createFilterPixmaps()

    kTooltips = {
        renderSetup.SET_VISIBILITY_ACTION:
        maya.stringTable['y_renderSetupDelegate.kVisibilityToolTip'],
        renderSetup.SET_RENDERABLE_ACTION:
        maya.stringTable['y_renderSetupDelegate.kRenderableToolTip'],
        renderSetup.SET_ENABLED_ACTION:
        maya.stringTable['y_renderSetupDelegate.kEnabledToolTip'],
        renderSetup.SET_ISOLATE_SELECTED_ACTION:
        maya.stringTable['y_renderSetupDelegate.kIsolateToolTip'],
        renderSetup.FILTER_MENU:
        maya.stringTable['y_renderSetupDelegate.kFiltersToolTip']
    }

    @staticmethod
    def getFilterIcon(filter):
        # filter can be an integer (built-in type filter) or an iterable of type names
        if not isinstance(
                filter, list) and filter in RenderSetupDelegate._kFilterIcons:
            return RenderSetupDelegate._kFilterIcons[filter]
        try:
            filters = list(filter)
        except:
            return None

        if len(filters) > 1:
            return RenderSetupDelegate._kFilterIcons[selector.Filters.kCustom]
        elif len(filters) > 0:
            f = filters[0]
            if f == 'shader/surface':
                return RenderSetupDelegate._kFilterIcons[
                    selector.Filters.kShaders]
            if f == 'shader/displacement':
                return baseDelegate.createPixmap(
                    ":/render_displacementShader.png")
            if f == 'shader/volume':
                return baseDelegate.createPixmap(":/render_volumeFog.png")
            if f == 'geometry':
                return baseDelegate.createPixmap(":/out_polySphere.png")
            try:
                return baseDelegate.createPixmap(":/render_%s.png" % f)
            except:
                pass
            try:
                return baseDelegate.createPixmap(":/out_%s.png" % f)
            except:
                pass
        return None

    def __init__(self, treeView):
        super(RenderSetupDelegate, self).__init__(treeView)

    def _getItem(self, index):
        return self.treeView().model().itemFromIndex(index)

    def _drawColorBar(self, painter, rect, item):
        rect2 = deepcopy(rect)
        rect2.setRight(rect2.left() + self.COLOR_BAR_WIDTH)
        painter.fillRect(rect2, item.data(renderSetupRoles.NODE_COLOR_BAR))

        if item.type(
        ) == renderSetup.RENDER_OVERRIDE_TYPE and item.isLocalRender():
            diameter = rect2.width() - 2
            rect3 = QRect(rect2.x() + 1,
                          rect2.y() + (rect2.height() - diameter) / 2,
                          diameter, diameter)
            brush = painter.brush()
            pen = painter.pen()
            hints = painter.renderHints()

            painter.setRenderHint(QPainter.Antialiasing, on=True)
            painter.setPen(Qt.NoPen)
            painter.setBrush(QBrush(QColor(67, 79, 70), style=Qt.SolidPattern))
            painter.drawEllipse(rect3)

            painter.setRenderHints(hints)
            painter.setPen(pen)
            painter.setBrush(brush)

    def _drawFill(self, painter, rect, item, isHighlighted, highlightColor):
        rect.setLeft(rect.left() + self.COLOR_BAR_WIDTH + 1)

        oldPen = painter.pen()

        if isHighlighted:
            rect.setLeft(rect.left() + self.HIGHLIGHTED_FILL_OFFSET)
            if not item.data(renderSetupRoles.NODE_ENABLED):
                painter.drawTiledPixmap(
                    rect, baseDelegate.BaseDelegate.DISABLED_HIGHLIGHT_IMAGE)
            else:
                painter.fillRect(rect, highlightColor)
            rect.setLeft(rect.left() - self.HIGHLIGHTED_FILL_OFFSET)
        else:
            painter.fillRect(rect, item.data(Qt.BackgroundRole))
            if not item.data(renderSetupRoles.NODE_ENABLED):
                painter.drawTiledPixmap(
                    rect, baseDelegate.BaseDelegate.DISABLED_BACKGROUND_IMAGE)

        if item.isActive():
            painter.setPen(QPen(item.data(renderSetupRoles.NODE_COLOR_BAR), 2))
            rect2 = deepcopy(rect)
            rect2.setRight(rect2.right() - 1)
            rect2.setTop(rect2.top() + 1)
            rect2.setBottom(rect2.bottom() - 1)
            painter.drawRect(rect2)

        painter.setPen(oldPen)

    def _addActionIcons(self, painter, rect, item, highlightedColor):
        top = rect.top() + (self.ICON_TOP_OFFSET)

        start = self.ACTION_BORDER
        count = item.getActionButtonCount()
        toolbarCount = count
        if item.type() == renderSetup.COLLECTION_TYPE:
            toolbarCount -= 1

        # draw the darkened toolbar frame
        self.drawToolbarFrame(painter, rect, toolbarCount)

        for iconIndex in range(0, count):
            actionName = item.getActionButton(iconIndex)
            pixmap = None
            drawDisclosure = False
            extraPadding = 0
            checked = False

            borderColor = None
            if (actionName == renderSetup.SET_VISIBILITY_ACTION):
                pixmap = self.VISIBILITY_IMAGE
                checked = item.data(renderSetupRoles.NODE_VISIBLE)
                if checked and item.data(renderSetupRoles.NODE_NEEDS_UPDATE):
                    borderColor = self.INFO_COLOR
            elif (actionName == renderSetup.SET_RENDERABLE_ACTION):
                pixmap = self.RENDERABLE_IMAGE
                checked = item.data(renderSetupRoles.NODE_RENDERABLE)
            elif (actionName == renderSetup.SET_ENABLED_ACTION):
                pixmap = RenderSetupDelegate.DISABLED_IMAGE
                checked = not item.data(renderSetupRoles.NODE_SELF_ENABLED)
            elif (actionName == renderSetup.SET_ISOLATE_SELECTED_ACTION):
                pixmap = RenderSetupDelegate.ISOLATE_IMAGE
                checked = item.data(renderSetupRoles.NODE_ISOLATE_SELECTED)
            elif (actionName == renderSetup.FILTER_MENU):
                filter = item.model.getSelector().getFilterType()
                if filter == selector.Filters.kCustom:
                    filter = item.model.getSelector().getTypeFilters()
                pixmap = RenderSetupDelegate.getFilterIcon(filter)
                left = rect.right() - (start + self.ACTION_WIDTH + 4)
                if pixmap:
                    self.drawPixmap(painter, pixmap, left, top)
                continue

            start += self.ACTION_WIDTH + extraPadding
            self.drawAction(painter, actionName, pixmap,
                            rect.right() - start, top,
                            highlightedColor if checked else None,
                            drawDisclosure, borderColor)

        if self.lastHitAction:
            # MAYA-66647 - This should be made into a separate action instead of a conditional action
            if self.lastHitAction == renderSetup.SET_VISIBILITY_ACTION and item.data(
                    renderSetupRoles.NODE_NEEDS_UPDATE):
                item.setToolTip(maya.stringTable[
                    'y_renderSetupDelegate.kUpdateVisibilityToolTip'])
            else:
                item.setToolTip(self.kTooltips[self.lastHitAction])
        else:
            item.setToolTip("")

    def createEditor(self, parent, option, index):
        """ Creates the double-click editor for renaming render setup entries. The override entry is right aligned. """
        editor = QLineEdit(parent)
        item = self._getItem(index)
        if item.type() == renderSetup.RENDER_OVERRIDE_TYPE:
            editor.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        return editor

    def getTextRect(self, rect, item):
        newRect = super(RenderSetupDelegate, self).getTextRect(rect, item)
        newRect.setBottom(rect.bottom() - self.BOTTOM_GAP_OFFSET)
        if item.type() == renderSetup.RENDER_LAYER_TYPE:
            newRect.setRight(rect.right() - self.LAYER_TEXT_RIGHT_OFFSET)
        elif item.type() == renderSetup.COLLECTION_TYPE:
            newRect.setRight(rect.right() - self.COLLECTION_TEXT_RIGHT_OFFSET)
        elif item.type() == renderSetup.RENDER_OVERRIDE_TYPE:
            warning = item.data(renderSetupRoles.NODE_WARNING)
            if not warning:
                newRect.setRight(rect.right() - self.TEXT_RIGHT_OFFSET)
            else:
                newRect.setRight(rect.right() - (
                    self.TEXT_RIGHT_OFFSET +
                    baseDelegate.BaseDelegate.WARNING_ICON_WIDTH +
                    baseDelegate.BaseDelegate.ACTION_BORDER))

        return newRect

    def updateEditorGeometry(self, editor, option, index):
        """ Sets the location for the double-click editor for renaming render setup entries. """
        item = self._getItem(index)
        rect = self.getTextRect(option.rect, item)

        indent = item.depth() * self.treeView().indentation()
        if item.type() == renderSetup.RENDER_LAYER_TYPE or item.type(
        ) == renderSetup.COLLECTION_TYPE:
            leftOffset = indent + item.data(renderSetupRoles.NODE_HEADING_WIDTH
                                            ) + self.LEFT_NON_TEXT_OFFSET
            rect.setLeft(leftOffset)

        editor.setGeometry(rect)

    def _drawWarning(self, painter, rect, item):
        warning = item.data(renderSetupRoles.NODE_WARNING)
        if warning and len(warning) > 0:
            fm = QFontMetrics(self.treeView().font())
            if item.type() == renderSetup.RENDER_OVERRIDE_TYPE:
                left = self.getTextRect(
                    rect,
                    item).right() + baseDelegate.BaseDelegate.ACTION_BORDER
            else:
                left = self.getTextRect(rect, item).left() + fm.boundingRect(
                    item.data(Qt.DisplayRole)).width(
                    ) + baseDelegate.BaseDelegate.ACTION_BORDER
            top = rect.top() + baseDelegate.BaseDelegate.ICON_TOP_OFFSET
            painter.drawPixmap(left, top,
                               baseDelegate.BaseDelegate.WARNING_IMAGE)

            iconRect = QRect(left, top,
                             baseDelegate.BaseDelegate.WARNING_ICON_WIDTH,
                             baseDelegate.BaseDelegate.WARNING_ICON_WIDTH)
            p = self.treeView().mapFromGlobal(QCursor.pos())
            if iconRect.contains(p):
                item.setToolTip(warning)
Ejemplo n.º 21
0
import maya.app.renderSetup.views.lightEditor.enterScope as enterScope
import maya.app.renderSetup.views.lightEditor.utils as utils
import maya.app.renderSetup.views.lightEditor.lightTypeManager as typeMgr
import maya.app.renderSetup.views.utils as viewsUtils
import maya.app.renderSetup.model.renderSetup as renderSetup
import maya.app.renderSetup.model.plug as plug
import maya.app.renderSetup.common.utils as commonUtils

LAYER_TEXT = maya.stringTable['y_editor.kLayerText']
DEFAULT_LAYER_TEXT = maya.stringTable['y_editor.kDefaultLayerText']
LIGHT_EDITOR_TEXT_GLOBAL_MODE = maya.stringTable[
    'y_editor.kLightEditorGlobalModelText']
LIGHT_EDITOR_TEXT_LAYER_MODE = maya.stringTable[
    'y_editor.kLightEditorLayerModelText']

NAME_COLUMN_WIDTH = viewsUtils.dpiScale(150)

LIGHT_EDITOR_COLUMN_ORDER_OPTION_VAR = "renderSetup_LightEditorColumnOrder"

# Reference to editor singleton instance
_editorInstance = None


class EditorTreeView(QTreeView):
    """
	This class implements the editor tree view.
	"""
    def __init__(self, parent):
        super(EditorTreeView, self).__init__(parent=parent)

        self.selectionChangeInstigator = None
Ejemplo n.º 22
0
class Node(object):
	"""
	This class wraps a DAG node in Maya.
	"""

	ITEM_ROW_HEIGHT = viewsUtils.dpiScale(30)

	def __init__(self, model, obj, attributes):
		super(Node, self).__init__()
		self.disposed = False
		self.model = model
		self.mayaHandle = om.MObjectHandle(obj)
		self.attributes = attributes
		self.parentNode = None
		self.hasMutableName = False

		# Set callback for name changes
		def _nameChangedCB(obj, oldName, clientData):
			if len(oldName)>0:
				self.nameChanged(oldName)

		self.nameChangedCallbackId = om.MNodeMessage.addNameChangedCallback(self.mayaHandle.object(), _nameChangedCB)

	def __del__(self):
		self.dispose()

	@staticmethod
	def getUuid(obj):
		# The UUID's on the Maya nodes are not unique for referenced objects.
		# So instead we use the internal hash code available on the MObjectHandle
		# to identify our nodes
		h = om.MObjectHandle(obj)
		return h.hashCode()

	def dispose(self):
		if self.disposed: return
		self.disposed = True

		if self.nameChangedCallbackId:
			om.MMessage.removeCallback(self.nameChangedCallbackId)
			self.nameChangedCallbackId = 0

		del self.mayaHandle
		self.mayaHandle = None
		self.attributes = None

	def typeId(self):
		return TYPE_ID_UNDEFINED

	def uuid(self):
		# The UUID's on the Maya nodes are not unique for referenced objects.
		# So instead we use the internal hash code available on the MObjectHandle
		# to identify our nodes
		return self.mayaHandle.hashCode()

	def setName(self, name):
		# Set name using the name attribute
		self.setAttributeByLabel("Name", name)

	def getName(self):
		# Get name using the name attribute
		return self.getAttributeByLabel("Name")

	def nameChanged(self, oldName):
		self.emitAttributeChanged("name")

	def getShape(self):
		return self.mayaHandle.object()

	def getShapeName(self):
		dn = om.MFnDependencyNode(self.mayaHandle.object())
		return dn.name()

	def childCount(self):
		return 0

	def child(self, i):
		return None

	def insertChild(self, child, i = -1):
		pass

	def removeChild(self, child):
		pass

	def hasChild(self, child):
		return False

	def parent(self):
		return self.parentNode

	def setParent(self, parent):
		self.parentNode = parent

	def syncWithChildren(self):
		pass

	def mayaName(self):
		pass

	def hasMayaResource(self):
		return self.mayaHandle.isValid()

	def nodesToDelete(self):
		pass

	def doDelete(self):
		self.dispose()

	def data(self, role, column):
		if role == Qt.TextColorRole:
			return QGuiApplication.palette().text().color()
		elif role == Qt.FontRole:
			return QApplication.font()
		elif role == Qt.TextAlignmentRole:
			if column==0:
				return Qt.AlignLeft | Qt.AlignVCenter
			else:
				return Qt.AlignCenter | Qt.AlignVCenter
		elif role == Qt.SizeHintRole:
			return QSize(0, self.ITEM_ROW_HEIGHT)
		elif role == ITEM_ROLE_TYPE:
			return self.typeId()
		elif role == Qt.EditRole:
			return self.getAttributeByIndex(column)
		elif role == Qt.DisplayRole:
			return self.getAttributeByIndex(column)
		elif role == ITEM_ROLE_ENABLED:
			return self.getAttributeByLabel("Enable")
		elif role == ITEM_ROLE_ISOLATED:
			return self.getAttributeByLabel("Isolate")
		elif role == ITEM_ROLE_ATTR_TYPE:
			return self.attributeType(column)
		elif role == ITEM_ROLE_ATTR_HIDDEN:
			return self.attributeHidden(column)
		elif role == ITEM_ROLE_IS_LAYER_MEMBER:
			return self._isMemberOfVisibleLayer()
		return None

	def setData(self, value, role, column):
		""" Sets the role data for the item. """
		attr = self.attribute(column)
		if not attr:
			return
		if role == Qt.EditRole:
			self.setAttributeByIndex(column, value)
		elif role == ITEM_ROLE_ENABLED:
			self.setAttributeByLabel("Enable", value)
		elif role == ITEM_ROLE_ISOLATED:
			self.setAttributeByLabel("Isolate", value)

	def emitDataChanged(self, column):
		myIndex = self.model.indexFromNode(self)
		row = myIndex.row()
		if column < 0:
			columnCount = self.attributes.count()
			idx1 = self.model.index(row, 0)
			idx2 = self.model.index(row, columnCount)
			self.model.emitDataChanged(idx1, idx2)
		else:
			idx = self.model.index(row, column)
			self.model.emitDataChanged(idx, idx)

	def emitAttributeChanged(self, attrName):
		if attrName == "visibility":
			# For visibility we need to update the whole row
			self.emitDataChanged(-1)
		else:
			# Find the index for this attribute and update it
			attr = self.attributes.findAttributeByName(attrName)
			if attr:
				self.emitDataChanged(attr.index)

	def attribute(self, column):
		return self.attributes.findAttributeByIndex(column)

	def attributeType(self, column):
		attr = self.attributes.findAttributeByIndex(column)
		if not attr:
			return plugModule.Plug.kInvalid
		plug = commonUtils.findPlug(self.getShape(), attr.name)
		return plugModule.Plug(plug).type if plug else plugModule.Plug.kInvalid

	def attributeHidden(self, column):
		attr = self.attributes.findAttributeByIndex(column)
		if attr:
			plg = plugModule.Plug(self.getShape(), attr.name)
			if plg.isValid:
				return plg.attribute().hidden
		return True

	def getAttributeByLabel(self, attrLabel):
		""" Gets the value of a given attribute. Returns None if the attribute doesn't exists. """
		attr = self.attributes.findAttributeByLabel(attrLabel)
		if not attr: return None
		return self._getAttribute(attr)

	def setAttributeByLabel(self, attrLabel, value):
		""" Sets the value of a given attribute. Does nothing if the attribute doesn't exists. """
		attr = self.attributes.findAttributeByLabel(attrLabel)
		if not attr: return None
		self._setAttribute(attr, value)

	def getAttributeByName(self, attrName):
		""" Gets the value of a given attribute. Returns None if the attribute doesn't exists. """
		attr = self.attributes.findAttributeByName(attrName)
		if not attr: return None
		return self._getAttribute(attr)

	def setAttributeByName(self, attrName, value):
		""" Sets the value of a given attribute. Does nothing if the attribute doesn't exists. """
		attr = self.attributes.findAttributeByName(attrName)
		if not attr: return None
		self._setAttribute(attr, value)

	def getAttributeByIndex(self, index):
		""" Gets the value of a given attribute. Returns None if the attribute doesn't exists. """
		attr = self.attributes.findAttributeByIndex(index)
		if not attr: return None
		return self._getAttribute(attr)

	def setAttributeByIndex(self, index, value):
		""" Sets the value of a given attribute. Does nothing if the attribute doesn't exists. """
		attr = self.attributes.findAttributeByIndex(index)
		if not attr: return None
		self._setAttribute(attr, value)

	def enable(self, value):
		pass

	def isEnabled(self):
		attr = self.attributes.findAttributeByLabel("Enable")
		return self._getAttributePlugValue(attr)

	def isolate(self, value):
		pass

	def isIsolated(self):
		attr = self.attributes.findAttributeByLabel("Isolate")
		return self._getAttributePlugValue(attr)

	def _getAttribute(self, attr):
		if attr.getter:
			return attr.getter(self, attr.name)
		else:
			return self._getAttributePlugValue(attr)

	def _setAttribute(self, attr, value):
		# Ignore the new value if it's not different from old
		oldValue = self._getAttribute(attr)
		if value == oldValue:
			return

		if attr.setter:
			attr.setter(self, attr.name, value)
		else:
			self._setAttributePlugValue(attr, value)
		
		self.emitDataChanged(attr.index)

	def _getPlugValue(self, plug):
		""" Get the value of a plug. """
		plugHandle = plugModule.Plug(plug)
		return plugHandle.value

	def _setPlugValue(self, plug, value):
		""" Set the value of a plug. """
		plugHandle = plugModule.Plug(plug)
		plugHandle.value = value

	def _getAttributePlugValue(self, attr):
		""" Get the value of an attribute. Considering overrides set on the attribute (if any). """
		plug = self._findPlug(attr)
		return self._getPlugValue(plug) if plug else None

	def _setAttributePlugValue(self, attr, value):
		""" Set the value of an attribute. Creating override on the attribute if needed. """
		with enterScope.EnterLightScope(self.model) as scope:
			if scope.active:
				plug = self._findPlug(attr, writeMode=True)
				if plug:
					self._setPlugValue(plug, value)

	def _findPlug(self, attr, writeMode=False):
		""" Find the plug matching the attribute name. 
		This method is overridden in derived classes. Default implementation returns 
		the ordinary attribute plug and doesn't handle overrides. """
		shapeNode = self.getShape()
		if not shapeNode:
			return None

		fnShapeNode = om.MFnDependencyNode(shapeNode)
		plug = None
		try:
			plug = fnShapeNode.findPlug(attr.name, False)
			# MAYA-66632: Could be improved by also checking if the 
			# plug type matches the given attribute type
		except:
			return None

		return plug

	def _getPrivateValue(self, attrName):
		""" Utility method to get the value of a private attribute. 
		An attribute that is only used internally and cannot have overrides on it. """
		plug = commonUtils.findPlug(self.getShape(), attrName)
		return self._getPlugValue(plug) if plug else None

	def _setPrivateValue(self, attrName, value):
		""" Utility method to set the value of a private attribute. 
		An attribute that is only used internally and cannot have overrides on it. """
		plug = commonUtils.findPlug(self.getShape(), attrName)
		if plug:
			self._setPlugValue(plug, value)

	def index(self):
		return self.model.indexFromNode(self)

	def _setChildIndex(self, value):
		plug = commonUtils.findPlug(self.getShape(), "childIndex")
		if plug:
			plug.setInt(value)

	def _getChildIndex(self):
		plug = commonUtils.findPlug(self.getShape(), "childIndex")
		return plug.asInt() if plug else None

	def _isMemberOfVisibleLayer(self):
		return True
Ejemplo n.º 23
0
class SimpleSelector(object):

    # Constants
    LIST_BOX_HEIGHT = utils.dpiScale(100)
    EXPRESSION_BUTTON_WIDTH = utils.dpiScale(50)
    INVERSE_STRING = maya.stringTable['y_simpleSelector.kInverse']
    SELECT_STRING = maya.stringTable['y_simpleSelector.kSelect']
    CREATE_EXPRESSION_STRING = maya.stringTable[
        'y_simpleSelector.kCreateExpression']
    DRAG_DROP_FILTER_STRING = maya.stringTable[
        'y_simpleSelector.kDragDropFilter']

    # Corresponding data model type.
    kModelType = selector.SimpleSelector.kTypeName

    def __init__(self, selector):
        self.expression = ""
        self._blockChangeMessages = False
        self._selector = selector
        self.filterType = None
        self.addToCollectionGroupBoxLayout = None
        self.includeExpressionWidgets = None
        self.includeExpression = None
        self.customFilterEdit = None
        self.filtersGroupBoxLayout = None
        self.staticSelector = None

    def build(self, layout, populate=True):
        self._setupFilterGroupBox(layout)
        self._setupAddToCollectionGroupBox(layout)
        if populate:
            self.populateFields()

    def displayType(self):
        """Return the user-visible display type string.

        By default this is the same for all objects of a selector class."""
        return self.kDisplayType

    def _setupExpression(self, expressionLabel, expressionChangedCB,
                         expressionFinishedCB):
        expressionWidget = QWidget()
        expressionLayout = QHBoxLayout()
        expressionLayout.setContentsMargins(0, 0, 0, 0)
        expressionLayout.setSpacing(utils.dpiScale(2))
        expressionWidget.setLayout(expressionLayout)
        expression = QLineEdit()
        tip = maya.stringTable['y_simpleSelector.kExpressionTooltipStr']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr1']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr2']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr3']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr4']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr5']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr6']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr7']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr8']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr9']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr10']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr11']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr12']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr13']
        tip += maya.stringTable['y_simpleSelector.kExpressionTooltipStr14']
        expression.setToolTip(tip)

        expression.textChanged.connect(expressionChangedCB)

        # editingFinished is triggered for both enter key pressed and focused lost.
        expression.editingFinished.connect(expressionFinishedCB)
        expression.returnPressed.connect(lambda: expression.clearFocus())

        expression.setPlaceholderText(self.CREATE_EXPRESSION_STRING)
        expressionLayout.addWidget(expression)

        selectButton = QPushButton(self.SELECT_STRING)
        selectButton.setToolTip(
            maya.stringTable['y_simpleSelector.kExpressionSelectTooltipStr'])
        selectButton.setMinimumWidth(self.EXPRESSION_BUTTON_WIDTH)
        selectButton.clicked.connect(self.selectIncludeExpression)
        expressionLayout.addWidget(selectButton)

        self.addToCollectionGroupBoxLayout.addRow(expressionLabel,
                                                  expressionWidget)
        return expressionWidget, expression

    def _setupIncludeExpression(self):
        includeExpressionLabel = IncludeExpressionLabel(
            maya.stringTable['y_simpleSelector.kInclude'])
        includeExpressionWidget, self.includeExpression = \
            self._setupExpression(includeExpressionLabel, self.includeExpressionChanged, self.includeExpressionEntered)
        self.includeExpressionWidgets = [includeExpressionWidget]
        self.expression = self._selector.getPattern()

    @abstractmethod
    def _getFilterEnum(self):
        pass

    def _setupFilterUI(self, layout):
        filterUIWidget = QWidget()
        filterUILayout = QHBoxLayout()
        filterUILayout.setContentsMargins(0, 0, 0, 0)
        filterUILayout.setSpacing(utils.dpiScale(2))
        filterUIWidget.setLayout(filterUILayout)

        #setup and add the filter combo box.
        self.filterType = QComboBox()
        self.filterType.setSizeAdjustPolicy(
            QComboBox.AdjustToMinimumContentsLengthWithIcon)
        sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(
            10)  # stronger than the spacer added below
        self.filterType.setSizePolicy(sizePolicy)
        self.filterType.setMinimumContentsLength(0)
        self.filterType.setMaximumWidth(200)
        self.filterType.setToolTip(
            maya.stringTable['y_simpleSelector.kFiltersToolTip'])

        for ftype in self._selector.getAvailableFilters():
            self.filterType.addItem(
                QIcon(RenderSetupDelegate.getFilterIcon(ftype)),
                selector.Filters.filterUIName(ftype), ftype)

        # get the current filter value and set the index of the combo box appropriately.
        filter = self._selector.getFilterType()
        self.filterType.currentIndexChanged[str].connect(
            self._filterTypeChanged)
        filterUILayout.addWidget(self.filterType)

        filterUILayout.addStretch()
        filterUILayout.addSpacing(4)

        self.customFilterEdit = CollectionFilterLineEdit()
        self.customFilterEdit.returnPressed.connect(
            lambda: self.customFilterEdit.clearFocus())
        self.customFilterEdit.setPlaceholderText(self.DRAG_DROP_FILTER_STRING)
        self.customFilterEdit.editingFinished.connect(self.customFilterEntered)
        showCustomFilter = (filter == selector.Filters.kCustom)

        layout.addRow("", filterUIWidget)
        layout.addRow(maya.stringTable['y_simpleSelector.kByTypeFilter'],
                      self.customFilterEdit)

    @ifNotBlockChangeMessages
    def _filterTypeChanged(self, value):
        filterNameMap = {
            selector.Filters.filterUIName(ftype): ftype
            for ftype in self._selector.getAvailableFilters()
        }
        self._selector.setFilterType(filterNameMap[value])

    def _setupStaticSelector(self):
        staticSelectionWidget = QWidget()
        staticSelectionLayout = QHBoxLayout()
        staticSelectionLayout.setContentsMargins(0, 0, 0, 0)
        staticSelectionLayout.setSpacing(utils.dpiScale(2))
        self.staticSelector = CollectionStaticSelectionWidget(self._selector)
        self.staticSelector.setFixedHeight(self.LIST_BOX_HEIGHT)
        staticSelectionLayout.addWidget(self.staticSelector)

        # Add the drag/drop buttons
        dragDropButtonLayout = QVBoxLayout()
        dragDropButtonLayout.setSpacing(utils.dpiScale(2))
        dragDropButtonLayout.setContentsMargins(0, 0, 0, 0)
        addButton = QPushButton(maya.stringTable['y_simpleSelector.kAdd'])
        addButton.setToolTip(
            maya.stringTable['y_simpleSelector.kStaticAddTooltipStr'])
        addButton.setMinimumWidth(self.EXPRESSION_BUTTON_WIDTH)
        addButton.clicked.connect(self.staticSelector.addEntry)
        dragDropButtonLayout.addWidget(addButton)
        removeButton = QPushButton(
            maya.stringTable['y_simpleSelector.kRemove'])
        removeButton.setToolTip(
            maya.stringTable['y_simpleSelector.kStaticRemoveTooltipStr'])
        removeButton.setMinimumWidth(self.EXPRESSION_BUTTON_WIDTH)
        removeButton.clicked.connect(self.staticSelector.removeEntry)
        dragDropButtonLayout.addWidget(removeButton)
        dragDropButtonLayout.addStretch(1)
        selectButton = QPushButton(self.SELECT_STRING)
        selectButton.setToolTip(
            maya.stringTable['y_simpleSelector.kStaticSelectTooltipStr'])
        selectButton.setMinimumWidth(self.EXPRESSION_BUTTON_WIDTH)
        selectButton.clicked.connect(self.selectStaticEntries)
        dragDropButtonLayout.addWidget(selectButton)
        dragDropButtonWidget = QWidget()
        staticSelectionLayout.addWidget(dragDropButtonWidget)
        dragDropButtonWidget.setLayout(dragDropButtonLayout)
        staticSelectionWidget.setLayout(staticSelectionLayout)
        self.addToCollectionGroupBoxLayout.addRow("", staticSelectionWidget)

    def _setupSelectAllButton(self):
        selectAllButtonWidget = QWidget()
        selectAllButtonLayout = QHBoxLayout()
        selectAllButtonLayout.setContentsMargins(0, 0, 0, 0)
        selectAllButtonLayout.setSpacing(utils.dpiScale(2))
        selectAllButton = QPushButton(
            maya.stringTable['y_simpleSelector.kSelectAll'])
        selectAllButtonLayout.addStretch(1)
        selectAllButtonLayout.addWidget(selectAllButton)
        selectAllButtonLayout.addStretch(1)
        selectAllButtonLayout.addSpacing(self.EXPRESSION_BUTTON_WIDTH)
        selectAllButtonWidget.setLayout(selectAllButtonLayout)
        self.addToCollectionGroupBoxLayout.addRow("", selectAllButtonWidget)

    def _setupFilterGroupBox(self, layout):
        filterGroupBox = QGroupBox(
            maya.stringTable['y_simpleSelector.kCollectionFilters'])
        font = QFont()
        font.setBold(True)
        filterGroupBox.setFont(font)
        filterGroupBox.setContentsMargins(0, utils.dpiScale(12), 0, 0)
        self.filtersGroupBoxLayout = Layout()
        self.filtersGroupBoxLayout.setVerticalSpacing(utils.dpiScale(2))

        self._setupFilterUI(self.filtersGroupBoxLayout)

        filterGroupBox.setLayout(self.filtersGroupBoxLayout)
        layout.addWidget(filterGroupBox)

    def _setupAddToCollectionGroupBox(self, layout):
        addToCollectionGroupBox = QGroupBox(
            maya.stringTable['y_simpleSelector.kAddToCollection'])
        font = QFont()
        font.setBold(True)
        addToCollectionGroupBox.setFont(font)
        addToCollectionGroupBox.setContentsMargins(0, utils.dpiScale(12), 0, 0)
        self.addToCollectionGroupBoxLayout = Layout()
        self.addToCollectionGroupBoxLayout.setVerticalSpacing(
            utils.dpiScale(2))

        self._setupIncludeExpression()
        self._setupStaticSelector()

        addToCollectionGroupBox.setLayout(self.addToCollectionGroupBoxLayout)
        layout.addWidget(addToCollectionGroupBox)

    def includeExpressionChanged(self, text):
        self.expression = text

    @ifNotBlockChangeMessages
    def includeExpressionEntered(self):
        self._selector.setPattern(self.expression)

    @ifNotBlockChangeMessages
    def customFilterEntered(self):
        customFilterText = self.customFilterEdit.text()
        self._selector.setCustomFilterValue(customFilterText)

    @guard.member('_blockChangeMessages', True)
    def populateFields(self):
        filter = self._selector.getFilterType()
        filterIndex = self.filterType.findData(filter)
        self.filterType.setCurrentIndex(filterIndex)

        showCustomFilter = (filter == selector.Filters.kCustom)
        customFilterText = self._selector.getCustomFilterValue()
        self.customFilterEdit.setText(customFilterText)
        self.customFilterEdit.setVisible(showCustomFilter)
        self.filtersGroupBoxLayout.labelForField(
            self.customFilterEdit).setVisible(showCustomFilter)

        expressionText = self._selector.getPattern()
        self.includeExpression.setText(expressionText)

        self.staticSelector.populate()

    def selectIncludeExpression(self):
        cmds.select(list(self._selector.getDynamicNames()),
                    add=False,
                    noExpand=True)

    def selectStaticEntries(self):
        self.staticSelector.selectMembers()
        cmds.select(list(self._selector.getStaticNames()),
                    add=False,
                    noExpand=True)

    def highlight(self, names):
        dynamicNames = self._selector.getDynamicNames()
        if next((name for name in names if name in dynamicNames),
                None) is not None:
            self.includeExpression.setSelection(
                0, len(self.includeExpression.text()))
        staticNames = self._selector.getStaticNames()
        self.staticSelector.highlight(
            set(name for name in names if name in staticNames))
Ejemplo n.º 24
0
def createPixmap(fileName):
    return utils.createPixmap(fileName, utils.dpiScale(20), utils.dpiScale(20))
Ejemplo n.º 25
0
 def sizeHint(self):
     return utils.dpiScale(self.STARTING_SIZE)
Ejemplo n.º 26
0
class CollapsibleArrowAndTitle(Frame):
    """
    This class defines the arrow used for a FrameLayout
    """

    # Constants
    WIDTH = utils.dpiScale(33)
    HEIGHT = utils.dpiScale(28)
    ARROW_COLOR = QColor(192, 192, 192)
    COLOR_BAR_WIDTH = utils.dpiScale(7)
    COLOR_BAR_HEIGHT = utils.dpiScale(28)
    EXPANDED_ARROW_OFFSET = utils.dpiScale(10.0)
    COLLAPSED_ARROW_OFFSET = utils.dpiScale(13.0)
    NODE_TYPE_TEXT_RECT = QRect(utils.dpiScale(20), 0, utils.dpiScale(1000),
                                HEIGHT)

    def __init__(self, item, parent):
        super(CollapsibleArrowAndTitle, self).__init__(item, parent=parent)
        self.isCollapsed = False
        fontMetric = QFontMetrics(self.item().data(Qt.FontRole))
        text = self.item().data(renderSetupRoles.NODE_TYPE_STR)
        self.setMinimumSize(self.WIDTH + fontMetric.width(text), self.HEIGHT)
        self.arrowPoints = BaseDelegate.EXPANDED_ARROW

    def setArrow(self, isCollapsed):
        """ Sets the arrow direction """
        self.arrowPoints = BaseDelegate.EXPANDED_ARROW if isCollapsed else BaseDelegate.COLLAPSED_ARROW

    def paintEvent(self, e):
        """ Draws the color bar and arrow """
        if self.item():
            painter = QPainter(self)

            # Draws the color bar
            painter.setPen(Qt.NoPen)
            rect = QRect(0, 0, self.COLOR_BAR_WIDTH, self.COLOR_BAR_HEIGHT)
            painter.fillRect(rect,
                             self.item().data(renderSetupRoles.NODE_COLOR_BAR))
            oldBrush = painter.brush()

            if self.item().type(
            ) == renderSetup.RENDER_OVERRIDE_TYPE and self.item(
            ).isLocalRender():
                diameter = rect.width() - 2
                rect2 = QRect(rect.x() + 1,
                              rect.y() + (rect.height() - diameter) / 2,
                              diameter, diameter)
                brush = painter.brush()
                pen = painter.pen()
                hints = painter.renderHints()

                painter.setRenderHint(QPainter.Antialiasing, on=True)
                painter.setPen(Qt.NoPen)
                painter.setBrush(
                    QBrush(QColor(67, 79, 70), style=Qt.SolidPattern))
                painter.drawEllipse(rect2)

                painter.setRenderHints(hints)
                painter.setPen(pen)
                painter.setBrush(brush)

            # Draws the arrow
            painter.setBrush(self.ARROW_COLOR)
            if self.arrowPoints == BaseDelegate.EXPANDED_ARROW:
                painter.translate(self.EXPANDED_ARROW_OFFSET, 0.0)
            else:
                painter.translate(self.COLLAPSED_ARROW_OFFSET, 0.0)
            painter.drawPolygon(self.arrowPoints)
            painter.setBrush(oldBrush)

            # Draws the node type text
            painter.setPen(QPen(self.item().data(Qt.TextColorRole)))
            text = self.item().data(renderSetupRoles.NODE_TYPE_STR)
            painter.setFont(self.item().data(Qt.FontRole))
            painter.drawText(self.NODE_TYPE_TEXT_RECT, text,
                             QTextOption(Qt.AlignLeft | Qt.AlignVCenter))
Ejemplo n.º 27
0
class toolBoxIII(QtWidgets.QWidget):

    mayaLightTypes = {
        "pointLight": cmds.pointLight,
        "ambientLight": cmds.ambientLight,
        "spotLight": cmds.spotLight,
        "directionalLight": cmds.directionalLight,
        "areaLight": partial(cmds.shadingNode, 'areaLight', al=True),
        "volumeLight": partial(cmds.shadingNode, 'volumeLight', al=True)
    }

    vrayLightTypes = {
        "VRayLightRectShape":
        partial(cmds.shadingNode, 'VRayLightRectShape', al=True),
        "VRayLightDomeShape":
        partial(cmds.shadingNode, 'VRayLightDomeShape', al=True),
        "VRayLightSphereShape":
        partial(cmds.shadingNode, 'VRayLightSphereShape', al=True),
        "VRayLightIESShape":
        partial(cmds.shadingNode, 'VRayLightIESShape', al=True),
        "VRayLightMesh":
        partial(cmds.shadingNode, 'VRayLightMeshShape', al=True),
        "VRayLightMeshLightLinking":
        partial(cmds.shadingNode, 'VRayLightMeshLightLinkingShape', al=True),
        "VRayPluginNodeLightShapeShape":
        partial(cmds.shadingNode, 'VRayPluginNodeLightShapeShape', al=True),
        "VRaySunShape":
        partial(cmds.shadingNode, 'VRayGeoSun', al=True)
    }

    renderManLightTypes = {
        "PxrAovLight": partial(cmds.shadingNode, 'PxrAovLight', al=True),
        "PxrDiskLight": partial(cmds.shadingNode, 'PxrDiskLight', al=True),
        "PxrDistantLight": partial(cmds.shadingNode,
                                   'PxrDistantLight',
                                   al=True),
        "PxrDomeLight": partial(cmds.shadingNode, 'PxrDomeLight', al=True),
        "PxrEnvDayLight": partial(cmds.shadingNode, 'PxrEnvDayLight', al=True),
        "PxrMeshLight": partial(cmds.shadingNode, 'PxrMeshLight', al=True),
        "PxrPortalLight": partial(cmds.shadingNode, 'PxrPortalLight', al=True),
        "PxrRectLight": partial(cmds.shadingNode, 'PxrRectLight', al=True),
        "PxrSphereLight": partial(cmds.shadingNode, 'PxrSphereLight', al=True)
    }

    arnoldLightTypes = {
        "aiAreaLight":
        partial(cmds.shadingNode, 'aiAreaLight', al=True),
        "aiMeshLight":
        mutils.createMeshLight,
        "aiPhotometricLight":
        partial(cmds.shadingNode, 'aiPhotometricLight', al=True),
        "aiSkyDomeLight":
        partial(cmds.shadingNode, 'aiSkyDomeLight', al=True)
    }

    BUTTON_SIZE = viewsUtils.dpiScale(20)

    def __init__(self, dock=True):
        if dock:
            parent = getDock()
        else:
            deleteDock()

            try:
                cmds.deleteUI('LightingManager')
            except:
                logger.debug('No previous UI exists')

            parent = QtWidgets.QDialog(parent=getMayaMainWindow())
            parent.setObjectName('LightingManager')
            parent.setWindowTitle('Lighting Manager')

            dlgLayout = QtWidgets.QVBoxLayout(parent)

        super(toolBoxIII, self).__init__(parent=parent)

        self.setWindowTitle('Lighting Manager')

        self.buildUI()

        self.populate()

        self.parent().layout().addWidget(self)

        if not dock:
            parent.show()

        self.userAppDir = cmds.internalVar(userAppDir=True)
        self.userLibaryDir = self.userAppDir + 'userLibrary'
        if not os.path.exists(self.userLibaryDir):
            os.mkdir(self.userLibaryDir)

    def buildUI(self):
        self.layout = QtWidgets.QGridLayout(self)
        pluginLights = typeMgr.pluginLights()
        self.mayaLights = sorted(typeMgr.mayaLights())
        self.vrayLights = sorted(
            [f for f in pluginLights if f.startswith("VRay")])
        self.renderManLights = sorted(
            [f for f in pluginLights if f.startswith("Pxr")])
        self.arnoldLights = sorted(
            [f for f in pluginLights if f.startswith("ai")])

        iconBtnWidget = QtWidgets.QWidget()
        self.iconBtnLayout = QtWidgets.QHBoxLayout(iconBtnWidget)
        self.layout.addWidget(iconBtnWidget, 0, 0)
        self.iconBtnLayout.addWidget(QtWidgets.QLabel("Maya_tk: "))

        # self.mayaLightTB = QtWidgets.QToolBar('Maya_tk Light')
        self.getMayaLight()

        self.getVrayLight()

        self.getRenderManLight()

        #self.getArnoldLight()

        self.lightLibraryUI()

        scrollWidget = QtWidgets.QWidget()
        scrollWidget.setSizePolicy(QtWidgets.QSizePolicy.Maximum,
                                   QtWidgets.QSizePolicy.Maximum)
        self.scrollLayout = QtWidgets.QVBoxLayout(scrollWidget)

        scrollArea = QtWidgets.QScrollArea()
        scrollArea.setWidgetResizable(True)
        scrollArea.setWidget(scrollWidget)
        self.layout.addWidget(scrollArea, 1, 0, 1, 5)

    def lightLibraryUI(self):
        libraryLabel = QtWidgets.QLabel('')
        libraryLabel.setAlignment(QtCore.Qt.AlignCenter)
        self.layout.addWidget(libraryLabel, 0, 0, 1, 4)

        libHeaderWidget = QtWidgets.QWidget()
        libHeaderLayout = QtWidgets.QHBoxLayout(libHeaderWidget)

        libHeaderScrollArea = QtWidgets.QScrollArea()
        libHeaderScrollArea.setWidget(libHeaderWidget)
        libHeaderScrollArea.setWidgetResizable(True)
        libHeaderScrollArea.setMaximumHeight(45)

        self.layout.addWidget(libHeaderScrollArea, 2, 0, 1, 5)
        self.saveNameField = QtWidgets.QLineEdit()
        self.saveNameField.setMinimumWidth(60)
        libHeaderLayout.addWidget(self.saveNameField)

        saveBtn = QtWidgets.QPushButton('Save')
        saveBtn.setMinimumWidth(120)
        saveBtn.clicked.connect(self.saveItem)
        libHeaderLayout.addWidget(saveBtn)

        buf = 12
        self.listLibWidget = QtWidgets.QListWidget()
        self.listLibWidget.setViewMode(QtWidgets.QListWidget.IconMode)
        self.listLibWidget.setIconSize(QtCore.QSize(60, 60))
        self.listLibWidget.setResizeMode(QtWidgets.QListWidget.Adjust)
        self.listLibWidget.setGridSize(QtCore.QSize(60 + buf, 60 + buf))
        self.layout.addWidget(self.listLibWidget, 3, 0, 1, 5)

        libFooterWidget = QtWidgets.QWidget()
        # libFooterWidget.setSizePolicy( QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum )
        self.libFooterLayout = QtWidgets.QGridLayout(libFooterWidget)
        self.libFooterLayout.setContentsMargins(QtCore.QMargins(2, 2, 2, 2))

        # Create QScrollArea
        scrollLibArea = QtWidgets.QScrollArea()
        scrollLibArea.setWidget(libFooterWidget)
        scrollLibArea.setWidgetResizable(True)
        scrollLibArea.setMaximumHeight(45)
        self.layout.addWidget(scrollLibArea, 4, 0, 1, 5)

        # Create QPlushButton
        importLibBtn = QtWidgets.QPushButton('Import')
        importLibBtn.setMinimumWidth(120)
        importLibBtn.clicked.connect(self.loadItem)
        self.libFooterLayout.addWidget(importLibBtn, 0, 0)

        # # Create QPlushButton
        referenceBtn = QtWidgets.QPushButton('Reference')
        referenceBtn.setMinimumWidth(120)
        referenceBtn.clicked.connect(self.referenceItem)
        self.libFooterLayout.addWidget(referenceBtn, 0, 1)
        #
        # Create QPlushButton
        removeBtn = QtWidgets.QPushButton('Remove')
        removeBtn.setMinimumWidth(120)
        removeBtn.clicked.connect(self.removeItem)
        self.libFooterLayout.addWidget(removeBtn, 0, 2)

    def populateAll(self):
        self.populateLibrarySection()
        self.populateManagerSection()

    def saveItem(self):
        name = self.saveNameField.text()
        if not name.strip():
            cmds.warning("You must give a name")
            cmds.confirmDialog(t='Warning', m='You must give a name', b='OK')
            return

        files = [f for f in os.listdir(DIRECTORY)]

        for file in files:
            if name in file:
                cmds.confirmDialog(t='Confirm',
                                   m='File %s already exists, override?' %
                                   name,
                                   b=['Yes', 'No'],
                                   db='Yes',
                                   cb='No',
                                   dismissString='No')

        self.library.save(name)
        self.saveNameField.setText('')
        self.populateAll()

    def removeItem(self):
        currentItem = self.listLibWidget.currentItem()
        if not currentItem:
            self.warningFunction('You must select something')
            return
        self.library.remove(currentItem)
        self.populateAll()

    def loadItem(self):
        currentItem = self.listLibWidget.currentItem()
        if not currentItem:
            self.warningFunction('You must select an item')

        name = currentItem.text()
        self.library.load(name)
        self.populateAll()

    def referenceItem(self):
        name = self.listLibWidget.currentItem().text() or ""
        if name == "":
            self.warningFunction('You must select something')
            return

        self.library.reference(name)
        self.populateAll()

    def populateLibrarySection(self):
        self.listLibWidget.clear()
        self.library.find()

        for name, info in self.library.items():
            item = QtWidgets.QListWidgetItem(name)
            self.listLibWidget.addItem(item)

            screenshot = info.get('screenshot')
            if screenshot:
                icon = QtGui.QIcon(screenshot)
                item.setIcon(icon)

    def getMayaLight(self):
        for lightType in self.mayaLights:
            icon = QIcon(typeMgr.getIcon(lightType))
            cmd = partial(self.createNewLight, lightType)
            toolTip = 'Create a new ' + lightType
            # mayaLightAction = self.createAction( lightType, icon, cmd, toolTip)
            # self.mayaLightTB.addAction(mayaLightAction)
            button = self.iconButton(cmd, icon, toolTip)
            self.iconBtnLayout.addWidget(button)
        # self.iconBtnLayout.addWidget(self.mayaLights)

    def getVrayLight(self):
        self.vrayLightTB = QtWidgets.QToolBar('Vray Light')
        if len(self.vrayLights) > 0:
            self.iconBtnLayout.addWidget(QtWidgets.QLabel("|"))
            self.iconBtnLayout.addWidget(QtWidgets.QLabel("Vray: "))
            for lightType in self.vrayLights:
                icon = QIcon(typeMgr.getIcon(lightType))
                cmd = partial(self.createNewLight, lightType)
                toolTip = 'Create a new ' + lightType
                # vrayLightAction = self.createAction( lightType,  icon, cmd, toolTip )
                # self.vrayLightTB.addAction( vrayLightAction )
                button = self.iconButton(cmd, icon, toolTip)
                self.iconBtnLayout.addWidget(button)
        else:
            pass

    def getRenderManLight(self):
        if len(self.renderManLights) > 0:
            self.iconBtnLayout.addWidget(QtWidgets.QLabel("|"))
            self.iconBtnLayout.addWidget(QtWidgets.QLabel("RenderMan: "))
            for lightType in self.renderManLights:
                icon = QIcon(typeMgr.getIcon(lightType))
                cmd = partial(self.createNewLight, lightType)
                toolTip = 'Create a new ' + lightType
                # renderManLightAction = self.createAction( lightType,  icon, cmd, toolTip )
                # mayaLightTB.addAction( renderManLightAction )
                button = self.iconButton(cmd, icon, toolTip)
                self.iconBtnLayout.addWidget(button)
        else:
            pass

    def getArnoldLight(self):
        if len(self.arnoldLights) > 0:
            self.iconBtnLayout.addWidget(QtWidgets.QLabel("|"))
            self.iconBtnLayout.addWidget(QtWidgets.QLabel("Arnold: "))
            for lightType in self.arnoldLights:
                icon = QIcon(typeMgr.getIcon(lightType))
                cmd = partial(self.createNewLight, lightType)
                toolTip = 'Create a new ' + lightType
                # arnoldLightAction = self.createAction( lightType, icon, cmd, toolTip )
                # mayaLightTB.addAction( arnoldLightAction )
                button = self.iconButton(cmd, icon, toolTip)
                self.iconBtnLayout.addWidget(button)
        # self.iconBtnLayout.addStretch(1)
        else:
            pass

    def iconButton(self, cmd, icon, toolTip):
        button = RenderSetupButton(self, icon, self.BUTTON_SIZE)
        button.setToolTip(toolTip)
        button.clicked.connect(partial(cmd))
        return button

    def createAction(self, lightType, icon, cmd, toolTip):
        action = QtWidgets.QAction(icon, lightType, self)
        action.setStatusTip(toolTip)
        action.triggered.connect(partial(cmd))
        return action

    def createNewLight(self, lightType=None, *args):
        if lightType in self.mayaLights:
            func = self.mayaLightTypes[lightType]
        else:
            pass

        if lightType in self.vrayLights:
            func = self.vrayLightTypes[lightType]
        else:
            pass

        if lightType in self.renderManLights:
            func = self.renderManLightTypes[lightType]
        else:
            pass

        if lightType in self.arnoldLights:
            func = self.arnoldLightTypes[lightType]
        else:
            pass

        light = func()

        self.addLight(light)

    def addLight(self, light):
        widget = LightManager(light)
        self.scrollLayout.addWidget(widget)
        widget.onSolo.connect(self.onSolo)

    def onSolo(self, value):
        lightWidgets = self.findChildren(LightManager)
        for widget in lightWidgets:
            if widget != self.sender():
                widget.disableLight(value)

    def populate(self):
        while self.scrollLayout.count():
            widget = self.scrollLayout.takeAt(0).widget()
            if widget:
                widget.setVisible(False)
                widget.deleteLater()

        type = [str(f) for f in self.mayaLights + typeMgr.pluginLights()]
        for light in pm.ls(type=type):
            self.addLight(light)
Ejemplo n.º 28
0
class EditorCentralWidget(QWidget):
    """ This class implements the dockable light editor. """

    # Constants
    STARTING_SIZE = QSize(viewsUtils.dpiScale(600), viewsUtils.dpiScale(600))
    BUTTON_SIZE = viewsUtils.dpiScale(20)
    TAB_LAYOUT_RIGHT_MARGIN = viewsUtils.dpiScale(2)
    TAB_LAYOUT_BOTTOM_MARGIN = viewsUtils.dpiScale(2)
    PREFERRED_SIZE = STARTING_SIZE
    MINIMUM_SIZE = QSize(viewsUtils.dpiScale(220), viewsUtils.dpiScale(220))

    def __init__(self, parent=None):
        super(EditorCentralWidget, self).__init__(parent=parent)
        self.disposed = False
        self.lookThroughWindow = None

        # Set up the model that the tree view will use
        typeMgr.rebuild()
        self.model = ItemModel()

        self.resize(self.STARTING_SIZE)

        layout = QVBoxLayout()

        # Create tab layout
        self.tabWidget = QWidget()
        tabLayout = QHBoxLayout()
        QLayoutItem.setAlignment(tabLayout, Qt.AlignBottom)
        tabLayout.setContentsMargins(0, 0, self.TAB_LAYOUT_RIGHT_MARGIN,
                                     self.TAB_LAYOUT_BOTTOM_MARGIN)
        tabLayout.setSizeConstraint(QLayout.SetMinimumSize)

        self.tabButtons = []
        self.lightButtons = []

        mayaLights = typeMgr.mayaLights()
        for lightType in mayaLights:
            if typeMgr.excludeFromUI(lightType):
                continue
            icon = QIcon(typeMgr.getIcon(lightType))
            button = RenderSetupButton(self, icon, self.BUTTON_SIZE)
            button.clicked.connect(self.getLightCreator(lightType))
            toolTip = maya.stringTable['y_editor.kCreateaNew1'] + lightType
            button.setToolTip(toolTip)
            self.tabButtons.append(button)
            self.lightButtons.append(button)
            tabLayout.addWidget(button)

        pluginLights = typeMgr.pluginLights()
        if len(pluginLights) > 0:
            tabLayout.addWidget(QLabel(" | "))

            for lightType in pluginLights:
                icon = QIcon(typeMgr.getIcon(lightType))
                button = RenderSetupButton(self, icon, self.BUTTON_SIZE)
                button.clicked.connect(self.getLightCreator(lightType))
                toolTip = maya.stringTable['y_editor.kCreateaNew2'] + lightType
                button.setToolTip(toolTip)
                self.tabButtons.append(button)
                # Don't add plugin lights to the lightButton array
                # This is only used for automated testing and a plugin light might
                # have custom dialogs pop up that the test system can't handle
                # self.lightButtons.append(button)
                tabLayout.addWidget(button)

        tabLayout.addWidget(QLabel(" | "))

        button = QPushButton(maya.stringTable['y_editor.kNewGroup2'])
        button.clicked.connect(self.newGroup)
        button.setToolTip(maya.stringTable['y_editor.kCreateaNewGroup'])
        self.tabButtons.append(button)
        self.groupButton = button
        tabLayout.addWidget(button)

        tabLayout.addWidget(QLabel(" | "))

        self.layerText = QLabel(LAYER_TEXT)
        tabLayout.addWidget(self.layerText)

        tabLayout.addStretch(1)

        icon = QIcon(":/view.png")
        button = RenderSetupButton(self, icon, self.BUTTON_SIZE)
        button.clicked.connect(self._lookThroughSelected)
        self.tabButtons.append(button)
        tabLayout.addWidget(button)

        icon = QIcon(":/snapToGeo.png")
        button = RenderSetupButton(self, icon, self.BUTTON_SIZE)
        button.clicked.connect(self._snapToSelected)
        self.tabButtons.append(button)
        tabLayout.addWidget(button)

        self.tabWidget.setLayout(tabLayout)
        layout.addWidget(self.tabWidget)

        # Adds tree view to the window's layouts
        self.treeView = EditorTreeView(self)
        self.treeView.header().resizeSections(QHeaderView.ResizeToContents)
        # The name column needs to be set to a larger size
        self.treeView.setColumnWidth(0, NAME_COLUMN_WIDTH)
        layout.addWidget(self.treeView)

        self.setLayout(layout)

        self.mayaPreFileNewOrOpenedID = om.MEventMessage.addEventCallback(
            "PreFileNewOrOpened", self._onMayaPreFileNewOrOpenedCB, self)
        self.mayaSelectionChangedID = om.MEventMessage.addEventCallback(
            "SelectionChanged", self._onMayaSelectionChangedCB, self)
        self.mayaNewSceneOpenedID = om.MEventMessage.addEventCallback(
            "NewSceneOpened", self._onMayaSceneChangedCB, self)
        self.mayaSceneOpenedID = om.MEventMessage.addEventCallback(
            "SceneOpened", self._onMayaSceneChangedCB, self)
        self.mayaSceneImportedID = om.MEventMessage.addEventCallback(
            "SceneImported", self._onMayaSceneChangedCB, self)
        self.mayaNodeAddedID = om.MDGMessage.addNodeAddedCallback(
            self._onMayaNodeAddedCB, "dependNode", self)

        # We need to track changes to Color Management since we
        # handle color management for light source colors ourself
        self.mayaColorMgtIDs = []
        self.mayaColorMgtIDs.append(
            om.MEventMessage.addEventCallback("colorMgtEnabledChanged",
                                              self._onMayaColorMgtChangedCB,
                                              self))
        self.mayaColorMgtIDs.append(
            om.MEventMessage.addEventCallback("colorMgtConfigChanged",
                                              self._onMayaColorMgtChangedCB,
                                              self))
        self.mayaColorMgtIDs.append(
            om.MEventMessage.addEventCallback("colorMgtWorkingSpaceChanged",
                                              self._onMayaColorMgtChangedCB,
                                              self))
        self.mayaColorMgtIDs.append(
            om.MEventMessage.addEventCallback(
                "colorMgtPrefsViewTransformChanged",
                self._onMayaColorMgtChangedCB, self))
        self.mayaColorMgtIDs.append(
            om.MEventMessage.addEventCallback("colorMgtPrefsReloaded",
                                              self._onMayaColorMgtChangedCB,
                                              self))
        self.mayaColorMgtIDs.append(
            om.MEventMessage.addEventCallback("colorMgtUserPrefsChanged",
                                              self._onMayaColorMgtChangedCB,
                                              self))

        self.model.loadScene()
        self.treeView.loadColumnOrder()
        self._onMayaSelectionChangedCB(None)

        # Restore all expanded nodes, beginning from the root
        self._restoreExpandedState(self.treeView.rootIndex())

    def sizeHint(self):
        return self.PREFERRED_SIZE

    def minimumSizeHint(self):
        return self.MINIMUM_SIZE

    def _onMayaPreFileNewOrOpenedCB(self, clientData):
        with enterScope.EnterMayaScope(self.model) as scope:
            if scope.active:
                # Cleanup internal state since a new file is about to open
                self.model.startReset()

    def _onMayaSelectionChangedCB(self, clientData):

        if self.model.isResetting(): return

        if not self.treeView.selectionChangeInstigator is None: return
        self.treeView.selectionChangeInstigator = "maya"

        selectionList = om.MGlobal.getActiveSelectionList()

        nodes = []

        for sidx in range(selectionList.length()):
            mayaObj = selectionList.getDependNode(sidx)

            # Extend to parent transform is needed
            if typeMgr.isValidLightShapeObject(mayaObj):
                mayaObj = typeMgr.findLightTransformObject(mayaObj)

            if mayaObj and (typeMgr.isValidLightTransformObject(mayaObj)
                            or typeMgr.isGroup(mayaObj)):
                node = self.model.findNode(mayaObj)
                if node:
                    nodes.append(node)

        # Workaround for a PySide2 issue in which QItemSelectionModel.select(QItemSelection, SelectionFlags) isn't available
        sm = self.treeView.selectionModel()
        sm.clear()
        for node in nodes:
            sm.select(self.model.indexFromNode(node),
                      QItemSelectionModel.Rows | QItemSelectionModel.Select)

        self.treeView.selectionChangeInstigator = None

        self.selectionChanged()

    def _onMayaSceneChangedCB(self, clientData):
        with enterScope.EnterMayaScope(self.model) as scope:
            if scope.active:
                self.model.loadScene()
                self._onMayaSelectionChangedCB(None)

    def _addLightSource(self,
                        transformObj,
                        shapeObj,
                        selected=None,
                        focus=True):
        # Check if we have a valid parent selected
        parentIndex = self.treeView.rootIndex()
        if selected is None:
            selected = self.treeView.selectedIndexes()
        if len(selected) > 0:
            selItem = selected[-1]  # Insert after last item
            parent = self.model.nodeFromIndex(selItem)
            if parent.typeId() != TYPE_ID_LIGHT_ITEM:
                parentIndex = selItem
            else:
                parentIndex = self.model.indexFromNode(parent.parent())

        # Insert to this parent
        light = self.model.addLightSource(transformObj, shapeObj, parentIndex)
        # We want to save the expand state, only if it's a group, not the root
        if parentIndex != self.treeView.rootIndex():
            self.treeView.setExpanded(parentIndex, True)
        if focus:
            self.treeView.focus(light)

        # Refresh editor
        self.scheduleRefresh()

    def _onMayaNodeAddedCB(self, mayaObj, clientData):
        if self.model.isResetting(): return
        with enterScope.EnterMayaScope(self.model) as scope:
            if scope.active:
                lightTransformObj = typeMgr.findLightTransformObject(mayaObj)
                if lightTransformObj:
                    lightSource = self.model.findNode(lightTransformObj)
                    if lightSource:
                        # Light source node already exists in out model.
                        # This must be a new light shape added to the transform.
                        # Just reset with the new light shape in this case.
                        lightSource.initialize(mayaObj)
                    else:
                        # Light source not found so create it
                        self._addLightSource(lightTransformObj,
                                             mayaObj,
                                             focus=False)

    def _onMayaColorMgtChangedCB(self, clientData):
        self.scheduleRefresh()

    def scheduleRefresh(self):
        if not cmds.about(batch=True):
            # Do the refresh through global editorRefresh function, handling the case
            # where editor is destroyed before the deferred refresh is executed
            cmds.evalDeferred(
                "import maya.app.renderSetup.views.lightEditor.editor as ed; ed.editorRefresh()",
                lowestPriority=True)

    def refresh(self):
        if not self.disposed:
            # Force an update on the model to refresh the view
            self.model.emitDataChanged(QModelIndex(), QModelIndex())

    def __del__(self):
        self.dispose()

    def dispose(self):
        if self.disposed: return
        self.disposed = True

        self.treeView.dispose()

        if self.lookThroughWindow:
            self.lookThroughWindow.windowStateChanged.disconnect(
                self.saveLookThroughWindowState)
            self.lookThroughWindow.close()
            self.lookThroughWindow = None

        if self.mayaPreFileNewOrOpenedID != 0:
            om.MEventMessage.removeCallback(self.mayaPreFileNewOrOpenedID)
            self.mayaPreFileNewOrOpenedID = 0

        if self.mayaSelectionChangedID != 0:
            om.MEventMessage.removeCallback(self.mayaSelectionChangedID)
            self.mayaSelectionChangedID = 0

        if self.mayaNewSceneOpenedID != 0:
            om.MEventMessage.removeCallback(self.mayaNewSceneOpenedID)
            self.mayaNewSceneOpenedID = 0

        if self.mayaSceneOpenedID != 0:
            om.MEventMessage.removeCallback(self.mayaSceneOpenedID)
            self.mayaSceneOpenedID = 0

        if self.mayaSceneImportedID != 0:
            om.MEventMessage.removeCallback(self.mayaSceneImportedID)
            self.mayaSceneImportedID = 0

        if self.mayaNodeAddedID != 0:
            om.MEventMessage.removeCallback(self.mayaNodeAddedID)
            self.mayaNodeAddedID = 0

        om.MEventMessage.removeCallbacks(self.mayaColorMgtIDs)
        self.mayaColorMgtIDs = []

        self.model.dispose()
        del self.model
        self.model = None

        # If this is our singleton instance reset it
        # to notify this window is closed and disposed now
        global _editorInstance
        if self == _editorInstance:
            _editorInstance = None

    def setEditorMode(self, mode, layer):
        # Note: Layer mode allows the creation of overrides
        #       Global mode forbids the creation of overrides
        self.model.setModelContext(layer, mode == Editor.EDITOR_LAYER_MODE)
        self.layerText.setText(LAYER_TEXT + layer.name() if mode == Editor.
                               EDITOR_LAYER_MODE else DEFAULT_LAYER_TEXT)

    def selectionChanged(self):
        if self.lookThroughWindow and self.lookThroughWindow.isVisible():
            # We don't want to window to pop to front for every new selection
            # so set bringToFront to False in this case
            self._lookThroughSelected(bringToFront=False)

    def newGroup(self):
        self.treeView.selectionChangeInstigator = "lightmanager"

        # Create the Maya node
        cmds.createNode("objectSet", name="Group")
        mayaObj = utils.findSelectedNodeFromMaya()
        if not mayaObj:
            self.treeView.selectionChangeInstigator = None
            return

        # Check if we have a valid parent selected
        parentIndex = self.treeView.rootIndex()
        selected = self.treeView.selectedIndexes()
        if len(selected) > 0:
            selItem = selected[-1]
            parent = self.model.nodeFromIndex(selItem)
            if parent.typeId() != TYPE_ID_LIGHT_ITEM:
                parentIndex = selItem
            else:
                parentIndex = self.model.indexFromNode(parent.parent())

        # Insert to this parent
        group = self.model.addGroup(mayaObj, parentIndex)
        self.treeView.focus(group)
        # We want to save the expand state, only if it's a group, not the root
        if parentIndex != self.treeView.rootIndex():
            self.treeView.setExpanded(parentIndex, True)

        self.treeView.selectionChangeInstigator = None

        self._onMayaSelectionChangedCB(None)

    def newLight(self, lightType):
        """ Adds a new light to the model. """

        # Capture selection before we create the new light source (since that changes selection)
        selectionList = self.treeView.selectedIndexes()

        with enterScope.EnterLightScope(self.model) as scope:
            if scope:
                cmd = typeMgr.getCreateCmd(lightType)
                if cmd and len(cmd) > 0:
                    mel.eval(cmd)
                else:
                    self._createLightWithTransform(lightType)

                transformObj = utils.findSelectedNodeFromMaya()
                if not typeMgr.isValidLightTransformObject(transformObj):
                    transformObj = typeMgr.findLightTransformObject(
                        transformObj)

                shapeObj = typeMgr.findLightShapeObject(transformObj)

                if transformObj and shapeObj:
                    self._addLightSource(transformObj,
                                         shapeObj,
                                         selected=selectionList,
                                         focus=True)
                    self._onMayaSelectionChangedCB(None)

    def _restoreExpandedState(self, index):
        """ Recursively get all indexes of the treeview
		and expand them if they were already expanded before closing the 
		window, and do the same on their children.
		It stops because lights do not have children
		(and if they have children, it will still work) """

        node = self.model.nodeFromIndex(index)
        for i in range(node.childCount()):
            childIndex = node.child(i).index()
            self.treeView.setExpanded(
                childIndex,
                viewsUtils.getExpandedState(node.child(i).mayaHandle.object()))
            self._restoreExpandedState(childIndex)

    def setAttributeByLabel(self, nodeName, attrLabel, value):
        """ Set value for attribute with given label on the node with given name. """
        obj = commonUtils.nameToNode(nodeName)
        if self.model is None or obj is None:
            return
        node = self.model.findNode(obj)
        node.setAttributeByLabel(attrLabel, value)

    def getLightCreator(self, lightType):
        def _lightCreator():
            self.newLight(lightType)

        return _lightCreator

    def _createLightWithTransform(self, lightType):
        name = cmds.shadingNode(lightType,
                                asLight=True,
                                name="%sShape1" % lightType)
        cmds.select(name)
        return name

    def _moveToOrigo(self):
        cmds.move(0, 0, 0, absolute=True)

    def _snapToSelected(self):
        sit = om.MItSelectionList(om.MGlobal.getActiveSelectionList())
        sit.setFilter(om.MItSelectionList.kDagSelectionItem)

        centerDagPath = None
        names = []
        while not sit.isDone():
            dp = sit.getDagPath()
            sit.next()
            if sit.isDone():
                centerDagPath = dp
            else:
                names.append(dp.fullPathName())

        if len(names) == 0:
            print(maya.stringTable['y_editor.kSnapToObjectNothingSelected'])
            return

        # NOTE: We use the exclusive matrix since the bounding box is partially transformed
        #       The bbox does not take parent transforms into account though
        mtx = centerDagPath.exclusiveMatrix()
        centerNode = centerDagPath.node()
        dagFN = om.MFnDagNode(centerNode)
        pos = dagFN.boundingBox.center * mtx

        cmds.move(pos[0],
                  pos[1],
                  pos[2],
                  names,
                  absolute=True,
                  worldSpaceDistance=True)

    def saveLookThroughWindowState(self):
        windowState = self.lookThroughWindow.showRepr()
        cmds.optionVar(sv=(LookThroughWindow.WINDOW_STATE_PREFERENCE,
                           windowState))

    def _lookThroughSelected(self, bringToFront=True):
        """ Opens a model panel with camera looking through currently selected light. """
        createLookThroughWindow(shouldBringToFront=bringToFront)

    def lookThroughWindowDestroyed(self):
        self.lookThroughWindow = None
Ejemplo n.º 29
0
class SceneDelegate(BaseDelegate):
    """
    This class provides customization of the appearance of items in the Model.
    """

    FRAME_INFO_OFFSET = utils.dpiScale(90)
    CURRENT_FRAME = maya.stringTable['y_sceneDelegate.kCurrentFrame']
    FRAME_RANGE = maya.stringTable['y_sceneDelegate.kFrameRange']

    QUICK_SETTINGS_IMAGE = createPixmap(":/RS_quick_settings_popup.png")

    kTooltips = {
        scene.SET_VISIBILITY_ACTION:
        maya.stringTable['y_sceneDelegate.kVisibilityToolTip'],
        scene.SET_RENDERABLE_ACTION:
        maya.stringTable['y_sceneDelegate.kRenderableToolTip'],
        scene.PRESET_MENU:
        maya.stringTable['y_sceneDelegate.kPresetMenuToolTip'],
        scene.AOVS_MENU:
        maya.stringTable['y_sceneDelegate.kAovsMenuToolTop']
    }

    def __init__(self, treeView):
        super(SceneDelegate, self).__init__(treeView)

    def _getItem(self, index):
        return self.treeView().model().itemFromIndex(index)

    def _drawFill(self, painter, rect, item, isHighlighted, highlightColor):
        rect2 = deepcopy(rect)

        oldPen = painter.pen()
        painter.fillRect(rect2, item.data(Qt.BackgroundRole))

        # draw a 2 pixel border around the box if the item is "active"
        if item.isActive():
            painter.setPen(QPen(item.data(scene.NODE_ACTIVE_FRAME), 2))
            rect2.setLeft(rect2.left() + 2)
            rect2.setRight(rect2.right() - 1)
            rect2.setTop(rect2.top() + 1)
            rect2.setBottom(rect2.bottom() - 1)
            painter.drawRect(rect2)
        painter.setPen(oldPen)

        rect.setLeft(rect.left() + self.COLOR_BAR_WIDTH)

    def _drawArrow(self, painter, rect, item):
        if item.type() != scene.SCENE_CATEGORY_TYPE:
            rect2 = deepcopy(rect)
            rect2.setLeft(rect2.left())
            rect2.setRight(rect2.left() + 3)
            for i in range(1, 7):
                painter.drawPoint(rect2.left(), rect2.top() + 4 * i)
                painter.drawPoint(rect2.right(), rect2.top() + 4 * i)

        super(SceneDelegate, self)._drawArrow(painter, rect, item)

    def _drawText(self, painter, rect, item):
        super(SceneDelegate, self)._drawText(painter, rect, item)

        if item.type() == scene.SCENE_CATEGORY_RENDER_SETTINGS_TYPE:
            oldPen = painter.pen()
            painter.setPen(QPen(item.data(Qt.TextColorRole), 1))
            painter.setFont(item.data(Qt.FontRole))
            textRect = deepcopy(rect)
            textRect.setLeft(textRect.left() + self.FRAME_INFO_OFFSET +
                             self.TEXT_LEFT_OFFSET)
            textRect.setRight(textRect.right() - self.TEXT_RIGHT_OFFSET)
            if not item.data(scene.NODE_FRAME_ANIMATION):
                painter.drawText(textRect, Qt.AlignCenter, self.CURRENT_FRAME)
            else:
                painter.drawText(
                    textRect, Qt.AlignCenter,
                    self.FRAME_RANGE % (item.data(scene.NODE_START_FRAME),
                                        item.data(scene.NODE_END_FRAME)))
            painter.setPen(oldPen)

    def _addActionIcons(self, painter, rect, item, highlightedColor):
        toolbarCount = item.getActionButtonCount()

        # draw the darkened toolbar frame
        if item.type(
        ) != scene.SCENE_CATEGORY_RENDER_SETTINGS_TYPE and item.type(
        ) != scene.SCENE_CATEGORY_AOVS_TYPE:
            self.drawToolbarFrame(painter, rect, toolbarCount)

        start = self.ACTION_BORDER
        for iconIndex in range(0, toolbarCount):
            actionName = item.getActionButton(iconIndex)
            checked = False
            pixmap = None
            if (actionName == scene.SET_VISIBILITY_ACTION):
                pixmap = self.VISIBILITY_IMAGE
                checked = item.data(scene.NODE_VISIBLE)
            elif (actionName == scene.SET_RENDERABLE_ACTION):
                pixmap = self.RENDERABLE_IMAGE
                checked = item.data(scene.NODE_RENDERABLE)
            elif (actionName == scene.PRESET_MENU
                  or actionName == scene.AOVS_MENU):
                pixmap = self.QUICK_SETTINGS_IMAGE

            start += self.ACTION_WIDTH
            self.drawAction(painter, actionName, pixmap,
                            rect.right() - start,
                            rect.top() + self.ICON_TOP_OFFSET,
                            highlightedColor if checked else None, False, None)

        if self.lastHitAction:
            try:
                item.setToolTip(self.kTooltips[self.lastHitAction])
            except KeyError:
                item.setToolTip("")
        else:
            item.setToolTip(
                ""
            )  # ===========================================================================
Ejemplo n.º 30
0
class BaseDelegate(QStyledItemDelegate):
    """
    This class provides customization of the appearance of items in a Model.
    """

    # Constants
    ARROW_COLOR = QColor(189, 189, 189)
    DISABLED_BACKGROUND_IMAGE = utils.createPixmap(":/RS_disabled_tile.png")
    DISABLED_HIGHLIGHT_IMAGE = utils.createPixmap(
        ":/RS_disabled_tile_highlight.png")
    COLOR_BAR_WIDTH = utils.dpiScale(6)
    TEXT_LEFT_OFFSET = utils.dpiScale(22)
    TEXT_RIGHT_OFFSET = utils.dpiScale(36)
    LAYER_TEXT_RIGHT_OFFSET = utils.dpiScale(70)
    COLLECTION_TEXT_RIGHT_OFFSET = utils.dpiScale(90)

    BOTTOM_GAP_OFFSET = utils.dpiScale(2)
    EXPANDED_ARROW_OFFSET = utils.dpiScale(3.0)
    COLLAPSED_ARROW_OFFSET = utils.dpiScale(6.0)
    EXPANDED_ARROW = (utils.dpiScale(QPointF(0.0, 11.0)),
                      utils.dpiScale(QPointF(10.0, 11.0)),
                      utils.dpiScale(QPointF(5.0, 16.0)))
    COLLAPSED_ARROW = (utils.dpiScale(QPointF(0.0, 8.0)),
                       utils.dpiScale(QPointF(5.0, 13.0)),
                       utils.dpiScale(QPointF(0.0, 18.0)))

    LAST_ICON_RIGHT_OFFSET = utils.dpiScale(24)
    ICON_WIDTH = utils.dpiScale(20)
    WARNING_ICON_WIDTH = utils.dpiScale(11)
    ICON_TOP_OFFSET = utils.dpiScale(4)

    ACTION_BORDER = utils.dpiScale(2)
    ACTION_WIDTH = utils.dpiScale(24)  # ICON_WIDTH + (2*ACTION_BORDER)

    VISIBILITY_IMAGE = utils.createPixmap(":/RS_visible.png")
    RENDERABLE_IMAGE = utils.createPixmap(":/RS_render.png")
    WARNING_IMAGE = utils.createPixmap(":/RS_warning.png")

    def __init__(self, treeView):
        super(BaseDelegate, self).__init__()
        self.treeView = weakref.ref(treeView)
        self.lastHitAction = None

    def _getItem(self, index):
        """ Override this function to return the item associated with the provided index. NOTE: Do not implement this function directly! """
        pass

    def _drawColorBar(self, painter, rect, item):
        """ Override this function to draw a color bar in front of the filled portion of the row. NOTE: Do not implement this function directly! """
        pass

    def _drawFill(self, painter, rect, item, isHighlighted, highlightColor):
        """ Override this function to draw the fill. NOTE: Do not implement this function directly! """
        pass

    def _drawArrow(self, painter, rect, item):
        painter.save()
        if item.rowCount() != 0:
            arrow = None
            if self.treeView().isExpanded(item.index()):
                painter.translate(rect.left() + self.EXPANDED_ARROW_OFFSET,
                                  rect.top())
                arrow = self.EXPANDED_ARROW
            else:
                painter.translate(rect.left() + self.COLLAPSED_ARROW_OFFSET,
                                  rect.top())
                arrow = self.COLLAPSED_ARROW
            oldBrush = painter.brush()
            painter.setBrush(self.ARROW_COLOR)
            painter.setPen(Qt.NoPen)
            painter.drawPolygon(arrow)
            painter.setBrush(oldBrush)
        painter.restore()

    def _drawText(self, painter, rect, item):
        oldPen = painter.pen()
        painter.setPen(QPen(item.data(Qt.TextColorRole), 1))
        painter.setFont(item.data(Qt.FontRole))
        textRect = self.getTextRect(rect, item)
        painter.drawText(textRect, item.data(Qt.TextAlignmentRole),
                         item.data(Qt.DisplayRole))
        painter.setPen(oldPen)

    def _drawWarning(self, painter, rect, item):
        pass

    def getTextRect(self, rect, item):
        textRect = deepcopy(rect)
        textRect.setLeft(textRect.left() + self.TEXT_LEFT_OFFSET)
        textRect.setRight(textRect.right() - self.TEXT_RIGHT_OFFSET)
        return textRect

    def _addActionIcons(self, painter, rect, item, highlightedColor):
        """ Override this function to draw the action icons (visibility, renderability, etc). NOTE: Do not implement this function directly! """
        pass

    def drawToolbarFrame(self, painter, rect, toolbarCount):
        # draw the darkened toolbar background
        if toolbarCount > 0:
            top = rect.top() + self.ICON_TOP_OFFSET
            backGroundColor = QColor(55, 55, 55)
            toolbarLength = toolbarCount * self.ACTION_WIDTH + (
                2 * self.ACTION_BORDER)
            left = rect.right() - (toolbarLength + self.ACTION_BORDER)
            left = left if left > 0 else 0
            painter.setOpacity(0.8)
            painter.fillRect(left, top - self.ACTION_BORDER, toolbarLength,
                             self.ACTION_WIDTH, backGroundColor)
            painter.setOpacity(1.0)

    def drawPixmap(self, painter, pixmap, left, top):
        painter.drawPixmap(QRect(left, top, self.ICON_WIDTH, self.ICON_WIDTH),
                           pixmap)

    def drawAction(self, painter, actionName, pixmap, left, top,
                   highlightedColor, drawDisclosure, borderColor):
        if (pixmap != None):
            iconRect = QRect(left, top, self.ICON_WIDTH, self.ICON_WIDTH)
            if highlightedColor is not None:
                painter.fillRect(iconRect, highlightedColor)

            # draw the icon.  Its opacity depends on mouse over.
            p = self.treeView().mapFromGlobal(QCursor.pos())
            if not iconRect.contains(p):
                painter.setOpacity(0.7)
            else:
                painter.setOpacity(1.0)
                self.lastHitAction = actionName
            self.drawPixmap(painter, pixmap, left, top)
            painter.setOpacity(1.0)

            if drawDisclosure:
                painter.drawPixmap(iconRect, self.DISCLOSURE_IMAGE)

            if borderColor:
                oldPen = painter.pen()
                painter.setPen(QPen(borderColor, 1))
                painter.drawRect(iconRect)
                painter.setPen(oldPen)

    def paint(self, painter, option, index):
        """ Renders the delegate using the given painter and style option for the item specified by index. """

        # If the index is invalid we have nothing to draw
        if not index.isValid():
            return

        item = self._getItem(index)
        indent = item.depth() * self.treeView().indentation()
        rect = deepcopy(option.rect)
        rect.setLeft(indent)
        rect.setBottom(rect.bottom() - self.BOTTOM_GAP_OFFSET)
        isHighlighted = option.showDecorationSelected and option.state & QStyle.State_Selected
        highlightedColor = option.palette.color(QPalette.Highlight)

        self._drawColorBar(painter, rect, item)
        self._drawFill(painter, rect, item, isHighlighted, highlightedColor)
        self._drawArrow(painter, rect, item)
        self._drawText(painter, rect, item)
        self._addActionIcons(painter, rect, item, highlightedColor)
        self._drawWarning(painter, rect, item)