qskinny/src/controls/QskSlider.cpp

247 lines
6.1 KiB
C++
Raw Normal View History

2017-07-21 18:21:34 +02:00
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskSlider.h"
#include "QskAnimationHint.h"
2018-08-03 08:15:28 +02:00
#include "QskAspect.h"
2017-07-21 18:21:34 +02:00
QSK_SUBCONTROL( QskSlider, Panel )
QSK_SUBCONTROL( QskSlider, Groove )
QSK_SUBCONTROL( QskSlider, Fill )
QSK_SUBCONTROL( QskSlider, Scale )
QSK_SUBCONTROL( QskSlider, Handle )
2019-04-02 17:50:08 +02:00
QSK_SYSTEM_STATE( QskSlider, Pressed, QskAspect::FirstSystemState << 1 )
QSK_SYSTEM_STATE( QskSlider, Minimum, QskAspect::FirstSystemState << 2 )
QSK_SYSTEM_STATE( QskSlider, Maximum, QskAspect::FirstSystemState << 3 )
2017-07-21 18:21:34 +02:00
class QskSlider::PrivateData
{
2018-08-03 08:15:28 +02:00
public:
PrivateData( Qt::Orientation orientation )
: pressedValue( 0 )
, tracking( true )
, orientation( orientation )
2017-07-21 18:21:34 +02:00
{
}
QPointF pressedPos;
qreal pressedValue;
bool tracking : 1;
Qt::Orientation orientation : 2;
};
2018-08-03 08:15:28 +02:00
QskSlider::QskSlider( QQuickItem* parent )
: QskSlider( Qt::Horizontal, parent )
2017-07-21 18:21:34 +02:00
{
}
2018-08-03 08:15:28 +02:00
QskSlider::QskSlider( Qt::Orientation orientation, QQuickItem* parent )
: Inherited( parent )
, m_data( new PrivateData( orientation ) )
2017-07-21 18:21:34 +02:00
{
setAcceptHoverEvents( true );
2018-08-03 08:15:28 +02:00
setFocusPolicy( Qt::StrongFocus );
2017-07-21 18:21:34 +02:00
if ( orientation == Qt::Horizontal )
initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Fixed );
2017-07-21 18:21:34 +02:00
else
initSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Minimum );
2017-07-21 18:21:34 +02:00
setMetric( QskSlider::Handle | QskAspect::Position, valueAsRatio() );
2017-07-21 18:21:34 +02:00
connect( this, &QskSlider::boundariesChanged, [ this ]() { updatePosition(); } );
connect( this, &QskSlider::valueChanged, [ this ]() { updatePosition(); } );
2017-07-21 18:21:34 +02:00
}
QskSlider::~QskSlider()
{
}
bool QskSlider::isPressed() const
{
return skinState() & Pressed;
}
void QskSlider::setOrientation( Qt::Orientation orientation )
{
if ( orientation != m_data->orientation )
{
m_data->orientation = orientation;
#if 1
// swapping the size policy: guess this is what a user expects
setSizePolicy( sizePolicy( Qt::Vertical ), sizePolicy( Qt::Horizontal ) );
#endif
resetImplicitSize();
update();
Q_EMIT orientationChanged( m_data->orientation );
}
}
Qt::Orientation QskSlider::orientation() const
{
return m_data->orientation;
}
QskAspect::Placement QskSlider::effectivePlacement() const
{
return static_cast< QskAspect::Placement >( m_data->orientation );
}
2017-07-21 18:21:34 +02:00
void QskSlider::setTracking( bool on )
{
if ( on != m_data->tracking )
{
m_data->tracking = on;
Q_EMIT trackingChanged( on );
}
}
bool QskSlider::isTracking() const
{
return m_data->tracking;
}
QSizeF QskSlider::contentsSizeHint(
Qt::SizeHint which, const QSizeF& ) const
2017-07-21 18:21:34 +02:00
{
if ( which != Qt::PreferredSize )
return QSizeF();
2017-07-21 18:21:34 +02:00
const qreal dim = metric( QskSlider::Panel | QskAspect::Size );
return ( m_data->orientation == Qt::Horizontal )
? QSizeF( 4 * dim, dim ) : QSizeF( dim, 4 * dim );
}
QSizeF QskSlider::handleSize() const
{
return handleRect().size();
}
QRectF QskSlider::handleRect() const
{
return subControlRect( QskSlider::Handle );
2017-07-21 18:21:34 +02:00
}
void QskSlider::mousePressEvent( QMouseEvent* event )
{
if ( handleRect().contains( event->pos() ) )
{
// Case 1: press started in the handle, start sliding
2017-07-21 18:21:34 +02:00
m_data->pressedPos = event->pos();
m_data->pressedValue = value();
setSkinStateFlag( Pressed );
Q_EMIT pressedChanged( true );
}
else if ( !pageSize() )
2017-07-21 18:21:34 +02:00
{
// Case 2: pageSize is not used, we're done here
}
else
{
// Case 3: pressed outside of the handle, page the scroller in
// the direction of the press requires an auto-repeat behavior
// until the slider reaches the destination, or it simply jumps
// there (configurable)
2017-07-21 18:21:34 +02:00
}
}
void QskSlider::mouseMoveEvent( QMouseEvent* event )
{
if ( !isPressed() )
return;
if ( m_data->tracking )
{
#if 0
// if tracking is false we need to update the position only
// without changing the value TODO..
#endif
}
const auto r = subControlRect( Scale );
2017-07-21 18:21:34 +02:00
qreal newValue;
if ( m_data->orientation == Qt::Horizontal )
{
const auto distance = event->localPos().x() - m_data->pressedPos.x();
newValue = m_data->pressedValue + distance / r.width() * boundaryLength();
2017-07-21 18:21:34 +02:00
}
else
{
const auto distance = event->localPos().y() - m_data->pressedPos.y();
newValue = m_data->pressedValue - distance / r.height() * boundaryLength();
2017-07-21 18:21:34 +02:00
}
setValue( newValue );
}
void QskSlider::mouseReleaseEvent( QMouseEvent* event )
{
if ( !isPressed() ) // Page event
{
const QPointF pos = event->localPos();
const auto szHandle = handleSize();
const auto rect = contentsRect();
bool up;
if ( m_data->orientation == Qt::Horizontal )
{
const qreal w = szHandle.width();
const qreal x = ( pos.x() - rect.x() - w * 0.5 ) / ( rect.width() - w );
up = x > valueAsRatio();
2017-07-21 18:21:34 +02:00
}
else
{
const qreal h = szHandle.height();
const qreal y = ( pos.y() - rect.y() - h * 0.5 ) / ( rect.height() - h );
up = y < 1.0 - valueAsRatio();
2017-07-21 18:21:34 +02:00
}
if ( up )
pageUp();
else
pageDown();
}
setSkinStateFlag( Pressed, false );
Q_EMIT pressedChanged( false );
}
void QskSlider::updatePosition()
{
using namespace QskAspect;
setSkinStateFlag( QskSlider::Minimum, value() <= minimum() );
setSkinStateFlag( QskSlider::Maximum, value() >= maximum() );
const Aspect aspect = QskSlider::Handle | Position | Metric;
const auto hint = animation( aspect | skinState() );
const qreal pos = valueAsRatio();
2017-07-21 18:21:34 +02:00
if ( hint.duration > 0 )
2017-07-21 18:21:34 +02:00
{
2017-08-22 19:47:06 +02:00
const qreal oldPos = metric( aspect );
2017-07-21 18:21:34 +02:00
setMetric( aspect, pos );
2017-08-22 19:47:06 +02:00
startTransition( aspect, hint, oldPos, pos );
2017-07-21 18:21:34 +02:00
}
else
{
setMetric( aspect, pos );
}
update();
}
#include "moc_QskSlider.cpp"