QskSubcontrolLayoutEngine introduced

This commit is contained in:
Uwe Rathmann 2022-08-26 12:56:12 +02:00
parent 896145ac11
commit b84dfc8226
9 changed files with 643 additions and 173 deletions

View File

@ -115,11 +115,17 @@ Qsk.Window
enabled: false
}
TestButton
{
graphicSource: "image://shapes/Diamond/SandyBrown"
graphicStrutSize
{
// no strutSize, so that the graphic is adjustd
width: -1
height : -1
}
shape
{
sizeMode: Qt.RelativeSize

View File

@ -490,16 +490,15 @@ void Editor::setupPushButton()
setBoxShape( Q::Panel, 100, Qt::RelativeSize );
setAlignment( Q::Graphic | A::Alignment, Qt::AlignCenter );
setAlignment( Q::Graphic, Qt::AlignCenter );
setStrutSize( Q::Graphic, 24_dp, 24_dp );
setPadding( Q::Graphic, 0 );
setFontRole( Q::Text, QskMaterial3Skin::M3LabelLarge );
setPadding( Q::Text, 0 );
setAlignment( Q::Text | A::Alignment, Qt::AlignCenter );
setAlignment( Q::Text | A::Alignment | A::Horizontal,
Qt::AlignLeft | Qt::AlignVCenter );
setAlignment( Q::Text | A::Vertical, Qt::AlignCenter );
setAlignment( Q::Text | A::Horizontal, Qt::AlignLeft | Qt::AlignVCenter );
// normal buttons (i.e. Filled):

View File

@ -607,13 +607,15 @@ void Editor::setupPushButton()
setTextOptions( Q::Text, Qt::ElideMiddle, QskTextOptions::NoWrap );
setFlagHint( Q::Text | Q::Disabled | A::Style, Qsk::Sunken );
setAlignment( Q::Text, Qt::AlignCenter );
setAlignment( Q::Text | A::Vertical, Qt::AlignCenter );
setAlignment( Q::Text | A::Horizontal, Qt::AlignLeft | Qt::AlignVCenter );
setColor( Q::Text, m_pal.themeForeground );
setColor( Q::Text | Q::Disabled, m_pal.darker200 );
// Graphic
setPadding( Q::Graphic, 2 );
setAlignment( Q::Graphic, Qt::AlignCenter );
}
void Editor::setupDialogButton()

View File

@ -8,13 +8,9 @@
#include "QskAnimationHint.h"
#include "QskGraphic.h"
#include "QskTextOptions.h"
#include "QskFunctions.h"
#include "QskSubcontrolLayoutEngine.h"
#include "QskSGNode.h"
#include <qfontmetrics.h>
#include <qmath.h>
static inline Qt::Orientation qskOrientation( const QskPushButton* button )
{
// For the moment we only handle the orientation TODO ...
@ -28,6 +24,76 @@ static inline Qt::Orientation qskOrientation( const QskPushButton* button )
return Qt::Vertical;
}
namespace
{
class LayoutEngine : public QskSubcontrolLayoutEngine
{
public:
LayoutEngine( const QskPushButton* button )
: QskSubcontrolLayoutEngine( qskOrientation( button ) )
{
using Q = QskPushButton;
const auto graphicSourceSize = button->graphic().defaultSize();
const bool hasText = !button->text().isEmpty();
const bool hasGraphic = !graphicSourceSize.isEmpty();
auto graphicElement = new GraphicElement( button, Q::Graphic );
graphicElement->setSourceSize( graphicSourceSize );
graphicElement->setIgnored( !hasGraphic );
auto textElement = new TextElement( button, Q::Text );
textElement->setText( button->text() );
textElement->setIgnored( !hasText );
using SP = QskSizePolicy;
if ( hasText && !hasGraphic )
{
textElement->setSizePolicy( SP::Preferred, SP::Constrained );
}
else if ( hasGraphic && !hasText )
{
const auto size = graphicElement->effectiveStrutSize();
if ( !size.isEmpty() )
graphicElement->setFixedSize( size );
else
graphicElement->setSizePolicy( SP::Ignored, SP::ConstrainedExpanding );
}
else if ( hasText && hasGraphic )
{
if ( orientation() == Qt::Horizontal )
{
graphicElement->setSizePolicy( SP::Constrained, SP::Fixed );
textElement->setSizePolicy( SP::Preferred, SP::Preferred );
}
else
{
graphicElement->setSizePolicy( SP::Fixed, SP::Fixed );
textElement->setSizePolicy( SP::Preferred, SP::Constrained );
}
auto size = graphicElement->effectiveStrutSize();
if ( size.isEmpty() )
{
const auto h = 1.5 * button->effectiveFontHeight( Q::Text );
size.setWidth( graphicElement->widthForHeight( h ) );
size.setHeight( h );
}
graphicElement->setPreferredSize( size );
}
setElementAt( 0, graphicElement );
setElementAt( 1, textElement );
}
};
}
QskPushButtonSkinlet::QskPushButtonSkinlet( QskSkin* skin )
: Inherited( skin )
{
@ -101,29 +167,12 @@ QRectF QskPushButtonSkinlet::textRect(
{
using Q = QskPushButton;
auto r = button->subControlContentsRect( contentsRect, Q::Panel );
if ( r.isEmpty() || !button->hasGraphic() )
return r;
const auto r = button->subControlContentsRect( contentsRect, Q::Panel );
if ( qskOrientation( button ) == Qt::Horizontal )
{
/*
For horizontal layouts Text depends on Graphic, while
for vertical Graphic depends on Text. Confusing ...
*/
const auto graphicsRect = subControlRect( button, contentsRect, Q::Graphic );
const auto spacing = button->spacingHint( Q::Panel );
LayoutEngine layoutEngine( button );
layoutEngine.setGeometries( r );
r.setX( r.x() + graphicsRect.width() + spacing );
}
else
{
const qreal h = button->effectiveFontHeight( Q::Text );
if ( h < r.height() )
r.setTop( r.bottom() - h );
}
return r;
return layoutEngine.elementAt( 1 )->geometry();
}
QRectF QskPushButtonSkinlet::graphicRect(
@ -131,81 +180,12 @@ QRectF QskPushButtonSkinlet::graphicRect(
{
using Q = QskPushButton;
auto r = button->subControlContentsRect( contentsRect, Q::Panel );
if ( r.isEmpty() || button->text().isEmpty() )
return r;
const auto r = button->subControlContentsRect( contentsRect, Q::Panel );
const auto orientation = qskOrientation( button );
const auto maxSize = button->strutSizeHint( Q::Graphic );
LayoutEngine layoutEngine( button );
layoutEngine.setGeometries( r );
const qreal maxW = maxSize.width();
const qreal maxH = maxSize.height();
if ( orientation == Qt::Vertical )
{
/*
For horizontal layouts Text depends on Graphic, while
for vertical Graphic depends on Text. Confusing ...
*/
const auto textRect = subControlRect( button, contentsRect, Q::Text );
const auto h = textRect.height() + button->spacingHint( Q::Panel );
if ( h > r.height() )
return QRectF();
r.setBottom( r.bottom() - h );
if ( maxW >= 0 || maxH >= 0 )
{
// limiting the size by maxSize
if ( maxW >= 0.0 && maxW < r.width() )
{
r.setX( r.center().x() - 0.5 * maxW );
r.setWidth( maxW );
}
if ( maxH >= 0.0 && maxH < r.height() )
{
r.setY( r.center().y() - 0.5 * maxH );
r.setHeight( maxH );
}
}
}
else
{
if ( maxW >= 0 || maxH >= 0 )
{
if ( maxW >= 0.0 && maxW < r.width() )
{
r.setWidth( maxW );
}
if ( maxH >= 0.0 && maxH < r.height() )
{
r.setY( r.center().y() - 0.5 * maxH );
r.setHeight( maxH );
}
}
}
r = r.marginsRemoved( button->paddingHint( Q::Graphic ) );
if ( !r.isEmpty() )
{
auto sz = button->graphic().defaultSize();
if ( !sz.isEmpty() )
{
sz.scale( r.size(), Qt::KeepAspectRatio );
if ( orientation == Qt::Vertical )
r = qskAlignedRectF( r, sz, Qt::AlignCenter );
else
r = qskAlignedRectF( r, sz, Qt::AlignLeft | Qt::AlignVCenter );
}
}
return r;
return layoutEngine.elementAt( 0 )->geometry();
}
QRectF QskPushButtonSkinlet::rippleRect(
@ -285,35 +265,9 @@ QSizeF QskPushButtonSkinlet::sizeHint( const QskSkinnable* skinnable,
const auto button = static_cast< const QskPushButton* >( skinnable );
QSizeF size( 0, 0 );
LayoutEngine layoutEngine( button );
const QFontMetricsF fm( button->effectiveFont( Q::Text ) );
if ( !button->text().isEmpty() )
{
// in elide mode we might want to ignore the text width ???
size += fm.size( Qt::TextShowMnemonic, button->text() );
}
if ( button->hasGraphic() )
{
const auto hint = graphicSizeHint( button );
const auto padding = button->paddingHint( Q::Graphic );
const auto orientation = qskOrientation( button );
if( orientation == Qt::Horizontal )
{
size.rwidth() += padding.left() + hint.width() + padding.right();
size.rheight() = qMax( size.height(), hint.height() );
}
else
{
size.rheight() += padding.top() + hint.height() + padding.bottom();
size.rwidth() = qMax( size.width(), hint.width() );
}
}
auto size = layoutEngine.sizeHint( which, QSizeF() );
size = size.expandedTo( button->strutSizeHint( Q::Panel ) );
size = button->outerBoxSize( Q::Panel, size );
@ -321,32 +275,4 @@ QSizeF QskPushButtonSkinlet::sizeHint( const QskSkinnable* skinnable,
return size;
}
QSizeF QskPushButtonSkinlet::graphicSizeHint( const QskPushButton* button ) const
{
using Q = QskPushButton;
auto size = button->strutSizeHint( Q::Graphic );
if ( !size.isEmpty() )
return size;
const auto& graphic = button->graphic();
auto w = size.width();
auto h = size.height();
if ( w > 0.0 )
{
h = graphic.heightForWidth( w );
}
else
{
if ( h <= 0.0 )
h = 1.5 * button->effectiveFontHeight( Q::Text );
w = graphic.widthForHeight( h );
}
return QSizeF( w, h );
}
#include "moc_QskPushButtonSkinlet.cpp"

View File

@ -45,8 +45,6 @@ class QSK_EXPORT QskPushButtonSkinlet : public QskSkinlet
QRectF graphicRect( const QskPushButton*, const QRectF& ) const;
QRectF rippleRect( const QskPushButton*, const QRectF& ) const;
QSizeF graphicSizeHint( const QskPushButton* ) const;
QSGNode* updateTextNode( const QskPushButton*, QSGNode* ) const;
QSGNode* updateRippleNode( const QskPushButton*, QSGNode* ) const;
};

View File

@ -28,17 +28,17 @@ class QskLayoutElement
QSizeF sizeConstraint( Qt::SizeHint, const QSizeF& constraint ) const;
private:
Q_DISABLE_COPY( QskLayoutElement )
qreal metric( Qt::Orientation, Qt::SizeHint, qreal constraint ) const;
virtual QSizeF sizeHint( Qt::SizeHint,
const QSizeF& constraint = QSizeF() ) const = 0;
qreal heightForWidth( qreal ) const;
qreal widthForHeight( qreal ) const;
private:
Q_DISABLE_COPY( QskLayoutElement )
qreal metric( Qt::Orientation, Qt::SizeHint, qreal constraint ) const;
qreal boundedSize( Qt::Orientation, qreal ) const;
};

View File

@ -0,0 +1,398 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskSubcontrolLayoutEngine.h"
#include "QskLayoutElement.h"
#include "QskLayoutChain.h"
#include "QskTextRenderer.h"
#include "QskSkinnable.h"
#include "QskMargins.h"
#include "QskTextOptions.h"
#include <qfont.h>
#include <qfontmetrics.h>
#include <qmath.h>
QskSubcontrolLayoutEngine::LayoutElement::LayoutElement(
const QskSkinnable* skinnable, const QskAspect::Subcontrol subControl )
: m_skinnable( skinnable )
, m_subControl( subControl )
{
}
Qt::Alignment QskSubcontrolLayoutEngine::LayoutElement::alignment() const
{
return m_skinnable->alignmentHint( m_subControl );
}
void QskSubcontrolLayoutEngine::LayoutElement::setMaximumSize( const QSizeF& size )
{
setExplicitSizeHint( Qt::MaximumSize, size );
}
void QskSubcontrolLayoutEngine::LayoutElement::setMinimumSize( const QSizeF& size )
{
setExplicitSizeHint( Qt::MinimumSize, size );
}
void QskSubcontrolLayoutEngine::LayoutElement::setPreferredSize( const QSizeF& size )
{
setExplicitSizeHint( Qt::PreferredSize, size );
}
void QskSubcontrolLayoutEngine::LayoutElement::setFixedSize( const QSizeF& size )
{
setSizePolicy( QskSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed ) );
const auto newSize = size.expandedTo( QSizeF( 0, 0 ) );
setExplicitSizeHint( Qt::PreferredSize, newSize );
}
void QskSubcontrolLayoutEngine::LayoutElement::setExplicitSizeHint(
Qt::SizeHint which, const QSizeF& size )
{
if ( which >= Qt::MinimumSize && which <= Qt::MaximumSize )
{
const QSizeF newSize( ( size.width() < 0 ) ? -1.0 : size.width(),
( size.height() < 0 ) ? -1.0 : size.height() );
m_explicitSizeHints[ which ] = size;
}
}
QSizeF QskSubcontrolLayoutEngine::LayoutElement::sizeHint(
Qt::SizeHint which, const QSizeF& constraint ) const
{
if ( which < Qt::MinimumSize || which > Qt::MaximumSize )
return QSizeF( 0, 0 );
if ( constraint.isValid() )
return constraint;
const bool isConstrained =
constraint.width() >= 0 || constraint.height() >= 0;
QSizeF hint;
if ( !isConstrained )
{
// explicit size hints are never constrained
hint = m_explicitSizeHints[ which ];
}
if ( which == Qt::PreferredSize )
{
if ( isConstrained )
{
const QskMargins padding = m_skinnable->paddingHint( m_subControl );
auto innerConstraint = constraint;
if ( constraint.width() > 0 )
{
const auto w = constraint.width() - padding.width();
if ( w <= 0 )
return QSizeF();
innerConstraint.setWidth( w );
}
else if ( constraint.height() > 0 )
{
const auto h = constraint.height() - padding.height();
if ( h <= 0 )
return QSizeF();
innerConstraint.setHeight( h );
}
hint = implicitSize( innerConstraint );
if ( hint.width() >= 0 )
hint.setWidth( hint.width() + padding.width() );
if ( hint.height() >= 0 )
hint.setHeight( hint.height() + padding.height() );
}
else
{
if ( !hint.isValid() )
{
const auto sz = implicitSize( constraint );
if ( hint.width() < 0 )
hint.setWidth( sz.width() );
if ( hint.height() < 0 )
hint.setHeight( sz.height() );
}
}
}
else
{
if ( isConstrained )
hint = QSizeF(); // not implemented
}
return hint;
}
QSizeF QskSubcontrolLayoutEngine::TextElement::implicitSize( const QSizeF& constraint ) const
{
const auto font = skinnable()->effectiveFont( subControl() );
const auto textOptions = skinnable()->textOptionsHint( subControl() );
QSizeF hint;
const qreal lineHeight = QFontMetricsF( font ).height();
if ( m_text.isEmpty() )
{
if ( constraint.height() < 0.0 )
hint.setHeight( qCeil( lineHeight ) );
}
else if ( constraint.width() >= 0.0 )
{
if ( textOptions.effectiveElideMode() != Qt::ElideNone )
{
hint.setHeight( qCeil( lineHeight ) );
}
else
{
/*
In case of QskTextOptions::NoWrap we could count
the line numbers and calculate the height from
lineHeight. TODO ...
*/
qreal maxHeight = std::numeric_limits< qreal >::max();
if ( maxHeight / lineHeight > textOptions.maximumLineCount() )
{
// be careful with overflows
maxHeight = textOptions.maximumLineCount() * lineHeight;
}
QSizeF size( constraint.width(), maxHeight );
size = QskTextRenderer::textSize( m_text, font, textOptions, size );
hint.setHeight( qCeil( size.height() ) );
}
}
else if ( constraint.height() >= 0.0 )
{
const qreal maxWidth = std::numeric_limits< qreal >::max();
QSizeF size( maxWidth, constraint.height() );
size = QskTextRenderer::textSize( m_text, font, textOptions, size );
hint.setWidth( qCeil( size.width() ) );
}
else
{
hint = QskTextRenderer::textSize( m_text, font, textOptions );
}
return hint;
}
QSizeF QskSubcontrolLayoutEngine::GraphicElement::effectiveStrutSize() const
{
auto size = skinnable()->strutSizeHint( subControl() );
if ( size.isEmpty() )
{
const qreal aspectRatio = m_sourceSize.width() / m_sourceSize.height();
if ( size.width() > 0 )
{
size.setHeight( size.width() / aspectRatio );
}
else if ( size.height() > 0 )
{
size.setWidth( size.height() * aspectRatio );
}
}
return size;
}
QSizeF QskSubcontrolLayoutEngine::GraphicElement::implicitSize( const QSizeF& constraint ) const
{
auto hint = m_sourceSize;
if ( !hint.isEmpty() )
{
const qreal aspectRatio = hint.width() / hint.height();
if ( constraint.width() >= 0.0 )
{
hint.setHeight( constraint.width() / aspectRatio );
hint.setWidth( -1.0 );
}
else if ( constraint.height() > 0.0 )
{
hint.setWidth( constraint.height() * aspectRatio );
hint.setHeight( -1.0 );
}
}
return hint;
}
static QskLayoutChain::CellData qskCell( const QskSubcontrolLayoutEngine::LayoutElement* element,
Qt::Orientation orientation, bool isLayoutOrientation, qreal constraint )
{
QskLayoutChain::CellData cell;
cell.isValid = true;
const auto policy = element->sizePolicy().policy( orientation );
if ( isLayoutOrientation )
{
const auto stretch = element->stretch();
if ( stretch < 0 )
cell.stretch = ( policy & QskSizePolicy::ExpandFlag ) ? 1 : 0;
else
cell.stretch = stretch;
}
cell.canGrow = policy & QskSizePolicy::GrowFlag;
cell.metrics = element->metrics( orientation, constraint );
return cell;
}
class QskSubcontrolLayoutEngine::PrivateData
{
public:
PrivateData( Qt::Orientation orientation )
: orientation( orientation )
{
}
Qt::Orientation orientation;
LayoutElement* elements[2] = {};
};
QskSubcontrolLayoutEngine::QskSubcontrolLayoutEngine( Qt::Orientation orientation )
: m_data( new PrivateData( orientation ) )
{
setExtraSpacingAt( Qt::TopEdge | Qt::BottomEdge | Qt::LeftEdge | Qt::RightEdge );
}
QskSubcontrolLayoutEngine::~QskSubcontrolLayoutEngine()
{
for ( auto element : m_data->elements )
delete element;
}
bool QskSubcontrolLayoutEngine::setOrientation( Qt::Orientation orientation )
{
if ( m_data->orientation != orientation )
{
m_data->orientation = orientation;
invalidate( LayoutCache );
return true;
}
return false;
}
Qt::Orientation QskSubcontrolLayoutEngine::orientation() const
{
return m_data->orientation;
}
void QskSubcontrolLayoutEngine::setElementAt( int index, LayoutElement* element )
{
if ( index >= 0 && index < count() )
{
delete m_data->elements[ index ];
m_data->elements[ index ] = element;
}
}
QskSubcontrolLayoutEngine::LayoutElement* QskSubcontrolLayoutEngine::elementAt( int index ) const
{
if ( index >= 0 && index < count() )
return m_data->elements[ index ];
return nullptr;
}
QskSizePolicy QskSubcontrolLayoutEngine::sizePolicyAt( int index ) const
{
if ( index >= 0 && index < count() )
{
if ( auto element = m_data->elements[ index ] )
return element->sizePolicy();
}
return QskSizePolicy();
}
int QskSubcontrolLayoutEngine::count() const
{
return sizeof( m_data->elements ) / sizeof( m_data->elements[0] );
}
void QskSubcontrolLayoutEngine::layoutItems()
{
int row = 0;
int col = 0;
for ( auto element : m_data->elements )
{
if ( element && !element->isIgnored() )
{
const auto rect = geometryAt( element, QRect( col, row, 1, 1 ) );
element->setGeometry( rect );
if ( m_data->orientation == Qt::Horizontal )
col++;
else
row++;
}
}
}
int QskSubcontrolLayoutEngine::effectiveCount( Qt::Orientation orientation ) const
{
return ( orientation == m_data->orientation ) ? 2 : 1;
}
void QskSubcontrolLayoutEngine::invalidateElementCache()
{
}
void QskSubcontrolLayoutEngine::setupChain( Qt::Orientation orientation,
const QskLayoutChain::Segments& constraints, QskLayoutChain& chain ) const
{
uint index1 = 0;
uint index2 = 0;
const bool isLayoutOrientation = ( orientation == m_data->orientation );
for ( auto element : m_data->elements )
{
if ( element == nullptr || element->isIgnored() )
continue;
qreal constraint = -1.0;
if ( !constraints.isEmpty() )
constraint = constraints[index1].length;
const auto cell = qskCell( element, orientation, isLayoutOrientation, constraint );
chain.expandCell( index2, cell );
if ( isLayoutOrientation )
index2++;
else
index1++;
}
}

View File

@ -0,0 +1,139 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#ifndef QSK_SUBCONTROL_LAYOUT_ENGINE_H
#define QSK_SUBCONTROL_LAYOUT_ENGINE_H
#include "QskGlobal.h"
#include "QskLayoutEngine2D.h"
#include "QskLayoutElement.h"
#include "QskAspect.h"
#include <qnamespace.h>
#include <memory>
class QskSkinnable;
/*
For the moment this layout is tailored for arranging one text and one graphic
horizontally/vertically. Candidate for becoming something more general in the future..
*/
class QskSubcontrolLayoutEngine : public QskLayoutEngine2D
{
public:
class LayoutElement : public QskLayoutElement
{
public:
LayoutElement( const QskSkinnable*, const QskAspect::Subcontrol );
inline const QskSkinnable* skinnable() const { return m_skinnable; }
inline QskAspect::Subcontrol subControl() const { return m_subControl; }
inline void setSizePolicy(
QskSizePolicy::Policy horizontalPolicy,
QskSizePolicy::Policy verticalPolicy )
{
setSizePolicy( QskSizePolicy( horizontalPolicy, verticalPolicy ) );
}
inline void setSizePolicy( QskSizePolicy policy ) { m_sizePolicy = policy; }
inline QskSizePolicy sizePolicy() const override { return m_sizePolicy; }
virtual Qt::Alignment alignment() const override;
inline void setIgnored( bool on ) { m_ignored = on; }
inline bool isIgnored() const { return m_ignored; }
inline void setStretch( int stretch ) { m_stretch = stretch; }
inline int stretch() const { return m_stretch; }
inline void setGeometry( const QRectF& rect ) { m_geometry = rect; }
inline const QRectF& geometry() const { return m_geometry; }
void setMaximumSize( const QSizeF& );
void setMinimumSize( const QSizeF& );
void setPreferredSize( const QSizeF& );
void setFixedSize( const QSizeF& );
void setExplicitSizeHint( Qt::SizeHint, const QSizeF& );
private:
QSizeF sizeHint( Qt::SizeHint, const QSizeF& ) const override;
virtual QSizeF implicitSize( const QSizeF& ) const = 0;
int m_stretch = -1;
bool m_ignored = false;
QskSizePolicy m_sizePolicy;
QSizeF m_explicitSizeHints[3];
QRectF m_geometry;
const QskSkinnable* m_skinnable;
const QskAspect::Subcontrol m_subControl;
};
class TextElement : public LayoutElement
{
public:
TextElement( const QskSkinnable* skinnable, QskAspect::Subcontrol subControl )
: LayoutElement( skinnable, subControl )
{
}
inline void setText( const QString& text ) { m_text = text; }
inline QString text() const { return m_text; }
private:
QSizeF implicitSize( const QSizeF& ) const override;
QString m_text;
};
class GraphicElement : public LayoutElement
{
public:
GraphicElement( const QskSkinnable* skinnable, QskAspect::Subcontrol subControl )
: LayoutElement( skinnable, subControl )
{
}
inline void setSourceSize( const QSizeF& size ) { m_sourceSize = size; }
inline QSizeF sourceSize() const { return m_sourceSize; }
QSizeF effectiveStrutSize() const;
private:
QSizeF implicitSize( const QSizeF& ) const override;
QSizeF m_sourceSize;
};
explicit QskSubcontrolLayoutEngine( Qt::Orientation );
~QskSubcontrolLayoutEngine() override;
Qt::Orientation orientation() const;
bool setOrientation( Qt::Orientation );
void setElementAt( int index, LayoutElement* );
LayoutElement* elementAt( int ) const;
int count() const override final;
private:
QskSizePolicy sizePolicyAt( int index ) const override;
void layoutItems() override;
int effectiveCount( Qt::Orientation ) const override;
void invalidateElementCache() override;
virtual void setupChain( Qt::Orientation,
const QskLayoutChain::Segments&, QskLayoutChain& ) const override;
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};
#endif

View File

@ -322,7 +322,8 @@ HEADERS += \
layouts/QskLinearBox.h \
layouts/QskLinearLayoutEngine.h \
layouts/QskStackBoxAnimator.h \
layouts/QskStackBox.h
layouts/QskStackBox.h \
layouts/QskSubcontrolLayoutEngine.h
SOURCES += \
layouts/QskGridBox.cpp \
@ -335,7 +336,8 @@ SOURCES += \
layouts/QskLinearBox.cpp \
layouts/QskLinearLayoutEngine.cpp \
layouts/QskStackBoxAnimator.cpp \
layouts/QskStackBox.cpp
layouts/QskStackBox.cpp \
layouts/QskSubcontrolLayoutEngine.cpp
HEADERS += \
dialogs/QskDialog.h \