QskSkinlet improved for subControls with multible instances

This commit is contained in:
Uwe Rathmann 2021-12-28 10:08:21 +01:00
parent 2201c80d09
commit f1a324b216
7 changed files with 99 additions and 76 deletions

View File

@ -162,7 +162,7 @@ void QskListViewSkinlet::updateBackgroundNodes(
if ( rowSelected >= rowMin && rowSelected <= rowMax ) if ( rowSelected >= rowMin && rowSelected <= rowMax )
{ {
QskSkinStateChanger stateChanger( listView ); QskSkinStateChanger stateChanger( listView );
stateChanger.addStates( QskListView::Selected ); stateChanger.setStates( listView->skinStates() | QskListView::Selected );
const QColor color = listView->color( QskListView::Cell ); const QColor color = listView->color( QskListView::Cell );
@ -436,12 +436,12 @@ QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView,
{ {
using namespace QskSGNode; using namespace QskSGNode;
QskAspect::States rowStates; auto rowStates = listView->skinStates();
if ( row == listView->selectedRow() ) if ( row == listView->selectedRow() )
rowStates |= QskListView::Selected; rowStates |= QskListView::Selected;
QskSkinStateChanger stateChanger( listView ); QskSkinStateChanger stateChanger( listView );
stateChanger.addStates( rowStates ); stateChanger.setStates( rowStates );
QSGNode* newNode = nullptr; QSGNode* newNode = nullptr;

View File

@ -308,13 +308,13 @@ void QskMenu::setSelectedIndex( int index )
QRectF QskMenu::cellRect( int index ) const QRectF QskMenu::cellRect( int index ) const
{ {
return effectiveSkinlet()->itemRect( return effectiveSkinlet()->subControlCell(
this, contentsRect(), QskMenu::Cell, index ); this, contentsRect(), QskMenu::Cell, index );
} }
int QskMenu::indexAtPosition( const QPointF& pos ) const int QskMenu::indexAtPosition( const QPointF& pos ) const
{ {
return effectiveSkinlet()->itemIndexAt( return effectiveSkinlet()->subControlCellIndexAt(
this, contentsRect(), QskMenu::Cell, pos ); this, contentsRect(), QskMenu::Cell, pos );
} }

View File

@ -44,7 +44,7 @@ static qreal qskMaxTextWidth( const QskMenu* menu )
for ( int i = 0; i < menu->count(); i++ ) for ( int i = 0; i < menu->count(); i++ )
{ {
const auto value = menu->itemAt( i ); const auto value = menu->itemAt( i );
const auto text = qskValueAt< QString >( menu, i ); const auto text = qskValueAt< QString >( menu, i );
if( !text.isEmpty() ) if( !text.isEmpty() )
{ {
@ -131,6 +131,10 @@ static QSGNode* qskUpdateTextNode( const QskMenu* menu,
static QSGNode* qskUpdateBackgroundNode( const QskMenu* menu, QSGNode* rootNode ) static QSGNode* qskUpdateBackgroundNode( const QskMenu* menu, QSGNode* rootNode )
{ {
using Q = QskMenu;
const auto skinlet = menu->effectiveSkinlet();
auto node = rootNode ? rootNode->firstChild() : nullptr; auto node = rootNode ? rootNode->firstChild() : nullptr;
QSGNode* lastNode = nullptr; QSGNode* lastNode = nullptr;
@ -140,11 +144,11 @@ static QSGNode* qskUpdateBackgroundNode( const QskMenu* menu, QSGNode* rootNode
{ {
QskSkinStateChanger stateChanger( menu ); QskSkinStateChanger stateChanger( menu );
if ( menu->currentIndex() == i ) stateChanger.setStates(
stateChanger.addStates( QskMenu::Selected ); skinlet->subControlCellStates( menu, Q::Cell, i ) );
newNode = QskSkinlet::updateBoxNode( newNode = QskSkinlet::updateBoxNode(
menu, node, menu->cellRect( i ), QskMenu::Cell ); menu, node, menu->cellRect( i ), Q::Cell );
} }
if ( newNode ) if ( newNode )
@ -196,15 +200,21 @@ static void qskUpdateItemNode(
static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode ) static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode )
{ {
const auto spacing = menu->spacingHint( QskMenu::Cell ); using Q = QskMenu;
const auto skinlet = menu->effectiveSkinlet();
const auto spacing = menu->spacingHint( Q::Cell );
const auto graphicWidth = qskGraphicWidth( menu ); const auto graphicWidth = qskGraphicWidth( menu );
const auto contentsRect = menu->contentsRect();
if ( rootNode == nullptr ) if ( rootNode == nullptr )
rootNode = new QSGNode(); rootNode = new QSGNode();
QSGNode* node = nullptr; QSGNode* node = nullptr;
for( int i = 0; i < menu->count(); i++ ) const auto count = skinlet->subControlCellCount( menu, Q::Cell );
for( int i = 0; i < count; i++ )
{ {
if ( node == nullptr ) if ( node == nullptr )
node = rootNode->firstChild(); node = rootNode->firstChild();
@ -219,10 +229,11 @@ static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode )
{ {
QskSkinStateChanger stateChanger( menu ); QskSkinStateChanger stateChanger( menu );
if ( menu->currentIndex() == i ) stateChanger.setStates(
stateChanger.addStates( QskMenu::Selected ); skinlet->subControlCellStates( menu, Q::Cell, i ) );
const auto cellRect = menu->cellRect( i ); const auto cellRect = skinlet->subControlCell(
menu, contentsRect, Q::Cell, i );
auto graphicRect = cellRect; auto graphicRect = cellRect;
graphicRect.setWidth( graphicWidth ); graphicRect.setWidth( graphicWidth );
@ -268,10 +279,11 @@ QRectF QskMenuSkinlet::subControlRect(
return Inherited::subControlRect( skinnable, contentsRect, subControl ); return Inherited::subControlRect( skinnable, contentsRect, subControl );
} }
QRectF QskMenuSkinlet::itemRect( QRectF QskMenuSkinlet::subControlCell(
const QskSkinnable* skinnable, const QRectF& contentsRect, const QskSkinnable* skinnable, const QRectF& contentsRect,
QskAspect::Subcontrol subControl, int index ) const QskAspect::Subcontrol subControl, int index ) const
{ {
// QskMenu::Text, QskMenu::Graphic ???
if ( subControl == QskMenu::Cell ) if ( subControl == QskMenu::Cell )
{ {
const auto menu = static_cast< const QskMenu* >( skinnable ); const auto menu = static_cast< const QskMenu* >( skinnable );
@ -285,43 +297,37 @@ QRectF QskMenuSkinlet::itemRect(
return QRectF( r.x(), r.y() + index * h, r.width(), h ); return QRectF( r.x(), r.y() + index * h, r.width(), h );
} }
return Inherited::itemRect( return Inherited::subControlCell(
skinnable, contentsRect, subControl, index ); skinnable, contentsRect, subControl, index );
} }
int QskMenuSkinlet::itemIndexAt( const QskSkinnable* skinnable, int QskMenuSkinlet::subControlCellCount(
const QRectF& rect, QskAspect::Subcontrol subControl, const QPointF& pos ) const const QskSkinnable* skinnable, QskAspect::Subcontrol subControl ) const
{ {
// QskMenu::Text, QskMenu::Graphic ???
if ( subControl == QskMenu::Cell ) if ( subControl == QskMenu::Cell )
{ {
const auto menu = static_cast< const QskMenu* >( skinnable ); const auto menu = static_cast< const QskMenu* >( skinnable );
return menu->count();
const auto panelRect = menu->subControlContentsRect( QskMenu::Panel );
if ( !panelRect.contains( pos ) )
return -1;
/*
A menu never has many items and we can simply iterate
without being concerned about performance issues
*/
const auto h = qskCellHeight( menu );
auto r = panelRect;
r.setHeight( h );
for ( int i = 0; i < menu->count(); i++ )
{
if ( r.contains( pos ) )
return i;
r.moveTop( r.bottom() );
}
return -1;
} }
return Inherited::itemIndexAt( skinnable, rect, subControl, pos ); return Inherited::subControlCellCount( skinnable, subControl );
}
QskAspect::States QskMenuSkinlet::subControlCellStates(
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const
{
auto states = Inherited::subControlCellStates( skinnable, subControl, index );
// QskMenu::Text, QskMenu::Graphic ???
if ( subControl == QskMenu::Cell )
{
const auto menu = static_cast< const QskMenu* >( skinnable );
if ( menu->currentIndex() == index )
states |= QskMenu::Selected;
}
return states;
} }
QSGNode* QskMenuSkinlet::updateContentsNode( QSGNode* QskMenuSkinlet::updateContentsNode(

View File

@ -23,11 +23,13 @@ class QSK_EXPORT QskMenuSkinlet : public QskPopupSkinlet
QRectF subControlRect( const QskSkinnable*, QRectF subControlRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol ) const override; const QRectF&, QskAspect::Subcontrol ) const override;
QRectF itemRect( const QskSkinnable*, QRectF subControlCell( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol, int index ) const override; const QRectF&, QskAspect::Subcontrol, int index ) const override;
int itemIndexAt( const QskSkinnable*, int subControlCellCount( const QskSkinnable*, QskAspect::Subcontrol ) const override;
const QRectF&, QskAspect::Subcontrol, const QPointF& ) const override;
QskAspect::States subControlCellStates( const QskSkinnable*,
QskAspect::Subcontrol, int index ) const override;
QSizeF sizeHint( const QskSkinnable*, QSizeF sizeHint( const QskSkinnable*,
Qt::SizeHint, const QSizeF& ) const override; Qt::SizeHint, const QSizeF& ) const override;

View File

@ -12,25 +12,20 @@
class QskSkinStateChanger class QskSkinStateChanger
{ {
public: public:
QskSkinStateChanger( const QskSkinnable*, QskSkinStateChanger( const QskSkinnable* );
QskAspect::States = QskAspect::States() );
~QskSkinStateChanger(); ~QskSkinStateChanger();
void addStates( QskAspect::States ); void setStates( QskAspect::States );
void clearStates( QskAspect::States );
private: private:
QskSkinnable* m_skinnable; QskSkinnable* m_skinnable;
const QskAspect::States m_oldStates; const QskAspect::States m_oldStates;
}; };
inline QskSkinStateChanger::QskSkinStateChanger( inline QskSkinStateChanger::QskSkinStateChanger( const QskSkinnable* skinnable )
const QskSkinnable* skinnable, QskAspect::States states )
: m_skinnable( const_cast< QskSkinnable* >( skinnable ) ) : m_skinnable( const_cast< QskSkinnable* >( skinnable ) )
, m_oldStates( skinnable->skinStates() ) , m_oldStates( skinnable->skinStates() )
{ {
addStates( states );
} }
inline QskSkinStateChanger::~QskSkinStateChanger() inline QskSkinStateChanger::~QskSkinStateChanger()
@ -39,20 +34,10 @@ inline QskSkinStateChanger::~QskSkinStateChanger()
m_skinnable->replaceSkinStates( m_oldStates ); m_skinnable->replaceSkinStates( m_oldStates );
} }
inline void QskSkinStateChanger::addStates( QskAspect::States states ) inline void QskSkinStateChanger::setStates( QskAspect::States states )
{ {
const auto newStates = m_oldStates | states; if ( states != m_skinnable->skinStates() )
m_skinnable->replaceSkinStates( states );
if ( newStates != m_skinnable->skinStates() )
m_skinnable->replaceSkinStates( newStates );
}
inline void QskSkinStateChanger::clearStates( QskAspect::States states )
{
const auto newStates = m_oldStates & ~states;
if ( newStates != m_skinnable->skinStates() )
m_skinnable->replaceSkinStates( newStates );
} }
#endif #endif

View File

@ -581,19 +581,31 @@ QSizeF QskSkinlet::hintWithoutConstraint(
return h; return h;
} }
int QskSkinlet::itemIndexAt( const QskSkinnable*, int QskSkinlet::subControlCellIndexAt( const QskSkinnable* skinnable,
const QRectF&, QskAspect::Subcontrol, const QPointF& ) const const QRectF& rect, QskAspect::Subcontrol subControl, const QPointF& pos ) const
{ {
/*
slow default implementation to be overloaded when
having many cells
*/
const auto cellCount = subControlCellCount( skinnable, subControl );
for ( int i = 0; i < cellCount; i++ )
{
const auto cellRect = subControlCell( skinnable, rect, subControl, i );
if ( cellRect.contains( pos ) )
return i;
}
return -1; return -1;
} }
QRectF QskSkinlet::itemRect( const QskSkinnable*, QskAspect::States QskSkinlet::subControlCellStates(
const QRectF&, QskAspect::Subcontrol, int index ) const const QskSkinnable* skinnable, QskAspect::Subcontrol, int index ) const
{ {
// When a subControl is for a unknown number of item, f.e. in a menu
Q_UNUSED( index ) Q_UNUSED( index )
return QRectF(); return skinnable->skinStates();
} }
#include "moc_QskSkinlet.cpp" #include "moc_QskSkinlet.cpp"

View File

@ -42,12 +42,17 @@ class QSK_EXPORT QskSkinlet
virtual QRectF subControlRect( const QskSkinnable*, virtual QRectF subControlRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol ) const; const QRectF&, QskAspect::Subcontrol ) const;
virtual QRectF itemRect( const QskSkinnable*, virtual QRectF subControlCell( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol, int index ) const; const QRectF&, QskAspect::Subcontrol, int index ) const;
virtual int itemIndexAt( const QskSkinnable*, virtual int subControlCellIndexAt( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol, const QPointF& ) const; const QRectF&, QskAspect::Subcontrol, const QPointF& ) const;
virtual int subControlCellCount( const QskSkinnable*, QskAspect::Subcontrol ) const;
virtual QskAspect::States subControlCellStates( const QskSkinnable*,
QskAspect::Subcontrol, int index ) const;
const QVector< quint8 >& nodeRoles() const; const QVector< quint8 >& nodeRoles() const;
void setOwnedBySkinnable( bool on ); void setOwnedBySkinnable( bool on );
@ -154,4 +159,17 @@ inline QSizeF QskSkinlet::sizeHint(
return QSizeF(); return QSizeF();
} }
inline QRectF QskSkinlet::subControlCell( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol, int index ) const
{
Q_UNUSED( index )
return QRectF();
}
inline int QskSkinlet::subControlCellCount(
const QskSkinnable*, QskAspect::Subcontrol ) const
{
return 1;
}
#endif #endif