implement Radio Button

This commit is contained in:
laserpants 2016-06-13 02:19:14 +03:00
parent 309e9eb5a8
commit 3493507c12
7 changed files with 372 additions and 48 deletions

View File

@ -1,13 +1,21 @@
#include "radiobutton.h" #include "radiobutton.h"
#include <QPainter> #include <QPainter>
#include <QEvent> #include <QEvent>
#include <QSignalTransition>
#include <QPropertyAnimation>
#include <QApplication>
#include <QDebug>
#include "radiobutton_p.h" #include "radiobutton_p.h"
#include "lib/rippleoverlay.h" #include "lib/rippleoverlay.h"
#include "lib/style.h"
#include "lib/ripple.h"
RadioButtonPrivate::RadioButtonPrivate(RadioButton *q) RadioButtonPrivate::RadioButtonPrivate(RadioButton *q)
: q_ptr(q), : q_ptr(q),
checkedIcon(QIcon("../qt-material-widgets/ic_radio_button_checked_black_24px.svg")), checkedIcon(new RadioButtonIcon(QIcon("../qt-material-widgets/ic_radio_button_checked_black_24px.svg"))),
uncheckedIcon(QIcon("../qt-material-widgets/ic_radio_button_unchecked_black_24px.svg")) uncheckedIcon(new RadioButtonIcon(QIcon("../qt-material-widgets/ic_radio_button_unchecked_black_24px.svg"))),
iconSize(24),
useThemeColors(true)
{ {
} }
@ -15,12 +23,79 @@ void RadioButtonPrivate::init()
{ {
Q_Q(RadioButton); Q_Q(RadioButton);
checkedIcon->setParent(q);
uncheckedIcon->setParent(q);
ripple = new RippleOverlay(q->parentWidget()); ripple = new RippleOverlay(q->parentWidget());
iconWidget = new RadioButtonIcon(q); machine = new QStateMachine(q);
QFont f(q->font()); QFont f(q->font());
f.setPointSizeF(11); f.setPointSizeF(11);
q->setFont(f); q->setFont(f);
uncheckedState = new QState;
checkedState = new QState;
machine->addState(uncheckedState);
machine->addState(checkedState);
machine->setInitialState(uncheckedState);
QSignalTransition *transition;
QPropertyAnimation *animation;
transition = new QSignalTransition(q, SIGNAL(toggled(bool)));
transition->setTargetState(checkedState);
uncheckedState->addTransition(transition);
animation = new QPropertyAnimation(checkedIcon, "iconSize");
animation->setDuration(250);
transition->addAnimation(animation);
animation = new QPropertyAnimation(uncheckedIcon, "iconSize");
animation->setDuration(250);
transition->addAnimation(animation);
transition = new QSignalTransition(q, SIGNAL(toggled(bool)));
transition->setTargetState(uncheckedState);
checkedState->addTransition(transition);
animation = new QPropertyAnimation(checkedIcon, "iconSize");
animation->setDuration(250);
transition->addAnimation(animation);
animation = new QPropertyAnimation(uncheckedIcon, "iconSize");
animation->setDuration(250);
transition->addAnimation(animation);
assignAnimationProperties();
updatePalette();
machine->start();
QCoreApplication::processEvents();
}
void RadioButtonPrivate::assignAnimationProperties()
{
uncheckedState->assignProperty(checkedIcon, "iconSize", 0);
uncheckedState->assignProperty(uncheckedIcon, "iconSize", iconSize);
checkedState->assignProperty(uncheckedIcon, "iconSize", 0);
checkedState->assignProperty(checkedIcon, "iconSize", iconSize);
}
void RadioButtonPrivate::updatePalette()
{
Q_Q(RadioButton);
if (q->isEnabled()) {
checkedIcon->setColor(q->checkedColor());
uncheckedIcon->setColor(q->uncheckedColor());
} else {
checkedIcon->setColor(q->disabledColor());
uncheckedIcon->setColor(q->disabledColor());
}
} }
RadioButton::RadioButton(QWidget *parent) RadioButton::RadioButton(QWidget *parent)
@ -28,21 +103,161 @@ RadioButton::RadioButton(QWidget *parent)
d_ptr(new RadioButtonPrivate(this)) d_ptr(new RadioButtonPrivate(this))
{ {
d_func()->init(); d_func()->init();
//QPushButton *b = new QPushButton;
//b->setParent(this);
//b->setIcon(d_func()->checkedIcon);
//b->setIconSize(QSize(12, 12));
//QGraphicsColorizeEffect *effect = new QGraphicsColorizeEffect;
//effect->setColor(Qt::blue);
//b->setGraphicsEffect(effect);
} }
RadioButton::~RadioButton() RadioButton::~RadioButton()
{ {
} }
void RadioButton::setUseThemeColors(bool state)
{
Q_D(RadioButton);
d->useThemeColors = state;
d->updatePalette();
update();
}
bool RadioButton::useThemeColors() const
{
Q_D(const RadioButton);
return d->useThemeColors;
}
void RadioButton::setCheckedColor(const QColor &color)
{
Q_D(RadioButton);
d->checkedColor = color;
setUseThemeColors(false);
}
QColor RadioButton::checkedColor() const
{
Q_D(const RadioButton);
if (d->useThemeColors || !d->checkedColor.isValid()) {
return Style::instance().themeColor("primary1");
} else {
return d->checkedColor;
}
}
void RadioButton::setUncheckedColor(const QColor &color)
{
Q_D(RadioButton);
d->uncheckedColor = color;
setUseThemeColors(false);
}
QColor RadioButton::uncheckedColor() const
{
Q_D(const RadioButton);
if (d->useThemeColors || !d->uncheckedColor.isValid()) {
return Style::instance().themeColor("text");
} else {
return d->uncheckedColor;
}
}
void RadioButton::setTextColor(const QColor &color)
{
Q_D(RadioButton);
d->textColor = color;
setUseThemeColors(false);
}
QColor RadioButton::textColor() const
{
Q_D(const RadioButton);
if (d->useThemeColors || !d->textColor.isValid()) {
return Style::instance().themeColor("text");
} else {
return d->textColor;
}
}
void RadioButton::setDisabledColor(const QColor &color)
{
Q_D(RadioButton);
d->disabledColor = color;
setUseThemeColors(false);
}
QColor RadioButton::disabledColor() const
{
Q_D(const RadioButton);
if (d->useThemeColors || !d->disabledColor.isValid()) {
// Transparency will not work here, since we use this color to
// tint the icon using a QGraphicsColorizeEffect
return Style::instance().themeColor("accent3");
} else {
return d->disabledColor;
}
}
void RadioButton::setCheckedIcon(const QIcon &icon)
{
Q_D(RadioButton);
d->checkedIcon->setIcon(icon);
}
QIcon RadioButton::checkedIcon() const
{
Q_D(const RadioButton);
return d->checkedIcon->icon();
}
void RadioButton::setUncheckedIcon(const QIcon &icon)
{
Q_D(RadioButton);
d->uncheckedIcon->setIcon(icon);
}
QIcon RadioButton::uncheckedIcon() const
{
Q_D(const RadioButton);
return d->uncheckedIcon->icon();
}
void RadioButton::setIconSize(int size)
{
Q_D(RadioButton);
if (size > 38) {
size = 38;
qWarning() << "RadioButton::setIconSize: maximum allowed icon size is 38";
}
d->iconSize = size;
d->assignAnimationProperties();
if (isChecked()) {
d->checkedIcon->setIconSize(size);
} else {
d->uncheckedIcon->setIconSize(size);
}
update();
}
int RadioButton::iconSize() const
{
Q_D(const RadioButton);
return d->iconSize;
}
QSize RadioButton::sizeHint() const QSize RadioButton::sizeHint() const
{ {
QString s(text()); QString s(text());
@ -64,7 +279,8 @@ bool RadioButton::event(QEvent *event)
case QEvent::Resize: case QEvent::Resize:
case QEvent::Move: case QEvent::Move:
d->ripple->setGeometry(geometry().adjusted(-8, -8, 8, 8)); d->ripple->setGeometry(geometry().adjusted(-8, -8, 8, 8));
d->iconWidget->setGeometry(geometry()); d->checkedIcon->setGeometry(rect());
d->uncheckedIcon->setGeometry(rect());
break; break;
case QEvent::ParentChange: case QEvent::ParentChange:
QWidget *widget; QWidget *widget;
@ -72,6 +288,16 @@ bool RadioButton::event(QEvent *event)
d->ripple->setParent(widget); d->ripple->setParent(widget);
} }
break; break;
case QEvent::EnabledChange:
d->updatePalette();
if (isChecked()) {
d->checkedIcon->setIconSize(d->iconSize);
d->uncheckedIcon->setIconSize(0);
} else {
d->checkedIcon->setIconSize(0);
d->uncheckedIcon->setIconSize(d->iconSize);
}
break;
default: default:
break; break;
} }
@ -80,39 +306,30 @@ bool RadioButton::event(QEvent *event)
void RadioButton::mousePressEvent(QMouseEvent *event) void RadioButton::mousePressEvent(QMouseEvent *event)
{ {
Q_UNUSED(event)
if (!isEnabled())
return;
Q_D(RadioButton); Q_D(RadioButton);
d->ripple->addRipple(QPoint(24, 24), 24); Ripple *ripple = new Ripple(QPoint(24, 24));
ripple->setRadiusEndValue(24);
ripple->setColor(isChecked() ? d->checkedIcon->color() : Qt::black);
d->ripple->addRipple(ripple);
QRadioButton::mousePressEvent(event); setChecked(!isChecked());
}
void RadioButton::mouseReleaseEvent(QMouseEvent *event)
{
QRadioButton::mouseReleaseEvent(event);
} }
void RadioButton::paintEvent(QPaintEvent *event) void RadioButton::paintEvent(QPaintEvent *event)
{ {
Q_UNUSED(event) Q_UNUSED(event)
//Q_D(RadioButton);
QPainter painter(this); QPainter painter(this);
//painter.save(); QPen pen;
//QRadioButton::paintEvent(event); pen.setColor(isEnabled() ? textColor() : disabledColor());
//painter.restore(); painter.setPen(pen);
//painter.drawRect(rect().adjusted(0, 0, -1, -1));
// Icon
//d->checkedIcon.paint(&painter, QRect(4, 4, 24, 24), Qt::AlignCenter, QIcon::Normal);
//d->checkedIcon.pixmap()
// Label
painter.drawText(44, 21, text()); painter.drawText(44, 21, text());
} }

