implementation of dynamic constraints reorganized

This commit is contained in:
Uwe Rathmann 2019-04-26 18:09:59 +02:00
parent 8dc73dfdac
commit dd39017dbe
14 changed files with 170 additions and 103 deletions

View File

@ -16,9 +16,9 @@ QskBox::~QskBox()
{
}
QRectF QskBox::layoutRect() const
QRectF QskBox::layoutRectForSize( const QSizeF& size ) const
{
return innerBox( Panel, subControlRect( Panel ) );
return innerBox( Panel, subControlRect( size, Panel ) );
}
QSizeF QskBox::contentsSizeHint() const

View File

@ -20,7 +20,7 @@ class QSK_EXPORT QskBox : public QskControl
QskBox( QQuickItem* parent = nullptr );
~QskBox() override;
QRectF layoutRect() const override;
QRectF layoutRectForSize( const QSizeF& ) const override;
QSizeF contentsSizeHint() const override;
};

View File

@ -13,6 +13,7 @@
#include "QskSkin.h"
#include "QskSkinlet.h"
#include "QskSkinHintTable.h"
#include "QskLayoutConstraint.h"
#include <qglobalstatic.h>
#include <qlocale.h>
@ -1013,6 +1014,15 @@ QRectF QskControl::subControlRect( QskAspect::Subcontrol subControl ) const
return effectiveSkinlet()->subControlRect( this, contentsRect(), subControl );
}
QRectF QskControl::subControlRect(
const QSizeF& size, QskAspect::Subcontrol subControl ) const
{
QRectF rect( 0.0, 0.0, size.width(), size.height() );
rect = qskValidOrEmptyInnerRect( rect, margins() );
return effectiveSkinlet()->subControlRect( this, rect, subControl );
}
bool QskControl::layoutMirroring() const
{
return d_func()->effectiveLayoutMirror;
@ -1379,58 +1389,24 @@ void QskControl::resetImplicitSize()
qreal QskControl::heightForWidth( qreal width ) const
{
qreal h = -1;
if ( !d_func()->autoLayoutChildren )
return -1.0;
if ( d_func()->autoLayoutChildren )
{
const auto innerSize = layoutRect().size();
const auto outerSize = size();
using namespace QskLayoutConstraint;
width -= outerSize.width() - innerSize.width();
const auto children = childItems();
for ( auto child : children )
{
if ( auto control = qobject_cast< const QskControl* >( child ) )
{
if ( !control->isTransparentForPositioner() )
h = qMax( h, control->heightForWidth( width ) );
}
}
if ( h >= 0 )
h += outerSize.height() - innerSize.height();
}
return h;
return constrainedMetric(
HeightForWidth, this, width, constrainedChildrenMetric );
}
qreal QskControl::widthForHeight( qreal height ) const
{
qreal w = -1;
if ( !d_func()->autoLayoutChildren )
return -1.0;
if ( d_func()->autoLayoutChildren )
{
const auto innerSize = layoutRect().size();
const auto outerSize = size();
using namespace QskLayoutConstraint;
height -= outerSize.height() - innerSize.height();
const auto children = childItems();
for ( auto child : children )
{
if ( auto control = qobject_cast< const QskControl* >( child ) )
{
if ( !control->isTransparentForPositioner() )
w = qMax( w, control->widthForHeight( height ) );
}
}
if ( w >= 0 )
w += outerSize.width() - innerSize.width();
}
return w;
return constrainedMetric(
WidthForHeight, this, height, constrainedChildrenMetric );
}
bool QskControl::event( QEvent* event )
@ -1932,9 +1908,10 @@ QskControl* QskControl::owningControl() const
return const_cast< QskControl* >( this );
}
QRectF QskControl::layoutRect() const
QRectF QskControl::layoutRectForSize( const QSizeF& size ) const
{
return contentsRect();
const QRectF r( 0.0, 0.0, size.width(), size.height() );
return qskValidOrEmptyInnerRect( r, margins() );
}
QRectF QskControl::gestureRect() const

View File

@ -110,12 +110,14 @@ class QSK_EXPORT QskControl : public QQuickItem, public QskSkinnable
QRectF rect() const;
QRectF contentsRect() const;
QRectF layoutRect() const;
virtual QRectF layoutRect() const;
virtual QRectF layoutRectForSize( const QSizeF& ) const;
virtual QRectF gestureRect() const;
virtual QRectF focusIndicatorRect() const;
QRectF subControlRect( QskAspect::Subcontrol ) const;
QRectF subControlRect( const QSizeF&, QskAspect::Subcontrol ) const;
void setAutoFillBackground( bool );
bool autoFillBackground() const;
@ -313,6 +315,11 @@ inline QSizeF QskControl::preferredSize() const
return explicitSizeHint( Qt::PreferredSize );
}
inline QRectF QskControl::layoutRect() const
{
return layoutRectForSize( size() );
}
inline QskControl* qskControlCast( QObject* object )
{
return qobject_cast< QskControl* >( object );

View File

@ -245,9 +245,9 @@ void QskPushButton::updateLayout()
}
}
QRectF QskPushButton::layoutRect() const
QRectF QskPushButton::layoutRectForSize( const QSizeF& size ) const
{
return innerBox( Panel, subControlRect( Panel ) );
return innerBox( Panel, subControlRect( size, Panel ) );
}
QSizeF QskPushButton::contentsSizeHint() const

