refactor checkbox and radiobutton code

This commit is contained in:
laserpants 2016-06-14 02:27:37 +03:00
parent b975f1b84b
commit fcde226168
16 changed files with 674 additions and 748 deletions

View File

@ -1,347 +1,80 @@
#include "checkbox.h" #include "checkbox.h"
#include <QPainter> #include <QStateMachine>
#include <QEvent> #include <QEvent>
#include <QSignalTransition> #include <QSignalTransition>
#include <QEventTransition>
#include <QPropertyAnimation> #include <QPropertyAnimation>
#include <QApplication> #include <QApplication>
#include <QDebug> #include <QDebug>
#include "checkbox_p.h" #include "checkbox_p.h"
#include "lib/rippleoverlay.h"
#include "lib/style.h"
#include "lib/ripple.h"
CheckboxPrivate::CheckboxPrivate(Checkbox *q) CheckBoxPrivate::CheckBoxPrivate(CheckBox *q)
: q_ptr(q), : CheckablePrivate(q)
checkedIcon(new CheckboxIcon(QIcon("../qt-material-widgets/ic_check_box_black_24px.svg"))),
uncheckedIcon(new CheckboxIcon(QIcon("../qt-material-widgets/ic_check_box_outline_blank_black_24px.svg"))),
iconSize(24),
useThemeColors(true)
{ {
} }
void CheckboxPrivate::init() CheckBoxPrivate::~CheckBoxPrivate()
{ {
Q_Q(Checkbox); }
q->setCheckable(true); void CheckBoxPrivate::init()
{
uncheckedIcon->setParent(q);
checkedIcon->setParent(q);
ripple = new RippleOverlay(q->parentWidget());
machine = new QStateMachine(q);
QFont f(q->font());
f.setPointSizeF(11);
q->setFont(f);
uncheckedState = new QState;
transitionState = new QState;
checkedState = new QState;
machine->addState(uncheckedState);
machine->addState(transitionState);
machine->addState(checkedState);
machine->setInitialState(uncheckedState);
QSignalTransition *transition;
QPropertyAnimation *animation; QPropertyAnimation *animation;
transition = new QSignalTransition(q, SIGNAL(toggled(bool)));
transition->setTargetState(transitionState);
uncheckedState->addTransition(transition);
transition = new QSignalTransition(transitionState, SIGNAL(propertiesAssigned()));
transition->setTargetState(checkedState);
transitionState->addTransition(transition);
animation = new QPropertyAnimation(checkedIcon, "iconSize"); animation = new QPropertyAnimation(checkedIcon, "iconSize");
animation->setStartValue(0);
animation->setEndValue(24);
animation->setDuration(250); animation->setDuration(250);
transition->addAnimation(animation); uncheckedTransition->addAnimation(animation);
transition = new QSignalTransition(q, SIGNAL(toggled(bool))); animation = new QPropertyAnimation(uncheckedIcon, "color");
transition->setTargetState(uncheckedState); animation->setDuration(250);
checkedState->addTransition(transition); uncheckedTransition->addAnimation(animation);
//
animation = new QPropertyAnimation(uncheckedIcon, "color");
animation->setDuration(550);
checkedTransition->addAnimation(animation);
animation = new QPropertyAnimation(checkedIcon, "opacity"); animation = new QPropertyAnimation(checkedIcon, "opacity");
animation->setDuration(350); animation->setDuration(450);
transition->addAnimation(animation); checkedTransition->addAnimation(animation);
animation = new QPropertyAnimation(checkedIcon, "iconSize"); //
animation->setDuration(1250);
transition->addAnimation(animation);
q->assignAnimationProperties(); checkedState->assignProperty(checkedIcon, "iconSize", 24);
updatePalette(); checkedState->assignProperty(checkedIcon, "opacity", 1);
uncheckedState->assignProperty(checkedIcon, "opacity", 0);
disabledCheckedState->assignProperty(checkedIcon, "opacity", 1);
disabledUncheckedState->assignProperty(uncheckedIcon, "opacity", 1);
}
machine->start(); CheckBox::CheckBox(QWidget *parent)
: Checkable(*new CheckBoxPrivate(this), parent)
{
Q_D(CheckBox);
d->init();
CheckBox::assignProperties();
d->machine->start();
QCoreApplication::processEvents(); QCoreApplication::processEvents();
} }
void CheckboxPrivate::updatePalette() CheckBox::~CheckBox()
{
Q_Q(Checkbox);
if (q->isEnabled()) {
checkedIcon->setColor(q->checkedColor());
uncheckedIcon->setColor(q->uncheckedColor());
} else {
checkedIcon->setColor(q->disabledColor());
uncheckedIcon->setColor(q->disabledColor());
}
}
Checkbox::Checkbox(QWidget *parent)
: QAbstractButton(parent),
d_ptr(new CheckboxPrivate(this))
{
d_func()->init();
}
Checkbox::~Checkbox()
{ {
} }
void Checkbox::setUseThemeColors(bool state) void CheckBox::assignProperties()
{ {
Q_D(Checkbox); Q_D(CheckBox);
d->useThemeColors = state; d->checkedState->assignProperty(d->checkedIcon, "color", checkedColor());
d->updatePalette();
update();
}
bool Checkbox::useThemeColors() const
{
Q_D(const Checkbox);
return d->useThemeColors;
}
void Checkbox::setCheckedColor(const QColor &color)
{
Q_D(Checkbox);
d->checkedColor = color;
setUseThemeColors(false);
}
QColor Checkbox::checkedColor() const
{
Q_D(const Checkbox);
if (d->useThemeColors || !d->checkedColor.isValid()) {
return Style::instance().themeColor("primary1");
} else {
return d->checkedColor;
}
}
void Checkbox::setUncheckedColor(const QColor &color)
{
Q_D(Checkbox);
d->uncheckedColor = color;
setUseThemeColors(false);
}
QColor Checkbox::uncheckedColor() const
{
Q_D(const Checkbox);
if (d->useThemeColors || !d->uncheckedColor.isValid()) {
return Style::instance().themeColor("text");
} else {
return d->uncheckedColor;
}
}
void Checkbox::setTextColor(const QColor &color)
{
Q_D(Checkbox);
d->textColor = color;
setUseThemeColors(false);
}
QColor Checkbox::textColor() const
{
Q_D(const Checkbox);
if (d->useThemeColors || !d->textColor.isValid()) {
return Style::instance().themeColor("text");
} else {
return d->textColor;
}
}
void Checkbox::setDisabledColor(const QColor &color)
{
Q_D(Checkbox);
d->disabledColor = color;
setUseThemeColors(false);
}
QColor Checkbox::disabledColor() const
{
Q_D(const Checkbox);
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 Checkbox::setCheckedIcon(const QIcon &icon)
{
Q_D(Checkbox);
d->checkedIcon->setIcon(icon);
}
QIcon Checkbox::checkedIcon() const
{
Q_D(const Checkbox);
return d->checkedIcon->icon();
}
void Checkbox::setUncheckedIcon(const QIcon &icon)
{
Q_D(Checkbox);
d->uncheckedIcon->setIcon(icon);
}
QIcon Checkbox::uncheckedIcon() const
{
Q_D(const Checkbox);
return d->uncheckedIcon->icon();
}
void Checkbox::setIconSize(int size)
{
Q_D(Checkbox);
if (size > 38) {
size = 38;
qWarning() << "Checkbox::setIconSize: maximum allowed icon size is 38";
}
d->iconSize = size;
assignAnimationProperties();
if (isChecked()) {
d->checkedIcon->setIconSize(size);
d->uncheckedIcon->setIconSize(0);
} else {
d->uncheckedIcon->setIconSize(size);
d->checkedIcon->setIconSize(0);
}
update();
}
int Checkbox::iconSize() const
{
Q_D(const Checkbox);
return d->iconSize;
}
QSize Checkbox::sizeHint() const
{
QString s(text());
if (s.isEmpty())
return QSize(32, 32);
QFontMetrics fm = fontMetrics();
QSize sz = fm.size(Qt::TextShowMnemonic, s);
return QSize(sz.width() + 44, 32);
}
bool Checkbox::event(QEvent *event)
{
Q_D(Checkbox);
switch (event->type())
{
case QEvent::Resize:
case QEvent::Move:
d->ripple->setGeometry(geometry().adjusted(-8, -8, 8, 8));
d->checkedIcon->setGeometry(rect());
d->uncheckedIcon->setGeometry(rect());
break;
case QEvent::ParentChange:
QWidget *widget;
if ((widget = parentWidget())) {
d->ripple->setParent(widget);
}
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:
break;
}
return QAbstractButton::event(event);
}
void Checkbox::mousePressEvent(QMouseEvent *event)
{
Q_UNUSED(event)
if (!isEnabled())
return;
Q_D(Checkbox);
Ripple *ripple = new Ripple(QPoint(24, 24));
ripple->setRadiusEndValue(24);
ripple->setColor(isChecked() ? d->checkedIcon->color() : Qt::black);
d->ripple->addRipple(ripple);
setChecked(!isChecked());
}
void Checkbox::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
QPainter painter(this);
QPen pen;
pen.setColor(isEnabled() ? textColor() : disabledColor());
painter.setPen(pen);
painter.drawText(44, 21, text());
}
void Checkbox::assignAnimationProperties()
{
Q_D(Checkbox);
d->uncheckedState->assignProperty(d->checkedIcon, "opacity", 0);
d->uncheckedState->assignProperty(d->checkedIcon, "iconSize", d->iconSize);
d->uncheckedState->assignProperty(d->uncheckedIcon, "color", uncheckedColor());
d->transitionState->assignProperty(d->checkedIcon, "iconSize", 0);
d->checkedState->assignProperty(d->checkedIcon, "opacity", 1);
d->checkedState->assignProperty(d->checkedIcon, "iconSize", d->iconSize);
d->checkedState->assignProperty(d->uncheckedIcon, "color", checkedColor()); d->checkedState->assignProperty(d->uncheckedIcon, "color", checkedColor());
d->uncheckedState->assignProperty(d->uncheckedIcon, "color", uncheckedColor());
d->uncheckedState->assignProperty(d->uncheckedIcon, "color", uncheckedColor());
d->disabledUncheckedState->assignProperty(d->uncheckedIcon, "color", disabledColor());
d->disabledCheckedState->assignProperty(d->checkedIcon, "color", disabledColor());
} }

