From 3d4c060fb5101b3cf01226ffc550ee36863c87c2 Mon Sep 17 00:00:00 2001 From: hultonha Date: Fri, 15 Oct 2021 15:19:38 +0100 Subject: [PATCH] updates to improve cursor lock behavior Signed-off-by: hultonha --- .../Input/QtEventToAzInputManager.cpp | 45 +++++++++++-------- .../Input/QtEventToAzInputManager.h | 11 ++--- .../Viewport/ViewportMessages.h | 14 ++++-- .../ViewportSelection/EditorHelpers.cpp | 7 +-- .../Viewport/RenderViewportWidget.h | 4 +- .../Source/Viewport/RenderViewportWidget.cpp | 8 ++-- 6 files changed, 52 insertions(+), 37 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp index d146dc91da..1f30fc1d19 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp @@ -244,6 +244,16 @@ namespace AzToolsFramework const auto eventType = event->type(); + if (eventType == QEvent::Type::MouseMove) + { + const auto* mouseEvent = static_cast(event); + if (m_overrideCursor && !m_sourceWidget->geometry().contains(mouseEvent->pos())) + { + qApp->restoreOverrideCursor(); + m_overrideCursor = false; + } + } + // Only accept mouse & key release events that originate from an object that is not our target widget, // as we don't want to erroneously intercept user input meant for another component. if (object != m_sourceWidget && eventType != QEvent::Type::KeyRelease && eventType != QEvent::Type::MouseButtonRelease) @@ -256,27 +266,14 @@ namespace AzToolsFramework // If our focus changes, go ahead and reset all input devices. HandleFocusChange(event); - if (eventType == QEvent::FocusOut) - { - if (m_capturingCursor) - { - qApp->restoreOverrideCursor(); - } - } - // If we focus in on the source widget and the mouse is contained in its // bounds, refresh the cached cursor position to ensure it is up to date (this // ensures cursor positions are refreshed correctly with context menu focus changes) if (eventType == QEvent::FocusIn) { const auto globalCursorPosition = QCursor::pos(); - if (m_sourceWidget->geometry().contains(globalCursorPosition)) + if (m_sourceWidget->geometry().contains(m_sourceWidget->mapFromGlobal(globalCursorPosition))) { - if (m_capturingCursor) - { - qApp->setOverrideCursor(Qt::ForbiddenCursor); - } - HandleMouseMoveEvent(globalCursorPosition); } } @@ -466,16 +463,26 @@ namespace AzToolsFramework } } - void QtEventToAzInputMapper::PushCursor(/*enum*/) + static Qt::CursorShape QtCursorFromAzCursor(const ViewportInteraction::CursorStyleOverride cursorStyleOverride) { - if (!m_overrideCursor) + switch (cursorStyleOverride) { - qApp->setOverrideCursor(Qt::ForbiddenCursor); - m_overrideCursor = true; + case ViewportInteraction::CursorStyleOverride::Forbidden: + return Qt::ForbiddenCursor; + default: + return Qt::ArrowCursor; } } - void QtEventToAzInputMapper::PopCursor() + void QtEventToAzInputMapper::SetOverrideCursor(ViewportInteraction::CursorStyleOverride cursorStyleOverride) + { + ClearOverrideCursor(); + + qApp->setOverrideCursor(QtCursorFromAzCursor(cursorStyleOverride)); + m_overrideCursor = true; + } + + void QtEventToAzInputMapper::ClearOverrideCursor() { if (m_overrideCursor) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h index 8127738dd3..4cb391e63b 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h @@ -15,10 +15,11 @@ #include #include #include - #include #include +#include + #include #include #include @@ -55,8 +56,8 @@ namespace AzToolsFramework //! like a dolly or rotation, where mouse movement is important but cursor location is not. void SetCursorCaptureEnabled(bool enabled); - void PushCursor(/*enum*/); - void PopCursor(); + void SetOverrideCursor(ViewportInteraction::CursorStyleOverride cursorStyleOverride); + void ClearOverrideCursor(); // QObject overrides... bool eventFilter(QObject* object, QEvent* event) override; @@ -167,8 +168,8 @@ namespace AzToolsFramework bool m_enabled = true; // Flags whether or not the cursor is being constrained to the source widget (for invisible mouse movement). bool m_capturingCursor = false; - // - bool m_overrideCursor = true; + // Flags whether the cursor has been overridden. + bool m_overrideCursor = false; // Our viewport-specific AZ devices. We control their internal input channel states. AZStd::unique_ptr m_mouseDevice; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h index 93ca8706eb..15e871459d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h @@ -300,6 +300,12 @@ namespace AzToolsFramework using EditorViewportInputTimeNowRequestBus = AZ::EBus; + //! The style of cursor override. + enum class CursorStyleOverride + { + Forbidden + }; + //! Viewport requests for managing the viewport cursor state. class ViewportMouseCursorRequests { @@ -310,10 +316,10 @@ namespace AzToolsFramework virtual void EndCursorCapture() = 0; //! Is the mouse over the viewport. virtual bool IsMouseOver() const = 0; - //! - virtual void PushOverrideCursor(/*enum*/) {} // make virtual - //! - virtual void PopOverrideCursor() {} // make virtual + //! Set the cursor style override. + virtual void SetOverrideCursor(CursorStyleOverride cursorStyleOverride) = 0; + //! Clear the current cursor style override. + virtual void ClearOverrideCursor() = 0; protected: ~ViewportMouseCursorRequests() = default; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp index 912e1ccff5..2f39834651 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp @@ -187,16 +187,17 @@ namespace AzToolsFramework } // Verify if the entity Id corresponds to an entity that is focused; if not, halt selection. - if (!IsSelectableAccordingToFocusMode(entityIdUnderCursor)) + if (entityIdUnderCursor.IsValid() && !IsSelectableAccordingToFocusMode(entityIdUnderCursor)) { ViewportInteraction::ViewportMouseCursorRequestBus::Event( - viewportId, &ViewportInteraction::ViewportMouseCursorRequestBus::Events::PushOverrideCursor); + viewportId, &ViewportInteraction::ViewportMouseCursorRequestBus::Events::SetOverrideCursor, + ViewportInteraction::CursorStyleOverride::Forbidden); return AZ::EntityId(); } ViewportInteraction::ViewportMouseCursorRequestBus::Event( - viewportId, &ViewportInteraction::ViewportMouseCursorRequestBus::Events::PopOverrideCursor); + viewportId, &ViewportInteraction::ViewportMouseCursorRequestBus::Events::ClearOverrideCursor); // Container Entity support - if the entity that is being selected is part of a closed container, // change the selection to the container instead. diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h index eebe445f7b..ded9e00535 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -102,8 +102,8 @@ namespace AtomToolsFramework void BeginCursorCapture() override; void EndCursorCapture() override; bool IsMouseOver() const override; - void PushOverrideCursor(/*enum*/) override; - void PopOverrideCursor() override; + void SetOverrideCursor(AzToolsFramework::ViewportInteraction::CursorStyleOverride cursorStyleOverride) override; + void ClearOverrideCursor() override; // AzFramework::WindowRequestBus::Handler overrides ... void SetWindowTitle(const AZStd::string& title) override; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index df639c8026..88897dddf1 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -367,14 +367,14 @@ namespace AtomToolsFramework m_inputChannelMapper->SetCursorCaptureEnabled(false); } - void RenderViewportWidget::PushOverrideCursor(/*enum*/) + void RenderViewportWidget::SetOverrideCursor(AzToolsFramework::ViewportInteraction::CursorStyleOverride cursorStyleOverride) { - m_inputChannelMapper->PushCursor(); + m_inputChannelMapper->SetOverrideCursor(cursorStyleOverride); } - void RenderViewportWidget::PopOverrideCursor() + void RenderViewportWidget::ClearOverrideCursor() { - m_inputChannelMapper->PopCursor(); + m_inputChannelMapper->ClearOverrideCursor(); } void RenderViewportWidget::SetWindowTitle(const AZStd::string& title)