View File

@ -13,12 +13,35 @@ public:
explicit RadioButton(QWidget *parent = 0); explicit RadioButton(QWidget *parent = 0);
~RadioButton(); ~RadioButton();
void setUseThemeColors(bool state);
bool useThemeColors() const;
void setCheckedColor(const QColor &color);
QColor checkedColor() const;
void setUncheckedColor(const QColor &color);
QColor uncheckedColor() const;
void setTextColor(const QColor &color);
QColor textColor() const;
void setDisabledColor(const QColor &color);
QColor disabledColor() const;
void setCheckedIcon(const QIcon &icon);
QIcon checkedIcon() const;
void setUncheckedIcon(const QIcon &icon);
QIcon uncheckedIcon() const;
void setIconSize(int size);
int iconSize() const;
QSize sizeHint() const; QSize sizeHint() const;
protected: protected:
bool event(QEvent *event) Q_DECL_OVERRIDE; bool event(QEvent *event) Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
const QScopedPointer<RadioButtonPrivate> d_ptr; const QScopedPointer<RadioButtonPrivate> d_ptr;

View File

@ -1,21 +1,58 @@
#include "radiobutton_internal.h" #include "radiobutton_internal.h"
#include <QPainter> #include <QPainter>
#include <QGraphicsColorizeEffect>
RadioButtonIcon::RadioButtonIcon(QWidget *parent) RadioButtonIcon::RadioButtonIcon(const QIcon &icon, QWidget *parent)
: QWidget(parent) : QWidget(parent),
_icon(icon),
_iconSize(24),
_effect(new QGraphicsColorizeEffect)
{ {
setAttribute(Qt::WA_TransparentForMouseEvents);
setGraphicsEffect(_effect);
} }
RadioButtonIcon::~RadioButtonIcon() RadioButtonIcon::~RadioButtonIcon()
{ {
} }
void RadioButtonIcon::setColor(const QColor &color)
{
_effect->setColor(color);
update();
}
QColor RadioButtonIcon::color() const
{
return _effect->color();
}
void RadioButtonIcon::setIconSize(int size)
{
_iconSize = size;
update();
}
int RadioButtonIcon::iconSize() const
{
return _iconSize;
}
void RadioButtonIcon::paintEvent(QPaintEvent *event) void RadioButtonIcon::paintEvent(QPaintEvent *event)
{ {
Q_UNUSED(event) Q_UNUSED(event)
#ifdef DEBUG_LAYOUT
QPainter debug(this);
debug.drawRect(rect().adjusted(0, 0, -1, -1));
#endif
if (0 == _iconSize)
return;
QPainter painter(this); QPainter painter(this);
painter.setPen(Qt::red); const int p = (height() - _iconSize)/2;
painter.drawRect(rect()); _icon.paint(&painter, QRect(p, p, _iconSize, _iconSize));
} }

