Skip to content

Commit

Permalink
EMSUSD-0 bring light linking changes from the shared repo
Browse files Browse the repository at this point in the history
- Fix setting a new prim and collection on an existing colletion widget.
- Remove obsolete list item delegate and unused painters from the list view widget.
- Remove unused painter function from the Theme class.
- Make the data setter return true or False if the data was set or not.
- (This will potentially make possible to not add an undo for do-nothing actions.)
- Add validation of the prim and collection to avoid printing stack traces to the user.
- Update the check condition to change include all.
- Don't change focus of the expression widget on enter.
- Don't allow pasting text with formatting (bold, etc)
- Making the resizing of the list widgets more robust.
- Added an error message when setting the expression causes an exception.
- Avoid submitting the expression when it has not changed, to avoid bad interactions with undo/redo.
  • Loading branch information
pierrebai-adsk committed Jan 13, 2025
1 parent 775d5de commit dabc82c
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 114 deletions.
1 change: 1 addition & 0 deletions lib/mayaUsd/resources/ae/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ if(MAYA_APP_VERSION VERSION_GREATER_EQUAL 2023)
${MAYAUSD_SHARED_COMPONENTS}/usdData/__init__.py
${MAYAUSD_SHARED_COMPONENTS}/usdData/usdCollectionData.py
${MAYAUSD_SHARED_COMPONENTS}/usdData/usdCollectionStringListData.py
${MAYAUSD_SHARED_COMPONENTS}/usdData/validator.py
DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/usd_shared_components/usdData/
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def __init__(self, data: CollectionData, parent: QWidget, expressionChangedCallb
self._expressionText.setMinimumHeight(Theme.instance().uiScaled(80))
self._expressionText.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self._expressionText.setPlaceholderText("Type an expression here...")
self._expressionText.setAcceptRichText(False)

mainLayout.addWidget(menuWidget, 0)
mainLayout.addWidget(self._expressionText, 1)
Expand All @@ -54,15 +55,21 @@ def _onDataChanged(self):
self._expressionText.setPlainText(usdExpressionAttr or '')

def submitExpression(self):
self._collData.setMembershipExpression(self._expressionText.toPlainText())
newText = self._expressionText.toPlainText() or ''
oldText = self._collData.getMembershipExpression() or ''
if newText == oldText:
return
self._collData.setMembershipExpression(newText)
if self._expressionCallback != None:
self._expressionCallback()

def eventFilter(self, obj, event):
if event.type() == QEvent.KeyPress and obj is self._expressionText:
if event.key() == Qt.Key_Return and self._expressionText.hasFocus():
self._expressionText.clearFocus()
if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
self.submitExpression()
return True
# For the case when they change prim without hitting enter;
# or click somewhere else in the UI
elif event.type() == QEvent.FocusOut:
self.submitExpression()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ def __init__(
):
super(CollectionWidget, self).__init__(parent)

self._collection: Usd.CollectionAPI = collection
self._prim: Usd.Prim = prim
self._collData = Host.instance().createCollectionData(prim, collection)

mainLayout = QVBoxLayout()
Expand Down Expand Up @@ -71,9 +69,7 @@ def __init__(
self.setLayout(mainLayout)

def setCollection(self, prim: Usd.Prim = None, collection: Usd.CollectionAPI = None):
self._collection = collection
self._prim = prim
self._collData = UsdCollectionData(prim, collection)
self._collData.setCollection(prim, collection)

if Usd.GetVersion() >= (0, 23, 11):

Expand All @@ -86,6 +82,8 @@ def onExpressionChanged(self):
len(self._collData._includes.getStrings()) == 0
and len(self._collData._includes.getStrings()) == 0
and self._collData.includesAll()
and self._collData.getMembershipExpression() != None
and self._collData.getMembershipExpression() != ""
)
if updateIncludeAll:
self._collData.setIncludeAll(False)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from PySide6.QtWidgets import ( # type: ignore
QLabel,
QListView,
QStyledItemDelegate,
QStyleOptionViewItem
)
except:
Expand All @@ -34,7 +33,7 @@
Signal,
)
from PySide2.QtGui import QPainter, QPaintEvent, QFont # type: ignore
from PySide2.QtWidgets import QLabel, QListView, QStyledItemDelegate, QStyleOptionViewItem # type: ignore
from PySide2.QtWidgets import QLabel, QListView, QStyleOptionViewItem # type: ignore


