diff --git a/examples/layouts/CMakeLists.txt b/examples/layouts/CMakeLists.txt index e8d8b0bd..a4b57bc3 100644 --- a/examples/layouts/CMakeLists.txt +++ b/examples/layouts/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCES LinearLayoutPage.h LinearLayoutPage.cpp DynamicConstraintsPage.h DynamicConstraintsPage.cpp StackLayoutPage.h StackLayoutPage.cpp + SwipeViewPage.h SwipeViewPage.cpp main.cpp ) qt_add_resources(SOURCES layouts.qrc) diff --git a/examples/layouts/SwipeViewPage.cpp b/examples/layouts/SwipeViewPage.cpp new file mode 100644 index 00000000..012e1951 --- /dev/null +++ b/examples/layouts/SwipeViewPage.cpp @@ -0,0 +1,61 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "SwipeViewPage.h" +#include "TestRectangle.h" + +#include +#include + +namespace +{ +class SwipeView : public QskSwipeView + { + Q_OBJECT + + public: + SwipeView( QQuickItem* parent = nullptr ) + : QskSwipeView( parent ) + { + setObjectName( "SwipeView" ); + + setBackgroundColor( Qt::white ); + setDefaultAlignment( Qt::AlignCenter ); + + addRectangle( "Gold" ); + addRectangle( "SeaGreen" ); + addRectangle( "SlateBlue" ); + addRectangle( "Peru" ); + + for ( int i = 0; i < itemCount(); i += 2 ) + { + if ( auto control = qskControlCast( itemAtIndex( i ) ) ) + control->setFixedSize( 200, 200 ); + } + } + private: + void addRectangle( const char* colorName ) + { + auto rect = new TestRectangle( colorName ); + rect->setText( QString::number( itemCount() + 1 ) ); + addItem( rect ); + } + + }; +} + +SwipeViewPage::SwipeViewPage( QQuickItem* parent ) + : QskLinearBox( Qt::Vertical, parent ) +{ + setObjectName( "SwipeViewPage" ); + + setMargins( 10 ); + setBackgroundColor( QskRgb::LightSteelBlue ); + + auto swipeView = new SwipeView(); + addItem( swipeView ); +} + +#include "SwipeViewPage.moc" diff --git a/examples/layouts/SwipeViewPage.h b/examples/layouts/SwipeViewPage.h new file mode 100644 index 00000000..02ce94dd --- /dev/null +++ b/examples/layouts/SwipeViewPage.h @@ -0,0 +1,14 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#pragma once + +#include + +class SwipeViewPage : public QskLinearBox +{ + public: + SwipeViewPage( QQuickItem* parent = nullptr ); +}; diff --git a/examples/layouts/main.cpp b/examples/layouts/main.cpp index e14cf38f..2797a959 100644 --- a/examples/layouts/main.cpp +++ b/examples/layouts/main.cpp @@ -8,6 +8,7 @@ #include "LinearLayoutPage.h" #include "GridLayoutPage.h" #include "StackLayoutPage.h" +#include "SwipeViewPage.h" #include "TestRectangle.h" #include @@ -43,6 +44,7 @@ int main( int argc, char* argv[] ) tabView->addTab( "Linear Layout", new LinearLayoutPage() ); tabView->addTab( "Dynamic\nConstraints", new DynamicConstraintsPage() ); tabView->addTab( "Stack Layout", new StackLayoutPage() ); + tabView->addTab( "Swipe View", new SwipeViewPage() ); tabView->setCurrentIndex( 0 ); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 07b1b761..28a22229 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -236,6 +236,7 @@ list(APPEND HEADERS controls/QskSubWindowSkinlet.h controls/QskSwitchButton.h controls/QskSwitchButtonSkinlet.h + controls/QskSwipeView.h controls/QskTabBar.h controls/QskTabButton.h controls/QskTabButtonSkinlet.h @@ -334,6 +335,7 @@ list(APPEND SOURCES controls/QskSubWindowSkinlet.cpp controls/QskSwitchButton.cpp controls/QskSwitchButtonSkinlet.cpp + controls/QskSwipeView.cpp controls/QskTabBar.cpp controls/QskTabButton.cpp controls/QskTabButtonSkinlet.cpp diff --git a/src/controls/QskSwipeView.cpp b/src/controls/QskSwipeView.cpp new file mode 100644 index 00000000..97cb574e --- /dev/null +++ b/src/controls/QskSwipeView.cpp @@ -0,0 +1,112 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskSwipeView.h" + +#include "QskEvent.h" +#include "QskGesture.h" +#include "QskPanGestureRecognizer.h" +#include "QskStackBoxAnimator.h" + +class QskSwipeView::PrivateData +{ + public: + QskPanGestureRecognizer panRecognizer; + int panRecognizerTimeout = 100; + int duration = 500; +}; + +QSK_SUBCONTROL( QskSwipeView, Panel ) + +QskSwipeView::QskSwipeView( QQuickItem* parent ) + : Inherited( parent ) + , m_data( new PrivateData() ) +{ + setSubcontrolProxy( QskBox::Panel, Panel ); + + setFiltersChildMouseEvents( true ); + + setAcceptedMouseButtons( Qt::LeftButton ); + + m_data->panRecognizer.setWatchedItem( this ); + m_data->panRecognizer.setOrientations( Qt::Horizontal ); + m_data->panRecognizer.setMinDistance( 50 ); +} + +QskSwipeView::~QskSwipeView() +{ +} + + +int QskSwipeView::duration() const +{ + return m_data->duration; +} + +void QskSwipeView::setDuration( int duration ) +{ + m_data->duration = duration; +} + + +bool QskSwipeView::gestureFilter( QQuickItem* item, QEvent* event ) +{ + // see QskScrollBox.cpp + + auto& recognizer = m_data->panRecognizer; + + if ( event->type() == QEvent::MouseButtonPress ) + { + if ( ( item != this ) && ( recognizer.timeout() < 0 ) ) + { + const auto mouseEvent = static_cast< QMouseEvent* >( event ); + + if ( recognizer.hasProcessedBefore( mouseEvent ) ) + return false; + } + + recognizer.setTimeout( ( item == this ) ? -1 : m_data->panRecognizerTimeout ); + } + + return m_data->panRecognizer.processEvent( item, event ); +} + +void QskSwipeView::gestureEvent( QskGestureEvent* event ) +{ + if( event->gesture()->type() == QskGesture::Pan && event->gesture()->state() == QskGesture::Started ) + { + const auto gesture = static_cast< const QskPanGesture* >( event->gesture().get() ); + + auto animator = dynamic_cast< QskStackBoxAnimator1* >( this->animator() ); + + if ( animator == nullptr ) + { + animator = new QskStackBoxAnimator1( this ); + animator->setOrientation( Qt::Horizontal ); + } + + animator->setDuration( m_data->duration ); + setAnimator( animator ); + + const auto direction = ( ( gesture->angle() < 90.0 ) || ( gesture->angle() > 270.0 ) ) + ? Qsk::LeftToRight : Qsk::RightToLeft; + + auto newIndex = ( direction == Qsk::LeftToRight ) ? currentIndex() - 1 : currentIndex() + 1; + + if( newIndex < 0 ) + newIndex += itemCount(); + + newIndex %= itemCount(); + + setCurrentIndex( newIndex ); + } + else + { + Inherited::gestureEvent( event ); + } + +} + +#include "moc_QskSwipeView.cpp" diff --git a/src/controls/QskSwipeView.h b/src/controls/QskSwipeView.h new file mode 100644 index 00000000..cbcc9c0e --- /dev/null +++ b/src/controls/QskSwipeView.h @@ -0,0 +1,38 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#ifndef QSK_SWIPE_VIEW_H +#define QSK_SWIPE_VIEW_H + +#include "QskStackBox.h" + +class QskTabBar; +class QskTabButton; + +class QSK_EXPORT QskSwipeView : public QskStackBox +{ + Q_OBJECT + + typedef QskStackBox Inherited; + + public: + QSK_SUBCONTROLS( Panel ) + + QskSwipeView( QQuickItem* parent = nullptr ); + ~QskSwipeView() override; + + int duration() const; + void setDuration( int ); + + protected: + bool gestureFilter( QQuickItem*, QEvent* ) override final; + void gestureEvent( QskGestureEvent* ) override final; + + private: + class PrivateData; + std::unique_ptr< PrivateData > m_data; +}; + +#endif