def testDoOp(self): # Change visibility, undo / redo. cmd = self.contextOps.doOpCmd(['Toggle Visibility']) self.assertIsNotNone(cmd) attrs = ufe.Attributes.attributes(self.ball35Item) self.assertIsNotNone(attrs) visibility = attrs.attribute(UsdGeom.Tokens.visibility) self.assertIsNotNone(visibility) # Initially, Ball_35 has inherited visibility. self.assertEqual(visibility.get(), UsdGeom.Tokens.inherited) ufeCmd.execute(cmd) self.assertEqual(visibility.get(), UsdGeom.Tokens.invisible) cmds.undo() self.assertEqual(visibility.get(), UsdGeom.Tokens.inherited) cmds.redo() self.assertEqual(visibility.get(), UsdGeom.Tokens.invisible) cmds.undo() # Change variant in variant set. def shadingVariant(): contextItems = self.contextOps.getItems( ['Variant Sets', 'shadingVariant']) for c in contextItems: if c.checked: return c.item self.assertEqual(shadingVariant(), 'Ball_8') cmd = self.contextOps.doOpCmd( ['Variant Sets', 'shadingVariant', 'Cue']) self.assertIsNotNone(cmd) ufeCmd.execute(cmd) self.assertEqual(shadingVariant(), 'Cue') cmds.undo() self.assertEqual(shadingVariant(), 'Ball_8') cmds.redo() self.assertEqual(shadingVariant(), 'Cue') cmds.undo()
def runUndoRedo(self, attr, newVal, decimalPlaces=None): oldVal = attr.get() assert oldVal != newVal, "Undo / redo testing requires setting a value different from the current value" ufeCmd.execute(attr.setCmd(newVal)) if decimalPlaces is not None: self.assertAlmostEqual(attr.get(), newVal, decimalPlaces) newVal = attr.get() else: self.assertEqual(attr.get(), newVal) cmds.undo() self.assertEqual(attr.get(), oldVal) cmds.redo() self.assertEqual(attr.get(), newVal)
def testZAttrChangeRedoAfterPrimCreateRedo(self): '''Redo attribute change after redo of prim creation.''' cmds.file(new=True, force=True) # Create a capsule, change one of its attributes. import mayaUsd_createStageWithNewLayer proxyShape = mayaUsd_createStageWithNewLayer.createStageWithNewLayer() proxyShapePath = ufe.PathString.path(proxyShape) proxyShapeItem = ufe.Hierarchy.createItem(proxyShapePath) proxyShapeContextOps = ufe.ContextOps.contextOps(proxyShapeItem) cmd = proxyShapeContextOps.doOpCmd(['Add New Prim', 'Capsule']) ufeCmd.execute(cmd) capsulePath = ufe.PathString.path('%s,/Capsule1' % proxyShape) capsuleItem = ufe.Hierarchy.createItem(capsulePath) # Create the attributes interface for the item. attrs = ufe.Attributes.attributes(capsuleItem) self.assertIsNotNone(attrs) self.assertTrue(attrs.hasAttribute('radius')) radiusAttr = attrs.attribute('radius') oldRadius = radiusAttr.get() ufeCmd.execute(radiusAttr.setCmd(2)) newRadius = radiusAttr.get() self.assertEqual(newRadius, 2) self.assertNotEqual(oldRadius, newRadius) # Undo 2x: undo attr change and prim creation. cmds.undo() cmds.undo() # Redo 2x: prim creation, attr change. cmds.redo() cmds.redo() # Re-create item, as its underlying prim was re-created. capsuleItem = ufe.Hierarchy.createItem(capsulePath) attrs = ufe.Attributes.attributes(capsuleItem) radiusAttr = attrs.attribute('radius') self.assertEqual(radiusAttr.get(), newRadius)
def testAddNewPrimWithDelete(self): cmds.file(new=True, force=True) # Create a proxy shape with empty stage to start with. import mayaUsd_createStageWithNewLayer mayaUsd_createStageWithNewLayer.createStageWithNewLayer() # Create a ContextOps interface for the proxy shape. proxyShapePath = ufe.Path( [mayaUtils.createUfePathSegment("|world|stage1|stageShape1")]) proxyShapeItem = ufe.Hierarchy.createItem(proxyShapePath) contextOps = ufe.ContextOps.contextOps(proxyShapeItem) # Add a new Xform prim. cmd = contextOps.doOpCmd(['Add New Prim', 'Xform']) self.assertIsNotNone(cmd) ufeCmd.execute(cmd) # The proxy shape should now have a single UFE child item. proxyShapehier = ufe.Hierarchy.hierarchy(proxyShapeItem) self.assertTrue(proxyShapehier.hasChildren()) self.assertEqual(len(proxyShapehier.children()), 1) # Using UFE, delete this new prim (which doesn't actually delete it but # instead makes it inactive). cmds.pickWalk(d='down') cmds.delete() # The proxy shape should now have no UFE child items (since we skip inactive). self.assertFalse(proxyShapehier.hasChildren()) self.assertEqual(len(proxyShapehier.children()), 0) # Add another Xform prim (which should get a unique name taking into # account the prim we just made inactive). cmd = contextOps.doOpCmd(['Add New Prim', 'Xform']) self.assertIsNotNone(cmd) ufeCmd.execute(cmd) # The proxy shape should now have a single UFE child item. self.assertTrue(proxyShapehier.hasChildren()) self.assertEqual(len(proxyShapehier.children()), 1)
def testUnload(self): mayaUtils.openTopLayerScene() propsPath = ufe.PathString.path( '|transform1|proxyShape1,/Room_set/Props') propsItem = ufe.Hierarchy.createItem(propsPath) propsHier = ufe.Hierarchy.hierarchy(propsItem) # Before unloading it should have 35 children (35 balls). self.assertTrue(propsHier.hasChildren()) ball1Children = propsHier.children() self.assertEqual(len(ball1Children), 35) # Unload props contextOps = ufe.ContextOps.contextOps(propsItem) cmd = contextOps.doOpCmd(['Unload']) ufeCmd.execute(cmd) # After unloading, it should still have 35 children because # the children method returns unloaded prims by default. self.assertTrue(propsHier.hasChildren()) ball1Children = propsHier.children() self.assertEqual(len(ball1Children), 35)
def testMayaSelectSwitchVariant(self): '''Stale selection items must be removed on variant switch.''' import mayaUsd_createStageWithNewLayer import maya.internal.ufeSupport.ufeCmdWrapper as ufeCmd # Create a scene with two variants. proxyShape = mayaUsd_createStageWithNewLayer.createStageWithNewLayer() stage = mayaUsd.lib.GetPrim(proxyShape).GetStage() top = stage.DefinePrim('/Xform1', 'Xform') vset = top.GetVariantSets().AddVariantSet('modelingVariant') vset.AddVariant('cube') vset.AddVariant('sphere') vset.SetVariantSelection('cube') with vset.GetVariantEditContext(): stage.DefinePrim('/Xform1/Cube', 'Cube') vset.SetVariantSelection('sphere') with vset.GetVariantEditContext(): stage.DefinePrim('/Xform1/Sphere', 'Sphere') # The sphere is the sole child of Xform1. Get an attribute from it, # select it. xformPath = ufe.PathString.path('%s,/Xform1' % proxyShape) spherePath = ufe.PathString.path('%s,/Xform1/Sphere' % proxyShape) xformItem = ufe.Hierarchy.createItem(xformPath) sphereItem = ufe.Hierarchy.createItem(spherePath) xformHier = ufe.Hierarchy.hierarchy(xformItem) xformChildren = xformHier.children() self.assertEqual(len(xformChildren), 1) self.assertEqual(xformChildren[0].path(), spherePath) sphereAttrs = ufe.Attributes.attributes(sphereItem) sphereRadius = sphereAttrs.attribute('radius') self.assertEqual(sphereRadius.get(), 1) sn = ufe.GlobalSelection.get() sn.clear() sn.append(sphereItem) self.assertEqual(len(sn), 1) # Switch variants using a command: the cube is now the sole child of # Xform1, we can get an attribute from the cube. The selection must # now be empty. xformCtxOps = ufe.ContextOps.contextOps(xformItem) cmd = xformCtxOps.doOpCmd(['Variant Sets', 'modelingVariant', 'cube']) ufeCmd.execute(cmd) cubePath = ufe.PathString.path('%s,/Xform1/Cube' % proxyShape) cubeItem = ufe.Hierarchy.createItem(cubePath) xformChildren = xformHier.children() self.assertEqual(len(xformChildren), 1) self.assertEqual(xformChildren[0].path(), cubePath) cubeAttrs = ufe.Attributes.attributes(cubeItem) cubeRadius = cubeAttrs.attribute('size') self.assertEqual(cubeRadius.get(), 2) self.assertTrue(sn.empty()) # Undo: selection is restored, seletion item is valid. cmds.undo() self.assertEqual(len(sn), 1) sphereItem = sn.front() self.assertEqual(sphereItem.path(), spherePath) sphereAttrs = ufe.Attributes.attributes(sphereItem) sphereRadius = sphereAttrs.attribute('radius') self.assertEqual(sphereRadius.get(), 1) xformChildren = xformHier.children() self.assertEqual(len(xformChildren), 1) self.assertEqual(xformChildren[0].path(), spherePath) # Redo: selection is cleared. cmds.redo() self.assertTrue(sn.empty()) xformChildren = xformHier.children() self.assertEqual(len(xformChildren), 1) self.assertEqual(xformChildren[0].path(), cubePath) # Undo: selection restored to sphere. cmds.undo() self.assertEqual(len(sn), 1) sphereItem = sn.front() self.assertEqual(sphereItem.path(), spherePath) # Now set the variant outside a Maya command. Stale scene items must be # removed from the selection. vset.SetVariantSelection('cube') self.assertTrue(sn.empty())
def testAddNewPrim(self): cmds.file(new=True, force=True) # Create a proxy shape with empty stage to start with. import mayaUsd_createStageWithNewLayer mayaUsd_createStageWithNewLayer.createStageWithNewLayer() # Create our UFE notification observer ufeObs = TestAddPrimObserver() if (os.getenv('UFE_PREVIEW_VERSION_NUM', '0000') < '2021'): ufe.Scene.addObjectDeleteObserver(ufeObs) ufe.Scene.addObjectAddObserver(ufeObs) else: ufe.Scene.addObserver(ufeObs) # Create a ContextOps interface for the proxy shape. proxyShapePath = ufe.Path( [mayaUtils.createUfePathSegment("|world|stage1|stageShape1")]) proxyShapeItem = ufe.Hierarchy.createItem(proxyShapePath) contextOps = ufe.ContextOps.contextOps(proxyShapeItem) # Add a new prim. cmd = contextOps.doOpCmd(['Add New Prim', 'Xform']) self.assertIsNotNone(cmd) ufeObs.reset() ufeCmd.execute(cmd) # Ensure we got the correct UFE notifs. self.assertEqual(ufeObs.nbAddNotif(), 1) self.assertEqual(ufeObs.nbDeleteNotif(), 0) # The proxy shape should now have a single UFE child item. proxyShapehier = ufe.Hierarchy.hierarchy(proxyShapeItem) self.assertTrue(proxyShapehier.hasChildren()) self.assertEqual(len(proxyShapehier.children()), 1) # Add a new prim to the prim we just added. cmds.pickWalk(d='down') # Get the scene item from the UFE selection. snIter = iter(ufe.GlobalSelection.get()) xformItem = next(snIter) # Create a ContextOps interface for it. contextOps = ufe.ContextOps.contextOps(xformItem) # Add a new prim. cmd = contextOps.doOpCmd(['Add New Prim', 'Xform']) self.assertIsNotNone(cmd) ufeObs.reset() ufeCmd.execute(cmd) # Ensure we got the correct UFE notifs. self.assertEqual(ufeObs.nbAddNotif(), 1) self.assertEqual(ufeObs.nbDeleteNotif(), 0) # The xform prim should now have a single UFE child item. xformHier = ufe.Hierarchy.hierarchy(xformItem) self.assertTrue(xformHier.hasChildren()) self.assertEqual(len(xformHier.children()), 1) # Add another prim cmd = contextOps.doOpCmd(['Add New Prim', 'Capsule']) self.assertIsNotNone(cmd) ufeObs.reset() ufeCmd.execute(cmd) # Ensure we got the correct UFE notifs. self.assertEqual(ufeObs.nbAddNotif(), 1) self.assertEqual(ufeObs.nbDeleteNotif(), 0) # The xform prim should now have two UFE child items. self.assertTrue(xformHier.hasChildren()) self.assertEqual(len(xformHier.children()), 2) # Undo will remove the new prim, meaning one less child. ufeObs.reset() cmds.undo() self.assertTrue(xformHier.hasChildren()) self.assertEqual(len(xformHier.children()), 1) # Ensure we got the correct UFE notifs. self.assertEqual(ufeObs.nbAddNotif(), 0) self.assertEqual(ufeObs.nbDeleteNotif(), 1) # Undo again will remove the first added prim, meaning no children. cmds.undo() self.assertFalse(xformHier.hasChildren()) # Ensure we got the correct UFE notifs. self.assertEqual(ufeObs.nbAddNotif(), 0) self.assertEqual(ufeObs.nbDeleteNotif(), 2) cmds.redo() self.assertTrue(xformHier.hasChildren()) self.assertEqual(len(xformHier.children()), 1) # Ensure we got the correct UFE notifs. self.assertEqual(ufeObs.nbAddNotif(), 1) self.assertEqual(ufeObs.nbDeleteNotif(), 2) cmds.redo() self.assertTrue(xformHier.hasChildren()) self.assertEqual(len(xformHier.children()), 2) # Ensure we got the correct UFE notifs. self.assertEqual(ufeObs.nbAddNotif(), 2) self.assertEqual(ufeObs.nbDeleteNotif(), 2)
def executeContextCmd(ufeItem, subCmd): '''Execute a context-menu command, supports among other things Load and Unload.''' contextOps = ufe.ContextOps.contextOps(ufeItem) cmd = contextOps.doOpCmd([subCmd]) self.assertIsNotNone(cmd) ufeCmd.execute(cmd)
def testUndoRedo(self): self._StartTest('capsule') mayaUtils.loadPlugin("ufeSupport") cmds.move(3, -3, 3, 'persp') cmds.rotate(60, 0, 45, 'persp') # modify the capsule's height, then undo and redo that operation and # make sure the viewport updates as expected. mayaPathSegment = mayaUtils.createUfePathSegment('|stage|stageShape') capsuleUsdPathSegment = usdUtils.createUfePathSegment('/Capsule1') capsulePath = ufe.Path([mayaPathSegment, capsuleUsdPathSegment]) capsuleItem = ufe.Hierarchy.createItem(capsulePath) capsuleAttrs = ufe.Attributes.attributes(capsuleItem) heightAttr = capsuleAttrs.attribute('height') # get the undo queue into a clean state with nothing on the queue # and no open chunks # disable and flush the undo queue cmds.undoInfo(state=False) # the undo queue could still have some open chunks which were in the # process of being created when I turned the undo queue off. For example, # this test gets run from the mel "python" command (see test.cmake), and # that chunk is currently open. # If I try to query the current chunk string to see if something IS open, # it is always the command I used to try to query the current chunk name! # Experimentally, I found have that there are typically two open chunks. # So just close two chunks. cmds.undoInfo(closeChunk=True) cmds.undoInfo(closeChunk=True) # flush those truncated chunks if they are on the undo queue. They shouldn't # be, because I already disabled the undo queue, but I am paranoid. cmds.flushUndo() # Now run the actual test I want to run. Enable the undo queue for each command # that I want on the queue, and disable the undo queue again, without flushing, # immediately after. cmds.undoInfo(stateWithoutFlush=True) ufeCmd.execute(heightAttr.setCmd(3)) cmds.undoInfo(stateWithoutFlush=False) self.assertSnapshotClose('%s_set_height.png' % self._testName) cmds.undoInfo(stateWithoutFlush=True) cmds.undo() cmds.undoInfo(stateWithoutFlush=False) self.assertSnapshotClose('%s_undo_set_height.png' % self._testName) cmds.undoInfo(stateWithoutFlush=True) cmds.redo() cmds.undoInfo(stateWithoutFlush=False) self.assertSnapshotClose('%s_redo_set_height.png' % self._testName) # Now the test is over, turn the undo queue back on incase this Maya session # gets re-used for more tests. cmds.undoInfo(stateWithoutFlush=True)
def testObservation(self): '''Test Attributes observation interface. Test both global attribute observation and per-node attribute observation. ''' # Create three observers, one for global attribute observation, and two # on different UFE items. proxyShapePathSegment = mayaUtils.createUfePathSegment( "|world|transform1|proxyShape1") path = ufe.Path([ proxyShapePathSegment, usdUtils.createUfePathSegment('/Room_set/Props/Ball_34') ]) ball34 = ufe.Hierarchy.createItem(path) path = ufe.Path([ proxyShapePathSegment, usdUtils.createUfePathSegment('/Room_set/Props/Ball_35') ]) ball35 = ufe.Hierarchy.createItem(path) (ball34Obs, ball35Obs, globalObs) = [TestObserver() for i in range(3)] # Maya registers a single global observer on startup. self.assertEqual(ufe.Attributes.nbObservers(), 1) # No item-specific observers. self.assertFalse(ufe.Attributes.hasObservers(ball34.path())) self.assertFalse(ufe.Attributes.hasObservers(ball35.path())) self.assertEqual(ufe.Attributes.nbObservers(ball34), 0) self.assertEqual(ufe.Attributes.nbObservers(ball35), 0) self.assertFalse(ufe.Attributes.hasObserver(ball34, ball34Obs)) self.assertFalse(ufe.Attributes.hasObserver(ball35, ball35Obs)) # No notifications yet. self.assertEqual(ball34Obs.notifications, 0) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 0) # Add a global observer. ufe.Attributes.addObserver(globalObs) self.assertEqual(ufe.Attributes.nbObservers(), 2) self.assertFalse(ufe.Attributes.hasObservers(ball34.path())) self.assertFalse(ufe.Attributes.hasObservers(ball35.path())) self.assertEqual(ufe.Attributes.nbObservers(ball34), 0) self.assertEqual(ufe.Attributes.nbObservers(ball35), 0) self.assertFalse(ufe.Attributes.hasObserver(ball34, ball34Obs)) self.assertFalse(ufe.Attributes.hasObserver(ball35, ball35Obs)) # Add item-specific observers. ufe.Attributes.addObserver(ball34, ball34Obs) self.assertEqual(ufe.Attributes.nbObservers(), 2) self.assertTrue(ufe.Attributes.hasObservers(ball34.path())) self.assertFalse(ufe.Attributes.hasObservers(ball35.path())) self.assertEqual(ufe.Attributes.nbObservers(ball34), 1) self.assertEqual(ufe.Attributes.nbObservers(ball35), 0) self.assertTrue(ufe.Attributes.hasObserver(ball34, ball34Obs)) self.assertFalse(ufe.Attributes.hasObserver(ball34, ball35Obs)) self.assertFalse(ufe.Attributes.hasObserver(ball35, ball35Obs)) ufe.Attributes.addObserver(ball35, ball35Obs) self.assertTrue(ufe.Attributes.hasObservers(ball35.path())) self.assertEqual(ufe.Attributes.nbObservers(ball34), 1) self.assertEqual(ufe.Attributes.nbObservers(ball35), 1) self.assertTrue(ufe.Attributes.hasObserver(ball35, ball35Obs)) self.assertFalse(ufe.Attributes.hasObserver(ball35, ball34Obs)) # Make a change to ball34, global and ball34 observers change. ball34Attrs = ufe.Attributes.attributes(ball34) ball34XlateAttr = ball34Attrs.attribute('xformOp:translate') self.assertEqual(ball34Obs.notifications, 0) ufeCmd.execute(ball34XlateAttr.setCmd(ufe.Vector3d(1, 2, 3))) self.assertEqual(ball34Obs.notifications, 1) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 1) # Undo, redo cmds.undo() self.assertEqual(ball34Obs.notifications, 2) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 2) cmds.redo() self.assertEqual(ball34Obs.notifications, 3) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 3) # Make a change to ball35, global and ball35 observers change. ball35Attrs = ufe.Attributes.attributes(ball35) ball35XlateAttr = ball35Attrs.attribute('xformOp:translate') ufeCmd.execute(ball35XlateAttr.setCmd(ufe.Vector3d(1, 2, 3))) self.assertEqual(ball34Obs.notifications, 3) self.assertEqual(ball35Obs.notifications, 1) self.assertEqual(globalObs.notifications, 4) # Undo, redo cmds.undo() self.assertEqual(ball34Obs.notifications, 3) self.assertEqual(ball35Obs.notifications, 2) self.assertEqual(globalObs.notifications, 5) cmds.redo() self.assertEqual(ball34Obs.notifications, 3) self.assertEqual(ball35Obs.notifications, 3) self.assertEqual(globalObs.notifications, 6) # Test removeObserver. ufe.Attributes.removeObserver(ball34, ball34Obs) self.assertFalse(ufe.Attributes.hasObservers(ball34.path())) self.assertTrue(ufe.Attributes.hasObservers(ball35.path())) self.assertEqual(ufe.Attributes.nbObservers(ball34), 0) self.assertEqual(ufe.Attributes.nbObservers(ball35), 1) self.assertFalse(ufe.Attributes.hasObserver(ball34, ball34Obs)) ufeCmd.execute(ball34XlateAttr.setCmd(ufe.Vector3d(4, 5, 6))) self.assertEqual(ball34Obs.notifications, 3) self.assertEqual(ball35Obs.notifications, 3) self.assertEqual(globalObs.notifications, 7) ufe.Attributes.removeObserver(globalObs) self.assertEqual(ufe.Attributes.nbObservers(), 1) ufeCmd.execute(ball34XlateAttr.setCmd(ufe.Vector3d(7, 8, 9))) self.assertEqual(ball34Obs.notifications, 3) self.assertEqual(ball35Obs.notifications, 3) self.assertEqual(globalObs.notifications, 7)
def testLoadAndUnload(self): ''' Tests the working set management contextOps "Load", "Load with Descendants", and "Unload". ''' proxyShapePathSegment = mayaUtils.createUfePathSegment( '|transform1|proxyShape1') propsPath = ufe.Path([ proxyShapePathSegment, usdUtils.createUfePathSegment('/Room_set/Props') ]) propsItem = ufe.Hierarchy.createItem(propsPath) ball1Path = ufe.Path([ proxyShapePathSegment, usdUtils.createUfePathSegment('/Room_set/Props/Ball_1') ]) ball1Item = ufe.Hierarchy.createItem(ball1Path) ball15Path = ufe.Path([ proxyShapePathSegment, usdUtils.createUfePathSegment('/Room_set/Props/Ball_15') ]) ball15Item = ufe.Hierarchy.createItem(ball15Path) def _validateLoadAndUnloadItems(hierItem, itemStrings): ALL_ITEM_STRINGS = set(['Load', 'Load with Descendants', 'Unload']) expectedItemStrings = set(itemStrings or []) expectedAbsentItemStrings = ALL_ITEM_STRINGS - expectedItemStrings contextOps = ufe.ContextOps.contextOps(hierItem) contextItems = contextOps.getItems([]) contextItemStrings = [c.item for c in contextItems] for itemString in expectedItemStrings: self.assertIn(itemString, contextItemStrings) for itemString in expectedAbsentItemStrings: self.assertNotIn(itemString, contextItemStrings) # The stage is fully loaded, so all items should have "Unload" items. _validateLoadAndUnloadItems(propsItem, ['Unload']) _validateLoadAndUnloadItems(ball1Item, ['Unload']) _validateLoadAndUnloadItems(ball15Item, ['Unload']) # The mesh prim path under each Ball asset prim has nothing loadable at # or below it, so it should not have any load or unload items. ball15meshPath = ufe.Path([ proxyShapePathSegment, usdUtils.createUfePathSegment('/Room_set/Props/Ball_15/mesh') ]) ball15meshItem = ufe.Hierarchy.createItem(ball15meshPath) _validateLoadAndUnloadItems(ball15meshItem, []) # Unload Ball_1. contextOps = ufe.ContextOps.contextOps(ball1Item) cmd = contextOps.doOpCmd(['Unload']) self.assertIsNotNone(cmd) ufeCmd.execute(cmd) # Only Ball_1 should have been unloaded, and since it has a payload, it # should now have "Load" and "Load with Descendants" context items. # "Props" will now also have "Load with Descendants" because something # loadable below it is unloaded. _validateLoadAndUnloadItems(propsItem, ['Load with Descendants', 'Unload']) _validateLoadAndUnloadItems(ball1Item, ['Load', 'Load with Descendants']) _validateLoadAndUnloadItems(ball15Item, ['Unload']) cmds.undo() _validateLoadAndUnloadItems(propsItem, ['Unload']) _validateLoadAndUnloadItems(ball1Item, ['Unload']) _validateLoadAndUnloadItems(ball15Item, ['Unload']) # Unload Props. contextOps = ufe.ContextOps.contextOps(propsItem) cmd = contextOps.doOpCmd(['Unload']) self.assertIsNotNone(cmd) ufeCmd.execute(cmd) # The "Props" prim does not have a payload of its own, so it should # only have the "Load with Descendants" item. The Ball assets will also # have been unloaded. _validateLoadAndUnloadItems(propsItem, ['Load with Descendants']) _validateLoadAndUnloadItems(ball1Item, ['Load', 'Load with Descendants']) _validateLoadAndUnloadItems(ball15Item, ['Load', 'Load with Descendants']) cmds.undo() _validateLoadAndUnloadItems(propsItem, ['Unload']) _validateLoadAndUnloadItems(ball1Item, ['Unload']) _validateLoadAndUnloadItems(ball15Item, ['Unload']) cmds.redo() _validateLoadAndUnloadItems(propsItem, ['Load with Descendants']) _validateLoadAndUnloadItems(ball1Item, ['Load', 'Load with Descendants']) _validateLoadAndUnloadItems(ball15Item, ['Load', 'Load with Descendants']) # Load Props. contextOps = ufe.ContextOps.contextOps(propsItem) cmd = contextOps.doOpCmd(['Load with Descendants']) self.assertIsNotNone(cmd) ufeCmd.execute(cmd) _validateLoadAndUnloadItems(propsItem, ['Unload']) _validateLoadAndUnloadItems(ball1Item, ['Unload']) _validateLoadAndUnloadItems(ball15Item, ['Unload']) cmds.undo() _validateLoadAndUnloadItems(propsItem, ['Load with Descendants']) _validateLoadAndUnloadItems(ball1Item, ['Load', 'Load with Descendants']) _validateLoadAndUnloadItems(ball15Item, ['Load', 'Load with Descendants'])
def testDoOp(self): # Change visibility, undo / redo. cmd = self.contextOps.doOpCmd(['Toggle Visibility']) self.assertIsNotNone(cmd) attrs = ufe.Attributes.attributes(self.ball35Item) self.assertIsNotNone(attrs) visibility = attrs.attribute(UsdGeom.Tokens.visibility) self.assertIsNotNone(visibility) # Initially, Ball_35 has inherited visibility. self.assertEqual(visibility.get(), UsdGeom.Tokens.inherited) ufeCmd.execute(cmd) self.assertEqual(visibility.get(), UsdGeom.Tokens.invisible) cmds.undo() self.assertEqual(visibility.get(), UsdGeom.Tokens.inherited) cmds.redo() self.assertEqual(visibility.get(), UsdGeom.Tokens.invisible) cmds.undo() # Active / Deactivate Prim cmd = self.contextOps.doOpCmd(['Toggle Active State']) self.assertIsNotNone(cmd) # Initially, Ball_35 should be active. self.assertTrue(self.ball35Prim.IsActive()) ufeCmd.execute(cmd) self.assertFalse(self.ball35Prim.IsActive()) cmds.undo() self.assertTrue(self.ball35Prim.IsActive()) cmds.redo() self.assertFalse(self.ball35Prim.IsActive()) # Mark / Unmark Prim as Instanceable cmd = self.contextOps.doOpCmd(['Toggle Instanceable State']) self.assertIsNotNone(cmd) # Initially, Ball_35 should be not instanceable. self.assertFalse(self.ball35Prim.IsInstanceable()) ufeCmd.execute(cmd) self.assertTrue(self.ball35Prim.IsInstanceable()) cmds.undo() self.assertFalse(self.ball35Prim.IsInstanceable()) cmds.redo() self.assertTrue(self.ball35Prim.IsInstanceable()) # Change variant in variant set. def shadingVariant(): contextItems = self.contextOps.getItems( ['Variant Sets', 'shadingVariant']) for c in contextItems: if c.checked: return c.item self.assertEqual(shadingVariant(), 'Ball_8') cmd = self.contextOps.doOpCmd( ['Variant Sets', 'shadingVariant', 'Cue']) self.assertIsNotNone(cmd) ufeCmd.execute(cmd) self.assertEqual(shadingVariant(), 'Cue') cmds.undo() self.assertEqual(shadingVariant(), 'Ball_8') cmds.redo() self.assertEqual(shadingVariant(), 'Cue') cmds.undo()
def testAddNewPrim(self): # Create a ContextOps interface for the proxy shape. proxyShapePath = ufe.Path( [mayaUtils.createUfePathSegment("|world|stage1|stageShape1")]) proxyShapeItem = ufe.Hierarchy.createItem(proxyShapePath) contextOps = ufe.ContextOps.contextOps(proxyShapeItem) # Add a new prim. cmd = contextOps.doOpCmd(['Add New Prim', 'Xform']) self.assertIsNotNone(cmd) ufeCmd.execute(cmd) # The proxy shape should now have a single UFE child item. proxyShapehier = ufe.Hierarchy.hierarchy(proxyShapeItem) self.assertTrue(proxyShapehier.hasChildren()) self.assertEqual(len(proxyShapehier.children()), 1) # Add a new prim to the prim we just added. cmds.pickWalk(d='down') # Get the scene item from the UFE selection. snIter = iter(ufe.GlobalSelection.get()) xformItem = next(snIter) # Create a ContextOps interface for it. contextOps = ufe.ContextOps.contextOps(xformItem) # Add a new prim. cmd = contextOps.doOpCmd(['Add New Prim', 'Xform']) self.assertIsNotNone(cmd) ufeCmd.execute(cmd) # The xform prim should now have a single UFE child item. xformHier = ufe.Hierarchy.hierarchy(xformItem) self.assertTrue(xformHier.hasChildren()) self.assertEqual(len(xformHier.children()), 1) # Add another prim cmd = contextOps.doOpCmd(['Add New Prim', 'Capsule']) self.assertIsNotNone(cmd) ufeCmd.execute(cmd) # The xform prim should now have two UFE child items. self.assertTrue(xformHier.hasChildren()) self.assertEqual(len(xformHier.children()), 2) # Undo will remove the new prim, meaning one less child. cmds.undo() self.assertTrue(xformHier.hasChildren()) self.assertEqual(len(xformHier.children()), 1) # Undo again will remove the first added prim, meaning no children. cmds.undo() self.assertFalse(xformHier.hasChildren()) cmds.redo() self.assertTrue(xformHier.hasChildren()) self.assertEqual(len(xformHier.children()), 1) cmds.redo() self.assertTrue(xformHier.hasChildren()) self.assertEqual(len(xformHier.children()), 2)
def testObservation(self): ''' Test Attributes observation interface. Test both global attribute observation and per-node attribute observation. ''' # Start we a clean scene so we can get a consistent number of notifications cmds.file(new=True, force=True) mayaUtils.openTopLayerScene() # Create three observers, one for global attribute observation, and two # on different UFE items. proxyShapePathSegment = mayaUtils.createUfePathSegment( "|transform1|proxyShape1") path = ufe.Path([ proxyShapePathSegment, usdUtils.createUfePathSegment('/Room_set/Props/Ball_34') ]) ball34 = ufe.Hierarchy.createItem(path) path = ufe.Path([ proxyShapePathSegment, usdUtils.createUfePathSegment('/Room_set/Props/Ball_35') ]) ball35 = ufe.Hierarchy.createItem(path) (ball34Obs, ball35Obs, globalObs) = [TestObserver() for i in range(3)] # Maya registers a single global observer on startup. self.assertEqual(ufe.Attributes.nbObservers(), 1) # No item-specific observers. self.assertFalse(ufe.Attributes.hasObservers(ball34.path())) self.assertFalse(ufe.Attributes.hasObservers(ball35.path())) self.assertEqual(ufe.Attributes.nbObservers(ball34), 0) self.assertEqual(ufe.Attributes.nbObservers(ball35), 0) self.assertFalse(ufe.Attributes.hasObserver(ball34, ball34Obs)) self.assertFalse(ufe.Attributes.hasObserver(ball35, ball35Obs)) # No notifications yet. self.assertEqual(ball34Obs.notifications, 0) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 0) # Add a global observer. ufe.Attributes.addObserver(globalObs) self.assertEqual(ufe.Attributes.nbObservers(), 2) self.assertFalse(ufe.Attributes.hasObservers(ball34.path())) self.assertFalse(ufe.Attributes.hasObservers(ball35.path())) self.assertEqual(ufe.Attributes.nbObservers(ball34), 0) self.assertEqual(ufe.Attributes.nbObservers(ball35), 0) self.assertFalse(ufe.Attributes.hasObserver(ball34, ball34Obs)) self.assertFalse(ufe.Attributes.hasObserver(ball35, ball35Obs)) # Add item-specific observers. ufe.Attributes.addObserver(ball34, ball34Obs) self.assertEqual(ufe.Attributes.nbObservers(), 2) self.assertTrue(ufe.Attributes.hasObservers(ball34.path())) self.assertFalse(ufe.Attributes.hasObservers(ball35.path())) self.assertEqual(ufe.Attributes.nbObservers(ball34), 1) self.assertEqual(ufe.Attributes.nbObservers(ball35), 0) self.assertTrue(ufe.Attributes.hasObserver(ball34, ball34Obs)) self.assertFalse(ufe.Attributes.hasObserver(ball34, ball35Obs)) self.assertFalse(ufe.Attributes.hasObserver(ball35, ball35Obs)) ufe.Attributes.addObserver(ball35, ball35Obs) self.assertTrue(ufe.Attributes.hasObservers(ball35.path())) self.assertEqual(ufe.Attributes.nbObservers(ball34), 1) self.assertEqual(ufe.Attributes.nbObservers(ball35), 1) self.assertTrue(ufe.Attributes.hasObserver(ball35, ball35Obs)) self.assertFalse(ufe.Attributes.hasObserver(ball35, ball34Obs)) # Make a change to ball34, global and ball34 observers change. ball34Attrs = ufe.Attributes.attributes(ball34) ball34XlateAttr = ball34Attrs.attribute('xformOp:translate') self.assertEqual(ball34Obs.notifications, 0) # The first modification adds a new spec to ball_34 & its ancestors # "Props" and "Room_set". Ufe should be filtering out those notifications # so the global observer should still only see one notification. ufeCmd.execute(ball34XlateAttr.setCmd(ufe.Vector3d(4, 4, 15))) self.assertEqual(ball34Obs.notifications, 1) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 1) # The second modification only sends one USD notification for "xformOps:translate" # because all the spec's already exist. Ufe should also see one notification. ufeCmd.execute(ball34XlateAttr.setCmd(ufe.Vector3d(4, 4, 20))) self.assertEqual(ball34Obs.notifications, 2) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 2) # Undo, redo cmds.undo() self.assertEqual(ball34Obs.notifications, 3) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 3) cmds.redo() self.assertEqual(ball34Obs.notifications, 4) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 4) # get ready to undo the first modification cmds.undo() self.assertEqual(ball34Obs.notifications, 5) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 5) # Undo-ing the modification which created the USD specs is a little # different in USD, but from Ufe we should just still see one notification. cmds.undo() self.assertEqual(ball34Obs.notifications, 6) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 6) cmds.redo() self.assertEqual(ball34Obs.notifications, 7) self.assertEqual(ball35Obs.notifications, 0) self.assertEqual(globalObs.notifications, 7) # Make a change to ball35, global and ball35 observers change. ball35Attrs = ufe.Attributes.attributes(ball35) ball35XlateAttr = ball35Attrs.attribute('xformOp:translate') # "xformOp:translate" ufeCmd.execute(ball35XlateAttr.setCmd(ufe.Vector3d(4, 8, 15))) self.assertEqual(ball34Obs.notifications, 7) self.assertEqual(ball35Obs.notifications, 1) self.assertEqual(globalObs.notifications, 8) # Undo, redo cmds.undo() self.assertEqual(ball34Obs.notifications, 7) self.assertEqual(ball35Obs.notifications, 2) self.assertEqual(globalObs.notifications, 9) cmds.redo() self.assertEqual(ball34Obs.notifications, 7) self.assertEqual(ball35Obs.notifications, 3) self.assertEqual(globalObs.notifications, 10) # Test removeObserver. ufe.Attributes.removeObserver(ball34, ball34Obs) self.assertFalse(ufe.Attributes.hasObservers(ball34.path())) self.assertTrue(ufe.Attributes.hasObservers(ball35.path())) self.assertEqual(ufe.Attributes.nbObservers(ball34), 0) self.assertEqual(ufe.Attributes.nbObservers(ball35), 1) self.assertFalse(ufe.Attributes.hasObserver(ball34, ball34Obs)) ufeCmd.execute(ball34XlateAttr.setCmd(ufe.Vector3d(4, 4, 25))) self.assertEqual(ball34Obs.notifications, 7) self.assertEqual(ball35Obs.notifications, 3) self.assertEqual(globalObs.notifications, 11) ufe.Attributes.removeObserver(globalObs) self.assertEqual(ufe.Attributes.nbObservers(), 1) ufeCmd.execute(ball34XlateAttr.setCmd(ufe.Vector3d(7, 8, 9))) self.assertEqual(ball34Obs.notifications, 7) self.assertEqual(ball35Obs.notifications, 3) self.assertEqual(globalObs.notifications, 11)