View File

@ -1,56 +1,24 @@
#ifndef CHECKBOX_H #ifndef CHECKBOX_H
#define CHECKBOX_H #define CHECKBOX_H
#include <QAbstractButton> #include "lib/checkable.h"
class CheckboxPrivate; class CheckBoxPrivate;
class Checkbox : public QAbstractButton class CheckBox : public Checkable
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Checkbox(QWidget *parent = 0); explicit CheckBox(QWidget *parent = 0);
~Checkbox(); ~CheckBox();
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;
protected: protected:
bool event(QEvent *event) Q_DECL_OVERRIDE; void assignProperties() Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
virtual void assignAnimationProperties();
const QScopedPointer<CheckboxPrivate> d_ptr;
private: private:
Q_DISABLE_COPY(Checkbox) Q_DISABLE_COPY(CheckBox)
Q_DECLARE_PRIVATE(Checkbox) Q_DECLARE_PRIVATE(CheckBox)
}; };
#endif // CHECKBOX_H #endif // CHECKBOX_H

View File

@ -1,5 +1,6 @@
#include "checkbox_internal.h" #include "checkbox_internal.h"
#include <QPainter> #include <QPainter>
#include <QDebug>
#include <QGraphicsColorizeEffect> #include <QGraphicsColorizeEffect>
CheckboxIcon::CheckboxIcon(const QIcon &icon, QWidget *parent) CheckboxIcon::CheckboxIcon(const QIcon &icon, QWidget *parent)
@ -71,7 +72,7 @@ void CheckboxIcon::paintEvent(QPaintEvent *event)
painter.setOpacity(_opacity); painter.setOpacity(_opacity);
const qreal p = static_cast<qreal>((height())-_iconSize)/2; const qreal p = static_cast<qreal>((height())-_iconSize)/2;
const qreal z = static_cast<qreal>(_iconSize)/24; const qreal z = _iconSize/24;
QTransform t; QTransform t;
t.translate(p, p); t.translate(p, p);