View File

@ -2,20 +2,39 @@
#define RADIOBUTTON_INTERNAL_H #define RADIOBUTTON_INTERNAL_H
#include <QWidget> #include <QWidget>
#include <QIcon>
class QGraphicsColorizeEffect;
class RadioButtonIcon : public QWidget class RadioButtonIcon : public QWidget
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor)
Q_PROPERTY(int iconSize READ iconSize WRITE setIconSize)
public: public:
RadioButtonIcon(QWidget *parent = 0); RadioButtonIcon(const QIcon &icon, QWidget *parent = 0);
~RadioButtonIcon(); ~RadioButtonIcon();
inline void setIcon(const QIcon &icon) { _icon = icon; update(); }
inline QIcon icon() const { return _icon; }
void setColor(const QColor &color);
QColor color() const;
void setIconSize(int size);
int iconSize() const;
protected: protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
private: private:
Q_DISABLE_COPY(RadioButtonIcon) Q_DISABLE_COPY(RadioButtonIcon)
QIcon _icon;
int _iconSize;
QGraphicsColorizeEffect *const _effect;
}; };
#endif // RADIOBUTTON_INTERNAL_H #endif // RADIOBUTTON_INTERNAL_H

View File

@ -2,6 +2,7 @@
#define RADIOBUTTON_P_H #define RADIOBUTTON_P_H
#include <QObject> #include <QObject>
#include <QStateMachine>
#include "radiobutton_internal.h" #include "radiobutton_internal.h"
class RadioButton; class RadioButton;
@ -17,11 +18,22 @@ public:
void init(); void init();
void assignAnimationProperties();
void updatePalette();
RadioButton *const q_ptr; RadioButton *const q_ptr;
RippleOverlay *ripple; RippleOverlay *ripple;
RadioButtonIcon *iconWidget; RadioButtonIcon *checkedIcon;
QIcon checkedIcon; RadioButtonIcon *uncheckedIcon;
QIcon uncheckedIcon; QStateMachine *machine;
QState *uncheckedState;
QState *checkedState;
int iconSize;
QColor checkedColor;
QColor uncheckedColor;
QColor textColor;
QColor disabledColor;
bool useThemeColors;
}; };
#endif // RADIOBUTTON_P_H #endif // RADIOBUTTON_P_H

