IOT dashboard: fix cube effect for more pages

This commit is contained in:
Peter Hartmann 2023-01-02 11:46:23 +01:00 committed by uwerat
parent c904f33cf1
commit dc356801e4
2 changed files with 130 additions and 70 deletions

View File

@ -16,39 +16,73 @@
#include <QQuickFramebufferObject> #include <QQuickFramebufferObject>
#include <QGuiApplication> #include <QGuiApplication>
#include <QQuickWindow> #include <QQuickWindow>
#include <QtMath>
namespace #include <QTimer>
Cube::Position Cube::s_neighbors[ Cube::NumPositions ][ 4 ] =
{ {
Qsk::Direction direction( const int from, const int to ) // Left:
{ { Cube::Back, // Right
if( from < Cube::Top ) // side Cube::Front, // Left
{ Cube::Top, // Bottom
if( to < Cube::Top ) // side to side Cube::Bottom }, // Top
{
return ( to > from ) ? Qsk::LeftToRight : Qsk::RightToLeft; // ### 2x case // Right:
} { Cube::Front,
else Cube::Back,
{ Cube::Top,
return ( to == Cube::Top ) ? Qsk::BottomToTop : Qsk::TopToBottom; // ### 2x case Cube::Bottom },
}
} // Top:
else if( from == Cube::Top ) { Cube::Left,
{ Cube::Right,
return Qsk::TopToBottom; // ### 2x case Cube::Back,
} Cube::Front },
else
{ // Bottom:
return Qsk::BottomToTop; // ### 2x case { Cube::Left,
} Cube::Right,
} Cube::Front,
} Cube::Back },
// Front:
{ Cube::Left,
Cube::Right,
Cube::Top,
Cube::Bottom },
// Back:
{ Cube::Left,
Cube::Right,
Cube::Top,
Cube::Bottom },
};
Cube::Cube( QQuickItem* parent ) Cube::Cube( QQuickItem* parent )
: QskStackBox( false, parent ) : QskStackBox( false, parent )
, m_currentPosition( Front )
{ {
// The code below covers the case where we need 2 cube movements to get
// to the desired position.
// We use transientIndexChanged here to be sure to start a new transition
// at the end; indexChanged doesn't work here.
connect( this, &QskStackBox::transientIndexChanged, this, [ this ]( qreal position )
{
const bool animationIsFinished = ( position == qFloor( position ) );
if( animationIsFinished && position != m_currentPosition )
{
QTimer::singleShot( 0, this, [this]()
{
switchToPosition( m_currentPosition );
} );
}
} );
} }
void Cube::startAnimation( Qsk::Direction direction ) void Cube::startAnimation( Qsk::Direction direction, int position )
{ {
using Animator = QskStackBoxAnimator4; using Animator = QskStackBoxAnimator4;
@ -70,25 +104,45 @@ void Cube::startAnimation( Qsk::Direction direction )
const bool inverted = ( direction == Qsk::LeftToRight || direction == Qsk::TopToBottom ); const bool inverted = ( direction == Qsk::LeftToRight || direction == Qsk::TopToBottom );
animator->setInverted( inverted ); animator->setInverted( inverted );
int newIndex = 0; setCurrentIndex( position );
}
switch( direction ) void Cube::switchPosition( const Qsk::Direction direction )
{
const auto position = s_neighbors[ m_currentPosition ][ direction ];
switchToPosition( position );
}
void Cube::switchToPosition( const Position position )
{
if( currentIndex() == position )
return;
m_currentPosition = static_cast< Position >( position );
const auto from = static_cast< Cube::Position >( currentIndex() );
const auto d = direction( from, m_currentPosition );
startAnimation( d, position );
Q_EMIT cubeIndexChanged( position );
}
Qsk::Direction Cube::direction( const Position from, const Position to )
{
// if direct neighbor: use that direction
// otherwise: we need 2 swipes, direction doesn't matter, so choose right to left
const auto neighbors = s_neighbors[ from ];
for( int i = 0; i < 4; ++i )
{ {
case Qsk::LeftToRight: if( neighbors[ i ] == to )
case Qsk::TopToBottom: {
newIndex = currentIndex() + 1; return static_cast< Qsk::Direction >( i );
break; }
case Qsk::RightToLeft:
case Qsk::BottomToTop:
newIndex = currentIndex() - 1;
break;
} }
newIndex %= itemCount(); return Qsk::RightToLeft;
if( newIndex < 0 )
newIndex += itemCount();
setCurrentIndex( newIndex );
} }
MainItem::MainItem( QQuickItem* parent ) MainItem::MainItem( QQuickItem* parent )
@ -96,7 +150,6 @@ MainItem::MainItem( QQuickItem* parent )
, m_mainLayout( new QskLinearBox( Qt::Horizontal, this ) ) , m_mainLayout( new QskLinearBox( Qt::Horizontal, this ) )
, m_menuBar( new MenuBar( m_mainLayout ) ) , m_menuBar( new MenuBar( m_mainLayout ) )
, m_cube( new Cube( m_mainLayout ) ) , m_cube( new Cube( m_mainLayout ) )
, m_currentIndex( 0 )
{ {
setAutoLayoutChildren( true ); setAutoLayoutChildren( true );
setAcceptedMouseButtons( Qt::LeftButton ); setAcceptedMouseButtons( Qt::LeftButton );
@ -108,7 +161,11 @@ MainItem::MainItem( QQuickItem* parent )
m_mainLayout->setSpacing( 0 ); m_mainLayout->setSpacing( 0 );
connect( m_menuBar, &MenuBar::pageChangeRequested, this, &MainItem::switchToPage ); connect( m_menuBar, &MenuBar::pageChangeRequested, this, [this]( int index )
{
const auto position = static_cast< Cube::Position >( index );
m_cube->switchToPosition( position );
} );
auto* const dashboardPage = new DashboardPage( m_cube ); auto* const dashboardPage = new DashboardPage( m_cube );
auto* const roomsPage = new RoomsPage( m_cube ); auto* const roomsPage = new RoomsPage( m_cube );
@ -117,13 +174,14 @@ MainItem::MainItem( QQuickItem* parent )
auto* const storagePage = new StoragePage( m_cube ); auto* const storagePage = new StoragePage( m_cube );
auto* const membersPage = new MembersPage( m_cube ); auto* const membersPage = new MembersPage( m_cube );
m_cube->addItem( dashboardPage ); m_cube->insertItem( Cube::Left, statisticsPage );
m_cube->addItem( roomsPage ); m_cube->insertItem( Cube::Right, roomsPage );
m_cube->addItem( devicesPage ); m_cube->insertItem( Cube::Top, storagePage );
m_cube->addItem( statisticsPage ); m_cube->insertItem( Cube::Bottom, membersPage );
m_cube->addItem( storagePage ); m_cube->insertItem( Cube::Front, dashboardPage );
m_cube->addItem( membersPage ); m_cube->insertItem( Cube::Back, devicesPage );
// the current item needs to be the one at the Front:
m_cube->setCurrentItem( dashboardPage ); m_cube->setCurrentItem( dashboardPage );
} }
@ -132,7 +190,7 @@ void MainItem::gestureEvent( QskGestureEvent* event )
if( event->gesture()->state() == QskGesture::Finished if( event->gesture()->state() == QskGesture::Finished
&& event->gesture()->type() == QskGesture::Pan ) && event->gesture()->type() == QskGesture::Pan )
{ {
auto* panGesture = static_cast< const QskPanGesture* >( event->gesture().get() ); const auto* panGesture = static_cast< const QskPanGesture* >( event->gesture().get() );
const auto delta = panGesture->origin() - panGesture->position(); const auto delta = panGesture->origin() - panGesture->position();
@ -147,7 +205,7 @@ void MainItem::gestureEvent( QskGestureEvent* event )
direction = ( delta.y() < 0 ) ? Qsk::TopToBottom : Qsk::BottomToTop; direction = ( delta.y() < 0 ) ? Qsk::TopToBottom : Qsk::BottomToTop;
} }
m_cube->startAnimation( direction ); m_cube->switchPosition( direction );
} }
} }
@ -173,15 +231,4 @@ bool MainItem::gestureFilter( QQuickItem* item, QEvent* event )
return recognizer.processEvent( item, event, false ); return recognizer.processEvent( item, event, false );
} }
void MainItem::switchToPage( const int index )
{
if( m_currentIndex == index )
return;
const auto d = direction( m_currentIndex, index );
m_cube->startAnimation( d );
m_menuBar->setActivePage( index );
m_currentIndex = index;
}
#include "moc_MainItem.cpp" #include "moc_MainItem.cpp"

