From 3f0075f61609791a368e35be6b1862b6145a6b1e Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 21 Jan 2018 14:10:12 +0100 Subject: [PATCH] improving focus handling after closing a popup --- src/controls/QskControl.cpp | 8 +++ src/controls/QskControl.h | 1 + src/controls/QskPopup.cpp | 101 ++++++++++-------------------------- src/controls/QskPopup.h | 2 + 4 files changed, 37 insertions(+), 75 deletions(-) diff --git a/src/controls/QskControl.cpp b/src/controls/QskControl.cpp index 437bac8c..9cbc4171 100644 --- a/src/controls/QskControl.cpp +++ b/src/controls/QskControl.cpp @@ -114,6 +114,14 @@ QQuickItem* qskNearestFocusScope( const QQuickItem* item ) return nullptr; } +QList qskPaintOrderChildItems( const QQuickItem* item ) +{ + if ( item ) + return QQuickItemPrivate::get( item )->paintOrderChildItems(); + + return QList(); +} + const QSGNode* qskItemNode( const QQuickItem* item ) { if ( item == nullptr ) diff --git a/src/controls/QskControl.h b/src/controls/QskControl.h index 681c9177..016e12c1 100644 --- a/src/controls/QskControl.h +++ b/src/controls/QskControl.h @@ -247,6 +247,7 @@ QSK_EXPORT bool qskIsTabFence( const QQuickItem* ); QSK_EXPORT bool qskIsShortcutScope( const QQuickItem* ); QSK_EXPORT QQuickItem* qskNearestFocusScope( const QQuickItem* ); +QSK_EXPORT QList qskPaintOrderChildItems( const QQuickItem* ); QSK_EXPORT const QSGNode* qskItemNode( const QQuickItem* ); QSK_EXPORT const QSGNode* qskPaintNode( const QQuickItem* ); diff --git a/src/controls/QskPopup.cpp b/src/controls/QskPopup.cpp index f203517a..ce15e07e 100644 --- a/src/controls/QskPopup.cpp +++ b/src/controls/QskPopup.cpp @@ -6,8 +6,6 @@ #include "QskPopup.h" #include "QskAspect.h" #include -#include -#include #include QSK_QT_PRIVATE_BEGIN @@ -17,7 +15,7 @@ QSK_QT_PRIVATE_END QSK_SUBCONTROL( QskPopup, Overlay ) -static void qskSetFocusInScope( QQuickItem* item, bool on ) +static void qskSetFocus( QQuickItem* item, bool on ) { if ( item->window() == nullptr ) return; @@ -39,71 +37,6 @@ static void qskSetFocusInScope( QQuickItem* item, bool on ) } } -static QQuickItem* qskNextFocusItem( const QskPopup* popup ) -{ - if ( popup == nullptr || popup->parentItem() == nullptr ) - return nullptr; - - const auto children = popup->parentItem()->childItems(); - if ( children.count() <= 1 ) - return nullptr; - - QskPopup* modalPopup = nullptr; - - for ( auto child : children ) - { - if ( ( child != popup ) && child->isVisible() ) - { - if ( auto otherPopup = qobject_cast< QskPopup* >( child ) ) - { - if ( !otherPopup->isModal() || ( modalPopup != nullptr ) ) - { - /* - We can't decide, wether to give the focus to - one of the popups or the top level item - */ - return nullptr; - } - - modalPopup = otherPopup; - } - } - } - - if ( modalPopup ) - { - // Exactly one popup, that is modal. - return modalPopup; - } - - const auto tabFocusBehavior = QGuiApplication::styleHints()->tabFocusBehavior(); - - int i = 0; - while( children[i] != popup ) - i++; - - for ( int j = i - 1; j != i; j-- ) - { - auto item = children[j]; - if ( item->isEnabled() && item->isVisible() ) - { - if ( item->activeFocusOnTab() ) - { - if ( ( tabFocusBehavior == Qt::TabFocusAllControls ) || - QQuickItemPrivate::canAcceptTabFocus( item ) ) - { - return item; - } - } - } - - if ( j == 0 ) - j = children.count(); - } - - return nullptr; -} - namespace { class InputGrabber final : public QQuickItem @@ -339,11 +272,11 @@ void QskPopup::grabFocus( bool on ) if ( on ) { - qskSetFocusInScope( this, true ); + qskSetFocus( this, true ); } else { - QQuickItem* focusItem = nullptr; + QQuickItem* successor = nullptr; if ( m_data->handoverFocus ) { @@ -352,13 +285,14 @@ void QskPopup::grabFocus( bool on ) when the active focus gets lost. For the situation of a popup being closed we try to do it. */ - focusItem = qskNextFocusItem( this ); + successor = focusSuccessor(); } - if ( focusItem ) - qskSetFocusInScope( focusItem, true ); - else - qskSetFocusInScope( this, false ); + if ( successor ) + qskSetFocus( successor, true ); + + if ( hasFocus() ) + qskSetFocus( this, false ); } } @@ -388,6 +322,23 @@ bool QskPopup::event( QEvent* event ) return ok; } +QQuickItem* QskPopup::focusSuccessor() const +{ + if ( const auto scope = qskNearestFocusScope( this ) ) + { + const auto children = qskPaintOrderChildItems( scope ); + for ( auto it = children.crbegin(); it != children.crend(); ++it) + { + auto child = *it; + + if ( child != this && child->isFocusScope() ) + return child; + } + } + + return nullptr; +} + void QskPopup::updateLayout() { if ( !m_data->isOpen ) diff --git a/src/controls/QskPopup.h b/src/controls/QskPopup.h index 63bb47e7..41f98fb3 100644 --- a/src/controls/QskPopup.h +++ b/src/controls/QskPopup.h @@ -43,6 +43,8 @@ protected: virtual void itemChange( QQuickItem::ItemChange, const QQuickItem::ItemChangeData& ) override; + virtual QQuickItem* focusSuccessor() const; + void grabFocus( bool ); private: