6#include "QskStackBoxAnimator.h"
7#include "QskStackBox.h"
10#include "QskFunctions.h"
13#include <private/qquickitem_p.h>
18 class RotationTransform :
public QQuickTransform
23 RotationTransform( Qt::Axis axis, qreal radians, QQuickItem* item )
24 : QQuickTransform( item )
26 , m_radians( radians )
28 prependToItem( item );
31 void setRadians( qreal radians )
33 if ( m_radians != radians )
40 void applyTo( QMatrix4x4* matrix)
const override
42 if (
const auto item = qobject_cast< QQuickItem* >( parent() ) )
44 const auto dx = 0.5 * item->width();
45 const auto dy = 0.5 * item->height();
48 transform.translate( dx, dy );
49 transform.rotateRadians( m_radians, m_axis );
50 transform.translate( -dx, -dy );
57 const Qt::Axis m_axis;
61 class QuickTransform final :
public QQuickTransform
66 QuickTransform( QQuickItem* item )
67 : QQuickTransform( item )
69 prependToItem( item );
72 void setTransform(
const QTransform& transform )
74 if ( transform != m_transform )
76 m_transform = transform;
81 void applyTo( QMatrix4x4* matrix )
const override
83 if (
const auto item = qobject_cast< QQuickItem* >( parent() ) )
84 *matrix *= m_transform;
88 QTransform m_transform;
91 template<
typename Transform >
92 Transform* qskFindTransform(
const QQuickItem* item )
94 const auto& transforms = QQuickItemPrivate::get( item )->transforms;
95 for (
const auto& t : transforms )
97 if (
auto transform = qobject_cast< Transform* >( t ) )
105QskStackBoxAnimator::QskStackBoxAnimator(
QskStackBox* parent )
112QskStackBoxAnimator::~QskStackBoxAnimator()
116void QskStackBoxAnimator::setStartIndex(
int index )
118 m_transientIndex = m_startIndex = index;
121void QskStackBoxAnimator::setEndIndex(
int index )
126int QskStackBoxAnimator::startIndex()
const
131int QskStackBoxAnimator::endIndex()
const
141QQuickItem* QskStackBoxAnimator::itemAt(
int index )
const
143 return stackBox()->itemAtIndex(
144 ( index == 0 ) ? m_startIndex : m_endIndex );
147qreal QskStackBoxAnimator::transientIndex()
const
149 return m_transientIndex;
152void QskStackBoxAnimator::advance( qreal progress )
154 qreal transientIndex;
156 if ( qFuzzyIsNull( progress ) )
158 transientIndex = m_startIndex;
160 else if ( qFuzzyCompare( progress, 1.0 ) )
162 transientIndex = m_endIndex;
166 const auto box = stackBox();
168 auto startIndex = m_startIndex;
169 auto endIndex = m_endIndex;
171 if ( startIndex == 0 )
173 if ( endIndex == box->itemCount() - 1 )
174 startIndex += box->itemCount();
176 else if ( startIndex == box->itemCount() - 1 )
179 endIndex += box->itemCount();
182 transientIndex = startIndex + ( endIndex - startIndex ) * progress;
185 if ( !qskFuzzyCompare( m_transientIndex, transientIndex ) )
187 m_transientIndex = transientIndex;
188 advanceIndex( progress );
190 Q_EMIT stackBox()->transientIndexChanged( m_transientIndex );
194QskStackBoxAnimator1::QskStackBoxAnimator1(
QskStackBox* parent )
203QskStackBoxAnimator1::~QskStackBoxAnimator1()
207void QskStackBoxAnimator1::setDirection(
Qsk::Direction direction )
209 if ( m_direction != direction )
212 m_direction = direction;
221void QskStackBoxAnimator1::setup()
223 auto stackBox = this->stackBox();
225 m_hasClip = stackBox->clip();
227 stackBox->setClip(
true );
229 stackBox->installEventFilter(
this );
233void QskStackBoxAnimator1::advanceIndex( qreal value )
235 auto stackBox = this->stackBox();
240 for (
int i = 0; i < 2; i++ )
242 if (
auto item = itemAt( i ) )
244 QRectF rect = qskItemGeometry( item );
248 const int index = ( i == 0 ) ? startIndex() : endIndex();
249 rect = stackBox->geometryForItemAt( index );
251 m_itemOffset[ i ] = isHorizontal ? rect.x() : rect.y();
258 qreal off = stackBox->width() * ( value - i );
262 x = m_itemOffset[ i ] + off;
267 qreal off = stackBox->height() * ( value - i );
272 y = m_itemOffset[ i ] + off;
275 qskSetItemGeometry( item, x, y, rect.width(), rect.height() );
277 if ( !item->isVisible() )
278 item->setVisible(
true );
285void QskStackBoxAnimator1::done()
287 for (
int i = 0; i < 2; i++ )
289 if (
auto item = itemAt( i ) )
291 item->removeEventFilter(
this );
292 item->setVisible( i == 1 );
297 stackBox()->setClip(
false );
300bool QskStackBoxAnimator1::eventFilter( QObject*
object, QEvent* event )
302 if ( !m_isDirty &&
object == stackBox() )
304 switch(
static_cast< int >( event->type() ) )
306 case QskEvent::GeometryChange:
307 case QskEvent::ContentsRectChange:
308 case QskEvent::LayoutRequest:
316 return QObject::eventFilter(
object, event );
319QskStackBoxAnimator2::QskStackBoxAnimator2(
QskStackBox* parent )
321 , m_orientation( Qt::Horizontal )
322 , m_inverted( false )
326QskStackBoxAnimator2::~QskStackBoxAnimator2()
330void QskStackBoxAnimator2::setOrientation( Qt::Orientation orientation )
332 if ( m_orientation != orientation )
335 m_orientation = orientation;
339Qt::Orientation QskStackBoxAnimator2::orientation()
const
341 return m_orientation;
344void QskStackBoxAnimator2::setInverted(
bool on )
346 if ( m_inverted != on )
353bool QskStackBoxAnimator2::isInverted()
const
358void QskStackBoxAnimator2::setup()
360 const auto axis = ( m_orientation == Qt::Horizontal )
361 ? Qt::YAxis : Qt::XAxis;
363 if (
auto item = itemAt( 0 ) )
364 ( void )
new RotationTransform( axis, 0.0, item );
366 if (
auto item = itemAt( 1 ) )
367 (
void )
new RotationTransform( axis, M_PI_2, item );
370void QskStackBoxAnimator2::advanceIndex( qreal value )
372 auto radians = value * M_PI;
374 if ( radians < M_PI_2 && radians > -M_PI_2 )
376 if (
auto item = itemAt( 0 ) )
379 radians = 2 * M_PI - radians;
381 auto rotation = qskFindTransform< RotationTransform >( item );
382 rotation->setRadians( radians );
384 item->setVisible(
true );
387 if (
auto item = itemAt( 1 ) )
389 item->setVisible(
false );
394 if (
auto item = itemAt( 0 ) )
396 item->setVisible(
false );
399 if (
auto item = itemAt( 1 ) )
401 radians = radians - M_PI;
403 radians = 2 * M_PI - radians;
405 auto rotation = qskFindTransform< RotationTransform >( item );
406 rotation->setRadians( radians );
408 item->setVisible(
true );
413void QskStackBoxAnimator2::done()
415 for (
int i = 0; i < 2; i++ )
417 if (
auto item = itemAt( i ) )
419 delete qskFindTransform< RotationTransform >( item );
420 item->setVisible( i == 1 );
425QskStackBoxAnimator3::QskStackBoxAnimator3(
QskStackBox* parent )
430QskStackBoxAnimator3::~QskStackBoxAnimator3()
434void QskStackBoxAnimator3::setup()
436 if (
auto item = itemAt( 1 ) )
438 item->setOpacity( 0.0 );
439 item->setVisible(
true );
443void QskStackBoxAnimator3::advanceIndex( qreal value )
445 if (
auto item1 = itemAt( 0 ) )
446 item1->setOpacity( 1.0 - value );
448 if (
auto item2 = itemAt( 1 ) )
449 item2->setOpacity( value );
452void QskStackBoxAnimator3::done()
454 for (
int i = 0; i < 2; i++ )
456 if (
auto item = itemAt( i ) )
458 item->setOpacity( 1.0 );
459 item->setVisible( i == 1 );
464QskStackBoxAnimator4::QskStackBoxAnimator4(
QskStackBox* parent )
466 , m_orientation( Qt::Horizontal )
467 , m_inverted( false )
471QskStackBoxAnimator4::~QskStackBoxAnimator4()
475void QskStackBoxAnimator4::setOrientation( Qt::Orientation orientation )
477 if ( m_orientation != orientation )
480 m_orientation = orientation;
484Qt::Orientation QskStackBoxAnimator4::orientation()
const
486 return m_orientation;
489void QskStackBoxAnimator4::setInverted(
bool on )
491 if ( m_inverted != on )
498bool QskStackBoxAnimator4::isInverted()
const
503void QskStackBoxAnimator4::setup()
505 if (
auto item = itemAt( 0 ) )
507 ( void )
new QuickTransform( item );
508 item->setVisible(
true );
511 if (
auto item = itemAt( 1 ) )
513 ( void )
new QuickTransform( item );
514 item->setVisible(
true );
518void QskStackBoxAnimator4::advanceIndex( qreal value )
520 auto item1 = itemAt( 1 );
521 auto item2 = itemAt( 0 );
524 std::swap( item1, item2 );
526 const qreal posEdge = isInverted() ? value : 1.0 - value;
530 const auto transform = transformation( item1,
false, posEdge );
532 auto rotation = qskFindTransform< QuickTransform >( item1 );
533 rotation->setTransform( transform );
538 const auto transform = transformation( item2,
true, posEdge );
540 auto rotation = qskFindTransform< QuickTransform >( item2 );
541 rotation->setTransform( transform );
545QTransform QskStackBoxAnimator4::transformation(
546 const QQuickItem* item,
bool first, qreal posEdge )
const
554 const qreal radians = M_PI_2 * ( 1.0 - posEdge );
556 QTransform transform;
558 if( orientation() == Qt::Horizontal )
560 const qreal dx = posEdge * ( item->x() + item->width() );
561 const qreal dy = 0.5 * item->height();
565 transform.translate( -item->x() + dx, dy );
566 transform.rotateRadians( radians, Qt::YAxis );
567 transform.translate( -item->width(), -dy );
571 transform.translate( dx, dy );
572 transform.rotateRadians( radians - M_PI_2, Qt::YAxis );
573 transform.translate( 0.0, -dy );
578 const qreal dx = 0.5 * item->width();
579 const qreal dy = posEdge * ( item->y() + item->height() );
583 transform.translate( dx, -item->y() + dy );
584 transform.rotateRadians( radians, Qt::XAxis );
585 transform.translate( -dx, -item->height() );
589 transform.translate( dx, dy );
590 transform.rotateRadians( radians - M_PI_2, Qt::XAxis );
591 transform.translate( -dx, 0.0 );
598void QskStackBoxAnimator4::done()
600 for (
int i = 0; i < 2; i++ )
602 if (
auto item = itemAt( i ) )
604 delete qskFindTransform< QuickTransform >( item );
605 item->setVisible( i == 1 );
610#include "moc_QskStackBoxAnimator.cpp"
611#include "QskStackBoxAnimator.moc"
Direction
This enum type specifies a horizontal ot vertical direction.