some auto scrolling modes added
This commit is contained in:
parent
b1c3acde8e
commit
4f6bf75426
@ -594,6 +594,9 @@ void QskMaterialSkin::initScrollViewHints()
|
||||
setGradient( subControl, pal.accentColor );
|
||||
setBoxBorderColors( subControl, pal.accentColor );
|
||||
}
|
||||
|
||||
// when changing the position by QskScrollView::scrollTo
|
||||
setAnimation( Q::Viewport | Metric, QskAnimationHint( 200, QEasingCurve::InCubic ) );
|
||||
}
|
||||
|
||||
void QskMaterialSkin::initListViewHints()
|
||||
|
@ -634,6 +634,9 @@ void QskSquiekSkin::initScrollViewHints()
|
||||
|
||||
setAnimation( subControl | Color, qskDuration );
|
||||
}
|
||||
|
||||
// when changing the position by QskScrollView::scrollTo
|
||||
setAnimation( Q::Viewport | Metric, QskAnimationHint( 200, QEasingCurve::OutCubic ) );
|
||||
}
|
||||
|
||||
void QskSquiekSkin::initListViewHints()
|
||||
|
@ -223,10 +223,12 @@ void QskListView::keyPressEvent( QKeyEvent* event )
|
||||
|
||||
if ( row != r )
|
||||
{
|
||||
auto pos = scrollPos();
|
||||
|
||||
const qreal rowPos = row * rowHeight();
|
||||
if ( rowPos < scrollPos().y() )
|
||||
{
|
||||
setScrollPos( QPointF( scrollPos().x(), rowPos ) );
|
||||
pos.setY( rowPos );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -236,9 +238,17 @@ void QskListView::keyPressEvent( QKeyEvent* event )
|
||||
if ( rowPos + rowHeight() > scrolledBottom )
|
||||
{
|
||||
const double y = rowPos + rowHeight() - vr.height();
|
||||
setScrollPos( QPointF( scrollPos().x(), y ) );
|
||||
pos.setY( y );
|
||||
}
|
||||
}
|
||||
|
||||
if ( pos != scrollPos() )
|
||||
{
|
||||
if ( event->isAutoRepeat() )
|
||||
setScrollPos( pos );
|
||||
else
|
||||
scrollTo( pos );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ QskPopup::QskPopup( QQuickItem* parent ):
|
||||
// we don't want to be resized by layout code
|
||||
setTransparentForPositioner( true );
|
||||
|
||||
setFlag( ItemIsFocusScope );
|
||||
setFlag( ItemIsFocusScope, true );
|
||||
setTabFence( true );
|
||||
setFocusPolicy( Qt::ClickFocus );
|
||||
}
|
||||
|
@ -7,13 +7,28 @@
|
||||
#include "QskScrollViewSkinlet.h"
|
||||
#include "QskLayoutConstraint.h"
|
||||
#include "QskBoxClipNode.h"
|
||||
#include "QskEvent.h"
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qquickitem_p.h>
|
||||
#include <private/qquickwindow_p.h>
|
||||
#include <private/qquickclipnode_p.h>
|
||||
#include <private/qquickitemchangelistener_p.h>
|
||||
QSK_QT_PRIVATE_END
|
||||
|
||||
static inline bool qskIsAncestorOf( const QQuickItem* item, const QQuickItem* child )
|
||||
{
|
||||
while ( child )
|
||||
{
|
||||
if ( child == item )
|
||||
return true;
|
||||
|
||||
child = child->parentItem();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static QSizeF qskAdjustedSize( const QQuickItem* item, const QSizeF& targetSize )
|
||||
{
|
||||
using namespace QskLayoutConstraint;
|
||||
@ -171,6 +186,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual bool event( QEvent* event ) override final;
|
||||
virtual void windowChangeEvent( QskWindowChangeEvent* ) override final;
|
||||
|
||||
virtual void itemChange( ItemChange, const ItemChangeData& ) override final;
|
||||
virtual void geometryChanged( const QRectF&, const QRectF& ) override final;
|
||||
@ -195,6 +211,9 @@ protected:
|
||||
virtual void updateNode( QSGNode* ) override final;
|
||||
|
||||
private:
|
||||
void connectWindow( const QQuickWindow*, bool on );
|
||||
void onFocusItemChanged();
|
||||
|
||||
inline QskScrollArea* scrollArea()
|
||||
{
|
||||
return static_cast< QskScrollArea* >( parentItem() );
|
||||
@ -213,6 +232,8 @@ QskScrollAreaClipItem::QskScrollAreaClipItem( QskScrollArea* scrollArea ):
|
||||
{
|
||||
setObjectName( QStringLiteral( "QskScrollAreaClipItem" ) );
|
||||
setClip( true );
|
||||
|
||||
connectWindow( window(), true );
|
||||
}
|
||||
|
||||
QskScrollAreaClipItem::~QskScrollAreaClipItem()
|
||||
@ -220,6 +241,23 @@ QskScrollAreaClipItem::~QskScrollAreaClipItem()
|
||||
enableGeometryListener( false );
|
||||
}
|
||||
|
||||
void QskScrollAreaClipItem::connectWindow( const QQuickWindow* window, bool on )
|
||||
{
|
||||
if ( window == nullptr )
|
||||
return;
|
||||
|
||||
if ( on )
|
||||
{
|
||||
connect( window, &QQuickWindow::activeFocusItemChanged,
|
||||
this, &QskScrollAreaClipItem::onFocusItemChanged );
|
||||
}
|
||||
else
|
||||
{
|
||||
disconnect( window, &QQuickWindow::activeFocusItemChanged,
|
||||
this, &QskScrollAreaClipItem::onFocusItemChanged );
|
||||
}
|
||||
}
|
||||
|
||||
void QskScrollAreaClipItem::updateNode( QSGNode* )
|
||||
{
|
||||
auto* d = QQuickItemPrivate::get( this );
|
||||
@ -337,6 +375,20 @@ void QskScrollAreaClipItem::enableGeometryListener( bool on )
|
||||
}
|
||||
}
|
||||
|
||||
void QskScrollAreaClipItem::onFocusItemChanged()
|
||||
{
|
||||
if ( window() == nullptr || !scrollArea()->autoScrollFocusItem() )
|
||||
return;
|
||||
|
||||
const auto focusItem = window()->activeFocusItem();
|
||||
if ( focusItem )
|
||||
{
|
||||
auto reason = QQuickWindowPrivate::get( window() )->lastFocusReason;
|
||||
if ( reason == Qt::TabFocusReason || reason == Qt::BacktabFocusReason )
|
||||
scrollArea()->ensureItemVisible( focusItem );
|
||||
}
|
||||
}
|
||||
|
||||
bool QskScrollAreaClipItem::event( QEvent* event )
|
||||
{
|
||||
if( event->type() == QEvent::LayoutRequest )
|
||||
@ -348,11 +400,20 @@ bool QskScrollAreaClipItem::event( QEvent* event )
|
||||
return Inherited::event( event );
|
||||
}
|
||||
|
||||
void QskScrollAreaClipItem::windowChangeEvent( QskWindowChangeEvent* event )
|
||||
{
|
||||
Inherited::windowChangeEvent( event );
|
||||
|
||||
connectWindow( event->oldWindow(), false );
|
||||
connectWindow( event->window(), true );
|
||||
}
|
||||
|
||||
class QskScrollArea::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
isItemResizable( true )
|
||||
isItemResizable( true ),
|
||||
autoScrollFocusItem( true )
|
||||
{
|
||||
}
|
||||
|
||||
@ -371,7 +432,9 @@ public:
|
||||
}
|
||||
|
||||
QskScrollAreaClipItem* clipItem;
|
||||
|
||||
bool isItemResizable : 1;
|
||||
bool autoScrollFocusItem : 1;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -424,6 +487,16 @@ QskScrollArea::~QskScrollArea()
|
||||
delete m_data->clipItem;
|
||||
}
|
||||
|
||||
void QskScrollArea::ensureItemVisible( const QQuickItem* item )
|
||||
{
|
||||
const QQuickItem* scrolledItem = this->scrolledItem();
|
||||
if ( scrolledItem && qskIsAncestorOf( scrolledItem, item ) )
|
||||
{
|
||||
const auto pos = scrolledItem->mapFromItem( item, QPointF() );
|
||||
ensureVisible( QRectF( pos.x(), pos.y(), item->width(), item->height() ) );
|
||||
}
|
||||
}
|
||||
|
||||
void QskScrollArea::updateLayout()
|
||||
{
|
||||
Inherited::updateLayout();
|
||||
@ -469,6 +542,20 @@ void QskScrollArea::adjustItem()
|
||||
}
|
||||
}
|
||||
|
||||
void QskScrollArea::setAutoScrollFocusedItem( bool on )
|
||||
{
|
||||
if ( m_data->autoScrollFocusItem != on )
|
||||
{
|
||||
m_data->autoScrollFocusItem = on;
|
||||
Q_EMIT autoScrollFocusedItemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool QskScrollArea::autoScrollFocusItem() const
|
||||
{
|
||||
return m_data->autoScrollFocusItem;
|
||||
}
|
||||
|
||||
void QskScrollArea::setItemResizable( bool on )
|
||||
{
|
||||
if ( on != m_data->isItemResizable )
|
||||
|
@ -18,6 +18,9 @@ class QSK_EXPORT QskScrollArea : public QskScrollView
|
||||
Q_PROPERTY( bool itemResizable READ isItemResizable
|
||||
WRITE setItemResizable NOTIFY itemResizableChanged FINAL )
|
||||
|
||||
Q_PROPERTY( bool autoScrollFocusedItem READ autoScrollFocusItem
|
||||
WRITE setAutoScrollFocusedItem NOTIFY autoScrollFocusedItemChanged FINAL )
|
||||
|
||||
using Inherited = QskScrollView;
|
||||
|
||||
public:
|
||||
@ -30,9 +33,15 @@ public:
|
||||
void setItemResizable( bool on );
|
||||
bool isItemResizable() const;
|
||||
|
||||
void setAutoScrollFocusedItem( bool on );
|
||||
bool autoScrollFocusItem() const;
|
||||
|
||||
void ensureItemVisible( const QQuickItem * );
|
||||
|
||||
Q_SIGNALS:
|
||||
void itemResizableChanged();
|
||||
void scrolledItemChanged();
|
||||
void autoScrollFocusedItemChanged();
|
||||
|
||||
protected:
|
||||
virtual void updateLayout() override;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "QskPanGestureRecognizer.h"
|
||||
#include "QskFlickAnimator.h"
|
||||
#include "QskBoxBorderMetrics.h"
|
||||
#include "QskAnimationHint.h"
|
||||
#include "QskGesture.h"
|
||||
#include "QskAspect.h"
|
||||
#include "QskEvent.h"
|
||||
@ -25,11 +26,12 @@ QSK_STATE( QskScrollView, HorizontalHandlePressed, QskAspect::FirstSystemState <
|
||||
|
||||
namespace
|
||||
{
|
||||
class FlickAnimator : public QskFlickAnimator
|
||||
class FlickAnimator final : public QskFlickAnimator
|
||||
{
|
||||
public:
|
||||
FlickAnimator()
|
||||
{
|
||||
// skin hints: TODO
|
||||
setDuration( 1000 );
|
||||
setEasingCurve( QEasingCurve::OutCubic );
|
||||
}
|
||||
@ -48,6 +50,61 @@ namespace
|
||||
private:
|
||||
QskScrollView* m_scrollView;
|
||||
};
|
||||
|
||||
class ScrollAnimator final : public QskAnimator
|
||||
{
|
||||
public:
|
||||
ScrollAnimator():
|
||||
m_scrollView( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
void setScrollView( QskScrollView* scrollView )
|
||||
{
|
||||
m_scrollView = scrollView;
|
||||
}
|
||||
|
||||
void scroll( const QPointF& from, const QPointF& to )
|
||||
{
|
||||
if ( isRunning() )
|
||||
{
|
||||
m_to = to;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( from == to || m_scrollView == nullptr )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_from = from;
|
||||
m_to = to;
|
||||
|
||||
const auto hint = m_scrollView->effectiveAnimation(
|
||||
QskAspect::Metric, QskScrollView::Viewport );
|
||||
|
||||
setDuration( hint.duration );
|
||||
setEasingCurve( hint.type );
|
||||
setWindow( m_scrollView->window() );
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void advance( qreal value ) override final
|
||||
{
|
||||
qreal x = m_from.x() + ( m_to.x() - m_from.x() ) * value;
|
||||
qreal y = m_from.y() + ( m_to.y() - m_from.y() ) * value;
|
||||
|
||||
m_scrollView->setScrollPos( QPointF( x, y ) );
|
||||
}
|
||||
|
||||
private:
|
||||
QskScrollView* m_scrollView;
|
||||
|
||||
QPointF m_from;
|
||||
QPointF m_to;
|
||||
};
|
||||
}
|
||||
|
||||
class QskScrollView::PrivateData
|
||||
@ -58,6 +115,7 @@ public:
|
||||
verticalScrollBarPolicy( Qt::ScrollBarAsNeeded ),
|
||||
scrollableSize( 0.0, 0.0 ),
|
||||
panRecognizerTimeout( 100 ), // value coming from the platform ???
|
||||
viewportPadding( 10 ),
|
||||
isScrolling( 0 )
|
||||
{
|
||||
}
|
||||
@ -72,6 +130,9 @@ public:
|
||||
int panRecognizerTimeout;
|
||||
|
||||
FlickAnimator flicker;
|
||||
ScrollAnimator scroller;
|
||||
|
||||
qreal viewportPadding;
|
||||
|
||||
qreal scrollPressPos;
|
||||
int isScrolling;
|
||||
@ -82,6 +143,7 @@ QskScrollView::QskScrollView( QQuickItem* parent ):
|
||||
m_data( new PrivateData() )
|
||||
{
|
||||
m_data->flicker.setScrollView( this );
|
||||
m_data->scroller.setScrollView( this );
|
||||
|
||||
m_data->panRecognizer.setWatchedItem( this );
|
||||
m_data->panRecognizer.setOrientations( Qt::Horizontal | Qt::Vertical );
|
||||
@ -174,6 +236,11 @@ QPointF QskScrollView::scrollPos() const
|
||||
return m_data->scrollPos;
|
||||
}
|
||||
|
||||
void QskScrollView::scrollTo( const QPointF& pos )
|
||||
{
|
||||
m_data->scroller.scroll( scrollPos(), pos );
|
||||
}
|
||||
|
||||
bool QskScrollView::isScrolling( Qt::Orientation orientation ) const
|
||||
{
|
||||
return m_data->isScrolling == orientation;
|
||||
@ -198,6 +265,86 @@ QSizeF QskScrollView::scrollableSize() const
|
||||
return m_data->scrollableSize;
|
||||
}
|
||||
|
||||
void QskScrollView::ensureVisible( const QPointF& pos )
|
||||
{
|
||||
const qreal margin = m_data->viewportPadding;
|
||||
|
||||
QRectF r( scrollPos(), viewContentsRect().size() );
|
||||
r.adjust( margin, margin, -margin, -margin );
|
||||
|
||||
qreal x = r.x();
|
||||
qreal y = r.y();
|
||||
|
||||
if ( pos.x() < r.left() )
|
||||
{
|
||||
x = pos.x();
|
||||
}
|
||||
else if ( pos.x() > r.right() )
|
||||
{
|
||||
x = pos.x() - r.width();
|
||||
}
|
||||
|
||||
if ( pos.y() < r.top() )
|
||||
{
|
||||
y = pos.y();
|
||||
}
|
||||
else if ( y > r.right() )
|
||||
{
|
||||
y = pos.y() - r.height();
|
||||
}
|
||||
|
||||
const QPoint newPos( x - margin, y - margin );
|
||||
|
||||
if ( isInitiallyPainted() )
|
||||
scrollTo( newPos );
|
||||
else
|
||||
setScrollPos( newPos );
|
||||
}
|
||||
|
||||
void QskScrollView::ensureVisible( const QRectF& itemRect )
|
||||
{
|
||||
const qreal margin = m_data->viewportPadding;
|
||||
|
||||
QRectF r( scrollPos(), viewContentsRect().size() );
|
||||
r.adjust( margin, margin, -margin, -margin );
|
||||
|
||||
qreal x = r.x();
|
||||
qreal y = r.y();
|
||||
|
||||
if ( itemRect.width() > r.width() )
|
||||
{
|
||||
x = itemRect.left() + 0.5 * ( itemRect.width() - r.width() );
|
||||
}
|
||||
else if ( itemRect.right() > r.right() )
|
||||
{
|
||||
x = itemRect.right() - r.width();
|
||||
}
|
||||
else if ( itemRect.left() < r.left() )
|
||||
{
|
||||
x = itemRect.left();
|
||||
}
|
||||
|
||||
if ( itemRect.height() > r.height() )
|
||||
{
|
||||
y = itemRect.top() + 0.5 * ( itemRect.height() - r.height() );
|
||||
}
|
||||
else if ( itemRect.bottom() > r.bottom() )
|
||||
{
|
||||
y = itemRect.bottom() - r.height();
|
||||
}
|
||||
else if ( itemRect.top() < r.top() )
|
||||
{
|
||||
y = itemRect.top();
|
||||
}
|
||||
|
||||
const QPoint newPos( x - margin, y - margin );
|
||||
|
||||
if ( isInitiallyPainted() )
|
||||
scrollTo( newPos );
|
||||
else
|
||||
setScrollPos( newPos );
|
||||
}
|
||||
|
||||
QRectF QskScrollView::viewContentsRect() const
|
||||
{
|
||||
// This code should be done in the skinlet. TODO ...
|
||||
|
@ -67,6 +67,10 @@ Q_SIGNALS:
|
||||
|
||||
public Q_SLOTS:
|
||||
void setScrollPos( const QPointF& );
|
||||
void scrollTo( const QPointF& );
|
||||
|
||||
void ensureVisible( const QPointF& );
|
||||
void ensureVisible( const QRectF& );
|
||||
|
||||
protected:
|
||||
virtual void mouseMoveEvent( QMouseEvent* ) override;
|
||||
|
Loading…
x
Reference in New Issue
Block a user