trying to reorganize QskListViewSkinlet to be able to make use of
updateSeriesNode and friends
This commit is contained in:
parent
75b64d049a
commit
638ee038aa
|
@ -1057,9 +1057,11 @@ void Editor::setupListView()
|
||||||
|
|
||||||
// alternating row colors
|
// alternating row colors
|
||||||
setColor( Q::Cell | A::Lower, Qt::white );
|
setColor( Q::Cell | A::Lower, Qt::white );
|
||||||
setColor( Q::Cell | A::Upper, m_pal.contrasted );
|
setColor( Q::Cell | Q::Selected | A::Lower, m_pal.highlighted );
|
||||||
|
|
||||||
|
setColor( Q::Cell | A::Upper, m_pal.contrasted );
|
||||||
|
setColor( Q::Cell | Q::Selected | A::Upper, m_pal.highlighted );
|
||||||
|
|
||||||
setColor( Q::Cell | Q::Selected, m_pal.highlighted );
|
|
||||||
setColor( Q::Text | Q::Selected, m_pal.highlightedText );
|
setColor( Q::Text | Q::Selected, m_pal.highlightedText );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,27 @@
|
||||||
|
|
||||||
QSK_SUBCONTROL( QskListView, Cell )
|
QSK_SUBCONTROL( QskListView, Cell )
|
||||||
QSK_SUBCONTROL( QskListView, Text )
|
QSK_SUBCONTROL( QskListView, Text )
|
||||||
|
QSK_SUBCONTROL( QskListView, Graphic )
|
||||||
|
|
||||||
QSK_STATE( QskListView, Selected, QskAspect::FirstUserState )
|
QSK_STATE( QskListView, Selected, QskAspect::FirstUserState )
|
||||||
|
|
||||||
#define FOCUS_ON_CURRENT 1
|
#define FOCUS_ON_CURRENT 1
|
||||||
|
|
||||||
|
static inline int qskRowAt( const QskListView* listView, const QPointF& pos )
|
||||||
|
{
|
||||||
|
const auto rect = listView->viewContentsRect();
|
||||||
|
if ( rect.contains( pos ) )
|
||||||
|
{
|
||||||
|
const auto y = pos.y() - rect.top() + listView->scrollPos().y();
|
||||||
|
|
||||||
|
const int row = y / listView->rowHeight();
|
||||||
|
if ( row >= 0 && row < listView->rowCount() )
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
class QskListView::PrivateData
|
class QskListView::PrivateData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -146,14 +162,6 @@ QskListView::SelectionMode QskListView::selectionMode() const
|
||||||
return m_data->selectionMode;
|
return m_data->selectionMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
QskColorFilter QskListView::graphicFilterAt( int row, int col ) const
|
|
||||||
{
|
|
||||||
Q_UNUSED( row )
|
|
||||||
Q_UNUSED( col )
|
|
||||||
|
|
||||||
return QskColorFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
QRectF QskListView::focusIndicatorRect() const
|
QRectF QskListView::focusIndicatorRect() const
|
||||||
{
|
{
|
||||||
#if FOCUS_ON_CURRENT
|
#if FOCUS_ON_CURRENT
|
||||||
|
@ -269,13 +277,10 @@ void QskListView::mousePressEvent( QMouseEvent* event )
|
||||||
{
|
{
|
||||||
if ( m_data->selectionMode != NoSelection )
|
if ( m_data->selectionMode != NoSelection )
|
||||||
{
|
{
|
||||||
const QRectF vr = viewContentsRect();
|
const int row = qskRowAt( this, qskMousePosition( event ) );
|
||||||
if ( vr.contains( event->pos() ) )
|
if ( row >= 0 )
|
||||||
{
|
{
|
||||||
const int row = ( event->pos().y() - vr.top() + scrollPos().y() ) / rowHeight();
|
|
||||||
if ( row >= 0 && row < rowCount() )
|
|
||||||
setSelectedRow( row );
|
setSelectedRow( row );
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ class QSK_EXPORT QskListView : public QskScrollView
|
||||||
using Inherited = QskScrollView;
|
using Inherited = QskScrollView;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QSK_SUBCONTROLS( Cell, Text )
|
QSK_SUBCONTROLS( Cell, Text, Graphic )
|
||||||
QSK_STATES( Selected )
|
QSK_STATES( Selected )
|
||||||
|
|
||||||
enum SelectionMode
|
enum SelectionMode
|
||||||
|
@ -63,10 +63,6 @@ class QSK_EXPORT QskListView : public QskScrollView
|
||||||
|
|
||||||
Q_INVOKABLE virtual QVariant valueAt( int row, int col ) const = 0;
|
Q_INVOKABLE virtual QVariant valueAt( int row, int col ) const = 0;
|
||||||
|
|
||||||
#if 1
|
|
||||||
virtual QskColorFilter graphicFilterAt( int row, int col ) const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QRectF focusIndicatorRect() const override;
|
QRectF focusIndicatorRect() const override;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
|
|
|
@ -11,16 +11,91 @@
|
||||||
#include "QskBoxHints.h"
|
#include "QskBoxHints.h"
|
||||||
#include "QskSGNode.h"
|
#include "QskSGNode.h"
|
||||||
#include "QskSkinStateChanger.h"
|
#include "QskSkinStateChanger.h"
|
||||||
|
#include "QskQuick.h"
|
||||||
|
|
||||||
#include <qmath.h>
|
#include <qmath.h>
|
||||||
#include <qsgnode.h>
|
#include <qsgnode.h>
|
||||||
#include <qtransform.h>
|
#include <qtransform.h>
|
||||||
|
|
||||||
class QskListViewNode final : public QSGTransformNode
|
namespace
|
||||||
{
|
{
|
||||||
|
class ForegroundNode : public QSGNode
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
inline QskListViewNode( int columnCount )
|
void invalidate()
|
||||||
: m_columnCount( columnCount )
|
{
|
||||||
|
removeAllChildNodes();
|
||||||
|
m_columnCount = m_oldRowMin = m_oldRowMax = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rearrangeNodes( int rowMin, int rowMax, int columnCount )
|
||||||
|
{
|
||||||
|
const bool doReorder = ( columnCount == m_columnCount )
|
||||||
|
&& ( rowMin <= m_oldRowMax ) && ( rowMax >= m_oldRowMin );
|
||||||
|
|
||||||
|
if ( doReorder )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We have nodes that will be at a different position in the
|
||||||
|
list of child nodes - however their content might be unchanged.
|
||||||
|
|
||||||
|
This is a common situation, when resizing or scrolling the list.
|
||||||
|
|
||||||
|
To avoid that the text/graphic nodes have to be updated we
|
||||||
|
try to rearrange the nodes, so that they are in increasing
|
||||||
|
row order for further processing.
|
||||||
|
|
||||||
|
To avoid delete/new calls we append the leading and prepend
|
||||||
|
the trailing nodes, so that they might be used later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( rowMin >= m_oldRowMin )
|
||||||
|
{
|
||||||
|
for ( int row = m_oldRowMin; row < rowMin; row++ )
|
||||||
|
{
|
||||||
|
for ( int col = 0; col < columnCount; col++ )
|
||||||
|
{
|
||||||
|
auto childNode = firstChild();
|
||||||
|
removeChildNode( childNode );
|
||||||
|
appendChildNode( childNode );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( int row = rowMin; row < m_oldRowMin; row++ )
|
||||||
|
{
|
||||||
|
for ( int col = 0; col < columnCount; col++ )
|
||||||
|
{
|
||||||
|
auto childNode = lastChild();
|
||||||
|
removeChildNode( childNode );
|
||||||
|
prependChildNode( childNode );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_oldRowMin = rowMin;
|
||||||
|
m_oldRowMax = rowMax;
|
||||||
|
m_columnCount = columnCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*
|
||||||
|
When scrolling the majority of the child nodes are simply translated
|
||||||
|
while only few rows appear/disappear. To implement this in an efficient
|
||||||
|
way we store how the nodes were related to the rows in the previous update,
|
||||||
|
*/
|
||||||
|
|
||||||
|
int m_oldRowMin = -1;
|
||||||
|
int m_oldRowMax = -1;
|
||||||
|
int m_columnCount = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ListViewNode final : public QSGTransformNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline ListViewNode()
|
||||||
{
|
{
|
||||||
m_backgroundNode.setFlag( QSGNode::OwnedByParent, false );
|
m_backgroundNode.setFlag( QSGNode::OwnedByParent, false );
|
||||||
appendChildNode( &m_backgroundNode );
|
appendChildNode( &m_backgroundNode );
|
||||||
|
@ -29,60 +104,72 @@ class QskListViewNode final : public QSGTransformNode
|
||||||
appendChildNode( &m_foregroundNode );
|
appendChildNode( &m_foregroundNode );
|
||||||
}
|
}
|
||||||
|
|
||||||
QSGNode* backgroundNode()
|
void initialize( const QskListView* listView )
|
||||||
{
|
{
|
||||||
return &m_backgroundNode;
|
const auto scrollPos = listView->scrollPos();
|
||||||
|
setMatrix( QTransform::fromTranslate( -scrollPos.x(), -scrollPos.y() ) );
|
||||||
|
|
||||||
|
m_clipRect = listView->viewContentsRect();
|
||||||
|
m_rowHeight = listView->rowHeight();
|
||||||
|
|
||||||
|
m_rowMin = qFloor( scrollPos.y() / m_rowHeight );
|
||||||
|
|
||||||
|
const auto rowMax = ( scrollPos.y() + m_clipRect.height() ) / m_rowHeight;
|
||||||
|
m_rowMax = qFloor( rowMax - 10e-6 );
|
||||||
|
|
||||||
|
if ( m_rowMax >= listView->rowCount() )
|
||||||
|
m_rowMax = listView->rowCount() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSGNode* foregroundNode()
|
QRectF clipRect() const { return m_clipRect; }
|
||||||
{
|
|
||||||
return &m_foregroundNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void resetRows( int rowMin, int rowMax )
|
int rowMin() const { return m_rowMin; }
|
||||||
{
|
int rowMax() const { return m_rowMax; }
|
||||||
m_rowMin = rowMin;
|
int rowCount() const { return m_rowMax - m_rowMin + 1; }
|
||||||
m_rowMax = rowMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int rowMin() const
|
int rowHeight() const { return m_rowHeight; }
|
||||||
{
|
|
||||||
return m_rowMin;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int rowMax() const
|
QSGNode* backgroundNode() { return &m_backgroundNode; }
|
||||||
{
|
ForegroundNode* foregroundNode() { return &m_foregroundNode; }
|
||||||
return m_rowMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool intersects( int rowMin, int rowMax ) const
|
|
||||||
{
|
|
||||||
return ( rowMin <= m_rowMax ) && ( rowMax >= m_rowMin );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int nodeCount() const
|
|
||||||
{
|
|
||||||
return ( m_rowMin >= 0 ) ? ( m_rowMax - m_rowMin + 1 ) * m_columnCount : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int columnCount() const
|
|
||||||
{
|
|
||||||
return m_columnCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void invalidate()
|
|
||||||
{
|
|
||||||
m_rowMin = m_rowMax = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_columnCount;
|
// caching some calculations to speed things up
|
||||||
int m_rowMin = -1;
|
|
||||||
int m_rowMax = -1;
|
QRectF m_clipRect;
|
||||||
|
qreal m_rowHeight;
|
||||||
|
|
||||||
|
int m_rowMin, m_rowMax;
|
||||||
|
|
||||||
QSGNode m_backgroundNode;
|
QSGNode m_backgroundNode;
|
||||||
QSGNode m_foregroundNode;
|
ForegroundNode m_foregroundNode;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ListViewNode* qskListViewNode( const QskListView* listView )
|
||||||
|
{
|
||||||
|
if ( auto node = const_cast< QSGNode* >( qskPaintNode( listView ) ) )
|
||||||
|
{
|
||||||
|
using namespace QskSGNode;
|
||||||
|
|
||||||
|
node = findChildNode( node, QskScrollViewSkinlet::ContentsRootRole );
|
||||||
|
if ( node )
|
||||||
|
{
|
||||||
|
node = node->firstChild();
|
||||||
|
if ( node )
|
||||||
|
{
|
||||||
|
Q_ASSERT( node->type() == QSGNode::TransformNodeType );
|
||||||
|
return static_cast< ListViewNode* >( node );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ListViewNode* qskListViewNode( const QskSkinnable* skinnable )
|
||||||
|
{
|
||||||
|
return qskListViewNode( static_cast< const QskListView* >( skinnable ) );
|
||||||
|
}
|
||||||
|
|
||||||
QskListViewSkinlet::QskListViewSkinlet( QskSkin* skin )
|
QskListViewSkinlet::QskListViewSkinlet( QskSkin* skin )
|
||||||
: Inherited( skin )
|
: Inherited( skin )
|
||||||
|
@ -96,57 +183,36 @@ QSGNode* QskListViewSkinlet::updateContentsNode(
|
||||||
{
|
{
|
||||||
const auto listView = static_cast< const QskListView* >( scrollView );
|
const auto listView = static_cast< const QskListView* >( scrollView );
|
||||||
|
|
||||||
auto listViewNode = static_cast< QskListViewNode* >( node );
|
auto listViewNode = QskSGNode::ensureNode< ListViewNode >( node );
|
||||||
if ( listViewNode == nullptr )
|
listViewNode->initialize( listView );
|
||||||
listViewNode = new QskListViewNode( listView->columnCount() );
|
|
||||||
|
|
||||||
QTransform transform;
|
updateBackgroundNodes( listView, listViewNode->backgroundNode() );
|
||||||
transform.translate( -listView->scrollPos().x(), -listView->scrollPos().y() );
|
updateForegroundNodes( listView, listViewNode->foregroundNode() );
|
||||||
listViewNode->setMatrix( transform );
|
|
||||||
|
|
||||||
updateBackgroundNodes( listView, listViewNode );
|
|
||||||
updateForegroundNodes( listView, listViewNode );
|
|
||||||
|
|
||||||
return listViewNode;
|
return listViewNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskListViewSkinlet::updateBackgroundNodes(
|
void QskListViewSkinlet::updateBackgroundNodes(
|
||||||
const QskListView* listView, QskListViewNode* listViewNode ) const
|
const QskListView* listView, QSGNode* backgroundNode ) const
|
||||||
{
|
{
|
||||||
using Q = QskListView;
|
using Q = QskListView;
|
||||||
using A = QskAspect;
|
using A = QskAspect;
|
||||||
|
|
||||||
auto backgroundNode = listViewNode->backgroundNode();
|
auto listViewNode = static_cast< const ListViewNode* >( backgroundNode->parent() );
|
||||||
|
|
||||||
const auto cellHeight = listView->rowHeight();
|
|
||||||
const auto viewRect = listView->viewContentsRect();
|
|
||||||
|
|
||||||
const auto scrolledPos = listView->scrollPos();
|
|
||||||
const int rowMin = qFloor( scrolledPos.y() / cellHeight );
|
|
||||||
|
|
||||||
int rowMax = qCeil( ( scrolledPos.y() + viewRect.height() ) / cellHeight );
|
|
||||||
if ( rowMax >= listView->rowCount() )
|
|
||||||
rowMax = listView->rowCount() - 1;
|
|
||||||
|
|
||||||
const auto x0 = viewRect.left() + scrolledPos.x();
|
|
||||||
const auto y0 = viewRect.top();
|
|
||||||
|
|
||||||
auto rowNode = backgroundNode->firstChild();
|
auto rowNode = backgroundNode->firstChild();
|
||||||
|
|
||||||
const auto boxHints1 = listView->boxHints( Q::Cell | A::Lower );
|
for ( int row = listViewNode->rowMin(); row <= listViewNode->rowMax(); row++ )
|
||||||
const auto boxHints2 = listView->boxHints( Q::Cell | A::Upper );
|
|
||||||
|
|
||||||
for ( int row = rowMin; row <= rowMax; row++ )
|
|
||||||
{
|
{
|
||||||
/*
|
QskSkinStateChanger stateChanger( listView );
|
||||||
We do not use sampleRect to avoid doing the calculation
|
stateChanger.setStates( sampleStates( listView, Q::Cell, row ) );
|
||||||
of viewRect for each row.
|
|
||||||
*/
|
|
||||||
const QRectF rect( x0, y0 + row * cellHeight, viewRect.width(), cellHeight );
|
|
||||||
|
|
||||||
auto newNode = updateBoxNode( listView, rowNode, rect,
|
const auto rect = sampleRect( listView, listView->contentsRect(), Q::Cell, row );
|
||||||
( row % 2 ) ? boxHints2 : boxHints1 );
|
|
||||||
|
|
||||||
|
const QskAspect aspect = Q::Cell | ( ( row % 2 ) ? A::Upper : A::Lower );
|
||||||
|
const auto boxHints = listView->boxHints( aspect );
|
||||||
|
|
||||||
|
auto newNode = updateBoxNode( listView, rowNode, rect, boxHints );
|
||||||
if ( newNode )
|
if ( newNode )
|
||||||
{
|
{
|
||||||
if ( newNode->parent() != backgroundNode )
|
if ( newNode->parent() != backgroundNode )
|
||||||
|
@ -156,45 +222,28 @@ void QskListViewSkinlet::updateBackgroundNodes(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int rowSelected = listView->selectedRow();
|
QskSGNode::removeAllChildNodesFrom( backgroundNode, rowNode );
|
||||||
if ( rowSelected >= rowMin && rowSelected <= rowMax )
|
|
||||||
{
|
|
||||||
QskSkinStateChanger stateChanger( listView );
|
|
||||||
stateChanger.setStates( listView->skinStates() | QskListView::Selected );
|
|
||||||
|
|
||||||
const QRectF rect( x0, y0 + rowSelected * cellHeight,
|
|
||||||
viewRect.width(), cellHeight );
|
|
||||||
|
|
||||||
rowNode = updateBoxNode( listView, rowNode, rect, Q::Cell );
|
|
||||||
if ( rowNode && rowNode->parent() != backgroundNode )
|
|
||||||
backgroundNode->appendChildNode( rowNode );
|
|
||||||
}
|
|
||||||
|
|
||||||
QskSGNode::removeAllChildNodesAfter( backgroundNode, rowNode );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskListViewSkinlet::updateForegroundNodes(
|
void QskListViewSkinlet::updateForegroundNodes(
|
||||||
const QskListView* listView, QskListViewNode* listViewNode ) const
|
const QskListView* listView, QSGNode* parentNode ) const
|
||||||
{
|
{
|
||||||
auto parentNode = listViewNode->foregroundNode();
|
auto foregroundNode = static_cast< ForegroundNode* >( parentNode );
|
||||||
|
|
||||||
if ( listView->rowCount() <= 0 || listView->columnCount() <= 0 )
|
if ( listView->rowCount() <= 0 || listView->columnCount() <= 0 )
|
||||||
{
|
{
|
||||||
parentNode->removeAllChildNodes();
|
foregroundNode->invalidate();
|
||||||
listViewNode->invalidate();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto margins = listView->paddingHint( QskListView::Cell );
|
auto listViewNode = static_cast< const ListViewNode* >( parentNode->parent() );
|
||||||
|
|
||||||
const auto cr = listView->viewContentsRect();
|
const auto clipRect = listViewNode->clipRect();
|
||||||
const auto scrolledPos = listView->scrollPos();
|
|
||||||
|
|
||||||
const int rowMin = qFloor( scrolledPos.y() / listView->rowHeight() );
|
const int rowMin = listViewNode->rowMin();
|
||||||
|
const int rowMax = listViewNode->rowMax();
|
||||||
|
|
||||||
int rowMax = rowMin + qCeil( cr.height() / listView->rowHeight() );
|
foregroundNode->rearrangeNodes( rowMin, rowMax, listView->columnCount() );
|
||||||
if ( rowMax >= listView->rowCount() )
|
|
||||||
rowMax = listView->rowCount() - 1;
|
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
// should be optimized for visible columns only
|
// should be optimized for visible columns only
|
||||||
|
@ -202,67 +251,28 @@ void QskListViewSkinlet::updateForegroundNodes(
|
||||||
const int colMax = listView->columnCount() - 1;
|
const int colMax = listView->columnCount() - 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool forwards = true;
|
const auto margins = listView->paddingHint( QskListView::Cell );
|
||||||
|
|
||||||
if ( listViewNode->intersects( rowMin, rowMax ) )
|
updateVisibleForegroundNodes(
|
||||||
{
|
listView, foregroundNode, rowMin, rowMax, margins );
|
||||||
/*
|
|
||||||
We try to avoid reallcations when scrolling, by reusing
|
|
||||||
the nodes of the cells leaving the viewport for those becoming visible.
|
|
||||||
*/
|
|
||||||
|
|
||||||
forwards = ( rowMin >= listViewNode->rowMin() );
|
|
||||||
|
|
||||||
if ( forwards )
|
|
||||||
{
|
|
||||||
// usually scrolling down
|
|
||||||
for ( int row = listViewNode->rowMin(); row < rowMin; row++ )
|
|
||||||
{
|
|
||||||
for ( int col = 0; col < listView->columnCount(); col++ )
|
|
||||||
{
|
|
||||||
QSGNode* childNode = parentNode->firstChild();
|
|
||||||
parentNode->removeChildNode( childNode );
|
|
||||||
parentNode->appendChildNode( childNode );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// usually scrolling up
|
|
||||||
for ( int row = rowMax; row < listViewNode->rowMax(); row++ )
|
|
||||||
{
|
|
||||||
for ( int col = 0; col < listView->columnCount(); col++ )
|
|
||||||
{
|
|
||||||
QSGNode* childNode = parentNode->lastChild();
|
|
||||||
parentNode->removeChildNode( childNode );
|
|
||||||
parentNode->prependChildNode( childNode );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateVisibleForegroundNodes( listView, listViewNode,
|
|
||||||
rowMin, rowMax, colMin, colMax, margins, forwards );
|
|
||||||
|
|
||||||
// finally putting the nodes into their position
|
// finally putting the nodes into their position
|
||||||
auto node = parentNode->firstChild();
|
auto node = foregroundNode->firstChild();
|
||||||
|
|
||||||
const auto rowHeight = listView->rowHeight();
|
const auto rowHeight = listView->rowHeight();
|
||||||
auto y = cr.top() + rowMin * rowHeight;
|
auto y = clipRect.top() + rowMin * rowHeight;
|
||||||
|
|
||||||
for ( int row = rowMin; row <= rowMax; row++ )
|
for ( int row = rowMin; row <= rowMax; row++ )
|
||||||
{
|
{
|
||||||
qreal x = cr.left();
|
qreal x = clipRect.left();
|
||||||
|
|
||||||
for ( int col = colMin; col <= colMax; col++ )
|
for ( int col = colMin; col <= colMax; col++ )
|
||||||
{
|
{
|
||||||
Q_ASSERT( node->type() == QSGNode::TransformNodeType );
|
Q_ASSERT( node->type() == QSGNode::TransformNodeType );
|
||||||
auto transformNode = static_cast< QSGTransformNode* >( node );
|
auto transformNode = static_cast< QSGTransformNode* >( node );
|
||||||
|
|
||||||
QTransform transform;
|
transformNode->setMatrix(
|
||||||
transform.translate( x + margins.left(), y + margins.top() );
|
QTransform::fromTranslate( x + margins.left(), y + margins.top() ) );
|
||||||
|
|
||||||
transformNode->setMatrix( transform );
|
|
||||||
|
|
||||||
node = node->nextSibling();
|
node = node->nextSibling();
|
||||||
x += listView->columnWidth( col );
|
x += listView->columnWidth( col );
|
||||||
|
@ -270,26 +280,12 @@ void QskListViewSkinlet::updateForegroundNodes(
|
||||||
|
|
||||||
y += rowHeight;
|
y += rowHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
listViewNode->resetRows( rowMin, rowMax );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskListViewSkinlet::updateVisibleForegroundNodes(
|
void QskListViewSkinlet::updateVisibleForegroundNodes(
|
||||||
const QskListView* listView, QskListViewNode* listViewNode,
|
const QskListView* listView, QSGNode* parentNode,
|
||||||
int rowMin, int rowMax, int colMin, int colMax, const QMarginsF& margins,
|
int rowMin, int rowMax, const QMarginsF& margins ) const
|
||||||
bool forward ) const
|
|
||||||
{
|
{
|
||||||
auto parentNode = listViewNode->foregroundNode();
|
|
||||||
|
|
||||||
const int rowCount = rowMax - rowMin + 1;
|
|
||||||
const int colCount = colMax - colMin + 1;
|
|
||||||
const int obsoleteNodesCount = listViewNode->nodeCount() - rowCount * colCount;
|
|
||||||
|
|
||||||
if ( forward )
|
|
||||||
{
|
|
||||||
for ( int i = 0; i < obsoleteNodesCount; i++ )
|
|
||||||
delete parentNode->lastChild();
|
|
||||||
|
|
||||||
auto node = parentNode->firstChild();
|
auto node = parentNode->firstChild();
|
||||||
|
|
||||||
for ( int row = rowMin; row <= rowMax; row++ )
|
for ( int row = rowMin; row <= rowMax; row++ )
|
||||||
|
@ -302,40 +298,18 @@ void QskListViewSkinlet::updateVisibleForegroundNodes(
|
||||||
|
|
||||||
node = updateForegroundNode( listView,
|
node = updateForegroundNode( listView,
|
||||||
parentNode, static_cast< QSGTransformNode* >( node ),
|
parentNode, static_cast< QSGTransformNode* >( node ),
|
||||||
row, col, QSizeF( w, h ), forward );
|
row, col, QSizeF( w, h ) );
|
||||||
|
|
||||||
node = node->nextSibling();
|
node = node->nextSibling();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for ( int i = 0; i < obsoleteNodesCount; i++ )
|
|
||||||
delete parentNode->firstChild();
|
|
||||||
|
|
||||||
auto* node = parentNode->lastChild();
|
QskSGNode::removeAllChildNodesFrom( parentNode, node );
|
||||||
|
|
||||||
for ( int row = rowMax; row >= rowMin; row-- )
|
|
||||||
{
|
|
||||||
const qreal h = listView->rowHeight() - ( margins.top() + margins.bottom() );
|
|
||||||
|
|
||||||
for ( int col = listView->columnCount() - 1; col >= 0; col-- )
|
|
||||||
{
|
|
||||||
const auto w = listView->columnWidth( col ) - ( margins.left() + margins.right() );
|
|
||||||
|
|
||||||
node = updateForegroundNode( listView,
|
|
||||||
parentNode, static_cast< QSGTransformNode* >( node ),
|
|
||||||
row, col, QSizeF( w, h ), forward );
|
|
||||||
|
|
||||||
node = node->previousSibling();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QSGTransformNode* QskListViewSkinlet::updateForegroundNode(
|
QSGTransformNode* QskListViewSkinlet::updateForegroundNode(
|
||||||
const QskListView* listView, QSGNode* parentNode, QSGTransformNode* cellNode,
|
const QskListView* listView, QSGNode* parentNode, QSGTransformNode* cellNode,
|
||||||
int row, int col, const QSizeF& size, bool forward ) const
|
int row, int col, const QSizeF& size ) const
|
||||||
{
|
{
|
||||||
const QRectF cellRect( 0.0, 0.0, size.width(), size.height() );
|
const QRectF cellRect( 0.0, 0.0, size.width(), size.height() );
|
||||||
|
|
||||||
|
@ -407,10 +381,7 @@ QSGTransformNode* QskListViewSkinlet::updateForegroundNode(
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( forward )
|
|
||||||
parentNode->appendChildNode( newCellNode );
|
parentNode->appendChildNode( newCellNode );
|
||||||
else
|
|
||||||
parentNode->prependChildNode( newCellNode );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,14 +391,11 @@ QSGTransformNode* QskListViewSkinlet::updateForegroundNode(
|
||||||
QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView,
|
QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView,
|
||||||
QSGNode* contentNode, const QRectF& rect, int row, int col ) const
|
QSGNode* contentNode, const QRectF& rect, int row, int col ) const
|
||||||
{
|
{
|
||||||
|
using Q = QskListView;
|
||||||
using namespace QskSGNode;
|
using namespace QskSGNode;
|
||||||
|
|
||||||
auto rowStates = listView->skinStates();
|
|
||||||
if ( row == listView->selectedRow() )
|
|
||||||
rowStates |= QskListView::Selected;
|
|
||||||
|
|
||||||
QskSkinStateChanger stateChanger( listView );
|
QskSkinStateChanger stateChanger( listView );
|
||||||
stateChanger.setStates( rowStates );
|
stateChanger.setStates( sampleStates( listView, Q::Cell, row ) );
|
||||||
|
|
||||||
QSGNode* newNode = nullptr;
|
QSGNode* newNode = nullptr;
|
||||||
|
|
||||||
|
@ -439,7 +407,7 @@ QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView,
|
||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
const auto alignment = listView->alignmentHint(
|
const auto alignment = listView->alignmentHint(
|
||||||
QskListView::Cell, Qt::AlignVCenter | Qt::AlignLeft );
|
Q::Cell, Qt::AlignVCenter | Qt::AlignLeft );
|
||||||
|
|
||||||
const auto value = listView->valueAt( row, col );
|
const auto value = listView->valueAt( row, col );
|
||||||
|
|
||||||
|
@ -448,7 +416,7 @@ QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView,
|
||||||
if ( nodeRole( contentNode ) == GraphicRole )
|
if ( nodeRole( contentNode ) == GraphicRole )
|
||||||
newNode = contentNode;
|
newNode = contentNode;
|
||||||
|
|
||||||
const auto colorFilter = listView->graphicFilterAt( row, col );
|
const auto colorFilter = listView->effectiveGraphicFilter( Q::Graphic );
|
||||||
|
|
||||||
newNode = updateGraphicNode( listView, newNode,
|
newNode = updateGraphicNode( listView, newNode,
|
||||||
value.value< QskGraphic >(), colorFilter, rect, alignment );
|
value.value< QskGraphic >(), colorFilter, rect, alignment );
|
||||||
|
@ -462,7 +430,7 @@ QSGNode* QskListViewSkinlet::updateCellNode( const QskListView* listView,
|
||||||
newNode = contentNode;
|
newNode = contentNode;
|
||||||
|
|
||||||
newNode = updateTextNode( listView, newNode, rect, alignment,
|
newNode = updateTextNode( listView, newNode, rect, alignment,
|
||||||
value.toString(), QskListView::Text );
|
value.toString(), Q::Text );
|
||||||
|
|
||||||
if ( newNode )
|
if ( newNode )
|
||||||
setNodeRole( newNode, TextRole );
|
setNodeRole( newNode, TextRole );
|
||||||
|
@ -494,22 +462,43 @@ QSizeF QskListViewSkinlet::sizeHint( const QskSkinnable* skinnable,
|
||||||
return QSizeF( w, -1.0 );
|
return QSizeF( w, -1.0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QskAspect::States QskListViewSkinlet::sampleStates( const QskSkinnable* skinnable,
|
||||||
|
QskAspect::Subcontrol subControl, int index ) const
|
||||||
|
{
|
||||||
|
using Q = QskListView;
|
||||||
|
|
||||||
|
if ( subControl == Q::Cell || subControl == Q::Text || subControl == Q::Graphic )
|
||||||
|
{
|
||||||
|
const auto listView = static_cast< const QskListView* >( skinnable );
|
||||||
|
|
||||||
|
auto states = listView->skinStates();
|
||||||
|
if ( index == listView->selectedRow() )
|
||||||
|
states |= Q::Selected;
|
||||||
|
|
||||||
|
return states;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Inherited::sampleStates( skinnable, subControl, index );
|
||||||
|
}
|
||||||
|
|
||||||
QRectF QskListViewSkinlet::sampleRect( const QskSkinnable* skinnable,
|
QRectF QskListViewSkinlet::sampleRect( const QskSkinnable* skinnable,
|
||||||
const QRectF& contentsRect, QskAspect::Subcontrol subControl, int index ) const
|
const QRectF& contentsRect, QskAspect::Subcontrol subControl, int index ) const
|
||||||
{
|
{
|
||||||
using Q = QskListView;
|
using Q = QskListView;
|
||||||
|
|
||||||
const auto listView = static_cast< const QskListView* >( skinnable );
|
const auto listView = static_cast< const QskListView* >( skinnable );
|
||||||
|
|
||||||
if ( subControl == Q::Cell )
|
if ( subControl == Q::Cell )
|
||||||
{
|
{
|
||||||
const auto cellHeight = listView->rowHeight();
|
auto node = qskListViewNode( listView );
|
||||||
const auto viewRect = listView->viewContentsRect();
|
const auto clipRect = node ? node->clipRect() : listView->viewContentsRect();
|
||||||
const auto scrolledPos = listView->scrollPos();
|
|
||||||
|
|
||||||
const double x0 = viewRect.left() + scrolledPos.x();
|
const auto w = clipRect.width();
|
||||||
const double y0 = viewRect.top();
|
const auto h = listView->rowHeight();
|
||||||
|
const auto x = clipRect.left() + listView->scrollPos().x();
|
||||||
|
const auto y = clipRect.top() + index * h;
|
||||||
|
|
||||||
return QRectF( x0, y0 + index * cellHeight, viewRect.width(), cellHeight );
|
return QRectF( x, y, w, h );
|
||||||
}
|
}
|
||||||
|
|
||||||
return Inherited::sampleRect( skinnable, contentsRect, subControl, index );
|
return Inherited::sampleRect( skinnable, contentsRect, subControl, index );
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include "QskScrollViewSkinlet.h"
|
#include "QskScrollViewSkinlet.h"
|
||||||
|
|
||||||
class QskListView;
|
class QskListView;
|
||||||
class QskListViewNode;
|
|
||||||
|
|
||||||
class QMarginsF;
|
class QMarginsF;
|
||||||
class QSizeF;
|
class QSizeF;
|
||||||
|
@ -40,25 +39,27 @@ class QSK_EXPORT QskListViewSkinlet : public QskScrollViewSkinlet
|
||||||
QRectF sampleRect( const QskSkinnable*,
|
QRectF sampleRect( const QskSkinnable*,
|
||||||
const QRectF&, QskAspect::Subcontrol, int index ) const override;
|
const QRectF&, QskAspect::Subcontrol, int index ) const override;
|
||||||
|
|
||||||
|
QskAspect::States sampleStates( const QskSkinnable*,
|
||||||
|
QskAspect::Subcontrol, int index ) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QSGNode* updateContentsNode(
|
QSGNode* updateContentsNode(
|
||||||
const QskScrollView*, QSGNode* ) const override;
|
const QskScrollView*, QSGNode* ) const override;
|
||||||
|
|
||||||
virtual QSGNode* updateCellNode( const QskListView*,
|
|
||||||
QSGNode*, const QRectF&, int row, int col ) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateForegroundNodes( const QskListView*, QskListViewNode* ) const;
|
void updateForegroundNodes( const QskListView*, QSGNode* ) const;
|
||||||
void updateBackgroundNodes( const QskListView*, QskListViewNode* ) const;
|
void updateBackgroundNodes( const QskListView*, QSGNode* ) const;
|
||||||
|
|
||||||
void updateVisibleForegroundNodes(
|
void updateVisibleForegroundNodes(
|
||||||
const QskListView*, QskListViewNode*,
|
const QskListView*, QSGNode*,
|
||||||
int rowMin, int rowMax, int colMin, int colMax,
|
int rowMin, int rowMax, const QMarginsF& margin ) const;
|
||||||
const QMarginsF& margin, bool forward ) const;
|
|
||||||
|
|
||||||
QSGTransformNode* updateForegroundNode( const QskListView*,
|
QSGTransformNode* updateForegroundNode( const QskListView*,
|
||||||
QSGNode* parentNode, QSGTransformNode* cellNode,
|
QSGNode* parentNode, QSGTransformNode* cellNode,
|
||||||
int row, int col, const QSizeF&, bool forward ) const;
|
int row, int col, const QSizeF& ) const;
|
||||||
|
|
||||||
|
QSGNode* updateCellNode( const QskListView*,
|
||||||
|
QSGNode*, const QRectF&, int row, int col ) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,7 +17,9 @@ static void qskAlignedHandle( qreal start, qreal end,
|
||||||
qreal scrollBarLength, qreal minHandleLength,
|
qreal scrollBarLength, qreal minHandleLength,
|
||||||
qreal& handleStart, qreal& handleEnd )
|
qreal& handleStart, qreal& handleEnd )
|
||||||
{
|
{
|
||||||
minHandleLength = qBound( 4.0, minHandleLength, scrollBarLength );
|
// no qBound: scrollBarLength might be < 4.0
|
||||||
|
minHandleLength = qMax( 4.0, minHandleLength );
|
||||||
|
minHandleLength = qMin( minHandleLength, scrollBarLength );
|
||||||
|
|
||||||
handleStart = start * scrollBarLength;
|
handleStart = start * scrollBarLength;
|
||||||
handleEnd = end * scrollBarLength;
|
handleEnd = end * scrollBarLength;
|
||||||
|
@ -178,22 +180,6 @@ QSGNode* QskScrollViewSkinlet::updateContentsNode(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSGNode* QskScrollViewSkinlet::contentsNode( const QskScrollView* scrollView )
|
|
||||||
{
|
|
||||||
if ( auto node = const_cast< QSGNode* >( qskPaintNode( scrollView ) ) )
|
|
||||||
{
|
|
||||||
node = QskSGNode::findChildNode( node, ContentsRootRole );
|
|
||||||
if ( node )
|
|
||||||
{
|
|
||||||
node = node->firstChild();
|
|
||||||
if ( node )
|
|
||||||
return node->firstChild();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
QRectF QskScrollViewSkinlet::viewportRect(
|
QRectF QskScrollViewSkinlet::viewportRect(
|
||||||
const QskScrollView* scrollView, const QRectF& contentsRect ) const
|
const QskScrollView* scrollView, const QRectF& contentsRect ) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,7 +43,6 @@ class QSK_EXPORT QskScrollViewSkinlet : public QskSkinlet
|
||||||
quint8 nodeRole, QSGNode* ) const override;
|
quint8 nodeRole, QSGNode* ) const override;
|
||||||
|
|
||||||
virtual QSGNode* updateContentsNode( const QskScrollView*, QSGNode* ) const;
|
virtual QSGNode* updateContentsNode( const QskScrollView*, QSGNode* ) const;
|
||||||
QSGNode* contentsNode( const QskScrollView* );
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSGNode* updateContentsRootNode( const QskScrollView*, QSGNode* ) const;
|
QSGNode* updateContentsRootNode( const QskScrollView*, QSGNode* ) const;
|
||||||
|
|
Loading…
Reference in New Issue