/****************************************************************************** * 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 "QskLayoutItem.h" #include "QskLayoutEngine.h" #include "QskStackBox.h" static Qsk::Direction qskDirection( Qt::Orientation orientation, int from, int to, int itemCount ) { Qsk::Direction direction; if ( orientation == Qt::Horizontal ) { 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; } QskStackBoxAnimator::QskStackBoxAnimator( QskStackBox* parent ): QObject( parent ), m_startIndex( -1 ), m_endIndex( -1 ) { } QskStackBoxAnimator::~QskStackBoxAnimator() { } void QskStackBoxAnimator::setStartIndex( int index ) { m_startIndex = index; } 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() ); } QskLayoutItem* QskStackBoxAnimator::layoutItemAt( int index ) const { return stackBox()->engine().layoutItemAt( ( index == 0 ) ? m_startIndex : m_endIndex ); } QskStackBoxAnimator1::QskStackBoxAnimator1( QskStackBox* parent ): QskStackBoxAnimator( parent ), m_orientation( Qt::Horizontal ) { } QskStackBoxAnimator1::~QskStackBoxAnimator1() { } void QskStackBoxAnimator1::setOrientation( Qt::Orientation orientation ) { if ( m_orientation != orientation ) { #if 1 stop(); #endif 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() ); for ( int i = 0; i < 2; i++ ) { QskLayoutItem* layoutItem = layoutItemAt( i ); if ( layoutItem ) { QQuickItem* item = layoutItem->item(); const Qt::Orientation orientation = this->orientation(); m_itemOffset[i] = ( orientation == Qt::Horizontal ) ? item->x() : item->y(); if ( i == 1 ) { // now move the new item outside of // the visible area and then "show" it if ( orientation == Qt::Horizontal ) item->setX( stackBox->width() ); else item->setY( stackBox->height() ); item->setVisible( true ); } // we don't want the engine() to interfere, when // controlling the item by the animation layoutItem->setUpdateMode( QskLayoutItem::UpdateNone ); } } m_hasClip = stackBox->clip(); if ( !m_hasClip ) stackBox->setClip( true ); } void QskStackBoxAnimator1::advance( qreal value ) { auto stackBox = this->stackBox(); for ( int i = 0; i < 2; i++ ) { QskLayoutItem* layoutItem = layoutItemAt( i ); if ( layoutItem == nullptr ) continue; if ( layoutItem->isGeometryDirty() ) { // the layout tried to replace the item, but we // want to have control over the position. But we // also lost resizing - that's why we have to do it here // manually stackBox->adjustItemAt( ( i == 0 ) ? startIndex() : endIndex() ); QQuickItem* item = layoutItem->item(); m_itemOffset[i] = ( m_orientation == Qt::Horizontal ) ? item->x() : item->y(); } QQuickItem* item = layoutItem->item(); if ( m_orientation == Qt::Horizontal ) { const qreal off = stackBox->width() * ( value - i ); if ( m_direction == Qsk::LeftToRight ) item->setX( m_itemOffset[i] - off ); else item->setX( m_itemOffset[i] + off ); } else { const qreal off = stackBox->height() * ( value - i ); if ( m_direction == Qsk::TopToBottom ) item->setY( m_itemOffset[i] + off ); else item->setY( m_itemOffset[i] - off ); } } } void QskStackBoxAnimator1::done() { for ( int i = 0; i < 2; i++ ) { if ( QskLayoutItem* layoutItem = layoutItemAt( i ) ) { layoutItem->setUpdateMode( QskLayoutItem::UpdateWhenVisible ); layoutItem->item()->setVisible( i == 1 ); } } if ( !m_hasClip ) stackBox()->setClip( false ); } QskStackBoxAnimator3::QskStackBoxAnimator3( QskStackBox* parent ): QskStackBoxAnimator( parent ) { } QskStackBoxAnimator3::~QskStackBoxAnimator3() { } void QskStackBoxAnimator3::setup() { QskLayoutItem* layoutItem = layoutItemAt( 1 ); if ( layoutItem ) { layoutItem->item()->setOpacity( 0.0 ); layoutItem->item()->setVisible( true ); } } void QskStackBoxAnimator3::advance( qreal value ) { QskLayoutItem* layoutItem1 = layoutItemAt( 0 ); if ( layoutItem1 ) layoutItem1->item()->setOpacity( 1.0 - value ); QskLayoutItem* layoutItem2 = layoutItemAt( 1 ); if ( layoutItem2 ) layoutItem2->item()->setOpacity( value ); } void QskStackBoxAnimator3::done() { for ( int i = 0; i < 2; i++ ) { if ( QskLayoutItem* layoutItem = layoutItemAt( i ) ) { layoutItem->item()->setOpacity( 1.0 ); layoutItem->item()->setVisible( i == 1 ); // not here !! } } } #include "moc_QskStackBoxAnimator.cpp"