6#include "QskGridLayoutEngine.h"
7#include "QskLayoutMetrics.h"
8#include "QskLayoutChain.h"
9#include "QskLayoutElement.h"
10#include "QskSizePolicy.h"
18static inline qreal qskSegmentLength(
19 const QskLayoutChain::Segments& s,
int start,
int end )
21 return s[ end ].start - s[ start ].start + s[ end ].length;
32 inline bool isDefault()
const
34 return m_stretch < 0 && m_metrics.isDefault();
37 bool setStretch(
int stretch )
39 if ( stretch != m_stretch )
47 bool setMetric( Qt::SizeHint which, qreal metric )
49 if ( metric != m_metrics.metric( which ) )
51 m_metrics.setMetric( which, metric );
60 cell.metrics = m_metrics.normalized();
61 cell.stretch = m_stretch;
62 cell.canGrow = m_stretch != 0;
68 inline int stretch()
const {
return m_stretch; }
78 int maxPosition()
const
80 if ( m_settings.empty() )
83 return m_settings.back().position;
91 bool setStretchAt(
int index,
int stretch )
93 auto setStretch = [stretch]( Setting& s )
94 {
return s.setStretch( stretch ); };
96 return setValueAt( index, setStretch );
99 bool setMetricAt(
int index, Qt::SizeHint which, qreal size )
101 auto setMetric = [which, size]( Setting& s )
102 {
return s.setMetric( which, size ); };
104 return setValueAt( index, setMetric );
107 Setting settingAt(
int index )
const
109 auto it = lowerBound( index );
110 if ( it != m_settings.end() )
116 const std::vector< Setting >& settings()
const {
return m_settings; }
119 inline bool setValueAt(
int pos,
120 const std::function<
bool( Setting& ) >& modify )
127 auto it = lowerBound( pos );
129 if ( it != m_settings.end() && it->position == pos )
131 isModified = modify( *it );
133 if ( isModified && it->isDefault() )
134 m_settings.erase( it );
139 isModified = modify( setting );
143 setting.position = pos;
144 m_settings.insert( it, setting );
151 inline std::vector< Setting >::iterator lowerBound(
int index )
const
153 auto cmp = [](
const Setting& setting,
const int& pos )
154 {
return setting.position < pos; };
156 auto& settings =
const_cast< std::vector< Setting >&
>( m_settings );
157 return std::lower_bound( settings.begin(), settings.end(), index, cmp );
160 std::vector< Setting > m_settings;
167 QQuickItem* item, Qt::Orientation orientation, qreal constraint )
170 return layoutItem.metrics( orientation, constraint );
176 Element( QQuickItem*,
const QRect& );
177 Element(
const QSizeF& spacing,
const QRect& );
178 Element(
const Element& );
180 Element& operator=(
const Element& );
182 QSizeF spacing()
const;
183 QQuickItem* item()
const;
186 void setGrid(
const QRect& );
188 QRect minimumGrid()
const;
190 bool isIgnored()
const;
207 class ElementsVector :
public std::vector< Element >
211 inline int count()
const {
return static_cast< int >( size() ); }
215Element::Element( QQuickItem* item,
const QRect& grid )
218 , m_isSpacer( false )
222Element::Element(
const QSizeF& spacing,
const QRect& grid )
223 : m_spacing( spacing )
229Element::Element(
const Element& other )
230 : m_grid( other.m_grid )
231 , m_isSpacer (other.m_isSpacer )
233 if ( other.m_isSpacer )
234 m_spacing = other.m_spacing;
236 m_item = other.m_item;
239Element& Element::operator=(
const Element& other )
241 m_isSpacer = other.m_isSpacer;
243 if ( other.m_isSpacer )
244 m_spacing = other.m_spacing;
246 m_item = other.m_item;
248 m_grid = other.m_grid;
253inline QSizeF Element::spacing()
const
255 return m_isSpacer ? m_spacing : QSizeF();
258inline QQuickItem* Element::item()
const
260 return m_isSpacer ? nullptr : m_item;
263QRect Element::grid()
const
268void Element::setGrid(
const QRect& grid )
273QRect Element::minimumGrid()
const
275 return QRect( m_grid.left(), m_grid.top(),
276 qMax( m_grid.width(), 1 ), qMax( m_grid.height(), 1 ) );
279bool Element::isIgnored()
const
281 return !( m_isSpacer || qskIsVisibleToLayout( m_item ) );
291 const qreal value = ( orientation == Qt::Horizontal )
292 ? m_spacing.width() : m_spacing.height();
294 cell.metrics.setMinimum( value );
295 cell.metrics.setPreferred( value );
296 cell.metrics.setMaximum( value );
300 const auto policy = qskSizePolicy( m_item ).policy( orientation );
302 cell.canGrow = policy & QskSizePolicy::GrowFlag;
304 if ( policy & QskSizePolicy::ExpandFlag )
311void Element::transpose()
313 m_grid.setRect( m_grid.top(), m_grid.left(),
314 m_grid.height(), m_grid.width() );
317class QskGridLayoutEngine::PrivateData
320 inline Element* elementAt(
int index )
const
322 if ( index < 0 || index >= this->elements.count() )
325 return const_cast< Element*
>( &this->elements[index] );
328 int insertElement( QQuickItem* item, QSizeF spacing, QRect grid )
331 if ( grid.width() == 0 )
334 if ( grid.height() == 0 )
339 elements.push_back( Element( item, grid ) );
343 if ( spacing.width() < 0.0 )
344 spacing.setWidth( 0.0 );
346 if ( spacing.height() < 0.0 )
347 spacing.setHeight( 0.0 );
349 elements.push_back( Element( spacing, grid ) );
352 grid = effectiveGrid( elements.back() );
354 rowCount = qMax( rowCount, grid.bottom() + 1 );
355 columnCount = qMax( columnCount, grid.right() + 1 );
357 return this->elements.count() - 1;
360 QRect effectiveGrid(
const Element& element )
const
362 QRect r = element.grid();
364 if ( r.width() <= 0 )
365 r.setRight( qMax( this->columnCount - 1, r.left() ) );
367 if ( r.height() <= 0 )
368 r.setBottom( qMax( this->rowCount - 1, r.top() ) );
373 Settings& settings( Qt::Orientation orientation )
const
375 auto that =
const_cast< PrivateData*
>( this );
376 return ( orientation == Qt::Horizontal )
377 ? that->columnSettings : that->rowSettings;
380 ElementsVector elements;
382 Settings rowSettings;
383 Settings columnSettings;
389QskGridLayoutEngine::QskGridLayoutEngine()
390 : m_data( new PrivateData() )
394QskGridLayoutEngine::~QskGridLayoutEngine()
398int QskGridLayoutEngine::count()
const
400 return m_data->elements.count();
403bool QskGridLayoutEngine::setStretchFactor(
404 int pos,
int stretch, Qt::Orientation orientation )
412 if ( !m_data->settings( orientation ).setStretchAt( pos, stretch ) )
415 if ( orientation == Qt::Horizontal )
417 if ( pos >= m_data->columnCount )
418 m_data->columnCount = pos + 1;
422 if ( pos >= m_data->rowCount )
423 m_data->rowCount = pos + 1;
430int QskGridLayoutEngine::stretchFactor(
431 int pos, Qt::Orientation orientation )
const
433 const auto setting = m_data->settings( orientation ).settingAt( pos );
434 return ( setting.position == pos ) ? setting.stretch() : 0;
437bool QskGridLayoutEngine::setRowSizeHint(
438 int row, Qt::SizeHint which, qreal height )
440 if ( !m_data->rowSettings.setMetricAt( row, which, height ) )
443 if ( row >= m_data->rowCount )
444 m_data->rowCount = row + 1;
450qreal QskGridLayoutEngine::rowSizeHint(
int row, Qt::SizeHint which )
const
452 const auto& settings = m_data->rowSettings;
453 return settings.settingAt( row ).metrics().metric( which );
456bool QskGridLayoutEngine::setColumnSizeHint(
457 int column, Qt::SizeHint which, qreal width )
459 if ( !m_data->columnSettings.setMetricAt( column, which, width ) )
462 if ( column >= m_data->columnCount )
463 m_data->columnCount = column + 1;
469qreal QskGridLayoutEngine::columnSizeHint(
int column, Qt::SizeHint which )
const
471 const auto& settings = m_data->columnSettings;
472 return settings.settingAt( column ).metrics().metric( which );
475int QskGridLayoutEngine::insertItem( QQuickItem* item,
const QRect& grid )
478 return m_data->insertElement( item, QSizeF(), grid );
481int QskGridLayoutEngine::insertSpacer(
const QSizeF& spacing,
const QRect& grid )
483 return m_data->insertElement(
nullptr, spacing, grid );
486bool QskGridLayoutEngine::removeAt(
int index )
488 const auto elementAt = m_data->elementAt( index );
489 if ( elementAt ==
nullptr )
492 const auto grid = elementAt->minimumGrid();
494 auto& elements = m_data->elements;
495 elements.erase( elements.begin() + index );
499 if ( grid.bottom() >= m_data->rowCount
500 || grid.right() >= m_data->columnCount )
502 int maxRow = m_data->rowSettings.maxPosition();
503 int maxColumn = m_data->columnSettings.maxPosition();
505 for (
const auto& element : elements )
507 const auto minGrid = element.minimumGrid();
509 maxRow = qMax( maxRow, minGrid.bottom() );
510 maxColumn = qMax( maxColumn, minGrid.right() );
513 m_data->rowCount = maxRow + 1;
514 m_data->columnCount = maxColumn + 1;
521bool QskGridLayoutEngine::clear()
523 m_data->elements.clear();
524 m_data->rowSettings.clear();
525 m_data->columnSettings.clear();
527 m_data->rowCount = m_data->columnCount = 0;
533int QskGridLayoutEngine::indexAt(
int row,
int column )
const
535 if ( row < m_data->rowCount && column < m_data->columnCount )
537 for ( uint i = 0; i < m_data->elements.size(); i++ )
539 const auto grid = m_data->effectiveGrid( m_data->elements[i] );
540 if ( grid.contains( column, row ) )
548QQuickItem* QskGridLayoutEngine::itemAt(
int index )
const
550 if (
const auto element = m_data->elementAt( index ) )
551 return element->item();
556QskSizePolicy QskGridLayoutEngine::sizePolicyAt(
int index )
const
558 return qskSizePolicy( itemAt( index ) );
561int QskGridLayoutEngine::indexOf(
const QQuickItem* item )
const
570 for (
int i = count() - 1; i >= 0; --i )
572 if ( itemAt( i ) == item )
580QSizeF QskGridLayoutEngine::spacerAt(
int index )
const
582 if (
const auto element = m_data->elementAt( index ) )
583 return element->spacing();
588QQuickItem* QskGridLayoutEngine::itemAt(
int row,
int column )
const
590 return itemAt( indexAt( row, column ) );
593bool QskGridLayoutEngine::setGridAt(
int index,
const QRect& grid )
595 if (
auto element = m_data->elementAt( index ) )
597 if ( element->grid() != grid )
599 element->setGrid( grid );
609QRect QskGridLayoutEngine::gridAt(
int index )
const
611 if (
auto element = m_data->elementAt( index ) )
612 return element->grid();
617QRect QskGridLayoutEngine::effectiveGridAt(
int index )
const
619 if (
auto element = m_data->elementAt( index ) )
620 return m_data->effectiveGrid( *element );
625void QskGridLayoutEngine::invalidateElementCache()
629void QskGridLayoutEngine::layoutItems()
631 for (
const auto& element : m_data->elements )
633 auto item = element.item();
635 if ( qskIsAdjustableByLayout( item ) )
637 const auto grid = m_data->effectiveGrid( element );
641 const auto rect = geometryAt( &layoutElement, grid );
642 if ( rect.size().isValid() )
643 qskSetItemGeometry( item, rect );
648void QskGridLayoutEngine::transpose()
650 for (
auto& element : m_data->elements )
653 qSwap( m_data->columnSettings, m_data->rowSettings );
654 qSwap( m_data->columnCount, m_data->rowCount );
659int QskGridLayoutEngine::effectiveCount(
660 Qt::Orientation orientation )
const
662 return ( orientation == Qt::Horizontal )
663 ? m_data->columnCount : m_data->rowCount;
666void QskGridLayoutEngine::setupChain( Qt::Orientation orientation,
667 const QskLayoutChain::Segments& constraints,
QskLayoutChain& chain )
const
673 QVarLengthArray< const Element* > postponed;
674 postponed.reserve( m_data->elements.count() );
676 for (
const auto& element : m_data->elements )
678 if ( element.isIgnored() )
681 auto grid = m_data->effectiveGrid( element );
682 if ( orientation == Qt::Horizontal )
683 grid.setRect( grid.y(), grid.x(), grid.height(), grid.width() );
685 if ( grid.height() == 1 )
687 qreal constraint = -1.0;
688 if ( !constraints.isEmpty() )
689 constraint = qskSegmentLength( constraints, grid.left(), grid.right() );
691 auto cell = element.cell( orientation );
693 if ( element.item() )
694 cell.metrics = qskItemMetrics( element.item(), orientation, constraint );
696 chain.expandCell( grid.top(), cell );
700 postponed += &element;
704 const auto& settings = m_data->settings( orientation );
706 for (
const auto& setting : settings.settings() )
707 chain.shrinkCell( setting.position, setting.cell() );
709 for (
const auto element : postponed )
711 auto grid = m_data->effectiveGrid( *element );
712 if ( orientation == Qt::Horizontal )
713 grid.setRect( grid.y(), grid.x(), grid.height(), grid.width() );
715 qreal constraint = -1.0;
716 if ( !constraints.isEmpty() )
717 constraint = qskSegmentLength( constraints, grid.left(), grid.right() );
719 auto cell = element->cell( orientation );
720 cell.metrics = qskItemMetrics( element->item(), orientation, constraint );
722 chain.expandCells( grid.top(), grid.height(), cell );