1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | |
30 | #include <QtTest/QtTest> |
31 | |
32 | #include <qgraphicsitem.h> |
33 | #include <qgraphicsscene.h> |
34 | #include <qgraphicssceneevent.h> |
35 | #include <qgraphicsview.h> |
36 | #include <qgraphicswidget.h> |
37 | #include <qgraphicsproxywidget.h> |
38 | |
39 | #include <math.h> |
40 | |
41 | #include <QtWidgets/QLabel> |
42 | #include <QtWidgets/QStyleFactory> |
43 | #include <QtWidgets/QCommonStyle> |
44 | #include <QtGui/QPainterPath> |
45 | #include <QtWidgets/QRubberBand> |
46 | #include <QtWidgets/QScrollBar> |
47 | #include <QtWidgets/QStyleOption> |
48 | #include <QtWidgets/QBoxLayout> |
49 | #include <QtWidgets/QStyle> |
50 | #include <QtWidgets/QPushButton> |
51 | #ifndef QT_NO_OPENGL |
52 | #include <QtWidgets/QOpenGLWidget> |
53 | #endif |
54 | #include <private/qgraphicsscene_p.h> |
55 | #include <private/qgraphicsview_p.h> |
56 | #include "../../../shared/platforminputcontext.h" |
57 | #include <private/qinputmethod_p.h> |
58 | #include <private/qguiapplication_p.h> |
59 | #include <qpa/qplatformintegration.h> |
60 | |
61 | #include "tst_qgraphicsview.h" |
62 | |
63 | #include <QtTest/private/qtesthelpers_p.h> |
64 | |
65 | using namespace QTestPrivate; |
66 | |
67 | Q_DECLARE_METATYPE(ExpectedValueDescription) |
68 | Q_DECLARE_METATYPE(QList<int>) |
69 | Q_DECLARE_METATYPE(QList<QRectF>) |
70 | Q_DECLARE_METATYPE(QTransform) |
71 | Q_DECLARE_METATYPE(QPainterPath) |
72 | Q_DECLARE_METATYPE(Qt::ScrollBarPolicy) |
73 | Q_DECLARE_METATYPE(ScrollBarCount) |
74 | |
75 | #ifdef Q_OS_MAC |
76 | //On mac we get full update. So check that the expected region is contained inside the actual |
77 | #define COMPARE_REGIONS(ACTUAL, EXPECTED) QVERIFY((EXPECTED).subtracted(ACTUAL).isEmpty()) |
78 | #else |
79 | #define COMPARE_REGIONS QCOMPARE |
80 | #endif |
81 | |
82 | static void sendMousePress(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton) |
83 | { |
84 | QMouseEvent event(QEvent::MouseButtonPress, point, widget->mapToGlobal(point), button, {}, {}); |
85 | QApplication::sendEvent(receiver: widget, event: &event); |
86 | } |
87 | |
88 | static void sendMouseMove(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::NoButton, Qt::MouseButtons buttons = {}) |
89 | { |
90 | QTest::mouseMove(widget, pos: point); |
91 | QMouseEvent event(QEvent::MouseMove, point, widget->mapToGlobal(point), button, buttons, {}); |
92 | QApplication::sendEvent(receiver: widget, event: &event); |
93 | QApplication::processEvents(); |
94 | } |
95 | |
96 | static void sendMouseRelease(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton) |
97 | { |
98 | QMouseEvent event(QEvent::MouseButtonRelease, point, widget->mapToGlobal(point), button, {}, {}); |
99 | QApplication::sendEvent(receiver: widget, event: &event); |
100 | } |
101 | |
102 | class EventSpy : public QObject |
103 | { |
104 | Q_OBJECT |
105 | public: |
106 | EventSpy(QObject *watched, QEvent::Type type) |
107 | : _count(0), spied(type) |
108 | { |
109 | watched->installEventFilter(filterObj: this); |
110 | } |
111 | |
112 | int count() const { return _count; } |
113 | void reset() { _count = 0; } |
114 | |
115 | protected: |
116 | bool eventFilter(QObject *watched, QEvent *event) |
117 | { |
118 | Q_UNUSED(watched); |
119 | if (event->type() == spied) |
120 | ++_count; |
121 | return false; |
122 | } |
123 | |
124 | int _count; |
125 | QEvent::Type spied; |
126 | }; |
127 | |
128 | #if defined QT_BUILD_INTERNAL |
129 | class FriendlyGraphicsScene : public QGraphicsScene |
130 | { |
131 | friend class tst_QGraphicsView; |
132 | Q_DECLARE_PRIVATE(QGraphicsScene); |
133 | }; |
134 | #endif |
135 | |
136 | class tst_QGraphicsView : public QObject |
137 | { |
138 | Q_OBJECT |
139 | |
140 | public: |
141 | tst_QGraphicsView() |
142 | : platformName(QGuiApplication::platformName().toLower()) |
143 | { } |
144 | private slots: |
145 | void cleanup(); |
146 | void construction(); |
147 | void renderHints(); |
148 | void alignment(); |
149 | void interactive(); |
150 | void scene(); |
151 | void setScene(); |
152 | void deleteScene(); |
153 | void sceneRect(); |
154 | void sceneRect_growing(); |
155 | void setSceneRect(); |
156 | void viewport(); |
157 | #ifndef QT_NO_OPENGL |
158 | void openGLViewport(); |
159 | #endif |
160 | void dragMode_scrollHand(); |
161 | void dragMode_rubberBand(); |
162 | void rubberBandSelectionMode(); |
163 | void rubberBandExtendSelection(); |
164 | void rotated_rubberBand(); |
165 | void backgroundBrush(); |
166 | void foregroundBrush(); |
167 | void matrix(); |
168 | void matrix_convenience(); |
169 | void matrix_combine(); |
170 | void centerOnPoint(); |
171 | void centerOnItem(); |
172 | void ensureVisibleRect(); |
173 | void fitInView(); |
174 | void itemsAtPoint(); |
175 | #if defined QT_BUILD_INTERNAL |
176 | void itemsAtPosition_data(); |
177 | void itemsAtPosition(); |
178 | #endif |
179 | void itemsInRect(); |
180 | void itemsInRect_cosmeticAdjust_data(); |
181 | void itemsInRect_cosmeticAdjust(); |
182 | void itemsInPoly(); |
183 | void itemsInPath(); |
184 | void itemAt(); |
185 | void itemAt2(); |
186 | void mapToScene(); |
187 | void mapToScenePoint(); |
188 | void mapToSceneRect_data(); |
189 | void mapToSceneRect(); |
190 | void mapToScenePoly(); |
191 | void mapToScenePath(); |
192 | void mapFromScenePoint(); |
193 | void mapFromSceneRect(); |
194 | void mapFromScenePoly(); |
195 | void mapFromScenePath(); |
196 | void sendEvent(); |
197 | #if QT_CONFIG(wheelevent) |
198 | void wheelEvent(); |
199 | #endif |
200 | #ifndef QT_NO_CURSOR |
201 | void cursor(); |
202 | void cursor2(); |
203 | #endif |
204 | void transformationAnchor(); |
205 | void resizeAnchor(); |
206 | void viewportUpdateMode(); |
207 | void viewportUpdateMode2(); |
208 | #if QT_CONFIG(draganddrop) |
209 | void acceptDrops(); |
210 | #endif |
211 | void optimizationFlags(); |
212 | void optimizationFlags_dontSavePainterState(); |
213 | void optimizationFlags_dontSavePainterState2_data(); |
214 | void optimizationFlags_dontSavePainterState2(); |
215 | void levelOfDetail_data(); |
216 | void levelOfDetail(); |
217 | void scrollBarRanges_data(); |
218 | void scrollBarRanges(); |
219 | void acceptMousePressEvent(); |
220 | void acceptMouseDoubleClickEvent(); |
221 | void forwardMousePress(); |
222 | void forwardMouseDoubleClick(); |
223 | void replayMouseMove(); |
224 | void itemsUnderMouse(); |
225 | void embeddedViews(); |
226 | void embeddedViewsWithFocus(); |
227 | void scrollAfterResize_data(); |
228 | void scrollAfterResize(); |
229 | void moveItemWhileScrolling_data(); |
230 | void moveItemWhileScrolling(); |
231 | void centerOnDirtyItem(); |
232 | void mouseTracking(); |
233 | void mouseTracking2(); |
234 | void mouseTracking3(); |
235 | void render(); |
236 | void exposeRegion(); |
237 | void update_data(); |
238 | void update(); |
239 | void update2_data(); |
240 | void update2(); |
241 | void update_ancestorClipsChildrenToShape(); |
242 | void update_ancestorClipsChildrenToShape2(); |
243 | void inputMethodSensitivity(); |
244 | void inputContextReset(); |
245 | void indirectPainting(); |
246 | void compositionModeInDrawBackground(); |
247 | |
248 | // task specific tests below me |
249 | void task172231_untransformableItems(); |
250 | void task180429_mouseReleaseDragMode(); |
251 | void task187791_setSceneCausesUpdate(); |
252 | void task186827_deleteReplayedItem(); |
253 | void task207546_focusCrash(); |
254 | void task210599_unsetDragWhileDragging(); |
255 | void task239729_noViewUpdate_data(); |
256 | void task239729_noViewUpdate(); |
257 | void task239047_fitInViewSmallViewport(); |
258 | void task245469_itemsAtPointWithClip(); |
259 | void task253415_reconnectUpdateSceneOnSceneChanged(); |
260 | void task255529_transformationAnchorMouseAndViewportMargins(); |
261 | void task259503_scrollingArtifacts(); |
262 | void QTBUG_4151_clipAndIgnore_data(); |
263 | void QTBUG_4151_clipAndIgnore(); |
264 | void QTBUG_5859_exposedRect(); |
265 | void hoverLeave(); |
266 | void QTBUG_16063_microFocusRect(); |
267 | #ifndef QT_NO_CURSOR |
268 | void QTBUG_7438_cursor(); |
269 | #endif |
270 | |
271 | public slots: |
272 | void dummySlot() {} |
273 | |
274 | private: |
275 | QString platformName; |
276 | }; |
277 | |
278 | void tst_QGraphicsView::cleanup() |
279 | { |
280 | // ensure not even skipped tests with custom input context leave it dangling |
281 | QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); |
282 | inputMethodPrivate->testContext = 0; |
283 | } |
284 | |
285 | void tst_QGraphicsView::construction() |
286 | { |
287 | QGraphicsView view; |
288 | QCOMPARE(view.renderHints(), QPainter::TextAntialiasing); |
289 | QCOMPARE(view.dragMode(), QGraphicsView::NoDrag); |
290 | QVERIFY(view.isInteractive()); |
291 | QVERIFY(!view.scene()); |
292 | QCOMPARE(view.sceneRect(), QRectF()); |
293 | QVERIFY(view.viewport()); |
294 | QCOMPARE(view.viewport()->metaObject()->className(), "QWidget" ); |
295 | QCOMPARE(view.transform(), QTransform()); |
296 | QVERIFY(view.items().isEmpty()); |
297 | QVERIFY(view.items(QPoint()).isEmpty()); |
298 | QVERIFY(view.items(QRect()).isEmpty()); |
299 | QVERIFY(view.items(QPolygon()).isEmpty()); |
300 | QVERIFY(view.items(QPainterPath()).isEmpty()); |
301 | QVERIFY(!view.itemAt(QPoint())); |
302 | QCOMPARE(view.mapToScene(QPoint()), QPointF()); |
303 | QCOMPARE(view.mapToScene(QRect()), QPolygonF()); |
304 | QCOMPARE(view.mapToScene(QPolygon()), QPolygonF()); |
305 | QCOMPARE(view.mapFromScene(QPointF()), QPoint()); |
306 | QPolygon poly; |
307 | poly << QPoint() << QPoint() << QPoint() << QPoint(); |
308 | QCOMPARE(view.mapFromScene(QRectF()), poly); |
309 | QCOMPARE(view.mapFromScene(QPolygonF()), QPolygon()); |
310 | QCOMPARE(view.transformationAnchor(), QGraphicsView::AnchorViewCenter); |
311 | QCOMPARE(view.resizeAnchor(), QGraphicsView::NoAnchor); |
312 | view.show(); |
313 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
314 | } |
315 | |
316 | class TestItem : public QGraphicsItem |
317 | { |
318 | public: |
319 | QRectF boundingRect() const |
320 | { return QRectF(-10, -10, 20, 20); } |
321 | |
322 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) |
323 | { hints = painter->renderHints(); painter->drawRect(rect: boundingRect()); } |
324 | |
325 | bool sceneEvent(QEvent *event) |
326 | { |
327 | events << event->type(); |
328 | return QGraphicsItem::sceneEvent(event); |
329 | } |
330 | |
331 | QList<QEvent::Type> events; |
332 | QPainter::RenderHints hints; |
333 | }; |
334 | |
335 | void tst_QGraphicsView::renderHints() |
336 | { |
337 | QGraphicsView view; |
338 | QCOMPARE(view.renderHints(), QPainter::TextAntialiasing); |
339 | view.setRenderHint(hint: QPainter::TextAntialiasing, enabled: false); |
340 | QCOMPARE(view.renderHints(), 0); |
341 | view.setRenderHint(hint: QPainter::Antialiasing, enabled: false); |
342 | QCOMPARE(view.renderHints(), 0); |
343 | view.setRenderHint(hint: QPainter::TextAntialiasing, enabled: true); |
344 | QCOMPARE(view.renderHints(), QPainter::TextAntialiasing); |
345 | view.setRenderHint(hint: QPainter::Antialiasing); |
346 | QCOMPARE(view.renderHints(), QPainter::TextAntialiasing | QPainter::Antialiasing); |
347 | view.setRenderHints({}); |
348 | QCOMPARE(view.renderHints(), 0); |
349 | |
350 | TestItem *item = new TestItem; |
351 | QGraphicsScene scene; |
352 | scene.addItem(item); |
353 | |
354 | view.setScene(&scene); |
355 | |
356 | view.setRenderHints(QPainter::TextAntialiasing | QPainter::Antialiasing); |
357 | QCOMPARE(view.renderHints(), QPainter::TextAntialiasing | QPainter::Antialiasing); |
358 | |
359 | QCOMPARE(item->hints, 0); |
360 | view.show(); |
361 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
362 | view.update(); |
363 | QTRY_COMPARE(item->hints, view.renderHints()); |
364 | |
365 | view.setRenderHints(QPainter::Antialiasing); |
366 | QCOMPARE(view.renderHints(), QPainter::Antialiasing); |
367 | |
368 | view.update(); |
369 | QTRY_COMPARE(item->hints, view.renderHints()); |
370 | } |
371 | |
372 | void tst_QGraphicsView::alignment() |
373 | { |
374 | QGraphicsScene scene; |
375 | scene.addRect(rect: QRectF(-10, -10, 20, 20)); |
376 | |
377 | QGraphicsView view(&scene); |
378 | setFrameless(&view); |
379 | view.show(); |
380 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
381 | |
382 | for (int i = 0; i < 3; ++i) { |
383 | for (int j = 0; j < 3; ++j) { |
384 | Qt::Alignment alignment; |
385 | switch (i) { |
386 | case 0: |
387 | alignment |= Qt::AlignLeft; |
388 | break; |
389 | case 1: |
390 | alignment |= Qt::AlignHCenter; |
391 | break; |
392 | case 2: |
393 | default: |
394 | alignment |= Qt::AlignRight; |
395 | break; |
396 | } |
397 | switch (j) { |
398 | case 0: |
399 | alignment |= Qt::AlignTop; |
400 | break; |
401 | case 1: |
402 | alignment |= Qt::AlignVCenter; |
403 | break; |
404 | case 2: |
405 | default: |
406 | alignment |= Qt::AlignBottom; |
407 | break; |
408 | } |
409 | view.setAlignment(alignment); |
410 | QCOMPARE(view.alignment(), alignment); |
411 | |
412 | for (int k = 0; k < 3; ++k) { |
413 | view.resize(w: 100 + k * 25, h: 100 + k * 25); |
414 | QApplication::processEvents(); |
415 | } |
416 | } |
417 | } |
418 | } |
419 | |
420 | void tst_QGraphicsView::interactive() |
421 | { |
422 | if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::WindowActivation)) |
423 | QSKIP("Window activation is not supported" ); |
424 | |
425 | TestItem *item = new TestItem; |
426 | item->setFlags(QGraphicsItem::ItemIsMovable); |
427 | QCOMPARE(item->events.size(), 0); |
428 | |
429 | QGraphicsScene scene(-200, -200, 400, 400); |
430 | scene.addItem(item); |
431 | |
432 | QGraphicsView view(&scene); |
433 | view.setFixedSize(w: 300, h: 300); |
434 | QCOMPARE(item->events.size(), 0); |
435 | view.show(); |
436 | view.activateWindow(); |
437 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
438 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
439 | |
440 | QTRY_COMPARE(item->events.size(), 1); // activate |
441 | |
442 | QPoint itemPoint = view.mapFromScene(point: item->scenePos()); |
443 | |
444 | QVERIFY(view.itemAt(itemPoint)); |
445 | |
446 | for (int i = 0; i < 100; ++i) { |
447 | sendMousePress(widget: view.viewport(), point: itemPoint); |
448 | QCOMPARE(item->events.size(), i * 5 + 3); |
449 | QCOMPARE(item->events.at(item->events.size() - 2), QEvent::GrabMouse); |
450 | QCOMPARE(item->events.at(item->events.size() - 1), QEvent::GraphicsSceneMousePress); |
451 | sendMouseRelease(widget: view.viewport(), point: itemPoint); |
452 | QCOMPARE(item->events.size(), i * 5 + 5); |
453 | QCOMPARE(item->events.at(item->events.size() - 2), QEvent::GraphicsSceneMouseRelease); |
454 | QCOMPARE(item->events.at(item->events.size() - 1), QEvent::UngrabMouse); |
455 | #ifndef QT_NO_CONTEXTMENU |
456 | QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, itemPoint, view.mapToGlobal(itemPoint)); |
457 | QApplication::sendEvent(receiver: view.viewport(), event: &contextEvent); |
458 | QCOMPARE(item->events.size(), i * 5 + 6); |
459 | QCOMPARE(item->events.last(), QEvent::GraphicsSceneContextMenu); |
460 | #endif // QT_NO_CONTEXTMENU |
461 | } |
462 | |
463 | view.setInteractive(false); |
464 | |
465 | for (int i = 0; i < 100; ++i) { |
466 | sendMousePress(widget: view.viewport(), point: itemPoint); |
467 | QCOMPARE(item->events.size(), 501); |
468 | QCOMPARE(item->events.last(), QEvent::GraphicsSceneContextMenu); |
469 | sendMouseRelease(widget: view.viewport(), point: itemPoint); |
470 | QCOMPARE(item->events.size(), 501); |
471 | QCOMPARE(item->events.last(), QEvent::GraphicsSceneContextMenu); |
472 | #ifndef QT_NO_CONTEXTMENU |
473 | QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, itemPoint, view.mapToGlobal(itemPoint)); |
474 | QApplication::sendEvent(receiver: view.viewport(), event: &contextEvent); |
475 | QCOMPARE(item->events.size(), 501); |
476 | QCOMPARE(item->events.last(), QEvent::GraphicsSceneContextMenu); |
477 | #endif // QT_NO_CONTEXTMENU |
478 | } |
479 | } |
480 | |
481 | void tst_QGraphicsView::scene() |
482 | { |
483 | QGraphicsView view; |
484 | QVERIFY(!view.scene()); |
485 | view.setScene(0); |
486 | QVERIFY(!view.scene()); |
487 | |
488 | { |
489 | QGraphicsScene scene; |
490 | view.setScene(&scene); |
491 | QCOMPARE(view.scene(), &scene); |
492 | } |
493 | |
494 | QCOMPARE(view.scene(), nullptr); |
495 | } |
496 | |
497 | void tst_QGraphicsView::setScene() |
498 | { |
499 | QGraphicsScene scene(-1000, -1000, 2000, 2000); |
500 | |
501 | QGraphicsView view(&scene); |
502 | view.show(); |
503 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
504 | |
505 | QCOMPARE(view.sceneRect(), scene.sceneRect()); |
506 | |
507 | QVERIFY(view.horizontalScrollBar()->isVisible()); |
508 | QVERIFY(view.verticalScrollBar()->isVisible()); |
509 | QVERIFY(!view.horizontalScrollBar()->isHidden()); |
510 | QVERIFY(!view.verticalScrollBar()->isHidden()); |
511 | |
512 | view.setScene(0); |
513 | |
514 | QTRY_VERIFY(!view.horizontalScrollBar()->isVisible()); |
515 | QTRY_VERIFY(!view.verticalScrollBar()->isVisible()); |
516 | QVERIFY(!view.horizontalScrollBar()->isHidden()); |
517 | QVERIFY(!view.verticalScrollBar()->isHidden()); |
518 | |
519 | QCOMPARE(view.sceneRect(), QRectF()); |
520 | } |
521 | |
522 | void tst_QGraphicsView::deleteScene() |
523 | { |
524 | QGraphicsScene *scene = new QGraphicsScene; |
525 | QGraphicsView view1(scene); |
526 | view1.show(); |
527 | QGraphicsView view2(scene); |
528 | view2.show(); |
529 | QGraphicsView view3(scene); |
530 | view3.show(); |
531 | delete scene; |
532 | QCOMPARE(view1.scene(), nullptr); |
533 | QCOMPARE(view2.scene(), nullptr); |
534 | QCOMPARE(view3.scene(), nullptr); |
535 | } |
536 | |
537 | void tst_QGraphicsView::sceneRect() |
538 | { |
539 | QGraphicsView view; |
540 | QCOMPARE(view.sceneRect(), QRectF()); |
541 | |
542 | view.setSceneRect(QRectF(-100, -100, 200, 200)); |
543 | QCOMPARE(view.sceneRect(), QRectF(-100, -100, 200, 200)); |
544 | view.setSceneRect(ax: -100, ay: -100, aw: 200, ah: 200); |
545 | QCOMPARE(view.sceneRect(), QRectF(-100, -100, 200, 200)); |
546 | |
547 | view.setSceneRect(QRectF()); |
548 | QCOMPARE(view.sceneRect(), QRectF()); |
549 | QGraphicsScene scene; |
550 | QGraphicsRectItem *item = scene.addRect(rect: QRectF(-100, -100, 100, 100)); |
551 | item->setPen(QPen(Qt::black, 0)); |
552 | |
553 | view.setScene(&scene); |
554 | |
555 | QCOMPARE(view.sceneRect(), QRectF(-100, -100, 100, 100)); |
556 | item->moveBy(dx: -100, dy: -100); |
557 | QCOMPARE(view.sceneRect(), QRectF(-200, -200, 200, 200)); |
558 | item->moveBy(dx: 100, dy: 100); |
559 | QCOMPARE(view.sceneRect(), QRectF(-200, -200, 200, 200)); |
560 | |
561 | view.setScene(0); |
562 | view.setSceneRect(QRectF()); |
563 | QCOMPARE(view.sceneRect(), QRectF()); |
564 | } |
565 | |
566 | void tst_QGraphicsView::sceneRect_growing() |
567 | { |
568 | QWidget toplevel; |
569 | |
570 | QGraphicsScene scene; |
571 | for (int i = 0; i < 100; ++i) |
572 | scene.addText(text: QLatin1String("(0, " ) + QString::number((i - 50) * 20))->setPos(ax: 0, ay: (i - 50) * 20); |
573 | |
574 | QGraphicsView view(&scene, &toplevel); |
575 | view.setFixedSize(w: 200, h: 200); |
576 | toplevel.show(); |
577 | QVERIFY(QTest::qWaitForWindowActive(&toplevel)); |
578 | |
579 | int size = 200; |
580 | scene.setSceneRect(x: -size, y: -size, w: size * 2, h: size * 2); |
581 | QCOMPARE(view.sceneRect(), scene.sceneRect()); |
582 | |
583 | QPointF topLeft = view.mapToScene(ax: 0, ay: 0); |
584 | |
585 | for (int i = 0; i < 5; ++i) { |
586 | size *= 2; |
587 | scene.setSceneRect(x: -size, y: -size, w: size * 2, h: size * 2); |
588 | |
589 | QApplication::processEvents(); |
590 | |
591 | QCOMPARE(view.sceneRect(), scene.sceneRect()); |
592 | QCOMPARE(view.mapToScene(0, 0), topLeft); |
593 | view.setSceneRect(ax: -size, ay: -size, aw: size * 2, ah: size * 2); |
594 | QCOMPARE(view.mapToScene(0, 0), topLeft); |
595 | view.setSceneRect(QRectF()); |
596 | } |
597 | } |
598 | |
599 | void tst_QGraphicsView::setSceneRect() |
600 | { |
601 | QRectF rect1(-100, -100, 200, 200); |
602 | QRectF rect2(-300, -300, 150, 150); |
603 | |
604 | QGraphicsScene scene; |
605 | QGraphicsView view(&scene); |
606 | |
607 | scene.setSceneRect(rect1); |
608 | QCOMPARE(scene.sceneRect(), rect1); |
609 | QCOMPARE(view.sceneRect(), rect1); |
610 | |
611 | scene.setSceneRect(rect2); |
612 | QCOMPARE(scene.sceneRect(), rect2); |
613 | QCOMPARE(view.sceneRect(), rect2); |
614 | |
615 | view.setSceneRect(rect1); |
616 | QCOMPARE(scene.sceneRect(), rect2); |
617 | QCOMPARE(view.sceneRect(), rect1); |
618 | |
619 | view.setSceneRect(rect2); |
620 | QCOMPARE(scene.sceneRect(), rect2); |
621 | QCOMPARE(view.sceneRect(), rect2); |
622 | |
623 | scene.setSceneRect(rect1); |
624 | QCOMPARE(scene.sceneRect(), rect1); |
625 | QCOMPARE(view.sceneRect(), rect2); |
626 | |
627 | // extreme transformations will max out the scrollbars' ranges. |
628 | view.setSceneRect(ax: -2000000, ay: -2000000, aw: 4000000, ah: 4000000); |
629 | view.scale(sx: 9000, sy: 9000); |
630 | QCOMPARE(view.horizontalScrollBar()->minimum(), INT_MIN); |
631 | QCOMPARE(view.horizontalScrollBar()->maximum(), INT_MAX); |
632 | QCOMPARE(view.verticalScrollBar()->minimum(), INT_MIN); |
633 | QCOMPARE(view.verticalScrollBar()->maximum(), INT_MAX); |
634 | } |
635 | |
636 | void tst_QGraphicsView::viewport() |
637 | { |
638 | QGraphicsScene scene; |
639 | scene.addText(text: "GraphicsView" ); |
640 | |
641 | QGraphicsView view(&scene); |
642 | QVERIFY(view.viewport() != 0); |
643 | |
644 | view.show(); |
645 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
646 | |
647 | QPointer<QWidget> widget = new QWidget; |
648 | view.setViewport(widget); |
649 | QCOMPARE(view.viewport(), (QWidget *)widget); |
650 | |
651 | view.show(); |
652 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
653 | |
654 | view.setViewport(0); |
655 | QVERIFY(widget.isNull()); |
656 | QVERIFY(view.viewport() != 0); |
657 | QVERIFY(view.viewport() != widget); |
658 | |
659 | view.show(); |
660 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
661 | } |
662 | |
663 | #ifndef QT_NO_OPENGL |
664 | void tst_QGraphicsView::openGLViewport() |
665 | { |
666 | if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::OpenGL)) |
667 | QSKIP("QOpenGL is not supported on this platform." ); |
668 | |
669 | QGraphicsScene scene; |
670 | scene.setBackgroundBrush(Qt::white); |
671 | scene.addText(text: "GraphicsView" ); |
672 | scene.addEllipse(rect: QRectF(400, 50, 50, 50)); |
673 | scene.addEllipse(rect: QRectF(-100, -400, 50, 50)); |
674 | scene.addEllipse(rect: QRectF(50, -100, 50, 50)); |
675 | scene.addEllipse(rect: QRectF(-100, 50, 50, 50)); |
676 | |
677 | QGraphicsView view(&scene); |
678 | view.setSceneRect(ax: -400, ay: -400, aw: 800, ah: 800); |
679 | view.resize(w: 400, h: 400); |
680 | |
681 | QOpenGLWidget *glw = new QOpenGLWidget; |
682 | QSignalSpy spy1(glw, SIGNAL(resized())); |
683 | QSignalSpy spy2(glw, SIGNAL(frameSwapped())); |
684 | |
685 | view.setViewport(glw); |
686 | |
687 | view.show(); |
688 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
689 | QTRY_VERIFY(spy1.count() > 0); |
690 | QTRY_VERIFY(spy2.count() >= spy1.count()); |
691 | spy1.clear(); |
692 | spy2.clear(); |
693 | |
694 | // Now test for resize (QTBUG-52419). This is special when the viewport is |
695 | // a QOpenGLWidget since the underlying FBO must also be maintained. |
696 | view.resize(w: 300, h: 300); |
697 | QTRY_VERIFY(spy1.count() > 0); |
698 | QTRY_VERIFY(spy2.count() >= spy1.count()); |
699 | // There is no sane way to check if the framebuffer contents got updated |
700 | // (grabFramebuffer is no good for the viewport case as that does not go |
701 | // through paintGL). So skip the actual verification. |
702 | } |
703 | #endif |
704 | |
705 | void tst_QGraphicsView::dragMode_scrollHand() |
706 | { |
707 | for (int j = 0; j < 2; ++j) { |
708 | QGraphicsView view; |
709 | setFrameless(&view); |
710 | QCOMPARE(view.dragMode(), QGraphicsView::NoDrag); |
711 | |
712 | view.setSceneRect(ax: -1000, ay: -1000, aw: 2000, ah: 2000); |
713 | view.setFixedSize(w: 100, h: 100); |
714 | view.show(); |
715 | |
716 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
717 | QApplication::processEvents(); |
718 | |
719 | view.setInteractive(j ? false : true); |
720 | |
721 | QGraphicsScene scene; |
722 | scene.addRect(rect: QRectF(-100, -100, 5, 5)); |
723 | scene.addRect(rect: QRectF(95, -100, 5, 5)); |
724 | scene.addRect(rect: QRectF(95, 95, 5, 5)); |
725 | QGraphicsItem *item = scene.addRect(rect: QRectF(-100, 95, 5, 5)); |
726 | item->setFlag(flag: QGraphicsItem::ItemIsSelectable); |
727 | item->setSelected(true); |
728 | QVERIFY(item->isSelected()); |
729 | QVERIFY(!view.scene()); |
730 | |
731 | view.setDragMode(QGraphicsView::ScrollHandDrag); |
732 | |
733 | for (int i = 0; i < 2; ++i) { |
734 | // ScrollHandDrag |
735 | #ifndef QT_NO_CURSOR |
736 | Qt::CursorShape cursorShape = view.viewport()->cursor().shape(); |
737 | #endif |
738 | int horizontalScrollBarValue = view.horizontalScrollBar()->value(); |
739 | int verticalScrollBarValue = view.verticalScrollBar()->value(); |
740 | { |
741 | // Press |
742 | QMouseEvent event(QEvent::MouseButtonPress, |
743 | view.viewport()->rect().center(), |
744 | Qt::LeftButton, Qt::LeftButton, {}); |
745 | event.setAccepted(true); |
746 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
747 | QVERIFY(event.isAccepted()); |
748 | } |
749 | QApplication::processEvents(); |
750 | |
751 | QTRY_VERIFY(item->isSelected()); |
752 | |
753 | for (int k = 0; k < 4; ++k) { |
754 | #ifndef QT_NO_CURSOR |
755 | QCOMPARE(view.viewport()->cursor().shape(), Qt::ClosedHandCursor); |
756 | #endif |
757 | { |
758 | // Move |
759 | QMouseEvent event(QEvent::MouseMove, |
760 | view.viewport()->rect().center() + QPoint(10, 0), |
761 | Qt::LeftButton, Qt::LeftButton, {}); |
762 | event.setAccepted(true); |
763 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
764 | QVERIFY(event.isAccepted()); |
765 | } |
766 | QVERIFY(item->isSelected()); |
767 | QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue - 10); |
768 | QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue); |
769 | { |
770 | // Move |
771 | QMouseEvent event(QEvent::MouseMove, |
772 | view.viewport()->rect().center() + QPoint(10, 10), |
773 | Qt::LeftButton, Qt::LeftButton, {}); |
774 | event.setAccepted(true); |
775 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
776 | QVERIFY(event.isAccepted()); |
777 | } |
778 | QVERIFY(item->isSelected()); |
779 | QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue - 10); |
780 | QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue - 10); |
781 | } |
782 | |
783 | { |
784 | // Release |
785 | QMouseEvent event(QEvent::MouseButtonRelease, |
786 | view.viewport()->rect().center() + QPoint(10, 10), |
787 | Qt::LeftButton, Qt::LeftButton, {}); |
788 | event.setAccepted(true); |
789 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
790 | QVERIFY(event.isAccepted()); |
791 | } |
792 | QApplication::processEvents(); |
793 | |
794 | QTRY_VERIFY(item->isSelected()); |
795 | QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue - 10); |
796 | QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue - 10); |
797 | #ifndef QT_NO_CURSOR |
798 | QCOMPARE(view.viewport()->cursor().shape(), cursorShape); |
799 | #endif |
800 | |
801 | // Check that items are not unselected because of a scroll hand drag. |
802 | QVERIFY(item->isSelected()); |
803 | |
804 | // Check that a click will still unselect the item. |
805 | { |
806 | // Press |
807 | QMouseEvent event(QEvent::MouseButtonPress, |
808 | view.viewport()->rect().center() + QPoint(10, 10), |
809 | Qt::LeftButton, Qt::LeftButton, {}); |
810 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
811 | } |
812 | { |
813 | // Release |
814 | QMouseEvent event(QEvent::MouseButtonRelease, |
815 | view.viewport()->rect().center() + QPoint(10, 10), |
816 | Qt::LeftButton, Qt::LeftButton, {}); |
817 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
818 | } |
819 | |
820 | if (view.isInteractive()) { |
821 | if (view.scene()) { |
822 | QVERIFY(!item->isSelected()); |
823 | item->setSelected(true); |
824 | } else { |
825 | QVERIFY(item->isSelected()); |
826 | } |
827 | } else { |
828 | QVERIFY(item->isSelected()); |
829 | } |
830 | |
831 | view.setScene(&scene); |
832 | } |
833 | } |
834 | } |
835 | |
836 | void tst_QGraphicsView::dragMode_rubberBand() |
837 | { |
838 | QGraphicsView view; |
839 | QCOMPARE(view.dragMode(), QGraphicsView::NoDrag); |
840 | |
841 | view.setSceneRect(ax: -1000, ay: -1000, aw: 2000, ah: 2000); |
842 | view.show(); |
843 | |
844 | QGraphicsScene scene; |
845 | scene.addRect(rect: QRectF(-100, -100, 25, 25))->setFlag(flag: QGraphicsItem::ItemIsSelectable); |
846 | scene.addRect(rect: QRectF(75, -100, 25, 25))->setFlag(flag: QGraphicsItem::ItemIsSelectable); |
847 | scene.addRect(rect: QRectF(75, 75, 25, 25))->setFlag(flag: QGraphicsItem::ItemIsSelectable); |
848 | scene.addRect(rect: QRectF(-100, 75, 25, 25))->setFlag(flag: QGraphicsItem::ItemIsSelectable); |
849 | |
850 | view.setDragMode(QGraphicsView::RubberBandDrag); |
851 | |
852 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
853 | QApplication::processEvents(); |
854 | |
855 | for (int i = 0; i < 2; ++i) { |
856 | // RubberBandDrag |
857 | #ifndef QT_NO_CURSOR |
858 | Qt::CursorShape cursorShape = view.viewport()->cursor().shape(); |
859 | #endif |
860 | int horizontalScrollBarValue = view.horizontalScrollBar()->value(); |
861 | int verticalScrollBarValue = view.verticalScrollBar()->value(); |
862 | { |
863 | // Press |
864 | QMouseEvent event(QEvent::MouseButtonPress, |
865 | view.viewport()->rect().center(), |
866 | Qt::LeftButton, Qt::LeftButton, {}); |
867 | event.setAccepted(true); |
868 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
869 | QVERIFY(event.isAccepted()); |
870 | } |
871 | #ifndef QT_NO_CURSOR |
872 | QCOMPARE(view.viewport()->cursor().shape(), cursorShape); |
873 | #endif |
874 | |
875 | QApplication::processEvents(); |
876 | |
877 | { |
878 | // Move |
879 | QMouseEvent event(QEvent::MouseMove, |
880 | view.viewport()->rect().center() + QPoint(100, 0), |
881 | Qt::LeftButton, Qt::LeftButton, {}); |
882 | event.setAccepted(true); |
883 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
884 | QVERIFY(event.isAccepted()); |
885 | } |
886 | QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue); |
887 | QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue); |
888 | |
889 | // We don't use QRubberBand as of 4.3; the band is drawn internally. |
890 | QVERIFY(!view.findChild<QRubberBand *>()); |
891 | |
892 | { |
893 | // Move |
894 | QMouseEvent event(QEvent::MouseMove, |
895 | view.viewport()->rect().center() + QPoint(100, 100), |
896 | Qt::LeftButton, Qt::LeftButton, {}); |
897 | event.setAccepted(true); |
898 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
899 | QVERIFY(event.isAccepted()); |
900 | } |
901 | QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue); |
902 | QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue); |
903 | |
904 | { |
905 | // Release |
906 | QMouseEvent event(QEvent::MouseButtonRelease, |
907 | view.viewport()->rect().center() + QPoint(100, 100), |
908 | Qt::LeftButton, Qt::LeftButton, {}); |
909 | event.setAccepted(true); |
910 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
911 | QVERIFY(event.isAccepted()); |
912 | } |
913 | QCOMPARE(view.horizontalScrollBar()->value(), horizontalScrollBarValue); |
914 | QCOMPARE(view.verticalScrollBar()->value(), verticalScrollBarValue); |
915 | #ifndef QT_NO_CURSOR |
916 | QCOMPARE(view.viewport()->cursor().shape(), cursorShape); |
917 | #endif |
918 | |
919 | if (view.scene()) |
920 | QCOMPARE(scene.selectedItems().size(), 1); |
921 | |
922 | view.setScene(&scene); |
923 | view.centerOn(ax: 0, ay: 0); |
924 | } |
925 | } |
926 | |
927 | void tst_QGraphicsView::rubberBandSelectionMode() |
928 | { |
929 | QWidget toplevel; |
930 | setFrameless(&toplevel); |
931 | |
932 | QGraphicsScene scene; |
933 | QGraphicsRectItem *rect = scene.addRect(rect: QRectF(10, 10, 80, 80)); |
934 | rect->setFlag(flag: QGraphicsItem::ItemIsSelectable); |
935 | |
936 | QGraphicsView view(&scene, &toplevel); |
937 | QCOMPARE(view.rubberBandSelectionMode(), Qt::IntersectsItemShape); |
938 | view.setDragMode(QGraphicsView::RubberBandDrag); |
939 | view.resize(w: 120, h: 120); |
940 | toplevel.show(); |
941 | |
942 | // Disable mouse tracking to prevent the window system from sending mouse |
943 | // move events to the viewport while we are synthesizing events. If |
944 | // QGraphicsView gets a mouse move event with no buttons down, it'll |
945 | // terminate the rubber band. |
946 | view.viewport()->setMouseTracking(false); |
947 | |
948 | QVERIFY(scene.selectedItems().isEmpty()); |
949 | sendMousePress(widget: view.viewport(), point: QPoint(), button: Qt::LeftButton); |
950 | sendMouseMove(widget: view.viewport(), point: view.viewport()->rect().center(), |
951 | button: Qt::LeftButton, buttons: Qt::LeftButton); |
952 | QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << rect); |
953 | sendMouseRelease(widget: view.viewport(), point: QPoint(), button: Qt::LeftButton); |
954 | |
955 | view.setRubberBandSelectionMode(Qt::ContainsItemShape); |
956 | QCOMPARE(view.rubberBandSelectionMode(), Qt::ContainsItemShape); |
957 | sendMousePress(widget: view.viewport(), point: QPoint(), button: Qt::LeftButton); |
958 | QVERIFY(scene.selectedItems().isEmpty()); |
959 | sendMouseMove(widget: view.viewport(), point: view.viewport()->rect().center(), |
960 | button: Qt::LeftButton, buttons: Qt::LeftButton); |
961 | QVERIFY(scene.selectedItems().isEmpty()); |
962 | sendMouseMove(widget: view.viewport(), point: view.viewport()->rect().bottomRight(), |
963 | button: Qt::LeftButton, buttons: Qt::LeftButton); |
964 | QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << rect); |
965 | } |
966 | |
967 | void tst_QGraphicsView::rubberBandExtendSelection() |
968 | { |
969 | QWidget toplevel; |
970 | setFrameless(&toplevel); |
971 | |
972 | QGraphicsScene scene(0, 0, 1000, 1000); |
973 | |
974 | QGraphicsView view(&scene, &toplevel); |
975 | view.setDragMode(QGraphicsView::RubberBandDrag); |
976 | toplevel.show(); |
977 | |
978 | // Disable mouse tracking to prevent the window system from sending mouse |
979 | // move events to the viewport while we are synthesizing events. If |
980 | // QGraphicsView gets a mouse move event with no buttons down, it'll |
981 | // terminate the rubber band. |
982 | view.viewport()->setMouseTracking(false); |
983 | |
984 | QGraphicsItem *item1 = scene.addRect(x: 10, y: 10, w: 100, h: 100); |
985 | QGraphicsItem *item2 = scene.addRect(x: 10, y: 120, w: 100, h: 100); |
986 | QGraphicsItem *item3 = scene.addRect(x: 10, y: 230, w: 100, h: 100); |
987 | |
988 | item1->setFlag(flag: QGraphicsItem::ItemIsSelectable); |
989 | item2->setFlag(flag: QGraphicsItem::ItemIsSelectable); |
990 | item3->setFlag(flag: QGraphicsItem::ItemIsSelectable); |
991 | |
992 | // select first item |
993 | item1->setSelected(true); |
994 | QCOMPARE(scene.selectedItems(), QList<QGraphicsItem *>() << item1); |
995 | |
996 | // first rubberband without modifier key |
997 | sendMousePress(widget: view.viewport(), point: view.mapFromScene(ax: 20, ay: 115), button: Qt::LeftButton); |
998 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: 20, ay: 300), button: Qt::LeftButton, buttons: Qt::LeftButton); |
999 | QVERIFY(!item1->isSelected()); |
1000 | QVERIFY(item2->isSelected()); |
1001 | QVERIFY(item3->isSelected()); |
1002 | sendMouseRelease(widget: view.viewport(), point: QPoint(), button: Qt::LeftButton); |
1003 | |
1004 | scene.clearSelection(); |
1005 | |
1006 | // select first item |
1007 | item1->setSelected(true); |
1008 | QVERIFY(item1->isSelected()); |
1009 | |
1010 | // now rubberband with modifier key |
1011 | { |
1012 | QPoint clickPoint = view.mapFromScene(ax: 20, ay: 115); |
1013 | QMouseEvent event(QEvent::MouseButtonPress, clickPoint, view.viewport()->mapToGlobal(clickPoint), |
1014 | Qt::LeftButton, {}, Qt::ControlModifier); |
1015 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
1016 | } |
1017 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: 20, ay: 300), button: Qt::LeftButton, buttons: Qt::LeftButton); |
1018 | QVERIFY(item1->isSelected()); |
1019 | QVERIFY(item2->isSelected()); |
1020 | QVERIFY(item3->isSelected()); |
1021 | } |
1022 | |
1023 | void tst_QGraphicsView::rotated_rubberBand() |
1024 | { |
1025 | QWidget toplevel; |
1026 | setFrameless(&toplevel); |
1027 | |
1028 | QGraphicsScene scene; |
1029 | const int dim = 3; |
1030 | for (int i = 0; i < dim; i++) { |
1031 | for (int j = 0; j < dim; j ++) { |
1032 | QGraphicsRectItem *rect = new QGraphicsRectItem(i * 20, j * 20, 10, 10); |
1033 | rect->setFlag(flag: QGraphicsItem::ItemIsSelectable); |
1034 | rect->setData(key: 0, value: (i == j)); |
1035 | scene.addItem(item: rect); |
1036 | } |
1037 | } |
1038 | |
1039 | QGraphicsView view(&scene, &toplevel); |
1040 | QCOMPARE(view.rubberBandSelectionMode(), Qt::IntersectsItemShape); |
1041 | view.setDragMode(QGraphicsView::RubberBandDrag); |
1042 | view.resize(w: 120, h: 120); |
1043 | view.rotate(angle: 45); |
1044 | toplevel.show(); |
1045 | QVERIFY(QTest::qWaitForWindowExposed(&toplevel)); |
1046 | |
1047 | // Disable mouse tracking to prevent the window system from sending mouse |
1048 | // move events to the viewport while we are synthesizing events. If |
1049 | // QGraphicsView gets a mouse move event with no buttons down, it'll |
1050 | // terminate the rubber band. |
1051 | view.viewport()->setMouseTracking(false); |
1052 | |
1053 | QVERIFY(scene.selectedItems().isEmpty()); |
1054 | int midWidth = view.viewport()->width() / 2; |
1055 | sendMousePress(widget: view.viewport(), point: QPoint(midWidth - 2, 0), button: Qt::LeftButton); |
1056 | sendMouseMove(widget: view.viewport(), point: QPoint(midWidth + 2, view.viewport()->height()), |
1057 | button: Qt::LeftButton, buttons: Qt::LeftButton); |
1058 | QCOMPARE(scene.selectedItems().count(), dim); |
1059 | foreach (const QGraphicsItem *item, scene.items()) { |
1060 | QCOMPARE(item->isSelected(), item->data(0).toBool()); |
1061 | } |
1062 | sendMouseRelease(widget: view.viewport(), point: QPoint(), button: Qt::LeftButton); |
1063 | } |
1064 | |
1065 | void tst_QGraphicsView::backgroundBrush() |
1066 | { |
1067 | QGraphicsScene scene; |
1068 | QGraphicsView view(&scene); |
1069 | scene.setBackgroundBrush(Qt::blue); |
1070 | QCOMPARE(scene.backgroundBrush(), QBrush(Qt::blue)); |
1071 | |
1072 | view.show(); |
1073 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
1074 | |
1075 | scene.setBackgroundBrush(QBrush()); |
1076 | QCOMPARE(scene.backgroundBrush(), QBrush()); |
1077 | QTest::qWait(ms: 25); |
1078 | |
1079 | QRadialGradient gradient(0, 0, 10); |
1080 | gradient.setSpread(QGradient::RepeatSpread); |
1081 | scene.setBackgroundBrush(gradient); |
1082 | |
1083 | QCOMPARE(scene.backgroundBrush(), QBrush(gradient)); |
1084 | QTest::qWait(ms: 25); |
1085 | } |
1086 | |
1087 | void tst_QGraphicsView::foregroundBrush() |
1088 | { |
1089 | QGraphicsScene scene; |
1090 | QGraphicsView view(&scene); |
1091 | scene.setForegroundBrush(Qt::blue); |
1092 | QCOMPARE(scene.foregroundBrush(), QBrush(Qt::blue)); |
1093 | |
1094 | view.show(); |
1095 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
1096 | |
1097 | scene.setForegroundBrush(QBrush()); |
1098 | QCOMPARE(scene.foregroundBrush(), QBrush()); |
1099 | QTest::qWait(ms: 25); |
1100 | |
1101 | QRadialGradient gradient(0, 0, 10); |
1102 | gradient.setSpread(QGradient::RepeatSpread); |
1103 | scene.setForegroundBrush(gradient); |
1104 | |
1105 | QCOMPARE(scene.foregroundBrush(), QBrush(gradient)); |
1106 | QTest::qWait(ms: 25); |
1107 | |
1108 | for (int i = 0; i < 50; ++i) { |
1109 | QRadialGradient gradient(view.rect().center() + QPoint(int(sin(x: i / 2.0) * 10), int(cos(x: i / 2.0) * 10)), 10); |
1110 | gradient.setColorAt(pos: 0, color: Qt::transparent); |
1111 | gradient.setColorAt(pos: 0.5, color: Qt::black); |
1112 | gradient.setColorAt(pos: 1, color: Qt::transparent); |
1113 | gradient.setSpread(QGradient::RepeatSpread); |
1114 | scene.setForegroundBrush(gradient); |
1115 | |
1116 | QRadialGradient gradient2(view.rect().center() + QPoint(int(sin(x: i / 1.7) * 10), int(cos(x: i / 1.7) * 10)), 10); |
1117 | gradient2.setColorAt(pos: 0, color: Qt::transparent); |
1118 | gradient2.setColorAt(pos: 0.5, color: Qt::black); |
1119 | gradient2.setColorAt(pos: 1, color: Qt::transparent); |
1120 | gradient2.setSpread(QGradient::RepeatSpread); |
1121 | scene.setBackgroundBrush(gradient2); |
1122 | |
1123 | QRadialGradient gradient3(view.rect().center() + QPoint(int(sin(x: i / 1.85) * 10), int(cos(x: i / 1.85) * 10)), 10); |
1124 | gradient3.setColorAt(pos: 0, color: Qt::transparent); |
1125 | gradient3.setColorAt(pos: 0.5, color: Qt::black); |
1126 | gradient3.setColorAt(pos: 1, color: Qt::transparent); |
1127 | gradient3.setSpread(QGradient::RepeatSpread); |
1128 | scene.setBackgroundBrush(gradient3); |
1129 | |
1130 | QApplication::processEvents(); |
1131 | } |
1132 | |
1133 | view.setSceneRect(ax: -1000, ay: -1000, aw: 2000, ah: 2000); |
1134 | for (int i = -500; i < 500; i += 10) { |
1135 | view.centerOn(ax: i, ay: 0); |
1136 | QApplication::processEvents(); |
1137 | QApplication::processEvents(); |
1138 | } |
1139 | for (int i = -500; i < 500; i += 10) { |
1140 | view.centerOn(ax: 0, ay: i); |
1141 | QApplication::processEvents(); |
1142 | QApplication::processEvents(); |
1143 | } |
1144 | } |
1145 | |
1146 | void tst_QGraphicsView::matrix() |
1147 | { |
1148 | { |
1149 | QGraphicsScene scene; |
1150 | QGraphicsView view(&scene); |
1151 | view.show(); |
1152 | |
1153 | // Show rendering of background with no scene |
1154 | for (int i = 0; i < 50; ++i) { |
1155 | view.rotate(angle: 5); |
1156 | QRadialGradient gradient(view.rect().center() + QPoint(int(sin(x: i / 2.0) * 10), int(cos(x: i / 2.0) * 10)), 10); |
1157 | gradient.setColorAt(pos: 0, color: Qt::transparent); |
1158 | gradient.setColorAt(pos: 0.5, color: Qt::black); |
1159 | gradient.setColorAt(pos: 1, color: Qt::transparent); |
1160 | gradient.setSpread(QGradient::RepeatSpread); |
1161 | scene.setForegroundBrush(gradient); |
1162 | QRadialGradient gradient2(view.rect().center() + QPoint(int(sin(x: i / 1.7) * 10), int(cos(x: i / 1.7) * 10)), 10); |
1163 | gradient2.setColorAt(pos: 0, color: Qt::transparent); |
1164 | gradient2.setColorAt(pos: 0.5, color: Qt::black); |
1165 | gradient2.setColorAt(pos: 1, color: Qt::transparent); |
1166 | gradient2.setSpread(QGradient::RepeatSpread); |
1167 | scene.setBackgroundBrush(gradient2); |
1168 | QApplication::processEvents(); |
1169 | QApplication::processEvents(); |
1170 | } |
1171 | } |
1172 | |
1173 | // Test transformation extremes, see if they cause crashes |
1174 | { |
1175 | QGraphicsScene scene; |
1176 | scene.addText(text: "GraphicsView rotated clockwise" ); |
1177 | |
1178 | QGraphicsView view(&scene); |
1179 | view.show(); |
1180 | for (int i = 0; i < 160; ++i) { |
1181 | view.rotate(angle: 18); |
1182 | QApplication::processEvents(); |
1183 | QApplication::processEvents(); |
1184 | } |
1185 | /* |
1186 | // These cause a crash |
1187 | for (int i = 0; i < 40; ++i) { |
1188 | view.shear(1.2, 1.2); |
1189 | QTest::qWait(20); |
1190 | } |
1191 | for (int i = 0; i < 40; ++i) { |
1192 | view.shear(-1.2, -1.2); |
1193 | QTest::qWait(20); |
1194 | } |
1195 | */ |
1196 | for (int i = 0; i < 20; ++i) { |
1197 | view.scale(sx: 1.2, sy: 1.2); |
1198 | QApplication::processEvents(); |
1199 | QApplication::processEvents(); |
1200 | } |
1201 | for (int i = 0; i < 20; ++i) { |
1202 | view.scale(sx: 0.6, sy: 0.6); |
1203 | QApplication::processEvents(); |
1204 | QApplication::processEvents(); |
1205 | } |
1206 | } |
1207 | } |
1208 | |
1209 | void tst_QGraphicsView::matrix_convenience() |
1210 | { |
1211 | QGraphicsView view; |
1212 | QCOMPARE(view.transform(), QTransform()); |
1213 | |
1214 | // Check the convenience functions |
1215 | view.rotate(angle: 90); |
1216 | QCOMPARE(view.transform(), QTransform().rotate(90)); |
1217 | view.scale(sx: 2, sy: 2); |
1218 | QCOMPARE(view.transform(), QTransform().scale(2, 2) * QTransform().rotate(90)); |
1219 | view.shear(sh: 1.2, sv: 1.2); |
1220 | QCOMPARE(view.transform(), QTransform().shear(1.2, 1.2) * QTransform().scale(2, 2) * QTransform().rotate(90)); |
1221 | view.translate(dx: 1, dy: 1); |
1222 | QCOMPARE(view.transform(), QTransform().translate(1, 1) * QTransform().shear(1.2, 1.2) * QTransform().scale(2, 2) * QTransform().rotate(90)); |
1223 | } |
1224 | |
1225 | void tst_QGraphicsView::matrix_combine() |
1226 | { |
1227 | // Check matrix combining |
1228 | QGraphicsView view; |
1229 | QCOMPARE(view.transform(), QTransform()); |
1230 | view.setTransform(matrix: QTransform().rotate(a: 90), combine: true); |
1231 | view.setTransform(matrix: QTransform().rotate(a: 90), combine: true); |
1232 | view.setTransform(matrix: QTransform().rotate(a: 90), combine: true); |
1233 | view.setTransform(matrix: QTransform().rotate(a: 90), combine: true); |
1234 | QCOMPARE(view.transform(), QTransform()); |
1235 | |
1236 | view.resetTransform(); |
1237 | QCOMPARE(view.transform(), QTransform()); |
1238 | view.setTransform(matrix: QTransform().rotate(a: 90), combine: false); |
1239 | view.setTransform(matrix: QTransform().rotate(a: 90), combine: false); |
1240 | view.setTransform(matrix: QTransform().rotate(a: 90), combine: false); |
1241 | view.setTransform(matrix: QTransform().rotate(a: 90), combine: false); |
1242 | QCOMPARE(view.transform(), QTransform().rotate(90)); |
1243 | } |
1244 | |
1245 | void tst_QGraphicsView::centerOnPoint() |
1246 | { |
1247 | QWidget toplevel; |
1248 | setFrameless(&toplevel); |
1249 | |
1250 | QGraphicsScene scene; |
1251 | scene.addEllipse(rect: QRectF(-100, -100, 50, 50)); |
1252 | scene.addEllipse(rect: QRectF(50, -100, 50, 50)); |
1253 | scene.addEllipse(rect: QRectF(-100, 50, 50, 50)); |
1254 | scene.addEllipse(rect: QRectF(50, 50, 50, 50)); |
1255 | |
1256 | QGraphicsView view(&scene, &toplevel); |
1257 | view.setSceneRect(ax: -400, ay: -400, aw: 800, ah: 800); |
1258 | view.setFixedSize(w: 100, h: 100); |
1259 | toplevel.show(); |
1260 | |
1261 | int tolerance = 5; |
1262 | |
1263 | for (int i = 0; i < 3; ++i) { |
1264 | for (int y = -100; y < 100; y += 23) { |
1265 | for (int x = -100; x < 100; x += 23) { |
1266 | view.centerOn(ax: x, ay: y); |
1267 | QPoint viewCenter = view.mapToScene(point: view.viewport()->rect().center()).toPoint(); |
1268 | |
1269 | // Fuzzy compare |
1270 | if (viewCenter.x() < x - tolerance || viewCenter.x() > x + tolerance |
1271 | || viewCenter.y() < y - tolerance || viewCenter.y() > y + tolerance) { |
1272 | QString error = QString("Compared values are not the same\n\tActual: (%1, %2)\n\tExpected: (%3, %4)" ) |
1273 | .arg(a: viewCenter.x()).arg(a: viewCenter.y()).arg(a: x).arg(a: y); |
1274 | QFAIL(qPrintable(error)); |
1275 | } |
1276 | |
1277 | QApplication::processEvents(); |
1278 | } |
1279 | } |
1280 | |
1281 | view.rotate(angle: 13); |
1282 | view.scale(sx: 1.5, sy: 1.5); |
1283 | view.shear(sh: 1.25, sv: 1.25); |
1284 | } |
1285 | } |
1286 | |
1287 | void tst_QGraphicsView::centerOnItem() |
1288 | { |
1289 | QGraphicsScene scene; |
1290 | QGraphicsItem *items[4]; |
1291 | items[0] = scene.addEllipse(rect: QRectF(-25, -25, 50, 50)); |
1292 | items[1] = scene.addEllipse(rect: QRectF(-25, -25, 50, 50)); |
1293 | items[2] = scene.addEllipse(rect: QRectF(-25, -25, 50, 50)); |
1294 | items[3] = scene.addEllipse(rect: QRectF(-25, -25, 50, 50)); |
1295 | items[0]->setPos(ax: -100, ay: -100); |
1296 | items[1]->setPos(ax: 100, ay: -100); |
1297 | items[2]->setPos(ax: -100, ay: 100); |
1298 | items[3]->setPos(ax: 100, ay: 100); |
1299 | |
1300 | QGraphicsView view(&scene); |
1301 | view.setSceneRect(ax: -1000, ay: -1000, aw: 2000, ah: 2000); |
1302 | view.show(); |
1303 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
1304 | int tolerance = 7; |
1305 | |
1306 | for (int x = 0; x < 3; ++x) { |
1307 | for (int i = 0; i < 4; ++i) { |
1308 | QApplication::processEvents(); |
1309 | view.centerOn(item: items[i]); |
1310 | |
1311 | QPoint viewCenter = view.mapToScene(point: view.viewport()->rect().center()).toPoint(); |
1312 | qreal x = items[i]->pos().x(); |
1313 | qreal y = items[i]->pos().y(); |
1314 | |
1315 | // Fuzzy compare |
1316 | if (viewCenter.x() < x - tolerance || viewCenter.x() > x + tolerance |
1317 | || viewCenter.y() < y - tolerance || viewCenter.y() > y + tolerance) { |
1318 | QString error = QString("Compared values are not the same\n\tActual: (%1, %2)\n\tExpected: (%3, %4)" ) |
1319 | .arg(a: viewCenter.x()).arg(a: viewCenter.y()).arg(a: x).arg(a: y); |
1320 | QFAIL(qPrintable(error)); |
1321 | } |
1322 | |
1323 | QApplication::processEvents(); |
1324 | } |
1325 | |
1326 | view.rotate(angle: 13); |
1327 | view.scale(sx: 1.5, sy: 1.5); |
1328 | view.shear(sh: 1.25, sv: 1.25); |
1329 | } |
1330 | } |
1331 | |
1332 | void tst_QGraphicsView::ensureVisibleRect() |
1333 | { |
1334 | QWidget toplevel; |
1335 | |
1336 | QGraphicsScene scene; |
1337 | QGraphicsItem *items[4]; |
1338 | items[0] = scene.addEllipse(rect: QRectF(-25, -25, 50, 50), pen: QPen(Qt::black), brush: QBrush(Qt::green)); |
1339 | items[1] = scene.addEllipse(rect: QRectF(-25, -25, 50, 50), pen: QPen(Qt::black), brush: QBrush(Qt::red)); |
1340 | items[2] = scene.addEllipse(rect: QRectF(-25, -25, 50, 50), pen: QPen(Qt::black), brush: QBrush(Qt::blue)); |
1341 | items[3] = scene.addEllipse(rect: QRectF(-25, -25, 50, 50), pen: QPen(Qt::black), brush: QBrush(Qt::yellow)); |
1342 | scene.addLine(line: QLineF(0, -100, 0, 100), pen: QPen(Qt::blue, 2)); |
1343 | scene.addLine(line: QLineF(-100, 0, 100, 0), pen: QPen(Qt::blue, 2)); |
1344 | items[0]->setPos(ax: -100, ay: -100); |
1345 | items[1]->setPos(ax: 100, ay: -100); |
1346 | items[2]->setPos(ax: -100, ay: 100); |
1347 | items[3]->setPos(ax: 100, ay: 100); |
1348 | |
1349 | QGraphicsItem *icon = scene.addEllipse(rect: QRectF(-10, -10, 20, 20), pen: QPen(Qt::black), brush: QBrush(Qt::gray)); |
1350 | |
1351 | QGraphicsView view(&scene, &toplevel); |
1352 | view.setSceneRect(ax: -500, ay: -500, aw: 1000, ah: 1000); |
1353 | view.setFixedSize(w: 250, h: 250); |
1354 | toplevel.show(); |
1355 | QVERIFY(QTest::qWaitForWindowExposed(&toplevel)); |
1356 | |
1357 | for (int y = -100; y < 100; y += 25) { |
1358 | for (int x = -100; x < 100; x += 13) { |
1359 | |
1360 | icon->setPos(ax: x, ay: y); |
1361 | |
1362 | switch (x & 3) { |
1363 | case 0: |
1364 | view.centerOn(ax: -500, ay: -500); |
1365 | break; |
1366 | case 1: |
1367 | view.centerOn(ax: 500, ay: -500); |
1368 | break; |
1369 | case 2: |
1370 | view.centerOn(ax: -500, ay: 500); |
1371 | break; |
1372 | case 3: |
1373 | default: |
1374 | view.centerOn(ax: 500, ay: 500); |
1375 | break; |
1376 | } |
1377 | |
1378 | QVERIFY(!view.viewport()->rect().contains(view.mapFromScene(x, y))); |
1379 | |
1380 | for (int margin = 10; margin < 60; margin += 15) { |
1381 | view.ensureVisible(ax: x, ay: y, aw: 0, ah: 0, xmargin: margin, ymargin: margin); |
1382 | |
1383 | QRect viewRect = view.viewport()->rect(); |
1384 | QPoint viewPoint = view.mapFromScene(ax: x, ay: y); |
1385 | |
1386 | QVERIFY(viewRect.contains(viewPoint)); |
1387 | QVERIFY(qAbs(viewPoint.x() - viewRect.left()) >= margin -1); |
1388 | QVERIFY(qAbs(viewPoint.x() - viewRect.right()) >= margin -1); |
1389 | QVERIFY(qAbs(viewPoint.y() - viewRect.top()) >= margin -1); |
1390 | QVERIFY(qAbs(viewPoint.y() - viewRect.bottom()) >= margin -1); |
1391 | |
1392 | QApplication::processEvents(); |
1393 | } |
1394 | } |
1395 | view.rotate(angle: 5); |
1396 | view.scale(sx: 1.05, sy: 1.05); |
1397 | view.translate(dx: 30, dy: -30); |
1398 | } |
1399 | } |
1400 | |
1401 | void tst_QGraphicsView::fitInView() |
1402 | { |
1403 | QGraphicsScene scene; |
1404 | QGraphicsItem *items[4]; |
1405 | items[0] = scene.addEllipse(rect: QRectF(-25, -25, 100, 20), pen: QPen(Qt::black), brush: QBrush(Qt::green)); |
1406 | items[1] = scene.addEllipse(rect: QRectF(-25, -25, 20, 100), pen: QPen(Qt::black), brush: QBrush(Qt::red)); |
1407 | items[2] = scene.addEllipse(rect: QRectF(-25, -25, 50, 50), pen: QPen(Qt::black), brush: QBrush(Qt::blue)); |
1408 | items[3] = scene.addEllipse(rect: QRectF(-25, -25, 50, 50), pen: QPen(Qt::black), brush: QBrush(Qt::yellow)); |
1409 | scene.addLine(line: QLineF(0, -100, 0, 100), pen: QPen(Qt::blue, 2)); |
1410 | scene.addLine(line: QLineF(-100, 0, 100, 0), pen: QPen(Qt::blue, 2)); |
1411 | items[0]->setPos(ax: -100, ay: -100); |
1412 | items[1]->setPos(ax: 100, ay: -100); |
1413 | items[2]->setPos(ax: -100, ay: 100); |
1414 | items[3]->setPos(ax: 100, ay: 100); |
1415 | |
1416 | items[0]->setTransform(matrix: QTransform().rotate(a: 30), combine: true); |
1417 | items[1]->setTransform(matrix: QTransform().rotate(a: -30), combine: true); |
1418 | |
1419 | QGraphicsView view(&scene); |
1420 | view.setSceneRect(ax: -400, ay: -400, aw: 800, ah: 800); |
1421 | view.setFixedSize(w: 400, h: 200); |
1422 | |
1423 | view.showNormal(); |
1424 | view.fitInView(rect: scene.itemsBoundingRect(), aspectRadioMode: Qt::IgnoreAspectRatio); |
1425 | qApp->processEvents(); |
1426 | |
1427 | // Sampled coordinates. |
1428 | QVERIFY(!view.itemAt(45, 41)); |
1429 | QVERIFY(!view.itemAt(297, 44)); |
1430 | QVERIFY(!view.itemAt(359, 143)); |
1431 | QCOMPARE(view.itemAt(79, 22), items[0]); |
1432 | QCOMPARE(view.itemAt(329, 41), items[1]); |
1433 | QCOMPARE(view.itemAt(38, 158), items[2]); |
1434 | QCOMPARE(view.itemAt(332, 160), items[3]); |
1435 | |
1436 | view.fitInView(item: items[0], aspectRadioMode: Qt::IgnoreAspectRatio); |
1437 | qApp->processEvents(); |
1438 | |
1439 | QCOMPARE(view.itemAt(19, 13), items[0]); |
1440 | QCOMPARE(view.itemAt(91, 47), items[0]); |
1441 | QCOMPARE(view.itemAt(202, 94), items[0]); |
1442 | QCOMPARE(view.itemAt(344, 161), items[0]); |
1443 | QVERIFY(!view.itemAt(236, 54)); |
1444 | QVERIFY(!view.itemAt(144, 11)); |
1445 | QVERIFY(!view.itemAt(29, 69)); |
1446 | QVERIFY(!view.itemAt(251, 167)); |
1447 | |
1448 | view.fitInView(item: items[0], aspectRadioMode: Qt::KeepAspectRatio); |
1449 | qApp->processEvents(); |
1450 | |
1451 | QCOMPARE(view.itemAt(325, 170), items[0]); |
1452 | QCOMPARE(view.itemAt(206, 74), items[0]); |
1453 | QCOMPARE(view.itemAt(190, 115), items[0]); |
1454 | QCOMPARE(view.itemAt(55, 14), items[0]); |
1455 | QVERIFY(!view.itemAt(109, 4)); |
1456 | QVERIFY(!view.itemAt(244, 68)); |
1457 | QVERIFY(!view.itemAt(310, 125)); |
1458 | QVERIFY(!view.itemAt(261, 168)); |
1459 | |
1460 | view.fitInView(item: items[0], aspectRadioMode: Qt::KeepAspectRatioByExpanding); |
1461 | qApp->processEvents(); |
1462 | |
1463 | QCOMPARE(view.itemAt(18, 10), items[0]); |
1464 | QCOMPARE(view.itemAt(95, 4), items[0]); |
1465 | QCOMPARE(view.itemAt(279, 175), items[0]); |
1466 | QCOMPARE(view.itemAt(359, 170), items[0]); |
1467 | QVERIFY(!view.itemAt(370, 166)); |
1468 | QVERIFY(!view.itemAt(136, 7)); |
1469 | QVERIFY(!view.itemAt(31, 44)); |
1470 | QVERIFY(!view.itemAt(203, 153)); |
1471 | } |
1472 | |
1473 | void tst_QGraphicsView::itemsAtPoint() |
1474 | { |
1475 | QGraphicsScene scene; |
1476 | scene.addRect(rect: QRectF(-10, -10, 20, 20))->setZValue(1); |
1477 | scene.addRect(rect: QRectF(-10, -10, 20, 20))->setZValue(0); |
1478 | scene.addRect(rect: QRectF(-10, -10, 20, 20))->setZValue(2); |
1479 | scene.addRect(rect: QRectF(-10, -10, 20, 20))->setZValue(-1); |
1480 | scene.addRect(rect: QRectF(-10, -10, 20, 20))->setZValue(3); |
1481 | |
1482 | QGraphicsView view; |
1483 | QVERIFY(view.items(0, 0).isEmpty()); |
1484 | |
1485 | view.setScene(&scene); |
1486 | view.setSceneRect(ax: -10000, ay: -10000, aw: 20000, ah: 20000); |
1487 | view.show(); |
1488 | |
1489 | QList<QGraphicsItem *> items = view.items(pos: view.viewport()->rect().center()); |
1490 | QCOMPARE(items.size(), 5); |
1491 | QCOMPARE(items.takeFirst()->zValue(), qreal(3)); |
1492 | QCOMPARE(items.takeFirst()->zValue(), qreal(2)); |
1493 | QCOMPARE(items.takeFirst()->zValue(), qreal(1)); |
1494 | QCOMPARE(items.takeFirst()->zValue(), qreal(0)); |
1495 | QCOMPARE(items.takeFirst()->zValue(), qreal(-1)); |
1496 | } |
1497 | |
1498 | #if defined QT_BUILD_INTERNAL |
1499 | void tst_QGraphicsView::itemsAtPosition_data() |
1500 | { |
1501 | QTest::addColumn<float>(name: "rotation" ); |
1502 | QTest::addColumn<float>(name: "scale" ); |
1503 | QTest::addColumn<QPoint>(name: "viewPos" ); |
1504 | QTest::addColumn<bool>(name: "ignoreTransform" ); |
1505 | QTest::addColumn<bool>(name: "hit" ); |
1506 | QTest::newRow(dataTag: "scaled + ignore transform, no hit" ) << 0.0f << 1000.0f << QPoint(0, 0) << true << false; |
1507 | QTest::newRow(dataTag: "scaled + ignore transform, hit" ) << 0.0f << 1000.0f << QPoint(100, 100) << true << true; |
1508 | QTest::newRow(dataTag: "rotated + scaled, no hit" ) << 45.0f << 2.0f << QPoint(90, 90) << false << false; |
1509 | QTest::newRow(dataTag: "rotated + scaled, hit" ) << 45.0f << 2.0f << QPoint(100, 100) << false << true; |
1510 | } |
1511 | |
1512 | void tst_QGraphicsView::itemsAtPosition() |
1513 | { |
1514 | QFETCH(float, rotation); |
1515 | QFETCH(float, scale); |
1516 | QFETCH(QPoint, viewPos); |
1517 | QFETCH(bool, ignoreTransform); |
1518 | QFETCH(bool, hit); |
1519 | |
1520 | FriendlyGraphicsScene scene; |
1521 | scene.setSceneRect(QRect(-100, -100, 200, 200)); |
1522 | QGraphicsItem *item = scene.addRect(x: -5, y: -5, w: 10, h: 10); |
1523 | |
1524 | if (ignoreTransform) |
1525 | item->setFlag(flag: QGraphicsItem::ItemIgnoresTransformations); |
1526 | |
1527 | QGraphicsView view; |
1528 | view.setFrameStyle(QFrame::NoFrame); |
1529 | view.resize(w: 200, h: 200); |
1530 | view.scale(sx: scale, sy: scale); |
1531 | view.rotate(angle: rotation); |
1532 | view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
1533 | view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
1534 | view.setScene(&scene); |
1535 | view.showNormal(); |
1536 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
1537 | |
1538 | QPoint screenPos = view.viewport()->mapToGlobal(viewPos); |
1539 | QPointF scenePos = view.mapToScene(point: viewPos); |
1540 | QGraphicsScenePrivate *viewPrivate = scene.d_func(); |
1541 | QList<QGraphicsItem *> items; |
1542 | items = viewPrivate->itemsAtPosition(screenPos, scenePos, widget: view.viewport()); |
1543 | QCOMPARE(!items.empty(), hit); |
1544 | } |
1545 | #endif |
1546 | |
1547 | void tst_QGraphicsView::itemsInRect() |
1548 | { |
1549 | QGraphicsScene scene; |
1550 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(1); |
1551 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(0); |
1552 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(2); |
1553 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(-1); |
1554 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(3); |
1555 | |
1556 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(5); |
1557 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(4); |
1558 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(6); |
1559 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(3); |
1560 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(7); |
1561 | |
1562 | QGraphicsView view; |
1563 | QVERIFY(view.items(QRect(-100, -100, 200, 200)).isEmpty()); |
1564 | view.setScene(&scene); |
1565 | view.setSceneRect(ax: -10000, ay: -10000, aw: 20000, ah: 20000); |
1566 | view.show(); |
1567 | |
1568 | QRect leftRect = view.mapFromScene(ax: -30, ay: -10, w: 20, h: 20).boundingRect(); |
1569 | QRect rightRect = view.mapFromScene(ax: 30, ay: -10, w: 20, h: 20).boundingRect(); |
1570 | |
1571 | QList<QGraphicsItem *> items = view.items(rect: leftRect); |
1572 | QCOMPARE(items.size(), 5); |
1573 | QCOMPARE(items.takeFirst()->zValue(), qreal(3)); |
1574 | QCOMPARE(items.takeFirst()->zValue(), qreal(2)); |
1575 | QCOMPARE(items.takeFirst()->zValue(), qreal(1)); |
1576 | QCOMPARE(items.takeFirst()->zValue(), qreal(0)); |
1577 | QCOMPARE(items.takeFirst()->zValue(), qreal(-1)); |
1578 | |
1579 | items = view.items(rect: rightRect); |
1580 | QCOMPARE(items.size(), 5); |
1581 | QCOMPARE(items.takeFirst()->zValue(), qreal(7)); |
1582 | QCOMPARE(items.takeFirst()->zValue(), qreal(6)); |
1583 | QCOMPARE(items.takeFirst()->zValue(), qreal(5)); |
1584 | QCOMPARE(items.takeFirst()->zValue(), qreal(4)); |
1585 | QCOMPARE(items.takeFirst()->zValue(), qreal(3)); |
1586 | } |
1587 | |
1588 | class CountPaintItem : public QGraphicsRectItem |
1589 | { |
1590 | public: |
1591 | int numPaints; |
1592 | |
1593 | CountPaintItem(const QRectF &rect) |
1594 | : QGraphicsRectItem(rect), numPaints(0) |
1595 | { } |
1596 | |
1597 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0) |
1598 | { |
1599 | ++numPaints; |
1600 | QGraphicsRectItem::paint(painter, option, widget); |
1601 | } |
1602 | }; |
1603 | |
1604 | void tst_QGraphicsView::itemsInRect_cosmeticAdjust_data() |
1605 | { |
1606 | QTest::addColumn<QRect>(name: "updateRect" ); |
1607 | QTest::addColumn<int>(name: "numPaints" ); |
1608 | QTest::addColumn<bool>(name: "adjustForAntialiasing" ); |
1609 | |
1610 | // Aliased. |
1611 | QTest::newRow(dataTag: "nil" ) << QRect() << 1 << false; |
1612 | QTest::newRow(dataTag: "0, 0, 300, 100" ) << QRect(0, 0, 300, 100) << 1 << false; |
1613 | QTest::newRow(dataTag: "0, 0, 100, 300" ) << QRect(0, 0, 100, 300) << 1 << false; |
1614 | QTest::newRow(dataTag: "200, 0, 100, 300" ) << QRect(200, 0, 100, 300) << 1 << false; |
1615 | QTest::newRow(dataTag: "0, 200, 300, 100" ) << QRect(0, 200, 300, 100) << 1 << false; |
1616 | QTest::newRow(dataTag: "0, 0, 300, 99" ) << QRect(0, 0, 300, 99) << 0 << false; |
1617 | QTest::newRow(dataTag: "0, 0, 99, 300" ) << QRect(0, 0, 99, 300) << 0 << false; |
1618 | QTest::newRow(dataTag: "201, 0, 99, 300" ) << QRect(201, 0, 99, 300) << 0 << false; |
1619 | QTest::newRow(dataTag: "0, 201, 300, 99" ) << QRect(0, 201, 300, 99) << 0 << false; |
1620 | |
1621 | // Anti-aliased. |
1622 | QTest::newRow(dataTag: "nil" ) << QRect() << 1 << true; |
1623 | QTest::newRow(dataTag: "0, 0, 300, 100" ) << QRect(0, 0, 300, 100) << 1 << true; |
1624 | QTest::newRow(dataTag: "0, 0, 100, 300" ) << QRect(0, 0, 100, 300) << 1 << true; |
1625 | QTest::newRow(dataTag: "200, 0, 100, 300" ) << QRect(200, 0, 100, 300) << 1 << true; |
1626 | QTest::newRow(dataTag: "0, 200, 300, 100" ) << QRect(0, 200, 300, 100) << 1 << true; |
1627 | QTest::newRow(dataTag: "0, 0, 300, 99" ) << QRect(0, 0, 300, 99) << 1 << true; |
1628 | QTest::newRow(dataTag: "0, 0, 99, 300" ) << QRect(0, 0, 99, 300) << 1 << true; |
1629 | QTest::newRow(dataTag: "201, 0, 99, 300" ) << QRect(201, 0, 99, 300) << 1 << true; |
1630 | QTest::newRow(dataTag: "0, 201, 300, 99" ) << QRect(0, 201, 300, 99) << 1 << true; |
1631 | QTest::newRow(dataTag: "0, 0, 300, 98" ) << QRect(0, 0, 300, 98) << 0 << false; |
1632 | QTest::newRow(dataTag: "0, 0, 98, 300" ) << QRect(0, 0, 98, 300) << 0 << false; |
1633 | QTest::newRow(dataTag: "202, 0, 98, 300" ) << QRect(202, 0, 98, 300) << 0 << false; |
1634 | QTest::newRow(dataTag: "0, 202, 300, 98" ) << QRect(0, 202, 300, 98) << 0 << false; |
1635 | } |
1636 | |
1637 | void tst_QGraphicsView::itemsInRect_cosmeticAdjust() |
1638 | { |
1639 | QFETCH(QRect, updateRect); |
1640 | QFETCH(int, numPaints); |
1641 | QFETCH(bool, adjustForAntialiasing); |
1642 | |
1643 | QGraphicsScene scene(-100, -100, 200, 200); |
1644 | CountPaintItem *rect = new CountPaintItem(QRectF(-50, -50, 100, 100)); |
1645 | rect->setPen(QPen(Qt::black, 0)); |
1646 | scene.addItem(item: rect); |
1647 | |
1648 | QGraphicsView view(&scene); |
1649 | view.setOptimizationFlag(flag: QGraphicsView::DontAdjustForAntialiasing, enabled: !adjustForAntialiasing); |
1650 | view.setRenderHint(hint: QPainter::Antialiasing, enabled: adjustForAntialiasing); |
1651 | view.setFrameStyle(0); |
1652 | view.resize(w: 300, h: 300); |
1653 | view.showNormal(); |
1654 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
1655 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
1656 | QTRY_VERIFY(rect->numPaints > 0); |
1657 | |
1658 | QCoreApplication::processEvents(); // Process all queued paint events |
1659 | rect->numPaints = 0; |
1660 | if (updateRect.isNull()) |
1661 | view.viewport()->update(); |
1662 | else |
1663 | view.viewport()->update(updateRect); |
1664 | qApp->processEvents(); |
1665 | QTRY_COMPARE(rect->numPaints, numPaints); |
1666 | } |
1667 | |
1668 | void tst_QGraphicsView::itemsInPoly() |
1669 | { |
1670 | QGraphicsScene scene; |
1671 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(1); |
1672 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(0); |
1673 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(2); |
1674 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(-1); |
1675 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(3); |
1676 | |
1677 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(5); |
1678 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(4); |
1679 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(6); |
1680 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(3); |
1681 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(7); |
1682 | |
1683 | QGraphicsView view; |
1684 | QVERIFY(view.items(QPolygon()).isEmpty()); |
1685 | view.setScene(&scene); |
1686 | view.setSceneRect(ax: -10000, ay: -10000, aw: 20000, ah: 20000); |
1687 | view.show(); |
1688 | |
1689 | QPolygon leftPoly = view.mapFromScene(rect: QRectF(-30, -10, 20, 20)); |
1690 | QPolygon rightPoly = view.mapFromScene(rect: QRectF(30, -10, 20, 20)); |
1691 | |
1692 | QList<QGraphicsItem *> items = view.items(polygon: leftPoly); |
1693 | QCOMPARE(items.size(), 5); |
1694 | QCOMPARE(items.takeFirst()->zValue(), qreal(3)); |
1695 | QCOMPARE(items.takeFirst()->zValue(), qreal(2)); |
1696 | QCOMPARE(items.takeFirst()->zValue(), qreal(1)); |
1697 | QCOMPARE(items.takeFirst()->zValue(), qreal(0)); |
1698 | QCOMPARE(items.takeFirst()->zValue(), qreal(-1)); |
1699 | |
1700 | items = view.items(polygon: rightPoly); |
1701 | QCOMPARE(items.size(), 5); |
1702 | QCOMPARE(items.takeFirst()->zValue(), qreal(7)); |
1703 | QCOMPARE(items.takeFirst()->zValue(), qreal(6)); |
1704 | QCOMPARE(items.takeFirst()->zValue(), qreal(5)); |
1705 | QCOMPARE(items.takeFirst()->zValue(), qreal(4)); |
1706 | QCOMPARE(items.takeFirst()->zValue(), qreal(3)); |
1707 | } |
1708 | |
1709 | void tst_QGraphicsView::itemsInPath() |
1710 | { |
1711 | QGraphicsScene scene; |
1712 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(1); |
1713 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(0); |
1714 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(2); |
1715 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(-1); |
1716 | scene.addRect(rect: QRectF(-30, -10, 20, 20))->setZValue(3); |
1717 | |
1718 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(5); |
1719 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(4); |
1720 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(6); |
1721 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(3); |
1722 | scene.addRect(rect: QRectF(30, -10, 20, 20))->setZValue(7); |
1723 | |
1724 | QGraphicsView view; |
1725 | QVERIFY(view.items(QPainterPath()).isEmpty()); |
1726 | view.setScene(&scene); |
1727 | view.translate(dx: 100, dy: 400); |
1728 | view.rotate(angle: 22.3); |
1729 | view.setSceneRect(ax: -10000, ay: -10000, aw: 20000, ah: 20000); |
1730 | view.show(); |
1731 | |
1732 | QPainterPath leftPath; |
1733 | leftPath.addEllipse(rect: QRect(view.mapFromScene(ax: -30, ay: -10), QSize(20, 20))); |
1734 | |
1735 | QPainterPath rightPath; |
1736 | rightPath.addEllipse(rect: QRect(view.mapFromScene(ax: 30, ay: -10), QSize(20, 20))); |
1737 | |
1738 | QList<QGraphicsItem *> items = view.items(path: leftPath); |
1739 | |
1740 | QCOMPARE(items.size(), 5); |
1741 | QCOMPARE(items.takeFirst()->zValue(), qreal(3)); |
1742 | QCOMPARE(items.takeFirst()->zValue(), qreal(2)); |
1743 | QCOMPARE(items.takeFirst()->zValue(), qreal(1)); |
1744 | QCOMPARE(items.takeFirst()->zValue(), qreal(0)); |
1745 | QCOMPARE(items.takeFirst()->zValue(), qreal(-1)); |
1746 | |
1747 | items = view.items(path: rightPath); |
1748 | QCOMPARE(items.size(), 5); |
1749 | QCOMPARE(items.takeFirst()->zValue(), qreal(7)); |
1750 | QCOMPARE(items.takeFirst()->zValue(), qreal(6)); |
1751 | QCOMPARE(items.takeFirst()->zValue(), qreal(5)); |
1752 | QCOMPARE(items.takeFirst()->zValue(), qreal(4)); |
1753 | QCOMPARE(items.takeFirst()->zValue(), qreal(3)); |
1754 | } |
1755 | |
1756 | void tst_QGraphicsView::itemAt() |
1757 | { |
1758 | QGraphicsScene scene; |
1759 | scene.addRect(rect: QRectF(-10, -10, 20, 20))->setZValue(1); |
1760 | scene.addRect(rect: QRectF(-10, -10, 20, 20))->setZValue(0); |
1761 | scene.addRect(rect: QRectF(-10, -10, 20, 20))->setZValue(2); |
1762 | scene.addRect(rect: QRectF(-10, -10, 20, 20))->setZValue(-1); |
1763 | scene.addRect(rect: QRectF(-10, -10, 20, 20))->setZValue(3); |
1764 | |
1765 | QGraphicsView view; |
1766 | QCOMPARE(view.itemAt(0, 0), (QGraphicsItem *)0); |
1767 | |
1768 | view.setScene(&scene); |
1769 | view.setSceneRect(ax: -10000, ay: -10000, aw: 20000, ah: 20000); |
1770 | view.show(); |
1771 | |
1772 | QCOMPARE(view.itemAt(0, 0), (QGraphicsItem *)0); |
1773 | QGraphicsItem* item = view.itemAt(pos: view.viewport()->rect().center()); |
1774 | QVERIFY(item); |
1775 | QCOMPARE(item->zValue(), qreal(3)); |
1776 | } |
1777 | |
1778 | void tst_QGraphicsView::itemAt2() |
1779 | { |
1780 | // test precision of the itemAt() function with items that are smaller |
1781 | // than 1 pixel. |
1782 | QGraphicsScene scene(0, 0, 100, 100); |
1783 | |
1784 | // Add a 0.5x0.5 item at position 0 on the scene, top-left corner at -0.25, -0.25. |
1785 | QGraphicsItem *item = scene.addRect(rect: QRectF(-0.25, -0.25, 0.5, 0.5), pen: QPen(Qt::black, 0.1)); |
1786 | |
1787 | QGraphicsView view(&scene); |
1788 | view.setFixedSize(w: 200, h: 200); |
1789 | view.setTransformationAnchor(QGraphicsView::NoAnchor); |
1790 | view.setRenderHint(hint: QPainter::Antialiasing); |
1791 | view.show(); |
1792 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
1793 | QApplication::processEvents(); |
1794 | |
1795 | QPoint itemViewPoint = view.mapFromScene(point: item->scenePos()); |
1796 | |
1797 | for (int i = 0; i < 3; ++i) { |
1798 | QVERIFY(view.itemAt(itemViewPoint)); |
1799 | QVERIFY(!view.items(itemViewPoint).isEmpty()); |
1800 | QVERIFY(view.itemAt(itemViewPoint + QPoint(-1, 0))); |
1801 | QVERIFY(!view.items(itemViewPoint + QPoint(-1, 0)).isEmpty()); |
1802 | QVERIFY(view.itemAt(itemViewPoint + QPoint(-1, -1))); |
1803 | QVERIFY(!view.items(itemViewPoint + QPoint(-1, -1)).isEmpty()); |
1804 | QVERIFY(view.itemAt(itemViewPoint + QPoint(0, -1))); |
1805 | QVERIFY(!view.items(itemViewPoint + QPoint(0, -1)).isEmpty()); |
1806 | item->moveBy(dx: 0.1, dy: 0); |
1807 | } |
1808 | |
1809 | // Here |
1810 | QVERIFY(view.itemAt(itemViewPoint)); |
1811 | QVERIFY(!view.items(itemViewPoint).isEmpty()); |
1812 | QVERIFY(view.itemAt(itemViewPoint + QPoint(0, -1))); |
1813 | QVERIFY(!view.items(itemViewPoint + QPoint(0, -1)).isEmpty()); |
1814 | |
1815 | if (sizeof(qreal) != sizeof(double)) |
1816 | QSKIP("Skipped due to rounding errors" ); |
1817 | |
1818 | // Not here |
1819 | QVERIFY(!view.itemAt(itemViewPoint + QPoint(-1, 0))); |
1820 | QVERIFY(view.items(itemViewPoint + QPoint(-1, 0)).isEmpty()); |
1821 | QVERIFY(!view.itemAt(itemViewPoint + QPoint(-1, -1))); |
1822 | QVERIFY(view.items(itemViewPoint + QPoint(-1, -1)).isEmpty()); |
1823 | } |
1824 | |
1825 | void tst_QGraphicsView::mapToScene() |
1826 | { |
1827 | // Uncomment the commented-out code to see what's going on. It doesn't |
1828 | // affect the test; it just slows it down. |
1829 | |
1830 | QGraphicsScene scene; |
1831 | scene.addPixmap(pixmap: QPixmap("3D-Qt-1-2.png" )); |
1832 | |
1833 | QWidget topLevel; |
1834 | QGraphicsView view(&topLevel); |
1835 | view.setScene(&scene); |
1836 | view.setSceneRect(ax: -500, ay: -500, aw: 1000, ah: 1000); |
1837 | QSize viewSize(300,300); |
1838 | |
1839 | view.setFixedSize(viewSize); |
1840 | topLevel.show(); |
1841 | QApplication::processEvents(); |
1842 | QVERIFY(view.isVisible()); |
1843 | QCOMPARE(view.size(), viewSize); |
1844 | |
1845 | // First once without setting the scene rect |
1846 | #ifdef Q_PROCESSOR_ARM |
1847 | const int step = 20; |
1848 | #else |
1849 | const int step = 5; |
1850 | #endif |
1851 | |
1852 | for (int x = 0; x < view.width(); x += step) { |
1853 | for (int y = 0; y < view.height(); y += step) { |
1854 | QCOMPARE(view.mapToScene(QPoint(x, y)), |
1855 | QPointF(view.horizontalScrollBar()->value() + x, |
1856 | view.verticalScrollBar()->value() + y)); |
1857 | } |
1858 | } |
1859 | |
1860 | for (int sceneRectHeight = 250; sceneRectHeight < 1000; sceneRectHeight += 250) { |
1861 | for (int sceneRectWidth = 250; sceneRectWidth < 1000; sceneRectWidth += 250) { |
1862 | view.setSceneRect(QRectF(-int(sceneRectWidth / 2), -int(sceneRectHeight / 2), |
1863 | sceneRectWidth, sceneRectHeight)); |
1864 | QApplication::processEvents(); |
1865 | |
1866 | int hmin = view.horizontalScrollBar()->minimum(); |
1867 | int hmax = view.horizontalScrollBar()->maximum(); |
1868 | int hstep = (hmax - hmin) / 3; |
1869 | int vmin = view.verticalScrollBar()->minimum(); |
1870 | int vmax = view.verticalScrollBar()->maximum(); |
1871 | int vstep = (vmax - vmin) / 3; |
1872 | |
1873 | for (int hscrollValue = hmin; hscrollValue < hmax; hscrollValue += hstep) { |
1874 | for (int vscrollValue = vmin; vscrollValue < vmax; vscrollValue += vstep) { |
1875 | |
1876 | view.horizontalScrollBar()->setValue(hscrollValue); |
1877 | view.verticalScrollBar()->setValue(vscrollValue); |
1878 | QApplication::processEvents(); |
1879 | |
1880 | int h = view.horizontalScrollBar()->value(); |
1881 | int v = view.verticalScrollBar()->value(); |
1882 | |
1883 | for (int x = 0; x < view.width(); x += step) { |
1884 | for (int y = 0; y < view.height(); y += step) { |
1885 | QCOMPARE(view.mapToScene(QPoint(x, y)), QPointF(h + x, v + y)); |
1886 | QCOMPARE(view.mapFromScene(QPointF(h + x, v + y)), QPoint(x, y)); |
1887 | } |
1888 | } |
1889 | } |
1890 | } |
1891 | } |
1892 | } |
1893 | } |
1894 | |
1895 | void tst_QGraphicsView::mapToScenePoint() |
1896 | { |
1897 | QGraphicsScene scene; |
1898 | QGraphicsView view(&scene); |
1899 | setFrameless(&view); |
1900 | view.rotate(angle: 90); |
1901 | view.setFixedSize(w: 117, h: 117); |
1902 | view.show(); |
1903 | QPoint center = view.viewport()->rect().center(); |
1904 | QCOMPARE(view.mapToScene(center + QPoint(10, 0)), |
1905 | view.mapToScene(center) + QPointF(0, -10)); |
1906 | } |
1907 | |
1908 | void tst_QGraphicsView::mapToSceneRect_data() |
1909 | { |
1910 | QTest::addColumn<QRect>(name: "viewRect" ); |
1911 | QTest::addColumn<QPolygonF>(name: "scenePoly" ); |
1912 | QTest::addColumn<qreal>(name: "rotation" ); |
1913 | |
1914 | QTest::newRow(dataTag: "nil" ) << QRect() << QPolygonF() << qreal(0); |
1915 | QTest::newRow(dataTag: "0, 0, 1, 1" ) << QRect(0, 0, 1, 1) << QPolygonF(QRectF(0, 0, 1, 1)) << qreal(0); |
1916 | QTest::newRow(dataTag: "0, 0, 10, 10" ) << QRect(0, 0, 10, 10) << QPolygonF(QRectF(0, 0, 10, 10)) << qreal(0); |
1917 | QTest::newRow(dataTag: "nil" ) << QRect() << QPolygonF() << qreal(90); |
1918 | QPolygonF p; |
1919 | p << QPointF(0, 0) << QPointF(0, -1) << QPointF(1, -1) << QPointF(1, 0) << QPointF(0, 0); |
1920 | QTest::newRow(dataTag: "0, 0, 1, 1" ) << QRect(0, 0, 1, 1) |
1921 | << p |
1922 | << qreal(90); |
1923 | p.clear(); |
1924 | p << QPointF(0, 0) << QPointF(0, -10) << QPointF(10, -10) << QPointF(10, 0) << QPointF(0, 0); |
1925 | QTest::newRow(dataTag: "0, 0, 10, 10" ) << QRect(0, 0, 10, 10) |
1926 | << p |
1927 | << qreal(90); |
1928 | } |
1929 | |
1930 | void tst_QGraphicsView::mapToSceneRect() |
1931 | { |
1932 | QFETCH(QRect, viewRect); |
1933 | QFETCH(QPolygonF, scenePoly); |
1934 | QFETCH(qreal, rotation); |
1935 | |
1936 | QGraphicsScene scene(-1000, -1000, 2000, 2000); |
1937 | scene.addRect(x: 25, y: -25, w: 50, h: 50); |
1938 | QGraphicsView view(&scene); |
1939 | view.setFrameStyle(0); |
1940 | view.setAlignment(Qt::AlignTop | Qt::AlignLeft); |
1941 | view.setFixedSize(w: 200, h: 200); |
1942 | view.setTransformationAnchor(QGraphicsView::NoAnchor); |
1943 | view.setResizeAnchor(QGraphicsView::NoAnchor); |
1944 | view.show(); |
1945 | |
1946 | view.rotate(angle: rotation); |
1947 | |
1948 | QPolygonF poly = view.mapToScene(rect: viewRect); |
1949 | if (!poly.isEmpty()) |
1950 | poly << poly[0]; |
1951 | |
1952 | QCOMPARE(poly, scenePoly); |
1953 | } |
1954 | |
1955 | void tst_QGraphicsView::mapToScenePoly() |
1956 | { |
1957 | QGraphicsScene scene; |
1958 | QGraphicsView view(&scene); |
1959 | setFrameless(&view); |
1960 | view.translate(dx: 100, dy: 100); |
1961 | view.setFixedSize(w: 117, h: 117); |
1962 | view.show(); |
1963 | QPoint center = view.viewport()->rect().center(); |
1964 | QRect rect(center + QPoint(10, 0), QSize(10, 10)); |
1965 | |
1966 | QPolygon poly; |
1967 | poly << rect.topLeft(); |
1968 | poly << rect.topRight(); |
1969 | poly << rect.bottomRight(); |
1970 | poly << rect.bottomLeft(); |
1971 | |
1972 | QPolygonF poly2; |
1973 | poly2 << view.mapToScene(point: rect.topLeft()); |
1974 | poly2 << view.mapToScene(point: rect.topRight()); |
1975 | poly2 << view.mapToScene(point: rect.bottomRight()); |
1976 | poly2 << view.mapToScene(point: rect.bottomLeft()); |
1977 | |
1978 | QCOMPARE(view.mapToScene(poly), poly2); |
1979 | } |
1980 | |
1981 | void tst_QGraphicsView::mapToScenePath() |
1982 | { |
1983 | QGraphicsScene scene; |
1984 | QGraphicsView view(&scene); |
1985 | view.setSceneRect(ax: -300, ay: -300, aw: 600, ah: 600); |
1986 | view.translate(dx: 10, dy: 10); |
1987 | view.setFixedSize(w: 300, h: 300); |
1988 | view.show(); |
1989 | QRect rect(QPoint(10, 0), QSize(10, 10)); |
1990 | |
1991 | QPainterPath path; |
1992 | path.addRect(rect); |
1993 | |
1994 | QPainterPath path2; |
1995 | path2.addRect(rect: rect.translated(dx: view.horizontalScrollBar()->value() - 10, |
1996 | dy: view.verticalScrollBar()->value() - 10)); |
1997 | QCOMPARE(view.mapToScene(path), path2); |
1998 | } |
1999 | |
2000 | void tst_QGraphicsView::mapFromScenePoint() |
2001 | { |
2002 | { |
2003 | QGraphicsScene scene; |
2004 | QGraphicsView view(&scene); |
2005 | view.rotate(angle: 90); |
2006 | view.scale(sx: 10, sy: 10); |
2007 | view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
2008 | view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
2009 | view.show(); |
2010 | |
2011 | QPoint mapped = view.mapFromScene(ax: 0, ay: 0); |
2012 | QPoint center = view.viewport()->rect().center(); |
2013 | if (qAbs(t: mapped.x() - center.x()) >= 2 |
2014 | || qAbs(t: mapped.y() - center.y()) >= 2) { |
2015 | QString error = QString("Compared values are not the same\n\tActual: (%1, %2)\n\tExpected: (%3, %4)" ) |
2016 | .arg(a: mapped.x()).arg(a: mapped.y()).arg(a: center.x()).arg(a: center.y()); |
2017 | QFAIL(qPrintable(error)); |
2018 | } |
2019 | } |
2020 | { |
2021 | QWidget toplevel; |
2022 | |
2023 | QGraphicsScene scene(0, 0, 200, 200); |
2024 | scene.addRect(rect: QRectF(0, 0, 200, 200), pen: QPen(Qt::black, 1)); |
2025 | QGraphicsView view(&scene, &toplevel); |
2026 | view.ensurePolished(); |
2027 | view.resize(view.sizeHint()); |
2028 | toplevel.show(); |
2029 | |
2030 | QCOMPARE(view.mapFromScene(0, 0), QPoint(0, 0)); |
2031 | QCOMPARE(view.mapFromScene(0.4, 0.4), QPoint(0, 0)); |
2032 | QCOMPARE(view.mapFromScene(0.5, 0.5), QPoint(1, 1)); |
2033 | QCOMPARE(view.mapFromScene(0.9, 0.9), QPoint(1, 1)); |
2034 | QCOMPARE(view.mapFromScene(1.0, 1.0), QPoint(1, 1)); |
2035 | QCOMPARE(view.mapFromScene(100, 100), QPoint(100, 100)); |
2036 | QCOMPARE(view.mapFromScene(100.5, 100.5), QPoint(101, 101)); |
2037 | QCOMPARE(view.mapToScene(0, 0), QPointF(0, 0)); |
2038 | QCOMPARE(view.mapToScene(1, 1), QPointF(1, 1)); |
2039 | QCOMPARE(view.mapToScene(100, 100), QPointF(100, 100)); |
2040 | } |
2041 | } |
2042 | |
2043 | void tst_QGraphicsView::mapFromSceneRect() |
2044 | { |
2045 | QGraphicsScene scene; |
2046 | QWidget topLevel; |
2047 | QGraphicsView view(&scene,&topLevel); |
2048 | view.rotate(angle: 90); |
2049 | view.setFixedSize(w: 200, h: 200); |
2050 | view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
2051 | view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
2052 | topLevel.show(); |
2053 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
2054 | |
2055 | QPolygon polygon; |
2056 | polygon << QPoint(98, 98); |
2057 | polygon << QPoint(98, 108); |
2058 | polygon << QPoint(88, 108); |
2059 | polygon << QPoint(88, 98); |
2060 | |
2061 | |
2062 | QPolygon viewPolygon = view.mapFromScene(ax: 0, ay: 0, w: 10, h: 10); |
2063 | for (int i = 0; i < 4; ++i) { |
2064 | QVERIFY(qAbs(viewPolygon[i].x() - polygon[i].x()) < 3); |
2065 | QVERIFY(qAbs(viewPolygon[i].y() - polygon[i].y()) < 3); |
2066 | } |
2067 | |
2068 | QPoint pt = view.mapFromScene(point: QPointF()); |
2069 | QPolygon p; |
2070 | p << pt << pt << pt << pt; |
2071 | QCOMPARE(view.mapFromScene(QRectF()), p); |
2072 | } |
2073 | |
2074 | void tst_QGraphicsView::mapFromScenePoly() |
2075 | { |
2076 | QGraphicsScene scene; |
2077 | QGraphicsView view(&scene); |
2078 | view.rotate(angle: 90); |
2079 | view.setFixedSize(w: 200, h: 200); |
2080 | view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
2081 | view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
2082 | view.show(); |
2083 | |
2084 | QPolygonF polygon; |
2085 | polygon << QPoint(0, 0); |
2086 | polygon << QPoint(10, 0); |
2087 | polygon << QPoint(10, 10); |
2088 | polygon << QPoint(0, 10); |
2089 | |
2090 | QPolygon polygon2; |
2091 | polygon2 << QPoint(98, 98); |
2092 | polygon2 << QPoint(98, 108); |
2093 | polygon2 << QPoint(88, 108); |
2094 | polygon2 << QPoint(88, 98); |
2095 | |
2096 | QPolygon viewPolygon = view.mapFromScene(polygon); |
2097 | for (int i = 0; i < 4; ++i) { |
2098 | QVERIFY(qAbs(viewPolygon[i].x() - polygon2[i].x()) < 3); |
2099 | QVERIFY(qAbs(viewPolygon[i].y() - polygon2[i].y()) < 3); |
2100 | } |
2101 | } |
2102 | |
2103 | void tst_QGraphicsView::mapFromScenePath() |
2104 | { |
2105 | QGraphicsScene scene; |
2106 | QGraphicsView view(&scene); |
2107 | view.rotate(angle: 90); |
2108 | view.setFixedSize(w: 200, h: 200); |
2109 | view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
2110 | view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
2111 | view.show(); |
2112 | |
2113 | QPolygonF polygon; |
2114 | polygon << QPoint(0, 0); |
2115 | polygon << QPoint(10, 0); |
2116 | polygon << QPoint(10, 10); |
2117 | polygon << QPoint(0, 10); |
2118 | QPainterPath path; |
2119 | path.addPolygon(polygon); |
2120 | |
2121 | QPolygon polygon2; |
2122 | polygon2 << QPoint(98, 98); |
2123 | polygon2 << QPoint(98, 108); |
2124 | polygon2 << QPoint(88, 108); |
2125 | polygon2 << QPoint(88, 98); |
2126 | QPainterPath path2; |
2127 | path2.addPolygon(polygon: polygon2); |
2128 | |
2129 | QPolygonF pathPoly = view.mapFromScene(path).toFillPolygon(matrix: QTransform()); |
2130 | QPolygonF path2Poly = path2.toFillPolygon(matrix: QTransform()); |
2131 | |
2132 | for (int i = 0; i < pathPoly.size(); ++i) { |
2133 | QVERIFY(qAbs(pathPoly[i].x() - path2Poly[i].x()) < 3); |
2134 | QVERIFY(qAbs(pathPoly[i].y() - path2Poly[i].y()) < 3); |
2135 | } |
2136 | } |
2137 | |
2138 | void tst_QGraphicsView::sendEvent() |
2139 | { |
2140 | QGraphicsScene scene; |
2141 | |
2142 | TestItem *item = new TestItem; |
2143 | scene.addItem(item); |
2144 | item->setFlag(flag: QGraphicsItem::ItemIsFocusable); |
2145 | item->setFlag(flag: QGraphicsItem::ItemIsMovable); |
2146 | |
2147 | QGraphicsView view(&scene); |
2148 | view.show(); |
2149 | QApplication::setActiveWindow(&view); |
2150 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2151 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
2152 | QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); |
2153 | |
2154 | item->setFocus(); |
2155 | |
2156 | QCOMPARE(scene.focusItem(), (QGraphicsItem *)item); |
2157 | QCOMPARE(item->events.size(), 2); |
2158 | QCOMPARE(item->events.last(), QEvent::FocusIn); |
2159 | |
2160 | QPoint itemPoint = view.mapFromScene(point: item->scenePos()); |
2161 | sendMousePress(widget: view.viewport(), point: itemPoint); |
2162 | QCOMPARE(item->events.size(), 4); |
2163 | QCOMPARE(item->events.at(item->events.size() - 2), QEvent::GrabMouse); |
2164 | QCOMPARE(item->events.at(item->events.size() - 1), QEvent::GraphicsSceneMousePress); |
2165 | |
2166 | QMouseEvent mouseMoveEvent(QEvent::MouseMove, itemPoint, view.viewport()->mapToGlobal(itemPoint), |
2167 | Qt::LeftButton, Qt::LeftButton, {}); |
2168 | QApplication::sendEvent(receiver: view.viewport(), event: &mouseMoveEvent); |
2169 | QCOMPARE(item->events.size(), 5); |
2170 | QCOMPARE(item->events.last(), QEvent::GraphicsSceneMouseMove); |
2171 | |
2172 | QMouseEvent mouseReleaseEvent(QEvent::MouseButtonRelease, itemPoint, |
2173 | view.viewport()->mapToGlobal(itemPoint), |
2174 | Qt::LeftButton, {}, {}); |
2175 | QApplication::sendEvent(receiver: view.viewport(), event: &mouseReleaseEvent); |
2176 | QCOMPARE(item->events.size(), 7); |
2177 | QCOMPARE(item->events.at(item->events.size() - 2), QEvent::GraphicsSceneMouseRelease); |
2178 | QCOMPARE(item->events.at(item->events.size() - 1), QEvent::UngrabMouse); |
2179 | |
2180 | QTest::keyPress(widget: view.viewport(), key: Qt::Key_Space); |
2181 | QCOMPARE(item->events.size(), 9); |
2182 | QCOMPARE(item->events.at(item->events.size() - 2), QEvent::ShortcutOverride); |
2183 | QCOMPARE(item->events.last(), QEvent::KeyPress); |
2184 | } |
2185 | |
2186 | #if QT_CONFIG(wheelevent) |
2187 | class MouseWheelScene : public QGraphicsScene |
2188 | { |
2189 | public: |
2190 | Qt::Orientation orientation; |
2191 | |
2192 | void wheelEvent(QGraphicsSceneWheelEvent *event) |
2193 | { |
2194 | orientation = event->orientation(); |
2195 | QGraphicsScene::wheelEvent(event); |
2196 | } |
2197 | }; |
2198 | |
2199 | void tst_QGraphicsView::wheelEvent() |
2200 | { |
2201 | // Create a scene with an invalid orientation. |
2202 | MouseWheelScene scene; |
2203 | scene.orientation = Qt::Orientation(-1); |
2204 | |
2205 | QGraphicsWidget *widget = new QGraphicsWidget; |
2206 | widget->setGeometry(ax: 0, ay: 0, aw: 400, ah: 400); |
2207 | widget->setFocusPolicy(Qt::WheelFocus); |
2208 | |
2209 | EventSpy spy(widget, QEvent::GraphicsSceneWheel); |
2210 | QCOMPARE(spy.count(), 0); |
2211 | |
2212 | scene.addItem(item: widget); |
2213 | |
2214 | // Assign a view. |
2215 | QGraphicsView view(&scene); |
2216 | view.show(); |
2217 | QApplication::setActiveWindow(&view); |
2218 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2219 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
2220 | QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); |
2221 | |
2222 | |
2223 | // Send a wheel event with horizontal orientation. |
2224 | { |
2225 | QWheelEvent event(view.mapFromScene(point: widget->boundingRect().center()), |
2226 | view.mapToGlobal(view.mapFromScene(point: widget->boundingRect().center())), |
2227 | QPoint(), QPoint(120, 0), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); |
2228 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
2229 | QCOMPARE(scene.orientation, Qt::Horizontal); |
2230 | } |
2231 | |
2232 | // Send a wheel event with vertical orientation. |
2233 | { |
2234 | QWheelEvent event(view.mapFromScene(point: widget->boundingRect().center()), |
2235 | view.mapToGlobal(view.mapFromScene(point: widget->boundingRect().center())), |
2236 | QPoint(), QPoint(0, 120), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); |
2237 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
2238 | QCOMPARE(scene.orientation, Qt::Vertical); |
2239 | } |
2240 | |
2241 | QCOMPARE(spy.count(), 2); |
2242 | QVERIFY(widget->hasFocus()); |
2243 | } |
2244 | #endif // QT_CONFIG(wheelevent) |
2245 | |
2246 | #ifndef QT_NO_CURSOR |
2247 | void tst_QGraphicsView::cursor() |
2248 | { |
2249 | QGraphicsScene scene; |
2250 | QGraphicsItem *item = scene.addRect(rect: QRectF(-10, -10, 20, 20)); |
2251 | item->setCursor(Qt::IBeamCursor); |
2252 | |
2253 | QGraphicsView view(&scene); |
2254 | view.setFixedSize(w: 400, h: 400); |
2255 | view.show(); |
2256 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2257 | |
2258 | QCOMPARE(view.viewport()->cursor().shape(), QCursor().shape()); |
2259 | view.viewport()->setCursor(Qt::PointingHandCursor); |
2260 | QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
2261 | |
2262 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: 0, ay: 0)); |
2263 | QCOMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor); |
2264 | |
2265 | sendMouseMove(widget: view.viewport(), point: QPoint(5, 5)); |
2266 | QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
2267 | } |
2268 | #endif |
2269 | |
2270 | #ifndef QT_NO_CURSOR |
2271 | void tst_QGraphicsView::cursor2() |
2272 | { |
2273 | QGraphicsScene scene; |
2274 | QGraphicsItem *item = scene.addRect(rect: QRectF(-10, -10, 20, 20)); |
2275 | item->setCursor(Qt::IBeamCursor); |
2276 | item->setZValue(1); |
2277 | |
2278 | QGraphicsItem *item2 = scene.addRect(rect: QRectF(-20, -20, 40, 40)); |
2279 | item2->setZValue(0); |
2280 | |
2281 | QGraphicsView view(&scene); |
2282 | view.viewport()->setCursor(Qt::PointingHandCursor); |
2283 | view.setFixedSize(w: 400, h: 400); |
2284 | view.show(); |
2285 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2286 | |
2287 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: -30, ay: -30)); |
2288 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
2289 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: 0, ay: 0)); |
2290 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor); |
2291 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: -30, ay: -30)); |
2292 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
2293 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: 0, ay: 0)); |
2294 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor); |
2295 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: -15, ay: 0)); |
2296 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
2297 | |
2298 | view.setDragMode(QGraphicsView::ScrollHandDrag); |
2299 | |
2300 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: -30, ay: -30)); |
2301 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::OpenHandCursor); |
2302 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: 0, ay: 0)); |
2303 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor); |
2304 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: -15, ay: -15)); |
2305 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::OpenHandCursor); |
2306 | |
2307 | view.setDragMode(QGraphicsView::NoDrag); |
2308 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::ArrowCursor); |
2309 | view.viewport()->setCursor(Qt::PointingHandCursor); |
2310 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
2311 | |
2312 | item2->setCursor(Qt::SizeAllCursor); |
2313 | |
2314 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: -30, ay: -30)); |
2315 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
2316 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: -15, ay: -15)); |
2317 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::SizeAllCursor); |
2318 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: 0, ay: 0)); |
2319 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor); |
2320 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: -15, ay: -15)); |
2321 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::SizeAllCursor); |
2322 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: 0, ay: 0)); |
2323 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor); |
2324 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: -30, ay: -30)); |
2325 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
2326 | |
2327 | view.setDragMode(QGraphicsView::ScrollHandDrag); |
2328 | |
2329 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: -30, ay: -30)); |
2330 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::OpenHandCursor); |
2331 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: 0, ay: 0)); |
2332 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::IBeamCursor); |
2333 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: -15, ay: -15)); |
2334 | QTRY_COMPARE(view.viewport()->cursor().shape(), Qt::SizeAllCursor); |
2335 | } |
2336 | #endif |
2337 | |
2338 | void tst_QGraphicsView::transformationAnchor() |
2339 | { |
2340 | QGraphicsScene scene(-1000, -1000, 2000, 2000); |
2341 | scene.addRect(rect: QRectF(-50, -50, 100, 100), pen: QPen(Qt::black), brush: QBrush(Qt::blue)); |
2342 | |
2343 | QGraphicsView view(&scene); |
2344 | setFrameless(&view); |
2345 | |
2346 | for (int i = 0; i < 2; ++i) { |
2347 | view.resize(w: 100, h: 100); |
2348 | view.show(); |
2349 | |
2350 | if (i == 0) { |
2351 | QCOMPARE(view.transformationAnchor(), QGraphicsView::AnchorViewCenter); |
2352 | } else { |
2353 | view.setTransformationAnchor(QGraphicsView::NoAnchor); |
2354 | } |
2355 | view.centerOn(ax: 0, ay: 0); |
2356 | view.horizontalScrollBar()->setValue(100); |
2357 | QApplication::processEvents(); |
2358 | |
2359 | QPointF center = view.mapToScene(point: view.viewport()->rect().center()); |
2360 | |
2361 | view.scale(sx: 10, sy: 10); |
2362 | |
2363 | QPointF newCenter = view.mapToScene(point: view.viewport()->rect().center()); |
2364 | |
2365 | if (i == 0) { |
2366 | qreal slack = 3; |
2367 | QVERIFY(qAbs(newCenter.x() - center.x()) < slack); |
2368 | QVERIFY(qAbs(newCenter.y() - center.y()) < slack); |
2369 | } else { |
2370 | qreal slack = qreal(0.3); |
2371 | QVERIFY(qAbs(newCenter.x() - center.x() / 10) < slack); |
2372 | QVERIFY(qAbs(newCenter.y() - center.y() / 10) < slack); |
2373 | } |
2374 | } |
2375 | } |
2376 | |
2377 | void tst_QGraphicsView::resizeAnchor() |
2378 | { |
2379 | QGraphicsScene scene(-1000, -1000, 2000, 2000); |
2380 | scene.addRect(rect: QRectF(-50, -50, 100, 100), pen: QPen(Qt::black), brush: QBrush(Qt::blue)); |
2381 | |
2382 | QGraphicsView view(&scene); |
2383 | setFrameless(&view); |
2384 | |
2385 | for (int i = 0; i < 2; ++i) { |
2386 | view.resize(w: 100, h: 100); |
2387 | view.show(); |
2388 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2389 | QApplication::processEvents(); |
2390 | |
2391 | if (i == 0) { |
2392 | QCOMPARE(view.resizeAnchor(), QGraphicsView::NoAnchor); |
2393 | } else { |
2394 | view.setResizeAnchor(QGraphicsView::AnchorViewCenter); |
2395 | } |
2396 | view.centerOn(ax: 0, ay: 0); |
2397 | QTest::qWait(ms: 25); |
2398 | |
2399 | QPointF f = view.mapToScene(ax: 50, ay: 50); |
2400 | QPointF center = view.mapToScene(point: view.viewport()->rect().center()); |
2401 | |
2402 | QApplication::processEvents(); |
2403 | |
2404 | for (int size = 200; size <= 400; size += 25) { |
2405 | view.resize(w: size, h: size); |
2406 | if (i == 0) { |
2407 | QTRY_COMPARE(view.mapToScene(50, 50), f); |
2408 | QTRY_VERIFY(view.mapToScene(view.viewport()->rect().center()) != center); |
2409 | } else { |
2410 | QTRY_VERIFY(view.mapToScene(50, 50) != f); |
2411 | |
2412 | QPointF newCenter = view.mapToScene(point: view.viewport()->rect().center()); |
2413 | int slack = 3; |
2414 | QVERIFY(qAbs(newCenter.x() - center.x()) < slack); |
2415 | QVERIFY(qAbs(newCenter.y() - center.y()) < slack); |
2416 | } |
2417 | QApplication::processEvents(); |
2418 | } |
2419 | } |
2420 | } |
2421 | |
2422 | class CustomView : public QGraphicsView |
2423 | { |
2424 | Q_OBJECT |
2425 | public: |
2426 | CustomView(QGraphicsScene *s = 0) : QGraphicsView(s) {} |
2427 | CustomView(QGraphicsScene *s, QWidget *parent) |
2428 | : QGraphicsView(s, parent) {} |
2429 | QList<QRegion> lastUpdateRegions; |
2430 | bool painted; |
2431 | |
2432 | protected: |
2433 | void paintEvent(QPaintEvent *event) |
2434 | { |
2435 | lastUpdateRegions << event->region(); |
2436 | painted = true; |
2437 | QGraphicsView::paintEvent(event); |
2438 | } |
2439 | }; |
2440 | |
2441 | void tst_QGraphicsView::viewportUpdateMode() |
2442 | { |
2443 | QGraphicsScene scene(0, 0, 100, 100); |
2444 | scene.setBackgroundBrush(Qt::red); |
2445 | |
2446 | CustomView view; |
2447 | QScreen *screen = QGuiApplication::primaryScreen(); |
2448 | view.setFixedSize(QSize(500, 500).boundedTo(otherSize: screen->availableGeometry().size())); // 500 is too big for all common smartphones |
2449 | view.setScene(&scene); |
2450 | QCOMPARE(view.viewportUpdateMode(), QGraphicsView::MinimalViewportUpdate); |
2451 | |
2452 | // Show the view, and initialize our test. |
2453 | view.show(); |
2454 | qApp->setActiveWindow(&view); |
2455 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2456 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
2457 | QTRY_VERIFY(!view.lastUpdateRegions.isEmpty()); |
2458 | view.lastUpdateRegions.clear(); |
2459 | |
2460 | // Issue two scene updates. |
2461 | scene.update(rect: QRectF(0, 0, 10, 10)); |
2462 | scene.update(rect: QRectF(20, 0, 10, 10)); |
2463 | |
2464 | // The view gets two updates for the update scene updates. |
2465 | QTRY_VERIFY(!view.lastUpdateRegions.isEmpty()); |
2466 | #ifndef Q_OS_MAC //cocoa doesn't support drawing regions |
2467 | QCOMPARE(view.lastUpdateRegions.last().rectCount(), 2); |
2468 | QCOMPARE(view.lastUpdateRegions.last().begin()[0].size(), QSize(14, 14)); |
2469 | QCOMPARE(view.lastUpdateRegions.last().begin()[1].size(), QSize(14, 14)); |
2470 | #endif |
2471 | |
2472 | // Set full update mode. |
2473 | view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate); |
2474 | QCOMPARE(view.viewportUpdateMode(), QGraphicsView::FullViewportUpdate); |
2475 | view.lastUpdateRegions.clear(); |
2476 | |
2477 | // Issue two scene updates. |
2478 | scene.update(rect: QRectF(0, 0, 10, 10)); |
2479 | scene.update(rect: QRectF(20, 0, 10, 10)); |
2480 | qApp->processEvents(); |
2481 | qApp->processEvents(); |
2482 | |
2483 | // The view gets one full viewport update for the update scene updates. |
2484 | QCOMPARE(view.lastUpdateRegions.last().rectCount(), 1); |
2485 | QCOMPARE(view.lastUpdateRegions.last().begin()[0].size(), view.viewport()->size()); |
2486 | view.lastUpdateRegions.clear(); |
2487 | |
2488 | // Set smart update mode |
2489 | view.setViewportUpdateMode(QGraphicsView::SmartViewportUpdate); |
2490 | QCOMPARE(view.viewportUpdateMode(), QGraphicsView::SmartViewportUpdate); |
2491 | |
2492 | // Issue 100 mini-updates |
2493 | for (int i = 0; i < 10; ++i) { |
2494 | for (int j = 0; j < 10; ++j) { |
2495 | scene.update(rect: QRectF(i * 3, j * 3, 1, 1)); |
2496 | } |
2497 | } |
2498 | qApp->processEvents(); |
2499 | qApp->processEvents(); |
2500 | |
2501 | // The view gets one bounding rect update. |
2502 | QCOMPARE(view.lastUpdateRegions.last().rectCount(), 1); |
2503 | QCOMPARE(view.lastUpdateRegions.last().begin()[0].size(), QSize(32, 32)); |
2504 | |
2505 | // Set no update mode |
2506 | view.setViewportUpdateMode(QGraphicsView::NoViewportUpdate); |
2507 | QCOMPARE(view.viewportUpdateMode(), QGraphicsView::NoViewportUpdate); |
2508 | |
2509 | // Issue two scene updates. |
2510 | view.lastUpdateRegions.clear(); |
2511 | TestItem item; |
2512 | scene.addItem(item: &item); |
2513 | item.moveBy(dx: 10, dy: 10); |
2514 | scene.update(rect: QRectF(0, 0, 10, 10)); |
2515 | scene.update(rect: QRectF(20, 0, 10, 10)); |
2516 | qApp->processEvents(); |
2517 | qApp->processEvents(); |
2518 | |
2519 | // The view should not get any painting calls from the scene updates |
2520 | QCOMPARE(view.lastUpdateRegions.size(), 0); |
2521 | } |
2522 | |
2523 | void tst_QGraphicsView::viewportUpdateMode2() |
2524 | { |
2525 | QWidget toplevel; |
2526 | |
2527 | // Create a view with viewport rect equal to QRect(0, 0, 200, 200). |
2528 | QGraphicsScene dummyScene; |
2529 | CustomView view(0, &toplevel); |
2530 | view.painted = false; |
2531 | view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); |
2532 | view.setScene(&dummyScene); |
2533 | view.ensurePolished(); // make sure we get the right content margins |
2534 | const QMargins margins = view.contentsMargins(); |
2535 | view.resize(w: 200 + margins.left() + margins.right(), h: 200 + margins.top() + margins.bottom()); |
2536 | toplevel.show(); |
2537 | qApp->setActiveWindow(&toplevel); |
2538 | QVERIFY(QTest::qWaitForWindowExposed(&toplevel)); |
2539 | QVERIFY(QTest::qWaitForWindowActive(&toplevel)); |
2540 | QTRY_VERIFY(view.painted); |
2541 | const QRect viewportRect = view.viewport()->rect(); |
2542 | QCOMPARE(viewportRect, QRect(0, 0, 200, 200)); |
2543 | |
2544 | #if defined QT_BUILD_INTERNAL |
2545 | QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(widget: &view)); |
2546 | |
2547 | QRect boundingRect; |
2548 | const QRect rect1(0, 0, 10, 10); |
2549 | QVERIFY(viewPrivate->updateRect(rect1)); |
2550 | QVERIFY(!viewPrivate->fullUpdatePending); |
2551 | boundingRect |= rect1; |
2552 | QCOMPARE(viewPrivate->dirtyBoundingRect, boundingRect); |
2553 | |
2554 | const QRect rect2(50, 50, 10, 10); |
2555 | QVERIFY(viewPrivate->updateRect(rect2)); |
2556 | QVERIFY(!viewPrivate->fullUpdatePending); |
2557 | boundingRect |= rect2; |
2558 | QCOMPARE(viewPrivate->dirtyBoundingRect, boundingRect); |
2559 | |
2560 | const QRect rect3(190, 190, 10, 10); |
2561 | QVERIFY(viewPrivate->updateRect(rect3)); |
2562 | QVERIFY(viewPrivate->fullUpdatePending); |
2563 | boundingRect |= rect3; |
2564 | QCOMPARE(viewPrivate->dirtyBoundingRect, boundingRect); |
2565 | |
2566 | view.lastUpdateRegions.clear(); |
2567 | viewPrivate->processPendingUpdates(); |
2568 | QTRY_COMPARE(view.lastUpdateRegions.size(), 1); |
2569 | // Note that we adjust by 2 for antialiasing. |
2570 | QCOMPARE(view.lastUpdateRegions.at(0), QRegion(boundingRect.adjusted(-2, -2, 2, 2) & viewportRect)); |
2571 | #endif |
2572 | } |
2573 | |
2574 | #if QT_CONFIG(draganddrop) |
2575 | void tst_QGraphicsView::acceptDrops() |
2576 | { |
2577 | QGraphicsView view; |
2578 | |
2579 | // Excepted default behavior. |
2580 | QVERIFY(view.acceptDrops()); |
2581 | QVERIFY(view.viewport()->acceptDrops()); |
2582 | |
2583 | // Excepted behavior with no drops. |
2584 | view.setAcceptDrops(false); |
2585 | QVERIFY(!view.acceptDrops()); |
2586 | QVERIFY(!view.viewport()->acceptDrops()); |
2587 | |
2588 | // Setting a widget with drops on a QGraphicsView without drops. |
2589 | QWidget *widget = new QWidget; |
2590 | widget->setAcceptDrops(true); |
2591 | view.setViewport(widget); |
2592 | QVERIFY(!view.acceptDrops()); |
2593 | QVERIFY(!view.viewport()->acceptDrops()); |
2594 | |
2595 | // Switching the view to accept drops. |
2596 | view.setAcceptDrops(true); |
2597 | QVERIFY(view.acceptDrops()); |
2598 | QVERIFY(view.viewport()->acceptDrops()); |
2599 | |
2600 | // Setting a widget with no drops on a QGraphicsView with drops. |
2601 | widget = new QWidget; |
2602 | widget->setAcceptDrops(false); |
2603 | view.setViewport(widget); |
2604 | QVERIFY(view.viewport()->acceptDrops()); |
2605 | QVERIFY(view.acceptDrops()); |
2606 | |
2607 | // Switching the view to not accept drops. |
2608 | view.setAcceptDrops(false); |
2609 | QVERIFY(!view.viewport()->acceptDrops()); |
2610 | } |
2611 | #endif |
2612 | |
2613 | void tst_QGraphicsView::optimizationFlags() |
2614 | { |
2615 | QGraphicsView view; |
2616 | QVERIFY(!view.optimizationFlags()); |
2617 | |
2618 | view.setOptimizationFlag(flag: QGraphicsView::DontSavePainterState); |
2619 | QVERIFY(view.optimizationFlags() & QGraphicsView::DontSavePainterState); |
2620 | view.setOptimizationFlag(flag: QGraphicsView::DontSavePainterState, enabled: false); |
2621 | QVERIFY(!view.optimizationFlags()); |
2622 | |
2623 | view.setOptimizationFlag(flag: QGraphicsView::DontAdjustForAntialiasing); |
2624 | QVERIFY(view.optimizationFlags() & QGraphicsView::DontAdjustForAntialiasing); |
2625 | view.setOptimizationFlag(flag: QGraphicsView::DontAdjustForAntialiasing, enabled: false); |
2626 | QVERIFY(!view.optimizationFlags()); |
2627 | |
2628 | view.setOptimizationFlags(QGraphicsView::DontAdjustForAntialiasing); |
2629 | QCOMPARE(view.optimizationFlags(), QGraphicsView::OptimizationFlags(QGraphicsView::DontAdjustForAntialiasing)); |
2630 | } |
2631 | |
2632 | class MessUpPainterItem : public QGraphicsRectItem |
2633 | { |
2634 | public: |
2635 | using QGraphicsRectItem::QGraphicsRectItem; |
2636 | bool dirtyPainter = false; |
2637 | bool receivedPaintEvent = false; |
2638 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *w) |
2639 | { |
2640 | receivedPaintEvent = true; |
2641 | dirtyPainter = (painter->pen().color() != w->palette().color(cr: w->foregroundRole())); |
2642 | painter->setPen(Qt::red); |
2643 | } |
2644 | }; |
2645 | |
2646 | class MyGraphicsView : public QGraphicsView |
2647 | { |
2648 | public: |
2649 | MyGraphicsView(QGraphicsScene * scene) : QGraphicsView(scene) |
2650 | { } |
2651 | |
2652 | void drawBackground(QPainter * painter, const QRectF & rect) { |
2653 | painter->setCompositionMode(QPainter::CompositionMode_Source); |
2654 | painter->drawRect(rect); |
2655 | } |
2656 | |
2657 | void drawItems (QPainter * painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[]) { |
2658 | if (!(optimizationFlags() & QGraphicsView::DontSavePainterState)) |
2659 | QCOMPARE(painter->compositionMode(),QPainter::CompositionMode_SourceOver); |
2660 | else |
2661 | QCOMPARE(painter->compositionMode(),QPainter::CompositionMode_Source); |
2662 | QGraphicsView::drawItems(painter,numItems,items,options); |
2663 | } |
2664 | }; |
2665 | |
2666 | void tst_QGraphicsView::optimizationFlags_dontSavePainterState() |
2667 | { |
2668 | MessUpPainterItem *parent = new MessUpPainterItem(QRectF(0, 0, 100, 100)); |
2669 | MessUpPainterItem *child = new MessUpPainterItem(QRectF(0, 0, 100, 100)); |
2670 | child->setParentItem(parent); |
2671 | |
2672 | QGraphicsScene scene; |
2673 | scene.addItem(item: parent); |
2674 | |
2675 | QGraphicsView view(&scene); |
2676 | view.show(); |
2677 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2678 | parent->receivedPaintEvent = false; |
2679 | child->receivedPaintEvent = false; |
2680 | view.viewport()->update(); |
2681 | |
2682 | QTRY_VERIFY(parent->receivedPaintEvent); |
2683 | QTRY_VERIFY(child->receivedPaintEvent); |
2684 | QVERIFY(!parent->dirtyPainter); |
2685 | QVERIFY(!child->dirtyPainter); |
2686 | |
2687 | view.setOptimizationFlags(QGraphicsView::DontSavePainterState); |
2688 | parent->receivedPaintEvent = false; |
2689 | child->receivedPaintEvent = false; |
2690 | view.viewport()->update(); |
2691 | |
2692 | QTRY_VERIFY(parent->receivedPaintEvent); |
2693 | QTRY_VERIFY(child->receivedPaintEvent); |
2694 | QVERIFY(!parent->dirtyPainter); |
2695 | QVERIFY(child->dirtyPainter); |
2696 | |
2697 | MyGraphicsView painter(&scene); |
2698 | painter.show(); |
2699 | QVERIFY(QTest::qWaitForWindowExposed(&painter)); |
2700 | |
2701 | MyGraphicsView painter2(&scene); |
2702 | painter2.setOptimizationFlag(flag: QGraphicsView::DontSavePainterState,enabled: true); |
2703 | painter2.show(); |
2704 | QVERIFY(QTest::qWaitForWindowExposed(&painter2)); |
2705 | } |
2706 | |
2707 | void tst_QGraphicsView::optimizationFlags_dontSavePainterState2_data() |
2708 | { |
2709 | QTest::addColumn<bool>(name: "savePainter" ); |
2710 | QTest::addColumn<bool>(name: "indirectPainting" ); |
2711 | QTest::newRow(dataTag: "With painter state protection, without indirect painting" ) << true << false; |
2712 | QTest::newRow(dataTag: "Without painter state protection, without indirect painting" ) << false << false; |
2713 | QTest::newRow(dataTag: "With painter state protectionm, with indirect painting" ) << true << true; |
2714 | QTest::newRow(dataTag: "Without painter state protection, with indirect painting" ) << false << true; |
2715 | } |
2716 | |
2717 | void tst_QGraphicsView::optimizationFlags_dontSavePainterState2() |
2718 | { |
2719 | QFETCH(bool, savePainter); |
2720 | QFETCH(bool, indirectPainting); |
2721 | |
2722 | class MyScene : public QGraphicsScene |
2723 | { |
2724 | public: |
2725 | void drawBackground(QPainter *p, const QRectF &) |
2726 | { transformInDrawBackground = p->worldTransform(); opacityInDrawBackground = p->opacity(); } |
2727 | |
2728 | void drawForeground(QPainter *p, const QRectF &) |
2729 | { transformInDrawForeground = p->worldTransform(); opacityInDrawForeground = p->opacity(); } |
2730 | |
2731 | QTransform transformInDrawBackground; |
2732 | QTransform transformInDrawForeground; |
2733 | qreal opacityInDrawBackground; |
2734 | qreal opacityInDrawForeground; |
2735 | }; |
2736 | |
2737 | MyScene scene; |
2738 | // Add transformed dummy items to make sure the painter's worldTransform() is changed in drawItems. |
2739 | QGraphicsRectItem *rectA = scene.addRect(x: 0, y: 0, w: 20, h: 20); |
2740 | QGraphicsRectItem *rectB = scene.addRect(x: 50, y: 50, w: 20, h: 20); |
2741 | |
2742 | rectA->setTransform(matrix: QTransform::fromScale(dx: 2, dy: 2)); |
2743 | rectA->setPen(QPen(Qt::black, 0)); |
2744 | rectB->setTransform(matrix: QTransform::fromTranslate(dx: 200, dy: 200)); |
2745 | rectB->setPen(QPen(Qt::black, 0)); |
2746 | |
2747 | foreach (QGraphicsItem *item, scene.items()) |
2748 | item->setOpacity(0.6); |
2749 | |
2750 | CustomView view(&scene); |
2751 | if (!savePainter) |
2752 | view.setOptimizationFlag(flag: QGraphicsView::DontSavePainterState); |
2753 | view.setOptimizationFlag(flag: QGraphicsView::IndirectPainting, enabled: indirectPainting); |
2754 | view.rotate(angle: 45); |
2755 | view.scale(sx: 1.5, sy: 1.5); |
2756 | view.show(); |
2757 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2758 | |
2759 | // Make sure the view is repainted; otherwise the tests below will fail. |
2760 | view.viewport()->update(); |
2761 | QTRY_VERIFY(view.painted); |
2762 | |
2763 | // Make sure the painter's world transform is preserved after drawItems. |
2764 | QTransform expectedTransform = view.viewportTransform(); |
2765 | QVERIFY(!expectedTransform.isIdentity()); |
2766 | QCOMPARE(scene.transformInDrawForeground, expectedTransform); |
2767 | QCOMPARE(scene.transformInDrawBackground, expectedTransform); |
2768 | |
2769 | qreal expectedOpacity = 1.0; |
2770 | QCOMPARE(scene.opacityInDrawBackground, expectedOpacity); |
2771 | QCOMPARE(scene.opacityInDrawForeground, expectedOpacity); |
2772 | |
2773 | // Trigger more painting, this time from QGraphicsScene::render. |
2774 | QImage image(scene.sceneRect().size().toSize(), QImage::Format_RGB32); |
2775 | QPainter painter(&image); |
2776 | scene.render(painter: &painter); |
2777 | painter.end(); |
2778 | |
2779 | expectedTransform = QTransform(); |
2780 | QCOMPARE(scene.transformInDrawForeground, expectedTransform); |
2781 | QCOMPARE(scene.transformInDrawBackground, expectedTransform); |
2782 | QCOMPARE(scene.opacityInDrawBackground, expectedOpacity); |
2783 | QCOMPARE(scene.opacityInDrawForeground, expectedOpacity); |
2784 | |
2785 | // Trigger more painting with another opacity on the painter. |
2786 | painter.begin(&image); |
2787 | painter.setOpacity(0.4); |
2788 | expectedOpacity = 0.4; |
2789 | scene.render(painter: &painter); |
2790 | painter.end(); |
2791 | |
2792 | QCOMPARE(scene.transformInDrawForeground, expectedTransform); |
2793 | QCOMPARE(scene.transformInDrawBackground, expectedTransform); |
2794 | QCOMPARE(scene.opacityInDrawBackground, expectedOpacity); |
2795 | QCOMPARE(scene.opacityInDrawForeground, expectedOpacity); |
2796 | } |
2797 | |
2798 | class LodItem : public QGraphicsRectItem |
2799 | { |
2800 | public: |
2801 | LodItem(const QRectF &rect) : QGraphicsRectItem(rect), lastLod(-42) |
2802 | { } |
2803 | |
2804 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *viewport) |
2805 | { |
2806 | lastLod = option->levelOfDetailFromTransform(worldTransform: painter->worldTransform()); |
2807 | QGraphicsRectItem::paint(painter, option, widget: viewport); |
2808 | } |
2809 | |
2810 | qreal lastLod; |
2811 | }; |
2812 | |
2813 | void tst_QGraphicsView::levelOfDetail_data() |
2814 | { |
2815 | QTest::addColumn<QTransform>(name: "transform" ); |
2816 | QTest::addColumn<qreal>(name: "lod" ); |
2817 | |
2818 | QTest::newRow(dataTag: "1:4, 1:4" ) << QTransform().scale(sx: 0.25, sy: 0.25) << qreal(0.25); |
2819 | QTest::newRow(dataTag: "1:2, 1:4" ) << QTransform().scale(sx: 0.5, sy: 0.25) << qreal(::sqrt(x: 0.125)); |
2820 | QTest::newRow(dataTag: "4:1, 1:2" ) << QTransform().scale(sx: 0.25, sy: 0.5) << qreal(::sqrt(x: 0.125)); |
2821 | |
2822 | QTest::newRow(dataTag: "1:2, 1:2" ) << QTransform().scale(sx: 0.5, sy: 0.5) << qreal(0.5); |
2823 | QTest::newRow(dataTag: "1:1, 1:2" ) << QTransform().scale(sx: 1, sy: 0.5) << qreal(::sqrt(x: 0.5)); |
2824 | QTest::newRow(dataTag: "2:1, 1:1" ) << QTransform().scale(sx: 0.5, sy: 1) << qreal(::sqrt(x: 0.5)); |
2825 | |
2826 | QTest::newRow(dataTag: "1:1, 1:1" ) << QTransform().scale(sx: 1, sy: 1) << qreal(1.0); |
2827 | QTest::newRow(dataTag: "2:1, 1:1" ) << QTransform().scale(sx: 2, sy: 1) << qreal(::sqrt(x: 2.0)); |
2828 | QTest::newRow(dataTag: "1:1, 2:1" ) << QTransform().scale(sx: 2, sy: 1) << qreal(::sqrt(x: 2.0)); |
2829 | QTest::newRow(dataTag: "2:1, 2:1" ) << QTransform().scale(sx: 2, sy: 2) << qreal(2.0); |
2830 | QTest::newRow(dataTag: "2:1, 4:1" ) << QTransform().scale(sx: 2, sy: 4) << qreal(::sqrt(x: 8.0)); |
2831 | QTest::newRow(dataTag: "4:1, 2:1" ) << QTransform().scale(sx: 4, sy: 2) << qreal(::sqrt(x: 8.0)); |
2832 | QTest::newRow(dataTag: "4:1, 4:1" ) << QTransform().scale(sx: 4, sy: 4) << qreal(4.0); |
2833 | } |
2834 | |
2835 | void tst_QGraphicsView::levelOfDetail() |
2836 | { |
2837 | QFETCH(QTransform, transform); |
2838 | QFETCH(qreal, lod); |
2839 | |
2840 | LodItem *item = new LodItem(QRectF(0, 0, 100, 100)); |
2841 | |
2842 | QGraphicsScene scene; |
2843 | scene.addItem(item); |
2844 | |
2845 | QGraphicsView view(&scene); |
2846 | view.show(); |
2847 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2848 | |
2849 | QTRY_COMPARE(item->lastLod, qreal(1)); |
2850 | |
2851 | view.setTransform(matrix: transform); |
2852 | |
2853 | QTRY_COMPARE(item->lastLod, lod); |
2854 | } |
2855 | |
2856 | // Moved to tst_qgraphicsview_2.cpp |
2857 | extern void _scrollBarRanges_data(); |
2858 | |
2859 | void tst_QGraphicsView::scrollBarRanges_data() |
2860 | { |
2861 | _scrollBarRanges_data(); |
2862 | } |
2863 | |
2864 | // Simulates motif scrollbar for range tests |
2865 | class FauxMotifStyle : public QCommonStyle { |
2866 | public: |
2867 | int styleHint(StyleHint hint, const QStyleOption *option, |
2868 | const QWidget *widget, QStyleHintReturn *returnData) const { |
2869 | if (hint == QStyle::SH_ScrollView_FrameOnlyAroundContents) |
2870 | return true; |
2871 | return QCommonStyle::styleHint(sh: hint, opt: option, w: widget, shret: returnData); |
2872 | } |
2873 | |
2874 | int pixelMetric(PixelMetric m, const QStyleOption *opt, const QWidget *widget) const { |
2875 | if (m == QStyle::PM_ScrollView_ScrollBarSpacing) |
2876 | return 4; |
2877 | return QCommonStyle::pixelMetric(m, opt, widget); |
2878 | } |
2879 | }; |
2880 | |
2881 | void tst_QGraphicsView::scrollBarRanges() |
2882 | { |
2883 | QFETCH(QByteArray, style); |
2884 | QFETCH(QSize, viewportSize); |
2885 | QFETCH(QRectF, sceneRect); |
2886 | QFETCH(ScrollBarCount, sceneRectOffsetFactors); |
2887 | QFETCH(QTransform, transform); |
2888 | QFETCH(Qt::ScrollBarPolicy, hbarpolicy); |
2889 | QFETCH(Qt::ScrollBarPolicy, vbarpolicy); |
2890 | QFETCH(ExpectedValueDescription, hmin); |
2891 | QFETCH(ExpectedValueDescription, hmax); |
2892 | QFETCH(ExpectedValueDescription, vmin); |
2893 | QFETCH(ExpectedValueDescription, vmax); |
2894 | QFETCH(bool, useStyledPanel); |
2895 | |
2896 | if (useStyledPanel && style == "macintosh" && platformName == QStringLiteral("cocoa" )) |
2897 | QSKIP("Insignificant on OSX" ); |
2898 | |
2899 | QScopedPointer<QStyle> stylePtr; |
2900 | |
2901 | QGraphicsScene scene; |
2902 | QGraphicsView view(&scene); |
2903 | view.setRenderHint(hint: QPainter::Antialiasing); |
2904 | view.setTransform(matrix: transform); |
2905 | view.setFrameStyle(useStyledPanel ? QFrame::StyledPanel : QFrame::NoFrame); |
2906 | |
2907 | if (style == "motif" ) |
2908 | stylePtr.reset(other: new FauxMotifStyle); |
2909 | else |
2910 | stylePtr.reset(other: QStyleFactory::create(QLatin1String(style))); |
2911 | view.setStyle(stylePtr.data()); |
2912 | view.setStyleSheet(" " ); // enables style propagation ;-) |
2913 | |
2914 | int adjust = 0; |
2915 | if (useStyledPanel) |
2916 | adjust = view.style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth) * 2; |
2917 | view.resize(viewportSize + QSize(adjust, adjust)); |
2918 | |
2919 | view.setHorizontalScrollBarPolicy(hbarpolicy); |
2920 | view.setVerticalScrollBarPolicy(vbarpolicy); |
2921 | |
2922 | view.showNormal(); |
2923 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2924 | |
2925 | const int offset = view.style()->pixelMetric(metric: QStyle::PM_ScrollBarExtent, option: 0, widget: 0); |
2926 | |
2927 | QRectF actualSceneRect; |
2928 | actualSceneRect.setLeft(sceneRect.left() + sceneRectOffsetFactors.left * offset); |
2929 | actualSceneRect.setWidth(sceneRect.width() + sceneRectOffsetFactors.right * offset); |
2930 | actualSceneRect.setTop(sceneRect.top() + sceneRectOffsetFactors.top * offset); |
2931 | actualSceneRect.setHeight(sceneRect.height() + sceneRectOffsetFactors.bottom * offset); |
2932 | scene.setSceneRect(actualSceneRect); |
2933 | scene.addRect(rect: actualSceneRect, pen: QPen(Qt::blue), brush: QBrush(QColor(Qt::green))); |
2934 | |
2935 | int expectedHmin = hmin.value + hmin.scrollBarExtentsToAdd * offset; |
2936 | int expectedVmin = vmin.value + vmin.scrollBarExtentsToAdd * offset; |
2937 | int expectedHmax = hmax.value + hmax.scrollBarExtentsToAdd * offset; |
2938 | int expectedVmax = vmax.value + vmax.scrollBarExtentsToAdd* offset; |
2939 | if (useStyledPanel && view.style()->styleHint(stylehint: QStyle::SH_ScrollView_FrameOnlyAroundContents)) { |
2940 | int spacing = view.style()->pixelMetric(metric: QStyle::PM_ScrollView_ScrollBarSpacing); |
2941 | expectedHmin += hmin.spacingsToAdd * spacing; |
2942 | expectedVmin += vmin.spacingsToAdd * spacing; |
2943 | expectedHmax += hmax.spacingsToAdd * spacing; |
2944 | expectedVmax += vmax.spacingsToAdd * spacing; |
2945 | } |
2946 | QCOMPARE(view.horizontalScrollBar()->minimum(), expectedHmin); |
2947 | QCOMPARE(view.verticalScrollBar()->minimum(), expectedVmin); |
2948 | QCOMPARE(view.horizontalScrollBar()->maximum(), expectedHmax); |
2949 | QCOMPARE(view.verticalScrollBar()->maximum(), expectedVmax); |
2950 | } |
2951 | |
2952 | class TestView : public QGraphicsView |
2953 | { |
2954 | public: |
2955 | TestView(QGraphicsScene *scene) |
2956 | : QGraphicsView(scene), pressAccepted(false), doubleClickAccepted(false) |
2957 | { } |
2958 | |
2959 | bool pressAccepted; |
2960 | bool doubleClickAccepted; |
2961 | |
2962 | protected: |
2963 | void mousePressEvent(QMouseEvent *event) |
2964 | { |
2965 | QGraphicsView::mousePressEvent(event); |
2966 | pressAccepted = event->isAccepted(); |
2967 | } |
2968 | void mouseDoubleClickEvent(QMouseEvent *event) |
2969 | { |
2970 | QGraphicsView::mouseDoubleClickEvent(event); |
2971 | doubleClickAccepted = event->isAccepted(); |
2972 | } |
2973 | }; |
2974 | |
2975 | void tst_QGraphicsView::acceptMousePressEvent() |
2976 | { |
2977 | QGraphicsScene scene; |
2978 | |
2979 | TestView view(&scene); |
2980 | view.show(); |
2981 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
2982 | |
2983 | QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton); |
2984 | QVERIFY(!view.pressAccepted); |
2985 | |
2986 | QSignalSpy spy(&scene, &QGraphicsScene::changed); |
2987 | scene.addRect(x: 0, y: 0, w: 2000, h: 2000)->setFlag(flag: QGraphicsItem::ItemIsMovable); |
2988 | QVERIFY(spy.wait()); |
2989 | |
2990 | QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton); |
2991 | QVERIFY(view.pressAccepted); |
2992 | } |
2993 | |
2994 | void tst_QGraphicsView::acceptMouseDoubleClickEvent() |
2995 | { |
2996 | QGraphicsScene scene; |
2997 | |
2998 | TestView view(&scene); |
2999 | view.show(); |
3000 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
3001 | |
3002 | QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton); |
3003 | QVERIFY(!view.doubleClickAccepted); |
3004 | |
3005 | QSignalSpy spy(&scene, &QGraphicsScene::changed); |
3006 | scene.addRect(x: 0, y: 0, w: 2000, h: 2000)->setFlag(flag: QGraphicsItem::ItemIsMovable); |
3007 | QVERIFY(spy.wait()); |
3008 | |
3009 | QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton); |
3010 | QVERIFY(view.doubleClickAccepted); |
3011 | } |
3012 | |
3013 | class TestWidget : public QWidget |
3014 | { |
3015 | public: |
3016 | TestWidget() |
3017 | : QWidget(), pressForwarded(false), doubleClickForwarded(false) |
3018 | { } |
3019 | |
3020 | bool pressForwarded; |
3021 | bool doubleClickForwarded; |
3022 | |
3023 | protected: |
3024 | void mousePressEvent(QMouseEvent *event) |
3025 | { |
3026 | QWidget::mousePressEvent(event); |
3027 | pressForwarded = true; |
3028 | } |
3029 | void mouseDoubleClickEvent(QMouseEvent *event) |
3030 | { |
3031 | QWidget::mouseDoubleClickEvent(event); |
3032 | doubleClickForwarded = true; |
3033 | } |
3034 | }; |
3035 | |
3036 | void tst_QGraphicsView::forwardMousePress() |
3037 | { |
3038 | TestWidget widget; |
3039 | QGraphicsScene scene; |
3040 | QGraphicsView view(&scene); |
3041 | QHBoxLayout layout; |
3042 | widget.setLayout(&layout); |
3043 | layout.addWidget(&view); |
3044 | widget.show(); |
3045 | QVERIFY(QTest::qWaitForWindowExposed(&widget)); |
3046 | |
3047 | widget.pressForwarded = false; |
3048 | QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton); |
3049 | QVERIFY(widget.pressForwarded); |
3050 | |
3051 | scene.addRect(x: 0, y: 0, w: 2000, h: 2000); |
3052 | |
3053 | qApp->processEvents(); // ensure scene rect is updated |
3054 | |
3055 | widget.pressForwarded = false; |
3056 | QTest::mouseClick(widget: view.viewport(), button: Qt::LeftButton); |
3057 | QVERIFY(widget.pressForwarded); |
3058 | } |
3059 | |
3060 | void tst_QGraphicsView::forwardMouseDoubleClick() |
3061 | { |
3062 | TestWidget widget; |
3063 | QGraphicsScene scene; |
3064 | QGraphicsView view(&scene); |
3065 | QHBoxLayout layout; |
3066 | widget.setLayout(&layout); |
3067 | layout.addWidget(&view); |
3068 | widget.show(); |
3069 | QVERIFY(QTest::qWaitForWindowExposed(&widget)); |
3070 | |
3071 | widget.doubleClickForwarded = false; |
3072 | QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton); |
3073 | QVERIFY(widget.doubleClickForwarded); |
3074 | |
3075 | scene.addRect(x: 0, y: 0, w: 2000, h: 2000); |
3076 | |
3077 | qApp->processEvents(); // ensure scene rect is updated |
3078 | |
3079 | widget.doubleClickForwarded = false; |
3080 | QTest::mouseDClick(widget: view.viewport(), button: Qt::LeftButton); |
3081 | QVERIFY(widget.doubleClickForwarded); |
3082 | } |
3083 | |
3084 | void tst_QGraphicsView::replayMouseMove() |
3085 | { |
3086 | // An empty scene in a view. The view will send the events to the scene in |
3087 | // any case. Note that the view doesn't have to be shown - the mouse event |
3088 | // sending functions below send the events directly to the viewport. |
3089 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3090 | QGraphicsView view(&scene); |
3091 | |
3092 | EventSpy sceneSpy(&scene, QEvent::GraphicsSceneMouseMove); |
3093 | EventSpy viewSpy(view.viewport(), QEvent::MouseMove); |
3094 | |
3095 | sendMousePress(widget: view.viewport(), point: view.viewport()->rect().center()); |
3096 | |
3097 | // One mouse event should be translated into one scene event. |
3098 | for (int i = 0; i < 3; ++i) { |
3099 | sendMouseMove(widget: view.viewport(), point: view.viewport()->rect().center(), |
3100 | button: Qt::LeftButton, buttons: Qt::MouseButtons(Qt::LeftButton)); |
3101 | QCOMPARE(viewSpy.count(), i + 1); |
3102 | QCOMPARE(sceneSpy.count(), i + 1); |
3103 | } |
3104 | |
3105 | // When the view is transformed, the view should get no more events. But |
3106 | // the scene should get replays. |
3107 | for (int i = 0; i < 3; ++i) { |
3108 | view.rotate(angle: 10); |
3109 | QCOMPARE(viewSpy.count(), 3); |
3110 | QCOMPARE(sceneSpy.count(), 3 + i + 1); |
3111 | } |
3112 | |
3113 | // When the view is scrolled, the view should get no more events. But the |
3114 | // scene should get replays. |
3115 | for (int i = 0; i < 3; ++i) { |
3116 | view.horizontalScrollBar()->setValue((i + 1) * 10); |
3117 | QCOMPARE(viewSpy.count(), 3); |
3118 | QCOMPARE(sceneSpy.count(), 6 + i + 1); |
3119 | } |
3120 | } |
3121 | |
3122 | void tst_QGraphicsView::itemsUnderMouse() |
3123 | { |
3124 | QGraphicsScene scene; |
3125 | QGraphicsProxyWidget w; |
3126 | w.setWidget(new QPushButton("W" )); |
3127 | w.resize(w: 50,h: 50); |
3128 | QGraphicsProxyWidget w2(&w); |
3129 | w2.setWidget(new QPushButton("W2" )); |
3130 | w2.resize(w: 50,h: 50); |
3131 | QGraphicsProxyWidget w3(&w2); |
3132 | w3.setWidget(new QPushButton("W3" )); |
3133 | w3.resize(w: 50,h: 50); |
3134 | w.setZValue(150); |
3135 | w2.setZValue(50); |
3136 | w3.setZValue(0); |
3137 | scene.addItem(item: &w); |
3138 | |
3139 | QGraphicsView view(&scene); |
3140 | view.show(); |
3141 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
3142 | |
3143 | QCOMPARE(view.items(view.mapFromScene(w3.boundingRect().center())).first(), |
3144 | static_cast<QGraphicsItem *>(&w3)); |
3145 | w2.setFlag(flag: QGraphicsItem::ItemIgnoresTransformations, enabled: true); |
3146 | QCOMPARE(view.items(view.mapFromScene(w3.boundingRect().center())).first(), |
3147 | static_cast<QGraphicsItem *>(&w3)); |
3148 | } |
3149 | |
3150 | class QGraphicsTextItem_task172231 : public QGraphicsTextItem |
3151 | { |
3152 | public: |
3153 | QGraphicsTextItem_task172231(const QString & text, QGraphicsItem * parent = 0) |
3154 | : QGraphicsTextItem(text, parent) {} |
3155 | QRectF exposedRect; |
3156 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
3157 | { |
3158 | exposedRect = option->exposedRect; |
3159 | QGraphicsTextItem::paint(painter, option, widget); |
3160 | } |
3161 | }; |
3162 | |
3163 | void tst_QGraphicsView::task172231_untransformableItems() |
3164 | { |
3165 | // check fix in QGraphicsView::paintEvent() |
3166 | |
3167 | QGraphicsScene scene; |
3168 | |
3169 | QGraphicsTextItem_task172231 *text = |
3170 | new QGraphicsTextItem_task172231("abcdefghijklmnopqrstuvwxyz" ); |
3171 | text->setFlag(flag: QGraphicsItem::ItemIgnoresTransformations); |
3172 | scene.addItem(item: text); |
3173 | |
3174 | QGraphicsView view(&scene); |
3175 | |
3176 | view.scale(sx: 2, sy: 1); |
3177 | view.show(); |
3178 | QApplication::setActiveWindow(&view); |
3179 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
3180 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
3181 | QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); |
3182 | |
3183 | QRectF origExposedRect = text->exposedRect; |
3184 | |
3185 | view.resize(w: int(0.75 * view.width()), h: view.height()); |
3186 | qApp->processEvents(); |
3187 | |
3188 | QCOMPARE(text->exposedRect, origExposedRect); |
3189 | |
3190 | // notice that the fix also goes into QGraphicsView::render() |
3191 | // and QGraphicsScene::render(), but in duplicated code that |
3192 | // is pending a refactoring, so for now we omit autotesting |
3193 | // these functions separately |
3194 | } |
3195 | |
3196 | class MousePressReleaseScene : public QGraphicsScene |
3197 | { |
3198 | public: |
3199 | MousePressReleaseScene() |
3200 | : presses(0), releases(0) |
3201 | { } |
3202 | int presses; |
3203 | int releases; |
3204 | |
3205 | protected: |
3206 | void mousePressEvent(QGraphicsSceneMouseEvent *event) |
3207 | { ++presses; QGraphicsScene::mousePressEvent(event); } |
3208 | void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) |
3209 | { ++releases; QGraphicsScene::mouseReleaseEvent(event); } |
3210 | }; |
3211 | |
3212 | void tst_QGraphicsView::task180429_mouseReleaseDragMode() |
3213 | { |
3214 | MousePressReleaseScene scene; |
3215 | |
3216 | QGraphicsView view(&scene); |
3217 | view.show(); |
3218 | |
3219 | sendMousePress(widget: view.viewport(), point: view.viewport()->rect().center()); |
3220 | QCOMPARE(scene.presses, 1); |
3221 | QCOMPARE(scene.releases, 0); |
3222 | sendMouseRelease(widget: view.viewport(), point: view.viewport()->rect().center()); |
3223 | QCOMPARE(scene.presses, 1); |
3224 | QCOMPARE(scene.releases, 1); |
3225 | |
3226 | view.setDragMode(QGraphicsView::RubberBandDrag); |
3227 | sendMousePress(widget: view.viewport(), point: view.viewport()->rect().center()); |
3228 | QCOMPARE(scene.presses, 2); |
3229 | QCOMPARE(scene.releases, 1); |
3230 | sendMouseRelease(widget: view.viewport(), point: view.viewport()->rect().center()); |
3231 | QCOMPARE(scene.presses, 2); |
3232 | QCOMPARE(scene.releases, 2); |
3233 | } |
3234 | |
3235 | void tst_QGraphicsView::task187791_setSceneCausesUpdate() |
3236 | { |
3237 | QGraphicsScene scene(0, 0, 200, 200); |
3238 | QGraphicsView view(&scene); |
3239 | view.show(); |
3240 | qApp->setActiveWindow(&view); |
3241 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
3242 | |
3243 | EventSpy updateSpy(view.viewport(), QEvent::Paint); |
3244 | QCOMPARE(updateSpy.count(), 0); |
3245 | |
3246 | view.setScene(0); |
3247 | QApplication::processEvents(); |
3248 | QTRY_COMPARE(updateSpy.count(), 1); |
3249 | view.setScene(&scene); |
3250 | QApplication::processEvents(); |
3251 | QTRY_COMPARE(updateSpy.count(), 2); |
3252 | } |
3253 | |
3254 | class MouseMoveCounter : public QGraphicsView |
3255 | { |
3256 | public: |
3257 | MouseMoveCounter() : mouseMoves(0) |
3258 | { } |
3259 | int mouseMoves; |
3260 | protected: |
3261 | void mouseMoveEvent(QMouseEvent *event) |
3262 | { |
3263 | ++mouseMoves; |
3264 | QGraphicsView::mouseMoveEvent(event); |
3265 | foreach (QGraphicsItem *item, scene()->items()) { |
3266 | scene()->removeItem(item); |
3267 | delete item; |
3268 | } |
3269 | scene()->addRect(x: 0, y: 0, w: 50, h: 50); |
3270 | scene()->addRect(x: 0, y: 0, w: 100, h: 100); |
3271 | } |
3272 | }; |
3273 | |
3274 | void tst_QGraphicsView::task186827_deleteReplayedItem() |
3275 | { |
3276 | // make sure the mouse is not over the window, causing spontaneous mouse moves |
3277 | QCursor::setPos(x: 1, y: 1); |
3278 | |
3279 | QGraphicsScene scene; |
3280 | scene.addRect(x: 0, y: 0, w: 50, h: 50); |
3281 | scene.addRect(x: 0, y: 0, w: 100, h: 100); |
3282 | |
3283 | MouseMoveCounter view; |
3284 | view.setScene(&scene); |
3285 | view.show(); |
3286 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
3287 | view.viewport()->setMouseTracking(true); |
3288 | |
3289 | QCOMPARE(view.mouseMoves, 0); |
3290 | { |
3291 | QMouseEvent event(QEvent::MouseMove, view.mapFromScene(ax: 25, ay: 25), Qt::NoButton, {}, {}); |
3292 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
3293 | } |
3294 | QCOMPARE(view.mouseMoves, 1); |
3295 | QTest::qWait(ms: 25); |
3296 | QTRY_COMPARE(view.mouseMoves, 1); |
3297 | QTest::qWait(ms: 25); |
3298 | { |
3299 | QMouseEvent event(QEvent::MouseMove, view.mapFromScene(ax: 25, ay: 25), Qt::NoButton, {}, {}); |
3300 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
3301 | } |
3302 | QCOMPARE(view.mouseMoves, 2); |
3303 | QTest::qWait(ms: 15); |
3304 | } |
3305 | |
3306 | void tst_QGraphicsView::task207546_focusCrash() |
3307 | { |
3308 | if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::WindowActivation)) |
3309 | QSKIP("Window activation is not supported" ); |
3310 | |
3311 | class _Widget : public QWidget |
3312 | { |
3313 | public: |
3314 | bool focusNextPrevChild(bool next) { return QWidget::focusNextPrevChild(next); } |
3315 | } widget; |
3316 | |
3317 | widget.setLayout(new QVBoxLayout()); |
3318 | QGraphicsView *gr1 = new QGraphicsView(&widget); |
3319 | QGraphicsView *gr2 = new QGraphicsView(&widget); |
3320 | widget.layout()->addWidget(w: gr1); |
3321 | widget.layout()->addWidget(w: gr2); |
3322 | widget.show(); |
3323 | widget.activateWindow(); |
3324 | QApplication::setActiveWindow(&widget); |
3325 | QVERIFY(QTest::qWaitForWindowActive(&widget)); |
3326 | QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&widget)); |
3327 | widget.focusNextPrevChild(next: true); |
3328 | QCOMPARE(static_cast<QWidget *>(gr2), widget.focusWidget()); |
3329 | } |
3330 | |
3331 | void tst_QGraphicsView::task210599_unsetDragWhileDragging() |
3332 | { |
3333 | QGraphicsScene scene(0, 0, 400, 400); |
3334 | QGraphicsView view(&scene); |
3335 | view.setGeometry(ax: 0, ay: 0, aw: 200, ah: 200); |
3336 | view.show(); |
3337 | |
3338 | QPoint origPos = QPoint(100, 100); |
3339 | QPoint step1Pos = QPoint(100, 110); |
3340 | QPoint step2Pos = QPoint(100, 120); |
3341 | |
3342 | // Enable and do a drag |
3343 | { |
3344 | view.setDragMode(QGraphicsView::ScrollHandDrag); |
3345 | QMouseEvent press(QEvent::MouseButtonPress, origPos, Qt::LeftButton, {}, {}); |
3346 | QMouseEvent move(QEvent::MouseMove, step1Pos, Qt::LeftButton, {}, {}); |
3347 | QApplication::sendEvent(receiver: view.viewport(), event: &press); |
3348 | QApplication::sendEvent(receiver: view.viewport(), event: &move); |
3349 | } |
3350 | |
3351 | // unset drag and release mouse, inverse order |
3352 | { |
3353 | view.setDragMode(QGraphicsView::NoDrag); |
3354 | QMouseEvent release(QEvent::MouseButtonRelease, step1Pos, Qt::LeftButton, {}, {}); |
3355 | QApplication::sendEvent(receiver: view.viewport(), event: &release); |
3356 | } |
3357 | |
3358 | QPoint basePos = view.mapFromScene(ax: 0, ay: 0); |
3359 | |
3360 | // reset drag, and move mouse without holding button down. |
3361 | { |
3362 | view.setDragMode(QGraphicsView::ScrollHandDrag); |
3363 | QMouseEvent move(QEvent::MouseMove, step2Pos, Qt::LeftButton, {}, {}); |
3364 | QApplication::sendEvent(receiver: view.viewport(), event: &move); |
3365 | } |
3366 | |
3367 | // Check that no draggin has occurred... |
3368 | QCOMPARE(basePos, view.mapFromScene(0, 0)); |
3369 | } |
3370 | |
3371 | class ChangedListener : public QObject |
3372 | { |
3373 | Q_OBJECT |
3374 | public: |
3375 | QList<QList<QRectF> > changes; |
3376 | |
3377 | public slots: |
3378 | void changed(const QList<QRectF> &dirty) |
3379 | { |
3380 | changes << dirty; |
3381 | } |
3382 | }; |
3383 | |
3384 | void tst_QGraphicsView::task239729_noViewUpdate_data() |
3385 | { |
3386 | QTest::addColumn<bool>(name: "a" ); |
3387 | |
3388 | QTest::newRow(dataTag: "a" ) << false; |
3389 | QTest::newRow(dataTag: "b" ) << true; |
3390 | } |
3391 | |
3392 | void tst_QGraphicsView::task239729_noViewUpdate() |
3393 | { |
3394 | QFETCH(bool, a); |
3395 | // The scene's changed signal is connected to something that isn't a view. |
3396 | QGraphicsScene scene; |
3397 | ChangedListener cl; |
3398 | QGraphicsView *view = 0; |
3399 | |
3400 | if (a) { |
3401 | view = new QGraphicsView(&scene); |
3402 | connect(sender: &scene, SIGNAL(changed(QList<QRectF>)), receiver: &cl, SLOT(changed(QList<QRectF>))); |
3403 | } else { |
3404 | connect(sender: &scene, SIGNAL(changed(QList<QRectF>)), receiver: &cl, SLOT(changed(QList<QRectF>))); |
3405 | view = new QGraphicsView(&scene); |
3406 | } |
3407 | |
3408 | EventSpy spy(view->viewport(), QEvent::Paint); |
3409 | QCOMPARE(spy.count(), 0); |
3410 | |
3411 | view->show(); |
3412 | qApp->setActiveWindow(view); |
3413 | QVERIFY(QTest::qWaitForWindowActive(view)); |
3414 | |
3415 | QTRY_VERIFY(spy.count() >= 1); |
3416 | spy.reset(); |
3417 | scene.update(); |
3418 | QApplication::processEvents(); |
3419 | QTRY_COMPARE(spy.count(), 1); |
3420 | |
3421 | delete view; |
3422 | } |
3423 | |
3424 | void tst_QGraphicsView::task239047_fitInViewSmallViewport() |
3425 | { |
3426 | // Ensure that with a small viewport, fitInView doesn't mirror the |
3427 | // scene. |
3428 | QWidget widget; |
3429 | setFrameless(&widget); |
3430 | QGraphicsScene scene; |
3431 | QGraphicsView *view = new QGraphicsView(&scene, &widget); |
3432 | view->resize(w: 3, h: 3); |
3433 | QCOMPARE(view->size(), QSize(3, 3)); |
3434 | widget.show(); |
3435 | view->fitInView(ax: 0, ay: 0, w: 100, h: 100); |
3436 | QPointF topLeft = view->mapToScene(ax: 0, ay: 0); |
3437 | QPointF bottomRight = view->mapToScene(ax: 100, ay: 100); |
3438 | QVERIFY(bottomRight.x() > topLeft.x()); |
3439 | QVERIFY(bottomRight.y() > topLeft.y()); |
3440 | |
3441 | view->fitInView(ax: 0, ay: 0, w: 0, h: 100); |
3442 | |
3443 | // Don't crash |
3444 | view->scale(sx: 0, sy: 0); |
3445 | view->fitInView(ax: 0, ay: 0, w: 100, h: 100); |
3446 | } |
3447 | |
3448 | void tst_QGraphicsView::task245469_itemsAtPointWithClip() |
3449 | { |
3450 | QGraphicsScene scene; |
3451 | QGraphicsItem *parent = scene.addRect(x: 0, y: 0, w: 100, h: 100); |
3452 | QGraphicsItem *child = new QGraphicsRectItem(40, 40, 20, 20, parent); |
3453 | parent->setFlag(flag: QGraphicsItem::ItemClipsChildrenToShape); |
3454 | |
3455 | QGraphicsView view(&scene); |
3456 | view.resize(w: 150,h: 150); |
3457 | view.rotate(angle: 90); |
3458 | view.show(); |
3459 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
3460 | |
3461 | QList<QGraphicsItem *> itemsAtCenter = view.items(pos: view.viewport()->rect().center()); |
3462 | QCOMPARE(itemsAtCenter, (QList<QGraphicsItem *>() << child << parent)); |
3463 | |
3464 | QPolygonF p = view.mapToScene(rect: QRect(view.viewport()->rect().center(), QSize(1, 1))); |
3465 | QList<QGraphicsItem *> itemsAtCenter2 = scene.items(polygon: p); |
3466 | QCOMPARE(itemsAtCenter2, itemsAtCenter); |
3467 | } |
3468 | |
3469 | static QGraphicsView *createSimpleViewAndScene() |
3470 | { |
3471 | QGraphicsView *view = new QGraphicsView; |
3472 | QGraphicsScene *scene = new QGraphicsScene(view); |
3473 | view->setScene(scene); |
3474 | |
3475 | view->setBackgroundBrush(Qt::blue); |
3476 | |
3477 | QGraphicsRectItem *rect = scene->addRect(x: 0, y: 0, w: 10, h: 10); |
3478 | rect->setBrush(Qt::red); |
3479 | rect->setPen(Qt::NoPen); |
3480 | return view; |
3481 | } |
3482 | |
3483 | class SpyItem : public QGraphicsRectItem |
3484 | { |
3485 | public: |
3486 | SpyItem() |
3487 | : QGraphicsRectItem(QRectF(0, 0, 100, 100)) |
3488 | { |
3489 | } |
3490 | |
3491 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) |
3492 | { |
3493 | transform = painter->transform(); |
3494 | } |
3495 | |
3496 | QTransform transform; |
3497 | }; |
3498 | |
3499 | void tst_QGraphicsView::embeddedViews() |
3500 | { |
3501 | QGraphicsView *v1 = createSimpleViewAndScene(); |
3502 | QGraphicsView *v2 = createSimpleViewAndScene(); |
3503 | |
3504 | QGraphicsProxyWidget *proxy = v1->scene()->addWidget(widget: v2); |
3505 | |
3506 | SpyItem *item = new SpyItem; |
3507 | v2->scene()->addItem(item); |
3508 | |
3509 | proxy->setTransform(matrix: QTransform::fromTranslate(dx: 5, dy: 5), combine: true); |
3510 | |
3511 | QImage actual(64, 64, QImage::Format_ARGB32_Premultiplied); |
3512 | actual.fill(pixel: 0); |
3513 | v1->QWidget::render(target: &actual); |
3514 | QTransform a = item->transform; |
3515 | |
3516 | v2->QWidget::render(target: &actual); |
3517 | QTransform b = item->transform; |
3518 | |
3519 | QCOMPARE(a, b); |
3520 | delete v1; |
3521 | } |
3522 | |
3523 | /*! |
3524 | Verify that a nested graphics view and embedded widgets receive window |
3525 | activation and focus correctly. |
3526 | |
3527 | See QTBUG-94091. |
3528 | */ |
3529 | void tst_QGraphicsView::embeddedViewsWithFocus() |
3530 | { |
3531 | class FocusWidget : public QWidget |
3532 | { |
3533 | public: |
3534 | FocusWidget() { setFocusPolicy(Qt::StrongFocus); } |
3535 | QSize sizeHint() const override { return QSize(100, 100); } |
3536 | |
3537 | int focusCount = 0; |
3538 | protected: |
3539 | void mousePressEvent(QMouseEvent *) override {} // accept event to avoid warning |
3540 | void focusInEvent(QFocusEvent *) override { ++focusCount; } |
3541 | void focusOutEvent(QFocusEvent *) override { --focusCount; } |
3542 | }; |
3543 | |
3544 | QGraphicsScene innerScene; |
3545 | FocusWidget *innerWidget = new FocusWidget; |
3546 | innerScene.addWidget(widget: innerWidget); |
3547 | QGraphicsView *innerView = new QGraphicsView(&innerScene); |
3548 | |
3549 | QGraphicsScene outerScene; |
3550 | FocusWidget *outerWidget = new FocusWidget; |
3551 | QGraphicsProxyWidget *outerProxy = outerScene.addWidget(widget: outerWidget); |
3552 | QGraphicsProxyWidget *nestedProxy = outerScene.addWidget(widget: innerView); |
3553 | outerProxy->setPos(ax: 0, ay: 0); |
3554 | nestedProxy->setPos(ax: 0, ay: outerWidget->sizeHint().height()); |
3555 | QGraphicsView outerView(&outerScene); |
3556 | outerView.show(); |
3557 | outerView.activateWindow(); |
3558 | QVERIFY(QTest::qWaitForWindowActive(&outerView)); |
3559 | const QPoint outerCenter(QPoint(innerWidget->sizeHint().width() / 2, |
3560 | innerWidget->sizeHint().height() / 2)); |
3561 | const QPoint innerCenter(outerCenter + QPoint(0, innerWidget->sizeHint().height())); |
3562 | QCOMPARE(outerView.itemAt(outerCenter), outerProxy); |
3563 | QCOMPARE(outerView.itemAt(innerCenter), nestedProxy); |
3564 | QVERIFY(outerScene.isActive()); |
3565 | QVERIFY(innerScene.isActive()); |
3566 | |
3567 | QCOMPARE(outerWidget->focusCount, 0); |
3568 | QCOMPARE(innerWidget->focusCount, 0); |
3569 | QTest::mouseClick(widget: outerView.viewport(), button: Qt::LeftButton, stateKey: {}, pos: outerCenter); |
3570 | QCOMPARE(outerWidget->focusCount, 1); |
3571 | QCOMPARE(innerWidget->focusCount, 0); |
3572 | QTest::mouseClick(widget: outerView.viewport(), button: Qt::LeftButton, stateKey: {}, pos: innerCenter); |
3573 | QCOMPARE(outerWidget->focusCount, 0); |
3574 | QCOMPARE(innerWidget->focusCount, 1); |
3575 | } |
3576 | |
3577 | void tst_QGraphicsView::scrollAfterResize_data() |
3578 | { |
3579 | QTest::addColumn<bool>(name: "reverse" ); |
3580 | QTest::addColumn<QTransform>(name: "x1" ); |
3581 | QTest::addColumn<QTransform>(name: "x2" ); |
3582 | QTest::addColumn<QTransform>(name: "x3" ); |
3583 | |
3584 | QStyle *style = QStyleFactory::create("windows" ); |
3585 | |
3586 | int frameWidth = style->pixelMetric(metric: QStyle::PM_DefaultFrameWidth); |
3587 | int extent = style->pixelMetric(metric: QStyle::PM_ScrollBarExtent); |
3588 | int inside = style->styleHint(stylehint: QStyle::SH_ScrollView_FrameOnlyAroundContents); |
3589 | int viewportWidth = 300; |
3590 | int scrollBarIndent = viewportWidth - extent - (inside ? 4 : 2)*frameWidth; |
3591 | |
3592 | QTest::newRow(dataTag: "normal" ) << false |
3593 | << QTransform() |
3594 | << QTransform() |
3595 | << QTransform().translate(dx: -10, dy: 0); |
3596 | QTest::newRow(dataTag: "reverse" ) << true |
3597 | << QTransform().translate(dx: scrollBarIndent, dy: 0) |
3598 | << QTransform().translate(dx: scrollBarIndent + 100, dy: 0) |
3599 | << QTransform().translate(dx: scrollBarIndent + 110, dy: 0); |
3600 | delete style; |
3601 | } |
3602 | |
3603 | void tst_QGraphicsView::scrollAfterResize() |
3604 | { |
3605 | QFETCH(bool, reverse); |
3606 | QFETCH(QTransform, x1); |
3607 | QFETCH(QTransform, x2); |
3608 | QFETCH(QTransform, x3); |
3609 | |
3610 | QStyle *style = QStyleFactory::create("windows" ); |
3611 | QWidget toplevel; |
3612 | |
3613 | QGraphicsView view(&toplevel); |
3614 | view.setStyle(style); |
3615 | if (reverse) |
3616 | view.setLayoutDirection(Qt::RightToLeft); |
3617 | |
3618 | view.setSceneRect(ax: -1000, ay: -1000, aw: 2000, ah: 2000); |
3619 | view.resize(w: 300, h: 300); |
3620 | toplevel.show(); |
3621 | QVERIFY(QTest::qWaitForWindowExposed(&toplevel)); |
3622 | view.horizontalScrollBar()->setValue(0); |
3623 | view.verticalScrollBar()->setValue(0); |
3624 | QCOMPARE(view.viewportTransform(), x1); |
3625 | view.resize(w: 400, h: 300); |
3626 | QCOMPARE(view.viewportTransform(), x2); |
3627 | view.horizontalScrollBar()->setValue(10); |
3628 | QCOMPARE(view.viewportTransform(), x3); |
3629 | delete style; |
3630 | } |
3631 | |
3632 | void tst_QGraphicsView::moveItemWhileScrolling_data() |
3633 | { |
3634 | QTest::addColumn<bool>(name: "adjustForAntialiasing" ); |
3635 | QTest::addColumn<bool>(name: "changedConnected" ); |
3636 | |
3637 | QTest::newRow(dataTag: "no adjust" ) << false << false; |
3638 | QTest::newRow(dataTag: "adjust" ) << true << false; |
3639 | QTest::newRow(dataTag: "no adjust changedConnected" ) << false << true; |
3640 | QTest::newRow(dataTag: "adjust changedConnected" ) << true << true; |
3641 | } |
3642 | |
3643 | void tst_QGraphicsView::moveItemWhileScrolling() |
3644 | { |
3645 | QFETCH(bool, adjustForAntialiasing); |
3646 | QFETCH(bool, changedConnected); |
3647 | |
3648 | class MoveItemScrollView : public QGraphicsView |
3649 | { |
3650 | public: |
3651 | MoveItemScrollView() |
3652 | { |
3653 | setWindowFlags(Qt::X11BypassWindowManagerHint); |
3654 | setScene(new QGraphicsScene(0, 0, 1000, 1000, this)); |
3655 | rect = scene()->addRect(x: 0, y: 0, w: 10, h: 10); |
3656 | rect->setPos(ax: 50, ay: 50); |
3657 | rect->setPen(QPen(Qt::black, 0)); |
3658 | painted = false; |
3659 | } |
3660 | QRegion lastPaintedRegion; |
3661 | QGraphicsRectItem *rect; |
3662 | bool painted; |
3663 | void waitForPaintEvent() |
3664 | { |
3665 | QTimer::singleShot(msec: 2000, receiver: &eventLoop, SLOT(quit())); |
3666 | eventLoop.exec(); |
3667 | } |
3668 | protected: |
3669 | QEventLoop eventLoop; |
3670 | void paintEvent(QPaintEvent *event) |
3671 | { |
3672 | painted = true; |
3673 | lastPaintedRegion = event->region(); |
3674 | QGraphicsView::paintEvent(event); |
3675 | if (eventLoop.isRunning()) |
3676 | eventLoop.quit(); |
3677 | } |
3678 | }; |
3679 | |
3680 | MoveItemScrollView view; |
3681 | view.setFrameStyle(0); |
3682 | view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
3683 | view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); |
3684 | view.setResizeAnchor(QGraphicsView::NoAnchor); |
3685 | view.setTransformationAnchor(QGraphicsView::NoAnchor); |
3686 | if (!adjustForAntialiasing) |
3687 | view.setOptimizationFlag(flag: QGraphicsView::DontAdjustForAntialiasing); |
3688 | view.resize(w: 200, h: 200); |
3689 | view.painted = false; |
3690 | view.showNormal(); |
3691 | if (changedConnected) |
3692 | QObject::connect(sender: view.scene(), SIGNAL(changed(QList<QRectF>)), receiver: this, SLOT(dummySlot())); |
3693 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
3694 | QApplication::processEvents(); |
3695 | QTRY_VERIFY(view.painted); |
3696 | view.painted = false; |
3697 | view.lastPaintedRegion = QRegion(); |
3698 | view.horizontalScrollBar()->setValue(view.horizontalScrollBar()->value() + 10); |
3699 | view.rect->moveBy(dx: 0, dy: 10); |
3700 | view.waitForPaintEvent(); |
3701 | QTRY_VERIFY(view.painted); |
3702 | |
3703 | QRegion expectedRegion; |
3704 | expectedRegion += QRect(0, 0, 200, 200); |
3705 | expectedRegion -= QRect(0, 0, 190, 200); |
3706 | int a = adjustForAntialiasing ? 2 : 1; |
3707 | expectedRegion += QRect(40, 50, 10, 10).adjusted(xp1: -a, yp1: -a, xp2: a, yp2: a); |
3708 | expectedRegion += QRect(40, 60, 10, 10).adjusted(xp1: -a, yp1: -a, xp2: a, yp2: a); |
3709 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
3710 | QSKIP("Wayland: This fails. Figure out why." ); |
3711 | COMPARE_REGIONS(view.lastPaintedRegion, expectedRegion); |
3712 | } |
3713 | |
3714 | void tst_QGraphicsView::centerOnDirtyItem() |
3715 | { |
3716 | QWidget toplevel; |
3717 | |
3718 | QGraphicsView view(&toplevel); |
3719 | toplevel.setWindowFlags(view.windowFlags() | Qt::WindowStaysOnTopHint); |
3720 | view.resize(w: 200, h: 200); |
3721 | |
3722 | QGraphicsScene *scene = new QGraphicsScene(&view); |
3723 | view.setScene(scene); |
3724 | view.setSceneRect(ax: -1000, ay: -1000, aw: 2000, ah: 2000); |
3725 | |
3726 | QGraphicsRectItem *item = new QGraphicsRectItem(0, 0, 10, 10); |
3727 | item->setBrush(Qt::red); |
3728 | scene->addItem(item); |
3729 | view.centerOn(item); |
3730 | |
3731 | toplevel.show(); |
3732 | QVERIFY(QTest::qWaitForWindowExposed(&toplevel)); |
3733 | |
3734 | QImage before(view.viewport()->size(), QImage::Format_ARGB32); |
3735 | view.viewport()->render(target: &before); |
3736 | |
3737 | item->setPos(ax: 20, ay: 0); |
3738 | view.centerOn(item); |
3739 | |
3740 | QImage after(view.viewport()->size(), QImage::Format_ARGB32); |
3741 | view.viewport()->render(target: &after); |
3742 | |
3743 | QCOMPARE(before, after); |
3744 | } |
3745 | |
3746 | void tst_QGraphicsView::mouseTracking() |
3747 | { |
3748 | // Mouse tracking should only be automatically enabled if items either accept hover events |
3749 | // or have a cursor set. We never disable mouse tracking if it is already enabled. |
3750 | |
3751 | { // Make sure mouse tracking is disabled by default. |
3752 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3753 | QGraphicsView view(&scene); |
3754 | QVERIFY(!view.viewport()->hasMouseTracking()); |
3755 | } |
3756 | |
3757 | { // Make sure we don't disable mouse tracking in setupViewport/setScene. |
3758 | QGraphicsView view; |
3759 | QWidget *viewport = new QWidget; |
3760 | viewport->setMouseTracking(true); |
3761 | view.setViewport(viewport); |
3762 | QVERIFY(viewport->hasMouseTracking()); |
3763 | |
3764 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3765 | view.setScene(&scene); |
3766 | QVERIFY(viewport->hasMouseTracking()); |
3767 | } |
3768 | |
3769 | // Make sure we enable mouse tracking when having items that accept hover events. |
3770 | { |
3771 | // Adding an item to the scene after the scene is set on the view. |
3772 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3773 | QGraphicsView view(&scene); |
3774 | |
3775 | QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); |
3776 | item->setAcceptHoverEvents(true); |
3777 | scene.addItem(item); |
3778 | QVERIFY(view.viewport()->hasMouseTracking()); |
3779 | } |
3780 | { |
3781 | // Adding an item to the scene before the scene is set on the view. |
3782 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3783 | QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); |
3784 | item->setAcceptHoverEvents(true); |
3785 | scene.addItem(item); |
3786 | |
3787 | QGraphicsView view(&scene); |
3788 | QVERIFY(view.viewport()->hasMouseTracking()); |
3789 | } |
3790 | { |
3791 | // QGraphicsWidget implicitly accepts hover if it has window decoration. |
3792 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3793 | QGraphicsView view(&scene); |
3794 | |
3795 | QGraphicsWidget *widget = new QGraphicsWidget; |
3796 | scene.addItem(item: widget); |
3797 | QVERIFY(!view.viewport()->hasMouseTracking()); |
3798 | // Enable window decoraton. |
3799 | widget->setWindowFlags(Qt::Window | Qt::WindowTitleHint); |
3800 | QVERIFY(view.viewport()->hasMouseTracking()); |
3801 | } |
3802 | |
3803 | // Make sure we enable mouse tracking when having items with a cursor set. |
3804 | { |
3805 | // Adding an item to the scene after the scene is set on the view. |
3806 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3807 | QGraphicsView view(&scene); |
3808 | |
3809 | QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); |
3810 | #ifndef QT_NO_CURSOR |
3811 | item->setCursor(Qt::CrossCursor); |
3812 | #endif |
3813 | scene.addItem(item); |
3814 | QVERIFY(view.viewport()->hasMouseTracking()); |
3815 | } |
3816 | { |
3817 | // Adding an item to the scene before the scene is set on the view. |
3818 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3819 | QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); |
3820 | #ifndef QT_NO_CURSOR |
3821 | item->setCursor(Qt::CrossCursor); |
3822 | #endif |
3823 | scene.addItem(item); |
3824 | |
3825 | QGraphicsView view(&scene); |
3826 | QVERIFY(view.viewport()->hasMouseTracking()); |
3827 | } |
3828 | |
3829 | // Make sure we propagate mouse tracking to all views. |
3830 | { |
3831 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3832 | QGraphicsView view1(&scene); |
3833 | QGraphicsView view2(&scene); |
3834 | QGraphicsView view3(&scene); |
3835 | |
3836 | QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); |
3837 | #ifndef QT_NO_CURSOR |
3838 | item->setCursor(Qt::CrossCursor); |
3839 | #endif |
3840 | scene.addItem(item); |
3841 | |
3842 | QVERIFY(view1.viewport()->hasMouseTracking()); |
3843 | QVERIFY(view2.viewport()->hasMouseTracking()); |
3844 | QVERIFY(view3.viewport()->hasMouseTracking()); |
3845 | } |
3846 | } |
3847 | |
3848 | void tst_QGraphicsView::mouseTracking2() |
3849 | { |
3850 | // Make sure mouse move events propagates to the scene when |
3851 | // mouse tracking is explicitly enabled on the view, |
3852 | // even when all items ignore hover events / use default cursor. |
3853 | |
3854 | QGraphicsScene scene; |
3855 | scene.addRect(x: 0, y: 0, w: 100, h: 100); |
3856 | |
3857 | QGraphicsView view(&scene); |
3858 | view.show(); |
3859 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
3860 | |
3861 | QVERIFY(!view.viewport()->hasMouseTracking()); |
3862 | view.viewport()->setMouseTracking(true); // Explicitly enable mouse tracking. |
3863 | QVERIFY(view.viewport()->hasMouseTracking()); |
3864 | |
3865 | EventSpy spy(&scene, QEvent::GraphicsSceneMouseMove); |
3866 | QCOMPARE(spy.count(), 0); |
3867 | QMouseEvent event(QEvent::MouseMove,view.viewport()->rect().center(), Qt::NoButton, |
3868 | Qt::MouseButtons(Qt::NoButton), {}); |
3869 | QApplication::sendEvent(receiver: view.viewport(), event: &event); |
3870 | QCOMPARE(spy.count(), 1); |
3871 | } |
3872 | |
3873 | void tst_QGraphicsView::mouseTracking3() |
3874 | { |
3875 | // Mouse tracking should be automatically enabled if AnchorUnderMouse is used for |
3876 | // view transform or resize. We never disable mouse tracking if it is already enabled. |
3877 | |
3878 | { // Make sure we enable mouse tracking when using AnchorUnderMouse for view transformation. |
3879 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3880 | QGraphicsView view(&scene); |
3881 | QVERIFY(!view.viewport()->hasMouseTracking()); |
3882 | |
3883 | view.setTransformationAnchor(QGraphicsView::AnchorUnderMouse); |
3884 | QVERIFY(view.viewport()->hasMouseTracking()); |
3885 | } |
3886 | |
3887 | { // Make sure we enable mouse tracking when using AnchorUnderMouse for view resizing. |
3888 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3889 | QGraphicsView view(&scene); |
3890 | QVERIFY(!view.viewport()->hasMouseTracking()); |
3891 | |
3892 | view.setResizeAnchor(QGraphicsView::AnchorUnderMouse); |
3893 | QVERIFY(view.viewport()->hasMouseTracking()); |
3894 | } |
3895 | |
3896 | { // Make sure we don't disable mouse tracking in setViewport/setScene (transformation anchor). |
3897 | QGraphicsView view; |
3898 | view.setTransformationAnchor(QGraphicsView::AnchorUnderMouse); |
3899 | QVERIFY(view.viewport()->hasMouseTracking()); |
3900 | |
3901 | QWidget *viewport = new QWidget; |
3902 | view.setViewport(viewport); |
3903 | QVERIFY(viewport->hasMouseTracking()); |
3904 | |
3905 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3906 | view.setScene(&scene); |
3907 | QVERIFY(viewport->hasMouseTracking()); |
3908 | } |
3909 | |
3910 | { // Make sure we don't disable mouse tracking in setViewport/setScene (resize anchor). |
3911 | QGraphicsView view; |
3912 | view.setResizeAnchor(QGraphicsView::AnchorUnderMouse); |
3913 | QVERIFY(view.viewport()->hasMouseTracking()); |
3914 | |
3915 | QWidget *viewport = new QWidget; |
3916 | view.setViewport(viewport); |
3917 | QVERIFY(viewport->hasMouseTracking()); |
3918 | |
3919 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3920 | view.setScene(&scene); |
3921 | QVERIFY(viewport->hasMouseTracking()); |
3922 | } |
3923 | |
3924 | // Make sure we don't disable mouse tracking when adding an item (transformation anchor). |
3925 | { // Adding an item to the scene before the scene is set on the view. |
3926 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3927 | QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); |
3928 | scene.addItem(item); |
3929 | |
3930 | QGraphicsView view; |
3931 | view.setTransformationAnchor(QGraphicsView::AnchorUnderMouse); |
3932 | view.setScene(&scene); |
3933 | QVERIFY(view.viewport()->hasMouseTracking()); |
3934 | } |
3935 | |
3936 | { // Adding an item to the scene after the scene is set on the view. |
3937 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3938 | QGraphicsView view(&scene); |
3939 | view.setTransformationAnchor(QGraphicsView::AnchorUnderMouse); |
3940 | |
3941 | QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); |
3942 | scene.addItem(item); |
3943 | QVERIFY(view.viewport()->hasMouseTracking()); |
3944 | } |
3945 | |
3946 | // Make sure we don't disable mouse tracking when adding an item (resize anchor). |
3947 | { // Adding an item to the scene before the scene is set on the view. |
3948 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3949 | QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); |
3950 | scene.addItem(item); |
3951 | |
3952 | QGraphicsView view; |
3953 | view.setResizeAnchor(QGraphicsView::AnchorUnderMouse); |
3954 | view.setScene(&scene); |
3955 | QVERIFY(view.viewport()->hasMouseTracking()); |
3956 | } |
3957 | |
3958 | { // Adding an item to the scene after the scene is set on the view. |
3959 | QGraphicsScene scene(-10000, -10000, 20000, 20000); |
3960 | QGraphicsView view(&scene); |
3961 | view.setResizeAnchor(QGraphicsView::AnchorUnderMouse); |
3962 | |
3963 | QGraphicsRectItem *item = new QGraphicsRectItem(10, 10, 10, 10); |
3964 | scene.addItem(item); |
3965 | QVERIFY(view.viewport()->hasMouseTracking()); |
3966 | } |
3967 | } |
3968 | |
3969 | class RenderTester : public QGraphicsRectItem |
3970 | { |
3971 | public: |
3972 | RenderTester(const QRectF &rect) |
3973 | : QGraphicsRectItem(rect), paints(0) |
3974 | { } |
3975 | |
3976 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, |
3977 | QWidget *widget) |
3978 | { |
3979 | QGraphicsRectItem::paint(painter, option, widget); |
3980 | ++paints; |
3981 | } |
3982 | |
3983 | int paints; |
3984 | }; |
3985 | |
3986 | void tst_QGraphicsView::render() |
3987 | { |
3988 | // ### This test can be much more thorough - see QGraphicsScene::render. |
3989 | QGraphicsScene scene; |
3990 | CustomView view(&scene); |
3991 | view.setFrameStyle(0); |
3992 | view.resize(w: 200, h: 200); |
3993 | view.painted = false; |
3994 | view.show(); |
3995 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
3996 | QApplication::processEvents(); |
3997 | QTRY_VERIFY(view.painted); |
3998 | |
3999 | RenderTester *r1 = new RenderTester(QRectF(0, 0, 50, 50)); |
4000 | RenderTester *r2 = new RenderTester(QRectF(50, 50, 50, 50)); |
4001 | RenderTester *r3 = new RenderTester(QRectF(0, 50, 50, 50)); |
4002 | RenderTester *r4 = new RenderTester(QRectF(50, 0, 50, 50)); |
4003 | scene.addItem(item: r1); |
4004 | scene.addItem(item: r2); |
4005 | scene.addItem(item: r3); |
4006 | scene.addItem(item: r4); |
4007 | |
4008 | qApp->processEvents(); |
4009 | |
4010 | QTRY_COMPARE(r1->paints, 1); |
4011 | QCOMPARE(r2->paints, 1); |
4012 | QCOMPARE(r3->paints, 1); |
4013 | QCOMPARE(r4->paints, 1); |
4014 | |
4015 | QPixmap pix(200, 200); |
4016 | pix.fill(fillColor: Qt::transparent); |
4017 | QPainter painter(&pix); |
4018 | view.render(painter: &painter); |
4019 | painter.end(); |
4020 | |
4021 | QCOMPARE(r1->paints, 2); |
4022 | QCOMPARE(r2->paints, 2); |
4023 | QCOMPARE(r3->paints, 2); |
4024 | QCOMPARE(r4->paints, 2); |
4025 | } |
4026 | |
4027 | void tst_QGraphicsView::exposeRegion() |
4028 | { |
4029 | RenderTester *item = new RenderTester(QRectF(0, 0, 20, 20)); |
4030 | QGraphicsScene scene; |
4031 | scene.addItem(item); |
4032 | |
4033 | item->paints = 0; |
4034 | CustomView view; |
4035 | view.setScene(&scene); |
4036 | view.show(); |
4037 | qApp->setActiveWindow(&view); |
4038 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4039 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
4040 | |
4041 | QTRY_VERIFY(item->paints > 0); |
4042 | |
4043 | item->paints = 0; |
4044 | view.lastUpdateRegions.clear(); |
4045 | |
4046 | // Update a small area in the viewport's topLeft() and bottomRight(). |
4047 | // (the boundingRect() of this area covers the entire viewport). |
4048 | QWidget *viewport = view.viewport(); |
4049 | QRegion expectedExposeRegion = QRect(0, 0, 5, 5); |
4050 | expectedExposeRegion += QRect(viewport->rect().bottomRight() - QPoint(5, 5), QSize(5, 5)); |
4051 | viewport->update(expectedExposeRegion); |
4052 | QApplication::processEvents(); |
4053 | |
4054 | // Make sure it triggers correct repaint on the view. |
4055 | QTRY_COMPARE(view.lastUpdateRegions.size(), 1); |
4056 | COMPARE_REGIONS(view.lastUpdateRegions.at(0), expectedExposeRegion); |
4057 | |
4058 | // Make sure the item didn't get any repaints. |
4059 | #ifndef Q_OS_MAC |
4060 | QCOMPARE(item->paints, 0); |
4061 | #endif |
4062 | } |
4063 | |
4064 | void tst_QGraphicsView::update_data() |
4065 | { |
4066 | // In view.viewport() coordinates. (viewport rect: QRect(0, 0, 200, 200)) |
4067 | QTest::addColumn<QRect>(name: "updateRect" ); |
4068 | QTest::newRow(dataTag: "empty" ) << QRect(); |
4069 | QTest::newRow(dataTag: "outside left" ) << QRect(-200, 0, 100, 100); |
4070 | QTest::newRow(dataTag: "outside right" ) << QRect(400, 0 ,100, 100); |
4071 | QTest::newRow(dataTag: "outside top" ) << QRect(0, -200, 100, 100); |
4072 | QTest::newRow(dataTag: "outside bottom" ) << QRect(0, 400, 100, 100); |
4073 | QTest::newRow(dataTag: "partially inside left" ) << QRect(-50, 0, 100, 100); |
4074 | QTest::newRow(dataTag: "partially inside right" ) << QRect(-150, 0, 100, 100); |
4075 | QTest::newRow(dataTag: "partially inside top" ) << QRect(0, -150, 100, 100); |
4076 | QTest::newRow(dataTag: "partially inside bottom" ) << QRect(0, 150, 100, 100); |
4077 | QTest::newRow(dataTag: "on topLeft edge" ) << QRect(-100, -100, 100, 100); |
4078 | QTest::newRow(dataTag: "on topRight edge" ) << QRect(200, -100, 100, 100); |
4079 | QTest::newRow(dataTag: "on bottomRight edge" ) << QRect(200, 200, 100, 100); |
4080 | QTest::newRow(dataTag: "on bottomLeft edge" ) << QRect(-200, 200, 100, 100); |
4081 | QTest::newRow(dataTag: "inside topLeft" ) << QRect(-99, -99, 100, 100); |
4082 | QTest::newRow(dataTag: "inside topRight" ) << QRect(199, -99, 100, 100); |
4083 | QTest::newRow(dataTag: "inside bottomRight" ) << QRect(199, 199, 100, 100); |
4084 | QTest::newRow(dataTag: "inside bottomLeft" ) << QRect(-199, 199, 100, 100); |
4085 | QTest::newRow(dataTag: "large1" ) << QRect(50, -100, 100, 400); |
4086 | QTest::newRow(dataTag: "large2" ) << QRect(-100, 50, 400, 100); |
4087 | QTest::newRow(dataTag: "large3" ) << QRect(-100, -100, 400, 400); |
4088 | QTest::newRow(dataTag: "viewport rect" ) << QRect(0, 0, 200, 200); |
4089 | } |
4090 | |
4091 | void tst_QGraphicsView::update() |
4092 | { |
4093 | QFETCH(QRect, updateRect); |
4094 | |
4095 | // some window manager resize the toplevel to max screen size |
4096 | // so we must make our view a child (no layout!) of a dummy toplevel |
4097 | // to ensure that it's really 200x200 pixels |
4098 | QWidget toplevel; |
4099 | |
4100 | // Create a view with viewport rect equal to QRect(0, 0, 200, 200). |
4101 | QGraphicsScene dummyScene; |
4102 | CustomView view(0, &toplevel); |
4103 | view.setScene(&dummyScene); |
4104 | view.ensurePolished(); // must ensure polished to get content margins right |
4105 | const QMargins margins = view.contentsMargins(); |
4106 | view.resize(w: 200 + margins.left() + margins.right(), h: 200 + margins.top() + margins.bottom()); |
4107 | toplevel.show(); |
4108 | QVERIFY(QTest::qWaitForWindowExposed(&toplevel)); |
4109 | |
4110 | |
4111 | QApplication::setActiveWindow(&toplevel); |
4112 | QApplication::processEvents(); |
4113 | QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&toplevel)); |
4114 | |
4115 | const QRect viewportRect = view.viewport()->rect(); |
4116 | QCOMPARE(viewportRect, QRect(0, 0, 200, 200)); |
4117 | |
4118 | #if defined QT_BUILD_INTERNAL |
4119 | const bool intersects = updateRect.intersects(r: viewportRect); |
4120 | QGraphicsViewPrivate *viewPrivate = static_cast<QGraphicsViewPrivate *>(qt_widget_private(widget: &view)); |
4121 | QTRY_COMPARE(viewPrivate->updateRect(updateRect), intersects); |
4122 | QApplication::processEvents(); |
4123 | |
4124 | view.lastUpdateRegions.clear(); |
4125 | viewPrivate->processPendingUpdates(); |
4126 | QVERIFY(viewPrivate->dirtyRegion.isEmpty()); |
4127 | QVERIFY(viewPrivate->dirtyBoundingRect.isEmpty()); |
4128 | QApplication::processEvents(); |
4129 | if (!intersects) { |
4130 | QTRY_VERIFY(view.lastUpdateRegions.isEmpty()); |
4131 | } else { |
4132 | QTRY_COMPARE(view.lastUpdateRegions.size(), 1); |
4133 | QTRY_COMPARE(view.lastUpdateRegions.at(0), QRegion(updateRect) & viewportRect); |
4134 | } |
4135 | QTRY_VERIFY(!viewPrivate->fullUpdatePending); |
4136 | #else |
4137 | Q_UNUSED(updateRect); |
4138 | #endif |
4139 | } |
4140 | |
4141 | void tst_QGraphicsView::update2_data() |
4142 | { |
4143 | QTest::addColumn<qreal>(name: "penWidth" ); |
4144 | QTest::addColumn<bool>(name: "antialiasing" ); |
4145 | QTest::addColumn<bool>(name: "changedConnected" ); |
4146 | |
4147 | // Anti-aliased. |
4148 | QTest::newRow(dataTag: "pen width: 0.0, antialiasing: true" ) << qreal(0.0) << true << false; |
4149 | QTest::newRow(dataTag: "pen width: 1.5, antialiasing: true" ) << qreal(1.5) << true << false; |
4150 | QTest::newRow(dataTag: "pen width: 2.0, antialiasing: true" ) << qreal(2.0) << true << false; |
4151 | QTest::newRow(dataTag: "pen width: 3.0, antialiasing: true" ) << qreal(3.0) << true << false; |
4152 | |
4153 | // Aliased. |
4154 | QTest::newRow(dataTag: "pen width: 0.0, antialiasing: false" ) << qreal(0.0) << false << false; |
4155 | QTest::newRow(dataTag: "pen width: 1.5, antialiasing: false" ) << qreal(1.5) << false << false; |
4156 | QTest::newRow(dataTag: "pen width: 2.0, antialiasing: false" ) << qreal(2.0) << false << false; |
4157 | QTest::newRow(dataTag: "pen width: 3.0, antialiasing: false" ) << qreal(3.0) << false << false; |
4158 | |
4159 | // changed() connected |
4160 | QTest::newRow(dataTag: "pen width: 0.0, antialiasing: false, changed" ) << qreal(0.0) << false << true; |
4161 | QTest::newRow(dataTag: "pen width: 1.5, antialiasing: true, changed" ) << qreal(1.5) << true << true; |
4162 | QTest::newRow(dataTag: "pen width: 2.0, antialiasing: false, changed" ) << qreal(2.0) << false << true; |
4163 | QTest::newRow(dataTag: "pen width: 3.0, antialiasing: true, changed" ) << qreal(3.0) << true << true; |
4164 | } |
4165 | |
4166 | void tst_QGraphicsView::update2() |
4167 | { |
4168 | QFETCH(qreal, penWidth); |
4169 | QFETCH(bool, antialiasing); |
4170 | QFETCH(bool, changedConnected); |
4171 | |
4172 | // Create a rect item. |
4173 | const QRectF rawItemRect(-50.4, -50.3, 100.2, 100.1); |
4174 | CountPaintItem *rect = new CountPaintItem(rawItemRect); |
4175 | QPen pen; |
4176 | pen.setWidthF(penWidth); |
4177 | rect->setPen(pen); |
4178 | |
4179 | // Add item to a scene. |
4180 | QGraphicsScene scene(-100, -100, 200, 200); |
4181 | if (changedConnected) |
4182 | QObject::connect(sender: &scene, SIGNAL(changed(QList<QRectF>)), receiver: this, SLOT(dummySlot())); |
4183 | |
4184 | scene.addItem(item: rect); |
4185 | |
4186 | // Create a view on the scene. |
4187 | CustomView view(&scene); |
4188 | view.setOptimizationFlag(flag: QGraphicsView::DontAdjustForAntialiasing, enabled: !antialiasing); |
4189 | view.setRenderHint(hint: QPainter::Antialiasing, enabled: antialiasing); |
4190 | view.setFrameStyle(0); |
4191 | view.resize(w: 200, h: 200); |
4192 | view.show(); |
4193 | qApp->setActiveWindow(&view); |
4194 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4195 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
4196 | QTRY_VERIFY(rect->numPaints > 0); |
4197 | |
4198 | // Calculate expected update region for the rect. |
4199 | QRectF expectedItemBoundingRect = rawItemRect; |
4200 | const qreal halfPenWidth = penWidth / qreal(2.0); |
4201 | expectedItemBoundingRect.adjust(xp1: -halfPenWidth, yp1: -halfPenWidth, xp2: halfPenWidth, yp2: halfPenWidth); |
4202 | QCOMPARE(rect->boundingRect(), expectedItemBoundingRect); |
4203 | |
4204 | QRect expectedItemDeviceBoundingRect = rect->deviceTransform(viewportTransform: view.viewportTransform()) |
4205 | .mapRect(expectedItemBoundingRect).toAlignedRect(); |
4206 | if (antialiasing) |
4207 | expectedItemDeviceBoundingRect.adjust(dx1: -2, dy1: -2, dx2: 2, dy2: 2); |
4208 | else |
4209 | expectedItemDeviceBoundingRect.adjust(dx1: -1, dy1: -1, dx2: 1, dy2: 1); |
4210 | const QRegion expectedUpdateRegion(expectedItemDeviceBoundingRect); |
4211 | |
4212 | // Reset. |
4213 | rect->numPaints = 0; |
4214 | view.lastUpdateRegions.clear(); |
4215 | view.painted = false; |
4216 | |
4217 | rect->update(); |
4218 | QTRY_VERIFY(view.painted); |
4219 | |
4220 | #ifndef Q_OS_MAC //cocoa doesn't support drawing regions |
4221 | QTRY_VERIFY(view.painted); |
4222 | QCOMPARE(view.lastUpdateRegions.size(), 1); |
4223 | QCOMPARE(view.lastUpdateRegions.at(0), expectedUpdateRegion); |
4224 | #endif |
4225 | } |
4226 | |
4227 | void tst_QGraphicsView::update_ancestorClipsChildrenToShape() |
4228 | { |
4229 | QGraphicsScene scene(-150, -150, 300, 300); |
4230 | |
4231 | /* |
4232 | Add three rects: |
4233 | |
4234 | +------------------+ |
4235 | | child | |
4236 | | +--------------+ | |
4237 | | | parent | | |
4238 | | | +-----------+ | |
4239 | | | |grandParent| | |
4240 | | | +-----------+ | |
4241 | | +--------------+ | |
4242 | +------------------+ |
4243 | |
4244 | ... where both the parent and the grand parent clips children to shape. |
4245 | */ |
4246 | QApplication::processEvents(); // Get rid of pending update. |
4247 | |
4248 | QGraphicsRectItem *grandParent = static_cast<QGraphicsRectItem *>(scene.addRect(x: 0, y: 0, w: 50, h: 50)); |
4249 | grandParent->setBrush(Qt::black); |
4250 | grandParent->setFlag(flag: QGraphicsItem::ItemClipsChildrenToShape); |
4251 | |
4252 | QGraphicsRectItem *parent = static_cast<QGraphicsRectItem *>(scene.addRect(x: -50, y: -50, w: 100, h: 100)); |
4253 | parent->setBrush(QColor(0, 0, 255, 125)); |
4254 | parent->setParentItem(grandParent); |
4255 | parent->setFlag(flag: QGraphicsItem::ItemClipsChildrenToShape); |
4256 | |
4257 | QGraphicsRectItem *child = static_cast<QGraphicsRectItem *>(scene.addRect(x: -100, y: -100, w: 200, h: 200)); |
4258 | child->setBrush(QColor(255, 0, 0, 125)); |
4259 | child->setParentItem(parent); |
4260 | |
4261 | CustomView view(&scene); |
4262 | view.show(); |
4263 | qApp->setActiveWindow(&view); |
4264 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4265 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
4266 | QTRY_VERIFY(view.painted); |
4267 | |
4268 | view.lastUpdateRegions.clear(); |
4269 | view.painted = false; |
4270 | |
4271 | // Call child->update() and make sure the updated area is within the ancestors' clip. |
4272 | QRectF expected = child->deviceTransform(viewportTransform: view.viewportTransform()).mapRect(child->boundingRect()); |
4273 | expected &= grandParent->deviceTransform(viewportTransform: view.viewportTransform()).mapRect(grandParent->boundingRect()); |
4274 | |
4275 | child->update(); |
4276 | QTRY_VERIFY(view.painted); |
4277 | |
4278 | #ifndef Q_OS_MAC //cocoa doesn't support drawing regions |
4279 | QTRY_VERIFY(view.painted); |
4280 | QCOMPARE(view.lastUpdateRegions.size(), 1); |
4281 | QCOMPARE(view.lastUpdateRegions.at(0), QRegion(expected.toAlignedRect())); |
4282 | #endif |
4283 | } |
4284 | |
4285 | void tst_QGraphicsView::update_ancestorClipsChildrenToShape2() |
4286 | { |
4287 | QGraphicsScene scene(-150, -150, 300, 300); |
4288 | |
4289 | /* |
4290 | Add two rects: |
4291 | |
4292 | +------------------+ |
4293 | | child | |
4294 | | +--------------+ | |
4295 | | | parent | | |
4296 | | | | | |
4297 | | | | | |
4298 | | | | | |
4299 | | +--------------+ | |
4300 | +------------------+ |
4301 | |
4302 | ... where the parent has no contents and clips the child to shape. |
4303 | */ |
4304 | QApplication::processEvents(); // Get rid of pending update. |
4305 | |
4306 | QGraphicsRectItem *parent = static_cast<QGraphicsRectItem *>(scene.addRect(x: -50, y: -50, w: 100, h: 100)); |
4307 | parent->setBrush(QColor(0, 0, 255, 125)); |
4308 | parent->setFlag(flag: QGraphicsItem::ItemClipsChildrenToShape); |
4309 | parent->setFlag(flag: QGraphicsItem::ItemHasNoContents); |
4310 | |
4311 | QGraphicsRectItem *child = static_cast<QGraphicsRectItem *>(scene.addRect(x: -100, y: -100, w: 200, h: 200)); |
4312 | child->setBrush(QColor(255, 0, 0, 125)); |
4313 | child->setParentItem(parent); |
4314 | |
4315 | CustomView view(&scene); |
4316 | view.show(); |
4317 | qApp->setActiveWindow(&view); |
4318 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4319 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
4320 | QTRY_VERIFY(view.painted); |
4321 | |
4322 | view.lastUpdateRegions.clear(); |
4323 | view.painted = false; |
4324 | |
4325 | // Call child->update() and make sure the updated area is within its parent's clip. |
4326 | QRectF expected = child->deviceTransform(viewportTransform: view.viewportTransform()).mapRect(child->boundingRect()); |
4327 | expected &= parent->deviceTransform(viewportTransform: view.viewportTransform()).mapRect(parent->boundingRect()); |
4328 | |
4329 | child->update(); |
4330 | QTRY_VERIFY(view.painted); |
4331 | |
4332 | #ifndef Q_OS_MAC //cocoa doesn't support drawing regions |
4333 | QTRY_VERIFY(view.painted); |
4334 | QCOMPARE(view.lastUpdateRegions.size(), 1); |
4335 | QCOMPARE(view.lastUpdateRegions.at(0), QRegion(expected.toAlignedRect())); |
4336 | #endif |
4337 | |
4338 | view.lastUpdateRegions.clear(); |
4339 | view.painted = false; |
4340 | |
4341 | // Invalidate the parent's geometry and trigger an update. |
4342 | // The update area should be clipped to the parent's bounding rect for 'normal' items, |
4343 | // but in this case the item has no contents (ItemHasNoContents) and its geometry |
4344 | // is invalidated, which means we cannot clip the child update. So, the expected |
4345 | // area is exactly the same as the child's bounding rect (adjusted for antialiasing). |
4346 | parent->setRect(parent->rect().adjusted(xp1: -10, yp1: -10, xp2: -10, yp2: -10)); |
4347 | expected = child->deviceTransform(viewportTransform: view.viewportTransform()).mapRect(child->boundingRect()); |
4348 | expected.adjust(xp1: -2, yp1: -2, xp2: 2, yp2: 2); // Antialiasing |
4349 | |
4350 | #ifndef Q_OS_MAC //cocoa doesn't support drawing regions |
4351 | QTRY_VERIFY(view.painted); |
4352 | QCOMPARE(view.lastUpdateRegions.size(), 1); |
4353 | QCOMPARE(view.lastUpdateRegions.at(0), QRegion(expected.toAlignedRect())); |
4354 | #endif |
4355 | } |
4356 | |
4357 | class FocusItem : public QGraphicsRectItem |
4358 | { |
4359 | public: |
4360 | FocusItem() : QGraphicsRectItem(0, 0, 20, 20) { |
4361 | m_viewHasIMEnabledInFocusInEvent = false; |
4362 | } |
4363 | |
4364 | void focusInEvent(QFocusEvent * /* event */) |
4365 | { |
4366 | QGraphicsView *view = scene()->views().first(); |
4367 | m_viewHasIMEnabledInFocusInEvent = view->testAttribute(attribute: Qt::WA_InputMethodEnabled); |
4368 | } |
4369 | |
4370 | bool m_viewHasIMEnabledInFocusInEvent; |
4371 | }; |
4372 | |
4373 | void tst_QGraphicsView::inputMethodSensitivity() |
4374 | { |
4375 | QGraphicsScene scene; |
4376 | QGraphicsView view(&scene); |
4377 | view.show(); |
4378 | QApplication::setActiveWindow(&view); |
4379 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4380 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
4381 | QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); |
4382 | |
4383 | FocusItem *item = new FocusItem; |
4384 | |
4385 | view.setAttribute(Qt::WA_InputMethodEnabled, on: true); |
4386 | |
4387 | scene.addItem(item); |
4388 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4389 | |
4390 | scene.removeItem(item); |
4391 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4392 | |
4393 | item->setFlag(flag: QGraphicsItem::ItemAcceptsInputMethod); |
4394 | scene.addItem(item); |
4395 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4396 | |
4397 | scene.removeItem(item); |
4398 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4399 | |
4400 | scene.addItem(item); |
4401 | scene.setFocusItem(item); |
4402 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4403 | |
4404 | scene.removeItem(item); |
4405 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4406 | |
4407 | item->setFlag(flag: QGraphicsItem::ItemIsFocusable); |
4408 | scene.addItem(item); |
4409 | scene.setFocusItem(item); |
4410 | QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item)); |
4411 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), true); |
4412 | QCOMPARE(item->m_viewHasIMEnabledInFocusInEvent, true); |
4413 | |
4414 | item->setFlag(flag: QGraphicsItem::ItemAcceptsInputMethod, enabled: false); |
4415 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4416 | |
4417 | item->setFlag(flag: QGraphicsItem::ItemAcceptsInputMethod, enabled: true); |
4418 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), true); |
4419 | |
4420 | // introduce another item that is focusable but does not accept input methods |
4421 | FocusItem *item2 = new FocusItem; |
4422 | item2->setFlag(flag: QGraphicsItem::ItemIsFocusable); |
4423 | scene.addItem(item: item2); |
4424 | scene.setFocusItem(item: item2); |
4425 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4426 | QCOMPARE(item2->m_viewHasIMEnabledInFocusInEvent, false); |
4427 | QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item2)); |
4428 | |
4429 | scene.setFocusItem(item); |
4430 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), true); |
4431 | QCOMPARE(item->m_viewHasIMEnabledInFocusInEvent, true); |
4432 | QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item)); |
4433 | |
4434 | view.setScene(0); |
4435 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4436 | QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item)); |
4437 | |
4438 | view.setScene(&scene); |
4439 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), true); |
4440 | QCOMPARE(item->m_viewHasIMEnabledInFocusInEvent, true); |
4441 | QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item)); |
4442 | |
4443 | scene.setFocusItem(item: item2); |
4444 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4445 | QCOMPARE(item2->m_viewHasIMEnabledInFocusInEvent, false); |
4446 | QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item2)); |
4447 | |
4448 | view.setScene(0); |
4449 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4450 | QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item2)); |
4451 | |
4452 | scene.setFocusItem(item); |
4453 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), false); |
4454 | QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item)); |
4455 | |
4456 | view.setScene(&scene); |
4457 | QCOMPARE(view.testAttribute(Qt::WA_InputMethodEnabled), true); |
4458 | QCOMPARE(item->m_viewHasIMEnabledInFocusInEvent, true); |
4459 | QCOMPARE(scene.focusItem(), static_cast<QGraphicsItem *>(item)); |
4460 | } |
4461 | |
4462 | void tst_QGraphicsView::inputContextReset() |
4463 | { |
4464 | if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::WindowActivation)) |
4465 | QSKIP("Window activation is not supported" ); |
4466 | |
4467 | PlatformInputContext inputContext; |
4468 | QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); |
4469 | inputMethodPrivate->testContext = &inputContext; |
4470 | |
4471 | QGraphicsScene scene; |
4472 | QGraphicsView view(&scene); |
4473 | QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled)); |
4474 | |
4475 | view.show(); |
4476 | QApplication::setActiveWindow(&view); |
4477 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4478 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
4479 | QCOMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view)); |
4480 | |
4481 | QGraphicsItem *item1 = new QGraphicsRectItem; |
4482 | item1->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod); |
4483 | |
4484 | inputContext.m_resetCallCount = 0; |
4485 | inputContext.m_commitCallCount = 0; |
4486 | scene.addItem(item: item1); |
4487 | QCOMPARE(inputContext.m_resetCallCount, 0); |
4488 | QCOMPARE(inputContext.m_commitCallCount, 0); |
4489 | |
4490 | scene.setFocusItem(item: item1); |
4491 | QCOMPARE(scene.focusItem(), (QGraphicsItem *)item1); |
4492 | QVERIFY(view.testAttribute(Qt::WA_InputMethodEnabled)); |
4493 | QCOMPARE(inputContext.m_resetCallCount, 0); |
4494 | QCOMPARE(inputContext.m_commitCallCount, 0); |
4495 | |
4496 | scene.setFocusItem(item: 0); |
4497 | // the input context is reset twice, once because an item has lost focus and again because |
4498 | // the Qt::WA_InputMethodEnabled flag is cleared because no item has focus. |
4499 | // QEXPECT_FAIL("", "QTBUG-22454", Abort); |
4500 | QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, 2); |
4501 | |
4502 | // introduce another item that is focusable but does not accept input methods |
4503 | QGraphicsItem *item2 = new QGraphicsRectItem; |
4504 | item2->setFlags(QGraphicsItem::ItemIsFocusable); |
4505 | scene.addItem(item: item2); |
4506 | |
4507 | inputContext.m_resetCallCount = 0; |
4508 | inputContext.m_commitCallCount = 0; |
4509 | scene.setFocusItem(item: item2); |
4510 | QCOMPARE(inputContext.m_resetCallCount, 0); |
4511 | QCOMPARE(inputContext.m_commitCallCount, 0); |
4512 | |
4513 | scene.setFocusItem(item: item1); |
4514 | QCOMPARE(inputContext.m_resetCallCount, 0); |
4515 | QCOMPARE(inputContext.m_commitCallCount, 0); |
4516 | |
4517 | // test changing between between items that accept input methods. |
4518 | item2->setFlags(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod); |
4519 | scene.setFocusItem(item: item2); |
4520 | QCOMPARE(inputContext.m_resetCallCount + inputContext.m_commitCallCount, 1); |
4521 | } |
4522 | |
4523 | void tst_QGraphicsView::indirectPainting() |
4524 | { |
4525 | class MyScene : public QGraphicsScene |
4526 | { public: |
4527 | MyScene() : QGraphicsScene(), drawCount(0) {} |
4528 | void drawItems(QPainter *, int, QGraphicsItem **, const QStyleOptionGraphicsItem *, QWidget *) |
4529 | { ++drawCount; } |
4530 | int drawCount; |
4531 | }; |
4532 | |
4533 | MyScene scene; |
4534 | QGraphicsItem *item = scene.addRect(x: 0, y: 0, w: 50, h: 50); |
4535 | |
4536 | QGraphicsView view(&scene); |
4537 | view.setOptimizationFlag(flag: QGraphicsView::IndirectPainting); |
4538 | view.show(); |
4539 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4540 | QTRY_VERIFY(scene.drawCount > 0); |
4541 | |
4542 | scene.drawCount = 0; |
4543 | item->setPos(ax: 20, ay: 20); |
4544 | QApplication::processEvents(); |
4545 | QTRY_VERIFY(scene.drawCount > 0); |
4546 | } |
4547 | |
4548 | void tst_QGraphicsView::compositionModeInDrawBackground() |
4549 | { |
4550 | class MyView : public QGraphicsView |
4551 | { public: |
4552 | MyView(QGraphicsScene *scene) : QGraphicsView(scene), |
4553 | painted(false), compositionMode(QPainter::CompositionMode_SourceOver) {} |
4554 | bool painted; |
4555 | QPainter::CompositionMode compositionMode; |
4556 | void drawBackground(QPainter *painter, const QRectF &) |
4557 | { |
4558 | compositionMode = painter->compositionMode(); |
4559 | painted = true; |
4560 | } |
4561 | }; |
4562 | |
4563 | QGraphicsScene dummy; |
4564 | MyView view(&dummy); |
4565 | view.show(); |
4566 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4567 | |
4568 | // Make sure the painter's composition mode is SourceOver in drawBackground. |
4569 | QTRY_VERIFY(view.painted); |
4570 | QCOMPARE(view.compositionMode, QPainter::CompositionMode_SourceOver); |
4571 | |
4572 | view.painted = false; |
4573 | view.setCacheMode(QGraphicsView::CacheBackground); |
4574 | view.viewport()->update(); |
4575 | |
4576 | // Make sure the painter's composition mode is SourceOver in drawBackground |
4577 | // with background cache enabled. |
4578 | QTRY_VERIFY(view.painted); |
4579 | QCOMPARE(view.compositionMode, QPainter::CompositionMode_SourceOver); |
4580 | } |
4581 | void tst_QGraphicsView::task253415_reconnectUpdateSceneOnSceneChanged() |
4582 | { |
4583 | QGraphicsView view; |
4584 | QGraphicsView dummyView; |
4585 | view.setWindowFlags(view.windowFlags() | Qt::WindowStaysOnTopHint); |
4586 | view.resize(w: 200, h: 200); |
4587 | |
4588 | QGraphicsScene scene1; |
4589 | QObject::connect(sender: &scene1, SIGNAL(changed(QList<QRectF>)), receiver: &dummyView, SLOT(updateScene(QList<QRectF>))); |
4590 | view.setScene(&scene1); |
4591 | |
4592 | QTest::qWait(ms: 12); |
4593 | |
4594 | QGraphicsScene scene2; |
4595 | QObject::connect(sender: &scene2, SIGNAL(changed(QList<QRectF>)), receiver: &dummyView, SLOT(updateScene(QList<QRectF>))); |
4596 | view.setScene(&scene2); |
4597 | |
4598 | QTest::qWait(ms: 12); |
4599 | |
4600 | bool wasConnected2 = QObject::disconnect(sender: &scene2, SIGNAL(changed(QList<QRectF>)), receiver: &view, member: 0); |
4601 | QVERIFY(wasConnected2); |
4602 | } |
4603 | |
4604 | void tst_QGraphicsView::task255529_transformationAnchorMouseAndViewportMargins() |
4605 | { |
4606 | QGraphicsScene scene(-100, -100, 200, 200); |
4607 | scene.addRect(rect: QRectF(-50, -50, 100, 100), pen: QPen(Qt::black), brush: QBrush(Qt::blue)); |
4608 | |
4609 | class VpGraphicsView: public QGraphicsView |
4610 | { |
4611 | public: |
4612 | VpGraphicsView(QGraphicsScene *scene, QWidget *parent=0) |
4613 | : QGraphicsView(scene, parent) |
4614 | { |
4615 | setViewportMargins(left: 8, top: 16, right: 12, bottom: 20); |
4616 | setTransformationAnchor(QGraphicsView::AnchorUnderMouse); |
4617 | setMouseTracking(true); |
4618 | } |
4619 | }; |
4620 | |
4621 | VpGraphicsView view(&scene); |
4622 | view.setWindowFlags(Qt::X11BypassWindowManagerHint); |
4623 | view.show(); |
4624 | qApp->setActiveWindow(&view); |
4625 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4626 | const bool isActiveWindow = QTest::qWaitForWindowActive(widget: &view); |
4627 | if (!isActiveWindow) |
4628 | QSKIP("Window activation failed, skipping test" , Abort); |
4629 | // This is highly unstable (observed to pass on Windows and some Linux configurations). |
4630 | #ifndef Q_OS_MAC |
4631 | for (int i = 0; i < 4; ++i) { |
4632 | QPoint mouseViewPos(20, 20); |
4633 | sendMouseMove(widget: view.viewport(), point: mouseViewPos); |
4634 | |
4635 | QPointF mouseScenePos = view.mapToScene(point: mouseViewPos); |
4636 | view.setTransform(matrix: QTransform().scale(sx: 5, sy: 5).rotate(a: 5, axis: Qt::ZAxis), combine: true); |
4637 | |
4638 | qreal slack = 1; |
4639 | |
4640 | QPointF newMouseScenePos = view.mapToScene(point: mouseViewPos); |
4641 | |
4642 | const qreal dx = qAbs(t: newMouseScenePos.x() - mouseScenePos.x()); |
4643 | const qreal dy = qAbs(t: newMouseScenePos.y() - mouseScenePos.y()); |
4644 | const QByteArray message = QString::fromLatin1(str: "QTBUG-22455, distance: dx=%1, dy=%2 slack=%3 (%4)." ). |
4645 | arg(a: dx).arg(a: dy).arg(a: slack).arg(qApp->style()->metaObject()->className()).toLocal8Bit(); |
4646 | if (i == 9 || (dx < slack && dy < slack)) { |
4647 | QVERIFY2(dx < slack && dy < slack, message.constData()); |
4648 | break; |
4649 | } |
4650 | |
4651 | QTest::qWait(ms: 100); |
4652 | } |
4653 | #endif |
4654 | } |
4655 | |
4656 | void tst_QGraphicsView::task259503_scrollingArtifacts() |
4657 | { |
4658 | QGraphicsScene scene(0, 0, 800, 600); |
4659 | |
4660 | QGraphicsRectItem card; |
4661 | card.setRect(ax: 0, ay: 0, w: 50, h: 50); |
4662 | card.setPen(QPen(Qt::darkRed)); |
4663 | card.setBrush(QBrush(Qt::cyan)); |
4664 | card.setZValue(2.0); |
4665 | card.setPos(ax: 300, ay: 300); |
4666 | scene.addItem(item: &card); |
4667 | |
4668 | class SAGraphicsView: public QGraphicsView |
4669 | { |
4670 | public: |
4671 | SAGraphicsView(QGraphicsScene *scene) |
4672 | : QGraphicsView(scene) |
4673 | , itSTimeToTest(false) |
4674 | { |
4675 | setViewportUpdateMode( QGraphicsView::MinimalViewportUpdate ); |
4676 | resize(QSize(640, 480)); |
4677 | } |
4678 | |
4679 | QRegion updateRegion; |
4680 | bool itSTimeToTest; |
4681 | |
4682 | void paintEvent(QPaintEvent *event) |
4683 | { |
4684 | QGraphicsView::paintEvent(event); |
4685 | |
4686 | if (itSTimeToTest) |
4687 | { |
4688 | QEXPECT_FAIL("" , "QTBUG-24296" , Continue); |
4689 | QCOMPARE(event->region(), updateRegion); |
4690 | } |
4691 | } |
4692 | }; |
4693 | |
4694 | SAGraphicsView view(&scene); |
4695 | view.show(); |
4696 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4697 | |
4698 | int hsbValue = view.horizontalScrollBar()->value(); |
4699 | view.horizontalScrollBar()->setValue(hsbValue / 2); |
4700 | QTest::qWait(ms: 10); |
4701 | view.horizontalScrollBar()->setValue(0); |
4702 | QTest::qWait(ms: 10); |
4703 | |
4704 | QRect itemDeviceBoundingRect = card.deviceTransform(viewportTransform: view.viewportTransform()).mapRect(card.boundingRect()).toRect(); |
4705 | itemDeviceBoundingRect.adjust(dx1: -2, dy1: -2, dx2: 2, dy2: 2); |
4706 | view.updateRegion = itemDeviceBoundingRect; |
4707 | view.updateRegion += itemDeviceBoundingRect.translated(dx: -100, dy: 0); |
4708 | view.itSTimeToTest = true; |
4709 | card.setPos(ax: 200, ay: 300); |
4710 | QTest::qWait(ms: 10); |
4711 | } |
4712 | |
4713 | void tst_QGraphicsView::QTBUG_4151_clipAndIgnore_data() |
4714 | { |
4715 | QTest::addColumn<bool>(name: "clip" ); |
4716 | QTest::addColumn<bool>(name: "ignoreTransformations" ); |
4717 | QTest::addColumn<int>(name: "numItems" ); |
4718 | |
4719 | QTest::newRow(dataTag: "none" ) << false << false << 3; |
4720 | QTest::newRow(dataTag: "clip" ) << true << false << 3; |
4721 | QTest::newRow(dataTag: "ignore" ) << false << true << 3; |
4722 | QTest::newRow(dataTag: "clip+ignore" ) << true << true << 3; |
4723 | } |
4724 | |
4725 | void tst_QGraphicsView::QTBUG_4151_clipAndIgnore() |
4726 | { |
4727 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
4728 | QSKIP("Wayland: This fails. Figure out why." ); |
4729 | |
4730 | QFETCH(bool, clip); |
4731 | QFETCH(bool, ignoreTransformations); |
4732 | QFETCH(int, numItems); |
4733 | |
4734 | QGraphicsScene scene; |
4735 | |
4736 | QGraphicsRectItem *parent = new QGraphicsRectItem(QRectF(0, 0, 50, 50), 0); |
4737 | QGraphicsRectItem *child = new QGraphicsRectItem(QRectF(-10, -10, 40, 40), parent); |
4738 | QGraphicsRectItem *ignore = new QGraphicsRectItem(QRectF(60, 60, 50, 50), 0); |
4739 | |
4740 | if (clip) |
4741 | parent->setFlags(QGraphicsItem::ItemClipsChildrenToShape); |
4742 | if (ignoreTransformations) |
4743 | ignore->setFlag(flag: QGraphicsItem::ItemIgnoresTransformations); |
4744 | |
4745 | parent->setBrush(Qt::red); |
4746 | child->setBrush(QColor(0, 0, 255, 128)); |
4747 | ignore->setBrush(Qt::green); |
4748 | |
4749 | scene.addItem(item: parent); |
4750 | scene.addItem(item: ignore); |
4751 | |
4752 | QGraphicsView view(&scene); |
4753 | setFrameless(&view); |
4754 | view.setFrameStyle(0); |
4755 | view.resize(w: 75, h: 75); |
4756 | view.show(); |
4757 | view.activateWindow(); |
4758 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4759 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
4760 | QCOMPARE(QApplication::activeWindow(), (QWidget *)&view); |
4761 | |
4762 | QCOMPARE(view.items(view.rect()).size(), numItems); |
4763 | } |
4764 | |
4765 | void tst_QGraphicsView::QTBUG_5859_exposedRect() |
4766 | { |
4767 | class CustomScene : public QGraphicsScene |
4768 | { |
4769 | public: |
4770 | CustomScene(const QRectF &rect) : QGraphicsScene(rect) { } |
4771 | void drawBackground(QPainter * /* painter */, const QRectF &rect) |
4772 | { lastBackgroundExposedRect = rect; } |
4773 | QRectF lastBackgroundExposedRect; |
4774 | }; |
4775 | |
4776 | class CustomRectItem : public QGraphicsRectItem |
4777 | { |
4778 | public: |
4779 | CustomRectItem(const QRectF &rect) : QGraphicsRectItem(rect) |
4780 | { setFlag(flag: QGraphicsItem::ItemUsesExtendedStyleOption); } |
4781 | void paint(QPainter * /* painter */, const QStyleOptionGraphicsItem *option, QWidget * /* widget */ = 0) |
4782 | { lastExposedRect = option->exposedRect; } |
4783 | QRectF lastExposedRect; |
4784 | }; |
4785 | |
4786 | CustomScene scene(QRectF(0,0,50,50)); |
4787 | |
4788 | CustomRectItem item(scene.sceneRect()); |
4789 | |
4790 | scene.addItem(item: &item); |
4791 | |
4792 | QGraphicsView view(&scene); |
4793 | view.scale(sx: 4.15, sy: 4.15); |
4794 | view.showNormal(); |
4795 | QApplication::setActiveWindow(&view); |
4796 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4797 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
4798 | |
4799 | view.viewport()->update(ax: 10,ay: 10,aw: 20,ah: 20); |
4800 | QTRY_COMPARE(item.lastExposedRect, scene.lastBackgroundExposedRect); |
4801 | } |
4802 | |
4803 | #ifndef QT_NO_CURSOR |
4804 | void tst_QGraphicsView::QTBUG_7438_cursor() |
4805 | { |
4806 | QGraphicsScene scene; |
4807 | QGraphicsItem *item = scene.addRect(rect: QRectF(-10, -10, 20, 20)); |
4808 | item->setFlag(flag: QGraphicsItem::ItemIsMovable); |
4809 | |
4810 | QGraphicsView view(&scene); |
4811 | view.setFixedSize(w: 400, h: 400); |
4812 | view.show(); |
4813 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4814 | |
4815 | QCOMPARE(view.viewport()->cursor().shape(), QCursor().shape()); |
4816 | view.viewport()->setCursor(Qt::PointingHandCursor); |
4817 | QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
4818 | sendMouseMove(widget: view.viewport(), point: view.mapFromScene(ax: 0, ay: 0)); |
4819 | QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
4820 | sendMousePress(widget: view.viewport(), point: view.mapFromScene(ax: 0, ay: 0)); |
4821 | QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
4822 | sendMouseRelease(widget: view.viewport(), point: view.mapFromScene(ax: 0, ay: 0)); |
4823 | QCOMPARE(view.viewport()->cursor().shape(), Qt::PointingHandCursor); |
4824 | } |
4825 | #endif |
4826 | |
4827 | class GraphicsItemWithHover : public QGraphicsRectItem |
4828 | { |
4829 | public: |
4830 | GraphicsItemWithHover() |
4831 | { |
4832 | setRect(ax: 0, ay: 0, w: 100, h: 100); |
4833 | setAcceptHoverEvents(true); |
4834 | } |
4835 | |
4836 | bool sceneEvent(QEvent *event) |
4837 | { |
4838 | if (!checkEvents) // ensures that we don't look at stray events before we are ready |
4839 | return QGraphicsRectItem::sceneEvent(event); |
4840 | |
4841 | if (event->type() == QEvent::GraphicsSceneHoverEnter) { |
4842 | receivedEnterEvent = true; |
4843 | enterWidget = static_cast<QGraphicsSceneHoverEvent *>(event)->widget(); |
4844 | } else if (event->type() == QEvent::GraphicsSceneHoverLeave) { |
4845 | receivedLeaveEvent = true; |
4846 | leaveWidget = static_cast<QGraphicsSceneHoverEvent *>(event)->widget(); |
4847 | } |
4848 | return QGraphicsRectItem::sceneEvent(event); |
4849 | } |
4850 | |
4851 | bool receivedEnterEvent = false; |
4852 | bool receivedLeaveEvent = false; |
4853 | QWidget *enterWidget = nullptr; |
4854 | QWidget *leaveWidget = nullptr; |
4855 | bool checkEvents = false; |
4856 | }; |
4857 | |
4858 | void tst_QGraphicsView::hoverLeave() |
4859 | { |
4860 | QGraphicsScene scene; |
4861 | QGraphicsView view(&scene); |
4862 | view.resize(w: 160, h: 160); |
4863 | GraphicsItemWithHover *item = new GraphicsItemWithHover; |
4864 | scene.addItem(item); |
4865 | |
4866 | view.showNormal(); |
4867 | qApp->setActiveWindow(&view); |
4868 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4869 | |
4870 | QWindow *viewWindow = view.window()->windowHandle(); |
4871 | QPoint posOutsideItem = view.mapFromScene(point: item->mapToScene(ax: 0, ay: 0)) - QPoint(5, 0); |
4872 | QPoint posOutsideItemGlobal = view.mapToGlobal(posOutsideItem); |
4873 | QPoint posOutsideItemInWindow = viewWindow->mapFromGlobal(pos: posOutsideItemGlobal); |
4874 | QTest::mouseMove(window: viewWindow, pos: posOutsideItemInWindow); |
4875 | |
4876 | item->checkEvents = true; |
4877 | QPoint posInItemGlobal = view.mapToGlobal(view.mapFromScene(point: item->mapToScene(ax: 10, ay: 10))); |
4878 | QTest::mouseMove(window: viewWindow, pos: viewWindow->mapFromGlobal(pos: posInItemGlobal)); |
4879 | QTRY_VERIFY(item->receivedEnterEvent); |
4880 | QCOMPARE(item->enterWidget, view.viewport()); |
4881 | |
4882 | QTest::mouseMove(window: viewWindow, pos: posOutsideItemInWindow); |
4883 | |
4884 | QTRY_VERIFY(item->receivedLeaveEvent); |
4885 | QCOMPARE(item->leaveWidget, view.viewport()); |
4886 | } |
4887 | |
4888 | class IMItem : public QGraphicsRectItem |
4889 | { |
4890 | public: |
4891 | IMItem(QGraphicsItem *parent = 0): |
4892 | QGraphicsRectItem(QRectF(0, 0, 20, 20), parent) |
4893 | { |
4894 | setFlag(flag: QGraphicsItem::ItemIsFocusable, enabled: true); |
4895 | setFlag(flag: QGraphicsItem::ItemAcceptsInputMethod, enabled: true); |
4896 | } |
4897 | |
4898 | QVariant inputMethodQuery(Qt::InputMethodQuery) const |
4899 | { |
4900 | return mf; |
4901 | } |
4902 | |
4903 | static QRectF mf; |
4904 | }; |
4905 | |
4906 | QRectF IMItem::mf(1.5, 1.6, 10, 10); |
4907 | |
4908 | void tst_QGraphicsView::QTBUG_16063_microFocusRect() |
4909 | { |
4910 | if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland" ), cs: Qt::CaseInsensitive)) |
4911 | QSKIP("Wayland: This fails. Figure out why." ); |
4912 | |
4913 | QGraphicsScene scene; |
4914 | IMItem *item = new IMItem(); |
4915 | scene.addItem(item); |
4916 | |
4917 | QGraphicsView view(&scene); |
4918 | setFrameless(&view); |
4919 | |
4920 | view.setFixedSize(w: 40, h: 40); |
4921 | view.show(); |
4922 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
4923 | QVERIFY(QTest::qWaitForWindowActive(&view)); |
4924 | |
4925 | scene.setFocusItem(item); |
4926 | view.setFocus(); |
4927 | QRectF mfv = view.inputMethodQuery(query: Qt::ImCursorRectangle).toRectF(); |
4928 | QCOMPARE(mfv, IMItem::mf.translated(-view.mapToScene(view.sceneRect().toRect()).boundingRect().topLeft())); |
4929 | } |
4930 | |
4931 | QTEST_MAIN(tst_QGraphicsView) |
4932 | #include "tst_qgraphicsview.moc" |
4933 | |