summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp431
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h41
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h79
-rw-r--r--src/gui/graphicsview/qgraphicswidget.h9
-rw-r--r--tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp88
-rw-r--r--tests/benchmarks/qgraphicsitem/qgraphicsitem.pro6
-rw-r--r--tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp170
7 files changed, 780 insertions, 44 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 72b832a..b7e88f4 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -130,12 +130,18 @@
\img graphicsview-parentchild.png
+ \section Transformation
+
QGraphicsItem supports affine transformations in addition to its base
position, pos(). To change the item's transformation, you can either pass
- a transformation matrix to setTransform(), or call one of the convenience
- functions rotate(), scale(), translate(), or shear(). Item transformations
- accumulate from parent to child, so if both a parent and child item are
- rotated 90 degrees, the child's total transformation will be 180 degrees.
+ a transformation matrix to setTransform(), or set the different transformation
+ properties (transformOrigin, x/y/zRotation, x/yScale, horizontal/verticalShear).
+ Note that setting the transformation matrix conflicts with using the properties.
+ Setting the properties will overwrite the transformation set with setTransform,
+ and using setTransform will reset the properties.
+
+ Item transformations accumulate from parent to child, so if both a parent and child
+ item are rotated 90 degrees, the child's total transformation will be 180 degrees.
Similarly, if the item's parent is scaled to 2x its original size, its
children will also be twice as large. An item's transformation does not
affect its own local geometry; all geometry functions (e.g., contains(),
@@ -146,6 +152,22 @@
and scenePos(), which returns its position in scene coordinates. To reset
an item's matrix, call resetTransform().
+ The order you set the transformation properties does not affect the resulting transformation
+ The resulting transformation is always computed in the following order
+
+ \code
+ [Origin] [RotateX] [RotateY] [RotateZ] [Shear] [Scale] [-Origin]
+ \endcode
+
+ So the transformation is equivalent to the following code
+
+ \code
+ QTransform().translate(xOrigin, yOrigin).rotate(xRotation, Qt::XAxis).rotate(yRotation, Qt::YAxis).rotate(zRotation, Qt::ZAxis)
+ .shear(horizontalShear, verticalShear).scale(xScale, yScale).translate(-xOrigin, -yOrigin);
+ \endcode
+
+ \section Painting
+
The paint() function is called by QGraphicsView to paint the item's
contents. The item has no background or default fill of its own; whatever
is behind the item will shine through all areas that are not explicitly
@@ -161,6 +183,8 @@
high z-values. Stacking order applies to sibling items; parents are always
drawn before their children.
+ \section Events
+
QGraphicsItem receives events from QGraphicsScene through the virtual
function sceneEvent(). This function distributes the most common events
to a set of convenience event handlers:
@@ -186,6 +210,8 @@
by the virtual function sceneEventFilter(). You can remove item
event filters by calling removeSceneEventFilter().
+ \section Custom Data
+
Sometimes it's useful to register custom data with an item, be it a custom
item, or a standard item. You can call setData() on any item to store data
in it using a key-value pair (the key being an integer, and the value is a
@@ -338,16 +364,17 @@
\value ItemTransformChange The item's transformation matrix changes. This
notification is only sent when the item's local transformation matrix
- changes (i.e., as a result of calling setTransform(), or one of the
- convenience transformation functions, such as rotate()). The value
+ changes (i.e., as a result of calling setTransform(). The value
argument is the new matrix (i.e., a QTransform); to get the old matrix,
- call transform(). Do not call setTransform() or any of the transformation
- convenience functions in itemChange() as this notification is delivered;
+ call transform(). Do not call setTransform() or set any of the transformation
+ properties in itemChange() as this notification is delivered;
instead, you can return the new matrix from itemChange().
+ This notification is not sent if you change the transformation properties.
\value ItemTransformHasChanged The item's transformation matrix has
- changed. This notification is only sent after the item's local
- trasformation matrix has changed. The value argument is the new matrix
+ changed either because setTransform is called, or one of the transformation
+ properties is changed. This notification is only sent after the item's local
+ transformation matrix has changed. The value argument is the new matrix
(same as transform()), and QGraphicsItem ignores the return value for this
notification (i.e., a read-only notification).
@@ -2559,8 +2586,13 @@ QMatrix QGraphicsItem::matrix() const
/*!
\since 4.3
- Returns this item's transformation matrix. If no matrix has been set, the
- identity matrix is returned.
+ Returns this item's transformation matrix.
+
+ Either the one set by setTransform, or the resulting transformation from
+ all the transfmation properties
+
+ If no matrix or transformation property has been set, the
+ identity matrix is returned.
\sa setTransform(), sceneTransform()
*/
@@ -2568,10 +2600,307 @@ QTransform QGraphicsItem::transform() const
{
if (!d_ptr->hasTransform)
return QTransform();
+ if (d_ptr->hasDecomposedTransform && d_ptr->dirtyTransform) {
+ QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform();
+ QTransform x;
+ decomposed->generateTransform(&x);
+ QVariant v(x);
+ d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, v);
+ d_ptr->dirtyTransform = 0;
+ d_ptr->dirtyTransformComponents = 1;
+ const_cast<QGraphicsItem *>(this)->itemChange(ItemTransformHasChanged, v);
+ return x;
+ }
return qVariantValue<QTransform>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform));
}
/*!
+ \property QGraphicsItem::xRotation
+
+ \since 4.6
+
+ This property holds the rotation angle in degrees around the X axis
+
+ The default is 0
+
+ \warning setting this property is conflicting with calling setTransform.
+ If a transform has been set, this function return the default value.
+
+ \sa {Transformations}
+*/
+qreal QGraphicsItem::xRotation() const
+{
+ return d_ptr->decomposedTransform()->xRotation;
+}
+
+void QGraphicsItem::setXRotation(qreal angle)
+{
+ if (!d_ptr->dirtyTransform) {
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+ }
+ QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform();
+ decomposed->xRotation = angle;
+ if (!d_ptr->dirtyTransform)
+ d_ptr->invalidateSceneTransformCache();
+ d_ptr->dirtyTransform = 1;
+ d_ptr->hasTransform = 1;
+}
+
+/*!
+ \property QGraphicsItem::yRotation
+
+ \since 4.6
+
+ This property holds the rotation angle in degrees around the Y axis
+
+ The default is 0
+
+ \warning setting this property is conflicting with calling setTransform.
+ If a transform has been set, this function return the default value.
+
+ \sa {Transformations}
+*/
+qreal QGraphicsItem::yRotation() const
+{
+ return d_ptr->decomposedTransform()->yRotation;
+}
+
+void QGraphicsItem::setYRotation(qreal angle)
+{
+ if (!d_ptr->dirtyTransform) {
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+ }
+ QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform();
+ decomposed->yRotation = angle;
+ if (!d_ptr->dirtyTransform)
+ d_ptr->invalidateSceneTransformCache();
+ d_ptr->dirtyTransform = 1;
+ d_ptr->hasTransform = 1;
+}
+
+/*!
+ \property QGraphicsItem::zRotation
+
+ \since 4.6
+
+ This property holds the rotation angle in degrees around the Z axis
+
+ The default is 0
+
+ \warning setting this property is conflicting with calling setTransform.
+ If a transform has been set, this function return the default value.
+
+ \sa {Transformations}
+*/
+qreal QGraphicsItem::zRotation() const
+{
+ return d_ptr->decomposedTransform()->zRotation;
+}
+
+void QGraphicsItem::setZRotation(qreal angle)
+{
+ if (!d_ptr->dirtyTransform) {
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+ }
+ QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform();
+ decomposed->zRotation = angle;
+ if (!d_ptr->dirtyTransform)
+ d_ptr->invalidateSceneTransformCache();
+ d_ptr->dirtyTransform = 1;
+ d_ptr->hasTransform = 1;
+}
+
+void QGraphicsItem::setRotation(qreal x, qreal y, qreal z)
+{
+ setXRotation(x);
+ setYRotation(y);
+ setZRotation(z);
+}
+
+/*!
+ \property QGraphicsItem::xScale
+
+ \since 4.6
+
+ This property holds the scale factor on the X axis.
+
+ The default is 1
+
+ \warning setting this property is conflicting with calling setTransform.
+ If a transform has been set, this function return the default value.
+
+ \sa {Transformations}
+*/
+qreal QGraphicsItem::xScale() const
+{
+ return d_ptr->decomposedTransform()->xScale;
+}
+
+void QGraphicsItem::setXScale(qreal factor)
+{
+ if (!d_ptr->dirtyTransform) {
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+ }
+ QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform();
+ decomposed->xScale = factor;
+ if (!d_ptr->dirtyTransform)
+ d_ptr->invalidateSceneTransformCache();
+ d_ptr->dirtyTransform = 1;
+ d_ptr->hasTransform = 1;
+}
+
+/*!
+ \property QGraphicsItem::yScale
+
+ \since 4.6
+
+ This property holds the scale factor on the Y axis.
+
+ The default is 1
+
+ \warning setting this property is conflicting with calling setTransform.
+ If a transform has been set, this function return the default value.
+
+ \sa {Transformations}
+*/
+qreal QGraphicsItem::yScale() const
+{
+ return d_ptr->decomposedTransform()->yScale;
+}
+
+void QGraphicsItem::setYScale(qreal factor)
+{
+ if (!d_ptr->dirtyTransform) {
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+ }
+ QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform();
+ decomposed->yScale = factor;
+ if (!d_ptr->dirtyTransform)
+ d_ptr->invalidateSceneTransformCache();
+ d_ptr->dirtyTransform = 1;
+ d_ptr->hasTransform = 1;
+}
+
+void QGraphicsItem::setScale(qreal sx, qreal sy)
+{
+ setXScale(sx);
+ setYScale(sy);
+}
+
+/*!
+ \property QGraphicsItem::horizontalShear
+
+ \since 4.6
+
+ This property holds the horizontal shear.
+
+ The default is 0.
+
+ \warning setting this property is conflicting with calling setTransform.
+ If a transform has been set, this function return the default value.
+
+ \sa {Transformations}
+*/
+qreal QGraphicsItem::horizontalShear() const
+{
+ return d_ptr->decomposedTransform()->horizontalShear;
+}
+
+void QGraphicsItem::setHorizontalShear(qreal shear)
+{
+ if (!d_ptr->dirtyTransform) {
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+ }
+ QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform();
+ decomposed->horizontalShear = shear;
+ if (!d_ptr->dirtyTransform)
+ d_ptr->invalidateSceneTransformCache();
+ d_ptr->dirtyTransform = 1;
+ d_ptr->hasTransform = 1;
+}
+
+/*!
+ \property QGraphicsItem::verticalShear
+
+ \since 4.6
+
+ This property holds the vertical shear.
+
+ The default is 0.
+
+ \warning setting this property is conflicting with calling setTransform.
+ If a transform has been set, this function return the default value.
+
+ \sa {Transformations}
+*/
+qreal QGraphicsItem::verticalShear() const
+{
+ return d_ptr->decomposedTransform()->verticalShear;
+}
+
+void QGraphicsItem::setVerticalShear(qreal shear)
+{
+ if (!d_ptr->dirtyTransform) {
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+ }
+ QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform();
+ decomposed->verticalShear = shear;
+ if (!d_ptr->dirtyTransform)
+ d_ptr->invalidateSceneTransformCache();
+ d_ptr->dirtyTransform = 1;
+ d_ptr->hasTransform = 1;
+}
+
+void QGraphicsItem::setShear(qreal sh, qreal sv)
+{
+ setHorizontalShear(sh);
+ setVerticalShear(sv);
+}
+
+/*!
+ \property QGraphicsItem::transformOrigin
+
+ \since 4.6
+
+ This property holds the transformation origin for the transformation properties.
+ This does not apply to the transformation set by setTransform.
+
+ The default is QPointF(0,0).
+
+ \warning setting this property is conflicting with calling setTransform.
+ If a transform has been set, this function return the default value.
+
+ \sa {Transformations}
+*/
+QPointF QGraphicsItem::transformOrigin() const
+{
+ const QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform();
+ return QPointF(decomposed->xOrigin, decomposed->yOrigin);
+}
+
+void QGraphicsItem::setTransformOrigin(const QPointF &origin)
+{
+ if (!d_ptr->dirtyTransform) {
+ d_ptr->fullUpdateHelper(true);
+ prepareGeometryChange();
+ }
+ QGraphicsItemPrivate::DecomposedTransform *decomposed = d_ptr->decomposedTransform();
+ decomposed->xOrigin = origin.x();
+ decomposed->yOrigin = origin.y();
+ if (!d_ptr->dirtyTransform)
+ d_ptr->invalidateSceneTransformCache();
+ d_ptr->dirtyTransform = 1;
+ d_ptr->hasTransform = 1;
+}
+
+/*!
\obsolete
Use sceneTransform() instead.
@@ -2846,7 +3175,7 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co
Use setTransform() instead.
- \sa transform(), rotate(), scale(), shear(), translate(), {The Graphics View Coordinate System}
+ \sa transform(), {The Graphics View Coordinate System}
*/
void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
{
@@ -2872,6 +3201,8 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
d_ptr->hasTransform = !newTransform.isIdentity();
d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform);
d_ptr->invalidateSceneTransformCache();
+ if (d_ptr->hasDecomposedTransform)
+ d_ptr->dirtyTransform = 1;
// Send post-notification.
// NB! We have to change the value from QMatrix to QTransform.
@@ -2894,7 +3225,10 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
to map an item coordiate to a scene coordinate, or mapFromScene() to map
from scene coordinates to item coordinates.
- \sa transform(), rotate(), scale(), shear(), translate(), {The Graphics View Coordinate System}
+ \warning using this function conflicts with using the transformation properties.
+ If you set a transformation, getting the properties will return default values.
+
+ \sa transform(), setRotation(), setScale(), setShear(), setTransformOrigin() {The Graphics View Coordinate System}
*/
void QGraphicsItem::setTransform(const QTransform &matrix, bool combine)
{
@@ -2920,6 +3254,8 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine)
d_ptr->hasTransform = !newTransform.isIdentity();
d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform);
d_ptr->invalidateSceneTransformCache();
+ if (d_ptr->hasDecomposedTransform)
+ d_ptr->dirtyTransform = 1;
// Send post-notification.
itemChange(ItemTransformHasChanged, newTransformVariant);
@@ -2938,8 +3274,9 @@ void QGraphicsItem::resetMatrix()
/*!
\since 4.3
- Resets this item's transformation matrix to the identity matrix. This is
- equivalent to calling \c setTransform(QTransform()).
+ Resets this item's transformation matrix to the identity matrix or
+ all the transformation properties to their default values.
+ This is equivalent to calling \c setTransform(QTransform()).
\sa setTransform(), transform()
*/
@@ -2949,6 +3286,9 @@ void QGraphicsItem::resetTransform()
}
/*!
+ \obsolete
+ Use setZRotation() instead
+
Rotates the current item transformation \a angle degrees clockwise around
its origin. To translate around an arbitrary point (x, y), you need to
combine translation and rotation with setTransform().
@@ -2957,6 +3297,9 @@ void QGraphicsItem::resetTransform()
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 6
+ \warning using this function conflicts with using the transformation properties.
+ Getting those properties after using this function will return default values.
+
\sa setTransform(), transform(), scale(), shear(), translate()
*/
void QGraphicsItem::rotate(qreal angle)
@@ -2965,6 +3308,9 @@ void QGraphicsItem::rotate(qreal angle)
}
/*!
+ \obsolete
+ Use setScale() instead
+
Scales the current item transformation by (\a sx, \a sy) around its
origin. To scale from an arbitrary point (x, y), you need to combine
translation and scaling with setTransform().
@@ -2973,7 +3319,10 @@ void QGraphicsItem::rotate(qreal angle)
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 7
- \sa setTransform(), transform(), rotate(), shear(), translate()
+ \warning using this function conflicts with using the transformation properties.
+ Getting those properties after using this function will return default values.
+
+ \sa setTransform(), transform()
*/
void QGraphicsItem::scale(qreal sx, qreal sy)
{
@@ -2981,9 +3330,15 @@ void QGraphicsItem::scale(qreal sx, qreal sy)
}
/*!
+ \obsolete
+ Use setShear instead.
+
Shears the current item transformation by (\a sh, \a sv).
- \sa setTransform(), transform(), rotate(), scale(), translate()
+ \warning using this function conflicts with using the transformation properties.
+ Getting those properties after using this function will return default values.
+
+ \sa setTransform(), transform()
*/
void QGraphicsItem::shear(qreal sh, qreal sv)
{
@@ -2991,13 +3346,19 @@ void QGraphicsItem::shear(qreal sh, qreal sv)
}
/*!
+ \obsolete
+ Use setPos() or setTransformOrigin() instead.
+
Translates the current item transformation by (\a dx, \a dy).
If all you want is to move an item, you should call moveBy() or
setPos() instead; this function changes the item's translation,
which is conceptually separate from its position.
- \sa setTransform(), transform(), rotate(), scale(), shear()
+ \warning using this function conflicts with using the transformation properties.
+ Getting those properties after using this function will return default values.
+
+ \sa setTransform(), transform()
*/
void QGraphicsItem::translate(qreal dx, qreal dy)
{
@@ -3121,7 +3482,7 @@ QRectF QGraphicsItem::childrenBoundingRect() const
Although the item's shape can be arbitrary, the bounding rect is
always rectangular, and it is unaffected by the items'
- transformation (scale(), rotate(), etc.).
+ transformation.
If you want to change the item's bounding rectangle, you must first call
prepareGeometryChange(). This notifies the scene of the imminent change,
@@ -8143,19 +8504,19 @@ bool QGraphicsTextItem::sceneEvent(QEvent *event)
void QGraphicsTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if ((QGraphicsItem::d_ptr->flags & (ItemIsSelectable | ItemIsMovable))
- && (event->buttons() & Qt::LeftButton) && dd->_q_mouseOnEdge(event)) {
- // User left-pressed on edge of selectable/movable item, use
- // base impl.
- dd->useDefaultImpl = true;
+ && (event->buttons() & Qt::LeftButton) && dd->_q_mouseOnEdge(event)) {
+ // User left-pressed on edge of selectable/movable item, use
+ // base impl.
+ dd->useDefaultImpl = true;
} else if (event->buttons() == event->button()
- && dd->control->textInteractionFlags() == Qt::NoTextInteraction) {
- // User pressed first button on non-interactive item.
- dd->useDefaultImpl = true;
+ && dd->control->textInteractionFlags() == Qt::NoTextInteraction) {
+ // User pressed first button on non-interactive item.
+ dd->useDefaultImpl = true;
}
if (dd->useDefaultImpl) {
QGraphicsItem::mousePressEvent(event);
- if (!event->isAccepted())
- dd->useDefaultImpl = false;
+ if (!event->isAccepted())
+ dd->useDefaultImpl = false;
return;
}
dd->sendControlEvent(event);
@@ -8180,14 +8541,14 @@ void QGraphicsTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (dd->useDefaultImpl) {
QGraphicsItem::mouseReleaseEvent(event);
- if (dd->control->textInteractionFlags() == Qt::NoTextInteraction
- && !event->buttons()) {
- // User released last button on non-interactive item.
+ if (dd->control->textInteractionFlags() == Qt::NoTextInteraction
+ && !event->buttons()) {
+ // User released last button on non-interactive item.
dd->useDefaultImpl = false;
- } else if ((event->buttons() & Qt::LeftButton) == 0) {
- // User released the left button on an interactive item.
+ } else if ((event->buttons() & Qt::LeftButton) == 0) {
+ // User released the left button on an interactive item.
dd->useDefaultImpl = false;
- }
+ }
return;
}
dd->sendControlEvent(event);
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index 0a0179e..f6ee197 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -241,11 +241,41 @@ public:
QTransform itemTransform(const QGraphicsItem *other, bool *ok = 0) const;
void setTransform(const QTransform &matrix, bool combine = false);
void resetTransform();
-
- void rotate(qreal angle);
- void scale(qreal sx, qreal sy);
- void shear(qreal sh, qreal sv);
- void translate(qreal dx, qreal dy);
+
+ void rotate(qreal angle); // ### obsolete
+ void scale(qreal sx, qreal sy); // ### obsolete
+ void shear(qreal sh, qreal sv); // ### obsolete
+ void translate(qreal dx, qreal dy); // ### obsolete
+
+ qreal xRotation() const;
+ void setXRotation(qreal angle);
+
+ qreal yRotation() const;
+ void setYRotation(qreal angle);
+
+ qreal zRotation() const;
+ void setZRotation(qreal angle);
+ void setRotation(qreal x, qreal y, qreal z);
+
+ qreal xScale() const;
+ void setXScale(qreal factor);
+
+ qreal yScale() const;
+ void setYScale(qreal factor);
+ void setScale(qreal sx, qreal sy);
+
+ qreal horizontalShear() const;
+ void setHorizontalShear(qreal shear);
+
+ qreal verticalShear() const;
+ void setVerticalShear(qreal shear);
+ void setShear(qreal sh, qreal sv);
+
+ QPointF transformOrigin() const;
+ void setTransformOrigin(const QPointF &origin);
+ inline void setTransformOrigin(qreal x, qreal y)
+ { setTransformOrigin(QPointF(x,y)); }
+
virtual void advance(int phase);
// Stacking order
@@ -1015,4 +1045,3 @@ QT_END_NAMESPACE
QT_END_HEADER
#endif // QGRAPHICSITEM_H
-
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 820ef04..cebc8ca 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -56,6 +56,8 @@
#include "qgraphicsitem.h"
#include "qpixmapcache.h"
+#include <QtCore/qpoint.h>
+
#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
QT_BEGIN_NAMESPACE
@@ -101,7 +103,8 @@ public:
ExtraMaxDeviceCoordCacheSize,
ExtraBoundingRegionGranularity,
ExtraOpacity,
- ExtraEffectiveOpacity
+ ExtraEffectiveOpacity,
+ ExtraDecomposedTransform
};
enum AncestorFlag {
@@ -145,6 +148,9 @@ public:
inSetPosHelper(0),
flags(0),
allChildrenCombineOpacity(1),
+ hasDecomposedTransform(0),
+ dirtyTransform(0),
+ dirtyTransformComponents(0),
globalStackingOrder(-1),
sceneTransformIndex(-1),
q_ptr(0)
@@ -331,15 +337,84 @@ public:
// New 32 bits
quint32 flags : 10;
quint32 allChildrenCombineOpacity : 1;
- quint32 padding : 21; // feel free to use
+ quint32 hasDecomposedTransform : 1;
+ quint32 dirtyTransform : 1;
+ quint32 dirtyTransformComponents : 1;
+ quint32 padding : 18; // feel free to use
// Optional stacking order
int globalStackingOrder;
int sceneTransformIndex;
+ struct DecomposedTransform;
+ DecomposedTransform *decomposedTransform() const
+ {
+ QGraphicsItemPrivate *that = const_cast<QGraphicsItemPrivate *>(this);
+ DecomposedTransform *decomposed;
+ if (hasDecomposedTransform) {
+ decomposed = qVariantValue<DecomposedTransform *>(extra(ExtraDecomposedTransform));
+ } else {
+ decomposed = new DecomposedTransform;
+ that->setExtra(ExtraDecomposedTransform, qVariantFromValue<DecomposedTransform *>(decomposed));
+ that->hasDecomposedTransform = 1;
+ if (!dirtyTransformComponents)
+ decomposed->reset();
+ }
+ if (dirtyTransformComponents) {
+ decomposed->initFrom(q_ptr->transform());
+ that->dirtyTransformComponents = 0;
+ }
+ return decomposed;
+ }
+
+ struct DecomposedTransform {
+ qreal xScale;
+ qreal yScale;
+ qreal xRotation;
+ qreal yRotation;
+ qreal zRotation;
+ qreal horizontalShear;
+ qreal verticalShear;
+ qreal xOrigin;
+ qreal yOrigin;
+
+ inline void reset()
+ {
+ xScale = 1.0;
+ yScale = 1.0;
+ xRotation = 0.0;
+ yRotation = 0.0;
+ zRotation = 0.0;
+ horizontalShear = 0.0;
+ verticalShear = 0.0;
+ xOrigin = 0.0;
+ yOrigin = 0.0;
+ }
+
+ inline void initFrom(const QTransform &x)
+ {
+ reset();
+ // ### decompose transform
+ Q_UNUSED(x);
+ }
+
+ inline void generateTransform(QTransform *x) const
+ {
+ x->translate(xOrigin, yOrigin);
+ x->rotate(xRotation, Qt::XAxis);
+ x->rotate(yRotation, Qt::YAxis);
+ x->rotate(zRotation, Qt::ZAxis);
+ x->shear(horizontalShear, verticalShear);
+ x->scale(xScale, yScale);
+ x->translate(-xOrigin, -yOrigin);
+ }
+ };
+
QGraphicsItem *q_ptr;
};
+Q_DECLARE_METATYPE(QGraphicsItemPrivate::DecomposedTransform *)
+
QT_END_NAMESPACE
#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicswidget.h b/src/gui/graphicsview/qgraphicswidget.h
index 34f1c5f..a5c9068 100644
--- a/src/gui/graphicsview/qgraphicswidget.h
+++ b/src/gui/graphicsview/qgraphicswidget.h
@@ -81,7 +81,14 @@ class Q_GUI_EXPORT QGraphicsWidget : public QObject, public QGraphicsItem, publi
Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity)
Q_PROPERTY(QPointF pos READ pos WRITE setPos)
Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry)
-
+ Q_PROPERTY(QPointF transformOrigin READ transformOrigin WRITE setTransformOrigin)
+ Q_PROPERTY(qreal xRotation READ xRotation WRITE setXRotation)
+ Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation)
+ Q_PROPERTY(qreal zRotation READ zRotation WRITE setZRotation)
+ Q_PROPERTY(qreal xScale READ xScale WRITE setXScale)
+ Q_PROPERTY(qreal yScale READ yScale WRITE setYScale)
+ Q_PROPERTY(qreal horizontalShear READ horizontalShear WRITE setHorizontalShear)
+ Q_PROPERTY(qreal verticalShear READ verticalShear WRITE setVerticalShear)
public:
QGraphicsWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0);
~QGraphicsWidget();
diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
index b3ae60a..d41b3b4 100644
--- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
+++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
@@ -219,6 +219,8 @@ private slots:
void updateCachedItemAfterMove();
void deviceTransform_data();
void deviceTransform();
+ void setTransformProperties_data();
+ void setTransformProperties();
// task specific tests below me
void task141694_textItemEnsureVisible();
@@ -6390,5 +6392,91 @@ void tst_QGraphicsItem::deviceTransform()
QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3);
}
+void tst_QGraphicsItem::setTransformProperties_data()
+{
+ QTest::addColumn<QPointF>("origin");
+ QTest::addColumn<qreal>("rotationX");
+ QTest::addColumn<qreal>("rotationY");
+ QTest::addColumn<qreal>("rotationZ");
+ QTest::addColumn<qreal>("scaleX");
+ QTest::addColumn<qreal>("scaleY");
+ QTest::addColumn<qreal>("shearX");
+ QTest::addColumn<qreal>("shearY");
+
+ QTest::newRow("nothing") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0)
+ << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
+
+ QTest::newRow("rotationZ") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(42.2)
+ << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
+
+ QTest::newRow("rotationXY") << QPointF() << qreal(12.5) << qreal(53.6) << qreal(0.0)
+ << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
+
+ QTest::newRow("rotationXYZ") << QPointF() << qreal(-25) << qreal(12) << qreal(556)
+ << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
+
+ QTest::newRow("rotationXYZ dicentred") << QPointF(-53, 25.2)
+ << qreal(-2578.2) << qreal(4565.2) << qreal(56)
+ << qreal(0.0) << qreal(0.0) << qreal(0.0) << qreal(0.0);
+
+ QTest::newRow("Scale") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0)
+ << qreal(6) << qreal(0.5) << qreal(0.0) << qreal(0.0);
+
+ QTest::newRow("Shear") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0)
+ << qreal(0.0) << qreal(0.0) << qreal(2.2) << qreal(0.5);
+
+ QTest::newRow("Scale and Shear") << QPointF() << qreal(0.0) << qreal(0.0) << qreal(0.0)
+ << qreal(5.2) << qreal(2.1) << qreal(5.2) << qreal(5.5);
+
+ QTest::newRow("Everything") << QPointF() << qreal(41) << qreal(-23) << qreal(0.56)
+ << qreal(8.2) << qreal(-0.2) << qreal(-12) << qreal(-0.8);
+
+ QTest::newRow("Everything dicentred") << QPointF(qreal(22.3), qreal(-56.2)) << qreal(-175) << qreal(196) << qreal(-1260)
+ << qreal(4) << qreal(2) << qreal(2.56) << qreal(0.8);
+}
+
+void tst_QGraphicsItem::setTransformProperties()
+{
+ QFETCH(QPointF,origin);
+ QFETCH(qreal,rotationX);
+ QFETCH(qreal,rotationY);
+ QFETCH(qreal,rotationZ);
+ QFETCH(qreal,scaleX);
+ QFETCH(qreal,scaleY);
+ QFETCH(qreal,shearX);
+ QFETCH(qreal,shearY);
+
+ QTransform result;
+ result.translate(origin.x(), origin.y());
+ result.rotate(rotationX, Qt::XAxis);
+ result.rotate(rotationY, Qt::YAxis);
+ result.rotate(rotationZ, Qt::ZAxis);
+ result.shear(shearX, shearY);
+ result.scale(scaleX, scaleY);
+ result.translate(-origin.x(), -origin.y());
+
+ QGraphicsScene scene;
+ QGraphicsRectItem *item = new QGraphicsRectItem(QRectF(0, 0, 100, 100));
+ scene.addItem(item);
+ item->setPos(100, 100);
+
+ item->setRotation(rotationX, rotationY, rotationZ);
+ item->setScale(scaleX, scaleY);
+ item->setShear(shearX, shearY);
+ item->setTransformOrigin(origin);
+
+ QCOMPARE(item->xRotation(), rotationX);
+ QCOMPARE(item->yRotation(), rotationY);
+ QCOMPARE(item->zRotation(), rotationZ);
+ QCOMPARE(item->xScale(), scaleX);
+ QCOMPARE(item->yScale(), scaleY);
+ QCOMPARE(item->horizontalShear(), shearX);
+ QCOMPARE(item->verticalShear(), shearY);
+ QCOMPARE(item->transformOrigin(), origin);
+
+ QCOMPARE(result, item->transform());
+}
+
+
QTEST_MAIN(tst_QGraphicsItem)
#include "tst_qgraphicsitem.moc"
diff --git a/tests/benchmarks/qgraphicsitem/qgraphicsitem.pro b/tests/benchmarks/qgraphicsitem/qgraphicsitem.pro
new file mode 100644
index 0000000..c8fc07b
--- /dev/null
+++ b/tests/benchmarks/qgraphicsitem/qgraphicsitem.pro
@@ -0,0 +1,6 @@
+load(qttest_p4)
+TEMPLATE = app
+TARGET = tst_qgraphicsitem
+
+SOURCES += tst_qgraphicsitem.cpp
+
diff --git a/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp
new file mode 100644
index 0000000..68e3aa1
--- /dev/null
+++ b/tests/benchmarks/qgraphicsitem/tst_qgraphicsitem.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include <QGraphicsItem>
+#include <QGraphicsScene>
+#include <QGraphicsView>
+
+//TESTED_FILES=
+
+class tst_QGraphicsItem : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QGraphicsItem();
+ virtual ~tst_QGraphicsItem();
+
+public slots:
+ void init();
+ void cleanup();
+
+private slots:
+ void setPos_data();
+ void setPos();
+ void setTransform_data();
+ void setTransform();
+ void rotate();
+ void scale();
+ void shear();
+ void translate();
+ void setRotation();
+ void setRotationXYZ();
+};
+
+tst_QGraphicsItem::tst_QGraphicsItem()
+{
+}
+
+tst_QGraphicsItem::~tst_QGraphicsItem()
+{
+}
+
+void tst_QGraphicsItem::init()
+{
+}
+
+void tst_QGraphicsItem::cleanup()
+{
+}
+
+void tst_QGraphicsItem::setPos_data()
+{
+ QTest::addColumn<QPointF>("pos");
+
+ QTest::newRow("0, 0") << QPointF(0, 0);
+ QTest::newRow("10, 10") << QPointF(10, 10);
+ QTest::newRow("-10, -10") << QPointF(-10, -10);
+}
+
+void tst_QGraphicsItem::setPos()
+{
+ QFETCH(QPointF, pos);
+
+ QGraphicsScene scene;
+ QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100));
+
+ QBENCHMARK {
+ rect->setPos(10, 10);
+ rect->transform(); // prevent lazy optimizing
+ }
+}
+
+void tst_QGraphicsItem::setTransform_data()
+{
+ QTest::addColumn<QTransform>("transform");
+
+ QTest::newRow("id") << QTransform();
+ QTest::newRow("rotate 45z") << QTransform().rotate(45);
+ QTest::newRow("scale 2x2") << QTransform().scale(2, 2);
+ QTest::newRow("translate 100, 100") << QTransform().translate(100, 100);
+ QTest::newRow("rotate 45x 45y 45z") << QTransform().rotate(45, Qt::XAxis)
+ .rotate(45, Qt::YAxis).rotate(45, Qt::ZAxis);
+}
+
+void tst_QGraphicsItem::setTransform()
+{
+ QFETCH(QTransform, transform);
+
+ QGraphicsScene scene;
+ QGraphicsRectItem *item = scene.addRect(QRectF(0, 0, 100, 100));
+
+ QBENCHMARK {
+ item->setTransform(transform);
+ item->transform(); // prevent lazy optimizing
+ }
+}
+
+void tst_QGraphicsItem::rotate()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100));
+
+ QBENCHMARK {
+ item->rotate(45);
+ item->transform(); // prevent lazy optimizing
+ }
+}
+
+void tst_QGraphicsItem::scale()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100));
+
+ QBENCHMARK {
+ item->scale(2, 2);
+ item->transform(); // prevent lazy optimizing
+ }
+}
+
+void tst_QGraphicsItem::shear()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100));
+
+ QBENCHMARK {
+ item->shear(1.5, 1.5);
+ item->transform(); // prevent lazy optimizing
+ }
+}
+
+void tst_QGraphicsItem::translate()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100));
+
+ QBENCHMARK {
+ item->translate(100, 100);
+ item->transform(); // prevent lazy optimizing
+ }
+}
+
+void tst_QGraphicsItem::setRotation()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100));
+
+ QBENCHMARK {
+ item->setXRotation(45);
+ item->transform(); // prevent lazy optimizing
+ }
+}
+
+void tst_QGraphicsItem::setRotationXYZ()
+{
+ QGraphicsScene scene;
+ QGraphicsItem *item = scene.addRect(QRectF(0, 0, 100, 100));
+
+ QBENCHMARK {
+ item->setRotation(45, 45, 45);
+ item->transform(); // prevent lazy optimizing
+ }
+}
+
+QTEST_MAIN(tst_QGraphicsItem)
+#include "tst_qgraphicsitem.moc"