2016-05-09 20:32:16 +00:00
|
|
|
// @todo -- separate decl. and impl.
|
|
|
|
// inverse mode
|
|
|
|
// paint track differently left of thumb
|
|
|
|
// direct click mode (mode thumb to click pos)
|
|
|
|
// paint thumb in halo widget
|
2016-05-01 19:56:39 +00:00
|
|
|
#ifndef SLIDER_P_H
|
|
|
|
#define SLIDER_P_H
|
|
|
|
|
|
|
|
#include "slider.h"
|
2016-05-01 21:10:31 +00:00
|
|
|
#include <QPainter>
|
2016-05-09 20:32:16 +00:00
|
|
|
#include <QPropertyAnimation>
|
|
|
|
#include <QStateMachine>
|
|
|
|
#include <QEventTransition>
|
|
|
|
#include <QSignalTransition>
|
|
|
|
#include <QDebug>
|
2016-05-02 20:35:04 +00:00
|
|
|
#include "lib/style.h"
|
2016-05-01 19:56:39 +00:00
|
|
|
|
2016-05-09 20:32:16 +00:00
|
|
|
#define THUMB_OUTER_SIZE 20
|
|
|
|
|
|
|
|
class Halo : public QWidget
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
Q_PROPERTY(qreal size WRITE setSize READ size)
|
|
|
|
|
|
|
|
public:
|
|
|
|
Halo(Slider *slider)
|
|
|
|
: QWidget(slider->parentWidget()),
|
|
|
|
slider(slider),
|
|
|
|
_size(0)
|
|
|
|
{
|
|
|
|
slider->installEventFilter(this);
|
|
|
|
setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
|
|
|
|
|
|
|
connect(slider, SIGNAL(sliderMoved(int)), this, SLOT(update()));
|
|
|
|
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(update()));
|
|
|
|
}
|
|
|
|
|
|
|
|
~Halo()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void setSize(qreal size)
|
|
|
|
{
|
|
|
|
_size = size;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline qreal size() const { return _size; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
bool eventFilter(QObject *obj, QEvent *event)
|
|
|
|
{
|
|
|
|
if (QEvent::ParentChange == event->type()) {
|
|
|
|
setParent(slider->parentWidget());
|
|
|
|
}
|
|
|
|
return QWidget::eventFilter(obj, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void paintEvent(QPaintEvent *event)
|
|
|
|
{
|
|
|
|
QPainter painter(this);
|
|
|
|
|
|
|
|
QBrush brush;
|
|
|
|
brush.setStyle(Qt::SolidPattern);
|
|
|
|
brush.setColor(QColor(0, 0, 0, 20));
|
|
|
|
painter.setBrush(brush);
|
|
|
|
painter.setPen(Qt::NoPen);
|
|
|
|
|
|
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
|
|
|
|
|
|
QPointF disp = Qt::Horizontal == slider->orientation()
|
|
|
|
? QPointF(THUMB_OUTER_SIZE/2 + slider->thumbOffset(),
|
|
|
|
slider->height()/2)
|
|
|
|
: QPointF(slider->width()/2,
|
|
|
|
THUMB_OUTER_SIZE/2 + slider->thumbOffset());
|
|
|
|
|
|
|
|
QRectF halo((slider->pos() - QPointF(_size, _size)/2) + disp,
|
|
|
|
QSize(_size, _size));
|
|
|
|
|
|
|
|
painter.drawEllipse(halo);
|
|
|
|
|
|
|
|
#ifdef DEBUG_LAYOUT
|
|
|
|
QPen pen;
|
|
|
|
pen.setColor(Qt::red);
|
|
|
|
pen.setWidth(2);
|
|
|
|
painter.setPen(pen);
|
|
|
|
painter.setBrush(Qt::NoBrush);
|
|
|
|
|
|
|
|
painter.drawRect(rect().adjusted(0, 0, -2, -2));
|
|
|
|
#endif
|
|
|
|
QWidget::paintEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const Slider *const slider;
|
|
|
|
qreal _size;
|
|
|
|
};
|
2016-05-01 23:22:43 +00:00
|
|
|
|
2016-05-01 19:56:39 +00:00
|
|
|
class SliderPrivate
|
|
|
|
{
|
|
|
|
Q_DISABLE_COPY(SliderPrivate)
|
|
|
|
Q_DECLARE_PUBLIC(Slider)
|
|
|
|
|
|
|
|
public:
|
|
|
|
SliderPrivate(Slider *parent)
|
2016-05-01 21:10:31 +00:00
|
|
|
: q_ptr(parent),
|
2016-05-09 20:32:16 +00:00
|
|
|
halo(new Halo(parent)),
|
2016-05-01 23:22:43 +00:00
|
|
|
hoverTrack(false),
|
2016-05-03 05:48:43 +00:00
|
|
|
hoverThumb(false),
|
2016-05-03 22:40:34 +00:00
|
|
|
step(false),
|
2016-05-09 20:32:16 +00:00
|
|
|
stepTo(0),
|
|
|
|
oldValue(parent->value()),
|
|
|
|
thumbSize(11),
|
|
|
|
thumbPenWidth(0),
|
|
|
|
thumbColor(Qt::white)
|
2016-05-01 19:56:39 +00:00
|
|
|
{
|
2016-05-01 23:22:43 +00:00
|
|
|
parent->setMouseTracking(true);
|
2016-05-01 19:56:39 +00:00
|
|
|
}
|
|
|
|
|
2016-05-09 20:32:16 +00:00
|
|
|
void init(Slider *slider)
|
|
|
|
{
|
|
|
|
QState *s1 = new QState(QState::ParallelStates);
|
|
|
|
|
|
|
|
QState *s11 = new QState(s1);
|
|
|
|
|
|
|
|
QState *inactiveState = new QState(s11);
|
|
|
|
QState *focusState = new QState(s11);
|
|
|
|
QState *pulseState = new QState(focusState);
|
|
|
|
QState *pulse2State = new QState(focusState);
|
|
|
|
QState *downState = new QState(s11);
|
|
|
|
|
|
|
|
focusState->setInitialState(pulseState);
|
|
|
|
|
|
|
|
inactiveState->assignProperty(halo, "size", 0);
|
|
|
|
pulseState->assignProperty(halo, "size", 35);
|
|
|
|
pulse2State->assignProperty(halo, "size", 28);
|
|
|
|
downState->assignProperty(halo, "size", 0);
|
|
|
|
|
|
|
|
inactiveState->assignProperty(slider, "thumbSize", 11);
|
|
|
|
focusState->assignProperty(slider, "thumbSize", 11);
|
|
|
|
downState->assignProperty(slider, "thumbSize", 17);
|
|
|
|
|
|
|
|
machine.addState(s1);
|
|
|
|
|
|
|
|
s11->setInitialState(inactiveState);
|
|
|
|
|
|
|
|
//machine.addState(inactiveState);
|
|
|
|
//machine.addState(focusState);
|
|
|
|
//machine.addState(downState);
|
|
|
|
|
|
|
|
//machine.setInitialState(inactiveState);
|
|
|
|
|
|
|
|
machine.setInitialState(s1);
|
|
|
|
|
|
|
|
QAbstractTransition *transition;
|
|
|
|
QPropertyAnimation *animation;
|
|
|
|
|
|
|
|
// Show halo on focus in
|
|
|
|
|
|
|
|
transition = new QEventTransition(slider, QEvent::FocusIn);
|
|
|
|
transition->setTargetState(focusState);
|
|
|
|
|
|
|
|
animation = new QPropertyAnimation(halo, "size");
|
|
|
|
transition->addAnimation(animation);
|
|
|
|
inactiveState->addTransition(transition);
|
|
|
|
|
|
|
|
// Hide halo on focus out
|
|
|
|
|
|
|
|
transition = new QEventTransition(slider, QEvent::FocusOut);
|
|
|
|
transition->setTargetState(inactiveState);
|
|
|
|
|
|
|
|
animation = new QPropertyAnimation(halo, "size");
|
|
|
|
transition->addAnimation(animation);
|
|
|
|
focusState->addTransition(transition);
|
|
|
|
|
|
|
|
// Pulse in
|
|
|
|
|
|
|
|
transition = new QSignalTransition(pulseState, SIGNAL(propertiesAssigned()));
|
|
|
|
transition->setTargetState(pulse2State);
|
|
|
|
|
|
|
|
animation = new QPropertyAnimation(halo, "size");
|
|
|
|
animation->setEasingCurve(QEasingCurve::InOutSine);
|
|
|
|
animation->setDuration(1000);
|
|
|
|
transition->addAnimation(animation);
|
|
|
|
pulseState->addTransition(transition);
|
|
|
|
|
|
|
|
// Pulse out
|
|
|
|
|
|
|
|
transition = new QSignalTransition(pulse2State, SIGNAL(propertiesAssigned()));
|
|
|
|
transition->setTargetState(pulseState);
|
|
|
|
|
|
|
|
animation = new QPropertyAnimation(halo, "size");
|
|
|
|
animation->setEasingCurve(QEasingCurve::InOutSine);
|
|
|
|
animation->setDuration(1000);
|
|
|
|
transition->addAnimation(animation);
|
|
|
|
pulse2State->addTransition(transition);
|
|
|
|
|
|
|
|
// Slider pressed
|
|
|
|
|
|
|
|
transition = new QSignalTransition(slider, SIGNAL(sliderPressed()));
|
|
|
|
transition->setTargetState(downState);
|
|
|
|
transition->addAnimation(new QPropertyAnimation(slider, "thumbSize"));
|
|
|
|
transition->addAnimation(new QPropertyAnimation(halo, "size"));
|
|
|
|
focusState->addTransition(transition);
|
|
|
|
|
|
|
|
// Slider released
|
|
|
|
|
|
|
|
transition = new QSignalTransition(slider, SIGNAL(sliderReleased()));
|
|
|
|
transition->setTargetState(focusState);
|
|
|
|
transition->addAnimation(new QPropertyAnimation(slider, "thumbSize"));
|
|
|
|
transition->addAnimation(new QPropertyAnimation(halo, "size"));
|
|
|
|
downState->addTransition(transition);
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
QState *s12 = new QState(s1);
|
|
|
|
|
|
|
|
QState *t1 = new QState(s12);
|
|
|
|
QState *t2 = new QState(s12);
|
|
|
|
|
|
|
|
t1->assignProperty(slider, "thumbColor", QColor(0, 0, 0));
|
|
|
|
t1->assignProperty(slider, "thumbPenWidth", 0);
|
|
|
|
t2->assignProperty(slider, "thumbColor", QColor(255, 255, 255));
|
|
|
|
t2->assignProperty(slider, "thumbPenWidth", 1.5);
|
|
|
|
|
|
|
|
//machine.addState(t1);
|
|
|
|
//machine.addState(t2);
|
|
|
|
|
|
|
|
//machine.addState(s12);
|
|
|
|
|
|
|
|
s12->setInitialState(t1);
|
|
|
|
|
|
|
|
transition = new QSignalTransition(slider, SIGNAL(changedToMinimum()));
|
|
|
|
transition->setTargetState(t2);
|
|
|
|
animation = new QPropertyAnimation(slider, "thumbColor");
|
|
|
|
animation->setDuration(700);
|
|
|
|
transition->addAnimation(animation);
|
|
|
|
animation = new QPropertyAnimation(slider, "thumbPenWidth");
|
|
|
|
animation->setDuration(700);
|
|
|
|
transition->addAnimation(animation);
|
|
|
|
t1->addTransition(transition);
|
|
|
|
|
|
|
|
transition = new QSignalTransition(slider, SIGNAL(changedFromMinimum()));
|
|
|
|
transition->setTargetState(t1);
|
|
|
|
animation = new QPropertyAnimation(slider, "thumbColor");
|
|
|
|
animation->setDuration(700);
|
|
|
|
transition->addAnimation(animation);
|
|
|
|
animation = new QPropertyAnimation(slider, "thumbPenWidth");
|
|
|
|
animation->setDuration(700);
|
|
|
|
transition->addAnimation(animation);
|
|
|
|
t2->addTransition(transition);
|
|
|
|
|
|
|
|
machine.start();
|
|
|
|
}
|
|
|
|
|
2016-05-04 20:44:33 +00:00
|
|
|
QRectF trackGeometry() const
|
2016-05-01 21:10:31 +00:00
|
|
|
{
|
|
|
|
Q_Q(const Slider);
|
|
|
|
|
2016-05-03 22:40:34 +00:00
|
|
|
return Qt::Horizontal == q->orientation()
|
2016-05-04 20:44:33 +00:00
|
|
|
? QRectF(THUMB_OUTER_SIZE/2, q->rect().height()/2 - 1,
|
2016-05-01 23:22:43 +00:00
|
|
|
q->rect().width() - THUMB_OUTER_SIZE, 2)
|
2016-05-04 20:44:33 +00:00
|
|
|
: QRectF(q->rect().width()/2 - 1, THUMB_OUTER_SIZE/2, 2,
|
2016-05-01 23:22:43 +00:00
|
|
|
q->rect().height() - THUMB_OUTER_SIZE);
|
2016-05-01 21:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void paintTrack(QPainter *painter)
|
|
|
|
{
|
2016-05-01 23:22:43 +00:00
|
|
|
painter->save();
|
|
|
|
|
2016-05-01 21:10:31 +00:00
|
|
|
QBrush brush;
|
|
|
|
brush.setStyle(Qt::SolidPattern);
|
|
|
|
brush.setColor(QColor(0, 0, 0, 255));
|
|
|
|
|
|
|
|
painter->fillRect(trackGeometry(), brush);
|
2016-05-01 21:44:38 +00:00
|
|
|
|
2016-05-01 21:10:31 +00:00
|
|
|
painter->restore();
|
|
|
|
|
|
|
|
#ifdef DEBUG_LAYOUT
|
2016-05-01 23:22:43 +00:00
|
|
|
if (hoverTrack) {
|
|
|
|
painter->save();
|
|
|
|
painter->setPen(Qt::red);
|
|
|
|
painter->drawRect(trackGeometry());
|
|
|
|
painter->restore();
|
|
|
|
}
|
2016-05-01 21:10:31 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-05-01 21:44:38 +00:00
|
|
|
QRectF thumbGeometry() const
|
|
|
|
{
|
|
|
|
Q_Q(const Slider);
|
|
|
|
|
2016-05-03 22:40:34 +00:00
|
|
|
return Qt::Horizontal == q->orientation()
|
2016-05-09 20:32:16 +00:00
|
|
|
? QRectF(q->thumbOffset(), q->rect().height()/2 - THUMB_OUTER_SIZE/2,
|
2016-05-01 23:22:43 +00:00
|
|
|
THUMB_OUTER_SIZE, THUMB_OUTER_SIZE)
|
2016-05-09 20:32:16 +00:00
|
|
|
: QRectF(q->rect().width()/2 - THUMB_OUTER_SIZE/2, q->thumbOffset(),
|
2016-05-01 23:22:43 +00:00
|
|
|
THUMB_OUTER_SIZE, THUMB_OUTER_SIZE);
|
2016-05-01 21:44:38 +00:00
|
|
|
}
|
|
|
|
|
2016-05-01 21:10:31 +00:00
|
|
|
void paintThumb(QPainter *painter)
|
|
|
|
{
|
2016-05-09 20:32:16 +00:00
|
|
|
painter->drawRect(thumbGeometry().adjusted(0, 0, -1, -1));
|
|
|
|
|
|
|
|
/*
|
2016-05-01 23:22:43 +00:00
|
|
|
painter->save();
|
|
|
|
|
2016-05-01 21:44:38 +00:00
|
|
|
QBrush brush;
|
|
|
|
brush.setStyle(Qt::SolidPattern);
|
2016-05-09 20:32:16 +00:00
|
|
|
brush.setColor(thumbColor);
|
2016-05-01 23:22:43 +00:00
|
|
|
painter->setBrush(brush);
|
2016-05-01 21:10:31 +00:00
|
|
|
|
2016-05-09 20:32:16 +00:00
|
|
|
if (thumbPenWidth) {
|
|
|
|
QPen pen;
|
|
|
|
pen.setWidthF(thumbPenWidth);
|
|
|
|
painter->setPen(pen);
|
|
|
|
} else {
|
|
|
|
painter->setPen(Qt::NoPen);
|
|
|
|
}
|
|
|
|
|
2016-05-01 21:44:38 +00:00
|
|
|
painter->setRenderHint(QPainter::Antialiasing);
|
|
|
|
|
2016-05-09 20:32:16 +00:00
|
|
|
QRectF thumb(0, 0, thumbSize, thumbSize);
|
2016-05-01 23:22:43 +00:00
|
|
|
thumb.moveCenter(thumbGeometry().center());
|
|
|
|
|
|
|
|
painter->drawEllipse(thumb);
|
2016-05-01 21:44:38 +00:00
|
|
|
|
2016-05-01 21:10:31 +00:00
|
|
|
painter->restore();
|
2016-05-01 23:22:43 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG_LAYOUT
|
|
|
|
painter->drawRect(thumbGeometry());
|
|
|
|
|
|
|
|
if (hoverThumb) {
|
|
|
|
painter->save();
|
|
|
|
painter->setPen(Qt::red);
|
|
|
|
painter->drawRect(thumbGeometry());
|
|
|
|
painter->restore();
|
|
|
|
}
|
|
|
|
#endif
|
2016-05-09 20:32:16 +00:00
|
|
|
*/
|
2016-05-01 21:10:31 +00:00
|
|
|
}
|
|
|
|
|
2016-05-02 20:57:57 +00:00
|
|
|
int valueFromPosition(const QPoint &pos) const
|
|
|
|
{
|
|
|
|
Q_Q(const Slider);
|
|
|
|
|
2016-05-03 22:40:34 +00:00
|
|
|
int position = Qt::Horizontal == q->orientation() ? pos.x() : pos.y();
|
|
|
|
|
|
|
|
int span = Qt::Horizontal == q->orientation()
|
2016-05-02 20:57:57 +00:00
|
|
|
? q->rect().width() - THUMB_OUTER_SIZE
|
|
|
|
: q->rect().height() - THUMB_OUTER_SIZE;
|
|
|
|
|
|
|
|
return Style::sliderValueFromPosition(
|
|
|
|
q->minimum(),
|
|
|
|
q->maximum(),
|
|
|
|
position - THUMB_OUTER_SIZE/2,
|
|
|
|
span,
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
2016-05-01 19:56:39 +00:00
|
|
|
Slider *const q_ptr;
|
2016-05-09 20:32:16 +00:00
|
|
|
Halo *const halo;
|
|
|
|
QStateMachine machine;
|
|
|
|
bool hoverTrack;
|
|
|
|
bool hoverThumb;
|
|
|
|
bool step;
|
|
|
|
int stepTo;
|
|
|
|
int oldValue;
|
|
|
|
qreal thumbSize;
|
|
|
|
qreal thumbPenWidth;
|
|
|
|
QColor thumbColor;
|
2016-05-01 19:56:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif // SLIDER_P_H
|