View File

@ -65,7 +65,7 @@ class QSK_EXPORT QskPushButton : public QskAbstractButton
QFont font() const;
QSizeF contentsSizeHint() const override;
QRectF layoutRect() const override;
QRectF layoutRectForSize( const QSizeF& ) const override;
public Q_SLOTS:
void setText( const QString& );

View File

@ -231,11 +231,11 @@ void QskSubWindow::updateLayout()
Inherited::updateLayout();
}
QRectF QskSubWindow::layoutRect() const
QRectF QskSubWindow::layoutRectForSize( const QSizeF& size ) const
{
QRectF rect = contentsRect();
const qreal top = rect.top() + subControlRect( TitleBar ).height();
const qreal top = rect.top() + subControlRect( size, TitleBar ).height();
rect.setTop( top );
return innerBox( Panel, rect );

View File

@ -79,7 +79,7 @@ class QSK_EXPORT QskSubWindow : public QskPopup
QRectF titleBarRect() const;
QSizeF contentsSizeHint() const override;
QRectF layoutRect() const override;
QRectF layoutRectForSize( const QSizeF& ) const override;
Q_SIGNALS:
void decoratedChanged();

View File

@ -101,9 +101,9 @@ QSizeF QskTabButton::contentsSizeHint() const
return size;
}
QRectF QskTabButton::layoutRect() const
QRectF QskTabButton::layoutRectForSize( const QSizeF& size ) const
{
return innerBox( Panel, subControlRect( Panel ) );
return innerBox( Panel, subControlRect( size, Panel ) );
}
QskAspect::Placement QskTabButton::effectivePlacement() const

View File

@ -37,7 +37,7 @@ class QSK_EXPORT QskTabButton : public QskAbstractButton
QskTextOptions textOptions() const;
QSizeF contentsSizeHint() const override;
QRectF layoutRect() const override;
QRectF layoutRectForSize( const QSizeF& ) const override;
QskAspect::Placement effectivePlacement() const override;

View File

@ -7,6 +7,7 @@
#include "QskEvent.h"
#include "QskLayoutEngine.h"
#include "QskLayoutItem.h"
#include "QskLayoutConstraint.h"
class QskLayoutBox::PrivateData
{
@ -266,24 +267,26 @@ QSizeF QskLayoutBox::layoutItemsSizeHint() const
qreal QskLayoutBox::heightForWidth( qreal width ) const
{
const auto m = margins();
width -= m.left() + m.right();
auto constrainedHeight =
[this]( QskLayoutConstraint::Type, const QskControl*, qreal width )
{
return engine().heightForWidth( width );
};
qreal height = engine().heightForWidth( width );
height += m.top() + m.bottom();
return height;
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::HeightForWidth, this, width, constrainedHeight );
}
qreal QskLayoutBox::widthForHeight( qreal height ) const
{
const auto m = margins();
height -= m.top() + m.bottom();
auto constrainedWidth =
[this]( QskLayoutConstraint::Type, const QskControl*, qreal height )
{
return engine().widthForHeight( height );
};
qreal width = engine().widthForHeight( height );
width += m.left() + m.right();
return width;
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::WidthForHeight, this, height, constrainedWidth );
}
void QskLayoutBox::geometryChangeEvent( QskGeometryChangeEvent* event )

View File

