From fefbbe1ffed87e3c9a4f17df76071218307f915c Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sat, 25 Jul 2020 14:19:14 +0200 Subject: [PATCH] QskBoundedInput added --- src/controls/QskBoundedInput.cpp | 282 ++++++++++++++++++++++++ src/controls/QskBoundedInput.h | 97 +++++++++ src/controls/QskBoundedValueInput.cpp | 294 ++------------------------ src/controls/QskBoundedValueInput.h | 78 +------ src/src.pro | 2 + 5 files changed, 412 insertions(+), 341 deletions(-) create mode 100644 src/controls/QskBoundedInput.cpp create mode 100644 src/controls/QskBoundedInput.h diff --git a/src/controls/QskBoundedInput.cpp b/src/controls/QskBoundedInput.cpp new file mode 100644 index 00000000..9624ca55 --- /dev/null +++ b/src/controls/QskBoundedInput.cpp @@ -0,0 +1,282 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#include "QskBoundedInput.h" +#include "QskFunctions.h" +#include "QskIntervalF.h" + +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() ) +{ + setFocusPolicy( Qt::StrongFocus ); + setAcceptedMouseButtons( Qt::LeftButton ); + setWheelEnabled( true ); +} + +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 ( qskFuzzyCompare( m_data->stepSize, stepSize ) ) + return; + + m_data->stepSize = stepSize; + Q_EMIT stepSizeChanged( stepSize ); + + update(); +} + +qreal QskBoundedInput::stepSize() const +{ + return m_data->stepSize; +} + +void QskBoundedInput::setPageSize( int pageSize ) +{ + if ( m_data->pageSize == pageSize ) + return; + + m_data->pageSize = pageSize; + Q_EMIT pageSizeChanged( pageSize ); + + update(); +} + +int QskBoundedInput::pageSize() const +{ + return m_data->pageSize; +} + +void QskBoundedInput::stepUp() +{ + increment( m_data->stepSize ); +} + +void QskBoundedInput::stepDown() +{ + increment( -m_data->stepSize ); +} + +void QskBoundedInput::pageUp() +{ + increment( m_data->pageSize * m_data->stepSize ); +} + +void QskBoundedInput::pageDown() +{ + increment( -m_data->pageSize * m_data->stepSize ); +} + +void QskBoundedInput::setSnap( bool snap ) +{ + if ( m_data->snap == snap ) + return; + + m_data->snap = snap; + Q_EMIT snapChanged( snap ); + + if ( snap ) + alignInput(); +} + +bool QskBoundedInput::snap() const +{ + return m_data->snap; +} + +void QskBoundedInput::setReadOnly( bool readOnly ) +{ + if ( readOnly == isReadOnly() ) + return; + + setSkinStateFlag( ReadOnly, readOnly ); + + // we are killing user settings here !! + setFocusPolicy( readOnly ? Qt::NoFocus : Qt::StrongFocus ); + setAcceptedMouseButtons( readOnly ? Qt::NoButton : Qt::LeftButton ); + setWheelEnabled( !readOnly ); + + Q_EMIT readOnlyChanged( readOnly ); +} + +bool QskBoundedInput::isReadOnly() const +{ + return skinState() & ReadOnly; +} + +void QskBoundedInput::keyPressEvent( QKeyEvent* event ) +{ + if ( !isReadOnly() ) + { + if ( event->key() == Qt::Key_Up || event->matches( QKeySequence::MoveToNextChar ) ) + { + increment( m_data->stepSize ); + return; + } + + if ( event->key() == Qt::Key_Down || event->matches( QKeySequence::MoveToPreviousChar ) ) + { + increment( -m_data->stepSize ); + return; + } + } + + Inherited::keyPressEvent( event ); +} + +#ifndef QT_NO_WHEELEVENT + +void QskBoundedInput::wheelEvent( QWheelEvent* event ) +{ + if ( isReadOnly() ) + return; + +#if QT_VERSION < 0x050e00 + const int wheelDelta = event->delta(); +#else + const auto delta = event->angleDelta(); + const int wheelDelta = ( qAbs( delta.x() ) > qAbs( delta.y() ) ) + ? delta.x() : delta.y(); +#endif + + const int steps = wheelDelta / QWheelEvent::DefaultDeltasPerStep; + increment( steps ); +} + +#endif + +void QskBoundedInput::componentComplete() +{ + Inherited::componentComplete(); + adjustBoundaries( true ); +} + +#include "moc_QskBoundedInput.cpp" diff --git a/src/controls/QskBoundedInput.h b/src/controls/QskBoundedInput.h new file mode 100644 index 00000000..4036d116 --- /dev/null +++ b/src/controls/QskBoundedInput.h @@ -0,0 +1,97 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#ifndef QSK_BOUNDED_INPUT_H +#define QSK_BOUNDED_INPUT_H + +#include "QskControl.h" + +class QskIntervalF; + +class QSK_EXPORT QskBoundedInput : 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 ) + + 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; + + public: + QSK_STATES( ReadOnly ) + + 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; + + void setSnap( bool ); + bool snap() const; + + void setReadOnly( bool ); + bool isReadOnly() const; + + public Q_SLOTS: + void setMinimum( qreal ); + void setMaximum( qreal ); + void setBoundaries( const QskIntervalF& ); + + void setStepSize( qreal ); + void setPageSize( int ); + + void stepUp(); + void stepDown(); + void pageUp(); + void pageDown(); + + 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 ); + + void readOnlyChanged( bool ); + + protected: + void keyPressEvent( QKeyEvent* event ) override; + +#ifndef QT_NO_WHEELEVENT + void wheelEvent( QWheelEvent* ) override; +#endif + + void componentComplete() override; + + virtual void alignInput() = 0; + + private: + void adjustBoundaries( bool increasing ); + + class PrivateData; + std::unique_ptr< PrivateData > m_data; +}; + +#endif diff --git a/src/controls/QskBoundedValueInput.cpp b/src/controls/QskBoundedValueInput.cpp index c8de265b..e7d1a53e 100644 --- a/src/controls/QskBoundedValueInput.cpp +++ b/src/controls/QskBoundedValueInput.cpp @@ -5,156 +5,38 @@ #include "QskBoundedValueInput.h" #include "QskFunctions.h" -#include "QskIntervalF.h" - -QSK_SYSTEM_STATE( QskBoundedValueInput, ReadOnly, ( QskAspect::FirstSystemState << 1 ) ) - -class QskBoundedValueInput::PrivateData -{ - public: - PrivateData() - : minimum( 0.0 ) - , maximum( 1.0 ) - , value( 0.0 ) - , stepSize( 0.1 ) - , pageSize( 1 ) - , snap( false ) - { - } - - qreal minimum; - qreal maximum; - qreal value; - qreal stepSize; - int pageSize; - bool snap : 1; -}; QskBoundedValueInput::QskBoundedValueInput( QQuickItem* parent ) - : QskControl( parent ) - , m_data( new PrivateData() ) + : QskBoundedInput( parent ) { - setFocusPolicy( Qt::StrongFocus ); - setAcceptedMouseButtons( Qt::LeftButton ); - setWheelEnabled( true ); } QskBoundedValueInput::~QskBoundedValueInput() { } -void QskBoundedValueInput::setMinimum( qreal minimum ) +qreal QskBoundedValueInput::alignedValue( qreal value ) const { - if ( m_data->minimum == minimum ) - return; - - m_data->minimum = minimum; - Q_EMIT minimumChanged( minimum ); - - if ( isComponentComplete() ) - adjustBoundariesAndValue( false ); - - Q_EMIT boundariesChanged( boundaries() ); - update(); -} - -qreal QskBoundedValueInput::minimum() const -{ - return m_data->minimum; -} - -void QskBoundedValueInput::setMaximum( qreal maximum ) -{ - if ( m_data->maximum == maximum ) - return; - - m_data->maximum = maximum; - Q_EMIT maximumChanged( maximum ); - - if ( isComponentComplete() ) - adjustBoundariesAndValue( true ); - - Q_EMIT boundariesChanged( boundaries() ); - update(); -} - -qreal QskBoundedValueInput::maximum() const -{ - return m_data->maximum; -} - -void QskBoundedValueInput::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() ) - adjustBoundariesAndValue( 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 QskBoundedValueInput::setBoundaries( const QskIntervalF& boundaries ) -{ - setBoundaries( boundaries.lowerBound(), boundaries.upperBound() ); -} - -QskIntervalF QskBoundedValueInput::boundaries() const -{ - return QskIntervalF( m_data->minimum, m_data->maximum ); -} - -void QskBoundedValueInput::adjustBoundariesAndValue( bool increasing ) -{ - if ( m_data->maximum < m_data->minimum ) + if ( snap() ) { - 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 ); - } + if ( const auto step = stepSize() ) + value = qRound( value / step ) * step; } - qreal newValue = m_data->value; + return qBound( minimum(), value, maximum() ); +} - if ( m_data->snap && m_data->stepSize != 0.0 ) - newValue = qRound( newValue / m_data->stepSize ) * m_data->stepSize; +void QskBoundedValueInput::alignInput() +{ + const auto newValue = alignedValue( m_value ); - newValue = qBound( m_data->minimum, newValue, m_data->maximum ); - - if ( newValue != m_data->value ) + if ( newValue != m_value ) { - m_data->value = newValue; + m_value = newValue; Q_EMIT valueChanged( newValue ); } } -qreal QskBoundedValueInput::boundaryLength() const -{ - return m_data->maximum - m_data->minimum; -} - qreal QskBoundedValueInput::fixupValue( qreal value ) const { return value; @@ -163,29 +45,26 @@ qreal QskBoundedValueInput::fixupValue( qreal value ) const void QskBoundedValueInput::setValueAsRatio( qreal ratio ) { ratio = qBound( 0.0, ratio, 1.0 ); - setValue( m_data->minimum + ratio * ( m_data->maximum - m_data->minimum ) ); + setValue( minimum() + ratio * boundaryLength() ); } qreal QskBoundedValueInput::valueAsRatio() const { - return ( m_data->value - m_data->minimum ) / ( m_data->maximum - m_data->minimum ); + return ( m_value - minimum() ) / boundaryLength(); } void QskBoundedValueInput::setValue( qreal value ) { if ( isComponentComplete() ) { - if ( m_data->snap && m_data->stepSize != 0.0 ) - value = qRound( value / m_data->stepSize ) * m_data->stepSize; - - value = qBound( m_data->minimum, value, m_data->maximum ); + value = alignedValue( value ); } value = fixupValue( value ); - if ( !qskFuzzyCompare( value, m_data->value ) ) + if ( !qskFuzzyCompare( value, m_value ) ) { - m_data->value = value; + m_value = value; Q_EMIT valueChanged( value ); update(); @@ -194,145 +73,12 @@ void QskBoundedValueInput::setValue( qreal value ) qreal QskBoundedValueInput::value() const { - return m_data->value; + return m_value; } -void QskBoundedValueInput::setStepSize( qreal stepSize ) +void QskBoundedValueInput::increment( qreal offset ) { - if ( qskFuzzyCompare( m_data->stepSize, stepSize ) ) - return; - - m_data->stepSize = stepSize; - Q_EMIT stepSizeChanged( stepSize ); - - update(); -} - -qreal QskBoundedValueInput::stepSize() const -{ - return m_data->stepSize; -} - -void QskBoundedValueInput::setPageSize( int pageSize ) -{ - if ( m_data->pageSize == pageSize ) - return; - - m_data->pageSize = pageSize; - Q_EMIT pageSizeChanged( pageSize ); - - update(); -} - -int QskBoundedValueInput::pageSize() const -{ - return m_data->pageSize; -} - -void QskBoundedValueInput::setSnap( bool snap ) -{ - if ( m_data->snap == snap ) - return; - - m_data->snap = snap; - Q_EMIT snapChanged( snap ); - - if ( snap ) - { - // Re-align value - } -} - -bool QskBoundedValueInput::snap() const -{ - return m_data->snap; -} - -void QskBoundedValueInput::setReadOnly( bool readOnly ) -{ - if ( readOnly == isReadOnly() ) - return; - - setSkinStateFlag( ReadOnly, readOnly ); - - // we are killing user settings here !! - setFocusPolicy( readOnly ? Qt::NoFocus : Qt::StrongFocus ); - setAcceptedMouseButtons( readOnly ? Qt::NoButton : Qt::LeftButton ); - setWheelEnabled( !readOnly ); - - Q_EMIT readOnlyChanged( readOnly ); -} - -bool QskBoundedValueInput::isReadOnly() const -{ - return skinState() & ReadOnly; -} - -void QskBoundedValueInput::stepUp() -{ - setValue( m_data->value + m_data->stepSize ); -} - -void QskBoundedValueInput::stepDown() -{ - setValue( m_data->value - m_data->stepSize ); -} - -void QskBoundedValueInput::pageUp() -{ - setValue( m_data->value + m_data->stepSize * m_data->pageSize ); -} - -void QskBoundedValueInput::pageDown() -{ - setValue( m_data->value - m_data->stepSize * m_data->pageSize ); -} - -void QskBoundedValueInput::keyPressEvent( QKeyEvent* event ) -{ - if ( !isReadOnly() ) - { - if ( event->key() == Qt::Key_Up || event->matches( QKeySequence::MoveToNextChar ) ) - { - stepUp(); - return; - } - - if ( event->key() == Qt::Key_Down || event->matches( QKeySequence::MoveToPreviousChar ) ) - { - stepDown(); - return; - } - } - - Inherited::keyPressEvent( event ); -} - -#ifndef QT_NO_WHEELEVENT - -void QskBoundedValueInput::wheelEvent( QWheelEvent* event ) -{ - if ( isReadOnly() ) - return; - -#if QT_VERSION < 0x050e00 - const int wheelDelta = event->delta(); -#else - const auto delta = event->angleDelta(); - const int wheelDelta = ( qAbs( delta.x() ) > qAbs( delta.y() ) ) - ? delta.x() : delta.y(); -#endif - - const int steps = wheelDelta / QWheelEvent::DefaultDeltasPerStep; - setValue( m_data->value + steps * m_data->stepSize ); -} - -#endif - -void QskBoundedValueInput::componentComplete() -{ - Inherited::componentComplete(); - adjustBoundariesAndValue( true ); + setValue( m_value + offset ); } #include "moc_QskBoundedValueInput.cpp" diff --git a/src/controls/QskBoundedValueInput.h b/src/controls/QskBoundedValueInput.h index 64280545..c8ebdbcc 100644 --- a/src/controls/QskBoundedValueInput.h +++ b/src/controls/QskBoundedValueInput.h @@ -6,101 +6,45 @@ #ifndef QSK_BOUNDED_VALUE_INPUT_H #define QSK_BOUNDED_VALUE_INPUT_H -#include "QskControl.h" +#include "QskBoundedInput.h" -class QskIntervalF; - -class QSK_EXPORT QskBoundedValueInput : public QskControl +class QSK_EXPORT QskBoundedValueInput : public QskBoundedInput { 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 value READ value WRITE setValue NOTIFY valueChanged ) + Q_PROPERTY( qreal valueAsRatio READ valueAsRatio + WRITE setValueAsRatio NOTIFY valueChanged ) - 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 = QskBoundedInput; public: - QSK_STATES( ReadOnly ) - QskBoundedValueInput( QQuickItem* parent = nullptr ); ~QskBoundedValueInput() override; - qreal minimum() const; - qreal maximum() const; - - qreal boundaryLength() const; - - void setBoundaries( qreal min, qreal max ); - QskIntervalF boundaries() const; - qreal value() const; // [0.0, 1.0] qreal valueAsRatio() const; - qreal stepSize() const; - int pageSize() const; - - void setSnap( bool ); - bool snap() const; - - void setReadOnly( bool ); - bool isReadOnly() const; - public Q_SLOTS: void setValue( qreal ); void setValueAsRatio( qreal ); - - void setMinimum( qreal ); - void setMaximum( qreal ); - void setBoundaries( const QskIntervalF& ); - - void setStepSize( qreal ); - void setPageSize( int ); - - void stepUp(); - void stepDown(); - void pageUp(); - void pageDown(); + void increment( qreal offset ) override; Q_SIGNALS: void valueChanged( qreal ); - void minimumChanged( qreal ); - void maximumChanged( qreal ); - void boundariesChanged( const QskIntervalF& ); - - void stepSizeChanged( qreal ); - void pageSizeChanged( qreal ); - void snapChanged( bool ); - - void readOnlyChanged( bool ); - protected: virtual qreal fixupValue( qreal value ) const; - void keyPressEvent( QKeyEvent* event ) override; - -#ifndef QT_NO_WHEELEVENT - void wheelEvent( QWheelEvent* ) override; -#endif - - void componentComplete() override; + void alignInput() override; private: - void adjustBoundariesAndValue( bool ); + void adjustValue(); - class PrivateData; - std::unique_ptr< PrivateData > m_data; + qreal alignedValue( qreal value ) const; + + qreal m_value = 0.0; }; #endif diff --git a/src/src.pro b/src/src.pro index ab6d0515..1ca8aeaa 100644 --- a/src/src.pro +++ b/src/src.pro @@ -110,6 +110,7 @@ HEADERS += \ controls/QskAbstractButton.h \ controls/QskAnimationHint.h \ controls/QskAnimator.h \ + controls/QskBoundedInput.h \ controls/QskBoundedValueInput.h \ controls/QskBox.h \ controls/QskBoxSkinlet.h \ @@ -178,6 +179,7 @@ HEADERS += \ SOURCES += \ controls/QskAbstractButton.cpp \ controls/QskAnimator.cpp \ + controls/QskBoundedInput.cpp \ controls/QskBoundedValueInput.cpp \ controls/QskBox.cpp \ controls/QskBoxSkinlet.cpp \