From 5d9bf64a7bb1fffa99201783319bc33f7e7a151e Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 13 Oct 2024 12:21:40 +0200 Subject: [PATCH] hiding the fill/centerIn implementation details --- src/controls/QskItemAnchors.cpp | 250 ++++++++++++++++++++++---------- src/controls/QskItemAnchors.h | 54 +++---- 2 files changed, 195 insertions(+), 109 deletions(-) diff --git a/src/controls/QskItemAnchors.cpp b/src/controls/QskItemAnchors.cpp index f4e93298..1ddfe404 100644 --- a/src/controls/QskItemAnchors.cpp +++ b/src/controls/QskItemAnchors.cpp @@ -68,6 +68,12 @@ namespace } } + bool isCenterAnchorPoint( Qt::AnchorPoint edge ) + { + return ( edge == Qt::AnchorHorizontalCenter ) + || ( edge == Qt::AnchorVerticalCenter ); + } + struct AnchorOperators { QQuickAnchorLine ( QQuickAnchors::*line ) () const; @@ -116,18 +122,27 @@ QQuickItem* QskItemAnchors::attachedItem() const QMarginsF QskItemAnchors::margins() const { - if ( const auto anchors = qskGetAnchors( m_attachedItem ) ) - { - return QMarginsF( anchors->leftMargin(), anchors->topMargin(), - anchors->rightMargin(), anchors->bottomMargin() ); - } + const auto anchors = qskGetAnchors( m_attachedItem ); + if ( anchors == nullptr ) + return QMarginsF(); - return QMarginsF(); + const auto d = QQuickAnchorsPrivate::get( anchors ); + + const auto left = d->leftMarginExplicit ? d->leftMargin : d->margins; + const auto right = d->rightMarginExplicit ? d->rightMargin : d->margins; + const auto top = d->rightMarginExplicit ? d->rightMargin : d->margins; + const auto bottom = d->bottomMarginExplicit ? d->bottomMargin : d->margins; + + return QMarginsF( left, top, right, bottom ); } void QskItemAnchors::setMargins( const QMarginsF& margins ) { - if ( const auto anchors = qskGetOrCreateAnchors( m_attachedItem ) ) + auto anchors = qskGetOrCreateAnchors( m_attachedItem ); + if ( anchors == nullptr ) + return; + + if ( margins != this->margins() ) { anchors->setLeftMargin( margins.left() ); anchors->setRightMargin( margins.right() ); @@ -136,15 +151,26 @@ void QskItemAnchors::setMargins( const QMarginsF& margins ) } } +void QskItemAnchors::setCenterOffsets( + qreal horizontalOffset, qreal verticalOffset ) +{ + if ( auto anchors = qskGetOrCreateAnchors( m_attachedItem ) ) + { + anchors->setHorizontalCenterOffset( horizontalOffset ); + anchors->setVerticalCenterOffset( verticalOffset ); + } +} + void QskItemAnchors::setCenterOffset( Qt::Orientation orientation, qreal offset ) { - if ( const auto anchors = qskGetOrCreateAnchors( m_attachedItem ) ) - { - if ( orientation == Qt::Horizontal ) - anchors->setHorizontalCenterOffset( offset ); - else - anchors->setVerticalCenterOffset( offset ); - } + auto anchors = qskGetOrCreateAnchors( m_attachedItem ); + if ( anchors == nullptr ) + return; + + if ( orientation == Qt::Horizontal ) + anchors->setHorizontalCenterOffset( offset ); + else + anchors->setVerticalCenterOffset( offset ); } qreal QskItemAnchors::centerOffset( Qt::Orientation orientation ) @@ -160,6 +186,22 @@ qreal QskItemAnchors::centerOffset( Qt::Orientation orientation ) return 0.0; } +QQuickItem* QskItemAnchors::baseItem( Qt::AnchorPoint edge ) const +{ + const auto anchors = qskGetAnchors( m_attachedItem ); + if ( anchors == nullptr ) + return nullptr; + + if ( auto fill = anchors->fill() ) + return !isCenterAnchorPoint( edge ) ? fill : nullptr; + + if ( auto centerIn = anchors->centerIn() ) + return isCenterAnchorPoint( edge ) ? centerIn : nullptr; + + const auto& ops = operators( edge ); + return ( ( anchors->*ops.line ) () ).item; +} + void QskItemAnchors::addAnchors( Qt::Corner corner, QQuickItem* baseItem, Qt::Corner baseCorner ) { @@ -179,24 +221,12 @@ void QskItemAnchors::addAnchors( Qt::Corner corner, baseItem, anchorPoint( baseCorner, Qt::Vertical ) ); } -void QskItemAnchors::addAnchors( QQuickItem* baseItem, Qt::Orientations orientations ) -{ - if ( orientations & Qt::Horizontal ) - { - addAnchor( Qt::AnchorLeft, baseItem, Qt::AnchorLeft ); - addAnchor( Qt::AnchorRight, baseItem, Qt::AnchorRight ); - } - - if ( orientations & Qt::Vertical ) - { - addAnchor( Qt::AnchorTop, baseItem, Qt::AnchorTop ); - addAnchor( Qt::AnchorBottom, baseItem, Qt::AnchorBottom ); - } -} - void QskItemAnchors::addAnchor( Qt::AnchorPoint edge, QQuickItem* baseItem, Qt::AnchorPoint baseEdge ) { + if ( baseItem == nullptr ) + return; + if ( const auto anchors = qskGetOrCreateAnchors( m_attachedItem ) ) { const auto& ops = operators( edge ); @@ -206,23 +236,132 @@ void QskItemAnchors::addAnchor( Qt::AnchorPoint edge, QQuickItem* baseItem, void QskItemAnchors::removeAnchor( Qt::AnchorPoint edge ) { - if ( const auto anchors = qskGetAnchors( m_attachedItem ) ) + const auto anchors = qskGetAnchors( m_attachedItem ); + if ( anchors == nullptr ) + return; + + if ( auto fill = anchors->fill() ) { - const auto& ops = operators( edge ); - ( anchors->*ops.resetLine ) (); + if ( !isCenterAnchorPoint( edge ) ) + { + anchors->resetFill(); + + // setting the other borders as anchors + for ( auto anchorPoint : { Qt::AnchorLeft, Qt::AnchorRight, + Qt::AnchorTop, Qt::AnchorBottom } ) + { + if ( edge != anchorPoint ) + addAnchor( anchorPoint, fill, anchorPoint ); + } + } + + return; } + + if ( auto centerIn = anchors->centerIn() ) + { + if ( isCenterAnchorPoint( edge ) ) + { + anchors->resetCenterIn(); + + // setting the other direction as anchor + const auto otherEdge = ( edge == Qt::AnchorHorizontalCenter ) + ? Qt::AnchorVerticalCenter : Qt::AnchorHorizontalCenter; + + addAnchor( otherEdge, centerIn, otherEdge ); + } + + return; + } + + const auto& ops = operators( edge ); + ( anchors->*ops.resetLine ) (); } - -QQuickItem* QskItemAnchors::baseItem( Qt::AnchorPoint edge ) const +void QskItemAnchors::clearAnchors() { if ( const auto anchors = qskGetAnchors( m_attachedItem ) ) { - const auto& ops = operators( edge ); - return ( ( anchors->*ops.line ) () ).item; - } + anchors->resetFill(); + anchors->resetCenterIn(); - return nullptr; + for ( int i = 0; i < 6; i++ ) + { + const auto& ops = operators( static_cast< Qt::AnchorPoint >( i ) ); + ( anchors->*ops.resetLine ) (); + } + } +} + +void QskItemAnchors::setBorderAnchors( QQuickItem* baseItem, Qt::Orientations orientations ) +{ + if ( baseItem == nullptr || m_attachedItem == nullptr ) + return; + + switch( orientations ) + { + case Qt::Horizontal: + { + addAnchor( Qt::AnchorLeft, baseItem, Qt::AnchorLeft ); + addAnchor( Qt::AnchorRight, baseItem, Qt::AnchorRight ); + break; + } + + case Qt::Vertical: + { + addAnchor( Qt::AnchorTop, baseItem, Qt::AnchorTop ); + addAnchor( Qt::AnchorBottom, baseItem, Qt::AnchorBottom ); + break; + } + + case Qt::Horizontal | Qt::Vertical: + { + auto anchors = qskGetOrCreateAnchors( m_attachedItem ); + for ( int i = 0; i < 6; i++ ) + { + const auto& ops = operators( static_cast< Qt::AnchorPoint >( i ) ); + ( anchors->*ops.resetLine ) (); + } + + anchors->setFill( baseItem ); + break; + } + } +} + +void QskItemAnchors::setCenterAnchors( QQuickItem* baseItem, Qt::Orientations orientations ) +{ + if ( baseItem == nullptr || m_attachedItem == nullptr ) + return; + + switch( orientations ) + { + case Qt::Horizontal: + { + addAnchor( Qt::AnchorHorizontalCenter, baseItem, Qt::AnchorHorizontalCenter ); + break; + } + + case Qt::Vertical: + { + addAnchor( Qt::AnchorVerticalCenter, baseItem, Qt::AnchorVerticalCenter ); + break; + } + + case Qt::Horizontal | Qt::Vertical: + { + auto anchors = qskGetOrCreateAnchors( m_attachedItem ); + + for ( int i = 0; i < 6; i++ ) + { + const auto& ops = operators( static_cast< Qt::AnchorPoint >( i ) ); + ( anchors->*ops.resetLine ) (); + } + + anchors->setCenterIn( baseItem ); + break; + } + } } Qt::AnchorPoint QskItemAnchors::basePosition( Qt::AnchorPoint edge ) const @@ -242,38 +381,3 @@ Qt::AnchorPoint QskItemAnchors::basePosition( Qt::AnchorPoint edge ) const return Qt::AnchorLeft; // something } - -void QskItemAnchors::setControlItem( QQuickItem* item, bool adjustSize ) -{ - if ( const auto anchors = qskGetOrCreateAnchors( m_attachedItem ) ) - { - if ( adjustSize ) - anchors->setFill( item ); - else - anchors->setCenterIn( item ); - } -} - -void QskItemAnchors::removeControlItem( bool adjustSize ) -{ - if ( auto anchors = qskGetAnchors( m_attachedItem ) ) - { - if ( adjustSize ) - anchors->resetFill(); - else - anchors->resetCenterIn(); - } -} - -QQuickItem* QskItemAnchors::controlItem( bool adjustSize ) const -{ - if ( const auto anchors = qskGetAnchors( m_attachedItem ) ) - { - if ( adjustSize ) - return anchors->fill(); - else - return anchors->centerIn(); - } - - return nullptr; -} diff --git a/src/controls/QskItemAnchors.h b/src/controls/QskItemAnchors.h index 0ba5a448..f75fab77 100644 --- a/src/controls/QskItemAnchors.h +++ b/src/controls/QskItemAnchors.h @@ -17,35 +17,23 @@ class QQuickItem; QskItemAnchors is a C++ API to access the Qt/Quick anchoring, that has been designed to be used from QML. - Qt/Quick anchoring is a simple concept, that allows to - - - attach a border ( Qt::AnchorPoint ) of attachedItem to a border of a baseItem - - center attachedItem to the center of a controlItem - - The Qt/Quick implementation supports attaching/centering to the parent or - the siblings of attachedItem only ( conceptually this limitation - would not be necessary ). - - While it is possible to have attachments for each border you can't - center and attach at the same time. - - The expected logic would be, that defining an attachment disables - centering and v.v. - however the implementation tolerates conflicts. - Even worse is is possible to define centering ( = centerIn ) and - center-/resizing ( = fill ) to different items at the same time. - - These conflicts are resolved by applying only one of the definitions in - the following precedence: - - 1) fill - 2) centerIn - 3) anchors + Qt/Quick anchoring is a simple concept, that allows to attach + borders ( Qt::AnchorPoint ) of attachedItem to a borders of + other items. It is up to the user to avoid cycles or conflicting + anchor chains. Note that Qt/Quick ( in opposite to Qt/GraphicsView ) anchoring is not capable of handling typical layout scenarios, like distributing - the space of a bounding rectangle to a chain of anchored children. + the space of a bounding rectangle to a chain of anchored children. For those you can use QskAnchorLayout/QskAnchorBox. + The Qt/Quick implementation supports attaching to the parent or + the siblings of attachedItem only ( conceptually this limitation + would not be necessary ). + + Note that what is known in QML as "fill" or "centerIn" can be done + using setBorderAnchors or setCenterAnchors. + Limitations: - access to baseline settings are not implemented ( for no other reason than Qt::AnchorPoint does not have it ) @@ -67,26 +55,20 @@ class QSK_EXPORT QskItemAnchors QMarginsF margins() const; void setMargins( const QMarginsF& ); + void setCenterOffsets( qreal horizontalOffset, qreal verticalOffset ); void setCenterOffset( Qt::Orientation, qreal offset ); qreal centerOffset( Qt::Orientation ); + // add to - or remove from - the list of anchors void addAnchor( Qt::AnchorPoint, QQuickItem*, Qt::AnchorPoint ); void addAnchors( Qt::Corner, QQuickItem*, Qt::Corner ); - void addAnchors( QQuickItem*, Qt::Orientations = Qt::Horizontal | Qt::Vertical ); - void removeAnchor( Qt::AnchorPoint ); - /* - Qt/Quick anchoring knows the convenience modes "fill" and "centerIn". - Internally these modes are not(!) mapped to anchor definitions. + void clearAnchors(); - Both modes are setting the center point of the attachedItem to the center - of the controlItem. "fill" also adjusts the size. - */ - - QQuickItem* controlItem( bool adjustSize ) const; - void setControlItem( QQuickItem*, bool adjustSize ); - void removeControlItem( bool adjustSize ); + // replacing the list of anchors + void setBorderAnchors( QQuickItem*, Qt::Orientations = Qt::Horizontal | Qt::Vertical ); + void setCenterAnchors( QQuickItem*, Qt::Orientations = Qt::Horizontal | Qt::Vertical ); private: QPointer< QQuickItem > m_attachedItem;