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>
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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 <AzCore/Component/Entity.h>
|
||||
#include <AzQtComponents/Components/ToastNotification.h>
|
||||
#include <AzQtComponents/Components/ui_ToastNotification.h>
|
||||
|
||||
#include <QCursor>
|
||||
#include <QIcon>
|
||||
#include <QToolButton>
|
||||
#include <QPropertyAnimation>
|
||||
|
||||
namespace AzQtComponents
|
||||
{
|
||||
ToastNotification::ToastNotification(QWidget* parent, const ToastConfiguration& toastConfiguration)
|
||||
: QDialog(parent, Qt::FramelessWindowHint)
|
||||
, m_closeOnClick(true)
|
||||
, m_ui(new Ui::ToastNotification())
|
||||
, m_fadeAnimation(nullptr)
|
||||
{
|
||||
setProperty("HasNoWindowDecorations", true);
|
||||
|
||||
setAttribute(Qt::WA_ShowWithoutActivating);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
m_ui->setupUi(this);
|
||||
|
||||
QIcon toastIcon;
|
||||
|
||||
switch (toastConfiguration.m_toastType)
|
||||
{
|
||||
case ToastType::Error:
|
||||
toastIcon = QIcon(":/stylesheet/img/logging/error.svg");
|
||||
break;
|
||||
case ToastType::Warning:
|
||||
toastIcon = QIcon(":/stylesheet/img/logging/warning-yellow.svg");
|
||||
break;
|
||||
case ToastType::Information:
|
||||
toastIcon = QIcon(":/stylesheet/img/logging/information.svg");
|
||||
break;
|
||||
case ToastType::Custom:
|
||||
toastIcon = QIcon(toastConfiguration.m_customIconImage);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_ui->iconLabel->setPixmap(toastIcon.pixmap(64, 64));
|
||||
|
||||
m_ui->titleLabel->setText(toastConfiguration.m_title);
|
||||
m_ui->mainLabel->setText(toastConfiguration.m_description);
|
||||
|
||||
m_lifeSpan.setInterval(aznumeric_cast<int>(toastConfiguration.m_duration.count()));
|
||||
m_closeOnClick = toastConfiguration.m_closeOnClick;
|
||||
|
||||
m_ui->closeButton->setVisible(m_closeOnClick);
|
||||
QObject::connect(m_ui->closeButton, &QToolButton::clicked, this, &ToastNotification::accept);
|
||||
|
||||
m_fadeDuration = toastConfiguration.m_fadeDuration;
|
||||
|
||||
QObject::connect(&m_lifeSpan, &QTimer::timeout, this, &ToastNotification::FadeOut);
|
||||
}
|
||||
|
||||
ToastNotification::~ToastNotification()
|
||||
{
|
||||
}
|
||||
|
||||
void ToastNotification::ShowToastAtCursor()
|
||||
{
|
||||
QPoint globalCursorPos = QCursor::pos();
|
||||
|
||||
// Left/middle align it relative to the cursor.
|
||||
QPointF anchorPoint(0, 0.5);
|
||||
|
||||
// Magic offset to try to get it to not hide under the cursor.
|
||||
// No way to get this programatically from what I can tell.
|
||||
globalCursorPos.setX(globalCursorPos.x() + 16);
|
||||
|
||||
ShowToastAtPoint(globalCursorPos, anchorPoint);
|
||||
}
|
||||
|
||||
void ToastNotification::ShowToastAtPoint(const QPoint& screenPosition, const QPointF& anchorPoint)
|
||||
{
|
||||
show();
|
||||
updateGeometry();
|
||||
|
||||
UpdatePosition(screenPosition, anchorPoint);
|
||||
}
|
||||
|
||||
void ToastNotification::UpdatePosition(const QPoint& screenPosition, const QPointF& anchorPoint)
|
||||
{
|
||||
QRect dialogGeometry = geometry();
|
||||
|
||||
QPoint finalPosition;
|
||||
finalPosition.setX(aznumeric_cast<int>(screenPosition.x() - dialogGeometry.width() * anchorPoint.x()));
|
||||
finalPosition.setY(aznumeric_cast<int>(screenPosition.y() - dialogGeometry.height() * anchorPoint.y()));
|
||||
|
||||
move(finalPosition);
|
||||
}
|
||||
|
||||
void ToastNotification::showEvent(QShowEvent* showEvent)
|
||||
{
|
||||
QDialog::showEvent(showEvent);
|
||||
|
||||
if (m_fadeDuration.count() > 0)
|
||||
{
|
||||
m_fadeAnimation = new QPropertyAnimation(this, "windowOpacity", this);
|
||||
m_fadeAnimation->setKeyValueAt(0, 0);
|
||||
m_fadeAnimation->setKeyValueAt(1, 1);
|
||||
|
||||
m_fadeAnimation->setDuration(static_cast<int>(m_fadeDuration.count()));
|
||||
|
||||
m_fadeAnimation->start();
|
||||
|
||||
QObject::connect(m_fadeAnimation, &QPropertyAnimation::finished, this, &ToastNotification::StartTimer);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void ToastNotification::hideEvent(QHideEvent* hideEvent)
|
||||
{
|
||||
QDialog::hideEvent(hideEvent);
|
||||
|
||||
m_lifeSpan.stop();
|
||||
|
||||
if (m_fadeAnimation)
|
||||
{
|
||||
m_fadeAnimation->stop();
|
||||
delete m_fadeAnimation;
|
||||
}
|
||||
|
||||
emit ToastNotificationHidden();
|
||||
}
|
||||
|
||||
void ToastNotification::mousePressEvent(QMouseEvent*)
|
||||
{
|
||||
if (m_closeOnClick)
|
||||
{
|
||||
emit ToastNotificationInteraction();
|
||||
accept();
|
||||
}
|
||||
}
|
||||
|
||||
bool ToastNotification::eventFilter(QObject*, QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
|
||||
if (mouseEvent && mouseEvent->button() == Qt::MouseButton::LeftButton)
|
||||
{
|
||||
accept();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ToastNotification::StartTimer()
|
||||
{
|
||||
delete m_fadeAnimation;
|
||||
m_fadeAnimation = nullptr;
|
||||
|
||||
if (m_lifeSpan.interval() != 0)
|
||||
{
|
||||
m_lifeSpan.start();
|
||||
}
|
||||
}
|
||||
|
||||
void ToastNotification::FadeOut()
|
||||
{
|
||||
if (m_fadeDuration.count() > 0)
|
||||
{
|
||||
m_fadeAnimation = new QPropertyAnimation(this, "windowOpacity", this);
|
||||
m_fadeAnimation->setKeyValueAt(0, windowOpacity());
|
||||
m_fadeAnimation->setKeyValueAt(1, 0);
|
||||
|
||||
m_fadeAnimation->setDuration(static_cast<int>(m_fadeDuration.count()));
|
||||
|
||||
m_fadeAnimation->start();
|
||||
|
||||
QObject::connect(m_fadeAnimation, &QPropertyAnimation::finished, this, &ToastNotification::accept);
|
||||
}
|
||||
else
|
||||
{
|
||||
accept();
|
||||
}
|
||||
}
|
||||
#include "Components/moc_ToastNotification.cpp"
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 <AzQtComponents/Components/ToastNotificationConfiguration.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <QEvent>
|
||||
#include <QDialog>
|
||||
#include <QMouseEvent>
|
||||
#include <QTimer>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ToastNotification;
|
||||
}
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QPropertyAnimation)
|
||||
|
||||
namespace AzQtComponents
|
||||
{
|
||||
class AZ_QT_COMPONENTS_API ToastNotification
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(ToastNotification, AZ::SystemAllocator, 0);
|
||||
|
||||
ToastNotification(QWidget* parent, const ToastConfiguration& toastConfiguration);
|
||||
virtual ~ToastNotification();
|
||||
|
||||
// Shows the toast notification relative to the current cursor.
|
||||
void ShowToastAtCursor();
|
||||
|
||||
// Aligns the toast notification so that the specified anchor point on the notification lies on the specified screen position.
|
||||
// i.e. anchor point of 0,0 will align the top left position of the dialog with the screen position
|
||||
// anchor point of 1,1 will align the bottom right position of the dialog with the screen position
|
||||
void ShowToastAtPoint(const QPoint& screenPosition, const QPointF& anchorPoint);
|
||||
|
||||
void UpdatePosition(const QPoint& screenPosition, const QPointF& anchorPoint);
|
||||
|
||||
// QDialog
|
||||
void showEvent(QShowEvent* showEvent) override;
|
||||
void hideEvent(QHideEvent* hideEvent) override;
|
||||
void mousePressEvent(QMouseEvent* mouseEvent) override;
|
||||
bool eventFilter(QObject* object, QEvent* event) override;
|
||||
|
||||
public slots:
|
||||
void StartTimer();
|
||||
void FadeOut();
|
||||
|
||||
signals:
|
||||
void ToastNotificationHidden();
|
||||
void ToastNotificationInteraction();
|
||||
|
||||
private:
|
||||
QPropertyAnimation* m_fadeAnimation;
|
||||
|
||||
bool m_closeOnClick;
|
||||
QTimer m_lifeSpan;
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
AZStd::chrono::milliseconds m_fadeDuration;
|
||||
AZStd::unique_ptr<Ui::ToastNotification> m_ui;
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
};
|
||||
} // namespace AzQtComponents
|
||||
@@ -0,0 +1,236 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ToastNotification</class>
|
||||
<widget class="QDialog" name="ToastNotification">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>225</width>
|
||||
<height>48</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>225</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="icon_frame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgba(255, 255, 255, 20);</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="iconLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">background-color: rgba(255, 255, 255, 0);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="resources.qrc">:/stylesheet/img/logging/information.svg</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="text_frame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="titleFrame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="titleLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Invalid Connection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="closeButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/stylesheet/img/close_x.svg</normaloff>:/stylesheet/img/close_x.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="mainLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Types are not a match.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
+18
@@ -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
|
||||
+46
@@ -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
|
||||
@@ -49,6 +49,11 @@ set(FILES
|
||||
Components/Titlebar.h
|
||||
Components/TitleBarOverdrawHandler.cpp
|
||||
Components/TitleBarOverdrawHandler.h
|
||||
Components/ToastNotification.cpp
|
||||
Components/ToastNotification.h
|
||||
Components/ToastNotificationConfiguration.h
|
||||
Components/ToastNotificationConfiguration.cpp
|
||||
Components/ToastNotification.ui
|
||||
Components/ToolButtonComboBox.cpp
|
||||
Components/ToolButtonComboBox.h
|
||||
Components/ToolButtonLineEdit.cpp
|
||||
|
||||
Reference in New Issue
Block a user