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 <<
" )";