NO_OBJECTS_FOUND_LABEL = "No objects found"
Expand All @@ -47,28 +46,6 @@ class FilteredStringListView(QListView):

itemSelectionChanged = Signal()

class Delegate(QStyledItemDelegate):
def __init__(self, model: QStringListModel, parent=None):
super(FilteredStringListView.Delegate, self).__init__(parent)
self._model = model

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: Union[QModelIndex, QPersistentModelIndex],
):
s: str = self._model.data(index, Qt.DisplayRole)
Theme.instance().paintStringListEntry(painter, option.rect, s)

def __init__(self, data: StringListData, headerTitle: str = "", parent=None):
super(FilteredStringListView, self).__init__(parent)
self.headerTitle = headerTitle
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from .theme import Theme
from .persistentStorage import PersistentStorage
from typing import Union

try:
from PySide6.QtCore import Qt, Signal, QRect # type: ignore
from PySide6.QtCore import QPoint, QRect, QSize, Qt, Signal # type: ignore
from PySide6.QtWidgets import QWidget, QStackedLayout, QVBoxLayout, QSizePolicy # type: ignore
except ImportError:
from PySide2.QtCore import Qt, Signal, QRect # type: ignore
from PySide2.QtCore import QPoint, QRect, QSize, Qt, Signal # type: ignore
from PySide2.QtWidgets import QWidget, QStackedLayout, QVBoxLayout, QSizePolicy # type: ignore


Expand All @@ -16,19 +17,23 @@ class _Overlay(QWidget):
dragged = Signal(int)
dragging = Signal(bool)

RESIZE_HANDLE_SIZE: int = Theme.instance().resizableActiveAreaSize()

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

self._active:bool = False
self._active: bool = False
self._mousePressGlobalPosY: Union[int, None] = None
self._maskRect: QRect = None
self._resizeHandleMask: 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.setMinimumSize(
self.RESIZE_HANDLE_SIZE,
self.RESIZE_HANDLE_SIZE,
)
self.setMouseTracking(True)
self.setFocusPolicy(Qt.NoFocus)

Expand All @@ -38,27 +43,50 @@ def paintEvent(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)
size: QSize = event.size()
self._resizeHandleMask = QRect(
0,
size.height() - self.RESIZE_HANDLE_SIZE,
size.width(),
self.RESIZE_HANDLE_SIZE,
)
self._updateMask()

def _isOverResizeHandle(self, pos: QPoint) -> bool:
x: int = pos.x()
if x < 0 or x >= self.width():
return False
lowerBorder: int = self.height()
upperBorder: int = lowerBorder - self.RESIZE_HANDLE_SIZE
y: int = pos.y()
return y >= upperBorder and y < lowerBorder

def _updateMask(self):
if self._active:
self.clearMask()
else:
self.setMask(self._resizeHandleMask)

@property
def active(self) -> bool:
return self._active

@active.setter
def active(self, value: bool):
if self._active == value:
return
self._active = value
self._updateMask()
self.update()
self.setCursor(Qt.SizeVerCursor if value else Qt.ArrowCursor)

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)
self.active = self._isOverResizeHandle(event.pos())
event.ignore()

def mousePressEvent(self, event):
Expand All @@ -71,28 +99,23 @@ def mousePressEvent(self, event):
event.ignore()

