17 #include "organicgrid.h" 19 #include <private/qquickitem_p.h> 21 OrganicGrid::OrganicGrid()
22 : m_firstVisibleIndex(-1)
23 , m_numberOfModulesPerRow(-1)
27 QSizeF OrganicGrid::smallDelegateSize()
const 29 return m_smallDelegateSize;
32 void OrganicGrid::setSmallDelegateSize(
const QSizeF size)
34 if (m_smallDelegateSize != size) {
35 m_smallDelegateSize = size;
36 Q_EMIT smallDelegateSizeChanged();
38 if (isComponentComplete()) {
44 QSizeF OrganicGrid::bigDelegateSize()
const 46 return m_bigDelegateSize;
49 void OrganicGrid::setBigDelegateSize(
const QSizeF size)
51 if (m_bigDelegateSize != size) {
52 m_bigDelegateSize = size;
53 Q_EMIT bigDelegateSizeChanged();
55 if (isComponentComplete()) {
61 QPointF OrganicGrid::positionForIndex(
int modelIndex)
const 63 const qreal moduleHeight = m_smallDelegateSize.height() + rowSpacing() + m_bigDelegateSize.height();
64 const qreal moduleWidth = m_smallDelegateSize.width() * 2 + columnSpacing() * 2 + m_bigDelegateSize.width();
65 const int itemsPerRow = m_numberOfModulesPerRow * 6;
66 const int rowIndex = floor(modelIndex / itemsPerRow);
67 const int columnIndex = floor((modelIndex - rowIndex * itemsPerRow) / 6);
69 qreal yPos = (moduleHeight + rowSpacing()) * rowIndex;
70 const int moduleIndex = modelIndex % 6;
71 if (moduleIndex == 2) {
72 yPos += m_smallDelegateSize.height() + rowSpacing();
73 }
else if (moduleIndex == 3 || moduleIndex == 5) {
74 yPos += m_bigDelegateSize.height() + rowSpacing();
77 qreal xPos = (moduleWidth + columnSpacing()) * columnIndex;
78 if (moduleIndex == 1) {
79 xPos += m_smallDelegateSize.width() + columnSpacing();
80 }
else if (moduleIndex == 3) {
81 xPos += m_bigDelegateSize.width() + columnSpacing();
82 }
else if (moduleIndex == 4) {
83 xPos += (m_smallDelegateSize.width() + columnSpacing()) * 2;
84 }
else if (moduleIndex == 5) {
85 xPos += m_bigDelegateSize.width() + m_smallDelegateSize.width() + columnSpacing() * 2;
88 return QPointF(xPos, yPos);
91 QSizeF OrganicGrid::sizeForIndex(
int modelIndex)
const 93 const int moduleIndex = modelIndex % 6;
94 if (moduleIndex == 0 || moduleIndex == 1 || moduleIndex == 3 || moduleIndex == 5) {
95 return m_smallDelegateSize;
97 return m_bigDelegateSize;
101 void OrganicGrid::findBottomModelIndexToAdd(
int *modelIndex, qreal *yPos)
103 if (m_visibleItems.isEmpty()) {
107 *modelIndex = m_firstVisibleIndex + m_visibleItems.count();
110 const int firstModuleIndex = ((*modelIndex) / 6) * 6;
111 *yPos = positionForIndex(firstModuleIndex).y();
115 void OrganicGrid::findTopModelIndexToAdd(
int *modelIndex, qreal *yPos)
117 if (m_visibleItems.isEmpty()) {
121 *modelIndex = m_firstVisibleIndex - 1;
124 const int lastModuleIndex = ((*modelIndex) / 6) * 6 + 5;
125 *yPos = positionForIndex(lastModuleIndex).y();
126 *yPos += sizeForIndex(lastModuleIndex).height();
130 void OrganicGrid::addItemToView(
int modelIndex, QQuickItem *item)
133 if (modelIndex == m_firstVisibleIndex + m_visibleItems.count()) {
134 m_visibleItems << item;
135 }
else if (modelIndex == m_firstVisibleIndex - 1) {
136 m_firstVisibleIndex = modelIndex;
137 m_visibleItems.prepend(item);
138 }
else if (modelIndex == 0) {
139 m_firstVisibleIndex = 0;
140 m_visibleItems << item;
142 qWarning() <<
"OrganicGrid::addItemToView - Got unexpected modelIndex" 143 << modelIndex << m_firstVisibleIndex << m_visibleItems.count();
147 const QPointF pos = positionForIndex(modelIndex);
148 item->setPosition(pos);
150 item->setSize(sizeForIndex(modelIndex));
153 bool OrganicGrid::removeNonVisibleItems(qreal bufferFromY, qreal bufferToY)
155 bool changed =
false;
158 int lastModuleIndex = (m_firstVisibleIndex / 6) * 6 + 5;
159 bool removeIndex = positionForIndex(lastModuleIndex).y() + sizeForIndex(lastModuleIndex).height() < bufferFromY;
160 while (removeIndex && !m_visibleItems.isEmpty()) {
161 releaseItem(m_visibleItems.takeFirst());
163 m_firstVisibleIndex++;
165 lastModuleIndex = (m_firstVisibleIndex / 6) * 6 + 5;
166 removeIndex = positionForIndex(lastModuleIndex).y() + sizeForIndex(lastModuleIndex).height() < bufferFromY;
169 int firstModuleIndex = ((m_firstVisibleIndex + m_visibleItems.count() - 1) / 6) * 6;
170 removeIndex = positionForIndex(firstModuleIndex).y() > bufferToY;
171 while (removeIndex && !m_visibleItems.isEmpty()) {
172 releaseItem(m_visibleItems.takeLast());
175 firstModuleIndex = ((m_firstVisibleIndex + m_visibleItems.count() - 1) / 6) * 6;
176 removeIndex = positionForIndex(firstModuleIndex).y() > bufferToY;
179 if (m_visibleItems.isEmpty()) {
180 m_firstVisibleIndex = -1;
186 void OrganicGrid::cleanupExistingItems()
188 Q_FOREACH(QQuickItem *item, m_visibleItems)
190 m_visibleItems.clear();
191 m_firstVisibleIndex = -1;
192 setImplicitHeightDirty();
197 const qreal moduleWidth = m_smallDelegateSize.width() * 2 + columnSpacing() * 2 + m_bigDelegateSize.width();
198 m_numberOfModulesPerRow = floor((width() + columnSpacing()) / (moduleWidth + columnSpacing()));
199 m_numberOfModulesPerRow = qMax(1, m_numberOfModulesPerRow);
201 int i = m_firstVisibleIndex;
202 const QList<QQuickItem*> allItems = m_visibleItems;
203 m_visibleItems.clear();
204 Q_FOREACH(QQuickItem *item, allItems) {
205 addItemToView(i, item);
210 void OrganicGrid::updateItemCulling(qreal visibleFromY, qreal visibleToY)
212 Q_FOREACH(QQuickItem *item, m_visibleItems) {
213 QQuickItemPrivate::get(item)->setCulled(item->y() + item->height() <= visibleFromY || item->y() >= visibleToY);
217 void OrganicGrid::calculateImplicitHeight()
219 const qreal moduleHeight = m_smallDelegateSize.height() + rowSpacing() + m_bigDelegateSize.height();
220 const int itemCount = !model() ? 0 : model()->rowCount();
221 const int itemsPerRow = m_numberOfModulesPerRow * 6;
222 const int fullRows = floor(itemCount / itemsPerRow);
223 const qreal fullRowsHeight = fullRows == 0 ? 0 : fullRows * moduleHeight + rowSpacing() * (fullRows - 1);
225 const int remainingItems = itemCount - fullRows * itemsPerRow;
226 if (remainingItems == 0) {
227 setImplicitHeight(fullRowsHeight);
228 }
else if (remainingItems <= 2) {
229 setImplicitHeight(fullRowsHeight + m_smallDelegateSize.height() + rowSpacing());
231 setImplicitHeight(fullRowsHeight + rowSpacing() + moduleHeight);
235 void OrganicGrid::processModelRemoves(
const QVector<QQmlChangeSet::Change> &removes)
237 Q_FOREACH(
const QQmlChangeSet::Change
remove, removes) {
238 for (
int i =
remove.count - 1; i >= 0; --i) {
239 const int indexToRemove =
remove.index + i;
241 const int lastIndex = m_firstVisibleIndex + m_visibleItems.count() - 1;
242 if (indexToRemove == lastIndex) {
243 releaseItem(m_visibleItems.takeLast());
245 if (indexToRemove < lastIndex) {
246 qDebug() <<
"OrganicGrid only supports removal from the end of the model, resetting instead";
247 cleanupExistingItems();
253 if (m_visibleItems.isEmpty()) {
254 m_firstVisibleIndex = -1;
256 setImplicitHeightDirty();