summaryrefslogtreecommitdiffstats
path: root/src/declarative/graphicsitems
diff options
context:
space:
mode:
authorFabien Freling <fabien.freling@nokia.com>2011-03-15 14:09:06 (GMT)
committerFabien Freling <fabien.freling@nokia.com>2011-03-15 14:09:06 (GMT)
commitb36f947147e3f5acf444c94d6e2a608506b7e753 (patch)
treea0bf253b8e315305cfada01871f3a1cbf54aef43 /src/declarative/graphicsitems
parentd524e983c60ba59f3c65d811ec92f02c97d1a8ab (diff)
parentc0cd8db0498daaa8151d1f80143b6849016bdc7c (diff)
downloadQt-b36f947147e3f5acf444c94d6e2a608506b7e753.zip
Qt-b36f947147e3f5acf444c94d6e2a608506b7e753.tar.gz
Qt-b36f947147e3f5acf444c94d6e2a608506b7e753.tar.bz2
Merge remote branch 'mainline/master' into merge_raster
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/qdeclarativeborderimage.cpp23
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflickable.cpp143
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflickable_p.h1
-rw-r--r--src/declarative/graphicsitems/qdeclarativeflickable_p_p.h8
-rw-r--r--src/declarative/graphicsitems/qdeclarativegridview.cpp605
-rw-r--r--src/declarative/graphicsitems/qdeclarativegridview_p.h17
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem.cpp190
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitem_p.h54
-rw-r--r--src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp2
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview.cpp551
-rw-r--r--src/declarative/graphicsitems/qdeclarativelistview_p.h16
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea.cpp40
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea_p.h5
-rw-r--r--src/declarative/graphicsitems/qdeclarativemousearea_p_p.h3
-rw-r--r--src/declarative/graphicsitems/qdeclarativepincharea.cpp19
-rw-r--r--src/declarative/graphicsitems/qdeclarativepincharea_p.h2
-rw-r--r--src/declarative/graphicsitems/qdeclarativepincharea_p_p.h7
-rw-r--r--src/declarative/graphicsitems/qdeclarativepositioners.cpp120
-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/qdeclarativetext.cpp280
-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.cpp211
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextedit_p.h11
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextedit_p_p.h9
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextinput.cpp317
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextinput_p.h18
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextinput_p_p.h27
-rw-r--r--src/declarative/graphicsitems/qdeclarativetextlayout.cpp11
34 files changed, 2254 insertions, 625 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/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp
index c03c624..8f37e90 100644
--- a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp
@@ -149,6 +149,20 @@ QT_BEGIN_NAMESPACE
\sa Image, AnimatedImage
*/
+/*!
+ \qmlproperty bool BorderImage::asynchronous
+
+ Specifies that images on the local filesystem should be loaded
+ asynchronously in a separate thread. The default value is
+ false, causing the user interface thread to block while the
+ image is loaded. Setting \a asynchronous to true is useful where
+ maintaining a responsive user interface is more desirable
+ than having images immediately visible.
+
+ Note that this property is only valid for images read from the
+ local filesystem. Images loaded via a network resource (e.g. HTTP)
+ are always loaded asynchonously.
+*/
QDeclarativeBorderImage::QDeclarativeBorderImage(QDeclarativeItem *parent)
: QDeclarativeImageBase(*(new QDeclarativeBorderImagePrivate), parent)
{
@@ -200,6 +214,15 @@ QDeclarativeBorderImage::~QDeclarativeBorderImage()
*/
/*!
+ \qmlproperty bool BorderImage::cache
+ \since Quick 1.1
+
+ Specifies whether the image should be cached. The default value is
+ true. Setting \a cache to false is useful when dealing with large images,
+ to make sure that they aren't cached at the expense of small 'ui element' images.
+*/
+
+/*!
\qmlproperty bool BorderImage::mirror
\since Quick 1.1
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp
index 2a16d21..1e2b70c 100644
--- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp
@@ -53,6 +53,10 @@ QT_BEGIN_NAMESPACE
// before we perform a flick.
static const int FlickThreshold = 20;
+// RetainGrabVelocity is the maxmimum instantaneous velocity that
+// will ensure the Flickable retains the grab on consecutive flicks.
+static const int RetainGrabVelocity = 15;
+
QDeclarativeFlickableVisibleArea::QDeclarativeFlickableVisibleArea(QDeclarativeFlickable *parent)
: QObject(parent), flickable(parent), m_xPosition(0.), m_widthRatio(0.)
, m_yPosition(0.), m_heightRatio(0.)
@@ -139,7 +143,7 @@ QDeclarativeFlickablePrivate::QDeclarativeFlickablePrivate()
, stealMouse(false), pressed(false), interactive(true), calcVelocity(false)
, deceleration(500), maxVelocity(2000), reportedVelocitySmoothing(100)
, delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(600)
- , vTime(0), visibleArea(0)
+ , fixupMode(Normal), vTime(0), visibleArea(0)
, flickableDirection(QDeclarativeFlickable::AutoFlickDirection)
, boundsBehavior(QDeclarativeFlickable::DragAndOvershootBounds)
{
@@ -215,6 +219,7 @@ void QDeclarativeFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal
{
Q_Q(QDeclarativeFlickable);
qreal maxDistance = -1;
+ data.fixingUp = false;
bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds;
// -ve velocity means list is moving up
if (velocity > 0) {
@@ -284,24 +289,45 @@ void QDeclarativeFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal
if (data.move.value() > minExtent || maxExtent > minExtent) {
timeline.reset(data.move);
if (data.move.value() != minExtent) {
- if (fixupDuration) {
- qreal dist = minExtent - data.move;
- timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
- timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
- } else {
+ switch (fixupMode) {
+ case Immediate:
timeline.set(data.move, minExtent);
+ break;
+ case ExtentChanged:
+ // The target has changed. Don't start from the beginning; just complete the
+ // second half of the animation using the new extent.
+ timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ break;
+ default: {
+ qreal dist = minExtent - data.move;
+ timeline.move(data.move, minExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
+ timeline.move(data.move, minExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ }
}
}
} else if (data.move.value() < maxExtent) {
timeline.reset(data.move);
- if (fixupDuration) {
- qreal dist = maxExtent - data.move;
- timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
- timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
- } else {
+ switch (fixupMode) {
+ case Immediate:
timeline.set(data.move, maxExtent);
+ break;
+ case ExtentChanged:
+ // The target has changed. Don't start from the beginning; just complete the
+ // second half of the animation using the new extent.
+ timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ break;
+ default: {
+ qreal dist = maxExtent - data.move;
+ timeline.move(data.move, maxExtent - dist/2, QEasingCurve(QEasingCurve::InQuad), fixupDuration/4);
+ timeline.move(data.move, maxExtent, QEasingCurve(QEasingCurve::OutExpo), 3*fixupDuration/4);
+ data.fixingUp = true;
+ }
}
}
+ fixupMode = Normal;
vTime = timeline.time();
}
@@ -672,7 +698,8 @@ void QDeclarativeFlickable::setFlickableDirection(FlickableDirection direction)
void QDeclarativeFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_Q(QDeclarativeFlickable);
- if (interactive && timeline.isActive() && (qAbs(hData.velocity) > 10 || qAbs(vData.velocity) > 10))
+ if (interactive && timeline.isActive()
+ && (qAbs(hData.smoothVelocity.value()) > RetainGrabVelocity || qAbs(vData.smoothVelocity.value()) > RetainGrabVelocity))
stealMouse = true; // If we've been flicked then steal the click.
else
stealMouse = false;
@@ -683,6 +710,12 @@ void QDeclarativeFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEven
vData.velocity = 0;
hData.dragStartOffset = 0;
vData.dragStartOffset = 0;
+ hData.dragMinBound = q->minXExtent();
+ vData.dragMinBound = q->minYExtent();
+ hData.dragMaxBound = q->maxXExtent();
+ vData.dragMaxBound = q->maxYExtent();
+ hData.fixingUp = false;
+ vData.fixingUp = false;
lastPos = QPoint();
QDeclarativeItemPrivate::start(lastPosTime);
pressPos = event->pos();
@@ -711,8 +744,8 @@ void QDeclarativeFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent
if (!vMoved)
vData.dragStartOffset = dy;
qreal newY = dy + vData.pressPos - vData.dragStartOffset;
- const qreal minY = q->minYExtent();
- const qreal maxY = q->maxYExtent();
+ const qreal minY = vData.dragMinBound;
+ const qreal maxY = vData.dragMaxBound;
if (newY > minY)
newY = minY + (newY - minY) / 2;
if (newY < maxY && maxY - minY <= 0)
@@ -743,8 +776,8 @@ void QDeclarativeFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent
if (!hMoved)
hData.dragStartOffset = dx;
qreal newX = dx + hData.pressPos - hData.dragStartOffset;
- const qreal minX = q->minXExtent();
- const qreal maxX = q->maxXExtent();
+ const qreal minX = hData.dragMinBound;
+ const qreal maxX = hData.dragMaxBound;
if (newX > minX)
newX = minX + (newX - minX) / 2;
if (newX < maxX && maxX - minX <= 0)
@@ -840,7 +873,8 @@ void QDeclarativeFlickable::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QDeclarativeFlickable);
if (d->interactive) {
- d->handleMousePressEvent(event);
+ if (!d->pressed)
+ d->handleMousePressEvent(event);
event->accept();
} else {
QDeclarativeItem::mousePressEvent(event);
@@ -905,11 +939,27 @@ void QDeclarativeFlickable::wheelEvent(QGraphicsSceneWheelEvent *event)
}
}
+bool QDeclarativeFlickablePrivate::isOutermostPressDelay() const
+{
+ Q_Q(const QDeclarativeFlickable);
+ QDeclarativeItem *item = q->parentItem();
+ while (item) {
+ QDeclarativeFlickable *flick = qobject_cast<QDeclarativeFlickable*>(item);
+ if (flick && flick->pressDelay() > 0 && flick->isInteractive())
+ return false;
+ item = item->parentItem();
+ }
+
+ return true;
+}
+
void QDeclarativeFlickablePrivate::captureDelayedPress(QGraphicsSceneMouseEvent *event)
{
Q_Q(QDeclarativeFlickable);
if (!q->scene() || pressDelay <= 0)
return;
+ if (!isOutermostPressDelay())
+ return;
delayedPressTarget = q->scene()->mouseGrabberItem();
delayedPressEvent = new QGraphicsSceneMouseEvent(event->type());
delayedPressEvent->setAccepted(false);
@@ -965,9 +1015,10 @@ void QDeclarativeFlickable::timerEvent(QTimerEvent *event)
if (scene()->mouseGrabberItem() == d->delayedPressTarget)
d->delayedPressTarget->ungrabMouse();
//Use the event handler that will take care of finding the proper item to propagate the event
- QApplication::sendEvent(scene(), d->delayedPressEvent);
+ QApplication::postEvent(scene(), d->delayedPressEvent);
+ } else {
+ delete d->delayedPressEvent;
}
- delete d->delayedPressEvent;
d->delayedPressEvent = 0;
}
}
@@ -1042,10 +1093,8 @@ void QDeclarativeFlickable::geometryChanged(const QRectF &newGeometry,
}
// Make sure that we're entirely in view.
if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
- int oldDuration = d->fixupDuration;
- d->fixupDuration = 0;
+ d->fixupMode = QDeclarativeFlickablePrivate::Immediate;
d->fixupX();
- d->fixupDuration = oldDuration;
}
}
if (newGeometry.height() != oldGeometry.height()) {
@@ -1057,10 +1106,8 @@ void QDeclarativeFlickable::geometryChanged(const QRectF &newGeometry,
}
// Make sure that we're entirely in view.
if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
- int oldDuration = d->fixupDuration;
- d->fixupDuration = 0;
+ d->fixupMode = QDeclarativeFlickablePrivate::Immediate;
d->fixupY();
- d->fixupDuration = oldDuration;
}
}
@@ -1214,10 +1261,11 @@ void QDeclarativeFlickable::setContentWidth(qreal w)
d->contentItem->setWidth(w);
// Make sure that we're entirely in view.
if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
- int oldDuration = d->fixupDuration;
- d->fixupDuration = 0;
+ d->fixupMode = QDeclarativeFlickablePrivate::Immediate;
+ d->fixupX();
+ } else if (!d->pressed && d->hData.fixingUp) {
+ d->fixupMode = QDeclarativeFlickablePrivate::ExtentChanged;
d->fixupX();
- d->fixupDuration = oldDuration;
}
emit contentWidthChanged();
d->updateBeginningEnd();
@@ -1241,10 +1289,11 @@ void QDeclarativeFlickable::setContentHeight(qreal h)
d->contentItem->setHeight(h);
// Make sure that we're entirely in view.
if (!d->pressed && !d->movingHorizontally && !d->movingVertically) {
- int oldDuration = d->fixupDuration;
- d->fixupDuration = 0;
+ d->fixupMode = QDeclarativeFlickablePrivate::Immediate;
+ d->fixupY();
+ } else if (!d->pressed && d->vData.fixingUp) {
+ d->fixupMode = QDeclarativeFlickablePrivate::ExtentChanged;
d->fixupY();
- d->fixupDuration = oldDuration;
}
emit contentHeightChanged();
d->updateBeginningEnd();
@@ -1253,11 +1302,10 @@ void QDeclarativeFlickable::setContentHeight(qreal h)
/*!
\qmlmethod Flickable::resizeContent(real width, real height, QPointF center)
\preliminary
+ \since Quick 1.1
Resizes the content to \a width x \a height about \a center.
- \bold {This method was added in QtQuick 1.1.}
-
This does not scale the contents of the Flickable - it only resizes the \l contentWidth
and \l contentHeight.
@@ -1289,11 +1337,10 @@ void QDeclarativeFlickable::resizeContent(qreal w, qreal h, QPointF center)
/*!
\qmlmethod Flickable::returnToBounds()
\preliminary
+ \since Quick 1.1
Ensures the content is within legal bounds.
- \bold {This method was added in QtQuick 1.1.}
-
This may be called to ensure that the content is within legal bounds
after manually positioning the content.
*/
@@ -1338,6 +1385,22 @@ bool QDeclarativeFlickable::yflick() const
return d->flickableDirection & QDeclarativeFlickable::VerticalFlick;
}
+bool QDeclarativeFlickable::sceneEvent(QEvent *event)
+{
+ bool rv = QDeclarativeItem::sceneEvent(event);
+ if (event->type() == QEvent::UngrabMouse) {
+ Q_D(QDeclarativeFlickable);
+ if (d->pressed) {
+ // if our mouse grab has been removed (probably by another Flickable),
+ // fix our state
+ d->pressed = false;
+ d->stealMouse = false;
+ setKeepMouseGrab(false);
+ }
+ }
+ return rv;
+}
+
bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QDeclarativeFlickable);
@@ -1365,7 +1428,7 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
d->handleMouseMoveEvent(&mouseEvent);
break;
case QEvent::GraphicsSceneMousePress:
- if (d->delayedPressEvent)
+ if (d->pressed) // we are already pressed - this is a delayed replay
return false;
d->handleMousePressEvent(&mouseEvent);
@@ -1384,6 +1447,8 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
// We send the release
scene()->sendEvent(s->mouseGrabberItem(), event);
// And the event has been consumed
+ d->stealMouse = false;
+ d->pressed = false;
return true;
}
d->handleMouseReleaseEvent(&mouseEvent);
@@ -1406,6 +1471,7 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
d->stealMouse = false;
d->pressed = false;
}
+
return false;
}
@@ -1504,6 +1570,9 @@ bool QDeclarativeFlickable::isFlickingVertically() const
If the flickable is dragged/flicked before the delay times out
the press event will not be delivered. If the button is released
within the timeout, both the press and release will be delivered.
+
+ Note that for nested Flickables with pressDelay set, the pressDelay of
+ inner Flickables is overridden by the outermost Flickable.
*/
int QDeclarativeFlickable::pressDelay() const
{
@@ -1596,6 +1665,7 @@ void QDeclarativeFlickable::movementXEnding()
emit movementEnded();
}
}
+ d->hData.fixingUp = false;
}
void QDeclarativeFlickable::movementYEnding()
@@ -1618,6 +1688,7 @@ void QDeclarativeFlickable::movementYEnding()
emit movementEnded();
}
}
+ d->vData.fixingUp = false;
}
void QDeclarativeFlickablePrivate::updateVelocity()
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable_p.h b/src/declarative/graphicsitems/qdeclarativeflickable_p.h
index 4fde1d5..a14cc1c 100644
--- a/src/declarative/graphicsitems/qdeclarativeflickable_p.h
+++ b/src/declarative/graphicsitems/qdeclarativeflickable_p.h
@@ -204,6 +204,7 @@ protected:
virtual void viewportMoved();
virtual void geometryChanged(const QRectF &newGeometry,
const QRectF &oldGeometry);
+ bool sceneEvent(QEvent *event);
bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
bool xflick() const;
diff --git a/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h
index 5ad6ff6..38a5eb3 100644
--- a/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h
+++ b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h
@@ -94,17 +94,21 @@ public:
struct AxisData {
AxisData(QDeclarativeFlickablePrivate *fp, void (QDeclarativeFlickablePrivate::*func)(qreal))
: move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true)
+ , fixingUp(false)
{}
QDeclarativeTimeLineValueProxy<QDeclarativeFlickablePrivate> move;
qreal viewSize;
qreal pressPos;
qreal dragStartOffset;
+ qreal dragMinBound;
+ qreal dragMaxBound;
qreal velocity;
qreal flickTarget;
QDeclarativeFlickablePrivate::Velocity smoothVelocity;
bool atEnd : 1;
bool atBeginning : 1;
+ bool fixingUp : 1;
};
void flickX(qreal velocity);
@@ -118,6 +122,7 @@ public:
void updateBeginningEnd();
+ bool isOutermostPressDelay() const;
void captureDelayedPress(QGraphicsSceneMouseEvent *event);
void clearDelayedPress();
@@ -160,6 +165,9 @@ public:
int pressDelay;
int fixupDuration;
+ enum FixupMode { Normal, Immediate, ExtentChanged };
+ FixupMode fixupMode;
+
static void fixupY_callback(void *);
static void fixupX_callback(void *);
diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp
index 694130b..5c2f781 100644
--- a/src/declarative/graphicsitems/qdeclarativegridview.cpp
+++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp
@@ -68,21 +68,62 @@ 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(int x, int y) const {
+ bool contains(qreal x, qreal y) const {
return (x >= item->x() && x < item->x() + view->cellWidth() &&
y >= item->y() && y < item->y() + view->cellHeight());
}
@@ -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);
}
}
}
@@ -912,76 +1022,107 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m
|| (flow == QDeclarativeGridView::LeftToRight && &data == &hData))
return;
- int oldDuration = fixupDuration;
- fixupDuration = moveReason == Mouse ? fixupDuration : 0;
+ 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);
- fixupDuration = oldDuration;
return;
}
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);
- if (fixupDuration)
+ if (fixupMode != Immediate) {
timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
- else
+ data.fixingUp = true;
+ } else {
timeline.set(data.move, -pos);
+ }
vTime = timeline.time();
}
} else if (haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) {
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 (fixupDuration)
+ if (fixupMode != Immediate) {
timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
- else
+ data.fixingUp = true;
+ } else {
timeline.set(data.move, -viewPos);
+ }
}
vTime = timeline.time();
}
} else {
QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
}
- fixupDuration = oldDuration;
+ fixupMode = Normal;
}
void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity)
{
Q_Q(QDeclarativeGridView);
+ data.fixingUp = false;
moveReason = Mouse;
if ((!haveHighlightRange || highlightRange != QDeclarativeGridView::StrictlyEnforceRange)
&& snapMode == QDeclarativeGridView::NoSnap) {
@@ -989,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());
}
@@ -1004,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());
}
@@ -1013,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;
@@ -1032,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
@@ -1224,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);
@@ -1549,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;
@@ -1556,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);
@@ -1565,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;
@@ -1572,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);
@@ -1588,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
@@ -1620,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();
}
}
@@ -1890,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
@@ -1956,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;
}
@@ -1971,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;
@@ -2094,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);
+ }
}
}
}
@@ -2122,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);
+ }
}
}
}
@@ -2147,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)
@@ -2197,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();
@@ -2250,6 +2570,7 @@ void QDeclarativeGridView::positionViewAtIndex(int index, int mode)
/*!
\qmlmethod GridView::positionViewAtBeginning()
\qmlmethod GridView::positionViewAtEnd()
+ \since Quick 1.1
Positions the view at the beginning or end, taking into account any header or footer.
@@ -2294,7 +2615,7 @@ void QDeclarativeGridView::positionViewAtEnd()
\bold Note: methods should only be called after the Component has completed.
*/
-int QDeclarativeGridView::indexAt(int x, int y) const
+int QDeclarativeGridView::indexAt(qreal x, qreal y) const
{
Q_D(const QDeclarativeGridView);
for (int i = 0; i < d->visibleItems.count(); ++i) {
@@ -2337,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()) {
@@ -2430,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()) {
@@ -2448,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,6 +2838,8 @@ void QDeclarativeGridView::itemsInserted(int modelIndex, int count)
d->updateCurrent(0);
}
emit currentIndexChanged();
+ } else if (d->itemCount == 0 && d->currentIndex == -1) {
+ setCurrentIndex(0);
}
// everything is in order now - emit add() signal
@@ -2756,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 248b9ef..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;
@@ -158,7 +167,7 @@ public:
enum PositionMode { Beginning, Center, End, Visible, Contain };
Q_INVOKABLE void positionViewAtIndex(int index, int mode);
- Q_INVOKABLE int indexAt(int x, int y) const;
+ Q_INVOKABLE int indexAt(qreal x, qreal y) const;
Q_INVOKABLE Q_REVISION(1) void positionViewAtBeginning();
Q_INVOKABLE Q_REVISION(1) void positionViewAtEnd();
@@ -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/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp
index ffef61b..9cf1e78 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,152 @@ void QDeclarativeKeyNavigationAttached::setFocusNavigation(QDeclarativeItem *cur
}
/*!
+ \qmlclass LayoutMirroring QDeclarativeLayoutMirroringAttached
+ \since QtQuick 1.1
+ \ingroup qml-utility-elements
+ \brief The LayoutMirroring is used for mirroring the Qt Quick application layouts.
+
+ LayoutMirroring \l enabled property can be used to horizontally mirror \l {anchor-layout}{Item anchors},
+ \l{Using QML Positioner and Repeater Items}{Positioner} elements and QML views like \l {GridView}{GridView}
+ and horizontal \l {ListView}{ListView}. Mirroring is a visual change, left anchors will become
+ right anchors and left-to-right positioner will instead position child items from right to left.
+ By default setting the \l enabled property to true only affects the item in question. You can set property
+ LayoutDirection \l childrenInherit to true if you want the item children also inherit the mirror setting.
+ If no attached property has been defined, mirroring is disabled.
+
+ The following example shows mirroring in action. When \l enabled is set to true, left anchor
+ becomes right, and \l {Row}{Row} starts positioning items in a reverse order:
+
+ \snippet doc/src/snippets/declarative/layoutmirroring.qml 0
+
+ Layout mirroring is useful when you need to support both left-to-right and right-to-left
+ layout versions of your application that target different language areas. Inheritance saves
+ you from having to mirror the layouts manually for each layout item in your application. Keep
+ in mind however that the mirroring does not affect the positioning done by modifying Item's x
+ co-ordinate directly, so even with the mirroring enabled you will often need to do some layout
+ fixes to support the other reading direction. Also, there are cases where you need to disable
+ mirroring of individual child items, either because mirroring is not the wanted behavior or
+ because the item already implements mirroring in some custom way.
+*/
+
+/*!
+ \qmlproperty bool LayoutMirroring::enabled
+
+ Setting this property to true mirrors item's layout horizontally, whether the layout is done
+ using \l {anchor-layout}{anchors}, \l{Using QML Positioner and Repeater Items}{Positioners}
+ or as a QML view \l {GridView}{GridView} or \l {ListView}{ListView}.
+*/
+
+/*!
+ \qmlproperty bool LayoutMirroring::childrenInherit
+
+ This property can be set to true if you want the item children
+ to inherit the item's mirror setting.
+*/
+
+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 +1555,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 \l {LayoutMirroring}{LayoutMirroring} attached property.
+
*/
/*!
@@ -2154,6 +2317,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 +2376,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 +2979,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 bc4a2d0..c4a9030 100644
--- a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp
+++ b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp
@@ -180,6 +180,7 @@ void QDeclarativeItemModule::defineModule()
qmlRegisterType<QDeclarativePinch>("QtQuick",1,1,"Pinch");
qmlRegisterType<QDeclarativePinchEvent>();
qmlRegisterType<QDeclarativeItem,1>("QtQuick",1,1,"Item");
+ qmlRegisterType<QDeclarativeMouseArea,1>("QtQuick",1,1,"MouseArea");
qmlRegisterType<QDeclarativeFlickable,1>("QtQuick",1,1,"Flickable");
qmlRegisterType<QDeclarativeListView,1>("QtQuick",1,1,"ListView");
qmlRegisterType<QDeclarativeGridView,1>("QtQuick",1,1,"GridView");
@@ -197,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 a60a4aa..2c23a1b 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) {
@@ -148,7 +168,7 @@ public:
else
item->setWidth(size);
}
- bool contains(int x, int y) const {
+ bool contains(qreal x, qreal y) const {
return (x >= item->x() && x < item->x() + item->width() &&
y >= item->y() && y < item->y() + item->height());
}
@@ -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);
@@ -228,23 +249,85 @@ public:
return 0;
}
+ // Returns the item before modelIndex, if created.
+ // May return an item marked for removal.
+ FxListItem *itemBefore(int modelIndex) const {
+ if (modelIndex < visibleIndex)
+ return 0;
+ int idx = 1;
+ int lastIndex = -1;
+ while (idx < visibleItems.count()) {
+ FxListItem *item = visibleItems.at(idx);
+ if (item->index != -1)
+ lastIndex = item->index;
+ if (item->index == modelIndex)
+ return visibleItems.at(idx-1);
+ ++idx;
+ }
+ if (lastIndex == modelIndex-1)
+ return visibleItems.last();
+ 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();
@@ -254,7 +337,7 @@ public:
return pos;
}
- qreal endPosition() const {
+ qreal lastPosition() const {
qreal pos = 0;
if (!visibleItems.isEmpty()) {
int invisibleCount = visibleItems.count() - visibleIndex;
@@ -271,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();
@@ -292,6 +383,7 @@ public:
else
idx = visibleItems.at(idx)->index;
int count = modelIndex - idx - 1;
+
return (*(--visibleItems.constEnd()))->endPosition() + spacing + count * (averageSize + spacing) + 1;
}
}
@@ -348,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) {
@@ -464,6 +556,7 @@ public:
QHash<QDeclarativeItem*,int> unrequestedItems;
FxListItem *currentItem;
QDeclarativeListView::Orientation orient;
+ Qt::LayoutDirection layoutDirection;
qreal visiblePos;
int visibleIndex;
qreal averageSize;
@@ -472,6 +565,8 @@ public:
int itemCount;
qreal highlightRangeStart;
qreal highlightRangeEnd;
+ bool highlightRangeStartValid;
+ bool highlightRangeEndValid;
QDeclarativeComponent *highlightComponent;
FxListItem *highlight;
FxListItem *trackedItem;
@@ -561,7 +656,7 @@ FxListItem *QDeclarativeListViewPrivate::createItem(int modelIndex)
QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
listItem->attached->m_section = sectionCriteria->sectionString(propValue);
if (modelIndex > 0) {
- if (FxListItem *item = visibleItem(modelIndex-1))
+ if (FxListItem *item = itemBefore(modelIndex))
listItem->attached->m_prevSection = item->attached->section();
else
listItem->attached->m_prevSection = sectionAt(modelIndex-1);
@@ -649,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;
@@ -795,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));
+ }
}
}
}
@@ -887,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)
@@ -922,7 +1022,7 @@ void QDeclarativeListViewPrivate::createSection(FxListItem *listItem)
} else {
QDeclarativeContext *context = new QDeclarativeContext(qmlContext(q));
context->setContextProperty(QLatin1String("section"), listItem->attached->m_section);
- QObject *nobj = sectionCriteria->delegate()->create(context);
+ QObject *nobj = sectionCriteria->delegate()->beginCreate(context);
if (nobj) {
QDeclarative_setParent_noEvent(context, nobj);
listItem->section = qobject_cast<QDeclarativeItem *>(nobj);
@@ -936,6 +1036,7 @@ void QDeclarativeListViewPrivate::createSection(FxListItem *listItem)
} else {
delete context;
}
+ sectionCriteria->delegate()->completeCreate();
}
listItem->setPosition(pos);
} else {
@@ -969,18 +1070,18 @@ void QDeclarativeListViewPrivate::updateSections()
QDeclarativeListViewAttached *prevAtt = 0;
int idx = -1;
for (int i = 0; i < visibleItems.count(); ++i) {
+ QDeclarativeListViewAttached *attached = visibleItems.at(i)->attached;
+ attached->setPrevSection(prevSection);
if (visibleItems.at(i)->index != -1) {
- QDeclarativeListViewAttached *attached = visibleItems.at(i)->attached;
- attached->setPrevSection(prevSection);
QString propValue = model->stringValue(visibleItems.at(i)->index, sectionCriteria->property());
attached->setSection(sectionCriteria->sectionString(propValue));
- if (prevAtt)
- prevAtt->setNextSection(attached->section());
- createSection(visibleItems.at(i));
- prevSection = attached->section();
- prevAtt = attached;
idx = visibleItems.at(i)->index;
}
+ createSection(visibleItems.at(i));
+ if (prevAtt)
+ prevAtt->setNextSection(attached->section());
+ prevSection = attached->section();
+ prevAtt = attached;
}
if (prevAtt) {
if (idx > 0 && idx < model->count()-1)
@@ -1104,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 {
@@ -1144,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 {
@@ -1177,56 +1278,83 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m
return;
correctFlick = false;
- int oldDuration = fixupDuration;
- fixupDuration = moveReason == Mouse ? fixupDuration : 0;
+ fixupMode = moveReason == Mouse ? fixupMode : Immediate;
+
+ 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) {
+ 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()) {
- if (fixupDuration)
+ if (fixupMode != Immediate) {
timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
- else
+ data.fixingUp = true;
+ } else {
timeline.set(data.move, -viewPos);
+ }
}
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);
- fixupDuration = oldDuration;
return;
}
qreal dist = qAbs(data.move + pos);
if (dist > 0) {
timeline.reset(data.move);
- if (fixupDuration)
+ if (fixupMode != Immediate) {
timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
- else
+ data.fixingUp = true;
+ } else {
timeline.set(data.move, -pos);
+ }
vTime = timeline.time();
}
} else {
QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
}
- fixupDuration = oldDuration;
+ fixupMode = Normal;
}
void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
@@ -1234,6 +1362,7 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m
{
Q_Q(QDeclarativeListView);
+ data.fixingUp = false;
moveReason = Mouse;
if ((!haveHighlightRange || highlightRange != QDeclarativeListView::StrictlyEnforceRange) && snapMode == QDeclarativeListView::NoSnap) {
correctFlick = true;
@@ -1241,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());
}
@@ -1256,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());
}
@@ -1265,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.
@@ -1290,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);
@@ -1323,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));
@@ -1342,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)
@@ -1361,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));
@@ -1859,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;
@@ -1866,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);
@@ -1875,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;
@@ -1882,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);
@@ -1960,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.
@@ -2339,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));
@@ -2381,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;
@@ -2425,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)
@@ -2450,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;
}
@@ -2468,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;
}
@@ -2496,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();
@@ -2506,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();
@@ -2528,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);
}
@@ -2583,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
@@ -2628,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();
@@ -2688,6 +2976,7 @@ void QDeclarativeListView::positionViewAtIndex(int index, int mode)
/*!
\qmlmethod ListView::positionViewAtBeginning()
\qmlmethod ListView::positionViewAtEnd()
+ \since Quick 1.1
Positions the view at the beginning or end, taking into account any header or footer.
@@ -2732,7 +3021,7 @@ void QDeclarativeListView::positionViewAtEnd()
\bold Note: methods should only be called after the Component has completed.
*/
-int QDeclarativeListView::indexAt(int x, int y) const
+int QDeclarativeListView::indexAt(qreal x, qreal y) const
{
Q_D(const QDeclarativeListView);
for (int i = 0; i < d->visibleItems.count(); ++i) {
@@ -2777,13 +3066,18 @@ void QDeclarativeListView::updateSections()
roles << d->sectionCriteria->property().toUtf8();
d->model->setWatchedRoles(roles);
d->updateSections();
+ if (d->itemCount)
+ d->layout();
}
}
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()
@@ -2798,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;
}
}
}
@@ -2854,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)
@@ -2863,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 {
@@ -2908,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();
@@ -2938,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();
@@ -3096,6 +3403,7 @@ void QDeclarativeListView::destroyRemoved()
}
// Correct the positioning of the items
+ d->updateSections();
d->layout();
}
@@ -3213,11 +3521,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());
@@ -3233,10 +3538,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 10fbf10..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);
@@ -208,7 +216,7 @@ public:
enum PositionMode { Beginning, Center, End, Visible, Contain };
Q_INVOKABLE void positionViewAtIndex(int index, int mode);
- Q_INVOKABLE int indexAt(int x, int y) const;
+ Q_INVOKABLE int indexAt(qreal x, qreal y) const;
Q_INVOKABLE Q_REVISION(1) void positionViewAtBeginning();
Q_INVOKABLE Q_REVISION(1) void positionViewAtEnd();
@@ -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/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp
index ffbae3f..da11b00 100644
--- a/src/declarative/graphicsitems/qdeclarativemousearea.cpp
+++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp
@@ -314,6 +314,8 @@ QDeclarativeMouseAreaPrivate::~QDeclarativeMouseAreaPrivate()
position of the release of the click, and whether the click was held.
The \e accepted property of the MouseEvent parameter is ignored in this handler.
+
+ \sa onCanceled()
*/
/*!
@@ -414,6 +416,40 @@ void QDeclarativeMouseArea::setEnabled(bool a)
emit enabledChanged();
}
}
+
+/*!
+ \qmlproperty bool MouseArea::preventStealing
+ \since Quick 1.1
+ This property holds whether the mouse events may be stolen from this
+ MouseArea.
+
+ If a MouseArea is placed within an item that filters child mouse
+ events, such as Flickable, the mouse
+ events may be stolen from the MouseArea if a gesture is recognized
+ by the parent element, e.g. a flick gesture. If preventStealing is
+ set to true, no element will steal the mouse events.
+
+ Note that setting preventStealing to true once an element has started
+ stealing events will have no effect until the next press event.
+
+ By default this property is false.
+*/
+bool QDeclarativeMouseArea::preventStealing() const
+{
+ Q_D(const QDeclarativeMouseArea);
+ return d->preventStealing;
+}
+
+void QDeclarativeMouseArea::setPreventStealing(bool prevent)
+{
+ Q_D(QDeclarativeMouseArea);
+ if (prevent != d->preventStealing) {
+ d->preventStealing = prevent;
+ setKeepMouseGrab(d->preventStealing && d->absorb);
+ emit preventStealingChanged();
+ }
+}
+
/*!
\qmlproperty MouseButtons MouseArea::pressedButtons
This property holds the mouse buttons currently pressed.
@@ -441,7 +477,7 @@ void QDeclarativeMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QDeclarativeMouseArea);
d->moved = false;
- d->stealMouse = false;
+ d->stealMouse = d->preventStealing;
if (!d->absorb)
QDeclarativeItem::mousePressEvent(event);
else {
@@ -458,7 +494,7 @@ void QDeclarativeMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
// we should only start timer if pressAndHold is connected to.
if (d->isPressAndHoldConnected())
d->pressAndHoldTimer.start(PressAndHoldDelay, this);
- setKeepMouseGrab(false);
+ setKeepMouseGrab(d->stealMouse);
event->setAccepted(setPressed(true));
}
}
diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p.h
index 937ac78..985f27e 100644
--- a/src/declarative/graphicsitems/qdeclarativemousearea_p.h
+++ b/src/declarative/graphicsitems/qdeclarativemousearea_p.h
@@ -129,6 +129,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeMouseArea : public QDeclarativeItem
Q_PROPERTY(Qt::MouseButtons acceptedButtons READ acceptedButtons WRITE setAcceptedButtons NOTIFY acceptedButtonsChanged)
Q_PROPERTY(bool hoverEnabled READ hoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged)
Q_PROPERTY(QDeclarativeDrag *drag READ drag CONSTANT) //### add flicking to QDeclarativeDrag or add a QDeclarativeFlick ???
+ Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged REVISION 1)
public:
QDeclarativeMouseArea(QDeclarativeItem *parent=0);
@@ -153,6 +154,9 @@ public:
QDeclarativeDrag *drag();
+ bool preventStealing() const;
+ void setPreventStealing(bool prevent);
+
Q_SIGNALS:
void hoveredChanged();
void pressedChanged();
@@ -161,6 +165,7 @@ Q_SIGNALS:
void hoverEnabledChanged();
void positionChanged(QDeclarativeMouseEvent *mouse);
void mousePositionChanged(QDeclarativeMouseEvent *mouse);
+ Q_REVISION(1) void preventStealingChanged();
void pressed(QDeclarativeMouseEvent *mouse);
void pressAndHold(QDeclarativeMouseEvent *mouse);
diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h
index 2a327af..67694fb 100644
--- a/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h
+++ b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h
@@ -68,7 +68,7 @@ class QDeclarativeMouseAreaPrivate : public QDeclarativeItemPrivate
public:
QDeclarativeMouseAreaPrivate()
: absorb(true), hovered(false), pressed(false), longPress(false),
- moved(false), stealMouse(false), doubleClick(false), drag(0)
+ moved(false), stealMouse(false), doubleClick(false), preventStealing(false), drag(0)
{
}
@@ -110,6 +110,7 @@ public:
bool dragY : 1;
bool stealMouse : 1;
bool doubleClick : 1;
+ bool preventStealing : 1;
QDeclarativeDrag *drag;
QPointF startScene;
qreal startX;
diff --git a/src/declarative/graphicsitems/qdeclarativepincharea.cpp b/src/declarative/graphicsitems/qdeclarativepincharea.cpp
index eae83f6..b09cb72 100644
--- a/src/declarative/graphicsitems/qdeclarativepincharea.cpp
+++ b/src/declarative/graphicsitems/qdeclarativepincharea.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
@@ -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.h b/src/declarative/graphicsitems/qdeclarativepincharea_p.h
index 6d04708..5d06db0 100644
--- a/src/declarative/graphicsitems/qdeclarativepincharea_p.h
+++ b/src/declarative/graphicsitems/qdeclarativepincharea_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
diff --git a/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h b/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h
index 5641e35..2769987 100644
--- a/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h
+++ b/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
@@ -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 27a1301..84dcec6 100644
--- a/src/declarative/graphicsitems/qdeclarativepositioners.cpp
+++ b/src/declarative/graphicsitems/qdeclarativepositioners.cpp
@@ -578,12 +578,14 @@ void QDeclarativeColumn::reportConflictingAnchors()
\sa Grid::spacing
*/
QDeclarativeRow::QDeclarativeRow(QDeclarativeItem *parent)
-: QDeclarativeBasePositioner(Horizontal, parent), m_layoutDirection(Qt::LeftToRight)
+: QDeclarativeBasePositioner(Horizontal, parent)
{
}
/*!
\qmlproperty enumeration Row::layoutDirection
+ \since Quick 1.1
+
This property holds the layoutDirection of the row.
Possible values:
@@ -599,20 +601,39 @@ QDeclarativeRow::QDeclarativeRow(QDeclarativeItem *parent)
*/
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;
@@ -621,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{
@@ -636,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
@@ -790,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)
{
}
@@ -859,16 +880,18 @@ void QDeclarativeGrid::setFlow(Flow flow)
/*!
\qmlproperty enumeration Grid::layoutDirection
+ \since Quick 1.1
+
This property holds the layout direction of the layout.
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
@@ -876,21 +899,39 @@ void QDeclarativeGrid::setFlow(Flow flow)
*/
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?
@@ -980,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;
@@ -988,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);
@@ -996,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();
@@ -1004,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;
@@ -1017,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();
@@ -1152,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)
@@ -1201,16 +1240,18 @@ void QDeclarativeFlow::setFlow(Flow flow)
/*!
\qmlproperty enumeration Flow::layoutDirection
+ \since Quick 1.1
+
This property holds the layout direction of the layout.
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
@@ -1230,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);
@@ -1262,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{
@@ -1285,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/qdeclarativetext.cpp b/src/declarative/graphicsitems/qdeclarativetext.cpp
index 559d061..994c01e 100644
--- a/src/declarative/graphicsitems/qdeclarativetext.cpp
+++ b/src/declarative/graphicsitems/qdeclarativetext.cpp
@@ -49,7 +49,6 @@
#include <QTextLayout>
#include <QTextLine>
#include <QTextDocument>
-#include <QTextCursor>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QAbstractTextDocumentLayout>
@@ -88,13 +87,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;
@@ -260,18 +258,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()) {
@@ -284,9 +290,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());
}
@@ -321,45 +327,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()) {
@@ -371,47 +361,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();
@@ -433,36 +423,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) {
@@ -470,7 +447,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()));
}
/*!
@@ -480,21 +457,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()) {
@@ -507,7 +470,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;
}
@@ -525,7 +488,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);
}
/*!
@@ -930,14 +893,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);
}
@@ -1060,9 +1027,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
@@ -1072,6 +1042,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
{
@@ -1082,16 +1057,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
@@ -1145,6 +1182,7 @@ void QDeclarativeText::setWrapMode(WrapMode mode)
/*!
\qmlproperty int Text::lineCount
+ \since Quick 1.1
Returns the number of lines visible in the text item.
@@ -1160,6 +1198,7 @@ int QDeclarativeText::lineCount() const
/*!
\qmlproperty bool Text::truncated
+ \since Quick 1.1
Returns true if the text has been truncated due to \l maximumLineCount
or \l elide.
@@ -1176,6 +1215,7 @@ bool QDeclarativeText::truncated() const
/*!
\qmlproperty int Text::maximumLineCount
+ \since Quick 1.1
Set this property to limit the number of lines that the text item will show.
If elide is set to Text.ElideRight, the text will be elided appropriately.
@@ -1342,44 +1382,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 */
@@ -1428,6 +1449,7 @@ qreal QDeclarativeText::paintedHeight() const
/*!
\qmlproperty real Text::lineHeight
+ \since Quick 1.1
Sets the line height for the text.
The value can be in pixels or a multiplier depending on lineHeightMode.
@@ -1524,8 +1546,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();
@@ -1557,7 +1579,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 e2f6265..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
@@ -544,6 +619,7 @@ void QDeclarativeTextEdit::setWrapMode(WrapMode mode)
/*!
\qmlproperty int TextEdit::lineCount
+ \since Quick 1.1
Returns the total number of lines in the textEdit item.
*/
@@ -605,6 +681,22 @@ int QDeclarativeTextEdit::positionAt(int x, int y) const
{
Q_D(const QDeclarativeTextEdit);
int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit);
+ QTextCursor cursor = d->control->textCursor();
+ if (r > cursor.position()) {
+ // The cursor position includes positions within the preedit text, but only positions in the
+ // same text block are offset so it is possible to get a position that is either part of the
+ // preedit or the next text block.
+ QTextLayout *layout = cursor.block().layout();
+ const int preeditLength = layout
+ ? layout->preeditAreaText().length()
+ : 0;
+ if (preeditLength > 0
+ && d->document->documentLayout()->blockBoundingRect(cursor.block()).contains(x,y-d->yoff)) {
+ r = r > cursor.position() + preeditLength
+ ? r - preeditLength
+ : cursor.position();
+ }
+ }
return r;
}
@@ -950,6 +1042,8 @@ void QDeclarativeTextEdit::componentComplete()
Q_D(QDeclarativeTextEdit);
QDeclarativePaintedItem::componentComplete();
if (d->dirty) {
+ d->determineHorizontalAlignment();
+ d->updateDefaultTextOption();
updateSize();
d->dirty = false;
}
@@ -977,6 +1071,10 @@ void QDeclarativeTextEdit::setSelectByMouse(bool on)
if (d->selectByMouse != on) {
d->selectByMouse = on;
setKeepMouseGrab(on);
+ if (on)
+ setTextInteractionFlags(d->control->textInteractionFlags() | Qt::TextSelectableByMouse);
+ else
+ setTextInteractionFlags(d->control->textInteractionFlags() & ~Qt::TextSelectableByMouse);
emit selectByMouseChanged(on);
}
}
@@ -1029,11 +1127,10 @@ void QDeclarativeTextEdit::setReadOnly(bool r)
setFlag(QGraphicsItem::ItemAcceptsInputMethod, !r);
Qt::TextInteractionFlags flags = Qt::LinksAccessibleByMouse;
- if (r) {
+ if (d->selectByMouse)
flags = flags | Qt::TextSelectableByMouse;
- } else {
- flags = flags | Qt::TextEditorInteraction;
- }
+ if (!r)
+ flags = flags | Qt::TextSelectableByKeyboard | Qt::TextEditable;
d->control->setTextInteractionFlags(flags);
if (!r)
d->control->moveCursor(QTextCursor::End);
@@ -1125,12 +1222,13 @@ void QDeclarativeTextEdit::keyReleaseEvent(QKeyEvent *event)
void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus)
{
Q_Q(QDeclarativeTextEdit);
- q->setCursorVisible(hasFocus);
+ q->setCursorVisible(hasFocus && scene && scene->hasFocus());
QDeclarativeItemPrivate::focusChanged(hasFocus);
}
/*!
\qmlmethod void TextEdit::deselect()
+ \since Quick 1.1
Removes active text selection.
*/
@@ -1195,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()
@@ -1251,8 +1366,8 @@ void QDeclarativeTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
}
}
}
- if (event->type() != QEvent::GraphicsSceneMouseDoubleClick || d->selectByMouse)
- d->control->processEvent(event, QPointF(0, -d->yoff));
+
+ d->control->processEvent(event, QPointF(0, -d->yoff));
if (!event->isAccepted())
QDeclarativePaintedItem::mousePressEvent(event);
}
@@ -1287,13 +1402,11 @@ Handles the given mouse \a event.
void QDeclarativeTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QDeclarativeTextEdit);
- if (d->selectByMouse) {
- d->control->processEvent(event, QPointF(0, -d->yoff));
- if (!event->isAccepted())
- QDeclarativePaintedItem::mouseDoubleClickEvent(event);
- } else {
+
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
QDeclarativePaintedItem::mouseDoubleClickEvent(event);
- }
+
}
/*!
@@ -1303,14 +1416,9 @@ Handles the given mouse \a event.
void QDeclarativeTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QDeclarativeTextEdit);
- if (d->selectByMouse) {
- d->control->processEvent(event, QPointF(0, -d->yoff));
- if (!event->isAccepted())
- QDeclarativePaintedItem::mouseMoveEvent(event);
- event->setAccepted(true);
- } else {
+ d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (!event->isAccepted())
QDeclarativePaintedItem::mouseMoveEvent(event);
- }
}
/*!
@@ -1320,7 +1428,10 @@ Handles the given input method \a event.
void QDeclarativeTextEdit::inputMethodEvent(QInputMethodEvent *event)
{
Q_D(QDeclarativeTextEdit);
+ const bool wasComposing = isInputMethodComposing();
d->control->processEvent(event, QPointF(0, -d->yoff));
+ if (wasComposing != isInputMethodComposing())
+ emit inputMethodComposingChanged();
}
/*!
@@ -1385,19 +1496,38 @@ void QDeclarativeTextEdit::updateImgCache(const QRectF &rf)
/*!
\qmlproperty bool TextEdit::canPaste
+ \since QtQuick 1.1
Returns true if the TextEdit is writable and the content of the clipboard is
suitable for pasting into the TextEdit.
-
- \since QtQuick 1.1
*/
-
bool QDeclarativeTextEdit::canPaste() const
{
Q_D(const QDeclarativeTextEdit);
return d->canPaste;
}
+/*!
+ \qmlproperty bool TextEdit::inputMethodComposing
+
+ \since QtQuick 1.1
+
+ This property holds whether the TextEdit has partial text input from an
+ input method.
+
+ While it is composing an input method may rely on mouse or key events from
+ the TextEdit to edit or commit the partial text. This property can be used
+ to determine when to disable events handlers that may interfere with the
+ correct operation of an input method.
+*/
+bool QDeclarativeTextEdit::isInputMethodComposing() const
+{
+ Q_D(const QDeclarativeTextEdit);
+ if (QTextLayout *layout = d->control->textCursor().block().layout())
+ return layout->preeditAreaText().length() > 0;
+ return false;
+}
+
void QDeclarativeTextEditPrivate::init()
{
Q_Q(QDeclarativeTextEdit);
@@ -1409,7 +1539,7 @@ void QDeclarativeTextEditPrivate::init()
control = new QTextControl(q);
control->setIgnoreUnusedNavigationEvents(true);
- control->setTextInteractionFlags(control->textInteractionFlags() | Qt::LinksAccessibleByMouse);
+ control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable);
control->setDragEnabled(false);
// QTextControl follows the default text color
@@ -1433,6 +1563,7 @@ void QDeclarativeTextEditPrivate::init()
#ifndef QT_NO_CLIPBOARD
QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged()));
QObject::connect(QApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged()));
+ canPaste = control->canPaste();
#endif
document = control->document();
@@ -1447,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();
@@ -1611,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 7785a7a..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)
@@ -94,6 +95,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextEdit : public QDeclarativeImplicitSizePa
Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged)
Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged REVISION 1)
Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged REVISION 1)
+ Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged REVISION 1)
public:
QDeclarativeTextEdit(QDeclarativeItem *parent=0);
@@ -152,6 +154,8 @@ public:
HAlignment hAlign() const;
void setHAlign(HAlignment align);
+ void resetHAlign();
+ HAlignment effectiveHAlign() const;
VAlignment vAlign() const;
void setVAlign(VAlignment align);
@@ -215,6 +219,8 @@ public:
QRectF boundingRect() const;
+ bool isInputMethodComposing() const;
+
Q_SIGNALS:
void textChanged(const QString &);
void paintedSizeChanged();
@@ -242,12 +248,15 @@ Q_SIGNALS:
Q_REVISION(1) void mouseSelectionModeChanged(SelectionMode mode);
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 f9f2b18..c6de7a0 100644
--- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp
+++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp
@@ -51,6 +51,7 @@
#include <QFontMetrics>
#include <QPainter>
#include <QTextBoundaryFinder>
+#include <QInputContext>
#include <qstyle.h>
#ifndef QT_NO_LINEEDIT
@@ -325,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
@@ -337,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
{
@@ -347,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;
+ return true;
+ emit q->horizontalAlignmentChanged(alignment);
+ if (oldEffectiveHAlign != q->effectiveHAlign())
+ emit q->effectiveHorizontalAlignmentChanged();
+ }
+ 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();
+ }
+ }
}
/*!
@@ -481,6 +556,7 @@ QRect QDeclarativeTextInput::cursorRectangle() const
Q_D(const QDeclarativeTextInput);
QRect r = d->control->cursorRect();
r.setHeight(r.height()-1); // Make consistent with TextEdit (QLineControl inexplicably adds 1)
+ r.moveLeft(r.x() - d->hscroll);
return r;
}
@@ -776,6 +852,15 @@ bool QDeclarativeTextInput::hasAcceptableInput() const
}
/*!
+ \qmlsignal TextInput::onAccepted()
+
+ This handler is called when the Return or Enter key is pressed.
+ Note that if there is a \l validator or \l inputMask set on the text
+ input, the handler will only be emitted if the input is in an acceptable
+ state.
+*/
+
+/*!
\qmlproperty enumeration TextInput::echoMode
Specifies how the text should be displayed in the TextInput.
@@ -911,14 +996,22 @@ void QDeclarativeTextInput::moveCursor()
QRectF QDeclarativeTextInput::positionToRectangle(int pos) const
{
Q_D(const QDeclarativeTextInput);
+ if (pos > d->control->cursorPosition())
+ pos += d->control->preeditAreaText().length();
return QRectF(d->control->cursorToX(pos)-d->hscroll,
0.0,
d->control->cursorWidth(),
cursorRectangle().height());
}
+int QDeclarativeTextInput::positionAt(int x) const
+{
+ return positionAt(x, CursorBetweenCharacters);
+}
+
/*!
- \qmlmethod int TextInput::positionAt(int x)
+ \qmlmethod int TextInput::positionAt(int x, CursorPosition position = CursorBetweenCharacters)
+ \since Quick 1.1
This function returns the character position at
x pixels from the left of the textInput. Position 0 is before the
@@ -927,18 +1020,33 @@ QRectF QDeclarativeTextInput::positionToRectangle(int pos) const
This means that for all x values before the first character this function returns 0,
and for all x values after the last character this function returns text.length.
+
+ The cursor position type specifies how the cursor position should be resolved.
+
+ \list
+ \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
+ \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
+ \endlist
*/
-int QDeclarativeTextInput::positionAt(int x) const
+int QDeclarativeTextInput::positionAt(int x, CursorPosition position) const
{
Q_D(const QDeclarativeTextInput);
- return d->control->xToPos(x + d->hscroll);
+ int pos = d->control->xToPos(x + d->hscroll, QTextLine::CursorPosition(position));
+ const int cursor = d->control->cursor();
+ if (pos > cursor) {
+ const int preeditLength = d->control->preeditAreaText().length();
+ pos = pos > cursor + preeditLength
+ ? pos - preeditLength
+ : cursor;
+ }
+ return pos;
}
void QDeclarativeTextInputPrivate::focusChanged(bool hasFocus)
{
Q_Q(QDeclarativeTextInput);
focused = hasFocus;
- q->setCursorVisible(hasFocus);
+ q->setCursorVisible(hasFocus && scene && scene->hasFocus());
if(q->echoMode() == QDeclarativeTextInput::PasswordEchoOnEdit && !hasFocus)
control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events
if (!hasFocus)
@@ -952,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())
@@ -972,18 +1085,22 @@ void QDeclarativeTextInput::inputMethodEvent(QInputMethodEvent *ev)
{
Q_D(QDeclarativeTextInput);
ev->ignore();
+ const bool wasComposing = d->control->preeditAreaText().length() > 0;
inputMethodPreHandler(ev);
- if (ev->isAccepted())
- return;
- if (d->control->isReadOnly()) {
- ev->ignore();
- } else {
- d->control->processInputMethodEvent(ev);
- updateSize();
- d->updateHorizontalScroll();
+ if (!ev->isAccepted()) {
+ if (d->control->isReadOnly()) {
+ ev->ignore();
+ } else {
+ d->control->processInputMethodEvent(ev);
+ updateSize();
+ d->updateHorizontalScroll();
+ }
}
if (!ev->isAccepted())
QDeclarativePaintedItem::inputMethodEvent(ev);
+
+ if (wasComposing != (d->control->preeditAreaText().length() > 0))
+ emit inputMethodComposingChanged();
}
/*!
@@ -993,6 +1110,8 @@ Handles the given mouse \a event.
void QDeclarativeTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QDeclarativeTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonDblClick))
+ return;
if (d->selectByMouse) {
int cursor = d->xToPos(event->pos().x());
d->control->selectWordAtPos(cursor);
@@ -1005,6 +1124,8 @@ void QDeclarativeTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *even
void QDeclarativeTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QDeclarativeTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonPress))
+ return;
if(d->focusOnPress){
bool hadActiveFocus = hasActiveFocus();
forceActiveFocus();
@@ -1032,6 +1153,8 @@ void QDeclarativeTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event)
void QDeclarativeTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QDeclarativeTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseMove))
+ return;
if (d->selectByMouse) {
if (qAbs(int(event->pos().x() - d->pressPos.x())) > QApplication::startDragDistance())
setKeepMouseGrab(true);
@@ -1049,6 +1172,8 @@ Handles the given mouse \a event.
void QDeclarativeTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_D(QDeclarativeTextInput);
+ if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonRelease))
+ return;
if (d->selectByMouse)
setKeepMouseGrab(false);
if (!d->showInputPanelOnFocus) { // input panel on click
@@ -1066,6 +1191,44 @@ void QDeclarativeTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
QDeclarativePaintedItem::mouseReleaseEvent(event);
}
+bool QDeclarativeTextInputPrivate::sendMouseEventToInputContext(
+ QGraphicsSceneMouseEvent *event, QEvent::Type eventType)
+{
+#if !defined QT_NO_IM
+ if (event->widget() && control->composeMode()) {
+ int tmp_cursor = xToPos(event->pos().x());
+ int mousePos = tmp_cursor - control->cursor();
+ if (mousePos < 0 || mousePos > control->preeditAreaText().length()) {
+ mousePos = -1;
+ // don't send move events outside the preedit area
+ if (eventType == QEvent::MouseMove)
+ return true;
+ }
+
+ QInputContext *qic = event->widget()->inputContext();
+ if (qic) {
+ QMouseEvent mouseEvent(
+ eventType,
+ event->widget()->mapFromGlobal(event->screenPos()),
+ event->screenPos(),
+ event->button(),
+ event->buttons(),
+ event->modifiers());
+ // may be causing reset() in some input methods
+ qic->mouseHandler(mousePos, &mouseEvent);
+ event->setAccepted(mouseEvent.isAccepted());
+ }
+ if (!control->preeditAreaText().isEmpty())
+ return true;
+ }
+#else
+ Q_UNUSED(event);
+ Q_UNUSED(eventType)
+#endif
+
+ return false;
+}
+
bool QDeclarativeTextInput::sceneEvent(QEvent *event)
{
bool rv = QDeclarativeItem::sceneEvent(event);
@@ -1120,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;
@@ -1156,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:
@@ -1204,13 +1368,16 @@ QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property)
Q_D(const QDeclarativeTextInput);
switch(property) {
case Qt::ImMicroFocus:
- return d->control->cursorRect();
+ return cursorRectangle();
case Qt::ImFont:
return font();
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:
@@ -1229,6 +1396,7 @@ QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property)
/*!
\qmlmethod void TextInput::deselect()
+ \since Quick 1.1
Removes active text selection.
*/
@@ -1249,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()
@@ -1410,6 +1595,13 @@ void QDeclarativeTextInput::setMouseSelectionMode(SelectionMode mode)
}
}
+/*!
+ \qmlproperty bool TextInput::canPaste
+ \since QtQuick 1.1
+
+ Returns true if the TextInput is writable and the content of the clipboard is
+ suitable for pasting into the TextEdit.
+*/
bool QDeclarativeTextInput::canPaste() const
{
Q_D(const QDeclarativeTextInput);
@@ -1478,38 +1670,41 @@ void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode)
anchor = d->control->selectionStart();
if (anchor < pos || (anchor == pos && cursor < pos)) {
- QTextBoundaryFinder finder(QTextBoundaryFinder::Word, d->control->text());
+ const QString text = d->control->text();
+ QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
finder.setPosition(anchor);
const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
- if (!(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();
+ anchor = finder.position() != -1 ? finder.position() : 0;
finder.setPosition(pos);
- if (!finder.isAtBoundary())
+ if (pos > 0 && !finder.boundaryReasons())
finder.toNextBoundary();
+ const int cursor = finder.position() != -1 ? finder.position() : text.length();
- d->control->setSelection(anchor, finder.position() - anchor);
+ d->control->setSelection(anchor, cursor - anchor);
} else if (anchor > pos || (anchor == pos && cursor > pos)) {
- QTextBoundaryFinder finder(QTextBoundaryFinder::Word, d->control->text());
+ const QString text = d->control->text();
+ QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
finder.setPosition(anchor);
const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
- if (!(reasons & QTextBoundaryFinder::EndWord)
- || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor)) {
+ if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
+ || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
finder.toNextBoundary();
}
-
- anchor = finder.position();
+ anchor = finder.position() != -1 ? finder.position() : text.length();
finder.setPosition(pos);
- if (!finder.isAtBoundary())
+ if (pos < text.length() && !finder.boundaryReasons())
finder.toPreviousBoundary();
+ const int cursor = finder.position() != -1 ? finder.position() : 0;
- d->control->setSelection(anchor, finder.position() - anchor);
+ d->control->setSelection(anchor, cursor - anchor);
}
}
}
@@ -1628,6 +1823,25 @@ void QDeclarativeTextInput::focusInEvent(QFocusEvent *event)
QDeclarativePaintedItem::focusInEvent(event);
}
+/*!
+ \qmlproperty bool TextInput::inputMethodComposing
+
+ \since QtQuick 1.1
+
+ This property holds whether the TextInput has partial text input from an
+ input method.
+
+ While it is composing an input method may rely on mouse or key events from
+ the TextInput to edit or commit the partial text. This property can be
+ used to determine when to disable events handlers that may interfere with
+ the correct operation of an input method.
+*/
+bool QDeclarativeTextInput::isInputMethodComposing() const
+{
+ Q_D(const QDeclarativeTextInput);
+ return d->control->preeditAreaText().length() > 0;
+}
+
void QDeclarativeTextInputPrivate::init()
{
Q_Q(QDeclarativeTextInput);
@@ -1652,7 +1866,12 @@ void QDeclarativeTextInputPrivate::init()
q, SLOT(q_canPasteChanged()));
q->connect(QApplication::clipboard(), SIGNAL(dataChanged()),
q, SLOT(q_canPasteChanged()));
+ canPaste = !control->isReadOnly() && QApplication::clipboard()->text().length() != 0;
#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;
@@ -1660,6 +1879,7 @@ void QDeclarativeTextInputPrivate::init()
QPalette p = control->palette();
selectedTextColor = p.color(QPalette::HighlightedText);
selectionColor = p.color(QPalette::Highlight);
+ determineHorizontalAlignment();
}
void QDeclarativeTextInput::cursorPosChanged()
@@ -1707,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 e1e66a9..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)
@@ -97,6 +97,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextInput : public QDeclarativeImplicitSizeP
Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged)
Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged REVISION 1)
Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged REVISION 1)
+ Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged REVISION 1)
public:
QDeclarativeTextInput(QDeclarativeItem* parent=0);
@@ -120,8 +121,14 @@ public:
SelectWords
};
+ enum CursorPosition {
+ CursorBetweenCharacters,
+ CursorOnCharacter
+ };
+
//Auxilliary functions needed to control the TextInput from QML
Q_INVOKABLE int positionAt(int x) const;
+ Q_INVOKABLE Q_REVISION(1) int positionAt(int x, CursorPosition position) const;
Q_INVOKABLE QRectF positionToRectangle(int pos) const;
Q_INVOKABLE void moveCursorSelection(int pos);
Q_INVOKABLE Q_REVISION(1) void moveCursorSelection(int pos, SelectionMode mode);
@@ -146,6 +153,8 @@ public:
HAlignment hAlign() const;
void setHAlign(HAlignment align);
+ void resetHAlign();
+ HAlignment effectiveHAlign() const;
bool isReadOnly() const;
void setReadOnly(bool);
@@ -204,6 +213,8 @@ public:
QRectF boundingRect() const;
bool canPaste() const;
+ bool isInputMethodComposing() const;
+
Q_SIGNALS:
void textChanged();
void cursorPositionChanged();
@@ -231,6 +242,8 @@ Q_SIGNALS:
void selectByMouseChanged(bool selectByMouse);
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,
@@ -251,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 f7446b4..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,7 +103,11 @@ 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);
QLineControl* control;
@@ -124,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();
diff --git a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp
index b24dd2c..31819f5 100644
--- a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp
+++ b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp
@@ -99,7 +99,6 @@ class DrawTextItemRecorder: public QPaintEngine
needFreshCurrentItem = false;
last.numChars += ti.num_chars;
- last.numGlyphs += ti.glyphs.numGlyphs;
}
}
@@ -111,7 +110,7 @@ class DrawTextItemRecorder: public QPaintEngine
currentItem.font = ti.font();
currentItem.charOffset = charOffset;
currentItem.numChars = ti.num_chars;
- currentItem.numGlyphs = ti.glyphs.numGlyphs;
+ currentItem.numGlyphs = 0;
currentItem.glyphOffset = glyphOffset;
currentItem.positionOffset = positionOffset;
currentItem.useBackendOptimizations = m_useBackendOptimizations;
@@ -121,6 +120,8 @@ class DrawTextItemRecorder: public QPaintEngine
m_inertText->items.append(currentItem);
}
+ QStaticTextItem &currentItem = m_inertText->items.last();
+
QTransform matrix = m_untransformedCoordinates ? QTransform() : state->transform();
matrix.translate(position.x(), position.y());
@@ -129,18 +130,18 @@ class DrawTextItemRecorder: public QPaintEngine
ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
int size = glyphs.size();
- Q_ASSERT(size == ti.glyphs.numGlyphs);
Q_ASSERT(size == positions.size());
+ currentItem.numGlyphs += size;
m_inertText->glyphs.resize(m_inertText->glyphs.size() + size);
m_inertText->positions.resize(m_inertText->glyphs.size());
m_inertText->chars.resize(m_inertText->chars.size() + ti.num_chars);
glyph_t *glyphsDestination = m_inertText->glyphs.data() + glyphOffset;
- qMemCopy(glyphsDestination, glyphs.constData(), sizeof(glyph_t) * ti.glyphs.numGlyphs);
+ qMemCopy(glyphsDestination, glyphs.constData(), sizeof(glyph_t) * size);
QFixedPoint *positionsDestination = m_inertText->positions.data() + positionOffset;
- qMemCopy(positionsDestination, positions.constData(), sizeof(QFixedPoint) * ti.glyphs.numGlyphs);
+ qMemCopy(positionsDestination, positions.constData(), sizeof(QFixedPoint) * size);
QChar *charsDestination = m_inertText->chars.data() + charOffset;
qMemCopy(charsDestination, ti.chars, sizeof(QChar) * ti.num_chars);