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 66ba5509..5af6b1e2 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 @@ -37,7 +38,8 @@ namespace addTab( "Linear Layout", new LinearLayoutPage() ); addTab( "Dynamic\nConstraints", new DynamicConstraintsPage() ); addTab( "Stack Layout", new StackLayoutPage() ); - + addTab( "Swipe View", new SwipeViewPage() ); + setCurrentIndex( 0 ); } }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f244a2bb..237d1577 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -240,6 +240,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 @@ -342,6 +343,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..3994c6c7 --- /dev/null +++ b/src/controls/QskSwipeView.cpp @@ -0,0 +1,120 @@ +/****************************************************************************** + * 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 duration = -1; // should be a skinHint +}; + +QSK_SUBCONTROL( QskSwipeView, Panel ) + +QskSwipeView::QskSwipeView( QQuickItem* parent ) + : Inherited( parent ) + , m_data( new PrivateData() ) +{ + setFiltersChildMouseEvents( true ); + setAcceptedMouseButtons( Qt::LeftButton ); + + auto& recognizer = m_data->panRecognizer; + + recognizer.setWatchedItem( this ); + + // should be skin hints + recognizer.setOrientations( Qt::Horizontal ); + recognizer.setMinDistance( 50 ); + recognizer.setTimeout( 100 ); + + resetDuration(); +} + +QskSwipeView::~QskSwipeView() +{ +} + +QskAspect::Subcontrol QskSwipeView::effectiveSubcontrol( + QskAspect::Subcontrol subControl ) const +{ + if ( subControl == QskBox::Panel ) + return QskSwipeView::Panel; + + return Inherited::effectiveSubcontrol( subControl ); +} + +int QskSwipeView::duration() const +{ + return m_data->duration; +} + +void QskSwipeView::setDuration( int duration ) +{ + m_data->duration = duration; +} + +void QskSwipeView::resetDuration() +{ + m_data->duration = 500; +} + +bool QskSwipeView::gestureFilter( const QQuickItem* item, const QEvent* event ) +{ + // see QskScrollBox.cpp + + auto& recognizer = m_data->panRecognizer; + + if ( event->type() == QEvent::MouseButtonPress ) + { + auto mouseEvent = static_cast< const QMouseEvent* >( event ); + if ( recognizer.hasProcessedBefore( mouseEvent ) ) + return false; + } + + return recognizer.processEvent( item, event ); + +} + +void QskSwipeView::gestureEvent( QskGestureEvent* event ) +{ + const auto gesture = static_cast< const QskPanGesture* >( event->gesture().get() ); + + if( gesture->type() == QskGesture::Pan && gesture->state() == QskGesture::Started ) + { + auto animator = dynamic_cast< QskStackBoxAnimator1* >( this->animator() ); + + if ( animator == nullptr ) + { + animator = new QskStackBoxAnimator1( this ); + animator->setOrientation( Qt::Horizontal ); + } + + animator->setDuration( m_data->duration ); + QskStackBox::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 ); + return; + } + + 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..bebb976d --- /dev/null +++ b/src/controls/QskSwipeView.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * 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 QSK_EXPORT QskSwipeView : public QskStackBox +{ + Q_OBJECT + + Q_PROPERTY( int duration READ duration WRITE setDuration RESET resetDuration ) + + using Inherited = QskStackBox; + + public: + QSK_SUBCONTROLS( Panel ) + + QskSwipeView( QQuickItem* parent = nullptr ); + ~QskSwipeView() override; + + int duration() const; + void setDuration( int ); + void resetDuration(); + + QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol ) const; + + protected: + bool gestureFilter( const QQuickItem*, const QEvent* ) override; + void gestureEvent( QskGestureEvent* ) override; + + private: + void setAnimator( QskStackBoxAnimator* ) = delete; + + class PrivateData; + std::unique_ptr< PrivateData > m_data; +}; + +#endif