implement checkbox

This commit is contained in:
laserpants 2016-06-13 14:49:43 +03:00
parent ed66ccc0f0
commit 54028ac4d5
5 changed files with 522 additions and 45 deletions

View File

@ -1,67 +1,347 @@
#include <QWidget>
#include <QPainter>
#include <QStylePainter>
#include <QStyleOptionButton>
#include "checkbox.h"
#include <QPainter>
#include <QEvent>
#include <QSignalTransition>
#include <QPropertyAnimation>
#include <QApplication>
#include <QDebug>
#include "checkbox_p.h"
#include "lib/rippleoverlay.h"
#include "lib/style.h"
#include "lib/ripple.h"
CheckboxPrivate::CheckboxPrivate(Checkbox *q)
: q_ptr(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()
{
Q_Q(Checkbox);
q->setCheckable(true);
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;
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->setDuration(250);
transition->addAnimation(animation);
transition = new QSignalTransition(q, SIGNAL(toggled(bool)));
transition->setTargetState(uncheckedState);
checkedState->addTransition(transition);
animation = new QPropertyAnimation(checkedIcon, "opacity");
animation->setDuration(350);
transition->addAnimation(animation);
animation = new QPropertyAnimation(checkedIcon, "iconSize");
animation->setDuration(1250);
transition->addAnimation(animation);
q->assignAnimationProperties();
updatePalette();
machine->start();
QCoreApplication::processEvents();
}
void CheckboxPrivate::updatePalette()
{
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)
: QAbstractButton(parent),
d_ptr(new CheckboxPrivate(this))
{
setFixedSize(200, 200);
d_func()->init();
}
Checkbox::~Checkbox()
{
}
void Checkbox::mousePressEvent(QMouseEvent *event)
void Checkbox::setUseThemeColors(bool state)
{
QAbstractButton::mousePressEvent(event);
Q_D(Checkbox);
d->useThemeColors = state;
d->updatePalette();
update();
}
void Checkbox::mouseReleaseEvent(QMouseEvent *event)
bool Checkbox::useThemeColors() const
{
QAbstractButton::mouseReleaseEvent(event);
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)
QStylePainter p(this);
QStyleOptionButton opt;
initStyleOption(&opt);
p.drawControl(QStyle::CE_CheckBox, opt);
QPainter painter(this);
p.drawRect(rect().adjusted(0, 0, -1, -1)); // tmp
QPen pen;
pen.setColor(isEnabled() ? textColor() : disabledColor());
painter.setPen(pen);
painter.drawText(44, 21, text());
}
void Checkbox::initStyleOption(QStyleOptionButton *option) const
void Checkbox::assignAnimationProperties()
{
if (!option)
return;
//Q_D(const QCheckBox);
option->initFrom(this);
/*
if (d->down)
option->state |= QStyle::State_Sunken;
if (d->tristate && d->noChange)
option->state |= QStyle::State_NoChange;
else
option->state |= d->checked ? QStyle::State_On : QStyle::State_Off;
*/
if (testAttribute(Qt::WA_Hover) && underMouse()) {
/*
if (d->hovering)
option->state |= QStyle::State_MouseOver;
else
option->state &= ~QStyle::State_MouseOver;
*/
}
option->text = "Label label";
/*
option->text = d->text;
option->icon = d->icon;
option->iconSize = iconSize();
*/
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());
}

View File

@ -3,7 +3,7 @@
#include <QAbstractButton>
class QStyleOptionButton;
class CheckboxPrivate;
class Checkbox : public QAbstractButton
{
@ -13,12 +13,44 @@ public:
explicit Checkbox(QWidget *parent = 0);
~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:
bool event(QEvent *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 initStyleOption(QStyleOptionButton *option) const;
virtual void assignAnimationProperties();
const QScopedPointer<CheckboxPrivate> d_ptr;
private:
Q_DISABLE_COPY(Checkbox)
Q_DECLARE_PRIVATE(Checkbox)
};
#endif // CHECKBOX_H

View File

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

View File

@ -0,0 +1,45 @@
#ifndef CHECKBOX_INTERNAL_H
#define CHECKBOX_INTERNAL_H
#include <QWidget>
#include <QIcon>
class QGraphicsColorizeEffect;
class CheckboxIcon : 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:
CheckboxIcon(const QIcon &icon, QWidget *parent = 0);
~CheckboxIcon();
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(CheckboxIcon)
QIcon _icon;
qreal _iconSize;
qreal _opacity;
QGraphicsColorizeEffect *const _effect;
};
#endif // CHECKBOX_INTERNAL_H

38
components/checkbox_p.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef CHECKBOX_P_H
#define CHECKBOX_P_H
#include <QObject>
#include <QStateMachine>
#include "checkbox_internal.h"
class Checkbox;
class RippleOverlay;
class CheckboxPrivate
{
Q_DISABLE_COPY(CheckboxPrivate)
Q_DECLARE_PUBLIC(Checkbox)
public:
CheckboxPrivate(Checkbox *q);
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