View File

@ -1,38 +1,18 @@
#ifndef CHECKBOX_P_H #ifndef CHECKBOX_P_H
#define CHECKBOX_P_H #define CHECKBOX_P_H
#include <QObject> #include "lib/checkable_p.h"
#include <QStateMachine>
#include "checkbox_internal.h"
class Checkbox; class CheckBoxPrivate : public CheckablePrivate
class RippleOverlay;
class CheckboxPrivate
{ {
Q_DISABLE_COPY(CheckboxPrivate) Q_DISABLE_COPY(CheckBoxPrivate)
Q_DECLARE_PUBLIC(Checkbox) Q_DECLARE_PUBLIC(CheckBox)
public: public:
CheckboxPrivate(Checkbox *q); CheckBoxPrivate(CheckBox *q);
~CheckBoxPrivate();
void init(); void init();
void updatePalette();
Checkbox *const q_ptr;
RippleOverlay *ripple;
CheckboxIcon *checkedIcon;
CheckboxIcon *uncheckedIcon;
QStateMachine *machine;
QState *uncheckedState;
QState *transitionState;
QState *checkedState;
int iconSize;
QColor checkedColor;
QColor uncheckedColor;
QColor textColor;
QColor disabledColor;
bool useThemeColors;
}; };
#endif // CHECKBOX_P_H #endif // CHECKBOX_P_H

View File

