Qt::FocusPolicy added. Hope this implementation does not break common

standards for mouse/wheel handling like being done in QC2
This commit is contained in:
Uwe Rathmann 2017-10-24 19:32:54 +02:00
parent 68125cfc7e
commit 2c0733182a
10 changed files with 170 additions and 65 deletions

View File

@ -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 );

View File

@ -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()

View File

@ -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;
}

View File

@ -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 )
};

View File

@ -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 )

View File

@ -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();

View File

@ -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 ) );
}

View File

@ -12,7 +12,9 @@
#include "QskWindow.h"
#include "QskObjectTree.h"
#include <QCoreApplication>
#include <QGuiApplication>
#include <QStyleHints>
#include <QPointer>
#include <QDebug>
@ -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();

View File

@ -84,6 +84,8 @@ private:
QskSetup();
virtual ~QskSetup();
virtual bool eventFilter( QObject*, QEvent* ) override final;
static QskSetup* s_instance;
class PrivateData;

View File

@ -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 )