def mouseReleaseEvent(self, event):
if self._active:
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:
self.active = self._isOverResizeHandle(event.pos())
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)
if self.active:
self.active = False
event.accept()
else:
event.ignore()
Expand All @@ -103,7 +126,7 @@ def __init__(
persistentStorageGroup: str = None,
persistentStorageKey: str = None,
parent: QWidget = None,
defaultSize = -1,
defaultSize: int = -1,
):
super(Resizable, self).__init__(parent)

Expand Down Expand Up @@ -154,6 +177,7 @@ def onResizeHandleDragging(self, dragging: bool):
self._dragStartContentSize = self._contentSize
else:
self.savePersistentStorage()
self.updateGeometry()

def onResizeHandleDragged(self, dy):
height = self._dragStartContentSize + dy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
except ImportError:
from PySide2.QtCore import QRect, Qt # type: ignore
from PySide2.QtGui import QPainter # type: ignore
from PySide2.QtWidgets import QCheckBox, QHBoxLayout, QVBoxLayout, QStyle, QStyleOptionHeaderV2, QStylePainter, QWidget # type: ignore
from PySide2.QtWidgets import QCheckBox, QHBoxLayout, QVBoxLayout, QStyle, QStyleOptionHeader as QStyleOptionHeaderV2, QStylePainter, QWidget # type: ignore

# TODO: support I8N
kIncludeAllLabel = "Include all"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,3 @@ def resizableContentMargin(self) -> int:
"""

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")
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ def includesAll(self) -> bool:
'''
return False

def setIncludeAll(self, state: bool):
def setIncludeAll(self, state: bool) -> bool:
'''
Sets if the collection should include all items by default.
Return True if successfully set.
Return False if already set to the same value.
'''
pass
return False

def getIncludeData(self) -> StringListData:
'''
Expand All @@ -47,11 +49,13 @@ def getExcludeData(self) -> StringListData:
'''
return None

def removeAllIncludeExclude(self):
def removeAllIncludeExclude(self) -> bool:
'''
Remove all included and excluded items.
Return True if successfully removed.
Return False if already empty.
'''
pass
return False

# Expression

Expand All @@ -61,20 +65,24 @@ def getExpansionRule(self):
'''
return None

def setExpansionRule(self, rule):
def setExpansionRule(self, rule) -> bool:
'''
Sets the expansion rule as a USD token.
Return True if successfully set.
Return False if already set to the same value.
'''
pass
return False

def getMembershipExpression(self) -> AnyStr:
'''
Returns the membership expression as text.
'''
return None

def setMembershipExpression(self, textExpression: AnyStr):
def setMembershipExpression(self, textExpression: AnyStr) -> bool:

Check notice on line 82 in lib/mayaUsd/resources/ae/usd-shared-components/src/python/usdSharedComponents/data/collectionData.py

View check run for this annotation

Autodesk Chorus / privacy/bearer

Potential PII: Social Network Group Membership

This check is currently in beta. - Personal Data at Autodesk: https://share.autodesk.com/:b:/r/sites/LegalTopicsToolkits/Shared%20Documents/Personal%20Data%20at%20Autodesk.pdf - Data Privacy & Governance Policies at Autodesk: https://share.autodesk.com/sites/DPG/SitePages/Policies-%26-Guidelines.aspx
'''
Set the textual membership expression.
Return True if successfully set.
Return False if already set to the same value.
'''
pass
return False
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@ def getStrings(self) -> Sequence[AnyStr]:
'''
return []

def addStrings(self, items: Sequence[AnyStr]):
def addStrings(self, items: Sequence[AnyStr]) -> bool:
'''
Add the given strings to the model.
Return True if successfully added.
'''
pass
return False

def removeStrings(self, items: Sequence[AnyStr]):
def removeStrings(self, items: Sequence[AnyStr]) -> bool:
'''
Remove the given strings from the model.
Return True if successfully removed.
Return False if already empty.
'''
pass
return False

def _isValidString(self, s) -> AnyStr:
'''
Expand Down
Loading

0 comments on commit dabc82c

Please sign in to comment.