trying to reduce the number of updates

This commit is contained in:
Uwe Rathmann 2024-10-14 10:56:37 +02:00
parent 0cdff58c93
commit 3d77cfbb7a
2 changed files with 179 additions and 107 deletions

View File

@ -12,7 +12,44 @@ QSK_QT_PRIVATE_BEGIN
#include <private/qquickitem_p.h> #include <private/qquickitem_p.h>
QSK_QT_PRIVATE_END QSK_QT_PRIVATE_END
QQuickAnchors* qskGetOrCreateAnchors( QQuickItem* item ) namespace
{
struct AnchorLineOperators
{
QQuickAnchorLine ( QQuickAnchors::*line ) () const;
void ( QQuickAnchors::*setLine )( const QQuickAnchorLine& );
void ( QQuickAnchors::*resetLine )();
};
class UpdateBlocker
{
public:
UpdateBlocker( QQuickAnchors* anchors )
: m_anchors( anchors )
{
auto d = QQuickAnchorsPrivate::get( anchors );
m_wasComplete = d->componentComplete;
d->componentComplete = false;
}
~UpdateBlocker()
{
reset();
}
void reset() const
{
auto d = QQuickAnchorsPrivate::get( m_anchors );
d->componentComplete = m_wasComplete;
}
private:
QQuickAnchors* m_anchors;
bool m_wasComplete;
};
}
static inline QQuickAnchors* qskGetOrCreateAnchors( QQuickItem* item )
{ {
if ( item == nullptr ) if ( item == nullptr )
return nullptr; return nullptr;
@ -20,7 +57,7 @@ QQuickAnchors* qskGetOrCreateAnchors( QQuickItem* item )
return QQuickItemPrivate::get( item )->anchors(); return QQuickItemPrivate::get( item )->anchors();
} }
QQuickAnchors* qskGetAnchors( QQuickItem* item ) static inline QQuickAnchors* qskGetAnchors( QQuickItem* item )
{ {
if ( item == nullptr ) if ( item == nullptr )
return nullptr; return nullptr;
@ -28,77 +65,67 @@ QQuickAnchors* qskGetAnchors( QQuickItem* item )
return QQuickItemPrivate::get( item )->_anchors; return QQuickItemPrivate::get( item )->_anchors;
} }
const QQuickAnchors* qskGetAnchors( const QQuickItem* item ) static inline const QQuickAnchors* qskGetAnchors( const QQuickItem* item )
{ {
return qskGetAnchors( const_cast< QQuickItem* >( item ) ); return qskGetAnchors( const_cast< QQuickItem* >( item ) );
} }
namespace static inline QQuickAnchors::Anchor qskToQuickAnchor( Qt::AnchorPoint edge )
{ {
inline QQuickAnchors::Anchor toQuickAnchor( Qt::AnchorPoint edge ) using A = QQuickAnchors;
{
using A = QQuickAnchors;
switch( edge ) switch( edge )
{ {
case Qt::AnchorLeft: return A::LeftAnchor; case Qt::AnchorLeft: return A::LeftAnchor;
case Qt::AnchorHorizontalCenter: return A::HCenterAnchor; case Qt::AnchorHorizontalCenter: return A::HCenterAnchor;
case Qt::AnchorRight: return A::RightAnchor; case Qt::AnchorRight: return A::RightAnchor;
case Qt::AnchorTop: return A::TopAnchor; case Qt::AnchorTop: return A::TopAnchor;
case Qt::AnchorVerticalCenter: return A::VCenterAnchor; case Qt::AnchorVerticalCenter: return A::VCenterAnchor;
case Qt::AnchorBottom: return A::BottomAnchor; case Qt::AnchorBottom: return A::BottomAnchor;
default: return A::InvalidAnchor; default: return A::InvalidAnchor;
}
} }
}
inline Qt::AnchorPoint toAnchorPoint( QQuickAnchors::Anchor anchor ) static inline Qt::AnchorPoint qskToAnchorPoint( QQuickAnchors::Anchor anchor )
{
using A = QQuickAnchors;
switch( anchor )
{ {
using A = QQuickAnchors; case A::LeftAnchor: return Qt::AnchorLeft;
case A::HCenterAnchor: return Qt::AnchorHorizontalCenter;
switch( anchor ) case A::RightAnchor: return Qt::AnchorRight;
{ case A::TopAnchor: return Qt::AnchorTop;
case A::LeftAnchor: return Qt::AnchorLeft; case A::VCenterAnchor: return Qt::AnchorVerticalCenter;
case A::HCenterAnchor: return Qt::AnchorHorizontalCenter; case A::BottomAnchor: return Qt::AnchorBottom;
case A::RightAnchor: return Qt::AnchorRight; case A::BaselineAnchor: return Qt::AnchorTop; // not supported
case A::TopAnchor: return Qt::AnchorTop; default: return Qt::AnchorLeft;
case A::VCenterAnchor: return Qt::AnchorVerticalCenter;
case A::BottomAnchor: return Qt::AnchorBottom;
case A::BaselineAnchor: return Qt::AnchorTop; // not supported
default: return Qt::AnchorLeft;
}
} }
}
bool isCenterAnchorPoint( Qt::AnchorPoint edge ) static inline bool qskIsCenterAnchorPoint( Qt::AnchorPoint edge )
{ {
return ( edge == Qt::AnchorHorizontalCenter ) return ( edge == Qt::AnchorHorizontalCenter )
|| ( edge == Qt::AnchorVerticalCenter ); || ( edge == Qt::AnchorVerticalCenter );
} }
struct AnchorOperators static inline const AnchorLineOperators& qskAnchorLineOperators( Qt::AnchorPoint edge )
{
using A = QQuickAnchors;
static constexpr AnchorLineOperators table[] =
{ {
QQuickAnchorLine ( QQuickAnchors::*line ) () const; // in order of Qt::AnchorPoint
void ( QQuickAnchors::*setLine )( const QQuickAnchorLine& );
void ( QQuickAnchors::*resetLine )(); { &A::left, &A::setLeft, &A::resetLeft },
{ &A::horizontalCenter, &A::setHorizontalCenter, &A::resetHorizontalCenter },
{ &A::right, &A::setRight, &A::resetRight },
{ &A::top, &A::setTop, &A::resetTop },
{ &A::verticalCenter, &A::setVerticalCenter, &A::resetVerticalCenter },
{ &A::bottom, &A::setBottom, &A::resetBottom }
}; };
const AnchorOperators& operators( Qt::AnchorPoint edge ) return table[edge];
{
using A = QQuickAnchors;
static constexpr AnchorOperators table[] =
{
// in order of Qt::AnchorPoint
{ &A::left, &A::setLeft, &A::resetLeft },
{ &A::horizontalCenter, &A::setHorizontalCenter, &A::resetHorizontalCenter },
{ &A::right, &A::setRight, &A::resetRight },
{ &A::top, &A::setTop, &A::resetTop },
{ &A::verticalCenter, &A::setVerticalCenter, &A::resetVerticalCenter },
{ &A::bottom, &A::setBottom, &A::resetBottom }
};
return table[edge];
}
} }
QskItemAnchors::QskItemAnchors( QQuickItem* attachedItem ) QskItemAnchors::QskItemAnchors( QQuickItem* attachedItem )
@ -142,12 +169,36 @@ void QskItemAnchors::setMargins( const QMarginsF& margins )
if ( anchors == nullptr ) if ( anchors == nullptr )
return; return;
if ( margins != this->margins() ) const auto oldMargins = this->margins();
Qt::Orientations changes;
if ( margins.left() != oldMargins.left() )
changes |= Qt::Horizontal;
if ( margins.right() != oldMargins.right() )
changes |= Qt::Horizontal;
if ( margins.top() != oldMargins.top() )
changes |= Qt::Vertical;
if ( margins.bottom() != oldMargins.bottom() )
changes |= Qt::Vertical;
if ( changes )
{ {
anchors->setLeftMargin( margins.left() ); const auto left = margins.left();
UpdateBlocker blocker( anchors );
anchors->setLeftMargin( left + 1.0 );
anchors->setRightMargin( margins.right() ); anchors->setRightMargin( margins.right() );
anchors->setTopMargin( margins.top() ); anchors->setTopMargin( margins.top() );
anchors->setBottomMargin( margins.bottom() ); anchors->setBottomMargin( margins.bottom() );
blocker.reset();
anchors->setLeftMargin( left ); // trigger final update
} }
} }
@ -193,17 +244,17 @@ QQuickItem* QskItemAnchors::settledItem( Qt::AnchorPoint edge ) const
return nullptr; return nullptr;
if ( auto fill = anchors->fill() ) if ( auto fill = anchors->fill() )
return !isCenterAnchorPoint( edge ) ? fill : nullptr; return !qskIsCenterAnchorPoint( edge ) ? fill : nullptr;
if ( auto centerIn = anchors->centerIn() ) if ( auto centerIn = anchors->centerIn() )
return isCenterAnchorPoint( edge ) ? centerIn : nullptr; return qskIsCenterAnchorPoint( edge ) ? centerIn : nullptr;
const auto& ops = operators( edge ); const auto& ops = qskAnchorLineOperators( edge );
return ( ( anchors->*ops.line ) () ).item; return ( ( anchors->*ops.line ) () ).item;
} }
void QskItemAnchors::addAnchors( Qt::Corner corner, void QskItemAnchors::addAnchors( Qt::Corner corner,
QQuickItem* baseItem, Qt::Corner baseCorner ) QQuickItem* settledItem, Qt::Corner settledItemCorner )
{ {
auto anchorPoint = auto anchorPoint =
[]( Qt::Corner corner, Qt::Orientation orientation ) []( Qt::Corner corner, Qt::Orientation orientation )
@ -215,22 +266,22 @@ void QskItemAnchors::addAnchors( Qt::Corner corner,
}; };
addAnchor( anchorPoint( corner, Qt::Horizontal ), addAnchor( anchorPoint( corner, Qt::Horizontal ),
baseItem, anchorPoint( baseCorner, Qt::Horizontal ) ); settledItem, anchorPoint( settledItemCorner, Qt::Horizontal ) );
addAnchor( anchorPoint( corner, Qt::Vertical ), addAnchor( anchorPoint( corner, Qt::Vertical ),
baseItem, anchorPoint( baseCorner, Qt::Vertical ) ); settledItem, anchorPoint( settledItemCorner, Qt::Vertical ) );
} }
void QskItemAnchors::addAnchor( Qt::AnchorPoint edge, QQuickItem* baseItem, void QskItemAnchors::addAnchor( Qt::AnchorPoint edge, QQuickItem* settledItem,
Qt::AnchorPoint baseEdge ) Qt::AnchorPoint settledItemEdge )
{ {
if ( baseItem == nullptr ) if ( settledItem == nullptr )
return; return;
if ( const auto anchors = qskGetOrCreateAnchors( m_attachedItem ) ) if ( const auto anchors = qskGetOrCreateAnchors( m_attachedItem ) )
{ {
const auto& ops = operators( edge ); const auto& ops = qskAnchorLineOperators( edge );
( anchors->*ops.setLine )( { baseItem, toQuickAnchor( baseEdge ) } ); ( anchors->*ops.setLine )( { settledItem, qskToQuickAnchor( settledItemEdge ) } );
} }
} }
@ -242,7 +293,7 @@ void QskItemAnchors::removeAnchor( Qt::AnchorPoint edge )
if ( auto fill = anchors->fill() ) if ( auto fill = anchors->fill() )
{ {
if ( !isCenterAnchorPoint( edge ) ) if ( !qskIsCenterAnchorPoint( edge ) )
{ {
anchors->resetFill(); anchors->resetFill();
@ -260,7 +311,7 @@ void QskItemAnchors::removeAnchor( Qt::AnchorPoint edge )
if ( auto centerIn = anchors->centerIn() ) if ( auto centerIn = anchors->centerIn() )
{ {
if ( isCenterAnchorPoint( edge ) ) if ( qskIsCenterAnchorPoint( edge ) )
{ {
anchors->resetCenterIn(); anchors->resetCenterIn();
@ -274,77 +325,98 @@ void QskItemAnchors::removeAnchor( Qt::AnchorPoint edge )
return; return;
} }
const auto& ops = operators( edge ); const auto& ops = qskAnchorLineOperators( edge );
( anchors->*ops.resetLine ) (); ( anchors->*ops.resetLine ) ();
} }
void QskItemAnchors::clearAnchors() void QskItemAnchors::clearAnchors()
{ {
if ( const auto anchors = qskGetAnchors( m_attachedItem ) ) const auto anchors = qskGetAnchors( m_attachedItem );
{ if ( anchors == nullptr )
anchors->resetFill(); return;
anchors->resetCenterIn();
for ( int i = 0; i < 6; i++ ) const UpdateBlocker blocker( anchors );
{
const auto& ops = operators( static_cast< Qt::AnchorPoint >( i ) ); anchors->resetFill();
( anchors->*ops.resetLine ) (); anchors->resetCenterIn();
}
for ( int i = 0; i < 6; i++ )
{
const auto& ops = qskAnchorLineOperators( static_cast< Qt::AnchorPoint >( i ) );
( anchors->*ops.resetLine ) ();
} }
} }
void QskItemAnchors::setBorderAnchors( QQuickItem* baseItem, Qt::Orientations orientations ) void QskItemAnchors::setBorderAnchors(
QQuickItem* settledItem, Qt::Orientations orientations )
{ {
if ( baseItem == nullptr || m_attachedItem == nullptr ) if ( settledItem == nullptr || m_attachedItem == nullptr )
return; return;
auto anchors = qskGetOrCreateAnchors( m_attachedItem );
switch( orientations ) switch( orientations )
{ {
case Qt::Horizontal: case Qt::Horizontal:
{ {
addAnchor( Qt::AnchorLeft, baseItem, Qt::AnchorLeft ); clearAnchors();
addAnchor( Qt::AnchorRight, baseItem, Qt::AnchorRight );
const UpdateBlocker blocker( anchors );
addAnchor( Qt::AnchorLeft, settledItem, Qt::AnchorLeft );
blocker.reset();
addAnchor( Qt::AnchorRight, settledItem, Qt::AnchorRight );
break; break;
} }
case Qt::Vertical: case Qt::Vertical:
{ {
addAnchor( Qt::AnchorTop, baseItem, Qt::AnchorTop ); clearAnchors();
addAnchor( Qt::AnchorBottom, baseItem, Qt::AnchorBottom );
const UpdateBlocker blocker( anchors );
addAnchor( Qt::AnchorTop, settledItem, Qt::AnchorTop );
blocker.reset();
addAnchor( Qt::AnchorBottom, settledItem, Qt::AnchorBottom );
break; break;
} }
case Qt::Horizontal | Qt::Vertical: case Qt::Horizontal | Qt::Vertical:
{ {
auto anchors = qskGetOrCreateAnchors( m_attachedItem ); if ( settledItem != anchors->fill() )
for ( int i = 0; i < 6; i++ )
{ {
const auto& ops = operators( static_cast< Qt::AnchorPoint >( i ) ); clearAnchors();
( anchors->*ops.resetLine ) (); anchors->setFill( settledItem );
} }
anchors->setFill( baseItem );
break; break;
} }
} }
} }
void QskItemAnchors::setCenterAnchors( QQuickItem* baseItem, Qt::Orientations orientations ) void QskItemAnchors::setCenterAnchors(
QQuickItem* settledItem, Qt::Orientations orientations )
{ {
if ( baseItem == nullptr || m_attachedItem == nullptr ) if ( settledItem == nullptr || m_attachedItem == nullptr )
return; return;
switch( orientations ) switch( orientations )
{ {
case Qt::Horizontal: case Qt::Horizontal:
{ {
addAnchor( Qt::AnchorHorizontalCenter, baseItem, Qt::AnchorHorizontalCenter ); clearAnchors();
addAnchor( Qt::AnchorHorizontalCenter,
settledItem, Qt::AnchorHorizontalCenter );
break; break;
} }
case Qt::Vertical: case Qt::Vertical:
{ {
addAnchor( Qt::AnchorVerticalCenter, baseItem, Qt::AnchorVerticalCenter ); clearAnchors();
addAnchor( Qt::AnchorVerticalCenter,
settledItem, Qt::AnchorVerticalCenter );
break; break;
} }
@ -352,13 +424,11 @@ void QskItemAnchors::setCenterAnchors( QQuickItem* baseItem, Qt::Orientations or
{ {
auto anchors = qskGetOrCreateAnchors( m_attachedItem ); auto anchors = qskGetOrCreateAnchors( m_attachedItem );
for ( int i = 0; i < 6; i++ ) if ( settledItem != anchors->centerIn() )
{ {
const auto& ops = operators( static_cast< Qt::AnchorPoint >( i ) ); clearAnchors();
( anchors->*ops.resetLine ) (); anchors->setCenterIn( settledItem );
} }
anchors->setCenterIn( baseItem );
break; break;
} }
} }
@ -375,8 +445,8 @@ Qt::AnchorPoint QskItemAnchors::settledItemAnchorPoint( Qt::AnchorPoint edge ) c
we are lying and report Qt::AnchorTop instead. Hm ... we are lying and report Qt::AnchorTop instead. Hm ...
*/ */
const auto& ops = operators( edge ); const auto& ops = qskAnchorLineOperators( edge );
return toAnchorPoint( ( ( anchors->*ops.line ) () ).anchorLine ); return qskToAnchorPoint( ( ( anchors->*ops.line ) () ).anchorLine );
} }
return Qt::AnchorLeft; // something return Qt::AnchorLeft; // something

View File

@ -29,7 +29,9 @@ class QQuickItem;
of attachedItem only ( conceptually this limitation would not be necessary ). of attachedItem only ( conceptually this limitation would not be necessary ).
Note that what is known in QML as "fill" or "centerIn" can be done Note that what is known in QML as "fill" or "centerIn" can be done
using setBorderAnchors or setCenterAnchors. using setBorderAnchors or setCenterAnchors. However the basic layout
functionality provided from QskControl::autoLayoutChildren usually
offers a more efficient implementation for most situations.
Limitations: Limitations:
- access to baseline settings are not implemented - access to baseline settings are not implemented