Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAYA-108691 - USD: undoing transform will not update manipulator #1266

Merged
merged 3 commits into from
Mar 23, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions lib/mayaUsd/ufe/StagesSubject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,31 @@ void StagesSubject::stageChanged(

auto stage = notice.GetStage();
for (const auto& changedPath : notice.GetResyncedPaths()) {
// When visibility is toggled for the first time or you add a xformop we enter
// here with a resync path. However the changedPath is not a prim path, so we
// don't care about it. In those cases, the changePath will contain something like:
// "/<prim>.visibility"
// "/<prim>.xformOp:translate"
if (changedPath.IsPrimPropertyPath()) {
// Special case to detect when an xformop is added or removed from a prim.
// We need to send some notifs so Maya can update (such as on undo
// to move the transform manipulator back to original position).
const TfToken nameToken = changedPath.GetNameToken();
if (nameToken == UsdGeomTokens->xformOpOrder || UsdGeomXformOp::IsXformOp(nameToken)) {
auto usdPrimPathStr = changedPath.GetPrimPath().GetString();
auto ufePath = stagePath(sender) + Ufe::PathSegment(usdPrimPathStr, g_USDRtid, '/');
if (!InTransform3dChange::inTransform3dChange()) {
Ufe::Transform3d::notify(ufePath);
}
#ifdef UFE_V2_FEATURES_AVAILABLE
if (!inAttributeChangedNotificationGuard()) {
Ufe::AttributeValueChanged vc(ufePath, changedPath.GetName());
Ufe::Attributes::notify(vc);
}
#endif
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we discussed, make sure to send extra UFE notifs for USD prim property path notifs on xformop.


// No further processing for this prim property path is required.
continue;
}

// Relational attributes will not be caught by the IsPrimPropertyPath()
// and we don't care about them.
if (changedPath.IsPropertyPath())
continue;

Expand Down
90 changes: 90 additions & 0 deletions test/lib/ufe/testComboCmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,35 @@ def checkWorldSpaceXform(testCase, objects):
usdWorld = [y for x in t3d.inclusiveMatrix().matrix for y in x]
assertVectorAlmostEqual(testCase, mayaWorld, usdWorld)

class TestObserver(ufe.Observer):
def __init__(self):
super(TestObserver, self).__init__()
self._transform3d = 0
self._valueChanged = 0

def __call__(self, notification):
if (ufeUtils.ufeFeatureSetVersion() >= 2):
if isinstance(notification, ufe.AttributeValueChanged):
self._valueChanged += 1
if isinstance(notification, ufe.Transform3dChanged):
self._transform3d += 1

@property
def nbValueChanged(self):
return self._valueChanged

@property
def nbTransform3d(self):
return self._transform3d

@property
def notifications(self):
return self._valueChanged + self._transform3d

def reset(self):
self._transform3d = 0
self._valueChanged = 0

class ComboCmdTestCase(testTRSBase.TRSTestCaseBase):
'''Verify the Transform3d UFE interface, for multiple runtimes.

Expand Down Expand Up @@ -812,6 +841,67 @@ def testFallback(self):
checkPivotsAndCompensations(self, mayaObj, usdSphere3d)
checkPivotsAndCompensations(self, mayaObj, usdFallbackSphere3d)

@unittest.skipUnless(ufeUtils.ufeFeatureSetVersion() >= 2, 'testPrimPropertyPathNotifs only available in UFE v2 or greater.')
def testPrimPropertyPathNotifs(self):
Comment on lines +844 to +845
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New test to verify that these new are received.

import mayaUsd_createStageWithNewLayer
proxyShape = mayaUsd_createStageWithNewLayer.createStageWithNewLayer()
proxyShapePath = ufe.PathString.path(proxyShape)
proxyShapeItem = ufe.Hierarchy.createItem(proxyShapePath)
proxyShapeContextOps = ufe.ContextOps.contextOps(proxyShapeItem)
proxyShapeContextOps.doOp(['Add New Prim', 'Capsule'])

# Select the capsule
capPath = ufe.PathString.path('%s,/Capsule1' % proxyShape)
capItem = ufe.Hierarchy.createItem(capPath)
ufe.GlobalSelection.get().clear()
ufe.GlobalSelection.get().append(capItem)

# No notifications yet.
obs = TestObserver()
ufe.Attributes.addObserver(capItem, obs)
ufe.Transform3d.addObserver(capItem, obs)
self.assertEqual(obs.notifications, 0)

# Move the capsule
cmds.move(0, 10, 10)

# Verify that we got both ValueChanged and Transform3d notifs.
# Note: we should get notifs on both the "xformOp:translate" and
# "xformOpOrder" attributes. We don't care how many, just that
# we are getting both of these notifs kinds on both the move
# and undo.
self.assertTrue(obs.nbValueChanged > 0)
self.assertTrue(obs.nbTransform3d > 0)

# Reset observer and then undo and again verify notifs.
obs.reset()
self.assertEqual(obs.notifications, 0)
cmds.undo()
self.assertTrue(obs.nbValueChanged > 0)
self.assertTrue(obs.nbTransform3d > 0)

# Reset and test same thing with Rotate.
obs.reset()
cmds.rotate(10, 0, 0)
self.assertTrue(obs.nbValueChanged > 0)
self.assertTrue(obs.nbTransform3d > 0)
obs.reset()
self.assertEqual(obs.notifications, 0)
cmds.undo()
self.assertTrue(obs.nbValueChanged > 0)
self.assertTrue(obs.nbTransform3d > 0)

# Reset and test same thing with Scale.
obs.reset()
cmds.scale(2, 2, 2)
self.assertTrue(obs.nbValueChanged > 0)
self.assertTrue(obs.nbTransform3d > 0)
obs.reset()
self.assertEqual(obs.notifications, 0)
cmds.undo()
self.assertTrue(obs.nbValueChanged > 0)
self.assertTrue(obs.nbTransform3d > 0)


if __name__ == '__main__':
unittest.main(verbosity=2)