improving focus handling after closing a popup
This commit is contained in:
parent
8cb65fefa6
commit
3f0075f616
@ -114,6 +114,14 @@ QQuickItem* qskNearestFocusScope( const QQuickItem* item )
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QList<QQuickItem *> qskPaintOrderChildItems( const QQuickItem* item )
|
||||
{
|
||||
if ( item )
|
||||
return QQuickItemPrivate::get( item )->paintOrderChildItems();
|
||||
|
||||
return QList<QQuickItem *>();
|
||||
}
|
||||
|
||||
const QSGNode* qskItemNode( const QQuickItem* item )
|
||||
{
|
||||
if ( item == nullptr )
|
||||
|
@ -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<QQuickItem *> qskPaintOrderChildItems( const QQuickItem* );
|
||||
|
||||
QSK_EXPORT const QSGNode* qskItemNode( const QQuickItem* );
|
||||
QSK_EXPORT const QSGNode* qskPaintNode( const QQuickItem* );
|
||||
|
@ -6,8 +6,6 @@
|
||||
#include "QskPopup.h"
|
||||
#include "QskAspect.h"
|
||||
#include <QQuickWindow>
|
||||
#include <QGuiApplication>
|
||||
#include <QStyleHints>
|
||||
#include <QtMath>
|
||||
|
||||
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 )
|
||||
|
@ -43,6 +43,8 @@ protected:
|
||||
virtual void itemChange( QQuickItem::ItemChange,
|
||||
const QQuickItem::ItemChangeData& ) override;
|
||||
|
||||
virtual QQuickItem* focusSuccessor() const;
|
||||
|
||||
void grabFocus( bool );
|
||||
|
||||
private:
|
||||
|
Loading…
x
Reference in New Issue
Block a user