Files
o3de/Gems/EMotionFX/Code/Tests/ProvidesUI/AnimGraph/CanDeleteAnimGraphNode.cpp
T
Chris Burel 13c7b06308 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.
2021-05-03 15:00:40 -07:00

83 lines
4.1 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <gtest/gtest.h>
#include <QApplication>
#include <QAction>
#include <QtTest>
#include <Tests/UI/AnimGraphUIFixture.h>
#include <EMotionFX/Source/AnimGraphManager.h>
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#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>
namespace EMotionFX {
#if AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_EDITOR_TESTS
TEST_F(AnimGraphUIFixture, DISABLED_CanDeleteAnimGraphNode)
#else
TEST_F(AnimGraphUIFixture, CanDeleteAnimGraphNode)
#endif // AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_EDITOR_TESTS
{
/*
Test Case: C22083484
Can Delete AnimGraph Node.
Tests the UI functionality for deleting an existing AnimGraph Node via the right-click context menu.
*/
RecordProperty("test_case_id", "C22083484");
AnimGraph* activeAnimGraph = CreateAnimGraph();
// Create a node to delete later
AnimGraphNode* node = CreateAnimGraphNode(azrtti_typeid<AnimGraphBindPoseNode>().ToString<AZStd::string>(), "-parentName Root -xPos 1 -yPos 1");
ASSERT_TRUE(node) << "Node was not created.";
// Verify no nodes are selecetd yet
EXPECT_EQ(m_blendGraphWidget->CalcNumSelectedNodes(), 0) << "Expected to have exactly zero (0) selected nodes";
EXPECT_EQ(m_blendGraphWidget->GetActiveGraph()->GetSelectedAnimGraphNodes().size(), 0) << "Expected to have zero (0) items selected in selection model";
// Select the new Graph Node (via left mouse click)
QRect nodeRect = m_blendGraphWidget->GetActiveGraph()->FindGraphNode(node)->GetRect();
QPoint localPoint = nodeRect.center();
QTest::mouseClick(m_blendGraphWidget, Qt::LeftButton, Qt::NoModifier, localPoint);
// Verify our node was selected
EXPECT_EQ(m_blendGraphWidget->CalcNumSelectedNodes(), 1) << "Expected to have exactly one (1) selected node";
EXPECT_EQ(m_blendGraphWidget->GetActiveGraph()->GetSelectedAnimGraphNodes().size(), 1) << "Not exactly one selection made";
// Open context menu
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_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();
deleteAction->trigger();
// Verify Result
EXPECT_EQ(nodeCount - 1, activeAnimGraph->GetNumNodes()) << "Delete Action from Context menu did not remove exactly 1 Node from AnimGraph";
EXPECT_EQ(m_blendGraphWidget->CalcNumSelectedNodes(), 0) << "BlendGraphWidget still has the deleted node selected";
EXPECT_EQ(m_blendGraphWidget->GetActiveGraph()->GetSelectedAnimGraphNodes().size(), 0) << "Selection model not cleared";
}
}