diff --git a/src/controls/QskBoundedControl.cpp b/src/controls/QskBoundedControl.cpp new file mode 100644 index 00000000..881f99d2 --- /dev/null +++ b/src/controls/QskBoundedControl.cpp @@ -0,0 +1,143 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#include "QskBoundedControl.h" +#include "QskFunctions.h" +#include "QskIntervalF.h" + +QskBoundedControl::QskBoundedControl( QQuickItem* parent ) + : QskBoundedControl( 0.0, 1.0, parent ) +{ +} + +QskBoundedControl::QskBoundedControl( qreal min, qreal max, QQuickItem* parent ) + : QskControl( parent ) + , m_minimum( qMin( min, max ) ) + , m_maximum( qMax( min, max ) ) +{ +} + +QskBoundedControl::~QskBoundedControl() +{ +} + +void QskBoundedControl::setMinimum( qreal minimum ) +{ + if ( qskFuzzyCompare( m_minimum, minimum ) ) + return; + + m_minimum = minimum; + Q_EMIT minimumChanged( minimum ); + + if ( isComponentComplete() ) + adjustBoundaries( false ); + + Q_EMIT boundariesChanged( boundaries() ); + update(); +} + +qreal QskBoundedControl::minimum() const +{ + return m_minimum; +} + +void QskBoundedControl::setMaximum( qreal maximum ) +{ + if ( qskFuzzyCompare( m_maximum, maximum ) ) + return; + + m_maximum = maximum; + Q_EMIT maximumChanged( maximum ); + + if ( isComponentComplete() ) + adjustBoundaries( true ); + + Q_EMIT boundariesChanged( boundaries() ); + update(); +} + +qreal QskBoundedControl::maximum() const +{ + return m_maximum; +} + +void QskBoundedControl::setBoundaries( qreal min, qreal max ) +{ + if ( max < min ) + max = min; + + const auto oldMin = m_minimum; + const auto oldMax = m_maximum; + + if ( min == oldMin && max == oldMax ) + return; + + m_minimum = min; + m_maximum = max; + + if ( isComponentComplete() ) + adjustBoundaries( false ); + + if ( m_minimum != oldMin ) + Q_EMIT minimumChanged( m_minimum ); + + if ( m_maximum != oldMax ) + Q_EMIT maximumChanged( m_maximum ); + + Q_EMIT boundariesChanged( boundaries() ); + update(); +} + +void QskBoundedControl::setBoundaries( const QskIntervalF& boundaries ) +{ + setBoundaries( boundaries.lowerBound(), boundaries.upperBound() ); +} + +QskIntervalF QskBoundedControl::boundaries() const +{ + return QskIntervalF( m_minimum, m_maximum ); +} + +void QskBoundedControl::adjustBoundaries( bool increasing ) +{ + if ( m_maximum >= m_minimum ) + return; + + if ( increasing ) + { + m_minimum = m_maximum; + Q_EMIT minimumChanged( m_minimum ); + } + else + { + m_maximum = m_minimum; + Q_EMIT maximumChanged( m_maximum ); + } + + Q_EMIT boundariesChanged( boundaries() ); +} + +qreal QskBoundedControl::boundaryLength() const +{ + return m_maximum - m_minimum; +} + +void QskBoundedControl::componentComplete() +{ + Inherited::componentComplete(); + adjustBoundaries( true ); +} + +qreal QskBoundedControl::boundedValue( qreal value ) const +{ + return qBound( minimum(), value, maximum() ); +} + +qreal QskBoundedControl::valueAsRatio( qreal value ) const +{ + return ( value - m_minimum ) / ( m_maximum - m_minimum ); +} + +#include "moc_QskBoundedControl.cpp" diff --git a/src/controls/QskBoundedControl.h b/src/controls/QskBoundedControl.h new file mode 100644 index 00000000..5d353020 --- /dev/null +++ b/src/controls/QskBoundedControl.h @@ -0,0 +1,61 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#ifndef QSK_BOUNDED_CONTROL_H +#define QSK_BOUNDED_CONTROL_H + +#include "QskControl.h" + +class QskIntervalF; + +class QSK_EXPORT QskBoundedControl : public QskControl +{ + Q_OBJECT + + Q_PROPERTY( qreal minimum READ minimum WRITE setMinimum NOTIFY minimumChanged ) + Q_PROPERTY( qreal maximum READ maximum WRITE setMaximum NOTIFY maximumChanged ) + Q_PROPERTY( QskIntervalF boundaries READ boundaries + WRITE setBoundaries NOTIFY boundariesChanged ) + + using Inherited = QskControl; + + public: + ~QskBoundedControl() override; + + qreal minimum() const; + qreal maximum() const; + + qreal boundaryLength() const; + + void setBoundaries( qreal min, qreal max ); + QskIntervalF boundaries() const; + + qreal boundedValue( qreal ) const; + qreal valueAsRatio( qreal ) const; + + public Q_SLOTS: + void setMinimum( qreal ); + void setMaximum( qreal ); + void setBoundaries( const QskIntervalF& ); + + Q_SIGNALS: + void minimumChanged( qreal ); + void maximumChanged( qreal ); + void boundariesChanged( const QskIntervalF& ); + + protected: + QskBoundedControl( QQuickItem* parent = nullptr ); + QskBoundedControl( qreal min, qreal max, QQuickItem* parent = nullptr ); + + void componentComplete() override; + + void adjustBoundaries( bool increasing ); + + private: + qreal m_minimum; + qreal m_maximum; +}; + +#endif diff --git a/src/controls/QskBoundedInput.cpp b/src/controls/QskBoundedInput.cpp index 553d815d..77db2bdc 100644 --- a/src/controls/QskBoundedInput.cpp +++ b/src/controls/QskBoundedInput.cpp @@ -11,203 +11,90 @@ QSK_SYSTEM_STATE( QskBoundedInput, ReadOnly, ( QskAspect::FirstSystemState << 1 ) ) -class QskBoundedInput::PrivateData -{ - public: - PrivateData() - : minimum( 0.0 ) - , maximum( 1.0 ) - , stepSize( 0.1 ) - , pageSize( 1 ) - , snap( false ) - { - } - - qreal minimum; - qreal maximum; - qreal stepSize; - int pageSize; - - bool snap : 1; -}; - QskBoundedInput::QskBoundedInput( QQuickItem* parent ) - : QskControl( parent ) - , m_data( new PrivateData() ) + : Inherited( parent ) + , m_stepSize( 0.1 ) + , m_pageSize( 1 ) + , m_snap( false ) { setFocusPolicy( Qt::StrongFocus ); setAcceptedMouseButtons( Qt::LeftButton ); setWheelEnabled( true ); + + if ( isComponentComplete() ) + { + connect( this, &QskBoundedControl::boundariesChanged, + this, &QskBoundedInput::alignInput ); + } } QskBoundedInput::~QskBoundedInput() { } -void QskBoundedInput::setMinimum( qreal minimum ) -{ - if ( m_data->minimum == minimum ) - return; - - m_data->minimum = minimum; - Q_EMIT minimumChanged( minimum ); - - if ( isComponentComplete() ) - adjustBoundaries( false ); - - Q_EMIT boundariesChanged( boundaries() ); - update(); -} - -qreal QskBoundedInput::minimum() const -{ - return m_data->minimum; -} - -void QskBoundedInput::setMaximum( qreal maximum ) -{ - if ( m_data->maximum == maximum ) - return; - - m_data->maximum = maximum; - Q_EMIT maximumChanged( maximum ); - - if ( isComponentComplete() ) - adjustBoundaries( true ); - - Q_EMIT boundariesChanged( boundaries() ); - update(); -} - -qreal QskBoundedInput::maximum() const -{ - return m_data->maximum; -} - -void QskBoundedInput::setBoundaries( qreal min, qreal max ) -{ - if ( max < min ) - max = min; - - const auto oldMin = m_data->minimum; - const auto oldMax = m_data->maximum; - - if ( min == oldMin && max == oldMax ) - return; - - m_data->minimum = min; - m_data->maximum = max; - - if ( isComponentComplete() ) - adjustBoundaries( false ); - - if ( m_data->minimum != oldMin ) - Q_EMIT minimumChanged( m_data->minimum ); - - if ( m_data->maximum != oldMax ) - Q_EMIT maximumChanged( m_data->maximum ); - - Q_EMIT boundariesChanged( boundaries() ); - update(); -} - -void QskBoundedInput::setBoundaries( const QskIntervalF& boundaries ) -{ - setBoundaries( boundaries.lowerBound(), boundaries.upperBound() ); -} - -QskIntervalF QskBoundedInput::boundaries() const -{ - return QskIntervalF( m_data->minimum, m_data->maximum ); -} - -void QskBoundedInput::adjustBoundaries( bool increasing ) -{ - if ( m_data->maximum < m_data->minimum ) - { - if ( increasing ) - { - m_data->minimum = m_data->maximum; - Q_EMIT minimumChanged( m_data->minimum ); - } - else - { - m_data->maximum = m_data->minimum; - Q_EMIT maximumChanged( m_data->maximum ); - } - - alignInput(); - } -} - -qreal QskBoundedInput::boundaryLength() const -{ - return m_data->maximum - m_data->minimum; -} - void QskBoundedInput::setStepSize( qreal stepSize ) { if ( qFuzzyIsNull( stepSize ) ) stepSize = 0.0; - if ( qFuzzyCompare( m_data->stepSize, stepSize ) ) + if ( qFuzzyCompare( m_stepSize, stepSize ) ) return; - m_data->stepSize = stepSize; + m_stepSize = stepSize; Q_EMIT stepSizeChanged( stepSize ); if ( isComponentComplete() ) { - if ( m_data->snap && stepSize ) + if ( m_snap && stepSize ) alignInput(); } } qreal QskBoundedInput::stepSize() const { - return m_data->stepSize; + return m_stepSize; } void QskBoundedInput::setPageSize( int pageSize ) { - if ( m_data->pageSize == pageSize ) + if ( m_pageSize == pageSize ) return; - m_data->pageSize = pageSize; + m_pageSize = pageSize; Q_EMIT pageSizeChanged( pageSize ); } int QskBoundedInput::pageSize() const { - return m_data->pageSize; + return m_pageSize; } void QskBoundedInput::stepUp() { - increment( m_data->stepSize ); + increment( m_stepSize ); } void QskBoundedInput::stepDown() { - increment( -m_data->stepSize ); + increment( -m_stepSize ); } void QskBoundedInput::pageUp() { - increment( m_data->pageSize * m_data->stepSize ); + increment( m_pageSize * m_stepSize ); } void QskBoundedInput::pageDown() { - increment( -m_data->pageSize * m_data->stepSize ); + increment( -m_pageSize * m_stepSize ); } void QskBoundedInput::setSnap( bool snap ) { - if ( m_data->snap == snap ) + if ( m_snap == snap ) return; - m_data->snap = snap; + m_snap = snap; Q_EMIT snapChanged( snap ); if ( isComponentComplete() && snap ) @@ -216,7 +103,18 @@ void QskBoundedInput::setSnap( bool snap ) bool QskBoundedInput::snap() const { - return m_data->snap; + return m_snap; +} + +void QskBoundedInput::componentComplete() +{ + if ( isComponentComplete() ) + { + connect( this, &QskBoundedControl::boundariesChanged, + this, &QskBoundedInput::alignInput, Qt::UniqueConnection ); + } + + Inherited::componentComplete(); } void QskBoundedInput::alignInput() @@ -225,20 +123,20 @@ void QskBoundedInput::alignInput() qreal QskBoundedInput::alignedValue( qreal value ) const { - if ( m_data->snap ) + if ( m_snap ) { - if ( const auto step = m_data->stepSize ) + if ( const auto step = m_stepSize ) value = qRound( value / step ) * step; } - return qBound( minimum(), value, maximum() ); + return boundedValue( value ); } QskIntervalF QskBoundedInput::alignedInterval( const QskIntervalF& interval ) const { - if ( m_data->snap ) + if ( m_snap ) { - if ( const auto step = m_data->stepSize ) + if ( const auto step = m_stepSize ) { const qreal lower = std::floor( interval.lowerBound() / step ) * step; const qreal upper = std::ceil( interval.upperBound() / step ) * step; @@ -276,13 +174,13 @@ void QskBoundedInput::keyPressEvent( QKeyEvent* event ) { if ( event->key() == Qt::Key_Up || event->matches( QKeySequence::MoveToNextChar ) ) { - increment( m_data->stepSize ); + increment( m_stepSize ); return; } if ( event->key() == Qt::Key_Down || event->matches( QKeySequence::MoveToPreviousChar ) ) { - increment( -m_data->stepSize ); + increment( -m_stepSize ); return; } } @@ -311,10 +209,4 @@ void QskBoundedInput::wheelEvent( QWheelEvent* event ) #endif -void QskBoundedInput::componentComplete() -{ - Inherited::componentComplete(); - adjustBoundaries( true ); -} - #include "moc_QskBoundedInput.cpp" diff --git a/src/controls/QskBoundedInput.h b/src/controls/QskBoundedInput.h index ace7ca20..8ccdf6d4 100644 --- a/src/controls/QskBoundedInput.h +++ b/src/controls/QskBoundedInput.h @@ -6,26 +6,21 @@ #ifndef QSK_BOUNDED_INPUT_H #define QSK_BOUNDED_INPUT_H -#include "QskControl.h" +#include "QskBoundedControl.h" class QskIntervalF; -class QSK_EXPORT QskBoundedInput : public QskControl +class QSK_EXPORT QskBoundedInput : public QskBoundedControl { Q_OBJECT - Q_PROPERTY( qreal minimum READ minimum WRITE setMinimum NOTIFY minimumChanged ) - Q_PROPERTY( qreal maximum READ maximum WRITE setMaximum NOTIFY maximumChanged ) - Q_PROPERTY( QskIntervalF boundaries READ boundaries - WRITE setBoundaries NOTIFY boundariesChanged ) - Q_PROPERTY( qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged ) Q_PROPERTY( int pageSize READ pageSize WRITE setPageSize NOTIFY pageSizeChanged ) Q_PROPERTY( bool snap READ snap WRITE setSnap NOTIFY snapChanged ) Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly NOTIFY readOnlyChanged ) - using Inherited = QskControl; + using Inherited = QskBoundedControl; public: QSK_STATES( ReadOnly ) @@ -33,14 +28,6 @@ class QSK_EXPORT QskBoundedInput : public QskControl QskBoundedInput( QQuickItem* parent = nullptr ); ~QskBoundedInput() override; - qreal minimum() const; - qreal maximum() const; - - qreal boundaryLength() const; - - void setBoundaries( qreal min, qreal max ); - QskIntervalF boundaries() const; - qreal stepSize() const; int pageSize() const; @@ -51,10 +38,6 @@ class QSK_EXPORT QskBoundedInput : public QskControl bool isReadOnly() const; public Q_SLOTS: - void setMinimum( qreal ); - void setMaximum( qreal ); - void setBoundaries( const QskIntervalF& ); - void setStepSize( qreal ); void setPageSize( int ); @@ -66,10 +49,6 @@ class QSK_EXPORT QskBoundedInput : public QskControl virtual void increment( qreal offset ) = 0; Q_SIGNALS: - void minimumChanged( qreal ); - void maximumChanged( qreal ); - void boundariesChanged( const QskIntervalF& ); - void stepSizeChanged( qreal ); void pageSizeChanged( qreal ); void snapChanged( bool ); @@ -84,17 +63,15 @@ class QSK_EXPORT QskBoundedInput : public QskControl #endif void componentComplete() override; - virtual void alignInput(); qreal alignedValue( qreal ) const; QskIntervalF alignedInterval( const QskIntervalF& ) const; private: - void adjustBoundaries( bool increasing ); - - class PrivateData; - std::unique_ptr< PrivateData > m_data; + qreal m_stepSize = 0.1; + int m_pageSize = 1; + bool m_snap = false; }; #endif diff --git a/src/controls/QskBoundedRangeInput.cpp b/src/controls/QskBoundedRangeInput.cpp index 882dd2f1..3d6dd9cb 100644 --- a/src/controls/QskBoundedRangeInput.cpp +++ b/src/controls/QskBoundedRangeInput.cpp @@ -50,7 +50,7 @@ void QskBoundedRangeInput::setLowerValue( qreal value ) if ( isComponentComplete() ) { value = std::min( value, m_range.upperBound() ); - value = qBound( minimum(), value, maximum() ); + value = boundedValue( value ); } setRange( QskIntervalF( value, m_range.upperBound() ) ); @@ -66,7 +66,7 @@ void QskBoundedRangeInput::setUpperValue( qreal value ) if ( isComponentComplete() ) { value = std::max( m_range.lowerBound(), value ); - value = qBound( minimum(), value, maximum() ); + value = boundedValue( value ); } setRange( QskIntervalF( m_range.lowerBound(), value ) ); diff --git a/src/controls/QskBoundedValueInput.cpp b/src/controls/QskBoundedValueInput.cpp index 7a35515a..16832b7b 100644 --- a/src/controls/QskBoundedValueInput.cpp +++ b/src/controls/QskBoundedValueInput.cpp @@ -34,9 +34,9 @@ void QskBoundedValueInput::setValueAsRatio( qreal ratio ) setValue( minimum() + ratio * boundaryLength() ); } -qreal QskBoundedValueInput::valueAsRatio() const +qreal QskBoundedValueInput::valueAsRatio() const { - return ( m_value - minimum() ) / boundaryLength(); + return valueAsRatio( m_value ); } void QskBoundedValueInput::setValue( qreal value ) diff --git a/src/controls/QskBoundedValueInput.h b/src/controls/QskBoundedValueInput.h index 0b66ce3e..71d9f213 100644 --- a/src/controls/QskBoundedValueInput.h +++ b/src/controls/QskBoundedValueInput.h @@ -26,6 +26,7 @@ class QSK_EXPORT QskBoundedValueInput : public QskBoundedInput // [0.0, 1.0] qreal valueAsRatio() const; + using QskBoundedInput::valueAsRatio; public Q_SLOTS: void setValue( qreal ); diff --git a/src/src.pro b/src/src.pro index 37d4feae..7c2a3300 100644 --- a/src/src.pro +++ b/src/src.pro @@ -110,6 +110,7 @@ HEADERS += \ controls/QskAbstractButton.h \ controls/QskAnimationHint.h \ controls/QskAnimator.h \ + controls/QskBoundedControl.h \ controls/QskBoundedInput.h \ controls/QskBoundedRangeInput.h \ controls/QskBoundedValueInput.h \ @@ -180,6 +181,7 @@ HEADERS += \ SOURCES += \ controls/QskAbstractButton.cpp \ controls/QskAnimator.cpp \ + controls/QskBoundedControl.cpp \ controls/QskBoundedInput.cpp \ controls/QskBoundedRangeInput.cpp \ controls/QskBoundedValueInput.cpp \