From fb921f985c159c8a75743ac0fd909928b7b5eb2a Mon Sep 17 00:00:00 2001 From: Whale107 <72391936+Whale107@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:25:10 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=A2=9E=E5=8A=A0=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E5=86=85=E9=80=9A=E7=9F=A5=E5=8A=A8=E7=94=BB=20(#592)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加应用内通知动画 Log: --- include/widgets/dfloatingmessage.h | 3 +- include/widgets/dmessagemanager.h | 8 +- src/widgets/dfloatingmessage.cpp | 21 +++- src/widgets/dmessagemanager.cpp | 127 +++++++++++++++++++++--- src/widgets/dstyle.cpp | 11 +- src/widgets/private/dmessagemanager_p.h | 33 ++++++ 6 files changed, 179 insertions(+), 24 deletions(-) create mode 100644 src/widgets/private/dmessagemanager_p.h diff --git a/include/widgets/dfloatingmessage.h b/include/widgets/dfloatingmessage.h index 382ee6b55..dea681929 100644 --- a/include/widgets/dfloatingmessage.h +++ b/include/widgets/dfloatingmessage.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -38,6 +38,7 @@ class DFloatingMessage : public DFloatingWidget Q_SIGNALS: void closeButtonClicked(); + void messageClosed(); protected: using DFloatingWidget::setWidget; diff --git a/include/widgets/dmessagemanager.h b/include/widgets/dmessagemanager.h index 198815368..d3cb5e06a 100644 --- a/include/widgets/dmessagemanager.h +++ b/include/widgets/dmessagemanager.h @@ -1,11 +1,11 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #ifndef DMESSAGEMANAGER_H #define DMESSAGEMANAGER_H -#include +#include #include #include #include @@ -16,9 +16,11 @@ DGUI_END_NAMESPACE DWIDGET_BEGIN_NAMESPACE class DFloatingMessage; -class DMessageManager: public QObject +class DMessageManagerPrivate; +class DMessageManager: public QObject, public DCORE_NAMESPACE::DObject { Q_OBJECT + D_DECLARE_PRIVATE(DMessageManager) private: DMessageManager(); //构造函数是私有的 diff --git a/src/widgets/dfloatingmessage.cpp b/src/widgets/dfloatingmessage.cpp index 2c5270909..c581f289e 100644 --- a/src/widgets/dfloatingmessage.cpp +++ b/src/widgets/dfloatingmessage.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -11,6 +11,7 @@ #include #include #include +#include class MessageLabel : public QLabel { @@ -54,13 +55,17 @@ void DFloatingMessagePrivate::init() iconButton->setIconSize(DSizeModeHelper::element(QSize(20, 20), QSize(30, 30))); hBoxLayout->addWidget(iconButton); + hBoxLayout->addSpacing(10); hBoxLayout->addWidget(labMessage); if (notifyType == DFloatingMessage::MessageType::TransientType) { //临时消息 timer = new QTimer(q); timer->setInterval(4000); timer->setSingleShot(true); - q->connect(timer, &QTimer::timeout, q, &DFloatingMessage::close); + q->connect(timer, &QTimer::timeout, q, [q]() { + q->close(); + Q_EMIT q->messageClosed(); + }); } else { //常驻消息 content = nullptr; closeButton = new DDialogCloseButton(q); @@ -69,8 +74,18 @@ void DFloatingMessagePrivate::init() hBoxLayout->addWidget(closeButton); q->connect(closeButton, &DIconButton::clicked, q, &DFloatingMessage::closeButtonClicked); - q->connect(closeButton, &DIconButton::clicked, q, &DFloatingMessage::close); + q->connect(closeButton, &DIconButton::clicked, q, [q]() { + q->close(); + Q_EMIT q->messageClosed(); + }); } + + auto effect = new QGraphicsDropShadowEffect(q); + effect->setColor(QColor(0, 0, 0, 0.1 * 255)); + effect->setBlurRadius(20); + effect->setXOffset(0); + effect->setYOffset(2); + q->setGraphicsEffect(effect); } /*! diff --git a/src/widgets/dmessagemanager.cpp b/src/widgets/dmessagemanager.cpp index 6e7a362b5..043731e81 100644 --- a/src/widgets/dmessagemanager.cpp +++ b/src/widgets/dmessagemanager.cpp @@ -1,19 +1,48 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022 - 2024 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later -#include "dmessagemanager.h" +#include "private/dmessagemanager_p.h" #include #include #include #include +#include #define D_MESSAGE_MANAGER_CONTENT "_d_message_manager_content" +const int MARGIN = 20; +const int MESSGAE_HEIGHT = 50; +const int ANIMATION_DURATION = 400; Q_DECLARE_METATYPE(QMargins) +class ImageLabel : public QLabel { + Q_OBJECT + Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity) +public: + explicit ImageLabel(QWidget *parent=nullptr) + : QLabel (parent) + , m_opacity(0) + { + }; + void setOpacity(qreal opac) { m_opacity = opac; } + qreal opacity() { return m_opacity ;} + +protected: + void paintEvent(QPaintEvent *e) override + { + Q_UNUSED(e) + QPainter p(this); + p.setRenderHint(QPainter::Antialiasing); + p.setOpacity(m_opacity); + p.drawPixmap(rect().marginsRemoved(contentsMargins()), *pixmap()); + }; +private: + qreal m_opacity; +}; + // 仅仅为了接口兼容, 符号不会减少, 如果使用了这个接口,实际调用走的有namespace的 class Q_DECL_EXPORT DMessageManager: public QObject { @@ -91,7 +120,30 @@ static void sendMessage_helper(DMessageManager *manager, QWidget *par, IconType manager->sendMessage(par, floMsg); } +DMessageManagerPrivate::DMessageManagerPrivate(DMessageManager *qq) + : DObjectPrivate(qq) + , m_aniGeometry(new QPropertyAnimation(qq)) + , m_aniOpacity(new QPropertyAnimation(qq)) + , m_aniGroup(new QParallelAnimationGroup(qq)) + , m_label(new ImageLabel) +{ + m_aniGeometry->setPropertyName("geometry"); + m_aniGeometry->setDuration(ANIMATION_DURATION); + m_aniGeometry->setEasingCurve(QEasingCurve::OutCubic); + + m_aniOpacity->setPropertyName("opacity"); + m_aniOpacity->setDuration(ANIMATION_DURATION); + m_aniOpacity->setEasingCurve(QEasingCurve::OutCubic); + m_aniOpacity->setTargetObject(m_label); + m_aniOpacity->setStartValue(0); + m_aniOpacity->setEndValue(1); + + m_aniGroup->addAnimation(m_aniGeometry); + m_aniGroup->addAnimation(m_aniOpacity); +} + DMessageManager::DMessageManager() //私有静态构造函数 + : DObject(*new DMessageManagerPrivate(this)) { } @@ -114,6 +166,7 @@ DMessageManager *DMessageManager::instance() //公有静态函数 */ void DMessageManager::sendMessage(QWidget *par, DFloatingMessage *floMsg) { + D_D(DMessageManager); QWidget *content = par->findChild(D_MESSAGE_MANAGER_CONTENT, Qt::FindDirectChildrenOnly); if (!content) { @@ -125,7 +178,7 @@ void DMessageManager::sendMessage(QWidget *par, DFloatingMessage *floMsg) if (par->property("_d_margins").isValid()) content->setContentsMargins(magins); else - content->setContentsMargins(QMargins(20, 0, 20, 0)); + content->setContentsMargins(QMargins(MARGIN, 0, MARGIN, 0)); content->installEventFilter(this); par->installEventFilter(this); @@ -133,10 +186,60 @@ void DMessageManager::sendMessage(QWidget *par, DFloatingMessage *floMsg) layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); layout->setDirection(QBoxLayout::BottomToTop); - content->show(); + } + + if (content->layout()->count() >= 1) { + content->layout()->itemAt(content->layout()->count() - 1)->widget()->hide(); + delete content->layout()->takeAt(content->layout()->count() - 1); } static_cast(content->layout())->addWidget(floMsg, 0, Qt::AlignHCenter); + + // 限制通知消息的最大宽度 + for (DFloatingMessage *message : content->findChildren(QString(), Qt::FindDirectChildrenOnly)) { + message->setMaximumWidth(par->rect().marginsRemoved(content->contentsMargins()).width()); + message->setMinimumHeight(message->sizeHint().height()); + } + + QRect geometry(QPoint(0, 0), floMsg->sizeHint() + QSize(MARGIN * 2, 0)); + geometry.moveCenter(par->rect().center()); + geometry.moveBottom(par->rect().bottom() - MESSGAE_HEIGHT); + + content->setGeometry(geometry); + content->hide(); + + if (d->m_aniGeometry->state() == QPropertyAnimation::State::Running) + return; + + d->m_label->setParent(par); + d->m_label->setAlignment(Qt::AlignCenter); + d->m_label->setContentsMargins(MARGIN, 0, MARGIN, 0); + d->m_label->setPixmap(floMsg->grab()); + d->m_label->setScaledContents(true); + d->m_label->show(); + d->m_aniGeometry->setTargetObject(d->m_label); + d->m_aniOpacity->setTargetObject(d->m_label); + d->m_aniGeometry->setStartValue(QRect(par->rect().center().x(), par->rect().bottom(), 0, 0)); + d->m_aniGeometry->setEndValue(content->geometry()); + d->m_aniGroup->start(); + connect(d->m_aniGroup, &QPropertyAnimation::finished, this, [d, content]() { + if (d->m_aniGroup->direction() == QAbstractAnimation::Backward) { + d->m_aniGroup->setDirection(QAbstractAnimation::Forward); + } else { + content->show(); + } + d->m_label->hide(); + }); + + connect(floMsg, &DFloatingMessage::messageClosed, [=, this]() { + d->m_aniGeometry->setStartValue(QRect(par->rect().center().x(), par->rect().bottom(), 0, 0)); + d->m_aniGeometry->setEndValue(content->geometry()); + d->m_label->setPixmap(floMsg->grab()); + + d->m_aniGroup->setDirection(QAbstractAnimation::Backward); + d->m_label->show(); + d->m_aniGroup->start(); + }); } /*! @@ -184,19 +287,11 @@ bool DMessageManager::setContentMargens(QWidget *par, const QMargins &margins) */ bool DMessageManager::eventFilter(QObject *watched, QEvent *event) { - if (event->type() == QEvent::LayoutRequest || event->type() == QEvent::Resize) { - if (QWidget *widget = qobject_cast(watched)) { - QWidget *content; - - if (widget->objectName() == D_MESSAGE_MANAGER_CONTENT) { - content = widget; - } else { - content = widget->findChild(D_MESSAGE_MANAGER_CONTENT, Qt::FindDirectChildrenOnly); - } + if (event->type() == QEvent::Resize) { + if (auto content = watched->findChild(D_MESSAGE_MANAGER_CONTENT, Qt::FindDirectChildrenOnly)) { - QWidget *par = content->parentWidget(); + auto par = qobject_cast(watched); - // 限制通知消息的最大宽度 for (DFloatingMessage *message : content->findChildren(QString(), Qt::FindDirectChildrenOnly)) { message->setMaximumWidth(par->rect().marginsRemoved(content->contentsMargins()).width()); message->setMinimumHeight(message->sizeHint().height()); @@ -204,7 +299,7 @@ bool DMessageManager::eventFilter(QObject *watched, QEvent *event) QRect geometry(QPoint(0, 0), content->sizeHint()); geometry.moveCenter(par->rect().center()); - geometry.moveBottom(par->rect().bottom()); + geometry.moveBottom(par->rect().bottom() - MESSGAE_HEIGHT); content->setGeometry(geometry); } } else if (event->type() == QEvent::ChildRemoved) { diff --git a/src/widgets/dstyle.cpp b/src/widgets/dstyle.cpp index ec6fbba33..d1fd1160a 100644 --- a/src/widgets/dstyle.cpp +++ b/src/widgets/dstyle.cpp @@ -1339,9 +1339,18 @@ void DStyle::drawPrimitive(const QStyle *style, DStyle::PrimitiveElement pe, con //先绘画阴影 DDrawUtils::drawShadow(p, btn->rect + shadow_margin, frameRadius, frameRadius, QColor(0, 0, 0, 0.25 * 255), shadowRadius, QPoint(offsetX, offsetY)); //再绘画上面的待显示区域 - p->setPen(QPen(btn->dpalette.frameShadowBorder(), 1)); + p->setPen(Qt::NoPen); p->setBrush(btn->noBackground ? Qt::NoBrush : p->background()); p->drawRoundedRect(opt->rect, frameRadius, frameRadius); + + p->setBrush(Qt::NoBrush); + QPen pen; + pen.setWidth(1); + pen.setColor(DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::DarkType + ? QColor(255, 255, 255, int(0.1 * 255)) + : QColor(0, 0, 0, int(0.12 * 255))); + p->setPen(pen); + p->drawRoundedRect(opt->rect, frameRadius, frameRadius); } break; } diff --git a/src/widgets/private/dmessagemanager_p.h b/src/widgets/private/dmessagemanager_p.h new file mode 100644 index 000000000..0b77cf637 --- /dev/null +++ b/src/widgets/private/dmessagemanager_p.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DABOUTDIALOG_P_H +#define DABOUTDIALOG_P_H + +#include "dmessagemanager.h" + +#include + +#include +#include +#include + +DWIDGET_BEGIN_NAMESPACE + +class DMessageManagerPrivate : public DCORE_NAMESPACE::DObjectPrivate +{ +public: + DMessageManagerPrivate(DMessageManager *qq); + + QPropertyAnimation *m_aniGeometry; + QPropertyAnimation *m_aniOpacity;; + QParallelAnimationGroup *m_aniGroup; + QLabel *m_label; + + D_DECLARE_PUBLIC(DMessageManager); +}; + +DWIDGET_END_NAMESPACE + +#endif // DABOUTDIALOG_P_H