#include "slider_internal.h" #include #include #include #include #include #include #include "lib/style.h" #include "slider.h" SliderStateMachine::SliderStateMachine(Slider *parent, SliderThumb *thumb, SliderTrack *track) : QStateMachine(parent) { Style &style = Style::instance(); QState *topState = new QState(QState::ParallelStates); QState *fstState = new QState(topState); QState *inactiveState = new QState(fstState); QState *focusState = new QState(fstState); QState *slidingState = new QState(fstState); QState *pulseOutState = new QState(focusState); QState *pulseInState = new QState(focusState); focusState->setInitialState(pulseOutState); inactiveState->assignProperty(thumb, "haloSize", 0); slidingState->assignProperty(thumb, "haloSize", 0); pulseOutState->assignProperty(thumb, "haloSize", 35); pulseInState->assignProperty(thumb, "haloSize", 28); inactiveState->assignProperty(thumb, "diameter", 11); focusState->assignProperty(thumb, "diameter", 11); slidingState->assignProperty(thumb, "diameter", 17); QColor fillColor = style.themeColor("primary1"); inactiveState->assignProperty(track, "fillColor", style.themeColor("accent3").lighter(130)); slidingState->assignProperty(track, "fillColor", style.themeColor("accent3")); focusState->assignProperty(track, "fillColor", style.themeColor("accent3")); addState(topState); fstState->setInitialState(inactiveState); setInitialState(topState); QAbstractTransition *transition; QPropertyAnimation *animation; // Show halo on mouse enter transition = new QSignalTransition(this, SIGNAL(noFocusMouseEnter())); transition->setTargetState(focusState); animation = new QPropertyAnimation(thumb, "haloSize"); animation->setEasingCurve(QEasingCurve::InOutSine); transition->addAnimation(animation); transition->addAnimation(new QPropertyAnimation(track, "fillColor")); inactiveState->addTransition(transition); // Show halo on focus in transition = new QEventTransition(parent, QEvent::FocusIn); transition->setTargetState(focusState); animation = new QPropertyAnimation(thumb, "haloSize"); animation->setEasingCurve(QEasingCurve::InOutSine); transition->addAnimation(animation); transition->addAnimation(new QPropertyAnimation(track, "fillColor")); inactiveState->addTransition(transition); // Hide halo on focus out transition = new QEventTransition(parent, QEvent::FocusOut); transition->setTargetState(inactiveState); animation = new QPropertyAnimation(thumb, "haloSize"); animation->setEasingCurve(QEasingCurve::InOutSine); transition->addAnimation(animation); transition->addAnimation(new QPropertyAnimation(track, "fillColor")); focusState->addTransition(transition); // Hide halo on mouse leave, except if widget has focus transition = new QSignalTransition(this, SIGNAL(noFocusMouseLeave())); transition->setTargetState(inactiveState); animation = new QPropertyAnimation(thumb, "haloSize"); animation->setEasingCurve(QEasingCurve::InOutSine); transition->addAnimation(animation); transition->addAnimation(new QPropertyAnimation(track, "fillColor")); focusState->addTransition(transition); // Pulse in transition = new QSignalTransition(pulseOutState, SIGNAL(propertiesAssigned())); transition->setTargetState(pulseInState); animation = new QPropertyAnimation(thumb, "haloSize"); animation->setEasingCurve(QEasingCurve::InOutSine); animation->setDuration(1000); transition->addAnimation(animation); pulseOutState->addTransition(transition); // Pulse out transition = new QSignalTransition(pulseInState, SIGNAL(propertiesAssigned())); transition->setTargetState(pulseOutState); animation = new QPropertyAnimation(thumb, "haloSize"); animation->setEasingCurve(QEasingCurve::InOutSine); animation->setDuration(1000); transition->addAnimation(animation); pulseInState->addTransition(transition); // Slider pressed transition = new QSignalTransition(parent, SIGNAL(sliderPressed())); transition->setTargetState(slidingState); animation = new QPropertyAnimation(thumb, "diameter"); animation->setDuration(70); transition->addAnimation(animation); animation = new QPropertyAnimation(thumb, "haloSize"); animation->setEasingCurve(QEasingCurve::InOutSine); transition->addAnimation(animation); focusState->addTransition(transition); // Slider released transition = new QSignalTransition(parent, SIGNAL(sliderReleased())); transition->setTargetState(focusState); animation = new QPropertyAnimation(thumb, "diameter"); animation->setDuration(70); transition->addAnimation(animation); animation = new QPropertyAnimation(thumb, "haloSize"); animation->setEasingCurve(QEasingCurve::InOutSine); transition->addAnimation(animation); slidingState->addTransition(transition); // Min. value transitions QState *sndState = new QState(topState); QState *minState = new QState(sndState); QState *normalState = new QState(sndState); QColor minHaloColor = style.themeColor("accent3"); minHaloColor.setAlphaF(0.15); QColor haloColor = style.themeColor("primary1"); haloColor.setAlphaF(0.15); QColor canvasColor = style.themeColor("canvas"); minState->assignProperty(thumb, "fillColor", canvasColor); minState->assignProperty(thumb, "haloColor", minHaloColor); minState->assignProperty(thumb, "borderColor", style.themeColor("accent3")); minState->assignProperty(thumb, "borderWidth", 2); normalState->assignProperty(thumb, "fillColor", fillColor); normalState->assignProperty(thumb, "haloColor", haloColor); normalState->assignProperty(thumb, "borderColor", fillColor); normalState->assignProperty(thumb, "borderWidth", 0); sndState->setInitialState(minState); transition = new QSignalTransition(this, SIGNAL(changedFromMinimum())); transition->setTargetState(normalState); animation = new QPropertyAnimation(thumb, "fillColor"); animation->setDuration(200); transition->addAnimation(animation); animation = new QPropertyAnimation(thumb, "haloColor"); animation->setDuration(200); transition->addAnimation(animation); animation = new QPropertyAnimation(thumb, "borderColor"); animation->setDuration(200); transition->addAnimation(animation); animation = new QPropertyAnimation(thumb, "borderWidth"); animation->setDuration(200); transition->addAnimation(animation); minState->addTransition(transition); transition = new QSignalTransition(this, SIGNAL(changedToMinimum())); transition->setTargetState(minState); animation = new QPropertyAnimation(thumb, "fillColor"); animation->setDuration(200); transition->addAnimation(animation); animation = new QPropertyAnimation(thumb, "haloColor"); animation->setDuration(200); transition->addAnimation(animation); animation = new QPropertyAnimation(thumb, "borderColor"); animation->setDuration(200); transition->addAnimation(animation); animation = new QPropertyAnimation(thumb, "borderWidth"); animation->setDuration(200); transition->addAnimation(animation); normalState->addTransition(transition); } SliderStateMachine::~SliderStateMachine() { } SliderThumb::SliderThumb(Slider *slider) : QWidget(slider->parentWidget()), slider(slider), _diameter(11), _borderWidth(2), _haloSize(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())); } SliderThumb::~SliderThumb() { } bool SliderThumb::eventFilter(QObject *obj, QEvent *event) { QEvent::Type type = event->type(); if (QEvent::ParentChange == type) { setParent(slider->parentWidget()); } else if (QEvent::Resize == type || QEvent::Move == type) { QWidget *widget; if ((widget = parentWidget())) { setGeometry(widget->rect()); } } return QWidget::eventFilter(obj, event); } void SliderThumb::paintEvent(QPaintEvent *event) { QPainter painter(this); // Halo QBrush brush; brush.setStyle(Qt::SolidPattern); brush.setColor(_haloColor); painter.setBrush(brush); painter.setPen(Qt::NoPen); painter.setRenderHint(QPainter::Antialiasing); QPointF disp = Qt::Horizontal == slider->orientation() ? QPointF(SLIDER_MARGIN + slider->thumbOffset(), slider->height()/2) : QPointF(slider->width()/2, SLIDER_MARGIN + slider->thumbOffset()); QRectF halo((slider->pos() - QPointF(_haloSize, _haloSize)/2) + disp, QSizeF(_haloSize, _haloSize)); painter.drawEllipse(halo); // Knob brush.setColor(slider->isEnabled() ? _fillColor : Style::instance().themeColor("disabled")); painter.setBrush(brush); if (slider->isEnabled()) { QPen pen; pen.setColor(_borderColor); pen.setWidthF(_borderWidth); painter.setPen(pen); } else { painter.setPen(Qt::NoPen); } QRectF geometry = Qt::Horizontal == slider->orientation() ? QRectF(slider->thumbOffset(), slider->height()/2 - SLIDER_MARGIN, SLIDER_MARGIN*2, SLIDER_MARGIN*2).translated(slider->pos()) : QRectF(slider->width()/2 - SLIDER_MARGIN, slider->thumbOffset(), SLIDER_MARGIN*2, SLIDER_MARGIN*2).translated(slider->pos()); qreal s = slider->isEnabled() ? _diameter : 7; QRectF thumb(0, 0, s, s); thumb.moveCenter(geometry.center()); painter.drawEllipse(thumb); #ifdef DEBUG_LAYOUT QPen pen; pen.setColor(Qt::red); pen.setWidth(2); painter.setPen(pen); painter.setBrush(Qt::NoBrush); painter.drawRect(geometry); painter.drawRect(rect().adjusted(0, 0, -2, -2)); #endif QWidget::paintEvent(event); } SliderTrack::SliderTrack(Slider *slider) : QWidget(slider->parentWidget()), slider(slider), _trackWidth(2) { slider->installEventFilter(this); setAttribute(Qt::WA_TransparentForMouseEvents, true); connect(slider, SIGNAL(sliderMoved(int)), this, SLOT(update())); } SliderTrack::~SliderTrack() { } bool SliderTrack::eventFilter(QObject *obj, QEvent *event) { QEvent::Type type = event->type(); if (QEvent::ParentChange == type) { setParent(slider->parentWidget()); } else if (QEvent::Resize == type || QEvent::Move == type) { if (parentWidget()) { setGeometry(parentWidget()->rect()); } } return QWidget::eventFilter(obj, event); } void SliderTrack::paintEvent(QPaintEvent *event) { QPainter painter(this); Style &style = Style::instance(); QBrush fg; fg.setStyle(Qt::SolidPattern); fg.setColor(slider->isEnabled() ? style.themeColor("primary1") : style.themeColor("disabled")); QBrush bg; bg.setStyle(Qt::SolidPattern); bg.setColor(slider->isEnabled() ? _fillColor : style.themeColor("disabled")); painter.setRenderHint(QPainter::Antialiasing); qreal offset = slider->thumbOffset(); if (Qt::Horizontal == slider->orientation()) { painter.translate(slider->x() + SLIDER_MARGIN, slider->y() + slider->height()/2 - static_cast(_trackWidth)/2); } else { painter.translate(slider->x() + slider->width()/2 - static_cast(_trackWidth)/2, slider->y() + SLIDER_MARGIN); } QRectF geometry = Qt::Horizontal == slider->orientation() ? QRectF(0, 0, slider->width() - SLIDER_MARGIN*2, _trackWidth) : QRectF(0, 0, _trackWidth, slider->height() - SLIDER_MARGIN*2); QRectF bgRect; QRectF fgRect; if (Qt::Horizontal == slider->orientation()) { fgRect = QRectF(0, 0, offset, _trackWidth); bgRect = QRectF(offset, 0, slider->width(), _trackWidth).intersected(geometry); } else { fgRect = QRectF(0, 0, _trackWidth, offset); bgRect = QRectF(0, offset, _trackWidth, slider->height()).intersected(geometry); } if (!slider->isEnabled()) { fgRect = fgRect.width() < 9 ? QRectF() : fgRect.adjusted(0, 0, -6, 0); bgRect = bgRect.width() < 9 ? QRectF() : bgRect.adjusted(6, 0, 0, 0); } if (slider->invertedAppearance()) { qSwap(bgRect, fgRect); } painter.fillRect(bgRect, bg); painter.fillRect(fgRect, fg); #ifdef DEBUG_LAYOUT if (slider->hovered()) { painter.save(); painter.setPen(Qt::red); painter.drawRect(geometry); painter.restore(); } #endif QWidget::paintEvent(event); }