set binding when its \e when clause becomes false.
Flickable: added dragging, draggingHorizontally and draggingVerically properties.
+Added topMargin, bottomMargin, leftMargin, rightMargin, xOrigin, yOrigin properties.
Image has two new properties: horizontalAlignment and verticalAlignment. It also has a new value for
fillMode (Image.Pad) that does not transform the image.
atBoundaryChange = true;
}
+ if (vData.extentsChanged) {
+ vData.extentsChanged = false;
+ emit q->yOriginChanged();
+ }
+
+ if (hData.extentsChanged) {
+ hData.extentsChanged = false;
+ emit q->xOriginChanged();
+ }
+
if (atBoundaryChange)
emit q->isAtBoundaryChanged();
void QSGFlickable::setContentX(qreal pos)
{
Q_D(QSGFlickable);
+ d->hData.explicitValue = true;
d->timeline.reset(d->hData.move);
d->vTime = d->timeline.time();
movementXEnding();
void QSGFlickable::setContentY(qreal pos)
{
Q_D(QSGFlickable);
+ d->vData.explicitValue = true;
d->timeline.reset(d->vData.move);
d->vTime = d->timeline.time();
movementYEnding();
qreal QSGFlickable::minYExtent() const
{
- return 0.0;
+ Q_D(const QSGFlickable);
+ return d->vData.startMargin;
}
qreal QSGFlickable::minXExtent() const
{
- return 0.0;
+ Q_D(const QSGFlickable);
+ return d->hData.startMargin;
}
/* returns -ve */
qreal QSGFlickable::maxXExtent() const
{
- return width() - vWidth();
+ Q_D(const QSGFlickable);
+ return width() - vWidth() - d->hData.endMargin;
}
/* returns -ve */
qreal QSGFlickable::maxYExtent() const
{
- return height() - vHeight();
+ Q_D(const QSGFlickable);
+ return height() - vHeight() - d->vData.endMargin;
+}
+
+void QSGFlickable::componentComplete()
+{
+ Q_D(QSGFlickable);
+ QSGItem::componentComplete();
+ if (!d->hData.explicitValue && d->hData.startMargin != 0.)
+ setContentX(-minXExtent());
+ if (!d->vData.explicitValue && d->vData.startMargin != 0.)
+ setContentY(-minYExtent());
}
void QSGFlickable::viewportMoved()
d->contentItem->setWidth(width());
else
d->contentItem->setWidth(w);
+ d->hData.markExtentsDirty();
// Make sure that we're entirely in view.
if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
d->fixupMode = QSGFlickablePrivate::Immediate;
d->contentItem->setHeight(height());
else
d->contentItem->setHeight(h);
+ d->vData.markExtentsDirty();
// Make sure that we're entirely in view.
if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
d->fixupMode = QSGFlickablePrivate::Immediate;
}
/*!
+ \qmlproperty real QtQuick2::Flickable::topMargin
+ \qmlproperty real QtQuick2::Flickable::leftMargin
+ \qmlproperty real QtQuick2::Flickable::bottomMargin
+ \qmlproperty real QtQuick2::Flickable::rightMargin
+
+ These properties hold the margins around the content. This space is reserved
+ in addition to the contentWidth and contentHeight.
+*/
+
+
+qreal QSGFlickable::topMargin() const
+{
+ Q_D(const QSGFlickable);
+ return d->vData.startMargin;
+}
+
+void QSGFlickable::setTopMargin(qreal m)
+{
+ Q_D(QSGFlickable);
+ if (d->vData.startMargin == m)
+ return;
+ d->vData.startMargin = m;
+ d->vData.markExtentsDirty();
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupY();
+ }
+ emit topMarginChanged();
+ d->updateBeginningEnd();
+}
+
+qreal QSGFlickable::bottomMargin() const
+{
+ Q_D(const QSGFlickable);
+ return d->vData.endMargin;
+}
+
+void QSGFlickable::setBottomMargin(qreal m)
+{
+ Q_D(QSGFlickable);
+ if (d->vData.endMargin == m)
+ return;
+ d->vData.endMargin = m;
+ d->vData.markExtentsDirty();
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupY();
+ }
+ emit bottomMarginChanged();
+ d->updateBeginningEnd();
+}
+
+qreal QSGFlickable::leftMargin() const
+{
+ Q_D(const QSGFlickable);
+ return d->hData.startMargin;
+}
+
+void QSGFlickable::setLeftMargin(qreal m)
+{
+ Q_D(QSGFlickable);
+ if (d->hData.startMargin == m)
+ return;
+ d->hData.startMargin = m;
+ d->hData.markExtentsDirty();
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupX();
+ }
+ emit leftMarginChanged();
+ d->updateBeginningEnd();
+}
+
+qreal QSGFlickable::rightMargin() const
+{
+ Q_D(const QSGFlickable);
+ return d->hData.endMargin;
+}
+
+void QSGFlickable::setRightMargin(qreal m)
+{
+ Q_D(QSGFlickable);
+ if (d->hData.endMargin == m)
+ return;
+ d->hData.endMargin = m;
+ d->hData.markExtentsDirty();
+ if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
+ d->fixupMode = QSGFlickablePrivate::Immediate;
+ d->fixupX();
+ }
+ emit rightMarginChanged();
+ d->updateBeginningEnd();
+}
+
+/*!
+ \qmlproperty real QtQuick2::Flickable::xOrigin
+ \qmlproperty real QtQuick2::Flickable::yOrigin
+
+ These properties hold the origin of the content. This is usually (0,0), however
+ ListView and GridView may have an arbitrary origin due to delegate size variation,
+ or item insertion/removal outside the visible region.
+*/
+
+qreal QSGFlickable::yOrigin() const
+{
+ Q_D(const QSGFlickable);
+ return -minYExtent() + d->vData.startMargin;
+}
+
+qreal QSGFlickable::xOrigin() const
+{
+ Q_D(const QSGFlickable);
+ return -minXExtent() + d->hData.startMargin;
+}
+
+
+/*!
\qmlmethod QtQuick2::Flickable::resizeContent(real width, real height, QPointF center)
- \preliminary
Resizes the content to \a width x \a height about \a center.
/*!
\qmlmethod QtQuick2::Flickable::returnToBounds()
- \preliminary
Ensures the content is within legal bounds.
Q_PROPERTY(qreal contentY READ contentY WRITE setContentY NOTIFY contentYChanged)
Q_PROPERTY(QSGItem *contentItem READ contentItem CONSTANT)
+ Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged)
+ Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged)
+ Q_PROPERTY(qreal yOrigin READ yOrigin NOTIFY yOriginChanged)
+
+ Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
+ Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
+ Q_PROPERTY(qreal xOrigin READ xOrigin NOTIFY xOriginChanged)
+
Q_PROPERTY(qreal horizontalVelocity READ horizontalVelocity NOTIFY horizontalVelocityChanged)
Q_PROPERTY(qreal verticalVelocity READ verticalVelocity NOTIFY verticalVelocityChanged)
qreal contentY() const;
virtual void setContentY(qreal pos);
+ qreal topMargin() const;
+ void setTopMargin(qreal m);
+
+ qreal bottomMargin() const;
+ void setBottomMargin(qreal m);
+
+ qreal leftMargin() const;
+ void setLeftMargin(qreal m);
+
+ qreal rightMargin() const;
+ void setRightMargin(qreal m);
+
+ virtual qreal yOrigin() const;
+ virtual qreal xOrigin() const;
+
bool isMoving() const;
bool isMovingHorizontally() const;
bool isMovingVertically() const;
void contentHeightChanged();
void contentXChanged();
void contentYChanged();
+ void topMarginChanged();
+ void bottomMarginChanged();
+ void leftMarginChanged();
+ void rightMarginChanged();
+ void yOriginChanged();
+ void xOriginChanged();
void movingChanged();
void movingHorizontallyChanged();
void movingVerticallyChanged();
virtual qreal maxYExtent() const;
qreal vWidth() const;
qreal vHeight() const;
+ virtual void componentComplete();
virtual void viewportMoved();
virtual void geometryChanged(const QRectF &newGeometry,
const QRectF &oldGeometry);
struct AxisData {
AxisData(QSGFlickablePrivate *fp, void (QSGFlickablePrivate::*func)(qreal))
- : move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true)
- , fixingUp(false), inOvershoot(false), dragging(false)
+ : move(fp, func), viewSize(-1), startMargin(0), endMargin(0)
+ , smoothVelocity(fp), atEnd(false), atBeginning(true)
+ , fixingUp(false), inOvershoot(false), dragging(false), extentsChanged(false)
+ , explicitValue(false), minExtentDirty(true), maxExtentDirty(true)
{}
void reset() {
inOvershoot = false;
}
+ void markExtentsDirty() {
+ minExtentDirty = true;
+ maxExtentDirty = true;
+ extentsChanged = true;
+ }
+
void addVelocitySample(qreal v, qreal maxVelocity);
void updateVelocity();
qreal dragMaxBound;
qreal velocity;
qreal flickTarget;
+ qreal startMargin;
+ qreal endMargin;
QSGFlickablePrivate::Velocity smoothVelocity;
QPODVector<qreal,10> velocityBuffer;
bool atEnd : 1;
bool fixingUp : 1;
bool inOvershoot : 1;
bool dragging : 1;
+ bool extentsChanged : 1;
+ bool explicitValue : 1;
+ mutable bool minExtentDirty : 1;
+ mutable bool maxExtentDirty : 1;
};
void flickX(qreal velocity);
d->header = 0;
d->headerComponent = headerComponent;
- d->minExtentDirty = true;
- d->maxExtentDirty = true;
+ d->markExtentsDirty();
if (isComponentComplete()) {
d->updateHeader();
if (header && header->item == item) {
updateHeader();
- minExtentDirty = true;
- maxExtentDirty = true;
+ markExtentsDirty();
if (!q->isMoving() && !q->isFlicking())
fixupPosition();
} else if (footer && footer->item == item) {
updateFooter();
- minExtentDirty = true;
- maxExtentDirty = true;
+ markExtentsDirty();
if (!q->isMoving() && !q->isFlicking())
fixupPosition();
}
void QSGItemView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
Q_D(QSGItemView);
- d->maxExtentDirty = true;
- d->minExtentDirty = true;
+ d->markExtentsDirty();
QSGFlickable::geometryChanged(newGeometry, oldGeometry);
}
if (d->layoutOrientation() == Qt::Horizontal)
return QSGFlickable::minYExtent();
- if (d->minExtentDirty) {
- d->minExtent = -d->startPosition();
+ if (d->vData.minExtentDirty) {
+ d->minExtent = d->vData.startMargin-d->startPosition();
if (d->header)
d->minExtent += d->headerSize();
if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
d->minExtent -= d->visibleItem(0)->sectionSize();
d->minExtent = qMax(d->minExtent, -(d->endPositionAt(0) - d->highlightRangeEnd));
}
- d->minExtentDirty = false;
+ d->vData.minExtentDirty = false;
}
return d->minExtent;
if (d->layoutOrientation() == Qt::Horizontal)
return height();
- if (d->maxExtentDirty) {
+ if (d->vData.maxExtentDirty) {
if (!d->model || !d->model->count()) {
d->maxExtent = d->header ? -d->headerSize() : 0;
d->maxExtent += height();
if (d->footer)
d->maxExtent -= d->footerSize();
+ d->maxExtent -= d->vData.endMargin;
qreal minY = minYExtent();
if (d->maxExtent > minY)
d->maxExtent = minY;
- d->maxExtentDirty = false;
+ d->vData.maxExtentDirty = false;
}
return d->maxExtent;
}
if (d->layoutOrientation() == Qt::Vertical)
return QSGFlickable::minXExtent();
- if (d->minExtentDirty) {
+ if (d->hData.minExtentDirty) {
d->minExtent = -d->startPosition();
qreal highlightStart;
qreal highlightEnd;
qreal endPositionFirstItem = 0;
if (d->isContentFlowReversed()) {
+ d->minExtent += d->hData.endMargin;
if (d->model && d->model->count())
endPositionFirstItem = d->positionAt(d->model->count()-1);
else if (d->header)
if (d->minExtent < maxX)
d->minExtent = maxX;
} else {
+ d->minExtent += d->hData.startMargin;
endPositionFirstItem = d->endPositionAt(0);
highlightStart = d->highlightRangeStart;
highlightEnd = d->highlightRangeEnd;
d->minExtent += highlightStart;
d->minExtent = qMax(d->minExtent, -(endPositionFirstItem - highlightEnd));
}
- d->minExtentDirty = false;
+ d->hData.minExtentDirty = false;
}
return d->minExtent;
if (d->layoutOrientation() == Qt::Vertical)
return width();
- if (d->maxExtentDirty) {
+ if (d->hData.maxExtentDirty) {
qreal highlightStart;
qreal highlightEnd;
qreal lastItemPosition = 0;
if (d->isContentFlowReversed()) {
if (d->header)
d->maxExtent -= d->headerSize();
+ d->maxExtent -= d->hData.startMargin;
} else {
if (d->footer)
d->maxExtent -= d->footerSize();
+ d->maxExtent -= d->hData.endMargin;
qreal minX = minXExtent();
if (d->maxExtent > minX)
d->maxExtent = minX;
}
- d->maxExtentDirty = false;
+ d->hData.maxExtentDirty = false;
}
return d->maxExtent;
QSGFlickable::setContentY(pos);
}
+qreal QSGItemView::xOrigin() const
+{
+ Q_D(const QSGItemView);
+ if (d->isContentFlowReversed())
+ return -maxXExtent() + d->size() - d->hData.startMargin;
+ else
+ return -minXExtent() + d->hData.startMargin;
+}
void QSGItemView::updatePolish()
{
, ownModel(false), wrap(false), lazyRelease(false), deferredRelease(false)
, inApplyModelChanges(false), inViewportMoved(false), forceLayout(false), currentIndexCleared(false)
, haveHighlightRange(false), autoHighlight(true), highlightRangeStartValid(false), highlightRangeEndValid(false)
- , minExtentDirty(true), maxExtentDirty(true)
{
}
qreal QSGItemViewPrivate::contentStartPosition() const
{
- return -headerSize();
+ Q_Q(const QSGItemView);
+ qreal pos = -headerSize();
+ if (layoutOrientation() == Qt::Vertical)
+ pos -= vData.startMargin;
+ else if (isContentFlowReversed())
+ pos -= hData.endMargin;
+ else
+ pos -= hData.startMargin;
+
+ return pos;
}
int QSGItemViewPrivate::findLastVisibleIndex(int defaultValue) const
createHighlight();
trackedItem = 0;
- minExtentDirty = true;
- maxExtentDirty = true;
+ markExtentsDirty();
itemCount = 0;
}
}
if (changed) {
- minExtentDirty = true;
- maxExtentDirty = true;
+ markExtentsDirty();
visibleItemsChanged();
} else if (!doBuffer && buffer && bufferMode != NoBuffer) {
refill(from, to, true);
layoutVisibleItems();
refill();
- minExtentDirty = true;
- maxExtentDirty = true;
+ markExtentsDirty();
updateHighlight();
int prevCount = itemCount;
bool removedVisible = false;
+ bool viewportChanged = !currentChanges.pendingChanges.removes().isEmpty()
+ || !currentChanges.pendingChanges.inserts().isEmpty();
FxViewItem *firstVisible = firstVisibleItem();
FxViewItem *origVisibleItemsFirst = visibleItems.count() ? visibleItems.first() : 0;
if (prevCount != itemCount)
emit q->countChanged();
+ bool visibleAffected = removedVisible || addedVisible || !currentChanges.pendingChanges.changes().isEmpty();
+ if (!visibleAffected && viewportChanged)
+ updateViewport();
+
inApplyModelChanges = false;
- return removedVisible || addedVisible || !currentChanges.pendingChanges.changes().isEmpty();
+ return visibleAffected;
}
FxViewItem *QSGItemViewPrivate::createItem(int modelIndex)
virtual void setContentX(qreal pos);
virtual void setContentY(qreal pos);
+ virtual qreal xOrigin() const;
signals:
void modelChanged();
void checkVisible() const;
+ void markExtentsDirty() {
+ if (layoutOrientation() == Qt::Vertical)
+ vData.markExtentsDirty();
+ else
+ hData.markExtentsDirty();
+ }
+
QDeclarativeGuard<QSGVisualModel> model;
QVariant modelVariant;
int itemCount;
bool autoHighlight : 1;
bool highlightRangeStartValid : 1;
bool highlightRangeEndValid : 1;
- mutable bool minExtentDirty : 1;
- mutable bool maxExtentDirty : 1;
protected:
virtual Qt::Orientation layoutOrientation() const = 0;
--- /dev/null
+import QtQuick 2.0
+
+Flickable {
+ width: 200; height: 200
+ contentWidth: row.width; contentHeight: row.height
+
+ topMargin: 20
+ bottomMargin: 30
+ leftMargin: 40
+ rightMargin: 50
+
+ Row {
+ id: row
+ Repeater {
+ model: 4
+ Rectangle { width: 400; height: 600; color: "blue" }
+ }
+ }
+}
void movingAndDragging();
void disabled();
void flickVelocity();
+ void margins();
private:
QDeclarativeEngine engine;
delete canvas;
}
+void tst_qsgflickable::margins()
+{
+ QDeclarativeEngine engine;
+ QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/margins.qml"));
+ QSGItem *root = qobject_cast<QSGItem*>(c.create());
+ QSGFlickable *obj = qobject_cast<QSGFlickable*>(root);
+ QVERIFY(obj != 0);
+
+ // starting state
+ QCOMPARE(obj->contentX(), -40.);
+ QCOMPARE(obj->contentY(), -20.);
+ QCOMPARE(obj->contentWidth(), 1600.);
+ QCOMPARE(obj->contentHeight(), 600.);
+ QCOMPARE(obj->xOrigin(), 0.);
+ QCOMPARE(obj->yOrigin(), 0.);
+
+ // Reduce left margin
+ obj->setLeftMargin(30);
+ QTRY_COMPARE(obj->contentX(), -30.);
+
+ // Reduce top margin
+ obj->setTopMargin(20);
+ QTRY_COMPARE(obj->contentY(), -20.);
+
+ // position to the far right, including margin
+ obj->setContentX(1600 + 50 - obj->width());
+ obj->returnToBounds();
+ QTest::qWait(200);
+ QCOMPARE(obj->contentX(), 1600. + 50. - obj->width());
+
+ // position beyond the far right, including margin
+ obj->setContentX(1600 + 50 - obj->width() + 1.);
+ obj->returnToBounds();
+ QTRY_COMPARE(obj->contentX(), 1600. + 50. - obj->width());
+
+ // Reduce right margin
+ obj->setRightMargin(40);
+ QTRY_COMPARE(obj->contentX(), 1600. + 40. - obj->width());
+ QCOMPARE(obj->contentWidth(), 1600.);
+
+ // position to the far bottom, including margin
+ obj->setContentY(600 + 30 - obj->height());
+ obj->returnToBounds();
+ QTest::qWait(200);
+ QCOMPARE(obj->contentY(), 600. + 30. - obj->height());
+
+ // position beyond the far bottom, including margin
+ obj->setContentY(600 + 30 - obj->height() + 1.);
+ obj->returnToBounds();
+ QTRY_COMPARE(obj->contentY(), 600. + 30. - obj->height());
+
+ // Reduce bottom margin
+ obj->setBottomMargin(20);
+ QTRY_COMPARE(obj->contentY(), 600. + 20. - obj->height());
+ QCOMPARE(obj->contentHeight(), 600.);
+
+ delete root;
+}
+
void tst_qsgflickable::flick(QSGView *canvas, const QPoint &from, const QPoint &to, int duration)
{
const int pointCount = 5;
--- /dev/null
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+
+ width: 240
+ height: 320
+ color: "#ffffff"
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ width: 100
+ height: 80
+ border.color: "blue"
+ property string name: model.name
+ Text {
+ text: index
+ }
+ Text {
+ x: 40
+ text: wrapper.x + ", " + wrapper.y
+ }
+ Text {
+ y: 20
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ y: 40
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ color: GridView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+ GridView {
+ id: grid
+ objectName: "grid"
+ width: 240
+ height: 320
+ cellWidth: 100
+ cellHeight: 80
+ leftMargin: 30
+ rightMargin: 50
+ flow: GridView.TopToBottom
+ layoutDirection: (testRightToLeft == true) ? Qt.RightToLeft : Qt.LeftToRight
+ model: testModel
+ delegate: myDelegate
+ }
+ Text { anchors.bottom: parent.bottom; text: grid.contentX }
+}
void testQtQuick11Attributes();
void testQtQuick11Attributes_data();
void columnCount();
+ void margins();
private:
QSGView *createView();
QCOMPARE(items.at(9)->y(), qreal(100));
}
+void tst_QSGGridView::margins()
+{
+ {
+ QSGView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ for (int i = 0; i < 40; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(false));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/margins.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QCOMPARE(gridview->contentX(), -30.);
+ QCOMPARE(gridview->xOrigin(), 0.);
+
+ // check end bound
+ gridview->positionViewAtEnd();
+ qreal pos = gridview->contentX();
+ gridview->setContentX(pos + 80);
+ gridview->returnToBounds();
+ QTRY_COMPARE(gridview->contentX(), pos + 50);
+
+ // remove item before visible and check that left margin is maintained
+ // and xOrigin is updated
+ gridview->setContentX(200);
+ model.removeItems(0, 4);
+ QTest::qWait(100);
+ gridview->setContentX(-50);
+ gridview->returnToBounds();
+ QCOMPARE(gridview->xOrigin(), 100.);
+ QTRY_COMPARE(gridview->contentX(), 70.);
+
+ // reduce left margin
+ gridview->setLeftMargin(20);
+ QCOMPARE(gridview->xOrigin(), 100.);
+ QTRY_COMPARE(gridview->contentX(), 80.);
+
+ // check end bound
+ gridview->positionViewAtEnd();
+ QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
+ pos = gridview->contentX();
+ gridview->setContentX(pos + 80);
+ gridview->returnToBounds();
+ QTRY_COMPARE(gridview->contentX(), pos + 50);
+
+ // reduce right margin
+ pos = gridview->contentX();
+ gridview->setRightMargin(40);
+ QCOMPARE(gridview->xOrigin(), 0.);
+ QTRY_COMPARE(gridview->contentX(), pos-10);
+
+ delete canvas;
+ }
+ {
+ //RTL
+ QSGView *canvas = createView();
+ canvas->show();
+
+ TestModel model;
+ for (int i = 0; i < 40; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+ ctxt->setContextProperty("testRightToLeft", QVariant(true));
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/margins.qml"));
+ qApp->processEvents();
+
+ QSGGridView *gridview = findItem<QSGGridView>(canvas->rootObject(), "grid");
+ QTRY_VERIFY(gridview != 0);
+
+ QSGItem *contentItem = gridview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QCOMPARE(gridview->contentX(), -240+30.);
+ QCOMPARE(gridview->xOrigin(), 0.);
+
+ // check end bound
+ gridview->positionViewAtEnd();
+ qreal pos = gridview->contentX();
+ gridview->setContentX(pos - 80);
+ gridview->returnToBounds();
+ QTRY_COMPARE(gridview->contentX(), pos - 50);
+
+ // remove item before visible and check that left margin is maintained
+ // and xOrigin is updated
+ gridview->setContentX(-400);
+ model.removeItems(0, 4);
+ QTest::qWait(100);
+ gridview->setContentX(-240+50);
+ gridview->returnToBounds();
+ QCOMPARE(gridview->xOrigin(), -100.);
+ QTRY_COMPARE(gridview->contentX(), -240-70.);
+
+ // reduce left margin (i.e. right side due to RTL)
+ pos = gridview->contentX();
+ gridview->setLeftMargin(20);
+ QCOMPARE(gridview->xOrigin(), -100.);
+ QTRY_COMPARE(gridview->contentX(), -240-80.);
+
+ // check end bound
+ gridview->positionViewAtEnd();
+ QCOMPARE(gridview->xOrigin(), 0.); // positionViewAtEnd() resets origin
+ pos = gridview->contentX();
+ gridview->setContentX(pos - 80);
+ gridview->returnToBounds();
+ QTRY_COMPARE(gridview->contentX(), pos - 50);
+
+ // reduce right margin (i.e. left side due to RTL)
+ pos = gridview->contentX();
+ gridview->setRightMargin(40);
+ QCOMPARE(gridview->xOrigin(), 0.);
+ QTRY_COMPARE(gridview->contentX(), pos+10);
+
+ delete canvas;
+ }
+}
+
QSGView *tst_QSGGridView::createView()
{
QSGView *canvas = new QSGView(0);
--- /dev/null
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ width: 240
+ height: 320
+ color: "#ffffff"
+
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ objectName: "wrapper"
+ height: 20
+ width: 240
+ Text {
+ text: index
+ }
+ Text {
+ x: 30
+ id: textName
+ objectName: "textName"
+ text: name
+ }
+ Text {
+ x: 120
+ id: textNumber
+ objectName: "textNumber"
+ text: number
+ }
+ Text {
+ x: 200
+ text: wrapper.y
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+ ListView {
+ id: list
+ objectName: "list"
+ anchors.fill: parent
+ topMargin: 30
+ bottomMargin: 50
+ model: testModel
+ delegate: myDelegate
+ }
+}
void onRemove_data();
void rightToLeft();
void test_mirroring();
+ void margins();
private:
template <class T> void items();
delete canvasB;
}
+void tst_QSGListView::margins()
+{
+ QSGView *canvas = createView();
+
+ TestModel2 model;
+ for (int i = 0; i < 50; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QDeclarativeContext *ctxt = canvas->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/margins.qml"));
+ canvas->show();
+ qApp->processEvents();
+
+ QSGListView *listview = findItem<QSGListView>(canvas->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+
+ QSGItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QCOMPARE(listview->contentY(), -30.);
+ QCOMPARE(listview->yOrigin(), 0.);
+
+ // check end bound
+ listview->positionViewAtEnd();
+ qreal pos = listview->contentY();
+ listview->setContentY(pos + 80);
+ listview->returnToBounds();
+ QTRY_COMPARE(listview->contentY(), pos + 50);
+
+ // remove item before visible and check that top margin is maintained
+ // and yOrigin is updated
+ listview->setContentY(100);
+ model.removeItem(1);
+ QTest::qWait(100);
+ listview->setContentY(-50);
+ listview->returnToBounds();
+ QCOMPARE(listview->yOrigin(), 20.);
+ QTRY_COMPARE(listview->contentY(), -10.);
+
+ // reduce top margin
+ listview->setTopMargin(20);
+ QCOMPARE(listview->yOrigin(), 20.);
+ QTRY_COMPARE(listview->contentY(), 0.);
+
+ // check end bound
+ listview->positionViewAtEnd();
+ pos = listview->contentY();
+ listview->setContentY(pos + 80);
+ listview->returnToBounds();
+ QTRY_COMPARE(listview->contentY(), pos + 50);
+
+ // reduce bottom margin
+ pos = listview->contentY();
+ listview->setBottomMargin(40);
+ QCOMPARE(listview->yOrigin(), 20.);
+ QTRY_COMPARE(listview->contentY(), pos-10);
+
+ delete canvas;
+}
+
void tst_QSGListView::qListModelInterface_items()
{
items<TestModel>();