View File

@ -15,17 +15,33 @@ class Cube : public QskStackBox
Q_OBJECT Q_OBJECT
public: public:
enum { enum Position {
Left, Left,
Front,
Right, Right,
Back,
Top, Top,
Bottom Bottom,
} Position; Front,
Back,
NumPositions
};
explicit Cube( QQuickItem* parent = nullptr ); explicit Cube( QQuickItem* parent = nullptr );
void startAnimation( Qsk::Direction direction );
public Q_SLOTS:
void switchPosition( const Qsk::Direction direction );
void switchToPosition( const Cube::Position position );
Q_SIGNALS:
// might be different from indexChanged:
void cubeIndexChanged( const int index );
private:
Qsk::Direction direction( const Position from, const Position to );
void startAnimation( Qsk::Direction direction, int position );
Cube::Position m_currentPosition;
static Position s_neighbors[ NumPositions ][ 4 ];
}; };
class MainItem : public QskControl class MainItem : public QskControl
@ -40,11 +56,8 @@ class MainItem : public QskControl
void gestureEvent( QskGestureEvent* ) override final; void gestureEvent( QskGestureEvent* ) override final;
private: private:
void switchToPage( const int index );
QskLinearBox* m_mainLayout; QskLinearBox* m_mainLayout;
MenuBar* m_menuBar; MenuBar* m_menuBar;
Cube* m_cube; Cube* m_cube;
QskPanGestureRecognizer m_panRecognizer; QskPanGestureRecognizer m_panRecognizer;
int m_currentIndex;
}; };