summaryrefslogtreecommitdiffstats
path: root/src/declarative/graphicsitems
diff options
context:
space:
mode:
authorDavid Boddie <david.boddie@nokia.com>2011-03-22 13:03:11 (GMT)
committerDavid Boddie <david.boddie@nokia.com>2011-03-22 13:03:11 (GMT)
commitacc903853d5ac54d646d324b7386c998bc07d464 (patch)
treef2ed3ccc611cebb70a4af7920a0fd0eec4ba5d73 /src/declarative/graphicsitems
parent56b4ada44ea5bfa1c4ee669aa00e9ae960965fe3 (diff)
parentbf95c0ed87bf8a2ccd0a3d57ed81b8ae8fb8c4f2 (diff)
downloadQt-acc903853d5ac54d646d324b7386c998bc07d464.zip
Qt-acc903853d5ac54d646d324b7386c998bc07d464.tar.gz
Qt-acc903853d5ac54d646d324b7386c998bc07d464.tar.bz2
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/qt into 4.7
Conflicts: doc/src/declarative/declarativeui.qdoc doc/src/examples/qml-examples.qdoc
Diffstat (limited to 'src/declarative/graphicsitems')
-rw-r--r--src/declarative/graphicsitems/qdeclarativeanchors.cpp97
-rw-r--r--src/declarative/graphicsitems/qdeclarativeanchors_p.h5
-rw-r--r--src/declarative/graphicsitems/qdeclarativeanchors_p_p.h1
-rw-r--r--src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp25
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflickable.cpp8
-rw-r--r--src/declarative/graphicsitems/qdeclarativegridview.cpp585
-rw-r--r--src/declarative/graphicsitems/qdeclarativegridview_p.h15
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimage.cpp17
-rw-r--r--src/declarative/graphicsitems/qdeclarativeimagebase.cpp2
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem.cpp209
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem_p.h54
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp1
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview.cpp491
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview_p.h14
-rw-r--r--src/declarative/graphicsitems/qdeclarativepathview.cpp2
-rw-r--r--src/declarative/graphicsitems/qdeclarativepincharea.cpp17
-rw-r--r--src/declarative/graphicsitems/qdeclarativepincharea_p_p.h5
-rw-r--r--src/declarative/graphicsitems/qdeclarativepositioners.cpp136
-rw-r--r--src/declarative/graphicsitems/qdeclarativepositioners_p.h15
-rw-r--r--src/declarative/graphicsitems/qdeclarativepositioners_p_p.h30
-rw-r--r--src/declarative/graphicsitems/qdeclarativerectangle.cpp4
-rw-r--r--src/declarative/graphicsitems/qdeclarativetext.cpp276
-rw-r--r--src/declarative/graphicsitems/qdeclarativetext_p.h6
-rw-r--r--src/declarative/graphicsitems/qdeclarativetext_p_p.h10
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextedit.cpp128
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextedit_p.h7
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextedit_p_p.h9
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextinput.cpp158
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextinput_p.h8
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextinput_p_p.h26
30 files changed, 1831 insertions, 530 deletions
diff --git a/src/declarative/graphicsitems/qdeclarativeanchors.cpp b/src/declarative/graphicsitems/qdeclarativeanchors.cpp
index 444bbd4..5ff6d2c 100644
--- a/src/declarative/graphicsitems/qdeclarativeanchors.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeanchors.cpp
@@ -175,16 +175,19 @@ QDeclarativeAnchors::~QDeclarativeAnchors()
void QDeclarativeAnchorsPrivate::fillChanged()
{
+ Q_Q(QDeclarativeAnchors);
if (!fill || !isItemComplete())
return;
if (updatingFill < 2) {
++updatingFill;
+ qreal horizontalMargin = q->mirrored() ? rightMargin : leftMargin;
+
if (fill == item->parentItem()) { //child-parent
- setItemPos(QPointF(leftMargin, topMargin));
+ setItemPos(QPointF(horizontalMargin, topMargin));
} else if (fill->parentItem() == item->parentItem()) { //siblings
- setItemPos(QPointF(fill->x()+leftMargin, fill->y()+topMargin));
+ setItemPos(QPointF(fill->x()+horizontalMargin, fill->y()+topMargin));
}
QGraphicsItemPrivate *fillPrivate = QGraphicsItemPrivate::get(fill);
setItemSize(QSizeF(fillPrivate->width()-leftMargin-rightMargin, fillPrivate->height()-topMargin-bottomMargin));
@@ -199,18 +202,21 @@ void QDeclarativeAnchorsPrivate::fillChanged()
void QDeclarativeAnchorsPrivate::centerInChanged()
{
+ Q_Q(QDeclarativeAnchors);
if (!centerIn || fill || !isItemComplete())
return;
if (updatingCenterIn < 2) {
++updatingCenterIn;
+
+ qreal effectiveHCenterOffset = q->mirrored() ? -hCenterOffset : hCenterOffset;
if (centerIn == item->parentItem()) {
- QPointF p(hcenter(item->parentItem()) - hcenter(item) + hCenterOffset,
+ QPointF p(hcenter(item->parentItem()) - hcenter(item) + effectiveHCenterOffset,
vcenter(item->parentItem()) - vcenter(item) + vCenterOffset);
setItemPos(p);
} else if (centerIn->parentItem() == item->parentItem()) {
- QPointF p(centerIn->x() + hcenter(centerIn) - hcenter(item) + hCenterOffset,
+ QPointF p(centerIn->x() + hcenter(centerIn) - hcenter(item) + effectiveHCenterOffset,
centerIn->y() + vcenter(centerIn) - vcenter(item) + vCenterOffset);
setItemPos(p);
}
@@ -311,6 +317,13 @@ void QDeclarativeAnchors::componentComplete()
d->componentComplete = true;
}
+bool QDeclarativeAnchors::mirrored()
+{
+ Q_D(QDeclarativeAnchors);
+ QGraphicsItemPrivate * itemPrivate = QGraphicsItemPrivate::get(d->item);
+ return itemPrivate->isDeclarativeItem ? static_cast<QDeclarativeItemPrivate *>(itemPrivate)->effectiveLayoutMirror : false;
+}
+
void QDeclarativeAnchorsPrivate::setItemHeight(qreal v)
{
updatingMe = true;
@@ -570,58 +583,94 @@ void QDeclarativeAnchorsPrivate::updateVerticalAnchors()
}
}
+inline QDeclarativeAnchorLine::AnchorLine reverseAnchorLine(QDeclarativeAnchorLine::AnchorLine anchorLine) {
+ if (anchorLine == QDeclarativeAnchorLine::Left) {
+ return QDeclarativeAnchorLine::Right;
+ } else if (anchorLine == QDeclarativeAnchorLine::Right) {
+ return QDeclarativeAnchorLine::Left;
+ } else {
+ return anchorLine;
+ }
+}
+
void QDeclarativeAnchorsPrivate::updateHorizontalAnchors()
{
+ Q_Q(QDeclarativeAnchors);
if (fill || centerIn || !isItemComplete())
return;
- if (updatingHorizontalAnchor < 2) {
+ if (updatingHorizontalAnchor < 3) {
++updatingHorizontalAnchor;
+ qreal effectiveRightMargin, effectiveLeftMargin, effectiveHorizontalCenterOffset;
+ QDeclarativeAnchorLine effectiveLeft, effectiveRight, effectiveHorizontalCenter;
+ QDeclarativeAnchors::Anchor effectiveLeftAnchor, effectiveRightAnchor;
+ if (q->mirrored()) {
+ effectiveLeftAnchor = QDeclarativeAnchors::RightAnchor;
+ effectiveRightAnchor = QDeclarativeAnchors::LeftAnchor;
+ effectiveLeft.item = right.item;
+ effectiveLeft.anchorLine = reverseAnchorLine(right.anchorLine);
+ effectiveRight.item = left.item;
+ effectiveRight.anchorLine = reverseAnchorLine(left.anchorLine);
+ effectiveHorizontalCenter.item = hCenter.item;
+ effectiveHorizontalCenter.anchorLine = reverseAnchorLine(hCenter.anchorLine);
+ effectiveLeftMargin = rightMargin;
+ effectiveRightMargin = leftMargin;
+ effectiveHorizontalCenterOffset = -hCenterOffset;
+ } else {
+ effectiveLeftAnchor = QDeclarativeAnchors::LeftAnchor;
+ effectiveRightAnchor = QDeclarativeAnchors::RightAnchor;
+ effectiveLeft = left;
+ effectiveRight = right;
+ effectiveHorizontalCenter = hCenter;
+ effectiveLeftMargin = leftMargin;
+ effectiveRightMargin = rightMargin;
+ effectiveHorizontalCenterOffset = hCenterOffset;
+ }
+
QGraphicsItemPrivate *itemPrivate = QGraphicsItemPrivate::get(item);
- if (usedAnchors & QDeclarativeAnchors::LeftAnchor) {
+ if (usedAnchors & effectiveLeftAnchor) {
//Handle stretching
bool invalid = true;
qreal width = 0.0;
- if (usedAnchors & QDeclarativeAnchors::RightAnchor) {
- invalid = calcStretch(left, right, leftMargin, -rightMargin, QDeclarativeAnchorLine::Left, width);
+ if (usedAnchors & effectiveRightAnchor) {
+ invalid = calcStretch(effectiveLeft, effectiveRight, effectiveLeftMargin, -effectiveRightMargin, QDeclarativeAnchorLine::Left, width);
} else if (usedAnchors & QDeclarativeAnchors::HCenterAnchor) {
- invalid = calcStretch(left, hCenter, leftMargin, hCenterOffset, QDeclarativeAnchorLine::Left, width);
+ invalid = calcStretch(effectiveLeft, effectiveHorizontalCenter, effectiveLeftMargin, effectiveHorizontalCenterOffset, QDeclarativeAnchorLine::Left, width);
width *= 2;
}
if (!invalid)
setItemWidth(width);
//Handle left
- if (left.item == item->parentItem()) {
- setItemX(adjustedPosition(left.item, left.anchorLine) + leftMargin);
- } else if (left.item->parentItem() == item->parentItem()) {
- setItemX(position(left.item, left.anchorLine) + leftMargin);
+ if (effectiveLeft.item == item->parentItem()) {
+ setItemX(adjustedPosition(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin);
+ } else if (effectiveLeft.item->parentItem() == item->parentItem()) {
+ setItemX(position(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin);
}
- } else if (usedAnchors & QDeclarativeAnchors::RightAnchor) {
+ } else if (usedAnchors & effectiveRightAnchor) {
//Handle stretching (left + right case is handled in updateLeftAnchor)
if (usedAnchors & QDeclarativeAnchors::HCenterAnchor) {
qreal width = 0.0;
- bool invalid = calcStretch(hCenter, right, hCenterOffset, -rightMargin,
+ bool invalid = calcStretch(effectiveHorizontalCenter, effectiveRight, effectiveHorizontalCenterOffset, -effectiveRightMargin,
QDeclarativeAnchorLine::Left, width);
if (!invalid)
setItemWidth(width*2);
}
//Handle right
- if (right.item == item->parentItem()) {
- setItemX(adjustedPosition(right.item, right.anchorLine) - itemPrivate->width() - rightMargin);
- } else if (right.item->parentItem() == item->parentItem()) {
- setItemX(position(right.item, right.anchorLine) - itemPrivate->width() - rightMargin);
+ if (effectiveRight.item == item->parentItem()) {
+ setItemX(adjustedPosition(effectiveRight.item, effectiveRight.anchorLine) - itemPrivate->width() - effectiveRightMargin);
+ } else if (effectiveRight.item->parentItem() == item->parentItem()) {
+ setItemX(position(effectiveRight.item, effectiveRight.anchorLine) - itemPrivate->width() - effectiveRightMargin);
}
} else if (usedAnchors & QDeclarativeAnchors::HCenterAnchor) {
//Handle hCenter
- if (hCenter.item == item->parentItem()) {
- setItemX(adjustedPosition(hCenter.item, hCenter.anchorLine) - hcenter(item) + hCenterOffset);
- } else if (hCenter.item->parentItem() == item->parentItem()) {
- setItemX(position(hCenter.item, hCenter.anchorLine) - hcenter(item) + hCenterOffset);
+ if (effectiveHorizontalCenter.item == item->parentItem()) {
+ setItemX(adjustedPosition(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset);
+ } else if (effectiveHorizontalCenter.item->parentItem() == item->parentItem()) {
+ setItemX(position(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset);
}
}
-
--updatingHorizontalAnchor;
} else {
// ### Make this certain :)
diff --git a/src/declarative/graphicsitems/qdeclarativeanchors_p.h b/src/declarative/graphicsitems/qdeclarativeanchors_p.h
index d2c0a89..388d6b9 100644
--- a/src/declarative/graphicsitems/qdeclarativeanchors_p.h
+++ b/src/declarative/graphicsitems/qdeclarativeanchors_p.h
@@ -79,6 +79,7 @@ class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeAnchors : public QObject
Q_PROPERTY(qreal baselineOffset READ baselineOffset WRITE setBaselineOffset NOTIFY baselineOffsetChanged)
Q_PROPERTY(QGraphicsObject *fill READ fill WRITE setFill RESET resetFill NOTIFY fillChanged)
Q_PROPERTY(QGraphicsObject *centerIn READ centerIn WRITE setCenterIn RESET resetCenterIn NOTIFY centerInChanged)
+ Q_PROPERTY(bool mirrored READ mirrored NOTIFY mirroredChanged REVISION 1)
public:
QDeclarativeAnchors(QObject *parent=0);
@@ -163,6 +164,8 @@ public:
void classBegin();
void componentComplete();
+ bool mirrored();
+
Q_SIGNALS:
void leftChanged();
void rightChanged();
@@ -181,9 +184,11 @@ Q_SIGNALS:
void verticalCenterOffsetChanged();
void horizontalCenterOffsetChanged();
void baselineOffsetChanged();
+ Q_REVISION(1) void mirroredChanged();
private:
friend class QDeclarativeItem;
+ friend class QDeclarativeItemPrivate;
friend class QDeclarativeGraphicsWidget;
Q_DISABLE_COPY(QDeclarativeAnchors)
Q_DECLARE_PRIVATE(QDeclarativeAnchors)
diff --git a/src/declarative/graphicsitems/qdeclarativeanchors_p_p.h b/src/declarative/graphicsitems/qdeclarativeanchors_p_p.h
index c4508e0..d8d2f15 100644
--- a/src/declarative/graphicsitems/qdeclarativeanchors_p_p.h
+++ b/src/declarative/graphicsitems/qdeclarativeanchors_p_p.h
@@ -133,6 +133,7 @@ public:
bool checkVAnchorValid(QDeclarativeAnchorLine anchor) const;
bool calcStretch(const QDeclarativeAnchorLine &edge1, const QDeclarativeAnchorLine &edge2, qreal offset1, qreal offset2, QDeclarativeAnchorLine::AnchorLine line, qreal &stretch);
+ bool isMirrored() const;
void updateHorizontalAnchors();
void updateVerticalAnchors();
void fillChanged();
diff --git a/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp b/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp
index 016b87d..8cc8165 100644
--- a/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp
@@ -231,9 +231,18 @@ void QDeclarativeAnimatedImage::load()
{
Q_D(QDeclarativeAnimatedImage);
+ QDeclarativeImageBase::Status oldStatus = d->status;
+ qreal oldProgress = d->progress;
+
if (d->url.isEmpty()) {
delete d->_movie;
+ d->setPixmap(QPixmap());
+ d->progress = 0;
d->status = Null;
+ if (d->status != oldStatus)
+ emit statusChanged(d->status);
+ if (d->progress != oldProgress)
+ emit progressChanged(d->progress);
} else {
#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url);
@@ -245,7 +254,8 @@ void QDeclarativeAnimatedImage::load()
delete d->_movie;
d->_movie = 0;
d->status = Error;
- emit statusChanged(d->status);
+ if (d->status != oldStatus)
+ emit statusChanged(d->status);
return;
}
connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
@@ -262,20 +272,25 @@ void QDeclarativeAnimatedImage::load()
d->setPixmap(d->_movie->currentPixmap());
d->status = Ready;
d->progress = 1.0;
- emit statusChanged(d->status);
- emit sourceChanged(d->url);
- emit progressChanged(d->progress);
+ if (d->status != oldStatus)
+ emit statusChanged(d->status);
+ if (d->progress != oldProgress)
+ emit progressChanged(d->progress);
return;
}
#endif
d->status = Loading;
+ d->progress = 0;
+ emit statusChanged(d->status);
+ emit progressChanged(d->progress);
QNetworkRequest req(d->url);
req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
d->reply = qmlEngine(this)->networkAccessManager()->get(req);
QObject::connect(d->reply, SIGNAL(finished()),
this, SLOT(movieRequestFinished()));
+ QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
}
- emit statusChanged(d->status);
}
#define ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION 16
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp
index 61f9513..511f789 100644
--- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp
@@ -1430,8 +1430,10 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
QGraphicsScene *s = scene();
QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
+ QGraphicsItem *grabberItem = s ? s->mouseGrabberItem() : 0;
+ bool disabledItem = grabberItem && !grabberItem->isEnabled();
bool stealThisEvent = d->stealMouse;
- if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
mouseEvent.setAccepted(false);
for (int i = 0x1; i <= 0x10; i <<= 1) {
if (event->buttons() & i) {
@@ -1478,12 +1480,12 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
break;
}
grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
- if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) {
+ if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || disabledItem) {
d->clearDelayedPress();
grabMouse();
}
- return stealThisEvent || d->delayedPressEvent;
+ return stealThisEvent || d->delayedPressEvent || disabledItem;
} else if (d->lastPosTime.isValid()) {
d->lastPosTime.invalidate();
}
diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp
index fd281fa..546f75e 100644
--- a/src/declarative/graphicsitems/qdeclarativegridview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp
@@ -68,19 +68,60 @@ public:
}
~FxGridItem() {}
- qreal rowPos() const { return (view->flow() == QDeclarativeGridView::LeftToRight ? item->y() : item->x()); }
- qreal colPos() const { return (view->flow() == QDeclarativeGridView::LeftToRight ? item->x() : item->y()); }
+ qreal rowPos() const {
+ qreal rowPos = 0;
+ if (view->flow() == QDeclarativeGridView::LeftToRight) {
+ rowPos = item->y();
+ } else {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft)
+ rowPos = -view->cellWidth()-item->x();
+ else
+ rowPos = item->x();
+ }
+ return rowPos;
+ }
+ qreal colPos() const {
+ qreal colPos = 0;
+ if (view->flow() == QDeclarativeGridView::LeftToRight) {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
+ int colSize = view->cellWidth();
+ int columns = view->width()/colSize;
+ colPos = colSize * (columns-1) - item->x();
+ } else {
+ colPos = item->x();
+ }
+ } else {
+ colPos = item->y();
+ }
+
+ return colPos;
+ }
+
qreal endRowPos() const {
- return view->flow() == QDeclarativeGridView::LeftToRight
- ? item->y() + view->cellHeight() - 1
- : item->x() + view->cellWidth() - 1;
+ if (view->flow() == QDeclarativeGridView::LeftToRight) {
+ return item->y() + view->cellHeight() - 1;
+ } else {
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft)
+ return -item->x() - 1;
+ else
+ return item->x() + view->cellWidth() - 1;
+ }
}
void setPosition(qreal col, qreal row) {
- if (view->flow() == QDeclarativeGridView::LeftToRight) {
- item->setPos(QPointF(col, row));
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
+ if (view->flow() == QDeclarativeGridView::LeftToRight) {
+ int columns = view->width()/view->cellWidth();
+ item->setPos(QPointF((view->cellWidth() * (columns-1) - col), row));
+ } else {
+ item->setPos(QPointF(-view->cellWidth()-row, col));
+ }
} else {
- item->setPos(QPointF(row, col));
+ if (view->flow() == QDeclarativeGridView::LeftToRight)
+ item->setPos(QPointF(col, row));
+ else
+ item->setPos(QPointF(row, col));
}
+
}
bool contains(qreal x, qreal y) const {
return (x >= item->x() && x < item->x() + view->cellWidth() &&
@@ -101,10 +142,12 @@ class QDeclarativeGridViewPrivate : public QDeclarativeFlickablePrivate
public:
QDeclarativeGridViewPrivate()
- : currentItem(0), flow(QDeclarativeGridView::LeftToRight)
+ : currentItem(0), layoutDirection(Qt::LeftToRight), flow(QDeclarativeGridView::LeftToRight)
, visibleIndex(0) , currentIndex(-1)
, cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1), itemCount(0)
- , highlightRangeStart(0), highlightRangeEnd(0), highlightRange(QDeclarativeGridView::NoHighlightRange)
+ , highlightRangeStart(0), highlightRangeEnd(0)
+ , highlightRangeStartValid(false), highlightRangeEndValid(false)
+ , highlightRange(QDeclarativeGridView::NoHighlightRange)
, highlightComponent(0), highlight(0), trackedItem(0)
, moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0)
, highlightMoveDuration(150)
@@ -144,35 +187,71 @@ public:
return 0;
}
+ bool isRightToLeftTopToBottom() const {
+ Q_Q(const QDeclarativeGridView);
+ return flow == QDeclarativeGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft;
+ }
+
+ void regenerate() {
+ Q_Q(QDeclarativeGridView);
+ if (q->isComponentComplete()) {
+ clear();
+ updateGrid();
+ q->refill();
+ updateCurrent(currentIndex);
+ }
+ }
+
+ void mirrorChange() {
+ Q_Q(QDeclarativeGridView);
+ regenerate();
+ emit q->effectiveLayoutDirectionChanged();
+ }
+
qreal position() const {
Q_Q(const QDeclarativeGridView);
return flow == QDeclarativeGridView::LeftToRight ? q->contentY() : q->contentX();
}
void setPosition(qreal pos) {
Q_Q(QDeclarativeGridView);
- if (flow == QDeclarativeGridView::LeftToRight)
+ if (flow == QDeclarativeGridView::LeftToRight) {
q->QDeclarativeFlickable::setContentY(pos);
- else
- q->QDeclarativeFlickable::setContentX(pos);
+ q->QDeclarativeFlickable::setContentX(0);
+ } else {
+ if (q->effectiveLayoutDirection() == Qt::LeftToRight)
+ q->QDeclarativeFlickable::setContentX(pos);
+ else
+ q->QDeclarativeFlickable::setContentX(-pos-size());
+ q->QDeclarativeFlickable::setContentY(0);
+ }
}
int size() const {
Q_Q(const QDeclarativeGridView);
return flow == QDeclarativeGridView::LeftToRight ? q->height() : q->width();
}
- qreal startPosition() const {
+ qreal originPosition() const {
qreal pos = 0;
if (!visibleItems.isEmpty())
pos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
return pos;
}
- qreal endPosition() const {
+ qreal lastPosition() const {
qreal pos = 0;
if (model && model->count())
pos = rowPosAt(model->count() - 1) + rowSize();
return pos;
}
+ qreal startPosition() const {
+ return isRightToLeftTopToBottom() ? -lastPosition()+1 : originPosition();
+ }
+
+ qreal endPosition() const {
+ return isRightToLeftTopToBottom() ? -originPosition()+1 : lastPosition();
+
+ }
+
bool isValid() const {
return model && model->count() && model->isValid();
}
@@ -227,7 +306,7 @@ public:
}
FxGridItem *firstVisibleItem() const {
- const qreal pos = position();
+ const qreal pos = isRightToLeftTopToBottom() ? -position()-size() : position();
for (int i = 0; i < visibleItems.count(); ++i) {
FxGridItem *item = visibleItems.at(i);
if (item->index != -1 && item->endRowPos() > pos)
@@ -237,15 +316,12 @@ public:
}
int lastVisibleIndex() const {
- int lastIndex = -1;
- for (int i = visibleItems.count()-1; i >= 0; --i) {
- FxGridItem *gridItem = visibleItems.at(i);
- if (gridItem->index != -1) {
- lastIndex = gridItem->index;
- break;
- }
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItem *item = visibleItems.at(i);
+ if (item->index != -1)
+ return item->index;
}
- return lastIndex;
+ return -1;
}
// Map a model index to visibleItems list index.
@@ -271,8 +347,15 @@ public:
pos += rowSize()/2;
snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
snapPos = pos - fmodf(pos - snapPos, qreal(rowSize()));
- qreal maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
- qreal minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
+ qreal maxExtent;
+ qreal minExtent;
+ if (isRightToLeftTopToBottom()) {
+ maxExtent = q->minXExtent();
+ minExtent = q->maxXExtent();
+ } else {
+ maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
+ minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
+ }
if (snapPos > maxExtent)
snapPos = maxExtent;
if (snapPos < minExtent)
@@ -363,6 +446,7 @@ public:
QList<FxGridItem*> visibleItems;
QHash<QDeclarativeItem*,int> unrequestedItems;
FxGridItem *currentItem;
+ Qt::LayoutDirection layoutDirection;
QDeclarativeGridView::Flow flow;
int visibleIndex;
int currentIndex;
@@ -373,6 +457,8 @@ public:
int itemCount;
qreal highlightRangeStart;
qreal highlightRangeEnd;
+ bool highlightRangeStartValid;
+ bool highlightRangeEndValid;
QDeclarativeGridView::HighlightRangeMode highlightRange;
QDeclarativeComponent *highlightComponent;
FxGridItem *highlight;
@@ -554,7 +640,7 @@ void QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer)
if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create
while (visibleItems.count() > 1
&& (item = visibleItems.first())
- && item->endRowPos() < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
+ && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) {
if (item->attached->delayRemove())
break;
// qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
@@ -596,12 +682,14 @@ void QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer)
void QDeclarativeGridViewPrivate::updateGrid()
{
Q_Q(QDeclarativeGridView);
+
columns = (int)qMax((flow == QDeclarativeGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.));
if (isValid()) {
if (flow == QDeclarativeGridView::LeftToRight)
q->setContentHeight(endPosition() - startPosition());
else
- q->setContentWidth(endPosition() - startPosition());
+ q->setContentWidth(lastPosition() - originPosition());
+ setPosition(0);
}
}
@@ -669,10 +757,14 @@ void QDeclarativeGridViewPrivate::updateUnrequestedPositions()
{
QHash<QDeclarativeItem*,int>::const_iterator it;
for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
+ QDeclarativeItem *item = it.key();
if (flow == QDeclarativeGridView::LeftToRight) {
- it.key()->setPos(QPointF(colPosAt(*it), rowPosAt(*it)));
+ item->setPos(QPointF(colPosAt(*it), rowPosAt(*it)));
} else {
- it.key()->setPos(QPointF(rowPosAt(*it), colPosAt(*it)));
+ if (isRightToLeftTopToBottom())
+ item->setPos(QPointF(-rowPosAt(*it)-item->width(), colPosAt(*it)));
+ else
+ item->setPos(QPointF(rowPosAt(*it), colPosAt(*it)));
}
}
}
@@ -837,23 +929,30 @@ void QDeclarativeGridViewPrivate::updateFooter()
}
}
if (footer) {
+ qreal colOffset = 0;
+ qreal rowOffset;
+ if (isRightToLeftTopToBottom()) {
+ rowOffset = footer->item->width()-cellWidth;
+ } else {
+ rowOffset = 0;
+ if (q->effectiveLayoutDirection() == Qt::RightToLeft)
+ colOffset = footer->item->width()-cellWidth;
+ }
if (visibleItems.count()) {
- qreal endPos = endPosition();
+ qreal endPos = lastPosition();
if (lastVisibleIndex() == model->count()-1) {
- footer->setPosition(0, endPos);
+ footer->setPosition(colOffset, endPos + rowOffset);
} else {
- qreal visiblePos = position() + q->height();
- if (endPos <= visiblePos || footer->endRowPos() < endPos)
- footer->setPosition(0, endPos);
+ qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size();
+ if (endPos <= visiblePos || footer->endRowPos() < endPos + rowOffset)
+ footer->setPosition(colOffset, endPos + rowOffset);
}
} else {
qreal endPos = 0;
if (header) {
- endPos += flow == QDeclarativeGridView::LeftToRight
- ? header->item->height()
- : header->item->width();
+ endPos += flow == QDeclarativeGridView::LeftToRight ? header->item->height() : header->item->width();
}
- footer->setPosition(0, endPos);
+ footer->setPosition(colOffset, endPos);
}
}
}
@@ -883,16 +982,27 @@ void QDeclarativeGridViewPrivate::updateHeader()
}
}
if (header) {
+ qreal colOffset = 0;
+ qreal rowOffset;
+ if (isRightToLeftTopToBottom()) {
+ rowOffset = -cellWidth;
+ } else {
+ rowOffset = -headerSize();
+ if (q->effectiveLayoutDirection() == Qt::RightToLeft)
+ colOffset = header->item->width()-cellWidth;
+ }
if (visibleItems.count()) {
- qreal startPos = startPosition();
+ qreal startPos = originPosition();
if (visibleIndex == 0) {
- header->setPosition(0, startPos - headerSize());
+ header->setPosition(colOffset, startPos + rowOffset);
} else {
- if (position() <= startPos || header->rowPos() > startPos - headerSize())
- header->setPosition(0, startPos - headerSize());
+ qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position();
+ qreal headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
+ if (tempPos <= startPos || headerPos > startPos + rowOffset)
+ header->setPosition(colOffset, startPos + rowOffset);
}
} else {
- header->setPosition(0, 0);
+ header->setPosition(colOffset, 0);
}
}
}
@@ -914,21 +1024,46 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m
fixupMode = moveReason == Mouse ? fixupMode : Immediate;
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal viewPos;
+ if (isRightToLeftTopToBottom()) {
+ // Handle Right-To-Left exceptions
+ viewPos = -position()-size();
+ highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
+ highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd;
+ } else {
+ viewPos = position();
+ highlightStart = highlightRangeStart;
+ highlightEnd = highlightRangeEnd;
+ }
+
if (snapMode != QDeclarativeGridView::NoSnap) {
- FxGridItem *topItem = snapItemAt(position()+highlightRangeStart);
- FxGridItem *bottomItem = snapItemAt(position()+highlightRangeEnd);
+ qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position();
+ FxGridItem *topItem = snapItemAt(tempPosition+highlightStart);
+ FxGridItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
qreal pos;
if (topItem && bottomItem && haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) {
- qreal topPos = qMin(topItem->rowPos() - highlightRangeStart, -maxExtent);
- qreal bottomPos = qMax(bottomItem->rowPos() - highlightRangeEnd, -minExtent);
+ qreal topPos = qMin(topItem->rowPos() - highlightStart, -maxExtent);
+ qreal bottomPos = qMax(bottomItem->rowPos() - highlightEnd, -minExtent);
pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos;
} else if (topItem) {
- if (topItem->index == 0 && header && position()+highlightRangeStart < header->rowPos()+headerSize()/2)
- pos = header->rowPos() - highlightRangeStart;
- else
- pos = qMax(qMin(topItem->rowPos() - highlightRangeStart, -maxExtent), -minExtent);
+ qreal headerPos = 0;
+ if (header)
+ headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos();
+ if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2) {
+ pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart;
+ } else {
+ if (isRightToLeftTopToBottom())
+ pos = qMax(qMin(-topItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
+ else
+ pos = qMax(qMin(topItem->rowPos() - highlightStart, -maxExtent), -minExtent);
+ }
} else if (bottomItem) {
- pos = qMax(qMin(bottomItem->rowPos() - highlightRangeStart, -maxExtent), -minExtent);
+ if (isRightToLeftTopToBottom())
+ pos = qMax(qMin(-bottomItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent);
+ else
+ pos = qMax(qMin(bottomItem->rowPos() - highlightStart, -maxExtent), -minExtent);
} else {
QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
return;
@@ -936,12 +1071,15 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m
if (currentItem && haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) {
updateHighlight();
qreal currPos = currentItem->rowPos();
- if (pos < currPos + rowSize() - highlightRangeEnd)
- pos = currPos + rowSize() - highlightRangeEnd;
- if (pos > currPos - highlightRangeStart)
- pos = currPos - highlightRangeStart;
+ if (isRightToLeftTopToBottom())
+ pos = -pos-size(); // Transform Pos if required
+ if (pos < currPos + rowSize() - highlightEnd)
+ pos = currPos + rowSize() - highlightEnd;
+ if (pos > currPos - highlightStart)
+ pos = currPos - highlightStart;
+ if (isRightToLeftTopToBottom())
+ pos = -pos-size(); // Untransform
}
-
qreal dist = qAbs(data.move + pos);
if (dist > 0) {
timeline.reset(data.move);
@@ -957,12 +1095,12 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m
if (currentItem) {
updateHighlight();
qreal pos = currentItem->rowPos();
- qreal viewPos = position();
- if (viewPos < pos + rowSize() - highlightRangeEnd)
- viewPos = pos + rowSize() - highlightRangeEnd;
- if (viewPos > pos - highlightRangeStart)
- viewPos = pos - highlightRangeStart;
-
+ if (viewPos < pos + rowSize() - highlightEnd)
+ viewPos = pos + rowSize() - highlightEnd;
+ if (viewPos > pos - highlightStart)
+ viewPos = pos - highlightStart;
+ if (isRightToLeftTopToBottom())
+ viewPos = -viewPos-size();
timeline.reset(data.move);
if (viewPos != position()) {
if (fixupMode != Immediate) {
@@ -992,12 +1130,14 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
return;
}
qreal maxDistance = 0;
- // -ve velocity means list is moving up
+ qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value();
+ // -ve velocity means list is moving up/left
if (velocity > 0) {
if (data.move.value() < minExtent) {
if (snapMode == QDeclarativeGridView::SnapOneRow) {
- if (FxGridItem *item = firstVisibleItem())
- maxDistance = qAbs(item->rowPos() + data.move.value());
+ if (FxGridItem *item = firstVisibleItem()) {
+ maxDistance = qAbs(item->rowPos() + dataValue);
+ }
} else {
maxDistance = qAbs(minExtent - data.move.value());
}
@@ -1007,8 +1147,8 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
} else {
if (data.move.value() > maxExtent) {
if (snapMode == QDeclarativeGridView::SnapOneRow) {
- qreal pos = snapPosAt(-data.move.value()) + rowSize();
- maxDistance = qAbs(pos + data.move.value());
+ qreal pos = snapPosAt(-dataValue) + (isRightToLeftTopToBottom() ? 0 : rowSize());
+ maxDistance = qAbs(pos + dataValue);
} else {
maxDistance = qAbs(maxExtent - data.move.value());
}
@@ -1016,7 +1156,10 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
data.flickTarget = maxExtent;
}
+
bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds;
+ qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
+
if (maxDistance > 0 || overShoot) {
// This mode requires the grid to stop exactly on a row boundary.
qreal v = velocity;
@@ -1035,7 +1178,9 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
dist = qMin(dist, maxDistance);
if (v > 0)
dist = -dist;
- data.flickTarget = -snapPosAt(-(data.move.value() - highlightRangeStart) + dist) + highlightRangeStart;
+ qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist;
+ data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+ data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget;
qreal adjDist = -data.flickTarget + data.move.value();
if (qAbs(adjDist) > qAbs(dist)) {
// Prevent painfully slow flicking - adjust velocity to suit flickDeceleration
@@ -1227,6 +1372,13 @@ QVariant QDeclarativeGridView::model() const
return d->modelVariant;
}
+// For internal use
+int QDeclarativeGridView::modelCount() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->model->count();
+}
+
void QDeclarativeGridView::setModel(const QVariant &model)
{
Q_D(QDeclarativeGridView);
@@ -1552,6 +1704,7 @@ qreal QDeclarativeGridView::preferredHighlightBegin() const
void QDeclarativeGridView::setPreferredHighlightBegin(qreal start)
{
Q_D(QDeclarativeGridView);
+ d->highlightRangeStartValid = true;
if (d->highlightRangeStart == start)
return;
d->highlightRangeStart = start;
@@ -1559,6 +1712,16 @@ void QDeclarativeGridView::setPreferredHighlightBegin(qreal start)
emit preferredHighlightBeginChanged();
}
+void QDeclarativeGridView::resetPreferredHighlightBegin()
+{
+ Q_D(QDeclarativeGridView);
+ d->highlightRangeStartValid = false;
+ if (d->highlightRangeStart == 0)
+ return;
+ d->highlightRangeStart = 0;
+ emit preferredHighlightBeginChanged();
+}
+
qreal QDeclarativeGridView::preferredHighlightEnd() const
{
Q_D(const QDeclarativeGridView);
@@ -1568,6 +1731,7 @@ qreal QDeclarativeGridView::preferredHighlightEnd() const
void QDeclarativeGridView::setPreferredHighlightEnd(qreal end)
{
Q_D(QDeclarativeGridView);
+ d->highlightRangeEndValid = true;
if (d->highlightRangeEnd == end)
return;
d->highlightRangeEnd = end;
@@ -1575,6 +1739,16 @@ void QDeclarativeGridView::setPreferredHighlightEnd(qreal end)
emit preferredHighlightEndChanged();
}
+void QDeclarativeGridView::resetPreferredHighlightEnd()
+{
+ Q_D(QDeclarativeGridView);
+ d->highlightRangeEndValid = false;
+ if (d->highlightRangeEnd == 0)
+ return;
+ d->highlightRangeEnd = 0;
+ emit preferredHighlightEndChanged();
+}
+
QDeclarativeGridView::HighlightRangeMode QDeclarativeGridView::highlightRangeMode() const
{
Q_D(const QDeclarativeGridView);
@@ -1591,6 +1765,60 @@ void QDeclarativeGridView::setHighlightRangeMode(HighlightRangeMode mode)
emit highlightRangeModeChanged();
}
+/*!
+ \qmlproperty enumeration GridView::layoutDirection
+ This property holds the layout direction of the grid.
+
+ Possible values:
+
+ \list
+ \o Qt.LeftToRight (default) - Items will be laid out starting in the top, left corner. The flow is
+ dependent on the \l GridView::flow property.
+ \o Qt.RightToLeft - Items will be laid out starting in the top, right corner. The flow is dependent
+ on the \l GridView:flow property.
+ \endlist
+
+ \bold Note: If GridView::flow is set to GridView.LeftToRight, this is not to be confused if
+ GridView::layoutDirection is set to Qt.RightToLeft. The GridView.LeftToRight flow value simply
+ indicates that the flow is horizontal.
+*/
+
+Qt::LayoutDirection QDeclarativeGridView::layoutDirection() const
+{
+ Q_D(const QDeclarativeGridView);
+ return d->layoutDirection;
+}
+
+void QDeclarativeGridView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QDeclarativeGridView);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ d->regenerate();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration GridView::effectiveLayoutDirection
+ This property holds the effective layout direction of the grid.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the grid will be mirrored. However, the
+ property \l {GridView::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa GridView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QDeclarativeGridView::effectiveLayoutDirection() const
+{
+ Q_D(const QDeclarativeGridView);
+ if (d->effectiveLayoutMirror)
+ return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
+ else
+ return d->layoutDirection;
+}
/*!
\qmlproperty enumeration GridView::flow
@@ -1623,10 +1851,7 @@ void QDeclarativeGridView::setFlow(Flow flow)
}
setContentX(0);
setContentY(0);
- d->clear();
- d->updateGrid();
- refill();
- d->updateCurrent(d->currentIndex);
+ d->regenerate();
emit flowChanged();
}
}
@@ -1893,11 +2118,23 @@ void QDeclarativeGridView::viewportMoved()
if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
// reposition highlight
qreal pos = d->highlight->rowPos();
- qreal viewPos = d->position();
- if (pos > viewPos + d->highlightRangeEnd - d->rowSize())
- pos = viewPos + d->highlightRangeEnd - d->rowSize();
- if (pos < viewPos + d->highlightRangeStart)
- pos = viewPos + d->highlightRangeStart;
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeftTopToBottom()) {
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ viewPos = -d->position()-d->size();
+ } else {
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ viewPos = d->position();
+ }
+ if (pos > viewPos + highlightEnd - d->rowSize())
+ pos = viewPos + highlightEnd - d->rowSize();
+ if (pos < viewPos + highlightStart)
+ pos = viewPos + highlightStart;
+
d->highlight->setPosition(d->highlight->colPos(), qRound(pos));
// update current index
@@ -1959,11 +2196,27 @@ qreal QDeclarativeGridView::minXExtent() const
if (d->flow == QDeclarativeGridView::LeftToRight)
return QDeclarativeFlickable::minXExtent();
qreal extent = -d->startPosition();
- if (d->header && d->visibleItems.count())
- extent += d->header->item->width();
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal endPositionFirstItem;
+ if (d->isRightToLeftTopToBottom()) {
+ endPositionFirstItem = d->rowPosAt(d->model->count()-1);
+ highlightStart = d->highlightRangeStartValid
+ ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
+ : d->size() - (d->lastPosition()-endPositionFirstItem);
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
+ if (d->footer && d->visibleItems.count())
+ extent += d->footer->item->width();
+ } else {
+ endPositionFirstItem = d->rowPosAt(0)+d->rowSize();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ if (d->header && d->visibleItems.count())
+ extent += d->header->item->width();
+ }
if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
- extent += d->highlightRangeStart;
- extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd));
+ extent += highlightStart;
+ extent = qMax(extent, -(endPositionFirstItem - highlightEnd));
}
return extent;
}
@@ -1974,17 +2227,38 @@ qreal QDeclarativeGridView::maxXExtent() const
if (d->flow == QDeclarativeGridView::LeftToRight)
return QDeclarativeFlickable::maxXExtent();
qreal extent;
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal lastItemPosition;
+ if (d->isRightToLeftTopToBottom()){
+ highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
+ lastItemPosition = d->endPosition();
+ } else {
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ if (d->model && d->model->count())
+ lastItemPosition = d->rowPosAt(d->model->count()-1);
+ }
if (!d->model || !d->model->count()) {
extent = 0;
- } if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
- extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart);
- if (d->highlightRangeEnd != d->highlightRangeStart)
- extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1));
+ } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
+ extent = -(lastItemPosition - highlightStart);
+ if (highlightEnd != highlightStart)
+ extent = d->isRightToLeftTopToBottom()
+ ? qMax(extent, -(d->endPosition() - highlightEnd + 1))
+ : qMin(extent, -(d->endPosition() - highlightEnd + 1));
} else {
extent = -(d->endPosition() - width());
}
- if (d->footer)
- extent -= d->footer->item->width();
+ if (d->isRightToLeftTopToBottom()) {
+ if (d->header)
+ extent -= d->header->item->width();
+ } else {
+ if (d->footer)
+ extent -= d->footer->item->width();
+ }
+
const qreal minX = minXExtent();
if (extent > minX)
extent = minX;
@@ -2097,15 +2371,30 @@ void QDeclarativeGridView::moveCurrentIndexLeft()
const int count = d->model ? d->model->count() : 0;
if (!count)
return;
- if (d->flow == QDeclarativeGridView::LeftToRight) {
- if (currentIndex() > 0 || d->wrap) {
- int index = currentIndex() - 1;
- setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+
+ if (effectiveLayoutDirection() == Qt::LeftToRight) {
+ if (d->flow == QDeclarativeGridView::LeftToRight) {
+ if (currentIndex() > 0 || d->wrap) {
+ int index = currentIndex() - 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ } else {
+ if (currentIndex() >= d->columns || d->wrap) {
+ int index = currentIndex() - d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
}
} else {
- if (currentIndex() >= d->columns || d->wrap) {
- int index = currentIndex() - d->columns;
- setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ if (d->flow == QDeclarativeGridView::LeftToRight) {
+ if (currentIndex() < count - 1 || d->wrap) {
+ int index = currentIndex() + 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ } else {
+ if (currentIndex() < count - d->columns || d->wrap) {
+ int index = currentIndex() + d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
}
}
}
@@ -2125,15 +2414,30 @@ void QDeclarativeGridView::moveCurrentIndexRight()
const int count = d->model ? d->model->count() : 0;
if (!count)
return;
- if (d->flow == QDeclarativeGridView::LeftToRight) {
- if (currentIndex() < count - 1 || d->wrap) {
- int index = currentIndex() + 1;
- setCurrentIndex((index >= 0 && index < count) ? index : 0);
+
+ if (effectiveLayoutDirection() == Qt::LeftToRight) {
+ if (d->flow == QDeclarativeGridView::LeftToRight) {
+ if (currentIndex() < count - 1 || d->wrap) {
+ int index = currentIndex() + 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
+ } else {
+ if (currentIndex() < count - d->columns || d->wrap) {
+ int index = currentIndex()+d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ }
}
} else {
- if (currentIndex() < count - d->columns || d->wrap) {
- int index = currentIndex()+d->columns;
- setCurrentIndex((index >= 0 && index < count) ? index : 0);
+ if (d->flow == QDeclarativeGridView::LeftToRight) {
+ if (currentIndex() > 0 || d->wrap) {
+ int index = currentIndex() - 1;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
+ } else {
+ if (currentIndex() >= d->columns || d->wrap) {
+ int index = currentIndex() - d->columns;
+ setCurrentIndex((index >= 0 && index < count) ? index : count-1);
+ }
}
}
}
@@ -2150,16 +2454,24 @@ void QDeclarativeGridViewPrivate::positionViewAtIndex(int index, int mode)
if (layoutScheduled)
layout();
- qreal pos = position();
+ qreal pos = isRightToLeftTopToBottom() ? -position() - size() : position();
FxGridItem *item = visibleItem(idx);
- qreal maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
+ qreal maxExtent;
+ if (flow == QDeclarativeGridView::LeftToRight)
+ maxExtent = -q->maxYExtent();
+ else
+ maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
+
if (!item) {
int itemPos = rowPosAt(idx);
// save the currently visible items in case any of them end up visible again
QList<FxGridItem*> oldVisible = visibleItems;
visibleItems.clear();
visibleIndex = idx - idx % columns;
- maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent();
+ if (flow == QDeclarativeGridView::LeftToRight)
+ maxExtent = -q->maxYExtent();
+ else
+ maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent();
setPosition(qMin(qreal(itemPos), maxExtent));
// now release the reference to all the old visible items.
for (int i = 0; i < oldVisible.count(); ++i)
@@ -2200,8 +2512,13 @@ void QDeclarativeGridViewPrivate::positionViewAtIndex(int index, int mode)
if (itemPos < pos)
pos = itemPos;
}
+
pos = qMin(pos, maxExtent);
- qreal minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent();
+ qreal minExtent;
+ if (flow == QDeclarativeGridView::LeftToRight)
+ minExtent = -q->minYExtent();
+ else
+ minExtent = isRightToLeftTopToBottom() ? q->maxXExtent()-size() : -q->minXExtent();
pos = qMax(pos, minExtent);
moveReason = QDeclarativeGridViewPrivate::Other;
q->cancelFlick();
@@ -2341,32 +2658,43 @@ void QDeclarativeGridView::trackedPositionChanged()
return;
if (d->moveReason == QDeclarativeGridViewPrivate::SetIndex) {
const qreal trackedPos = d->trackedItem->rowPos();
- const qreal viewPos = d->position();
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeftTopToBottom()) {
+ viewPos = -d->position()-d->size();
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ } else {
+ viewPos = d->position();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ }
qreal pos = viewPos;
if (d->haveHighlightRange) {
if (d->highlightRange == StrictlyEnforceRange) {
- if (trackedPos > pos + d->highlightRangeEnd - d->rowSize())
- pos = trackedPos - d->highlightRangeEnd + d->rowSize();
- if (trackedPos < pos + d->highlightRangeStart)
- pos = trackedPos - d->highlightRangeStart;
+ if (trackedPos > pos + highlightEnd - d->rowSize())
+ pos = trackedPos - highlightEnd + d->rowSize();
+ if (trackedPos < pos + highlightStart)
+ pos = trackedPos - highlightStart;
} else {
- if (trackedPos < d->startPosition() + d->highlightRangeStart) {
+ if (trackedPos < d->startPosition() + highlightStart) {
pos = d->startPosition();
- } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + d->highlightRangeEnd) {
+ } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + highlightEnd) {
pos = d->endPosition() - d->size() + 1;
if (pos < d->startPosition())
pos = d->startPosition();
} else {
- if (trackedPos < viewPos + d->highlightRangeStart) {
- pos = trackedPos - d->highlightRangeStart;
- } else if (trackedPos > viewPos + d->highlightRangeEnd - d->rowSize()) {
- pos = trackedPos - d->highlightRangeEnd + d->rowSize();
+ if (trackedPos < viewPos + highlightStart) {
+ pos = trackedPos - highlightStart;
+ } else if (trackedPos > viewPos + highlightEnd - d->rowSize()) {
+ pos = trackedPos - highlightEnd + d->rowSize();
}
}
}
} else {
if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) {
- pos = d->currentItem->rowPos() < trackedPos ? trackedPos : d->currentItem->rowPos();
+ pos = qMax(trackedPos, d->currentItem->rowPos());
} else if (d->trackedItem->endRowPos() >= viewPos + d->size()
&& d->currentItem->endRowPos() >= viewPos + d->size()) {
if (d->trackedItem->endRowPos() <= d->currentItem->endRowPos()) {
@@ -2434,7 +2762,8 @@ void QDeclarativeGridView::itemsInserted(int modelIndex, int count)
modelIndex = d->visibleIndex;
}
- int to = d->buffer+d->position()+d->size()-1;
+ qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+d->width()+1 : d->position();
+ int to = d->buffer+tempPos+d->size()-1;
int colPos = 0;
int rowPos = 0;
if (d->visibleItems.count()) {
@@ -2452,10 +2781,7 @@ void QDeclarativeGridView::itemsInserted(int modelIndex, int count)
}
}
} else if (d->itemCount == 0 && d->header) {
- if (d->flow == QDeclarativeGridView::LeftToRight)
- rowPos = d->headerSize();
- else
- colPos = d->headerSize();
+ rowPos = d->headerSize();
}
// Update the indexes of the following visible items.
@@ -2508,10 +2834,10 @@ void QDeclarativeGridView::itemsInserted(int modelIndex, int count)
if (d->currentItem) {
d->currentItem->index = d->currentIndex;
d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
- } else if (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared)) {
- d->updateCurrent(0);
}
emit currentIndexChanged();
+ } else if (d->itemCount == 0 && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
+ setCurrentIndex(0);
}
// everything is in order now - emit add() signal
@@ -2578,6 +2904,8 @@ void QDeclarativeGridView::itemsRemoved(int modelIndex, int count)
d->currentIndex = -1;
if (d->itemCount)
d->updateCurrent(qMin(modelIndex, d->itemCount-1));
+ else
+ emit currentIndexChanged();
}
// update visibleIndex
@@ -2760,7 +3088,10 @@ void QDeclarativeGridView::animStopped()
void QDeclarativeGridView::refill()
{
Q_D(QDeclarativeGridView);
- d->refill(d->position(), d->position()+d->size()-1);
+ if (d->isRightToLeftTopToBottom())
+ d->refill(-d->position()-d->size()+1, -d->position());
+ else
+ d->refill(d->position(), d->position()+d->size()-1);
}
diff --git a/src/declarative/graphicsitems/qdeclarativegridview_p.h b/src/declarative/graphicsitems/qdeclarativegridview_p.h
index e68a9ba..4d99a14 100644
--- a/src/declarative/graphicsitems/qdeclarativegridview_p.h
+++ b/src/declarative/graphicsitems/qdeclarativegridview_p.h
@@ -69,11 +69,13 @@ class Q_AUTOTEST_EXPORT QDeclarativeGridView : public QDeclarativeFlickable
Q_PROPERTY(bool highlightFollowsCurrentItem READ highlightFollowsCurrentItem WRITE setHighlightFollowsCurrentItem)
Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged)
- Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged)
- Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged)
+ Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged RESET resetPreferredHighlightBegin)
+ Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged RESET resetPreferredHighlightEnd)
Q_PROPERTY(HighlightRangeMode highlightRangeMode READ highlightRangeMode WRITE setHighlightRangeMode NOTIFY highlightRangeModeChanged)
Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1)
Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged)
Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
Q_PROPERTY(int cellWidth READ cellWidth WRITE setCellWidth NOTIFY cellWidthChanged)
@@ -95,6 +97,7 @@ public:
~QDeclarativeGridView();
QVariant model() const;
+ int modelCount() const;
void setModel(const QVariant &);
QDeclarativeComponent *delegate() const;
@@ -122,9 +125,15 @@ public:
qreal preferredHighlightBegin() const;
void setPreferredHighlightBegin(qreal);
+ void resetPreferredHighlightBegin();
qreal preferredHighlightEnd() const;
void setPreferredHighlightEnd(qreal);
+ void resetPreferredHighlightEnd();
+
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection(Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
enum Flow { LeftToRight, TopToBottom };
Flow flow() const;
@@ -184,6 +193,8 @@ Q_SIGNALS:
void modelChanged();
void delegateChanged();
void flowChanged();
+ Q_REVISION(1) void layoutDirectionChanged();
+ Q_REVISION(1) void effectiveLayoutDirectionChanged();
void keyNavigationWrapsChanged();
void cacheBufferChanged();
void snapModeChanged();
diff --git a/src/declarative/graphicsitems/qdeclarativeimage.cpp b/src/declarative/graphicsitems/qdeclarativeimage.cpp
index 2c9bde5..ed5d5fc 100644
--- a/src/declarative/graphicsitems/qdeclarativeimage.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeimage.cpp
@@ -147,8 +147,8 @@ void QDeclarativeImagePrivate::setPixmap(const QPixmap &pixmap)
/*!
\qmlproperty enumeration Image::fillMode
- Set this property to define what happens when the image set for the item is smaller
- than the size of the item.
+ Set this property to define what happens when the source image has a different size
+ than the item.
\list
\o Image.Stretch - the image is scaled to fit
@@ -234,6 +234,9 @@ void QDeclarativeImagePrivate::setPixmap(const QPixmap &pixmap)
\endtable
+ Note that \c clip is \c false by default which means that the element might
+ paint outside its bounding rectangle even if the fillMode is set to \c PreserveAspectCrop.
+
\sa {declarative/imageelements/image}{Image example}
*/
QDeclarativeImage::FillMode QDeclarativeImage::fillMode() const
@@ -386,14 +389,16 @@ void QDeclarativeImage::updatePaintedGeometry()
if (d->fillMode == PreserveAspectFit) {
if (!d->pix.width() || !d->pix.height())
return;
- qreal widthScale = width() / qreal(d->pix.width());
- qreal heightScale = height() / qreal(d->pix.height());
+ qreal w = widthValid() ? width() : d->pix.width();
+ qreal widthScale = w / qreal(d->pix.width());
+ qreal h = heightValid() ? height() : d->pix.height();
+ qreal heightScale = h / qreal(d->pix.height());
if (widthScale <= heightScale) {
- d->paintedWidth = width();
+ d->paintedWidth = w;
d->paintedHeight = widthScale * qreal(d->pix.height());
} else if(heightScale < widthScale) {
d->paintedWidth = heightScale * qreal(d->pix.width());
- d->paintedHeight = height();
+ d->paintedHeight = h;
}
if (widthValid() && !heightValid()) {
setImplicitHeight(d->paintedHeight);
diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp
index 471c87f..2de3ba0 100644
--- a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp
@@ -130,7 +130,7 @@ QSize QDeclarativeImageBase::sourceSize() const
int width = d->sourcesize.width();
int height = d->sourcesize.height();
- return QSize(width != -1 ? width : implicitWidth(), height != -1 ? height : implicitHeight());
+ return QSize(width != -1 ? width : d->pix.width(), height != -1 ? height : d->pix.height());
}
bool QDeclarativeImageBase::cache() const
diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp
index 468b5cb..6602dda 100644
--- a/src/declarative/graphicsitems/qdeclarativeitem.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp
@@ -39,12 +39,12 @@
**
****************************************************************************/
-#include "private/qdeclarativeitem_p.h"
#include "qdeclarativeitem.h"
#include "private/qdeclarativeevents_p_p.h"
#include <private/qdeclarativeengine_p.h>
#include <private/qgraphicsitem_p.h>
+#include <QtDeclarative/private/qdeclarativeitem_p.h>
#include <qdeclarativeengine.h>
#include <qdeclarativeopenmetaobject_p.h>
@@ -615,19 +615,28 @@ void QDeclarativeKeyNavigationAttached::keyPressed(QKeyEvent *event, bool post)
return;
}
+ bool mirror = false;
switch(event->key()) {
- case Qt::Key_Left:
- if (d->left) {
- setFocusNavigation(d->left, "left");
+ case Qt::Key_Left: {
+ if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent()))
+ mirror = QDeclarativeItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ QDeclarativeItem* leftItem = mirror ? d->right : d->left;
+ if (leftItem) {
+ setFocusNavigation(leftItem, mirror ? "right" : "left");
event->accept();
}
break;
- case Qt::Key_Right:
- if (d->right) {
- setFocusNavigation(d->right, "right");
+ }
+ case Qt::Key_Right: {
+ if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent()))
+ mirror = QDeclarativeItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ QDeclarativeItem* rightItem = mirror ? d->left : d->right;
+ if (rightItem) {
+ setFocusNavigation(rightItem, mirror ? "left" : "right");
event->accept();
}
break;
+ }
case Qt::Key_Up:
if (d->up) {
setFocusNavigation(d->up, "up");
@@ -669,16 +678,19 @@ void QDeclarativeKeyNavigationAttached::keyReleased(QKeyEvent *event, bool post)
return;
}
+ bool mirror = false;
switch(event->key()) {
case Qt::Key_Left:
- if (d->left) {
+ if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent()))
+ mirror = QDeclarativeItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ if (mirror ? d->right : d->left)
event->accept();
- }
break;
case Qt::Key_Right:
- if (d->right) {
+ if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent()))
+ mirror = QDeclarativeItemPrivate::get(parentItem)->effectiveLayoutMirror;
+ if (mirror ? d->left : d->right)
event->accept();
- }
break;
case Qt::Key_Up:
if (d->up) {
@@ -731,6 +743,171 @@ void QDeclarativeKeyNavigationAttached::setFocusNavigation(QDeclarativeItem *cur
}
/*!
+ \qmlclass LayoutMirroring QDeclarativeLayoutMirroringAttached
+ \since QtQuick 1.1
+ \ingroup qml-utility-elements
+ \brief The LayoutMirroring attached property is used to mirror layout behavior.
+
+ The LayoutMirroring attached property is used to horizontally mirror \l {anchor-layout}{Item anchors},
+ \l{Using QML Positioner and Repeater Items}{positioner} elements (such as \l Row and \l Grid)
+ and views (such as \l GridView and horizontal \l ListView). Mirroring is a visual change: left
+ anchors become right anchors, and positioner elements like \l Grid and \l Row reverse the
+ horizontal layout of child items.
+
+ Mirroring is enabled for an item by setting the \l enabled property to true. By default, this
+ only affects the item itself; setting the \l childrenInherit property to true propagates the mirroring
+ behavior to all child elements as well. If the \c LayoutMirroring attached property has not been defined
+ for an item, mirroring is not enabled.
+
+ The following example shows mirroring in action. The \l Row below is specified as being anchored
+ to the left of its parent. However, since mirroring has been enabled, the anchor is horizontally
+ reversed and it is now anchored to the right. Also, since items in a \l Row are positioned
+ from left to right by default, they are now positioned from right to left instead, as demonstrated
+ by the numbering and opacity of the items:
+
+ \snippet doc/src/snippets/declarative/layoutmirroring.qml 0
+
+ \image layoutmirroring.png
+
+ Layout mirroring is useful when it is necessary to support both left-to-right and right-to-left
+ layout versions of an application to target different language areas. The \l childrenInherit
+ property allows layout mirroring to be applied without manually setting layout configurations
+ for every item in an application. Keep in mind, however, that mirroring does not affect any
+ positioning that is defined by the \l Item \l {Item::}{x} coordinate value, so even with
+ mirroring enabled, it will often be necessary to apply some layout fixes to support the
+ desired layout direction. Also, it may be necessary to disable the mirroring of individual
+ child items (by setting \l {enabled}{LayoutMirroring.enabled} to false for such items) if
+ mirroring is not the desired behavior, or if the child item already implements mirroring in
+ some custom way.
+
+ See \l {QML Right-to-left User Interfaces} for further details on using \c LayoutMirroring and
+ other related features to implement right-to-left support for an application.
+*/
+
+/*!
+ \qmlproperty bool LayoutMirroring::enabled
+
+ This property holds whether the item's layout is mirrored horizontally. Setting this to true
+ horizontally reverses \l {anchor-layout}{anchor} settings such that left anchors become right,
+ and right anchors become left. For \l{Using QML Positioner and Repeater Items}{positioner} elements
+ (such as \l Row and \l Grid) and view elements (such as \l {GridView}{GridView} and \l {ListView}{ListView})
+ this also mirrors the horizontal layout direction of the item.
+
+ The default value is false.
+*/
+
+/*!
+ \qmlproperty bool LayoutMirroring::childrenInherit
+
+ This property holds whether the \l {enabled}{LayoutMirroring.enabled} value for this item
+ is inherited by its children.
+
+ The default value is false.
+*/
+
+QDeclarativeLayoutMirroringAttached::QDeclarativeLayoutMirroringAttached(QObject *parent) : QObject(parent), itemPrivate(0)
+{
+ if (QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent)) {
+ itemPrivate = QDeclarativeItemPrivate::get(item);
+ itemPrivate->attachedLayoutDirection = this;
+ } else
+ qmlInfo(parent) << tr("LayoutDirection attached property only works with Items");
+}
+
+QDeclarativeLayoutMirroringAttached * QDeclarativeLayoutMirroringAttached::qmlAttachedProperties(QObject *object)
+{
+ return new QDeclarativeLayoutMirroringAttached(object);
+}
+
+bool QDeclarativeLayoutMirroringAttached::enabled() const
+{
+ return itemPrivate ? itemPrivate->effectiveLayoutMirror : false;
+}
+
+void QDeclarativeLayoutMirroringAttached::setEnabled(bool enabled)
+{
+ if (!itemPrivate)
+ return;
+
+ itemPrivate->isMirrorImplicit = false;
+ if (enabled != itemPrivate->effectiveLayoutMirror) {
+ itemPrivate->setLayoutMirror(enabled);
+ if (itemPrivate->inheritMirrorFromItem)
+ itemPrivate->resolveLayoutMirror();
+ }
+}
+
+void QDeclarativeLayoutMirroringAttached::resetEnabled()
+{
+ if (itemPrivate && !itemPrivate->isMirrorImplicit) {
+ itemPrivate->isMirrorImplicit = true;
+ itemPrivate->resolveLayoutMirror();
+ }
+}
+
+bool QDeclarativeLayoutMirroringAttached::childrenInherit() const
+{
+ return itemPrivate ? itemPrivate->inheritMirrorFromItem : false;
+}
+
+void QDeclarativeLayoutMirroringAttached::setChildrenInherit(bool childrenInherit) {
+ if (itemPrivate && childrenInherit != itemPrivate->inheritMirrorFromItem) {
+ itemPrivate->inheritMirrorFromItem = childrenInherit;
+ itemPrivate->resolveLayoutMirror();
+ childrenInheritChanged();
+ }
+}
+
+void QDeclarativeItemPrivate::resolveLayoutMirror()
+{
+ Q_Q(QDeclarativeItem);
+ if (QDeclarativeItem *parentItem = q->parentItem()) {
+ QDeclarativeItemPrivate *parentPrivate = QDeclarativeItemPrivate::get(parentItem);
+ setImplicitLayoutMirror(parentPrivate->inheritedLayoutMirror, parentPrivate->inheritMirrorFromParent);
+ } else {
+ setImplicitLayoutMirror(isMirrorImplicit ? false : effectiveLayoutMirror, inheritMirrorFromItem);
+ }
+}
+
+void QDeclarativeItemPrivate::setImplicitLayoutMirror(bool mirror, bool inherit)
+{
+ inherit = inherit || inheritMirrorFromItem;
+ if (!isMirrorImplicit && inheritMirrorFromItem)
+ mirror = effectiveLayoutMirror;
+ if (mirror == inheritedLayoutMirror && inherit == inheritMirrorFromParent)
+ return;
+
+ inheritMirrorFromParent = inherit;
+ inheritedLayoutMirror = inheritMirrorFromParent ? mirror : false;
+
+ if (isMirrorImplicit)
+ setLayoutMirror(inherit ? inheritedLayoutMirror : false);
+ for (int i = 0; i < children.count(); ++i) {
+ if (QDeclarativeItem *child = qobject_cast<QDeclarativeItem *>(children.at(i))) {
+ QDeclarativeItemPrivate *childPrivate = QDeclarativeItemPrivate::get(child);
+ childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent);
+ }
+ }
+}
+
+void QDeclarativeItemPrivate::setLayoutMirror(bool mirror)
+{
+ if (mirror != effectiveLayoutMirror) {
+ effectiveLayoutMirror = mirror;
+ if (_anchors) {
+ _anchors->d_func()->fillChanged();
+ _anchors->d_func()->centerInChanged();
+ _anchors->d_func()->updateHorizontalAnchors();
+ emit _anchors->mirroredChanged();
+ }
+ mirrorChange();
+ if (attachedLayoutDirection) {
+ emit attachedLayoutDirection->enabledChanged();
+ }
+ }
+}
+
+/*!
\qmlclass Keys QDeclarativeKeysAttached
\ingroup qml-basic-interaction-elements
\since 4.7
@@ -1397,6 +1574,11 @@ QDeclarativeKeysAttached *QDeclarativeKeysAttached::qmlAttachedProperties(QObjec
\endqml
See the \l {Keys}{Keys} attached property for detailed documentation.
+
+ \section1 Layout Mirroring
+
+ Item layouts can be mirrored using the \l {LayoutMirroring}{LayoutMirroring} attached property.
+
*/
/*!
@@ -2154,6 +2336,8 @@ QDeclarativeAnchorLine QDeclarativeItemPrivate::baseline() const
\qmlproperty real Item::anchors.verticalCenterOffset
\qmlproperty real Item::anchors.baselineOffset
+ \qmlproperty bool Item::anchors.mirrored
+
Anchors provide a way to position an item by specifying its
relationship with other items.
@@ -2211,6 +2395,8 @@ QDeclarativeAnchorLine QDeclarativeItemPrivate::baseline() const
To clear an anchor value, set it to \c undefined.
+ \c anchors.mirrored returns true it the layout has been \l {LayoutMirroring}{mirrored}.
+
\note You can only anchor an item to siblings or a parent.
For more information see \l {anchor-layout}{Anchor Layouts}.
@@ -2812,6 +2998,7 @@ QVariant QDeclarativeItem::itemChange(GraphicsItemChange change,
Q_D(QDeclarativeItem);
switch (change) {
case ItemParentHasChanged:
+ d->resolveLayoutMirror();
emit parentChanged(parentItem());
d->parentNotifier.notify();
break;
diff --git a/src/declarative/graphicsitems/qdeclarativeitem_p.h b/src/declarative/graphicsitems/qdeclarativeitem_p.h
index 4303c0a..dae581c 100644
--- a/src/declarative/graphicsitems/qdeclarativeitem_p.h
+++ b/src/declarative/graphicsitems/qdeclarativeitem_p.h
@@ -77,6 +77,7 @@ QT_BEGIN_NAMESPACE
class QNetworkReply;
class QDeclarativeItemKeyFilter;
+class QDeclarativeLayoutMirroringAttached;
//### merge into private?
class QDeclarativeContents : public QObject, public QDeclarativeItemChangeListener
@@ -125,8 +126,10 @@ public:
_stateGroup(0), origin(QDeclarativeItem::Center),
widthValid(false), heightValid(false),
componentComplete(true), keepMouse(false),
- smooth(false), transformOriginDirty(true), doneEventPreHandler(false), keyHandler(0),
- mWidth(0), mHeight(0), mImplicitWidth(0), mImplicitHeight(0), hadSubFocusItem(false)
+ smooth(false), transformOriginDirty(true), doneEventPreHandler(false),
+ inheritedLayoutMirror(false), effectiveLayoutMirror(false), isMirrorImplicit(true),
+ inheritMirrorFromParent(false), inheritMirrorFromItem(false), keyHandler(0),
+ mWidth(0), mHeight(0), mImplicitWidth(0), mImplicitHeight(0), attachedLayoutDirection(0), hadSubFocusItem(false)
{
QGraphicsItemPrivate::acceptedMouseButtons = 0;
isDeclarativeItem = 1;
@@ -134,7 +137,6 @@ public:
QGraphicsItem::ItemHasNoContents
| QGraphicsItem::ItemIsFocusable
| QGraphicsItem::ItemNegativeZStacksBehindParent);
-
}
void init(QDeclarativeItem *parent)
@@ -143,11 +145,17 @@ public:
if (parent) {
QDeclarative_setParent_noEvent(q, parent);
q->setParentItem(parent);
+ QDeclarativeItemPrivate *parentPrivate = QDeclarativeItemPrivate::get(parent);
+ setImplicitLayoutMirror(parentPrivate->inheritedLayoutMirror, parentPrivate->inheritMirrorFromParent);
}
baselineOffset.invalidate();
mouseSetsFocus = false;
}
+ bool isMirrored() const {
+ return effectiveLayoutMirror;
+ }
+
// Private Properties
qreal width() const;
void setWidth(qreal);
@@ -162,6 +170,10 @@ public:
virtual void implicitWidthChanged();
virtual void implicitHeightChanged();
+ void resolveLayoutMirror();
+ void setImplicitLayoutMirror(bool mirror, bool inherit);
+ void setLayoutMirror(bool mirror);
+
QDeclarativeListProperty<QObject> data();
QDeclarativeListProperty<QObject> resources();
@@ -272,6 +284,11 @@ public:
bool smooth:1;
bool transformOriginDirty : 1;
bool doneEventPreHandler : 1;
+ bool inheritedLayoutMirror:1;
+ bool effectiveLayoutMirror:1;
+ bool isMirrorImplicit:1;
+ bool inheritMirrorFromParent:1;
+ bool inheritMirrorFromItem:1;
QDeclarativeItemKeyFilter *keyHandler;
@@ -280,6 +297,8 @@ public:
qreal mImplicitWidth;
qreal mImplicitHeight;
+ QDeclarativeLayoutMirroringAttached* attachedLayoutDirection;
+
bool hadSubFocusItem;
QPointF computeTransformOrigin() const;
@@ -326,6 +345,8 @@ public:
virtual void focusChanged(bool);
+ virtual void mirrorChange() {};
+
static qint64 consistentTime;
static void setConsistentTime(qint64 t);
static void start(QElapsedTimer &);
@@ -423,6 +444,31 @@ private:
void setFocusNavigation(QDeclarativeItem *currentItem, const char *dir);
};
+class QDeclarativeLayoutMirroringAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled RESET resetEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(bool childrenInherit READ childrenInherit WRITE setChildrenInherit NOTIFY childrenInheritChanged)
+
+public:
+ explicit QDeclarativeLayoutMirroringAttached(QObject *parent = 0);
+
+ bool enabled() const;
+ void setEnabled(bool);
+ void resetEnabled();
+
+ bool childrenInherit() const;
+ void setChildrenInherit(bool);
+
+ static QDeclarativeLayoutMirroringAttached *qmlAttachedProperties(QObject *);
+Q_SIGNALS:
+ void enabledChanged();
+ void childrenInheritChanged();
+private:
+ friend class QDeclarativeItemPrivate;
+ QDeclarativeItemPrivate *itemPrivate;
+};
+
class QDeclarativeKeysAttachedPrivate : public QObjectPrivate
{
public:
@@ -572,5 +618,7 @@ QML_DECLARE_TYPE(QDeclarativeKeysAttached)
QML_DECLARE_TYPEINFO(QDeclarativeKeysAttached, QML_HAS_ATTACHED_PROPERTIES)
QML_DECLARE_TYPE(QDeclarativeKeyNavigationAttached)
QML_DECLARE_TYPEINFO(QDeclarativeKeyNavigationAttached, QML_HAS_ATTACHED_PROPERTIES)
+QML_DECLARE_TYPE(QDeclarativeLayoutMirroringAttached)
+QML_DECLARE_TYPEINFO(QDeclarativeLayoutMirroringAttached, QML_HAS_ATTACHED_PROPERTIES)
#endif // QDECLARATIVEITEM_P_H
diff --git a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp
index 3c8f64e..c4a9030 100644
--- a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp
@@ -198,6 +198,7 @@ void QDeclarativeItemModule::defineModule()
qmlRegisterRevision<QDeclarativeImplicitSizeItem,1>("QtQuick",1,1);
qmlRegisterRevision<QDeclarativeImplicitSizePaintedItem,0>("QtQuick",1,0);
qmlRegisterRevision<QDeclarativeImplicitSizePaintedItem,1>("QtQuick",1,1);
+ qmlRegisterUncreatableType<QDeclarativeLayoutMirroringAttached>("QtQuick",1,1,"LayoutMirroring", QDeclarativeLayoutMirroringAttached::tr("LayoutMirroring is only available via attached properties"));
#ifndef QT_NO_IMPORT_QT47_QML
#ifdef QT_NO_MOVIE
diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp
index e369ba6..6ae1ddc 100644
--- a/src/declarative/graphicsitems/qdeclarativelistview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp
@@ -100,13 +100,21 @@ public:
}
~FxListItem() {}
qreal position() const {
- if (section)
- return (view->orientation() == QDeclarativeListView::Vertical ? section->y() : section->x());
- else
- return (view->orientation() == QDeclarativeListView::Vertical ? item->y() : item->x());
+ if (section) {
+ if (view->orientation() == QDeclarativeListView::Vertical)
+ return section->y();
+ else
+ return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section->width()-section->x() : section->x());
+ } else {
+ return itemPosition();
+ }
}
+
qreal itemPosition() const {
- return (view->orientation() == QDeclarativeListView::Vertical ? item->y() : item->x());
+ if (view->orientation() == QDeclarativeListView::Vertical)
+ return item->y();
+ else
+ return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-item->x() : item->x());
}
qreal size() const {
if (section)
@@ -123,9 +131,13 @@ public:
return 0.0;
}
qreal endPosition() const {
- return (view->orientation() == QDeclarativeListView::Vertical
- ? item->y() + (item->height() >= 1.0 ? item->height() : 1)
- : item->x() + (item->width() >= 1.0 ? item->width() : 1)) - 1;
+ if (view->orientation() == QDeclarativeListView::Vertical) {
+ return item->y() + (item->height() >= 1.0 ? item->height() : 1) - 1;
+ } else {
+ return (view->effectiveLayoutDirection() == Qt::RightToLeft
+ ? -item->width()-item->x() + (item->width() >= 1.0 ? item->width() : 1)
+ : item->x() + (item->width() >= 1.0 ? item->width() : 1)) - 1;
+ }
}
void setPosition(qreal pos) {
if (view->orientation() == QDeclarativeListView::Vertical) {
@@ -135,11 +147,19 @@ public:
}
item->setY(pos);
} else {
- if (section) {
- section->setX(pos);
- pos += section->width();
+ if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
+ if (section) {
+ section->setX(-section->width()-pos);
+ pos += section->width();
+ }
+ item->setX(-item->width()-pos);
+ } else {
+ if (section) {
+ section->setX(pos);
+ pos += section->width();
+ }
+ item->setX(pos);
}
- item->setX(pos);
}
}
void setSize(qreal size) {
@@ -168,10 +188,11 @@ class QDeclarativeListViewPrivate : public QDeclarativeFlickablePrivate
public:
QDeclarativeListViewPrivate()
- : currentItem(0), orient(QDeclarativeListView::Vertical)
+ : currentItem(0), orient(QDeclarativeListView::Vertical), layoutDirection(Qt::LeftToRight)
, visiblePos(0), visibleIndex(0)
, averageSize(100.0), currentIndex(-1), requestedIndex(-1)
, itemCount(0), highlightRangeStart(0), highlightRangeEnd(0)
+ , highlightRangeStartValid(false), highlightRangeEndValid(false)
, highlightComponent(0), highlight(0), trackedItem(0)
, moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0)
, sectionCriteria(0), spacing(0.0)
@@ -204,7 +225,7 @@ public:
}
FxListItem *firstVisibleItem() const {
- const qreal pos = position();
+ const qreal pos = isRightToLeft() ? -position()-size() : position();
for (int i = 0; i < visibleItems.count(); ++i) {
FxListItem *item = visibleItems.at(i);
if (item->index != -1 && item->endPosition() > pos)
@@ -214,7 +235,7 @@ public:
}
FxListItem *nextVisibleItem() const {
- const qreal pos = position();
+ const qreal pos = isRightToLeft() ? -position()-size() : position();
bool foundFirst = false;
for (int i = 0; i < visibleItems.count(); ++i) {
FxListItem *item = visibleItems.at(i);
@@ -248,23 +269,65 @@ public:
return 0;
}
+ void regenerate() {
+ Q_Q(QDeclarativeListView);
+ if (q->isComponentComplete()) {
+ if (header) {
+ if (q->scene())
+ q->scene()->removeItem(header->item);
+ header->item->deleteLater();
+ delete header;
+ header = 0;
+ }
+ if (footer) {
+ if (q->scene())
+ q->scene()->removeItem(footer->item);
+ footer->item->deleteLater();
+ delete footer;
+ footer = 0;
+ }
+ updateHeader();
+ updateFooter();
+ clear();
+ setPosition(0);
+ q->refill();
+ updateCurrent(currentIndex);
+ }
+ }
+
+ void mirrorChange() {
+ Q_Q(QDeclarativeListView);
+ regenerate();
+ emit q->effectiveLayoutDirectionChanged();
+ }
+
+ bool isRightToLeft() const {
+ Q_Q(const QDeclarativeListView);
+ return orient == QDeclarativeListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
+ }
+
qreal position() const {
Q_Q(const QDeclarativeListView);
return orient == QDeclarativeListView::Vertical ? q->contentY() : q->contentX();
}
+
void setPosition(qreal pos) {
Q_Q(QDeclarativeListView);
- if (orient == QDeclarativeListView::Vertical)
+ if (orient == QDeclarativeListView::Vertical) {
q->QDeclarativeFlickable::setContentY(pos);
- else
- q->QDeclarativeFlickable::setContentX(pos);
+ } else {
+ if (isRightToLeft())
+ q->QDeclarativeFlickable::setContentX(-pos-size());
+ else
+ q->QDeclarativeFlickable::setContentX(pos);
+ }
}
qreal size() const {
Q_Q(const QDeclarativeListView);
return orient == QDeclarativeListView::Vertical ? q->height() : q->width();
}
- qreal startPosition() const {
+ qreal originPosition() const {
qreal pos = 0;
if (!visibleItems.isEmpty()) {
pos = (*visibleItems.constBegin())->position();
@@ -274,7 +337,7 @@ public:
return pos;
}
- qreal endPosition() const {
+ qreal lastPosition() const {
qreal pos = 0;
if (!visibleItems.isEmpty()) {
int invisibleCount = visibleItems.count() - visibleIndex;
@@ -291,6 +354,14 @@ public:
return pos;
}
+ qreal startPosition() const {
+ return isRightToLeft() ? -lastPosition()-1 : originPosition();
+ }
+
+ qreal endPosition() const {
+ return isRightToLeft() ? -originPosition()-1 : lastPosition();
+ }
+
qreal positionAt(int modelIndex) const {
if (FxListItem *item = visibleItem(modelIndex))
return item->position();
@@ -312,6 +383,7 @@ public:
else
idx = visibleItems.at(idx)->index;
int count = modelIndex - idx - 1;
+
return (*(--visibleItems.constEnd()))->endPosition() + spacing + count * (averageSize + spacing) + 1;
}
}
@@ -368,7 +440,7 @@ public:
} else if (pos > endPos)
return endPos + qRound((pos - endPos) / averageSize) * averageSize;
}
- return qRound((pos - startPosition()) / averageSize) * averageSize + startPosition();
+ return qRound((pos - originPosition()) / averageSize) * averageSize + originPosition();
}
FxListItem *snapItemAt(qreal pos) {
@@ -484,6 +556,7 @@ public:
QHash<QDeclarativeItem*,int> unrequestedItems;
FxListItem *currentItem;
QDeclarativeListView::Orientation orient;
+ Qt::LayoutDirection layoutDirection;
qreal visiblePos;
int visibleIndex;
qreal averageSize;
@@ -492,6 +565,8 @@ public:
int itemCount;
qreal highlightRangeStart;
qreal highlightRangeEnd;
+ bool highlightRangeStartValid;
+ bool highlightRangeEndValid;
QDeclarativeComponent *highlightComponent;
FxListItem *highlight;
FxListItem *trackedItem;
@@ -669,7 +744,6 @@ void QDeclarativeListViewPrivate::refill(qreal from, qreal to, bool doBuffer)
if (visibleItems.at(i)->index != -1)
modelIndex = visibleItems.at(i)->index + 1;
}
-
bool changed = false;
FxListItem *item = 0;
qreal pos = itemEnd + 1;
@@ -815,8 +889,12 @@ void QDeclarativeListViewPrivate::updateUnrequestedPositions()
if (item->y() + item->height() > pos && item->y() < pos + q->height())
item->setY(positionAt(*it));
} else {
- if (item->x() + item->width() > pos && item->x() < pos + q->width())
- item->setX(positionAt(*it));
+ if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
+ if (isRightToLeft())
+ item->setX(-positionAt(*it)-item->width());
+ else
+ item->setX(positionAt(*it));
+ }
}
}
}
@@ -907,7 +985,9 @@ void QDeclarativeListViewPrivate::updateHighlight()
createHighlight();
if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) {
// auto-update highlight
- highlightPosAnimator->to = currentItem->itemPosition();
+ highlightPosAnimator->to = isRightToLeft()
+ ? -currentItem->itemPosition()-currentItem->itemSize()
+ : currentItem->itemPosition();
highlightSizeAnimator->to = currentItem->itemSize();
if (orient == QDeclarativeListView::Vertical) {
if (highlight->item->width() == 0)
@@ -1125,7 +1205,7 @@ void QDeclarativeListViewPrivate::updateFooter()
}
if (footer) {
if (visibleItems.count()) {
- qreal endPos = endPosition() + 1;
+ qreal endPos = lastPosition() + 1;
if (lastVisibleIndex() == model->count()-1) {
footer->setPosition(endPos);
} else {
@@ -1165,7 +1245,7 @@ void QDeclarativeListViewPrivate::updateHeader()
}
if (header) {
if (visibleItems.count()) {
- qreal startPos = startPosition();
+ qreal startPos = originPosition();
if (visibleIndex == 0) {
header->setPosition(startPos - header->size());
} else {
@@ -1200,14 +1280,30 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m
correctFlick = false;
fixupMode = moveReason == Mouse ? fixupMode : Immediate;
- if (currentItem && haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange) {
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal viewPos;
+ if (isRightToLeft()) {
+ // Handle Right-To-Left exceptions
+ viewPos = -position()-size();
+ highlightStart = highlightRangeStartValid ? size() - highlightRangeEnd : highlightRangeStart;
+ highlightEnd = highlightRangeEndValid ? size() - highlightRangeStart : highlightRangeEnd;
+ } else {
+ viewPos = position();
+ highlightStart = highlightRangeStart;
+ highlightEnd = highlightRangeEnd;
+ }
+
+ if (currentItem && haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange
+ && moveReason != QDeclarativeListViewPrivate::SetIndex) {
updateHighlight();
qreal pos = currentItem->itemPosition();
- qreal viewPos = position();
- if (viewPos < pos + currentItem->itemSize() - highlightRangeEnd)
- viewPos = pos + currentItem->itemSize() - highlightRangeEnd;
- if (viewPos > pos - highlightRangeStart)
- viewPos = pos - highlightRangeStart;
+ if (viewPos < pos + currentItem->itemSize() - highlightEnd)
+ viewPos = pos + currentItem->itemSize() - highlightEnd;
+ if (viewPos > pos - highlightStart)
+ viewPos = pos - highlightStart;
+ if (isRightToLeft())
+ viewPos = -viewPos-size();
timeline.reset(data.move);
if (viewPos != position()) {
@@ -1219,17 +1315,26 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m
}
}
vTime = timeline.time();
- } else if (snapMode != QDeclarativeListView::NoSnap) {
- FxListItem *topItem = snapItemAt(position()+highlightRangeStart);
- FxListItem *bottomItem = snapItemAt(position()+highlightRangeEnd);
+ } else if (snapMode != QDeclarativeListView::NoSnap && moveReason != QDeclarativeListViewPrivate::SetIndex) {
+ qreal tempPosition = isRightToLeft() ? -position()-size() : position();
+ FxListItem *topItem = snapItemAt(tempPosition+highlightStart);
+ FxListItem *bottomItem = snapItemAt(tempPosition+highlightEnd);
qreal pos;
- if (topItem) {
- if (topItem->index == 0 && header && position()+highlightRangeStart < header->position()+header->size()/2)
- pos = header->position() - highlightRangeStart;
+ bool isInBounds = -position() > maxExtent && -position() < minExtent;
+ if (topItem && isInBounds) {
+ if (topItem->index == 0 && header && tempPosition+highlightStart < header->position()+header->size()/2) {
+ pos = isRightToLeft() ? - header->position() + highlightStart - size() : header->position() - highlightStart;
+ } else {
+ if (isRightToLeft())
+ pos = qMax(qMin(-topItem->position() + highlightStart - size(), -maxExtent), -minExtent);
+ else
+ pos = qMax(qMin(topItem->position() - highlightStart, -maxExtent), -minExtent);
+ }
+ } else if (bottomItem && isInBounds) {
+ if (isRightToLeft())
+ pos = qMax(qMin(-bottomItem->position() + highlightStart - size(), -maxExtent), -minExtent);
else
- pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
- } else if (bottomItem) {
- pos = qMax(qMin(bottomItem->position() - highlightRangeStart, -maxExtent), -minExtent);
+ pos = qMax(qMin(bottomItem->position() - highlightStart, -maxExtent), -minExtent);
} else {
QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
return;
@@ -1265,12 +1370,13 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
return;
}
qreal maxDistance = 0;
+ qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value();
// -ve velocity means list is moving up/left
if (velocity > 0) {
if (data.move.value() < minExtent) {
if (snapMode == QDeclarativeListView::SnapOneItem) {
- if (FxListItem *item = firstVisibleItem())
- maxDistance = qAbs(item->position() + data.move.value());
+ if (FxListItem *item = isRightToLeft() ? nextVisibleItem() : firstVisibleItem())
+ maxDistance = qAbs(item->position() + dataValue);
} else {
maxDistance = qAbs(minExtent - data.move.value());
}
@@ -1280,8 +1386,8 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
} else {
if (data.move.value() > maxExtent) {
if (snapMode == QDeclarativeListView::SnapOneItem) {
- if (FxListItem *item = nextVisibleItem())
- maxDistance = qAbs(item->position() + data.move.value());
+ if (FxListItem *item = isRightToLeft() ? firstVisibleItem() : nextVisibleItem())
+ maxDistance = qAbs(item->position() + dataValue);
} else {
maxDistance = qAbs(maxExtent - data.move.value());
}
@@ -1289,7 +1395,10 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
if (snapMode == QDeclarativeListView::NoSnap && highlightRange != QDeclarativeListView::StrictlyEnforceRange)
data.flickTarget = maxExtent;
}
+
bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds;
+ qreal highlightStart = isRightToLeft() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart;
+
if (maxDistance > 0 || overShoot) {
// These modes require the list to stop exactly on an item boundary.
// The initial flick will estimate the boundary to stop on.
@@ -1314,7 +1423,9 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
if (v > 0)
dist = -dist;
if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QDeclarativeListView::SnapOneItem) {
- data.flickTarget = -snapPosAt(-(data.move.value() - highlightRangeStart) + dist) + highlightRangeStart;
+ qreal distTemp = isRightToLeft() ? -dist : dist;
+ data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart;
+ data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
if (overShoot) {
if (data.flickTarget >= minExtent) {
overshootDist = overShootDistance(v, vSize);
@@ -1347,6 +1458,7 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
data.flickTarget -= overshootDist;
}
}
+
timeline.reset(data.move);
timeline.accel(data.move, v, accel, maxDistance + overshootDist);
timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
@@ -1366,8 +1478,11 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
} else {
// reevaluate the target boundary.
qreal newtarget = data.flickTarget;
- if (snapMode != QDeclarativeListView::NoSnap || highlightRange == QDeclarativeListView::StrictlyEnforceRange)
- newtarget = -snapPosAt(-(data.flickTarget - highlightRangeStart)) + highlightRangeStart;
+ if (snapMode != QDeclarativeListView::NoSnap || highlightRange == QDeclarativeListView::StrictlyEnforceRange) {
+ qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
+ newtarget = -snapPosAt(-(tempFlickTarget - highlightStart)) + highlightStart;
+ newtarget = isRightToLeft() ? -newtarget+size() : newtarget;
+ }
if (velocity < 0 && newtarget <= maxExtent)
newtarget = maxExtent - overshootDist;
else if (velocity > 0 && newtarget >= minExtent)
@@ -1385,6 +1500,7 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
fixup(data, minExtent, maxExtent);
return;
}
+
timeline.reset(data.move);
timeline.accelDistance(data.move, v, -dist);
timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this));
@@ -1883,6 +1999,7 @@ qreal QDeclarativeListView::preferredHighlightBegin() const
void QDeclarativeListView::setPreferredHighlightBegin(qreal start)
{
Q_D(QDeclarativeListView);
+ d->highlightRangeStartValid = true;
if (d->highlightRangeStart == start)
return;
d->highlightRangeStart = start;
@@ -1890,6 +2007,16 @@ void QDeclarativeListView::setPreferredHighlightBegin(qreal start)
emit preferredHighlightBeginChanged();
}
+void QDeclarativeListView::resetPreferredHighlightBegin()
+{
+ Q_D(QDeclarativeListView);
+ d->highlightRangeStartValid = false;
+ if (d->highlightRangeStart == 0)
+ return;
+ d->highlightRangeStart = 0;
+ emit preferredHighlightBeginChanged();
+}
+
qreal QDeclarativeListView::preferredHighlightEnd() const
{
Q_D(const QDeclarativeListView);
@@ -1899,6 +2026,7 @@ qreal QDeclarativeListView::preferredHighlightEnd() const
void QDeclarativeListView::setPreferredHighlightEnd(qreal end)
{
Q_D(QDeclarativeListView);
+ d->highlightRangeEndValid = true;
if (d->highlightRangeEnd == end)
return;
d->highlightRangeEnd = end;
@@ -1906,6 +2034,16 @@ void QDeclarativeListView::setPreferredHighlightEnd(qreal end)
emit preferredHighlightEndChanged();
}
+void QDeclarativeListView::resetPreferredHighlightEnd()
+{
+ Q_D(QDeclarativeListView);
+ d->highlightRangeEndValid = false;
+ if (d->highlightRangeEnd == 0)
+ return;
+ d->highlightRangeEnd = 0;
+ emit preferredHighlightEndChanged();
+}
+
QDeclarativeListView::HighlightRangeMode QDeclarativeListView::highlightRangeMode() const
{
Q_D(const QDeclarativeListView);
@@ -1984,15 +2122,63 @@ void QDeclarativeListView::setOrientation(QDeclarativeListView::Orientation orie
setContentHeight(-1);
setFlickableDirection(HorizontalFlick);
}
- d->clear();
- d->setPosition(0);
- refill();
+ d->regenerate();
emit orientationChanged();
- d->updateCurrent(d->currentIndex);
}
}
/*!
+ \qmlproperty enumeration ListView::layoutDirection
+ This property holds the layout direction of the horizontal list.
+
+ Possible values:
+
+ \list
+ \o Qt.LeftToRight (default) - Items will be laid out from left to right.
+ \o Qt.RightToLeft - Items will be laid out from right to let.
+ \endlist
+
+ \sa ListView::effectiveLayoutDirection
+*/
+
+Qt::LayoutDirection QDeclarativeListView::layoutDirection() const
+{
+ Q_D(const QDeclarativeListView);
+ return d->layoutDirection;
+}
+
+void QDeclarativeListView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QDeclarativeListView);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ d->regenerate();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration ListView::effectiveLayoutDirection
+ This property holds the effective layout direction of the horizontal list.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the horizontal list will be mirrored. However, the
+ property \l {ListView::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa ListView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QDeclarativeListView::effectiveLayoutDirection() const
+{
+ Q_D(const QDeclarativeListView);
+ if (d->effectiveLayoutMirror)
+ return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
+ else
+ return d->layoutDirection;
+}
+
+/*!
\qmlproperty bool ListView::keyNavigationWraps
This property holds whether the list wraps key navigation.
@@ -2363,11 +2549,23 @@ void QDeclarativeListView::viewportMoved()
if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
// reposition highlight
qreal pos = d->highlight->position();
- qreal viewPos = d->position();
- if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
- pos = viewPos + d->highlightRangeEnd - d->highlight->size();
- if (pos < viewPos + d->highlightRangeStart)
- pos = viewPos + d->highlightRangeStart;
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeft()) {
+ // Handle Right-To-Left exceptions
+ viewPos = -d->position()-d->size();
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ } else {
+ viewPos = d->position();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ }
+ if (pos > viewPos + highlightEnd - d->highlight->size())
+ pos = viewPos + highlightEnd - d->highlight->size();
+ if (pos < viewPos + highlightStart)
+ pos = viewPos + highlightStart;
d->highlightPosAnimator->stop();
d->highlight->setPosition(qRound(pos));
@@ -2405,13 +2603,15 @@ void QDeclarativeListView::viewportMoved()
if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2)
&& minX != d->hData.flickTarget)
d->flickX(-d->hData.smoothVelocity.value());
- d->bufferMode = QDeclarativeListViewPrivate::BufferBefore;
+ d->bufferMode = d->isRightToLeft()
+ ? QDeclarativeListViewPrivate::BufferAfter : QDeclarativeListViewPrivate::BufferBefore;
} else if (d->hData.velocity < 0) {
const qreal maxX = maxXExtent();
if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2)
&& maxX != d->hData.flickTarget)
d->flickX(-d->hData.smoothVelocity.value());
- d->bufferMode = QDeclarativeListViewPrivate::BufferAfter;
+ d->bufferMode = d->isRightToLeft()
+ ? QDeclarativeListViewPrivate::BufferBefore : QDeclarativeListViewPrivate::BufferAfter;
}
}
d->inFlickCorrection = false;
@@ -2449,7 +2649,8 @@ qreal QDeclarativeListView::maxYExtent() const
return height();
if (d->maxExtentDirty) {
if (!d->model || !d->model->count()) {
- d->maxExtent = 0;
+ d->maxExtent = d->header ? -d->header->size() : 0;
+ d->maxExtent += height();
} else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart);
if (d->highlightRangeEnd != d->highlightRangeStart)
@@ -2474,11 +2675,34 @@ qreal QDeclarativeListView::minXExtent() const
return QDeclarativeFlickable::minXExtent();
if (d->minExtentDirty) {
d->minExtent = -d->startPosition();
- if (d->header)
- d->minExtent += d->header->size();
+
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal endPositionFirstItem = 0;
+ if (d->isRightToLeft()) {
+ if (d->model && d->model->count())
+ endPositionFirstItem = d->positionAt(d->model->count()-1);
+ else if (d->header)
+ d->minExtent += d->header->size();
+ highlightStart = d->highlightRangeStartValid
+ ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem)
+ : d->size() - (d->lastPosition()-endPositionFirstItem);
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size();
+ if (d->footer)
+ d->minExtent += d->footer->size();
+ qreal maxX = maxXExtent();
+ if (d->minExtent < maxX)
+ d->minExtent = maxX;
+ } else {
+ endPositionFirstItem = d->endPositionAt(0);
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ if (d->header && d->visibleItems.count())
+ d->minExtent += d->header->size();
+ }
if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
- d->minExtent += d->highlightRangeStart;
- d->minExtent = qMax(d->minExtent, -(d->endPositionAt(0) - d->highlightRangeEnd + 1));
+ d->minExtent += highlightStart;
+ d->minExtent = qMax(d->minExtent, -(endPositionFirstItem - highlightEnd + 1));
}
d->minExtentDirty = false;
}
@@ -2492,23 +2716,46 @@ qreal QDeclarativeListView::maxXExtent() const
if (d->orient == QDeclarativeListView::Vertical)
return width();
if (d->maxExtentDirty) {
+ qreal highlightStart;
+ qreal highlightEnd;
+ qreal lastItemPosition = 0;
+ d->maxExtent = 0;
+ if (d->isRightToLeft()) {
+ highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size();
+ highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size();
+ lastItemPosition = d->endPosition();
+ } else {
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ if (d->model && d->model->count())
+ lastItemPosition = d->positionAt(d->model->count()-1);
+ }
if (!d->model || !d->model->count()) {
- d->maxExtent = 0;
+ if (!d->isRightToLeft())
+ d->maxExtent = d->header ? -d->header->size() : 0;
+ d->maxExtent += width();
} else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
- d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart);
- if (d->highlightRangeEnd != d->highlightRangeStart)
- d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd + 1));
+ d->maxExtent = -(lastItemPosition - highlightStart);
+ if (highlightEnd != highlightStart) {
+ d->maxExtent = d->isRightToLeft()
+ ? qMax(d->maxExtent, -(d->endPosition() - highlightEnd + 1))
+ : qMin(d->maxExtent, -(d->endPosition() - highlightEnd + 1));
+ }
} else {
d->maxExtent = -(d->endPosition() - width() + 1);
}
- if (d->footer)
- d->maxExtent -= d->footer->size();
- qreal minX = minXExtent();
- if (d->maxExtent > minX)
- d->maxExtent = minX;
+ if (d->isRightToLeft()) {
+ if (d->header && d->visibleItems.count())
+ d->maxExtent -= d->header->size();
+ } else {
+ if (d->footer)
+ d->maxExtent -= d->footer->size();
+ qreal minX = minXExtent();
+ if (d->maxExtent > minX)
+ d->maxExtent = minX;
+ }
d->maxExtentDirty = false;
}
-
return d->maxExtent;
}
@@ -2520,7 +2767,8 @@ void QDeclarativeListView::keyPressEvent(QKeyEvent *event)
return;
if (d->model && d->model->count() && d->interactive) {
- if ((d->orient == QDeclarativeListView::Horizontal && event->key() == Qt::Key_Left)
+ if ((!d->isRightToLeft() && event->key() == Qt::Key_Left)
+ || (d->orient == QDeclarativeListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right)
|| (d->orient == QDeclarativeListView::Vertical && event->key() == Qt::Key_Up)) {
if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) {
decrementCurrentIndex();
@@ -2530,7 +2778,8 @@ void QDeclarativeListView::keyPressEvent(QKeyEvent *event)
event->accept();
return;
}
- } else if ((d->orient == QDeclarativeListView::Horizontal && event->key() == Qt::Key_Right)
+ } else if ((!d->isRightToLeft() && event->key() == Qt::Key_Right)
+ || (d->orient == QDeclarativeListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left)
|| (d->orient == QDeclarativeListView::Vertical && event->key() == Qt::Key_Down)) {
if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) {
incrementCurrentIndex();
@@ -2552,6 +2801,11 @@ void QDeclarativeListView::geometryChanged(const QRectF &newGeometry,
Q_D(QDeclarativeListView);
d->maxExtentDirty = true;
d->minExtentDirty = true;
+ if (d->isRightToLeft() && d->orient == Qt::Horizontal) {
+ // maintain position relative to the right edge
+ int dx = newGeometry.width() - oldGeometry.width();
+ setContentX(contentX() - dx);
+ }
QDeclarativeFlickable::geometryChanged(newGeometry, oldGeometry);
}
@@ -2607,9 +2861,14 @@ void QDeclarativeListViewPrivate::positionViewAtIndex(int index, int mode)
if (layoutScheduled)
layout();
- qreal pos = position();
+ qreal pos = isRightToLeft() ? -position() - size() : position();
FxListItem *item = visibleItem(idx);
- qreal maxExtent = orient == QDeclarativeListView::Vertical ? -q->maxYExtent() : -q->maxXExtent();
+ qreal maxExtent;
+ if (orient == QDeclarativeListView::Vertical)
+ maxExtent = -q->maxYExtent();
+ else
+ maxExtent = isRightToLeft() ? q->minXExtent()-size(): -q->maxXExtent();
+
if (!item) {
int itemPos = positionAt(idx);
// save the currently visible items in case any of them end up visible again
@@ -2652,7 +2911,12 @@ void QDeclarativeListViewPrivate::positionViewAtIndex(int index, int mode)
pos = itemPos;
}
pos = qMin(pos, maxExtent);
- qreal minExtent = orient == QDeclarativeListView::Vertical ? -q->minYExtent() : -q->minXExtent();
+ qreal minExtent;
+ if (orient == QDeclarativeListView::Vertical) {
+ minExtent = -q->minYExtent();
+ } else {
+ minExtent = isRightToLeft() ? q->maxXExtent()-size(): -q->minXExtent();
+ }
pos = qMax(pos, minExtent);
moveReason = QDeclarativeListViewPrivate::Other;
q->cancelFlick();
@@ -2810,7 +3074,10 @@ void QDeclarativeListView::updateSections()
void QDeclarativeListView::refill()
{
Q_D(QDeclarativeListView);
- d->refill(d->position(), d->position()+d->size()-1);
+ if (d->isRightToLeft())
+ d->refill(-d->position()-d->size()+1, -d->position());
+ else
+ d->refill(d->position(), d->position()+d->size()-1);
}
void QDeclarativeListView::trackedPositionChanged()
@@ -2825,26 +3092,37 @@ void QDeclarativeListView::trackedPositionChanged()
trackedPos -= d->currentItem->sectionSize();
trackedSize += d->currentItem->sectionSize();
}
- const qreal viewPos = d->position();
+ qreal viewPos;
+ qreal highlightStart;
+ qreal highlightEnd;
+ if (d->isRightToLeft()) {
+ viewPos = -d->position()-d->size();
+ highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd;
+ } else {
+ viewPos = d->position();
+ highlightStart = d->highlightRangeStart;
+ highlightEnd = d->highlightRangeEnd;
+ }
qreal pos = viewPos;
if (d->haveHighlightRange) {
if (d->highlightRange == StrictlyEnforceRange) {
- if (trackedPos > pos + d->highlightRangeEnd - d->trackedItem->size())
- pos = trackedPos - d->highlightRangeEnd + d->trackedItem->size();
- if (trackedPos < pos + d->highlightRangeStart)
- pos = trackedPos - d->highlightRangeStart;
+ if (trackedPos > pos + highlightEnd - d->trackedItem->size())
+ pos = trackedPos - highlightEnd + d->trackedItem->size();
+ if (trackedPos < pos + highlightStart)
+ pos = trackedPos - highlightStart;
} else {
- if (trackedPos < d->startPosition() + d->highlightRangeStart) {
+ if (trackedPos < d->startPosition() + highlightStart) {
pos = d->startPosition();
- } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + d->highlightRangeEnd) {
+ } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + highlightEnd) {
pos = d->endPosition() - d->size() + 1;
if (pos < d->startPosition())
pos = d->startPosition();
} else {
- if (trackedPos < viewPos + d->highlightRangeStart) {
- pos = trackedPos - d->highlightRangeStart;
- } else if (trackedPos > viewPos + d->highlightRangeEnd - trackedSize) {
- pos = trackedPos - d->highlightRangeEnd + trackedSize;
+ if (trackedPos < viewPos + highlightStart) {
+ pos = trackedPos - highlightStart;
+ } else if (trackedPos > viewPos + highlightEnd - trackedSize) {
+ pos = trackedPos - highlightEnd + trackedSize;
}
}
}
@@ -2881,7 +3159,9 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count)
d->updateUnrequestedIndexes();
d->moveReason = QDeclarativeListViewPrivate::Other;
+ qreal tempPos = d->isRightToLeft() ? -d->position()-d->size() : d->position();
int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0;
+
if (index < 0) {
int i = d->visibleItems.count() - 1;
while (i > 0 && d->visibleItems.at(i)->index == -1)
@@ -2890,7 +3170,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count)
// there are no visible items except items marked for removal
index = d->visibleItems.count();
} else if (d->visibleItems.at(i)->index + 1 == modelIndex
- && d->visibleItems.at(i)->endPosition() < d->buffer+d->position()+d->size()-1) {
+ && d->visibleItems.at(i)->endPosition() < d->buffer+tempPos+d->size()-1) {
// Special case of appending an item to the model.
index = d->visibleItems.count();
} else {
@@ -2935,7 +3215,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count)
// Insert items before the visible item.
int insertionIdx = index;
int i = 0;
- int from = d->position() - d->buffer;
+ int from = tempPos - d->buffer;
for (i = count-1; i >= 0 && pos > from; --i) {
if (!addedVisible) {
d->scheduleLayout();
@@ -2965,7 +3245,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count)
}
} else {
int i = 0;
- int to = d->buffer+d->position()+d->size()-1;
+ int to = d->buffer+tempPos+d->size()-1;
for (i = 0; i < count && pos <= to; ++i) {
if (!addedVisible) {
d->scheduleLayout();
@@ -2992,10 +3272,10 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count)
if (d->currentItem) {
d->currentItem->index = d->currentIndex;
d->currentItem->setPosition(d->currentItem->position() + diff);
- } else if (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared)) {
- d->updateCurrent(0);
}
emit currentIndexChanged();
+ } else if (!d->itemCount && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) {
+ d->updateCurrent(0);
}
// Update the indexes of the following visible items.
for (; index < d->visibleItems.count(); ++index) {
@@ -3076,6 +3356,8 @@ void QDeclarativeListView::itemsRemoved(int modelIndex, int count)
d->currentIndex = -1;
if (d->itemCount)
d->updateCurrent(qMin(modelIndex, d->itemCount-1));
+ else
+ emit currentIndexChanged();
}
// update visibleIndex
@@ -3241,11 +3523,8 @@ void QDeclarativeListView::itemsChanged(int, int)
void QDeclarativeListView::modelReset()
{
Q_D(QDeclarativeListView);
- d->clear();
- d->setPosition(0);
- refill();
d->moveReason = QDeclarativeListViewPrivate::SetIndex;
- d->updateCurrent(d->currentIndex);
+ d->regenerate();
if (d->highlight && d->currentItem) {
if (d->autoHighlight)
d->highlight->setPosition(d->currentItem->position());
@@ -3261,10 +3540,14 @@ void QDeclarativeListView::createdItem(int index, QDeclarativeItem *item)
if (d->requestedIndex != index) {
item->setParentItem(contentItem());
d->unrequestedItems.insert(item, index);
- if (d->orient == QDeclarativeListView::Vertical)
+ if (d->orient == QDeclarativeListView::Vertical) {
item->setY(d->positionAt(index));
- else
- item->setX(d->positionAt(index));
+ } else {
+ if (d->isRightToLeft())
+ item->setX(-d->positionAt(index)-item->width());
+ else
+ item->setX(d->positionAt(index));
+ }
}
}
diff --git a/src/declarative/graphicsitems/qdeclarativelistview_p.h b/src/declarative/graphicsitems/qdeclarativelistview_p.h
index 265f4bd..3b12225 100644
--- a/src/declarative/graphicsitems/qdeclarativelistview_p.h
+++ b/src/declarative/graphicsitems/qdeclarativelistview_p.h
@@ -107,12 +107,14 @@ class Q_AUTOTEST_EXPORT QDeclarativeListView : public QDeclarativeFlickable
Q_PROPERTY(qreal highlightResizeSpeed READ highlightResizeSpeed WRITE setHighlightResizeSpeed NOTIFY highlightResizeSpeedChanged)
Q_PROPERTY(int highlightResizeDuration READ highlightResizeDuration WRITE setHighlightResizeDuration NOTIFY highlightResizeDurationChanged)
- Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged)
- Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged)
+ Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged RESET resetPreferredHighlightBegin)
+ Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged RESET resetPreferredHighlightEnd)
Q_PROPERTY(HighlightRangeMode highlightRangeMode READ highlightRangeMode WRITE setHighlightRangeMode NOTIFY highlightRangeModeChanged)
Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1)
Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged)
Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
Q_PROPERTY(QDeclarativeViewSection *section READ sectionCriteria CONSTANT)
@@ -158,9 +160,11 @@ public:
qreal preferredHighlightBegin() const;
void setPreferredHighlightBegin(qreal);
+ void resetPreferredHighlightBegin();
qreal preferredHighlightEnd() const;
void setPreferredHighlightEnd(qreal);
+ void resetPreferredHighlightEnd();
qreal spacing() const;
void setSpacing(qreal spacing);
@@ -169,6 +173,10 @@ public:
Orientation orientation() const;
void setOrientation(Orientation);
+ Qt::LayoutDirection layoutDirection() const;
+ void setLayoutDirection(Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
+
bool isWrapEnabled() const;
void setWrapEnabled(bool);
@@ -220,6 +228,8 @@ Q_SIGNALS:
void countChanged();
void spacingChanged();
void orientationChanged();
+ Q_REVISION(1) void layoutDirectionChanged();
+ Q_REVISION(1) void effectiveLayoutDirectionChanged();
void currentIndexChanged();
void currentSectionChanged();
void highlightMoveSpeedChanged();
diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp
index 4e401e9..778b8b9 100644
--- a/src/declarative/graphicsitems/qdeclarativepathview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp
@@ -796,6 +796,7 @@ void QDeclarativePathView::setPreferredHighlightBegin(qreal start)
return;
d->highlightRangeStart = start;
d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ refill();
emit preferredHighlightBeginChanged();
}
@@ -812,6 +813,7 @@ void QDeclarativePathView::setPreferredHighlightEnd(qreal end)
return;
d->highlightRangeEnd = end;
d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
+ refill();
emit preferredHighlightEndChanged();
}
diff --git a/src/declarative/graphicsitems/qdeclarativepincharea.cpp b/src/declarative/graphicsitems/qdeclarativepincharea.cpp
index eae83f6..9bc3d8d 100644
--- a/src/declarative/graphicsitems/qdeclarativepincharea.cpp
+++ b/src/declarative/graphicsitems/qdeclarativepincharea.cpp
@@ -300,9 +300,8 @@ void QDeclarativePinchArea::updatePinch()
d->stealMouse = false;
setKeepMouseGrab(false);
d->inPinch = false;
- const qreal rotationAngle = d->pinchStartAngle - d->pinchLastAngle;
QPointF pinchCenter = mapFromScene(d->sceneLastCenter);
- QDeclarativePinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, rotationAngle);
+ QDeclarativePinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, d->pinchRotation);
pe.setStartCenter(d->pinchStartCenter);
pe.setPreviousCenter(pinchCenter);
pe.setPreviousAngle(d->pinchLastAngle);
@@ -349,6 +348,7 @@ void QDeclarativePinchArea::updatePinch()
d->pinchStartAngle = angle;
d->pinchLastScale = 1.0;
d->pinchLastAngle = angle;
+ d->pinchRotation = 0.0;
d->lastPoint1 = d->touchPoints.at(0).pos();
d->lastPoint2 = d->touchPoints.at(1).pos();
QDeclarativePinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0);
@@ -380,11 +380,14 @@ void QDeclarativePinchArea::updatePinch()
}
} else if (d->pinchStartDist > 0) {
qreal scale = dist / d->pinchStartDist;
- qreal rotationAngle = d->pinchStartAngle - angle;
- if (rotationAngle > 180)
- rotationAngle -= 360;
+ qreal da = d->pinchLastAngle - angle;
+ if (da > 180)
+ da -= 360;
+ else if (da < -180)
+ da += 360;
+ d->pinchRotation += da;
QPointF pinchCenter = mapFromScene(sceneCenter);
- QDeclarativePinchEvent pe(pinchCenter, scale, angle, rotationAngle);
+ QDeclarativePinchEvent pe(pinchCenter, scale, angle, d->pinchRotation);
pe.setStartCenter(d->pinchStartCenter);
pe.setPreviousCenter(mapFromScene(d->sceneLastCenter));
pe.setPreviousAngle(d->pinchLastAngle);
@@ -422,7 +425,7 @@ void QDeclarativePinchArea::updatePinch()
}
if (d->pinchStartRotation >= pinch()->minimumRotation()
&& d->pinchStartRotation <= pinch()->maximumRotation()) {
- qreal r = rotationAngle + d->pinchStartRotation;
+ qreal r = d->pinchRotation + d->pinchStartRotation;
r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation());
pinch()->target()->setRotation(r);
}
diff --git a/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h b/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h
index 5641e35..cd5cf2a 100644
--- a/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h
+++ b/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h
@@ -68,7 +68,9 @@ class QDeclarativePinchAreaPrivate : public QDeclarativeItemPrivate
public:
QDeclarativePinchAreaPrivate()
: absorb(true), stealMouse(false), inPinch(false)
- , pinchRejected(false), pinch(0), pinchStartDist(0)
+ , pinchRejected(false), pinch(0), pinchStartDist(0), pinchStartScale(1.0)
+ , pinchLastScale(1.0), pinchStartRotation(0.0), pinchStartAngle(0.0)
+ , pinchLastAngle(0.0), pinchRotation(0.0)
{
}
@@ -97,6 +99,7 @@ public:
qreal pinchStartRotation;
qreal pinchStartAngle;
qreal pinchLastAngle;
+ qreal pinchRotation;
QPointF sceneStartCenter;
QPointF pinchStartCenter;
QPointF sceneLastCenter;
diff --git a/src/declarative/graphicsitems/qdeclarativepositioners.cpp b/src/declarative/graphicsitems/qdeclarativepositioners.cpp
index c0be2a2..8a9bdb3 100644
--- a/src/declarative/graphicsitems/qdeclarativepositioners.cpp
+++ b/src/declarative/graphicsitems/qdeclarativepositioners.cpp
@@ -385,7 +385,7 @@ void QDeclarativeBasePositioner::finishApplyTransitions()
Items with a width or height of 0 will not be positioned.
- \sa Row, Grid, Flow, {declarative/positioners/addandremove}{Positioners example}
+ \sa Row, Grid, Flow, {declarative/positioners}{Positioners example}
*/
/*!
\qmlproperty Transition Column::add
@@ -425,7 +425,7 @@ void QDeclarativeBasePositioner::finishApplyTransitions()
}
\endqml
- \sa add, {declarative/positioners/addandremove}{Positioners example}
+ \sa add, {declarative/positioners}{Positioners example}
*/
/*!
\qmlproperty int Column::spacing
@@ -528,7 +528,7 @@ void QDeclarativeColumn::reportConflictingAnchors()
Items with a width or height of 0 will not be positioned.
- \sa Column, Grid, Flow, {declarative/positioners/addandremove}{Positioners example}
+ \sa Column, Grid, Flow, {declarative/positioners}{Positioners example}
*/
/*!
\qmlproperty Transition Row::add
@@ -567,7 +567,7 @@ void QDeclarativeColumn::reportConflictingAnchors()
}
\endqml
- \sa add, {declarative/positioners/addandremove}{Positioners example}
+ \sa add, {declarative/positioners}{Positioners example}
*/
/*!
\qmlproperty int Row::spacing
@@ -578,7 +578,7 @@ void QDeclarativeColumn::reportConflictingAnchors()
\sa Grid::spacing
*/
QDeclarativeRow::QDeclarativeRow(QDeclarativeItem *parent)
-: QDeclarativeBasePositioner(Horizontal, parent), m_layoutDirection(Qt::LeftToRight)
+: QDeclarativeBasePositioner(Horizontal, parent)
{
}
@@ -597,24 +597,43 @@ QDeclarativeRow::QDeclarativeRow(QDeclarativeItem *parent)
the right anchor remains to the right of the row.
\endlist
- \sa Grid::layoutDirection, Flow::layoutDirection, {declarative/positioners/layoutdirection}{Layout directions example}
+ \sa Grid::layoutDirection, Flow::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
*/
Qt::LayoutDirection QDeclarativeRow::layoutDirection() const
{
- return m_layoutDirection;
+ return QDeclarativeBasePositionerPrivate::getLayoutDirection(this);
}
void QDeclarativeRow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
{
- if (m_layoutDirection != layoutDirection) {
- m_layoutDirection = layoutDirection;
+ QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate* >(QDeclarativeBasePositionerPrivate::get(this));
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
prePositioning();
emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
}
}
+/*!
+ \qmlproperty enumeration Row::effectiveLayoutDirection
+ This property holds the effective layout direction of the row positioner.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the row positioner will be mirrored. However, the
+ property \l {Row::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa Row::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QDeclarativeRow::effectiveLayoutDirection() const
+{
+ return QDeclarativeBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
void QDeclarativeRow::doPositioning(QSizeF *contentSize)
{
+ QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this));
int hoffset = 0;
QList<int> hoffsets;
@@ -623,7 +642,7 @@ void QDeclarativeRow::doPositioning(QSizeF *contentSize)
if (!child.item || !child.isVisible)
continue;
- if(m_layoutDirection == Qt::LeftToRight){
+ if(d->isLeftToRight()){
if(child.item->x() != hoffset)
positionX(hoffset, child);
}else{
@@ -638,7 +657,7 @@ void QDeclarativeRow::doPositioning(QSizeF *contentSize)
contentSize->setWidth(hoffset - spacing());
- if(m_layoutDirection == Qt::LeftToRight)
+ if(d->isLeftToRight())
return;
//Right to Left layout
@@ -734,7 +753,7 @@ void QDeclarativeRow::reportConflictingAnchors()
Items with a width or height of 0 will not be positioned.
- \sa Flow, Row, Column, {declarative/positioners/addandremove}{Positioners example}
+ \sa Flow, Row, Column, {declarative/positioners}{Positioners example}
*/
/*!
\qmlproperty Transition Grid::add
@@ -772,7 +791,7 @@ void QDeclarativeRow::reportConflictingAnchors()
}
\endqml
- \sa add, {declarative/positioners/addandremove}{Positioners example}
+ \sa add, {declarative/positioners}{Positioners example}
*/
/*!
\qmlproperty int Grid::spacing
@@ -792,7 +811,7 @@ void QDeclarativeRow::reportConflictingAnchors()
\sa rows, columns
*/
QDeclarativeGrid::QDeclarativeGrid(QDeclarativeItem *parent) :
- QDeclarativeBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_flow(LeftToRight), m_layoutDirection(Qt::LeftToRight)
+ QDeclarativeBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_flow(LeftToRight)
{
}
@@ -868,33 +887,51 @@ void QDeclarativeGrid::setFlow(Flow flow)
Possible values are:
\list
- \o Qt.LeftToRight (default) - Items are positioned beginning
- from the top, left anchor. The flow direction is dependent
- on the \l Grid::flow property.
- \o Qt.RightToLeft - Items are positioned beginning from the
- top, right anchor. The flow direction is dependent on the
+ \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
+ and left to right. The flow direction is dependent on the
+ \l Grid::flow property.
+ \o Qt.RightToLeft - Items are positioned from the top to bottom,
+ and right to left. The flow direction is dependent on the
\l Grid::flow property.
\endlist
- \sa Flow::layoutDirection, Row::layoutDirection, {declarative/positioners/layoutdirection}{Layout directions example}
+ \sa Flow::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
*/
Qt::LayoutDirection QDeclarativeGrid::layoutDirection() const
{
- return m_layoutDirection;
+ return QDeclarativeBasePositionerPrivate::getLayoutDirection(this);
}
void QDeclarativeGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
{
- if (m_layoutDirection != layoutDirection) {
- m_layoutDirection = layoutDirection;
+ QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this));
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
prePositioning();
emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
}
}
-void QDeclarativeGrid::doPositioning(QSizeF *contentSize)
+/*!
+ \qmlproperty enumeration Grid::effectiveLayoutDirection
+ This property holds the effective layout direction of the grid positioner.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the grid positioner will be mirrored. However, the
+ property \l {Grid::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QDeclarativeGrid::effectiveLayoutDirection() const
{
+ return QDeclarativeBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+void QDeclarativeGrid::doPositioning(QSizeF *contentSize)
+{
+ QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this));
int c = m_columns;
int r = m_rows;
//Is allocating the extra QPODVector too much overhead?
@@ -984,7 +1021,7 @@ void QDeclarativeGrid::doPositioning(QSizeF *contentSize)
end = widthSum;
int xoffset=0;
- if(m_layoutDirection == Qt::RightToLeft)
+ if(!d->isLeftToRight())
xoffset=end;
int yoffset=0;
int curRow =0;
@@ -992,7 +1029,7 @@ void QDeclarativeGrid::doPositioning(QSizeF *contentSize)
for (int i = 0; i < visibleItems.count(); ++i) {
const PositionedItem &child = visibleItems.at(i);
int childXOffset = xoffset;
- if(m_layoutDirection == Qt::RightToLeft)
+ if(!d->isLeftToRight())
childXOffset -= QGraphicsItemPrivate::get(child.item)->width();
if((child.item->x()!=childXOffset)||(child.item->y()!=yoffset)){
positionX(childXOffset, child);
@@ -1000,7 +1037,7 @@ void QDeclarativeGrid::doPositioning(QSizeF *contentSize)
}
if (m_flow == LeftToRight) {
- if(m_layoutDirection == Qt::LeftToRight)
+ if(d->isLeftToRight())
xoffset+=maxColWidth[curCol]+spacing();
else
xoffset-=maxColWidth[curCol]+spacing();
@@ -1008,7 +1045,7 @@ void QDeclarativeGrid::doPositioning(QSizeF *contentSize)
curCol%=c;
if (!curCol){
yoffset+=maxRowHeight[curRow]+spacing();
- if(m_layoutDirection == Qt::LeftToRight)
+ if(d->isLeftToRight())
xoffset=0;
else
xoffset=end;
@@ -1021,7 +1058,7 @@ void QDeclarativeGrid::doPositioning(QSizeF *contentSize)
curRow++;
curRow%=r;
if (!curRow){
- if(m_layoutDirection == Qt::LeftToRight)
+ if(d->isLeftToRight())
xoffset+=maxColWidth[curCol]+spacing();
else
xoffset-=maxColWidth[curCol]+spacing();
@@ -1100,7 +1137,7 @@ void QDeclarativeGrid::reportConflictingAnchors()
Items with a width or height of 0 will not be positioned.
- \sa Column, Row, Grid, {declarative/positioners/addandremove}{Positioners example}
+ \sa Column, Row, Grid, {declarative/positioners}{Positioners example}
*/
/*!
\qmlproperty Transition Flow::add
@@ -1139,7 +1176,7 @@ void QDeclarativeGrid::reportConflictingAnchors()
}
\endqml
- \sa add, {declarative/positioners/addandremove}{Positioners example}
+ \sa add, {declarative/positioners}{Positioners example}
*/
/*!
\qmlproperty int Flow::spacing
@@ -1156,12 +1193,10 @@ class QDeclarativeFlowPrivate : public QDeclarativeBasePositionerPrivate
public:
QDeclarativeFlowPrivate()
- : QDeclarativeBasePositionerPrivate(), flow(QDeclarativeFlow::LeftToRight),
- layoutDirection(Qt::LeftToRight)
+ : QDeclarativeBasePositionerPrivate(), flow(QDeclarativeFlow::LeftToRight)
{}
QDeclarativeFlow::Flow flow;
- Qt::LayoutDirection layoutDirection;
};
QDeclarativeFlow::QDeclarativeFlow(QDeclarativeItem *parent)
@@ -1212,15 +1247,15 @@ void QDeclarativeFlow::setFlow(Flow flow)
Possible values are:
\list
- \o Qt.LeftToRight (default) - Items are positioned beginning
- from the top, left anchor. The flow direction is dependent
- on the \l Flow::flow property.
- \o Qt.RightToLeft - Items are positioned beginning from the
- top, right anchor. The flow direction is dependent on the
+ \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
+ and left to right. The flow direction is dependent on the
+ \l Flow::flow property.
+ \o Qt.RightToLeft - Items are positioned from the top to bottom,
+ and right to left. The flow direction is dependent on the
\l Flow::flow property.
\endlist
- \sa Grid::layoutDirection, Row::layoutDirection, {declarative/positioners/layoutdirection}{Layout directions example}
+ \sa Grid::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
*/
Qt::LayoutDirection QDeclarativeFlow::layoutDirection() const
@@ -1236,9 +1271,26 @@ void QDeclarativeFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
d->layoutDirection = layoutDirection;
prePositioning();
emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
}
}
+/*!
+ \qmlproperty enumeration Flow::effectiveLayoutDirection
+ This property holds the effective layout direction of the flow positioner.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the grid positioner will be mirrored. However, the
+ property \l {Flow::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa Flow::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QDeclarativeFlow::effectiveLayoutDirection() const
+{
+ return QDeclarativeBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
void QDeclarativeFlow::doPositioning(QSizeF *contentSize)
{
Q_D(QDeclarativeFlow);
@@ -1268,7 +1320,7 @@ void QDeclarativeFlow::doPositioning(QSizeF *contentSize)
}
}
- if(d->layoutDirection == Qt::LeftToRight){
+ if(d->isLeftToRight()){
if(child.item->x() != hoffset)
positionX(hoffset, child);
}else{
@@ -1291,7 +1343,7 @@ void QDeclarativeFlow::doPositioning(QSizeF *contentSize)
}
}
- if(d->layoutDirection == Qt::LeftToRight)
+ if(d->isLeftToRight())
return;
int end;
diff --git a/src/declarative/graphicsitems/qdeclarativepositioners_p.h b/src/declarative/graphicsitems/qdeclarativepositioners_p.h
index 55d8fa1..214c04f 100644
--- a/src/declarative/graphicsitems/qdeclarativepositioners_p.h
+++ b/src/declarative/graphicsitems/qdeclarativepositioners_p.h
@@ -130,20 +130,22 @@ class Q_AUTOTEST_EXPORT QDeclarativeRow: public QDeclarativeBasePositioner
{
Q_OBJECT
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1)
public:
QDeclarativeRow(QDeclarativeItem *parent=0);
Qt::LayoutDirection layoutDirection() const;
void setLayoutDirection (Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
Q_SIGNALS:
Q_REVISION(1) void layoutDirectionChanged();
+ Q_REVISION(1) void effectiveLayoutDirectionChanged();
protected:
virtual void doPositioning(QSizeF *contentSize);
virtual void reportConflictingAnchors();
private:
- Qt::LayoutDirection m_layoutDirection;
Q_DISABLE_COPY(QDeclarativeRow)
};
@@ -154,7 +156,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeGrid : public QDeclarativeBasePositioner
Q_PROPERTY(int columns READ columns WRITE setColumns NOTIFY columnsChanged)
Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1)
-
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1)
public:
QDeclarativeGrid(QDeclarativeItem *parent=0);
@@ -171,12 +173,14 @@ public:
Qt::LayoutDirection layoutDirection() const;
void setLayoutDirection (Qt::LayoutDirection);
+ Qt::LayoutDirection effectiveLayoutDirection() const;
Q_SIGNALS:
void rowsChanged();
void columnsChanged();
void flowChanged();
Q_REVISION(1) void layoutDirectionChanged();
+ Q_REVISION(1) void effectiveLayoutDirectionChanged();
protected:
virtual void doPositioning(QSizeF *contentSize);
@@ -186,7 +190,6 @@ private:
int m_rows;
int m_columns;
Flow m_flow;
- Qt::LayoutDirection m_layoutDirection;
Q_DISABLE_COPY(QDeclarativeGrid)
};
@@ -194,8 +197,9 @@ class QDeclarativeFlowPrivate;
class Q_AUTOTEST_EXPORT QDeclarativeFlow: public QDeclarativeBasePositioner
{
Q_OBJECT
- Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1)
Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
+ Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1)
+ Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1)
public:
QDeclarativeFlow(QDeclarativeItem *parent=0);
@@ -206,10 +210,11 @@ public:
Qt::LayoutDirection layoutDirection() const;
void setLayoutDirection (Qt::LayoutDirection);
-
+ Qt::LayoutDirection effectiveLayoutDirection() const;
Q_SIGNALS:
void flowChanged();
Q_REVISION(1) void layoutDirectionChanged();
+ Q_REVISION(1) void effectiveLayoutDirectionChanged();
protected:
virtual void doPositioning(QSizeF *contentSize);
diff --git a/src/declarative/graphicsitems/qdeclarativepositioners_p_p.h b/src/declarative/graphicsitems/qdeclarativepositioners_p_p.h
index df105c6..e80129d 100644
--- a/src/declarative/graphicsitems/qdeclarativepositioners_p_p.h
+++ b/src/declarative/graphicsitems/qdeclarativepositioners_p_p.h
@@ -75,7 +75,7 @@ public:
QDeclarativeBasePositionerPrivate()
: spacing(0), type(QDeclarativeBasePositioner::None)
, moveTransition(0), addTransition(0), queuedPositioning(false)
- , doingPositioning(false), anchorConflict(false)
+ , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight)
{
}
@@ -100,6 +100,9 @@ public:
bool doingPositioning : 1;
bool anchorConflict : 1;
+ Qt::LayoutDirection layoutDirection;
+
+
void schedulePositioning()
{
Q_Q(QDeclarativeBasePositioner);
@@ -109,6 +112,18 @@ public:
}
}
+ void mirrorChange() {
+ Q_Q(QDeclarativeBasePositioner);
+ if (type != QDeclarativeBasePositioner::Vertical)
+ q->prePositioning();
+ }
+ bool isLeftToRight() const {
+ if (type == QDeclarativeBasePositioner::Vertical)
+ return true;
+ else
+ return effectiveLayoutMirror ? layoutDirection == Qt::RightToLeft : layoutDirection == Qt::LeftToRight;
+ }
+
virtual void itemSiblingOrderChanged(QDeclarativeItem* other)
{
Q_UNUSED(other);
@@ -139,6 +154,19 @@ public:
Q_Q(QDeclarativeBasePositioner);
q->positionedItems.removeOne(QDeclarativeBasePositioner::PositionedItem(item));
}
+
+ static Qt::LayoutDirection getLayoutDirection(const QDeclarativeBasePositioner *positioner)
+ {
+ return positioner->d_func()->layoutDirection;
+ }
+
+ static Qt::LayoutDirection getEffectiveLayoutDirection(const QDeclarativeBasePositioner *positioner)
+ {
+ if (positioner->d_func()->effectiveLayoutMirror)
+ return positioner->d_func()->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
+ else
+ return positioner->d_func()->layoutDirection;
+ }
};
QT_END_NAMESPACE
diff --git a/src/declarative/graphicsitems/qdeclarativerectangle.cpp b/src/declarative/graphicsitems/qdeclarativerectangle.cpp
index 7d36524..b3235ef 100644
--- a/src/declarative/graphicsitems/qdeclarativerectangle.cpp
+++ b/src/declarative/graphicsitems/qdeclarativerectangle.cpp
@@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE
void QDeclarativePen::setColor(const QColor &c)
{
_color = c;
- _valid = _color.alpha() ? true : false;
+ _valid = (_color.alpha() && _width >= 1) ? true : false;
emit penChanged();
}
@@ -80,7 +80,7 @@ void QDeclarativePen::setWidth(int w)
return;
_width = w;
- _valid = (_width < 1) ? false : true;
+ _valid = (_color.alpha() && _width >= 1) ? true : false;
emit penChanged();
}
diff --git a/src/declarative/graphicsitems/qdeclarativetext.cpp b/src/declarative/graphicsitems/qdeclarativetext.cpp
index 044425d..fdc1a71 100644
--- a/src/declarative/graphicsitems/qdeclarativetext.cpp
+++ b/src/declarative/graphicsitems/qdeclarativetext.cpp
@@ -50,7 +50,6 @@
#include <QTextLayout>
#include <QTextLine>
#include <QTextDocument>
-#include <QTextCursor>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QAbstractTextDocumentLayout>
@@ -97,13 +96,12 @@ DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE);
QString QDeclarativeTextPrivate::elideChar = QString(0x2026);
QDeclarativeTextPrivate::QDeclarativeTextPrivate()
-: color((QRgb)0), style(QDeclarativeText::Normal), hAlign(QDeclarativeText::AlignLeft),
+: color((QRgb)0), style(QDeclarativeText::Normal), hAlign(QDeclarativeText::AlignLeft),
vAlign(QDeclarativeText::AlignTop), elideMode(QDeclarativeText::ElideNone),
format(QDeclarativeText::AutoText), wrapMode(QDeclarativeText::NoWrap), lineHeight(1),
- lineHeightMode(QDeclarativeText::ProportionalHeight),
- lineCount(1), truncated(false), maximumLineCount(INT_MAX),
+ lineHeightMode(QDeclarativeText::ProportionalHeight), lineCount(1), truncated(false), maximumLineCount(INT_MAX),
maximumLineCountValid(false), imageCacheDirty(true), updateOnComponentComplete(true), richText(false), singleline(false),
- cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false), naturalWidth(0), doc(0)
+ cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false), hAlignImplicit(true), rightToLeftText(false), naturalWidth(0), doc(0)
{
cacheAllTextAsImage = enableImageCache();
QGraphicsItemPrivate::acceptedMouseButtons = Qt::LeftButton;
@@ -283,18 +281,26 @@ void QDeclarativeTextPrivate::updateSize()
//setup instance of QTextLayout for all cases other than richtext
if (!richText) {
- size = setupTextLayout();
- if (layedOutTextSize != size) {
+ QRect textRect = setupTextLayout();
+ if (layedOutTextRect.size() != textRect.size())
q->prepareGeometryChange();
- layedOutTextSize = size;
- }
+ layedOutTextRect = textRect;
+ size = textRect.size();
dy -= size.height();
} else {
singleline = false; // richtext can't elide or be optimized for single-line case
ensureDoc();
doc->setDefaultFont(font);
+
+ QDeclarativeText::HAlignment horizontalAlignment = q->effectiveHAlign();
+ if (rightToLeftText) {
+ if (horizontalAlignment == QDeclarativeText::AlignLeft)
+ horizontalAlignment = QDeclarativeText::AlignRight;
+ else if (horizontalAlignment == QDeclarativeText::AlignRight)
+ horizontalAlignment = QDeclarativeText::AlignLeft;
+ }
QTextOption option;
- option.setAlignment((Qt::Alignment)int(hAlign | vAlign));
+ option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
option.setWrapMode(QTextOption::WrapMode(wrapMode));
doc->setDefaultTextOption(option);
if (requireImplicitWidth && q->widthValid()) {
@@ -307,9 +313,9 @@ void QDeclarativeTextPrivate::updateSize()
doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
dy -= (int)doc->size().height();
QSize dsize = doc->size().toSize();
- if (dsize != layedOutTextSize) {
+ if (dsize != layedOutTextRect.size()) {
q->prepareGeometryChange();
- layedOutTextSize = dsize;
+ layedOutTextRect = QRect(QPoint(0,0), dsize);
}
size = QSize(int(doc->idealWidth()),dsize.height());
}
@@ -344,45 +350,29 @@ void QDeclarativeTextPrivate::updateSize()
Returns the size of the final text. This can be used to position the text vertically (the text is
already absolutely positioned horizontally).
*/
-QSize QDeclarativeTextPrivate::setupTextLayout()
+QRect QDeclarativeTextPrivate::setupTextLayout()
{
// ### text layout handling should be profiled and optimized as needed
// what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
Q_Q(QDeclarativeText);
layout.setCacheEnabled(true);
- qreal height = 0;
- qreal widthUsed = 0;
qreal lineWidth = 0;
- int visibleTextLength = 0;
int visibleCount = 0;
//set manual width
- if ((wrapMode != QDeclarativeText::NoWrap || elideMode != QDeclarativeText::ElideNone) && q->widthValid())
+ if (q->widthValid())
lineWidth = q->width();
QTextOption textOption = layout.textOption();
- if (hAlign == QDeclarativeText::AlignJustify)
- textOption.setAlignment(Qt::Alignment(hAlign));
+ textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
layout.setTextOption(textOption);
- QDeclarativeText::HAlignment hAlignment = hAlign;
- if(text.isRightToLeft()) {
- if ((hAlign == QDeclarativeText::AlignLeft) || (hAlign == QDeclarativeText::AlignJustify)) {
- hAlignment = QDeclarativeText::AlignRight;
- } else if (hAlign == QDeclarativeText::AlignRight) {
- hAlignment = QDeclarativeText::AlignLeft;
- } else {
- hAlignment = hAlign;
- }
- }
-
bool elideText = false;
bool truncate = false;
QFontMetrics fm(layout.font());
- qreal elideWidth = fm.width(elideChar);
elidePos = QPointF();
if (requireImplicitWidth && q->widthValid()) {
@@ -394,47 +384,47 @@ QSize QDeclarativeTextPrivate::setupTextLayout()
break;
}
layout.endLayout();
- naturalWidth = 0;
+ QRectF br;
for (int i = 0; i < layout.lineCount(); ++i) {
QTextLine line = layout.lineAt(i);
- naturalWidth = qMax(naturalWidth, line.naturalTextWidth());
+ br = br.united(line.naturalTextRect());
}
+ naturalWidth = br.width();
}
if (maximumLineCountValid) {
layout.beginLayout();
if (!lineWidth)
lineWidth = INT_MAX;
- int y = 0;
int linesLeft = maximumLineCount;
+ int visibleTextLength = 0;
while (linesLeft > 0) {
QTextLine line = layout.createLine();
if (!line.isValid())
break;
visibleCount++;
- line.setLineWidth(lineWidth);
+ if (lineWidth)
+ line.setLineWidth(lineWidth);
visibleTextLength += line.textLength();
if (--linesLeft == 0) {
if (visibleTextLength < text.length()) {
truncate = true;
if (elideMode==QDeclarativeText::ElideRight && q->widthValid()) {
+ qreal elideWidth = fm.width(elideChar);
// Need to correct for alignment
line.setLineWidth(lineWidth-elideWidth);
- int x = line.naturalTextWidth();
- if (hAlignment == QDeclarativeText::AlignRight) {
- x = q->width()-elideWidth;
- } else if (hAlignment == QDeclarativeText::AlignHCenter) {
- x = (q->width()+line.naturalTextWidth()-elideWidth)/2;
+ if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
+ line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
+ elidePos.setX(line.naturalTextRect().left() - elideWidth);
+ } else {
+ elidePos.setX(line.naturalTextRect().right());
}
- elidePos = QPointF(x, y + fm.ascent());
elideText = true;
}
}
}
-
- y += line.height();
}
layout.endLayout();
@@ -456,36 +446,23 @@ QSize QDeclarativeTextPrivate::setupTextLayout()
layout.endLayout();
}
+ qreal height = 0;
+ QRectF br;
for (int i = 0; i < layout.lineCount(); ++i) {
QTextLine line = layout.lineAt(i);
- widthUsed = qMax(widthUsed, line.naturalTextWidth());
+ // set line spacing
+ line.setPosition(QPointF(line.position().x(), height));
+ if (elideText && i == layout.lineCount()-1) {
+ elidePos.setY(height + fm.ascent());
+ br = br.united(QRectF(elidePos, QSizeF(fm.width(elideChar), fm.ascent())));
+ }
+ br = br.united(line.naturalTextRect());
+ height += (lineHeightMode == QDeclarativeText::FixedHeight) ? lineHeight : line.height() * lineHeight;
}
+ br.setHeight(height);
- qreal layoutWidth = q->widthValid() ? q->width() : widthUsed;
if (!q->widthValid())
- naturalWidth = layoutWidth;
-
- qreal x = 0;
- for (int i = 0; i < layout.lineCount(); ++i) {
- QTextLine line = layout.lineAt(i);
- line.setPosition(QPointF(0, height));
- height += (lineHeightMode == QDeclarativeText::FixedHeight) ? lineHeight : line.height() * lineHeight;
-
- if (!cacheAllTextAsImage) {
- if ((hAlignment == QDeclarativeText::AlignLeft) || (hAlignment == QDeclarativeText::AlignJustify)) {
- x = 0;
- } else if (hAlignment == QDeclarativeText::AlignRight) {
- x = layoutWidth - line.naturalTextWidth();
- if (elideText && i == layout.lineCount()-1)
- x -= elideWidth; // Correct for when eliding multilines
- } else if (hAlignment == QDeclarativeText::AlignHCenter) {
- x = (layoutWidth - line.naturalTextWidth()) / 2;
- if (elideText && i == layout.lineCount()-1)
- x -= elideWidth/2; // Correct for when eliding multilines
- }
- line.setPosition(QPointF(x, line.y()));
- }
- }
+ naturalWidth = br.width();
//Update the number of visible lines
if (lineCount != visibleCount) {
@@ -493,7 +470,7 @@ QSize QDeclarativeTextPrivate::setupTextLayout()
emit q->lineCountChanged();
}
- return QSize(qCeil(widthUsed), qCeil(height));
+ return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
}
/*!
@@ -503,21 +480,7 @@ QSize QDeclarativeTextPrivate::setupTextLayout()
QPixmap QDeclarativeTextPrivate::textLayoutImage(bool drawStyle)
{
//do layout
- QSize size = layedOutTextSize;
-
- qreal x = 0;
- for (int i = 0; i < layout.lineCount(); ++i) {
- QTextLine line = layout.lineAt(i);
- if ((hAlign == QDeclarativeText::AlignLeft) || (hAlign == QDeclarativeText::AlignJustify)) {
- x = 0;
- } else if (hAlign == QDeclarativeText::AlignRight) {
- x = size.width() - line.naturalTextWidth();
- } else if (hAlign == QDeclarativeText::AlignHCenter) {
- x = (size.width() - line.naturalTextWidth()) / 2;
- }
- line.setPosition(QPointF(x, line.y()));
- }
-
+ QSize size = layedOutTextRect.size();
//paint text
QPixmap img(size);
if (!size.isEmpty()) {
@@ -530,7 +493,7 @@ QPixmap QDeclarativeTextPrivate::textLayoutImage(bool drawStyle)
#ifdef Q_WS_MAC
qt_applefontsmoothing_enabled = oldSmooth;
#endif
- drawTextLayout(&p, QPointF(0,0), drawStyle);
+ drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle);
}
return img;
}
@@ -548,7 +511,7 @@ void QDeclarativeTextPrivate::drawTextLayout(QPainter *painter, const QPointF &p
painter->setFont(font);
layout.draw(painter, pos);
if (!elidePos.isNull())
- painter->drawText(elidePos, elideChar);
+ painter->drawText(pos + elidePos, elideChar);
}
/*!
@@ -953,14 +916,18 @@ void QDeclarativeText::setText(const QString &n)
return;
d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n));
- if (d->richText && isComponentComplete()) {
- d->ensureDoc();
- d->doc->setText(n);
- }
-
d->text = n;
+ if (isComponentComplete()) {
+ if (d->richText) {
+ d->ensureDoc();
+ d->doc->setText(n);
+ d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+ } else {
+ d->rightToLeftText = d->text.isRightToLeft();
+ }
+ d->determineHorizontalAlignment();
+ }
d->updateLayout();
-
emit textChanged(d->text);
}
@@ -1083,9 +1050,12 @@ void QDeclarativeText::setStyleColor(const QColor &color)
/*!
\qmlproperty enumeration Text::horizontalAlignment
\qmlproperty enumeration Text::verticalAlignment
+ \qmlproperty enumeration Text::effectiveHorizontalAlignment
Sets the horizontal and vertical alignment of the text within the Text items
- width and height. By default, the text is top-left aligned.
+ width and height. By default, the text is vertically aligned to the top. Horizontal
+ alignment follows the natural alignment of the text, for example text that is read
+ from left to right will be aligned to the left.
The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and
\c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom
@@ -1095,6 +1065,11 @@ void QDeclarativeText::setStyleColor(const QColor &color)
all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will
need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to
that of the parent.
+
+ When using the attached property LayoutMirroring::enabled to mirror application
+ layouts, the horizontal alignment of text will also be mirrored. However, the property
+ \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
+ of Text, use the read-only property \c effectiveHorizontalAlignment.
*/
QDeclarativeText::HAlignment QDeclarativeText::hAlign() const
{
@@ -1105,16 +1080,78 @@ QDeclarativeText::HAlignment QDeclarativeText::hAlign() const
void QDeclarativeText::setHAlign(HAlignment align)
{
Q_D(QDeclarativeText);
- if (d->hAlign == align)
- return;
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete())
+ d->updateLayout();
+}
- if (isComponentComplete())
- prepareGeometryChange();
+void QDeclarativeText::resetHAlign()
+{
+ Q_D(QDeclarativeText);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete())
+ d->updateLayout();
+}
- d->hAlign = align;
- d->updateLayout();
+QDeclarativeText::HAlignment QDeclarativeText::effectiveHAlign() const
+{
+ Q_D(const QDeclarativeText);
+ QDeclarativeText::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QDeclarativeText::AlignLeft:
+ effectiveAlignment = QDeclarativeText::AlignRight;
+ break;
+ case QDeclarativeText::AlignRight:
+ effectiveAlignment = QDeclarativeText::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QDeclarativeTextPrivate::setHAlign(QDeclarativeText::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QDeclarativeText);
+ if (hAlign != alignment || forceAlign) {
+ QDeclarativeText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+
+ emit q->horizontalAlignmentChanged(hAlign);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QDeclarativeTextPrivate::determineHorizontalAlignment()
+{
+ Q_Q(QDeclarativeText);
+ if (hAlignImplicit && q->isComponentComplete()) {
+ bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
+ return setHAlign(alignToRight ? QDeclarativeText::AlignRight : QDeclarativeText::AlignLeft);
+ }
+ return false;
+}
- emit horizontalAlignmentChanged(align);
+void QDeclarativeTextPrivate::mirrorChange()
+{
+ Q_Q(QDeclarativeText);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QDeclarativeText::AlignRight || hAlign == QDeclarativeText::AlignLeft)) {
+ updateLayout();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
+}
+
+QTextDocument *QDeclarativeTextPrivate::textDocument()
+{
+ return doc;
}
QDeclarativeText::VAlignment QDeclarativeText::vAlign() const
@@ -1368,44 +1405,25 @@ QRectF QDeclarativeText::boundingRect() const
{
Q_D(const QDeclarativeText);
- int w = width();
- int h = height();
-
- int x = 0;
- int y = 0;
-
- QSize size = d->layedOutTextSize;
+ QRect rect = d->layedOutTextRect;
if (d->style != Normal)
- size += QSize(2,2);
+ rect.adjust(-1, 0, 1, 2);
// Could include font max left/right bearings to either side of rectangle.
- switch (d->hAlign) {
- case AlignLeft:
- case AlignJustify:
- x = 0;
- break;
- case AlignRight:
- x = w - size.width();
- break;
- case AlignHCenter:
- x = (w - size.width()) / 2;
- break;
- }
-
+ int h = height();
switch (d->vAlign) {
case AlignTop:
- y = 0;
break;
case AlignBottom:
- y = h - size.height();
+ rect.setY(h - rect.height());
break;
case AlignVCenter:
- y = (h - size.height()) / 2;
+ rect.setY((h - rect.height()) / 2);
break;
}
- return QRectF(x,y,size.width(),size.height());
+ return QRectF(rect);
}
/*! \internal */
@@ -1551,8 +1569,8 @@ void QDeclarativeText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWid
} else {
QRectF bounds = boundingRect();
- bool needClip = clip() && (d->layedOutTextSize.width() > width() ||
- d->layedOutTextSize.height() > height());
+ bool needClip = clip() && (d->layedOutTextRect.width() > width() ||
+ d->layedOutTextRect.height() > height());
if (needClip) {
p->save();
@@ -1584,7 +1602,11 @@ void QDeclarativeText::componentComplete()
if (d->richText) {
d->ensureDoc();
d->doc->setText(d->text);
+ d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
+ } else {
+ d->rightToLeftText = d->text.isRightToLeft();
}
+ d->determineHorizontalAlignment();
d->updateLayout();
}
}
diff --git a/src/declarative/graphicsitems/qdeclarativetext_p.h b/src/declarative/graphicsitems/qdeclarativetext_p.h
index b8835d1..a1153c2 100644
--- a/src/declarative/graphicsitems/qdeclarativetext_p.h
+++ b/src/declarative/graphicsitems/qdeclarativetext_p.h
@@ -69,7 +69,8 @@ class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeText : public QDeclarativeImplici
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
Q_PROPERTY(TextStyle style READ style WRITE setStyle NOTIFY styleChanged)
Q_PROPERTY(QColor styleColor READ styleColor WRITE setStyleColor NOTIFY styleColorChanged)
- Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign NOTIFY horizontalAlignmentChanged)
+ Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged)
+ Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged REVISION 1)
Q_PROPERTY(VAlignment verticalAlignment READ vAlign WRITE setVAlign NOTIFY verticalAlignmentChanged)
Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
Q_PROPERTY(int lineCount READ lineCount NOTIFY lineCountChanged REVISION 1)
@@ -133,6 +134,8 @@ public:
HAlignment hAlign() const;
void setHAlign(HAlignment align);
+ void resetHAlign();
+ HAlignment effectiveHAlign() const;
VAlignment vAlign() const;
void setVAlign(VAlignment align);
@@ -188,6 +191,7 @@ Q_SIGNALS:
void paintedSizeChanged();
Q_REVISION(1) void lineHeightChanged(qreal lineHeight);
Q_REVISION(1) void lineHeightModeChanged(LineHeightMode mode);
+ Q_REVISION(1) void effectiveHorizontalAlignmentChanged();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
diff --git a/src/declarative/graphicsitems/qdeclarativetext_p_p.h b/src/declarative/graphicsitems/qdeclarativetext_p_p.h
index 36ae123..e3ab62a 100644
--- a/src/declarative/graphicsitems/qdeclarativetext_p_p.h
+++ b/src/declarative/graphicsitems/qdeclarativetext_p_p.h
@@ -76,6 +76,10 @@ public:
void updateSize();
void updateLayout();
+ bool determineHorizontalAlignment();
+ bool setHAlign(QDeclarativeText::HAlignment, bool forceAlign = false);
+ void mirrorChange();
+ QTextDocument *textDocument();
QString text;
QFont font;
@@ -110,8 +114,10 @@ public:
bool cacheAllTextAsImage:1;
bool internalWidthUpdate:1;
bool requireImplicitWidth:1;
+ bool hAlignImplicit:1;
+ bool rightToLeftText:1;
- QSize layedOutTextSize;
+ QRect layedOutTextRect;
QSize paintedSize;
qreal naturalWidth;
virtual qreal implicitWidth() const;
@@ -119,7 +125,7 @@ public:
QPixmap textDocumentImage(bool drawStyle);
QTextDocumentWithImageResources *doc;
- QSize setupTextLayout();
+ QRect setupTextLayout();
QPixmap textLayoutImage(bool drawStyle);
void drawTextLayout(QPainter *p, const QPointF &pos, bool drawStyle);
QDeclarativeTextLayout layout;
diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp
index d3c5b82..2cb1c94 100644
--- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp
+++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp
@@ -48,6 +48,7 @@
#include <QtCore/qmath.h>
+#include <private/qtextengine_p.h>
#include <QTextLayout>
#include <QTextLine>
#include <QTextDocument>
@@ -249,6 +250,7 @@ void QDeclarativeTextEdit::setText(const QString &text)
Q_D(QDeclarativeTextEdit);
if (QDeclarativeTextEdit::text() == text)
return;
+
d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
if (d->richText) {
#ifndef QT_NO_TEXTHTMLPARSER
@@ -457,9 +459,12 @@ void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color)
/*!
\qmlproperty enumeration TextEdit::horizontalAlignment
\qmlproperty enumeration TextEdit::verticalAlignment
+ \qmlproperty enumeration TextEdit::effectiveHorizontalAlignment
Sets the horizontal and vertical alignment of the text within the TextEdit item's
- width and height. By default, the text is top-left aligned.
+ width and height. By default, the text alignment follows the natural alignment
+ of the text, for example text that is read from left to right will be aligned to
+ the left.
Valid values for \c horizontalAlignment are:
\list
@@ -473,8 +478,13 @@ void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color)
\list
\o TextEdit.AlignTop (default)
\o TextEdit.AlignBottom
- \c TextEdit.AlignVCenter
+ \o TextEdit.AlignVCenter
\endlist
+
+ When using the attached property LayoutMirroring::enabled to mirror application
+ layouts, the horizontal alignment of text will also be mirrored. However, the property
+ \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
+ of TextEdit, use the read-only property \c effectiveHorizontalAlignment.
*/
QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const
{
@@ -482,15 +492,80 @@ QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const
return d->hAlign;
}
-void QDeclarativeTextEdit::setHAlign(QDeclarativeTextEdit::HAlignment alignment)
+void QDeclarativeTextEdit::setHAlign(HAlignment align)
{
Q_D(QDeclarativeTextEdit);
- if (alignment == d->hAlign)
- return;
- d->hAlign = alignment;
- d->updateDefaultTextOption();
- updateSize();
- emit horizontalAlignmentChanged(d->hAlign);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
+ d->updateDefaultTextOption();
+ updateSize();
+ }
+}
+
+void QDeclarativeTextEdit::resetHAlign()
+{
+ Q_D(QDeclarativeTextEdit);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete()) {
+ d->updateDefaultTextOption();
+ updateSize();
+ }
+}
+
+QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::effectiveHAlign() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ QDeclarativeTextEdit::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QDeclarativeTextEdit::AlignLeft:
+ effectiveAlignment = QDeclarativeTextEdit::AlignRight;
+ break;
+ case QDeclarativeTextEdit::AlignRight:
+ effectiveAlignment = QDeclarativeTextEdit::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QDeclarativeTextEditPrivate::setHAlign(QDeclarativeTextEdit::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QDeclarativeTextEdit);
+ if (hAlign != alignment || forceAlign) {
+ QDeclarativeTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+ emit q->horizontalAlignmentChanged(alignment);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QDeclarativeTextEditPrivate::determineHorizontalAlignment()
+{
+ Q_Q(QDeclarativeTextEdit);
+ if (hAlignImplicit && q->isComponentComplete()) {
+ bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
+ return setHAlign(alignToRight ? QDeclarativeTextEdit::AlignRight : QDeclarativeTextEdit::AlignLeft);
+ }
+ return false;
+}
+
+void QDeclarativeTextEditPrivate::mirrorChange()
+{
+ Q_Q(QDeclarativeTextEdit);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QDeclarativeTextEdit::AlignRight || hAlign == QDeclarativeTextEdit::AlignLeft)) {
+ updateDefaultTextOption();
+ q->updateSize();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
}
QDeclarativeTextEdit::VAlignment QDeclarativeTextEdit::vAlign() const
@@ -967,6 +1042,8 @@ void QDeclarativeTextEdit::componentComplete()
Q_D(QDeclarativeTextEdit);
QDeclarativePaintedItem::componentComplete();
if (d->dirty) {
+ d->determineHorizontalAlignment();
+ d->updateDefaultTextOption();
updateSize();
d->dirty = false;
}
@@ -1216,6 +1293,23 @@ void QDeclarativeTextEdit::select(int start, int end)
updateSelectionMarkers();
}
+/*!
+ \qmlmethod void TextEdit::isRightToLeft(int start, int end)
+
+ Returns true if the natural reading direction of the editor text
+ found between positions \a start and \a end is right to left.
+*/
+bool QDeclarativeTextEdit::isRightToLeft(int start, int end)
+{
+ Q_D(QDeclarativeTextEdit);
+ if (start > end) {
+ qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
+ return false;
+ } else {
+ return d->text.mid(start, end - start).isRightToLeft();
+ }
+}
+
#ifndef QT_NO_CLIPBOARD
/*!
\qmlmethod TextEdit::cut()
@@ -1414,7 +1508,7 @@ bool QDeclarativeTextEdit::canPaste() const
}
/*!
- \qmlproperty bool TextEdit::isInputMethodComposing()
+ \qmlproperty bool TextEdit::inputMethodComposing
\since QtQuick 1.1
@@ -1484,6 +1578,9 @@ void QDeclarativeTextEdit::q_textChanged()
{
Q_D(QDeclarativeTextEdit);
d->text = text();
+ d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft();
+ d->determineHorizontalAlignment();
+ d->updateDefaultTextOption();
updateSize();
updateTotalLines();
updateMicroFocus();
@@ -1648,9 +1745,18 @@ void QDeclarativeTextEdit::updateTotalLines()
void QDeclarativeTextEditPrivate::updateDefaultTextOption()
{
+ Q_Q(QDeclarativeTextEdit);
QTextOption opt = document->defaultTextOption();
int oldAlignment = opt.alignment();
- opt.setAlignment((Qt::Alignment)(int)(hAlign | vAlign));
+
+ QDeclarativeTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign();
+ if (rightToLeftText) {
+ if (horizontalAlignment == QDeclarativeTextEdit::AlignLeft)
+ horizontalAlignment = QDeclarativeTextEdit::AlignRight;
+ else if (horizontalAlignment == QDeclarativeTextEdit::AlignRight)
+ horizontalAlignment = QDeclarativeTextEdit::AlignLeft;
+ }
+ opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign));
QTextOption::WrapMode oldWrapMode = opt.wrapMode();
opt.setWrapMode(QTextOption::WrapMode(wrapMode));
diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p.h
index 612f9a9..25ca1e7 100644
--- a/src/declarative/graphicsitems/qdeclarativetextedit_p.h
+++ b/src/declarative/graphicsitems/qdeclarativetextedit_p.h
@@ -72,7 +72,8 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextEdit : public QDeclarativeImplicitSizePa
Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor NOTIFY selectionColorChanged)
Q_PROPERTY(QColor selectedTextColor READ selectedTextColor WRITE setSelectedTextColor NOTIFY selectedTextColorChanged)
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
- Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign NOTIFY horizontalAlignmentChanged)
+ Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged)
+ Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged REVISION 1)
Q_PROPERTY(VAlignment verticalAlignment READ vAlign WRITE setVAlign NOTIFY verticalAlignmentChanged)
Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
Q_PROPERTY(int lineCount READ lineCount NOTIFY lineCountChanged REVISION 1)
@@ -153,6 +154,8 @@ public:
HAlignment hAlign() const;
void setHAlign(HAlignment align);
+ void resetHAlign();
+ HAlignment effectiveHAlign() const;
VAlignment vAlign() const;
void setVAlign(VAlignment align);
@@ -246,12 +249,14 @@ Q_SIGNALS:
Q_REVISION(1) void linkActivated(const QString &link);
Q_REVISION(1) void canPasteChanged();
Q_REVISION(1) void inputMethodComposingChanged();
+ Q_REVISION(1) void effectiveHorizontalAlignmentChanged();
public Q_SLOTS:
void selectAll();
void selectWord();
void select(int start, int end);
Q_REVISION(1) void deselect();
+ Q_REVISION(1) bool isRightToLeft(int start, int end);
#ifndef QT_NO_CLIPBOARD
void cut();
void copy();
diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h
index 111cc02..36e1b51 100644
--- a/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h
+++ b/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h
@@ -71,8 +71,8 @@ public:
: color("black"), hAlign(QDeclarativeTextEdit::AlignLeft), vAlign(QDeclarativeTextEdit::AlignTop),
imgDirty(true), dirty(false), richText(false), cursorVisible(false), focusOnPress(true),
showInputPanelOnFocus(true), clickCausedFocus(false), persistentSelection(true), requireImplicitWidth(false),
- textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0), cursorComponent(0), cursor(0),
- format(QDeclarativeTextEdit::AutoText), document(0), wrapMode(QDeclarativeTextEdit::NoWrap),
+ hAlignImplicit(true), rightToLeftText(false), textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0),
+ cursorComponent(0), cursor(0), format(QDeclarativeTextEdit::AutoText), document(0), wrapMode(QDeclarativeTextEdit::NoWrap),
mouseSelectionMode(QDeclarativeTextEdit::SelectCharacters), selectByMouse(false), canPaste(false),
yoff(0)
{
@@ -88,6 +88,9 @@ public:
void updateDefaultTextOption();
void relayoutDocument();
void updateSelection();
+ bool determineHorizontalAlignment();
+ bool setHAlign(QDeclarativeTextEdit::HAlignment, bool forceAlign = false);
+ void mirrorChange();
qreal implicitWidth() const;
void focusChanged(bool);
@@ -112,6 +115,8 @@ public:
bool clickCausedFocus : 1;
bool persistentSelection : 1;
bool requireImplicitWidth:1;
+ bool hAlignImplicit:1;
+ bool rightToLeftText:1;
qreal textMargin;
int lastSelectionStart;
int lastSelectionEnd;
diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp
index 29b1f6b..af18c90 100644
--- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp
+++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp
@@ -326,9 +326,12 @@ void QDeclarativeTextInput::setSelectedTextColor(const QColor &color)
/*!
\qmlproperty enumeration TextInput::horizontalAlignment
+ \qmlproperty enumeration TextInput::effectiveHorizontalAlignment
Sets the horizontal alignment of the text within the TextInput item's
- width and height. By default, the text is left aligned.
+ width and height. By default, the text alignment follows the natural alignment
+ of the text, for example text that is read from left to right will be aligned to
+ the left.
TextInput does not have vertical alignment, as the natural height is
exactly the height of the single line of text. If you set the height
@@ -338,6 +341,11 @@ void QDeclarativeTextInput::setSelectedTextColor(const QColor &color)
The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
\c TextInput.AlignHCenter.
+
+ When using the attached property LayoutMirroring::enabled to mirror application
+ layouts, the horizontal alignment of text will also be mirrored. However, the property
+ \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
+ of TextInput, use the read-only property \c effectiveHorizontalAlignment.
*/
QDeclarativeTextInput::HAlignment QDeclarativeTextInput::hAlign() const
{
@@ -348,12 +356,78 @@ QDeclarativeTextInput::HAlignment QDeclarativeTextInput::hAlign() const
void QDeclarativeTextInput::setHAlign(HAlignment align)
{
Q_D(QDeclarativeTextInput);
- if(align == d->hAlign)
- return;
- d->hAlign = align;
- updateRect();
- d->updateHorizontalScroll();
- emit horizontalAlignmentChanged(d->hAlign);
+ bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
+ d->hAlignImplicit = false;
+ if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
+ updateRect();
+ d->updateHorizontalScroll();
+ }
+}
+
+void QDeclarativeTextInput::resetHAlign()
+{
+ Q_D(QDeclarativeTextInput);
+ d->hAlignImplicit = true;
+ if (d->determineHorizontalAlignment() && isComponentComplete()) {
+ updateRect();
+ d->updateHorizontalScroll();
+ }
+}
+
+QDeclarativeTextInput::HAlignment QDeclarativeTextInput::effectiveHAlign() const
+{
+ Q_D(const QDeclarativeTextInput);
+ QDeclarativeTextInput::HAlignment effectiveAlignment = d->hAlign;
+ if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
+ switch (d->hAlign) {
+ case QDeclarativeTextInput::AlignLeft:
+ effectiveAlignment = QDeclarativeTextInput::AlignRight;
+ break;
+ case QDeclarativeTextInput::AlignRight:
+ effectiveAlignment = QDeclarativeTextInput::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+ return effectiveAlignment;
+}
+
+bool QDeclarativeTextInputPrivate::setHAlign(QDeclarativeTextInput::HAlignment alignment, bool forceAlign)
+{
+ Q_Q(QDeclarativeTextInput);
+ if ((hAlign != alignment || forceAlign) && alignment <= QDeclarativeTextInput::AlignHCenter) { // justify not supported
+ QDeclarativeTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
+ hAlign = alignment;
+ emit q->horizontalAlignmentChanged(alignment);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ return true;
+ }
+ return false;
+}
+
+bool QDeclarativeTextInputPrivate::determineHorizontalAlignment()
+{
+ if (hAlignImplicit) {
+ // if no explicit alignment has been set, follow the natural layout direction of the text
+ QString text = control->text();
+ bool isRightToLeft = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
+ return setHAlign(isRightToLeft ? QDeclarativeTextInput::AlignRight : QDeclarativeTextInput::AlignLeft);
+ }
+ return false;
+}
+
+void QDeclarativeTextInputPrivate::mirrorChange()
+{
+ Q_Q(QDeclarativeTextInput);
+ if (q->isComponentComplete()) {
+ if (!hAlignImplicit && (hAlign == QDeclarativeTextInput::AlignRight || hAlign == QDeclarativeTextInput::AlignLeft)) {
+ q->updateRect();
+ updateHorizontalScroll();
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ }
}
/*!
@@ -986,16 +1060,21 @@ void QDeclarativeTextInput::keyPressEvent(QKeyEvent* ev)
keyPressPreHandler(ev);
if (ev->isAccepted())
return;
- if (((ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier) // Don't allow MacOSX up/down support, and we don't allow a completer.
- || (((d->control->cursor() == 0 && ev->key() == Qt::Key_Left)
- || (d->control->cursor() == d->control->text().length()
- && ev->key() == Qt::Key_Right))
- && (d->lastSelectionStart == d->lastSelectionEnd)))
- {
- //ignore when moving off the end
- //unless there is a selection, because then moving will do something (deselect)
+
+ // Don't allow MacOSX up/down support, and we don't allow a completer.
+ bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
+ if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
+ // Ignore when moving off the end unless there is a selection,
+ // because then moving will do something (deselect).
+ int cursorPosition = d->control->cursor();
+ if (cursorPosition == 0)
+ ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
+ if (cursorPosition == d->control->text().length())
+ ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
+ }
+ if (ignore) {
ev->ignore();
- }else{
+ } else {
d->control->processKeyEvent(ev);
}
if (!ev->isAccepted())
@@ -1204,11 +1283,12 @@ void QDeclarativeTextInputPrivate::updateHorizontalScroll()
int cix = qRound(control->cursorToX(control->cursor() + preeditLength));
QRect br(q->boundingRect().toRect());
int widthUsed = calculateTextWidth();
- Qt::Alignment va = QStyle::visualAlignment(control->layoutDirection(), QFlag(Qt::Alignment(hAlign)));
+
+ QDeclarativeTextInput::HAlignment effectiveHAlign = q->effectiveHAlign();
if (autoScroll) {
if (widthUsed <= br.width()) {
// text fits in br; use hscroll for alignment
- switch (va & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
+ switch (effectiveHAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
case Qt::AlignRight:
hscroll = widthUsed - br.width() - 1;
break;
@@ -1240,11 +1320,11 @@ void QDeclarativeTextInputPrivate::updateHorizontalScroll()
hscroll = cix;
}
} else {
- switch (va & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
- case Qt::AlignRight:
+ switch (effectiveHAlign) {
+ case QDeclarativeTextInput::AlignRight:
hscroll = q->width() - widthUsed;
break;
- case Qt::AlignHCenter:
+ case QDeclarativeTextInput::AlignHCenter:
hscroll = (q->width() - widthUsed) / 2;
break;
default:
@@ -1294,7 +1374,10 @@ QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property)
case Qt::ImCursorPosition:
return QVariant(d->control->cursor());
case Qt::ImSurroundingText:
- return QVariant(text());
+ if (d->control->echoMode() == PasswordEchoOnEdit && !d->control->passwordEchoEditing())
+ return QVariant(displayText());
+ else
+ return QVariant(text());
case Qt::ImCurrentSelection:
return QVariant(selectedText());
case Qt::ImMaximumTextLength:
@@ -1334,6 +1417,23 @@ void QDeclarativeTextInput::selectAll()
d->control->setSelection(0, d->control->text().length());
}
+/*!
+ \qmlmethod void TextInput::isRightToLeft(int start, int end)
+
+ Returns true if the natural reading direction of the editor text
+ found between positions \a start and \a end is right to left.
+*/
+bool QDeclarativeTextInput::isRightToLeft(int start, int end)
+{
+ Q_D(QDeclarativeTextInput);
+ if (start > end) {
+ qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
+ return false;
+ } else {
+ return d->control->text().mid(start, end - start).isRightToLeft();
+ }
+}
+
#ifndef QT_NO_CLIPBOARD
/*!
\qmlmethod TextInput::cut()
@@ -1575,8 +1675,8 @@ void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode)
finder.setPosition(anchor);
const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
- if (anchor < text.length() && !(reasons & QTextBoundaryFinder::StartWord)
- || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor)) {
+ if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
+ || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
finder.toPreviousBoundary();
}
anchor = finder.position() != -1 ? finder.position() : 0;
@@ -1593,8 +1693,8 @@ void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode)
finder.setPosition(anchor);
const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
- if (anchor > 0 && !(reasons & QTextBoundaryFinder::EndWord)
- || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor)) {
+ if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
+ || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
finder.toNextBoundary();
}
anchor = finder.position() != -1 ? finder.position() : text.length();
@@ -1724,7 +1824,7 @@ void QDeclarativeTextInput::focusInEvent(QFocusEvent *event)
}
/*!
- \qmlproperty bool TextInput::isInputMethodComposing()
+ \qmlproperty bool TextInput::inputMethodComposing
\since QtQuick 1.1
@@ -1770,6 +1870,8 @@ void QDeclarativeTextInputPrivate::init()
#endif // QT_NO_CLIPBOARD
q->connect(control, SIGNAL(updateMicroFocus()),
q, SLOT(updateMicroFocus()));
+ q->connect(control, SIGNAL(displayTextChanged(QString)),
+ q, SLOT(updateRect()));
q->updateSize();
oldValidity = control->hasAcceptableInput();
lastSelectionStart = 0;
@@ -1777,6 +1879,7 @@ void QDeclarativeTextInputPrivate::init()
QPalette p = control->palette();
selectedTextColor = p.color(QPalette::HighlightedText);
selectionColor = p.color(QPalette::Highlight);
+ determineHorizontalAlignment();
}
void QDeclarativeTextInput::cursorPosChanged()
@@ -1824,6 +1927,7 @@ void QDeclarativeTextInput::q_textChanged()
{
Q_D(QDeclarativeTextInput);
updateSize();
+ d->determineHorizontalAlignment();
d->updateHorizontalScroll();
updateMicroFocus();
emit textChanged();
diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p.h
index 822d5e2..8c873b3 100644
--- a/src/declarative/graphicsitems/qdeclarativetextinput_p.h
+++ b/src/declarative/graphicsitems/qdeclarativetextinput_p.h
@@ -70,8 +70,8 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextInput : public QDeclarativeImplicitSizeP
Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor NOTIFY selectionColorChanged)
Q_PROPERTY(QColor selectedTextColor READ selectedTextColor WRITE setSelectedTextColor NOTIFY selectedTextColorChanged)
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
- Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign NOTIFY horizontalAlignmentChanged)
-
+ Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged)
+ Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged REVISION 1)
Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly NOTIFY readOnlyChanged)
Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible NOTIFY cursorVisibleChanged)
Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
@@ -153,6 +153,8 @@ public:
HAlignment hAlign() const;
void setHAlign(HAlignment align);
+ void resetHAlign();
+ HAlignment effectiveHAlign() const;
bool isReadOnly() const;
void setReadOnly(bool);
@@ -241,6 +243,7 @@ Q_SIGNALS:
Q_REVISION(1) void mouseSelectionModeChanged(SelectionMode mode);
Q_REVISION(1) void canPasteChanged();
Q_REVISION(1) void inputMethodComposingChanged();
+ Q_REVISION(1) void effectiveHorizontalAlignmentChanged();
protected:
virtual void geometryChanged(const QRectF &newGeometry,
@@ -261,6 +264,7 @@ public Q_SLOTS:
void selectWord();
void select(int start, int end);
Q_REVISION(1) void deselect();
+ Q_REVISION(1) bool isRightToLeft(int start, int end);
#ifndef QT_NO_CLIPBOARD
void cut();
void copy();
diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h
index ab2838b..fd4da2e 100644
--- a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h
+++ b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h
@@ -74,9 +74,9 @@ public:
color((QRgb)0), style(QDeclarativeText::Normal),
styleColor((QRgb)0), hAlign(QDeclarativeTextInput::AlignLeft),
mouseSelectionMode(QDeclarativeTextInput::SelectCharacters),
- hscroll(0), oldScroll(0), focused(false), focusOnPress(true),
+ hscroll(0), oldScroll(0), oldValidity(false), focused(false), focusOnPress(true),
showInputPanelOnFocus(true), clickCausedFocus(false), cursorVisible(false),
- autoScroll(true), selectByMouse(false), canPaste(false)
+ autoScroll(true), selectByMouse(false), canPaste(false), hAlignImplicit(true)
{
#ifdef Q_OS_SYMBIAN
if (QSysInfo::symbianVersion() == QSysInfo::SV_SF_1 || QSysInfo::symbianVersion() == QSysInfo::SV_SF_3) {
@@ -103,6 +103,9 @@ public:
void startCreatingCursor();
void focusChanged(bool hasFocus);
void updateHorizontalScroll();
+ bool determineHorizontalAlignment();
+ bool setHAlign(QDeclarativeTextInput::HAlignment, bool forceAlign = false);
+ void mirrorChange();
int calculateTextWidth();
bool sendMouseEventToInputContext(QGraphicsSceneMouseEvent *event, QEvent::Type eventType);
@@ -125,17 +128,18 @@ public:
int lastSelectionEnd;
int oldHeight;
int oldWidth;
- bool oldValidity;
int hscroll;
int oldScroll;
- bool focused;
- bool focusOnPress;
- bool showInputPanelOnFocus;
- bool clickCausedFocus;
- bool cursorVisible;
- bool autoScroll;
- bool selectByMouse;
- bool canPaste;
+ bool oldValidity:1;
+ bool focused:1;
+ bool focusOnPress:1;
+ bool showInputPanelOnFocus:1;
+ bool clickCausedFocus:1;
+ bool cursorVisible:1;
+ bool autoScroll:1;
+ bool selectByMouse:1;
+ bool canPaste:1;
+ bool hAlignImplicit:1;
static inline QDeclarativeTextInputPrivate *get(QDeclarativeTextInput *t) {
return t->d_func();