Instantly share code, notes, and snippets.
Last active
November 17, 2021 13:26
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save oclero/1b86893772eb2ced371e3927a7797636 to your computer and use it in GitHub Desktop.
QPushButton shadow
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "ButtonShadowBehavior.hpp" | |
#include <QAbstractButton> | |
#include <QtWidgets/QGraphicsDropShadowEffect> | |
#include <QState> | |
#include <QStateMachine> | |
#include <QSignalTransition> | |
#include <QParallelAnimationGroup> | |
#include <QVariantAnimation> | |
namespace abvent::noon { | |
ButtonShadowBehavior::ButtonShadowBehavior(QAbstractButton* parent) | |
: QObject(parent) | |
, _button(parent) { | |
install(); | |
} | |
ButtonShadowBehavior::~ButtonShadowBehavior() { | |
uninstall(); | |
} | |
void ButtonShadowBehavior::install() { | |
if (_installed) | |
return; | |
_installed = true; | |
// Setup shadow. | |
_shadow = new QGraphicsDropShadowEffect(_button); | |
_shadow->setBlurRadius(_blurNormal); | |
_shadow->setOffset(_offset); | |
_shadow->setColor(_colorNormal); | |
_button->setGraphicsEffect(_shadow); | |
// Setup state machine. | |
_stateMachine = new QStateMachine(this); | |
auto stateNormal = new QState(); | |
auto statePressed = new QState(); | |
// Normal->Pressed | |
auto normalToPressedTransition = stateNormal->addTransition(_button, &QAbstractButton::pressed, statePressed); | |
{ | |
auto normalToPressedAnimation = new QParallelAnimationGroup(_stateMachine); | |
auto blurAnimation = new QVariantAnimation(normalToPressedAnimation); | |
blurAnimation->setDuration(_animationDuration); | |
blurAnimation->setEndValue(_blurPressed); | |
QObject::connect(blurAnimation, &QVariantAnimation::valueChanged, this, [this](const QVariant& value) { | |
if (_shadow) { | |
const auto newValue = value.toInt(); | |
_shadow->setBlurRadius(newValue); | |
} | |
}); | |
auto colorAnimation = new QVariantAnimation(normalToPressedAnimation); | |
colorAnimation->setDuration(_animationDuration); | |
colorAnimation->setEndValue(_colorPressed); | |
QObject::connect(colorAnimation, &QVariantAnimation::valueChanged, this, [this](const QVariant& value) { | |
if (_shadow) { | |
const auto newValue = value.value<QColor>(); | |
_shadow->setColor(newValue); | |
} | |
}); | |
normalToPressedAnimation->addAnimation(blurAnimation); | |
normalToPressedAnimation->addAnimation(colorAnimation); | |
normalToPressedTransition->addAnimation(normalToPressedAnimation); | |
QObject::connect(normalToPressedTransition, &QAbstractTransition::triggered, normalToPressedAnimation, | |
[this, normalToPressedAnimation, blurAnimation, colorAnimation]() { | |
blurAnimation->setStartValue(static_cast<int>(_shadow->blurRadius())); | |
colorAnimation->setStartValue(_shadow->color()); | |
normalToPressedAnimation->start(); | |
}); | |
} | |
// Pressed->Normal | |
auto pressedToNormalTransition = statePressed->addTransition(_button, &QAbstractButton::released, stateNormal); | |
{ | |
auto pressedToNormalAnimation = new QParallelAnimationGroup(_stateMachine); | |
auto blurAnimation = new QVariantAnimation(pressedToNormalAnimation); | |
blurAnimation->setDuration(_animationDuration); | |
blurAnimation->setEndValue(_blurNormal); | |
QObject::connect(blurAnimation, &QVariantAnimation::valueChanged, this, [this](const QVariant& value) { | |
if (_shadow) { | |
_shadow->setBlurRadius(value.toInt()); | |
} | |
}); | |
auto colorAnimation = new QVariantAnimation(pressedToNormalAnimation); | |
colorAnimation->setDuration(_animationDuration); | |
colorAnimation->setEndValue(_colorNormal); | |
QObject::connect(colorAnimation, &QVariantAnimation::valueChanged, this, [this](const QVariant& value) { | |
if (_shadow) { | |
_shadow->setColor(value.value<QColor>()); | |
} | |
}); | |
pressedToNormalTransition->addAnimation(blurAnimation); | |
pressedToNormalTransition->addAnimation(colorAnimation); | |
pressedToNormalTransition->addAnimation(pressedToNormalAnimation); | |
QObject::connect(pressedToNormalTransition, &QAbstractTransition::triggered, pressedToNormalAnimation, | |
[this, pressedToNormalAnimation, blurAnimation, colorAnimation]() { | |
if (_shadow) { | |
blurAnimation->setStartValue(static_cast<int>(_shadow->blurRadius())); | |
colorAnimation->setStartValue(_shadow->color()); | |
pressedToNormalAnimation->start(); | |
} | |
}); | |
} | |
_stateMachine->addState(stateNormal); // Takes ownership. | |
_stateMachine->addState(statePressed); // Takes ownership. | |
_stateMachine->setInitialState(stateNormal); | |
_stateMachine->start(); | |
} | |
void ButtonShadowBehavior::uninstall() { | |
if (!_installed) | |
return; | |
_installed = false; | |
_stateMachine.clear(); | |
_shadow.clear(); | |
_button->setGraphicsEffect(nullptr); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
class ButtonShadowBehavior : public QObject { | |
Q_OBJECT | |
public: | |
explicit ButtonShadowBehavior(QAbstractButton* parent = nullptr); | |
~ButtonShadowBehavior(); | |
private: | |
void install(); | |
void uninstall(); | |
bool _installed{ false }; | |
QPointer<QAbstractButton> _button{ nullptr }; | |
QPointer<QGraphicsDropShadowEffect> _shadow{ nullptr }; | |
QPointer<QStateMachine> _stateMachine{ nullptr }; | |
int _animationDuration{ 150 }; | |
double _blurNormal{ 8. }; | |
double _blurPressed{ 32. }; | |
QColor _colorNormal{ 0, 0, 0, 80 }; | |
QColor _colorPressed{ 0, 0, 0, 255 }; | |
QPointF _offset{ 0., 1. }; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment