qskinny/src/controls/QskScrollView.cpp
2020-03-12 09:59:07 +01:00

295 lines
7.7 KiB
C++

/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskScrollView.h"
#include "QskAnimationHint.h"
#include "QskBoxBorderMetrics.h"
QSK_SUBCONTROL( QskScrollView, Panel )
QSK_SUBCONTROL( QskScrollView, Viewport )
QSK_SUBCONTROL( QskScrollView, HorizontalScrollBar )
QSK_SUBCONTROL( QskScrollView, HorizontalScrollHandle )
QSK_SUBCONTROL( QskScrollView, VerticalScrollBar )
QSK_SUBCONTROL( QskScrollView, VerticalScrollHandle )
QSK_SYSTEM_STATE( QskScrollView, VerticalHandlePressed, QskAspect::FirstSystemState << 1 )
QSK_SYSTEM_STATE( QskScrollView, HorizontalHandlePressed, QskAspect::FirstSystemState << 2 )
class QskScrollView::PrivateData
{
public:
PrivateData()
: horizontalScrollBarPolicy( Qt::ScrollBarAsNeeded )
, verticalScrollBarPolicy( Qt::ScrollBarAsNeeded )
, isScrolling( 0 )
{
}
Qt::ScrollBarPolicy horizontalScrollBarPolicy;
Qt::ScrollBarPolicy verticalScrollBarPolicy;
qreal scrollPressPos;
int isScrolling;
};
QskScrollView::QskScrollView( QQuickItem* parent )
: Inherited( parent )
, m_data( new PrivateData() )
{
setAcceptedMouseButtons( Qt::LeftButton );
}
QskScrollView::~QskScrollView()
{
}
QskAnimationHint QskScrollView::flickHint() const
{
return effectiveAnimation( QskAspect::Metric,
QskScrollView::Viewport, QskAspect::NoState );
}
void QskScrollView::setVerticalScrollBarPolicy( Qt::ScrollBarPolicy policy )
{
if ( policy != m_data->verticalScrollBarPolicy )
{
m_data->verticalScrollBarPolicy = policy;
update();
Q_EMIT verticalScrollBarPolicyChanged();
}
}
Qt::ScrollBarPolicy QskScrollView::verticalScrollBarPolicy() const
{
return m_data->verticalScrollBarPolicy;
}
void QskScrollView::setHorizontalScrollBarPolicy( Qt::ScrollBarPolicy policy )
{
if ( policy != m_data->horizontalScrollBarPolicy )
{
m_data->horizontalScrollBarPolicy = policy;
update();
Q_EMIT horizontalScrollBarPolicyChanged();
}
}
Qt::ScrollBarPolicy QskScrollView::horizontalScrollBarPolicy() const
{
return m_data->horizontalScrollBarPolicy;
}
bool QskScrollView::isScrolling( Qt::Orientation orientation ) const
{
return m_data->isScrolling == orientation;
}
QRectF QskScrollView::viewContentsRect() const
{
// This code should be done in the skinlet. TODO ...
const qreal bw = boxBorderMetricsHint( Viewport ).widthAt( Qt::TopEdge );
const QRectF r = subControlRect( Viewport );
return r.adjusted( bw, bw, -bw, -bw );
}
void QskScrollView::mousePressEvent( QMouseEvent* event )
{
if ( subControlRect( VerticalScrollBar ).contains( event->pos() ) )
{
const QRectF handleRect = subControlRect( VerticalScrollHandle );
if ( handleRect.contains( event->pos() ) )
{
m_data->isScrolling = Qt::Vertical;
m_data->scrollPressPos = event->y();
setSkinStateFlag( VerticalHandlePressed, true );
}
else
{
const QRectF vRect = viewContentsRect();
qreal y = scrollPos().y();
if ( event->y() < handleRect.top() )
y -= vRect.height();
else
y += vRect.height();
setScrollPos( QPointF( scrollPos().x(), y ) );
}
return;
}
if ( subControlRect( HorizontalScrollBar ).contains( event->pos() ) )
{
const QRectF handleRect = subControlRect( HorizontalScrollHandle );
if ( handleRect.contains( event->pos() ) )
{
m_data->isScrolling = Qt::Horizontal;
m_data->scrollPressPos = event->x();
setSkinStateFlag( HorizontalHandlePressed, true );
}
else
{
const QRectF vRect = viewContentsRect();
qreal x = scrollPos().x();
if ( event->x() < handleRect.left() )
x -= vRect.width();
else
x += vRect.width();
setScrollPos( QPointF( x, scrollPos().y() ) );
}
return;
}
Inherited::mousePressEvent( event );
}
void QskScrollView::mouseMoveEvent( QMouseEvent* event )
{
if ( !m_data->isScrolling )
{
Inherited::mouseMoveEvent( event );
return;
}
QPointF pos = scrollPos();
if ( m_data->isScrolling == Qt::Horizontal )
{
const qreal dx = event->x() - m_data->scrollPressPos;
const qreal w = subControlRect( HorizontalScrollBar ).width();
pos.rx() += dx / w * scrollableSize().width();
m_data->scrollPressPos = event->x();
}
else if ( m_data->isScrolling == Qt::Vertical )
{
const qreal dy = event->y() - m_data->scrollPressPos;
const qreal h = subControlRect( VerticalScrollBar ).height();
pos.ry() += dy / h * scrollableSize().height();
m_data->scrollPressPos = event->y();
}
if ( pos != scrollPos() )
setScrollPos( pos );
}
void QskScrollView::mouseReleaseEvent( QMouseEvent* event )
{
if ( !m_data->isScrolling )
{
Inherited::mouseReleaseEvent( event );
return;
}
m_data->isScrolling = 0;
m_data->scrollPressPos = 0;
setSkinStateFlag( HorizontalHandlePressed, false );
setSkinStateFlag( VerticalHandlePressed, false );
}
#ifndef QT_NO_WHEELEVENT
QPointF QskScrollView::scrollOffset( const QWheelEvent* event ) const
{
QPointF offset;
#if QT_VERSION < 0x050e00
const auto wheelPos = event->posF();
const auto wheelDelta = event->delta();
#else
const auto wheelPos = event->position();
const QPoint delta = event->angleDelta();
const int wheelDelta = ( qAbs( delta.x() ) > qAbs( delta.y() ) )
? delta.x() : delta.y();
#endif
if ( subControlRect( VerticalScrollBar ).contains( wheelPos ) )
{
offset.setY( wheelDelta );
}
else if ( subControlRect( HorizontalScrollBar ).contains( wheelPos ) )
{
offset.setX( wheelDelta );
}
else
{
offset = Inherited::scrollOffset( event );
}
return offset;
}
#endif
Qt::Orientations QskScrollView::scrollableOrientations() const
{
// layoutRect ???
const QRectF vr = contentsRect();
auto policyVertical = m_data->verticalScrollBarPolicy;
auto policyHorizontal = m_data->horizontalScrollBarPolicy;
if ( policyVertical == Qt::ScrollBarAsNeeded )
{
qreal height = vr.height();
if ( policyHorizontal == Qt::ScrollBarAlwaysOn )
height -= metric( HorizontalScrollBar | QskAspect::Size );
if ( scrollableSize().height() > height )
policyVertical = Qt::ScrollBarAlwaysOn;
}
if ( policyHorizontal == Qt::ScrollBarAsNeeded )
{
qreal width = vr.width();
if ( policyVertical == Qt::ScrollBarAlwaysOn )
width -= metric( VerticalScrollBar | QskAspect::Size );
if ( scrollableSize().width() > width )
{
policyHorizontal = Qt::ScrollBarAlwaysOn;
// we have to check the vertical once more
if ( ( policyVertical == Qt::ScrollBarAsNeeded ) &&
( scrollableSize().height() >
vr.height() - metric( HorizontalScrollBar | QskAspect::Size ) ) )
{
policyVertical = Qt::ScrollBarAlwaysOn;
}
}
}
Qt::Orientations orientations;
if ( policyHorizontal == Qt::ScrollBarAlwaysOn )
orientations |= Qt::Horizontal;
if ( policyVertical == Qt::ScrollBarAlwaysOn )
orientations |= Qt::Vertical;
return orientations;
}
#include "moc_QskScrollView.cpp"