diff --git a/examples/tabview/main.cpp b/examples/tabview/main.cpp index 7d76da9a..790ccd87 100644 --- a/examples/tabview/main.cpp +++ b/examples/tabview/main.cpp @@ -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 ); diff --git a/src/controls/QskControl.cpp b/src/controls/QskControl.cpp index 38bd9187..cb6bae13 100644 --- a/src/controls/QskControl.cpp +++ b/src/controls/QskControl.cpp @@ -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() diff --git a/src/controls/QskControl.h b/src/controls/QskControl.h index f777afff..07a4e8df 100644 --- a/src/controls/QskControl.h +++ b/src/controls/QskControl.h @@ -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; diff --git a/src/controls/QskFocusIndicator.cpp b/src/controls/QskFocusIndicator.cpp index 8e250ba8..2259287a 100644 --- a/src/controls/QskFocusIndicator.cpp +++ b/src/controls/QskFocusIndicator.cpp @@ -8,6 +8,7 @@ #include "QskEvent.h" #include "QskQuick.h" +#include #include 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; + // We want to be on top, but do we cover all corner cases ??? + setParentItem( window()->contentItem() ); + setZ( 10e-6 ); + const auto focusItem = window()->activeFocusItem(); + QQuickItem* clippingItem = nullptr; - if ( ( focusItem == nullptr ) || ( focusItem == window()->contentItem() ) ) + if ( focusItem && ( 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 ??? - - setZ( item->z() + 10e-6 ); - break; - } - - item = itemParent; - + 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->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(); diff --git a/src/controls/QskFocusIndicator.h b/src/controls/QskFocusIndicator.h index a67f6c4b..7c2d32f8 100644 --- a/src/controls/QskFocusIndicator.h +++ b/src/controls/QskFocusIndicator.h @@ -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; diff --git a/src/controls/QskScrollArea.cpp b/src/controls/QskScrollArea.cpp index ffba3f73..23fdca7f 100644 --- a/src/controls/QskScrollArea.cpp +++ b/src/controls/QskScrollArea.cpp @@ -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 ) diff --git a/src/controls/QskScrollArea.h b/src/controls/QskScrollArea.h index f0f46ead..624fa075 100644 --- a/src/controls/QskScrollArea.h +++ b/src/controls/QskScrollArea.h @@ -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 ); diff --git a/src/controls/QskTabBar.cpp b/src/controls/QskTabBar.cpp index 199561bb..1750c410 100644 --- a/src/controls/QskTabBar.cpp +++ b/src/controls/QskTabBar.cpp @@ -12,6 +12,8 @@ #include "QskAnimationHint.h" #include "QskQuick.h" +#include + 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