diff --git a/examples/collections/progressbarexample.cpp b/examples/collections/progressbarexample.cpp index 8c7010c9e..a79dfe507 100644 --- a/examples/collections/progressbarexample.cpp +++ b/examples/collections/progressbarexample.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "progressbarexample.h" DWIDGET_USE_NAMESPACE @@ -28,6 +29,7 @@ ProgressBarExampleWindow::ProgressBarExampleWindow(QWidget *parent) addExampleWindow(new DProgressBarExample(this)); addExampleWindow(new DWaterProgressExample(this)); addExampleWindow(new DColoredProgressBarExample(this)); + addExampleWindow(new DIndeterminateProgressBarExample(this)); } DProgressBarExample::DProgressBarExample(QWidget *parent) @@ -181,3 +183,32 @@ int DColoredProgressBarExample::getFixedHeight() const { return 200; } + +DIndeterminateProgressBarExample::DIndeterminateProgressBarExample(QWidget *parent) + : ExampleWindowInterface(parent) +{ + auto mainLayout = new QVBoxLayout(this); + auto indeterBar = new DIndeterminateProgressbar(); + indeterBar->setFixedSize(500, 35); + mainLayout->addWidget(indeterBar, 0, Qt::AlignCenter); + setLayout(mainLayout); +} + +QString DIndeterminateProgressBarExample::getTitleName() const +{ + return "DIndeterminateProgressbar"; +} + +QString DIndeterminateProgressBarExample::getDescriptionInfo() const +{ + return QString("一个模糊进度条,不展示具体进度值,\n" + "用于等待时间不确定的情况。主要用\n" + "在小工具主窗口内部,作为一个中间状态\n" + "展示给用户,最终的结果往往会跟随成功\n" + "或者失败的图标。"); +} + +int DIndeterminateProgressBarExample::getFixedHeight() const +{ + return 200; +} diff --git a/examples/collections/progressbarexample.h b/examples/collections/progressbarexample.h index fb71257c5..c22ee1319 100644 --- a/examples/collections/progressbarexample.h +++ b/examples/collections/progressbarexample.h @@ -53,4 +53,16 @@ class DColoredProgressBarExample : public ExampleWindowInterface int getFixedHeight() const override; }; +class DIndeterminateProgressBarExample : public ExampleWindowInterface +{ + Q_OBJECT + +public: + explicit DIndeterminateProgressBarExample(QWidget *parent = nullptr); + + QString getTitleName() const override; + QString getDescriptionInfo() const override; + int getFixedHeight() const override; +}; + #endif // PROGRESSBAREXAMPLE_H diff --git a/include/DWidget/DIndeterminateProgressbar b/include/DWidget/DIndeterminateProgressbar new file mode 100644 index 000000000..1d45e0b4a --- /dev/null +++ b/include/DWidget/DIndeterminateProgressbar @@ -0,0 +1 @@ +#include "dindeterminateprogressbar.h" diff --git a/include/widgets/dindeterminateprogressbar.h b/include/widgets/dindeterminateprogressbar.h new file mode 100644 index 000000000..7883b1bea --- /dev/null +++ b/include/widgets/dindeterminateprogressbar.h @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DINDETERMINATEPROGRESSBAR_H +#define DINDETERMINATEPROGRESSBAR_H + +#include +#include + +class DIndeterminateProgressbarPrivate; +class DIndeterminateProgressbar : public QWidget, public DTK_CORE_NAMESPACE::DObject +{ + Q_OBJECT +public: + explicit DIndeterminateProgressbar(QWidget *parent = nullptr); + +protected: + void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *e) override; + +private: + D_DECLARE_PRIVATE(DIndeterminateProgressbar) +}; + +#endif // DINDETERMINATEPROGRESSBAR_H diff --git a/include/widgets/dtoolbutton.h b/include/widgets/dtoolbutton.h index 95d4feb50..61982ea02 100644 --- a/include/widgets/dtoolbutton.h +++ b/include/widgets/dtoolbutton.h @@ -5,23 +5,34 @@ #ifndef DTOOLBUTTON_H #define DTOOLBUTTON_H -#include #include +#include + +#include +#include + DWIDGET_BEGIN_NAMESPACE +DGUI_USE_NAMESPACE -class LIBDTKWIDGETSHARED_EXPORT DToolButton : public QToolButton +class DToolButtonPrivate; +class LIBDTKWIDGETSHARED_EXPORT DToolButton : public QToolButton, public DCORE_NAMESPACE::DObject { Q_OBJECT public: DToolButton(QWidget *parent = nullptr); void setAlignment(Qt::Alignment flag); Qt::Alignment alignment() const; + void setDciIcon(const DDciIcon &dciIcon); protected: void paintEvent(QPaintEvent *event) override; void initStyleOption(QStyleOptionToolButton *option) const; QSize sizeHint() const override; + bool event(QEvent *e) override; + +private: + D_DECLARE_PRIVATE(DToolButton) }; DWIDGET_END_NAMESPACE diff --git a/src/widgets/assets/icons/bloom/checkbox_checked.dci b/src/widgets/assets/icons/bloom/checkbox_checked.dci new file mode 100644 index 000000000..de3949458 Binary files /dev/null and b/src/widgets/assets/icons/bloom/checkbox_checked.dci differ diff --git a/src/widgets/assets/icons/bloom/checkbox_unchecked.dci b/src/widgets/assets/icons/bloom/checkbox_unchecked.dci new file mode 100644 index 000000000..413e4145a Binary files /dev/null and b/src/widgets/assets/icons/bloom/checkbox_unchecked.dci differ diff --git a/src/widgets/assets/icons/bloom/radio_checked.dci b/src/widgets/assets/icons/bloom/radio_checked.dci new file mode 100644 index 000000000..69df89f3b Binary files /dev/null and b/src/widgets/assets/icons/bloom/radio_checked.dci differ diff --git a/src/widgets/assets/icons/bloom/radio_unchecked.dci b/src/widgets/assets/icons/bloom/radio_unchecked.dci new file mode 100644 index 000000000..792ce8ec2 Binary files /dev/null and b/src/widgets/assets/icons/bloom/radio_unchecked.dci differ diff --git a/src/widgets/assets/icons/dtk-icon-theme.qrc b/src/widgets/assets/icons/dtk-icon-theme.qrc index c4761d464..d0c68f8ba 100644 --- a/src/widgets/assets/icons/dtk-icon-theme.qrc +++ b/src/widgets/assets/icons/dtk-icon-theme.qrc @@ -72,5 +72,9 @@ bloom/window_maximize.dci bloom/window_minimize.dci bloom/window_normal.dci + bloom/radio_checked.dci + bloom/radio_unchecked.dci + bloom/checkbox_checked.dci + bloom/checkbox_unchecked.dci diff --git a/src/widgets/dindeterminateprogressbar.cpp b/src/widgets/dindeterminateprogressbar.cpp new file mode 100644 index 000000000..bb0713140 --- /dev/null +++ b/src/widgets/dindeterminateprogressbar.cpp @@ -0,0 +1,133 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "private/dindeterminateprogressbar_p.h" + +#include + +#include +#include +#include +#include +#include + +const int SPOT_WIDGET_WIDTH = 200; + +DIndeterminateProgressbarPrivate::DIndeterminateProgressbarPrivate(DIndeterminateProgressbar *qq) + : DObjectPrivate(qq) + , m_sliderWidget(new QWidget(qq)) + , m_timer(new QTimer(qq)) + , m_leftToRight(true) + , m_spotWidget(new QWidget(qq)) + , m_animation(new QPropertyAnimation(m_spotWidget, "pos", qq)) +{ +} + +DIndeterminateProgressbar::DIndeterminateProgressbar(QWidget *parent) + : QWidget(parent) + , DObject(*new DIndeterminateProgressbarPrivate(this)) +{ + D_D(DIndeterminateProgressbar); + d->m_spotWidget->setFixedSize(SPOT_WIDGET_WIDTH, height()); + d->m_spotWidget->move(-SPOT_WIDGET_WIDTH, 0); + + d->m_sliderWidget->setFixedWidth(150); + d->m_sliderWidget->move(0, 0); + + d->m_timer->setInterval(10); + static int step = 0; + connect(d->m_timer, &QTimer::timeout, this, [this, d]() { + if (d->m_sliderWidget->geometry().right() >= rect().right()) { + d->m_leftToRight = false; + } + + if (d->m_sliderWidget->geometry().left() <= rect().left()) { + d->m_leftToRight = true; + } + + d->m_leftToRight ? step += 2 : step -= 2; + d->m_sliderWidget->move(step, 0); + }); + d->m_timer->start(); +} + +void DIndeterminateProgressbar::resizeEvent(QResizeEvent *e) +{ + D_D(DIndeterminateProgressbar); + d->m_sliderWidget->setFixedHeight(height()); + d->m_spotWidget->setFixedSize(SPOT_WIDGET_WIDTH, height()); + + d->m_animation->setStartValue(QPoint(-SPOT_WIDGET_WIDTH, 0)); + d->m_animation->setEndValue(QPoint(rect().right(), 0)); + d->m_animation->setDuration(3000); + d->m_animation->setEasingCurve(QEasingCurve::InQuad); + d->m_animation->start(); + connect(d->m_animation, &QPropertyAnimation::finished, this, [d]() { + d->m_animation->start(); + }); + QWidget::resizeEvent(e); +} + +void DIndeterminateProgressbar::paintEvent(QPaintEvent *e) +{ + D_D(DIndeterminateProgressbar); + QWidget::paintEvent(e); + QPainter p(this); + + p.setRenderHint(QPainter::Antialiasing); + int radius; + this->height() <= DTK_WIDGET_NAMESPACE::DStyle::pixelMetric(style(), DTK_WIDGET_NAMESPACE::DStyle::PM_FrameRadius) * 2 + ? radius = height() / 2 + : radius = DTK_WIDGET_NAMESPACE::DStyle::pixelMetric(style(), DTK_WIDGET_NAMESPACE::DStyle::PM_FrameRadius); + + p.setBrush(QColor(0, 0, 0, int(0.1 * 255))); + p.setPen(Qt::NoPen); + + p.drawRoundedRect(rect(), radius, radius); + + QPen pen; + pen.setWidth(1); + pen.setColor(QColor(0, 0, 0, int(0.2 * 255))); + p.setBrush(Qt::NoBrush); + p.setPen(pen); + p.drawRoundedRect(rect().marginsRemoved(QMargins(1, 1, 1, 1)), radius, radius); + + p.setPen(Qt::NoPen); + p.setBrush(palette().highlight().color()); + p.drawRoundedRect(d->m_sliderWidget->geometry(), radius, radius); + + pen.setColor(QColor(0, 0, 0, int(0.3 * 255))); + p.setBrush(Qt::NoBrush); + p.setPen(pen); + p.drawRoundedRect(d->m_sliderWidget->geometry().marginsRemoved(QMargins(1, 1, 1, 1)), radius, radius); + + if (d->m_sliderWidget->width() < d->m_spotWidget->width() / 2) + return; + + QPointF pointStart(d->m_spotWidget->geometry().left(), d->m_spotWidget->geometry().center().y()); + QPointF pointEnd(d->m_spotWidget->geometry().right(), d->m_spotWidget->geometry().center().y()); + + QColor shadowColor(0, 0, 0, int(0.15 * 255)); + QColor spotColor(255, 255, 255, int(0.5 * 255)); + QColor highLightColor(palette().highlight().color()); + + QLinearGradient linear(pointStart, pointEnd); + linear.setColorAt(0, highLightColor); + linear.setColorAt(0.35, shadowColor); + linear.setColorAt(0.5, spotColor); + linear.setColorAt(0.65, shadowColor); + linear.setColorAt(1, highLightColor); + linear.setSpread(QGradient::PadSpread); + linear.setInterpolationMode(QLinearGradient::InterpolationMode::ColorInterpolation); + + p.setBrush(linear); + p.setPen(Qt::NoPen); + + QPainterPath clipPath; + clipPath.addRoundedRect(d->m_sliderWidget->geometry(), radius, radius); + p.setClipPath(clipPath); + p.setClipping(true); + p.drawRoundedRect(d->m_spotWidget->geometry().marginsRemoved(QMargins(2, 2, 2, 2)), radius, radius); + p.setClipping(false); +} diff --git a/src/widgets/dtitlebar.cpp b/src/widgets/dtitlebar.cpp index 23d604ad0..6c32eeaf1 100644 --- a/src/widgets/dtitlebar.cpp +++ b/src/widgets/dtitlebar.cpp @@ -775,7 +775,7 @@ void DTitlebarPrivate::setIconVisible(bool visible) return; if (visible) { - if (auto spacerItem = dynamic_cast(leftLayout->takeAt(0))) + if (dynamic_cast(leftLayout->itemAt(0))) delete leftLayout->takeAt(0); leftLayout->insertSpacing(0, 10); diff --git a/src/widgets/dtoolbutton.cpp b/src/widgets/dtoolbutton.cpp index a2ac4d42f..7ce71c191 100644 --- a/src/widgets/dtoolbutton.cpp +++ b/src/widgets/dtoolbutton.cpp @@ -2,13 +2,25 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later -#include "dtoolbutton.h" +#include "private/dtoolbutton_p.h" + +#include +#include #include #include +#include +#include +#include DWIDGET_BEGIN_NAMESPACE +Dtk::Widget::DToolButtonPrivate::DToolButtonPrivate(DToolButton *qq) + : DObjectPrivate(qq) +{ + +} + /*! @~english @class Dtk::Widget::DToolButton @@ -17,8 +29,15 @@ DWIDGET_BEGIN_NAMESPACE DToolButton::DToolButton(QWidget *parent) : QToolButton(parent) + , DObject(*new DToolButtonPrivate(this)) { - + D_D(DToolButton); + connect(this, &DToolButton::pressed, this, [d]() { + d->m_dciPlayer.play(DDciIcon::Pressed); + }); + connect(this, &DToolButton::released, this, [d]() { + d->m_dciPlayer.play(DDciIcon::Normal); + }); } /*! @@ -30,10 +49,26 @@ DToolButton::DToolButton(QWidget *parent) void DToolButton::paintEvent(QPaintEvent *event) { + D_D(DToolButton); Q_UNUSED(event) QStylePainter p(this); QStyleOptionToolButton opt; initStyleOption(&opt); + + if (!d->m_dciIcon.isNull()) { + p.setRenderHint(QPainter::SmoothPixmapTransform); + p.drawImage(rect(), d->m_dciPlayer.currentImage()); + + if (opt.state & QStyle::State_HasFocus) { + p.setPen(QPen(palette().highlight().color(), 2)); + p.setBrush(Qt::NoBrush); + p.setRenderHint(QPainter::Antialiasing); + int radius = DStyle::pixelMetric(style(), DStyle::PM_FrameRadius); + p.drawRoundedRect(opt.rect.marginsRemoved(QMargins(1, 1, 1, 1)), radius, radius); + } + return; + } + p.drawComplexControl(QStyle::CC_ToolButton, opt); } @@ -60,6 +95,26 @@ QSize DToolButton::sizeHint() const return QToolButton::sizeHint(); } +bool DToolButton::event(QEvent *e) +{ + D_D(DToolButton); + if (d->m_dciIcon.isNull()) + return QToolButton::event(e); + + if (e->type() == QEvent::WindowActivate) { + auto palette = DDciIconPalette::fromQPalette(this->palette()); + d->m_dciPlayer.setPalette(palette); + d->m_dciPlayer.setTheme(DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::DarkType + ? DDciIcon::Dark : DDciIcon::Light); + d->m_dciPlayer.setMode(DDciIcon::Normal); + } else if (e->type() == QEvent::HoverEnter) { + d->m_dciPlayer.play(DDciIcon::Hover); + } else if (e->type() == QEvent::HoverLeave) { + d->m_dciPlayer.play(DDciIcon::Normal); + } + return QToolButton::event(e); +} + /*! @~english @fn void DToolButton::setAlignment(Qt::Alignment flag) @@ -85,4 +140,22 @@ Qt::Alignment DToolButton::alignment() const return Qt::AlignLeft; } +void DToolButton::setDciIcon(const DDciIcon &dciIcon) +{ + D_D(DToolButton); + d->m_dciIcon = dciIcon; + d->m_dciPlayer.setIcon(dciIcon); + d->m_dciPlayer.setIconSize(120); + + connect(&d->m_dciPlayer, &DDciIconPlayer::updated, this, [this]() { + update(); + }); + + connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, this, [this, d](DGuiApplicationHelper::ColorType colorType) { + auto palette = DDciIconPalette::fromQPalette(this->palette()); + d->m_dciPlayer.setPalette(palette); + d->m_dciPlayer.setTheme(colorType ? DDciIcon::Dark : DDciIcon::Light); + }); +} + DWIDGET_END_NAMESPACE diff --git a/src/widgets/private/dindeterminateprogressbar_p.h b/src/widgets/private/dindeterminateprogressbar_p.h new file mode 100644 index 000000000..330504358 --- /dev/null +++ b/src/widgets/private/dindeterminateprogressbar_p.h @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DINDETERMINATEPROGRESSBAR_P_H +#define DINDETERMINATEPROGRESSBAR_P_H + +#include +#include + +#include + +class QPropertyAnimation; +class DIndeterminateProgressbarPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate +{ +public: + DIndeterminateProgressbarPrivate(DIndeterminateProgressbar *qq); + + QWidget *m_sliderWidget; + QTimer *m_timer; + bool m_leftToRight; + QWidget *m_spotWidget; + QPropertyAnimation *m_animation; + +private: + D_DECLARE_PUBLIC(DIndeterminateProgressbar) +}; + +#endif // DINDETERMINATEPROGRESSBAR_P_H diff --git a/src/widgets/private/dtoolbutton_p.h b/src/widgets/private/dtoolbutton_p.h new file mode 100644 index 000000000..ff90bf41e --- /dev/null +++ b/src/widgets/private/dtoolbutton_p.h @@ -0,0 +1,26 @@ +// 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 +#include + +DWIDGET_BEGIN_NAMESPACE + +class DToolButtonPrivate : public DCORE_NAMESPACE::DObjectPrivate +{ +public: + DToolButtonPrivate(DToolButton *qq); + + DDciIcon m_dciIcon; + DDciIconPlayer m_dciPlayer; + + Q_DECLARE_PUBLIC(DToolButton) +}; + +DWIDGET_END_NAMESPACE + +#endif // DABOUTDIALOG_P_H