@ -1,21 +1,19 @@
#include "radiobutton.h" #include "radiobutton.h"
#include <QPainter> #include <QStateMachine>
#include <QEvent> #include <QEvent>
#include <QSignalTransition> #include <QSignalTransition>
#include <QEventTransition>
#include <QPropertyAnimation> #include <QPropertyAnimation>
#include <QApplication> #include <QApplication>
#include <QDebug> #include <QDebug>
#include "radiobutton_p.h" #include "radiobutton_p.h"
#include "lib/rippleoverlay.h"
#include "lib/style.h"
#include "lib/ripple.h"
RadioButtonPrivate::RadioButtonPrivate(RadioButton *q) RadioButtonPrivate::RadioButtonPrivate(RadioButton *q)
: q_ptr(q), : CheckablePrivate(q)
checkedIcon(new RadioButtonIcon(QIcon("../qt-material-widgets/ic_radio_button_checked_black_24px.svg"))), {
uncheckedIcon(new RadioButtonIcon(QIcon("../qt-material-widgets/ic_radio_button_unchecked_black_24px.svg"))), }
iconSize(24),
useThemeColors(true) RadioButtonPrivate::~RadioButtonPrivate()
{ {
} }
@ -23,318 +21,76 @@ void RadioButtonPrivate::init()
{ {
Q_Q(RadioButton); Q_Q(RadioButton);
q->setCheckable(true);
q->setAutoExclusive(true); q->setAutoExclusive(true);
checkedIcon->setParent(q); q->setCheckedIcon(QIcon("../qt-material-widgets/ic_radio_button_checked_black_24px.svg"));
uncheckedIcon->setParent(q); q->setUncheckedIcon(QIcon("../qt-material-widgets/ic_radio_button_unchecked_black_24px.svg"));
ripple = new RippleOverlay(q->parentWidget());
machine = new QStateMachine(q);
QFont f(q->font());
f.setPointSizeF(11);
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(checkedIcon, "iconSize", 0);
uncheckedState->assignProperty(uncheckedIcon, "iconSize", iconSize); uncheckedState->assignProperty(uncheckedIcon, "iconSize", 24);
disabledUncheckedState->assignProperty(checkedIcon, "iconSize", 0);
disabledUncheckedState->assignProperty(uncheckedIcon, "iconSize", 24);
checkedState->assignProperty(uncheckedIcon, "iconSize", 0); checkedState->assignProperty(uncheckedIcon, "iconSize", 0);
checkedState->assignProperty(checkedIcon, "iconSize", iconSize); checkedState->assignProperty(checkedIcon, "iconSize", 24);
} disabledCheckedState->assignProperty(uncheckedIcon, "iconSize", 0);
disabledCheckedState->assignProperty(checkedIcon, "iconSize", 24);
void RadioButtonPrivate::updatePalette() uncheckedState->assignProperty(checkedIcon, "opacity", 0);
{ uncheckedState->assignProperty(uncheckedIcon, "opacity", 1);
Q_Q(RadioButton); checkedState->assignProperty(uncheckedIcon, "opacity", 0);
checkedState->assignProperty(checkedIcon, "opacity", 1);
if (q->isEnabled()) { disabledUncheckedState->assignProperty(uncheckedIcon, "opacity", 1);
checkedIcon->setColor(q->checkedColor()); disabledCheckedState->assignProperty(checkedIcon, "opacity", 1);
uncheckedIcon->setColor(q->uncheckedColor());
} else { QPropertyAnimation *animation;
checkedIcon->setColor(q->disabledColor());
uncheckedIcon->setColor(q->disabledColor()); animation = new QPropertyAnimation(checkedIcon, "iconSize");
} animation->setDuration(250);
machine->addDefaultAnimation(animation);
animation = new QPropertyAnimation(uncheckedIcon, "iconSize");
animation->setDuration(250);
machine->addDefaultAnimation(animation);
animation = new QPropertyAnimation(uncheckedIcon, "opacity");
animation->setDuration(250);
machine->addDefaultAnimation(animation);
animation = new QPropertyAnimation(checkedIcon, "opacity");
animation->setDuration(250);
machine->addDefaultAnimation(animation);
} }
RadioButton::RadioButton(QWidget *parent) RadioButton::RadioButton(QWidget *parent)
: QAbstractButton(parent), : Checkable(*new RadioButtonPrivate(this), parent)
d_ptr(new RadioButtonPrivate(this))
{ {
d_func()->init(); Q_D(RadioButton);
d->init();
RadioButton::assignProperties();
d->machine->start();
QCoreApplication::processEvents();
} }
RadioButton::~RadioButton() RadioButton::~RadioButton()
{ {
} }
void RadioButton::setUseThemeColors(bool state) void RadioButton::assignProperties()
{ {
Q_D(RadioButton); Q_D(RadioButton);
d->useThemeColors = state; d->disabledUncheckedState->assignProperty(d->uncheckedIcon, "color", disabledColor());
d->updatePalette(); d->disabledUncheckedState->assignProperty(d->checkedIcon, "color", disabledColor());
update(); d->disabledCheckedState->assignProperty(d->checkedIcon, "color", disabledColor());
} d->disabledCheckedState->assignProperty(d->uncheckedIcon, "color", disabledColor());
bool RadioButton::useThemeColors() const d->uncheckedState->assignProperty(d->uncheckedIcon, "color", uncheckedColor());
{ d->uncheckedState->assignProperty(d->checkedIcon, "color", checkedColor());
Q_D(const RadioButton); d->checkedState->assignProperty(d->uncheckedIcon, "color", uncheckedColor());
d->checkedState->assignProperty(d->checkedIcon, "color", checkedColor());
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);
d->uncheckedIcon->setIconSize(0);
} else {
d->uncheckedIcon->setIconSize(size);
d->checkedIcon->setIconSize(0);
}
update();
}
int RadioButton::iconSize() const
{
Q_D(const RadioButton);
return d->iconSize;
}
QSize RadioButton::sizeHint() const
{
QString s(text());
if (s.isEmpty())
return QSize(32, 32);
QFontMetrics fm = fontMetrics();
QSize sz = fm.size(Qt::TextShowMnemonic, s);
return QSize(sz.width() + 44, 32);
}
bool RadioButton::event(QEvent *event)
{
Q_D(RadioButton);
switch (event->type())
{
case QEvent::Resize:
case QEvent::Move:
d->ripple->setGeometry(geometry().adjusted(-8, -8, 8, 8));
d->checkedIcon->setGeometry(rect());
d->uncheckedIcon->setGeometry(rect());
break;
case QEvent::ParentChange:
QWidget *widget;
if ((widget = parentWidget())) {
d->ripple->setParent(widget);
}
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:
break;
}
return QAbstractButton::event(event);
}
void RadioButton::mousePressEvent(QMouseEvent *event)
{
Q_UNUSED(event)
if (!isEnabled())
return;
Q_D(RadioButton);
Ripple *ripple = new Ripple(QPoint(24, 24));
ripple->setRadiusEndValue(24);
ripple->setColor(isChecked() ? d->checkedIcon->color() : Qt::black);
d->ripple->addRipple(ripple);
setChecked(!isChecked());
}
void RadioButton::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
QPainter painter(this);
QPen pen;
pen.setColor(isEnabled() ? textColor() : disabledColor());
painter.setPen(pen);
painter.drawText(44, 21, text());
} }

