Files
o3de/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp
T
Michael Pollind 32bebe1c8c bugifx: resolve crash with project manager (#5151)
- system allocator not configured in environment for AZQtComponents
- WA_DeleteOnClose will destroy the toast dialog causing a crashing when ToastNotificationsView tries to access the pointer

issue: https://github.com/o3de/o3de/issues/5129
Signed-off-by: Michael Pollind <mpollind@gmail.com>
2021-11-02 08:59:19 -07:00

236 lines
6.9 KiB
C++

/*
* 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>
#include <QPainter>
namespace AzQtComponents
{
ToastNotification::ToastNotification(QWidget* parent, const ToastConfiguration& toastConfiguration)
: QDialog(parent, Qt::FramelessWindowHint)
, m_closeOnClick(true)
, m_ui(new Ui::ToastNotification())
, m_fadeAnimation(nullptr)
, m_configuration(toastConfiguration)
{
setProperty("HasNoWindowDecorations", true);
setAttribute(Qt::WA_ShowWithoutActivating);
m_borderRadius = toastConfiguration.m_borderRadius;
if (m_borderRadius > 0)
{
setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
setAttribute(Qt::WA_TranslucentBackground);
}
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);
// hide the optional description if none is provided so the title is centered vertically
if (toastConfiguration.m_description.isEmpty())
{
m_ui->mainLabel->setVisible(false);
m_ui->verticalLayout->removeWidget(m_ui->mainLabel);
}
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()
{
}
bool ToastNotification::IsDuplicate(const ToastConfiguration& toastConfiguration)
{
return toastConfiguration.m_title == m_configuration.m_title
&& toastConfiguration.m_description == m_configuration.m_description;
}
void ToastNotification::paintEvent(QPaintEvent* event)
{
if (m_borderRadius > 0)
{
QPainter p(this);
p.setPen(Qt::transparent);
QColor painterColor;
painterColor.setRgbF(0, 0, 0, 255);
p.setBrush(painterColor);
p.setRenderHint(QPainter::Antialiasing);
p.drawRoundedRect(rect(), m_borderRadius, m_borderRadius);
}
else
{
QDialog::paintEvent(event);
}
}
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"
}