QskControl::focusIndicatorClipRect added

This commit is contained in:
Uwe Rathmann 2020-03-16 13:17:51 +01:00
parent b1c3c11984
commit 6ea56cdf30
8 changed files with 81 additions and 74 deletions

View File

@ -99,7 +99,7 @@ int main( int argc, char* argv[] )
auto layoutBox = new QskLinearBox( Qt::Vertical );
layoutBox->setDefaultAlignment( Qt::AlignLeft );
layoutBox->setMargins( 5 );
layoutBox->setMargins( 20 );
layoutBox->setSpacing( 10 );
layoutBox->addItem( buttonBox );
layoutBox->addItem( tabView );

View File

@ -959,13 +959,9 @@ QRectF QskControl::focusIndicatorRect() const
return contentsRect();
}
bool QskControl::hasFocusIndicatorClip() const
QRectF QskControl::focusIndicatorClipRect() const
{
/*
Often we want to clip the focus indicator,
when the control is clipped.
*/
return clip();
return clipRect();
}
void QskControl::updateLayout()

View File

@ -93,7 +93,7 @@ class QSK_EXPORT QskControl : public QskQuickItem, public QskSkinnable
virtual QRectF gestureRect() const;
virtual QRectF focusIndicatorRect() const;
virtual bool hasFocusIndicatorClip() const;
virtual QRectF focusIndicatorClipRect() const;
QRectF subControlRect( QskAspect::Subcontrol ) const;
QRectF subControlRect( const QSizeF&, QskAspect::Subcontrol ) const;

View File

@ -8,6 +8,7 @@
#include "QskEvent.h"
#include "QskQuick.h"
#include <qpointer.h>
#include <qquickwindow.h>
QSK_SUBCONTROL( QskFocusIndicator, Panel )
@ -24,6 +25,21 @@ static inline QRectF qskFocusIndicatorRect( const QQuickItem* item )
return qskItemRect( item );
}
static inline QRectF qskFocusIndicatorClipRect( const QQuickItem* item )
{
QRectF rect( 0.0, 0.0, -1.0, -1.0 );
if ( item )
{
if ( auto control = qskControlCast( item ) )
rect = control->focusIndicatorClipRect();
else
rect = item->clipRect();
}
return rect;
}
class QskFocusIndicator::PrivateData
{
public:
@ -35,6 +51,7 @@ class QskFocusIndicator::PrivateData
connections.clear();
}
QPointer< QQuickItem > clippingItem;
QVector< QMetaObject::Connection > connections;
};
@ -55,6 +72,19 @@ bool QskFocusIndicator::contains( const QPointF& ) const
return false;
}
QRectF QskFocusIndicator::clipRect() const
{
if ( m_data->clippingItem )
{
auto rect = qskFocusIndicatorClipRect( m_data->clippingItem );
rect = mapRectFromItem( m_data->clippingItem, rect );
return rect;
}
return Inherited::clipRect();
}
void QskFocusIndicator::onFocusItemGeometryChanged()
{
updateFocusFrame();
@ -78,64 +108,34 @@ void QskFocusIndicator::onFocusItemChanged()
if ( window() == nullptr )
return;
const auto focusItem = window()->activeFocusItem();
if ( ( focusItem == nullptr ) || ( focusItem == window()->contentItem() ) )
{
/*
We might get here, when the previously focused item was destroyed.
Might happen in common situations, like when a subwindow
was closed. We put ourself below the root item then.
*/
if ( parentItem() != window()->contentItem() )
setParentItem( window()->contentItem() );
updateFocusFrame();
return;
}
m_data->connections += connectItem( focusItem );
const QQuickItem* item = focusItem;
while ( item->parentItem() )
{
auto itemParent = item->parentItem();
bool doReparent = ( itemParent == window()->contentItem() );
if ( !doReparent )
{
/*
When the focus item is clipped - maybe because of being at the
border of a scrollarea - the focus indicator might need to be
clipped as well. The easiest way to have this is to put us
below the item having the clip.
*/
if ( auto control = qskControlCast( itemParent ) )
doReparent = control->hasFocusIndicatorClip();
else
doReparent = itemParent->clip();
}
if ( doReparent )
setParentItem( itemParent );
if ( itemParent == parentItem() )
{
// We want to be on top, but do we cover all corner cases ???
setParentItem( window()->contentItem() );
setZ( 10e-6 );
setZ( item->z() + 10e-6 );
break;
const auto focusItem = window()->activeFocusItem();
QQuickItem* clippingItem = nullptr;
if ( focusItem && ( focusItem != window()->contentItem() ) )
{
auto item = focusItem;
m_data->connections += connectItem( item );
while ( auto itemParent = item->parentItem() )
{
m_data->connections += connectItem( itemParent );
if ( clippingItem == nullptr && itemParent->clip() )
{
const auto clipRect = qskFocusIndicatorClipRect( itemParent );
if ( !clipRect.isEmpty() )
clippingItem = itemParent;
}
item = itemParent;
m_data->connections += connectItem( item );
}
}
m_data->clippingItem = clippingItem;
updateFocusFrame();
}
@ -148,6 +148,9 @@ void QskFocusIndicator::updateFocusFrame()
{
r = r.marginsAdded( marginsHint( Panel | QskAspect::Padding ) );
setGeometry( r );
const auto clipRect = qskFocusIndicatorClipRect( m_data->clippingItem );
setClip( !clipRect.isEmpty() );
}
update();

View File

@ -23,6 +23,7 @@ class QSK_EXPORT QskFocusIndicator : public QskControl
~QskFocusIndicator() override;
bool contains( const QPointF& ) const override;
QRectF clipRect() const override;
protected:
void windowChangeEvent( QskWindowChangeEvent* ) override;

View File

@ -124,11 +124,6 @@ class QskScrollAreaClipItem final : public QskControl, public QQuickItemChangeLi
return scrollArea()->subControlRect( QskScrollView::Viewport );
}
bool hasFocusIndicatorClip() const override
{
return scrollArea()->hasFocusIndicatorClip();
}
protected:
bool event( QEvent* event ) override;
@ -405,11 +400,6 @@ void QskScrollArea::adjustItem()
}
}
bool QskScrollArea::hasFocusIndicatorClip() const
{
return true;
}
void QskScrollArea::setItemResizable( bool on )
{
if ( on != m_data->isItemResizable )

View File

@ -30,8 +30,6 @@ class QSK_EXPORT QskScrollArea : public QskScrollView
void setItemResizable( bool on );
bool isItemResizable() const;
bool hasFocusIndicatorClip() const override;
Q_SIGNALS:
void scrolledItemChanged();
void itemResizableChanged( bool );

View File

@ -12,6 +12,8 @@
#include "QskAnimationHint.h"
#include "QskQuick.h"
#include <qquickwindow.h>
QSK_SUBCONTROL( QskTabBar, Panel )
static inline Qt::Orientation qskOrientation( int position )
@ -71,11 +73,28 @@ namespace
enableAutoTranslation( true );
setFocusPolicy( Qt::NoFocus );
connect( this, &ScrollBox::scrollPosChanged,
this, &QskControl::focusIndicatorRectChanged );
}
bool hasFocusIndicatorClip() const override
QRectF focusIndicatorClipRect() const override
{
return false;
auto r = clipRect();
if ( window() )
{
if ( auto focusItem = window()->activeFocusItem() )
{
const auto itemRect = mapRectFromItem(
focusItem, focusItem->boundingRect() );
if ( r.intersects( itemRect ) )
return QRectF();
}
}
return r;
}
QskAnimationHint flickHint() const override