From 857a79d736d8888a304c6c7beede4e4c05ee62c5 Mon Sep 17 00:00:00 2001 From: Pierre Baillargeon Date: Wed, 4 Oct 2023 17:12:53 -0400 Subject: [PATCH 1/4] EMSUSD-254 Allow selecting the referenced prim To allow selecting the referenced prim when adding a new USD reference or payload, multiple sub-systems had to be modified: - The usdImportDialog command, to accept new parameters - Qt dialog layout. - The Qt tree model and tree item implementing the USD hierchy view. - The functions managing the USD ref/payload filel dialog. - The Python code that ties everything together. Modify the usdImportDialog command: - Add a new flag to the usdImprotDialog command to control if variants are shown. - Add a new flag to the usdImprotDialog command to control if the root prim is shown. - Add a new flag to the usdImprotDialog command to set the window title. - Add a new flag to the usdImprotDialog command to set the help label. - Add a new flag to the usdImprotDialog command to set the help target. - Allow setting the prim path with the edit flag. - Use the new prim path flag in the Python code that builds the UI. - Added helper function to manage the transfer of the prim path from the UI to the command. Modify the Qt dialog to enable all those flags: - Add a USDImportDialogOptions structure to hold all the various options. - Pass that around to all the relevant sub-functions. - Modify the dialog to hide variants, header message, etc when relevant. - Change the add ref/payload dialog accept button label to be "Reference". - Implement most of the referenced prim logic. - Fix the import dialog to only use the prim path if not empty. Modify the USD hierarchy tree model and item: - Change TreeModel to handle not showing the root and not showing variants. - Made the tree item add a 'default prim' icon next to the prim name when it is the default prim. - Added the default prim image used by the tree item. - Make the tree model factory preselect the top prim. - Modify the factory to create the correct number of column depending on if variants are shown. - Make the tree model factory use the first root prim if no default prim are present. - Added a helper method on the tree model to retrieve the first item. Modify the relative-file utility classes: - Allow all the relative-UI classes to hook into the filename selection. - For the add payload/ref one, update the referenced prim UI when the filename changes. - Still missing pre-selecting the correct prim in the selection dialog and some corner cases. - Save the selected prim path in an option var to communicate it to the calling code. Modify the cntext menu: - Use all of the above to create the add-ref or add-payload command with the selected prim path. --- .../scripts/mayaUsdLibRegisterStrings.py | 9 ++ .../scripts/mayaUsdMayaReferenceUtils.py | 115 ++++++++++++++++-- lib/mayaUsd/resources/scripts/mayaUsdUtils.py | 10 ++ lib/mayaUsd/ufe/MayaUsdContextOps.cpp | 13 +- lib/mayaUsd/utils/utilFileSystem.cpp | 8 ++ lib/mayaUsd/utils/utilFileSystem.h | 5 + lib/usd/ui/importDialog/TreeItem.cpp | 79 +++++++----- lib/usd/ui/importDialog/TreeItem.h | 28 +++-- lib/usd/ui/importDialog/TreeModel.cpp | 102 ++++++++++++---- lib/usd/ui/importDialog/TreeModel.h | 37 +++--- lib/usd/ui/importDialog/TreeModelFactory.cpp | 113 ++++++++++++----- lib/usd/ui/importDialog/TreeModelFactory.h | 53 +++++--- lib/usd/ui/importDialog/USDImportDialog.cpp | 51 ++++++-- lib/usd/ui/importDialog/USDImportDialog.h | 27 +++- lib/usd/ui/importDialog/USDImportDialog.ui | 8 +- .../ui/importDialog/USDImportDialogCmd.cpp | 85 ++++++++++--- .../importDialog/images/defaultPrim_100.png | Bin 0 -> 1514 bytes .../importDialog/images/defaultPrim_150.png | Bin 0 -> 2277 bytes .../importDialog/images/defaultPrim_200.png | Bin 0 -> 2031 bytes lib/usd/ui/importDialog/images/ui.qrc | 3 + lib/usd/ui/importDialogDemo/testMayaUsdUI.cpp | 5 +- .../scripts/mayaUsd_USDRootFileRelative.py | 60 ++++++--- 22 files changed, 607 insertions(+), 204 deletions(-) create mode 100644 lib/usd/ui/importDialog/images/defaultPrim_100.png create mode 100644 lib/usd/ui/importDialog/images/defaultPrim_150.png create mode 100644 lib/usd/ui/importDialog/images/defaultPrim_200.png diff --git a/lib/mayaUsd/resources/scripts/mayaUsdLibRegisterStrings.py b/lib/mayaUsd/resources/scripts/mayaUsdLibRegisterStrings.py index 40040f3b88..1440646645 100644 --- a/lib/mayaUsd/resources/scripts/mayaUsdLibRegisterStrings.py +++ b/lib/mayaUsd/resources/scripts/mayaUsdLibRegisterStrings.py @@ -73,6 +73,15 @@ def mayaUsdLibRegisterStrings(): register('kTextVariant', 'Variant') register('kTextVariantToolTip','If selected, your Maya reference will be defined in a variant. This will enable your prim to\nhave 2 variants you can switch between in the Outliner; the Maya reference and its USD cache.') + register('kAddRefOrPayloadPrimPathToolTip', 'Specifying a prim path will make an explicit reference to a prim.\n' + + 'If there is no default prim in your chosen reference, this field auto populates with the top level prim for you to reference in.\n' + + 'If the field is left blank, no prim will be referenced.') + register('kAddRefOrPayloadPrimPathLabel', 'Prim Path') + register('kAddRefOrPayloadPrimPathPlaceHolder', ' (Default Prim)') + register('kAddRefOrPayloadPrimPathHelpLabel', 'Help on Select a Prim for Reference') + register('kAddRefOrPayloadPrimPathTitle', 'Select a Prim to Reference') + register('kAddRefOrPayloadSelectLabel', 'Select') + # mayaUsdClearRefsOrPayloadsOptions.py register('kClearRefsOrPayloadsOptionsTitle', 'Clear All USD References/Payloads') register('kClearRefsOrPayloadsOptionsMessage', 'Clear all references/payloads on %s?') diff --git a/lib/mayaUsd/resources/scripts/mayaUsdMayaReferenceUtils.py b/lib/mayaUsd/resources/scripts/mayaUsdMayaReferenceUtils.py index e96d660a8e..6d54508a4e 100644 --- a/lib/mayaUsd/resources/scripts/mayaUsdMayaReferenceUtils.py +++ b/lib/mayaUsd/resources/scripts/mayaUsdMayaReferenceUtils.py @@ -16,6 +16,7 @@ import maya.cmds as cmds from mayaUsdLibRegisterStrings import getMayaUsdLibString +from pxr import Sdf # These names should not be localized as Usd only accepts [a-z,A-Z] as valid characters. kDefaultMayaReferencePrimName = 'MayaReference1' @@ -27,13 +28,15 @@ compositionArcReference = 'Reference' _compositionArcValues = [compositionArcReference, compositionArcPayload] -listEditTypeKey = '' +listEditTypeKey = 'listEditType' listEditTypePrepend = 'Prepend' listEditTypeAppend = 'Append' _listEditedAsValues = [listEditTypePrepend, listEditTypeAppend] loadPayloadKey = 'loadPayload' +referencedPrimPathKey = 'referencedPrimPath' + def defaultMayaReferencePrimName(): return kDefaultMayaReferencePrimName @@ -118,7 +121,84 @@ def _compositionArcChanged(selectedItem): enableLoadPayload = bool(compositionArc == compositionArcPayload) cmds.checkBoxGrp('loadPayload', edit=True, enable=enableLoadPayload) -def createUsdRefOrPayloadUI(showLoadPayload=False): +def _selectReferencedPrim(*args): + """ + Open a dialog to select a prim from the currently selected file + to be the referenced prim. + """ + filename = _getCurrentFilename() + primPath = cmds.textFieldGrp('mayaUsdAddRefOrPayloadPrimPath', query=True, text=True) + title = getMayaUsdLibString('kAddRefOrPayloadPrimPathTitle') + helpLabel = getMayaUsdLibString('kAddRefOrPayloadPrimPathHelpLabel') + helpToken = 'something something' + result = cmds.usdImportDialog(filename, hideVariants=True, hideRoot=True, primPath=primPath, title=title, helpLabel=helpLabel, helpToken=helpToken) + if result: + primPath = cmds.usdImportDialog(query=True, primPath=True) + cmds.textFieldGrp('mayaUsdAddRefOrPayloadPrimPath', edit=True, text=primPath) + cmds.usdImportDialog(clearData=True) + +_currentFileName = None + +def _setCurrentFilename(filename): + """Sets the current file selection.""" + global _currentFileName + _currentFileName = filename + +def _getCurrentFilename(): + """Retrieve the current file selection.""" + global _currentFileName + return _currentFileName + +def _resetReferencedPrim(*args): + """Reset the referenced prim UI""" + _updateReferencedPrimBasedOnFile() + +def _getDefaultAndRootPrims(filename): + """Retrieve the default and first root prims of a USD file.""" + defPrim, rootPrim = None, None + try: + layer = Sdf.Layer.FindOrOpen(filename) + if layer: + # Note: the root prims at the USD layer level are SdfPrimSpec, + # so they are not SdfPath themselves nor prim. That is + # why their path is retrieved via their path property. + # + # The default prim is a pure token though, because it is + # a metadata on the layer, so it can be used as-is. + rootPrims = layer.rootPrims + rootPrim = rootPrims[0].path if len(rootPrims) > 0 else None + defPrim = layer.defaultPrim + except Exception as ex: + print(str(ex)) + + return defPrim, rootPrim + +def _updateReferencedPrimBasedOnFile(): + """Update all UI related to the referenced prim based on the currently selected file.""" + filename = _getCurrentFilename() + if not filename: + cmds.textFieldGrp('mayaUsdAddRefOrPayloadPrimPath', edit=True, text='', placeholderText='') + cmds.textFieldGrp('mayaUsdAddRefOrPayloadPrimPath', edit=True, enable=False) + cmds.button('mayaUsdAddRefOrPayloadFilePathBrowser', edit=True, enable=False) + cmds.symbolButton('mayaUsdAddRefOrPayloadFilePathReset', edit=True, enable=False) + return + + cmds.textFieldGrp('mayaUsdAddRefOrPayloadPrimPath', edit=True, enable=True) + cmds.button('mayaUsdAddRefOrPayloadFilePathBrowser', edit=True, enable=True) + cmds.symbolButton('mayaUsdAddRefOrPayloadFilePathReset', edit=True, enable=True) + + defaultPrim, rootPrim = _getDefaultAndRootPrims(filename) + if defaultPrim: + placeHolder = defaultPrim + getMayaUsdLibString('kAddRefOrPayloadPrimPathPlaceHolder') + cmds.textFieldGrp('mayaUsdAddRefOrPayloadPrimPath', edit=True, text='', placeholderText=placeHolder) + elif rootPrim: + cmds.textFieldGrp('mayaUsdAddRefOrPayloadPrimPath', edit=True, text=rootPrim, placeholderText='') + else: + cmds.textFieldGrp('mayaUsdAddRefOrPayloadPrimPath', edit=True, text='', placeholderText='') + +def createUsdRefOrPayloadUI(uiForLoad=False): + _setCurrentFilename(None) + with SetParentContext(cmds.rowLayout(numberOfColumns=2)): tooltip = getMayaUsdLibString('kOptionAsUSDReferenceToolTip') cmds.optionMenuGrp('compositionArcTypeMenu', @@ -136,27 +216,48 @@ def createUsdRefOrPayloadUI(showLoadPayload=False): for label in listEditedAsLabels: cmds.menuItem(label=label) - if showLoadPayload: + if uiForLoad: + with SetParentContext(cmds.rowLayout(numberOfColumns=3, adjustableColumn1=True)): + tooltip = getMayaUsdLibString('kAddRefOrPayloadPrimPathToolTip') + primPathLabel = getMayaUsdLibString("kAddRefOrPayloadPrimPathLabel") + selectLabel = getMayaUsdLibString("kAddRefOrPayloadSelectLabel") + cmds.textFieldGrp('mayaUsdAddRefOrPayloadPrimPath', label=primPathLabel, ann=tooltip) + cmds.button('mayaUsdAddRefOrPayloadFilePathBrowser', label=selectLabel, ann=tooltip) + cmds.symbolButton('mayaUsdAddRefOrPayloadFilePathReset', image="refresh.png", ann=tooltip) + cmds.checkBoxGrp('loadPayload', label=getMayaUsdLibString('kOptionLoadPayload'), annotation=getMayaUsdLibString('kLoadPayloadAnnotation'), ncb=1) -def initUsdRefOrPayloadUI(values, showLoadPayload=False): +def initUsdRefOrPayloadUI(values, uiForLoad=False): compositionArcMenuIndex = _getMenuIndex(_compositionArcValues, values[compositionArcKey]) cmds.optionMenuGrp('compositionArcTypeMenu', edit=True, select=compositionArcMenuIndex) listEditTypeMenuIndex = _getMenuIndex(_listEditedAsValues,values[listEditTypeKey]) cmds.optionMenu('listEditedAsMenu', edit=True, select=listEditTypeMenuIndex) - if showLoadPayload: + if uiForLoad: cmds.optionMenuGrp('compositionArcTypeMenu', edit=True, cc=_compositionArcChanged) _compositionArcChanged(compositionArcMenuIndex) cmds.checkBoxGrp('loadPayload', edit=True, value1=values[loadPayloadKey]) -def commitUsdRefOrPayloadUI(showLoadPayload=False): + cmds.button("mayaUsdAddRefOrPayloadFilePathBrowser", c=_selectReferencedPrim, edit=True) + cmds.button("mayaUsdAddRefOrPayloadFilePathReset", c=_resetReferencedPrim, edit=True) + + _updateReferencedPrimBasedOnFile() + +def updateUsdRefOrPayloadUI(selectedFile): + if selectedFile == _getCurrentFilename(): + return + _setCurrentFilename(selectedFile) + _updateReferencedPrimBasedOnFile() + +def commitUsdRefOrPayloadUI(uiForLoad=False): values = {} values[compositionArcKey] = _getMenuGrpValue('compositionArcTypeMenu', _compositionArcValues) values[listEditTypeKey ] = _getMenuValue('listEditedAsMenu', _listEditedAsValues) - values[loadPayloadKey ] = cmds.checkBoxGrp('loadPayload', query=True, value1=True) if showLoadPayload else True + values[loadPayloadKey ] = cmds.checkBoxGrp('loadPayload', query=True, value1=True) if uiForLoad else True + values[referencedPrimPathKey] = cmds.textFieldGrp('mayaUsdAddRefOrPayloadPrimPath', query=True, text=True) if uiForLoad else '' + return values diff --git a/lib/mayaUsd/resources/scripts/mayaUsdUtils.py b/lib/mayaUsd/resources/scripts/mayaUsdUtils.py index 803192d5b1..e304a04b7b 100644 --- a/lib/mayaUsd/resources/scripts/mayaUsdUtils.py +++ b/lib/mayaUsd/resources/scripts/mayaUsdUtils.py @@ -211,6 +211,16 @@ def saveWantPayloadLoaded(want): opVarName = "mayaUsd_WantPayloadLoaded" cmds.optionVar(iv=(opVarName, want)) +def getReferencedPrimPath(): + opVarName = "mayaUsd_ReferencedPrimPath" + if not cmds.optionVar(exists=opVarName): + return '' + return cmds.optionVar(query=opVarName) + +def saveReferencedPrimPath(primPath): + opVarName = "mayaUsd_ReferencedPrimPath" + cmds.optionVar(sv=(opVarName, primPath)) + def showHelpMayaUSD(contentId): """ Helper method to display help content. diff --git a/lib/mayaUsd/ufe/MayaUsdContextOps.cpp b/lib/mayaUsd/ufe/MayaUsdContextOps.cpp index 1d5ef496bf..544407888d 100644 --- a/lib/mayaUsd/ufe/MayaUsdContextOps.cpp +++ b/lib/mayaUsd/ufe/MayaUsdContextOps.cpp @@ -184,6 +184,7 @@ const char* _selectUSDFileScript() string $result[] = `fileDialog2 -fileMode 1 -caption "Add USD Reference/Payload to Prim" + -okCaption Reference -fileFilter "USD Files (%s);;%s" -optionsUICreate addUSDReferenceCreateUi -optionsUIInit addUSDReferenceInitUi @@ -555,10 +556,12 @@ Ufe::UndoableCommand::Ptr MayaUsdContextOps::doOpCmd(const ItemPath& itemPath) if (path.empty()) return nullptr; - const bool asRef = UsdMayaUtilFileSystem::wantReferenceCompositionArc(); - const bool prepend = UsdMayaUtilFileSystem::wantPrependCompositionArc(); + const std::string primPath = UsdMayaUtilFileSystem::getReferencedPrimPath(); + const bool asRef = UsdMayaUtilFileSystem::wantReferenceCompositionArc(); + const bool prepend = UsdMayaUtilFileSystem::wantPrependCompositionArc(); if (asRef) { - return std::make_shared(prim(), path, prepend); + return std::make_shared( + prim(), path, primPath, prepend); } else { Ufe::UndoableCommand::Ptr preloadCmd; const bool preload = UsdMayaUtilFileSystem::wantPayloadLoaded(); @@ -569,8 +572,8 @@ Ufe::UndoableCommand::Ptr MayaUsdContextOps::doOpCmd(const ItemPath& itemPath) preloadCmd = std::make_shared(prim()); } - auto payloadCmd - = std::make_shared(prim(), path, prepend); + auto payloadCmd = std::make_shared( + prim(), path, primPath, prepend); auto compoCmd = std::make_shared(); compoCmd->append(preloadCmd); diff --git a/lib/mayaUsd/utils/utilFileSystem.cpp b/lib/mayaUsd/utils/utilFileSystem.cpp index bce8debdfa..7c6db5b768 100644 --- a/lib/mayaUsd/utils/utilFileSystem.cpp +++ b/lib/mayaUsd/utils/utilFileSystem.cpp @@ -422,6 +422,14 @@ bool UsdMayaUtilFileSystem::wantPayloadLoaded() && MGlobal::optionVarIntValue(WANT_PAYLOAD_LOADED); } +std::string UsdMayaUtilFileSystem::getReferencedPrimPath() +{ + static const MString WANT_REFERENCE_COMPOSITION_ARC = "mayaUsd_ReferencedPrimPath"; + if (!MGlobal::optionVarExists(WANT_REFERENCE_COMPOSITION_ARC)) + return {}; + return MGlobal::optionVarStringValue(WANT_REFERENCE_COMPOSITION_ARC).asChar(); +} + const char* getScenesFolderScript = R"( global proc string UsdMayaUtilFileSystem_GetScenesFolder() { diff --git a/lib/mayaUsd/utils/utilFileSystem.h b/lib/mayaUsd/utils/utilFileSystem.h index 86b403da1d..9a89251fc1 100644 --- a/lib/mayaUsd/utils/utilFileSystem.h +++ b/lib/mayaUsd/utils/utilFileSystem.h @@ -171,6 +171,11 @@ bool wantPrependCompositionArc(); MAYAUSD_CORE_PUBLIC bool wantPayloadLoaded(); +/*! \brief returns the prim path referenced by the USD reference or payload. + */ +MAYAUSD_CORE_PUBLIC +std::string getReferencedPrimPath(); + /*! \brief prepares the UI used to save layers, so that the UI can potentially make the selected file name relative to the given directory. */ diff --git a/lib/usd/ui/importDialog/TreeItem.cpp b/lib/usd/ui/importDialog/TreeItem.cpp index d2cd266d2c..2049ce98e1 100644 --- a/lib/usd/ui/importDialog/TreeItem.cpp +++ b/lib/usd/ui/importDialog/TreeItem.cpp @@ -25,44 +25,53 @@ namespace MAYAUSD_NS_DEF { -QPixmap* TreeItem::fsCheckBoxOn = nullptr; -QPixmap* TreeItem::fsCheckBoxOnDisabled = nullptr; -QPixmap* TreeItem::fsCheckBoxOff = nullptr; -QPixmap* TreeItem::fsCheckBoxOffDisabled = nullptr; +const QPixmap* TreeItem::fsCheckBoxOn = nullptr; +const QPixmap* TreeItem::fsCheckBoxOnDisabled = nullptr; +const QPixmap* TreeItem::fsCheckBoxOff = nullptr; +const QPixmap* TreeItem::fsCheckBoxOffDisabled = nullptr; -TreeItem::TreeItem(const UsdPrim& prim, Type t) noexcept +TreeItem::TreeItem(const UsdPrim& prim, bool isDefaultPrim, Column column) noexcept : ParentClass() , fPrim(prim) - , fType(t) + , fColumn(column) , fCheckState(CheckState::kChecked_Disabled) , fVariantSelectionModified(false) { - initializeItem(); + initializeItem(isDefaultPrim); } UsdPrim TreeItem::prim() const { return fPrim; } int TreeItem::type() const { return ParentClass::ItemType::UserType; } +const QPixmap* TreeItem::createPixmap(const char* pixmapURL) const +{ + const QPixmap* pixmap = nullptr; + + const TreeModel* treeModel = qobject_cast(model()); + if (treeModel != nullptr) { + pixmap = treeModel->mayaQtUtil().createPixmap(pixmapURL); + } else { + // The tree model should never be null, but we can recover here if it is. + TF_RUNTIME_ERROR("Unexpected null tree model"); + pixmap = new QPixmap(pixmapURL); + } + + // If the resource fails to load, return a non-null pointer. + static const QPixmap empty; + if (!pixmap) + pixmap = ∅ + + return pixmap; +} + const QPixmap& TreeItem::checkImage() const { if (fsCheckBoxOn == nullptr) { - const TreeModel* treeModel = qobject_cast(model()); - if (treeModel != nullptr) { - fsCheckBoxOn = treeModel->mayaQtUtil().createPixmap(":/ImportDialog/checkboxOn.png"); - fsCheckBoxOnDisabled - = treeModel->mayaQtUtil().createPixmap(":/ImportDialog/checkboxOnDisabled.png"); - fsCheckBoxOff = treeModel->mayaQtUtil().createPixmap(":/ImportDialog/checkboxOff.png"); - fsCheckBoxOffDisabled - = treeModel->mayaQtUtil().createPixmap(":/ImportDialog/checkboxOffDisabled.png"); - } else { - // The tree model should never be null, but we can recover here if it is. - TF_RUNTIME_ERROR("Unexpected null tree model"); - fsCheckBoxOn = new QPixmap(":/ImportDialog/checkboxOn.png"); - fsCheckBoxOnDisabled = new QPixmap(":/ImportDialog/checkboxOnDisabled.png"); - fsCheckBoxOff = new QPixmap(":/ImportDialog/checkboxOff.png"); - fsCheckBoxOffDisabled = new QPixmap(":/ImportDialog/checkboxOffDisabled.png"); - } + fsCheckBoxOn = createPixmap(":/ImportDialog/checkboxOn.png"); + fsCheckBoxOnDisabled = createPixmap(":/ImportDialog/checkboxOnDisabled.png"); + fsCheckBoxOff = createPixmap(":/ImportDialog/checkboxOff.png"); + fsCheckBoxOffDisabled = createPixmap(":/ImportDialog/checkboxOffDisabled.png"); } switch (fCheckState) { @@ -76,30 +85,34 @@ const QPixmap& TreeItem::checkImage() const void TreeItem::setCheckState(TreeItem::CheckState st) { - assert(fType == Type::kLoad); - if (fType == Type::kLoad) + assert(fColumn == kColumnLoad); + if (fColumn == kColumnLoad) fCheckState = st; } void TreeItem::setVariantSelectionModified() { - assert(fType == Type::kVariants); - if (fType == Type::kVariants) + assert(fColumn == kColumnVariants); + if (fColumn == kColumnVariants) fVariantSelectionModified = true; } -void TreeItem::initializeItem() +void TreeItem::initializeItem(bool isDefaultPrim) { - switch (fType) { - case Type::kLoad: fCheckState = CheckState::kChecked_Disabled; break; - case Type::kName: + switch (fColumn) { + case kColumnLoad: fCheckState = CheckState::kChecked_Disabled; break; + case kColumnName: if (fPrim.IsPseudoRoot()) setText("Root"); else setText(QString::fromStdString(fPrim.GetName().GetString())); + if (isDefaultPrim) { + if (const QPixmap* pixmap = TreeModel::getDefaultPrimPixmap()) + setData(*pixmap, Qt::DecorationRole); + } break; - case Type::kType: setText(QString::fromStdString(fPrim.GetTypeName().GetString())); break; - case Type::kVariants: { + case kColumnType: setText(QString::fromStdString(fPrim.GetTypeName().GetString())); break; + case kColumnVariants: { if (fPrim.HasVariantSets()) { // We set a special role flag when this prim has variant sets. // So we know when to create the label and combo box(es) for the variant diff --git a/lib/usd/ui/importDialog/TreeItem.h b/lib/usd/ui/importDialog/TreeItem.h index 39727b01ad..7db4ab6542 100644 --- a/lib/usd/ui/importDialog/TreeItem.h +++ b/lib/usd/ui/importDialog/TreeItem.h @@ -39,12 +39,13 @@ class MAYAUSD_UI_PUBLIC TreeItem : public QStandardItem public: using ParentClass = QStandardItem; - enum class Type + enum Column { - kLoad, - kName, - kType, - kVariants + kColumnLoad, + kColumnName, + kColumnType, + kColumnVariants, + kColumnLast }; enum class CheckState @@ -60,7 +61,7 @@ class MAYAUSD_UI_PUBLIC TreeItem : public QStandardItem * \param prim The USD Prim to represent with this item. * \param text Column text to display on the View of the the Qt TreeModel. */ - explicit TreeItem(const UsdPrim& prim, Type t) noexcept; + explicit TreeItem(const UsdPrim& prim, bool isDefaultPrim, Column column) noexcept; /** * \brief Destructor. @@ -102,14 +103,15 @@ class MAYAUSD_UI_PUBLIC TreeItem : public QStandardItem void resetVariantSelectionModified() { fVariantSelectionModified = false; } private: - void initializeItem(); + void initializeItem(bool isDefaultPrim); + const QPixmap* createPixmap(const char* pixmapURL) const; protected: // The USD Prim that the item represents in the TreeModel. UsdPrim fPrim; - // The type of this item. - Type fType; + // The column of this item. + Column fColumn; // For the LOAD column, the check state. CheckState fCheckState; @@ -117,10 +119,10 @@ class MAYAUSD_UI_PUBLIC TreeItem : public QStandardItem // Special flag set when the variant selection was modified. bool fVariantSelectionModified; - static QPixmap* fsCheckBoxOn; - static QPixmap* fsCheckBoxOnDisabled; - static QPixmap* fsCheckBoxOff; - static QPixmap* fsCheckBoxOffDisabled; + static const QPixmap* fsCheckBoxOn; + static const QPixmap* fsCheckBoxOnDisabled; + static const QPixmap* fsCheckBoxOff; + static const QPixmap* fsCheckBoxOffDisabled; }; } // namespace MAYAUSD_NS_DEF diff --git a/lib/usd/ui/importDialog/TreeModel.cpp b/lib/usd/ui/importDialog/TreeModel.cpp index 299265bbc3..54f98240d9 100644 --- a/lib/usd/ui/importDialog/TreeModel.cpp +++ b/lib/usd/ui/importDialog/TreeModel.cpp @@ -15,6 +15,8 @@ // #include "TreeModel.h" +#include "USDImportDialog.h" + #include #include #include @@ -30,12 +32,14 @@ namespace MAYAUSD_NS_DEF { namespace { -TreeItem* -findTreeItem(TreeModel* treeModel, const QModelIndex& parent, std::function fn) +TreeItem* findTreeItem( + const TreeModel* treeModel, + const QModelIndex& parent, + std::function fn) { for (int r = 0; r < treeModel->rowCount(parent); ++r) { // Note: only the load column (0) has children, so we use it when looking for children. - QModelIndex childIndex = treeModel->index(r, TreeModel::kTreeColumn_Load, parent); + QModelIndex childIndex = treeModel->index(r, TreeItem::kColumnLoad, parent); TreeItem* item = static_cast(treeModel->itemFromIndex(childIndex)); if (fn(item)) { return item; @@ -76,14 +80,14 @@ void resetVariantToPrimSelection(TreeItem* variantItem) void resetAllVariants(TreeModel* treeModel, const QModelIndex& parent) { for (int r = 0; r < treeModel->rowCount(parent); ++r) { - QModelIndex variantIndex = treeModel->index(r, TreeModel::kTreeColumn_Variants, parent); + QModelIndex variantIndex = treeModel->index(r, TreeItem::kColumnVariants, parent); TreeItem* variantItem = static_cast(treeModel->itemFromIndex(variantIndex)); if (nullptr != variantItem && variantItem->variantSelectionModified()) { resetVariantToPrimSelection(variantItem); } - QModelIndex childIndex = treeModel->index(r, TreeModel::kTreeColumn_Load, parent); + QModelIndex childIndex = treeModel->index(r, TreeItem::kColumnLoad, parent); if (treeModel->hasChildren(childIndex)) { resetAllVariants(treeModel, childIndex); } @@ -92,14 +96,22 @@ void resetAllVariants(TreeModel* treeModel, const QModelIndex& parent) } // namespace +const QPixmap* TreeModel::fsDefaultPrimImage = nullptr; + TreeModel::TreeModel( - const IMayaMQtUtil& mayaQtUtil, - const ImportData* importData /*= nullptr*/, - QObject* parent /*= nullptr*/) noexcept + const IMayaMQtUtil& mayaQtUtil, + const ImportData* importData, + const USDImportDialogOptions& options, + QObject* parent /*= nullptr*/) noexcept : ParentClass { parent } , fImportData { importData } , fMayaQtUtil { mayaQtUtil } + , fShowVariants(options.showVariants) + , fShowRoot(options.showRoot) { + if (!fsDefaultPrimImage) { + fsDefaultPrimImage = fMayaQtUtil.createPixmap(":/ImportDialog/defaultPrim.png"); + } } QVariant TreeModel::data(const QModelIndex& index, int role /*= Qt::DisplayRole*/) const @@ -109,7 +121,7 @@ QVariant TreeModel::data(const QModelIndex& index, int role /*= Qt::DisplayRole* TreeItem* item = static_cast(itemFromIndex(index)); - if ((role == Qt::DecorationRole) && (index.column() == kTreeColumn_Load)) + if ((role == Qt::DecorationRole) && (index.column() == TreeItem::kColumnLoad)) return item->checkImage(); return ParentClass::data(index, role); @@ -123,7 +135,7 @@ Qt::ItemFlags TreeModel::flags(const QModelIndex& index) const // The base class implementation returns a combination of flags that enables // the item (ItemIsEnabled) and allows it to be selected (ItemIsSelectable). Qt::ItemFlags flags = ParentClass::flags(index); - if (index.column() == kTreeColumn_Load) + if (index.column() == TreeItem::kColumnLoad) flags &= ~Qt::ItemIsSelectable; return flags; @@ -152,7 +164,7 @@ void TreeModel::setChildCheckState(const QModelIndex& parent, TreeItem::CheckSta int rMin = -1, rMax = -1; for (int r = 0; r < rowCount(parent); ++r) { // Note: only the load column (0) has children, so we use it when looking for children. - QModelIndex childIndex = this->index(r, kTreeColumn_Load, parent); + QModelIndex childIndex = this->index(r, TreeItem::kColumnLoad, parent); TreeItem* item = static_cast(itemFromIndex(childIndex)); // If child item state matches the input, no need to recurse. @@ -167,8 +179,8 @@ void TreeModel::setChildCheckState(const QModelIndex& parent, TreeItem::CheckSta setChildCheckState(childIndex, state); } } - QModelIndex rMinIndex = this->index(rMin, kTreeColumn_Load, parent); - QModelIndex rMaxIndex = this->index(rMax, kTreeColumn_Load, parent); + QModelIndex rMinIndex = this->index(rMin, TreeItem::kColumnLoad, parent); + QModelIndex rMaxIndex = this->index(rMax, TreeItem::kColumnLoad, parent); QVector roles; roles << Qt::DecorationRole; Q_EMIT dataChanged(rMinIndex, rMaxIndex, roles); @@ -192,7 +204,7 @@ void TreeModel::fillStagePopulationMask(UsdStagePopulationMask& popMask, const Q { for (int r = 0; r < rowCount(parent); ++r) { // Note: only the load column (0) has children, so we use it when looking for children. - QModelIndex childIndex = this->index(r, kTreeColumn_Load, parent); + QModelIndex childIndex = this->index(r, TreeItem::kColumnLoad, parent); TreeItem* item = static_cast(itemFromIndex(childIndex)); if (item->checkState() == TreeItem::CheckState::kChecked) { auto primPath = item->prim().GetPath(); @@ -212,8 +224,11 @@ void TreeModel::fillPrimVariantSelections( ImportData::PrimVariantSelections& primVariantSelections, const QModelIndex& parent) { + if (!fShowVariants) + return; + for (int r = 0; r < rowCount(parent); ++r) { - QModelIndex variantIndex = this->index(r, kTreeColumn_Variants, parent); + QModelIndex variantIndex = this->index(r, TreeItem::kColumnVariants, parent); TreeItem* item = static_cast(itemFromIndex(variantIndex)); if (item->variantSelectionModified()) { // Note: both the variant name and variant selection roles contain a @@ -236,7 +251,7 @@ void TreeModel::fillPrimVariantSelections( } // Note: only the load column (0) has children, so we use it when looking for children. - QModelIndex childIndex = this->index(r, kTreeColumn_Load, parent); + QModelIndex childIndex = this->index(r, TreeItem::kColumnLoad, parent); if (hasChildren(childIndex)) { fillPrimVariantSelections(primVariantSelections, childIndex); } @@ -245,8 +260,11 @@ void TreeModel::fillPrimVariantSelections( void TreeModel::openPersistentEditors(QTreeView* tv, const QModelIndex& parent) { + if (!fShowVariants) + return; + for (int r = 0; r < rowCount(parent); ++r) { - QModelIndex varSelIndex = this->index(r, kTreeColumn_Variants, parent); + QModelIndex varSelIndex = this->index(r, TreeItem::kColumnVariants, parent); int type = varSelIndex.data(ItemDelegate::kTypeRole).toInt(); if (type == ItemDelegate::kVariants) { QSortFilterProxyModel* proxyModel = qobject_cast(tv->model()); @@ -254,7 +272,7 @@ void TreeModel::openPersistentEditors(QTreeView* tv, const QModelIndex& parent) } // Note: only the load column (0) has children, so we use it when looking for children. - QModelIndex childIndex = this->index(r, kTreeColumn_Load, parent); + QModelIndex childIndex = this->index(r, TreeItem::kColumnLoad, parent); if (hasChildren(childIndex)) { openPersistentEditors(tv, childIndex); } @@ -308,6 +326,27 @@ void TreeModel::checkEnableItem(TreeItem* item) } } +TreeItem* TreeModel::findPathItem(const PXR_NS::SdfPath& path) const +{ + auto fnFindRoot = [path](TreeItem* item) -> bool { + if (item->prim().GetPath() == path) + return true; + return false; + }; + return findTreeItem(this, QModelIndex(), fnFindRoot); +} + +TreeItem* TreeModel::findPrimItem(const UsdPrim& prim) const +{ + return findPathItem(prim.GetPath()); +} + +TreeItem* TreeModel::getFirstItem() const +{ + QModelIndex childIndex = index(0, TreeItem::kColumnLoad, QModelIndex()); + return static_cast(itemFromIndex(childIndex)); +} + void TreeModel::updateCheckedItemCount() const { int nbChecked = 0, nbVariantsModified = 0; @@ -327,7 +366,7 @@ void TreeModel::countCheckedItems( for (int r = 0; r < rowCount(parent); ++r) { TreeItem* item; - QModelIndex checkedChildIndex = this->index(r, kTreeColumn_Load, parent); + QModelIndex checkedChildIndex = this->index(r, TreeItem::kColumnLoad, parent); item = static_cast(itemFromIndex(checkedChildIndex)); const TreeItem::CheckState state = item->checkState(); @@ -335,12 +374,14 @@ void TreeModel::countCheckedItems( || TreeItem::CheckState::kChecked_Disabled == state) { nbChecked++; - // We are only counting modified variants of in-scope prims - QModelIndex variantChildIndex = this->index(r, kTreeColumn_Variants, parent); - item = static_cast(itemFromIndex(variantChildIndex)); + if (fShowVariants) { + // We are only counting modified variants of in-scope prims + QModelIndex variantChildIndex = this->index(r, TreeItem::kColumnVariants, parent); + item = static_cast(itemFromIndex(variantChildIndex)); - if (item->variantSelectionModified()) { - nbVariantsModified++; + if (item->variantSelectionModified()) { + nbVariantsModified++; + } } } @@ -359,7 +400,7 @@ void TreeModel::updateModifiedVariantCount() const void TreeModel::onItemClicked(TreeItem* item) { - if (item->index().column() == kTreeColumn_Load) { + if (item->index().column() == TreeItem::kColumnLoad) { // We only allow toggling an enabled checked or unchecked item. TreeItem::CheckState st = item->checkState(); if (st == TreeItem::CheckState::kChecked) { @@ -370,6 +411,15 @@ void TreeModel::onItemClicked(TreeItem* item) } } -void TreeModel::resetVariants() { resetAllVariants(this, QModelIndex()); } +void TreeModel::resetVariants() +{ + if (!fShowVariants) + return; + + resetAllVariants(this, QModelIndex()); +} + +/*static*/ +const QPixmap* TreeModel::getDefaultPrimPixmap() { return fsDefaultPrimImage; } } // namespace MAYAUSD_NS_DEF diff --git a/lib/usd/ui/importDialog/TreeModel.h b/lib/usd/ui/importDialog/TreeModel.h index 6a913751cd..b2ffd8d48e 100644 --- a/lib/usd/ui/importDialog/TreeModel.h +++ b/lib/usd/ui/importDialog/TreeModel.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -33,6 +34,7 @@ PXR_NAMESPACE_USING_DIRECTIVE namespace MAYAUSD_NS_DEF { class IMayaMQtUtil; +struct USDImportDialogOptions; /** * \brief Qt Model to explore the hierarchy of a USD file. @@ -51,27 +53,15 @@ class MAYAUSD_UI_PUBLIC TreeModel : public QStandardItemModel * \param parent A reference to the parent of the TreeModel. */ explicit TreeModel( - const IMayaMQtUtil& mayaQtUtil, - const ImportData* importData = nullptr, - QObject* parent = nullptr) noexcept; + const IMayaMQtUtil& mayaQtUtil, + const ImportData* importData, + const USDImportDialogOptions& options, + QObject* parent = nullptr) noexcept; // QStandardItemModel overrides QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; - /** - * \brief Order of the columns as they appear in the Tree. - * \remarks The order of the enumeration is important. - */ - enum TREE_COLUMNS - { - kTreeColumn_Load, // Should we load this prim? - kTreeColumn_Name, // Name of the item as it appears in the TreeView. - kTreeColumn_Type, // Type of the primitive. - kTreeColumn_Variants, // Variant Set(s) and Variant Selection of the primitive. - kTreeColumn_Last // Last element of the enum. - }; - void setRootPrimPath(const std::string& path); void getRootPrimPath(std::string&, const QModelIndex& parent); void fillStagePopulationMask(UsdStagePopulationMask& popMask, const QModelIndex& parent); @@ -87,10 +77,16 @@ class MAYAUSD_UI_PUBLIC TreeModel : public QStandardItemModel void resetVariants(); -private: void uncheckEnableTree(); void checkEnableItem(TreeItem* item); + TreeItem* findPrimItem(const PXR_NS::UsdPrim& prim) const; + TreeItem* findPathItem(const PXR_NS::SdfPath& path) const; + TreeItem* getFirstItem() const; + + static const QPixmap* getDefaultPrimPixmap(); + +private: void updateCheckedItemCount() const; void countCheckedItems(const QModelIndex& parent, int& nbChecked, int& nbVariantsModified) const; @@ -111,6 +107,13 @@ public Q_SLOTS: // Special interface we can use to perform Maya Qt utilities (such as Pixmap loading). const IMayaMQtUtil& fMayaQtUtil; + + bool fShowVariants; + bool fShowRoot; + + // Need to be in the tree model becasue we need to create it before + // the tree item have their model set. + static const QPixmap* fsDefaultPrimImage; }; } // namespace MAYAUSD_NS_DEF diff --git a/lib/usd/ui/importDialog/TreeModelFactory.cpp b/lib/usd/ui/importDialog/TreeModelFactory.cpp index ed1f3291e6..1e5e5b4b1b 100644 --- a/lib/usd/ui/importDialog/TreeModelFactory.cpp +++ b/lib/usd/ui/importDialog/TreeModelFactory.cpp @@ -15,6 +15,8 @@ // #include "TreeModelFactory.h" +#include "USDImportDialog.h" + #include #include #include @@ -40,72 +42,112 @@ static_assert( /*static*/ std::unique_ptr TreeModelFactory::createEmptyTreeModel( - const IMayaMQtUtil& mayaQtUtil, - const ImportData* importData /*= nullptr*/, - QObject* parent /*= nullptr*/) + const IMayaMQtUtil& mayaQtUtil, + const ImportData* importData, + const USDImportDialogOptions& options, + QObject* parent /*= nullptr*/) { - std::unique_ptr treeModel(new TreeModel(mayaQtUtil, importData, parent)); - treeModel->setHorizontalHeaderLabels({ QObject::tr(""), - QObject::tr("Prim Name"), - QObject::tr("Prim Type"), - QObject::tr("Variant Set and Variant") }); + std::unique_ptr treeModel(new TreeModel(mayaQtUtil, importData, options, parent)); + + QStringList headerLabels({ QObject::tr(""), QObject::tr("Name"), QObject::tr("Type") }); + if (options.showVariants) + headerLabels.append(QObject::tr("Variant Set and Variant")); + + treeModel->setHorizontalHeaderLabels(headerLabels); return treeModel; -} +} // namespace MAYAUSD_NS_DEF /*static*/ std::unique_ptr TreeModelFactory::createFromStage( - const UsdStageRefPtr& stage, - const IMayaMQtUtil& mayaQtUtil, - const ImportData* importData /*= nullptr*/, - QObject* parent, - int* nbItems /*= nullptr*/ + const UsdStageRefPtr& stage, + const IMayaMQtUtil& mayaQtUtil, + const ImportData* importData, + const USDImportDialogOptions& options, + QObject* parent, + int* nbItems /*= nullptr*/ ) { - std::unique_ptr treeModel = createEmptyTreeModel(mayaQtUtil, importData, parent); - int cnt = buildTreeHierarchy(stage->GetPseudoRoot(), treeModel->invisibleRootItem()); + std::unique_ptr treeModel + = createEmptyTreeModel(mayaQtUtil, importData, options, parent); + + UsdPrim rootPrim = stage->GetPseudoRoot(); + UsdPrim defPrim = stage->GetDefaultPrim(); + + const int cnt = options.showRoot + ? buildTreeHierarchy(rootPrim, defPrim, treeModel->invisibleRootItem(), options) + : buildTreeChildren(rootPrim, defPrim, treeModel->invisibleRootItem(), options); + if (nbItems != nullptr) *nbItems = cnt; + + TreeItem* item = treeModel->findPrimItem(defPrim); + if (!item) + item = treeModel->getFirstItem(); + if (item) + treeModel->checkEnableItem(item); + return treeModel; } /*static*/ -QList TreeModelFactory::createPrimRow(const UsdPrim& prim) +QList TreeModelFactory::createPrimRow( + const UsdPrim& prim, + const UsdPrim& defaultPrim, + const USDImportDialogOptions& options) { + const bool isDefaultPrim = (prim == defaultPrim); // Cache the values to be displayed, in order to avoid querying the USD Prim too frequently // (despite it being cached and optimized for frequent access). Avoiding frequent conversions // from USD Strings to Qt Strings helps in keeping memory allocations low. - QList ret = { new TreeItem(prim, TreeItem::Type::kLoad), - new TreeItem(prim, TreeItem::Type::kName), - new TreeItem(prim, TreeItem::Type::kType), - new TreeItem(prim, TreeItem::Type::kVariants) }; + QList ret = { new TreeItem(prim, isDefaultPrim, TreeItem::kColumnLoad), + new TreeItem(prim, isDefaultPrim, TreeItem::kColumnName), + new TreeItem(prim, isDefaultPrim, TreeItem::kColumnType) }; + + if (options.showVariants) { + ret.append(new TreeItem(prim, isDefaultPrim, TreeItem::kColumnVariants)); + } return ret; } /*static*/ -int TreeModelFactory::buildTreeHierarchy(const UsdPrim& prim, QStandardItem* parentItem) +int TreeModelFactory::buildTreeHierarchy( + const UsdPrim& prim, + const UsdPrim& defaultPrim, + QStandardItem* parentItem, + const USDImportDialogOptions& options) { - QList primDataCells = createPrimRow(prim); + QList primDataCells = createPrimRow(prim, defaultPrim, options); parentItem->appendRow(primDataCells); - int cnt = 1; + return 1 + buildTreeChildren(prim, defaultPrim, primDataCells.front(), options); +} - for (const auto& childPrim : prim.GetAllChildren()) { - cnt += buildTreeHierarchy(childPrim, primDataCells.front()); - } +/*static*/ +int TreeModelFactory::buildTreeChildren( + const UsdPrim& prim, + const UsdPrim& defaultPrim, + QStandardItem* parentItem, + const USDImportDialogOptions& options) +{ + int cnt = 0; + for (const auto& childPrim : prim.GetAllChildren()) + cnt += buildTreeHierarchy(childPrim, defaultPrim, parentItem, options); return cnt; } /*static*/ int TreeModelFactory::buildTreeHierarchy( - const UsdPrim& prim, - QStandardItem* parentItem, - const unordered_sdfpath_set& primsToIncludeInTree, - size_t& insertionsRemaining) + const UsdPrim& prim, + const UsdPrim& defaultPrim, + QStandardItem* parentItem, + const USDImportDialogOptions& options, + const unordered_sdfpath_set& primsToIncludeInTree, + size_t& insertionsRemaining) { int cnt = 0; bool primShouldBeIncluded = primsToIncludeInTree.find(prim.GetPath()) != primsToIncludeInTree.end(); if (primShouldBeIncluded) { - QList primDataCells = createPrimRow(prim); + QList primDataCells = createPrimRow(prim, defaultPrim, options); parentItem->appendRow(primDataCells); ++cnt; @@ -114,7 +156,12 @@ int TreeModelFactory::buildTreeHierarchy( if (--insertionsRemaining > 0) { for (const auto& childPrim : prim.GetAllChildren()) { cnt += buildTreeHierarchy( - childPrim, primDataCells.front(), primsToIncludeInTree, insertionsRemaining); + childPrim, + defaultPrim, + primDataCells.front(), + options, + primsToIncludeInTree, + insertionsRemaining); } } } diff --git a/lib/usd/ui/importDialog/TreeModelFactory.h b/lib/usd/ui/importDialog/TreeModelFactory.h index 29745860f0..b523877fed 100644 --- a/lib/usd/ui/importDialog/TreeModelFactory.h +++ b/lib/usd/ui/importDialog/TreeModelFactory.h @@ -38,6 +38,7 @@ namespace MAYAUSD_NS_DEF { class IMayaMQtUtil; class TreeModel; class ImportData; +struct USDImportDialogOptions; /** * \brief Factory to create a tree-like structure of USD content suitable to be displayed in a @@ -58,9 +59,10 @@ class MAYAUSD_UI_PUBLIC TreeModelFactory * \return An empty TreeModel. */ static std::unique_ptr createEmptyTreeModel( - const IMayaMQtUtil& mayaQtUtil, - const ImportData* importData = nullptr, - QObject* parent = nullptr); + const IMayaMQtUtil& mayaQtUtil, + const ImportData* importData, + const USDImportDialogOptions& options, + QObject* parent = nullptr); /** * \brief Create a TreeModel from the given USD Stage. @@ -70,11 +72,12 @@ class MAYAUSD_UI_PUBLIC TreeModelFactory * \return A TreeModel created from the given USD Stage. */ static std::unique_ptr createFromStage( - const UsdStageRefPtr& stage, - const IMayaMQtUtil& mayaQtUtil, - const ImportData* importData = nullptr, - QObject* parent = nullptr, - int* nbItems = nullptr); + const UsdStageRefPtr& stage, + const IMayaMQtUtil& mayaQtUtil, + const ImportData* importData, + const USDImportDialogOptions& options, + QObject* parent = nullptr, + int* nbItems = nullptr); protected: // Type definition for an STL unordered set of SDF Paths: @@ -85,7 +88,10 @@ class MAYAUSD_UI_PUBLIC TreeModelFactory * \param prim The USD Prim for which to create the list of data cells. * \return The List of data cells used to represent the given USD Prim's data in the tree. */ - static QList createPrimRow(const UsdPrim& prim); + static QList createPrimRow( + const UsdPrim& prim, + const UsdPrim& defaultPrim, + const USDImportDialogOptions& options); /** * \brief Build the tree hierarchy starting at the given USD Prim. @@ -93,7 +99,24 @@ class MAYAUSD_UI_PUBLIC TreeModelFactory * \param parentItem The parent into which to attach the tree hierarchy. * \return The number of items added. */ - static int buildTreeHierarchy(const UsdPrim& prim, QStandardItem* parentItem); + static int buildTreeHierarchy( + const UsdPrim& prim, + const UsdPrim& defaultPrim, + QStandardItem* parentItem, + const USDImportDialogOptions& options); + + /** + * \brief Build the tree hierarchy for teh chidlren of the given USD Prim. + * \param prim The USD Prim from which to extract the children. + * \param parentItem The parent into which to attach the tree hierarchy. + * \return The number of items added. + */ + static int buildTreeChildren( + const UsdPrim& prim, + const UsdPrim& defaultPrim, + QStandardItem* parentItem, + const USDImportDialogOptions& options); + /** * \brief Build the tree hierarchy starting at the given USD Prim. * \param prim The USD Prim from which to start building the tree hierarchy. @@ -103,10 +126,12 @@ class MAYAUSD_UI_PUBLIC TreeModelFactory * \return The number of items added. */ static int buildTreeHierarchy( - const UsdPrim& prim, - QStandardItem* parentItem, - const unordered_sdfpath_set& primsToIncludeInTree, - size_t& insertionsRemaining); + const UsdPrim& prim, + const UsdPrim& defaultPrim, + QStandardItem* parentItem, + const USDImportDialogOptions& options, + const unordered_sdfpath_set& primsToIncludeInTree, + size_t& insertionsRemaining); }; } // namespace MAYAUSD_NS_DEF diff --git a/lib/usd/ui/importDialog/USDImportDialog.cpp b/lib/usd/ui/importDialog/USDImportDialog.cpp index 34c77f6d38..d09d2cedf9 100644 --- a/lib/usd/ui/importDialog/USDImportDialog.cpp +++ b/lib/usd/ui/importDialog/USDImportDialog.cpp @@ -31,11 +31,13 @@ namespace MAYAUSD_NS_DEF { IUSDImportView::~IUSDImportView() { } USDImportDialog::USDImportDialog( - const std::string& filename, - const ImportData* importData, - const IMayaMQtUtil& mayaQtUtil, - QWidget* parent /*= nullptr*/) + const std::string& filename, + const ImportData* importData, + const USDImportDialogOptions& options, + const IMayaMQtUtil& mayaQtUtil, + QWidget* parent /*= nullptr*/) : QDialog { parent } + , fOptions(options) , fUI { new Ui::ImportDialog() } , fStage { UsdStage::Open(filename, UsdStage::InitialLoadSet::LoadAll) } , fFilename { filename } @@ -45,12 +47,14 @@ USDImportDialog::USDImportDialog( throw std::invalid_argument("Invalid filename passed to USD Import Dialog"); fUI->setupUi(this); + applyOptions(); // If we were given some import data we will only use it if it matches our // input filename. In the case where the user opened dialog, clicked Apply and // then reopens the dialog we want to reset the dialog to the previous state. const ImportData* matchingImportData = nullptr; - if ((importData != nullptr) && (fFilename == importData->filename())) { + if ((importData != nullptr) && (fFilename == importData->filename()) + && importData->rootPrimPath().size() > 0) { fRootPrimPath = importData->rootPrimPath(); matchingImportData = importData; } @@ -66,8 +70,8 @@ USDImportDialog::USDImportDialog( // These calls must come after the UI is initialized via "setupUi()": int nbItems = 0; - fTreeModel - = TreeModelFactory::createFromStage(fStage, mayaQtUtil, matchingImportData, this, &nbItems); + fTreeModel = TreeModelFactory::createFromStage( + fStage, mayaQtUtil, matchingImportData, fOptions, this, &nbItems); fProxyModel = std::unique_ptr(new QSortFilterProxyModel(this)); QObject::connect( fTreeModel.get(), SIGNAL(checkedStateChanged(int)), this, SLOT(onCheckedStateChanged(int))); @@ -88,7 +92,7 @@ USDImportDialog::USDImportDialog( fProxyModel->setDynamicSortFilter(false); fProxyModel->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); fUI->treeView->setModel(fProxyModel.get()); - fUI->treeView->setTreePosition(TreeModel::kTreeColumn_Name); + fUI->treeView->setTreePosition(TreeItem::kColumnName); fUI->treeView->setAlternatingRowColors(true); fUI->treeView->setSelectionMode(QAbstractItemView::SingleSelection); QObject::connect( @@ -133,9 +137,11 @@ USDImportDialog::USDImportDialog( constexpr int kTypeWidth = 120; constexpr int kNameWidth = 500; header->setMinimumSectionSize(kLoadWidth); - header->resizeSection(TreeModel::kTreeColumn_Load, kLoadWidth); - header->resizeSection(TreeModel::kTreeColumn_Name, kNameWidth); - header->resizeSection(TreeModel::kTreeColumn_Type, kTypeWidth); + header->resizeSection(TreeItem::kColumnLoad, kLoadWidth); + header->resizeSection(TreeItem::kColumnName, kNameWidth); + if (fOptions.showVariants) { + header->resizeSection(TreeItem::kColumnType, kTypeWidth); + } header->setSectionResizeMode(0, QHeaderView::Fixed); // Display the full path of the file to import: @@ -145,6 +151,23 @@ USDImportDialog::USDImportDialog( fUI->applyButton->setEnabled(true); } +void USDImportDialog::applyOptions() +{ + if (fOptions.title.size() > 0) { + setWindowTitle(fOptions.title.c_str()); + } + + if (fOptions.helpLabel.size() > 0) { + fUI->actionHelp_on_Hierarchy_View->setText( + QCoreApplication::translate("ImportDialog", fOptions.helpLabel.c_str(), nullptr)); + } + + fUI->nbVariantsChanged->setVisible(fOptions.showVariants); + fUI->nbVariantsChangedLabel->setVisible(fOptions.showVariants); + + fUI->selectPrims->setVisible(fOptions.showHeaderMessage); +} + USDImportDialog::~USDImportDialog() { // Note: the destructor is needed here so we can forward declare the Ui::ImportDialog @@ -218,8 +241,10 @@ void USDImportDialog::onResetFileTriggered() void USDImportDialog::onHierarchyViewHelpTriggered() { - MGlobal::executePythonCommand( - "from mayaUsdUtils import showHelpMayaUSD; showHelpMayaUSD(\"UsdHierarchyView\");"); + MString url = fOptions.helpURL.size() > 0 ? fOptions.helpURL.c_str() : "UsdHierarchyView"; + MString cmd; + cmd.format("from mayaUsdUtils import showHelpMayaUSD; showHelpMayaUSD('^1s');", url); + MGlobal::executePythonCommand(cmd); } void USDImportDialog::onCheckedStateChanged(int nbChecked) diff --git a/lib/usd/ui/importDialog/USDImportDialog.h b/lib/usd/ui/importDialog/USDImportDialog.h index 18bca6e95e..777cf13285 100644 --- a/lib/usd/ui/importDialog/USDImportDialog.h +++ b/lib/usd/ui/importDialog/USDImportDialog.h @@ -40,6 +40,19 @@ namespace MAYAUSD_NS_DEF { class IMayaMQtUtil; +/** + * \brief Options for the USD file import dialog. + */ +struct MAYAUSD_UI_PUBLIC USDImportDialogOptions +{ + std::string title; + std::string helpLabel; + std::string helpURL; + bool showVariants = true; + bool showRoot = true; + bool showHeaderMessage = true; +}; + /** * \brief USD file import dialog. */ @@ -56,10 +69,11 @@ class MAYAUSD_UI_PUBLIC USDImportDialog * \param parent A reference to the parent widget of the dialog. */ explicit USDImportDialog( - const std::string& filename, - const ImportData* importData, - const IMayaMQtUtil& mayaQtUtil, - QWidget* parent = nullptr); + const std::string& filename, + const ImportData* importData, + const USDImportDialogOptions& options, + const IMayaMQtUtil& mayaQtUtil, + QWidget* parent = nullptr); //! Destructor. ~USDImportDialog(); @@ -83,6 +97,11 @@ private Q_SLOTS: void onModifiedVariantsChanged(int); protected: + void applyOptions(); + + // The options for the dialog. + USDImportDialogOptions fOptions; + // Reference to the Qt UI View of the dialog: std::unique_ptr fUI; diff --git a/lib/usd/ui/importDialog/USDImportDialog.ui b/lib/usd/ui/importDialog/USDImportDialog.ui index 8ab6bc64dd..85f5298460 100644 --- a/lib/usd/ui/importDialog/USDImportDialog.ui +++ b/lib/usd/ui/importDialog/USDImportDialog.ui @@ -102,7 +102,7 @@ true - Apply + OK @@ -146,7 +146,7 @@ - Total Number of Prims in Scope: + Prims in selected scope: @@ -200,9 +200,9 @@ - + - Variants Switched in Scope: + Variants switched in selected scope: diff --git a/lib/usd/ui/importDialog/USDImportDialogCmd.cpp b/lib/usd/ui/importDialog/USDImportDialogCmd.cpp index 87d698fb8e..300f6b4d5d 100644 --- a/lib/usd/ui/importDialog/USDImportDialogCmd.cpp +++ b/lib/usd/ui/importDialog/USDImportDialogCmd.cpp @@ -62,6 +62,17 @@ constexpr auto kPrimCountFlagLong = "-primCount"; constexpr auto kSwitchedVariantCountFlag = "-swc"; constexpr auto kSwitchedVariantCountFlagLong = "-switchedVariantCount"; +constexpr auto kHideRoot = "-hr"; +constexpr auto kHideRootLong = "-hideRoot"; +constexpr auto kHideVariantsFlag = "-hv"; +constexpr auto kHideVariantsFlagLong = "-hideVariants"; +constexpr auto kWindowTitleFlag = "-ti"; +constexpr auto kWindowTitleFlagLong = "-title"; +constexpr auto kHelpLabelFlag = "-hl"; +constexpr auto kHelpLabelFlagLong = "-helpLabel"; +constexpr auto kHelpTokenFlag = "-ht"; +constexpr auto kHelpTokenFlagLong = "-helpToken"; + constexpr auto kParentWindowFlag = "-pw"; constexpr auto kParentWindowFlagLong = "-parentWindow"; @@ -160,6 +171,31 @@ MStatus USDImportDialogCmd::applyToProxy(const MString& proxyPath) return MS::kSuccess; } +static MString getStringArg(const MArgParser& argData, MStatus& status) +{ + MStringArray array; + status = argData.getObjects(array); + if (!status) + return {}; + + if (array.length() != 1) { + status = MS::kInvalidParameter; + return {}; + } + + return array[0].asChar(); +} + +static MString getStringFlagArg(const MArgParser& argData, const char* flag) +{ + if (!argData.isFlagSet(flag)) + return {}; + + MString value; + argData.getFlagArgument(flag, 0, value); + return value; +} + MStatus USDImportDialogCmd::doIt(const MArgList& args) { MStatus st; @@ -199,28 +235,26 @@ MStatus USDImportDialogCmd::doIt(const MArgList& args) // No command object is expected if (argData.isFlagSet(kApplyToProxyFlag)) { - MStringArray proxyArray; - st = argData.getObjects(proxyArray); - if (!st || proxyArray.length() != 1) - return MS::kInvalidParameter; + MString proxy = getStringArg(argData, st); + if (!st) + return st; - return applyToProxy(proxyArray[0]); + return applyToProxy(proxy); } - MStringArray filenameArray; - st = argData.getObjects(filenameArray); - if (st && (filenameArray.length() > 0)) { + const MString filename = getStringArg(argData, st); + if (st) { // We only use the first one. MFileObject fo; MString assetPath; - fo.setRawFullName(filenameArray[0]); + fo.setRawFullName(filename); bool validTarget = fo.exists(); if (!validTarget) { // Give the default usd-asset-resolver a chance - if (const char* cStr = filenameArray[0].asChar()) { + if (const char* cStr = filename.asChar()) { validTarget = !ArGetResolver().Resolve(cStr).empty(); if (validTarget) - assetPath = filenameArray[0]; + assetPath = filename; } } else assetPath = fo.resolvedFullName(); @@ -229,6 +263,15 @@ MStatus USDImportDialogCmd::doIt(const MArgList& args) USDQtUtil usdQtUtil; ImportData& importData = ImportData::instance(); + if (argData.isFlagSet(kPrimPathFlag)) { + ImportData& importData = ImportData::instance(); + importData.setFilename(filename.asChar()); + // Note: must be done after setting the filename because setting + // the filename clears the data. + const MString primPath = getStringFlagArg(argData, kPrimPathFlag); + importData.setRootPrimPath(primPath.asChar()); + } + // Creating the View can pause Maya, usually only briefly but it's noticable, so we'll // toggle the wait cursor to show that it's working. QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); @@ -236,8 +279,16 @@ MStatus USDImportDialogCmd::doIt(const MArgList& args) const MString parentWindowName = parseTextArg(argData, kParentWindowFlag, ""); QWidget* parentWindow = findParentWindow(parentWindowName); - std::unique_ptr usdImportDialog( - new USDImportDialog(assetPath.asChar(), &importData, usdQtUtil, parentWindow)); + USDImportDialogOptions options; + options.title = getStringFlagArg(argData, kWindowTitleFlag).asChar(); + options.helpLabel = getStringFlagArg(argData, kHelpLabelFlag).asChar(); + options.helpURL = getStringFlagArg(argData, kHelpTokenFlag).asChar(); + options.showHeaderMessage = !argData.isFlagSet(kHideRoot); + options.showRoot = !argData.isFlagSet(kHideRoot); + options.showVariants = !argData.isFlagSet(kHideVariantsFlag); + + std::unique_ptr usdImportDialog(new USDImportDialog( + assetPath.asChar(), &importData, options, usdQtUtil, parentWindow)); QApplication::restoreOverrideCursor(); @@ -269,13 +320,19 @@ MSyntax USDImportDialogCmd::createSyntax() MSyntax syntax; syntax.enableQuery(true); syntax.enableEdit(false); - syntax.addFlag(kPrimPathFlag, kPrimPathFlagLong); + syntax.addFlag(kPrimPathFlag, kPrimPathFlagLong, MSyntax::kString); syntax.addFlag(kClearDataFlag, kClearDataFlagLong); syntax.addFlag(kApplyToProxyFlag, kApplyToProxyFlagLong); syntax.addFlag(kPrimCountFlag, kPrimCountFlagLong); syntax.addFlag(kSwitchedVariantCountFlag, kSwitchedVariantCountFlagLong); syntax.addFlag(kParentWindowFlag, kParentWindowFlagLong, MSyntax::kString); + syntax.addFlag(kHideRoot, kHideRootLong); + syntax.addFlag(kHideVariantsFlag, kHideVariantsFlagLong); + syntax.addFlag(kWindowTitleFlag, kWindowTitleFlagLong, MSyntax::kString); + syntax.addFlag(kHelpLabelFlag, kHelpLabelFlagLong, MSyntax::kString); + syntax.addFlag(kHelpTokenFlag, kHelpTokenFlagLong, MSyntax::kString); + syntax.setObjectType(MSyntax::kStringObjects, 0, 1); return syntax; } diff --git a/lib/usd/ui/importDialog/images/defaultPrim_100.png b/lib/usd/ui/importDialog/images/defaultPrim_100.png new file mode 100644 index 0000000000000000000000000000000000000000..b0219157ffa2343b2d9a3aae2eccd15df9cd38e3 GIT binary patch literal 1514 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1%F9IK~z{r?U-9g zRaqFvKQ;53cf6pcqM{Oo&UmGAl2J_2m%O7=Ow%YvB7!1_sZTx#Gt7h!b5S2e#0No9 z5ig^Sj8Kv`qLo+1vWJuiO3Q0H>;Ij-5BqG-k<2ETrXPIlwZ6U2*=zszxBhFLV?-)0 zT(}S{4&RCRT7-`XQxX4nwnh9c;&&0h+`fJLFC=BOA`0;=#Nh`K5OANkpV6`>;#Uzx zLdX_ zCv|jmNZAjEr>CdX`Y=3v_>gYgxIs%xOH$^&fNpsv-rnBdi-seo1pfa1l$x4K=g*&K zQG9)UX?%Q~mY0|Ld~|d)B_t$JNJt1-Sy|DOCr>zk_3Bk}a&lrZJv=;UdU~4T;^HVd zIhnsp+=sv8_3PJseRXv;ZEtUD9|C=McXyhcoaCt%6cj`~J+Nt_!ooswaBv_?OG`R+ z>J;6-f1mR*un$a4jOWs&OMDIP_3G6t{!Dp!Ih{Chf?{G~=KqfM00a< zd|h#IF@=SN@n_@X<9RHLi;I+zkwHmGNj(0Ag#{k73L8`+wlP{RU%t!_vAViSQBhG+ zRzrArIHjef@mrjknW6ObbP5d(<#Q`5D}2O&&^9wO<8u&Ybaa#lk(-;#*8qsJwY4Sn zG<`$N&d%}?FW~9Zr`%Qp3vhOJrm?Xxa&vRzLXg2ZJPXGB_U&7G^ym@iZES4#2w+_( zpv}!qnwpxTbLY%ki$YE1!yfd93%wNZV2J+-v7NM|&_@COD4 zXn1&-0~LWU2SYTot}dFG znBb~wY;0tE!gHax^k6El&WwE1`T2Q1qI{L0#A9P)>DH}V9GKErkqwcPlS3616;xYW ztE~(pBmMTfv$G?$G$JbdGD^|aynOjm`xywJMz)cIc=6(e)FN72TcbB`-bg*7XV0FI zxw*O2(*+`GC;7(41|Q{%;c-fE6I2!qS&o}GZ%Su%fxloiZD?qql9Cc?ZEcm#Xu!0B zU&$z|59bhv0jsTydfY%c0}P>Fso|YUU{QM5hKTq%!$56-g#gA54^)E10y%7B;4_(- znRNQ}Y3Zyk@ECxF2I1%D$9)<2CVVO|Fpv!&MlXYxg#p9l0R%=>z&c!9TsWr&4}9gy z6`m~^AD-o1s!xehM0}t83;^3K125t+MAVp>0Mn(ryPNk<1qB7XqABU`@8_w4b5&JU zyzM~Q>*Ma-yKK;Td3jV>S*c^<03L-(yng*Ui>35Lye#-_ety2zbK#2+JS!`U`})A* zR905TB4VtE1wzR{L}eu!s6sGgBsPm7qA?~y$E@&xc>7Ra-_*ieQu`Kegat(j-mac) zffiVYY$Iy$Q0hfSUk+OwY`b7DnAYp-{FC-$0Fw?g7AqDuUB7Wkfo!UVyh)$&s|5rH z2?z`c2-IQ$eK{o`Q9#fj^c$1ww@AdFn&y8K<;wbzfL?`YXs584)>tZk67h|QBmWHi zguxVU5K$X)$9*e*t{4=I7k{XEq0nscN*A>`L QjsO4v07*qoM6N<$g4>J7?EnA( literal 0 HcmV?d00001 diff --git a/lib/usd/ui/importDialog/images/defaultPrim_150.png b/lib/usd/ui/importDialog/images/defaultPrim_150.png new file mode 100644 index 0000000000000000000000000000000000000000..4c56464a3854e7b9502729bc6eb6c41c7eef3e40 GIT binary patch literal 2277 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2zp6GK~!i%?VD*# zRaX$l2M||qLE^p#+~Wck^@B)_D_9evv9=$u5{yM-G_j@{H8E}x8%?7hY@()0jMW(9 zQovmnH3EWl#Rbr~#f_rIeee0tz4N$S?tSk;c@)z3OD5;s^B#9OGiT1s+=majASx=# zS2dAJVw4O~5~?IviJuZLHP0s{B}xjF@maOD*eY5n7>fKs$pR%I81qtV zDN>T8jT=*FXehU5&YaOlJwwl)cs!zO*RF9}8wd^#rcRwYasS-8bKF)VSlNS>vI}s4 zh*|&VDRnl)<{4H<$UylM;^HjI*zk|-e|fhJ9wq>p-rz`#JhUx=Cd_3N|v z`tnrND1G|$p=r~mQEY6iK2og&C`nejt%n17Iz-ns7I^vj`O)OblevHD)G6A#cQ5z< z3*zG9Xzkjyo|gw(+QrKL zKa!c5Npt7Ur6o(2=p!ECXXsdpAx`t;MvWTrUV=RZz|}dUb?esDy?b|R)vA>~Vhzq~ z1q=zs5E2sNxTYDnV_XMf#%{biz%$8n1q1|ejDgk)<99J<_-@OVE%{hz-@ZMI5#!%A zY}k{$JX=>Gltyq~pg+m=q8I8n~+ z1_cGt)TvXcTQ{6rqo}BecI?C>mvqeqWu#flX?2BTQDY8Cfq&z{XK zSh#Q@wQJW-Khj7|O{GJJ4(UhbfkGB6(41d>em;eVhjSm`-te44vu4d4*FSvtFpU{A zhWntfu#ncTUr&Pu4dVH_ckdp@E5P61pVqBg$NeKmj__OvSFT*4O`A6H7(_hlojZ4E z&z?PW^X5%Hw%}K+XxoUYckkW~C11L9iB6wB&DIMgTQOtC3|4YMK><(1_3PK!8Zq(0 zyLa#C)~#FIhk`F&yy%F8J9g~I69Oe?XJ=DdS{h#$);(p)6o-`?`S1amMAaxMDWR7y z5u6g0mX`AU;-1_AO3us6V*x{l4rL>?0?&kJ#Iu64XU}r$3MljP<;!&b{CU1F1aE8B ztfA=WXeur)rrg|Idhy}~d)tWH-D z58z6TU`2vny?Sx$3MkU3WFV^s4<&s5tkv-UjiP~^r?Q^GxQ(1Vd6HYi6IOAD+&^$v z$w1}~U<-Wu^eOj^a|};(`}S?_JK3*;B)zf(D+|1O^@>|T+?^5ZgJ9;&nY3ZU28SSh z0rI&kU@*unmo8n(X%EgZYSbwH3~8BQr{FJNzUV#oko2Z9Y0jHBZz_CW=ENMB!H{0R zeytx>4)ZpG>jLw*7^$;t2#Wq&>sCap-CRsCPPib!lkCs3f598%|HNrxQh&;xF)C(-N_iCQX`f zD>QH3To-XRExjh5;HhXuu*M^^x?)%G*^JRtpTsxD%r)!YA2UzarxMQSuZzbm+kOpqZ;z zwKrobT`M>FUAlCkapT76N6rziAX|nY^} zE|egDMDPHGBdG`Q4#&THK*=xY9B9a$H8$mzgdnoP)`;)uZ z!uPH2-ELekR>q{lhLlgXky=V(Mn=YOvU~roBwy=VV^kU@!`XxYxcRCo8DJ&58z|vk zDswHndw2CrR@8DO|D}ZM!>nkfam*+ZUeAS$UTPW?Kk)l8wq8d(uKyC@dnHvb9($=R zK!@KcojOXGW%-JZ+ONM+%^yn2C(m9OsVSJNg|!IW7?k{{cBoN7(LgC1l?(i|D2xZZ z)D^HN!(CT+8R2lqSgvRzYIVaHzE%R44&~$5 zD0q!zX(V1e4vOgr_3_^s@-I2*O2JN26rz6sB)NZ4n^~@x00000NkvXXu0mjfqEkrD literal 0 HcmV?d00001 diff --git a/lib/usd/ui/importDialog/images/defaultPrim_200.png b/lib/usd/ui/importDialog/images/defaultPrim_200.png new file mode 100644 index 0000000000000000000000000000000000000000..4b61d79a80a6a14db4195cfad947961c57f33bc3 GIT binary patch literal 2031 zcmd6n`8V5%8ph+6Gi_Z`)YewrQaY_}$}lZ@CB6|$1W9V&68j!&C2C(o2qk~gx_JDUxa(i3WJ10+UL$~iH)Q`%mxO5bkU^$!b^!~O?D_8qP@L6H8mBF z$D>dv7z}1=Y8n_A=Glau4;=jZ0;hQVO4Sgg6Zxs{a_4u@M>T54-+tEi~pa=G^Q z_7f8m#l^)B9z4j-&Mqq}OG!ydPENM8v>X~5B9qDE~i91brjDY3P+6$k_mA3mI% zoP7NF@!;SflgVsuZtm^v_4fA8$jC@aO5$)hv$L~tadEA!t^NJ|O-)S+2?^8F(`+`o zySqCkCT47G?8%cSPoF;J@pyfGeFFmni;Ig$ByxU!9*ssjIyyEsHX;xR2M34I(NQli zuduMNh=_=gkdT>~nb_Fa`ucinYwP&6!S@pOVEMDvc(ZV?j0+Aj6pCowU%{~x_)X$ax4CjOtfd4haAx`sd&|q>(v}EIw zI4$VfNGj3Yv=|Ayd?GdYy03J-2B0dZn5v3^iVhbN=F6hgrDx5GpYKBV8G85oL}g`q z(3Obs$S+@{PYPTe@vy{~*Kcy#G+1=aE10Ve$t0^+!UFVVmt>O5t4$ECQ$7ZB?*46sC-TFedLbc<2X_h zy@EMH$-u+9u%7oyqD!G&58wHNFF*zTxy%5MF>O~@Y_YCyr-?*S)5M+v{(8z5SLSBJ zXV1aQ#T9~ZE_6-wAriQFG zuC8(@u7ZSi2X1Q5T-5Kh;1X~G-*J{;v_%t!SDhk*s|GFV2#vx}={=OL`Z_Vzli%ay zBX8j5bwE+}dMP{wa@mtvTKg;qMl*SJ-8WA)ibo*C!+8lLaDNL*`AM}R28U zZOUhd)y%I&VJ(tXz2DQg&2wFO-Aa@*YlJ}+5p$oVMk0fGUr+zVUQ-{A1!Dy%7v<1O zYtMVv$YbwiRrE)7WI+YYKR-!RvbCR6wwW?Ah4EdNg;S2?k5bAWgN@}Y20OdIoRYx0czu}M@z3RU=Aw%u z{&=@Rd*uAx;)FJ)C(r#Q4-n>fyxR-XI%jka|4lA*bj$ma=(PMZ(QvdrU$v`kgP;3c zf#JE#vOc~&VUybU;rq(C{x{1V^J@v^RKE|m(2qaZ@BVptpz8wo^D7S@LVMjz9161m z;g3SFUws#TGmpeycsx>DDh+V U)Tz8y6hBsoB?1k!!@W}f2IOKQMgRZ+ literal 0 HcmV?d00001 diff --git a/lib/usd/ui/importDialog/images/ui.qrc b/lib/usd/ui/importDialog/images/ui.qrc index 68fa235810..e2b478e1db 100644 --- a/lib/usd/ui/importDialog/images/ui.qrc +++ b/lib/usd/ui/importDialog/images/ui.qrc @@ -4,6 +4,7 @@ checkboxOffDisabled_100.png checkboxOn_100.png checkboxOnDisabled_100.png + defaultPrim_100.png checkboxOff_150.png checkboxOff_200.png @@ -13,6 +14,8 @@ checkboxOn_200.png checkboxOnDisabled_150.png checkboxOnDisabled_200.png + defaultPrim_150.png + defaultPrim_200.png diff --git a/lib/usd/ui/importDialogDemo/testMayaUsdUI.cpp b/lib/usd/ui/importDialogDemo/testMayaUsdUI.cpp index 939850dd21..c0f5cc9c38 100644 --- a/lib/usd/ui/importDialogDemo/testMayaUsdUI.cpp +++ b/lib/usd/ui/importDialogDemo/testMayaUsdUI.cpp @@ -101,8 +101,9 @@ int main(int argc, char* argv[]) } // Create and show the ImportUI - TestUIQtUtil uiQtUtil; - MayaUsd::USDImportDialog usdImportDialog(usdFile, &importData, uiQtUtil); + TestUIQtUtil uiQtUtil; + MayaUsd::USDImportDialogOptions options; + MayaUsd::USDImportDialog usdImportDialog(usdFile, &importData, options, uiQtUtil); // Give the dialog the Maya dark style. QStyle* adsk = app.style(); diff --git a/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py b/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py index 20eaabbdee..5dfa8c2dde 100644 --- a/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py +++ b/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py @@ -219,20 +219,42 @@ def onMakePathRelativeChanged(cls, checked): enableFields = cls._canBeRelative and checked cmds.textFieldGrp(cls.kUnresolvedPathTextField, edit=True, enable=enableFields, text='') if enableFields: - cls.updateFilePathPreviewFields(checked) + cls.updateFilePathPreviewFields(cls.getSelectedFile(), checked) @classmethod def onfileNameEditFieldChanged(cls, text): """Callback from Qt textChanged event from fileNameEditField.""" - cls.updateFilePathPreviewFields() + cls.updateFilePathRelatedUi(cls.getRawSelectedFile()) @classmethod def onLookinTextChanged(cls, text): """Callback from Qt currentTextChanged from LookIn combobox.""" - cls.updateFilePathPreviewFields() + cls.updateFilePathRelatedUi(cls.getRawSelectedFile()) @classmethod - def updateFilePathPreviewFields(cls, makePathRelative=None): + def getRawSelectedFile(cls): + """Determine what the currently-selected file full path name.""" + # If the accept button is disabled it means there is no valid input in the file + # name edit field. + selFiles = cls._fileDialog.selectedFiles() if cls._fileDialog and cls._acceptButton and cls._acceptButton.isEnabled() else None + selectedFile = selFiles[0] if selFiles else '' + + if cls._ensureUsdExtension: + # Make sure the file path has a valid USD extension. This is NOT done by the fileDialog so + # the user is free to enter any extension they want. The layer editor code will then verify + # (and fix if needed) the file path before saving. We do the same here for preview. + selectedFile = mayaUsdLib.Util.ensureUSDFileExtension(selectedFile) if selectedFile else '' + + return selectedFile + + @classmethod + def updateFilePathRelatedUi(cls, unresolvedPath): + """Update all UI that cares about the given selected file.""" + cls.updateFilePathPreviewFields(unresolvedPath) + + @classmethod + def updateFilePathPreviewFields(cls, unresolvedPath, makePathRelative=None): + """Update the file-path preview UI.""" if not cls._haveRelativePathFields: return @@ -245,19 +267,6 @@ def updateFilePathPreviewFields(cls, makePathRelative=None): if not makePathRelative: return - # If the accept button is disabled it means there is no valid input in the file - # name edit field. - selFiles = cls._fileDialog.selectedFiles() if cls._fileDialog and cls._acceptButton and cls._acceptButton.isEnabled() else None - selectedFile = selFiles[0] if selFiles else '' - - if cls._ensureUsdExtension: - # Make sure the file path has a valid USD extension. This is NOT done by the fileDialog so - # the user is free to enter any extension they want. The layer editor code will then verify - # (and fix if needed) the file path before saving. We do the same here for preview. - unresolvedPath = mayaUsdLib.Util.ensureUSDFileExtension(selectedFile) if selectedFile else '' - else: - unresolvedPath = selectedFile - relativePath = '' if unresolvedPath and cls._relativeToDir: relativePath = mayaUsdLib.Util.getPathRelativeToDirectory(unresolvedPath, cls._relativeToDir) @@ -269,13 +278,13 @@ def updateFilePathPreviewFields(cls, makePathRelative=None): def selectionChanged(cls, parentLayout, selection): """Callback from fileDialog selectionChanged.""" cmds.setParent(parentLayout) - cls.updateFilePathPreviewFields() + cls.updateFilePathRelatedUi(cls.getRawSelectedFile()) @classmethod def fileTypeChanged(cls, parentLayout, newType): """Callback from fileDialog command fileTypeChanged.""" cmds.setParent(parentLayout) - cls.updateFilePathPreviewFields() + cls.updateFilePathRelatedUi(cls.getRawSelectedFile()) class usdRootFileRelative(usdFileRelative): ''' @@ -430,6 +439,7 @@ def uiCommit(cls, parentLayout, selectedFile=None): compositionArc = values[mayaRefUtils.compositionArcKey] listEditType = values[mayaRefUtils.listEditTypeKey] loadPayload = values[mayaRefUtils.loadPayloadKey] + primPath = values[mayaRefUtils.referencedPrimPathKey] wantReference = bool(compositionArc == mayaRefUtils.compositionArcReference) wantPrepend = bool(listEditType == mayaRefUtils.listEditTypePrepend) @@ -438,6 +448,18 @@ def uiCommit(cls, parentLayout, selectedFile=None): mayaUsdUtils.saveWantReferenceCompositionArc(wantReference) mayaUsdUtils.saveWantPrependCompositionArc(wantPrepend) mayaUsdUtils.saveWantPayloadLoaded(wantLoad) + mayaUsdUtils.saveReferencedPrimPath(primPath) + + @classmethod + def updateFilePathRelatedUi(cls, unresolvedPath): + """Update all UI that cares about the given selected file.""" + super(usdAddRefOrPayloadRelativeToEditTargetLayer, cls).updateFilePathRelatedUi(unresolvedPath) + cls.updateMayaReferenceUi(unresolvedPath) + + @classmethod + def updateMayaReferenceUi(cls, unresolvedPath): + mayaRefUtils.updateUsdRefOrPayloadUI(unresolvedPath) + class usdImageRelativeToEditTargetLayer(usdFileRelativeToEditTargetLayer): ''' From a112115f4c0e893b7f9c5bee87dfe5d35d2bbb9b Mon Sep 17 00:00:00 2001 From: Pierre Baillargeon Date: Fri, 6 Oct 2023 15:47:58 -0400 Subject: [PATCH 2/4] EMSUSD-254 fix typo in a python function call --- plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py b/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py index 5dfa8c2dde..967067d9bc 100644 --- a/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py +++ b/plugin/adsk/scripts/mayaUsd_USDRootFileRelative.py @@ -219,7 +219,7 @@ def onMakePathRelativeChanged(cls, checked): enableFields = cls._canBeRelative and checked cmds.textFieldGrp(cls.kUnresolvedPathTextField, edit=True, enable=enableFields, text='') if enableFields: - cls.updateFilePathPreviewFields(cls.getSelectedFile(), checked) + cls.updateFilePathPreviewFields(cls.getRawSelectedFile(), checked) @classmethod def onfileNameEditFieldChanged(cls, text): From 55645e827c306321c9580f699d3d68f12cd2e33a Mon Sep 17 00:00:00 2001 From: Pierre Baillargeon Date: Wed, 11 Oct 2023 10:15:35 -0400 Subject: [PATCH 3/4] EMSUSD-254 position the icon on the right. --- lib/usd/ui/importDialog/ItemDelegate.cpp | 6 +++++- .../importDialog/images/defaultPrim_100.png | Bin 1514 -> 1568 bytes .../importDialog/images/defaultPrim_150.png | Bin 2277 -> 2353 bytes .../importDialog/images/defaultPrim_200.png | Bin 2031 -> 2106 bytes 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/usd/ui/importDialog/ItemDelegate.cpp b/lib/usd/ui/importDialog/ItemDelegate.cpp index 0cf14d3df2..5ebaa3206d 100644 --- a/lib/usd/ui/importDialog/ItemDelegate.cpp +++ b/lib/usd/ui/importDialog/ItemDelegate.cpp @@ -85,7 +85,11 @@ void ItemDelegate::paint( // painter->drawRect(QRect(0, option.rect.y(), option.rect.right(), option.rect.bottom())); // painter->restore(); - ParentClass::paint(painter, option, index); + QStyleOptionViewItem adjustedOption(option); + adjustedOption.decorationPosition = QStyleOptionViewItem::Right; + adjustedOption.decorationAlignment = Qt::AlignLeft; + + ParentClass::paint(painter, adjustedOption, index); } void ItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const diff --git a/lib/usd/ui/importDialog/images/defaultPrim_100.png b/lib/usd/ui/importDialog/images/defaultPrim_100.png index b0219157ffa2343b2d9a3aae2eccd15df9cd38e3..ae68144b1435399a040bc102769d34c42c0c485f 100644 GIT binary patch delta 1548 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 diff --git a/lib/usd/ui/importDialog/images/defaultPrim_150.png b/lib/usd/ui/importDialog/images/defaultPrim_150.png index 4c56464a3854e7b9502729bc6eb6c41c7eef3e40..bc847bf6f02c0d9a25e17edd8fe2bacbcf89cedb 100644 GIT binary patch delta 2339 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 JPDHLkV1n@XfD-@! delta 2263 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 B`Y-?h delta 1423 zcmV;A1#tSh5bqBmiBL{Q4GJ0x0000DNk~Le0001{0000a2m=5B05mSKma!pp0)N8* z01m?e$8V@)000FzNkl@fIOCXB@fxaf^c0xlt)1+34&`b zWecPtL>Unkf*C~*^ZwC&&zW-{3(G^4-0u(foHKX0^O>1557u$Ra`N&E3e8(rVL^W0 zE-PiF*BFpoNx zC8g@TK}E{S)Z0fgo{YIGFV7O4Q#V896-1Tl@2B%b>K#>8MAhoGgT{mWEc$hbukwjv& zG+KUX7XzKtel+&t8Oc9Ns=r+-?luVDsrLCDeTvL^F^3;QR@b>0it|OS$a6adc z-$Rf}5v5Y8N)t!HZ2uQ{e#w=H?z1symCaX*nI=l7(;1jFH;>FEo_`QvLJLH-CWMI| zBWDN=&CGv|M`%2wPQH4^JU|`nBKa_kdHo?RJThi+j#8KiGel(f*O7`vJh7r4b3|0Z z#!Op2bW%d(W=4MFn@tgHff!Uoj9I>9DmhO=n61Vve*=q=D~n~U*cGQhJzSiSeQY~z z6AeUh4!0VebKLgP=^*3lX7TZLyN*XPDiX6Ex0-XkNl5TU%3_6; zOqn-UfZ4#|7*Q2llhSFja@N$5g)I}aY%zJ2sAds*n1dKM6^ChgDV<^y!t_B{MCZj~ zTU!xKzY_r_uT;kLM)SE?(OPH;VXqrvJL!++Z=Mi(nAkR|A4MXOZ42~FF(2D-c3;f2 zSY#45TwwZ%7k^;h<`9^_v&Dxc_pMf(sCwAjWsMng$6{i8LdSi1nD^-qi8UFUb(nO+ z)RmM4ljIVJZlKTEb5lrw8Dr~@zo^c!jj|Sr8rfpJ81t$3tsQxKn2q)n{Il5~zIK>) z&4DBlP8QkRw%K~Z>kb$+!7C1!6H*NA#kBn+Y8ER>hJO!BEYsxbDjyGwX||9-S4J=X zMGM&Rd`zsBzc-hM{!y+DqVa+1sSOR0d$B3z##ego1s7htrkd6^?C;kQ0aIFF?Zxb8 zi@&goPLy%==;Du|S^Y=}CQ`JGUEaq;=89hE^lBv>I~-y85pBWgV<+|Ei+|h`oL|(fO9<-3O@gNF{no=Y`AO_XEq$7dX6-Ugx9w5y_$j)vA(%MdUSwjf zqsn+pQsMy2!2nbCWzn8%abe{HTtOl{%c97#?}oI@OFvL)<_{%HOV<9YmIX}YGoP}@ z(95j#{1(-Savz-1ICkkV_ZnADAxPQJyt*z80 d6^Z4#{{fa}skEaQ;}rk^002ovPDHLkV1n0ZtGxgK From 346a93995e87b0f6f2716e8e0e60fc3fa9b95910 Mon Sep 17 00:00:00 2001 From: Pierre Baillargeon Date: Thu, 12 Oct 2023 10:48:22 -0400 Subject: [PATCH 4/4] EMSUSD-254 update the default prim icons Also, center the icons vertically. --- lib/usd/ui/importDialog/ItemDelegate.cpp | 2 +- .../importDialog/images/defaultPrim_100.png | Bin 1568 -> 837 bytes .../importDialog/images/defaultPrim_150.png | Bin 2353 -> 1323 bytes .../importDialog/images/defaultPrim_200.png | Bin 2106 -> 1623 bytes 4 files changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/usd/ui/importDialog/ItemDelegate.cpp b/lib/usd/ui/importDialog/ItemDelegate.cpp index 5ebaa3206d..14bc02e3f7 100644 --- a/lib/usd/ui/importDialog/ItemDelegate.cpp +++ b/lib/usd/ui/importDialog/ItemDelegate.cpp @@ -87,7 +87,7 @@ void ItemDelegate::paint( QStyleOptionViewItem adjustedOption(option); adjustedOption.decorationPosition = QStyleOptionViewItem::Right; - adjustedOption.decorationAlignment = Qt::AlignLeft; + adjustedOption.decorationAlignment = Qt::AlignLeft | Qt::AlignVCenter; ParentClass::paint(painter, adjustedOption, index); } diff --git a/lib/usd/ui/importDialog/images/defaultPrim_100.png b/lib/usd/ui/importDialog/images/defaultPrim_100.png index ae68144b1435399a040bc102769d34c42c0c485f..c6788ef5e4655ae092b87c753ce773a726d35919 100644 GIT binary patch literal 837 zcmV-L1G@Z)P)q|6n->SZN;h9mR7gdy4KME3IQ5K0|EsC6eQqCa2OmUaA(j!f&y}!LLLDu1PQ1U z;BUUi?q*qL`ERb5<4Yz3GjC?zeDB*gJ8K~cYyzTs$4^mi>Hk7UDV0{MRo-N5(f<*= z-HNJ63*t^78j12Ih#Z+2XaoxKo<#LSlrMCG9=~ZpVn^1=1S-n=MJMvi01}^NN<35Q zlk(OB+!SRUXF`1*`k;g2;o*V2Uhht0ZfiHr0j!Vtjs%->xGn(-bZ;67Cu+5t zRr-reiK($S2USSsL^O>ZM&-B_4SoWSm#e55MVofKvh3dsnpW?Mj!T2 zr_I=KPCF2&0!~@2R`Pf})a&)g=ku{rKpOhm?Y5?(bUID>e4diYB#p;ob{ZSQCZQY< z02GTw%49O6-<&!}p-|B5j6jfv!y(TH5|J|I^EvzQ`1nZmdY$_HKFl~(Ml)hhc4d!!clY_V7l%DGVBi1s){pb$8L8p?yxfNr6>ubddok9!NqYW3iYPZR8o8 z%;APx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!T0vI}LrC-> zC>CNi>BtBgUM9R>VjSzCLWI;bwRG11+iRcMZudDJvk9i@2a9#t`|Pv!e|_u!t#j;1 zM|^yIxTwAnwBfSIwp-LufV~<0ntvL zo}O~VI@#ITv}eyA+OT1Lw(jHO!{4i7GMVW7`STPV9W6)JkF&Eg#l*y{cdlQHd449_ zRzXC+7f;@_X%l&Qc~Na`E!EW2$kF%5&Ye4D>;2Hz*GB~f1@z>}6FKruK(`#FX&rli zfB$bq?W1&wf`WqRdaV zva)FN=FKd)udgo+3=GiW!-pv;DT$vYzK5Uj>eVa0|H_psw6L&Xeo^#y?ASrw-QB#c z_wL2M!!yOLTK{qoSfB8Xg|z`-+Q;DKavWKYQfJ5uVHF=qRP7rP1-@$9evbA3x?f z>+m>x_H4OqTLck}Bb=EtXU_18PEAeG{{8#qs6td!6s4r3a5M}K4pM4rD(&01kFULW z@q%ki8f_;hC%y*Z9zJ}?6V1%bwo1dSTJ*97np`jtJu}Dv!KIOI^*v*zLTd1R> zgSKzq&cULBYj_vT`R&`c)ZgFF;~pL!Tm#r7f^2SXj(U1}=-|PFy!fz|-rimc4-e;e zH^5)kR)NrFlfp#d$5mBTbp85ux^?T8yrO_4b^rc-YHn`kg2=)IKx1Pg*R8Fs)Y8(z z6D}(&qX!Qj@Vyv=*!K4Jd>_zeYpv*ui;J?QP+woqb$fd|-Me>>+eX~Hd6VY{A+Zw? z;VRYD)g(>`bnV(T8Xq5*qszhWtgNi0J9qBTqeqW8dT-pg!B&X(LI4_IlgX>64o02W z$jAuS*eY7Eoemv3MCIk>TwotKX;|X)>C<%K!Uei|^{P3-?Cgxw!J9X4WJ?iR+gGu6 zjC%RkS(I=>1mponUOuBXV0F|#*G_gZ|y*6v+2Bk{hDj_f$&@{ zmiNklCdFJ6>amjl1UDWRgGg3g^gN4Ia^mRA(8h2ftn+9<{~l(m3Ugo=LNK)aJH zp+AAZ%eBA`4On5?MnGu%v}CYq0Lcr<2%fA32@Yd8!ol~_)6*$5G*n()4m=MaIidsx z26A5oJ`Udu4i4rdh2*4y1;tAtF##+Bq6;>)b?a6h(*sdNQsP~Q`Qcq`iDE5Uq47NR z9RQA)78dI-Sz84{E9NS|*1UW7E}t*+^71%SYiVd`;BAR(moH!DBNw)q5p8X4oK$jh za_G{fOUn`ufM+72^YimrP_0K}LE-Bas={lxkUe@Z$Q! zXf%f79gdu^GFZs$EdK@ZAwbfI6bAw5XBCsk#5k1xqICa3O$3&_(kNN!MF!SH29`ty zdO?BFn3fMHGN=&xttv85_ezl{zbnoECfXCj2LgH(D$Ug~+l8CO{zr*{<)~|`#nJv{B5_ce_cKj;D0z>Ao2aEw~N(H|hWY diff --git a/lib/usd/ui/importDialog/images/defaultPrim_150.png b/lib/usd/ui/importDialog/images/defaultPrim_150.png index bc847bf6f02c0d9a25e17edd8fe2bacbcf89cedb..e9317a7bd5ad95acec34c73597b1f6a9aafe4360 100644 GIT binary patch literal 1323 zcmV+`1=RY9P)4{|2Dy~US zjo5Bn!NrSnv&Vs zSxJh4fdQMUNoQxLG&MCzl?m0c&U?|}$UPVv8kYn;W^ky_Nm_eK|Ndu;=A4 zJUlEzLqoRS>FKE?#o*we+}+*D&dyF*^}_mhc6KIPTU&B@c^O#`ahar)866#!D&nAL z@P$d8NwFb#6b%gx(%9IT7qq^mRAas;Lz?Cs52u>cNsReVcmebSIV+V_lb5HJrrvQYcz7Dv8 za4jt@q3z-s`kdf%OM&NsijBbJ(KoyhNy};9^*0GI_xASeGwBQB(?`uqAV@6Gvra06 z4ji)+n7s_BS{E~RdwbjFPft%<;Sq-biF1W(dN1mzhqy1?gLW{u>J{R^lK`S24E5DJ zDR_gpz>cw)pP#q&@f@qGtM;BOX?joE<)0i$fXKWpN!*&%x)6wHlizd%>kTUx1s!IP zo12^Mx!$Lmu#^COVI5ytSt)1(lP33O-aIa?Yd|@&Nk#`}1zOtEhwTrUk$G!N# zD`52mBz^(8FK!Q!iNY@~E^OI2tJ3Q{pLLMQ_XACeTrlIY_jbgU2fzShy$l+HVXeFf z@elUW(vr1o0v7@f5~8V9hOxW5YX#uXl#PuIYq`OIMw%&4;~`!B}pk|!s?XMjubEwwk^p2JvrMAl5Vi#P?zNY zp8QNg!tab!fNoEtF6OuYxUPHcI1Ya6-XAP7z8n7Q^%ol;f!9ImAXf^-<002ovPDHLkV1oL3d~W~% literal 2353 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 X^E;p6x`Zm?00000NkvXXu0mjf)zy8; diff --git a/lib/usd/ui/importDialog/images/defaultPrim_200.png b/lib/usd/ui/importDialog/images/defaultPrim_200.png index 3c8eaa43a6d48f0cdc8ad73cf8278ab763758257..2f78c311567824c1c5ab22d2ed2836d064be3fbe 100644 GIT binary patch literal 1623 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