Handle EMotionFX hotkeys with QActions instead of in keyPressEvent (#514)
EMotionFX has user-customizable hotkeys. These hotkeys are registered by individual plugins, and then the user can set what they want the hotkey to be. The way this was implemented was by reimplementing `keyPressEvent` and `keyReleaseEvent` for each widget that used customizable hotkeys, and in there call `KeyboardShortcutManager::Check` to see if key press matched any existing hotkey mapping. However, the main Editor has behavior that prevents events from reaching EMotionFX's `keyPressEvent` method, if a keypress matches a hotkey that is also used by the main Editor. This is due to the global event filter defined in `ShortcutDispatcher::eventFilter`. This event filter takes a Qt `Shortcut` event, and will re-dispatch that event to all parent widgets of a given receiver. So if a parent widget, like the main Editor, *does* have a QAction that matches a given key sequence, that widget will receive the event, the event is marked as processed, and no `KeyPress` event is ever sent to the original widget where the event occurred. All this means that processing hotkeys in a `keyPressEvent` won't work reliably. The main editor defines a hotkey for the `delete` key, so that can never be received in a `keyPressEvent` by any child widget of the Editor. This change removes all the hotkey logic from the `keyPressEvent` methods, and replaces them with `QAction` instances. Hotkeys are defined with `QAction::setShortcut`, and added to each widget that they apply to. In addition, the `KeyboardShortcutManager` class had to be adjusted to suit this new way of defining the hotkeys. It now has a pointer to each `QAction*` that can have a customizable hotkey. It has also been greatly simplified, since it can use a `QKeySequence` instead of separate variables for `int key; bool hasCtrlModifier; bool hasAltModifier`. Applying user-defined hotkeys now has to be done after the hotkeys are registered from a plugin. It is the plugin's responsibility to reload the user-defined hotkeys after registering all of its actions.
This commit is contained in:
@@ -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)
|
||||
|
||||
+22
-82
@@ -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();
|
||||
|
||||
+2
-6
@@ -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
|
||||
|
||||
+32
-41
@@ -66,6 +66,7 @@
|
||||
#include <EMotionFX/Source/Importer/Importer.h>
|
||||
#include <EMotionFX/Source/MotionManager.h>
|
||||
#include <EMotionFX/Source/MotionSet.h>
|
||||
#include <qnamespace.h>
|
||||
AZ_PUSH_DISABLE_WARNING(4267, "-Wconversion")
|
||||
#include <ISystem.h>
|
||||
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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -136,7 +136,6 @@ namespace EMStudio
|
||||
mActivePlugins.push_back(newPlugin);
|
||||
|
||||
newPlugin->Init();
|
||||
newPlugin->RegisterKeyboardShortcuts();
|
||||
|
||||
return newPlugin;
|
||||
}
|
||||
|
||||
-11
@@ -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)
|
||||
{
|
||||
|
||||
+5
-3
@@ -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); }
|
||||
|
||||
+35
-2
@@ -16,7 +16,9 @@
|
||||
#include "../PreferencesWindow.h"
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <EMotionFX/CommandSystem/Source/SelectionList.h>
|
||||
#include <EMotionFX/CommandSystem/Source/ActorInstanceCommands.h>
|
||||
#include <AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx>
|
||||
#include <MysticQt/Source/KeyboardShortcutManager.h>
|
||||
|
||||
#include <QToolBar>
|
||||
|
||||
@@ -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)
|
||||
|
||||
+2
@@ -43,6 +43,8 @@ namespace EMStudio
|
||||
RenderViewWidget(RenderPlugin* parentPlugin, QWidget* parentWidget);
|
||||
virtual ~RenderViewWidget();
|
||||
|
||||
void CreateActions();
|
||||
|
||||
enum ERenderFlag
|
||||
{
|
||||
RENDER_SOLID = 0,
|
||||
|
||||
-68
@@ -25,7 +25,6 @@
|
||||
#include "../EMStudioManager.h"
|
||||
#include "../MainWindow.h"
|
||||
#include <MCore/Source/AzCoreConversions.h>
|
||||
#include <MysticQt/Source/KeyboardShortcutManager.h>
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
+2
-2
@@ -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:
|
||||
|
||||
-2
@@ -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);
|
||||
|
||||
+21
-3
@@ -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
|
||||
|
||||
+6
@@ -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<QPersistentModelIndex> m_pasteItems;
|
||||
PasteOperation m_pasteOperation;
|
||||
|
||||
void SetPasteOperation(PasteOperation newOperation);
|
||||
};
|
||||
} // namespace EMStudio
|
||||
|
||||
+1
-31
@@ -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)
|
||||
{
|
||||
|
||||
+21
-3
@@ -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();
|
||||
|
||||
+325
-183
@@ -26,6 +26,7 @@
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NavigateWidget.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NavigationHistory.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NavigationLinkWidget.h>
|
||||
#include <MysticQt/Source/KeyboardShortcutManager.h>
|
||||
#include <Editor/AnimGraphEditorBus.h>
|
||||
#include <QKeyEvent>
|
||||
#include <QPushButton>
|
||||
@@ -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<QToolButton*>(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<QToolButton*>(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>() == 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<AnimGraphModel::ModelItemType>();
|
||||
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<int> 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
|
||||
|
||||
+30
-27
@@ -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<QAction*, NUM_OPTIONS> m_actions{};
|
||||
AnimGraphPlugin* m_parentPlugin = nullptr;
|
||||
NavigationLinkWidget* mNavigationLink = nullptr;
|
||||
QStackedWidget m_viewportStack;
|
||||
|
||||
-254
@@ -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
|
||||
|
||||
-3
@@ -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;
|
||||
|
||||
+17
-38
@@ -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
|
||||
|
||||
+10
-54
@@ -28,7 +28,6 @@
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/MotionWindow/MotionWindowPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/MotionSetsWindow/MotionSetsWindowPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/TimeView/TimeViewPlugin.h>
|
||||
#include <MysticQt/Source/KeyboardShortcutManager.h>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+7
-4
@@ -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
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
// include required headers
|
||||
#include "KeyboardShortcutManager.h"
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
|
||||
#include <MCore/Source/LogManager.h>
|
||||
#include <MCore/Source/IDGenerator.h>
|
||||
@@ -19,52 +21,27 @@
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtGui/QKeyEvent>
|
||||
|
||||
|
||||
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>& 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>& 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<Group>(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<Action>(qaction, local));
|
||||
|
||||
QAction::connect(qaction, &QAction::destroyed, this, [this, groupName = AZStd::string(groupName), local](QObject* qaction)
|
||||
{
|
||||
UnregisterKeyboardShortcut(static_cast<QAction*>(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>& 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* 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<Action>& 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>& 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>& 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>& 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<QKeySequence>())
|
||||
{
|
||||
const QKeySequence key = keyValue.value<QKeySequence>();
|
||||
action->m_qaction->setShortcut(key);
|
||||
}
|
||||
else if (keyValue.canConvert<int>())
|
||||
{
|
||||
const int key = keyValue.value<int>();
|
||||
const bool ctrlModifier = settings->value("Ctrl", false).value<bool>();
|
||||
const bool altModifier = settings->value("Alt", false).value<bool>();
|
||||
action->m_qaction->setShortcut(key | (ctrlModifier ? Qt::ControlModifier : 0) | (altModifier ? Qt::AltModifier : 0));
|
||||
}
|
||||
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
settings->endGroup();
|
||||
}
|
||||
}
|
||||
} // namespace MysticQt
|
||||
} // namespace MysticQt
|
||||
|
||||
@@ -10,12 +10,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MYSTICQT_KEYBOARDSHORTCUTMANAGER_H
|
||||
#define __MYSTICQT_KEYBOARDSHORTCUTMANAGER_H
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QKeySequence>
|
||||
#include <QAction>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <MCore/Source/Array.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <MCore/Source/StandardHeaders.h>
|
||||
#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> 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<AZStd::unique_ptr<Action>>& 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<Action*> mActions;
|
||||
AZStd::string m_name;
|
||||
AZStd::vector<AZStd::unique_ptr<Action>> 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<Group*> mGroups;
|
||||
AZStd::vector<AZStd::unique_ptr<Group>> m_groups;
|
||||
|
||||
Group* FindGroupByName(const char* groupName) const;
|
||||
Group* FindGroupByName(AZStd::string_view groupName) const;
|
||||
};
|
||||
} // namespace MysticQt
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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<size_t>(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<size_t>(s.size())};
|
||||
}
|
||||
|
||||
inline QString FromStdString(AZStd::string_view s)
|
||||
{
|
||||
return QString::fromUtf8(s.data(), static_cast<int>(s.size()));
|
||||
}
|
||||
|
||||
// forward declare a MysticQt class
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <EMotionStudio/EMStudioSDK/Source/EMStudioManager.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphWidget.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.h>
|
||||
|
||||
#include <EMotionFX/Source/AnimGraphBindPoseNode.h>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <EMotionFX/Source/AnimGraphMotionNode.h>
|
||||
#include <EMotionFX/Source/AnimGraphStateMachine.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/AnimGraphPlugin.h>
|
||||
#include <EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/BlendGraphViewWidget.h>
|
||||
#include <QApplication>
|
||||
#include <QtTest>
|
||||
#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";
|
||||
|
||||
Reference in New Issue
Block a user