2015-09-06 20:20:00 +02:00
|
|
|
#include "./notificationlabel.h"
|
2015-04-22 19:33:53 +02:00
|
|
|
|
|
|
|
#include <QBrush>
|
|
|
|
#include <QConicalGradient>
|
2017-07-30 20:57:55 +02:00
|
|
|
#include <QCoreApplication>
|
2018-03-07 01:18:01 +01:00
|
|
|
#include <QFontMetrics>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QPaintEvent>
|
|
|
|
#include <QPainter>
|
|
|
|
#include <QPixmap>
|
2017-07-30 20:57:55 +02:00
|
|
|
#include <QStringBuilder>
|
2018-06-05 22:45:43 +02:00
|
|
|
#include <QStyle>
|
2018-03-07 01:18:01 +01:00
|
|
|
#include <QStyleOption>
|
2015-04-22 19:33:53 +02:00
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
namespace QtGui {
|
|
|
|
|
2017-08-08 18:45:23 +02:00
|
|
|
const QChar NotificationLabel::s_bulletPoint(0x2022);
|
|
|
|
const QString NotificationLabel::s_bulletLine(QStringLiteral("\n• "));
|
|
|
|
|
2018-03-07 01:18:01 +01:00
|
|
|
NotificationLabel::NotificationLabel(QWidget *parent)
|
|
|
|
: QWidget(parent)
|
|
|
|
, m_type(NotificationType::Information)
|
|
|
|
, m_subject(NotificationSubject::None)
|
|
|
|
, m_percentage(-1)
|
|
|
|
, m_minIconSize(25)
|
|
|
|
, m_maxIconSize(25)
|
|
|
|
, m_pixmapsInvalidated(true)
|
|
|
|
, m_animationStep(0)
|
|
|
|
, m_maxLineCount(infiniteLines)
|
|
|
|
, m_currentLineCount(0)
|
2015-04-22 19:33:53 +02:00
|
|
|
{
|
|
|
|
connect(&m_updateTimer, &QTimer::timeout, this, &NotificationLabel::updateAnimation);
|
|
|
|
m_updateTimer.setInterval(80);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationLabel::paintEvent(QPaintEvent *event)
|
|
|
|
{
|
|
|
|
QStyle *style = QWidget::style();
|
|
|
|
QStyleOption option;
|
2020-09-04 00:59:22 +02:00
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
|
|
|
option.initFrom(this);
|
|
|
|
#else
|
2015-04-22 19:33:53 +02:00
|
|
|
option.init(this);
|
2020-09-04 00:59:22 +02:00
|
|
|
#endif
|
2015-04-22 19:33:53 +02:00
|
|
|
int iconSize = option.rect.height() > m_maxIconSize ? m_maxIconSize : option.rect.height();
|
|
|
|
QRect pixmapRect(option.rect.x(), option.rect.y(), iconSize, iconSize);
|
|
|
|
pixmapRect.moveCenter(QRect(option.rect.x(), option.rect.y(), iconSize, option.rect.height()).center());
|
|
|
|
QRect textRect(option.rect.x() + iconSize + 5, option.rect.y(), option.rect.width() - iconSize - 5, option.rect.height());
|
|
|
|
QPainter painter(this);
|
|
|
|
|
2018-03-07 01:18:01 +01:00
|
|
|
if (event->rect().contains(textRect)) {
|
|
|
|
style->drawItemText(&painter, textRect,
|
|
|
|
static_cast<int>(QStyle::visualAlignment(layoutDirection(), Qt::AlignVCenter | Qt::AlignLeft | Qt::AlignJustify)), option.palette,
|
|
|
|
isEnabled(), m_text, foregroundRole());
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
2018-03-07 01:18:01 +01:00
|
|
|
if (event->rect().contains(pixmapRect)) {
|
2015-04-22 19:33:53 +02:00
|
|
|
setupPixmaps(pixmapRect.size());
|
2018-03-07 01:18:01 +01:00
|
|
|
switch (m_type) {
|
2015-04-22 19:33:53 +02:00
|
|
|
case NotificationType::Progress:
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_subject == NotificationSubject::None) {
|
2019-06-25 14:00:09 +02:00
|
|
|
drawProgressIndicator(painter, pixmapRect, option.palette.color(QPalette::WindowText), m_animationStep);
|
2015-04-22 19:33:53 +02:00
|
|
|
} else {
|
|
|
|
style->drawItemPixmap(&painter, pixmapRect, Qt::AlignTop | Qt::AlignLeft, m_mainPixmap);
|
|
|
|
QSize size = pixmapRect.size() * 0.3;
|
|
|
|
pixmapRect.adjust(size.width(), size.height(), 0, 0);
|
2019-06-25 14:00:09 +02:00
|
|
|
drawProgressIndicator(painter, pixmapRect, option.palette.color(QPalette::WindowText), m_animationStep);
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_subject == NotificationSubject::None) {
|
2015-04-22 19:33:53 +02:00
|
|
|
style->drawItemPixmap(&painter, pixmapRect, Qt::AlignCenter, m_mainPixmap);
|
|
|
|
} else {
|
|
|
|
style->drawItemPixmap(&painter, pixmapRect, Qt::AlignTop | Qt::AlignLeft, m_mainPixmap);
|
|
|
|
style->drawItemPixmap(&painter, pixmapRect, Qt::AlignBottom | Qt::AlignRight, m_smallPixmap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-30 20:57:55 +02:00
|
|
|
void NotificationLabel::mouseDoubleClickEvent(QMouseEvent *event)
|
|
|
|
{
|
2017-08-08 18:44:42 +02:00
|
|
|
Q_UNUSED(event)
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_type == NotificationType::Progress) {
|
2017-07-30 20:57:55 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
showMessageBox();
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
void NotificationLabel::updateAnimation()
|
|
|
|
{
|
2018-03-07 01:18:01 +01:00
|
|
|
switch (m_type) {
|
2015-04-22 19:33:53 +02:00
|
|
|
case NotificationType::Progress:
|
|
|
|
m_animationStep = m_animationStep >= 15 ? m_animationStep - 15 : (360 - 15);
|
|
|
|
break;
|
2018-03-07 01:18:01 +01:00
|
|
|
default:;
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
update(iconRect());
|
|
|
|
}
|
|
|
|
|
2017-07-30 20:57:55 +02:00
|
|
|
void NotificationLabel::showMessageBox() const
|
|
|
|
{
|
|
|
|
QMessageBox msgbox;
|
|
|
|
msgbox.setWindowTitle((m_context.isEmpty() ? tr("Notifications") : m_context) % QStringLiteral(" - ") % QCoreApplication::applicationName());
|
|
|
|
msgbox.setIconPixmap(m_mainPixmap);
|
|
|
|
msgbox.setText(m_text);
|
|
|
|
msgbox.exec();
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
QRect NotificationLabel::iconRect() const
|
|
|
|
{
|
|
|
|
QRect rect = this->rect();
|
|
|
|
int iconSize = rect.height() > m_maxIconSize ? m_maxIconSize : rect.height();
|
|
|
|
QRect pixmapRect(rect.x(), rect.y(), iconSize, iconSize);
|
|
|
|
pixmapRect.moveCenter(QRect(rect.x(), rect.y(), iconSize, rect.height()).center());
|
|
|
|
return pixmapRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect NotificationLabel::textRect() const
|
|
|
|
{
|
|
|
|
QRect rect = this->rect();
|
|
|
|
int iconSize = rect.height() > m_maxIconSize ? m_maxIconSize : rect.height();
|
|
|
|
return QRect(rect.x() + iconSize + 5, rect.y(), rect.width() - iconSize - 5, rect.height());
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationLabel::setupPixmaps(const QSize &size)
|
|
|
|
{
|
2017-08-08 18:44:42 +02:00
|
|
|
const QStyle *const style = QWidget::style();
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_pixmapsInvalidated) {
|
2015-04-22 19:33:53 +02:00
|
|
|
m_mainPixmap = QPixmap();
|
|
|
|
m_smallPixmap = QPixmap();
|
2017-08-08 18:44:42 +02:00
|
|
|
QStyle::StandardPixmap icon;
|
2018-03-07 01:18:01 +01:00
|
|
|
switch (m_type) {
|
2015-04-22 19:33:53 +02:00
|
|
|
case NotificationType::Information:
|
|
|
|
icon = QStyle::SP_MessageBoxInformation;
|
|
|
|
break;
|
|
|
|
case NotificationType::Warning:
|
|
|
|
icon = QStyle::SP_MessageBoxWarning;
|
|
|
|
break;
|
|
|
|
case NotificationType::Critical:
|
|
|
|
icon = QStyle::SP_MessageBoxCritical;
|
|
|
|
break;
|
|
|
|
case NotificationType::TaskComplete:
|
|
|
|
icon = QStyle::SP_DialogApplyButton;
|
|
|
|
break;
|
|
|
|
default:
|
2017-08-08 18:44:42 +02:00
|
|
|
icon = static_cast<QStyle::StandardPixmap>(QStyle::SP_CustomBase + 1);
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
2018-03-07 01:18:01 +01:00
|
|
|
switch (m_subject) {
|
2015-04-22 19:33:53 +02:00
|
|
|
case NotificationSubject::None:
|
2018-03-07 01:18:01 +01:00
|
|
|
if (icon != QStyle::SP_CustomBase + 1) {
|
2015-04-22 19:33:53 +02:00
|
|
|
m_mainPixmap = style->standardIcon(icon, nullptr, this).pixmap(size);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NotificationSubject::Saving:
|
|
|
|
m_mainPixmap = style->standardIcon(QStyle::SP_DialogSaveButton, nullptr, this).pixmap(size * 0.8);
|
2018-03-07 01:18:01 +01:00
|
|
|
if (icon != QStyle::SP_CustomBase + 1) {
|
2015-04-22 19:33:53 +02:00
|
|
|
m_smallPixmap = style->standardIcon(icon, nullptr, this).pixmap(size * 0.6);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
m_pixmapsInvalidated = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:41:06 +01:00
|
|
|
void NotificationLabel::drawProgressIndicator(QPainter &painter, QRect rect, const QColor &color, int angle)
|
2015-04-22 19:33:53 +02:00
|
|
|
{
|
2017-08-08 18:44:42 +02:00
|
|
|
constexpr int circleWidth = 6;
|
|
|
|
constexpr int halfCircleWidth = circleWidth / 2;
|
2015-04-22 19:33:53 +02:00
|
|
|
rect.adjust(halfCircleWidth + 1, halfCircleWidth + 1, -halfCircleWidth - 1, -halfCircleWidth - 1);
|
2017-08-08 18:44:42 +02:00
|
|
|
const QPointF center = rect.center();
|
2015-04-22 19:33:53 +02:00
|
|
|
painter.setRenderHint(QPainter::Antialiasing, true);
|
|
|
|
QConicalGradient linearGrad(center, angle);
|
2015-11-09 21:41:06 +01:00
|
|
|
linearGrad.setColorAt(0, color);
|
2015-04-22 19:33:53 +02:00
|
|
|
linearGrad.setColorAt(1, Qt::transparent);
|
|
|
|
painter.setPen(QPen(linearGrad, circleWidth, Qt::SolidLine, Qt::RoundCap));
|
|
|
|
painter.drawArc(rect, angle * 16 + 25 * 16, 16 * 310);
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_percentage > 0 && m_percentage <= 100) {
|
2015-04-22 19:33:53 +02:00
|
|
|
QFont font = this->font();
|
2017-08-08 18:44:42 +02:00
|
|
|
font.setPixelSize(rect.width() / 2);
|
2015-04-22 19:33:53 +02:00
|
|
|
painter.setFont(font);
|
2015-11-09 21:41:06 +01:00
|
|
|
painter.setPen(color);
|
2015-04-22 19:33:53 +02:00
|
|
|
painter.drawText(rect, Qt::AlignCenter, QString::number(m_percentage));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-08 18:45:23 +02:00
|
|
|
void NotificationLabel::applyMaxLineCount()
|
|
|
|
{
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_maxLineCount == infiniteLines || m_currentLineCount < 2) {
|
2017-08-08 18:45:23 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-07-23 22:17:47 +02:00
|
|
|
auto newStart = QString::size_type();
|
2018-03-07 01:18:01 +01:00
|
|
|
for (; m_currentLineCount > m_maxLineCount; --m_currentLineCount) {
|
2023-07-23 22:17:47 +02:00
|
|
|
const auto nextBullet = m_text.indexOf(s_bulletLine, newStart);
|
2018-03-07 01:18:01 +01:00
|
|
|
if (nextBullet < 0) {
|
2017-08-08 18:45:23 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
newStart = nextBullet;
|
|
|
|
}
|
2018-03-07 01:18:01 +01:00
|
|
|
if (newStart) {
|
2017-08-08 18:45:23 +02:00
|
|
|
m_text.remove(0, newStart + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
QSize NotificationLabel::sizeHint() const
|
|
|
|
{
|
2016-10-09 19:44:06 +02:00
|
|
|
const QFontMetrics fm(fontMetrics());
|
2015-04-22 19:33:53 +02:00
|
|
|
QSize size = fm.size(0, m_text);
|
2018-03-07 01:18:01 +01:00
|
|
|
if (size.height() < m_minIconSize) {
|
2015-04-22 19:33:53 +02:00
|
|
|
size.setHeight(m_minIconSize);
|
|
|
|
}
|
2016-10-09 19:44:06 +02:00
|
|
|
const int iconSize = size.height() > m_maxIconSize ? m_maxIconSize : size.height();
|
2015-04-22 19:33:53 +02:00
|
|
|
size.setWidth(iconSize + 5 + size.width());
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2016-10-09 19:44:06 +02:00
|
|
|
QSize NotificationLabel::minimumSizeHint() const
|
|
|
|
{
|
|
|
|
return QSize(m_minIconSize, m_minIconSize);
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
void NotificationLabel::setText(const QString &text)
|
|
|
|
{
|
2016-10-09 22:41:34 +02:00
|
|
|
const bool updateTooltip = toolTip().isEmpty() || toolTip() == m_text;
|
2015-04-22 19:33:53 +02:00
|
|
|
m_text = text;
|
2017-08-08 18:45:23 +02:00
|
|
|
m_currentLineCount = 1;
|
2015-04-22 19:33:53 +02:00
|
|
|
updateGeometry();
|
|
|
|
update(textRect());
|
2018-03-07 01:18:01 +01:00
|
|
|
if (updateTooltip) {
|
2016-10-09 22:41:34 +02:00
|
|
|
setToolTip(m_text);
|
2016-10-09 19:44:06 +02:00
|
|
|
}
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
|
2016-03-03 22:21:15 +01:00
|
|
|
void NotificationLabel::clearText()
|
|
|
|
{
|
2018-03-07 01:18:01 +01:00
|
|
|
if (toolTip() == m_text) {
|
2016-10-09 22:41:34 +02:00
|
|
|
setToolTip(QString());
|
2016-10-09 19:44:06 +02:00
|
|
|
}
|
2016-03-03 22:21:15 +01:00
|
|
|
m_text.clear();
|
2017-08-08 18:45:23 +02:00
|
|
|
m_currentLineCount = 0;
|
2016-03-03 22:21:15 +01:00
|
|
|
updateGeometry();
|
|
|
|
update(textRect());
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
void NotificationLabel::appendLine(const QString &line)
|
|
|
|
{
|
2016-10-09 19:44:06 +02:00
|
|
|
const bool updateTooltip = toolTip().isEmpty() || toolTip() == m_text;
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_text.isEmpty()) {
|
2015-04-22 19:33:53 +02:00
|
|
|
m_text = line;
|
2017-08-08 18:45:23 +02:00
|
|
|
m_currentLineCount = 1;
|
2015-04-22 19:33:53 +02:00
|
|
|
} else {
|
2018-03-07 01:18:01 +01:00
|
|
|
if (!m_text.startsWith(s_bulletPoint)) {
|
2017-08-08 18:45:23 +02:00
|
|
|
m_text = s_bulletPoint % QChar(' ') % m_text % s_bulletLine % line;
|
|
|
|
} else {
|
|
|
|
m_text = m_text % s_bulletLine % line;
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
2017-08-08 18:45:23 +02:00
|
|
|
++m_currentLineCount;
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
2017-08-08 18:45:23 +02:00
|
|
|
applyMaxLineCount();
|
2015-04-22 19:33:53 +02:00
|
|
|
updateGeometry();
|
|
|
|
update(textRect());
|
2018-03-07 01:18:01 +01:00
|
|
|
if (updateTooltip) {
|
2016-10-09 19:44:06 +02:00
|
|
|
setToolTip(m_text);
|
|
|
|
}
|
2015-04-22 19:33:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationLabel::setNotificationSubject(NotificationSubject value)
|
|
|
|
{
|
|
|
|
m_subject = value;
|
|
|
|
m_pixmapsInvalidated = true;
|
|
|
|
update(iconRect());
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationLabel::setNotificationType(NotificationType value)
|
|
|
|
{
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_type != value) {
|
2015-04-22 19:33:53 +02:00
|
|
|
m_type = value;
|
|
|
|
m_pixmapsInvalidated = true;
|
|
|
|
m_animationStep = 0;
|
|
|
|
update(iconRect());
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_type == NotificationType::Progress) {
|
2015-04-22 19:33:53 +02:00
|
|
|
m_updateTimer.start();
|
|
|
|
} else {
|
|
|
|
m_updateTimer.stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationLabel::setPercentage(int percentage)
|
|
|
|
{
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_percentage != percentage) {
|
2015-04-22 19:33:53 +02:00
|
|
|
m_percentage = percentage;
|
|
|
|
update(iconRect());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NotificationLabel::setMaxIconSize(int size)
|
|
|
|
{
|
|
|
|
m_maxIconSize = size;
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_minIconSize > size) {
|
2015-04-22 19:33:53 +02:00
|
|
|
m_minIconSize = size;
|
|
|
|
}
|
|
|
|
m_pixmapsInvalidated = true;
|
|
|
|
updateGeometry();
|
|
|
|
}
|
|
|
|
|
2017-08-08 18:45:23 +02:00
|
|
|
void NotificationLabel::setMaxLineCount(std::size_t maxLineCount)
|
|
|
|
{
|
|
|
|
m_maxLineCount = maxLineCount;
|
|
|
|
applyMaxLineCount();
|
|
|
|
}
|
|
|
|
|
2015-04-22 19:33:53 +02:00
|
|
|
void NotificationLabel::setMinIconSize(int size)
|
|
|
|
{
|
|
|
|
m_minIconSize = size;
|
2018-03-07 01:18:01 +01:00
|
|
|
if (m_maxIconSize < size) {
|
2015-04-22 19:33:53 +02:00
|
|
|
m_maxIconSize = size;
|
|
|
|
}
|
|
|
|
m_pixmapsInvalidated = true;
|
|
|
|
updateGeometry();
|
|
|
|
}
|
|
|
|
|
2018-03-07 01:18:01 +01:00
|
|
|
} // namespace QtGui
|