6#include "QskLayoutChain.h" 
    8#include <qvarlengtharray.h> 
   14QskLayoutChain::QskLayoutChain()
 
   18QskLayoutChain::~QskLayoutChain()
 
   22void QskLayoutChain::invalidate()
 
   28void QskLayoutChain::reset( 
int count, qreal constraint )
 
   30    m_cells.fill( CellData(), count );
 
   31    m_constraint = constraint;
 
   36void QskLayoutChain::shrinkCell( 
int index, 
const CellData& newCell )
 
   38    if ( !newCell.isValid )
 
   41    auto& cell = m_cells[ index ];
 
   46        cell.stretch = qMax( cell.stretch, 0 );
 
   51        cell.canGrow &= newCell.canGrow;
 
   52        if ( newCell.stretch >= 0 )
 
   53            cell.stretch = qMax( cell.stretch, newCell.stretch );
 
   55        if ( !newCell.metrics.isDefault() )
 
   57            auto& metrics = cell.metrics;
 
   58            auto& newMetrics = newCell.metrics;
 
   60            metrics.setMinimum( qMax( metrics.minimum(), newMetrics.minimum() ) );
 
   61            metrics.setPreferred( qMax( metrics.preferred(), newMetrics.preferred() ) );
 
   63            if ( newMetrics.maximum() < metrics.maximum() )
 
   65                metrics.setMaximum( newMetrics.maximum() );
 
   69            cell.metrics.normalize();
 
   74void QskLayoutChain::expandCell( 
int index, 
const CellData& newCell )
 
   76    if ( !newCell.isValid )
 
   79    auto& cell = m_cells[ index ];
 
   88        cell.canGrow |= newCell.canGrow;
 
   89        cell.stretch = qMax( cell.stretch, newCell.stretch );
 
   91        cell.metrics.setMetrics(
 
   92            qMax( cell.metrics.minimum(), newCell.metrics.minimum() ),
 
   93            qMax( cell.metrics.preferred(), newCell.metrics.preferred() ),
 
   94            qMax( cell.metrics.maximum(), newCell.metrics.maximum() )
 
   99void QskLayoutChain::expandCells(
 
  100    int index, 
int count, 
const CellData& multiCell )
 
  103    chain.setSpacing( m_spacing );
 
  104    chain.reset( count, -1 );
 
  106    for ( 
int i = 0; i < count; i++ )
 
  108        auto& cell = chain.m_cells[ i ];
 
  109        cell = m_cells[ index + i ];
 
  114            cell.canGrow = multiCell.canGrow;
 
  115            cell.stretch = multiCell.stretch;
 
  120    QskLayoutChain::Segments minimum;
 
  121    QskLayoutChain::Segments preferred;
 
  122    QskLayoutChain::Segments maximum;
 
  124    const auto chainMetrics = chain.boundingMetrics();
 
  126    if ( multiCell.metrics.minimum() > chainMetrics.minimum() )
 
  127        minimum = chain.segments( multiCell.metrics.minimum() );
 
  129    if ( multiCell.metrics.preferred() > chainMetrics.preferred() )
 
  130        preferred = chain.segments( multiCell.metrics.preferred() );
 
  132    if ( chainMetrics.maximum() == QskLayoutMetrics::unlimited )
 
  134        if ( multiCell.metrics.maximum() < QskLayoutMetrics::unlimited )
 
  135            maximum = chain.segments( multiCell.metrics.maximum() );
 
  138    for ( 
int i = 0; i < count; i++ )
 
  140        auto& cell = m_cells[ index + i ];
 
  142        cell.canGrow |= multiCell.canGrow;
 
  143        cell.stretch = qMax( cell.stretch, multiCell.stretch );
 
  145        if ( !minimum.isEmpty() )
 
  146            cell.metrics.expandMinimum( minimum[i].length );
 
  148        if ( !preferred.isEmpty() )
 
  149            cell.metrics.expandPreferred( preferred[i].length );
 
  151        if ( !maximum.isEmpty() && !cell.isValid )
 
  152            cell.metrics.setMaximum( maximum[i].length );
 
  154        cell.metrics.normalize();
 
  164void QskLayoutChain::finish()
 
  167    qreal preferred = 0.0;
 
  173    if ( !m_cells.empty() )
 
  175        const auto maxMaximum = QskLayoutMetrics::unlimited;
 
  177        for ( 
auto& cell : m_cells )
 
  182            minimum += cell.metrics.minimum();
 
  183            preferred += cell.metrics.preferred();
 
  185            if ( maximum < maxMaximum )
 
  187                if ( cell.stretch == 0 && !cell.canGrow )
 
  189                    maximum += cell.metrics.preferred();
 
  193                    if ( cell.metrics.maximum() == maxMaximum )
 
  194                        maximum = maxMaximum;
 
  196                        maximum += cell.metrics.maximum();
 
  200            m_sumStretches += cell.stretch;
 
  204        const qreal spacing = ( m_validCells - 1 ) * m_spacing;
 
  207        preferred += spacing;
 
  209        if ( maximum < maxMaximum )
 
  213    m_boundingMetrics.setMinimum( minimum );
 
  214    m_boundingMetrics.setPreferred( preferred );
 
  215    m_boundingMetrics.setMaximum( maximum );
 
  218bool QskLayoutChain::setSpacing( qreal spacing )
 
  220    if ( m_spacing != spacing )
 
  229QskLayoutChain::Segments QskLayoutChain::segments( qreal size )
 const 
  231    if ( m_validCells == 0 )
 
  236    if ( size <= m_boundingMetrics.minimum() )
 
  238        segments = distributed( Qt::MinimumSize, 0.0, 0.0 );
 
  240    else if ( size < m_boundingMetrics.preferred() )
 
  242        segments = minimumExpanded( size );
 
  244    else if ( size <= m_boundingMetrics.maximum() )
 
  246        segments = preferredStretched( size );
 
  250        const qreal padding = size - m_boundingMetrics.maximum();
 
  264            case Leading | Trailing:
 
  265                offset = 0.5 * padding;
 
  269                extra = padding / m_validCells;
 
  272        segments = distributed( Qt::MaximumSize, offset, extra );
 
  278QskLayoutChain::Segments QskLayoutChain::distributed(
 
  279    int which, qreal offset, 
const qreal extra )
 const 
  281    qreal fillSpacing = 0.0;
 
  283    Segments segments( m_cells.size() );
 
  285    for ( 
int i = 0; i < segments.count(); i++ )
 
  287        const auto& cell = m_cells[i];
 
  288        auto& segment = segments[i];
 
  292            segment.start = offset;
 
  293            segment.length = 0.0;
 
  297            offset += fillSpacing;
 
  298            fillSpacing = m_spacing;
 
  300            segment.start = offset;
 
  302            qreal size = cell.metrics.metric( which );
 
  305            if ( which == Qt::MaximumSize && size == QskLayoutMetrics::unlimited )
 
  313                size = cell.metrics.metric( Qt::PreferredSize );
 
  317            if ( which == Qt::MaximumSize && cell.isShrunk )
 
  319                segment.length = size;
 
  320                offset += segment.length + extra;
 
  324                segment.length = size + extra;
 
  325                offset += segment.length;
 
  333QskLayoutChain::Segments QskLayoutChain::minimumExpanded( qreal size )
 const 
  335    Segments segments( m_cells.size() );
 
  337    qreal fillSpacing = 0.0;
 
  351    const qreal factor = ( size - m_boundingMetrics.minimum() ) /
 
  352        ( m_boundingMetrics.preferred() - m_boundingMetrics.minimum() );
 
  354    for ( 
int i = 0; i < m_cells.count(); i++ )
 
  356        const auto& cell = m_cells[i];
 
  357        auto& segment = segments[i];
 
  361            segment.start = offset;
 
  362            segment.length = 0.0;
 
  366            offset += fillSpacing;
 
  367            fillSpacing = m_spacing;
 
  369            segment.start = offset;
 
  370            segment.length = cell.metrics.minimum()
 
  371                + factor * ( cell.metrics.preferred() - cell.metrics.minimum() );
 
  373            offset += segment.length;
 
  380QskLayoutChain::Segments QskLayoutChain::preferredStretched( qreal size )
 const 
  382    const int count = m_cells.size();
 
  387    qreal sumFactors = 0.0;
 
  389    QVarLengthArray< qreal > factors( count );
 
  390    Segments segments( count );
 
  392    for ( 
int i = 0; i < count; i++ )
 
  394        const auto& cell = m_cells[i];
 
  398            segments[i].length = 0.0;
 
  403        if ( cell.metrics.preferred() >= cell.metrics.maximum() )
 
  409            if ( m_sumStretches == 0 )
 
  410                factors[i] = cell.canGrow ? 1.0 : 0.0;
 
  412                factors[i] = cell.stretch;
 
  416        sumFactors += factors[i];
 
  419    qreal sumSizes = 0.0;
 
  421    if ( sumFactors > 0.0 )
 
  423        sumSizes = size - ( m_validCells - 1 ) * m_spacing;
 
  429            for ( 
int i = 0; i < count; i++ )
 
  431                if ( factors[i] < 0.0 )
 
  434                const auto sz = sumSizes * factors[i] / sumFactors;
 
  436                const auto& hint = m_cells[i].metrics;
 
  437                const auto boundedSize =
 
  438                    qBound( hint.preferred(), sz, hint.maximum() );
 
  440                if ( boundedSize != sz )
 
  442                    segments[i].length = boundedSize;
 
  443                    sumSizes -= boundedSize;
 
  444                    sumFactors -= factors[i];
 
  457    qreal fillSpacing = 0.0;
 
  459    for ( 
int i = 0; i < count; i++ )
 
  461        const auto& cell = m_cells[i];
 
  462        auto& segment = segments[i];
 
  464        const auto& factor = factors[i];
 
  468            offset += fillSpacing;
 
  469            fillSpacing = m_spacing;
 
  472        segment.start = offset;
 
  477                segment.length = sumSizes * factor / sumFactors;
 
  479                segment.length = cell.metrics.preferred();
 
  482        offset += segment.length;
 
  488#ifndef QT_NO_DEBUG_STREAM 
  494    QDebugStateSaver saver( debug );
 
  497    debug << 
"( " << segment.start << 
", " << segment.end() << 
" )";
 
  504    QDebugStateSaver saver( debug );
 
  509        debug << 
"( " << 
"Invalid " << 
" )";
 
  513        debug << 
"( " << cell.metrics << 
", " 
  514            << cell.stretch << 
", " << cell.canGrow << 
" )";