@ -7,6 +7,8 @@
#include "QskControl.h"
#include "QskSizePolicy.h"
#include <functional>
static inline qreal qskHintFor(
const QQuickItem* item, const char* method, qreal widthOrHeight )
{
@ -85,6 +87,71 @@ qreal QskLayoutConstraint::widthForHeight( const QQuickItem* item, qreal height
return qskHintFor( item, "widthForHeight", height );
}
qreal QskLayoutConstraint::constrainedMetric(
Type type, const QskControl* control, qreal widthOrHeight,
std::function< qreal( Type, const QskControl*, qreal ) > constrainFunction )
{
#if 1
/*
In case of having a corner radius of Qt::RelativeSize the margins
we might have a wrong result when using QskLayoutConstraint::unlimited.
No idea how to solve this in a generic way: TODO ...
*/
#endif
const qreal upperLimit = 10e6;
if ( type == WidthForHeight )
{
const QSizeF outer( upperLimit, widthOrHeight );
const QSizeF inner = control->layoutRectForSize( outer ).size();
qreal width = constrainFunction( type, control, inner.height() );
if ( width >= 0.0 )
width += outer.width() - inner.width();
return width;
}
else
{
const QSizeF outer( widthOrHeight, upperLimit );
const QSizeF inner = control->layoutRectForSize( outer ).size();
qreal height = constrainFunction( type, control, inner.width() );
if ( height >= 0.0 )
height += outer.height() - inner.height();
return height;
}
}
qreal QskLayoutConstraint::constrainedChildrenMetric(
Type type, const QskControl* control, qreal widthOrHeight )
{
auto constrainFunction =
( type == WidthForHeight ) ? widthForHeight : heightForWidth;
qreal constrainedValue = -1.0;
const auto children = control->childItems();
for ( auto child : children )
{
if ( auto control = qskControlCast( child ) )
{
if ( !control->isTransparentForPositioner() )
{
const auto v = constrainFunction( control, widthOrHeight );
if ( v > constrainedValue )
constrainedValue = v;
}
}
}
return constrainedValue;
}
QSizeF QskLayoutConstraint::effectiveConstraint(
const QQuickItem* item, Qt::SizeHint whichHint )
{

View File

@ -12,15 +12,30 @@
#include <limits>
class QskSizePolicy;
class QskControl;
class QQuickItem;
class QSizeF;
namespace std { template< typename T > class function; }
namespace QskLayoutConstraint
{
enum Type
{
WidthForHeight,
HeightForWidth
};
QSK_EXPORT bool hasDynamicConstraint( const QQuickItem* );
QSK_EXPORT qreal heightForWidth( const QQuickItem*, qreal width );
QSK_EXPORT qreal widthForHeight( const QQuickItem*, qreal height );
QSK_EXPORT qreal constrainedMetric(
Type, const QskControl*, qreal value,
std::function< qreal( Type, const QskControl*, qreal ) > );
QSK_EXPORT qreal constrainedChildrenMetric( Type, const QskControl*, qreal width );
QSK_EXPORT QSizeF effectiveConstraint( const QQuickItem*, Qt::SizeHint );
QSK_EXPORT QskSizePolicy sizePolicy( const QQuickItem* );

View File

@ -11,6 +11,30 @@
#include <qpointer.h>
static qreal qskConstrainedValue( QskLayoutConstraint::Type type,
const QskControl* control, qreal widthOrHeight )
{
using namespace QskLayoutConstraint;
auto constrainFunction =
( type == WidthForHeight ) ? widthForHeight : heightForWidth;
qreal constrainedValue = -1;
auto stackBox = static_cast< const QskStackBox* >( control );
for ( int i = 0; i < stackBox->itemCount(); i++ )
{
if ( const auto item = stackBox->itemAtIndex( i ) )
{
const qreal v = constrainFunction( item, widthOrHeight );
if ( v > constrainedValue )
constrainedValue = v;
}
}
return constrainedValue;
}
class QskStackBox::PrivateData
{
public:
@ -252,40 +276,14 @@ QSizeF QskStackBox::layoutItemsSizeHint() const
qreal QskStackBox::heightForWidth( qreal width ) const
{
const auto m = margins();
width -= m.left() + m.right();
qreal height = -1;
const QskLayoutEngine& engine = this->engine();
for ( int i = 0; i < engine.itemCount(); i++ )
{
const QskLayoutItem* layoutItem = engine.layoutItemAt( i );
if ( const auto item = layoutItem->item() )
height = qMax( height, QskLayoutConstraint::heightForWidth( item, width ) );
}
height += m.top() + m.bottom();
return height;
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::HeightForWidth, this, width, qskConstrainedValue );
}
qreal QskStackBox::widthForHeight( qreal height ) const
{
const auto m = margins();
height -= m.top() + m.bottom();
qreal width = -1;
const QskLayoutEngine& engine = this->engine();
for ( int i = 0; i < engine.itemCount(); i++ )
{
const QskLayoutItem* layoutItem = engine.layoutItemAt( i );
if ( const auto item = layoutItem->item() )
width = qMax( width, QskLayoutConstraint::widthForHeight( item, height ) );
}
width += m.left() + m.right();
return width;
return QskLayoutConstraint::constrainedMetric(
QskLayoutConstraint::WidthForHeight, this, height, qskConstrainedValue );
}
void QskStackBox::layoutItemInserted( QskLayoutItem* layoutItem, int index )