Skip to content

Commit

Permalink
chore: 增加ButtonBox hover 和切换动画
Browse files Browse the repository at this point in the history
增加ButtonBox hover 和切换动画

Log:
  • Loading branch information
Whale107 committed Aug 5, 2024
1 parent b8497a4 commit eacb5d5
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 6 deletions.
7 changes: 6 additions & 1 deletion include/widgets/dbuttonbox.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand Down Expand Up @@ -47,6 +47,8 @@ class DButtonBoxButton : public QAbstractButton, public DCORE_NAMESPACE::DObject
void paintEvent(QPaintEvent *e) override;
void keyPressEvent(QKeyEvent *event) override;
bool event(QEvent *e) override;

friend class DButtonBox;
};

class DButtonBoxPrivate;
Expand Down Expand Up @@ -78,6 +80,9 @@ class DButtonBox : public QWidget, public DCORE_NAMESPACE::DObject
void buttonReleased(QAbstractButton *);
void buttonToggled(QAbstractButton *, bool);

protected:
bool eventFilter(QObject *o, QEvent *e) override;

private:
void paintEvent(QPaintEvent *e) override;

Expand Down
114 changes: 111 additions & 3 deletions src/widgets/dbuttonbox.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#include "dbuttonbox.h"
#include "private/dbuttonbox_p.h"
#include <private/qabstractbutton_p.h>
#include "dstyleoption.h"
#include "dstyle.h"

Expand All @@ -12,7 +13,7 @@
#include <QHBoxLayout>
#include <QStyleOptionButton>
#include <QStylePainter>
#include <private/qabstractbutton_p.h>
#include <QVariantAnimation>

DWIDGET_BEGIN_NAMESPACE

Expand Down Expand Up @@ -291,6 +292,7 @@ void DButtonBoxButton::paintEvent(QPaintEvent *e)
DStylePainter p(this);
DStyleOptionButtonBoxButton option;
initStyleOption(&option);
option.palette.setColor(QPalette::HighlightedText, this->palette().highlight().color());
p.drawControl(DStyle::CE_ButtonBoxButton, option);
}

Expand Down Expand Up @@ -351,6 +353,10 @@ bool DButtonBoxButton::event(QEvent *e)

DButtonBoxPrivate::DButtonBoxPrivate(DButtonBox *qq)

Check warning on line 354 in src/widgets/dbuttonbox.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Member variable 'DButtonBoxPrivate::group' is not initialized in the constructor.

Check warning on line 354 in src/widgets/dbuttonbox.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Member variable 'DButtonBoxPrivate::layout' is not initialized in the constructor.
: DObjectPrivate(qq)
, m_hoverId(-1)
, m_checkedId(-1)
, m_hoverMoveAnimation(new QVariantAnimation(qq))
, m_checkMoveAnimation(new QVariantAnimation(qq))
{

}
Expand All @@ -366,6 +372,15 @@ void DButtonBoxPrivate::init()
q->connect(group, SIGNAL(buttonPressed(QAbstractButton*)), q, SIGNAL(buttonPressed(QAbstractButton*)));
q->connect(group, SIGNAL(buttonReleased(QAbstractButton*)), q, SIGNAL(buttonReleased(QAbstractButton*)));
q->connect(group, SIGNAL(buttonToggled(QAbstractButton*, bool)), q, SIGNAL(buttonToggled(QAbstractButton*, bool)));
q->connect(m_hoverMoveAnimation, &QVariantAnimation::valueChanged, q, [q]() {
q->update();
});
q->connect(m_checkMoveAnimation, &QVariantAnimation::valueChanged, q, [q]() {
q->update();
});
m_hoverMoveAnimation->setEasingCurve(QEasingCurve::InCubic);
m_hoverMoveAnimation->setDuration(150);
m_checkMoveAnimation->setDuration(200);

layout = new QHBoxLayout(q);
layout->setContentsMargins(0,0,0,0);
Expand Down Expand Up @@ -484,6 +499,7 @@ void DButtonBox::setButtonList(const QList<DButtonBoxButton *> &list, bool check
d->group->addButton(button);

button->setCheckable(checkable);
button->installEventFilter(this);
}
}

Expand Down Expand Up @@ -575,9 +591,11 @@ int DButtonBox::checkedId() const
void DButtonBox::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e)
D_D(DButtonBox);

QStylePainter p(this);
QStyleOptionButton opt;
p.setRenderHint(QPainter::Antialiasing);
opt.state = QStyle::State_None;
opt.rect = rect();
opt.direction = layoutDirection();
Expand All @@ -591,7 +609,97 @@ void DButtonBox::paintEvent(QPaintEvent *e)
opt.state |= QStyle::State_Active;
}

p.drawControl(QStyle::CE_PushButtonBevel, opt);
int radius = DStyle::pixelMetric(style(), DStyle::PM_FrameRadius);
if (d->m_hoverId >= 0 && d->m_hoverId < buttonList().size()) {
QColor background = this->palette().button().color();
background.setAlphaF(0.6);
p.setBrush(background);
p.setPen(QPen(background, 1));
p.drawRoundedRect(d->m_hoverMoveAnimation->currentValue().toRect(), radius, radius);
}

if (d->m_checkedId >= 0 && d->m_checkedId < buttonList().size()) {
const QColor &background = this->palette().dark().color();
p.setBrush(background);
p.setPen(QPen(background, 1));

QRect rect;
if (d->m_checkMoveAnimation->currentValue().toRect().isValid())
rect = d->m_checkMoveAnimation->currentValue().toRect();
else
rect = buttonList().at(d->m_checkedId)->geometry();
p.drawRoundedRect(rect, radius, radius);

p.setPen(Qt::NoPen);
QColor shadowColor = Qt::black;
shadowColor.setAlphaF(0.2);
p.setBrush(shadowColor);

QPainterPath rectPath;
rectPath.addRoundedRect(rect, radius, radius);

QRect excludeRect = rect;
excludeRect.setHeight(rect.height() - 2);
QPainterPath shadowPath;
shadowPath.addRoundedRect(excludeRect, radius, radius);
shadowPath = rectPath.subtracted(shadowPath);

p.drawPath(shadowPath);
}
}

