focus navigation improved
This commit is contained in:
parent
3f0075f616
commit
5d91175d05
@ -42,6 +42,11 @@ static inline void qskSendEventTo( QObject* object, QEvent::Type type )
|
||||
QCoreApplication::sendEvent( object, &event );
|
||||
}
|
||||
|
||||
bool qskIsItemComplete( const QQuickItem* item )
|
||||
{
|
||||
return QQuickItemPrivate::get( item )->componentComplete;
|
||||
}
|
||||
|
||||
bool qskIsAncestorOf( const QQuickItem* item, const QQuickItem* child )
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
|
||||
@ -413,6 +418,12 @@ public:
|
||||
bool isWheelEnabled : 1;
|
||||
};
|
||||
|
||||
static void qskUpdateControlFlags( QskControl::Flags flags, QskControl* control )
|
||||
{
|
||||
auto d = static_cast< QskControlPrivate* >( QQuickItemPrivate::get( control ) );
|
||||
d->updateControlFlags( flags );
|
||||
}
|
||||
|
||||
QskControl::QskControl( QQuickItem* parent ):
|
||||
Inherited( *( new QskControlPrivate() ), parent )
|
||||
{
|
||||
@ -443,16 +454,18 @@ QskControl::QskControl( QQuickItem* parent ):
|
||||
qskRegistry->insert( this );
|
||||
}
|
||||
|
||||
static void qskUpdateControlFlags( QskControl::Flags flags, QskControl* control )
|
||||
{
|
||||
auto d = static_cast< QskControlPrivate* >( QQuickItemPrivate::get( control ) );
|
||||
d->updateControlFlags( flags );
|
||||
}
|
||||
|
||||
QskControl::~QskControl()
|
||||
{
|
||||
if ( qskRegistry )
|
||||
qskRegistry->remove( this );
|
||||
|
||||
/*
|
||||
We set componentComplete to false, so that operations
|
||||
that are triggered by detaching the item from its parent
|
||||
can be aware of the about-to-delete state.
|
||||
*/
|
||||
Q_D( QskControl );
|
||||
d->componentComplete = false;
|
||||
}
|
||||
|
||||
const char* QskControl::className() const
|
||||
@ -1089,8 +1102,11 @@ bool QskControl::event( QEvent* event )
|
||||
|
||||
if ( auto focusItem = nextItemInFocusChain( true ) )
|
||||
{
|
||||
if ( qskIsAncestorOf( this, focusItem ) )
|
||||
if ( qskIsItemComplete( focusItem )
|
||||
&& qskIsAncestorOf( this, focusItem ) )
|
||||
{
|
||||
focusItem->setFocus( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -241,6 +241,7 @@ inline QSizeF QskControl::sizeHint() const
|
||||
return effectiveConstraint( Qt::PreferredSize );
|
||||
}
|
||||
|
||||
QSK_EXPORT bool qskIsItemComplete( const QQuickItem* item );
|
||||
QSK_EXPORT bool qskIsAncestorOf( const QQuickItem* item, const QQuickItem *child );
|
||||
QSK_EXPORT bool qskIsTransparentForPositioner( const QQuickItem* );
|
||||
QSK_EXPORT bool qskIsTabFence( const QQuickItem* );
|
||||
|
@ -21,6 +21,23 @@ static inline bool qskIsUpdateBlocked( const QQuickItem* item )
|
||||
if ( const auto control = qobject_cast< const QskControl* >( item ) )
|
||||
return control->testControlFlag( QskControl::DeferredUpdate );
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Blocking items, that are outside the window would be easy,
|
||||
but we have not yet found a performant way to send update notifications
|
||||
when an item enters/leaves the window. TODO ...
|
||||
*/
|
||||
else if ( const auto control = qobject_cast< const QskControl* >( item ) )
|
||||
{
|
||||
const QRectF itemRect( item->mapToScene( QPointF() ), item->size() );
|
||||
const QRectF sceneRect( 0, 0, item->window()->width(), item->window()->height() );
|
||||
|
||||
return !itemRect.intersects( sceneRect );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -143,12 +143,13 @@ QRectF QskFocusIndicator::focusRect() const
|
||||
{
|
||||
if ( window() && parentItem() )
|
||||
{
|
||||
const QQuickItem* focusItem = window()->activeFocusItem();
|
||||
if ( focusItem && ( focusItem != this )
|
||||
&& ( focusItem != window()->contentItem() ) )
|
||||
const QQuickItem* item = window()->activeFocusItem();
|
||||
|
||||
if ( item && ( item != this ) && item->isVisible()
|
||||
&& ( item != window()->contentItem() ) )
|
||||
{
|
||||
const auto rect = qskFocusIndicatorRect( focusItem );
|
||||
return parentItem()->mapRectFromItem( focusItem, rect );
|
||||
const auto rect = qskFocusIndicatorRect( item );
|
||||
return parentItem()->mapRectFromItem( item, rect );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,8 +331,11 @@ QQuickItem* QskPopup::focusSuccessor() const
|
||||
{
|
||||
auto child = *it;
|
||||
|
||||
if ( child != this && child->isFocusScope() )
|
||||
if ( ( child != this ) && child->isFocusScope()
|
||||
&& child->activeFocusOnTab() && child->isVisible() )
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,12 +24,29 @@ QSK_QT_PRIVATE_END
|
||||
static void qskResolveLocale( QskWindow* );
|
||||
static bool qskEnforcedSkin = false;
|
||||
|
||||
static void qskSendEventTo( QObject* object, QEvent::Type type )
|
||||
static inline void qskSendEventTo( QObject* object, QEvent::Type type )
|
||||
{
|
||||
QEvent event( type );
|
||||
QCoreApplication::sendEvent( object, &event );
|
||||
}
|
||||
|
||||
static QQuickItem* qskDefaultFocusItem( QQuickWindow* window )
|
||||
{
|
||||
const auto children = qskPaintOrderChildItems( window->contentItem() );
|
||||
for ( auto it = children.crbegin(); it != children.crend(); ++it)
|
||||
{
|
||||
auto child = *it;
|
||||
|
||||
if ( child->isFocusScope() && child->isVisible()
|
||||
&& child->isEnabled() && child->activeFocusOnTab() )
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return window->contentItem()->nextItemInFocusChain( true );
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class ChildListener final : public QQuickItemChangeListener
|
||||
@ -187,7 +204,6 @@ bool QskWindow::autoLayoutChildren() const
|
||||
return d->autoLayoutChildren;
|
||||
}
|
||||
|
||||
|
||||
void QskWindow::addItem( QQuickItem* item )
|
||||
{
|
||||
if ( item == nullptr )
|
||||
@ -246,9 +262,49 @@ bool QskWindow::event( QEvent* event )
|
||||
return Inherited::event( event );
|
||||
}
|
||||
|
||||
void QskWindow::keyPressEvent( QKeyEvent* event )
|
||||
{
|
||||
if ( !( event->modifiers() & ( Qt::ControlModifier | Qt::AltModifier ) ) )
|
||||
{
|
||||
if ( ( event->key() == Qt::Key_Backtab ) || ( event->key() == Qt::Key_Tab ) )
|
||||
{
|
||||
auto focusItem = activeFocusItem();
|
||||
if ( focusItem == nullptr || focusItem == contentItem() )
|
||||
{
|
||||
/*
|
||||
The Qt/Quick implementation for navigating along the
|
||||
focus tab chain gives unsufficient results, when the
|
||||
starting point is the root item. In this specific
|
||||
situation we also have to include all items being
|
||||
tab fences into consideration.
|
||||
|
||||
In certain situations Qt/Quick gets even stuck in a non
|
||||
terminating loop: see Qt-Bug 65943
|
||||
|
||||
So we better block the focus navigation and find the
|
||||
next focus item on our own.
|
||||
*/
|
||||
ensureFocus( Qt::TabFocusReason );
|
||||
event->accept();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Inherited::keyPressEvent( event );
|
||||
}
|
||||
|
||||
void QskWindow::keyReleaseEvent( QKeyEvent* event )
|
||||
{
|
||||
Inherited::keyReleaseEvent( event );
|
||||
}
|
||||
|
||||
void QskWindow::exposeEvent( QExposeEvent* event )
|
||||
{
|
||||
ensureFocus( Qt::OtherFocusReason );
|
||||
layoutItems();
|
||||
|
||||
Inherited::exposeEvent( event );
|
||||
}
|
||||
|
||||
@ -391,6 +447,18 @@ void QskWindow::layoutItems()
|
||||
}
|
||||
}
|
||||
|
||||
void QskWindow::ensureFocus( Qt::FocusReason reason )
|
||||
{
|
||||
auto focusItem = contentItem()->scopedFocusItem();
|
||||
|
||||
if ( focusItem == nullptr )
|
||||
{
|
||||
focusItem = qskDefaultFocusItem( this );
|
||||
if ( focusItem )
|
||||
focusItem->setFocus( true, reason );
|
||||
}
|
||||
}
|
||||
|
||||
void QskWindow::setCustomRenderMode( const char* mode )
|
||||
{
|
||||
class RenderJob final : public QRunnable
|
||||
|
@ -82,8 +82,11 @@ protected:
|
||||
virtual bool event( QEvent* ) override;
|
||||
virtual void resizeEvent( QResizeEvent* ) override;
|
||||
virtual void exposeEvent( QExposeEvent* ) override;
|
||||
virtual void keyPressEvent(QKeyEvent *) override;
|
||||
virtual void keyReleaseEvent(QKeyEvent *) override;
|
||||
|
||||
virtual void layoutItems();
|
||||
virtual void ensureFocus( Qt::FocusReason );
|
||||
|
||||
private:
|
||||
void resizeFramebuffer();
|
||||
|
Loading…
x
Reference in New Issue
Block a user