6#include "QskListViewSkinlet.h"
7#include "QskListView.h"
9#include "QskColorFilter.h"
10#include "QskGraphic.h"
11#include "QskBoxHints.h"
13#include "QskSkinStateChanger.h"
18#include <qtransform.h>
22 class ForegroundNode :
public QSGNode
27 removeAllChildNodes();
28 m_columnCount = m_oldRowMin = m_oldRowMax = -1;
31 void rearrangeNodes(
int rowMin,
int rowMax,
int columnCount )
33 const bool doReorder = ( columnCount == m_columnCount )
34 && ( rowMin <= m_oldRowMax ) && ( rowMax >= m_oldRowMin );
52 if ( rowMin >= m_oldRowMin )
54 for (
int row = m_oldRowMin; row < rowMin; row++ )
56 for (
int col = 0; col < columnCount; col++ )
58 auto childNode = firstChild();
59 removeChildNode( childNode );
60 appendChildNode( childNode );
66 for (
int row = rowMin; row < m_oldRowMin; row++ )
68 for (
int col = 0; col < columnCount; col++ )
70 auto childNode = lastChild();
71 removeChildNode( childNode );
72 prependChildNode( childNode );
80 m_columnCount = columnCount;
92 int m_columnCount = -1;
95 class ListViewNode final :
public QSGTransformNode
100 m_backgroundNode.setFlag( QSGNode::OwnedByParent,
false );
101 appendChildNode( &m_backgroundNode );
103 m_foregroundNode.setFlag( QSGNode::OwnedByParent,
false );
104 appendChildNode( &m_foregroundNode );
109 const auto scrollPos = listView->scrollPos();
110 setMatrix( QTransform::fromTranslate( -scrollPos.x(), -scrollPos.y() ) );
112 m_clipRect = listView->viewContentsRect();
113 m_rowHeight = listView->rowHeight();
115 m_rowMin = qFloor( scrollPos.y() / m_rowHeight );
117 const auto rowMax = ( scrollPos.y() + m_clipRect.height() ) / m_rowHeight;
118 m_rowMax = qFloor( rowMax - 10e-6 );
120 if ( m_rowMax >= listView->rowCount() )
121 m_rowMax = listView->rowCount() - 1;
124 QRectF clipRect()
const {
return m_clipRect; }
126 int rowMin()
const {
return m_rowMin; }
127 int rowMax()
const {
return m_rowMax; }
128 int rowCount()
const {
return m_rowMax - m_rowMin + 1; }
130 int rowHeight()
const {
return m_rowHeight; }
132 QSGNode* backgroundNode() {
return &m_backgroundNode; }
133 ForegroundNode* foregroundNode() {
return &m_foregroundNode; }
141 int m_rowMin, m_rowMax;
143 QSGNode m_backgroundNode;
144 ForegroundNode m_foregroundNode;
148static inline ListViewNode* qskListViewNode(
const QskListView* listView )
150 if (
auto node =
const_cast< QSGNode*
>( qskPaintNode( listView ) ) )
152 using namespace QskSGNode;
154 node = findChildNode( node, QskScrollViewSkinlet::ContentsRootRole );
157 node = node->firstChild();
160 Q_ASSERT( node->type() == QSGNode::TransformNodeType );
161 return static_cast< ListViewNode*
>( node );
169static inline ListViewNode* qskListViewNode(
const QskSkinnable* skinnable )
171 return qskListViewNode(
static_cast< const QskListView*
>( skinnable ) );
174QskListViewSkinlet::QskListViewSkinlet(
QskSkin* skin )
179QskListViewSkinlet::~QskListViewSkinlet() =
default;
181QSGNode* QskListViewSkinlet::updateContentsNode(
184 const auto listView =
static_cast< const QskListView*
>( scrollView );
186 auto listViewNode = QskSGNode::ensureNode< ListViewNode >( node );
187 listViewNode->initialize( listView );
189 updateBackgroundNodes( listView, listViewNode->backgroundNode() );
190 updateForegroundNodes( listView, listViewNode->foregroundNode() );
195void QskListViewSkinlet::updateBackgroundNodes(
196 const QskListView* listView, QSGNode* backgroundNode )
const
200 auto listViewNode =
static_cast< const ListViewNode*
>( backgroundNode->parent() );
202 auto rowNode = backgroundNode->firstChild();
204 for (
int row = listViewNode->rowMin(); row <= listViewNode->rowMax(); row++ )
207 stateChanger.setStates( sampleStates( listView, Q::Cell, row ), row );
209 const auto rect = sampleRect( listView, listView->
contentsRect(), Q::Cell, row );
211 auto newNode = updateBoxNode( listView, rowNode, rect, Q::Cell );
214 if ( newNode->parent() != backgroundNode )
215 backgroundNode->appendChildNode( newNode );
217 rowNode = newNode->nextSibling();
221 QskSGNode::removeAllChildNodesFrom( backgroundNode, rowNode );
224void QskListViewSkinlet::updateForegroundNodes(
225 const QskListView* listView, QSGNode* parentNode )
const
227 auto foregroundNode =
static_cast< ForegroundNode*
>( parentNode );
229 if ( listView->rowCount() <= 0 || listView->columnCount() <= 0 )
231 foregroundNode->invalidate();
235 auto listViewNode =
static_cast< const ListViewNode*
>( parentNode->parent() );
237 const auto clipRect = listViewNode->clipRect();
239 const int rowMin = listViewNode->rowMin();
240 const int rowMax = listViewNode->rowMax();
242 foregroundNode->rearrangeNodes( rowMin, rowMax, listView->columnCount() );
246 const int colMin = 0;
247 const int colMax = listView->columnCount() - 1;
250 const auto margins = listView->
paddingHint( QskListView::Cell );
252 updateVisibleForegroundNodes(
253 listView, foregroundNode, rowMin, rowMax, margins );
256 auto node = foregroundNode->firstChild();
258 const auto rowHeight = listView->rowHeight();
259 auto y = clipRect.top() + rowMin * rowHeight;
261 for (
int row = rowMin; row <= rowMax; row++ )
263 qreal x = clipRect.left();
265 for (
int col = colMin; col <= colMax; col++ )
267 Q_ASSERT( node->type() == QSGNode::TransformNodeType );
268 auto transformNode =
static_cast< QSGTransformNode*
>( node );
270 transformNode->setMatrix(
271 QTransform::fromTranslate( x + margins.left(), y + margins.top() ) );
273 node = node->nextSibling();
274 x += listView->columnWidth( col );
281void QskListViewSkinlet::updateVisibleForegroundNodes(
283 int rowMin,
int rowMax,
const QMarginsF& margins )
const
285 auto node = parentNode->firstChild();
287 for (
int row = rowMin; row <= rowMax; row++ )
289 const auto h = listView->rowHeight() - ( margins.top() + margins.bottom() );
291 for (
int col = 0; col < listView->columnCount(); col++ )
293 const auto w = listView->columnWidth( col ) - ( margins.left() + margins.right() );
295 node = updateForegroundNode( listView,
296 parentNode,
static_cast< QSGTransformNode*
>( node ),
297 row, col, QSizeF( w, h ) );
299 node = node->nextSibling();
303 QskSGNode::removeAllChildNodesFrom( parentNode, node );
306QSGTransformNode* QskListViewSkinlet::updateForegroundNode(
307 const QskListView* listView, QSGNode* parentNode, QSGTransformNode* cellNode,
308 int row,
int col,
const QSizeF& size )
const
310 const QRectF cellRect( 0.0, 0.0, size.width(), size.height() );
316 QSGTransformNode* newCellNode =
nullptr;
318 if ( cellNode && ( cellNode->type() == QSGNode::TransformNodeType ) )
320 QSGNode* oldNode = cellNode;
322 auto newNode = updateCellNode( listView, oldNode, cellRect, row, col );
325 if ( newNode->type() == QSGNode::TransformNodeType )
327 newCellNode =
static_cast< QSGTransformNode*
>( newNode );
331 newCellNode =
new QSGTransformNode();
332 newCellNode->appendChildNode( newNode );
338 QSGNode* oldNode = cellNode ? cellNode->firstChild() :
nullptr;
339 auto newNode = updateCellNode( listView, oldNode, cellRect, row, col );
343 if ( newNode->type() == QSGNode::TransformNodeType )
345 newCellNode =
static_cast< QSGTransformNode*
>( newNode );
349 if ( cellNode ==
nullptr )
351 newCellNode =
new QSGTransformNode();
352 newCellNode->appendChildNode( newNode );
356 if ( newNode != oldNode )
358 delete cellNode->firstChild();
359 cellNode->appendChildNode( newNode );
361 newCellNode = cellNode;
368 if ( newCellNode ==
nullptr )
369 newCellNode =
new QSGTransformNode();
371 if ( cellNode != newCellNode )
375 parentNode->insertChildNodeAfter( newCellNode, cellNode );
380 parentNode->appendChildNode( newCellNode );
387QSGNode* QskListViewSkinlet::updateCellNode(
const QskListView* listView,
388 QSGNode* contentNode,
const QRectF& rect,
int row,
int col )
const
391 using namespace QskSGNode;
394 stateChanger.setStates( sampleStates( listView, Q::Cell, row ), row );
396 QSGNode* newNode =
nullptr;
406 Q::Cell, Qt::AlignVCenter | Qt::AlignLeft );
408 const auto value = listView->valueAt( row, col );
412 if ( nodeRole( contentNode ) == GraphicRole )
413 newNode = contentNode;
417 newNode = updateGraphicNode( listView, newNode,
418 value.value<
QskGraphic >(), colorFilter, rect, alignment );
421 setNodeRole( newNode, GraphicRole );
423 else if ( value.canConvert< QString >() )
425 if ( nodeRole( contentNode ) == TextRole )
426 newNode = contentNode;
428 newNode = updateTextNode( listView, newNode, rect, alignment,
429 value.toString(), Q::Text );
432 setNodeRole( newNode, TextRole );
436 qWarning() <<
"QskListViewSkinlet: got unsupported QVariant type" << value.typeName();
442QSizeF QskListViewSkinlet::sizeHint(
const QskSkinnable* skinnable,
443 Qt::SizeHint which,
const QSizeF& )
const
445 const auto listView =
static_cast< const QskListView*
>( skinnable );
449 if ( which != Qt::MaximumSize )
451 if ( listView->preferredWidthFromColumns() )
453 w = listView->scrollableSize().width();
458 return QSizeF( w, -1.0 );
461QskAspect::States QskListViewSkinlet::sampleStates(
const QskSkinnable* skinnable,
466 if ( subControl == Q::Cell || subControl == Q::Text || subControl == Q::Graphic )
468 const auto listView =
static_cast< const QskListView*
>( skinnable );
469 return listView->rowStates( index );
472 return Inherited::sampleStates( skinnable, subControl, index );
475QRectF QskListViewSkinlet::sampleRect(
const QskSkinnable* skinnable,
480 const auto listView =
static_cast< const QskListView*
>( skinnable );
482 if ( subControl == Q::Cell )
484 auto node = qskListViewNode( listView );
485 const auto clipRect = node ? node->clipRect() : listView->viewContentsRect();
487 const auto w = clipRect.width();
488 const auto h = listView->rowHeight();
489 const auto x = clipRect.left() + listView->scrollPos().x();
490 const auto y = clipRect.top() + index * h;
492 return QRectF( x, y, w, h );
495 return Inherited::sampleRect( skinnable, contentsRect, subControl, index );
498#include "moc_QskListViewSkinlet.cpp"
Subcontrol
For use within the rendering or lay-outing of a specific QskSkinnable.
QRectF contentsRect() const
A paint device for scalable graphics.
QMarginsF paddingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a padding hint.
QskColorFilter effectiveGraphicFilter(QskAspect::Subcontrol) const
qreal metric(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a metric hint.
Qt::Alignment alignmentHint(QskAspect, Qt::Alignment=Qt::Alignment()) const
Retrieves an alignment hint.