AnchorBox improved

This commit is contained in:
Uwe Rathmann 2020-04-04 18:47:44 +02:00
parent d5604823c2
commit a655c96c8b
3 changed files with 80 additions and 67 deletions

View File

@ -30,22 +30,22 @@ namespace
switch( anchorPoint ) switch( anchorPoint )
{ {
case Qt::AnchorLeft: case Qt::AnchorLeft:
return Term( left ); return Term( m_left );
case Qt::AnchorHorizontalCenter: case Qt::AnchorHorizontalCenter:
return centerH(); return centerH();
case Qt::AnchorRight: case Qt::AnchorRight:
return Term( right ); return Term( m_right );
case Qt::AnchorTop: case Qt::AnchorTop:
return Term( top ); return Term( m_top );
case Qt::AnchorVerticalCenter: case Qt::AnchorVerticalCenter:
return centerV(); return centerV();
case Qt::AnchorBottom: case Qt::AnchorBottom:
return Term( bottom ); return Term( m_bottom );
} }
return Expression(); return Expression();
@ -58,17 +58,23 @@ namespace
QRectF rect() const QRectF rect() const
{ {
return QRectF( left.value(), top.value(), return QRectF( m_left.value(), m_top.value(),
right.value() - left.value(), bottom.value() - top.value() ); m_right.value() - m_left.value(), m_bottom.value() - m_top.value() );
} }
Expression width() const { return right - left; } inline Expression width() const { return m_right - m_left; }
Expression height() const { return bottom - top; } inline Expression height() const { return m_bottom - m_top; }
Expression centerH() const { return left + 0.5 * width(); } inline Expression centerH() const { return m_left + 0.5 * width(); }
Expression centerV() const { return top + 0.5 * height(); } inline Expression centerV() const { return m_top + 0.5 * height(); }
Variable left, right, top, bottom; inline const Variable& left() const { return m_left; }
inline const Variable& right() const { return m_right; }
inline const Variable& top() const { return m_top; }
inline const Variable& bottom() const { return m_bottom; }
private:
Variable m_left, m_right, m_top, m_bottom;
}; };
class Anchor class Anchor
@ -85,13 +91,19 @@ namespace
class AnchorBox::PrivateData class AnchorBox::PrivateData
{ {
public: public:
void setupSolver( int type, Solver& ); void setupSolver( Solver& );
void setItemGeometries( const AnchorBox*, const QRectF& );
private:
void setupAnchorConstraints( Solver& );
void setupSizeConstraints( Solver& );
public:
QMap< QQuickItem*, Geometry > geometries; QMap< QQuickItem*, Geometry > geometries;
QVector< Anchor > anchors; QVector< Anchor > anchors;
}; };
void AnchorBox::PrivateData::setupSolver( int type, Solver& solver ) void AnchorBox::PrivateData::setupAnchorConstraints( Solver& solver )
{ {
for ( const auto& anchor : anchors ) for ( const auto& anchor : anchors )
{ {
@ -102,57 +114,96 @@ void AnchorBox::PrivateData::setupSolver( int type, Solver& solver )
== r2.expressionAt( anchor.edge2 ) ); == r2.expressionAt( anchor.edge2 ) );
#if 1 #if 1
if ( type < 0 )
{ {
const auto o = qskOrientation( anchor.edge1 );
/*
A constraint with medium strength to make anchored item
being stretched according to their stretch factors s1, s2.
( For the moment we don't support having specific factors. )
*/
const auto s1 = 1.0; const auto s1 = 1.0;
const auto s2 = 1.0; const auto s2 = 1.0;
const auto o = qskOrientation( anchor.edge1 );
Constraint c( r1.length( o ) * s1 == r2.length( o ) * s2, Strength::medium ); Constraint c( r1.length( o ) * s1 == r2.length( o ) * s2, Strength::medium );
solver.addConstraint( c ); solver.addConstraint( c );
} }
#endif #endif
} }
}
void AnchorBox::PrivateData::setupSizeConstraints( Solver& solver )
{
for ( auto it = geometries.begin(); it != geometries.end(); ++it ) for ( auto it = geometries.begin(); it != geometries.end(); ++it )
{ {
const auto item = it.key(); const auto item = it.key();
auto& r = it.value(); auto& r = it.value();
if ( type < 0 || type == Qt::MinimumSize )
{ {
// minimum size
const auto minSize = qskSizeConstraint( item, Qt::MinimumSize ); const auto minSize = qskSizeConstraint( item, Qt::MinimumSize );
if ( minSize.width() >= 0.0 ) if ( minSize.width() >= 0.0 )
solver.addConstraint( r.right >= r.left + minSize.width() ); solver.addConstraint( r.right() >= r.left() + minSize.width() );
if ( minSize.height() >= 0.0 ) if ( minSize.height() >= 0.0 )
solver.addConstraint( r.bottom >= r.top + minSize.height() ); solver.addConstraint( r.bottom() >= r.top() + minSize.height() );
} }
if ( type < 0 || type == Qt::PreferredSize )
{ {
// preferred size
const auto prefSize = qskSizeConstraint( item, Qt::PreferredSize ); const auto prefSize = qskSizeConstraint( item, Qt::PreferredSize );
Constraint c1( r.right == r.left + prefSize.width(), Strength::strong ); Constraint c1( r.right() == r.left() + prefSize.width(), Strength::strong );
solver.addConstraint( c1 ); solver.addConstraint( c1 );
Constraint c2( r.bottom == r.top + prefSize.height(), Strength::strong ); Constraint c2( r.bottom() == r.top() + prefSize.height(), Strength::strong );
solver.addConstraint( c2 ); solver.addConstraint( c2 );
} }
if ( type < 0 || type == Qt::MaximumSize )
{ {
// maximum size
const auto maxSize = qskSizeConstraint( item, Qt::MaximumSize ); const auto maxSize = qskSizeConstraint( item, Qt::MaximumSize );
if ( maxSize.width() >= 0.0 ) if ( maxSize.width() >= 0.0 )
solver.addConstraint( r.right <= r.left + maxSize.width() ); solver.addConstraint( r.right() <= r.left() + maxSize.width() );
if ( maxSize.height() >= 0.0 ) if ( maxSize.height() >= 0.0 )
solver.addConstraint( r.bottom <= r.top + maxSize.height() ); solver.addConstraint( r.bottom() <= r.top() + maxSize.height() );
} }
} }
} }
void AnchorBox::PrivateData::setupSolver( Solver& solver )
{
setupAnchorConstraints( solver );
setupSizeConstraints( solver );
}
void AnchorBox::PrivateData::setItemGeometries(
const AnchorBox* box, const QRectF& rect )
{
Solver solver;
setupSolver( solver );
const auto& r0 = geometries[ const_cast< AnchorBox* >( box ) ];
solver.addConstraint( r0.left() == rect.left() );
solver.addConstraint( r0.right() == rect.right() );
solver.addConstraint( r0.top() == rect.top() );
solver.addConstraint( r0.bottom() == rect.bottom() );
solver.updateVariables();
for ( auto it = geometries.begin(); it != geometries.end(); ++it )
qskSetItemGeometry( it.key(), it.value().rect() );
#if 0
qDebug() << "=== Rect:" << rect;
for ( auto it = geometries.begin(); it != geometries.end(); ++it )
qDebug() << it.key()->objectName() << it.value().rect();
#endif
}
AnchorBox::AnchorBox( QQuickItem* parent ) AnchorBox::AnchorBox( QQuickItem* parent )
: QskControl( parent ) : QskControl( parent )
, m_data( new PrivateData ) , m_data( new PrivateData )
@ -206,40 +257,9 @@ void AnchorBox::addAnchor( QQuickItem* item1, Qt::AnchorPoint edge1,
m_data->anchors += anchor; m_data->anchors += anchor;
} }
QSizeF AnchorBox::boxHint( Qt::SizeHint which ) QSizeF AnchorBox::layoutSizeHint( Qt::SizeHint, const QSizeF& ) const
{ {
Solver solver; return QSizeF();
m_data->setupSolver( which, solver );
solver.updateVariables();
auto& r0 = m_data->geometries[ this ];
return QSizeF( r0.rect().size() );
}
void AnchorBox::setItemGeometries( const QRectF& rect )
{
Solver solver;
m_data->setupSolver( -1, solver );
auto& r0 = m_data->geometries[ this ];
solver.addConstraint( r0.left == rect.left() );
solver.addConstraint( r0.right == rect.right() );
solver.addConstraint( r0.top == rect.top() );
solver.addConstraint( r0.bottom == rect.bottom() );
solver.updateVariables();
const auto& geometries = m_data->geometries;
for ( auto it = geometries.begin(); it != geometries.end(); ++it )
qskSetItemGeometry( it.key(), it.value().rect() );
#if 0
qDebug() << "=== Rect:" << rect;
for ( auto it = geometries.begin(); it != geometries.end(); ++it )
qDebug() << it.key()->objectName() << it.value().rect();
#endif
} }
void AnchorBox::geometryChangeEvent( QskGeometryChangeEvent* event ) void AnchorBox::geometryChangeEvent( QskGeometryChangeEvent* event )
@ -253,7 +273,7 @@ void AnchorBox::geometryChangeEvent( QskGeometryChangeEvent* event )
void AnchorBox::updateLayout() void AnchorBox::updateLayout()
{ {
if ( !maybeUnresized() ) if ( !maybeUnresized() )
setItemGeometries( layoutRect() ); m_data->setItemGeometries( this, layoutRect() );
} }
#include "moc_AnchorBox.cpp" #include "moc_AnchorBox.cpp"

