diff --git a/kstyle/animations/breezecheckboxdata.cpp b/kstyle/animations/breezecheckboxdata.cpp index 2752c8c5..ca7c573e 100644 --- a/kstyle/animations/breezecheckboxdata.cpp +++ b/kstyle/animations/breezecheckboxdata.cpp @@ -1,142 +1,164 @@ /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include "breezecheckboxdata.h" namespace Breeze { const CheckBoxRenderState CheckBoxData::offState { /* Position */ QPointF(0, 0), /* LinePointPosition */ invalidPointF, invalidPointF, invalidPointF, /* PointPosition */ invalidPointF, invalidPointF, invalidPointF, /* PointRadius */ 0.0f, 0.0f, 0.0f }; const CheckBoxRenderState CheckBoxData::onState { /* Position */ QPointF(-1, 3), /* LinePointPosition */ QPointF(-3, -3), QPointF(0, 0), QPointF(5, -5), /* PointPosition */ invalidPointF, invalidPointF, invalidPointF, /* PointRadius */ 0.0f, 0.0f, 0.0f, }; const CheckBoxRenderState CheckBoxData::partialState { /* Position */ QPointF(0, 0), /* LinePointPosition */ invalidPointF, invalidPointF, invalidPointF, /* PointPosition */ QPointF(-4, 0), QPointF( 0, 0), QPointF(4, 0), /* PointRadius */ 1.0f, 1.0f, 1.0f, }; const TimelineAnimation::EntryList CheckBoxData::offToOnTransition { {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::offState; }}, {0.0f, "position", CheckBoxData::onState.position}, {0.0f, "linePointPosition0", CheckBoxData::onState.linePointPosition0}, {0.0f, 0.4f, "linePointPosition1", CheckBoxData::onState.linePointPosition0, CheckBoxData::onState.linePointPosition1, QEasingCurve::InOutCubic}, {0.5f, 0.5f, "linePointPosition2", CheckBoxData::onState.linePointPosition1, CheckBoxData::onState.linePointPosition2, QEasingCurve::InOutCubic}, {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::onState; }}, }; const TimelineAnimation::EntryList CheckBoxData::onToOffTransition { {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::onState; }}, {0.0f, 0.5f, "linePointPosition0", CheckBoxData::onState.linePointPosition0, CheckBoxData::onState.linePointPosition1, QEasingCurve::InOutCubic}, {0.6f, 0.4f, "linePointPosition0", CheckBoxData::onState.linePointPosition1, CheckBoxData::onState.linePointPosition2, QEasingCurve::InOutCubic}, {0.6f, 0.4f, "linePointPosition1", CheckBoxData::onState.linePointPosition1, CheckBoxData::onState.linePointPosition2, QEasingCurve::InOutCubic}, {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::offState; }}, }; const TimelineAnimation::EntryList CheckBoxData::offToPartialTransition { {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::offState; }}, {0.0f, "pointPosition0", CheckBoxData::partialState.pointPosition0}, {0.0f, "pointPosition1", CheckBoxData::partialState.pointPosition1}, {0.0f, "pointPosition2", CheckBoxData::partialState.pointPosition2}, {0.0f, 0.6f, "pointRadius0", QVariant(), CheckBoxData::partialState.pointRadius0, QEasingCurve::OutCubic}, {0.2f, 0.6f, "pointRadius1", QVariant(), CheckBoxData::partialState.pointRadius1, QEasingCurve::OutCubic}, {0.4f, 0.6f, "pointRadius2", QVariant(), CheckBoxData::partialState.pointRadius2, QEasingCurve::OutCubic}, {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::partialState; }}, }; const TimelineAnimation::EntryList CheckBoxData::partialToOffTransition { {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::partialState; }}, {0.0f, 0.6f, "pointRadius0", CheckBoxData::partialState.pointRadius0, CheckBoxData::offState.pointRadius0, QEasingCurve::InCubic}, {0.2f, 0.6f, "pointRadius1", CheckBoxData::partialState.pointRadius1, CheckBoxData::offState.pointRadius1, QEasingCurve::InCubic}, {0.4f, 0.6f, "pointRadius2", CheckBoxData::partialState.pointRadius2, CheckBoxData::offState.pointRadius2, QEasingCurve::InCubic}, {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::offState; }}, }; static const float partialPointRadiusSqrt2 = CheckBoxData::partialState.pointRadius0 * sqrtf(2); static const float partialPointRadiusSqrt3 = CheckBoxData::partialState.pointRadius0 * sqrtf(3); static const QPointF onStateAbsLinePointPosition2 = CheckBoxData::onState.linePointPosition2 + CheckBoxData::onState.position; const TimelineAnimation::EntryList CheckBoxData::partialToOnTransition { {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::partialState; }}, {0.0f, 0.5f, "pointPosition0", CheckBoxData::partialState.pointPosition0, CheckBoxData::partialState.pointPosition1, QEasingCurve::InOutCubic}, {0.0f, 0.5f, "pointPosition2", CheckBoxData::partialState.pointPosition2, CheckBoxData::partialState.pointPosition1, QEasingCurve::InOutCubic}, {0.0f, 0.5f, "pointRadius0", CheckBoxData::partialState.pointRadius0, partialPointRadiusSqrt3, QEasingCurve::InOutCubic}, {0.0f, 0.5f, "pointRadius1", CheckBoxData::partialState.pointRadius1, partialPointRadiusSqrt3, QEasingCurve::InOutCubic}, {0.0f, 0.5f, "pointRadius2", CheckBoxData::partialState.pointRadius2, partialPointRadiusSqrt3, QEasingCurve::InOutCubic}, {0.5f, "pointPosition0", invalidPointF}, {0.5f, "pointPosition2", invalidPointF}, {0.6f, 0.4f, "position", CheckBoxData::partialState.position, CheckBoxData::onState.position, QEasingCurve::InOutCubic}, {0.6f, 0.4f, "pointPosition1", CheckBoxData::partialState.pointPosition1, CheckBoxData::onState.position, QEasingCurve::InOutCubic}, {0.6f, 0.4f, "pointRadius1", partialPointRadiusSqrt3, CheckBoxData::onState.pointRadius1, QEasingCurve::InOutCubic}, {0.6f, "linePointPosition1", CheckBoxData::onState.linePointPosition1}, {0.6f, 0.4f, "linePointPosition0", CheckBoxData::onState.linePointPosition1, CheckBoxData::onState.linePointPosition0, QEasingCurve::InOutCubic}, {0.6f, 0.4f, "linePointPosition2", CheckBoxData::onState.linePointPosition1, CheckBoxData::onState.linePointPosition2, QEasingCurve::InOutCubic}, {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::onState; }}, }; const TimelineAnimation::EntryList CheckBoxData::onToPartialTransition { {0.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::onState; }}, {0.0f, 0.4f, "position", QVariant(), CheckBoxData::partialState.position, QEasingCurve::InOutCubic}, {0.0f, 0.4f, "linePointPosition0", QVariant(), CheckBoxData::onState.linePointPosition1, QEasingCurve::InOutCubic}, {0.0f, 0.4f, "linePointPosition2", QVariant(), CheckBoxData::onState.linePointPosition1, QEasingCurve::InOutCubic}, {0.0f, 0.4f, "pointPosition1", CheckBoxData::onState.position, CheckBoxData::partialState.pointPosition1, QEasingCurve::InOutCubic}, {0.0f, 0.4f, "pointRadius1", QVariant(), partialPointRadiusSqrt3, QEasingCurve::InOutCubic}, {0.5f, 0.5f, "pointPosition0", CheckBoxData::partialState.pointPosition1, CheckBoxData::partialState.pointPosition0, QEasingCurve::InOutCubic}, {0.5f, 0.5f, "pointPosition2", CheckBoxData::partialState.pointPosition1, CheckBoxData::partialState.pointPosition2, QEasingCurve::InOutCubic}, {0.5f, 0.5f, "pointRadius0", partialPointRadiusSqrt3, CheckBoxData::partialState.pointRadius0, QEasingCurve::InOutCubic}, {0.5f, 0.5f, "pointRadius1", partialPointRadiusSqrt3, CheckBoxData::partialState.pointRadius1, QEasingCurve::InOutCubic}, {0.5f, 0.5f, "pointRadius2", partialPointRadiusSqrt3, CheckBoxData::partialState.pointRadius2, QEasingCurve::InOutCubic}, {1.0f, [](void *renderState) { *static_cast(renderState) = CheckBoxData::partialState; }}, }; //______________________________________________ bool CheckBoxData::updateState( CheckBoxState value ) { if( !_initialized ) { - _state = value; _initialized = true; + + renderState = *renderStateForState(_state); + return false; } else if( _state == value ) { return false; } else { _previousState = _state; _state = value; animation().data()->setDirection(Animation::Forward); + + timeline->stop(); + if (_previousState == CheckOff && _state == CheckOn) { timeline->setTransitions(&CheckBoxData::offToOnTransition); } + if (_previousState == CheckOn && _state == CheckOff) { timeline->setTransitions(&CheckBoxData::onToOffTransition); } + if (_previousState == CheckOff && _state == CheckPartial) { timeline->setTransitions(&CheckBoxData::offToPartialTransition); } + if (_previousState == CheckPartial && _state == CheckOff) { timeline->setTransitions(&CheckBoxData::partialToOffTransition); } + if (_previousState == CheckPartial && _state == CheckOn) { timeline->setTransitions(&CheckBoxData::partialToOnTransition); } + if (_previousState == CheckOn && _state == CheckPartial) { timeline->setTransitions(&CheckBoxData::onToPartialTransition); } + timeline->start(); + if( !animation().data()->isRunning() ) animation().data()->start(); return true; } } + const CheckBoxRenderState * CheckBoxData::renderStateForState(CheckBoxState state) + { + switch(state) { + default: + case CheckOff: return &offState; + case CheckOn: return &onState; + case CheckPartial: return &partialState; + }; + } + } diff --git a/kstyle/animations/breezecheckboxdata.h b/kstyle/animations/breezecheckboxdata.h index eb096942..ac25ac04 100644 --- a/kstyle/animations/breezecheckboxdata.h +++ b/kstyle/animations/breezecheckboxdata.h @@ -1,348 +1,350 @@ #ifndef breezecheckboxdata_h #define breezecheckboxdata_h /************************************************************************* * Copyright (C) 2014 by Hugo Pereira Da Costa * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * *************************************************************************/ #include #include "breezegenericdata.h" namespace Breeze { #define declvaluetype(v) std::remove_reference::type //// //// //// //// /// /// /// // // / / / / static constexpr const qreal qrealQNaN {std::numeric_limits::quiet_NaN()}; // TODO: remove if unused anywhere but below static constexpr const QPointF invalidPointF {qrealQNaN, qrealQNaN}; static const auto isInvalidPointF = [](const QPointF &point) { return std::isnan(point.x()) && std::isnan(point.y()); }; struct CheckBoxRenderState { Q_GADGET Q_PROPERTY(QPointF position MEMBER position) Q_PROPERTY(QPointF linePointPosition0 MEMBER linePointPosition0) Q_PROPERTY(QPointF linePointPosition1 MEMBER linePointPosition1) Q_PROPERTY(QPointF linePointPosition2 MEMBER linePointPosition2) Q_PROPERTY(QPointF pointPosition0 MEMBER pointPosition0) Q_PROPERTY(QPointF pointPosition1 MEMBER pointPosition1) Q_PROPERTY(QPointF pointPosition2 MEMBER pointPosition2) Q_PROPERTY(qreal pointRadius0 MEMBER pointRadius0) Q_PROPERTY(qreal pointRadius1 MEMBER pointRadius1) Q_PROPERTY(qreal pointRadius2 MEMBER pointRadius2) public: QPointF position; QPointF linePointPosition0, linePointPosition1, linePointPosition2; QPointF pointPosition0, pointPosition1, pointPosition2; qreal pointRadius0, pointRadius1, pointRadius2; QString toString() const { QString str("CheckBoxRenderState {\n"); static const auto pointFToString = [](const QPointF &p)->QString { if (isInvalidPointF(p)) { return QStringLiteral("(InvalidPointF)"); } return QStringLiteral("{%1, %2}").arg(p.x()).arg(p.y()); }; str.append(QStringLiteral(" position = %1,\n").arg(pointFToString(position))); str.append(QStringLiteral(" linePointPosition = {%1, %2, %3},\n") .arg(pointFToString(linePointPosition0)) .arg(pointFToString(linePointPosition1)) .arg(pointFToString(linePointPosition2))); str.append(QStringLiteral(" pointPosition = {%1, %2, %3},\n") .arg(pointFToString(pointPosition0)) .arg(pointFToString(pointPosition1)) .arg(pointFToString(pointPosition2))); str.append(QStringLiteral(" pointRadius = {%1, %2, %3},\n") .arg(pointRadius0) .arg(pointRadius1) .arg(pointRadius2)); str.append("}"); return str; } }; class TimelineAnimation: public QAbstractAnimation { Q_OBJECT public: struct Entry { /**************************************/ using ActionFunc = void (*)(void *renderState); Entry(float relStartTime, ActionFunc action) : relStartTime(relStartTime) , relDuration(0) , action(action) {} Entry(float relStartTime, QByteArray propertyName, QVariant to) : relStartTime(relStartTime) , relDuration(0) , action(nullptr) , propertyName(std::move(propertyName)) , from(QVariant()) , to(std::move(to)) {} Entry(float relStartTime, float relDuration, QByteArray propertyName, QVariant from, QVariant to, QEasingCurve easingCurve) : relStartTime(relStartTime) , relDuration(relDuration) , action(nullptr) , propertyName(std::move(propertyName)) , from(std::move(from)) , to(std::move(to)) , easingCurve(std::move(easingCurve)) {} float relStartTime; float relDuration; ActionFunc action; QByteArray propertyName; QVariant from; QVariant to; QEasingCurve easingCurve; inline bool isSetter() const { return qFuzzyIsNull(relDuration) && !from.isValid(); } inline bool isStartingFromPreviousValue() const { return !from.isValid() && to.isValid(); } }; /*******************************************************/ using EntryList = QList; TimelineAnimation(QObject *parent, int durationMs, CheckBoxRenderState *data, const EntryList *transitions = nullptr) : QAbstractAnimation(parent) , _durationMs(durationMs) , _data(q_check_ptr(data)) { setTransitions(transitions); } void setDuration(int durationMs) { _durationMs = durationMs; } int duration() const override { return _durationMs; } void setTransitions(const EntryList *transitions) { stop(); _transitions = transitions; if(transitions != nullptr) { _transitionStates = QVector(transitions->size()); } else { _transitionStates.clear(); } } Q_SIGNALS: void valueChanged(); protected: void updateCurrentTime(int currentTime) override { if(_transitions == nullptr) { return; } bool changed = false; for (int i = 0; i < _transitions->size(); ++i) { const Entry &transition = (*_transitions)[i]; TransitionState &state = _transitionStates[i]; if (state.processed) { continue; } int absStartTime = qRound(transition.relStartTime * _durationMs); int absEndTime = qRound((transition.relStartTime + transition.relDuration) * _durationMs); if (transition.action != nullptr) { if (absEndTime <= currentTime) { transition.action(_data); state.processed = true; } continue; } int propertyIndex = _data->staticMetaObject.indexOfProperty(transition.propertyName); Q_ASSERT(propertyIndex >= 0); auto property = _data->staticMetaObject.property(propertyIndex); const QVariant value = property.readOnGadget(_data); if (absEndTime < currentTime) { // Already ended if (value != transition.to) { property.writeOnGadget(_data, transition.to); changed = true; } state.processed = true; } else if (absStartTime <= currentTime) { // Is running if (transition.isStartingFromPreviousValue() && !state.previousValue.isValid()) { state.previousValue = value; } const qreal transitionProgress = (qreal(currentTime)/_durationMs - transition.relStartTime) / transition.relDuration; const QVariant &from = transition.isStartingFromPreviousValue() ? state.previousValue : transition.from; const QVariant newValue = interpolate(from, transition.to, transition.easingCurve.valueForProgress(transitionProgress)); if (value != newValue) { property.writeOnGadget(_data, newValue); changed = true; } } else { // Too early break; } } if (changed) { emit valueChanged(); } } void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) override { Q_UNUSED(oldState); switch(newState) { case Running: for(auto &state: _transitionStates) { state = TransitionState(); } break; default: break; } } private: int _durationMs; template static ValueType interpolateGeneric(const QVariant &from, const QVariant &to, qreal progress) { const auto a = from.value(); const auto b = to.value(); return a * (1.0 - progress) + b * progress; } static QVariant interpolate(const QVariant &from, const QVariant &to, qreal progress) { switch(QMetaType::Type(from.type())) { case QMetaType::Int: return interpolateGeneric(from, to, progress); case QMetaType::UInt: return interpolateGeneric(from, to, progress); case QMetaType::LongLong: return interpolateGeneric(from, to, progress); case QMetaType::ULongLong: return interpolateGeneric(from, to, progress); case QMetaType::Float: return interpolateGeneric(from, to, progress); case QMetaType::Double: return interpolateGeneric(from, to, progress); case QMetaType::QPoint: return interpolateGeneric(from, to, progress); case QMetaType::QPointF: return interpolateGeneric(from, to, progress); default: qWarning("Interpolation not supported for type %s", from.typeName()); return to; } } struct TransitionState { QVariant previousValue {QVariant()}; bool processed {false}; }; CheckBoxRenderState *_data; const EntryList *_transitions; QVector _transitionStates; }; struct AbstractState { virtual QVariant get(unsigned id) = 0; virtual void set(unsigned id, const QVariant &value) = 0; }; struct CheckMarkState { QPointF position; QPointF linePointPosition[3]; QPointF pointPosition[3]; qreal pointRadius[3]; enum DataId: unsigned { Position, LinePointPosition_0, LinePointPosition_1, LinePointPosition_2, PointPosition_0, PointPosition_1, PointPosition_2, PointRadius_0, PointRadius_1, PointRadius_2, }; }; class CheckBoxData: public GenericData { Q_OBJECT public: //* constructor CheckBoxData( QObject* parent, QWidget* target, int duration, CheckBoxState state = CheckBoxState::CheckUnknown ): GenericData( parent, target, duration ), _initialized( false ), _state( state ), _previousState( CheckBoxState::CheckUnknown ), timeline(new TimelineAnimation(this, 250, &renderState)) { connect(timeline, &TimelineAnimation::valueChanged, target, QOverload<>::of(&QWidget::update)); } //* destructor ~CheckBoxData() override { timeline->stop(); } /** returns true if state has changed and starts timer accordingly */ virtual bool updateState( CheckBoxState value ); virtual CheckBoxState state() const { return _state; } virtual CheckBoxState previousState() const { return _previousState; } TimelineAnimation *timeline; static const CheckBoxRenderState offState; static const CheckBoxRenderState onState; static const CheckBoxRenderState partialState; + static const CheckBoxRenderState * renderStateForState(CheckBoxState state); + static const TimelineAnimation::EntryList offToOnTransition; static const TimelineAnimation::EntryList onToOffTransition; static const TimelineAnimation::EntryList offToPartialTransition; static const TimelineAnimation::EntryList partialToOffTransition; static const TimelineAnimation::EntryList partialToOnTransition; static const TimelineAnimation::EntryList onToPartialTransition; CheckBoxRenderState renderState; private: static void initTransitions(); bool _initialized; CheckBoxState _state; CheckBoxState _previousState; }; } #endif \ No newline at end of file diff --git a/kstyle/checkbox.cpp b/kstyle/checkbox.cpp index 5c3d09ef..5c8a372a 100644 --- a/kstyle/checkbox.cpp +++ b/kstyle/checkbox.cpp @@ -1,190 +1,155 @@ #include "breezestyle.h" #include "breeze.h" #include "breezeanimations.h" #include "breezecheckboxdata.h" #include #include #include #include #include #include #include #include #include namespace Breeze { static void renderCheckMark(QPainter *painter, const QPoint &position, const QColor &color, const CheckBoxRenderState &s) { painter->setBrush(Qt::NoBrush); painter->setPen(QPen(color, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); QPainterPath pp; const QPointF linePointPosition[] = {s.linePointPosition0, s.linePointPosition1, s.linePointPosition2}; const QPointF pointPosition[] = {s.pointPosition0, s.pointPosition1, s.pointPosition2}; const qreal pointRadius[] = {s.pointRadius0, s.pointRadius1, s.pointRadius2}; int i = 0; for(; i < 3; ++i) { if(!isInvalidPointF(linePointPosition[i])) { pp.moveTo(linePointPosition[i]); break; } } for(; i < 3; ++i) { if(!isInvalidPointF(linePointPosition[i])) { pp.lineTo(linePointPosition[i]); } } pp.translate(s.position + position); painter->drawPath(pp); painter->setPen(Qt::NoPen); for (int i = 0; i < 3; ++i) { if (isInvalidPointF(pointPosition[i]) || qFuzzyIsNull(pointRadius[i])) { continue; } painter->setBrush(color); painter->drawEllipse(pointPosition[i] + position, pointRadius[i], pointRadius[i]); } } //___________________________________________________________________________________ void Style::drawChoicePrimitive(const QStyleOption *option, QPainter *painter, const QWidget* widget, bool isRadioButton) const { // copy rect and palette const auto& rect( option->rect ); const auto& palette( option->palette ); // copy state const State& state( option->state ); const bool enabled( state & State_Enabled ); // State_Selected can be active in list and menu items const bool mouseOver( enabled && ( state & (State_MouseOver | State_Selected) ) ); const bool hasFocus( enabled && ( state & (State_HasFocus | State_Selected) ) ); const bool isChecked( state & State_On ); // focus takes precedence over mouse over _animations->widgetStateEngine().updateState( widget, AnimationFocus, hasFocus ); _animations->widgetStateEngine().updateState( widget, AnimationHover, mouseOver ); _animations->widgetStateEngine().updateState( widget, AnimationPressed, isChecked ); // Render background and frame // Foreground and background color const auto &normalBackground = palette.color(QPalette::Base); const auto &normalForeground = palette.color(QPalette::Text); const auto &checkedBackground = palette.color(QPalette::Highlight); const auto &checkedForeground = palette.color(QPalette::HighlightedText); const qreal stateOpacityOrInvalid = _animations->widgetStateEngine().opacity( widget, AnimationPressed ); const qreal stateOpacity = stateOpacityOrInvalid != AnimationData::OpacityInvalid ? stateOpacityOrInvalid : 1.0 * int(isChecked); const auto background = KColorUtils::mix(normalBackground, checkedBackground, stateOpacity); const auto foreground = KColorUtils::mix(normalForeground, checkedForeground, stateOpacity); // Frame color - hover priority const AnimationMode mode( _animations->widgetStateEngine().frameAnimationMode( widget ) ); const qreal opacity( _animations->widgetStateEngine().frameOpacity( widget ) ); QColor outline = _helper->frameOutlineColor(palette, mouseOver, hasFocus, opacity, mode, background); _helper->renderFrame( painter, rect.adjusted(0, 0, -0, -0), background, outline , isRadioButton); // Render mark static const auto inQuadEasingCurve = [](qreal v) { return v*v; }; static const auto outQuadEasingCurve = [](qreal v) { return 1.0-inQuadEasingCurve(1.0-v); }; painter->setRenderHint( QPainter::Antialiasing, true ); if(isRadioButton) { RadioButtonState radioButtonState = state & State_On ? RadioOn : RadioOff; if( _animations->widgetStateEngine().isAnimated( widget, AnimationPressed ) ) { radioButtonState = radioButtonState == RadioOn ? RadioOffToOn : RadioOnToOff; } if(radioButtonState == RadioOff) { return; } const QPointF center = {rect.x() + rect.width() / 2.0, rect.y() + rect.height() / 2.0}; const qreal fullRadius = 4.0; if(radioButtonState == RadioOn) { painter->setBrush( foreground ); painter->setPen( Qt::NoPen ); painter->drawEllipse(center, fullRadius, fullRadius); } else { const qreal radius = outQuadEasingCurve(stateOpacity) * fullRadius; painter->setBrush(foreground); painter->setPen( Qt::NoPen ); painter->drawEllipse(center, radius, radius); } } else { const CheckBoxState checkBoxState = state & State_NoChange ? CheckPartial : state & State_On ? CheckOn : CheckOff; bool startAnim = (checkBoxState != _animations->checkBoxEngine().state(widget)); _animations->checkBoxEngine().updateState(widget, checkBoxState); - - const CheckBoxState previousCheckBoxState = _animations->checkBoxEngine().previousState(widget); - - qreal progress = _animations->checkBoxEngine().progress(widget); - if(!_animations->checkBoxEngine().isAnimated(widget)) { - progress = 1.0; - } - - const QPoint centerOffset = {rect.width()/2 + rect.x(), rect.height()/2 + rect.y()}; - DataMap::Value dataPtr = _animations->checkBoxEngine().data(widget); - - static const auto stateToData = [](CheckBoxState state) -> const CheckBoxRenderState * { - switch(state) { - case CheckUnknown: - case CheckOff: return &CheckBoxData::offState; - case CheckOn: return &CheckBoxData::onState; - case CheckPartial: return &CheckBoxData::partialState; - }; - return nullptr; - }; - const CheckBoxRenderState *state = nullptr; if (dataPtr.isNull()) { - state = stateToData(checkBoxState); + state = CheckBoxData::renderStateForState(checkBoxState); Q_CHECK_PTR(state); } else { CheckBoxData *data = dataPtr.data(); state = &data->renderState; - if(previousCheckBoxState == CheckBoxState::CheckUnknown) { - // First rendering. Don't animate, it is initial state. - data->renderState = *q_check_ptr(stateToData(checkBoxState)); - } else { - if (startAnim) { - data->timeline->stop(); - if (previousCheckBoxState == CheckOff && checkBoxState == CheckOn) { data->timeline->setTransitions(&CheckBoxData::offToOnTransition); } - if (previousCheckBoxState == CheckOn && checkBoxState == CheckOff) { data->timeline->setTransitions(&CheckBoxData::onToOffTransition); } - if (previousCheckBoxState == CheckOff && checkBoxState == CheckPartial) { data->timeline->setTransitions(&CheckBoxData::offToPartialTransition); } - if (previousCheckBoxState == CheckPartial && checkBoxState == CheckOff) { data->timeline->setTransitions(&CheckBoxData::partialToOffTransition); } - if (previousCheckBoxState == CheckPartial && checkBoxState == CheckOn) { data->timeline->setTransitions(&CheckBoxData::partialToOnTransition); } - if (previousCheckBoxState == CheckOn && checkBoxState == CheckPartial) { data->timeline->setTransitions(&CheckBoxData::onToPartialTransition); } - data->timeline->start(); - } - } } + const QPoint centerOffset = {rect.width()/2 + rect.x(), rect.height()/2 + rect.y()}; renderCheckMark(painter, centerOffset, foreground, *state); } } }