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_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)
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)
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
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)
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)
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)
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)
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)
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 _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 _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 _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 _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 _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)
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)
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)
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)
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)
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)
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
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
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))
def createPixmap(fileName): return utils.createPixmap(fileName, utils.dpiScale(20), utils.dpiScale(20))
def sizeHint(self): return utils.dpiScale(self.STARTING_SIZE)
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))
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)
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
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( "" ) # ===========================================================================
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)