work on toasts
This commit is contained in:
parent
5f2dab4362
commit
6e0bcdb872
@ -5,12 +5,15 @@
|
|||||||
#include "miscellaneous/iconfactory.h"
|
#include "miscellaneous/iconfactory.h"
|
||||||
|
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
BaseToastNotification::BaseToastNotification(QWidget* parent) : QDialog(parent) {
|
BaseToastNotification::BaseToastNotification(QWidget* parent) : QDialog(parent) {
|
||||||
setAttribute(Qt::WidgetAttribute::WA_ShowWithoutActivating);
|
setAttribute(Qt::WidgetAttribute::WA_ShowWithoutActivating);
|
||||||
setFixedWidth(NOTIFICATIONS_WIDTH);
|
setFixedWidth(NOTIFICATIONS_WIDTH);
|
||||||
setFocusPolicy(Qt::FocusPolicy::NoFocus);
|
setFocusPolicy(Qt::FocusPolicy::NoFocus);
|
||||||
|
|
||||||
|
setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose, false);
|
||||||
|
|
||||||
setWindowFlags(
|
setWindowFlags(
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
Qt::WindowType::SubWindow |
|
Qt::WindowType::SubWindow |
|
||||||
@ -19,6 +22,8 @@ BaseToastNotification::BaseToastNotification(QWidget* parent) : QDialog(parent)
|
|||||||
#endif
|
#endif
|
||||||
Qt::WindowType::FramelessWindowHint | Qt::WindowType::WindowStaysOnTopHint | Qt::WindowType::WindowSystemMenuHint);
|
Qt::WindowType::FramelessWindowHint | Qt::WindowType::WindowStaysOnTopHint | Qt::WindowType::WindowSystemMenuHint);
|
||||||
|
|
||||||
|
setStyleSheet(QSL("BaseToastNotification { border: 1px solid black; }"));
|
||||||
|
|
||||||
installEventFilter(this);
|
installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +32,11 @@ BaseToastNotification::~BaseToastNotification() {}
|
|||||||
void BaseToastNotification::setupCloseButton(QAbstractButton* btn) {
|
void BaseToastNotification::setupCloseButton(QAbstractButton* btn) {
|
||||||
btn->setIcon(qApp->icons()->fromTheme(QSL("dialog-close"), QSL("gtk-close")));
|
btn->setIcon(qApp->icons()->fromTheme(QSL("dialog-close"), QSL("gtk-close")));
|
||||||
|
|
||||||
connect(btn, &QAbstractButton::clicked, this, &BaseToastNotification::closeRequested);
|
connect(btn, &QAbstractButton::clicked, this, &BaseToastNotification::close);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseToastNotification::setupTimedClosing() {
|
||||||
|
QTimer::singleShot(15000, this, &BaseToastNotification::close);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseToastNotification::eventFilter(QObject* watched, QEvent* event) {
|
bool BaseToastNotification::eventFilter(QObject* watched, QEvent* event) {
|
||||||
@ -40,5 +49,7 @@ bool BaseToastNotification::eventFilter(QObject* watched, QEvent* event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BaseToastNotification::closeEvent(QCloseEvent* event) {
|
void BaseToastNotification::closeEvent(QCloseEvent* event) {
|
||||||
event->ignore();
|
emit closeRequested(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseToastNotification::reject() {}
|
||||||
|
@ -17,14 +17,21 @@ class BaseToastNotification : public QDialog {
|
|||||||
// If true, then notification is always moved as close to top as possible.
|
// If true, then notification is always moved as close to top as possible.
|
||||||
virtual bool alwaysOnTop() const = 0;
|
virtual bool alwaysOnTop() const = 0;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
virtual void reject();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||||
virtual void closeEvent(QCloseEvent* event);
|
virtual void closeEvent(QCloseEvent* event);
|
||||||
|
|
||||||
void setupCloseButton(QAbstractButton* btn);
|
void setupCloseButton(QAbstractButton* btn);
|
||||||
|
void setupTimedClosing();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void closeRequested();
|
void closeRequested(BaseToastNotification* notif);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_timerId;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BASETOASTNOTIFICATION_H
|
#endif // BASETOASTNOTIFICATION_H
|
||||||
|
@ -16,6 +16,7 @@ ToastNotification::ToastNotification(Notification::Event event,
|
|||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
||||||
setupCloseButton(m_ui.m_btnClose);
|
setupCloseButton(m_ui.m_btnClose);
|
||||||
|
setupTimedClosing();
|
||||||
loadNotification(event, msg, action);
|
loadNotification(event, msg, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,9 +38,8 @@ void ToastNotificationsManager::setPosition(NotificationPosition position) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ToastNotificationsManager::clear() {
|
void ToastNotificationsManager::clear() {
|
||||||
for (BaseToastNotification* nt : m_activeNotifications) {
|
for (BaseToastNotification* notif : m_activeNotifications) {
|
||||||
nt->close();
|
closeNotification(notif);
|
||||||
nt->deleteLater();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_activeNotifications.clear();
|
m_activeNotifications.clear();
|
||||||
@ -51,6 +50,8 @@ void ToastNotificationsManager::showNotification(Notification::Event event,
|
|||||||
const GuiAction& action) {
|
const GuiAction& action) {
|
||||||
ToastNotification* notif = new ToastNotification(event, msg, action, qApp->mainFormWidget());
|
ToastNotification* notif = new ToastNotification(event, msg, action, qApp->mainFormWidget());
|
||||||
|
|
||||||
|
hookNotification(notif);
|
||||||
|
|
||||||
auto* screen = moveToProperScreen(notif);
|
auto* screen = moveToProperScreen(notif);
|
||||||
|
|
||||||
// Insert new notification into free space.
|
// Insert new notification into free space.
|
||||||
@ -58,14 +59,13 @@ void ToastNotificationsManager::showNotification(Notification::Event event,
|
|||||||
|
|
||||||
auto notif_new_pos = cornerForNewNotification(screen->availableGeometry());
|
auto notif_new_pos = cornerForNewNotification(screen->availableGeometry());
|
||||||
|
|
||||||
moveNotificationToCorner(notif, notif_new_pos);
|
|
||||||
|
|
||||||
notif->move(notif_new_pos);
|
|
||||||
|
|
||||||
// Make sure notification is finally resized.
|
// Make sure notification is finally resized.
|
||||||
notif->adjustSize();
|
notif->adjustSize();
|
||||||
qApp->processEvents();
|
qApp->processEvents();
|
||||||
|
|
||||||
|
// Move notification, at this point we already need to know its precise size.
|
||||||
|
moveNotificationToCorner(notif, notif_new_pos);
|
||||||
|
|
||||||
// Remove out-of-bounds old notifications and shift existing
|
// Remove out-of-bounds old notifications and shift existing
|
||||||
// ones to make space for new notifications.
|
// ones to make space for new notifications.
|
||||||
removeOutOfBoundsNotifications(notif->height());
|
removeOutOfBoundsNotifications(notif->height());
|
||||||
@ -76,6 +76,21 @@ void ToastNotificationsManager::showNotification(Notification::Event event,
|
|||||||
|
|
||||||
void ToastNotificationsManager::showNotification(const QList<Message>& new_messages) {}
|
void ToastNotificationsManager::showNotification(const QList<Message>& new_messages) {}
|
||||||
|
|
||||||
|
void ToastNotificationsManager::closeNotification(BaseToastNotification* notif) {
|
||||||
|
auto notif_idx = m_activeNotifications.indexOf(notif);
|
||||||
|
|
||||||
|
notif->deleteLater();
|
||||||
|
|
||||||
|
m_activeNotifications.removeAll(notif);
|
||||||
|
|
||||||
|
// Shift all notifications.
|
||||||
|
if (notif_idx < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
makeSpaceForNotification(notif->height(), true, notif_idx);
|
||||||
|
}
|
||||||
|
|
||||||
QScreen* ToastNotificationsManager::activeScreen() const {
|
QScreen* ToastNotificationsManager::activeScreen() const {
|
||||||
if (m_screen >= 0) {
|
if (m_screen >= 0) {
|
||||||
auto all_screens = QGuiApplication::screens();
|
auto all_screens = QGuiApplication::screens();
|
||||||
@ -88,23 +103,28 @@ QScreen* ToastNotificationsManager::activeScreen() const {
|
|||||||
return QGuiApplication::primaryScreen();
|
return QGuiApplication::primaryScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
QPoint ToastNotificationsManager::cornerForNewNotification(QRect rect) {
|
QPoint ToastNotificationsManager::cornerForNewNotification(QRect screen_rect) {
|
||||||
switch (m_position) {
|
switch (m_position) {
|
||||||
case ToastNotificationsManager::TopLeft:
|
case ToastNotificationsManager::TopLeft:
|
||||||
return rect.topLeft() + QPoint(NOTIFICATIONS_MARGIN, NOTIFICATIONS_MARGIN);
|
return screen_rect.topLeft() + QPoint(NOTIFICATIONS_MARGIN, NOTIFICATIONS_MARGIN);
|
||||||
|
|
||||||
case ToastNotificationsManager::TopRight:
|
case ToastNotificationsManager::TopRight:
|
||||||
return rect.topRight() - QPoint(NOTIFICATIONS_WIDTH + NOTIFICATIONS_MARGIN, -NOTIFICATIONS_MARGIN);
|
return screen_rect.topRight() - QPoint(NOTIFICATIONS_WIDTH + NOTIFICATIONS_MARGIN, -NOTIFICATIONS_MARGIN);
|
||||||
|
|
||||||
case ToastNotificationsManager::BottomLeft:
|
case ToastNotificationsManager::BottomLeft:
|
||||||
return rect.bottomLeft() - QPoint(-NOTIFICATIONS_MARGIN, NOTIFICATIONS_MARGIN);
|
return screen_rect.bottomLeft() - QPoint(-NOTIFICATIONS_MARGIN, NOTIFICATIONS_MARGIN);
|
||||||
|
|
||||||
case ToastNotificationsManager::BottomRight:
|
case ToastNotificationsManager::BottomRight:
|
||||||
return rect.bottomRight() - QPoint(NOTIFICATIONS_MARGIN, NOTIFICATIONS_MARGIN);
|
default:
|
||||||
|
return screen_rect.bottomRight() - QPoint(NOTIFICATIONS_MARGIN, NOTIFICATIONS_MARGIN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToastNotificationsManager::moveNotificationToCorner(BaseToastNotification* notif, const QPoint& corner) {
|
void ToastNotificationsManager::hookNotification(BaseToastNotification* notif) {
|
||||||
|
connect(notif, &BaseToastNotification::closeRequested, this, &ToastNotificationsManager::closeNotification);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsManager::moveNotificationToCorner(BaseToastNotification* notif, QPoint corner) {
|
||||||
switch (m_position) {
|
switch (m_position) {
|
||||||
case ToastNotificationsManager::TopLeft:
|
case ToastNotificationsManager::TopLeft:
|
||||||
notif->move(corner);
|
notif->move(corner);
|
||||||
@ -119,14 +139,34 @@ void ToastNotificationsManager::moveNotificationToCorner(BaseToastNotification*
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ToastNotificationsManager::BottomRight:
|
case ToastNotificationsManager::BottomRight:
|
||||||
notif->move(corner);
|
notif->move(corner.x() - notif->frameGeometry().width(), corner.y() - notif->frameGeometry().height());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToastNotificationsManager::makeSpaceForNotification(int height_to_make_space) {
|
void ToastNotificationsManager::makeSpaceForNotification(int height_to_make_space, bool reverse, int stard_idx) {
|
||||||
for (BaseToastNotification* notif : m_activeNotifications) {
|
for (int i = stard_idx; i < m_activeNotifications.size(); i++) {
|
||||||
notif->move(notif->pos().x(), notif->pos().y() + height_to_make_space + NOTIFICATIONS_MARGIN);
|
BaseToastNotification* notif = m_activeNotifications.at(i);
|
||||||
|
|
||||||
|
switch (m_position) {
|
||||||
|
case ToastNotificationsManager::TopLeft:
|
||||||
|
case ToastNotificationsManager::TopRight: {
|
||||||
|
auto shift_down = reverse ? [](int x, int y) {return x - y;} : [](int x, int y) {return x + y;};
|
||||||
|
|
||||||
|
// Move it all down.
|
||||||
|
notif->move(notif->pos().x(), shift_down(notif->pos().y(), (height_to_make_space + NOTIFICATIONS_MARGIN)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ToastNotificationsManager::BottomLeft:
|
||||||
|
case ToastNotificationsManager::BottomRight: {
|
||||||
|
auto shift_up = reverse ? [](int x, int y) {return x + y;} : [](int x, int y) {return x - y;};
|
||||||
|
|
||||||
|
// Move it all up.
|
||||||
|
notif->move(notif->pos().x(), shift_up(notif->pos().y(), height_to_make_space + NOTIFICATIONS_MARGIN));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,13 +40,18 @@ class ToastNotificationsManager : public QObject {
|
|||||||
void showNotification(Notification::Event event, const GuiMessage& msg, const GuiAction& action);
|
void showNotification(Notification::Event event, const GuiMessage& msg, const GuiAction& action);
|
||||||
void showNotification(const QList<Message>& new_messages);
|
void showNotification(const QList<Message>& new_messages);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void closeNotification(BaseToastNotification* notif);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QScreen* activeScreen() const;
|
QScreen* activeScreen() const;
|
||||||
QPoint cornerForNewNotification(QRect rect);
|
|
||||||
void moveNotificationToCorner(BaseToastNotification* notif, const QPoint& corner);
|
|
||||||
void makeSpaceForNotification(int height_to_make_space);
|
|
||||||
void removeOutOfBoundsNotifications(int height_to_reserve);
|
|
||||||
QScreen* moveToProperScreen(BaseToastNotification* notif);
|
QScreen* moveToProperScreen(BaseToastNotification* notif);
|
||||||
|
QPoint cornerForNewNotification(QRect screen_rect);
|
||||||
|
|
||||||
|
void hookNotification(BaseToastNotification* notif);
|
||||||
|
void moveNotificationToCorner(BaseToastNotification* notif, QPoint corner);
|
||||||
|
void makeSpaceForNotification(int height_to_make_space, bool reverse = false, int stard_idx = 0);
|
||||||
|
void removeOutOfBoundsNotifications(int height_to_reserve);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NotificationPosition m_position;
|
NotificationPosition m_position;
|
||||||
|
@ -690,6 +690,7 @@ void Application::showGuiMessageCore(Notification::Event event,
|
|||||||
const GuiAction& action,
|
const GuiAction& action,
|
||||||
QWidget* parent) {
|
QWidget* parent) {
|
||||||
m_toastNotifications->showNotification(event, msg, action);
|
m_toastNotifications->showNotification(event, msg, action);
|
||||||
|
return;
|
||||||
|
|
||||||
if (SystemTrayIcon::areNotificationsEnabled()) {
|
if (SystemTrayIcon::areNotificationsEnabled()) {
|
||||||
auto notification = m_notifications->notificationForEvent(event);
|
auto notification = m_notifications->notificationForEvent(event);
|
||||||
@ -785,7 +786,7 @@ void Application::onAboutToQuit() {
|
|||||||
// Make sure that we obtain close lock BEFORE even trying to quit the application.
|
// Make sure that we obtain close lock BEFORE even trying to quit the application.
|
||||||
const bool locked_safely = feedUpdateLock()->tryLock(4 * CLOSE_LOCK_TIMEOUT);
|
const bool locked_safely = feedUpdateLock()->tryLock(4 * CLOSE_LOCK_TIMEOUT);
|
||||||
|
|
||||||
processEvents();
|
QCoreApplication::processEvents();
|
||||||
qDebugNN << LOGSEC_CORE << "Cleaning up resources and saving application state.";
|
qDebugNN << LOGSEC_CORE << "Cleaning up resources and saving application state.";
|
||||||
|
|
||||||
if (locked_safely) {
|
if (locked_safely) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user