diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioPlugin.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioPlugin.h index 85fc9c8d56..e33a5f3f51 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioPlugin.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/EMStudioPlugin.h @@ -78,8 +78,6 @@ namespace EMStudio virtual void OnBeforeRemovePlugin(uint32 classID) { MCORE_UNUSED(classID); } virtual void OnMainWindowClosed() {} - virtual void RegisterKeyboardShortcuts() {} - struct RenderInfo { MCORE_MEMORYOBJECTCATEGORY(EMStudioPlugin::RenderInfo, MCore::MCORE_DEFAULT_ALIGNMENT, MEMCATEGORY_EMSTUDIOSDK) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/KeyboardShortcutsWindow.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/KeyboardShortcutsWindow.cpp index b8093d2115..d6fdb9128b 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/KeyboardShortcutsWindow.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/KeyboardShortcutsWindow.cpp @@ -116,14 +116,6 @@ namespace EMStudio } - void KeyboardShortcutsWindow::hideEvent(QHideEvent* event) - { - MCORE_UNUSED(event); - //if (mShortcutReceiverDialog) - // mShortcutReceiverDialog->reject(); - } - - // reconstruct the whole interface void KeyboardShortcutsWindow::ReInit() { @@ -138,11 +130,11 @@ namespace EMStudio // add the groups to the left list widget MysticQt::KeyboardShortcutManager* shortcutManager = GetMainWindow()->GetShortcutManager(); - const uint32 numGroups = shortcutManager->GetNumGroups(); + const size_t numGroups = shortcutManager->GetNumGroups(); for (uint32 i = 0; i < numGroups; ++i) { MysticQt::KeyboardShortcutManager::Group* group = shortcutManager->GetGroup(i); - mListWidget->addItem(group->GetName()); + mListWidget->addItem(FromStdString(group->GetName())); } mTableWidget->blockSignals(false); @@ -183,10 +175,10 @@ namespace EMStudio // get access to the shortcut group and some data MysticQt::KeyboardShortcutManager* shortcutManager = GetMainWindow()->GetShortcutManager(); MysticQt::KeyboardShortcutManager::Group* group = shortcutManager->GetGroup(mSelectedGroup); - const uint32 numActions = group->GetNumActions(); + const size_t numActions = group->GetNumActions(); // set the row count - mTableWidget->setRowCount(numActions); + mTableWidget->setRowCount(aznumeric_caster(numActions)); // fill the table with the media root folders for (uint32 i = 0; i < numActions; ++i) @@ -195,11 +187,11 @@ namespace EMStudio MysticQt::KeyboardShortcutManager::Action* action = group->GetAction(i); // add the item to the table and set the row height - QTableWidgetItem* item = new QTableWidgetItem(action->mName.c_str()); + QTableWidgetItem* item = new QTableWidgetItem(action->m_qaction->text()); item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); mTableWidget->setItem(i, 0, item); - const QString keyText = ConstructStringFromShortcut(action->mKey, action->mCtrl, action->mAlt); + const QString keyText = ConstructStringFromShortcut(action->m_qaction->shortcut()); item = new QTableWidgetItem(keyText); item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); @@ -255,18 +247,14 @@ namespace EMStudio // handle conflicts if (shortcutWindow.mConflictDetected) { - shortcutWindow.mConflictAction->mKey = -1; - shortcutWindow.mConflictAction->mCtrl = false; - shortcutWindow.mConflictAction->mAlt = false; + shortcutWindow.mConflictAction->m_qaction->setShortcut({}); } // adjust the shortcut action - action->mKey = shortcutWindow.mKey; - action->mAlt = shortcutWindow.mAlt; - action->mCtrl = shortcutWindow.mCtrl; + action->m_qaction->setShortcut(shortcutWindow.mKey); // save the new shortcuts - QSettings settings(AZStd::string(GetManager()->GetAppDataFolder() + "EMStudioKeyboardShortcuts.cfg").c_str(), QSettings::IniFormat, this); + QSettings settings(FromStdString(AZStd::string(GetManager()->GetAppDataFolder() + "EMStudioKeyboardShortcuts.cfg")), QSettings::IniFormat, this); shortcutManager->Save(&settings); // reinit the window @@ -277,31 +265,14 @@ namespace EMStudio // construct a text version of a shortcut - QString KeyboardShortcutsWindow::ConstructStringFromShortcut(int key, bool ctrl, bool alt) + QString KeyboardShortcutsWindow::ConstructStringFromShortcut(QKeySequence key) { - if (key == -1) + if (key.isEmpty()) { return "not set"; } - QString keyText; - - if (ctrl) - { - #if AZ_TRAIT_OS_PLATFORM_APPLE - keyText += "COMMAND + "; - #else - keyText += "CTRL + "; - #endif - } - if (alt) - { - keyText += "ALT + "; - } - - keyText += QKeySequence(key).toString(QKeySequence::NativeText); - - return keyText; + return key.toString(QKeySequence::NativeText); } @@ -313,9 +284,7 @@ namespace EMStudio return; } - mContextMenuAction->mKey = mContextMenuAction->mDefaultKey; - mContextMenuAction->mCtrl = mContextMenuAction->mDefaultCtrl; - mContextMenuAction->mAlt = mContextMenuAction->mDefaultAlt; + mContextMenuAction->m_qaction->setShortcut(mContextMenuAction->m_defaultKeySequence); ReInit(); } @@ -378,19 +347,14 @@ namespace EMStudio setWindowTitle(" "); layout->addWidget(new QLabel("Press the new shortcut on the keyboard:")); - // find the initial shortcut - //MysticQt::KeyboardShortcutManager* shortcutManager = GetMainWindow()->GetShortcutManager(); - mOrgAction = action; mOrgGroup = group; mConflictAction = nullptr; mConflictDetected = false; - mKey = action->mKey; - mCtrl = action->mCtrl; - mAlt = action->mAlt; + mKey = action->m_qaction->shortcut(); - QString keyText = KeyboardShortcutsWindow::ConstructStringFromShortcut(mKey, mCtrl, mAlt); + QString keyText = KeyboardShortcutsWindow::ConstructStringFromShortcut(mKey); mLabel = new QLabel(keyText); mLabel->setAlignment(Qt::AlignHCenter); @@ -431,9 +395,7 @@ namespace EMStudio // reset the shortcut to its default value void ShortcutReceiverDialog::ResetToDefault() { - mKey = mOrgAction->mDefaultKey; - mCtrl = mOrgAction->mDefaultCtrl; - mAlt = mOrgAction->mDefaultAlt; + mKey = mOrgAction->m_defaultKeySequence; UpdateInterface(); } @@ -444,10 +406,8 @@ namespace EMStudio { MysticQt::KeyboardShortcutManager* shortcutManager = GetMainWindow()->GetShortcutManager(); - QString keyText = KeyboardShortcutsWindow::ConstructStringFromShortcut(mKey, mCtrl, mAlt); - // check if the currently assigned shortcut is already taken by another shortcut - mConflictAction = shortcutManager->FindShortcut(mKey, mCtrl, mAlt, mOrgGroup); + mConflictAction = shortcutManager->FindShortcut(mKey, mOrgGroup); if (mConflictAction == nullptr || mConflictAction == mOrgAction) { mOKButton->setToolTip(""); @@ -465,39 +425,25 @@ namespace EMStudio if (mConflictAction) { - AZStd::string tempString; - - tempString = AZStd::string::format("Assigning new shortcut will unassign '%s' automatically.", mConflictAction->mName.c_str()); - mOKButton->setToolTip(tempString.c_str()); + mOKButton->setToolTip(QString("Assigning new shortcut will unassign '%1' automatically.").arg(mConflictAction->m_qaction->text())); MysticQt::KeyboardShortcutManager::Group* conflictGroup = shortcutManager->FindGroupForShortcut(mConflictAction); if (conflictGroup) { - tempString = AZStd::string::format("Conflicts with: %s -> %s", conflictGroup->GetName(), mConflictAction->mName.c_str()); + mConflictKeyLabel->setText(QString("Conflicts with: %1 -> %2").arg(FromStdString(conflictGroup->GetName())).arg(mConflictAction->m_qaction->text())); } else { - tempString = AZStd::string::format("Conflicts with: %s", mConflictAction->mName.c_str()); + mConflictKeyLabel->setText(QString("Conflicts with: %1").arg(mConflictAction->m_qaction->text())); } - - mConflictKeyLabel->setText(tempString.c_str()); } } // adjust the label text to the new shortcut + const QString keyText = KeyboardShortcutsWindow::ConstructStringFromShortcut(mKey); mLabel->setText(keyText); } - - // close dialog as soon as it lost focus - void ShortcutReceiverDialog::focusOutEvent(QFocusEvent* event) - { - MCORE_UNUSED(event); - // if (event->reason() == Qt::ActiveWindowFocusReason) - // reject(); - } - - // called when the user pressed a new shortcut void ShortcutReceiverDialog::keyPressEvent(QKeyEvent* event) { @@ -513,18 +459,12 @@ namespace EMStudio if (event->key() == Qt::Key_Escape) { - //mKey = mOrgAction->mKey; - //mCtrl = mOrgAction->mCtrl; - //mAlt = mOrgAction->mAlt; - // close the dialog when pressing ESC reject(); } else { - mKey = event->key(); - mCtrl = event->modifiers() & Qt::ControlModifier; - mAlt = event->modifiers() & Qt::AltModifier; + mKey = event->key() | event->modifiers(); } UpdateInterface(); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/KeyboardShortcutsWindow.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/KeyboardShortcutsWindow.h index 024479cc90..f6d4f43642 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/KeyboardShortcutsWindow.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/KeyboardShortcutsWindow.h @@ -41,12 +41,9 @@ namespace EMStudio virtual ~ShortcutReceiverDialog() {} void keyPressEvent(QKeyEvent* event) override; - void focusOutEvent(QFocusEvent* event) override; void UpdateInterface(); - int mKey; - bool mCtrl; - bool mAlt; + QKeySequence mKey; bool mConflictDetected; MysticQt::KeyboardShortcutManager::Action* mConflictAction; @@ -74,7 +71,7 @@ namespace EMStudio void Init(); void ReInit(); - static QString ConstructStringFromShortcut(int key, bool ctrl, bool alt); + static QString ConstructStringFromShortcut(QKeySequence key); MysticQt::KeyboardShortcutManager::Group* GetCurrentGroup() const; void setVisible(bool visible) override; @@ -95,6 +92,5 @@ namespace EMStudio ShortcutReceiverDialog* mShortcutReceiverDialog; void contextMenuEvent(QContextMenuEvent* event) override; - void hideEvent(QHideEvent* event) override; }; } // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp index 496b6b8e94..950b63ff26 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp @@ -66,6 +66,7 @@ #include #include #include +#include AZ_PUSH_DISABLE_WARNING(4267, "-Wconversion") #include AZ_POP_DISABLE_WARNING @@ -508,14 +509,33 @@ namespace EMStudio mShortcutManager = new MysticQt::KeyboardShortcutManager(); // load the old shortcuts - QSettings shortcutSettings(AZStd::string(GetManager()->GetAppDataFolder() + "EMStudioKeyboardShortcuts.cfg").c_str(), QSettings::IniFormat, this); - mShortcutManager->Load(&shortcutSettings); + LoadKeyboardShortcuts(); // add the application mode group - const char* layoutGroupName = "Layouts"; - mShortcutManager->RegisterKeyboardShortcut("AnimGraph", layoutGroupName, Qt::Key_1, false, true, false); - mShortcutManager->RegisterKeyboardShortcut("Animation", layoutGroupName, Qt::Key_2, false, true, false); - mShortcutManager->RegisterKeyboardShortcut("Character", layoutGroupName, Qt::Key_3, false, true, false); + constexpr AZStd::string_view layoutGroupName = "Layouts"; + QAction* animGraphLayoutAction = new QAction( + "AnimGraph", + this); + animGraphLayoutAction->setShortcut(Qt::Key_1 | Qt::AltModifier); + mShortcutManager->RegisterKeyboardShortcut(animGraphLayoutAction, layoutGroupName, false); + connect(animGraphLayoutAction, &QAction::triggered, [this]{ mApplicationMode->setCurrentIndex(0); }); + addAction(animGraphLayoutAction); + + QAction* animationLayoutAction = new QAction( + "Animation", + this); + animationLayoutAction->setShortcut(Qt::Key_2 | Qt::AltModifier); + mShortcutManager->RegisterKeyboardShortcut(animationLayoutAction, layoutGroupName, false); + connect(animationLayoutAction, &QAction::triggered, [this]{ mApplicationMode->setCurrentIndex(1); }); + addAction(animationLayoutAction); + + QAction* characterLayoutAction = new QAction( + "Character", + this); + characterLayoutAction->setShortcut(Qt::Key_1 | Qt::AltModifier); + mShortcutManager->RegisterKeyboardShortcut(characterLayoutAction, layoutGroupName, false); + connect(characterLayoutAction, &QAction::triggered, [this]{ mApplicationMode->setCurrentIndex(2); }); + addAction(characterLayoutAction); EMotionFX::ActorEditorRequestBus::Handler::BusConnect(); @@ -1267,6 +1287,12 @@ namespace EMStudio mRecentActors.AddRecentFile(fileName.toUtf8().data()); } + void MainWindow::LoadKeyboardShortcuts() + { + QSettings shortcutSettings(AZStd::string(GetManager()->GetAppDataFolder() + "EMStudioKeyboardShortcuts.cfg").c_str(), QSettings::IniFormat, this); + mShortcutManager->Load(&shortcutSettings); + } + void MainWindow::LoadActor(const char* fileName, bool replaceCurrentScene) { // create the final command @@ -2577,41 +2603,6 @@ namespace EMStudio QTimer::singleShot(0, this, &MainWindow::RaiseFloatingWidgets); } - void MainWindow::keyPressEvent(QKeyEvent* event) - { - const char* layoutGroupName = "Layouts"; - const uint32 numLayouts = GetMainWindow()->GetNumLayouts(); - for (uint32 i = 0; i < numLayouts; ++i) - { - if (mShortcutManager->Check(event, GetLayoutName(i), layoutGroupName)) - { - mApplicationMode->setCurrentIndex(i); - event->accept(); - return; - } - } - - event->ignore(); - } - - - void MainWindow::keyReleaseEvent(QKeyEvent* event) - { - const char* layoutGroupName = "Layouts"; - const uint32 numLayouts = GetNumLayouts(); - for (uint32 i = 0; i < numLayouts; ++i) - { - if (mShortcutManager->Check(event, layoutGroupName, GetLayoutName(i))) - { - event->accept(); - return; - } - } - - event->ignore(); - } - - // get the name of the currently active layout const char* MainWindow::GetCurrentLayoutName() const { diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h index 15edaef144..850715b23f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.h @@ -152,9 +152,6 @@ namespace EMStudio FileManager* GetFileManager() const { return mFileManager; } PreferencesWindow* GetPreferencesWindow() const { return mPreferencesWindow; } - void keyPressEvent(QKeyEvent* event) override; - void keyReleaseEvent(QKeyEvent* event) override; - uint32 GetNumLayouts() const { return mLayoutNames.GetLength(); } const char* GetLayoutName(uint32 index) const { return mLayoutNames[index].c_str(); } const char* GetCurrentLayoutName() const; @@ -168,6 +165,8 @@ namespace EMStudio void AddRecentActorFile(const QString& fileName); + void LoadKeyboardShortcuts(); + public slots: void OnAutosaveTimeOut(); void LoadLayoutAfterShow(); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/PluginManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/PluginManager.cpp index 214ed68367..ffe29ed691 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/PluginManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/PluginManager.cpp @@ -136,7 +136,6 @@ namespace EMStudio mActivePlugins.push_back(newPlugin); newPlugin->Init(); - newPlugin->RegisterKeyboardShortcuts(); return newPlugin; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp index 47b88b1fa2..8e4c1bce37 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp @@ -1020,17 +1020,6 @@ namespace EMStudio } - // register keyboard shortcuts used for the render plugin - void RenderPlugin::RegisterKeyboardShortcuts() - { - MysticQt::KeyboardShortcutManager* shortcutManger = GetMainWindow()->GetShortcutManager(); - - shortcutManger->RegisterKeyboardShortcut("Show Selected", "Render Window", Qt::Key_S, false, false, true); - shortcutManger->RegisterKeyboardShortcut("Show Entire Scene", "Render Window", Qt::Key_A, false, false, true); - shortcutManger->RegisterKeyboardShortcut("Toggle Selection Box Rendering", "Render Window", Qt::Key_J, false, false, true); - } - - // find the trajectory path for a given actor instance MCommon::RenderUtil::TrajectoryTracePath* RenderPlugin::FindTracePath(EMotionFX::ActorInstance* actorInstance) { diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.h index 43f237b89e..7dab0a5f95 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.h @@ -124,9 +124,6 @@ namespace EMStudio void ViewCloseup(bool selectedInstancesOnly = true, RenderWidget* renderWidget = nullptr, float flightTime = DEFAULT_FLIGHT_TIME); void SetSkipFollowCalcs(bool skipFollowCalcs); - // keyboard shortcuts - void RegisterKeyboardShortcuts() override; - // manipulators void ReInitTransformationManipulators(); MCommon::TransformationManipulator* GetActiveManipulator(MCommon::Camera* camera, int32 mousePosX, int32 mousePosY); @@ -177,6 +174,11 @@ namespace EMStudio void SaveRenderOptions(); void LoadRenderOptions(); + inline static constexpr AZStd::string_view s_renderWindowShortcutGroupName = "Render Window"; + inline static constexpr AZStd::string_view s_showSelectedShortcutName = "Show Selected"; + inline static constexpr AZStd::string_view s_showEntireSceneShortcutName = "Show Entire Scene"; + inline static constexpr AZStd::string_view s_toggleSelectionBoxRenderingShortcutName = "Toggle Selection Box Rendering"; + public slots: void SetManipulatorMode(RenderOptions::ManipulatorMode mode); void SetSelectionMode() { SetManipulatorMode(RenderOptions::ManipulatorMode::SELECT); } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp index f6c44980fe..9abb05ea2c 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp @@ -16,7 +16,9 @@ #include "../PreferencesWindow.h" #include #include +#include #include +#include #include @@ -156,8 +158,17 @@ namespace EMStudio cameraMenu->addSeparator(); cameraMenu->addAction("Reset Camera", [this]() { this->OnResetCamera(); }); - cameraMenu->addAction("Show Selected", this, &RenderViewWidget::OnShowSelected); - cameraMenu->addAction("Show Entire Scene", this, &RenderViewWidget::OnShowEntireScene); + + QAction* showSelectedAction = cameraMenu->addAction("Show Selected", this, &RenderViewWidget::OnShowSelected); + showSelectedAction->setShortcut(Qt::Key_S); + GetMainWindow()->GetShortcutManager()->RegisterKeyboardShortcut(showSelectedAction, RenderPlugin::s_renderWindowShortcutGroupName, true); + addAction(showSelectedAction); + + QAction* showEntireSceneAction = cameraMenu->addAction("Show Entire Scene", this, &RenderViewWidget::OnShowEntireScene); + showEntireSceneAction->setShortcut(Qt::Key_A); + GetMainWindow()->GetShortcutManager()->RegisterKeyboardShortcut(showEntireSceneAction, RenderPlugin::s_renderWindowShortcutGroupName, true); + addAction(showEntireSceneAction); + cameraMenu->addSeparator(); mFollowCharacterAction = cameraMenu->addAction(tr("Follow Character")); @@ -181,8 +192,30 @@ namespace EMStudio connect(m_manipulatorModes[RenderOptions::ROTATE], &QAction::triggered, mPlugin, &RenderPlugin::SetRotationMode); connect(m_manipulatorModes[RenderOptions::SCALE], &QAction::triggered, mPlugin, &RenderPlugin::SetScaleMode); + QAction* toggleSelectionBoxRendering = new QAction( + "Toggle Selection Box Rendering", + this + ); + toggleSelectionBoxRendering->setShortcut(Qt::Key_J); + GetMainWindow()->GetShortcutManager()->RegisterKeyboardShortcut(toggleSelectionBoxRendering, RenderPlugin::s_renderWindowShortcutGroupName, true); + connect(toggleSelectionBoxRendering, &QAction::triggered, this, [this] + { + mPlugin->GetRenderOptions()->SetRenderSelectionBox(mPlugin->GetRenderOptions()->GetRenderSelectionBox() ^ true); + }); + addAction(toggleSelectionBoxRendering); + + QAction* deleteSelectedActorInstance = new QAction( + "Delete Selected Actor Instance", + this + ); + deleteSelectedActorInstance->setShortcut(Qt::Key_Delete); + connect(deleteSelectedActorInstance, &QAction::triggered, []{ CommandSystem::RemoveSelectedActorInstances(); }); + addAction(deleteSelectedActorInstance); + Reset(); UpdateInterface(); + + GetMainWindow()->LoadKeyboardShortcuts(); } void RenderViewWidget::SetManipulatorMode(RenderOptions::ManipulatorMode mode) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.h index 33b648f9c9..3ef48d0749 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.h @@ -43,6 +43,8 @@ namespace EMStudio RenderViewWidget(RenderPlugin* parentPlugin, QWidget* parentWidget); virtual ~RenderViewWidget(); + void CreateActions(); + enum ERenderFlag { RENDER_SOLID = 0, diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp index 6218194fc6..5ca912ef71 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.cpp @@ -25,7 +25,6 @@ #include "../EMStudioManager.h" #include "../MainWindow.h" #include -#include namespace EMStudio @@ -76,7 +75,6 @@ namespace EMStudio delete mAxisFakeCamera; } - // start view closeup flight void RenderWidget::ViewCloseup(const MCore::AABB& aabb, float flightTime, uint32 viewCloseupWaiting) { @@ -726,72 +724,6 @@ namespace EMStudio } - // called when a key got pressed - void RenderWidget::OnKeyPressEvent(QWidget* renderWidget, QKeyEvent* event) - { - MCORE_UNUSED(renderWidget); - MysticQt::KeyboardShortcutManager* shortcutManger = GetMainWindow()->GetShortcutManager(); - - if (shortcutManger->Check(event, "Show Selected", "Render Window")) - { - mPlugin->ViewCloseup(true, this); - event->accept(); - return; - } - - if (shortcutManger->Check(event, "Show Entire Scene", "Render Window")) - { - mPlugin->ViewCloseup(false, this); - event->accept(); - return; - } - - if (shortcutManger->Check(event, "Toggle Selection Box Rendering", "Render Window")) - { - mPlugin->GetRenderOptions()->SetRenderSelectionBox(mPlugin->GetRenderOptions()->GetRenderSelectionBox() ^ true); - event->accept(); - return; - } - - if (event->key() == Qt::Key_Delete) - { - CommandSystem::RemoveSelectedActorInstances(); - event->accept(); - return; - } - - event->ignore(); - } - - - // called when a key got released - void RenderWidget::OnKeyReleaseEvent(QWidget* renderWidget, QKeyEvent* event) - { - MCORE_UNUSED(renderWidget); - MysticQt::KeyboardShortcutManager* shortcutManger = GetMainWindow()->GetShortcutManager(); - - if (shortcutManger->Check(event, "Show Selected", "Render Window")) - { - event->accept(); - return; - } - - if (shortcutManger->Check(event, "Show Entire Scene", "Render Window")) - { - event->accept(); - return; - } - - if (event->key() == Qt::Key_Delete) - { - event->accept(); - return; - } - - event->ignore(); - } - - // handles context menu events void RenderWidget::OnContextMenuEvent(QWidget* renderWidget, bool shiftPressed, bool altPressed, int32 localMouseX, int32 localMouseY, QPoint globalMousePos) { diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.h index f376f10f84..99c1c38f70 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderWidget.h @@ -96,6 +96,8 @@ namespace EMStudio RenderWidget(RenderPlugin* renderPlugin, RenderViewWidget* viewWidget); virtual ~RenderWidget(); + void CreateActions(); + // main render callback virtual void Render() = 0; virtual void Update() = 0; @@ -132,8 +134,6 @@ namespace EMStudio void OnMousePressEvent(QWidget* renderWidget, QMouseEvent* event); void OnMouseReleaseEvent(QWidget* renderWidget, QMouseEvent* event); void OnWheelEvent(QWidget* renderWidget, QWheelEvent* event); - void OnKeyPressEvent(QWidget* renderWidget, QKeyEvent* event); - void OnKeyReleaseEvent(QWidget* renderWidget, QKeyEvent* event); void OnContextMenuEvent(QWidget* renderWidget, bool shiftPressed, bool altPressed, int32 localMouseX, int32 localMouseY, QPoint globalMousePos); protected: diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/GLWidget.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/GLWidget.h index 107869de33..c81d7c61ae 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/GLWidget.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/GLWidget.h @@ -72,8 +72,6 @@ namespace EMStudio void mousePressEvent(QMouseEvent* event) { RenderWidget::OnMousePressEvent(this, event); } void mouseReleaseEvent(QMouseEvent* event) { RenderWidget::OnMouseReleaseEvent(this, event); } void wheelEvent(QWheelEvent* event) { RenderWidget::OnWheelEvent(this, event); } - void keyPressEvent(QKeyEvent* event) { RenderWidget::OnKeyPressEvent(this, event); } - void keyReleaseEvent(QKeyEvent* event) { RenderWidget::OnKeyReleaseEvent(this, event); } void focusInEvent(QFocusEvent* event); void focusOutEvent(QFocusEvent* event); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphActionManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphActionManager.cpp index 9cbd654393..f76f684ea5 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphActionManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphActionManager.cpp @@ -99,7 +99,7 @@ namespace EMStudio } if (!m_pasteItems.empty()) { - m_pasteOperation = PasteOperation::Copy; + SetPasteOperation(PasteOperation::Copy); } } @@ -126,7 +126,7 @@ namespace EMStudio } if (!m_pasteItems.empty()) { - m_pasteOperation = PasteOperation::Cut; + SetPasteOperation(PasteOperation::Cut); } } @@ -168,8 +168,8 @@ namespace EMStudio } } - m_pasteOperation = PasteOperation::None; m_pasteItems.clear(); + SetPasteOperation(PasteOperation::None); } void AnimGraphActionManager::SetEntryState() @@ -443,6 +443,18 @@ namespace EMStudio } } + void AnimGraphActionManager::NavigateToParent() + { + const QModelIndex parentFocus = m_plugin->GetAnimGraphModel().GetParentFocus(); + if (parentFocus.isValid()) + { + QModelIndex newParentFocus = parentFocus.model()->parent(parentFocus); + if (newParentFocus.isValid()) + { + m_plugin->GetAnimGraphModel().Focus(newParentFocus); + } + } + } void AnimGraphActionManager::OpenReferencedAnimGraph(EMotionFX::AnimGraphReferenceNode* referenceNode) { @@ -678,4 +690,10 @@ namespace EMStudio GetCommandManager()->ExecuteCommandGroup(commandGroup, outResult); } } + + void AnimGraphActionManager::SetPasteOperation(PasteOperation newOperation) + { + m_pasteOperation = newOperation; + emit PasteStateChanged(); + } } // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphActionManager.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphActionManager.h index 30b520d2a5..9182272875 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphActionManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphActionManager.h @@ -72,6 +72,9 @@ namespace EMStudio Bottom }; + signals: + void PasteStateChanged(); + public slots: void Copy(); void Cut(); @@ -95,6 +98,7 @@ namespace EMStudio void DeleteSelectedNodes(); void NavigateToNode(); + void NavigateToParent(); void OpenReferencedAnimGraph(EMotionFX::AnimGraphReferenceNode* referenceNode); @@ -126,5 +130,7 @@ namespace EMStudio AnimGraphPlugin* m_plugin; AZStd::vector m_pasteItems; PasteOperation m_pasteOperation; + + void SetPasteOperation(PasteOperation newOperation); }; } // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.cpp index 2669153dfd..d9b77ccf89 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.cpp @@ -461,10 +461,7 @@ namespace EMStudio { m_actionFilter = actionFilter; - if (mViewWidget) - { - mViewWidget->UpdateSelection(); - } + emit ActionFilterChanged(); } const AnimGraphActionFilter& AnimGraphPlugin::GetActionFilter() const @@ -1408,33 +1405,6 @@ namespace EMStudio } - // register keyboard shortcuts used for the render plugin - void AnimGraphPlugin::RegisterKeyboardShortcuts() - { - MysticQt::KeyboardShortcutManager* shortcutManager = GetMainWindow()->GetShortcutManager(); - - shortcutManager->RegisterKeyboardShortcut("Fit Entire Graph", "Anim Graph Window", Qt::Key_A, false, false, true); - shortcutManager->RegisterKeyboardShortcut("Zoom On Selected Nodes", "Anim Graph Window", Qt::Key_Z, false, false, true); - - shortcutManager->RegisterKeyboardShortcut("Open Parent Node", "Anim Graph Window", Qt::Key_Up, false, false, true); - shortcutManager->RegisterKeyboardShortcut("Open Selected Node", "Anim Graph Window", Qt::Key_Down, false, false, true); - shortcutManager->RegisterKeyboardShortcut("History Back", "Anim Graph Window", Qt::Key_Left, false, false, true); - shortcutManager->RegisterKeyboardShortcut("History Forward", "Anim Graph Window", Qt::Key_Right, false, false, true); - - shortcutManager->RegisterKeyboardShortcut("Align Left", "Anim Graph Window", Qt::Key_L, true, false, true); - shortcutManager->RegisterKeyboardShortcut("Align Right", "Anim Graph Window", Qt::Key_R, true, false, true); - shortcutManager->RegisterKeyboardShortcut("Align Top", "Anim Graph Window", Qt::Key_T, true, false, true); - shortcutManager->RegisterKeyboardShortcut("Align Bottom", "Anim Graph Window", Qt::Key_B, true, false, true); - - shortcutManager->RegisterKeyboardShortcut("Cut", "Anim Graph Window", Qt::Key_X, true, false, true); - shortcutManager->RegisterKeyboardShortcut("Copy", "Anim Graph Window", Qt::Key_C, true, false, true); - shortcutManager->RegisterKeyboardShortcut("Paste", "Anim Graph Window", Qt::Key_V, true, false, true); - shortcutManager->RegisterKeyboardShortcut("Select All", "Anim Graph Window", Qt::Key_A, true, false, true); - shortcutManager->RegisterKeyboardShortcut("Unselect All", "Anim Graph Window", Qt::Key_D, true, false, true); - shortcutManager->RegisterKeyboardShortcut("Delete Selected Nodes", "Anim Graph Window", Qt::Key_Delete, false, false, true); - } - - // double clicked a node history item in the timeview plugin void AnimGraphPlugin::OnDoubleClickedRecorderNodeHistoryItem(EMotionFX::Recorder::ActorInstanceData* actorInstanceData, EMotionFX::Recorder::NodeHistoryItem* historyItem) { diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h index c1e2004aae..cb8e015429 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h @@ -49,7 +49,6 @@ namespace EMotionFX class AnimGraphObjectFactory; } - namespace EMStudio { // forward declarations @@ -151,8 +150,6 @@ namespace EMStudio void LoadOptions(); void SaveOptions(); - void RegisterKeyboardShortcuts() override; - bool CheckIfCanCreateObject(EMotionFX::AnimGraphObject* parentObject, const EMotionFX::AnimGraphObject* object, EMotionFX::AnimGraphObject::ECategory category) const; void ProcessFrame(float timePassedInSeconds) override; @@ -171,6 +168,27 @@ namespace EMStudio /// Is the given anim graph running on any selected actor instance? bool IsAnimGraphActive(EMotionFX::AnimGraph* animGraph) const; + inline static constexpr AZStd::string_view s_animGraphWindowShortcutGroupName = "Anim Graph Window"; + inline static constexpr AZStd::string_view s_fitEntireGraphShortcutName = "Fit Entire Graph"; + inline static constexpr AZStd::string_view s_zoomOnSelectedNodesShortcutName = "Zoom On Selected Nodes"; + inline static constexpr AZStd::string_view s_openParentNodeShortcutName = "Open Parent Node"; + inline static constexpr AZStd::string_view s_openSelectedNodeShortcutName = "Open Selected Node"; + inline static constexpr AZStd::string_view s_historyBackShortcutName = "History Back"; + inline static constexpr AZStd::string_view s_historyForwardShortcutName = "History Forward"; + inline static constexpr AZStd::string_view s_alignLeftShortcutName = "Align Left"; + inline static constexpr AZStd::string_view s_alignRightShortcutName = "Align Right"; + inline static constexpr AZStd::string_view s_alignTopShortcutName = "Align Top"; + inline static constexpr AZStd::string_view s_alignBottomShortcutName = "Align Bottom"; + inline static constexpr AZStd::string_view s_cutShortcutName = "Cut"; + inline static constexpr AZStd::string_view s_copyShortcutName = "Copy"; + inline static constexpr AZStd::string_view s_pasteShortcutName = "Paste"; + inline static constexpr AZStd::string_view s_selectAllShortcutName = "Select All"; + inline static constexpr AZStd::string_view s_unselectAllShortcutName = "Unselect All"; + inline static constexpr AZStd::string_view s_deleteSelectedNodesShortcutName = "Delete Selected Nodes"; + + signals: + void ActionFilterChanged(); + public slots: void OnFileOpen(); void OnFileSave(); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.cpp index 4203271b58..eccabd37b5 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -40,74 +41,298 @@ namespace EMStudio : QWidget(parentWidget) , m_parentPlugin(plugin) { - for (uint32 i = 0; i < NUM_OPTIONS; ++i) + EMotionFX::ActorEditorRequestBus::Handler::BusConnect(); + } + + void BlendGraphViewWidget::CreateActions() + { + MysticQt::KeyboardShortcutManager* shortcutManager = GetMainWindow()->GetShortcutManager(); + + m_actions[SELECTION_ALIGNLEFT] = new QAction( + QIcon(":/EMotionFX/AlignLeft.svg"), + FromStdString(AnimGraphPlugin::s_alignLeftShortcutName), + this); + m_actions[SELECTION_ALIGNLEFT]->setShortcut(Qt::Key_L | Qt::ControlModifier); + shortcutManager->RegisterKeyboardShortcut(m_actions[SELECTION_ALIGNLEFT], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[SELECTION_ALIGNLEFT], &QAction::triggered, &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::AlignLeft); + + m_actions[SELECTION_ALIGNRIGHT] = new QAction( + QIcon(":/EMotionFX/AlignRight.svg"), + FromStdString(AnimGraphPlugin::s_alignRightShortcutName), + this); + m_actions[SELECTION_ALIGNRIGHT]->setShortcut(Qt::Key_R | Qt::ControlModifier); + shortcutManager->RegisterKeyboardShortcut(m_actions[SELECTION_ALIGNRIGHT], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[SELECTION_ALIGNRIGHT], &QAction::triggered, &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::AlignRight); + + m_actions[SELECTION_ALIGNTOP] = new QAction( + QIcon(":/EMotionFX/AlignTop.svg"), + FromStdString(AnimGraphPlugin::s_alignTopShortcutName), + this); + m_actions[SELECTION_ALIGNTOP]->setShortcut(Qt::Key_T | Qt::ControlModifier); + shortcutManager->RegisterKeyboardShortcut(m_actions[SELECTION_ALIGNTOP], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[SELECTION_ALIGNTOP], &QAction::triggered, &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::AlignTop); + + m_actions[SELECTION_ALIGNBOTTOM] = new QAction( + QIcon(":/EMotionFX/AlignBottom.svg"), + FromStdString(AnimGraphPlugin::s_alignBottomShortcutName), + this); + m_actions[SELECTION_ALIGNBOTTOM]->setShortcut(Qt::Key_B | Qt::ControlModifier); + shortcutManager->RegisterKeyboardShortcut(m_actions[SELECTION_ALIGNBOTTOM], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[SELECTION_ALIGNBOTTOM], &QAction::triggered, &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::AlignBottom); + + m_actions[SELECTION_SELECTALL] = new QAction( + FromStdString(AnimGraphPlugin::s_selectAllShortcutName), + this + ); + m_actions[SELECTION_SELECTALL]->setShortcut(Qt::Key_A | Qt::ControlModifier); + shortcutManager->RegisterKeyboardShortcut(m_actions[SELECTION_SELECTALL], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[SELECTION_SELECTALL], &QAction::triggered, [this] { - m_actions[i] = nullptr; + NodeGraph* activeGraph = m_parentPlugin->GetGraphWidget()->GetActiveGraph(); + if (activeGraph) + { + activeGraph->SelectAllNodes(); + } + }); + + m_actions[SELECTION_UNSELECTALL] = new QAction( + FromStdString(AnimGraphPlugin::s_unselectAllShortcutName), + this + ); + m_actions[SELECTION_UNSELECTALL]->setShortcut(Qt::Key_D | Qt::ControlModifier); + shortcutManager->RegisterKeyboardShortcut(m_actions[SELECTION_UNSELECTALL], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[SELECTION_UNSELECTALL], &QAction::triggered, [this] + { + NodeGraph* activeGraph = m_parentPlugin->GetGraphWidget()->GetActiveGraph(); + if (activeGraph) + { + activeGraph->UnselectAllNodes(); + } + }); + + m_actions[FILE_NEW] = new QAction( + QIcon(":/EMotionFX/Plus.svg"), + tr("Create a new anim graph"), + this); + m_actions[FILE_NEW]->setObjectName("EMFX.BlendGraphViewWidget.NewButton"); + connect(m_actions[FILE_NEW], &QAction::triggered, this, &BlendGraphViewWidget::OnCreateAnimGraph); + + m_actions[FILE_OPEN] = new QAction( + tr("Open..."), + this); + connect(m_actions[FILE_OPEN], &QAction::triggered, m_parentPlugin, &AnimGraphPlugin::OnFileOpen); + + m_actions[FILE_SAVE] = new QAction( + tr("Save"), + this); + connect(m_actions[FILE_SAVE], &QAction::triggered, m_parentPlugin, &AnimGraphPlugin::OnFileSave); + + m_actions[FILE_SAVEAS] = new QAction( + tr("Save as..."), + this); + connect(m_actions[FILE_SAVEAS], &QAction::triggered, m_parentPlugin, &AnimGraphPlugin::OnFileSaveAs); + + m_actions[NAVIGATION_FORWARD] = new QAction( + QIcon(":/EMotionFX/Forward.svg"), + FromStdString(AnimGraphPlugin::s_historyForwardShortcutName), + this); + m_actions[NAVIGATION_FORWARD]->setShortcut(Qt::Key_Right); + shortcutManager->RegisterKeyboardShortcut(m_actions[NAVIGATION_FORWARD], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[NAVIGATION_FORWARD], &QAction::triggered, [this] + { + m_parentPlugin->GetNavigationHistory()->StepForward(); + UpdateNavigation(); + }); + + m_actions[NAVIGATION_BACK] = new QAction( + QIcon(":/EMotionFX/Backward.svg"), + FromStdString(AnimGraphPlugin::s_historyBackShortcutName), + this); + m_actions[NAVIGATION_BACK]->setShortcut(Qt::Key_Left); + shortcutManager->RegisterKeyboardShortcut(m_actions[NAVIGATION_BACK], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[NAVIGATION_BACK], &QAction::triggered, [this] + { + m_parentPlugin->GetNavigationHistory()->StepBackward(); + UpdateNavigation(); + }); + + m_actions[NAVIGATION_NAVPANETOGGLE] = new QAction( + QIcon(":/EMotionFX/List.svg"), + tr("Show/hide navigation pane"), + this); + connect(m_actions[NAVIGATION_NAVPANETOGGLE], &QAction::triggered, this, &BlendGraphViewWidget::ToggleNavigationPane); + + m_actions[NAVIGATION_OPEN_SELECTED] = new QAction( + FromStdString(AnimGraphPlugin::s_openSelectedNodeShortcutName), + this); + m_actions[NAVIGATION_OPEN_SELECTED]->setShortcut(Qt::Key_Down); + shortcutManager->RegisterKeyboardShortcut(m_actions[NAVIGATION_OPEN_SELECTED], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[NAVIGATION_OPEN_SELECTED], &QAction::triggered, &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::NavigateToNode); + + m_actions[NAVIGATION_TO_PARENT] = new QAction( + FromStdString(AnimGraphPlugin::s_openParentNodeShortcutName), + this); + m_actions[NAVIGATION_TO_PARENT]->setShortcut(Qt::Key_Up); + shortcutManager->RegisterKeyboardShortcut(m_actions[NAVIGATION_TO_PARENT], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[NAVIGATION_TO_PARENT], &QAction::triggered, &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::NavigateToParent); + + m_actions[NAVIGATION_FRAME_ALL] = new QAction( + QIcon(":/EMotionFX/ZoomSelected.svg"), + FromStdString(AnimGraphPlugin::s_fitEntireGraphShortcutName), + this); + m_actions[NAVIGATION_FRAME_ALL]->setShortcut(Qt::Key_A); + shortcutManager->RegisterKeyboardShortcut(m_actions[NAVIGATION_FRAME_ALL], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[NAVIGATION_FRAME_ALL], &QAction::triggered, this, &BlendGraphViewWidget::ZoomToAll); + + m_actions[NAVIGATION_ZOOMSELECTION] = new QAction( + QIcon(":/EMotionFX/ZoomSelected.svg"), + FromStdString(AnimGraphPlugin::s_zoomOnSelectedNodesShortcutName), + this); + m_actions[NAVIGATION_ZOOMSELECTION]->setShortcut(Qt::Key_Z); + shortcutManager->RegisterKeyboardShortcut(m_actions[NAVIGATION_ZOOMSELECTION], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[NAVIGATION_ZOOMSELECTION], &QAction::triggered, this, &BlendGraphViewWidget::ZoomSelected); + + m_actions[ACTIVATE_ANIMGRAPH] = new QAction( + QIcon(":/EMotionFX/PlayForward.svg"), + tr("Activate Animgraph/State"), + this); + connect(m_actions[ACTIVATE_ANIMGRAPH], &QAction::triggered, &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::ActivateAnimGraph); + + m_actions[VISUALIZATION_PLAYSPEEDS] = new QAction( + tr("Display Play Speeds"), + this); + m_actions[VISUALIZATION_PLAYSPEEDS]->setCheckable(true); + connect(m_actions[VISUALIZATION_PLAYSPEEDS], &QAction::triggered, this, &BlendGraphViewWidget::OnDisplayPlaySpeeds); + + m_actions[VISUALIZATION_GLOBALWEIGHTS] = new QAction( + tr("Display Global Weights"), + this); + m_actions[VISUALIZATION_GLOBALWEIGHTS]->setCheckable(true); + connect(m_actions[VISUALIZATION_GLOBALWEIGHTS], &QAction::triggered, this, &BlendGraphViewWidget::OnDisplayGlobalWeights); + + m_actions[VISUALIZATION_SYNCSTATUS] = new QAction( + tr("Display Sync Status"), + this); + m_actions[VISUALIZATION_SYNCSTATUS]->setCheckable(true); + connect(m_actions[VISUALIZATION_SYNCSTATUS], &QAction::triggered, this, &BlendGraphViewWidget::OnDisplaySyncStatus); + + m_actions[VISUALIZATION_PLAYPOSITIONS] = new QAction( + tr("Display Play Positions"), + this); + m_actions[VISUALIZATION_PLAYPOSITIONS]->setCheckable(true); + connect(m_actions[VISUALIZATION_PLAYPOSITIONS], &QAction::triggered, this, &BlendGraphViewWidget::OnDisplayPlayPositions); + + m_actions[EDIT_CUT] = new QAction( + FromStdString(AnimGraphPlugin::s_cutShortcutName), + this + ); + m_actions[EDIT_CUT]->setShortcut(Qt::Key_X | Qt::ControlModifier); + shortcutManager->RegisterKeyboardShortcut(m_actions[EDIT_CUT], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[EDIT_CUT], &QAction::triggered, this, [this] + { + m_parentPlugin->GetActionManager().Cut(); + }); + + m_actions[EDIT_COPY] = new QAction( + FromStdString(AnimGraphPlugin::s_copyShortcutName), + this + ); + m_actions[EDIT_COPY]->setShortcut(Qt::Key_C | Qt::ControlModifier); + shortcutManager->RegisterKeyboardShortcut(m_actions[EDIT_COPY], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[EDIT_COPY], &QAction::triggered, this, [this] + { + m_parentPlugin->GetActionManager().Copy(); + }); + + m_actions[EDIT_PASTE] = new QAction( + FromStdString(AnimGraphPlugin::s_pasteShortcutName), + this + ); + m_actions[EDIT_PASTE]->setShortcut(Qt::Key_V | Qt::ControlModifier); + shortcutManager->RegisterKeyboardShortcut(m_actions[EDIT_PASTE], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[EDIT_PASTE], &QAction::triggered, this, [this] + { + const BlendGraphWidget* graphWidget = m_parentPlugin->GetGraphWidget(); + const NodeGraph* activeGraph = graphWidget->GetActiveGraph(); + if (!activeGraph) + { + return; + } + const QPoint pastePosition = graphWidget->underMouse() + ? graphWidget->SnapLocalToGrid(graphWidget->LocalToGlobal(graphWidget->mapFromGlobal(QCursor::pos()))) + : graphWidget->SnapLocalToGrid(graphWidget->LocalToGlobal(graphWidget->rect().center())); + m_parentPlugin->GetActionManager().Paste(activeGraph->GetModelIndex(), pastePosition); + }); + + m_actions[EDIT_DELETE] = new QAction( + FromStdString(AnimGraphPlugin::s_deleteSelectedNodesShortcutName), + this + ); + m_actions[EDIT_DELETE]->setShortcut(Qt::Key_Delete); + shortcutManager->RegisterKeyboardShortcut(m_actions[EDIT_DELETE], AnimGraphPlugin::s_animGraphWindowShortcutGroupName, true); + connect(m_actions[EDIT_DELETE], &QAction::triggered, this, [this] + { + m_parentPlugin->GetGraphWidget()->DeleteSelectedItems(); + }); + + for (QAction* action : m_actions) + { + addAction(action); } - EMotionFX::ActorEditorRequestBus::Handler::BusConnect(); + GetMainWindow()->LoadKeyboardShortcuts(); } QToolBar* BlendGraphViewWidget::CreateTopToolBar() { QToolBar* toolBar = new QToolBar(this); toolBar->setObjectName("EMFX.BlendGraphViewWidget.TopToolBar"); - // Create new anim graph - { - QAction* action = toolBar->addAction(QIcon(":/EMotionFX/Plus.svg"), - tr("Create a new anim graph"), - this, &BlendGraphViewWidget::OnCreateAnimGraph); - action->setObjectName("EMFX.BlendGraphViewWidget.NewButton"); - - //action->setShortcut(QKeySequence::New); - m_actions[FILE_NEW] = action; - } + + toolBar->addAction(m_actions[FILE_NEW]); // Open anim graph { - QAction* action = toolBar->addAction( - QIcon(":/EMotionFX/Open.svg"), - tr("Open anim graph asset")); - m_actions[FILE_OPEN] = action; - - QToolButton* toolButton = qobject_cast(toolBar->widgetForAction(action)); - AZ_Assert(toolButton, "The action widget must be a tool button."); - toolButton->setPopupMode(QToolButton::InstantPopup); - - m_openMenu = new QMenu(toolBar); - action->setMenu(m_openMenu); - BuildOpenMenu(); + m_openMenu = new QMenu(this); connect(m_openMenu, &QMenu::aboutToShow, this, &BlendGraphViewWidget::BuildOpenMenu); + + QAction* action = new QAction( + QIcon(":/EMotionFX/Open.svg"), + tr("Open")); + action->setMenu(m_openMenu); + + QToolButton* button = new QToolButton(); + button->setDefaultAction(action); + button->setPopupMode(QToolButton::InstantPopup); + + toolBar->addWidget(button); } + // Save anim graph { - QAction* saveMenuAction = toolBar->addAction( + QMenu* contextMenu = new QMenu(toolBar); + contextMenu->addAction(m_actions[FILE_SAVE]); + contextMenu->addAction(m_actions[FILE_SAVEAS]); + + QAction* saveMenuAction = new QAction( QIcon(":/EMotionFX/Save.svg"), tr("Save anim graph")); - - QToolButton* toolButton = qobject_cast(toolBar->widgetForAction(saveMenuAction)); - AZ_Assert(toolButton, "The action widget must be a tool button."); - toolButton->setPopupMode(QToolButton::InstantPopup); - - QMenu* contextMenu = new QMenu(toolBar); - - m_actions[FILE_SAVE] = contextMenu->addAction(tr("Save"), m_parentPlugin, &AnimGraphPlugin::OnFileSave); - m_actions[FILE_SAVEAS] = contextMenu->addAction(tr("Save as..."), m_parentPlugin, &AnimGraphPlugin::OnFileSaveAs); - saveMenuAction->setMenu(contextMenu); + + QToolButton* button = new QToolButton(); + button->setDefaultAction(saveMenuAction); + button->setPopupMode(QToolButton::InstantPopup); + + toolBar->addWidget(button); } toolBar->addSeparator(); - m_actions[ACTIVATE_ANIMGRAPH] = toolBar->addAction(QIcon(":/EMotionFX/PlayForward.svg"), - tr("Activate Animgraph/State"), - &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::ActivateAnimGraph); + toolBar->addAction(m_actions[ACTIVATE_ANIMGRAPH]); + toolBar->addSeparator(); - m_actions[SELECTION_ZOOMSELECTION] = toolBar->addAction(QIcon(":/EMotionFX/ZoomSelected.svg"), - tr("Zoom Selection"), - this, &BlendGraphViewWidget::ZoomSelected); + toolBar->addAction(m_actions[NAVIGATION_ZOOMSELECTION]); // Visualization options { @@ -121,15 +346,10 @@ namespace EMStudio QMenu* contextMenu = new QMenu(toolBar); - m_actions[VISUALIZATION_PLAYSPEEDS] = contextMenu->addAction(tr("Display Play Speeds"), this, &BlendGraphViewWidget::OnDisplayPlaySpeeds); - m_actions[VISUALIZATION_GLOBALWEIGHTS] = contextMenu->addAction(tr("Display Global Weights"), this, &BlendGraphViewWidget::OnDisplayGlobalWeights); - m_actions[VISUALIZATION_SYNCSTATUS] = contextMenu->addAction(tr("Display Sync Status"), this, &BlendGraphViewWidget::OnDisplaySyncStatus); - m_actions[VISUALIZATION_PLAYPOSITIONS] = contextMenu->addAction(tr("Display Play Positions"), this, &BlendGraphViewWidget::OnDisplayPlayPositions); - - m_actions[VISUALIZATION_PLAYSPEEDS]->setCheckable(true); - m_actions[VISUALIZATION_GLOBALWEIGHTS]->setCheckable(true); - m_actions[VISUALIZATION_SYNCSTATUS]->setCheckable(true); - m_actions[VISUALIZATION_PLAYPOSITIONS]->setCheckable(true); + contextMenu->addAction(m_actions[VISUALIZATION_PLAYSPEEDS]); + contextMenu->addAction(m_actions[VISUALIZATION_GLOBALWEIGHTS]); + contextMenu->addAction(m_actions[VISUALIZATION_SYNCSTATUS]); + contextMenu->addAction(m_actions[VISUALIZATION_PLAYPOSITIONS]); menuAction->setMenu(contextMenu); } @@ -137,21 +357,10 @@ namespace EMStudio toolBar->addSeparator(); // Alignment Options - m_actions[SELECTION_ALIGNLEFT] = toolBar->addAction(QIcon(":/EMotionFX/AlignLeft.svg"), - tr("Align left"), - &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::AlignLeft); - - m_actions[SELECTION_ALIGNRIGHT] = toolBar->addAction(QIcon(":/EMotionFX/AlignRight.svg"), - tr("Align right"), - &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::AlignRight); - - m_actions[SELECTION_ALIGNTOP] = toolBar->addAction(QIcon(":/EMotionFX/AlignTop.svg"), - tr("Align top"), - &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::AlignTop); - - m_actions[SELECTION_ALIGNBOTTOM] = toolBar->addAction(QIcon(":/EMotionFX/AlignBottom.svg"), - tr("Align bottom"), - &m_parentPlugin->GetActionManager(), &AnimGraphActionManager::AlignBottom); + toolBar->addAction(m_actions[SELECTION_ALIGNLEFT]); + toolBar->addAction(m_actions[SELECTION_ALIGNRIGHT]); + toolBar->addAction(m_actions[SELECTION_ALIGNTOP]); + toolBar->addAction(m_actions[SELECTION_ALIGNBOTTOM]); return toolBar; } @@ -160,27 +369,15 @@ namespace EMStudio { QToolBar* toolBar = new QToolBar(this); - m_actions[NAVIGATION_BACK] = toolBar->addAction(QIcon(":/EMotionFX/Backward.svg"), - tr("Back"), - this, [=] { - m_parentPlugin->GetNavigationHistory()->StepBackward(); - UpdateNavigation(); - }); + toolBar->addAction(m_actions[NAVIGATION_BACK]); - m_actions[NAVIGATION_FORWARD] = toolBar->addAction(QIcon(":/EMotionFX/Forward.svg"), - tr("Forward"), - this, [=] { - m_parentPlugin->GetNavigationHistory()->StepForward(); - UpdateNavigation(); - }); + toolBar->addAction(m_actions[NAVIGATION_FORWARD]); mNavigationLink = new NavigationLinkWidget(m_parentPlugin, this); mNavigationLink->setMinimumHeight(28); toolBar->addWidget(mNavigationLink); - m_actions[NAVIGATION_NAVPANETOGGLE] = toolBar->addAction(QIcon(":/EMotionFX/List.svg"), - tr("Show/hide navigation pane"), - this, &BlendGraphViewWidget::ToggleNavigationPane); + toolBar->addAction(m_actions[NAVIGATION_NAVPANETOGGLE]); return toolBar; } @@ -188,8 +385,11 @@ namespace EMStudio void BlendGraphViewWidget::Init(BlendGraphWidget* blendGraphWidget) { connect(&m_parentPlugin->GetAnimGraphModel(), &AnimGraphModel::FocusChanged, this, &BlendGraphViewWidget::OnFocusChanged); - connect(&m_parentPlugin->GetAnimGraphModel().GetSelectionModel(), &QItemSelectionModel::selectionChanged, this, &BlendGraphViewWidget::UpdateSelection); + connect(&m_parentPlugin->GetAnimGraphModel().GetSelectionModel(), &QItemSelectionModel::selectionChanged, this, &BlendGraphViewWidget::UpdateEnabledActions); connect(m_parentPlugin->GetNavigationHistory(), &NavigationHistory::ChangedSteppingLimits, this, &BlendGraphViewWidget::UpdateNavigation); + connect(m_parentPlugin->GetGraphWidget(), &NodeGraphWidget::ActiveGraphChanged, this, &BlendGraphViewWidget::UpdateEnabledActions); + connect(m_parentPlugin, &AnimGraphPlugin::ActionFilterChanged, this, &BlendGraphViewWidget::UpdateEnabledActions); + connect(&m_parentPlugin->GetActionManager(), &AnimGraphActionManager::PasteStateChanged, this, &BlendGraphViewWidget::UpdateEnabledActions); // create the vertical layout with the menu and the graph widget as entries QVBoxLayout* verticalLayout = new QVBoxLayout(this); @@ -198,6 +398,7 @@ namespace EMStudio verticalLayout->setMargin(2); // Create toolbars + CreateActions(); verticalLayout->addWidget(CreateTopToolBar()); verticalLayout->addWidget(CreateNavigationToolBar()); @@ -217,7 +418,7 @@ namespace EMStudio UpdateNavigation(); UpdateAnimGraphOptions(); - UpdateSelection(); + UpdateEnabledActions(); } BlendGraphViewWidget::~BlendGraphViewWidget() @@ -252,47 +453,35 @@ namespace EMStudio } } - void BlendGraphViewWidget::UpdateSelection() + void BlendGraphViewWidget::UpdateEnabledActions() { // do we have any selection? const bool anySelection = m_parentPlugin->GetAnimGraphModel().GetSelectionModel().hasSelection(); - SetOptionEnabled(SELECTION_ZOOMSELECTION, anySelection); + SetOptionEnabled(NAVIGATION_ZOOMSELECTION, anySelection); - QModelIndex firstSelectedNode; - bool atLeastTwoNodes = false; + const auto isNodeSelected = [](const QModelIndex& index) + { + return index.isValid() + && index.data(AnimGraphModel::ROLE_MODEL_ITEM_TYPE).value() == AnimGraphModel::ModelItemType::NODE; + }; const QModelIndexList selectedIndexes = m_parentPlugin->GetAnimGraphModel().GetSelectionModel().selectedRows(); - for (const QModelIndex& selected : selectedIndexes) - { - const AnimGraphModel::ModelItemType itemType = selected.data(AnimGraphModel::ROLE_MODEL_ITEM_TYPE).value(); - if (itemType == AnimGraphModel::ModelItemType::NODE) - { - if (firstSelectedNode.isValid()) - { - atLeastTwoNodes = true; - break; - } - else - { - firstSelectedNode = selected; - } - } - } + const auto firstSelectedNode = AZStd::find_if(selectedIndexes.begin(), selectedIndexes.end(), isNodeSelected); + const auto secondSelectedNode = AZStd::find_if(firstSelectedNode, selectedIndexes.end(), isNodeSelected); + const bool atLeastTwoNodes = secondSelectedNode != selectedIndexes.end(); - if (m_parentPlugin->GetActionFilter().m_editNodes && - atLeastTwoNodes) - { - SetOptionEnabled(SELECTION_ALIGNLEFT, true); - SetOptionEnabled(SELECTION_ALIGNRIGHT, true); - SetOptionEnabled(SELECTION_ALIGNTOP, true); - SetOptionEnabled(SELECTION_ALIGNBOTTOM, true); - } - else - { - SetOptionEnabled(SELECTION_ALIGNLEFT, false); - SetOptionEnabled(SELECTION_ALIGNRIGHT, false); - SetOptionEnabled(SELECTION_ALIGNTOP, false); - SetOptionEnabled(SELECTION_ALIGNBOTTOM, false); - } + const bool enableAlignActions = m_parentPlugin->GetActionFilter().m_editNodes && atLeastTwoNodes; + SetOptionEnabled(SELECTION_ALIGNLEFT, enableAlignActions); + SetOptionEnabled(SELECTION_ALIGNRIGHT, enableAlignActions); + SetOptionEnabled(SELECTION_ALIGNTOP, enableAlignActions); + SetOptionEnabled(SELECTION_ALIGNBOTTOM, enableAlignActions); + + const bool isEditable = m_parentPlugin->GetGraphWidget()->GetActiveGraph() && !m_parentPlugin->GetGraphWidget()->GetActiveGraph()->IsInReferencedGraph(); + const AnimGraphActionFilter& actionFilter = m_parentPlugin->GetActionFilter(); + + SetOptionEnabled(EDIT_CUT, actionFilter.m_copyAndPaste && anySelection && isEditable); + SetOptionEnabled(EDIT_COPY, actionFilter.m_copyAndPaste && anySelection); + SetOptionEnabled(EDIT_PASTE, actionFilter.m_copyAndPaste && isEditable && m_parentPlugin->GetActionManager().GetIsReadyForPaste()); + SetOptionEnabled(EDIT_DELETE, actionFilter.m_copyAndPaste && anySelection && isEditable); } AnimGraphNodeWidget* BlendGraphViewWidget::GetWidgetForNode(const EMotionFX::AnimGraphNode* node) @@ -375,19 +564,17 @@ namespace EMStudio void BlendGraphViewWidget::SetOptionFlag(EOptionFlag option, bool isEnabled) { - const uint32 optionIndex = (uint32)option; - if (m_actions[optionIndex]) + if (m_actions[option]) { - m_actions[optionIndex]->setChecked(isEnabled); + m_actions[option]->setChecked(isEnabled); } } void BlendGraphViewWidget::SetOptionEnabled(EOptionFlag option, bool isEnabled) { - const uint32 optionIndex = (uint32)option; - if (m_actions[optionIndex]) + if (m_actions[option]) { - m_actions[optionIndex]->setEnabled(isEnabled); + m_actions[option]->setEnabled(isEnabled); } } @@ -395,8 +582,7 @@ namespace EMStudio { m_openMenu->clear(); - m_actions[FILE_OPEN] = m_openMenu->addAction(tr("Open...")); - connect(m_actions[FILE_OPEN], &QAction::triggered, m_parentPlugin, &AnimGraphPlugin::OnFileOpen); + m_openMenu->addAction(m_actions[FILE_OPEN]); const uint32 numAnimGraphs = EMotionFX::GetAnimGraphManager().GetNumAnimGraphs(); if (numAnimGraphs > 0) @@ -521,6 +707,19 @@ namespace EMStudio } } + void BlendGraphViewWidget::ZoomToAll() + { + BlendGraphWidget* blendGraphWidget = m_parentPlugin->GetGraphWidget(); + if (blendGraphWidget) + { + NodeGraph* nodeGraph = blendGraphWidget->GetActiveGraph(); + if (nodeGraph) + { + nodeGraph->FitGraphOnScreen(geometry().width(), geometry().height(), blendGraphWidget->GetMousePos()); + } + } + } + void BlendGraphViewWidget::OnActivateState() { // Transition to the selected state. @@ -546,7 +745,6 @@ namespace EMStudio } } - void BlendGraphViewWidget::NavigateToRoot() { const QModelIndex nodeModelIndex = m_parentPlugin->GetGraphWidget()->GetActiveGraph()->GetModelIndex(); @@ -556,20 +754,6 @@ namespace EMStudio } } - - void BlendGraphViewWidget::NavigateToParent() - { - const QModelIndex parentFocus = m_parentPlugin->GetAnimGraphModel().GetParentFocus(); - if (parentFocus.isValid()) - { - QModelIndex newParentFocus = parentFocus.model()->parent(parentFocus); - if (newParentFocus.isValid()) - { - m_parentPlugin->GetAnimGraphModel().Focus(newParentFocus); - } - } - } - void BlendGraphViewWidget::ToggleNavigationPane() { QList sizes = m_viewportSplitter->sizes(); @@ -588,16 +772,6 @@ namespace EMStudio m_viewportSplitter->setSizes(sizes); } - void BlendGraphViewWidget::NavigateToNode() - { - const QModelIndexList currentModelIndexes = m_parentPlugin->GetAnimGraphModel().GetSelectionModel().selectedRows(); - if (!currentModelIndexes.empty()) - { - const QModelIndex currentModelIndex = currentModelIndexes.front(); - m_parentPlugin->GetAnimGraphModel().Focus(currentModelIndex); - } - } - // toggle playspeed viz void BlendGraphViewWidget::OnDisplayPlaySpeeds() { @@ -638,36 +812,4 @@ namespace EMStudio EMotionFX::AnimGraphEditorNotificationBus::Broadcast(&EMotionFX::AnimGraphEditorNotificationBus::Events::OnShow); } - void BlendGraphViewWidget::keyPressEvent(QKeyEvent* event) - { - switch (event->key()) - { - case Qt::Key_Backspace: - { - m_parentPlugin->GetNavigationHistory()->StepBackward(); - event->accept(); - break; - } - - default: - event->ignore(); - } - } - - - // on key release - void BlendGraphViewWidget::keyReleaseEvent(QKeyEvent* event) - { - switch (event->key()) - { - case Qt::Key_Backspace: - { - event->accept(); - break; - } - - default: - event->ignore(); - } - } } // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.h index dbc200856a..196fadb115 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.h @@ -53,25 +53,32 @@ namespace EMStudio public: enum EOptionFlag { - SELECTION_ALIGNLEFT = 0, - SELECTION_ALIGNRIGHT = 1, - SELECTION_ALIGNTOP = 2, - SELECTION_ALIGNBOTTOM = 3, - FILE_NEW = 4, - FILE_OPENFILE = 5, - FILE_OPEN = 6, - FILE_SAVE = 7, - FILE_SAVEAS = 8, - NAVIGATION_FORWARD = 9, - NAVIGATION_BACK = 10, - NAVIGATION_NAVPANETOGGLE = 11, - SELECTION_ZOOMSELECTION = 12, - ACTIVATE_ANIMGRAPH = 13, - WINDOWS_NODEGROUPWINDOW = 14, - VISUALIZATION_PLAYSPEEDS = 15, - VISUALIZATION_GLOBALWEIGHTS = 16, - VISUALIZATION_SYNCSTATUS = 17, - VISUALIZATION_PLAYPOSITIONS = 18, + SELECTION_ALIGNLEFT, + SELECTION_ALIGNRIGHT, + SELECTION_ALIGNTOP, + SELECTION_ALIGNBOTTOM, + SELECTION_SELECTALL, + SELECTION_UNSELECTALL, + FILE_NEW, + FILE_OPEN, + FILE_SAVE, + FILE_SAVEAS, + NAVIGATION_FORWARD, + NAVIGATION_BACK, + NAVIGATION_NAVPANETOGGLE, + NAVIGATION_OPEN_SELECTED, + NAVIGATION_TO_PARENT, + NAVIGATION_FRAME_ALL, + NAVIGATION_ZOOMSELECTION, + ACTIVATE_ANIMGRAPH, + VISUALIZATION_PLAYSPEEDS, + VISUALIZATION_GLOBALWEIGHTS, + VISUALIZATION_SYNCSTATUS, + VISUALIZATION_PLAYPOSITIONS, + EDIT_CUT, + EDIT_COPY, + EDIT_PASTE, + EDIT_DELETE, NUM_OPTIONS //automatically gets the next number assigned }; @@ -85,13 +92,12 @@ namespace EMStudio void Init(BlendGraphWidget* blendGraphWidget); void UpdateAnimGraphOptions(); - void UpdateSelection(); + void UpdateEnabledActions(); // If there is a specific widget to handle this node returns that. // Else, returns nullptr. AnimGraphNodeWidget* GetWidgetForNode(const EMotionFX::AnimGraphNode* node); - // Get Actions (used for testing purposes) QAction* GetAction(EOptionFlag option) const { return m_actions[option]; } public slots: @@ -100,11 +106,10 @@ namespace EMStudio void OnCreateAnimGraph(); void NavigateToRoot(); - void NavigateToNode(); - void NavigateToParent(); void ToggleNavigationPane(); void ZoomSelected(); + void ZoomToAll(); void OnActivateState(); @@ -122,17 +127,15 @@ namespace EMStudio void showEvent(QShowEvent* showEvent); - void keyReleaseEvent(QKeyEvent* event) override; - void keyPressEvent(QKeyEvent* event) override; - private: + void CreateActions(); QToolBar* CreateTopToolBar(); QToolBar* CreateNavigationToolBar(); QMenuBar* m_menu = nullptr; QMenu* m_openMenu = nullptr; QHBoxLayout* m_toolbarLayout = nullptr; - QAction* m_actions[NUM_OPTIONS]; + AZStd::array m_actions{}; AnimGraphPlugin* m_parentPlugin = nullptr; NavigationLinkWidget* mNavigationLink = nullptr; QStackedWidget m_viewportStack; diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp index 7cd5a2d849..623f9f94a9 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.cpp @@ -71,12 +71,6 @@ namespace EMStudio } - // destructor - BlendGraphWidget::~BlendGraphWidget() - { - } - - // when dropping stuff in our window void BlendGraphWidget::dropEvent(QDropEvent* event) { @@ -1555,254 +1549,6 @@ namespace EMStudio } - // on keypress - void BlendGraphWidget::keyPressEvent(QKeyEvent* event) - { - MysticQt::KeyboardShortcutManager* shortcutManager = GetMainWindow()->GetShortcutManager(); - const AnimGraphActionFilter& actionFilter = mPlugin->GetActionFilter(); - - if (shortcutManager->Check(event, "Open Parent Node", "Anim Graph Window")) - { - const QModelIndex parentFocus = mPlugin->GetAnimGraphModel().GetParentFocus(); - if (parentFocus.isValid()) - { - QModelIndex newParentFocus = parentFocus.model()->parent(parentFocus); - if (newParentFocus.isValid()) - { - mPlugin->GetAnimGraphModel().Focus(newParentFocus); - } - } - event->accept(); - return; - } - - if (shortcutManager->Check(event, "Open Selected Node", "Anim Graph Window")) - { - mPlugin->GetActionManager().NavigateToNode(); - event->accept(); - return; - } - - if (shortcutManager->Check(event, "History Back", "Anim Graph Window")) - { - mPlugin->GetNavigationHistory()->StepBackward(); - event->accept(); - return; - } - - if (shortcutManager->Check(event, "History Forward", "Anim Graph Window")) - { - mPlugin->GetNavigationHistory()->StepForward(); - event->accept(); - return; - } - - if (mActiveGraph && - !mActiveGraph->IsInReferencedGraph()) - { - if (actionFilter.m_editNodes) - { - if (shortcutManager->Check(event, "Align Left", "Anim Graph Window")) - { - mPlugin->GetActionManager().AlignLeft(); - event->accept(); - return; - } - - if (shortcutManager->Check(event, "Align Right", "Anim Graph Window")) - { - mPlugin->GetActionManager().AlignRight(); - event->accept(); - return; - } - - if (shortcutManager->Check(event, "Align Top", "Anim Graph Window")) - { - mPlugin->GetActionManager().AlignTop(); - event->accept(); - return; - } - - if (shortcutManager->Check(event, "Align Bottom", "Anim Graph Window")) - { - mPlugin->GetActionManager().AlignBottom(); - event->accept(); - return; - } - } - - if (actionFilter.m_copyAndPaste && - shortcutManager->Check(event, "Cut", "Anim Graph Window")) - { - mPlugin->GetActionManager().Cut(); - event->accept(); - return; - } - } - - if (actionFilter.m_copyAndPaste) - { - if (shortcutManager->Check(event, "Copy", "Anim Graph Window")) - { - mPlugin->GetActionManager().Copy(); - event->accept(); - return; - } - - if (shortcutManager->Check(event, "Paste", "Anim Graph Window")) - { - if (mActiveGraph && !mActiveGraph->IsInReferencedGraph()) - { - if (mPlugin->GetActionManager().GetIsReadyForPaste()) - { - QModelIndex modelIndex = GetActiveGraph()->GetModelIndex(); - if (modelIndex.isValid()) - { - if (rect().contains(mapFromGlobal(QCursor::pos())) == false) - { - mPlugin->GetActionManager().Paste(modelIndex, GetMousePos()); - event->accept(); - } - } - } - } - return; - } - } - - if (shortcutManager->Check(event, "Select All", "Anim Graph Window")) - { - if (mActiveGraph) - { - mActiveGraph->SelectAllNodes(); - event->accept(); - } - return; - } - - if (shortcutManager->Check(event, "Unselect All", "Anim Graph Window")) - { - if (mActiveGraph) - { - mActiveGraph->UnselectAllNodes(); - event->accept(); - } - return; - } - - if (mActiveGraph && - actionFilter.m_delete && - !mActiveGraph->IsInReferencedGraph() && - shortcutManager->Check(event, "Delete Selected Nodes", "Anim Graph Window")) - { - DeleteSelectedItems(); - event->accept(); - return; - } - - return NodeGraphWidget::keyPressEvent(event); - } - - - // on key release - void BlendGraphWidget::keyReleaseEvent(QKeyEvent* event) - { - MysticQt::KeyboardShortcutManager* shortcutManager = GetMainWindow()->GetShortcutManager(); - const AnimGraphActionFilter& actionFilter = mPlugin->GetActionFilter(); - - if (shortcutManager->Check(event, "Open Parent Node", "Anim Graph Window")) - { - event->accept(); - return; - } - if (shortcutManager->Check(event, "Open Selected Node", "Anim Graph Window")) - { - event->accept(); - return; - } - if (shortcutManager->Check(event, "History Back", "Anim Graph Window")) - { - event->accept(); - return; - } - if (shortcutManager->Check(event, "History Forward", "Anim Graph Window")) - { - event->accept(); - return; - } - - if (mActiveGraph && !mActiveGraph->IsInReferencedGraph()) - { - if (actionFilter.m_editNodes) - { - if (shortcutManager->Check(event, "Align Left", "Anim Graph Window")) - { - event->accept(); - return; - } - if (shortcutManager->Check(event, "Align Right", "Anim Graph Window")) - { - event->accept(); - return; - } - if (shortcutManager->Check(event, "Align Top", "Anim Graph Window")) - { - event->accept(); - return; - } - if (shortcutManager->Check(event, "Align Bottom", "Anim Graph Window")) - { - event->accept(); - return; - } - } - - if (actionFilter.m_copyAndPaste && - shortcutManager->Check(event, "Cut", "Anim Graph Window")) - { - event->accept(); - return; - } - } - - if (actionFilter.m_copyAndPaste) - { - if (shortcutManager->Check(event, "Copy", "Anim Graph Window")) - { - event->accept(); - return; - } - if (mActiveGraph && !mActiveGraph->IsInReferencedGraph() && shortcutManager->Check(event, "Paste", "Anim Graph Window")) - { - event->accept(); - return; - } - } - - if (shortcutManager->Check(event, "Select All", "Anim Graph Window")) - { - event->accept(); - return; - } - if (shortcutManager->Check(event, "Unselect All", "Anim Graph Window")) - { - event->accept(); - return; - } - - if (mActiveGraph && - actionFilter.m_delete && - !mActiveGraph->IsInReferencedGraph() && - shortcutManager->Check(event, "Delete Selected Nodes", "Anim Graph Window")) - { - event->accept(); - return; - } - - return NodeGraphWidget::keyReleaseEvent(event); - } - - void BlendGraphWidget::OnRowsInserted(const QModelIndex& parent, int first, int last) { // Here we could be receiving connections, transitions or nodes being inserted into diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.h index f5c5d4a5ea..7453e4cc53 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.h @@ -45,7 +45,6 @@ namespace EMStudio public: BlendGraphWidget(AnimGraphPlugin* plugin, QWidget* parent); - ~BlendGraphWidget(); // overloaded bool CheckIfIsCreateConnectionValid(uint32 portNr, GraphNode* portNode, NodePort* port, bool isInputPort) override; @@ -120,8 +119,6 @@ namespace EMStudio void OnSelectionModelChanged(const QItemSelection& selected, const QItemSelection& deselected); private: - void keyReleaseEvent(QKeyEvent* event) override; - void keyPressEvent(QKeyEvent* event) override; EMotionFX::AnimGraphStateTransition* FindTransitionForConnection(NodeConnection* connection) const; EMotionFX::BlendTreeConnection* FindBlendTreeConnection(NodeConnection* connection) const; diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/ContextMenu.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/ContextMenu.cpp index 8866ec678e..80603c37bf 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/ContextMenu.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/ContextMenu.cpp @@ -183,17 +183,11 @@ namespace EMStudio if (graphNode == nullptr) { QMenu* menu = new QMenu(parentWidget); - if (actionFilter.m_copyAndPaste && actionManager.GetIsReadyForPaste()) - { - const QModelIndex modelIndex = nodeGraph->GetModelIndex(); - if (modelIndex.isValid()) - { - localMousePos = SnapLocalToGrid(LocalToGlobal(localMousePos)); - QAction* pasteAction = menu->addAction("Paste"); - connect(pasteAction, &QAction::triggered, [&actionManager, modelIndex, localMousePos]() { actionManager.Paste(modelIndex, localMousePos); }); - menu->addSeparator(); - } + if (actionFilter.m_copyAndPaste && actionManager.GetIsReadyForPaste() && nodeGraph->GetModelIndex().isValid()) + { + menu->addAction(viewWidget->GetAction(BlendGraphViewWidget::EDIT_PASTE)); + menu->addSeparator(); } if (actionFilter.m_createNodes) @@ -324,8 +318,7 @@ namespace EMStudio // we can only go to the selected node in case the selected node has a visual graph (state machine / blend tree) if (animGraphNode->GetHasVisualGraph()) { - QAction* goToNodeAction = menu->addAction("Open Selected Node"); - connect(goToNodeAction, &QAction::triggered, &actionManager, &AnimGraphActionManager::NavigateToNode); + menu->addAction(viewWidget->GetAction(BlendGraphViewWidget::NAVIGATION_OPEN_SELECTED)); menu->addSeparator(); } @@ -360,20 +353,17 @@ namespace EMStudio if (!inReferenceGraph) { // cut and copy actions - QAction* cutAction = menu->addAction("Cut"); - connect(cutAction, &QAction::triggered, &actionManager, &AnimGraphActionManager::Cut); + menu->addAction(viewWidget->GetAction(BlendGraphViewWidget::EDIT_CUT)); } - QAction* ccopyAction = menu->addAction("Copy"); - connect(ccopyAction, &QAction::triggered, &actionManager, &AnimGraphActionManager::Copy); + menu->addAction(viewWidget->GetAction(BlendGraphViewWidget::EDIT_COPY)); menu->addSeparator(); } if (actionFilter.m_delete && !inReferenceGraph) { - QAction* removeNodeAction = menu->addAction("Delete Node"); - connect(removeNodeAction, &QAction::triggered, &actionManager, &AnimGraphActionManager::DeleteSelectedNodes); + menu->addAction(viewWidget->GetAction(BlendGraphViewWidget::EDIT_DELETE)); menu->addSeparator(); } } @@ -403,22 +393,14 @@ namespace EMStudio if (actionFilter.m_editNodes && !inReferenceGraph) { - QAction* alignLeftAction = menu.addAction("Align Left"); - QAction* alignRightAction = menu.addAction("Align Right"); - QAction* alignTopAction = menu.addAction("Align Top"); - QAction* alignBottomAction = menu.addAction("Align Bottom"); - - - connect(alignLeftAction, &QAction::triggered, &actionManager, &AnimGraphActionManager::AlignLeft); - connect(alignRightAction, &QAction::triggered, &actionManager, &AnimGraphActionManager::AlignRight); - connect(alignTopAction, &QAction::triggered, &actionManager, &AnimGraphActionManager::AlignTop); - connect(alignBottomAction, &QAction::triggered, &actionManager, &AnimGraphActionManager::AlignBottom); - + menu.addAction(viewWidget->GetAction(BlendGraphViewWidget::SELECTION_ALIGNLEFT)); + menu.addAction(viewWidget->GetAction(BlendGraphViewWidget::SELECTION_ALIGNRIGHT)); + menu.addAction(viewWidget->GetAction(BlendGraphViewWidget::SELECTION_ALIGNTOP)); + menu.addAction(viewWidget->GetAction(BlendGraphViewWidget::SELECTION_ALIGNBOTTOM)); menu.addSeparator(); } - QAction* zoomSelectionAction = menu.addAction("Zoom Selection"); - connect(zoomSelectionAction, &QAction::triggered, viewWidget, &BlendGraphViewWidget::ZoomSelected); + menu.addAction(viewWidget->GetAction(BlendGraphViewWidget::NAVIGATION_ZOOMSELECTION)); menu.addSeparator(); @@ -494,12 +476,10 @@ namespace EMStudio if (!inReferenceGraph) { - QAction* cutAction = menu.addAction("Cut"); - connect(cutAction, &QAction::triggered, &actionManager, &AnimGraphActionManager::Cut); + menu.addAction(viewWidget->GetAction(BlendGraphViewWidget::EDIT_CUT)); } - QAction* ccopyAction = menu.addAction("Copy"); - connect(ccopyAction, &QAction::triggered, &actionManager, &AnimGraphActionManager::Copy); + menu.addAction(viewWidget->GetAction(BlendGraphViewWidget::EDIT_COPY)); } menu.addSeparator(); @@ -507,8 +487,7 @@ namespace EMStudio if (actionFilter.m_delete && !inReferenceGraph) { - QAction* removeNodesAction = menu.addAction("Delete Nodes"); - connect(removeNodesAction, &QAction::triggered, &actionManager, &AnimGraphActionManager::DeleteSelectedNodes); + menu.addAction(viewWidget->GetAction(BlendGraphViewWidget::EDIT_DELETE)); menu.addSeparator(); } @@ -526,4 +505,4 @@ namespace EMStudio } } } -} +} // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraphWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraphWidget.cpp index eae890c69d..f102cc5d96 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraphWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraphWidget.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -155,6 +154,11 @@ namespace EMStudio // set the active graph void NodeGraphWidget::SetActiveGraph(NodeGraph* graph) { + if (mActiveGraph == graph) + { + return; + } + if (mActiveGraph) { mActiveGraph->StopCreateConnection(); @@ -165,6 +169,8 @@ namespace EMStudio mActiveGraph = graph; mMoveNode = nullptr; + + emit ActiveGraphChanged(); } @@ -322,7 +328,7 @@ namespace EMStudio // convert to a global position - QPoint NodeGraphWidget::LocalToGlobal(const QPoint& inPoint) + QPoint NodeGraphWidget::LocalToGlobal(const QPoint& inPoint) const { if (mActiveGraph) { @@ -334,7 +340,7 @@ namespace EMStudio // convert to a local position - QPoint NodeGraphWidget::GlobalToLocal(const QPoint& inPoint) + QPoint NodeGraphWidget::GlobalToLocal(const QPoint& inPoint) const { if (mActiveGraph) { @@ -345,7 +351,7 @@ namespace EMStudio } - QPoint NodeGraphWidget::SnapLocalToGrid(const QPoint& inPoint, uint32 cellSize) + QPoint NodeGraphWidget::SnapLocalToGrid(const QPoint& inPoint, uint32 cellSize) const { MCORE_UNUSED(cellSize); @@ -1491,45 +1497,9 @@ namespace EMStudio } } - MysticQt::KeyboardShortcutManager* shortcutManager = GetMainWindow()->GetShortcutManager(); - - if (shortcutManager->Check(event, "Fit Entire Graph", "Anim Graph Window")) - { - // zoom to fit the entire graph in view - if (mActiveGraph) - { - mActiveGraph->FitGraphOnScreen(geometry().width(), geometry().height(), GetMousePos()); - } - - event->accept(); - return; - } - - if (shortcutManager->Check(event, "Zoom On Selected Nodes", "Anim Graph Window")) - { - if (mActiveGraph) - { - // try zooming on the selection rect - QRect selectionRect = mActiveGraph->CalcRectFromSelection(true); - if (selectionRect.isEmpty() == false) - { - mActiveGraph->ZoomOnRect(selectionRect, geometry().width(), geometry().height()); - //update(); - } - else // zoom on the full scene - { - mActiveGraph->FitGraphOnScreen(geometry().width(), geometry().height(), GetMousePos()); - } - } - - event->accept(); - return; - } - event->ignore(); } - // on key release void NodeGraphWidget::keyReleaseEvent(QKeyEvent* event) { @@ -1552,20 +1522,6 @@ namespace EMStudio } } - MysticQt::KeyboardShortcutManager* shortcutManager = GetMainWindow()->GetShortcutManager(); - - if (shortcutManager->Check(event, "Fit Entire Graph", "Anim Graph Window")) - { - event->accept(); - return; - } - - if (shortcutManager->Check(event, "Zoom On Selected Nodes", "Anim Graph Window")) - { - event->accept(); - return; - } - event->ignore(); } diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraphWidget.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraphWidget.h index 68e9f72209..9b8d8c6ace 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraphWidget.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraphWidget.h @@ -65,9 +65,9 @@ namespace EMStudio uint32 CalcNumSelectedNodes() const; - QPoint LocalToGlobal(const QPoint& inPoint); - QPoint GlobalToLocal(const QPoint& inPoint); - QPoint SnapLocalToGrid(const QPoint& inPoint, uint32 cellSize = 10); + QPoint LocalToGlobal(const QPoint& inPoint) const; + QPoint GlobalToLocal(const QPoint& inPoint) const; + QPoint SnapLocalToGrid(const QPoint& inPoint, uint32 cellSize = 10) const; void CalcSelectRect(QRect& outRect); @@ -106,6 +106,9 @@ namespace EMStudio const QString& GetTitleBarText() const { return m_titleBarText; } void SetTitleBarText(const QString& text) { m_titleBarText = text; } + signals: + void ActiveGraphChanged(); + protected: //virtual void paintEvent(QPaintEvent* event); void mouseMoveEvent(QMouseEvent* event) override; @@ -160,4 +163,4 @@ namespace EMStudio float m_borderOverwriteWidth; QString m_titleBarText; }; -} // namespace EMStudio +} // namespace EMStudio diff --git a/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.cpp b/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.cpp index 202feb3d18..0d44330b34 100644 --- a/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.cpp +++ b/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.cpp @@ -12,6 +12,8 @@ // include required headers #include "KeyboardShortcutManager.h" +#include +#include #include #include @@ -19,52 +21,27 @@ #include #include - namespace MysticQt { - // find action by name - KeyboardShortcutManager::Action* KeyboardShortcutManager::Group::FindActionByName(const char* actionName, bool local) const + void KeyboardShortcutManager::Group::RemoveAction(QAction* qaction, bool local) { - const uint32 numActions = mActions.GetLength(); - for (uint32 i = 0; i < numActions; ++i) + m_actions.erase(AZStd::find_if(begin(m_actions), end(m_actions), [&qaction, local](const AZStd::unique_ptr& action) { - if (mActions[i]->mLocal == local && mActions[i]->mName == actionName) - { - return mActions[i]; - } - } - - return nullptr; + return action->m_local == local && action->m_qaction == qaction; + })); } - // constructor - KeyboardShortcutManager::KeyboardShortcutManager() + KeyboardShortcutManager::Action* KeyboardShortcutManager::Group::FindActionByName(const QString& actionName, bool local) const { - } - - - // destructor - KeyboardShortcutManager::~KeyboardShortcutManager() - { - Clear(); - } - - - // get rid of all groups including their actions - void KeyboardShortcutManager::Clear() - { - // get rid of the groups - const uint32 numGroups = mGroups.GetLength(); - for (uint32 i = 0; i < numGroups; ++i) + const auto found = AZStd::find_if(begin(m_actions), end(m_actions), [&actionName, local](const AZStd::unique_ptr& action) { - delete mGroups[i]; - } + return action->m_local == local && action->m_qaction->text() == actionName; + }); - mGroups.Clear(); + return found != end(m_actions) ? found->get() : nullptr; } - - void KeyboardShortcutManager::RegisterKeyboardShortcut(const char* actionName, const char* groupName, int defaultKey, bool defaultCtrl, bool defaultAlt, bool local) + void KeyboardShortcutManager::RegisterKeyboardShortcut(QAction* qaction, AZStd::string_view groupName, bool local) { // find the group with the given name Group* group = FindGroupByName(groupName); @@ -72,188 +49,112 @@ namespace MysticQt // if there is no group with the given name, create it if (group == nullptr) { - group = new Group(groupName); - mGroups.Add(group); + m_groups.emplace_back(AZStd::make_unique(groupName)); + group = m_groups.back().get(); } // check if the action is already there to avoid adding it twice - Action* action = group->FindActionByName(actionName, local); + Action* action = group->FindActionByName(qaction->text(), local); if (action) { - action->mDefaultKey = defaultKey; - action->mDefaultCtrl = defaultCtrl; - action->mDefaultAlt = defaultAlt; + action->m_defaultKeySequence = qaction->shortcut(); return; } // create the new action and add it to the group - action = new Action(actionName, defaultKey, defaultCtrl, defaultAlt, local); - group->AddAction(action); + group->AddAction(AZStd::make_unique(qaction, local)); + + QAction::connect(qaction, &QAction::destroyed, this, [this, groupName = AZStd::string(groupName), local](QObject* qaction) + { + UnregisterKeyboardShortcut(static_cast(qaction), groupName, local); + }); + } + + void KeyboardShortcutManager::UnregisterKeyboardShortcut(QAction* qaction, AZStd::string_view groupName, bool local) + { + Group* group = FindGroupByName(groupName); + + if (!group) + { + return; + } + + group->RemoveAction(qaction, local); } // find the action with the given name in the given group - KeyboardShortcutManager::Action* KeyboardShortcutManager::FindAction(const char* actionName, const char* groupName) + KeyboardShortcutManager::Action* KeyboardShortcutManager::FindAction(const QString& actionName, AZStd::string_view groupName) const { - const uint32 numGroups = mGroups.GetLength(); - - // first search global shortcuts - for (uint32 i = 0; i < numGroups; ++i) + const Group* group = FindGroupByName(groupName); + if (!group) { - if (mGroups[i]->GetNameString() == groupName) - { - Action* action = mGroups[i]->FindActionByName(actionName, false); - if (action) - { - return action; - } - } + return nullptr; } - // then local shortcuts - for (uint32 i = 0; i < numGroups; ++i) + Action* action = group->FindActionByName(actionName, false); + if (action) { - if (mGroups[i]->GetNameString() == groupName) - { - Action* action = mGroups[i]->FindActionByName(actionName, true); - if (action) - { - return action; - } - } + return action; } - - // failure, not found - return nullptr; + return group->FindActionByName(actionName, true); } // find a group by name - KeyboardShortcutManager::Group* KeyboardShortcutManager::FindGroupByName(const char* groupName) const + KeyboardShortcutManager::Group* KeyboardShortcutManager::FindGroupByName(AZStd::string_view groupName) const { - // iterate through the groups and find the one with the given name - const uint32 numGroups = mGroups.GetLength(); - for (uint32 i = 0; i < numGroups; ++i) + const auto found = AZStd::find_if(begin(m_groups), end(m_groups), [&groupName](const AZStd::unique_ptr& group) { - if (mGroups[i]->GetNameString() == groupName) - { - return mGroups[i]; - } - } - - // failure, a group with the given name hasn't been found - return nullptr; - } - - - bool KeyboardShortcutManager::Check(QKeyEvent* event, const char* actionName, const char* groupName) - { - // find the corresponding action for the given strings - Action* action = FindAction(actionName, groupName); - if (action == nullptr) - { - //MCore::LogError("Action named '%s' in group '%s' not registered. Please register the shortcut before using it.", actionName, groupName); - return false; - } - - const bool ctrlPressed = event->modifiers() & Qt::ControlModifier; - //const bool shiftPressed = event->modifiers() & Qt::ShiftModifier; - const bool altPressed = event->modifiers() & Qt::AltModifier; - - Group* group = FindGroupByName(groupName); - Action* conflictAction = FindShortcut(event->key(), ctrlPressed, altPressed, group); - - // check if they are equal, if yes this means they match - if (action == conflictAction) - { - return true; - } - - // check if the action and the key event are the same shortcut - /*if (event->key() == action->mKey && - ctrlPressed == action->mCtrl && - altPressed == action->mAlt) - return true;*/ - - return false; + return group->GetName() == groupName; + }); + return found != end(m_groups) ? found->get() : nullptr; } // find the correspondng group for the given action - KeyboardShortcutManager::Group* KeyboardShortcutManager::FindGroupForShortcut(Action* action) + KeyboardShortcutManager::Group* KeyboardShortcutManager::FindGroupForShortcut(Action* action) const { - // get the number of available groups - const uint32 numGroups = mGroups.GetLength(); - - // first check the global shortcuts - for (uint32 i = 0; i < numGroups; ++i) + const auto foundGroup = AZStd::find_if(begin(m_groups), end(m_groups), [action](const AZStd::unique_ptr& group) { - Group* group = mGroups[i]; - - // iterate through the actions and save them - const uint32 numActions = group->GetNumActions(); - for (uint32 j = 0; j < numActions; ++j) + const auto foundAction = AZStd::find_if(begin(group->GetActions()), end(group->GetActions()), [action](const AZStd::unique_ptr& actionInGroup) { - if (group->GetAction(j) == action) - { - return group; - } - } - } - - // failure, not found - return nullptr; + return action == actionInGroup.get(); + }); + return foundAction != end(group->GetActions()) ? foundAction->get() : nullptr; + }); + return foundGroup != end(m_groups) ? foundGroup->get() : nullptr; } - KeyboardShortcutManager::Action* KeyboardShortcutManager::FindShortcut(int key, bool ctrl, bool alt, Group* group) + KeyboardShortcutManager::Action* KeyboardShortcutManager::FindShortcut(QKeySequence keySequence, Group* group) const { - // get the number of available groups - const uint32 numGroups = mGroups.GetLength(); + const auto findMatchingAction = [keySequence] (const Group* group, const bool local) + { + return AZStd::find_if(begin(group->GetActions()), end(group->GetActions()), [keySequence, local] (const AZStd::unique_ptr& action) + { + if (action->m_local != local) + { + return false; + } + + return action->m_qaction->shortcut().matches(keySequence) == QKeySequence::ExactMatch; + }); + }; // first check the global shortcuts - for (uint32 i = 0; i < numGroups; ++i) + const auto globalAction = findMatchingAction(group, false); + if (globalAction != end(group->GetActions())) { - Group* currentGroup = mGroups[i]; - - // iterate through the actions and save them - const uint32 numActions = currentGroup->GetNumActions(); - for (uint32 j = 0; j < numActions; ++j) - { - // get the shortcut action - KeyboardShortcutManager::Action* action = currentGroup->GetAction(j); - if (action->mLocal) - { - continue; - } - - // check if the action and shortcut are the same - if (key == action->mKey && - ctrl == action->mCtrl && - alt == action->mAlt) - { - return action; - } - } + return globalAction->get(); } - // iterate through the actions and save them - const uint32 numActions = group->GetNumActions(); - for (uint32 j = 0; j < numActions; ++j) + const auto localAction = findMatchingAction(group, true); + if (localAction != end(group->GetActions())) { - // get the shortcut action - KeyboardShortcutManager::Action* action = group->GetAction(j); - - // check if the action and shortcut are the same - if (key == action->mKey && - ctrl == action->mCtrl && - alt == action->mAlt) - { - return action; - } + return localAction->get(); } - // failure, shortcut not found return nullptr; } @@ -264,24 +165,16 @@ namespace MysticQt settings->clear(); // iterate through the groups and save all actions for them - const uint32 numGroups = mGroups.GetLength(); - for (uint32 i = 0; i < numGroups; ++i) + for (const AZStd::unique_ptr& group : m_groups) { - Group* group = mGroups[i]; - settings->beginGroup(group->GetName()); + settings->beginGroup(QString::fromUtf8(group->GetName().data(), group->GetName().size())); // iterate through the actions and save them - const uint32 numActions = group->GetNumActions(); - for (uint32 j = 0; j < numActions; ++j) + for (const AZStd::unique_ptr& action : group->GetActions()) { - // get the shortcut action - KeyboardShortcutManager::Action* action = group->GetAction(j); - - settings->beginGroup(action->mName.c_str()); - settings->setValue("Key", action->mKey); - settings->setValue("Ctrl", action->mCtrl); - settings->setValue("Alt", action->mAlt); - settings->setValue("Local", action->mLocal); + settings->beginGroup(action->m_qaction->text()); + settings->setValue("Key", action->m_qaction->shortcut()); + settings->setValue("Local", action->m_local); settings->endGroup(); } @@ -292,33 +185,49 @@ namespace MysticQt void KeyboardShortcutManager::Load(QSettings* settings) { - // clear the shortcut manager before loading - Clear(); - // iterate through the groups and load all actions - QStringList groupNames = settings->childGroups(); - const uint32 numGroups = groupNames.count(); - for (uint32 i = 0; i < numGroups; ++i) + const QStringList groupNames = settings->childGroups(); + for (const QString& groupName : groupNames) { - QString groupName = groupNames[i]; - settings->beginGroup(groupNames[i]); - QStringList actionNames = settings->childGroups(); + Group* group = FindGroupByName(FromQtString(groupName)); + if (!group) + { + continue; + } + + settings->beginGroup(groupName); + const QStringList actionNames = settings->childGroups(); // iterate through the actions and save them - const uint32 numActions = actionNames.count(); - for (uint32 j = 0; j < numActions; ++j) + for (const QString& actionName : actionNames) { - QString actionName = actionNames[j]; settings->beginGroup(actionName); - int key = settings->value("Key", "").toInt(); - bool ctrlPressed = settings->value("Ctrl", false).toBool(); - bool altPressed = settings->value("Alt", false).toBool(); - bool local = settings->value("Local", false).toBool(); - RegisterKeyboardShortcut(FromQtString(actionName).c_str(), FromQtString(groupName).c_str(), key, ctrlPressed, altPressed, local); + const bool local = settings->value("Local", false).toBool(); + + Action* action = group->FindActionByName(actionName, local); + if (!action) + { + continue; + } + + const QVariant keyValue = settings->value("Key", ""); + if (keyValue.canConvert()) + { + const QKeySequence key = keyValue.value(); + action->m_qaction->setShortcut(key); + } + else if (keyValue.canConvert()) + { + const int key = keyValue.value(); + const bool ctrlModifier = settings->value("Ctrl", false).value(); + const bool altModifier = settings->value("Alt", false).value(); + action->m_qaction->setShortcut(key | (ctrlModifier ? Qt::ControlModifier : 0) | (altModifier ? Qt::AltModifier : 0)); + } + settings->endGroup(); } settings->endGroup(); } } -} // namespace MysticQt +} // namespace MysticQt diff --git a/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.h b/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.h index 9bd1b58812..ce989767e0 100644 --- a/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.h +++ b/Gems/EMotionFX/Code/MysticQt/Source/KeyboardShortcutManager.h @@ -10,12 +10,14 @@ * */ -#ifndef __MYSTICQT_KEYBOARDSHORTCUTMANAGER_H -#define __MYSTICQT_KEYBOARDSHORTCUTMANAGER_H +#pragma once #if !defined(Q_MOC_RUN) +#include +#include +#include #include -#include +#include #include #include "MysticQtConfig.h" #endif @@ -26,86 +28,58 @@ class QSettings; namespace MysticQt { class MYSTICQT_API KeyboardShortcutManager + : public QObject { - MCORE_MEMORYOBJECTCATEGORY(KeyboardShortcutManager, MCore::MCORE_DEFAULT_ALIGNMENT, MEMCATEGORY_MYSTICQT); - public: - KeyboardShortcutManager(); - virtual ~KeyboardShortcutManager(); - struct Action { - MCORE_MEMORYOBJECTCATEGORY(KeyboardShortcutManager::Action, MCore::MCORE_DEFAULT_ALIGNMENT, MEMCATEGORY_MYSTICQT); + QAction* m_qaction; + QKeySequence m_defaultKeySequence; + bool m_local; - AZStd::string mName; - int mKey; - bool mCtrl; - bool mAlt; - bool mLocal; - - int mDefaultKey; - bool mDefaultCtrl; - bool mDefaultAlt; - - Action(const char* name, int defaultKey, bool defaultCtrl, bool defaultAlt, bool local) + Action(QAction* qaction, bool local) + : m_qaction(qaction) + , m_defaultKeySequence(qaction->shortcut()) + , m_local(local) { - mName = name; - mLocal = local; - - mKey = defaultKey; - mCtrl = defaultCtrl; - mAlt = defaultAlt; - - mDefaultKey = defaultKey; - mDefaultCtrl = defaultCtrl; - mDefaultAlt = defaultAlt; } }; class Group { - MCORE_MEMORYOBJECTCATEGORY(KeyboardShortcutManager::Group, MCore::MCORE_DEFAULT_ALIGNMENT, MEMCATEGORY_MYSTICQT); public: - Group(const char* groupName) { mName = groupName; } - virtual ~Group() + Group(AZStd::string_view groupName) + : m_name(groupName) { - const uint32 numActions = mActions.GetLength(); - for (uint32 i = 0; i < numActions; ++i) - { - delete mActions[i]; - } - mActions.Clear(); } - void AddAction(Action* action) { mActions.Add(action); } - uint32 GetNumActions() const { return mActions.GetLength(); } - Action* GetAction(uint32 index) { return mActions[index]; } - const char* GetName() const { return mName.c_str(); } - const AZStd::string& GetNameString() const { return mName; } - Action* FindActionByName(const char* actionName, bool local) const; + + void AddAction(AZStd::unique_ptr action) { m_actions.emplace_back(AZStd::move(action)); } + void RemoveAction(QAction* action, bool local); + size_t GetNumActions() const { return m_actions.size(); } + Action* GetAction(size_t index) { return m_actions[index].get(); } + const AZStd::vector>& GetActions() const { return m_actions; } + const AZStd::string& GetName() const { return m_name; } + Action* FindActionByName(const QString& actionName, bool local) const; private: - AZStd::string mName; - MCore::Array mActions; + AZStd::string m_name; + AZStd::vector> m_actions; }; - void RegisterKeyboardShortcut(const char* actionName, const char* groupName, int defaultKey, bool defaultCtrl, bool defaultAlt, bool local); - bool Check(QKeyEvent* event, const char* actionName, const char* groupName); - Action* FindShortcut(int key, bool ctrl, bool alt, Group* group); - Action* FindAction(const char* actionName, const char* groupName); - Group* FindGroupForShortcut(Action* action); - uint32 GetNumGroups() const { return mGroups.GetLength(); } - Group* GetGroup(uint32 index) const { return mGroups[index]; } - void Clear(); + void RegisterKeyboardShortcut(QAction* qaction, AZStd::string_view groupName, bool local); + void UnregisterKeyboardShortcut(QAction* qaction, AZStd::string_view groupName, bool local); + Action* FindShortcut(QKeySequence keySequence, Group* group) const; + Action* FindAction(const QString& actionName, AZStd::string_view groupName) const; + Group* FindGroupForShortcut(Action* action) const; + size_t GetNumGroups() const { return m_groups.size(); } + Group* GetGroup(size_t index) const { return m_groups[index].get(); } void Save(QSettings* settings); void Load(QSettings* settings); private: - MCore::Array mGroups; + AZStd::vector> m_groups; - Group* FindGroupByName(const char* groupName) const; + Group* FindGroupByName(AZStd::string_view groupName) const; }; } // namespace MysticQt - - -#endif diff --git a/Gems/EMotionFX/Code/MysticQt/Source/MysticQtConfig.h b/Gems/EMotionFX/Code/MysticQt/Source/MysticQtConfig.h index 54d2fddb54..90df0bf418 100644 --- a/Gems/EMotionFX/Code/MysticQt/Source/MysticQtConfig.h +++ b/Gems/EMotionFX/Code/MysticQt/Source/MysticQtConfig.h @@ -39,14 +39,19 @@ enum // convert from a QString into an AZStd::string MCORE_INLINE AZStd::string FromQtString(const QString& s) { - return s.toUtf8().data(); + return {s.toUtf8().data(), static_cast(s.size())}; } // convert from a QString into an AZStd::string MCORE_INLINE void FromQtString(const QString& s, AZStd::string* result) { - *result = s.toUtf8().data(); + *result = AZStd::string{s.toUtf8().data(), static_cast(s.size())}; +} + +inline QString FromStdString(AZStd::string_view s) +{ + return QString::fromUtf8(s.data(), static_cast(s.size())); } // forward declare a MysticQt class diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/CanDeleteAnimGraphNode.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/CanDeleteAnimGraphNode.cpp index a7f9ae228f..c7b2363ad4 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/CanDeleteAnimGraphNode.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/CanDeleteAnimGraphNode.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -64,8 +65,10 @@ namespace EMotionFX { m_blendGraphWidget->OnContextMenuEvent(m_blendGraphWidget, localPoint, m_blendGraphWidget->LocalToGlobal(localPoint), m_animGraphPlugin, m_blendGraphWidget->GetActiveGraph()->GetSelectedAnimGraphNodes(), true, false, m_animGraphPlugin->GetActionFilter()); // Find Action for deleting node - QAction* deleteAction = GetNamedAction(m_blendGraphWidget, "Delete Node"); - ASSERT_TRUE(deleteAction) << "Could not find the 'Delete Node' action in the context menu"; + QAction* deleteAction = GetNamedAction(m_animGraphPlugin->GetViewWidget(), FromStdString(EMStudio::AnimGraphPlugin::s_deleteSelectedNodesShortcutName)); + ASSERT_TRUE(deleteAction) << "Could not find the '" << + std::string(EMStudio::AnimGraphPlugin::s_deleteSelectedNodesShortcutName.data(), EMStudio::AnimGraphPlugin::s_deleteSelectedNodesShortcutName.size()) + << "' action in the context menu"; // Trigger delete const size_t nodeCount = activeAnimGraph->GetNumNodes(); diff --git a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/Transitions/RemoveTransition.cpp b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/Transitions/RemoveTransition.cpp index 819c24baa7..98fec0fe13 100644 --- a/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/Transitions/RemoveTransition.cpp +++ b/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/Transitions/RemoveTransition.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include "qtestsystem.h" @@ -80,9 +81,8 @@ namespace EMotionFX ASSERT_TRUE(modelIndex.isValid()) << "Anim graph transition has an invalid model index."; animGraphModel.GetSelectionModel().select(QItemSelection(modelIndex, modelIndex), QItemSelectionModel::Current | QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); - // Delete key pressed. - EMStudio::BlendGraphWidget* blendGraphWidget = animGraphPlugin->GetGraphWidget(); - QTest::keyClick((QWidget*)blendGraphWidget, Qt::Key_Delete); + EMStudio::BlendGraphViewWidget* blendGraphViewWidget = animGraphPlugin->GetViewWidget(); + blendGraphViewWidget->GetAction(EMStudio::BlendGraphViewWidget::EDIT_DELETE)->trigger(); // Check if the transition get deleted. ASSERT_EQ(0, m_animGraph->GetRootStateMachine()->GetNumTransitions()) << " Anim Graph transition should be removed";