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 ); auto layoutBox = new QskLinearBox( Qt::Vertical );
layoutBox->setDefaultAlignment( Qt::AlignLeft ); layoutBox->setDefaultAlignment( Qt::AlignLeft );
layoutBox->setMargins( 5 ); layoutBox->setMargins( 20 );
layoutBox->setSpacing( 10 ); layoutBox->setSpacing( 10 );
layoutBox->addItem( buttonBox ); layoutBox->addItem( buttonBox );
layoutBox->addItem( tabView ); layoutBox->addItem( tabView );

View File

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

View File

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

View File

@ -8,6 +8,7 @@
#include "QskEvent.h" #include "QskEvent.h"
#include "QskQuick.h" #include "QskQuick.h"
#include <qpointer.h>
#include <qquickwindow.h> #include <qquickwindow.h>
QSK_SUBCONTROL( QskFocusIndicator, Panel ) QSK_SUBCONTROL( QskFocusIndicator, Panel )
@ -24,6 +25,21 @@ static inline QRectF qskFocusIndicatorRect( const QQuickItem* item )
return qskItemRect( 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 class QskFocusIndicator::PrivateData
{ {
public: public:
@ -35,6 +51,7 @@ class QskFocusIndicator::PrivateData
connections.clear(); connections.clear();
} }
QPointer< QQuickItem > clippingItem;
QVector< QMetaObject::Connection > connections; QVector< QMetaObject::Connection > connections;
}; };
@ -55,6 +72,19 @@ bool QskFocusIndicator::contains( const QPointF& ) const
return false; 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() void QskFocusIndicator::onFocusItemGeometryChanged()
{ {
updateFocusFrame(); updateFocusFrame();
@ -78,64 +108,34 @@ void QskFocusIndicator::onFocusItemChanged()
if ( window() == nullptr ) if ( window() == nullptr )
return; return;
// We want to be on top, but do we cover all corner cases ???
setParentItem( window()->contentItem() );
setZ( 10e-6 );
const auto focusItem = window()->activeFocusItem(); const auto focusItem = window()->activeFocusItem();
QQuickItem* clippingItem = nullptr;
if ( ( focusItem == nullptr ) || ( focusItem == window()->contentItem() ) ) if ( focusItem && ( focusItem != window()->contentItem() ) )
{ {
/* auto item = focusItem;
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 ???
setZ( item->z() + 10e-6 );
break;
}
item = itemParent;
m_data->connections += connectItem( item ); 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->clippingItem = clippingItem;
updateFocusFrame(); updateFocusFrame();
} }
@ -148,6 +148,9 @@ void QskFocusIndicator::updateFocusFrame()
{ {
r = r.marginsAdded( marginsHint( Panel | QskAspect::Padding ) ); r = r.marginsAdded( marginsHint( Panel | QskAspect::Padding ) );
setGeometry( r ); setGeometry( r );
const auto clipRect = qskFocusIndicatorClipRect( m_data->clippingItem );
setClip( !clipRect.isEmpty() );
} }
update(); update();

View File

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

View File

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

View File

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

View File

@ -12,6 +12,8 @@
#include "QskAnimationHint.h" #include "QskAnimationHint.h"
#include "QskQuick.h" #include "QskQuick.h"
#include <qquickwindow.h>
QSK_SUBCONTROL( QskTabBar, Panel ) QSK_SUBCONTROL( QskTabBar, Panel )
static inline Qt::Orientation qskOrientation( int position ) static inline Qt::Orientation qskOrientation( int position )
@ -71,11 +73,28 @@ namespace
enableAutoTranslation( true ); enableAutoTranslation( true );
setFocusPolicy( Qt::NoFocus ); 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 QskAnimationHint flickHint() const override