2017-07-21 18:21:34 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskStackBoxAnimator.h"
|
|
|
|
#include "QskStackBox.h"
|
2019-06-19 14:08:45 +02:00
|
|
|
#include "QskEvent.h"
|
|
|
|
#include "QskQuick.h"
|
2022-01-04 13:50:40 +01:00
|
|
|
#include "QskFunctions.h"
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2022-07-19 16:50:40 +02:00
|
|
|
QSK_QT_PRIVATE_BEGIN
|
|
|
|
#include <private/qquickitem_p.h>
|
|
|
|
QSK_QT_PRIVATE_END
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
static Qsk::Direction qskDirection(
|
|
|
|
Qt::Orientation orientation, int from, int to, int itemCount )
|
|
|
|
{
|
|
|
|
Qsk::Direction direction;
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
if ( orientation == Qt::Horizontal )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
direction = Qsk::RightToLeft;
|
|
|
|
|
|
|
|
if ( to > from )
|
|
|
|
{
|
|
|
|
const bool isWrapping = ( from == 0 ) && ( to == itemCount - 1 );
|
|
|
|
|
|
|
|
if ( !isWrapping )
|
|
|
|
direction = Qsk::LeftToRight;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const bool isWrapping = ( to == 0 ) && ( from == itemCount - 1 );
|
|
|
|
|
|
|
|
if ( isWrapping )
|
|
|
|
direction = Qsk::LeftToRight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
direction = Qsk::BottomToTop;
|
|
|
|
|
|
|
|
if ( to > from )
|
|
|
|
{
|
|
|
|
const bool isWrapping = ( from == 0 ) && ( to == itemCount - 1 );
|
|
|
|
|
|
|
|
if ( !isWrapping )
|
|
|
|
direction = Qsk::TopToBottom;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const bool isWrapping = ( to == 0 ) && ( from == itemCount - 1 );
|
|
|
|
|
|
|
|
if ( isWrapping )
|
|
|
|
direction = Qsk::TopToBottom;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return direction;
|
|
|
|
}
|
|
|
|
|
2022-07-19 16:50:40 +02:00
|
|
|
namespace
|
|
|
|
{
|
2022-07-25 18:42:18 +02:00
|
|
|
class RotationTransform : public QQuickTransform
|
2022-07-19 16:50:40 +02:00
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
2022-07-25 18:42:18 +02:00
|
|
|
public:
|
|
|
|
RotationTransform( Qt::Axis axis, qreal angle, QQuickItem* item )
|
2022-07-19 16:50:40 +02:00
|
|
|
: QQuickTransform( item )
|
2022-07-25 18:42:18 +02:00
|
|
|
, m_axis( axis )
|
2022-07-19 16:50:40 +02:00
|
|
|
, m_angle( angle )
|
|
|
|
{
|
|
|
|
prependToItem( item );
|
|
|
|
}
|
|
|
|
|
|
|
|
void setAngle( qreal angle )
|
|
|
|
{
|
2022-07-25 18:42:18 +02:00
|
|
|
if ( m_angle != angle )
|
|
|
|
{
|
|
|
|
m_angle = angle;
|
|
|
|
update();
|
|
|
|
}
|
2022-07-19 16:50:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void applyTo( QMatrix4x4* matrix) const override
|
|
|
|
{
|
|
|
|
if ( const auto item = qobject_cast< QQuickItem* >( parent() ) )
|
|
|
|
{
|
|
|
|
const auto dx = 0.5 * item->width();
|
|
|
|
const auto dy = 0.5 * item->height();
|
|
|
|
|
|
|
|
QTransform transform;
|
|
|
|
transform.translate( dx, dy );
|
2022-07-25 18:42:18 +02:00
|
|
|
transform.rotate( m_angle, m_axis );
|
2022-07-19 16:50:40 +02:00
|
|
|
transform.translate( -dx, -dy );
|
|
|
|
|
|
|
|
*matrix *= transform;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-07-25 18:42:18 +02:00
|
|
|
private:
|
|
|
|
const Qt::Axis m_axis;
|
2022-07-19 16:50:40 +02:00
|
|
|
qreal m_angle = 0.0;
|
|
|
|
};
|
2022-07-25 18:42:18 +02:00
|
|
|
|
|
|
|
static RotationTransform* qskFindRotationTransform( const QQuickItem* item )
|
|
|
|
{
|
|
|
|
const auto& transforms = QQuickItemPrivate::get( item )->transforms;
|
|
|
|
for ( const auto& t : transforms )
|
|
|
|
{
|
|
|
|
if ( auto transform = qobject_cast< RotationTransform* >( t ) )
|
|
|
|
return transform;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
2022-07-19 16:50:40 +02:00
|
|
|
}
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
QskStackBoxAnimator::QskStackBoxAnimator( QskStackBox* parent )
|
|
|
|
: QObject( parent )
|
|
|
|
, m_startIndex( -1 )
|
|
|
|
, m_endIndex( -1 )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskStackBoxAnimator::~QskStackBoxAnimator()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskStackBoxAnimator::setStartIndex( int index )
|
|
|
|
{
|
2022-01-04 13:50:40 +01:00
|
|
|
m_transientIndex = m_startIndex = index;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskStackBoxAnimator::setEndIndex( int index )
|
|
|
|
{
|
|
|
|
m_endIndex = index;
|
|
|
|
}
|
|
|
|
|
|
|
|
int QskStackBoxAnimator::startIndex() const
|
|
|
|
{
|
|
|
|
return m_startIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
int QskStackBoxAnimator::endIndex() const
|
|
|
|
{
|
|
|
|
return m_endIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
QskStackBox* QskStackBoxAnimator::stackBox() const
|
|
|
|
{
|
|
|
|
return static_cast< QskStackBox* >( parent() );
|
|
|
|
}
|
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
QQuickItem* QskStackBoxAnimator::itemAt( int index ) const
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-06-19 14:08:45 +02:00
|
|
|
return stackBox()->itemAtIndex(
|
2017-07-21 18:21:34 +02:00
|
|
|
( index == 0 ) ? m_startIndex : m_endIndex );
|
|
|
|
}
|
|
|
|
|
2022-01-04 13:50:40 +01:00
|
|
|
qreal QskStackBoxAnimator::transientIndex() const
|
|
|
|
{
|
|
|
|
return m_transientIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskStackBoxAnimator::advance( qreal progress )
|
|
|
|
{
|
|
|
|
qreal transientIndex;
|
|
|
|
|
|
|
|
if ( qFuzzyIsNull( progress ) )
|
|
|
|
{
|
|
|
|
transientIndex = m_startIndex;
|
|
|
|
}
|
|
|
|
else if ( qFuzzyCompare( progress, 1.0 ) )
|
|
|
|
{
|
|
|
|
transientIndex = m_endIndex;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const auto box = stackBox();
|
|
|
|
|
|
|
|
auto startIndex = m_startIndex;
|
|
|
|
auto endIndex = m_endIndex;
|
|
|
|
|
|
|
|
if ( startIndex == 0 )
|
|
|
|
{
|
|
|
|
if ( endIndex == box->itemCount() - 1 )
|
|
|
|
startIndex += box->itemCount();
|
|
|
|
}
|
|
|
|
else if ( startIndex == box->itemCount() - 1 )
|
|
|
|
{
|
|
|
|
if ( endIndex == 0 )
|
|
|
|
endIndex += box->itemCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
transientIndex = startIndex + ( endIndex - startIndex ) * progress;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !qskFuzzyCompare( m_transientIndex, transientIndex ) )
|
|
|
|
{
|
|
|
|
m_transientIndex = transientIndex;
|
|
|
|
advanceIndex( progress );
|
|
|
|
|
|
|
|
Q_EMIT stackBox()->transientIndexChanged( m_transientIndex );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
QskStackBoxAnimator1::QskStackBoxAnimator1( QskStackBox* parent )
|
|
|
|
: QskStackBoxAnimator( parent )
|
|
|
|
, m_orientation( Qt::Horizontal )
|
2019-06-19 14:08:45 +02:00
|
|
|
, m_isDirty( false )
|
2019-05-16 08:14:32 +02:00
|
|
|
, m_hasClip( false )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-06-19 14:08:45 +02:00
|
|
|
// catching geometryChanges to know about resizing
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QskStackBoxAnimator1::~QskStackBoxAnimator1()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskStackBoxAnimator1::setOrientation( Qt::Orientation orientation )
|
|
|
|
{
|
|
|
|
if ( m_orientation != orientation )
|
|
|
|
{
|
|
|
|
stop();
|
|
|
|
m_orientation = orientation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt::Orientation QskStackBoxAnimator1::orientation() const
|
|
|
|
{
|
|
|
|
return m_orientation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskStackBoxAnimator1::setup()
|
|
|
|
{
|
|
|
|
auto stackBox = this->stackBox();
|
|
|
|
|
|
|
|
m_direction = qskDirection( m_orientation,
|
|
|
|
startIndex(), endIndex(), stackBox->itemCount() );
|
|
|
|
|
|
|
|
m_hasClip = stackBox->clip();
|
|
|
|
if ( !m_hasClip )
|
|
|
|
stackBox->setClip( true );
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
stackBox->installEventFilter( this );
|
|
|
|
m_isDirty = true;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2022-01-04 13:50:40 +01:00
|
|
|
void QskStackBoxAnimator1::advanceIndex( qreal value )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
auto stackBox = this->stackBox();
|
2019-06-19 14:08:45 +02:00
|
|
|
const bool isHorizontal = m_orientation == Qt::Horizontal;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
for ( int i = 0; i < 2; i++ )
|
|
|
|
{
|
2019-06-19 14:08:45 +02:00
|
|
|
if ( auto item = itemAt( i ) )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-06-19 14:08:45 +02:00
|
|
|
QRectF rect = qskItemGeometry( item );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
if ( m_isDirty )
|
|
|
|
{
|
|
|
|
const int index = ( i == 0 ) ? startIndex() : endIndex();
|
|
|
|
rect = stackBox->geometryForItemAt( index );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
m_itemOffset[ i ] = isHorizontal ? rect.x() : rect.y();
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
qreal x, y;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
if ( isHorizontal )
|
|
|
|
{
|
|
|
|
qreal off = stackBox->width() * ( value - i );
|
|
|
|
if ( m_direction == Qsk::LeftToRight )
|
|
|
|
off = -off;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
x = m_itemOffset[ i ] + off;
|
|
|
|
y = rect.y();
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
else
|
2019-06-19 14:08:45 +02:00
|
|
|
{
|
|
|
|
qreal off = stackBox->height() * ( value - i );
|
|
|
|
if ( m_direction == Qsk::BottomToTop )
|
|
|
|
off = -off;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
x = rect.x();
|
|
|
|
y = m_itemOffset[ i ] + off;
|
|
|
|
}
|
|
|
|
|
|
|
|
qskSetItemGeometry( item, x, y, rect.width(), rect.height() );
|
|
|
|
|
|
|
|
if ( !item->isVisible() )
|
|
|
|
item->setVisible( true );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
2019-06-19 14:08:45 +02:00
|
|
|
|
|
|
|
m_isDirty = false;
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskStackBoxAnimator1::done()
|
|
|
|
{
|
|
|
|
for ( int i = 0; i < 2; i++ )
|
|
|
|
{
|
2019-06-19 14:08:45 +02:00
|
|
|
if ( auto item = itemAt( i ) )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-06-19 14:08:45 +02:00
|
|
|
item->removeEventFilter( this );
|
|
|
|
item->setVisible( i == 1 );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !m_hasClip )
|
|
|
|
stackBox()->setClip( false );
|
|
|
|
}
|
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
bool QskStackBoxAnimator1::eventFilter( QObject* object, QEvent* event )
|
|
|
|
{
|
|
|
|
if ( !m_isDirty && object == stackBox() )
|
|
|
|
{
|
|
|
|
switch( static_cast< int >( event->type() ) )
|
|
|
|
{
|
|
|
|
case QskEvent::GeometryChange:
|
|
|
|
case QskEvent::ContentsRectChange:
|
|
|
|
case QskEvent::LayoutRequest:
|
|
|
|
{
|
|
|
|
m_isDirty = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return QObject::eventFilter( object, event );
|
|
|
|
}
|
|
|
|
|
2022-07-19 16:50:40 +02:00
|
|
|
QskStackBoxAnimator2::QskStackBoxAnimator2( QskStackBox* parent )
|
|
|
|
: QskStackBoxAnimator( parent )
|
2022-07-25 18:42:18 +02:00
|
|
|
, m_orientation( Qt::Horizontal )
|
|
|
|
, m_inverted( false )
|
2022-07-19 16:50:40 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskStackBoxAnimator2::~QskStackBoxAnimator2()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-07-25 18:42:18 +02:00
|
|
|
void QskStackBoxAnimator2::setOrientation( Qt::Orientation orientation )
|
|
|
|
{
|
|
|
|
if ( m_orientation != orientation )
|
|
|
|
{
|
|
|
|
stop();
|
|
|
|
m_orientation = orientation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt::Orientation QskStackBoxAnimator2::orientation() const
|
|
|
|
{
|
|
|
|
return m_orientation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskStackBoxAnimator2::setInverted( bool on )
|
|
|
|
{
|
|
|
|
if ( m_inverted != on )
|
|
|
|
{
|
|
|
|
stop();
|
|
|
|
m_inverted = on;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskStackBoxAnimator2::isInverted() const
|
|
|
|
{
|
|
|
|
return m_inverted;
|
|
|
|
}
|
|
|
|
|
2022-07-19 16:50:40 +02:00
|
|
|
void QskStackBoxAnimator2::setup()
|
|
|
|
{
|
2022-07-25 18:42:18 +02:00
|
|
|
const auto axis = ( m_orientation == Qt::Horizontal )
|
|
|
|
? Qt::YAxis : Qt::XAxis;
|
|
|
|
|
2022-07-19 16:50:40 +02:00
|
|
|
if ( auto item = itemAt( 0 ) )
|
2022-07-25 18:42:18 +02:00
|
|
|
( void ) new RotationTransform( axis, 0.0, item );
|
2022-07-19 16:50:40 +02:00
|
|
|
|
|
|
|
if ( auto item = itemAt( 1 ) )
|
2022-07-25 18:42:18 +02:00
|
|
|
( void ) new RotationTransform( axis, 90.0, item );
|
2022-07-19 16:50:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskStackBoxAnimator2::advanceIndex( qreal value )
|
|
|
|
{
|
2022-07-25 18:42:18 +02:00
|
|
|
auto degrees = value * 180.0;
|
|
|
|
|
|
|
|
if ( degrees < 90.0 && degrees > -90.0 )
|
2022-07-19 16:50:40 +02:00
|
|
|
{
|
|
|
|
if ( auto item = itemAt( 0 ) )
|
|
|
|
{
|
2022-07-25 18:42:18 +02:00
|
|
|
if ( !m_inverted )
|
|
|
|
degrees = 360.0 - degrees;
|
|
|
|
|
|
|
|
auto rotation = qskFindRotationTransform( item );
|
|
|
|
rotation->setAngle( degrees );
|
|
|
|
|
2022-07-19 16:50:40 +02:00
|
|
|
item->setVisible( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( auto item = itemAt( 1 ) )
|
|
|
|
{
|
|
|
|
item->setVisible( false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( auto item = itemAt( 0 ) )
|
|
|
|
{
|
|
|
|
item->setVisible( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( auto item = itemAt( 1 ) )
|
|
|
|
{
|
2022-07-25 18:42:18 +02:00
|
|
|
degrees = degrees - 180.0;
|
|
|
|
if ( !m_inverted )
|
|
|
|
degrees = 360.0 - degrees;
|
|
|
|
|
|
|
|
auto rotation = qskFindRotationTransform( item );
|
|
|
|
rotation->setAngle( degrees );
|
2022-07-19 16:50:40 +02:00
|
|
|
|
|
|
|
item->setVisible( true );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskStackBoxAnimator2::done()
|
|
|
|
{
|
|
|
|
for ( int i = 0; i < 2; i++ )
|
|
|
|
{
|
|
|
|
if ( auto item = itemAt( i ) )
|
|
|
|
{
|
2022-07-25 18:42:18 +02:00
|
|
|
delete qskFindRotationTransform( item );
|
|
|
|
item->setVisible( i == 1 );
|
2022-07-19 16:50:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
QskStackBoxAnimator3::QskStackBoxAnimator3( QskStackBox* parent )
|
|
|
|
: QskStackBoxAnimator( parent )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QskStackBoxAnimator3::~QskStackBoxAnimator3()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskStackBoxAnimator3::setup()
|
|
|
|
{
|
2019-06-19 14:08:45 +02:00
|
|
|
if ( auto item = itemAt( 1 ) )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-06-19 14:08:45 +02:00
|
|
|
item->setOpacity( 0.0 );
|
|
|
|
item->setVisible( true );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-04 13:50:40 +01:00
|
|
|
void QskStackBoxAnimator3::advanceIndex( qreal value )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-06-19 14:08:45 +02:00
|
|
|
if ( auto item1 = itemAt( 0 ) )
|
|
|
|
item1->setOpacity( 1.0 - value );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2019-06-19 14:08:45 +02:00
|
|
|
if ( auto item2 = itemAt( 1 ) )
|
|
|
|
item2->setOpacity( value );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskStackBoxAnimator3::done()
|
|
|
|
{
|
|
|
|
for ( int i = 0; i < 2; i++ )
|
|
|
|
{
|
2019-06-19 14:08:45 +02:00
|
|
|
if ( auto item = itemAt( i ) )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-06-19 14:08:45 +02:00
|
|
|
item->setOpacity( 1.0 );
|
|
|
|
item->setVisible( i == 1 ); // not here !!
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "moc_QskStackBoxAnimator.cpp"
|
2022-07-19 16:50:40 +02:00
|
|
|
#include "QskStackBoxAnimator.moc"
|