6#include "QskHintAnimator.h"
7#include "QskAnimationHint.h"
21static inline qreal qskAligned05( qreal value )
24 return qRound( 2.0 * value ) / 2.0;
27static inline QSizeF qskAligned05(
const QSizeF& size )
29 return QSizeF( qskAligned05( size.width() ), qskAligned05( size.height() ) );
34 const qreal left = qskAligned05( margins.left() );
35 const qreal top = qskAligned05( margins.top() );
36 const qreal right = qskAligned05( margins.right() );
37 const qreal bottom = qskAligned05( margins.bottom() );
42static inline QVariant qskAligned05(
const QVariant& value )
48 if ( metrics.sizeMode() == Qt::AbsoluteSize )
50 metrics.setWidths( qskAligned05( metrics.widths() ) );
51 return QVariant::fromValue( metrics );
57 if ( metrics.sizeMode() == Qt::AbsoluteSize )
59 for (
int i = Qt::TopLeftCorner; i <= Qt::BottomRightCorner; i++ )
61 const auto corner =
static_cast< Qt::Corner
>( i );
62 metrics.setRadius( corner, qskAligned05( metrics.radius( corner ) ) );
65 return QVariant::fromValue( metrics );
70 const auto margins = value.value<
QskMargins >();
71 return QVariant::fromValue( qskAligned05( margins ) );
79static inline void qskSendAnimatorEvent(
80 const QskAspect aspect,
int index,
bool on, QObject* receiver )
82 const auto state = on ? QskAnimatorEvent::Started : QskAnimatorEvent::Terminated;
84 const auto thread = receiver->thread();
85 if ( thread && ( thread != QThread::currentThread() ) )
94 QCoreApplication::postEvent( receiver, event );
99 QCoreApplication::sendEvent( receiver, &event );
103QskHintAnimator::QskHintAnimator() noexcept
108QskHintAnimator::QskHintAnimator(
const QskAspect aspect,
int index ) noexcept
114QskHintAnimator::~QskHintAnimator()
118void QskHintAnimator::setAspect(
const QskAspect aspect )
noexcept
123void QskHintAnimator::setIndex(
int index )
noexcept
128void QskHintAnimator::setUpdateFlags( QskAnimationHint::UpdateFlags flags )
noexcept
130 m_updateFlags = flags;
133void QskHintAnimator::setControl(
QskControl* control )
noexcept
138void QskHintAnimator::advance( qreal progress )
140 const auto oldValue = currentValue();
142 Inherited::advance( progress );
145 setCurrentValue( qskAligned05( currentValue() ) );
148 if ( m_control && ( currentValue() != oldValue ) )
150 if ( m_updateFlags == QskAnimationHint::UpdateAuto )
154 m_control->resetImplicitSize();
156 if ( !m_control->childItems().isEmpty() )
164 if ( m_updateFlags & QskAnimationHint::UpdateSizeHint )
165 m_control->resetImplicitSize();
167 if ( m_updateFlags & QskAnimationHint::UpdatePolish )
170 if ( m_updateFlags & QskAnimationHint::UpdateNode )
176#ifndef QT_NO_DEBUG_STREAM
182 QDebugStateSaver saver( debug );
185 debug <<
"Animator" <<
"( ";
187 debug << animator.aspect() <<
", " << animator.endValue().typeName() <<
", ";
189 if ( animator.index() >= 0 )
190 debug << animator.index() <<
", ";
192 if ( animator.isRunning() )
193 debug <<
"R: " << animator.duration() <<
", " << animator.elapsed();
195 debug <<
"S" << animator.duration();
197 if (
auto control = animator.control() )
198 debug <<
", " << control->className() <<
", " << (
void*) control;
209 class AnimatorMap :
public std::vector< QskHintAnimator* >
219 const Key key { aspect, index };
221 auto it = std::lower_bound( cbegin(), cend(), key, lessThan );
224 if ( ( ( *it )->aspect() == aspect ) && ( ( *it )->index() == index ) )
233 const Key key { aspect, index };
235 auto it = std::lower_bound( begin(), end(), key, lessThan );
236 if ( it == end() || ( *it )->aspect() != aspect || ( *it )->index() != index )
251 static inline bool lessThan(
const QskHintAnimator* animator,
const Key& key )
253 if ( animator->aspect() == key.aspect )
254 return animator->index() < key.index;
256 return animator->aspect() < key.aspect;
260 class AnimatorGuard final :
public QObject
267 QskAnimator::addCleanupHandler(
this,
268 SLOT(cleanup()), Qt::QueuedConnection );
273 auto it = std::lower_bound( m_tables.begin(), m_tables.end(), table );
274 if ( it == m_tables.end() || *it != table )
275 m_tables.insert( it, table );
280 auto it = std::lower_bound( m_tables.begin(), m_tables.end(), table );
281 if ( it != m_tables.end() && *it == table )
282 m_tables.erase( it );
288 for (
auto it = m_tables.begin(); it != m_tables.end(); )
290 if ( ( *it )->cleanup() )
291 it = m_tables.erase( it );
299 std::vector< QskHintAnimatorTable* > m_tables;
302 Q_GLOBAL_STATIC( AnimatorGuard, qskAnimatorGuard )
305class QskHintAnimatorTable::PrivateData
308 AnimatorMap animators;
311QskHintAnimatorTable::QskHintAnimatorTable()
315QskHintAnimatorTable::~QskHintAnimatorTable()
317 if ( qskAnimatorGuard )
318 qskAnimatorGuard->unregisterTable(
this );
323void QskHintAnimatorTable::start(
QskControl* control,
325 const QVariant& from,
const QVariant& to )
327 if ( m_data ==
nullptr )
329 m_data =
new PrivateData();
331 if ( qskAnimatorGuard )
332 qskAnimatorGuard->registerTable(
this );
335 auto animator = m_data->animators.findOrInsert( aspect, index );
337 animator->setStartValue( from );
338 animator->setEndValue( to );
340 animator->setDuration( animationHint.duration );
341 animator->setEasingCurve( animationHint.type );
342 animator->setUpdateFlags( animationHint.updateFlags );
344 animator->setControl( control );
345 animator->setWindow( control->window() );
349 qskSendAnimatorEvent( aspect, index,
true, control );
355 return m_data->animators.find( aspect, index );
360QVariant QskHintAnimatorTable::currentValue(
QskAspect aspect,
int index )
const
364 if (
auto animator = m_data->animators.find( aspect, index ) )
366 if ( animator->isRunning() )
367 return animator->currentValue();
374bool QskHintAnimatorTable::cleanup()
376 if ( m_data ==
nullptr )
379 auto& animators = m_data->animators;
381 for (
auto it = animators.begin(); it != animators.end(); )
386 if ( !animator->isRunning() )
388 const auto control = animator->control();
389 const auto aspect = animator->aspect();
390 const auto index = animator->index();
394 it = animators.erase( it );
397 qskSendAnimatorEvent( aspect, index,
false, control );
405 if ( animators.empty() )
416#include "QskHintAnimator.moc"
Lookup key for a QskSkinHintTable.
constexpr bool isColor() const noexcept
Base class of all controls.