From 33d55e6131b6eb62ff07aa534ef0db35030baeaa Mon Sep 17 00:00:00 2001 From: Ulrich Haberl Date: Wed, 30 Oct 2024 18:59:56 +0100 Subject: [PATCH 1/8] including light linking spike demo code --- .../resources/ae/usdschemabase/ae_template.py | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py b/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py index 30fc1dedaf..cbd524329d 100644 --- a/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py +++ b/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py @@ -204,6 +204,55 @@ def get(self): folderIndex[groups].items.append(attributeInfo.name) return self._attributeLayout +import logging +logging.basicConfig(level=logging.DEBUG) +logger = logging.getLogger(__name__) + +class LightLinkingCustomControl(object): + '''Custom control for the light linking data we want to display.''' + def __init__(self, item, prim, useNiceName): + # In Maya 2022.1 we need to hold onto the Ufe SceneItem to make + # sure it doesn't go stale. This is not needed in latest Maya. + super(LightLinkingCustomControl, self).__init__() + mayaVer = '%s.%s' % (cmds.about(majorVersion=True), cmds.about(minorVersion=True)) + self.item = item if mayaVer == '2022.1' else None + self.prim = prim + self.useNiceName = useNiceName + + def onCreate(self, *args): + try: + try: + from shiboken6 import wrapInstance + from PySide6.QtWidgets import QWidget + except: + from shiboken2 import wrapInstance # type: ignore + from PySide2.QtWidgets import QWidget # type: ignore + + from maya.OpenMayaUI import MQtUtil + + self.parent = cmds.setParent(q=True) + ptr = MQtUtil.findControl(self.parent) + parentWidget = wrapInstance(int(ptr), QWidget) + + sys.path.append('C:/dev/usd-shared-components/src/python') + import usd_shared_components.light_linking.LightLinking as ll + + self.widget = ll.create() + parentWidget.layout().addWidget(self.widget) + + except Exception as ex: + logger.exception(ex) + + self.refresh() + + def onReplace(self, *args): + # Nothing needed here since USD data is not time varying. Normally this template + # is force rebuilt all the time, except in response to time change from Maya. In + # that case we don't need to update our controls since none will change. + pass + + def refresh(self): + pass # SchemaBase template class for categorization of the attributes. # We no longer use the base class ufeAeTemplate.Template as we want to control @@ -470,6 +519,12 @@ def createMetadataSection(self, sectionName, attrs, collapse): usdNoticeControl = UsdNoticeListener(self.prim, [metaDataControl]) self.defineCustom(metaDataControl) self.defineCustom(usdNoticeControl) + + def createLightLinkingSection(self): + # We don't use createSection() because these are metadata (not attributes). + with ufeAeTemplate.Layout(self, 'Light Linking', collapse=True): + lightLinkingControl = LightLinkingCustomControl(self.item, self.prim, self.useNiceName) + self.defineCustom(lightLinkingControl) def createCustomExtraAttrs(self, sectionName, attrs, collapse): # We are not using the maya default "Extra Attributes" section @@ -649,6 +704,7 @@ def isSectionOpen(sectionName): 'display': self.createDisplaySection, 'extraAttributes': self.createCustomExtraAttrs, 'metadata': self.createMetadataSection, + 'lightLinkCollectionAPI': self.createLightLinkingSection, # does this work? 'customCallbacks': self.createCustomCallbackSection, }) From e795d1abc2895eb3b621bb6faf70bbb34a0dc0a2 Mon Sep 17 00:00:00 2001 From: Talis Barbalho Date: Wed, 6 Nov 2024 13:10:20 -0500 Subject: [PATCH 2/8] Added include all button --- lib/mayaUsd/resources/ae/CMakeLists.txt | 18 ++ .../collection/__init__.py | 1 + .../usdSharedComponents/collection/widget.py | 48 ++++ .../usdSharedComponents/common/__init__.py | 1 + .../python/usdSharedComponents/common/list.py | 94 +++++++ .../common/persistentStorage.py | 36 +++ .../usdSharedComponents/common/resizable.py | 233 ++++++++++++++++++ .../usdSharedComponents/common/theme.py | 112 +++++++++ .../resources/ae/usdschemabase/ae_template.py | 49 ++-- 9 files changed, 568 insertions(+), 24 deletions(-) create mode 100644 lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/collection/__init__.py create mode 100644 lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/collection/widget.py create mode 100644 lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/__init__.py create mode 100644 lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/list.py create mode 100644 lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/persistentStorage.py create mode 100644 lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/resizable.py create mode 100644 lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py diff --git a/lib/mayaUsd/resources/ae/CMakeLists.txt b/lib/mayaUsd/resources/ae/CMakeLists.txt index 9687299914..a2e42083f0 100644 --- a/lib/mayaUsd/resources/ae/CMakeLists.txt +++ b/lib/mayaUsd/resources/ae/CMakeLists.txt @@ -37,3 +37,21 @@ foreach(_SUBDIR ${MAYAUSD_AE_TEMPLATES}) endforeach() install(FILES __init__.py DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/${PROJECT_NAME}) + +# Install shared components + +set(MAYAUSD_SHARED_COMPONENTS usd-shared-components/src/python/usdSharedComponents) +install(FILES + ${MAYAUSD_SHARED_COMPONENTS}/collection/__init__.py + ${MAYAUSD_SHARED_COMPONENTS}/collection/widget.py + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/usd_shared_components/collection/ +) + +install(FILES + ${MAYAUSD_SHARED_COMPONENTS}/common/__init__.py + ${MAYAUSD_SHARED_COMPONENTS}/common/list.py + ${MAYAUSD_SHARED_COMPONENTS}/common/persistentStorage.py + ${MAYAUSD_SHARED_COMPONENTS}/common/resizable.py + ${MAYAUSD_SHARED_COMPONENTS}/common/theme.py + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/usd_shared_components/common/ +) \ No newline at end of file diff --git a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/collection/__init__.py b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/collection/__init__.py new file mode 100644 index 0000000000..bba3421a13 --- /dev/null +++ b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/collection/__init__.py @@ -0,0 +1 @@ +# Shared common components for USD plugins for 3dsMax and Maya diff --git a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/collection/widget.py b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/collection/widget.py new file mode 100644 index 0000000000..03a0428760 --- /dev/null +++ b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/collection/widget.py @@ -0,0 +1,48 @@ +from ..common.list import StringList +from ..common.resizable import Resizable + +try: + from PySide6.QtWidgets import QWidget, QVBoxLayout +except ImportError: + from PySide2.QtWidgets import QWidget, QVBoxLayout # type: ignore + +from pxr import Usd + +class CollectionWidget(QWidget): + def __init__(self, collection: Usd.CollectionAPI = None, parent: QWidget = None): + super(CollectionWidget, self).__init__(parent) + + self._collection: Usd.CollectionAPI = collection + + includes = [] + excludes = [] + shouldIncludeAll = False + + if self._collection is not None: + includeRootAttribute = self._collection.GetIncludeRootAttr() + if includeRootAttribute.IsAuthored(): + shouldIncludeAll = self._collection.GetIncludeRootAttr().Get() + + for p in self._collection.GetIncludesRel().GetTargets(): + includes.append(p.pathString) + for p in self._collection.GetExcludesRel().GetTargets(): + excludes.append(p.pathString) + + self.mainLayout = QVBoxLayout(self) + self.mainLayout.setContentsMargins(0,0,0,0) + + self._include = StringList( includes, "Include", "Include all", self) + self._include.cbIncludeAll.setChecked(shouldIncludeAll) + self._include.cbIncludeAll.stateChanged.connect(self.onIncludeAllToggle) + self._resizableInclude = Resizable(self._include, "USD_Light_Linking", "IncludeListHeight", self) + + self.mainLayout.addWidget(self._resizableInclude) + + self._exclude = StringList( excludes, "Exclude", "", self) + self._resizableExclude = Resizable(self._exclude, "USD_Light_Linking", "ExcludeListHeight", self) + + self.mainLayout.addWidget(self._resizableExclude) + self.mainLayout.addStretch(1) + + def onIncludeAllToggle(self): + self._collection.GetIncludeRootAttr().Set(self._include.cbIncludeAll.isChecked()) \ No newline at end of file diff --git a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/__init__.py b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/__init__.py new file mode 100644 index 0000000000..bba3421a13 --- /dev/null +++ b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/__init__.py @@ -0,0 +1 @@ +# Shared common components for USD plugins for 3dsMax and Maya diff --git a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/list.py b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/list.py new file mode 100644 index 0000000000..5455f89115 --- /dev/null +++ b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/list.py @@ -0,0 +1,94 @@ +from typing import Sequence +from .theme import Theme + +try: + from PySide6.QtCore import ( + QModelIndex, + QPersistentModelIndex, + QSize, + QStringListModel, + Qt, + Signal, + ) + from PySide6.QtGui import QPainter + from PySide6.QtWidgets import QStyleOptionViewItem, QStyledItemDelegate, QListView, QLabel, QVBoxLayout, QHBoxLayout, QWidget, QCheckBox +except: + from PySide2.QtGui import QPainter # type: ignore + from PySide2.QtWidgets import QStyleOptionViewItem, QStyledItemDelegate, QListView, QLabel, QVBoxLayout, QHBoxLayout, QWidget, QCheckBox # type: ignore + +class _StringList(QListView): + selectedItemsChanged = Signal() + + class Delegate(QStyledItemDelegate): + def __init__(self, model: QStringListModel, parent=None): + super(_StringList.Delegate, self).__init__(parent) + self._model = model + + def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex | QPersistentModelIndex): + s: int = Theme.instance().uiScaled(24) + return QSize(s, s) + + def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex | QPersistentModelIndex): + s: str = self._model.data(index, Qt.DisplayRole) + Theme.instance().paintStringListEntry(painter, option.rect, s) + + def __init__(self, items: Sequence[str] = [], parent=None): + super(_StringList, self).__init__(parent) + self._model = QStringListModel(items, self) + self.setModel(self._model) + + self.setUniformItemSizes(True) + self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + self.setTextElideMode(Qt.TextElideMode.ElideMiddle) + self.setSelectionBehavior(QListView.SelectRows) + self.setSelectionMode(QListView.MultiSelection) + self.setContentsMargins(0,0,0,0) + + self.selectionModel().selectionChanged.connect(lambda: self.selectedItemsChanged.emit()) + + def drawFrame(self, painter: QPainter): + pass + + @property + def items(self) -> Sequence[str]: + return self._model.stringList + + @items.setter + def items(self, items: Sequence[str]): + self._model.setStringList(items) + + @property + def selectedItems(self) -> Sequence[str]: + return [index.data(Qt.DisplayRole) for index in self.selectedIndexes()] + + +class StringList(QWidget): + + def __init__(self, items: Sequence[str] = [], headerTitle: str = "", toggleTitle: str = "", parent=None): + super().__init__() + self.list = _StringList(items, self) + + layout = QVBoxLayout(self) + LEFT_RIGHT_MARGINS = 2 + layout.setContentsMargins(LEFT_RIGHT_MARGINS, 0, LEFT_RIGHT_MARGINS, 0) + + headerWidget = QWidget(self) + headerLayout = QHBoxLayout(headerWidget) + + titleLabel = QLabel(headerTitle, self) + headerLayout.addWidget(titleLabel) + headerLayout.addStretch(1) + headerLayout.setContentsMargins(0,0,0,0) + + # only add the check box on the header if there's a label + if toggleTitle != None and toggleTitle != "": + self.cbIncludeAll = QCheckBox(toggleTitle, self) + self.cbIncludeAll.setCheckable(True) + headerLayout.addWidget(self.cbIncludeAll) + + headerWidget.setLayout(headerLayout) + + layout.addWidget(headerWidget) + layout.addWidget(self.list) + + self.setLayout(layout) \ No newline at end of file diff --git a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/persistentStorage.py b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/persistentStorage.py new file mode 100644 index 0000000000..821247783d --- /dev/null +++ b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/persistentStorage.py @@ -0,0 +1,36 @@ +try: + from PySide6.QtCore import QSettings +except: + from PySide2.QtCore import QSettings # type: ignore + + +class PersistentStorage(object): + _instance = None + + def __init__(self): + raise RuntimeError("Call instance() instead") + + @classmethod + def instance(cls): + if cls._instance is None: + cls._instance = cls.__new__(cls) + return cls._instance + + @classmethod + def injectInstance(cls, persistentStorage): + cls._instance = persistentStorage + + def _settings(self) -> QSettings: + return QSettings("settings.ini", QSettings.IniFormat) + + def set(self, group: str, key: str, value: object): + settings: QSettings = self._settings() + settings.beginGroup(group) + settings.setValue(key, value) + settings.endGroup() + settings.sync() + + def get(self, group: str, key: str, default: object = None) -> object: + settings: QSettings = self._settings() + settings.beginGroup(group) + return settings.value(key, default, type=type(default)) diff --git a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/resizable.py b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/resizable.py new file mode 100644 index 0000000000..18d1497aaa --- /dev/null +++ b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/resizable.py @@ -0,0 +1,233 @@ +from .theme import Theme +from .persistentStorage import PersistentStorage + +try: + from PySide6.QtCore import Qt, Signal, QRect + from PySide6.QtWidgets import QWidget, QStackedLayout, QVBoxLayout, QSizePolicy +except ImportError: + from PySide2.QtCore import Qt, Signal, QRect # type: ignore + from PySide2.QtWidgets import QWidget, QStackedLayout, QVBoxLayout, QSizePolicy # type: ignore + + +class Resizable(QWidget): + + __slots__ = [ + "_contentLayout", + "_minContentSize", + "_maxContentSize", + "_persistentStorageGroup", + "_persistentStorageKey", + "_contentSize", + "_dragStartContentSize", + "_widget", + "_overlay", + ] + + class _Overlay(QWidget): + + dragged = Signal(int) + dragging = Signal(bool) + + __slots__ = ["_active", "_mousePressGlobalPosY", "_maskRect"] + + def __init__(self, parent=None): + super(Resizable._Overlay, self).__init__(parent) + + self._active:bool = False + self._mousePressGlobalPosY: int | None = None + self._maskRect: QRect = None + + self.setWindowFlags(Qt.FramelessWindowHint) + self.setAttribute(Qt.WA_TranslucentBackground) + self.setAttribute(Qt.WA_NoSystemBackground) + self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + s: int = Theme.instance().resizableActiveAreaSize() + self.setMinimumSize(s, s) + self.setMouseTracking(True) + self.setFocusPolicy(Qt.NoFocus) + + def paintEvent(self, _): + if self._active: + Theme.instance().paintResizableOverlay(self) + + def resizeEvent(self, event): + super().resizeEvent(event) + s: int = Theme.instance().resizableActiveAreaSize() + self._maskRect = QRect(0, event.size().height() - s, event.size().width(), s) + if not self._active: + self.setMask(self._maskRect) + + def mouseMoveEvent(self, event): + if self._mousePressGlobalPosY is not None: + diff = event.globalPos().y() - self._mousePressGlobalPosY + # self._mousePressGlobalPosY = event.globalPos().y() + self.dragged.emit(diff) + event.accept() + else: + _overActiveArea: bool = event.pos().y() >= self.height() - Theme.instance().resizableActiveAreaSize() + if _overActiveArea != self._active: + self._active = _overActiveArea + if self._active: + self.clearMask() + else: + self.setMask(self._maskRect) + self.update() + self.setCursor(Qt.SizeVerCursor if self._active else Qt.ArrowCursor) + event.ignore() + + def mousePressEvent(self, event): + if self._active: + self.clearMask() + self._mousePressGlobalPosY = event.globalPos().y() + self.dragging.emit(True) + event.accept() + else: + event.ignore() + + def mouseReleaseEvent(self, event): + if self._active: + self._mousePressGlobalPosY = None + self.dragging.emit(False) + event.accept() + else: + event.ignore() + + def enterEvent(self, event): + self._active = event.pos().y() >= self.height() - Theme.instance().resizableActiveAreaSize() + if self._active: + event.accept() + self._active = False + self.update() + self.setCursor(Qt.SizeVerCursor) + else: + event.ignore() + + def leaveEvent(self, event): + if self._active: + self._active = False + self.update() + self.setCursor(Qt.ArrowCursor) + event.accept() + else: + event.ignore() + + def __init__( + self, + w: QWidget = None, + persistentStorageGroup: str = None, + persistentStorageKey: str = None, + parent: QWidget = None, + ): + super(Resizable, self).__init__(parent) + + stackedLayout = QStackedLayout() + stackedLayout.setContentsMargins(0, 0, 0, 0) + stackedLayout.setSpacing(0) + stackedLayout.setStackingMode(QStackedLayout.StackAll) + + contentWidget = QWidget(self) + self._contentLayout = QVBoxLayout(contentWidget) + self._contentLayout.setContentsMargins(0, 0, 0, Theme.instance().resizableContentMargin()) + self._contentLayout.setSpacing(0) + + self._minContentSize: int = 0 + self._maxContentSize: int = 500 + + self._persistentStorageGroup: str = persistentStorageGroup + self._persistentStorageKey: str = persistentStorageKey + + self._contentSize: int = -1 + self._dragStartContentSize: int = -1 + self._widget: QWidget = None + + self.loadPersistentStorage() + + if w is not None: + self.widget = w + + self._overlay = Resizable._Overlay(self) + stackedLayout.addWidget(contentWidget) + stackedLayout.addWidget(self._overlay) + stackedLayout.setCurrentIndex(1) + + self._overlay.dragged.connect(self.onResizeHandleDragged) + self._overlay.dragging.connect(self.onResizeHandleDragging) + + mainLayout = QVBoxLayout(self) + mainLayout.setContentsMargins(0, 0, 0, 0) + mainLayout.setSpacing(0) + mainLayout.addLayout(stackedLayout, 1) + + def onResizeHandleDragging(self, dragging: bool): + if dragging: + self._dragStartContentSize = self._contentSize + else: + self.savePersistentStorage() + + def onResizeHandleDragged(self, dy): + height = self._dragStartContentSize + dy + self.contentSize = height + + @property + def widget(self): + return self._widget + + @widget.setter + def widget(self, w: QWidget): + if self._widget != w: + if self._widget is not None: + self._contentLayout.removeWidget(self._widget) + self._widget.hide() + self._widget = w + if self._widget is not None: + self._contentLayout.insertWidget(0, self._widget, 1) + self._widget.show() + if self._contentSize == -1: + self.contentSize = self._widget.height() + else: + self.contentSize = self._contentSize + + @property + def contentSize(self): + return self._contentSize + + @contentSize.setter + def contentSize(self, s: int): + self._contentSize = max(self._minContentSize, min(self._maxContentSize, s)) + if self._widget is not None: + self._widget.setFixedHeight(self._contentSize) + + @property + def minContentSize(self): + return self._minContentSize + + @minContentSize.setter + def minContentSize(self, s: int): + self._minContentSize = max(0, s) + if self._contentSize != -1 and self._minContentSize > self._contentSize: + self.contentSize = self._minContentSize + + @property + def maxContentSize(self) -> int: + return self._maxContentSize + + @maxContentSize.setter + def maxContentSize(self, s: int): + self._maxContentSize = max(0, s) + if self._contentSize != -1 and self._maxContentSize < self._contentSize: + self.contentSize = self._maxContentSize + + def setPersistentStorage(self, group: str, key: str): + self._persistentStorageGroup = group + self._persistentStorageKey = key + + def savePersistentStorage(self): + if self._contentSize != -1 and self._persistentStorageGroup is not None and self._persistentStorageKey is not None: + s: float = Theme.instance().uiUnScaled(float(self._contentSize)) + PersistentStorage.instance().set(self._persistentStorageGroup, self._persistentStorageKey, s) + + def loadPersistentStorage(self): + if self._persistentStorageGroup is not None and self._persistentStorageKey is not None: + s: float = float(PersistentStorage.instance().get(self._persistentStorageGroup, self._persistentStorageKey, -1.0)) + if s != -1.0: + self.contentSize = round(Theme.instance().uiScaled(s)) diff --git a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py new file mode 100644 index 0000000000..1ee11ca1de --- /dev/null +++ b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py @@ -0,0 +1,112 @@ +try: + from PySide6.QtCore import QRect, Qt + from PySide6.QtGui import QPainter, QColor, QPen, QIcon + from PySide6.QtWidgets import QWidget +except: + from PySide2.QtCore import QRect # type: ignore + from PySide2.QtGui import QPainter, QColor, QPen, QIcon # type: ignore + from PySide2.QtWidgets import QWidget # type: ignore + + +from enum import Flag, auto + + +class Theme(object): + _instance = None + + __slots__ = ["_palette"] + + def __init__(self): + raise RuntimeError("Call instance() instead") + + @classmethod + def instance(cls): + if cls._instance is None: + cls._instance = cls.__new__(cls) + cls._instance._palette = None + return cls._instance + + @classmethod + def injectInstance(cls, theme): + cls._instance = theme + + @property + def uiScaleFactor(self) -> float: + ### Returns the UI scale factor. + return 1.0 + + def uiScaled(self, value: float | int): + ### Returns the scaled value. + if isinstance(value, float): + return value * self.uiScaleFactor + if isinstance(value, int): + return int(round(float(value) * self.uiScaleFactor)) + raise ValueError("Value must be a float or an int") + + def uiUnScaled(self, value: float | int): + ### Returns the scaled value. + return float(value) / self.uiScaleFactor + + def icon(self, name: str) -> QIcon: + ### Returns the icon with the given name. + return QIcon(f"./icons/{name}.svg") + + class Palette(object): + colorResizeBorderActive: QColor = QColor(0x5285a6) + + @property + def palette(self) -> Palette: + if self._palette is None: + self._palette = self.Palette() + return self._palette + + class State(Flag): + Normal = auto() + Hover = auto() + Pressed = auto() + Disabled = auto() + Empty = auto() + + def paintResizableOverlay(self, widget: QWidget): + """ Paints the overlay of a Resizable. + + Args: + widget (QWidget): the widget to paint the overlay on. + """ + + painter = QPainter(widget) + painter.setRenderHint(QPainter.Antialiasing, False) + rect = widget.rect() + rect.adjust(0, 0, 0, - self.resizableContentMargin()) + lineWidth: int = self.uiScaled(2) + if lineWidth == 1: + rect.adjust(1, 1, -1, -1) + elif lineWidth > 1: + halfLineWidth = round(lineWidth / 2.0) + rect.adjust(halfLineWidth, halfLineWidth, -halfLineWidth, -halfLineWidth) + + painter.setPen(QPen(self.palette.colorResizeBorderActive, lineWidth, Qt.SolidLine, Qt.SquareCap, Qt.MiterJoin)) + painter.setBrush(Qt.NoBrush) + painter.drawRect(rect) + + def resizableActiveAreaSize(self) -> int: + """Returns the size of the active area at the bottom of a Resizable.""" + + return self.uiScaled(6) + + def resizableContentMargin(self) -> int: + """Returns the bottom margin of the content of a Resizable. + + The content margin is the the part of the active area extending the + content widget area to make the active area of the Resizable easier to + grab without overlapping too much of the content. + """ + + return self.uiScaled(2) + + + def paintList(self, widget: QWidget, updateRect: QRect, state: State): + raise RuntimeError("Needs to be implemented in derived class") + + def paintStringListEntry(self, painter: QPainter, rect: QRect, string: str): + raise RuntimeError("Needs to be implemented in derived class") \ No newline at end of file diff --git a/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py b/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py index cbd524329d..3f9320900e 100644 --- a/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py +++ b/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py @@ -23,6 +23,7 @@ from .metadataCustomControl import MetadataCustomControl from .observers import UfeAttributesObserver, UfeConnectionChangedObserver, UsdNoticeListener +import sys import collections import fnmatch import re @@ -220,30 +221,30 @@ def __init__(self, item, prim, useNiceName): self.useNiceName = useNiceName def onCreate(self, *args): - try: + if self.prim.IsValid() == True and self.prim.HasAPI('CollectionAPI', 'lightLink'): try: - from shiboken6 import wrapInstance - from PySide6.QtWidgets import QWidget - except: - from shiboken2 import wrapInstance # type: ignore - from PySide2.QtWidgets import QWidget # type: ignore + try: + from shiboken6 import wrapInstance + from PySide6.QtWidgets import QWidget + except: + from shiboken2 import wrapInstance # type: ignore + from PySide2.QtWidgets import QWidget # type: ignore + + from maya.OpenMayaUI import MQtUtil + + self.parent = cmds.setParent(q=True) + ptr = MQtUtil.findControl(self.parent) + parentWidget = wrapInstance(int(ptr), QWidget) + + from usd_shared_components.collection.widget import CollectionWidget + + self.widget = CollectionWidget(Usd.CollectionAPI.Get(self.prim, 'lightLink')) + parentWidget.layout().addWidget(self.widget) - from maya.OpenMayaUI import MQtUtil - - self.parent = cmds.setParent(q=True) - ptr = MQtUtil.findControl(self.parent) - parentWidget = wrapInstance(int(ptr), QWidget) - - sys.path.append('C:/dev/usd-shared-components/src/python') - import usd_shared_components.light_linking.LightLinking as ll - - self.widget = ll.create() - parentWidget.layout().addWidget(self.widget) - - except Exception as ex: - logger.exception(ex) + except Exception as ex: + logger.exception(ex) - self.refresh() + self.refresh() def onReplace(self, *args): # Nothing needed here since USD data is not time varying. Normally this template @@ -520,9 +521,9 @@ def createMetadataSection(self, sectionName, attrs, collapse): self.defineCustom(metaDataControl) self.defineCustom(usdNoticeControl) - def createLightLinkingSection(self): + def createLightLinkingSection(self, sectionName, attrs, collapse): # We don't use createSection() because these are metadata (not attributes). - with ufeAeTemplate.Layout(self, 'Light Linking', collapse=True): + with ufeAeTemplate.Layout(self, 'Light Linking', collapse): lightLinkingControl = LightLinkingCustomControl(self.item, self.prim, self.useNiceName) self.defineCustom(lightLinkingControl) @@ -704,7 +705,7 @@ def isSectionOpen(sectionName): 'display': self.createDisplaySection, 'extraAttributes': self.createCustomExtraAttrs, 'metadata': self.createMetadataSection, - 'lightLinkCollectionAPI': self.createLightLinkingSection, # does this work? + 'lightLinkCollectionAPI': self.createLightLinkingSection, 'customCallbacks': self.createCustomCallbackSection, }) From 9975b2bc4d9aadd251233ff9829bce3dc31c0c11 Mon Sep 17 00:00:00 2001 From: Talis Barbalho Date: Wed, 6 Nov 2024 16:01:56 -0500 Subject: [PATCH 3/8] Fix test --- test/lib/testAttributeEditorTemplate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/testAttributeEditorTemplate.py b/test/lib/testAttributeEditorTemplate.py index 78f3a62055..40b65b9e52 100644 --- a/test/lib/testAttributeEditorTemplate.py +++ b/test/lib/testAttributeEditorTemplate.py @@ -505,7 +505,7 @@ def testAEForLight(self): expectedInitialSectionLabels = [ 'Light ', 'Cylinder Light', - 'Light Link Collection ', + 'Light Linking', 'Shadow Link Collection '] self.assertListEqual( actualSectionLabels[0:len(expectedInitialSectionLabels)], From 3faa8438753b522ccedadb0b05efbd0aedb28ad1 Mon Sep 17 00:00:00 2001 From: Talis Barbalho Date: Mon, 11 Nov 2024 14:29:33 -0500 Subject: [PATCH 4/8] create file for control --- lib/mayaUsd/resources/ae/CMakeLists.txt | 1 + .../usdSharedComponents/common/theme.py | 4 -- .../resources/ae/usdschemabase/ae_template.py | 51 +------------------ .../ae/usdschemabase/lightCustomControl.py | 48 +++++++++++++++++ 4 files changed, 50 insertions(+), 54 deletions(-) create mode 100644 lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py diff --git a/lib/mayaUsd/resources/ae/CMakeLists.txt b/lib/mayaUsd/resources/ae/CMakeLists.txt index a2e42083f0..3a6f1cf8a7 100644 --- a/lib/mayaUsd/resources/ae/CMakeLists.txt +++ b/lib/mayaUsd/resources/ae/CMakeLists.txt @@ -29,6 +29,7 @@ foreach(_SUBDIR ${MAYAUSD_AE_TEMPLATES}) ${_SUBDIR}/displayCustomControl.py ${_SUBDIR}/enumCustomControl.py ${_SUBDIR}/imageCustomControl.py + ${_SUBDIR}/lightCustomControl.py ${_SUBDIR}/materialCustomControl.py ${_SUBDIR}/metadataCustomControl.py ${_SUBDIR}/observers.py diff --git a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py index 1ee11ca1de..7f2a3c16b0 100644 --- a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py +++ b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py @@ -47,10 +47,6 @@ def uiUnScaled(self, value: float | int): ### Returns the scaled value. return float(value) / self.uiScaleFactor - def icon(self, name: str) -> QIcon: - ### Returns the icon with the given name. - return QIcon(f"./icons/{name}.svg") - class Palette(object): colorResizeBorderActive: QColor = QColor(0x5285a6) diff --git a/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py b/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py index 3f9320900e..11ca209f8a 100644 --- a/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py +++ b/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py @@ -21,6 +21,7 @@ from .displayCustomControl import DisplayCustomControl from .materialCustomControl import MaterialCustomControl from .metadataCustomControl import MetadataCustomControl +from .lightCustomControl import LightLinkingCustomControl from .observers import UfeAttributesObserver, UfeConnectionChangedObserver, UsdNoticeListener import sys @@ -205,56 +206,6 @@ def get(self): folderIndex[groups].items.append(attributeInfo.name) return self._attributeLayout -import logging -logging.basicConfig(level=logging.DEBUG) -logger = logging.getLogger(__name__) - -class LightLinkingCustomControl(object): - '''Custom control for the light linking data we want to display.''' - def __init__(self, item, prim, useNiceName): - # In Maya 2022.1 we need to hold onto the Ufe SceneItem to make - # sure it doesn't go stale. This is not needed in latest Maya. - super(LightLinkingCustomControl, self).__init__() - mayaVer = '%s.%s' % (cmds.about(majorVersion=True), cmds.about(minorVersion=True)) - self.item = item if mayaVer == '2022.1' else None - self.prim = prim - self.useNiceName = useNiceName - - def onCreate(self, *args): - if self.prim.IsValid() == True and self.prim.HasAPI('CollectionAPI', 'lightLink'): - try: - try: - from shiboken6 import wrapInstance - from PySide6.QtWidgets import QWidget - except: - from shiboken2 import wrapInstance # type: ignore - from PySide2.QtWidgets import QWidget # type: ignore - - from maya.OpenMayaUI import MQtUtil - - self.parent = cmds.setParent(q=True) - ptr = MQtUtil.findControl(self.parent) - parentWidget = wrapInstance(int(ptr), QWidget) - - from usd_shared_components.collection.widget import CollectionWidget - - self.widget = CollectionWidget(Usd.CollectionAPI.Get(self.prim, 'lightLink')) - parentWidget.layout().addWidget(self.widget) - - except Exception as ex: - logger.exception(ex) - - self.refresh() - - def onReplace(self, *args): - # Nothing needed here since USD data is not time varying. Normally this template - # is force rebuilt all the time, except in response to time change from Maya. In - # that case we don't need to update our controls since none will change. - pass - - def refresh(self): - pass - # SchemaBase template class for categorization of the attributes. # We no longer use the base class ufeAeTemplate.Template as we want to control # the placement of the metadata at the bottom (after extra attributes). diff --git a/lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py b/lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py new file mode 100644 index 0000000000..bbbf410c4d --- /dev/null +++ b/lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py @@ -0,0 +1,48 @@ +import maya.cmds as cmds +from pxr import Usd + +class LightLinkingCustomControl(object): + '''Custom control for the light linking data we want to display.''' + def __init__(self, item, prim, useNiceName): + # In Maya 2022.1 we need to hold onto the Ufe SceneItem to make + # sure it doesn't go stale. This is not needed in latest Maya. + super(LightLinkingCustomControl, self).__init__() + mayaVer = '%s.%s' % (cmds.about(majorVersion=True), cmds.about(minorVersion=True)) + self.item = item if mayaVer == '2022.1' else None + self.prim = prim + self.useNiceName = useNiceName + + def onCreate(self, *args): + if self.prim.IsValid() == True and self.prim.HasAPI('CollectionAPI', 'lightLink'): + try: + try: + from shiboken6 import wrapInstance + from PySide6.QtWidgets import QWidget + except: + from shiboken2 import wrapInstance # type: ignore + from PySide2.QtWidgets import QWidget # type: ignore + + from maya.OpenMayaUI import MQtUtil + + self.parent = cmds.setParent(q=True) + ptr = MQtUtil.findControl(self.parent) + parentWidget = wrapInstance(int(ptr), QWidget) + + from usd_shared_components.collection.widget import CollectionWidget # type: ignore + + self.widget = CollectionWidget(Usd.CollectionAPI.Get(self.prim, 'lightLink')) + parentWidget.layout().addWidget(self.widget) + + except Exception as ex: + print(ex) + + self.refresh() + + def onReplace(self, *args): + # Nothing needed here since USD data is not time varying. Normally this template + # is force rebuilt all the time, except in response to time change from Maya. In + # that case we don't need to update our controls since none will change. + pass + + def refresh(self): + pass \ No newline at end of file From f4c1455328de9f788d74ada300374d3592841b3a Mon Sep 17 00:00:00 2001 From: Talis Barbalho Date: Mon, 11 Nov 2024 14:41:17 -0500 Subject: [PATCH 5/8] better exception message --- lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py b/lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py index bbbf410c4d..7daa6b0196 100644 --- a/lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py +++ b/lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py @@ -34,7 +34,7 @@ def onCreate(self, *args): parentWidget.layout().addWidget(self.widget) except Exception as ex: - print(ex) + print('Failed to create Light custom control: %s' % (ex)) self.refresh() From 268e3d932eb1cb8feec56c88e830f16cb811c3ac Mon Sep 17 00:00:00 2001 From: Talis Barbalho Date: Mon, 18 Nov 2024 16:47:07 -0500 Subject: [PATCH 6/8] Adjust maya version in test --- test/lib/testAttributeEditorTemplate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/testAttributeEditorTemplate.py b/test/lib/testAttributeEditorTemplate.py index 40b65b9e52..c1e93d093d 100644 --- a/test/lib/testAttributeEditorTemplate.py +++ b/test/lib/testAttributeEditorTemplate.py @@ -512,7 +512,7 @@ def testAEForLight(self): expectedInitialSectionLabels) # Note: there are no extra attributes in Maya 2022. - if mayaUtils.mayaMajorMinorVersions() >= (2023, 0): + if mayaUtils.mayaMajorMinorVersions() >= (2022, 5): expectedFinalSectionLabels = [ 'Transforms', 'Display', From 759083fecddec9886748d3108f0afe20d6ef7f08 Mon Sep 17 00:00:00 2001 From: Talis Barbalho Date: Tue, 19 Nov 2024 13:36:46 -0500 Subject: [PATCH 7/8] Only support LL in 2023+ --- lib/mayaUsd/resources/ae/CMakeLists.txt | 39 ++++++++++++------- .../python/usdSharedComponents/common/list.py | 14 +++++-- .../usdSharedComponents/common/resizable.py | 4 +- .../usdSharedComponents/common/theme.py | 6 +-- .../resources/ae/usdschemabase/ae_template.py | 29 ++++++++------ .../ae/usdschemabase/lightCustomControl.py | 2 +- test/lib/testAttributeEditorTemplate.py | 20 +++++++--- 7 files changed, 72 insertions(+), 42 deletions(-) diff --git a/lib/mayaUsd/resources/ae/CMakeLists.txt b/lib/mayaUsd/resources/ae/CMakeLists.txt index 3a6f1cf8a7..6a1d3ebd35 100644 --- a/lib/mayaUsd/resources/ae/CMakeLists.txt +++ b/lib/mayaUsd/resources/ae/CMakeLists.txt @@ -41,18 +41,27 @@ install(FILES __init__.py DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/${PROJE # Install shared components -set(MAYAUSD_SHARED_COMPONENTS usd-shared-components/src/python/usdSharedComponents) -install(FILES - ${MAYAUSD_SHARED_COMPONENTS}/collection/__init__.py - ${MAYAUSD_SHARED_COMPONENTS}/collection/widget.py - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/usd_shared_components/collection/ -) - -install(FILES - ${MAYAUSD_SHARED_COMPONENTS}/common/__init__.py - ${MAYAUSD_SHARED_COMPONENTS}/common/list.py - ${MAYAUSD_SHARED_COMPONENTS}/common/persistentStorage.py - ${MAYAUSD_SHARED_COMPONENTS}/common/resizable.py - ${MAYAUSD_SHARED_COMPONENTS}/common/theme.py - DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/usd_shared_components/common/ -) \ No newline at end of file +if(MAYA_APP_VERSION VERSION_GREATER_EQUAL 2023) + foreach(_SUBDIR ${MAYAUSD_AE_TEMPLATES}) + install(FILES + ${_SUBDIR}/lightCustomControl.py + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/ufe_ae/usd/nodes/${_SUBDIR} + ) + endforeach() + + set(MAYAUSD_SHARED_COMPONENTS usd-shared-components/src/python/usdSharedComponents) + install(FILES + ${MAYAUSD_SHARED_COMPONENTS}/collection/__init__.py + ${MAYAUSD_SHARED_COMPONENTS}/collection/widget.py + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/usd_shared_components/collection/ + ) + + install(FILES + ${MAYAUSD_SHARED_COMPONENTS}/common/__init__.py + ${MAYAUSD_SHARED_COMPONENTS}/common/list.py + ${MAYAUSD_SHARED_COMPONENTS}/common/persistentStorage.py + ${MAYAUSD_SHARED_COMPONENTS}/common/resizable.py + ${MAYAUSD_SHARED_COMPONENTS}/common/theme.py + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/usd_shared_components/common/ + ) +endif() diff --git a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/list.py b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/list.py index 5455f89115..477430fb58 100644 --- a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/list.py +++ b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/list.py @@ -1,4 +1,4 @@ -from typing import Sequence +from typing import Sequence, Union from .theme import Theme try: @@ -13,6 +13,14 @@ from PySide6.QtGui import QPainter from PySide6.QtWidgets import QStyleOptionViewItem, QStyledItemDelegate, QListView, QLabel, QVBoxLayout, QHBoxLayout, QWidget, QCheckBox except: + from PySide2.QtCore import ( + QModelIndex, + QPersistentModelIndex, + QSize, + QStringListModel, + Qt, + Signal, + ) from PySide2.QtGui import QPainter # type: ignore from PySide2.QtWidgets import QStyleOptionViewItem, QStyledItemDelegate, QListView, QLabel, QVBoxLayout, QHBoxLayout, QWidget, QCheckBox # type: ignore @@ -24,11 +32,11 @@ def __init__(self, model: QStringListModel, parent=None): super(_StringList.Delegate, self).__init__(parent) self._model = model - def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex | QPersistentModelIndex): + def sizeHint(self, option: QStyleOptionViewItem, index: Union[QModelIndex, QPersistentModelIndex]): s: int = Theme.instance().uiScaled(24) return QSize(s, s) - def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex | QPersistentModelIndex): + def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: Union[QModelIndex, QPersistentModelIndex]): s: str = self._model.data(index, Qt.DisplayRole) Theme.instance().paintStringListEntry(painter, option.rect, s) diff --git a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/resizable.py b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/resizable.py index 18d1497aaa..a904dc9ce4 100644 --- a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/resizable.py +++ b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/resizable.py @@ -1,6 +1,6 @@ from .theme import Theme from .persistentStorage import PersistentStorage - +from typing import Union try: from PySide6.QtCore import Qt, Signal, QRect from PySide6.QtWidgets import QWidget, QStackedLayout, QVBoxLayout, QSizePolicy @@ -34,7 +34,7 @@ def __init__(self, parent=None): super(Resizable._Overlay, self).__init__(parent) self._active:bool = False - self._mousePressGlobalPosY: int | None = None + self._mousePressGlobalPosY: Union[int, None] = None self._maskRect: QRect = None self.setWindowFlags(Qt.FramelessWindowHint) diff --git a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py index 7f2a3c16b0..fe66f23f11 100644 --- a/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py +++ b/lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/common/theme.py @@ -7,7 +7,7 @@ from PySide2.QtGui import QPainter, QColor, QPen, QIcon # type: ignore from PySide2.QtWidgets import QWidget # type: ignore - +from typing import Union from enum import Flag, auto @@ -35,7 +35,7 @@ def uiScaleFactor(self) -> float: ### Returns the UI scale factor. return 1.0 - def uiScaled(self, value: float | int): + def uiScaled(self, value: Union[float, int]): ### Returns the scaled value. if isinstance(value, float): return value * self.uiScaleFactor @@ -43,7 +43,7 @@ def uiScaled(self, value: float | int): return int(round(float(value) * self.uiScaleFactor)) raise ValueError("Value must be a float or an int") - def uiUnScaled(self, value: float | int): + def uiUnScaled(self, value: Union[float, int]): ### Returns the scaled value. return float(value) / self.uiScaleFactor diff --git a/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py b/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py index 11ca209f8a..ff9c00a516 100644 --- a/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py +++ b/lib/mayaUsd/resources/ae/usdschemabase/ae_template.py @@ -21,10 +21,13 @@ from .displayCustomControl import DisplayCustomControl from .materialCustomControl import MaterialCustomControl from .metadataCustomControl import MetadataCustomControl -from .lightCustomControl import LightLinkingCustomControl from .observers import UfeAttributesObserver, UfeConnectionChangedObserver, UsdNoticeListener +try: + from .lightCustomControl import LightLinkingCustomControl + lightLinkingSupported = True +except: + lightLinkingSupported = False -import sys import collections import fnmatch import re @@ -648,17 +651,19 @@ def isSectionOpen(sectionName): # By default, calls the generic createSection, which will search # in the list of known custom control creators for the one to be # used. + customAttributes = { + 'shader': self.createShaderAttributesSection, + 'transforms': self.createTransformAttributesSection, + 'display': self.createDisplaySection, + 'extraAttributes': self.createCustomExtraAttrs, + 'metadata': self.createMetadataSection, + 'customCallbacks': self.createCustomCallbackSection, + } + # only support lightLinking custom attribute for Maya 2023+ + if lightLinkingSupported: + customAttributes['lightLinkCollectionAPI'] = self.createLightLinkingSection sectionCreators = collections.defaultdict( - lambda : self.createSection, - { - 'shader': self.createShaderAttributesSection, - 'transforms': self.createTransformAttributesSection, - 'display': self.createDisplaySection, - 'extraAttributes': self.createCustomExtraAttrs, - 'metadata': self.createMetadataSection, - 'lightLinkCollectionAPI': self.createLightLinkingSection, - 'customCallbacks': self.createCustomCallbackSection, - }) + lambda : self.createSection, customAttributes) # Create the section in the specified order. for typeName in schemasOrder: diff --git a/lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py b/lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py index 7daa6b0196..9d1d1c5a98 100644 --- a/lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py +++ b/lib/mayaUsd/resources/ae/usdschemabase/lightCustomControl.py @@ -13,7 +13,7 @@ def __init__(self, item, prim, useNiceName): self.useNiceName = useNiceName def onCreate(self, *args): - if self.prim.IsValid() == True and self.prim.HasAPI('CollectionAPI', 'lightLink'): + if self.prim.IsValid() == True and self.prim.HasAPI(Usd.CollectionAPI, 'lightLink'): try: try: from shiboken6 import wrapInstance diff --git a/test/lib/testAttributeEditorTemplate.py b/test/lib/testAttributeEditorTemplate.py index c1e93d093d..940b28d4de 100644 --- a/test/lib/testAttributeEditorTemplate.py +++ b/test/lib/testAttributeEditorTemplate.py @@ -502,17 +502,25 @@ def testAEForLight(self): # Note: different version of USD can have different schemas, # so we only compare the ones we are interested in verifying. - expectedInitialSectionLabels = [ - 'Light ', - 'Cylinder Light', - 'Light Linking', - 'Shadow Link Collection '] + expectedInitialSectionLabels = [] + if mayaUtils.mayaMajorMinorVersions() >= (2023, 0): + expectedInitialSectionLabels = [ + 'Light ', + 'Cylinder Light', + 'Light Linking', + 'Shadow Link Collection '] + else: + expectedInitialSectionLabels = [ + 'Light ', + 'Cylinder Light', + 'Light Link Collection ', + 'Shadow Link Collection '] self.assertListEqual( actualSectionLabels[0:len(expectedInitialSectionLabels)], expectedInitialSectionLabels) # Note: there are no extra attributes in Maya 2022. - if mayaUtils.mayaMajorMinorVersions() >= (2022, 5): + if mayaUtils.mayaMajorMinorVersions() >= (2023, 0): expectedFinalSectionLabels = [ 'Transforms', 'Display', From cccc76654cf0348120118fffa7db1aa5795508a2 Mon Sep 17 00:00:00 2001 From: Talis Barbalho Date: Tue, 19 Nov 2024 13:48:48 -0500 Subject: [PATCH 8/8] Missed removing cmake install --- lib/mayaUsd/resources/ae/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/mayaUsd/resources/ae/CMakeLists.txt b/lib/mayaUsd/resources/ae/CMakeLists.txt index 6a1d3ebd35..472eac4234 100644 --- a/lib/mayaUsd/resources/ae/CMakeLists.txt +++ b/lib/mayaUsd/resources/ae/CMakeLists.txt @@ -29,7 +29,6 @@ foreach(_SUBDIR ${MAYAUSD_AE_TEMPLATES}) ${_SUBDIR}/displayCustomControl.py ${_SUBDIR}/enumCustomControl.py ${_SUBDIR}/imageCustomControl.py - ${_SUBDIR}/lightCustomControl.py ${_SUBDIR}/materialCustomControl.py ${_SUBDIR}/metadataCustomControl.py ${_SUBDIR}/observers.py