From fe3b6ca5fe33d1e99d23e44c6982f040c95a7c82 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 14 Jul 2023 15:11:05 +0200 Subject: [PATCH] list view: Support focusing individual cells --- src/controls/QskListView.cpp | 34 +++++++++++++++++++++++++++-- src/controls/QskListView.h | 2 ++ src/controls/QskListViewSkinlet.cpp | 30 ++++++++++++++++++++----- src/controls/QskListViewSkinlet.h | 3 +++ 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/controls/QskListView.cpp b/src/controls/QskListView.cpp index 952805c6..4c283d14 100644 --- a/src/controls/QskListView.cpp +++ b/src/controls/QskListView.cpp @@ -7,6 +7,7 @@ #include "QskAspect.h" #include "QskColorFilter.h" #include "QskEvent.h" +#include "QskSkinlet.h" #include #include @@ -40,6 +41,8 @@ QskListView::QskListView( QQuickItem* parent ) , m_data( new PrivateData() ) { setSubcontrolProxy( Inherited::Viewport, Viewport ); + + connect( this, &QskScrollView::scrollPosChanged, this, &QskControl::focusIndicatorRectChanged ); } QskListView::~QskListView() @@ -125,6 +128,7 @@ void QskListView::setSelectedRow( int row ) { m_data->selectedRow = row; Q_EMIT selectedRowChanged( row ); + Q_EMIT focusIndicatorRectChanged(); update(); } @@ -161,6 +165,21 @@ QskColorFilter QskListView::graphicFilterAt( int row, int col ) const return QskColorFilter(); } +QRectF QskListView::focusIndicatorRect() const +{ + if( selectedRow() >= 0 ) + { + auto rect = effectiveSkinlet()->sampleRect( this, + contentsRect(), Cell, selectedRow() ); + + const auto p = scrollPos(); + rect.adjust( -p.x(), -p.y(), -p.x(), -p.y() ); + return rect; + } + + return Inherited::focusIndicatorRect(); +} + void QskListView::keyPressEvent( QKeyEvent* event ) { if ( m_data->selectionMode == NoSelection ) @@ -208,8 +227,19 @@ void QskListView::keyPressEvent( QKeyEvent* event ) } default: { - Inherited::keyPressEvent( event ); - return; + if ( const int steps = qskFocusChainIncrement( event ) ) + { + row += steps; + + if( row < 0 ) + { + row += rowCount(); + } + else if( row >= rowCount() ) + { + row %= rowCount(); + } + } } } diff --git a/src/controls/QskListView.h b/src/controls/QskListView.h index b6a9eb15..d66e4758 100644 --- a/src/controls/QskListView.h +++ b/src/controls/QskListView.h @@ -75,6 +75,8 @@ class QSK_EXPORT QskListView : public QskScrollView virtual QskColorFilter graphicFilterAt( int row, int col ) const; #endif + QRectF focusIndicatorRect() const override; + public Q_SLOTS: void setSelectedRow( int row ); diff --git a/src/controls/QskListViewSkinlet.cpp b/src/controls/QskListViewSkinlet.cpp index 0a26ccf4..6b44f6e1 100644 --- a/src/controls/QskListViewSkinlet.cpp +++ b/src/controls/QskListViewSkinlet.cpp @@ -127,8 +127,6 @@ void QskListViewSkinlet::updateBackgroundNodes( rowMax = listView->rowCount() - 1; const int rowSelected = listView->selectedRow(); - const double x0 = viewRect.left() + scrolledPos.x(); - const double y0 = viewRect.top(); auto rowNode = backgroundNode->firstChild(); @@ -138,8 +136,7 @@ void QskListViewSkinlet::updateBackgroundNodes( { if ( row % 2 ) { - const QRectF rect( x0, y0 + row * cellHeight, - viewRect.width(), cellHeight ); + const auto rect = sampleRect( listView, listView->contentsRect(), Q::Cell, row ); auto newNode = updateBoxNode( listView, rowNode, rect, Q::Cell ); if ( newNode ) @@ -158,8 +155,7 @@ void QskListViewSkinlet::updateBackgroundNodes( QskSkinStateChanger stateChanger( listView ); stateChanger.setStates( listView->skinStates() | QskListView::Selected ); - const QRectF rect( x0, y0 + rowSelected * cellHeight, - viewRect.width(), cellHeight ); + const auto rect = sampleRect( listView, listView->contentsRect(), Q::Cell, rowSelected ); rowNode = updateBoxNode( listView, rowNode, rect, Q::Cell ); if ( rowNode && rowNode->parent() != backgroundNode ) @@ -490,4 +486,26 @@ QSizeF QskListViewSkinlet::sizeHint( const QskSkinnable* skinnable, return QSizeF( w, -1.0 ); } +QRectF QskListViewSkinlet::sampleRect( const QskSkinnable* skinnable, + const QRectF& contentsRect, QskAspect::Subcontrol subControl, int index ) const +{ + using Q = QskListView; + const auto listView = static_cast< const QskListView* >( skinnable ); + + if ( subControl == Q::Cell ) + { + const auto cellHeight = listView->rowHeight(); + const auto viewRect = listView->viewContentsRect(); + const auto scrolledPos = listView->scrollPos(); + + const double x0 = viewRect.left() + scrolledPos.x(); + const double y0 = viewRect.top(); + + const QRectF rect( x0, y0 + index * cellHeight, viewRect.width(), cellHeight ); + return rect; + } + + return Inherited::sampleRect( skinnable, contentsRect, subControl, index ); +} + #include "moc_QskListViewSkinlet.cpp" diff --git a/src/controls/QskListViewSkinlet.h b/src/controls/QskListViewSkinlet.h index 7f2f9d88..4f174962 100644 --- a/src/controls/QskListViewSkinlet.h +++ b/src/controls/QskListViewSkinlet.h @@ -37,6 +37,9 @@ class QSK_EXPORT QskListViewSkinlet : public QskScrollViewSkinlet QSizeF sizeHint( const QskSkinnable*, Qt::SizeHint, const QSizeF& ) const override; + QRectF sampleRect( const QskSkinnable*, + const QRectF&, QskAspect::Subcontrol, int index ) const override; + protected: QSGNode* updateContentsNode( const QskScrollView*, QSGNode* ) const override;