diff --git a/include/widgets/dfloatingmessage.h b/include/widgets/dfloatingmessage.h index 382ee6b5..dea68192 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 19881536..d3cb5e06 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 2c527090..c581f289 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 6e7a362b..043731e8 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 234d0da2..ca5c7cd5 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 00000000..0b77cf63 --- /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