Move Qt Toast Notifications from GraphCanvas into Framework
Move the existing Qt Toast Notification QWidgets, EBuses and logic from the GraphCanvas gem into AzQtComponents and AzToolsFramework so they can be re-used. Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com>monroegm-disable-blank-issue-2
parent
67532ed18f
commit
7ddcdffed7
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <AzQtComponents/Components/ToastNotificationConfiguration.h>
|
||||||
|
|
||||||
|
namespace AzQtComponents
|
||||||
|
{
|
||||||
|
ToastConfiguration::ToastConfiguration(ToastType toastType, const QString& title, const QString& description)
|
||||||
|
: m_toastType(toastType)
|
||||||
|
, m_title(title)
|
||||||
|
, m_description(description)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
} // namespace AzQtComponents
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(Q_MOC_RUN)
|
||||||
|
#include <AzQtComponents/AzQtComponentsAPI.h>
|
||||||
|
#include <AzCore/Memory/SystemAllocator.h>
|
||||||
|
#include <AzCore/std/chrono/chrono.h>
|
||||||
|
#include <QString>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace AzQtComponents
|
||||||
|
{
|
||||||
|
enum class ToastType
|
||||||
|
{
|
||||||
|
Information,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
Custom
|
||||||
|
};
|
||||||
|
|
||||||
|
class AZ_QT_COMPONENTS_API ToastConfiguration
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AZ_CLASS_ALLOCATOR(ToastConfiguration, AZ::SystemAllocator, 0);
|
||||||
|
ToastConfiguration(ToastType toastType, const QString& title, const QString& description);
|
||||||
|
|
||||||
|
bool m_closeOnClick = true;
|
||||||
|
|
||||||
|
ToastType m_toastType = ToastType::Information;
|
||||||
|
|
||||||
|
QString m_title;
|
||||||
|
QString m_description;
|
||||||
|
QString m_customIconImage;
|
||||||
|
|
||||||
|
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||||
|
AZStd::chrono::milliseconds m_duration = AZStd::chrono::milliseconds(5000);
|
||||||
|
AZStd::chrono::milliseconds m_fadeDuration = AZStd::chrono::milliseconds(250);
|
||||||
|
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||||
|
};
|
||||||
|
} // namespace AzQtComponents
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(Q_MOC_RUN)
|
||||||
|
#include <AzCore/EBus/EBus.h>
|
||||||
|
#include <AzCore/Component/EntityId.h>
|
||||||
|
#include <AzQtComponents/Components/ToastNotificationConfiguration.h>
|
||||||
|
|
||||||
|
#include <QPoint>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace AzToolsFramework
|
||||||
|
{
|
||||||
|
typedef AZ::EntityId ToastId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An EBus for receiving notifications when a user interacts with or dismisses
|
||||||
|
* a toast notification.
|
||||||
|
*/
|
||||||
|
class ToastNotifications
|
||||||
|
: public AZ::EBusTraits
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||||
|
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||||
|
using BusIdType = ToastId;
|
||||||
|
|
||||||
|
virtual void OnToastInteraction() {}
|
||||||
|
virtual void OnToastDismissed() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
using ToastNotificationBus = AZ::EBus<ToastNotifications>;
|
||||||
|
|
||||||
|
typedef AZ::u32 ToastRequestBusId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An EBus used to hide or show toast notifications. Generally, these request are handled by a
|
||||||
|
* ToastNotificationsView that has been created with a specific ToastRequestBusId
|
||||||
|
* e.g. AZ_CRC("ExampleToastNotificationView")
|
||||||
|
*/
|
||||||
|
class ToastRequests
|
||||||
|
: public AZ::EBusTraits
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
||||||
|
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||||
|
using BusIdType = ToastRequestBusId; // bus is addressed by CRC of the view name
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide a toast notification widget.
|
||||||
|
*
|
||||||
|
* @param toastId The toast notification's ToastId
|
||||||
|
*/
|
||||||
|
virtual void HideToastNotification(const ToastId& toastId) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a toast notification with the specified toast configuration. When handled by a ToastNotificationsView,
|
||||||
|
* notifications are queued and presented to the user in sequence.
|
||||||
|
*
|
||||||
|
* @param toastConfiguration The toast configuration
|
||||||
|
* @return a ToastId
|
||||||
|
*/
|
||||||
|
virtual ToastId ShowToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a toast notification with the specified toast configuration at the current moust cursor location.
|
||||||
|
*
|
||||||
|
* @param toastConfiguration The toast configuration
|
||||||
|
* @return a ToastId
|
||||||
|
*/
|
||||||
|
virtual ToastId ShowToastAtCursor(const AzQtComponents::ToastConfiguration& toastConfiguration) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a toast notification with the specified toast configuration at the specified location.
|
||||||
|
*
|
||||||
|
* @param screenPosition The screen position
|
||||||
|
* @param anchorPoint The anchorPoint for the toast notification widget
|
||||||
|
* @param toastConfiguration The toast configuration
|
||||||
|
* @return a ToastId
|
||||||
|
*/
|
||||||
|
virtual ToastId ShowToastAtPoint(const QPoint& screenPosition, const QPointF& anchorPoint, const AzQtComponents::ToastConfiguration&) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ToastRequestBus = AZ::EBus<ToastRequests>;
|
||||||
|
}
|
||||||
@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AzToolsFramework/UI/Notifications/ToastNotificationsView.h>
|
||||||
|
#include <AzQtComponents/Components/ToastNotification.h>
|
||||||
|
#include <AzCore/Component/Entity.h>
|
||||||
|
#include <AzCore/Serialization/SerializeContext.h>
|
||||||
|
#include <AzCore/std/functional.h>
|
||||||
|
|
||||||
|
namespace AzToolsFramework
|
||||||
|
{
|
||||||
|
ToastNotificationsView::ToastNotificationsView(QWidget* parent, ToastRequestBusId busId)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
ToastRequestBus::Handler::BusConnect(busId);
|
||||||
|
}
|
||||||
|
|
||||||
|
ToastNotificationsView::~ToastNotificationsView()
|
||||||
|
{
|
||||||
|
ToastRequestBus::Handler::BusDisconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsView::OnHide()
|
||||||
|
{
|
||||||
|
QWidget::hide();
|
||||||
|
|
||||||
|
if (m_activeNotification.IsValid())
|
||||||
|
{
|
||||||
|
auto notificationIter = m_notifications.find(m_activeNotification);
|
||||||
|
if (notificationIter != m_notifications.end())
|
||||||
|
{
|
||||||
|
notificationIter->second->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsView::UpdateToastPosition()
|
||||||
|
{
|
||||||
|
if (m_activeNotification.IsValid())
|
||||||
|
{
|
||||||
|
auto notificationIter = m_notifications.find(m_activeNotification);
|
||||||
|
if (notificationIter != m_notifications.end())
|
||||||
|
{
|
||||||
|
notificationIter->second->UpdatePosition(GetGlobalPoint(), m_anchorPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsView::OnShow()
|
||||||
|
{
|
||||||
|
QWidget::show();
|
||||||
|
|
||||||
|
if (m_activeNotification.IsValid() || !m_queuedNotifications.empty())
|
||||||
|
{
|
||||||
|
DisplayQueuedNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToastId ToastNotificationsView::ShowToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration)
|
||||||
|
{
|
||||||
|
ToastId toastId = CreateToastNotification(toastConfiguration);
|
||||||
|
m_queuedNotifications.emplace_back(toastId);
|
||||||
|
|
||||||
|
if (!m_activeNotification.IsValid())
|
||||||
|
{
|
||||||
|
DisplayQueuedNotification();
|
||||||
|
}
|
||||||
|
|
||||||
|
return toastId;
|
||||||
|
}
|
||||||
|
|
||||||
|
ToastId ToastNotificationsView::ShowToastAtCursor(const AzQtComponents::ToastConfiguration& toastConfiguration)
|
||||||
|
{
|
||||||
|
ToastId toastId = CreateToastNotification(toastConfiguration);
|
||||||
|
m_notifications[toastId]->ShowToastAtCursor();
|
||||||
|
return toastId;
|
||||||
|
}
|
||||||
|
|
||||||
|
ToastId ToastNotificationsView::ShowToastAtPoint(const QPoint& screenPosition, const QPointF& anchorPoint, const AzQtComponents::ToastConfiguration& toastConfiguration)
|
||||||
|
{
|
||||||
|
ToastId toastId = CreateToastNotification(toastConfiguration);
|
||||||
|
m_notifications[toastId]->ShowToastAtPoint(screenPosition, anchorPoint);
|
||||||
|
return toastId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsView::HideToastNotification(const ToastId& toastId)
|
||||||
|
{
|
||||||
|
auto notificationIter = m_notifications.find(toastId);
|
||||||
|
if (notificationIter != m_notifications.end())
|
||||||
|
{
|
||||||
|
auto queuedIter = AZStd::find(m_queuedNotifications.begin(), m_queuedNotifications.end(), toastId);
|
||||||
|
if (queuedIter != m_queuedNotifications.end())
|
||||||
|
{
|
||||||
|
m_queuedNotifications.erase(queuedIter);
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationIter->second->reject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToastId ToastNotificationsView::CreateToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration)
|
||||||
|
{
|
||||||
|
AzQtComponents::ToastNotification* notification = aznew AzQtComponents::ToastNotification(parentWidget(), toastConfiguration);
|
||||||
|
ToastId toastId = AZ::Entity::MakeId();
|
||||||
|
m_notifications[toastId] = notification;
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
m_notifications[toastId], &AzQtComponents::ToastNotification::ToastNotificationHidden,
|
||||||
|
[toastId]()
|
||||||
|
{
|
||||||
|
ToastNotificationBus::Event(toastId, &ToastNotificationBus::Events::OnToastDismissed);
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
m_notifications[toastId], &AzQtComponents::ToastNotification::ToastNotificationInteraction,
|
||||||
|
[toastId]()
|
||||||
|
{
|
||||||
|
ToastNotificationBus::Event(toastId, &ToastNotificationBus::Events::OnToastInteraction);
|
||||||
|
});
|
||||||
|
|
||||||
|
return toastId;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint ToastNotificationsView::GetGlobalPoint()
|
||||||
|
{
|
||||||
|
QPoint relativePoint = m_offset;
|
||||||
|
|
||||||
|
AZ_Assert(parentWidget(), "ToastNotificationsView has invalid parent QWidget");
|
||||||
|
if (m_anchorPoint.x() == 1.0)
|
||||||
|
{
|
||||||
|
relativePoint.setX(parentWidget()->width() - m_offset.x());
|
||||||
|
}
|
||||||
|
if (m_anchorPoint.y() == 1.0)
|
||||||
|
{
|
||||||
|
relativePoint.setY(parentWidget()->height() - m_offset.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
return parentWidget()->mapToGlobal(relativePoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsView::DisplayQueuedNotification()
|
||||||
|
{
|
||||||
|
AZ_Assert(parentWidget(), "ToastNotificationsView has invalid parent QWidget");
|
||||||
|
if (m_queuedNotifications.empty() || !parentWidget()->isVisible() || !isVisible())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ToastId toastId = m_queuedNotifications.front();
|
||||||
|
m_queuedNotifications.erase(m_queuedNotifications.begin());
|
||||||
|
|
||||||
|
auto notificationIter = m_notifications.find(toastId);
|
||||||
|
if (notificationIter != m_notifications.end())
|
||||||
|
{
|
||||||
|
m_activeNotification = toastId;
|
||||||
|
|
||||||
|
notificationIter->second->ShowToastAtPoint(GetGlobalPoint(), m_anchorPoint);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
notificationIter->second, &AzQtComponents::ToastNotification::ToastNotificationHidden,
|
||||||
|
[&]()
|
||||||
|
{
|
||||||
|
m_activeNotification.SetInvalid();
|
||||||
|
DisplayQueuedNotification();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't actually show something, recurse to avoid things getting stuck in the queue.
|
||||||
|
if (!m_activeNotification.IsValid())
|
||||||
|
{
|
||||||
|
DisplayQueuedNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(Q_MOC_RUN)
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPoint>
|
||||||
|
#include <QPointF>
|
||||||
|
|
||||||
|
#include <AzCore/std/containers/vector.h>
|
||||||
|
#include <AzCore/std/containers/unordered_map.h>
|
||||||
|
#include <AzToolsFramework/UI/Notifications/ToastBus.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace AzQtComponents
|
||||||
|
{
|
||||||
|
class ToastNotification;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace AzToolsFramework
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* \brief A QWidget that displays and manages a queue of toast notifications.
|
||||||
|
*
|
||||||
|
* This view must be updated by its parent when the parent widget is show, hidden, moved
|
||||||
|
* or resized because toast notifications are displayed on top of the parent and are not part
|
||||||
|
* of the layout, so they must be manually moved.
|
||||||
|
*/
|
||||||
|
class ToastNotificationsView final
|
||||||
|
: public QWidget
|
||||||
|
, protected ToastRequestBus::Handler
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ToastNotificationsView(QWidget* parent, ToastRequestBusId busId);
|
||||||
|
~ToastNotificationsView() override;
|
||||||
|
|
||||||
|
void HideToastNotification(const ToastId& toastId) override;
|
||||||
|
|
||||||
|
ToastId ShowToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration) override;
|
||||||
|
ToastId ShowToastAtCursor(const AzQtComponents::ToastConfiguration& toastConfiguration) override;
|
||||||
|
ToastId ShowToastAtPoint(const QPoint& screenPosition, const QPointF& anchorPoint, const AzQtComponents::ToastConfiguration&) override;
|
||||||
|
|
||||||
|
void OnHide();
|
||||||
|
void OnShow();
|
||||||
|
void UpdateToastPosition();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ToastId CreateToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration);
|
||||||
|
void DisplayQueuedNotification();
|
||||||
|
QPoint GetGlobalPoint();
|
||||||
|
|
||||||
|
ToastId m_activeNotification;
|
||||||
|
AZStd::unordered_map<ToastId, AzQtComponents::ToastNotification*> m_notifications;
|
||||||
|
AZStd::vector<ToastId> m_queuedNotifications;
|
||||||
|
|
||||||
|
QPoint m_offset = QPoint(10, 10);
|
||||||
|
QPointF m_anchorPoint = QPointF(1, 0);
|
||||||
|
};
|
||||||
|
} // AzToolsFramework
|
||||||
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
||||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AzCore/EBus/EBus.h>
|
|
||||||
|
|
||||||
#include <GraphCanvas/Editor/EditorTypes.h>
|
|
||||||
|
|
||||||
namespace GraphCanvas
|
|
||||||
{
|
|
||||||
class ToastNotifications
|
|
||||||
: public AZ::EBusTraits
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
|
|
||||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
|
||||||
using BusIdType = ToastId;
|
|
||||||
|
|
||||||
virtual void OnToastInteraction() {}
|
|
||||||
virtual void OnToastDismissed() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
using ToastNotificationBus = AZ::EBus<ToastNotifications>;
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue