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/src/widgets/assets/icons/bloom/switch_off.dci b/src/widgets/assets/icons/bloom/switch_off.dci new file mode 100644 index 000000000..957f499a4 Binary files /dev/null and b/src/widgets/assets/icons/bloom/switch_off.dci differ diff --git a/src/widgets/assets/icons/bloom/switch_on.dci b/src/widgets/assets/icons/bloom/switch_on.dci new file mode 100644 index 000000000..20ec32c84 Binary files /dev/null and b/src/widgets/assets/icons/bloom/switch_on.dci differ diff --git a/src/widgets/assets/icons/dtk-icon-theme.qrc b/src/widgets/assets/icons/dtk-icon-theme.qrc index c4761d464..6d7924473 100644 --- a/src/widgets/assets/icons/dtk-icon-theme.qrc +++ b/src/widgets/assets/icons/dtk-icon-theme.qrc @@ -72,5 +72,7 @@ bloom/window_maximize.dci bloom/window_minimize.dci bloom/window_normal.dci + bloom/switch_on.dci + bloom/switch_off.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/dstyle.cpp b/src/widgets/dstyle.cpp index 234d0da24..d19556fc6 100644 --- a/src/widgets/dstyle.cpp +++ b/src/widgets/dstyle.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 @@ -1443,9 +1443,6 @@ void DStyle::drawControl(const QStyle *style, DStyle::ControlElement ce, const Q DStyleOptionButton option = *btn; option.dpalette = btn->dpalette; option.rect = dstyle.subElementRect(SE_SwitchButtonGroove, opt, w); - dstyle.drawPrimitive(PE_SwitchButtonGroove, &option, p, w); - option.rect = dstyle.subElementRect(SE_SwitchButtonHandle, opt, w); - dstyle.drawPrimitive(PE_SwitchButtonHandle, &option, p, w); if (btn->state & State_HasFocus) { QStyleOptionFocusRect fropt; diff --git a/src/widgets/dswitchbutton.cpp b/src/widgets/dswitchbutton.cpp index 273269737..dcbd18c2a 100644 --- a/src/widgets/dswitchbutton.cpp +++ b/src/widgets/dswitchbutton.cpp @@ -3,12 +3,14 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "dswitchbutton.h" -#include -#include #include "private/dswitchbutton_p.h" -#include +#include +#include +#include +#include +#include DWIDGET_BEGIN_NAMESPACE @@ -48,12 +50,16 @@ QSize DSwitchButton::sizeHint() const */ void DSwitchButton::paintEvent(QPaintEvent *e) { + D_D(DSwitchButton); Q_UNUSED(e); DStylePainter painter(this); DStyleOptionButton opt; initStyleOption(&opt); painter.drawControl(DStyle::CE_SwitchButton, opt); + + painter.setRenderHint(QPainter::SmoothPixmapTransform); + painter.drawImage(rect().adjusted(0, -12, 0, 12), d->player.currentImage()); } /*! @@ -108,7 +114,37 @@ void DSwitchButtonPrivate::init() q->setObjectName("DSwitchButton"); q->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); q->setCheckable(true); - q->connect(q, &DSwitchButton::toggled, q, &DSwitchButton::checkedChanged); + + auto initPlayer= [this, q]() { + DDciIcon icon = !checked ? DDciIcon::fromTheme("switch_on") : DDciIcon::fromTheme("switch_off"); + player.setIcon(icon); + player.setMode(DDciIcon::Mode::Normal); + DDciIconPalette palette; + palette.setHighlight(q->palette().highlight().color()); + player.setPalette(palette); + }; + + initPlayer(); + player.setDevicePixelRatio(qApp->devicePixelRatio()); + player.setIconSize(120); + + q->connect(q, &DSwitchButton::toggled, q, [q, this](bool ckd) { + if (checked == ckd) + return; + + checked = ckd; + DDciIcon icon = checked ? DDciIcon::fromTheme("switch_on") : DDciIcon::fromTheme("switch_off"); + player.setIcon(icon); + player.play(DDciIcon::Mode::Normal); + + Q_EMIT q->checkedChanged(checked); + }); + + q->connect(&player, &DDciIconPlayer::updated, q, [q, this]() { + q->update(); + }); + + q->connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, q, initPlayer); } DWIDGET_END_NAMESPACE 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/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/dswitchbutton_p.h b/src/widgets/private/dswitchbutton_p.h index 6fc76e72e..81c8513ad 100644 --- a/src/widgets/private/dswitchbutton_p.h +++ b/src/widgets/private/dswitchbutton_p.h @@ -6,9 +6,11 @@ #define DSWITCHBUTTON_P_H #include +#include #include +DGUI_USE_NAMESPACE DWIDGET_BEGIN_NAMESPACE class DSwitchButtonPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate @@ -28,6 +30,8 @@ class DSwitchButtonPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate double animationStartValue = 0.0; double animationEndValue = 0.0; + DDciIconPlayer player; + public: D_DECLARE_PUBLIC(DSwitchButton) };