View File

@ -21,15 +21,13 @@ class AnchorBox : public QskControl
void addAnchor( QQuickItem*, Qt::AnchorPoint, Qt::AnchorPoint ); void addAnchor( QQuickItem*, Qt::AnchorPoint, Qt::AnchorPoint );
void addAnchor( QQuickItem*, Qt::AnchorPoint, QQuickItem*, Qt::AnchorPoint ); void addAnchor( QQuickItem*, Qt::AnchorPoint, QQuickItem*, Qt::AnchorPoint );
QSizeF boxHint( Qt::SizeHint );
protected: protected:
void geometryChangeEvent( QskGeometryChangeEvent* ) override; void geometryChangeEvent( QskGeometryChangeEvent* ) override;
void updateLayout() override; void updateLayout() override;
private: QSizeF layoutSizeHint( Qt::SizeHint, const QSizeF& ) const override;
void setItemGeometries( const QRectF& );
private:
class PrivateData; class PrivateData;
std::unique_ptr< PrivateData > m_data; std::unique_ptr< PrivateData > m_data;
}; };

View File

@ -66,11 +66,6 @@ class MyBox : public AnchorBox
virtual void geometryChangeEvent( QskGeometryChangeEvent* event ) override virtual void geometryChangeEvent( QskGeometryChangeEvent* event ) override
{ {
AnchorBox::geometryChangeEvent( event ); AnchorBox::geometryChangeEvent( event );
#if 1
qDebug() << boxHint( Qt::MinimumSize );
qDebug() << boxHint( Qt::PreferredSize );
qDebug() << boxHint( Qt::MaximumSize );
#endif
} }
}; };