View File

@ -17,13 +17,27 @@ RadioButtonExamples::RadioButtonExamples(QWidget *parent)
RadioButton *radioButton1 = new RadioButton; RadioButton *radioButton1 = new RadioButton;
RadioButton *radioButton2 = new RadioButton; RadioButton *radioButton2 = new RadioButton;
RadioButton *radioButton3 = new RadioButton; RadioButton *radioButton3 = new RadioButton;
RadioButton *radioButton4 = new RadioButton;
RadioButton *radioButton5 = new RadioButton;
radioButton3->setCheckedIcon(QIcon("../qt-material-widgets/ic_star_black_24px.svg"));
radioButton3->setUncheckedIcon(QIcon("../qt-material-widgets/ic_star_border_black_24px.svg"));
radioButton3->setIconSize(30);
radioButton1->setText("Auto select"); radioButton1->setText("Auto select");
radioButton2->setText("Option #2"); radioButton2->setText("Option #2");
radioButton4->setText("Disabled option");
radioButton5->setText("Disabled option (checked)");
bg->addButton(radioButton1); radioButton4->setDisabled(true);
bg->addButton(radioButton2); radioButton5->setDisabled(true);
bg->addButton(radioButton3); radioButton5->setChecked(true);
bg->addButton(radioButton1, 1);
bg->addButton(radioButton2, 2);
bg->addButton(radioButton3, 3);
bg->addButton(radioButton4, 4);
bg->addButton(radioButton5, 5);
QWidget *widget = new QWidget; QWidget *widget = new QWidget;
QVBoxLayout *vbl = new QVBoxLayout; QVBoxLayout *vbl = new QVBoxLayout;
@ -38,6 +52,8 @@ RadioButtonExamples::RadioButtonExamples(QWidget *parent)
vbl->addWidget(radioButton1); vbl->addWidget(radioButton1);
vbl->addWidget(radioButton2); vbl->addWidget(radioButton2);
vbl->addWidget(radioButton3); vbl->addWidget(radioButton3);
vbl->addWidget(radioButton4);
vbl->addWidget(radioButton5);
ExampleView *view = new ExampleView; ExampleView *view = new ExampleView;
view->setWidget(widget); view->setWidget(widget);

View File

@ -15,7 +15,7 @@ RaisedButtonExamples::RaisedButtonExamples(QWidget *parent)
raisedButton->setText("Press me!"); raisedButton->setText("Press me!");
raisedButton->setMaximumWidth(408); raisedButton->setMaximumWidth(408);
raisedButton->setDisabled(true); //raisedButton->setDisabled(true);
//raisedButton->setDisabled(true); //raisedButton->setDisabled(true);