diff --git a/lib/mayaUsd/python/wrapUtil.cpp b/lib/mayaUsd/python/wrapUtil.cpp index e6cf610ef0..fe613cd937 100644 --- a/lib/mayaUsd/python/wrapUtil.cpp +++ b/lib/mayaUsd/python/wrapUtil.cpp @@ -15,6 +15,7 @@ // #include #include +#include #include #include @@ -51,5 +52,8 @@ void wrapUtil() .def("IsAuthored", UsdMayaUtil::IsAuthored) .def("prettifyName", &UsdMayaUtil::prettifyName) .staticmethod("prettifyName") - .def("getDictionaryFromEncodedOptions", getDictionaryFromEncodedOptions); + .def("getDictionaryFromEncodedOptions", getDictionaryFromEncodedOptions) + .def( + "getPathRelativeToMayaSceneFile", + &UsdMayaUtilFileSystem::getPathRelativeToMayaSceneFile); } diff --git a/lib/mayaUsd/utils/utilFileSystem.cpp b/lib/mayaUsd/utils/utilFileSystem.cpp index 32d9b0c67b..ba04f417bd 100644 --- a/lib/mayaUsd/utils/utilFileSystem.cpp +++ b/lib/mayaUsd/utils/utilFileSystem.cpp @@ -121,10 +121,16 @@ std::string UsdMayaUtilFileSystem::getPathRelativeToMayaSceneFile(const std::str { ghc::filesystem::path absolutePath(fileName); ghc::filesystem::path basePath(getMayaSceneFileDir()); + + // If Maya scene file doesn't exist yet, use the absolute path + if (basePath.empty()) { + return fileName; + } + ghc::filesystem::path relativePath = absolutePath.lexically_relative(basePath); if (relativePath.empty()) { - TF_RUNTIME_ERROR( + TF_WARN( "File name (%s) cannot be resolved as relative to the Maya scene file, using the " "absolute path.", fileName.c_str()); diff --git a/lib/mayaUsd/utils/utilFileSystem.h b/lib/mayaUsd/utils/utilFileSystem.h index df66d5b79a..e0b5dea28f 100644 --- a/lib/mayaUsd/utils/utilFileSystem.h +++ b/lib/mayaUsd/utils/utilFileSystem.h @@ -49,7 +49,8 @@ std::string getMayaSceneFileDir(); MAYAUSD_CORE_PUBLIC std::string getMayaWorkspaceScenesDir(); -/*! \brief takes in an absolute file path and returns the path relative to maya scene file +/*! \brief takes in an absolute file path and returns the path relative to maya scene file. +When there is no scene file, the absolute (input) path will be returned. */ MAYAUSD_CORE_PUBLIC std::string getPathRelativeToMayaSceneFile(const std::string& fileName); diff --git a/plugin/adsk/scripts/AETemplateHelpers.py b/plugin/adsk/scripts/AETemplateHelpers.py index 8d9ddc4fe6..fd1e739f5d 100644 --- a/plugin/adsk/scripts/AETemplateHelpers.py +++ b/plugin/adsk/scripts/AETemplateHelpers.py @@ -2,6 +2,7 @@ import maya.cmds as cmds import ufe import mayaUsd.ufe +import mayaUsd.lib as mayaUsdLib from mayaUSDRegisterStrings import getMayaUsdString from mayaUsdUtils import getUSDDialogFileFilters @@ -60,6 +61,9 @@ def GetStageFromProxyShapeAttr(attr): return(stageName, proxyStage) +def RequireUsdPathsRelativeToMayaSceneFile(): + return cmds.optionVar(exists="mayaUsd_MakePathRelativeToSceneFile") and cmds.optionVar(query="mayaUsd_MakePathRelativeToSceneFile") + def ProxyShapeFilePathChanged(filePathAttr, newFilePath=None): # Function called from the MayaUsd Proxy Shape template when the file path # text field of the file path attibute custom control is modified or interacted with. @@ -125,11 +129,23 @@ def ProxyShapeFilePathChanged(filePathAttr, newFilePath=None): title = getMayaUsdString("kLoadUSDFile") okCaption = getMayaUsdString("kLoad") fileFilter = getUSDDialogFileFilters() - res = cmds.fileDialog2(caption=title, fileMode=1, ff=fileFilter, okc=okCaption) + + startDir = '' + if cmds.file(q=True, exists=True): + fullPath = cmds.file(q=True, loc=True) + startDir = os.path.dirname(fullPath) + + res = cmds.fileDialog2(caption=title, fileMode=1, ff=fileFilter, okc=okCaption, + optionsUICreate='mayaUsd_USDRootFileRelative_UICreate', + optionsUIInit='mayaUsd_USDRootFileRelative_UIInit', + optionsUICommit2='mayaUsd_USDRootFileRelative_UICommit', + startingDirectory=startDir) if res and len(res) == 1: debugMessage(' User picked USD file, setting file path attribute') # Simply set the file path attribute. The proxy shape will load the file. usdFileToLoad = res[0] + if RequireUsdPathsRelativeToMayaSceneFile(): + usdFileToLoad = mayaUsdLib.Util.getPathRelativeToMayaSceneFile(usdFileToLoad) cmds.setAttr(filePathAttr, usdFileToLoad, type='string') return True elif newFilePath is not None: diff --git a/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py b/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py index 4ff9793c05..9a200dc80a 100644 --- a/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py +++ b/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py @@ -10,9 +10,14 @@ class usdRootFileRelative(object): @classmethod def uiCreate(cls, parentLayout): + """ + Helper method to create the UI layout for the USD root file relative actions. + + Input parentLayout arg is expected to the a scroll layout into which controls + can be added. + """ pushOptionsUITemplate() cmds.setParent(parentLayout) - parent = cmds.scrollLayout(childResizable=True) optBoxForm = cmds.formLayout('optionsBoxForm') topFrame = cmds.frameLayout( @@ -49,7 +54,7 @@ def uiInit(cls, parentLayout, filterType): cmds.checkBox(cls.kMakePathRelativeCheckBox, edit=True, enable=haveSceneFile) @classmethod - def uiCommit(cls, parentLayout, selectedFile): + def uiCommit(cls, parentLayout, selectedFile=None): cmds.setParent(parentLayout) # Get the current checkbox state and save to optionVar. diff --git a/plugin/adsk/scripts/mayaUsd_createStageFromFile.mel b/plugin/adsk/scripts/mayaUsd_createStageFromFile.mel index befb26d14a..0856e8e7b0 100644 --- a/plugin/adsk/scripts/mayaUsd_createStageFromFile.mel +++ b/plugin/adsk/scripts/mayaUsd_createStageFromFile.mel @@ -64,10 +64,18 @@ proc string getLatestLoadStageFolder() // stageFromFile_UISetup // creates the options of the stageFromFile dialog -global proc string stageFromFile_UISetup(string $parent) { +global proc string stageFromFile_UISetup(string $parent) +{ + // First create the scroll layout here and then call the python + // helper to add the rest of the UI. setParent $parent; string $layout = `scrollLayout -childResizable true`; + // Add the USD root file relative section. + python("import mayaUsd_USDRootFileRelative as murel\nmurel.usdRootFileRelative.uiCreate('" + $layout + "')"); + + // Then add the stage from file specific section. + setParent $layout; $title = `getMayaUsdString("kUsdFileOptions")`; $frame = `frameLayout -label $title -collapsable false`; checkBoxGrp -l `getMayaUsdString("kLoadPayloads")` @@ -90,9 +98,13 @@ global proc string stageFromFile_UISetup(string $parent) { // stageFromFile_UIInit // init defaults values for the options of the stageFromFile dialog -global proc stageFromFile_UIInit(string $parent, string $filterType) { +global proc stageFromFile_UIInit(string $parent, string $filterType) +{ setOptionVars(false); + // Init the USD root file relative section. + python("import mayaUsd_USDRootFileRelative as murel\nmurel.usdRootFileRelative.uiInit('" + $parent + "', '" + $filterType + "')"); + string $ppath = `optionVar -q stageFromFile_primPath`; string $exppath = `optionVar -q stageFromFile_excludePrimPath`; int $loadp = `optionVar -q stageFromFile_loadPayloads`; @@ -103,9 +115,13 @@ global proc stageFromFile_UIInit(string $parent, string $filterType) { checkBoxGrp -e -value1 $loadp loadPayloadsCheckBox; } -global proc stageFromFile_UICommit(string $parent) { +global proc stageFromFile_UICommit(string $parent) +{ setParent $parent; + // Commit the USD root file relative section. + python("import mayaUsd_USDRootFileRelative as murel\nmurel.usdRootFileRelative.uiCommit('" + $parent + "')"); + // fetch values optionVar -stringValue stageFromFile_primPath (`textFieldGrp -q -text primPathField`); @@ -115,7 +131,8 @@ global proc stageFromFile_UICommit(string $parent) { (`checkBoxGrp -q -value1 loadPayloadsCheckBox`); } -proc string doCreateStage(string $fileName) { +proc string doCreateStage(string $fileName) +{ // actually load the file string $baseName = basenameEx($fileName); if( ! isValidObjectName($baseName) ) @@ -125,8 +142,13 @@ proc string doCreateStage(string $fileName) { string $exppath = `optionVar -q stageFromFile_excludePrimPath`; int $loadp = `optionVar -q stageFromFile_loadPayloads`; + string $fileNameToSave = $fileName; + if (`optionVar -exists mayaUsd_MakePathRelativeToSceneFile` && `optionVar -query mayaUsd_MakePathRelativeToSceneFile`) { + $fileNameToSave = `python("import mayaUsd.lib as mayaUsdLib; mayaUsdLib.Util.getPathRelativeToMayaSceneFile('" + $fileName + "')")`; + } + string $shapeNode = `createNode "mayaUsdProxyShape" -skipSelect -name ($baseName+"Shape")`; - setAttr -type "string" ($shapeNode+".filePath") $fileName; + setAttr -type "string" ($shapeNode+".filePath") $fileNameToSave; setAttr -type "string" ($shapeNode+".primPath") $ppath; setAttr -type "string" ($shapeNode+".excludePrimPaths") $exppath; setAttr ($shapeNode+".loadPayloads") $loadp; @@ -216,7 +238,8 @@ global proc mayaUsd_createStageFromFileOptions() showOptionBox(); } -global proc mayaUsd_createStageFromFile() { +global proc mayaUsd_createStageFromFile() +{ setOptionVars(false); $caption = getMayaUsdString("kCreateUsdStageFromFile"); diff --git a/plugin/adsk/scripts/mayaUsd_layerEditorFileDialogs.mel b/plugin/adsk/scripts/mayaUsd_layerEditorFileDialogs.mel index 1f110fff39..64eb13da7d 100644 --- a/plugin/adsk/scripts/mayaUsd_layerEditorFileDialogs.mel +++ b/plugin/adsk/scripts/mayaUsd_layerEditorFileDialogs.mel @@ -15,7 +15,11 @@ global proc mayaUsd_USDRootFileRelative_UICreate(string $parent) { - python("import mayaUsd_USDRootFileRelative as murel\nmurel.usdRootFileRelative.uiCreate('" + $parent + "')"); + // First create the scroll layout here and then call the python + // helper to add the rest of the UI. + setParent $parent; + string $layout = `scrollLayout -childResizable true`; + python("import mayaUsd_USDRootFileRelative as murel\nmurel.usdRootFileRelative.uiCreate('" + $layout + "')"); } global proc mayaUsd_USDRootFileRelative_UIInit(string $parent, string $filterType)