diff --git a/playground/inputpanel/LineEdit.cpp b/playground/inputpanel/LineEdit.cpp index 599c520c..cfba9241 100644 --- a/playground/inputpanel/LineEdit.cpp +++ b/playground/inputpanel/LineEdit.cpp @@ -50,7 +50,7 @@ LineEdit::LineEdit( QQuickItem* parent ): Q_D( LineEdit ); d->init(); - setActiveFocusOnTab( true ); + setFocusPolicy( Qt::StrongFocus ); #if 1 auto skinlet = new LineEditSkinlet(); skinlet->setOwnedBySkinnable( true ); diff --git a/src/controls/QskAbstractButton.cpp b/src/controls/QskAbstractButton.cpp index 2e4e93d9..5f7467d4 100644 --- a/src/controls/QskAbstractButton.cpp +++ b/src/controls/QskAbstractButton.cpp @@ -56,9 +56,9 @@ QskAbstractButton::QskAbstractButton( QQuickItem* parent ): Inherited( parent ), m_data( new PrivateData() ) { + setFocusPolicy( Qt::StrongFocus ); setAcceptedMouseButtons( Qt::LeftButton ); setAcceptHoverEvents( true ); - setActiveFocusOnTab( true ); } QskAbstractButton::~QskAbstractButton() @@ -302,21 +302,15 @@ void QskAbstractButton::mouseMoveEvent( QMouseEvent* event ) event->accept(); } -void QskAbstractButton::mousePressEvent( QMouseEvent* event ) +void QskAbstractButton::mousePressEvent( QMouseEvent* ) { - // QPlatformTheme::GroupBoxTitleFont - // isSignalConnected( pressAndHold, ()); - // QGuiApplication::styleHints()->mousePressAndHoldInterval() + // QGuiApplication::styleHints()->mousePressAndHoldInterval() ??? setPressed( true ); - forceActiveFocus( Qt::MouseFocusReason ); - - event->accept(); } -void QskAbstractButton::mouseReleaseEvent( QMouseEvent* event ) +void QskAbstractButton::mouseReleaseEvent( QMouseEvent* ) { releaseButton(); - event->accept(); } void QskAbstractButton::mouseUngrabEvent() diff --git a/src/controls/QskControl.cpp b/src/controls/QskControl.cpp index 9420c3cc..005eaeca 100644 --- a/src/controls/QskControl.cpp +++ b/src/controls/QskControl.cpp @@ -175,7 +175,9 @@ QskControl::QskControl( QQuickItemPrivate& dd, QQuickItem* parent ): m_blockedPolish( false ), m_blockedImplicitSize( true ), m_clearPreviousNodes( false ), - m_isInitiallyPainted( false ) + m_isInitiallyPainted( false ), + m_focusPolicy( Qt::NoFocus ), + m_isWheelEnabled( false ) { Q_D( QskControl ); @@ -198,7 +200,7 @@ QskControl::QskControl( QQuickItemPrivate& dd, QQuickItem* parent ): } setFlag( QQuickItem::ItemHasContents, true ); - setActiveFocusOnTab( false ); + QQuickItem::setActiveFocusOnTab( false ); if ( parent ) { @@ -368,6 +370,44 @@ bool QskControl::polishOnResize() const return m_polishOnResize; } +void QskControl::setWheelEnabled( bool on ) +{ + if ( on != m_isWheelEnabled ) + { + m_isWheelEnabled = on; + // Q_EMIT wheelEnabledChanged(); + } +} + +bool QskControl::isWheelEnabled() const +{ + return m_isWheelEnabled; +} + +void QskControl::setFocusPolicy( Qt::FocusPolicy policy ) +{ + if ( policy != m_focusPolicy ) + { + m_focusPolicy = policy & ~Qt::TabFocus; + QQuickItem::setActiveFocusOnTab( policy & Qt::TabFocus ); + +#if 0 + // we have to get rid of the hack used in playground/inputpanel + // so that we can add additional signals !!! + Q_EMIT ( focusPolicyChanged() ); +#endif + } +} + +Qt::FocusPolicy QskControl::focusPolicy() const +{ + uint policy = m_focusPolicy; + if ( activeFocusOnTab() ) + policy |= Qt::TabFocus; + + return static_cast< Qt::FocusPolicy >( policy ); +} + void QskControl::setTabFence( bool on ) { Q_D( QskControl ); @@ -1068,7 +1108,6 @@ void QskControl::itemChange( QQuickItem::ItemChange change, } case QQuickItem::ItemActiveFocusHasChanged: { - // creating focus events ??? setSkinStateFlag( Focused, hasActiveFocus() ); break; } diff --git a/src/controls/QskControl.h b/src/controls/QskControl.h index bc83af66..57adca9a 100644 --- a/src/controls/QskControl.h +++ b/src/controls/QskControl.h @@ -44,6 +44,17 @@ class QSK_EXPORT QskControl : public QQuickItem, public QskResizable, public Qsk Q_PROPERTY( bool transparentForPositioners READ isTransparentForPositioner WRITE setTransparentForPositioner NOTIFY controlFlagsChanged FINAL ) +#if 0 + Q_PROPERTY( Qt::FocusPolicy focusPolicy READ focusPolicy + WRITE setFocusPolicy NOTIFY focusPolicyChanged FINAL ) + + Q_PROPERTY( bool wheelEnabled READ isWheelEnabled + WRITE setWheelEnabled NOTIFY wheelEnabledChanged FINAL ) +#else + Q_PROPERTY( Qt::FocusPolicy focusPolicy READ focusPolicy WRITE setFocusPolicy FINAL ) + Q_PROPERTY( bool wheelEnabled READ isWheelEnabled WRITE setWheelEnabled FINAL ) +#endif + Q_PROPERTY( bool tabFence READ isTabFence WRITE setTabFence NOTIFY controlFlagsChanged FINAL ) @@ -56,11 +67,6 @@ class QSK_EXPORT QskControl : public QQuickItem, public QskResizable, public Qsk Q_PROPERTY( QSizeF maximumSize READ maximumSize WRITE setMaximumSize ) Q_PROPERTY( QSizeF preferredSize READ preferredSize WRITE setPreferredSize ) -#if 0 - Q_PROPERTY(Qt::FocusPolicy focusPolicy READ focusPolicy - WRITE setFocusPolicy NOTIFY focusPolicyChanged FINAL) -#endif - using Inherited = QQuickItem; public: @@ -122,6 +128,12 @@ public: static const QSGNode* itemNode( const QQuickItem* ); static const QSGNode* paintNode( const QQuickItem* ); + void setWheelEnabled( bool ); + bool isWheelEnabled() const; + + void setFocusPolicy( Qt::FocusPolicy ); + Qt::FocusPolicy focusPolicy() const; + void setTabFence( bool ); bool isTabFence() const; @@ -203,6 +215,8 @@ private Q_SLOTS: void updateControlFlags(); private: + void setActiveFocusOnTab( bool ) = delete; // use setFocusPolicy instead + virtual QSGNode* updatePaintNode( QSGNode*, UpdatePaintNodeData* ) override final; virtual void updatePolish() override final; @@ -237,6 +251,9 @@ private: bool m_isInitiallyPainted : 1; + uint m_focusPolicy : 4; + bool m_isWheelEnabled; + Q_DECLARE_PRIVATE( QskControl ) }; diff --git a/src/controls/QskListView.cpp b/src/controls/QskListView.cpp index 56f85612..39ad4837 100644 --- a/src/controls/QskListView.cpp +++ b/src/controls/QskListView.cpp @@ -35,7 +35,6 @@ QskListView::QskListView( QQuickItem* parent ): QskScrollView( parent ), m_data( new PrivateData() ) { - setAcceptedMouseButtons( Qt::LeftButton ); } QskListView::~QskListView() @@ -248,8 +247,6 @@ void QskListView::keyReleaseEvent( QKeyEvent* event ) void QskListView::mousePressEvent( QMouseEvent* event ) { - forceActiveFocus( Qt::MouseFocusReason ); - if ( m_data->selectionMode != NoSelection ) { const QRectF vr = viewContentsRect(); @@ -258,12 +255,8 @@ void QskListView::mousePressEvent( QMouseEvent* event ) const int row = ( event->pos().y() - vr.top() + scrollPos().y() ) / rowHeight(); if ( row >= 0 && row < rowCount() ) setSelectedRow( row ); - - return; } } - - Inherited::mousePressEvent( event ); } void QskListView::mouseReleaseEvent( QMouseEvent* event ) diff --git a/src/controls/QskRangeControl.cpp b/src/controls/QskRangeControl.cpp index 2559bf26..4c08dbc7 100644 --- a/src/controls/QskRangeControl.cpp +++ b/src/controls/QskRangeControl.cpp @@ -34,8 +34,8 @@ QskRangeControl::QskRangeControl( QQuickItem* parent ): QskControl( parent ), m_data( new PrivateData() ) { - setActiveFocusOnTab( !m_data->readOnly ); setAcceptedMouseButtons( Qt::LeftButton ); + setWheelEnabled( true ); } QskRangeControl::~QskRangeControl() @@ -219,7 +219,9 @@ void QskRangeControl::setReadOnly( bool readOnly ) if ( m_data->readOnly == readOnly ) return; - setActiveFocusOnTab( !readOnly ); + // we are killing user settings here !! + setFocusPolicy( m_data->readOnly ? Qt::NoFocus : Qt::StrongFocus ); + setWheelEnabled( m_data->readOnly ); m_data->readOnly = readOnly; Q_EMIT readOnlyChanged( readOnly ); @@ -274,18 +276,12 @@ void QskRangeControl::keyPressEvent( QKeyEvent* event ) void QskRangeControl::wheelEvent( QWheelEvent* event ) { - if ( isReadOnly() ) - { - return Inherited::wheelEvent( event ); - } - const int steps = event->delta() / 120; setValue( m_data->value + steps * m_data->stepSize ); } #endif - void QskRangeControl::componentComplete() { Inherited::componentComplete(); diff --git a/src/controls/QskScrollView.cpp b/src/controls/QskScrollView.cpp index f0b72d54..95b7b46a 100644 --- a/src/controls/QskScrollView.cpp +++ b/src/controls/QskScrollView.cpp @@ -85,7 +85,8 @@ QskScrollView::QskScrollView( QQuickItem* parent ): m_data->panRecognizer.setTimeout( 200 ); setAcceptedMouseButtons( Qt::LeftButton ); - setActiveFocusOnTab( true ); + setWheelEnabled( true ); + setFocusPolicy( Qt::StrongFocus ); } QskScrollView::~QskScrollView() @@ -256,11 +257,7 @@ void QskScrollView::mousePressEvent( QMouseEvent* event ) setScrollPos( QPointF( x, m_data->scrollPos.y() ) ); } - - return; } - - Inherited::mousePressEvent( event ); } void QskScrollView::mouseMoveEvent( QMouseEvent* event ) @@ -294,7 +291,7 @@ void QskScrollView::mouseMoveEvent( QMouseEvent* event ) setScrollPos( pos ); } -void QskScrollView::mouseReleaseEvent( QMouseEvent* event ) +void QskScrollView::mouseReleaseEvent( QMouseEvent* ) { if ( m_data->isScrolling ) { @@ -303,11 +300,7 @@ void QskScrollView::mouseReleaseEvent( QMouseEvent* event ) setSkinStateFlag( HorizontalHandlePressed, false ); setSkinStateFlag( VerticalHandlePressed, false ); - - return; } - - Inherited::mouseReleaseEvent( event ); } void QskScrollView::gestureEvent( QskGestureEvent* event ) @@ -347,11 +340,6 @@ void QskScrollView::gestureEvent( QskGestureEvent* event ) void QskScrollView::wheelEvent( QWheelEvent* event ) { - if ( !isEnabled() ) - { - return Inherited::wheelEvent( event ); - } - const qreal dy = event->delta() / 120 * 20.0; setScrollPos( m_data->scrollPos - QPointF( 0.0, dy ) ); } diff --git a/src/controls/QskSetup.cpp b/src/controls/QskSetup.cpp index 6c8277e6..a1481b62 100644 --- a/src/controls/QskSetup.cpp +++ b/src/controls/QskSetup.cpp @@ -12,7 +12,9 @@ #include "QskWindow.h" #include "QskObjectTree.h" -#include +#include +#include + #include #include @@ -66,7 +68,13 @@ static void qskApplicationHook() qAddPostRoutine( QskSetup::cleanup ); } +static void qskApplicationFilter() +{ + QCoreApplication::instance()->installEventFilter( QskSetup::instance() ); +} + Q_CONSTRUCTOR_FUNCTION( qskApplicationHook ) +Q_COREAPP_STARTUP_FUNCTION( qskApplicationFilter ) extern bool qskInheritLocale( QskControl*, const QLocale& ); extern bool qskInheritLocale( QskWindow*, const QLocale& ); @@ -260,7 +268,7 @@ QskSkin* QskSetup::skin() void QskSetup::addGraphicProvider( const QString& providerId, QskGraphicProvider* provider ) { m_data->graphicProviders.insert( providerId, provider ); -} +} QskGraphicProvider* QskSetup::graphicProvider( const QString& providerId ) const { @@ -272,7 +280,7 @@ QskGraphicProvider* QskSetup::graphicProvider( const QString& providerId ) const } return m_data->graphicProviders.provider( providerId ); -} +} void QskSetup::setInputPanel( QskInputPanel* inputPanel ) { @@ -306,6 +314,75 @@ void QskSetup::inheritLocale( QObject* object, const QLocale& locale ) QskObjectTree::traverseDown( object, visitor ); } +bool QskSetup::eventFilter( QObject* object, QEvent* event ) +{ + if ( auto control = qobject_cast< QskControl* >( object ) ) + { + /* + Qt::FocusPolicy has always been there with widgets, got lost with + Qt/Quick and has been reintroduced with Qt/Quick Controls 2 ( QC2 ). + Unfortunately this was done once more by adding code on top instead + of fixing the foundation. + + But we also don't want to have how it is done in QC2 by adding + the focus management in the event handler of the base class. + This implementatio reverts the expected default behaviour of when + events are accepted/ignored + is an error prone nightmare, when it + comes to overloading event handlers missing to call the base class. + + That's why we prefer to do the focus management outside of the + event handlers. + */ + switch( event->type() ) + { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + { + if ( ( control->focusPolicy() & Qt::ClickFocus ) == Qt::ClickFocus ) + { + const bool focusOnRelease = + QGuiApplication::styleHints()->setFocusOnTouchRelease(); + + if ( focusOnRelease ) + { + if ( event->type() == QEvent::MouseButtonRelease ) + control->forceActiveFocus( Qt::MouseFocusReason ); + } + else + { + if ( event->type() == QEvent::MouseButtonPress ) + control->forceActiveFocus( Qt::MouseFocusReason ); + } + } + break; + } + case QEvent::Wheel: + { + if ( !control->isWheelEnabled() ) + { + /* + We block further processing of the event. This is in line + with not receiving any mouse event that have not been + explicitly enabled with setAcceptedMouseButtons(). + + */ + event->ignore(); + return true; + } + + if ( ( control->focusPolicy() & Qt::WheelFocus ) == Qt::WheelFocus ) + control->forceActiveFocus( Qt::MouseFocusReason ); + + break; + } + default: + break; + } + } + + return false; +} + QskSetup* QskSetup::qmlAttachedProperties( QObject* ) { return QskSetup::instance(); diff --git a/src/controls/QskSetup.h b/src/controls/QskSetup.h index a0cd5595..891b5298 100644 --- a/src/controls/QskSetup.h +++ b/src/controls/QskSetup.h @@ -84,6 +84,8 @@ private: QskSetup(); virtual ~QskSetup(); + virtual bool eventFilter( QObject*, QEvent* ) override final; + static QskSetup* s_instance; class PrivateData; diff --git a/src/controls/QskSlider.cpp b/src/controls/QskSlider.cpp index 6ff37591..7a5524ec 100644 --- a/src/controls/QskSlider.cpp +++ b/src/controls/QskSlider.cpp @@ -45,7 +45,7 @@ QskSlider::QskSlider( Qt::Orientation orientation, QQuickItem* parent ): m_data( new PrivateData( orientation ) ) { setAcceptHoverEvents( true ); - setActiveFocusOnTab( true ); + setFocusPolicy(Qt::StrongFocus); if ( orientation == Qt::Horizontal ) initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Fixed ); @@ -130,27 +130,26 @@ QRectF QskSlider::handleRect() const void QskSlider::mousePressEvent( QMouseEvent* event ) { - // Case 1: press started in the handle, start sliding - if ( handleRect().contains( event->pos() ) ) { + // Case 1: press started in the handle, start sliding + m_data->pressedPos = event->pos(); m_data->pressedValue = value(); setSkinStateFlag( Pressed ); Q_EMIT pressedChanged( true ); - return; } - - // Case 2: pageSize is not used, we're done here - if ( !pageSize() ) + else if ( !pageSize() ) { - event->ignore(); - return; + // 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) } - - // 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) - } void QskSlider::mouseMoveEvent( QMouseEvent* event )