View File

@ -1,11 +1,11 @@
#ifndef RADIOBUTTON_H #ifndef RADIOBUTTON_H
#define RADIOBUTTON_H #define RADIOBUTTON_H
#include <QAbstractButton> #include "lib/checkable.h"
class RadioButtonPrivate; class RadioButtonPrivate;
class RadioButton : public QAbstractButton class RadioButton : public Checkable
{ {
Q_OBJECT Q_OBJECT
@ -13,38 +13,8 @@ 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;
protected: protected:
bool event(QEvent *event) Q_DECL_OVERRIDE; void assignProperties() Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
const QScopedPointer<RadioButtonPrivate> d_ptr;
private: private:
Q_DISABLE_COPY(RadioButton) Q_DISABLE_COPY(RadioButton)

View File

@ -1,39 +1,18 @@
#ifndef RADIOBUTTON_P_H #ifndef RADIOBUTTON_P_H
#define RADIOBUTTON_P_H #define RADIOBUTTON_P_H
#include <QObject> #include "lib/checkable_p.h"
#include <QStateMachine>
#include "radiobutton_internal.h"
class RadioButton; class RadioButtonPrivate : public CheckablePrivate
class RippleOverlay;
class RadioButtonPrivate
{ {
Q_DISABLE_COPY(RadioButtonPrivate) Q_DISABLE_COPY(RadioButtonPrivate)
Q_DECLARE_PUBLIC(RadioButton) Q_DECLARE_PUBLIC(RadioButton)
public: public:
RadioButtonPrivate(RadioButton *q); RadioButtonPrivate(RadioButton *q);
~RadioButtonPrivate();
void init(); void init();
void assignAnimationProperties();
void updatePalette();
RadioButton *const q_ptr;
RippleOverlay *ripple;
RadioButtonIcon *checkedIcon;
RadioButtonIcon *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

@ -100,9 +100,7 @@ void RaisedButtonPrivate::init()
RaisedButton::RaisedButton(QWidget *parent) RaisedButton::RaisedButton(QWidget *parent)
: FlatButton(*new RaisedButtonPrivate(this), parent) : FlatButton(*new RaisedButtonPrivate(this), parent)
{ {
Q_D(RaisedButton); d_func()->init();
d->init();
setMinimumHeight(42); setMinimumHeight(42);
} }

View File

@ -1,5 +1,6 @@
#include <QLayout> #include <QLayout>
#include <QEvent> #include <QEvent>
#include <QCheckBox>
#include "checkboxexamples.h" #include "checkboxexamples.h"
#include "components/checkbox.h" #include "components/checkbox.h"
#include "exampleview.h" #include "exampleview.h"
@ -11,7 +12,10 @@ CheckboxExamples::CheckboxExamples(QWidget *parent)
QLayout *layout = widget()->layout(); QLayout *layout = widget()->layout();
{ {
Checkbox *checkbox = new Checkbox; CheckBox *checkbox = new CheckBox;
checkbox->setText("Do the macarena");
checkbox->setDisabled(true);
checkbox->setChecked(true);
ExampleView *view = new ExampleView; ExampleView *view = new ExampleView;
view->setWidget(checkbox); view->setWidget(checkbox);
@ -23,6 +27,12 @@ CheckboxExamples::CheckboxExamples(QWidget *parent)
frame->setWidget(view); frame->setWidget(view);
layout->addWidget(frame); layout->addWidget(frame);
QCheckBox *cb = new QCheckBox;
layout->addWidget(cb);
connect(cb, SIGNAL(toggled(bool)), checkbox, SLOT(setDisabled(bool)));
} }
} }

View File

@ -22,7 +22,6 @@ RadioButtonExamples::RadioButtonExamples(QWidget *parent)
radioButton3->setCheckedIcon(QIcon("../qt-material-widgets/ic_star_black_24px.svg")); radioButton3->setCheckedIcon(QIcon("../qt-material-widgets/ic_star_black_24px.svg"));
radioButton3->setUncheckedIcon(QIcon("../qt-material-widgets/ic_star_border_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");

307
lib/checkable.cpp Normal file
View File

@ -0,0 +1,307 @@
#include "checkable.h"
#include <QPainter>
#include <QEvent>
#include <QStateMachine>
#include <QSignalTransition>
#include <QEventTransition>
#include <QPropertyAnimation>
#include <QApplication>
#include <QDebug>
#include "checkable_p.h"
#include "lib/rippleoverlay.h"
#include "lib/style.h"
#include "lib/ripple.h"
CheckablePrivate::CheckablePrivate(Checkable *q)
: q_ptr(q),
checkedIcon(new CheckableIcon(QIcon("../qt-material-widgets/ic_check_box_black_24px.svg"))),
uncheckedIcon(new CheckableIcon(QIcon("../qt-material-widgets/ic_check_box_outline_blank_black_24px.svg"))),
useThemeColors(true)
{
}
CheckablePrivate::~CheckablePrivate()
{
}
void CheckablePrivate::init()
{
Q_Q(Checkable);
q->setCheckable(true);
uncheckedIcon->setParent(q);
checkedIcon->setParent(q);
ripple = new RippleOverlay(q->parentWidget());
QFont f(q->font());
f.setPointSizeF(11);
q->setFont(f);
//
machine = new QStateMachine(q);
uncheckedState = new QState;
checkedState = new QState;
disabledUncheckedState = new QState;
disabledCheckedState = new QState;
machine->addState(uncheckedState);
machine->addState(checkedState);
machine->addState(disabledUncheckedState);
machine->addState(disabledCheckedState);
machine->setInitialState(uncheckedState);
// Transition to checked
uncheckedTransition = new QSignalTransition(q, SIGNAL(toggled(bool)));
uncheckedTransition->setTargetState(checkedState);
uncheckedState->addTransition(uncheckedTransition);
// Transition to unchecked
checkedTransition = new QSignalTransition(q, SIGNAL(toggled(bool)));
checkedTransition->setTargetState(uncheckedState);
checkedState->addTransition(checkedTransition);
QAbstractTransition *transition;
// Enabled-Disabled transitions
transition = new QEventTransition(q, QEvent::EnabledChange);
transition->setTargetState(disabledUncheckedState);
uncheckedState->addTransition(transition);
transition = new QEventTransition(q, QEvent::EnabledChange);
transition->setTargetState(uncheckedState);
disabledUncheckedState->addTransition(transition);
transition = new QEventTransition(q, QEvent::EnabledChange);
transition->setTargetState(disabledCheckedState);
checkedState->addTransition(transition);
transition = new QEventTransition(q, QEvent::EnabledChange);
transition->setTargetState(checkedState);
disabledCheckedState->addTransition(transition);
transition = new QSignalTransition(q, SIGNAL(toggled(bool)));
transition->setTargetState(disabledCheckedState);
disabledUncheckedState->addTransition(transition);
transition = new QSignalTransition(q, SIGNAL(toggled(bool)));
transition->setTargetState(disabledUncheckedState);
disabledCheckedState->addTransition(transition);
}
Checkable::Checkable(QWidget *parent)
: QAbstractButton(parent),
d_ptr(new CheckablePrivate(this))
{
d_func()->init();
}
Checkable::~Checkable()
{
}
void Checkable::setUseThemeColors(bool state)
{
Q_D(Checkable);
d->useThemeColors = state;
assignProperties();
update();
}
bool Checkable::useThemeColors() const
{
Q_D(const Checkable);
return d->useThemeColors;
}
void Checkable::setCheckedColor(const QColor &color)
{
Q_D(Checkable);
d->checkedColor = color;
setUseThemeColors(false);
}
QColor Checkable::checkedColor() const
{
Q_D(const Checkable);
if (d->useThemeColors || !d->checkedColor.isValid()) {
return Style::instance().themeColor("primary1");
} else {
return d->checkedColor;
}
}
void Checkable::setUncheckedColor(const QColor &color)
{
Q_D(Checkable);
d->uncheckedColor = color;
setUseThemeColors(false);
}
QColor Checkable::uncheckedColor() const
{
Q_D(const Checkable);
if (d->useThemeColors || !d->uncheckedColor.isValid()) {
return Style::instance().themeColor("text");
} else {
return d->uncheckedColor;
}
}
void Checkable::setTextColor(const QColor &color)
{
Q_D(Checkable);
d->textColor = color;
setUseThemeColors(false);
}
QColor Checkable::textColor() const
{
Q_D(const Checkable);
if (d->useThemeColors || !d->textColor.isValid()) {
return Style::instance().themeColor("text");
} else {
return d->textColor;
}
}
void Checkable::setDisabledColor(const QColor &color)
{
Q_D(Checkable);
d->disabledColor = color;
setUseThemeColors(false);
}
QColor Checkable::disabledColor() const
{
Q_D(const Checkable);
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 Checkable::setCheckedIcon(const QIcon &icon)
{
Q_D(Checkable);
d->checkedIcon->setIcon(icon);
}
QIcon Checkable::checkedIcon() const
{
Q_D(const Checkable);
return d->checkedIcon->icon();
}
void Checkable::setUncheckedIcon(const QIcon &icon)
{
Q_D(Checkable);
d->uncheckedIcon->setIcon(icon);
}
QIcon Checkable::uncheckedIcon() const
{
Q_D(const Checkable);
return d->uncheckedIcon->icon();
}
QSize Checkable::sizeHint() const
{
QString s(text());
if (s.isEmpty())
return QSize(32, 32);
QFontMetrics fm = fontMetrics();
QSize sz = fm.size(Qt::TextShowMnemonic, s);
return QSize(sz.width() + 44, 32);
}
Checkable::Checkable(CheckablePrivate &d, QWidget *parent)
: QAbstractButton(parent),
d_ptr(&d)
{
d_func()->init();
}
bool Checkable::event(QEvent *event)
{
Q_D(Checkable);
switch (event->type())
{
case QEvent::Resize:
case QEvent::Move:
d->ripple->setGeometry(geometry().adjusted(-8, -8, 8, 8));
d->checkedIcon->setGeometry(rect());
d->uncheckedIcon->setGeometry(rect());
break;
case QEvent::ParentChange:
QWidget *widget;
if ((widget = parentWidget())) {
d->ripple->setParent(widget);
}
break;
default:
break;
}
return QAbstractButton::event(event);
}
void Checkable::mousePressEvent(QMouseEvent *event)
{
Q_UNUSED(event)
if (!isEnabled())
return;
Q_D(Checkable);
Ripple *ripple = new Ripple(QPoint(24, 24));
ripple->setRadiusEndValue(20);
ripple->setColor(isChecked() ? checkedColor() : uncheckedColor());
d->ripple->addRipple(ripple);
setChecked(!isChecked());
}
void Checkable::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
QPainter painter(this);
QPen pen;
pen.setColor(isEnabled() ? textColor() : disabledColor());
painter.setPen(pen);
painter.drawText(44, 21, text());
}
void Checkable::assignProperties()
{
}

55
lib/checkable.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef CHECKABLE_H
#define CHECKABLE_H
#include <QAbstractButton>
class CheckablePrivate;
class Checkable : public QAbstractButton
{
Q_OBJECT
public:
explicit Checkable(QWidget *parent = 0);
virtual ~Checkable();
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;
QSize sizeHint() const;
protected:
Checkable(CheckablePrivate &d, QWidget *parent = 0);
bool event(QEvent *event) Q_DECL_OVERRIDE;
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
virtual void assignProperties();
const QScopedPointer<CheckablePrivate> d_ptr;
private:
Q_DISABLE_COPY(Checkable)
Q_DECLARE_PRIVATE(Checkable)
};
#endif // CHECKABLE_H

View File

@ -0,0 +1,82 @@
#include "checkable_internal.h"
#include <QPainter>
#include <QGraphicsColorizeEffect>
CheckableIcon::CheckableIcon(const QIcon &icon, QWidget *parent)
: QWidget(parent),
_effect(new QGraphicsColorizeEffect),
_icon(icon),
_iconSize(24),
_opacity(1.0)
{
setAttribute(Qt::WA_TransparentForMouseEvents);
setGraphicsEffect(_effect);
}
CheckableIcon::~CheckableIcon()
{
}
void CheckableIcon::setColor(const QColor &color)
{
if (_effect->color() == color)
return;
_effect->setColor(color);
update();
}
QColor CheckableIcon::color() const
{
return _effect->color();
}
void CheckableIcon::setIconSize(qreal size)
{
_iconSize = size;
update();
}
qreal CheckableIcon::iconSize() const
{
return _iconSize;
}
void CheckableIcon::setOpacity(qreal opacity)
{
_opacity = opacity;
update();
}
qreal CheckableIcon::opacity() const
{
return _opacity;
}
void CheckableIcon::paintEvent(QPaintEvent *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);
painter.setRenderHint(QPainter::Antialiasing);
painter.setOpacity(_opacity);
const qreal p = static_cast<qreal>((height())-_iconSize)/2;
const qreal z = _iconSize/24;
QTransform t;
t.translate(p, p);
t.scale(z, z);
painter.setTransform(t);
_icon.paint(&painter, QRect(0, 0, 24, 24));
}

45
lib/checkable_internal.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef CHECKABLE_INTERNAL_H
#define CHECKABLE_INTERNAL_H
#include <QWidget>
#include <QIcon>
class QGraphicsColorizeEffect;
class CheckableIcon : public QWidget
{
Q_OBJECT
Q_PROPERTY(QColor color READ color WRITE setColor)
Q_PROPERTY(qreal iconSize READ iconSize WRITE setIconSize)
Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)
public:
CheckableIcon(const QIcon &icon, QWidget *parent = 0);
~CheckableIcon();
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(qreal size);
qreal iconSize() const;
void setOpacity(qreal opacity);
qreal opacity() const;
protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
private:
Q_DISABLE_COPY(CheckableIcon)
QGraphicsColorizeEffect *const _effect;
QIcon _icon;
qreal _iconSize;
qreal _opacity;
};
#endif // CHECKABLE_INTERNAL_H

42
lib/checkable_p.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef CHECKABLE_P_H
#define CHECKABLE_P_H
#include <QObject>
#include "checkable_internal.h"
class QStateMachine;
class QState;
class QSignalTransition;
class Checkable;
class RippleOverlay;
class CheckablePrivate
{
Q_DISABLE_COPY(CheckablePrivate)
Q_DECLARE_PUBLIC(Checkable)
public:
CheckablePrivate(Checkable *q);
virtual ~CheckablePrivate();
void init();
Checkable *const q_ptr;
RippleOverlay *ripple;
CheckableIcon *checkedIcon;
CheckableIcon *uncheckedIcon;
QStateMachine *machine;
QState *uncheckedState;
QState *checkedState;
QState *disabledUncheckedState;
QState *disabledCheckedState;
QSignalTransition *uncheckedTransition;
QSignalTransition *checkedTransition;
QColor checkedColor;
QColor uncheckedColor;
QColor textColor;
QColor disabledColor;
bool useThemeColors;
};
#endif // CHECKABLE_P_H

View File

@ -60,8 +60,8 @@ SOURCES += main.cpp\
components/badge.cpp \ components/badge.cpp \
components/progress.cpp \ components/progress.cpp \
components/selectfield.cpp \ components/selectfield.cpp \
components/radiobutton_internal.cpp \ lib/checkable.cpp \
components/checkbox_internal.cpp lib/checkable_internal.cpp
HEADERS += mainwindow.h \ HEADERS += mainwindow.h \
components/appbar.h \ components/appbar.h \
@ -124,9 +124,10 @@ HEADERS += mainwindow.h \
components/selectfield.h \ components/selectfield.h \
components/fab_p.h \ components/fab_p.h \
components/radiobutton_p.h \ components/radiobutton_p.h \
components/radiobutton_internal.h \
components/checkbox_p.h \ components/checkbox_p.h \
components/checkbox_internal.h lib/checkable.h \
lib/checkable_p.h \
lib/checkable_internal.h
RESOURCES += \ RESOURCES += \
resources.qrc resources.qrc