Make *ItemBoundingRect modes work with custom shapes.

Currently, calling
QGraphicsScene::items(QPointF(0, 0), Qt::IntersectsItemBoundingRect) or
QGraphicsScene::items(QPointF(0, 0), Qt::ContainsItemBoundingRect)
will exclude items whose shape does not contain QPointF(0, 0). This is
because QGraphicsSceneIndexPointIntersector::intersect() also checks if
the point is contained within the shape, instead of just checking
if it is contained within the bounding rect.

Task-number: QTBUG-19036

Change-Id: Ie701af2a5694d40cf9b3c9c19adbb09a53a4e398
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Reviewed-by: Andreas Aardal Hanssen <andreas@hanssen.name>
This commit is contained in:
Mitch Curtis 2013-07-16 10:44:48 +02:00 committed by The Qt Project
parent 9b8b6c7db8
commit 5ec344cc77
2 changed files with 53 additions and 1 deletions

View File

@ -151,7 +151,7 @@ public:
itemd->sceneTransform.dy()) itemd->sceneTransform.dy())
: itemd->sceneTransform.mapRect(brect); : itemd->sceneTransform.mapRect(brect);
keep = sceneBoundingRect.intersects(QRectF(scenePoint, QSizeF(1, 1))); keep = sceneBoundingRect.intersects(QRectF(scenePoint, QSizeF(1, 1)));
if (keep) { if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
QPointF p = itemd->sceneTransformTranslateOnly QPointF p = itemd->sceneTransformTranslateOnly
? QPointF(scenePoint.x() - itemd->sceneTransform.dx(), ? QPointF(scenePoint.x() - itemd->sceneTransform.dx(),
scenePoint.y() - itemd->sceneTransform.dy()) scenePoint.y() - itemd->sceneTransform.dy())

View File

@ -61,6 +61,8 @@ private slots:
void movingItems(); void movingItems();
void connectedToSceneRectChanged(); void connectedToSceneRectChanged();
void items(); void items();
void boundingRectPointIntersection_data();
void boundingRectPointIntersection();
void removeItems(); void removeItems();
void clear(); void clear();
@ -233,6 +235,56 @@ void tst_QGraphicsSceneIndex::items()
QCOMPARE(scene.items().size(), 3); QCOMPARE(scene.items().size(), 3);
} }
class CustomShapeItem : public QGraphicsItem
{
public:
CustomShapeItem(const QPainterPath &shape) : QGraphicsItem(0), mShape(shape) {}
QPainterPath shape() const { return mShape; }
QRectF boundingRect() const { return mShape.boundingRect(); }
void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) {}
private:
QPainterPath mShape;
};
Q_DECLARE_METATYPE(Qt::ItemSelectionMode)
Q_DECLARE_METATYPE(QPainterPath)
void tst_QGraphicsSceneIndex::boundingRectPointIntersection_data()
{
QTest::addColumn<QPainterPath>("itemShape");
QTest::addColumn<Qt::ItemSelectionMode>("mode");
QTest::newRow("zero shape - intersects rect") << QPainterPath() << Qt::IntersectsItemBoundingRect;
QTest::newRow("zero shape - contains rect") << QPainterPath() << Qt::ContainsItemBoundingRect;
QPainterPath triangle;
triangle.moveTo(50, 0);
triangle.lineTo(0, 50);
triangle.lineTo(100, 50);
triangle.lineTo(50, 0);
QTest::newRow("triangle shape - intersects rect") << triangle << Qt::IntersectsItemBoundingRect;
QTest::newRow("triangle shape - contains rect") << triangle << Qt::ContainsItemBoundingRect;
QPainterPath rect;
rect.addRect(QRectF(0, 0, 100, 100));
QTest::newRow("rectangle shape - intersects rect") << rect << Qt::IntersectsItemBoundingRect;
QTest::newRow("rectangle shape - contains rect") << rect << Qt::ContainsItemBoundingRect;
}
void tst_QGraphicsSceneIndex::boundingRectPointIntersection()
{
QFETCH(QPainterPath, itemShape);
QFETCH(Qt::ItemSelectionMode, mode);
QGraphicsScene scene;
CustomShapeItem *item = new CustomShapeItem(itemShape);
scene.addItem(item);
QList<QGraphicsItem*> items = scene.items(QPointF(0, 0), mode, Qt::AscendingOrder);
QVERIFY(!items.isEmpty());
QCOMPARE(items.first(), item);
}
class RectWidget : public QGraphicsWidget class RectWidget : public QGraphicsWidget
{ {
Q_OBJECT Q_OBJECT