bool DButtonBox::eventFilter(QObject *o, QEvent *e)
{
D_D(DButtonBox);

for (int i = 0; i < buttonList().size(); ++i) {
if (o == buttonList().at(i)) {
DStyleOptionButtonBoxButton option;
dynamic_cast<DButtonBoxButton *>(o)->initStyleOption(&option);
if (option.state.testFlag(QStyle::State_On)) {
if (d->m_checkedId == i)
return false;

if (d->m_checkedId >= 0 && d->m_checkedId < buttonList().size()) {
d->m_checkMoveAnimation->setStartValue(buttonList().at(d->m_checkedId)->geometry());
d->m_checkedId = i;
d->m_checkMoveAnimation->setEndValue(buttonList().at(d->m_checkedId)->geometry());
} else {
d->m_checkedId = i;
d->m_checkMoveAnimation->setStartValue(0);
d->m_checkMoveAnimation->setEndValue(0);
}
d->m_checkMoveAnimation->start();
update();
}
if (e->type() == QEvent::HoverEnter) {
if (d->m_hoverId == i)
return false;

d->m_hoverId = i;

if (d->m_hoverId < 0 || d->m_hoverId >= buttonList().size())
return false;

QRect smallRect = buttonList().at(d->m_hoverId)->geometry();
smallRect.setSize(QSize(smallRect.width() / 2, smallRect.height() / 2));
smallRect.moveCenter(buttonList().at(d->m_hoverId)->geometry().center());
d->m_hoverMoveAnimation->setStartValue(smallRect);
d->m_hoverMoveAnimation->setEndValue(buttonList().at(d->m_hoverId)->geometry());
d->m_hoverMoveAnimation->start();
update();
} else if (e->type() == QEvent::HoverLeave) {
d->m_hoverId = -1;
update();
} else if (e->type() == QEvent::Resize) {
if (d->m_checkedId >= 0 && d->m_checkedId < buttonList().size()) {
d->m_checkMoveAnimation->setStartValue(buttonList().at(d->m_checkedId)->geometry());
d->m_checkMoveAnimation->setEndValue(buttonList().at(d->m_checkedId)->geometry());
}
}
}
}
return QWidget::eventFilter(o, e);
}

DWIDGET_END_NAMESPACE
8 changes: 7 additions & 1 deletion src/widgets/dstyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1487,7 +1487,6 @@ void DStyle::drawControl(const QStyle *style, DStyle::ControlElement ce, const Q
case CE_ButtonBoxButton: {
if (const DStyleOptionButton *btn = qstyleoption_cast<const DStyleOptionButton *>(opt)) {
DStyleHelper dstyle(style);
dstyle.drawControl(CE_ButtonBoxButtonBevel, btn, p, w);
DStyleOptionButton subopt = *btn;
if (btn->features & DStyleOptionButton::HasDciIcon)
subopt.dciIcon = btn->dciIcon;
Expand All @@ -1498,6 +1497,7 @@ void DStyle::drawControl(const QStyle *style, DStyle::ControlElement ce, const Q
DStyleOptionButtonBoxButton fropt;
fropt = *boxbtn;
fropt.rect = dstyle.subElementRect(SE_ButtonBoxButtonFocusRect, btn, w);
fropt.position = DStyleOptionButtonBoxButton::OnlyOne;
style->drawPrimitive(PE_FrameFocusRect, &fropt, p, w);
}
}
Expand Down Expand Up @@ -1572,6 +1572,12 @@ void DStyle::drawControl(const QStyle *style, DStyle::ControlElement ce, const Q
break;
}
case CE_ButtonBoxButtonLabel: {
if (opt->state & StateFlag::State_MouseOver) {
p->scale(1.2, 1.2);
p->setRenderHint(QPainter::SmoothPixmapTransform);
p->translate(-0.2 * opt->rect.width() / 2, -0.2 * opt->rect.height() / 2);
}

style->drawControl(CE_PushButtonLabel, opt, p, w);
break;
}
Expand Down
9 changes: 8 additions & 1 deletion src/widgets/private/dbuttonbox_p.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019 - 2022 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2019 - 2024 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand All @@ -12,6 +12,7 @@

QT_BEGIN_NAMESPACE
class QBoxLayout;
class QVariantAnimation;
QT_END_NAMESPACE

DWIDGET_BEGIN_NAMESPACE
Expand All @@ -26,6 +27,12 @@ class DButtonBoxPrivate : public DCORE_NAMESPACE::DObjectPrivate
QButtonGroup *group;
QBoxLayout *layout;

int m_hoverId;
int m_checkedId;

QVariantAnimation *m_hoverMoveAnimation;

Check warning on line 33 in src/widgets/private/dbuttonbox_p.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

variable QVariantAnimation* Dtk::Widget::DButtonBoxPrivate::m_hoverMoveAnimation is not documented!
QVariantAnimation *m_checkMoveAnimation;

Check warning on line 34 in src/widgets/private/dbuttonbox_p.h

View workflow job for this annotation

GitHub Actions / check_job / DOXYGEN_CHECK

variable QVariantAnimation* Dtk::Widget::DButtonBoxPrivate::m_checkMoveAnimation is not documented!

D_DECLARE_PUBLIC(DButtonBox)
};

Expand Down

0 comments on commit eacb5d5

Please sign in to comment.