From d881c4c89834c381f8ee9cd95f1d3965972b6b35 Mon Sep 17 00:00:00 2001 From: laserpants Date: Mon, 9 May 2016 23:32:16 +0300 Subject: [PATCH] snapshot --- components/slider.cpp | 144 ++++++++++------- components/slider.h | 25 ++- components/slider_p.h | 308 ++++++++++++++++++++++++++++++------ examples/sliderexamples.cpp | 34 +++- examples/sliderexamples.h | 3 + 5 files changed, 403 insertions(+), 111 deletions(-) diff --git a/components/slider.cpp b/components/slider.cpp index 658ed0c..5af040b 100644 --- a/components/slider.cpp +++ b/components/slider.cpp @@ -11,67 +11,105 @@ Slider::Slider(QWidget *parent) : QAbstractSlider(parent), d_ptr(new SliderPrivate(this)) { - QPropertyAnimation *animation; + d_ptr->init(this); - animation = new QPropertyAnimation; + setFocusPolicy(Qt::StrongFocus); - animation->setPropertyName("haloScaleFactor"); - animation->setTargetObject(this); - animation->setStartValue(0.8); - animation->setEndValue(1); - animation->setDuration(900); - animation->setEasingCurve(QEasingCurve::InOutQuad); + QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed); + if (orientation() == Qt::Vertical) + sp.transpose(); + setSizePolicy(sp); + setAttribute(Qt::WA_WState_OwnSizePolicy, false); - d_ptr->haloAnimation->addAnimation(animation); - - animation = new QPropertyAnimation; - - animation->setPropertyName("haloScaleFactor"); - animation->setTargetObject(this); - animation->setStartValue(1); - animation->setEndValue(0.8); - animation->setDuration(900); - animation->setEasingCurve(QEasingCurve::InOutQuad); - - d_ptr->haloAnimation->addAnimation(animation); - - d_ptr->haloAnimation->setLoopCount(-1); - d_ptr->haloAnimation->start(); - - connect(this, SIGNAL(actionTriggered(int)), this, SLOT(handleAction(int))); +// connect(this, SIGNAL(actionTriggered(int)), this, SLOT(handleAction(int))); } Slider::~Slider() { } -void Slider::setHaloScaleFactor(qreal factor) +QSize Slider::minimumSizeHint() const +{ + return QSize(20, 20); +} + +int Slider::thumbOffset() const +{ + return Style::sliderPositionFromValue( + minimum(), + maximum(), + sliderPosition(), + Qt::Horizontal == orientation() + ? rect().width() - 20 : rect().height() - 20, + false); +} + +void Slider::setThumbSize(qreal size) { Q_D(Slider); - d->haloScaleFactor = factor; + d->thumbSize = size; update(); } -qreal Slider::haloScaleFactor() const +qreal Slider::thumbSize() const { Q_D(const Slider); - return d->haloScaleFactor; + return d->thumbSize; } -void Slider::handleAction(int action) +void Slider::setThumbPenWidth(qreal width) { Q_D(Slider); - if (!d->step) - return; + d->thumbPenWidth = width; + update(); +} - if ((SliderPageStepAdd == action && sliderPosition() > d->stepTo) || - (SliderPageStepSub == action && sliderPosition() < d->stepTo)) - { - setSliderPosition(d->stepTo); +qreal Slider::thumbPenWidth() const +{ + Q_D(const Slider); + + return d->thumbPenWidth; +} + +void Slider::setThumbColor(const QColor &color) +{ + Q_D(Slider); + + d->thumbColor = color; + update(); +} + +QColor Slider::thumbColor() const +{ + Q_D(const Slider); + + return d->thumbColor; +} + +void Slider::sliderChange(SliderChange change) +{ + Q_D(Slider); + + if (SliderOrientationChange == change) { + QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Fixed); + if (orientation() == Qt::Vertical) + sp.transpose(); + setSizePolicy(sp); + } else if (SliderValueChange == change) { + if (minimum() == value()) { + triggerAction(SliderToMinimum); + emit changedToMinimum(); + } else if (maximum() == value()) { + triggerAction(SliderToMaximum); + } else if (minimum() == d->oldValue) { + emit changedFromMinimum(); + } + d->oldValue = value(); } + QAbstractSlider::sliderChange(change); } void Slider::paintEvent(QPaintEvent *event) @@ -83,10 +121,12 @@ void Slider::paintEvent(QPaintEvent *event) QPainter painter(this); d->paintTrack(&painter); - d->paintHalo(&painter); d->paintThumb(&painter); #ifdef DEBUG_LAYOUT + if (hasFocus()) + painter.drawRect(rect().adjusted(0, 0, -1, -1)); + QPen pen; pen.setColor(Qt::red); pen.setWidth(1); @@ -94,10 +134,6 @@ void Slider::paintEvent(QPaintEvent *event) painter.setPen(pen); painter.setBrush(Qt::NoBrush); painter.drawRect(rect().adjusted(0, 0, -1, -1)); - - painter.setFont(QFont("monospace", 8)); - painter.drawText(8, 18, "Value: " % QString::number(value())); - painter.drawText(8, 36, "Position: " % QString::number(sliderPosition())); #endif } @@ -105,10 +141,12 @@ void Slider::mouseMoveEvent(QMouseEvent *event) { Q_D(Slider); - if (isSliderDown()) { + if (isSliderDown()) + { setSliderPosition(d->valueFromPosition(event->pos())); - } else { - + } + else + { QRectF track(d->trackGeometry().adjusted(-2, -2, 2, 2)); if (track.contains(event->pos()) != d->hoverTrack) { @@ -142,19 +180,15 @@ void Slider::mousePressEvent(QMouseEvent *event) return; } - QRectF track(d->trackGeometry().adjusted(-2, -2, 2, 2)); + d->step = true; + d->stepTo = d->valueFromPosition(pos); - if (track.contains(pos)) { - d->step = true; - d->stepTo = d->valueFromPosition(pos); + SliderAction action = d->stepTo > sliderPosition() + ? SliderPageStepAdd + : SliderPageStepSub; - SliderAction action = d->stepTo > sliderPosition() - ? SliderPageStepAdd - : SliderPageStepSub; - - triggerAction(action); - setRepeatAction(action, 200); - } + triggerAction(action); + setRepeatAction(action); } void Slider::mouseReleaseEvent(QMouseEvent *event) diff --git a/components/slider.h b/components/slider.h index 8e07c35..5c7c179 100644 --- a/components/slider.h +++ b/components/slider.h @@ -10,19 +10,34 @@ class Slider : public QAbstractSlider { Q_OBJECT - Q_PROPERTY(qreal haloScaleFactor WRITE setHaloScaleFactor READ haloScaleFactor) + Q_PROPERTY(qreal thumbSize WRITE setThumbSize READ thumbSize) + Q_PROPERTY(qreal thumbPenWidth WRITE setThumbPenWidth READ thumbPenWidth) + Q_PROPERTY(QColor thumbColor WRITE setThumbColor READ thumbColor) public: explicit Slider(QWidget *parent = 0); ~Slider(); - void setHaloScaleFactor(qreal factor); - qreal haloScaleFactor() const; + QSize minimumSizeHint() const; -protected slots: - void handleAction(int action); + int thumbOffset() const; + + void setThumbSize(qreal size); + qreal thumbSize() const; + + void setThumbPenWidth(qreal width); + qreal thumbPenWidth() const; + + void setThumbColor(const QColor &color); + QColor thumbColor() const; + +signals: + void changedToMinimum(); + void changedFromMinimum(); protected: + void sliderChange(SliderChange change) Q_DECL_OVERRIDE; + void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; diff --git a/components/slider_p.h b/components/slider_p.h index a614a1d..b5d2286 100644 --- a/components/slider_p.h +++ b/components/slider_p.h @@ -1,12 +1,101 @@ +// @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 #ifndef SLIDER_P_H #define SLIDER_P_H #include "slider.h" #include -#include +#include +#include +#include +#include +#include #include "lib/style.h" -#define THUMB_OUTER_SIZE 35 +#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; +}; class SliderPrivate { @@ -16,16 +105,155 @@ class SliderPrivate public: SliderPrivate(Slider *parent) : q_ptr(parent), - haloAnimation(new QSequentialAnimationGroup(parent)), - haloScaleFactor(1), + halo(new Halo(parent)), hoverTrack(false), hoverThumb(false), step(false), - stepTo(0) + stepTo(0), + oldValue(parent->value()), + thumbSize(11), + thumbPenWidth(0), + thumbColor(Qt::white) { parent->setMouseTracking(true); } + 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(); + } + QRectF trackGeometry() const { Q_Q(const Slider); @@ -63,58 +291,36 @@ public: { Q_Q(const Slider); - const int span = Qt::Horizontal == q->orientation() - ? q->rect().width() - THUMB_OUTER_SIZE - : q->rect().height() - THUMB_OUTER_SIZE; - - const int pos = Style::sliderPositionFromValue( - q->minimum(), - q->maximum(), - q->sliderPosition(), - span, - false); - return Qt::Horizontal == q->orientation() - ? QRectF(pos, q->rect().height()/2 - THUMB_OUTER_SIZE/2, + ? QRectF(q->thumbOffset(), q->rect().height()/2 - THUMB_OUTER_SIZE/2, THUMB_OUTER_SIZE, THUMB_OUTER_SIZE) - : QRectF(q->rect().width()/2 - THUMB_OUTER_SIZE/2, pos, + : QRectF(q->rect().width()/2 - THUMB_OUTER_SIZE/2, q->thumbOffset(), THUMB_OUTER_SIZE, THUMB_OUTER_SIZE); } - void paintHalo(QPainter *painter) - { - painter->save(); - - QBrush brush; - brush.setStyle(Qt::SolidPattern); - brush.setColor(QColor(0, 0, 0, 20)); - painter->setBrush(brush); - painter->setPen(Qt::NoPen); - - painter->setRenderHint(QPainter::Antialiasing); - - qreal size = THUMB_OUTER_SIZE * haloScaleFactor; - - QRectF halo(0, 0, size, size); - halo.moveCenter(thumbGeometry().center()); - - painter->drawEllipse(halo); - - painter->restore(); - } - void paintThumb(QPainter *painter) { + painter->drawRect(thumbGeometry().adjusted(0, 0, -1, -1)); + + /* painter->save(); QBrush brush; brush.setStyle(Qt::SolidPattern); - brush.setColor(QColor(0, 0, 0, 255)); + brush.setColor(thumbColor); painter->setBrush(brush); + if (thumbPenWidth) { + QPen pen; + pen.setWidthF(thumbPenWidth); + painter->setPen(pen); + } else { + painter->setPen(Qt::NoPen); + } + painter->setRenderHint(QPainter::Antialiasing); - QRectF thumb(0, 0, 11, 11); + QRectF thumb(0, 0, thumbSize, thumbSize); thumb.moveCenter(thumbGeometry().center()); painter->drawEllipse(thumb); @@ -131,6 +337,7 @@ public: painter->restore(); } #endif + */ } int valueFromPosition(const QPoint &pos) const @@ -152,13 +359,16 @@ public: } Slider *const q_ptr; - - QSequentialAnimationGroup *const haloAnimation; - qreal haloScaleFactor; - bool hoverTrack; - bool hoverThumb; - bool step; - int stepTo; + Halo *const halo; + QStateMachine machine; + bool hoverTrack; + bool hoverThumb; + bool step; + int stepTo; + int oldValue; + qreal thumbSize; + qreal thumbPenWidth; + QColor thumbColor; }; #endif // SLIDER_P_H diff --git a/examples/sliderexamples.cpp b/examples/sliderexamples.cpp index 0e4768e..c7a4f76 100644 --- a/examples/sliderexamples.cpp +++ b/examples/sliderexamples.cpp @@ -13,7 +13,8 @@ SliderExamples::SliderExamples(QWidget *parent) _edit(new QLineEdit), _edit2(new QLineEdit), _slider(new Slider), - _slider2(new Slider) + _slider2(new Slider), + __slider(new QSlider) { QLayout *mainLayout = widget()->layout(); @@ -82,7 +83,7 @@ SliderExamples::SliderExamples(QWidget *parent) QPushButton *button = new QPushButton("Change orientation"); - _slider->setMinimumWidth(250); + //_slider->setMinimumWidth(250); layout->addWidget(_slider); layout->addWidget(button); @@ -105,6 +106,29 @@ SliderExamples::SliderExamples(QWidget *parent) widget->setLayout(layout); widget->setMinimumWidth(350); + QPushButton *button = new QPushButton("Change orientation"); + + //__slider->setMinimumWidth(250); + layout->addWidget(__slider); + layout->addWidget(button); + + ExampleView *view = new ExampleView; + view->setWidget(widget); + + Frame *frame = new Frame; + frame->setCodeSnippet("xxx"); + frame->setWidget(view); + + mainLayout->addWidget(frame); + + connect(button, SIGNAL(pressed()), this, SLOT(flip2())); + } + { + QVBoxLayout *layout = new QVBoxLayout; + QWidget *widget = new QWidget; + widget->setLayout(layout); + widget->setMinimumWidth(350); + QHBoxLayout *hLayout = new QHBoxLayout; QPushButton *button = new QPushButton("Update value"); hLayout->addWidget(_edit2); @@ -166,6 +190,12 @@ void SliderExamples::flip() Qt::Vertical : Qt::Horizontal); } +void SliderExamples::flip2() +{ + __slider->setOrientation(Qt::Horizontal == __slider->orientation() ? + Qt::Vertical : Qt::Horizontal); +} + void SliderExamples::updateSliderValue() { _slider2->setValue(_edit2->text().toInt()); diff --git a/examples/sliderexamples.h b/examples/sliderexamples.h index 92c565a..13c4b2a 100644 --- a/examples/sliderexamples.h +++ b/examples/sliderexamples.h @@ -4,6 +4,7 @@ #include "examplelist.h" class QLineEdit; +class QSlider; class Slider; class SliderExamples : public ExampleList @@ -17,6 +18,7 @@ public: protected slots: void updateValue(int value); void flip(); + void flip2(); void updateSliderValue(); private: @@ -24,6 +26,7 @@ private: QLineEdit *const _edit2; Slider *const _slider; Slider *const _slider2; + QSlider *const __slider; }; #endif // SLIDEREXAMPLES_H