hiding the fill/centerIn implementation details

This commit is contained in:
Uwe Rathmann 2024-10-13 12:21:40 +02:00
parent d2b12bcf44
commit 5d9bf64a7b
2 changed files with 195 additions and 109 deletions

View File

@ -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;
}

View File

@ -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;