focusIndicator around the current row

This commit is contained in:
Uwe Rathmann 2023-07-18 16:18:36 +02:00
parent f0a2803df7
commit 881a607428
4 changed files with 65 additions and 10 deletions

View File

@ -7,6 +7,7 @@
#include "QskAspect.h" #include "QskAspect.h"
#include "QskColorFilter.h" #include "QskColorFilter.h"
#include "QskEvent.h" #include "QskEvent.h"
#include "QskSkinlet.h"
#include <qguiapplication.h> #include <qguiapplication.h>
#include <qstylehints.h> #include <qstylehints.h>
@ -24,20 +25,26 @@ class QskListView::PrivateData
PrivateData() PrivateData()
: preferredWidthFromColumns( false ) : preferredWidthFromColumns( false )
, selectionMode( QskListView::SingleSelection ) , selectionMode( QskListView::SingleSelection )
, selectedRow( -1 )
{ {
} }
/*
Currently we only support single selection. We can't navigate
the current item ( = focus ) without changing the selection.
So for the moment the selected row is always the currentRow.
*/
bool preferredWidthFromColumns : 1; bool preferredWidthFromColumns : 1;
SelectionMode selectionMode : 4; SelectionMode selectionMode : 4;
int selectedRow; int selectedRow = -1;
}; };
QskListView::QskListView( QQuickItem* parent ) QskListView::QskListView( QQuickItem* parent )
: QskScrollView( parent ) : QskScrollView( parent )
, m_data( new PrivateData() ) , m_data( new PrivateData() )
{ {
connect( this, &QskScrollView::scrollPosChanged, &QskControl::focusIndicatorRectChanged );
} }
QskListView::~QskListView() QskListView::~QskListView()
@ -123,6 +130,7 @@ void QskListView::setSelectedRow( int row )
{ {
m_data->selectedRow = row; m_data->selectedRow = row;
Q_EMIT selectedRowChanged( row ); Q_EMIT selectedRowChanged( row );
Q_EMIT focusIndicatorRectChanged();
update(); update();
} }
@ -159,6 +167,19 @@ QskColorFilter QskListView::graphicFilterAt( int row, int col ) const
return QskColorFilter(); return QskColorFilter();
} }
QRectF QskListView::focusIndicatorRect() const
{
if( m_data->selectedRow >= 0 )
{
const auto rect = effectiveSkinlet()->sampleRect(
this, contentsRect(), Cell, m_data->selectedRow );
return rect.translated( -scrollPos() );
}
return Inherited::focusIndicatorRect();
}
void QskListView::keyPressEvent( QKeyEvent* event ) void QskListView::keyPressEvent( QKeyEvent* event )
{ {
if ( m_data->selectionMode == NoSelection ) if ( m_data->selectionMode == NoSelection )
@ -206,8 +227,19 @@ void QskListView::keyPressEvent( QKeyEvent* event )
} }
default: default:
{ {
Inherited::keyPressEvent( event ); if ( const int steps = qskFocusChainIncrement( event ) )
return; {
row += steps;
if( row < 0 )
{
row += rowCount();
}
else if( row >= rowCount() )
{
row %= rowCount();
}
}
} }
} }

View File

@ -75,6 +75,8 @@ class QSK_EXPORT QskListView : public QskScrollView
virtual QskColorFilter graphicFilterAt( int row, int col ) const; virtual QskColorFilter graphicFilterAt( int row, int col ) const;
#endif #endif
QRectF focusIndicatorRect() const override;
public Q_SLOTS: public Q_SLOTS:
void setSelectedRow( int row ); void setSelectedRow( int row );

View File

@ -127,8 +127,6 @@ void QskListViewSkinlet::updateBackgroundNodes(
rowMax = listView->rowCount() - 1; rowMax = listView->rowCount() - 1;
const int rowSelected = listView->selectedRow(); const int rowSelected = listView->selectedRow();
const double x0 = viewRect.left() + scrolledPos.x();
const double y0 = viewRect.top();
auto rowNode = backgroundNode->firstChild(); auto rowNode = backgroundNode->firstChild();
@ -138,8 +136,7 @@ void QskListViewSkinlet::updateBackgroundNodes(
{ {
if ( row % 2 ) if ( row % 2 )
{ {
const QRectF rect( x0, y0 + row * cellHeight, const auto rect = sampleRect( listView, listView->contentsRect(), Q::Cell, row );
viewRect.width(), cellHeight );
auto newNode = updateBoxNode( listView, rowNode, rect, Q::Cell ); auto newNode = updateBoxNode( listView, rowNode, rect, Q::Cell );
if ( newNode ) if ( newNode )
@ -158,8 +155,7 @@ void QskListViewSkinlet::updateBackgroundNodes(
QskSkinStateChanger stateChanger( listView ); QskSkinStateChanger stateChanger( listView );
stateChanger.setStates( listView->skinStates() | QskListView::Selected ); stateChanger.setStates( listView->skinStates() | QskListView::Selected );
const QRectF rect( x0, y0 + rowSelected * cellHeight, const auto rect = sampleRect( listView, listView->contentsRect(), Q::Cell, rowSelected );
viewRect.width(), cellHeight );
rowNode = updateBoxNode( listView, rowNode, rect, Q::Cell ); rowNode = updateBoxNode( listView, rowNode, rect, Q::Cell );
if ( rowNode && rowNode->parent() != backgroundNode ) if ( rowNode && rowNode->parent() != backgroundNode )
@ -490,4 +486,26 @@ QSizeF QskListViewSkinlet::sizeHint( const QskSkinnable* skinnable,
return QSizeF( w, -1.0 ); 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" #include "moc_QskListViewSkinlet.cpp"

View File

@ -37,6 +37,9 @@ class QSK_EXPORT QskListViewSkinlet : public QskScrollViewSkinlet
QSizeF sizeHint( const QskSkinnable*, QSizeF sizeHint( const QskSkinnable*,
Qt::SizeHint, const QSizeF& ) const override; Qt::SizeHint, const QSizeF& ) const override;
QRectF sampleRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol, int index ) const override;
protected: protected:
QSGNode* updateContentsNode( QSGNode* updateContentsNode(
const QskScrollView*, QSGNode* ) const override; const QskScrollView*, QSGNode* ) const override;