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

View File

@ -308,13 +308,13 @@ void QskMenu::setSelectedIndex( int index )
QRectF QskMenu::cellRect( int index ) const
{
return effectiveSkinlet()->itemRect(
return effectiveSkinlet()->subControlCell(
this, contentsRect(), QskMenu::Cell, index );
}
int QskMenu::indexAtPosition( const QPointF& pos ) const
{
return effectiveSkinlet()->itemIndexAt(
return effectiveSkinlet()->subControlCellIndexAt(
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++ )
{
const auto value = menu->itemAt( i );
const auto text = qskValueAt< QString >( menu, i );
if( !text.isEmpty() )
{
@ -131,6 +131,10 @@ static QSGNode* qskUpdateTextNode( const QskMenu* menu,
static QSGNode* qskUpdateBackgroundNode( const QskMenu* menu, QSGNode* rootNode )
{
using Q = QskMenu;
const auto skinlet = menu->effectiveSkinlet();
auto node = rootNode ? rootNode->firstChild() : nullptr;
QSGNode* lastNode = nullptr;
@ -140,11 +144,11 @@ static QSGNode* qskUpdateBackgroundNode( const QskMenu* menu, QSGNode* rootNode
{
QskSkinStateChanger stateChanger( menu );
if ( menu->currentIndex() == i )
stateChanger.addStates( QskMenu::Selected );
stateChanger.setStates(
skinlet->subControlCellStates( menu, Q::Cell, i ) );
newNode = QskSkinlet::updateBoxNode(
menu, node, menu->cellRect( i ), QskMenu::Cell );
menu, node, menu->cellRect( i ), Q::Cell );
}
if ( newNode )
@ -196,15 +200,21 @@ static void qskUpdateItemNode(
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 contentsRect = menu->contentsRect();
if ( rootNode == nullptr )
rootNode = new QSGNode();
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 )
node = rootNode->firstChild();
@ -219,10 +229,11 @@ static QSGNode* qskUpdateItemsNode( const QskMenu* menu, QSGNode* rootNode )
{
QskSkinStateChanger stateChanger( menu );
if ( menu->currentIndex() == i )
stateChanger.addStates( QskMenu::Selected );
stateChanger.setStates(
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;
graphicRect.setWidth( graphicWidth );
@ -268,10 +279,11 @@ QRectF QskMenuSkinlet::subControlRect(
return Inherited::subControlRect( skinnable, contentsRect, subControl );
}
QRectF QskMenuSkinlet::itemRect(
QRectF QskMenuSkinlet::subControlCell(
const QskSkinnable* skinnable, const QRectF& contentsRect,
QskAspect::Subcontrol subControl, int index ) const
{
// QskMenu::Text, QskMenu::Graphic ???
if ( subControl == QskMenu::Cell )
{
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 Inherited::itemRect(
return Inherited::subControlCell(
skinnable, contentsRect, subControl, index );
}
int QskMenuSkinlet::itemIndexAt( const QskSkinnable* skinnable,
const QRectF& rect, QskAspect::Subcontrol subControl, const QPointF& pos ) const
int QskMenuSkinlet::subControlCellCount(
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl ) const
{
// QskMenu::Text, QskMenu::Graphic ???
if ( subControl == QskMenu::Cell )
{
const auto menu = static_cast< const QskMenu* >( skinnable );
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 menu->count();
}
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(

View File

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

View File

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

View File

@ -581,19 +581,31 @@ QSizeF QskSkinlet::hintWithoutConstraint(
return h;
}
int QskSkinlet::itemIndexAt( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol, const QPointF& ) const
int QskSkinlet::subControlCellIndexAt( const QskSkinnable* skinnable,
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;
}
QRectF QskSkinlet::itemRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol, int index ) const
QskAspect::States QskSkinlet::subControlCellStates(
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 )
return QRectF();
return skinnable->skinStates();
}
#include "moc_QskSkinlet.cpp"

View File

@ -42,12 +42,17 @@ class QSK_EXPORT QskSkinlet
virtual QRectF subControlRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol ) const;
virtual QRectF itemRect( const QskSkinnable*,
virtual QRectF subControlCell( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol, int index ) const;
virtual int itemIndexAt( const QskSkinnable*,
virtual int subControlCellIndexAt( const QskSkinnable*,
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;
void setOwnedBySkinnable( bool on );
@ -154,4 +159,17 @@ inline QSizeF QskSkinlet::sizeHint(
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