Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qgraphicsscene.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
168#include "qgraphicsscene.h"
169
170#include "qgraphicsitem.h"
171#include "qgraphicsitem_p.h"
172#include "qgraphicslayout.h"
173#include "qgraphicsscene_p.h"
174#include "qgraphicssceneevent.h"
175#include "qgraphicsview.h"
176#include "qgraphicsview_p.h"
177#include "qgraphicswidget.h"
178#include "qgraphicswidget_p.h"
182
183#include <QtCore/qdebug.h>
184#include <QtCore/qlist.h>
185#include <QtCore/qmath.h>
186#include <QtCore/qrect.h>
187#include <QtCore/qset.h>
188#include <QtCore/qstack.h>
189#include <QtCore/qtimer.h>
190#include <QtCore/qvarlengtharray.h>
191#include <QtCore/QMetaMethod>
192#include <QtWidgets/qapplication.h>
193#include <QtGui/qevent.h>
194#include <QtWidgets/qgraphicslayout.h>
195#include <QtWidgets/qgraphicsproxywidget.h>
196#include <QtWidgets/qgraphicswidget.h>
197#include <QtGui/qpaintengine.h>
198#include <QtGui/qpainter.h>
199#include <QtGui/qpainterpath.h>
200#include <QtGui/qpixmapcache.h>
201#include <QtGui/qpolygon.h>
202#include <QtGui/qpointingdevice.h>
203#include <QtWidgets/qstyleoption.h>
204#if QT_CONFIG(tooltip)
205#include <QtWidgets/qtooltip.h>
206#endif
207#include <QtGui/qtransform.h>
208#include <QtGui/qinputmethod.h>
209#include <private/qapplication_p.h>
210#include <private/qevent_p.h>
211#include <QtGui/private/qeventpoint_p.h>
212#include <private/qobject_p.h>
213#if QT_CONFIG(graphicseffect)
214#include <private/qgraphicseffect_p.h>
215#endif
216#include <private/qgesturemanager_p.h>
217#include <private/qpathclipper_p.h>
218
219#include <QtCore/qpointer.h>
220
221// #define GESTURE_DEBUG
222#ifndef GESTURE_DEBUG
223# define DEBUG if (0) qDebug
224#else
225# define DEBUG qDebug
226#endif
227
229
231
233{
234 hover->setWidget(mouseEvent->widget());
235 hover->setPos(mouseEvent->pos());
236 hover->setScenePos(mouseEvent->scenePos());
237 hover->setScreenPos(mouseEvent->screenPos());
238 hover->setLastPos(mouseEvent->lastPos());
239 hover->setLastScenePos(mouseEvent->lastScenePos());
240 hover->setLastScreenPos(mouseEvent->lastScreenPos());
241 hover->setModifiers(mouseEvent->modifiers());
242 hover->setAccepted(mouseEvent->isAccepted());
243}
244
249 : indexMethod(QGraphicsScene::BspTreeIndex),
250 index(nullptr),
251 lastItemCount(0),
252 hasSceneRect(false),
253 dirtyGrowingItemsBoundingRect(true),
254 updateAll(false),
255 calledEmitUpdated(false),
256 processDirtyItemsEmitted(false),
257 needSortTopLevelItems(true),
258 holesInTopLevelSiblingIndex(false),
259 topLevelSequentialOrdering(true),
260 scenePosDescendantsUpdatePending(false),
261 stickyFocus(false),
262 hasFocus(false),
263 lastMouseGrabberItemHasImplicitMouseGrab(false),
264 allItemsIgnoreHoverEvents(true),
265 allItemsUseDefaultCursor(true),
266 painterStateProtection(true),
267 sortCacheEnabled(false),
268 allItemsIgnoreTouchEvents(true),
269 focusOnTouch(true),
270 minimumRenderSize(0.0),
271 selectionChanging(0),
272 rectAdjust(2),
273 focusItem(nullptr),
274 lastFocusItem(nullptr),
275 passiveFocusItem(nullptr),
276 tabFocusFirst(nullptr),
277 activePanel(nullptr),
278 lastActivePanel(nullptr),
279 activationRefCount(0),
280 childExplicitActivation(0),
281 lastMouseGrabberItem(nullptr),
282 dragDropItem(nullptr),
283 enterWidget(nullptr),
284 lastDropAction(Qt::IgnoreAction),
285 style(nullptr)
286{
287}
288
293{
294 Q_Q(QGraphicsScene);
295
297
298 // Keep this index so we can check for connected slots later on.
299 changedSignalIndex = signalIndex("changed(QList<QRectF>)");
300 processDirtyItemsIndex = q->metaObject()->indexOfSlot("_q_processDirtyItems()");
301 polishItemsIndex = q->metaObject()->indexOfSlot("_q_polishItems()");
302
303 qApp->d_func()->scene_list.append(q);
304 q->update();
305}
306
314
316{
317 Q_Q(QGraphicsScene);
318 calledEmitUpdated = false;
319
321 if (!hasSceneRect) {
322 const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
323 growingItemsBoundingRect |= q->itemsBoundingRect();
324 if (oldGrowingItemsBoundingRect != growingItemsBoundingRect)
325 emit q->sceneRectChanged(growingItemsBoundingRect);
326 }
328 }
329
330 // Ensure all views are connected if anything is connected. This disables
331 // the optimization that items send updates directly to the views, but it
332 // needs to happen in order to keep compatibility with the behavior from
333 // Qt 4.4 and backward.
335 for (auto view : std::as_const(views)) {
336 if (!view->d_func()->connectedToScene) {
337 view->d_func()->connectedToScene = true;
338 q->connect(q, SIGNAL(changed(QList<QRectF>)),
339 view, SLOT(updateScene(QList<QRectF>)));
340 }
341 }
342 } else {
343 if (views.isEmpty()) {
344 updateAll = false;
345 return;
346 }
347 for (auto view : std::as_const(views))
348 view->d_func()->processPendingUpdates();
349 // It's important that we update all views before we dispatch, hence two for-loops.
350 for (auto view : std::as_const(views))
351 view->d_func()->dispatchPendingUpdateRequests();
352 return;
353 }
354
355 // Notify the changes to anybody interested.
356 QList<QRectF> oldUpdatedRects;
357 if (updateAll) {
358 oldUpdatedRects << q->sceneRect();
359 } else {
360 // Switch to a ranged constructor in Qt 6...
361 oldUpdatedRects.reserve(int(updatedRects.size()));
362 std::copy(updatedRects.cbegin(), updatedRects.cend(),
363 std::back_inserter(oldUpdatedRects));
364 }
365
366 updateAll = false;
367 updatedRects.clear();
368 emit q->changed(oldUpdatedRects);
369}
370
383
390{
395 else
397 // NB! Do not use topLevelItems.removeAt(item->d_ptr->siblingIndex) because
398 // the item is not guaranteed to be at the index after the list is sorted
399 // (see ensureSortedTopLevelItems()).
400 item->d_ptr->siblingIndex = -1;
403}
404
409{
411 return;
412
413 const QVariant booleanTrueVariant(true);
414 QGraphicsItem *item = nullptr;
415 QGraphicsItemPrivate *itemd = nullptr;
416 const int oldUnpolishedCount = unpolishedItems.size();
417
418 for (int i = 0; i < oldUnpolishedCount; ++i) {
420 if (!item)
421 continue;
422 itemd = item->d_ptr.data();
423 itemd->pendingPolish = false;
424 if (!itemd->explicitlyHidden) {
427 }
428 if (itemd->isWidget) {
431 }
432 }
433
434 if (unpolishedItems.size() == oldUnpolishedCount) {
435 // No new items were added to the vector.
437 } else {
438 // New items were appended; keep them and remove the old ones.
439 unpolishedItems.remove(0, oldUnpolishedCount);
442 }
443}
444
446{
448
449 if (updateAll) {
451 // No need for further processing (except resetting the dirty states).
452 // The growingItemsBoundingRect is updated in _q_emitUpdated.
453 for (auto topLevelItem : std::as_const(topLevelItems))
454 resetDirtyItem(topLevelItem, /*recursive=*/true);
455 return;
456 }
457
458 const bool wasPendingSceneUpdate = calledEmitUpdated;
459 const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
460
461 // Process items recursively.
462 for (auto topLevelItem : std::as_const(topLevelItems))
463 processDirtyItemsRecursive(topLevelItem);
464
466 if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect)
467 emit q_func()->sceneRectChanged(growingItemsBoundingRect);
468
469 if (wasPendingSceneUpdate)
470 return;
471
472 for (auto view : std::as_const(views))
473 view->d_func()->processPendingUpdates();
474
475 if (calledEmitUpdated) {
476 // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive
477 // and we cannot wait for the control to reach the eventloop before the
478 // changed signal is emitted, so we emit it now.
480 }
481
482 // Immediately dispatch all pending update requests on the views.
483 for (auto view : std::as_const(views))
484 view->d_func()->dispatchPendingUpdateRequests();
485}
486
491{
493 while (p) {
495 p = p->d_ptr->parent;
496 }
499 QMetaObject::invokeMethod(q_func(), "_q_updateScenePosDescendants", Qt::QueuedConnection);
500 }
501}
502
511
520
525{
526 for (QGraphicsItem *item : std::as_const(scenePosItems)) {
528 while (p) {
530 p = p->d_ptr->parent;
531 }
532 }
534}
535
549{
550 Q_Q(QGraphicsScene);
551
552 // Clear focus on the item to remove any reference in the focusWidget chain.
553 item->clearFocus();
554
555 markDirty(item, QRectF(), /*invalidateChildren=*/false, /*force=*/false,
556 /*ignoreOpacity=*/false, /*removingItemFromScene=*/true);
557
558 if (item->d_ptr->inDestructor) {
559 // The item is actually in its destructor, we call the special method in the index.
560 index->deleteItem(item);
561 } else {
562 // Can potentially call item->boundingRect() (virtual function), that's why
563 // we only can call this function if the item is not in its destructor.
564 index->removeItem(item);
565 }
566
568
571
572 QGraphicsScene *oldScene = item->d_func()->scene;
573 item->d_func()->scene = nullptr;
574
575 //We need to remove all children first because they might use their parent
576 //attributes (e.g. sceneTransform).
577 if (!item->d_ptr->inDestructor) {
578 // Remove all children recursively
579 for (auto child : std::as_const(item->d_ptr->children))
581 }
582
583 if (!item->d_ptr->inDestructor && !item->parentItem() && item->isWidget()) {
584 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
585 widget->d_func()->fixFocusChainBeforeReparenting(nullptr, oldScene, nullptr);
586 }
587
588 // Unregister focus proxy.
590
591 // Remove from parent, or unregister from toplevels.
592 if (QGraphicsItem *parentItem = item->parentItem()) {
593 if (parentItem->scene()) {
594 Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem",
595 "Parent item's scene is different from this item's scene");
596 item->setParentItem(nullptr);
597 }
598 } else {
600 }
601
602 // Reset the mouse grabber and focus item data.
603 if (item == focusItem)
604 focusItem = nullptr;
605 if (item == lastFocusItem)
606 lastFocusItem = nullptr;
607 if (item == passiveFocusItem)
608 passiveFocusItem = nullptr;
609 if (item == activePanel) {
610 // ### deactivate...
611 activePanel = nullptr;
612 }
613 if (item == lastActivePanel)
614 lastActivePanel = nullptr;
615
616 // Change tabFocusFirst to the next widget in focus chain if removing the current one.
617 if (item == tabFocusFirst) {
619 if (wd->focusNext && wd->focusNext != tabFocusFirst && wd->focusNext->scene() == q)
621 else
622 tabFocusFirst = nullptr;
623 }
624
625 // Cancel active touches
626 {
628 while (it != itemForTouchPointId.end()) {
629 if (it.value() == item) {
632 } else {
633 ++it;
634 }
635 }
636 }
637
638 // Disable selectionChanged() for individual items
640 int oldSelectedItemsSize = selectedItems.size();
641
642 // Update selected & hovered item bookkeeping
646 if (item->d_ptr->pendingPolish) {
647 const int unpolishedIndex = unpolishedItems.indexOf(item);
648 if (unpolishedIndex != -1)
649 unpolishedItems[unpolishedIndex] = 0;
650 item->d_ptr->pendingPolish = false;
651 }
653
654 //We remove all references of item from the sceneEventFilter arrays
656 while (iterator != sceneEventFilters.end()) {
657 if (iterator.value() == item || iterator.key() == item)
658 iterator = sceneEventFilters.erase(iterator);
659 else
660 ++iterator;
661 }
662
665
666 // Reset the mouse grabber and focus item data.
668 ungrabMouse(item, /* item is dying */ item->d_ptr->inDestructor);
669
670 // Reset the keyboard grabber
672 ungrabKeyboard(item, /* item is dying */ item->d_ptr->inDestructor);
673
674 // Reset the last mouse grabber item
676 lastMouseGrabberItem = nullptr;
677
678 // Reset the current drop item
679 if (item == dragDropItem)
680 dragDropItem = nullptr;
681
682 // Re-enable selectionChanged() for individual items
684 if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize)
685 emit q->selectionChanged();
686
687#ifndef QT_NO_GESTURES
688 for (auto it = gestureTargets.begin(); it != gestureTargets.end();) {
689 if (it.value() == item)
691 else
692 ++it;
693 }
694
695 if (QGraphicsObject *dummy = item->toGraphicsObject()) {
699 }
700
701 for (auto it = item->d_ptr->gestureContext.constBegin();
703 ungrabGesture(item, it.key());
704#endif // QT_NO_GESTURES
705}
706
711{
712 Q_Q(QGraphicsScene);
713 if (item && item->scene() != q) {
714 qWarning("QGraphicsScene::setActivePanel: item %p must be part of this scene",
715 item);
716 return;
717 }
718
719 // Ensure the scene has focus when we change panel activation.
721
722 // Find the item's panel.
723 QGraphicsItem *panel = item ? item->panel() : nullptr;
724 lastActivePanel = panel ? activePanel : nullptr;
725 if (panel == activePanel || (!q->isActive() && !duringActivationEvent))
726 return;
727
728 QGraphicsItem *oldFocusItem = focusItem;
729
730 // Deactivate the last active panel.
731 if (activePanel) {
732 if (QGraphicsItem *fi = activePanel->focusItem()) {
733 // Remove focus from the current focus item.
734 if (fi == q->focusItem())
735 setFocusItemHelper(nullptr, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
736 }
737
739 q->sendEvent(activePanel, &event);
740 } else if (panel && !duringActivationEvent) {
741 // Deactivate the scene if changing activation to a panel.
742 const auto items = q->items();
744 for (QGraphicsItem *item : items) {
745 if (item->isVisible() && !item->isPanel() && !item->parentItem())
746 q->sendEvent(item, &event);
747 }
748 }
749
750 // Update activate state.
754
755 // Activate
756 if (panel) {
758 q->sendEvent(panel, &event);
759
760 // Set focus on the panel's focus item, or itself if it's
761 // focusable, or on the first focusable item in the panel's
762 // focus chain as a last resort.
763 if (QGraphicsItem *focusItem = panel->focusItem()) {
764 setFocusItemHelper(focusItem, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
765 } else if (panel->flags() & QGraphicsItem::ItemIsFocusable) {
766 setFocusItemHelper(panel, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
767 } else if (panel->isWidget()) {
768 QGraphicsWidget *fw = static_cast<QGraphicsWidget *>(panel)->d_func()->focusNext;
769 do {
770 if (fw->focusPolicy() & Qt::TabFocus) {
771 setFocusItemHelper(fw, Qt::ActiveWindowFocusReason, /* emitFocusChanged = */ false);
772 break;
773 }
774 fw = fw->d_func()->focusNext;
775 } while (fw != panel);
776 }
777 } else if (q->isActive()) {
778 const auto items = q->items();
779 // Activate the scene
781 for (QGraphicsItem *item : items) {
782 if (item->isVisible() && !item->isPanel() && !item->parentItem())
783 q->sendEvent(item, &event);
784 }
785 }
786
787 emit q->focusItemChanged(focusItem, oldFocusItem, Qt::ActiveWindowFocusReason);
788}
789
801 Qt::FocusReason focusReason,
802 bool emitFocusChanged)
803{
804 Q_Q(QGraphicsScene);
805 if (item == focusItem)
806 return;
807
808 // Clear focus if asked to set focus on something that can't
809 // accept input focus.
811 || !item->isVisible() || !item->isEnabled())) {
812 item = nullptr;
813 }
814
815 // Set focus on the scene if an item requests focus.
816 if (item) {
817 q->setFocus(focusReason);
818 if (item == focusItem) {
819 if (emitFocusChanged)
820 emit q->focusItemChanged(focusItem, (QGraphicsItem *)nullptr, focusReason);
821 return;
822 }
823 }
824
825 QGraphicsItem *oldFocusItem = focusItem;
826 if (focusItem) {
828
829#ifndef QT_NO_IM
831 // Close any external input method panel. This happens
832 // automatically by removing WA_InputMethodEnabled on
833 // the views, but if we are changing focus, we have to
834 // do it ourselves.
835 if (qApp)
837 }
838#endif //QT_NO_IM
839
840 focusItem = nullptr;
841 QFocusEvent event(QEvent::FocusOut, focusReason);
843 }
844
845 // This handles the case that the item has been removed from the
846 // scene in response to the FocusOut event.
847 if (item && item->scene() != q)
848 item = nullptr;
849
850 if (item)
851 focusItem = item;
853
854 if (item) {
855 QFocusEvent event(QEvent::FocusIn, focusReason);
857 }
858
859 if (emitFocusChanged)
860 emit q->focusItemChanged(focusItem, oldFocusItem, focusReason);
861}
862
882
893{
896 Q_ASSERT(index != -1);
897
898 for (int i = popupWidgets.size() - 1; i >= index; --i) {
900 ungrabMouse(widget, itemIsDying);
901 if (focusItem && popupWidgets.isEmpty()) {
904 } else if (keyboardGrabberItems.contains(static_cast<QGraphicsItem *>(widget))) {
905 ungrabKeyboard(static_cast<QGraphicsItem *>(widget), itemIsDying);
906 }
907 if (!itemIsDying && widget->isVisible()) {
908 widget->QGraphicsItem::d_ptr->setVisibleHelper(false, /* explicit = */ false);
909 }
910 }
911}
912
917{
918 // Append to list of mouse grabber items, and send a mouse grab event.
921 Q_ASSERT(!implicit);
923 qWarning("QGraphicsItem::grabMouse: already a mouse grabber");
924 } else {
925 // Upgrade to an explicit mouse grab
927 }
928 } else {
929 qWarning("QGraphicsItem::grabMouse: already blocked by mouse grabber: %p",
931 }
932 return;
933 }
934
935 // Send ungrab event to the last grabber.
936 if (!mouseGrabberItems.isEmpty()) {
939 // Implicit mouse grab is immediately lost.
940 last->ungrabMouse();
941 } else {
942 // Just send ungrab event to current grabber.
943 QEvent ungrabEvent(QEvent::UngrabMouse);
944 sendEvent(last, &ungrabEvent);
945 }
946 }
947
950
951 // Send grab event to current grabber.
952 QEvent grabEvent(QEvent::GrabMouse);
953 sendEvent(item, &grabEvent);
954}
955
960{
962 if (index == -1) {
963 qWarning("QGraphicsItem::ungrabMouse: not a mouse grabber");
964 return;
965 }
966
968 // Recursively ungrab the next mouse grabber until we reach this item
969 // to ensure state consistency.
970 ungrabMouse(mouseGrabberItems.at(index + 1), itemIsDying);
971 }
973 // If the item is a popup, go via removePopup to ensure state
974 // consistency and that it gets hidden correctly - beware that
975 // removePopup() reenters this function to continue removing the grab.
976 removePopup(popupWidgets.constLast(), itemIsDying);
977 return;
978 }
979
980 // Send notification about mouse ungrab.
981 if (!itemIsDying) {
984 }
985
986 // Remove the item from the list of grabbers. Whenever this happens, we
987 // reset the implicitGrab (there can be only ever be one implicit grabber
988 // in a scene, and it is always the latest grabber; if the implicit grab
989 // is lost, it is not automatically regained.
992
993 // Send notification about mouse regrab. ### It's unfortunate that all the
994 // items get a GrabMouse event, but this is a rare case with a simple
995 // implementation and it does ensure a consistent state.
996 if (!itemIsDying && !mouseGrabberItems.isEmpty()) {
999 sendEvent(last, &event);
1000 }
1001}
1002
1012
1017{
1020 qWarning("QGraphicsItem::grabKeyboard: already a keyboard grabber");
1021 else
1022 qWarning("QGraphicsItem::grabKeyboard: already blocked by keyboard grabber: %p",
1024 return;
1025 }
1026
1027 // Send ungrab event to the last grabber.
1029 // Just send ungrab event to current grabber.
1030 QEvent ungrabEvent(QEvent::UngrabKeyboard);
1031 sendEvent(keyboardGrabberItems.constLast(), &ungrabEvent);
1032 }
1033
1035
1036 // Send grab event to current grabber.
1037 QEvent grabEvent(QEvent::GrabKeyboard);
1038 sendEvent(item, &grabEvent);
1039}
1040
1045{
1047 if (index == -1) {
1048 qWarning("QGraphicsItem::ungrabKeyboard: not a keyboard grabber");
1049 return;
1050 }
1052 // Recursively ungrab the topmost keyboard grabber until we reach this
1053 // item to ensure state consistency.
1054 ungrabKeyboard(keyboardGrabberItems.at(index + 1), itemIsDying);
1055 }
1056
1057 // Send notification about keyboard ungrab.
1058 if (!itemIsDying) {
1060 sendEvent(item, &event);
1061 }
1062
1063 // Remove the item from the list of grabbers.
1065
1066 // Send notification about mouse regrab.
1067 if (!itemIsDying && !keyboardGrabberItems.isEmpty()) {
1070 sendEvent(last, &event);
1071 }
1072}
1073
1082
1084{
1085 for (QGraphicsView *view : std::as_const(views))
1086 view->viewport()->setMouseTracking(true);
1087}
1088
1092QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &screenPos,
1093 const QPointF &scenePos,
1094 QWidget *widget) const
1095{
1096 Q_Q(const QGraphicsScene);
1097 QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
1098 if (!view)
1099 return q->items(scenePos, Qt::IntersectsItemShape, Qt::DescendingOrder, QTransform());
1100
1101 const QRectF pointRect(QPointF(widget->mapFromGlobal(screenPos)), QSizeF(1, 1));
1102 if (!view->isTransformed())
1103 return q->items(pointRect, Qt::IntersectsItemShape, Qt::DescendingOrder);
1104
1105 const QTransform viewTransform = view->viewportTransform();
1106 if (viewTransform.type() <= QTransform::TxScale) {
1107 return q->items(viewTransform.inverted().mapRect(pointRect), Qt::IntersectsItemShape,
1108 Qt::DescendingOrder, viewTransform);
1109 }
1110 return q->items(viewTransform.inverted().map(pointRect), Qt::IntersectsItemShape,
1111 Qt::DescendingOrder, viewTransform);
1112}
1113
1118{
1119 for (int i = 0x1; i <= 0x10; i <<= 1) {
1120 if (event->buttons() & i) {
1123 event->widget()));
1126 }
1127 }
1128}
1129
1137
1155
1160{
1163 while (parent) {
1164 if (parent->d_ptr->filtersDescendantEvents && parent->sceneEventFilter(item, event))
1165 return true;
1167 return false;
1168 parent = parent->parentItem();
1169 }
1170 }
1171 return false;
1172}
1173
1178{
1180 return false;
1181
1184 while (it != end) {
1185 // ### The filterer and filteree might both be deleted.
1186 if (it.value()->sceneEventFilter(it.key(), event))
1187 return true;
1188 ++it;
1189 }
1190 return false;
1191}
1192
1203{
1204#if QT_CONFIG(gestures)
1205 if (QGraphicsObject *object = item->toGraphicsObject()) {
1206 QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
1207 if (gestureManager) {
1208 if (gestureManager->filterEvent(object, event))
1209 return true;
1210 }
1211 }
1212#endif // QT_CONFIG(gestures)
1213
1214 if (filterEvent(item, event))
1215 return false;
1217 return false;
1218 if (!item || !item->isEnabled())
1219 return false;
1221 bool spont = event->spontaneous();
1223 return true;
1224 event->m_spont = spont;
1225 }
1226 return item->sceneEvent(event);
1227}
1228
1234{
1235 dest->setWidget(source->widget());
1236 dest->setPos(source->pos());
1237 dest->setScenePos(source->scenePos());
1238 dest->setScreenPos(source->screenPos());
1239 dest->setButtons(source->buttons());
1240 dest->setModifiers(source->modifiers());
1241 dest->setPossibleActions(source->possibleActions());
1242 dest->setProposedAction(source->proposedAction());
1243 dest->setDropAction(source->dropAction());
1244 dest->setSource(source->source());
1245 dest->setMimeData(source->mimeData());
1246}
1247
1252 QGraphicsSceneDragDropEvent *dragDropEvent)
1253{
1254 dragDropEvent->setPos(item->d_ptr->genericMapFromScene(dragDropEvent->scenePos(), dragDropEvent->widget()));
1255 sendEvent(item, dragDropEvent);
1256}
1257
1262 QGraphicsSceneHoverEvent *hoverEvent)
1263{
1265 event.setWidget(hoverEvent->widget());
1266 const QTransform mapFromScene = item->d_ptr->genericMapFromSceneTransform(hoverEvent->widget());
1267 event.setPos(mapFromScene.map(hoverEvent->scenePos()));
1268 event.setScenePos(hoverEvent->scenePos());
1269 event.setScreenPos(hoverEvent->screenPos());
1270 event.setLastPos(mapFromScene.map(hoverEvent->lastScenePos()));
1271 event.setLastScenePos(hoverEvent->lastScenePos());
1272 event.setLastScreenPos(hoverEvent->lastScreenPos());
1273 event.setModifiers(hoverEvent->modifiers());
1274 sendEvent(item, &event);
1275}
1276
1281{
1282 if (mouseEvent->button() == 0 && mouseEvent->buttons() == 0 && lastMouseGrabberItemHasImplicitMouseGrab) {
1283 // ### This is a temporary fix for until we get proper mouse
1284 // grab events.
1286 return;
1287 }
1288
1291 return;
1292
1293 const QTransform mapFromScene = item->d_ptr->genericMapFromSceneTransform(mouseEvent->widget());
1294 const QPointF itemPos = mapFromScene.map(mouseEvent->scenePos());
1295 for (int i = 0x1; i <= 0x10; i <<= 1) {
1300 }
1301 mouseEvent->setPos(itemPos);
1302 mouseEvent->setLastPos(mapFromScene.map(mouseEvent->lastScenePos()));
1303 sendEvent(item, mouseEvent);
1304}
1305
1310{
1311 Q_Q(QGraphicsScene);
1312
1313 // Ignore by default, unless we find a mouse grabber that accepts it.
1314 mouseEvent->ignore();
1315
1316 // Deliver to any existing mouse grabber.
1317 if (!mouseGrabberItems.isEmpty()) {
1319 return;
1320 // The event is ignored by default, but we disregard the event's
1321 // accepted state after delivery; the mouse is grabbed, after all.
1322 sendMouseEvent(mouseEvent);
1323 return;
1324 }
1325
1326 // Start by determining the number of items at the current position.
1327 // Reuse value from earlier calculations if possible.
1330 mouseEvent->scenePos(),
1331 mouseEvent->widget());
1332 }
1333
1334 // Update window activation.
1336 QGraphicsWidget *newActiveWindow = topItem ? topItem->window() : nullptr;
1337 if (newActiveWindow && newActiveWindow->isBlockedByModalPanel(&topItem)) {
1338 // pass activation to the blocking modal window
1339 newActiveWindow = topItem ? topItem->window() : nullptr;
1340 }
1341
1342 if (newActiveWindow != q->activeWindow())
1343 q->setActiveWindow(newActiveWindow);
1344
1345 // Set focus on the topmost enabled item that can take focus.
1346 bool setFocus = false;
1347
1348 for (QGraphicsItem *item : std::as_const(cachedItemsUnderMouse)) {
1351 // Make sure we don't clear focus.
1352 setFocus = true;
1353 break;
1354 }
1356 if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
1357 setFocus = true;
1358 if (item != q->focusItem() && item->d_ptr->mouseSetsFocus)
1359 q->setFocusItem(item, Qt::MouseFocusReason);
1360 break;
1361 }
1362 }
1363 if (item->isPanel())
1364 break;
1366 break;
1367 }
1368
1369 // Check for scene modality.
1370 bool sceneModality = false;
1371 for (auto modalPanel : std::as_const(modalPanels)) {
1372 if (modalPanel->panelModality() == QGraphicsItem::SceneModal) {
1373 sceneModality = true;
1374 break;
1375 }
1376 }
1377
1378 // If nobody could take focus, clear it.
1379 if (!stickyFocus && !setFocus && !sceneModality)
1380 q->setFocusItem(nullptr, Qt::MouseFocusReason);
1381
1382 // Any item will do.
1383 if (sceneModality && cachedItemsUnderMouse.isEmpty())
1385
1386 // Find a mouse grabber by sending mouse press events to all mouse grabber
1387 // candidates one at a time, until the event is accepted. It's accepted by
1388 // default, so the receiver has to explicitly ignore it for it to pass
1389 // through.
1390 for (QGraphicsItem *item : std::as_const(cachedItemsUnderMouse)) {
1391 if (!(item->acceptedMouseButtons() & mouseEvent->button())) {
1392 // Skip items that don't accept the event's mouse button.
1393 continue;
1394 }
1395
1396 // Check if this item is blocked by a modal panel and deliver the mouse event to the
1397 // blocking panel instead of this item if blocked.
1399
1400 grabMouse(item, /* implicit = */ true);
1401 mouseEvent->accept();
1402
1403 // check if the item we are sending to are disabled (before we send the event)
1404 bool disabled = !item->isEnabled();
1405 bool isPanel = item->isPanel();
1406 if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick
1408 // If this item is different from the item that received the last
1409 // mouse event, and mouseEvent is a double-click event, then the
1410 // event is converted to a press. Known limitation:
1411 // Triple-clicking will not generate a double-click, though.
1413 mousePress.m_spont = mouseEvent->spontaneous();
1414 mousePress.accept();
1415 mousePress.setButton(mouseEvent->button());
1416 mousePress.setButtons(mouseEvent->buttons());
1417 mousePress.setScreenPos(mouseEvent->screenPos());
1418 mousePress.setScenePos(mouseEvent->scenePos());
1419 mousePress.setModifiers(mouseEvent->modifiers());
1420 mousePress.setWidget(mouseEvent->widget());
1421 mousePress.setButtonDownPos(mouseEvent->button(),
1422 mouseEvent->buttonDownPos(mouseEvent->button()));
1423 mousePress.setButtonDownScenePos(mouseEvent->button(),
1424 mouseEvent->buttonDownScenePos(mouseEvent->button()));
1425 mousePress.setButtonDownScreenPos(mouseEvent->button(),
1426 mouseEvent->buttonDownScreenPos(mouseEvent->button()));
1427 sendMouseEvent(&mousePress);
1428 mouseEvent->setAccepted(mousePress.isAccepted());
1429 } else {
1430 sendMouseEvent(mouseEvent);
1431 }
1432
1433 bool dontSendUngrabEvents = mouseGrabberItems.isEmpty() || mouseGrabberItems.constLast() != item;
1434 if (disabled) {
1435 ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
1436 break;
1437 }
1438 if (mouseEvent->isAccepted()) {
1442 return;
1443 }
1444 ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
1445
1446 // Don't propagate through panels.
1447 if (isPanel)
1448 break;
1449 }
1450
1451 // Is the event still ignored? Then the mouse press goes to the scene.
1452 // Reset the mouse grabber, clear the selection, clear focus, and leave
1453 // the event ignored so that it can propagate through the originating
1454 // view.
1455 if (!mouseEvent->isAccepted()) {
1457
1458 QGraphicsView *view = mouseEvent->widget() ? qobject_cast<QGraphicsView *>(mouseEvent->widget()->parentWidget()) : 0;
1459 bool dontClearSelection = view && view->dragMode() == QGraphicsView::ScrollHandDrag;
1460 bool extendSelection = (mouseEvent->modifiers() & Qt::ControlModifier) != 0;
1461 dontClearSelection |= extendSelection;
1462 if (!dontClearSelection) {
1463 // Clear the selection if the originating view isn't in scroll
1464 // hand drag mode. The view will clear the selection if no drag
1465 // happened.
1466 q->clearSelection();
1467 }
1468 }
1469}
1470
1493
1501{
1502 if (this->font == font && this->font.resolveMask() == font.resolveMask())
1503 return;
1505}
1506
1514{
1515 QFont naturalFont = QApplication::font();
1516 naturalFont.setResolveMask(0);
1517 QFont resolvedFont = font.resolve(naturalFont);
1518 updateFont(resolvedFont);
1519}
1520
1528{
1529 Q_Q(QGraphicsScene);
1530
1531 // Update local font setting.
1532 this->font = font;
1533
1534 // Resolve the fonts of all top-level widget items, or widget items
1535 // whose parent is not a widget.
1536 const auto items = q->items();
1537 for (QGraphicsItem *item : items) {
1538 if (!item->parentItem()) {
1539 // Resolvefont for an item is a noop operation, but
1540 // every item can be a widget, or can have a widget
1541 // childre.
1543 }
1544 }
1545
1546 // Send the scene a FontChange event.
1549}
1550
1558{
1559 if (this->palette == palette && this->palette.resolveMask() == palette.resolveMask())
1560 return;
1562}
1563
1571{
1572 QPalette naturalPalette = QGuiApplication::palette();
1573 naturalPalette.setResolveMask(0);
1574 QPalette resolvedPalette = palette.resolve(naturalPalette);
1575 updatePalette(resolvedPalette);
1576}
1577
1585{
1586 Q_Q(QGraphicsScene);
1587
1588 // Update local palette setting.
1589 this->palette = palette;
1590
1591 // Resolve the palettes of all top-level widget items, or widget items
1592 // whose parent is not a widget.
1593 const auto items = q->items();
1594 for (QGraphicsItem *item : items) {
1595 if (!item->parentItem()) {
1596 // ResolvePalette for an item is a noop operation, but
1597 // every item can be a widget, or can have a widget
1598 // children.
1600 }
1601 }
1602
1603 // Send the scene a PaletteChange event.
1606}
1607
1613 : QObject(*new QGraphicsScenePrivate, parent)
1614{
1615 d_func()->init();
1616}
1617
1626 : QObject(*new QGraphicsScenePrivate, parent)
1627{
1628 d_func()->init();
1630}
1631
1641 : QObject(*new QGraphicsScenePrivate, parent)
1642{
1643 d_func()->init();
1645}
1646
1654{
1655 Q_D(QGraphicsScene);
1656
1657 // Remove this scene from qApp's global scene list.
1659 qApp->d_func()->scene_list.removeAll(this);
1660
1661 clear();
1662
1663 // Remove this scene from all associated views.
1664 // Note: d->views is modified by QGraphicsView::setScene, so must make a copy
1665 const auto views = d->views;
1666 for (auto view : std::as_const(views))
1667 view->setScene(nullptr);
1668}
1669
1686{
1687 Q_D(const QGraphicsScene);
1688 if (d->hasSceneRect)
1689 return d->sceneRect;
1690
1691 if (d->dirtyGrowingItemsBoundingRect) {
1692 // Lazily update the growing items bounding rect
1693 QGraphicsScenePrivate *thatd = const_cast<QGraphicsScenePrivate *>(d);
1694 QRectF oldGrowingBoundingRect = thatd->growingItemsBoundingRect;
1695 thatd->growingItemsBoundingRect |= itemsBoundingRect();
1696 thatd->dirtyGrowingItemsBoundingRect = false;
1697 if (oldGrowingBoundingRect != thatd->growingItemsBoundingRect)
1698 emit const_cast<QGraphicsScene *>(this)->sceneRectChanged(thatd->growingItemsBoundingRect);
1699 }
1700 return d->growingItemsBoundingRect;
1701}
1703{
1704 Q_D(QGraphicsScene);
1705 if (rect != d->sceneRect) {
1706 d->hasSceneRect = !rect.isNull();
1707 d->sceneRect = rect;
1708 emit sceneRectChanged(d->hasSceneRect ? rect : d->growingItemsBoundingRect);
1709 }
1710}
1711
1747 Qt::AspectRatioMode aspectRatioMode)
1748{
1749 // ### Switch to using the recursive rendering algorithm instead.
1750
1751 // Default source rect = scene rect
1752 QRectF sourceRect = source;
1753 if (sourceRect.isNull())
1754 sourceRect = sceneRect();
1755
1756 // Default target rect = device rect
1757 QRectF targetRect = target;
1758 if (targetRect.isNull()) {
1760 targetRect = sourceRect;
1761 else
1762 targetRect.setRect(0, 0, painter->device()->width(), painter->device()->height());
1763 }
1764
1765 // Find the ideal x / y scaling ratio to fit \a source into \a target.
1766 qreal xratio = targetRect.width() / sourceRect.width();
1767 qreal yratio = targetRect.height() / sourceRect.height();
1768
1769 // Scale according to the aspect ratio mode.
1770 switch (aspectRatioMode) {
1772 xratio = yratio = qMin(xratio, yratio);
1773 break;
1775 xratio = yratio = qMax(xratio, yratio);
1776 break;
1778 break;
1779 }
1780
1781 // Find all items to draw, and reverse the list (we want to draw
1782 // in reverse order).
1783 QList<QGraphicsItem *> itemList = items(sourceRect, Qt::IntersectsItemBoundingRect);
1784 QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
1785 const qsizetype numItems = itemList.size();
1786 for (qsizetype i = 0; i < numItems; ++i)
1787 itemArray[numItems - i - 1] = itemList.at(i);
1788 itemList.clear();
1789
1790 painter->save();
1791
1792 // Transform the painter.
1794 QTransform painterTransform;
1795 painterTransform *= QTransform()
1796 .translate(targetRect.left(), targetRect.top())
1797 .scale(xratio, yratio)
1798 .translate(-sourceRect.left(), -sourceRect.top());
1799 painter->setWorldTransform(painterTransform, true);
1800
1801 // Generate the style options
1802 QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems];
1803 for (qsizetype i = 0; i < numItems; ++i)
1804 itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect());
1805
1806 // Render the scene.
1807 drawBackground(painter, sourceRect);
1808 drawItems(painter, numItems, itemArray, styleOptionArray);
1809 drawForeground(painter, sourceRect);
1810
1811 delete [] itemArray;
1812 delete [] styleOptionArray;
1813
1814 painter->restore();
1815}
1816
1834{
1835 Q_D(const QGraphicsScene);
1836 return d->indexMethod;
1837}
1839{
1840 Q_D(QGraphicsScene);
1841 if (d->indexMethod == method)
1842 return;
1843
1844 d->indexMethod = method;
1845
1846 QList<QGraphicsItem *> oldItems = d->index->items(Qt::DescendingOrder);
1847 delete d->index;
1848 if (method == BspTreeIndex)
1849 d->index = new QGraphicsSceneBspTreeIndex(this);
1850 else
1851 d->index = new QGraphicsSceneLinearIndex(this);
1852 for (int i = oldItems.size() - 1; i >= 0; --i)
1853 d->index->addItem(oldItems.at(i));
1854}
1855
1889{
1890 Q_D(const QGraphicsScene);
1891 QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
1892 return bspTree ? bspTree->bspTreeDepth() : 0;
1893}
1895{
1896 Q_D(QGraphicsScene);
1897 if (depth < 0) {
1898 qWarning("QGraphicsScene::setBspTreeDepth: invalid depth %d ignored; must be >= 0", depth);
1899 return;
1900 }
1901
1902 QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
1903 if (!bspTree) {
1904 qWarning("QGraphicsScene::setBspTreeDepth: cannot apply if indexing method is not BSP");
1905 return;
1906 }
1907 bspTree->setBspTreeDepth(depth);
1908}
1909
1918{
1919 // Does not take untransformable items into account.
1921 const auto items_ = items();
1922 for (QGraphicsItem *item : items_)
1924 return boundingRect;
1925}
1926
1933QList<QGraphicsItem *> QGraphicsScene::items(Qt::SortOrder order) const
1934{
1935 Q_D(const QGraphicsScene);
1936 return d->index->items(order);
1937}
1938
1973{
1974 Q_D(const QGraphicsScene);
1975 return d->index->items(pos, mode, order, deviceTransform);
1976}
1977
1999{
2000 Q_D(const QGraphicsScene);
2001 return d->index->items(rect, mode, order, deviceTransform);
2002}
2003
2025{
2026 Q_D(const QGraphicsScene);
2027 return d->index->items(polygon, mode, order, deviceTransform);
2028}
2029
2051{
2052 Q_D(const QGraphicsScene);
2053 return d->index->items(path, mode, order, deviceTransform);
2054}
2055
2070{
2071 Q_D(const QGraphicsScene);
2072 if (!item) {
2073 qWarning("QGraphicsScene::collidingItems: cannot find collisions for null item");
2074 return QList<QGraphicsItem *>();
2075 }
2076
2077 // Does not support ItemIgnoresTransformations.
2078 QList<QGraphicsItem *> tmp;
2079 const auto itemsInVicinity = d->index->estimateItems(item->sceneBoundingRect(), Qt::DescendingOrder);
2080 for (QGraphicsItem *itemInVicinity : itemsInVicinity) {
2081 if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode))
2082 tmp << itemInVicinity;
2083 }
2084 return tmp;
2085}
2086
2101{
2102 const QList<QGraphicsItem *> itemsAtPoint = items(position, Qt::IntersectsItemShape,
2104 return itemsAtPoint.isEmpty() ? nullptr : itemsAtPoint.first();
2105}
2106
2130QList<QGraphicsItem *> QGraphicsScene::selectedItems() const
2131{
2132 Q_D(const QGraphicsScene);
2133
2134 // Optimization: Lazily removes items that are not selected.
2135 QGraphicsScene *that = const_cast<QGraphicsScene *>(this);
2136 QSet<QGraphicsItem *> actuallySelectedSet;
2137 for (QGraphicsItem *item : std::as_const(that->d_func()->selectedItems)) {
2138 if (item->isSelected())
2139 actuallySelectedSet << item;
2140 }
2141
2142 that->d_func()->selectedItems = actuallySelectedSet;
2143
2144 return d->selectedItems.values();
2145}
2146
2155{
2156 Q_D(const QGraphicsScene);
2157 return d->selectionArea;
2158}
2159
2179
2195 Qt::ItemSelectionOperation selectionOperation,
2198{
2199 Q_D(QGraphicsScene);
2200
2201 // Note: with boolean path operations, we can improve performance here
2202 // quite a lot by "growing" the old path instead of replacing it. That
2203 // allows us to only check the intersect area for changes, instead of
2204 // reevaluating the whole path over again.
2205 d->selectionArea = path;
2206
2207 QSet<QGraphicsItem *> unselectItems = d->selectedItems;
2208
2209 // Disable emitting selectionChanged() for individual items.
2210 ++d->selectionChanging;
2211 bool changed = false;
2212
2213 // Set all items in path to selected.
2214 const auto items = this->items(path, mode, Qt::DescendingOrder, deviceTransform);
2215 for (QGraphicsItem *item : items) {
2217 if (!item->isSelected())
2218 changed = true;
2219 unselectItems.remove(item);
2220 item->setSelected(true);
2221 }
2222 }
2223
2224 switch (selectionOperation) {
2226 // Deselect all items outside path.
2227 for (QGraphicsItem *item : std::as_const(unselectItems)) {
2228 item->setSelected(false);
2229 changed = true;
2230 }
2231 break;
2232 default:
2233 break;
2234 }
2235
2236 // Re-enable emitting selectionChanged() for individual items.
2237 --d->selectionChanging;
2238
2239 if (!d->selectionChanging && changed)
2241}
2242
2249{
2250 Q_D(QGraphicsScene);
2251
2252 // Disable emitting selectionChanged
2253 ++d->selectionChanging;
2254 // iterate over a copy, as clearing selection might invalidate selectedItems
2255 const auto selectedItems = d->selectedItems;
2256 QSet<QGraphicsItem *> stillSelectedSet;
2257
2259 item->setSelected(false);
2260 // items might override itemChange to prevent deselection
2261 if (item->isSelected())
2262 stillSelectedSet << item;
2263 }
2264 const bool changed = stillSelectedSet != selectedItems;
2265 d->selectedItems = stillSelectedSet;
2266
2267 // Re-enable emitting selectionChanged() for individual items.
2268 --d->selectionChanging;
2269
2270 if (!d->selectionChanging && changed)
2272}
2273
2283{
2284 Q_D(QGraphicsScene);
2285 // NB! We have to clear the index before deleting items; otherwise the
2286 // index might try to access dangling item pointers.
2287 d->index->clear();
2288 // NB! QGraphicsScenePrivate::unregisterTopLevelItem() removes items
2289 while (!d->topLevelItems.isEmpty())
2290 delete d->topLevelItems.first();
2291 Q_ASSERT(d->topLevelItems.isEmpty());
2292 d->lastItemCount = 0;
2293 d->allItemsIgnoreHoverEvents = true;
2294 d->allItemsUseDefaultCursor = true;
2295 d->allItemsIgnoreTouchEvents = true;
2296 d->focusOnTouch = true;
2297}
2298
2313{
2314 // Build a list of the first item's ancestors
2315 QList<QGraphicsItem *> ancestors;
2316 int n = 0;
2317 if (!items.isEmpty()) {
2319 while ((parent = parent->parentItem()))
2320 ancestors.append(parent);
2321 }
2322
2323 // Find the common ancestor for all items
2324 QGraphicsItem *commonAncestor = nullptr;
2325 if (!ancestors.isEmpty()) {
2326 while (n < items.size()) {
2327 int commonIndex = -1;
2329 do {
2330 int index = ancestors.indexOf(parent, qMax(0, commonIndex));
2331 if (index != -1) {
2332 commonIndex = index;
2333 break;
2334 }
2335 } while ((parent = parent->parentItem()));
2336
2337 if (commonIndex == -1) {
2338 commonAncestor = nullptr;
2339 break;
2340 }
2341
2342 commonAncestor = ancestors.at(commonIndex);
2343 }
2344 }
2345
2346 // Create a new group at that level
2347 QGraphicsItemGroup *group = new QGraphicsItemGroup(commonAncestor);
2348 if (!commonAncestor)
2349 addItem(group);
2350 for (QGraphicsItem *item : items)
2351 group->addToGroup(item);
2352 return group;
2353}
2354
2363{
2364 const auto items = group->childItems();
2365 for (QGraphicsItem *item : items)
2366 group->removeFromGroup(item);
2368 delete group;
2369}
2370
2397{
2398 Q_D(QGraphicsScene);
2399 if (!item) {
2400 qWarning("QGraphicsScene::addItem: cannot add null item");
2401 return;
2402 }
2403 if (item->d_ptr->scene == this) {
2404 qWarning("QGraphicsScene::addItem: item has already been added to this scene");
2405 return;
2406 }
2407 // Remove this item from its existing scene
2408 if (QGraphicsScene *oldScene = item->d_ptr->scene)
2409 oldScene->removeItem(item);
2410
2411 // Notify the item that its scene is changing, and allow the item to
2412 // react.
2414 QVariant::fromValue<QGraphicsScene *>(this)));
2415 QGraphicsScene *targetScene = qvariant_cast<QGraphicsScene *>(newSceneVariant);
2416 if (targetScene != this) {
2417 if (targetScene && item->d_ptr->scene != targetScene)
2418 targetScene->addItem(item);
2419 return;
2420 }
2421
2422 if (d->unpolishedItems.isEmpty()) {
2423 QMetaMethod method = metaObject()->method(d->polishItemsIndex);
2424 method.invoke(this, Qt::QueuedConnection);
2425 }
2426 d->unpolishedItems.append(item);
2427 item->d_ptr->pendingPolish = true;
2428
2429 // Detach this item from its parent if the parent's scene is different
2430 // from this scene.
2431 if (QGraphicsItem *itemParent = item->d_ptr->parent) {
2432 if (itemParent->d_ptr->scene != this)
2433 item->setParentItem(nullptr);
2434 }
2435
2436 // Add the item to this scene
2437 item->d_func()->scene = targetScene;
2438
2439 // Add the item in the index
2440 d->index->addItem(item);
2441
2442 // Add to list of toplevels if this item is a toplevel.
2443 if (!item->d_ptr->parent)
2444 d->registerTopLevelItem(item);
2445
2446 // Add to list of items that require an update. We cannot assume that the
2447 // item is fully constructed, so calling item->update() can lead to a pure
2448 // virtual function call to boundingRect().
2449 d->markDirty(item);
2450 d->dirtyGrowingItemsBoundingRect = true;
2451
2452 // Disable selectionChanged() for individual items
2453 ++d->selectionChanging;
2454 int oldSelectedItemSize = d->selectedItems.size();
2455
2456 // Enable mouse tracking if we haven't already done so, and the item needs it.
2457 // We cannot use itemAcceptsHoverEvents_helper() here, since we need to enable
2458 // mouse tracking also if this item is temporarily blocked by a modal panel.
2459
2460 auto needsMouseTracking = [](const QGraphicsItemPrivate *item) {
2461 return item->acceptsHover
2462 || (item->isWidget && static_cast<const QGraphicsWidgetPrivate *>(item)->hasDecoration());
2463 };
2464
2465 if (d->allItemsIgnoreHoverEvents && needsMouseTracking(item->d_ptr.data())) {
2466 d->allItemsIgnoreHoverEvents = false;
2467 d->enableMouseTrackingOnViews();
2468 }
2469#ifndef QT_NO_CURSOR
2470 if (d->allItemsUseDefaultCursor && item->d_ptr->hasCursor) {
2471 d->allItemsUseDefaultCursor = false;
2472 if (d->allItemsIgnoreHoverEvents) // already enabled otherwise
2473 d->enableMouseTrackingOnViews();
2474 }
2475#endif //QT_NO_CURSOR
2476
2477 // Enable touch events if the item accepts touch events.
2478 if (d->allItemsIgnoreTouchEvents && item->d_ptr->acceptTouchEvents) {
2479 d->allItemsIgnoreTouchEvents = false;
2480 d->enableTouchEventsOnViews();
2481 }
2482
2483#ifndef QT_NO_GESTURES
2484 for (auto it = item->d_ptr->gestureContext.constBegin();
2486 d->grabGesture(item, it.key());
2487#endif
2488
2489 // Update selection lists
2490 if (item->isSelected())
2491 d->selectedItems << item;
2492 if (item->isWidget() && item->isVisible() && static_cast<QGraphicsWidget *>(item)->windowType() == Qt::Popup)
2493 d->addPopup(static_cast<QGraphicsWidget *>(item));
2495 d->enterModal(item);
2496
2497 // Update creation order focus chain. Make sure to leave the widget's
2498 // internal tab order intact.
2499 if (item->isWidget()) {
2500 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
2501 if (!d->tabFocusFirst) {
2502 // No first tab focus widget - make this the first tab focus
2503 // widget.
2504 d->tabFocusFirst = widget;
2505 } else if (!widget->parentWidget() && !widget->isPanel()) {
2506 // Adding a widget that is not part of a tab focus chain.
2507 QGraphicsWidget *myNewPrev = d->tabFocusFirst->d_func()->focusPrev;
2508 myNewPrev->d_func()->focusNext = widget;
2509 widget->d_func()->focusPrev->d_func()->focusNext = d->tabFocusFirst;
2510 d->tabFocusFirst->d_func()->focusPrev = widget->d_func()->focusPrev;
2511 widget->d_func()->focusPrev = myNewPrev;
2512 }
2513 }
2514
2515 // Add all children recursively
2517 for (auto child : std::as_const(item->d_ptr->children))
2518 addItem(child);
2519
2520 // Resolve font and palette.
2521 item->d_ptr->resolveFont(d->font.resolveMask());
2522 item->d_ptr->resolvePalette(d->palette.resolveMask());
2523
2524
2525 // Re-enable selectionChanged() for individual items
2526 --d->selectionChanging;
2527 if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemSize)
2529
2530 // Deliver post-change notification
2532
2533 // Update explicit activation
2534 bool autoActivate = true;
2535 if (!d->childExplicitActivation && item->d_ptr->explicitActivate)
2536 d->childExplicitActivation = item->d_ptr->wantsActive ? 1 : 2;
2537 if (d->childExplicitActivation && item->isPanel()) {
2538 if (d->childExplicitActivation == 1)
2540 else
2541 autoActivate = false;
2542 d->childExplicitActivation = 0;
2543 } else if (!item->d_ptr->parent) {
2544 d->childExplicitActivation = 0;
2545 }
2546
2547 // Auto-activate this item's panel if nothing else has been activated
2548 if (autoActivate) {
2549 if (!d->lastActivePanel && !d->activePanel && item->isPanel()) {
2550 if (isActive())
2552 else
2553 d->lastActivePanel = item;
2554 }
2555 }
2556
2558 d->registerScenePosItem(item);
2559
2560 // Ensure that newly added items that have subfocus set, gain
2561 // focus automatically if there isn't a focus item already.
2562 if (!d->focusItem && item != d->lastFocusItem && item->focusItem() == item)
2563 item->focusItem()->setFocus();
2564
2565 d->updateInputMethodSensitivityInViews();
2566}
2567
2584{
2586 item->setPen(pen);
2587 item->setBrush(brush);
2588 addItem(item);
2589 return item;
2590}
2591
2616{
2618 item->setPen(pen);
2619 addItem(item);
2620 return item;
2621}
2622
2647{
2649 item->setPen(pen);
2650 item->setBrush(brush);
2651 addItem(item);
2652 return item;
2653}
2654
2675
2692 const QPen &pen, const QBrush &brush)
2693{
2695 item->setPen(pen);
2696 item->setBrush(brush);
2697 addItem(item);
2698 return item;
2699}
2700
2719{
2721 item->setPen(pen);
2722 item->setBrush(brush);
2723 addItem(item);
2724 return item;
2725}
2726
2750{
2752 item->setFont(font);
2753 addItem(item);
2754 return item;
2755}
2756
2778
2798{
2799 QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(nullptr, wFlags);
2800 proxy->setWidget(widget);
2801 addItem(proxy);
2802 return proxy;
2803}
2804
2813{
2814 // ### Refactoring: This function shares much functionality with _q_removeItemLater()
2815 Q_D(QGraphicsScene);
2816 if (!item) {
2817 qWarning("QGraphicsScene::removeItem: cannot remove 0-item");
2818 return;
2819 }
2820 if (item->scene() != this) {
2821 qWarning("QGraphicsScene::removeItem: item %p's scene (%p)"
2822 " is different from this scene (%p)",
2823 item, item->scene(), this);
2824 return;
2825 }
2826
2827 // Notify the item that it's scene is changing to 0, allowing the item to
2828 // react.
2830 QVariant::fromValue<QGraphicsScene *>(0)));
2831 QGraphicsScene *targetScene = qvariant_cast<QGraphicsScene *>(newSceneVariant);
2832 if (targetScene != nullptr && targetScene != this) {
2833 targetScene->addItem(item);
2834 return;
2835 }
2836
2837 d->removeItemHelper(item);
2838
2839 // Deliver post-change notification
2841
2842 d->updateInputMethodSensitivityInViews();
2843}
2844
2857{
2858 Q_D(const QGraphicsScene);
2859 return isActive() ? d->focusItem : d->passiveFocusItem;
2860}
2861
2879{
2880 Q_D(QGraphicsScene);
2881 if (item)
2882 item->setFocus(focusReason);
2883 else
2884 d->setFocusItemHelper(item, focusReason);
2885}
2886
2895{
2896 Q_D(const QGraphicsScene);
2897 return d->hasFocus;
2898}
2899
2911{
2912 Q_D(QGraphicsScene);
2913 if (d->hasFocus || !isActive())
2914 return;
2915 QFocusEvent event(QEvent::FocusIn, focusReason);
2917}
2918
2929{
2930 Q_D(QGraphicsScene);
2931 if (d->hasFocus) {
2932 d->hasFocus = false;
2933 d->passiveFocusItem = d->focusItem;
2935 }
2936}
2937
2957{
2958 Q_D(QGraphicsScene);
2959 d->stickyFocus = enabled;
2960}
2962{
2963 Q_D(const QGraphicsScene);
2964 return d->stickyFocus;
2965}
2966
2990{
2991 Q_D(const QGraphicsScene);
2992 return !d->mouseGrabberItems.isEmpty() ? d->mouseGrabberItems.last() : 0;
2993}
2994
3012{
3013 Q_D(const QGraphicsScene);
3014 return d->backgroundBrush;
3015}
3017{
3018 Q_D(QGraphicsScene);
3019 d->backgroundBrush = brush;
3020 for (QGraphicsView *view : std::as_const(d->views)) {
3021 view->resetCachedContent();
3022 view->viewport()->update();
3023 }
3024 update();
3025}
3026
3048{
3049 Q_D(const QGraphicsScene);
3050 return d->foregroundBrush;
3051}
3053{
3054 Q_D(QGraphicsScene);
3055 d->foregroundBrush = brush;
3056 const auto views_ = views();
3057 for (QGraphicsView *view : views_)
3058 view->viewport()->update();
3059 update();
3060}
3061
3072{
3073 Q_D(const QGraphicsScene);
3074 if (!d->focusItem || !(d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
3075 return QVariant();
3076 const QTransform matrix = d->focusItem->sceneTransform();
3077 QVariant value = d->focusItem->inputMethodQuery(query);
3078 if (value.userType() == QMetaType::QRectF)
3079 value = matrix.mapRect(value.toRectF());
3080 else if (value.userType() == QMetaType::QPointF)
3081 value = matrix.map(value.toPointF());
3082 else if (value.userType() == QMetaType::QRect)
3083 value = matrix.mapRect(value.toRect());
3084 else if (value.userType() == QMetaType::QPoint)
3085 value = matrix.map(value.toPoint());
3086 return value;
3087}
3088
3096{
3097 Q_D(QGraphicsScene);
3098 if (d->updateAll || (rect.isEmpty() && !rect.isNull()))
3099 return;
3100
3101 // Check if anyone's connected; if not, we can send updates directly to
3102 // the views. Otherwise or if there are no views, use old behavior.
3103 bool directUpdates = !(d->isSignalConnected(d->changedSignalIndex)) && !d->views.isEmpty();
3104 if (rect.isNull()) {
3105 d->updateAll = true;
3106 d->updatedRects.clear();
3107 if (directUpdates) {
3108 // Update all views.
3109 for (auto view : std::as_const(d->views))
3110 view->d_func()->fullUpdatePending = true;
3111 }
3112 } else {
3113 if (directUpdates) {
3114 // Update all views.
3115 for (auto view : std::as_const(d->views)) {
3116 if (view->isTransformed())
3117 view->d_func()->updateRectF(view->viewportTransform().mapRect(rect));
3118 else
3119 view->d_func()->updateRectF(rect);
3120 }
3121 } else {
3122 d->updatedRects.insert(rect);
3123 }
3124 }
3125
3126 if (!d->calledEmitUpdated) {
3127 d->calledEmitUpdated = true;
3128 QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection);
3129 }
3130}
3131
3163{
3164 const auto views_ = views();
3165 for (QGraphicsView *view : views_)
3166 view->invalidateScene(rect, layers);
3167 update(rect);
3168}
3169
3184QList <QGraphicsView *> QGraphicsScene::views() const
3185{
3186 Q_D(const QGraphicsScene);
3187 return d->views;
3188}
3189
3204{
3205 for (int i = 0; i < 2; ++i) {
3206 const auto items_ = items();
3207 for (QGraphicsItem *item : items_)
3208 item->advance(i);
3209 }
3210}
3211
3234{
3235 Q_D(QGraphicsScene);
3236
3237 switch (event->type()) {
3245 case QEvent::TouchBegin:
3247 case QEvent::TouchEnd:
3248 // Reset the under-mouse list to ensure that this event gets fresh
3249 // item-under-mouse data. Be careful about this list; if people delete
3250 // items from inside event handlers, this list can quickly end up
3251 // having stale pointers in it. We need to clear it before dispatching
3252 // events that use it.
3253 // ### this should only be cleared if we received a new mouse move event,
3254 // which relies on us fixing the replay mechanism in QGraphicsView.
3255 d->cachedItemsUnderMouse.clear();
3256 break;
3257 default:
3258 break;
3259 }
3260
3261 switch (event->type()) {
3264 break;
3267 break;
3270 break;
3273 break;
3276 break;
3277 case QEvent::KeyPress:
3278 if (!d->focusItem) {
3279 QKeyEvent *k = static_cast<QKeyEvent *>(event);
3280 if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
3281 if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
3282 bool res = false;
3283 if (k->key() == Qt::Key_Backtab
3284 || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) {
3285 res = focusNextPrevChild(false);
3286 } else if (k->key() == Qt::Key_Tab) {
3287 res = focusNextPrevChild(true);
3288 }
3289 if (!res)
3290 event->ignore();
3291 return true;
3292 }
3293 }
3294 }
3295 keyPressEvent(static_cast<QKeyEvent *>(event));
3296 break;
3297 case QEvent::KeyRelease:
3298 keyReleaseEvent(static_cast<QKeyEvent *>(event));
3299 break;
3302 while (parent) {
3303 d->sendEvent(parent, event);
3304 if (event->isAccepted())
3305 return true;
3306 parent = parent->parentItem();
3307 }
3308 }
3309 return false;
3311 {
3312 QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent *>(event);
3313 d->lastSceneMousePos = mouseEvent->scenePos();
3314 mouseMoveEvent(mouseEvent);
3315 break;
3316 }
3319 break;
3322 break;
3325 break;
3327 wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event));
3328 break;
3329 case QEvent::FocusIn:
3330 focusInEvent(static_cast<QFocusEvent *>(event));
3331 break;
3332 case QEvent::FocusOut:
3333 focusOutEvent(static_cast<QFocusEvent *>(event));
3334 break;
3338 {
3339 QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event);
3340 d->lastSceneMousePos = hoverEvent->scenePos();
3341 d->dispatchHoverEvent(hoverEvent);
3342 break;
3343 }
3344 case QEvent::Leave:
3345 Q_ASSERT_X(false, "QGraphicsScene::event",
3346 "QGraphicsScene must not receive QEvent::Leave, use GraphicsSceneLeave");
3347 break;
3349 {
3350 auto *leaveEvent = static_cast<QGraphicsSceneEvent*>(event);
3351 d->leaveScene(leaveEvent->widget());
3352 break;
3353 }
3355 helpEvent(static_cast<QGraphicsSceneHelpEvent *>(event));
3356 break;
3358 inputMethodEvent(static_cast<QInputMethodEvent *>(event));
3359 break;
3361 if (!d->activationRefCount++) {
3362 if (d->lastActivePanel) {
3363 // Activate the last panel.
3364 d->setActivePanelHelper(d->lastActivePanel, true);
3365 } else if (d->tabFocusFirst && d->tabFocusFirst->isPanel()) {
3366 // Activate the panel of the first item in the tab focus
3367 // chain.
3368 d->setActivePanelHelper(d->tabFocusFirst, true);
3369 } else {
3370 // Activate all toplevel items.
3372 const auto items_ = items();
3373 for (QGraphicsItem *item : items_) {
3374 if (item->isVisible() && !item->isPanel() && !item->parentItem())
3375 sendEvent(item, &event);
3376 }
3377 }
3378 }
3379 break;
3381 if (!--d->activationRefCount) {
3382 if (d->activePanel) {
3383 // Deactivate the active panel (but keep it so we can
3384 // reactivate it later).
3385 QGraphicsItem *lastActivePanel = d->activePanel;
3386 d->setActivePanelHelper(nullptr, true);
3387 d->lastActivePanel = lastActivePanel;
3388 } else {
3389 // Activate all toplevel items.
3391 const auto items_ = items();
3392 for (QGraphicsItem *item : items_) {
3393 if (item->isVisible() && !item->isPanel() && !item->parentItem())
3394 sendEvent(item, &event);
3395 }
3396 }
3397 }
3398 break;
3400 // Resolve the existing scene font.
3401 d->resolveFont();
3402 break;
3403 }
3404 case QEvent::FontChange:
3405 // Update the entire scene when the font changes.
3406 update();
3407 break;
3409 // Resolve the existing scene palette.
3410 d->resolvePalette();
3411 break;
3412 }
3414 // Update the entire scene when the palette changes.
3415 update();
3416 break;
3418 // Reresolve all widgets' styles. Update all top-level widgets'
3419 // geometries that do not have an explicit style set.
3420 update();
3421 break;
3423 // Because QGraphicsItem is not a QObject, QStyle driven
3424 // animations are forced to update the whole scene
3425 update();
3426 break;
3427 case QEvent::TouchBegin:
3429 case QEvent::TouchEnd:
3430 d->touchEventHandler(static_cast<QTouchEvent *>(event));
3431 break;
3432#ifndef QT_NO_GESTURES
3433 case QEvent::Gesture:
3435 d->gestureEventHandler(static_cast<QGestureEvent *>(event));
3436 break;
3437#endif // QT_NO_GESTURES
3438 default:
3439 return QObject::event(event);
3440 }
3441 return true;
3442}
3443
3451{
3452 if (watched != qApp)
3453 return false;
3454
3455 switch (event->type()) {
3458 break;
3461 break;
3462 default:
3463 break;
3464 }
3465 return false;
3466}
3467
3480{
3481 Q_D(QGraphicsScene);
3482 // Ignore by default.
3483 contextMenuEvent->ignore();
3484
3485 // Send the event to all items at this position until one item accepts the
3486 // event.
3487 const auto items = d->itemsAtPosition(contextMenuEvent->screenPos(),
3488 contextMenuEvent->scenePos(),
3489 contextMenuEvent->widget());
3490 for (QGraphicsItem *item : items) {
3492 contextMenuEvent->widget()));
3493 contextMenuEvent->accept();
3494 if (!d->sendEvent(item, contextMenuEvent))
3495 break;
3496
3497 if (contextMenuEvent->isAccepted())
3498 break;
3499 }
3500}
3501
3513{
3514 Q_D(QGraphicsScene);
3515 d->dragDropItem = nullptr;
3516 d->lastDropAction = Qt::IgnoreAction;
3517 event->accept();
3518}
3519
3530{
3531 Q_D(QGraphicsScene);
3532 event->ignore();
3533
3534 if (!d->mouseGrabberItems.isEmpty()) {
3535 // Mouse grabbers that start drag events lose the mouse grab.
3536 d->clearMouseGrabber();
3537 d->mouseGrabberButtonDownPos.clear();
3538 d->mouseGrabberButtonDownScenePos.clear();
3539 d->mouseGrabberButtonDownScreenPos.clear();
3540 }
3541
3542 bool eventDelivered = false;
3543
3544 // Find the topmost enabled items under the cursor. They are all
3545 // candidates for accepting drag & drop events.
3546 const auto items = d->itemsAtPosition(event->screenPos(),
3547 event->scenePos(),
3548 event->widget());
3549 for (QGraphicsItem *item : items) {
3550 if (!item->isEnabled() || !item->acceptDrops())
3551 continue;
3552
3553 if (item != d->dragDropItem) {
3554 // Enter the new drag drop item. If it accepts the event, we send
3555 // the leave to the parent item.
3557 d->cloneDragDropEvent(&dragEnter, event);
3558 dragEnter.setDropAction(event->proposedAction());
3559 d->sendDragDropEvent(item, &dragEnter);
3560 event->setAccepted(dragEnter.isAccepted());
3561 event->setDropAction(dragEnter.dropAction());
3562 if (!event->isAccepted()) {
3563 // Propagate to the item under
3564 continue;
3565 }
3566
3567 d->lastDropAction = event->dropAction();
3568
3569 if (d->dragDropItem) {
3570 // Leave the last drag drop item. A perfect implementation
3571 // would set the position of this event to the point where
3572 // this event and the last event intersect with the item's
3573 // shape, but that's not easy to do. :-)
3575 d->cloneDragDropEvent(&dragLeave, event);
3576 d->sendDragDropEvent(d->dragDropItem, &dragLeave);
3577 }
3578
3579 // We've got a new drag & drop item
3580 d->dragDropItem = item;
3581 }
3582
3583 // Send the move event.
3584 event->setDropAction(d->lastDropAction);
3585 event->accept();
3586 d->sendDragDropEvent(item, event);
3587 if (event->isAccepted())
3588 d->lastDropAction = event->dropAction();
3589 eventDelivered = true;
3590 break;
3591 }
3592
3593 if (!eventDelivered) {
3594 if (d->dragDropItem) {
3595 // Leave the last drag drop item
3597 d->cloneDragDropEvent(&dragLeave, event);
3598 d->sendDragDropEvent(d->dragDropItem, &dragLeave);
3599 d->dragDropItem = nullptr;
3600 }
3601 // Propagate
3602 event->setDropAction(Qt::IgnoreAction);
3603 }
3604}
3605
3614{
3615 Q_D(QGraphicsScene);
3616 if (d->dragDropItem) {
3617 // Leave the last drag drop item
3618 d->sendDragDropEvent(d->dragDropItem, event);
3619 d->dragDropItem = nullptr;
3620 }
3621}
3622
3631{
3632 Q_UNUSED(event);
3633 Q_D(QGraphicsScene);
3634 if (d->dragDropItem) {
3635 // Drop on the last drag drop item
3636 d->sendDragDropEvent(d->dragDropItem, event);
3637 d->dragDropItem = nullptr;
3638 }
3639}
3640
3651{
3652 Q_D(QGraphicsScene);
3653
3654 d->hasFocus = true;
3655 switch (focusEvent->reason()) {
3656 case Qt::TabFocusReason:
3657 if (!focusNextPrevChild(true))
3658 focusEvent->ignore();
3659 break;
3661 if (!focusNextPrevChild(false))
3662 focusEvent->ignore();
3663 break;
3664 default:
3665 if (d->passiveFocusItem) {
3666 // Set focus on the last focus item
3667 setFocusItem(d->passiveFocusItem, focusEvent->reason());
3668 }
3669 break;
3670 }
3671}
3672
3683{
3684 Q_D(QGraphicsScene);
3685 d->hasFocus = false;
3686 d->passiveFocusItem = d->focusItem;
3687 setFocusItem(nullptr, focusEvent->reason());
3688
3689 // Remove all popups when the scene loses focus.
3690 if (!d->popupWidgets.isEmpty())
3691 d->removePopup(d->popupWidgets.constFirst());
3692}
3693
3710{
3711#if !QT_CONFIG(tooltip)
3713#else
3714 // Find the first item that does tooltips
3715 Q_D(QGraphicsScene);
3716 const QList<QGraphicsItem *> itemsAtPos = d->itemsAtPosition(helpEvent->screenPos(),
3717 helpEvent->scenePos(),
3718 helpEvent->widget());
3719 QGraphicsItem *toolTipItem = nullptr;
3720 for (auto item : itemsAtPos) {
3721 if (item->d_func()->isProxyWidget()) {
3722 // if the item is a proxy widget, the event is forwarded to it
3724 if (helpEvent->isAccepted())
3725 return;
3726 }
3727 if (!item->toolTip().isEmpty()) {
3728 toolTipItem = item;
3729 break;
3730 }
3731 }
3732
3733 // Show or hide the tooltip
3734 QString text;
3735 QPoint point;
3736 if (toolTipItem && !toolTipItem->toolTip().isEmpty()) {
3737 text = toolTipItem->toolTip();
3738 point = helpEvent->screenPos();
3739 }
3740 QToolTip::showText(point, text, helpEvent->widget());
3741 helpEvent->setAccepted(!text.isEmpty());
3742#endif
3743}
3744
3746{
3747 return (item->d_ptr->acceptsHover
3748 || (item->d_ptr->isWidget
3749 && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration()))
3751}
3752
3764{
3766 return false;
3767
3768 // Find the first item that accepts hover events, reusing earlier
3769 // calculated data is possible.
3772 hoverEvent->scenePos(),
3773 hoverEvent->widget());
3774 }
3775
3776 QGraphicsItem *item = nullptr;
3777 for (auto tmp : std::as_const(cachedItemsUnderMouse)) {
3779 item = tmp;
3780 break;
3781 }
3782 }
3783
3784 // Find the common ancestor item for the new topmost hoverItem and the
3785 // last item in the hoverItem list.
3786 QGraphicsItem *commonAncestorItem = (item && !hoverItems.isEmpty()) ? item->commonAncestorItem(hoverItems.constLast()) : nullptr;
3787 while (commonAncestorItem && !itemAcceptsHoverEvents_helper(commonAncestorItem))
3788 commonAncestorItem = commonAncestorItem->parentItem();
3789 if (commonAncestorItem && commonAncestorItem->panel() != item->panel()) {
3790 // The common ancestor isn't in the same panel as the two hovered
3791 // items.
3792 commonAncestorItem = nullptr;
3793 }
3794
3795 // Check if the common ancestor item is known.
3796 int index = commonAncestorItem ? hoverItems.indexOf(commonAncestorItem) : -1;
3797 // Send hover leaves to any existing hovered children of the common
3798 // ancestor item.
3799 for (int i = hoverItems.size() - 1; i > index; --i) {
3800 QGraphicsItem *lastItem = hoverItems.takeLast();
3801 if (itemAcceptsHoverEvents_helper(lastItem))
3802 sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, hoverEvent);
3803 }
3804
3805 // Item is a child of a known item. Generate enter events for the
3806 // missing links.
3807 QList<QGraphicsItem *> parents;
3809 while (parent && parent != commonAncestorItem) {
3810 parents.append(parent);
3811 if (parent->isPanel()) {
3812 // Stop at the panel - we don't deliver beyond this point.
3813 break;
3814 }
3815 parent = parent->parentItem();
3816 }
3817 for (auto it = parents.crbegin(), end = parents.crend(); it != end; ++it) {
3819 hoverItems << parent;
3822 }
3823
3824 // Generate a move event for the item itself
3825 if (item
3826 && !hoverItems.isEmpty()
3827 && item == hoverItems.constLast()) {
3829 return true;
3830 }
3831 return false;
3832}
3833
3841{
3842#if QT_CONFIG(tooltip)
3844#endif
3845 QGraphicsView *view = qobject_cast<QGraphicsView *>(viewport->parent());
3846 // Send HoverLeave events to all existing hover items, topmost first.
3847 QGraphicsSceneHoverEvent hoverEvent;
3848 hoverEvent.setWidget(viewport);
3849
3850 if (view) {
3851 QPoint cursorPos = QCursor::pos();
3852 hoverEvent.setScenePos(view->mapToScene(viewport->mapFromGlobal(cursorPos)));
3853 hoverEvent.setLastScenePos(hoverEvent.scenePos());
3854 hoverEvent.setScreenPos(cursorPos);
3855 hoverEvent.setLastScreenPos(hoverEvent.screenPos());
3856 }
3857
3858 while (!hoverItems.isEmpty()) {
3859 QGraphicsItem *lastItem = hoverItems.takeLast();
3860 if (itemAcceptsHoverEvents_helper(lastItem))
3861 sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, &hoverEvent);
3862 }
3863}
3864
3873{
3874 // ### Merge this function with keyReleaseEvent; they are identical
3875 // ### (except this comment).
3876 Q_D(QGraphicsScene);
3877 QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.constLast() : 0;
3878 if (!item)
3879 item = focusItem();
3880 if (item) {
3881 QGraphicsItem *p = item;
3882 do {
3883 // Accept the event by default
3884 keyEvent->accept();
3885 // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
3886 // is filtered out, stop propagating it.
3887 if (p->isBlockedByModalPanel())
3888 break;
3889 if (!d->sendEvent(p, keyEvent))
3890 break;
3891 } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
3892 } else {
3893 keyEvent->ignore();
3894 }
3895}
3896
3905{
3906 // ### Merge this function with keyPressEvent; they are identical (except
3907 // ### this comment).
3908 Q_D(QGraphicsScene);
3909 QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.constLast() : 0;
3910 if (!item)
3911 item = focusItem();
3912 if (item) {
3913 QGraphicsItem *p = item;
3914 do {
3915 // Accept the event by default
3916 keyEvent->accept();
3917 // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
3918 // is filtered out, stop propagating it.
3919 if (p->isBlockedByModalPanel())
3920 break;
3921 if (!d->sendEvent(p, keyEvent))
3922 break;
3923 } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
3924 } else {
3925 keyEvent->ignore();
3926 }
3927}
3928
3949{
3950 Q_D(QGraphicsScene);
3951 if (d->mouseGrabberItems.isEmpty()) {
3952 // Dispatch hover events
3954 _q_hoverFromMouseEvent(&hover, mouseEvent);
3955 d->dispatchHoverEvent(&hover);
3956 }
3957
3958 d->mousePressEventHandler(mouseEvent);
3959}
3960
3974{
3975 Q_D(QGraphicsScene);
3976 if (d->mouseGrabberItems.isEmpty()) {
3977 if (mouseEvent->buttons())
3978 return;
3980 _q_hoverFromMouseEvent(&hover, mouseEvent);
3981 mouseEvent->setAccepted(d->dispatchHoverEvent(&hover));
3982 return;
3983 }
3984
3985 // Forward the event to the mouse grabber
3986 d->sendMouseEvent(mouseEvent);
3987 mouseEvent->accept();
3988}
3989
4004{
4005 Q_D(QGraphicsScene);
4006 if (d->mouseGrabberItems.isEmpty()) {
4007 mouseEvent->ignore();
4008 return;
4009 }
4010
4011 // Forward the event to the mouse grabber
4012 d->sendMouseEvent(mouseEvent);
4013 mouseEvent->accept();
4014
4015 // Reset the mouse grabber when the last mouse button has been released.
4016 if (!mouseEvent->buttons()) {
4017 if (!d->mouseGrabberItems.isEmpty()) {
4018 d->lastMouseGrabberItem = d->mouseGrabberItems.constLast();
4019 if (d->lastMouseGrabberItemHasImplicitMouseGrab)
4020 d->mouseGrabberItems.constLast()->ungrabMouse();
4021 } else {
4022 d->lastMouseGrabberItem = nullptr;
4023 }
4024
4025 // Generate a hoverevent
4026 QGraphicsSceneHoverEvent hoverEvent;
4027 _q_hoverFromMouseEvent(&hoverEvent, mouseEvent);
4028 d->dispatchHoverEvent(&hoverEvent);
4029 }
4030}
4031
4052{
4053 Q_D(QGraphicsScene);
4054 d->mousePressEventHandler(mouseEvent);
4055}
4056
4071{
4072 Q_D(QGraphicsScene);
4073 const QList<QGraphicsItem *> wheelCandidates = d->itemsAtPosition(wheelEvent->screenPos(),
4074 wheelEvent->scenePos(),
4075 wheelEvent->widget());
4076
4077 // Find the first popup under the mouse (including the popup's descendants) starting from the last.
4078 // Remove all popups after the one found, or all or them if no popup is under the mouse.
4079 // Then continue with the event.
4080 QList<QGraphicsWidget *>::const_iterator iter = d->popupWidgets.constEnd();
4081 while (iter > d->popupWidgets.constBegin() && !wheelCandidates.isEmpty()) {
4082 --iter;
4083 if (wheelCandidates.first() == *iter || (*iter)->isAncestorOf(wheelCandidates.first()))
4084 break;
4085 d->removePopup(*iter);
4086 }
4087
4088 bool hasSetFocus = false;
4089 for (QGraphicsItem *item : wheelCandidates) {
4090 if (!hasSetFocus && item->isEnabled()
4092 if (item->isWidget() && static_cast<QGraphicsWidget *>(item)->focusPolicy() == Qt::WheelFocus) {
4093 hasSetFocus = true;
4094 if (item != focusItem())
4096 }
4097 }
4098
4099 wheelEvent->setPos(item->d_ptr->genericMapFromScene(wheelEvent->scenePos(),
4100 wheelEvent->widget()));
4101 wheelEvent->accept();
4102 bool isPanel = item->isPanel();
4103 bool ret = d->sendEvent(item, wheelEvent);
4104
4105 if (ret && (isPanel || wheelEvent->isAccepted()))
4106 break;
4107 }
4108}
4109
4121{
4122 Q_D(QGraphicsScene);
4123 if (d->focusItem && (d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod)) {
4124 d->sendEvent(d->focusItem, event);
4125 return;
4126 }
4127 if (d->lastFocusItem && d->lastFocusItem != d->focusItem && (d->lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
4128 d->sendEvent(d->lastFocusItem, event);
4129}
4130
4145{
4146 Q_D(QGraphicsScene);
4147
4148 if (d->backgroundBrush.style() != Qt::NoBrush) {
4149 if (d->painterStateProtection)
4150 painter->save();
4151 painter->setBrushOrigin(0, 0);
4153 if (d->painterStateProtection)
4154 painter->restore();
4155 }
4156}
4157
4172{
4173 Q_D(QGraphicsScene);
4174
4175 if (d->foregroundBrush.style() != Qt::NoBrush) {
4176 if (d->painterStateProtection)
4177 painter->save();
4178 painter->setBrushOrigin(0, 0);
4180 if (d->painterStateProtection)
4181 painter->restore();
4182 }
4183}
4184
4187 bool useWindowOpacity, bool painterStateProtection)
4188{
4189 if (!item->isWidget()) {
4191 return;
4192 }
4193 QGraphicsWidget *widgetItem = static_cast<QGraphicsWidget *>(item);
4194 QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(widgetItem);
4195 const qreal windowOpacity = (proxy && proxy->widget() && useWindowOpacity)
4196 ? proxy->widget()->windowOpacity() : 1.0;
4197 const qreal oldPainterOpacity = painter->opacity();
4198
4199 if (qFuzzyIsNull(windowOpacity))
4200 return;
4201 // Set new painter opacity.
4202 if (windowOpacity < 1.0)
4203 painter->setOpacity(oldPainterOpacity * windowOpacity);
4204
4205 // set layoutdirection on the painter
4206 Qt::LayoutDirection oldLayoutDirection = painter->layoutDirection();
4208
4209 if (widgetItem->isWindow() && widgetItem->windowType() != Qt::Popup && widgetItem->windowType() != Qt::ToolTip
4210 && !(widgetItem->windowFlags() & Qt::FramelessWindowHint)) {
4211 if (painterStateProtection)
4212 painter->save();
4213 widgetItem->paintWindowFrame(painter, option, widget);
4214 if (painterStateProtection)
4215 painter->restore();
4216 } else if (widgetItem->autoFillBackground()) {
4217 painter->fillRect(option->exposedRect, widgetItem->palette().window());
4218 }
4219
4220 widgetItem->paint(painter, option, widget);
4221
4222 // Restore layoutdirection on the painter.
4223 painter->setLayoutDirection(oldLayoutDirection);
4224 // Restore painter opacity.
4225 if (windowOpacity < 1.0)
4226 painter->setOpacity(oldPainterOpacity);
4227}
4228
4229static void _q_paintIntoCache(QPixmap *pix, QGraphicsItem *item, const QRegion &pixmapExposed,
4230 const QTransform &itemToPixmap, QPainter::RenderHints renderHints,
4231 const QStyleOptionGraphicsItem *option, bool painterStateProtection)
4232{
4233 QPixmap subPix;
4234 QPainter pixmapPainter;
4235 QRect br = pixmapExposed.boundingRect();
4236
4237 // Don't use subpixmap if we get a full update.
4238 if (pixmapExposed.isEmpty() || (pixmapExposed.rectCount() == 1 && br.contains(pix->rect()))) {
4240 pixmapPainter.begin(pix);
4241 } else {
4242 subPix = QPixmap(br.size() * pix->devicePixelRatio());
4243 subPix.setDevicePixelRatio(pix->devicePixelRatio());
4244 subPix.fill(Qt::transparent);
4245 pixmapPainter.begin(&subPix);
4246 pixmapPainter.translate(-br.topLeft());
4247 if (!pixmapExposed.isEmpty()) {
4248 // Applied to subPix; paint is adjusted to the coordinate space is
4249 // correct.
4250 pixmapPainter.setClipRegion(pixmapExposed);
4251 }
4252 }
4253
4254 pixmapPainter.setRenderHints(pixmapPainter.renderHints(), false);
4255 pixmapPainter.setRenderHints(renderHints, true);
4256 pixmapPainter.setWorldTransform(itemToPixmap, true);
4257
4258 // Render.
4259 _q_paintItem(item, &pixmapPainter, option, nullptr, false, painterStateProtection);
4260 pixmapPainter.end();
4261
4262 if (!subPix.isNull()) {
4263 // Blit the subpixmap into the main pixmap.
4264 pixmapPainter.begin(pix);
4265 pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
4266 pixmapPainter.setClipRegion(pixmapExposed);
4267 pixmapPainter.drawPixmap(br.topLeft(), subPix);
4268 pixmapPainter.end();
4269 }
4270}
4271
4272// Copied from qpaintengine_vg.cpp
4273// Returns \c true for 90, 180, and 270 degree rotations.
4274static inline bool transformIsSimple(const QTransform& transform)
4275{
4277 if (type <= QTransform::TxScale) {
4278 return true;
4279 } else if (type == QTransform::TxRotate) {
4280 // Check for 90, and 270 degree rotations.
4281 qreal m11 = transform.m11();
4282 qreal m12 = transform.m12();
4283 qreal m21 = transform.m21();
4284 qreal m22 = transform.m22();
4285 if (m11 == 0.0f && m22 == 0.0f) {
4286 if (m12 == 1.0f && m21 == -1.0f)
4287 return true; // 90 degrees.
4288 else if (m12 == -1.0f && m21 == 1.0f)
4289 return true; // 270 degrees.
4290 else if (m12 == -1.0f && m21 == -1.0f)
4291 return true; // 90 degrees inverted y.
4292 else if (m12 == 1.0f && m21 == 1.0f)
4293 return true; // 270 degrees inverted y.
4294 }
4295 }
4296 return false;
4297}
4298
4306 bool painterStateProtection)
4307{
4308 QGraphicsItemPrivate *itemd = item->d_ptr.data();
4309 QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode);
4310
4311 // Render directly, using no cache.
4312 if (cacheMode == QGraphicsItem::NoCache) {
4314 return;
4315 }
4316
4317 const qreal devicePixelRatio = painter->device()->devicePixelRatio();
4318 const qreal oldPainterOpacity = painter->opacity();
4319 qreal newPainterOpacity = oldPainterOpacity;
4320 QGraphicsProxyWidget *proxy = item->isWidget() ? qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(item)) : 0;
4321 if (proxy && proxy->widget()) {
4322 const qreal windowOpacity = proxy->widget()->windowOpacity();
4323 if (windowOpacity < 1.0)
4324 newPainterOpacity *= windowOpacity;
4325 }
4326
4327 // Item's (local) bounding rect
4328 QRectF brect = item->boundingRect();
4329 QRectF adjustedBrect(brect);
4330 _q_adjustRect(&adjustedBrect);
4331 if (adjustedBrect.isEmpty())
4332 return;
4333
4334 // Fetch the off-screen transparent buffer and exposed area info.
4335 QPixmapCache::Key pixmapKey;
4336 QPixmap pix;
4337
4338 bool pixmapFound;
4339 QGraphicsItemCache *itemCache = itemd->extraItemCache();
4340 if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
4341 pixmapKey = itemCache->key;
4342 } else {
4343 pixmapKey = itemCache->deviceData.value(widget).key;
4344 }
4345
4346 // Find pixmap in cache.
4347 pixmapFound = QPixmapCache::find(pixmapKey, &pix);
4348
4349 // Render using item coordinate cache mode.
4350 if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
4351 QSize pixmapSize;
4352 bool fixedCacheSize = itemCache->fixedSize.isValid();
4353 QRect br = brect.toAlignedRect();
4354 if (fixedCacheSize) {
4355 pixmapSize = itemCache->fixedSize;
4356 } else {
4357 pixmapSize = br.size();
4358 }
4359
4360 pixmapSize *= devicePixelRatio;
4361
4362 // Create or recreate the pixmap.
4363 int adjust = itemCache->fixedSize.isValid() ? 0 : 2;
4364 QSize adjustSize(adjust*2, adjust*2);
4365 br.adjust(-adjust / devicePixelRatio, -adjust / devicePixelRatio, adjust / devicePixelRatio, adjust / devicePixelRatio);
4366 if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) {
4367 pix = QPixmap(pixmapSize + adjustSize);
4368 itemCache->boundingRect = br;
4369 itemCache->exposed.clear();
4370 itemCache->allExposed = true;
4371 } else if (itemCache->boundingRect != br) {
4372 itemCache->boundingRect = br;
4373 itemCache->exposed.clear();
4374 itemCache->allExposed = true;
4375 }
4376
4377 // Redraw any newly exposed areas.
4378 if (itemCache->allExposed || !itemCache->exposed.isEmpty()) {
4379
4380 //We know that we will modify the pixmap, removing it from the cache
4381 //will detach the one we have and avoid a deep copy
4382 if (pixmapFound)
4383 QPixmapCache::remove(pixmapKey);
4384
4385 // Fit the item's bounding rect into the pixmap's coordinates.
4386 QTransform itemToPixmap;
4387 if (fixedCacheSize) {
4388 const QPointF scale((pixmapSize.width() / devicePixelRatio) / brect.width(),
4389 (pixmapSize.height() / devicePixelRatio) / brect.height());
4390 itemToPixmap.scale(scale.x(), scale.y());
4391 }
4392 itemToPixmap.translate(-br.x(), -br.y());
4393
4394 // Generate the item's exposedRect and map its list of expose
4395 // rects to device coordinates.
4397 QRegion pixmapExposed;
4398 QRectF exposedRect;
4399 if (!itemCache->allExposed) {
4400 for (const auto &rect : std::as_const(itemCache->exposed)) {
4401 exposedRect |= rect;
4402 pixmapExposed += itemToPixmap.mapRect(rect).toAlignedRect();
4403 }
4404 } else {
4405 exposedRect = brect;
4406 }
4407 styleOptionTmp.exposedRect = exposedRect;
4408
4409 // Render.
4410 pix.setDevicePixelRatio(devicePixelRatio);
4411 _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
4413
4414 // insert this pixmap into the cache.
4415 itemCache->key = QPixmapCache::insert(pix);
4416
4417 // Reset expose data.
4418 itemCache->allExposed = false;
4419 itemCache->exposed.clear();
4420 }
4421
4422 // Redraw the exposed area using the transformed painter. Depending on
4423 // the hardware, this may be a server-side operation, or an expensive
4424 // qpixmap-image-transform-pixmap roundtrip.
4425 if (newPainterOpacity != oldPainterOpacity) {
4426 painter->setOpacity(newPainterOpacity);
4427 painter->drawPixmap(br.topLeft(), pix);
4428 painter->setOpacity(oldPainterOpacity);
4429 } else {
4430 painter->drawPixmap(br.topLeft(), pix);
4431 }
4432 return;
4433 }
4434
4435 // Render using device coordinate cache mode.
4436 if (cacheMode == QGraphicsItem::DeviceCoordinateCache) {
4437 // Find the item's bounds in device coordinates.
4438 QRectF deviceBounds = painter->worldTransform().mapRect(brect);
4439 QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
4440 if (deviceRect.isEmpty())
4441 return;
4442 QRect viewRect = widget ? widget->rect() : QRect();
4443 if (widget && !viewRect.intersects(deviceRect))
4444 return;
4445
4446 // Resort to direct rendering if the device rect exceeds the
4447 // (optional) maximum bounds. (QGraphicsSvgItem uses this).
4448 QSize maximumCacheSize =
4450 if (!maximumCacheSize.isEmpty()
4451 && (deviceRect.width() > maximumCacheSize.width()
4452 || deviceRect.height() > maximumCacheSize.height())) {
4454 oldPainterOpacity != newPainterOpacity, painterStateProtection);
4455 return;
4456 }
4457
4458 // Create or reuse offscreen pixmap, possibly scroll/blit from the old one.
4459 // If the world transform is rotated we always recreate the cache to avoid
4460 // wrong blending.
4461 bool pixModified = false;
4462 QGraphicsItemCache::DeviceData *deviceData = &itemCache->deviceData[widget];
4463 bool invertable = true;
4464 QTransform diff = deviceData->lastTransform.inverted(&invertable);
4465 if (invertable)
4466 diff *= painter->worldTransform();
4467 deviceData->lastTransform = painter->worldTransform();
4468 bool allowPartialCacheExposure = false;
4469 bool simpleTransform = invertable && diff.type() <= QTransform::TxTranslate
4471 if (!simpleTransform) {
4472 pixModified = true;
4473 itemCache->allExposed = true;
4474 itemCache->exposed.clear();
4475 deviceData->cacheIndent = QPoint();
4476 pix = QPixmap();
4477 } else if (!viewRect.isNull()) {
4478 allowPartialCacheExposure = deviceData->cacheIndent != QPoint();
4479 }
4480
4481 // Allow partial cache exposure if the device rect isn't fully contained and
4482 // deviceRect is 20% taller or wider than the viewRect.
4483 if (!allowPartialCacheExposure && !viewRect.isNull() && !viewRect.contains(deviceRect)) {
4484 allowPartialCacheExposure = (viewRect.width() * 1.2 < deviceRect.width())
4485 || (viewRect.height() * 1.2 < deviceRect.height());
4486 }
4487
4488 QRegion scrollExposure;
4489 if (allowPartialCacheExposure) {
4490 // Part of pixmap is drawn. Either device contains viewrect (big
4491 // item covers whole screen) or parts of device are outside the
4492 // viewport. In either case the device rect must be the intersect
4493 // between the two.
4494 int dx = deviceRect.left() < viewRect.left() ? viewRect.left() - deviceRect.left() : 0;
4495 int dy = deviceRect.top() < viewRect.top() ? viewRect.top() - deviceRect.top() : 0;
4496 QPoint newCacheIndent(dx, dy);
4497 deviceRect &= viewRect;
4498
4499 if (pix.isNull()) {
4500 deviceData->cacheIndent = QPoint();
4501 itemCache->allExposed = true;
4502 itemCache->exposed.clear();
4503 pixModified = true;
4504 }
4505
4506 // Copy / "scroll" the old pixmap onto the new ole and calculate
4507 // scrolled exposure.
4508 if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size() / devicePixelRatio) {
4509 QPoint diff = newCacheIndent - deviceData->cacheIndent;
4510 QPixmap newPix(deviceRect.size() * devicePixelRatio);
4511 // ### Investigate removing this fill (test with Plasma and
4512 // graphicssystem raster).
4513 newPix.fill(Qt::transparent);
4514 if (!pix.isNull()) {
4515 newPix.setDevicePixelRatio(devicePixelRatio);
4516 QPainter newPixPainter(&newPix);
4517 newPixPainter.drawPixmap(-diff, pix);
4518 newPixPainter.end();
4519 }
4520 QRegion exposed;
4521 exposed += QRect(QPoint(0,0), newPix.size() / devicePixelRatio);
4522 if (!pix.isNull())
4523 exposed -= QRect(-diff, pix.size() / devicePixelRatio);
4524 scrollExposure = exposed;
4525
4526 pix = newPix;
4527 pixModified = true;
4528 }
4529 deviceData->cacheIndent = newCacheIndent;
4530 } else {
4531 // Full pixmap is drawn.
4532 deviceData->cacheIndent = QPoint();
4533
4534 // Auto-adjust the pixmap size.
4535 if (deviceRect.size() != pix.size() / devicePixelRatio) {
4536 // exposed needs to cover the whole pixmap
4537 pix = QPixmap(deviceRect.size() * devicePixelRatio);
4538 pixModified = true;
4539 itemCache->allExposed = true;
4540 itemCache->exposed.clear();
4541 }
4542 }
4543
4544 // Check for newly invalidated areas.
4545 if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) {
4546 //We know that we will modify the pixmap, removing it from the cache
4547 //will detach the one we have and avoid a deep copy
4548 if (pixmapFound)
4549 QPixmapCache::remove(pixmapKey);
4550
4551 // Construct an item-to-pixmap transform.
4553 QTransform itemToPixmap = painter->worldTransform();
4554 if (!p.isNull())
4555 itemToPixmap *= QTransform::fromTranslate(-p.x(), -p.y());
4556
4557 // Map the item's logical expose to pixmap coordinates.
4558 QRegion pixmapExposed = scrollExposure;
4559 if (!itemCache->allExposed) {
4560 for (const auto &rect : std::as_const(itemCache->exposed))
4561 pixmapExposed += itemToPixmap.mapRect(rect).toRect().adjusted(-1, -1, 1, 1);
4562 }
4563
4564 // Calculate the style option's exposedRect.
4565 QRectF br;
4566 if (itemCache->allExposed) {
4567 br = item->boundingRect();
4568 } else {
4569 for (const auto &rect : std::as_const(itemCache->exposed))
4570 br |= rect;
4571 QTransform pixmapToItem = itemToPixmap.inverted();
4572 for (const QRect &r : std::as_const(scrollExposure))
4573 br |= pixmapToItem.mapRect(r);
4574 }
4576 styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1);
4577
4578 // Render the exposed areas.
4579 pix.setDevicePixelRatio(devicePixelRatio);
4580 _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
4582
4583 // Reset expose data.
4584 pixModified = true;
4585 itemCache->allExposed = false;
4586 itemCache->exposed.clear();
4587 }
4588
4589 if (pixModified) {
4590 // Insert this pixmap into the cache.
4591 deviceData->key = QPixmapCache::insert(pix);
4592 }
4593
4594 // Redraw the exposed area using an untransformed painter. This
4595 // effectively becomes a bitblit that does not transform the cache.
4596 QTransform restoreTransform = painter->worldTransform();
4598 if (newPainterOpacity != oldPainterOpacity) {
4599 painter->setOpacity(newPainterOpacity);
4601 painter->setOpacity(oldPainterOpacity);
4602 } else {
4604 }
4605 painter->setWorldTransform(restoreTransform);
4606 return;
4607 }
4608}
4609
4611 QRegion *exposedRegion, QWidget *widget)
4612{
4613 // Make sure we don't have unpolished items before we draw.
4614 if (!unpolishedItems.isEmpty())
4616
4617 updateAll = false;
4618 QRectF exposedSceneRect;
4619 if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) {
4620 exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1);
4621 if (viewTransform)
4622 exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect);
4623 }
4624 const QList<QGraphicsItem *> tli = index->estimateTopLevelItems(exposedSceneRect, Qt::AscendingOrder);
4625 for (const auto subTree : tli)
4626 drawSubtreeRecursive(subTree, painter, viewTransform, exposedRegion, widget);
4627}
4628
4630 const QTransform *const viewTransform,
4631 QRegion *exposedRegion, QWidget *widget,
4632 qreal parentOpacity, const QTransform *const effectTransform)
4633{
4634 Q_ASSERT(item);
4635
4636 if (!item->d_ptr->visible)
4637 return;
4638
4639 const bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
4640 const bool itemHasChildren = !item->d_ptr->children.isEmpty();
4641 if (!itemHasContents && !itemHasChildren)
4642 return; // Item has neither contents nor children!(?)
4643
4644 const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
4645 const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
4646 if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity()))
4647 return;
4648
4650 QTransform *transformPtr = nullptr;
4651 bool translateOnlyTransform = false;
4652#define ENSURE_TRANSFORM_PTR \
4653 if (!transformPtr) { \
4654 Q_ASSERT(!itemIsUntransformable); \
4655 if (viewTransform) { \
4656 transform = item->d_ptr->sceneTransform; \
4657 transform *= *viewTransform; \
4658 transformPtr = &transform; \
4659 } else { \
4660 transformPtr = &item->d_ptr->sceneTransform; \
4661 translateOnlyTransform = item->d_ptr->sceneTransformTranslateOnly; \
4662 } \
4663 }
4664
4665 // Update the item's scene transform if the item is transformable;
4666 // otherwise calculate the full transform,
4667 bool wasDirtyParentSceneTransform = false;
4668 const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
4669 if (itemIsUntransformable) {
4670 transform = item->deviceTransform(viewTransform ? *viewTransform : QTransform());
4671 transformPtr = &transform;
4672 } else if (item->d_ptr->dirtySceneTransform) {
4675 wasDirtyParentSceneTransform = true;
4676 }
4677
4678 const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
4680 bool drawItem = itemHasContents && !itemIsFullyTransparent;
4681 if (drawItem || minimumRenderSize > 0.0) {
4684 QRectF preciseViewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy())
4685 : transformPtr->mapRect(brect);
4686
4687 bool itemIsTooSmallToRender = false;
4688 if (minimumRenderSize > 0.0
4689 && (preciseViewBoundingRect.width() < minimumRenderSize
4690 || preciseViewBoundingRect.height() < minimumRenderSize)) {
4691 itemIsTooSmallToRender = true;
4692 drawItem = false;
4693 }
4694
4695 bool itemIsOutsideVisibleRect = false;
4696 if (drawItem) {
4697 QRect viewBoundingRect = preciseViewBoundingRect.toAlignedRect();
4698 viewBoundingRect.adjust(-int(rectAdjust), -int(rectAdjust), rectAdjust, rectAdjust);
4699 if (widget)
4700 item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
4701 drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect)
4702 : !viewBoundingRect.normalized().isEmpty();
4703 itemIsOutsideVisibleRect = !drawItem;
4704 }
4705
4706 if (itemIsTooSmallToRender || itemIsOutsideVisibleRect) {
4707 // We cannot simply use !drawItem here. If we did it is possible
4708 // to enter the outer if statement with drawItem == false and minimumRenderSize > 0
4709 // and finally end up inside this inner if, even though none of the above two
4710 // conditions are met. In that case we should not return from this function
4711 // but call draw() instead.
4712 if (!itemHasChildren)
4713 return;
4714 if (itemClipsChildrenToShape) {
4715 if (wasDirtyParentSceneTransform)
4717 return;
4718 }
4719 }
4720 } // else we know for sure this item has children we must process.
4721
4722 if (itemHasChildren && itemClipsChildrenToShape)
4724
4725#if QT_CONFIG(graphicseffect)
4728 QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp,
4729 painter, opacity, wasDirtyParentSceneTransform, itemHasContents && !itemIsFullyTransparent);
4731 QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *>
4732 (source->d_func());
4733 sourced->info = &info;
4734 const QTransform restoreTransform = painter->worldTransform();
4735 if (effectTransform)
4736 painter->setWorldTransform(*transformPtr * *effectTransform);
4737 else
4738 painter->setWorldTransform(*transformPtr);
4739 painter->setOpacity(opacity);
4740
4741 if (sourced->currentCachedSystem() != Qt::LogicalCoordinates
4742 && sourced->lastEffectTransform != painter->worldTransform())
4743 {
4744 if (sourced->lastEffectTransform.type() <= QTransform::TxTranslate
4746 {
4747 QRectF sourceRect = sourced->boundingRect(Qt::DeviceCoordinates);
4748 QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect).toAlignedRect();
4749
4750 sourced->setCachedOffset(effectRect.topLeft());
4751 } else {
4752 sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged);
4753 }
4754
4755 sourced->lastEffectTransform = painter->worldTransform();
4756 }
4757
4759 painter->setWorldTransform(restoreTransform);
4760 sourced->info = nullptr;
4761 } else
4762#endif // QT_CONFIG(graphicseffect)
4763 {
4764 draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity,
4765 effectTransform, wasDirtyParentSceneTransform, drawItem);
4766 }
4767}
4768
4770{
4771 painter->save();
4772 QRectF clipRect;
4773 const QPainterPath clipPath(item->shape());
4774 if (QPathClipper::pathToRect(clipPath, &clipRect))
4776 else
4778}
4779
4780static inline void setWorldTransform(QPainter *painter, const QTransform *const transformPtr,
4781 const QTransform *effectTransform)
4782{
4783 Q_ASSERT(transformPtr);
4784 if (effectTransform)
4785 painter->setWorldTransform(*transformPtr * *effectTransform);
4786 else
4787 painter->setWorldTransform(*transformPtr);
4788}
4789
4791 const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget,
4792 qreal opacity, const QTransform *effectTransform,
4793 bool wasDirtyParentSceneTransform, bool drawItem)
4794{
4795 const auto &children = item->d_ptr->children;
4796
4797 const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
4798 const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
4799 const bool itemHasChildren = !children.isEmpty();
4800 bool setChildClip = itemClipsChildrenToShape;
4801 bool itemHasChildrenStackedBehind = false;
4802
4803 int i = 0;
4804 if (itemHasChildren) {
4805 if (itemClipsChildrenToShape)
4806 setWorldTransform(painter, transformPtr, effectTransform);
4807
4809 // Items with the 'ItemStacksBehindParent' flag are put in front of the list
4810 // so all we have to do is to check the first item.
4811 itemHasChildrenStackedBehind = (children.at(0)->d_ptr->flags
4813
4814 if (itemHasChildrenStackedBehind) {
4815 if (itemClipsChildrenToShape) {
4817 setChildClip = false;
4818 }
4819
4820 // Draw children behind
4821 for (i = 0; i < children.size(); ++i) {
4823 if (wasDirtyParentSceneTransform)
4824 child->d_ptr->dirtySceneTransform = 1;
4825 if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
4826 break;
4827 if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
4828 continue;
4829 drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
4830 }
4831 }
4832 }
4833
4834 // Draw item
4835 if (drawItem) {
4836 Q_ASSERT(!itemIsFullyTransparent);
4838 Q_ASSERT(transformPtr);
4839 item->d_ptr->initStyleOption(&styleOptionTmp, *transformPtr, exposedRegion
4840 ? *exposedRegion : QRegion(), exposedRegion == nullptr);
4841
4842 const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape;
4843 bool restorePainterClip = false;
4844
4845 if (!itemHasChildren || !itemClipsChildrenToShape) {
4846 // Item does not have children or clip children to shape.
4847 setWorldTransform(painter, transformPtr, effectTransform);
4848 if ((restorePainterClip = itemClipsToShape))
4850 } else if (itemHasChildrenStackedBehind){
4851 // Item clips children to shape and has children stacked behind, which means
4852 // the painter is already clipped to the item's shape.
4853 if (itemClipsToShape) {
4854 // The clip is already correct. Ensure correct world transform.
4855 setWorldTransform(painter, transformPtr, effectTransform);
4856 } else {
4857 // Remove clip (this also ensures correct world transform).
4858 painter->restore();
4859 setChildClip = true;
4860 }
4861 } else if (itemClipsToShape) {
4862 // Item clips children and itself to shape. It does not have hildren stacked
4863 // behind, which means the clip has not yet been set. We set it now and re-use it
4864 // for the children.
4866 setChildClip = false;
4867 }
4868
4869 if (painterStateProtection && !restorePainterClip)
4870 painter->save();
4871
4872 painter->setOpacity(opacity);
4873 if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget)
4875 else
4877
4878 if (painterStateProtection || restorePainterClip)
4879 painter->restore();
4880
4881 static int drawRect = qEnvironmentVariableIntValue("QT_DRAW_SCENE_ITEM_RECTS");
4882 if (drawRect) {
4883 QPen oldPen = painter->pen();
4884 QBrush oldBrush = painter->brush();
4885 quintptr ptr = reinterpret_cast<quintptr>(item);
4886 const QColor color = QColor::fromHsv(ptr % 255, 255, 255);
4890 painter->setPen(oldPen);
4891 painter->setBrush(oldBrush);
4892 }
4893 }
4894
4895 // Draw children in front
4896 if (itemHasChildren) {
4897 if (setChildClip)
4899
4900 for (; i < children.size(); ++i) {
4902 if (wasDirtyParentSceneTransform)
4903 child->d_ptr->dirtySceneTransform = 1;
4904 if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
4905 continue;
4906 drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
4907 }
4908
4909 // Restore child clip
4910 if (itemClipsChildrenToShape)
4911 painter->restore();
4912 }
4913}
4914
4915void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren,
4916 bool force, bool ignoreOpacity, bool removingItemFromScene,
4917 bool updateBoundingRect)
4918{
4919 Q_ASSERT(item);
4920 if (updateAll)
4921 return;
4922
4923 if (removingItemFromScene && !ignoreOpacity && !item->d_ptr->ignoreOpacity) {
4924 // If any of the item's ancestors ignore opacity, it means that the opacity
4925 // was set to 0 (and the update request has not yet been processed). That
4926 // also means that we have to ignore the opacity for the item itself; otherwise
4927 // things like: parent->setOpacity(0); scene->removeItem(child) won't work.
4928 // Note that we only do this when removing items from the scene. In all other
4929 // cases the ignoreOpacity bit propagates properly in processDirtyItems, but
4930 // since the item is removed immediately it won't be processed there.
4932 while (p) {
4933 if (p->d_ptr->ignoreOpacity) {
4934 item->d_ptr->ignoreOpacity = true;
4935 break;
4936 }
4937 p = p->d_ptr->parent;
4938 }
4939 }
4940
4941 if (item->d_ptr->discardUpdateRequest(/*ignoreVisibleBit=*/force,
4942 /*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren,
4943 /*ignoreOpacity=*/ignoreOpacity)) {
4944 if (item->d_ptr->dirty) {
4945 // The item is already marked as dirty and will be processed later. However,
4946 // we have to make sure ignoreVisible and ignoreOpacity are set properly;
4947 // otherwise things like: item->update(); item->hide() (force is now true)
4948 // won't work as expected.
4949 if (force)
4950 item->d_ptr->ignoreVisible = 1;
4951 if (ignoreOpacity)
4952 item->d_ptr->ignoreOpacity = 1;
4953 }
4954 return;
4955 }
4956
4957 const bool fullItemUpdate = rect.isNull();
4958 if (!fullItemUpdate && rect.isEmpty())
4959 return;
4960
4962 QMetaMethod method = q_ptr->metaObject()->method(processDirtyItemsIndex);
4964// QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection);
4966 }
4967
4968 if (removingItemFromScene) {
4969 // Note that this function can be called from the item's destructor, so
4970 // do NOT call any virtual functions on it within this block.
4972 // This block of code is kept for compatibility. Since 4.5, by default
4973 // QGraphicsView does not connect the signal and we use the below
4974 // method of delivering updates.
4975 q_func()->update();
4976 return;
4977 }
4978
4979 for (auto view : std::as_const(views)) {
4980 QGraphicsViewPrivate *viewPrivate = view->d_func();
4981 QRect rect = item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport);
4982 rect.translate(viewPrivate->dirtyScrollOffset);
4983 viewPrivate->updateRect(rect);
4984 }
4985 return;
4986 }
4987
4988 bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents;
4989 if (!hasNoContents) {
4990 item->d_ptr->dirty = 1;
4991 if (fullItemUpdate)
4993 else if (!item->d_ptr->fullUpdatePending)
4995 } else if (item->d_ptr->graphicsEffect) {
4996 invalidateChildren = true;
4997 }
4998
4999 if (invalidateChildren) {
5001 item->d_ptr->dirtyChildren = 1;
5002 }
5003
5004 if (force)
5005 item->d_ptr->ignoreVisible = 1;
5006 if (ignoreOpacity)
5007 item->d_ptr->ignoreOpacity = 1;
5008
5009 if (!updateBoundingRect)
5011}
5012
5014 const QRectF &rect, bool itemIsUntransformable)
5015{
5016 Q_ASSERT(view);
5017 Q_ASSERT(item);
5018
5019 QGraphicsItem *itemq = static_cast<QGraphicsItem *>(item->q_ptr);
5020 QGraphicsView *viewq = static_cast<QGraphicsView *>(view->q_ptr);
5021
5022 if (itemIsUntransformable) {
5023 const QTransform xform = itemq->deviceTransform(viewq->viewportTransform());
5024 if (!item->hasBoundingRegionGranularity)
5025 return view->updateRectF(xform.mapRect(rect));
5026 return view->updateRegion(rect, xform);
5027 }
5028
5029 if (item->sceneTransformTranslateOnly && view->identityMatrix) {
5030 const qreal dx = item->sceneTransform.dx();
5031 const qreal dy = item->sceneTransform.dy();
5032 QRectF r(rect);
5033 r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll());
5034 return view->updateRectF(r);
5035 }
5036
5037 if (!viewq->isTransformed()) {
5038 if (!item->hasBoundingRegionGranularity)
5039 return view->updateRectF(item->sceneTransform.mapRect(rect));
5040 return view->updateRegion(rect, item->sceneTransform);
5041 }
5042
5044 xform *= viewq->viewportTransform();
5045 if (!item->hasBoundingRegionGranularity)
5046 return view->updateRectF(xform.mapRect(rect));
5047 return view->updateRegion(rect, xform);
5048}
5049
5051 qreal parentOpacity)
5052{
5053 Q_Q(QGraphicsScene);
5054 Q_ASSERT(item);
5056
5057 if (!item->d_ptr->dirty && !item->d_ptr->dirtyChildren) {
5059 return;
5060 }
5061
5062 const bool itemIsHidden = !item->d_ptr->ignoreVisible && !item->d_ptr->visible;
5063 if (itemIsHidden) {
5064 resetDirtyItem(item, /*recursive=*/true);
5065 return;
5066 }
5067
5068 bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
5069 const bool itemHasChildren = !item->d_ptr->children.isEmpty();
5070 if (!itemHasContents) {
5071 if (!itemHasChildren) {
5073 return; // Item has neither contents nor children!(?)
5074 }
5076 itemHasContents = true;
5077 }
5078
5079 const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
5080 const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity
5082 if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) {
5083 resetDirtyItem(item, /*recursive=*/itemHasChildren);
5084 return;
5085 }
5086
5087 bool wasDirtyParentSceneTransform = item->d_ptr->dirtySceneTransform;
5088 const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
5089 if (wasDirtyParentSceneTransform && !itemIsUntransformable) {
5092 }
5093
5094 const bool wasDirtyParentViewBoundingRects = item->d_ptr->paintedViewBoundingRectsNeedRepaint;
5095 if (itemIsFullyTransparent || !itemHasContents || dirtyAncestorContainsChildren) {
5096 // Make sure we don't process invisible items or items with no content.
5097 item->d_ptr->dirty = 0;
5099 // Might have a dirty view bounding rect otherwise.
5100 if (itemIsFullyTransparent || !itemHasContents)
5102 }
5103
5105 // Update growingItemsBoundingRect.
5109 } else {
5111 }
5112 }
5113
5114 // Process item.
5116 const bool useCompatUpdate = views.isEmpty() || isSignalConnected(changedSignalIndex);
5117 const QRectF itemBoundingRect = adjustedItemEffectiveBoundingRect(item);
5118
5119 if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) {
5120 // This block of code is kept for compatibility. Since 4.5, by default
5121 // QGraphicsView does not connect the signal and we use the below
5122 // method of delivering updates.
5124 q->update(itemBoundingRect.translated(item->d_ptr->sceneTransform.dx(),
5126 } else {
5127 QRectF rect = item->d_ptr->sceneTransform.mapRect(itemBoundingRect);
5128 if (!rect.isEmpty())
5129 q->update(rect);
5130 }
5131 } else {
5132 QRectF dirtyRect;
5133 bool uninitializedDirtyRect = true;
5134
5135 for (auto view : std::as_const(views)) {
5136 QGraphicsViewPrivate *viewPrivate = view->d_func();
5137 QRect &paintedViewBoundingRect = item->d_ptr->paintedViewBoundingRects[viewPrivate->viewport];
5138 if (viewPrivate->fullUpdatePending
5139 || viewPrivate->viewportUpdateMode == QGraphicsView::NoViewportUpdate) {
5140 // Okay, if we have a full update pending or no viewport update, this item's
5141 // paintedViewBoundingRect will be updated correctly in the next paintEvent if
5142 // it is inside the viewport, but for now we can pretend that it is outside.
5143 paintedViewBoundingRect = QRect(-1, -1, -1, -1);
5144 continue;
5145 }
5146
5148 paintedViewBoundingRect.translate(viewPrivate->dirtyScrollOffset);
5149 if (!viewPrivate->updateRect(paintedViewBoundingRect))
5150 paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
5151 }
5152
5153 if (!item->d_ptr->dirty)
5154 continue;
5155
5157 && paintedViewBoundingRect.x() == -1 && paintedViewBoundingRect.y() == -1
5158 && paintedViewBoundingRect.width() == -1 && paintedViewBoundingRect.height() == -1) {
5159 continue; // Outside viewport.
5160 }
5161
5162 if (uninitializedDirtyRect) {
5163 dirtyRect = itemBoundingRect;
5164 if (!item->d_ptr->fullUpdatePending) {
5166 dirtyRect &= item->d_ptr->needsRepaint;
5167 }
5168 uninitializedDirtyRect = false;
5169 }
5170
5171 if (dirtyRect.isEmpty())
5172 continue; // Discard updates outside the bounding rect.
5173
5174 if (!updateHelper(viewPrivate, item->d_ptr.data(), dirtyRect, itemIsUntransformable)
5176 paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
5177 }
5178 }
5179 }
5180 }
5181
5182 // Process children.
5183 if (itemHasChildren && item->d_ptr->dirtyChildren) {
5184 const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
5186 // Items with no content are threated as 'dummy' items which means they are never drawn and
5187 // 'processed', so the painted view bounding rect is never up-to-date. This means that whenever
5188 // such an item changes geometry, its children have to take care of the update regardless
5189 // of whether the item clips children to shape or not.
5190 const bool bypassUpdateClip = !itemHasContents && wasDirtyParentViewBoundingRects;
5191 if (itemClipsChildrenToShape && !bypassUpdateClip) {
5192 // Make sure child updates are clipped to the item's bounding rect.
5193 for (auto view : std::as_const(views))
5194 view->d_func()->setUpdateClip(item);
5195 }
5196 if (!dirtyAncestorContainsChildren) {
5197 dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending
5198 && itemClipsChildrenToShape;
5199 }
5200 const bool allChildrenDirty = item->d_ptr->allChildrenDirty;
5201 const bool parentIgnoresVisible = item->d_ptr->ignoreVisible;
5202 const bool parentIgnoresOpacity = item->d_ptr->ignoreOpacity;
5203 for (auto child : std::as_const(item->d_ptr->children)) {
5204 if (wasDirtyParentSceneTransform)
5205 child->d_ptr->dirtySceneTransform = 1;
5206 if (wasDirtyParentViewBoundingRects)
5207 child->d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
5208 if (parentIgnoresVisible)
5209 child->d_ptr->ignoreVisible = 1;
5210 if (parentIgnoresOpacity)
5211 child->d_ptr->ignoreOpacity = 1;
5212 if (allChildrenDirty) {
5213 child->d_ptr->dirty = 1;
5214 child->d_ptr->fullUpdatePending = 1;
5215 child->d_ptr->dirtyChildren = 1;
5216 child->d_ptr->allChildrenDirty = 1;
5217 }
5218 processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity);
5219 }
5220
5221 if (itemClipsChildrenToShape) {
5222 // Reset updateClip.
5223 for (auto view : std::as_const(views))
5224 view->d_func()->setUpdateClip(nullptr);
5225 }
5226 } else if (wasDirtyParentSceneTransform) {
5228 }
5229
5231}
5232
5265 int numItems,
5267 const QStyleOptionGraphicsItem options[], QWidget *widget)
5268{
5269 Q_D(QGraphicsScene);
5270 // Make sure we don't have unpolished items before we draw.
5271 if (!d->unpolishedItems.isEmpty())
5272 d->_q_polishItems();
5273
5274 const qreal opacity = painter->opacity();
5275 QTransform viewTransform = painter->worldTransform();
5276 Q_UNUSED(options);
5277
5278 // Determine view, expose and flags.
5279 QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
5280 QRegion *expose = nullptr;
5281 const quint32 oldRectAdjust = d->rectAdjust;
5282 if (view) {
5283 d->updateAll = false;
5284 expose = &view->d_func()->exposedRegion;
5285 if (view->d_func()->optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
5286 d->rectAdjust = 1;
5287 else
5288 d->rectAdjust = 2;
5289 }
5290
5291 // Find all toplevels, they are already sorted.
5292 QList<QGraphicsItem *> topLevelItems;
5293 for (int i = 0; i < numItems; ++i) {
5294 QGraphicsItem *item = items[i]->topLevelItem();
5295 if (!item->d_ptr->itemDiscovered) {
5296 topLevelItems << item;
5298 d->drawSubtreeRecursive(item, painter, &viewTransform, expose, widget);
5299 }
5300 }
5301
5302 d->rectAdjust = oldRectAdjust;
5303 // Reset discovery bits.
5304 for (auto topLevelItem : std::as_const(topLevelItems))
5305 topLevelItem->d_ptr->itemDiscovered = 0;
5306
5307 painter->setWorldTransform(viewTransform);
5308 painter->setOpacity(opacity);
5309}
5310
5325{
5326 Q_D(QGraphicsScene);
5327
5329 if (item && !item->isWidget()) {
5330 // Tab out of the scene.
5331 return false;
5332 }
5333 if (!item) {
5334 if (d->lastFocusItem && !d->lastFocusItem->isWidget()) {
5335 // Restore focus to the last focusable non-widget item that had
5336 // focus.
5338 return true;
5339 }
5340 if (d->activePanel) {
5341 if (d->activePanel->flags() & QGraphicsItem::ItemIsFocusable) {
5343 return true;
5344 }
5345 if (d->activePanel->isWidget()) {
5346 QGraphicsWidget *test = static_cast<QGraphicsWidget *>(d->activePanel);
5347 QGraphicsWidget *fw = next ? test->d_func()->focusNext : test->d_func()->focusPrev;
5348 do {
5349 if (fw->focusPolicy() & Qt::TabFocus) {
5351 return true;
5352 }
5353 fw = next ? fw->d_func()->focusNext : fw->d_func()->focusPrev;
5354 } while (fw != d->activePanel);
5355 }
5356 }
5357 }
5358 if (!item && !d->tabFocusFirst) {
5359 // No widgets...
5360 return false;
5361 }
5362
5363 // The item must be a widget.
5364 QGraphicsWidget *widget = nullptr;
5365 if (!item) {
5366 widget = next ? d->tabFocusFirst : d->tabFocusFirst->d_func()->focusPrev;
5367 } else {
5368 QGraphicsWidget *test = static_cast<QGraphicsWidget *>(item);
5369 widget = next ? test->d_func()->focusNext : test->d_func()->focusPrev;
5370 if (!widget->panel() && ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))) {
5371 // Tab out of the scene.
5372 return false;
5373 }
5374 }
5375 QGraphicsWidget *widgetThatHadFocus = widget;
5376
5377 // Run around the focus chain until we find a widget that can take tab focus.
5378 do {
5380 && widget->isEnabled() && widget->isVisibleTo(nullptr)
5382 && (!item || !item->isPanel() || item->isAncestorOf(widget))
5383 ) {
5385 return true;
5386 }
5387 widget = next ? widget->d_func()->focusNext : widget->d_func()->focusPrev;
5388 if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
5389 return false;
5390 } while (widget != widgetThatHadFocus);
5391
5392 return false;
5393}
5394
5464{
5465 Q_D(const QGraphicsScene);
5466 // ### This function, and the use of styles in general, is non-reentrant.
5467 return d->style ? d->style : QApplication::style();
5468}
5469
5488{
5489 Q_D(QGraphicsScene);
5490 // ### This function, and the use of styles in general, is non-reentrant.
5491 if (style == d->style)
5492 return;
5493
5494 // Delete the old style,
5495 delete d->style;
5496 if ((d->style = style))
5497 d->style->setParent(this);
5498
5499 // Notify the scene.
5502
5503 // Notify all widgets that don't have a style explicitly set.
5504 const auto items_ = items();
5505 for (QGraphicsItem *item : items_) {
5506 if (item->isWidget()) {
5507 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
5510 }
5511 }
5512}
5513
5538{
5539 Q_D(const QGraphicsScene);
5540 return d->font;
5541}
5543{
5544 Q_D(QGraphicsScene);
5545 QFont naturalFont = QApplication::font();
5546 naturalFont.setResolveMask(0);
5547 QFont resolvedFont = font.resolve(naturalFont);
5548 d->setFont_helper(resolvedFont);
5549}
5550
5575{
5576 Q_D(const QGraphicsScene);
5577 return d->palette;
5578}
5580{
5581 Q_D(QGraphicsScene);
5582 QPalette naturalPalette = QGuiApplication::palette();
5583 naturalPalette.setResolveMask(0);
5584 QPalette resolvedPalette = palette.resolve(naturalPalette);
5585 d->setPalette_helper(resolvedPalette);
5586}
5587
5597{
5598 Q_D(const QGraphicsScene);
5599 return d->activationRefCount > 0;
5600}
5601
5610{
5611 Q_D(const QGraphicsScene);
5612 return d->activePanel;
5613}
5614
5627{
5628 Q_D(QGraphicsScene);
5629 d->setActivePanelHelper(item, false);
5630}
5631
5641{
5642 Q_D(const QGraphicsScene);
5643 if (d->activePanel && d->activePanel->isWindow())
5644 return static_cast<QGraphicsWidget *>(d->activePanel);
5645 return nullptr;
5646}
5647
5657{
5658 if (widget && widget->scene() != this) {
5659 qWarning("QGraphicsScene::setActiveWindow: widget %p must be part of this scene",
5660 widget);
5661 return;
5662 }
5663
5664 // Activate the widget's panel (all windows are panels).
5665 QGraphicsItem *panel = widget ? widget->panel() : nullptr;
5667
5668 // Raise
5669 if (panel) {
5670 QGraphicsItem *parent = panel->parentItem();
5671 // Raise ### inefficient for toplevels
5672
5673 // Find the highest z value.
5674 qreal z = panel->zValue();
5675 const auto siblings = parent ? parent->childItems() : items();
5676 for (QGraphicsItem *sibling : siblings) {
5677 if (sibling != panel && sibling->isWindow())
5678 z = qMax(z, sibling->zValue());
5679 }
5680
5681 // This will probably never overflow.
5682 const qreal litt = qreal(0.001);
5683 panel->setZValue(z + litt);
5684 }
5685}
5686
5700{
5701 Q_D(QGraphicsScene);
5702 if (!item) {
5703 qWarning("QGraphicsScene::sendEvent: cannot send event to a null item");
5704 return false;
5705 }
5706 if (item->scene() != this) {
5707 qWarning("QGraphicsScene::sendEvent: item %p's scene (%p)"
5708 " is different from this scene (%p)",
5709 item, item->scene(), this);
5710 return false;
5711 }
5712 return d->sendEvent(item, event);
5713}
5714
5747{
5748 Q_D(const QGraphicsScene);
5749 return d->minimumRenderSize;
5750}
5752{
5753 Q_D(QGraphicsScene);
5754 d->minimumRenderSize = minSize;
5755 update();
5756}
5757
5782{
5783 Q_D(const QGraphicsScene);
5784 return d->focusOnTouch;
5785}
5786
5788{
5789 Q_D(QGraphicsScene);
5790 d->focusOnTouch = enabled;
5791}
5792
5794{
5795 views << view;
5796#ifndef QT_NO_GESTURES
5797 for (auto it = grabbedGestures.constBegin();
5798 it != grabbedGestures.constEnd(); ++it)
5799 view->viewport()->grabGesture(it.key());
5800#endif
5801}
5802
5807
5809{
5810 const QTransform mapFromScene =
5811 item->d_ptr->genericMapFromSceneTransform(static_cast<const QWidget *>(touchEvent->target()));
5812
5813 for (int i = 0; i < touchEvent->pointCount(); ++i) {
5814 auto &pt = touchEvent->point(i);
5815 QMutableEventPoint::setPosition(pt, mapFromScene.map(pt.scenePosition()));
5816 }
5817}
5818
5820{
5821 int closestTouchPointId = -1;
5822 qreal closestDistance = qreal(0.);
5823 for (const QEventPoint &touchPoint : std::as_const(sceneCurrentTouchPoints)) {
5824 qreal distance = QLineF(scenePos, touchPoint.scenePosition()).length();
5825 if (closestTouchPointId == -1|| distance < closestDistance) {
5826 closestTouchPointId = touchPoint.id();
5827 closestDistance = distance;
5828 }
5829 }
5830 return closestTouchPointId;
5831}
5832
5834{
5835 typedef QPair<QEventPoint::States, QList<QEventPoint> > StatesAndTouchPoints;
5836 QHash<QGraphicsItem *, StatesAndTouchPoints> itemsNeedingEvents;
5837
5838 const auto &touchPoints = sceneTouchEvent->points();
5839 for (const auto &touchPoint : touchPoints) {
5840 // update state
5841 QGraphicsItem *item = nullptr;
5842 if (touchPoint.state() == QEventPoint::State::Pressed) {
5843 if (sceneTouchEvent->pointingDevice()->type() == QInputDevice::DeviceType::TouchPad) {
5844 // on touch-pad devices, send all touch points to the same item
5846 ? 0
5847 : itemForTouchPointId.constBegin().value();
5848 }
5849
5850 if (!item) {
5851 // determine which item this touch point will go to
5852 cachedItemsUnderMouse = itemsAtPosition(touchPoint.globalPosition().toPoint(),
5853 touchPoint.scenePosition(),
5854 static_cast<QWidget *>(sceneTouchEvent->target()));
5856 }
5857
5858 if (sceneTouchEvent->pointingDevice()->type() == QInputDevice::DeviceType::TouchScreen) {
5859 // on touch-screens, combine this touch point with the closest one we find
5860 int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePosition());
5861 QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId);
5862 if (!item || (closestItem && cachedItemsUnderMouse.contains(closestItem)))
5863 item = closestItem;
5864 }
5865 if (!item)
5866 continue;
5867
5868 itemForTouchPointId.insert(touchPoint.id(), item);
5869 sceneCurrentTouchPoints.insert(touchPoint.id(), touchPoint);
5870 } else if (touchPoint.state() == QEventPoint::State::Released) {
5871 item = itemForTouchPointId.take(touchPoint.id());
5872 if (!item)
5873 continue;
5874
5875 sceneCurrentTouchPoints.remove(touchPoint.id());
5876 } else {
5877 item = itemForTouchPointId.value(touchPoint.id());
5878 if (!item)
5879 continue;
5880 Q_ASSERT(sceneCurrentTouchPoints.contains(touchPoint.id()));
5881 sceneCurrentTouchPoints[touchPoint.id()] = touchPoint;
5882 }
5883
5884 StatesAndTouchPoints &statesAndTouchPoints = itemsNeedingEvents[item];
5885 statesAndTouchPoints.first = QEventPoint::States(statesAndTouchPoints.first | touchPoint.state());
5886 statesAndTouchPoints.second.append(touchPoint);
5887 }
5888
5889 if (itemsNeedingEvents.isEmpty()) {
5890 sceneTouchEvent->ignore();
5891 return;
5892 }
5893
5894 bool ignoreSceneTouchEvent = true;
5896 const QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator end = itemsNeedingEvents.constEnd();
5897 for (; it != end; ++it) {
5898 QGraphicsItem *item = it.key();
5899
5901
5902 // determine event type from the state mask
5903 QEvent::Type eventType;
5904 switch (it.value().first) {
5906 // all touch points have pressed state
5907 eventType = QEvent::TouchBegin;
5908 break;
5910 // all touch points have released state
5911 eventType = QEvent::TouchEnd;
5912 break;
5914 // don't send the event if nothing changed
5915 continue;
5916 default:
5917 // all other combinations
5918 eventType = QEvent::TouchUpdate;
5919 break;
5920 }
5921
5922 QMutableTouchEvent touchEvent(eventType, sceneTouchEvent->pointingDevice(), sceneTouchEvent->modifiers(), it.value().second);
5923 touchEvent.setTarget(sceneTouchEvent->target());
5924 touchEvent.setModifiers(sceneTouchEvent->modifiers());
5925 touchEvent.setTimestamp(sceneTouchEvent->timestamp());
5926
5927 switch (touchEvent.type()) {
5928 case QEvent::TouchBegin:
5929 {
5930 // if the TouchBegin handler recurses, we assume that means the event
5931 // has been implicitly accepted and continue to send touch events
5933 bool res = sendTouchBeginEvent(item, &touchEvent) && touchEvent.isAccepted();
5934 if (!res) {
5935 // forget about these touch points, we didn't handle them
5936 const auto &unhandledTouchPoints = touchEvent.points();
5937 for (const auto &touchPoint : unhandledTouchPoints) {
5938 itemForTouchPointId.remove(touchPoint.id());
5939 sceneCurrentTouchPoints.remove(touchPoint.id());
5940 }
5941 ignoreSceneTouchEvent = false;
5942 }
5943 break;
5944 }
5945 default:
5947 updateTouchPointsForItem(item, &touchEvent);
5948 (void) sendEvent(item, &touchEvent);
5949 ignoreSceneTouchEvent = false;
5950 }
5951 break;
5952 }
5953 }
5954 // don't override the acceptance state of the individual points
5955 sceneTouchEvent->QInputEvent::setAccepted(ignoreSceneTouchEvent);
5956}
5957
5959{
5960 Q_Q(QGraphicsScene);
5961
5962 if (focusOnTouch) {
5964 const QEventPoint &firstTouchPoint = touchEvent->points().first();
5965 cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint.globalPosition().toPoint(),
5966 firstTouchPoint.scenePosition(),
5967 static_cast<QWidget *>(touchEvent->target()));
5968 }
5969
5970 // Set focus on the topmost enabled item that can take focus.
5971 bool setFocus = false;
5972
5973 for (QGraphicsItem *item : std::as_const(cachedItemsUnderMouse)) {
5975 if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
5976 setFocus = true;
5977 if (item != q->focusItem())
5978 q->setFocusItem(item, Qt::MouseFocusReason);
5979 break;
5980 }
5981 }
5982 if (item->isPanel())
5983 break;
5985 break;
5987 // Make sure we don't clear focus.
5988 setFocus = true;
5989 break;
5990 }
5991 }
5992
5993 // If nobody could take focus, clear it.
5994 if (!stickyFocus && !setFocus)
5995 q->setFocusItem(nullptr, Qt::MouseFocusReason);
5996 }
5997
5998 bool res = false;
5999 bool eventAccepted = touchEvent->isAccepted();
6000 for (QGraphicsItem *item : std::as_const(cachedItemsUnderMouse)) {
6001 // first, try to deliver the touch event
6002 updateTouchPointsForItem(item, touchEvent);
6003 bool acceptTouchEvents = item->acceptTouchEvents();
6004 touchEvent->setAccepted(acceptTouchEvents);
6005 res = acceptTouchEvents && sendEvent(item, touchEvent);
6006 eventAccepted = touchEvent->isAccepted();
6007 if (itemForTouchPointId.value(touchEvent->points().first().id()) == 0) {
6008 // item was deleted
6009 item = nullptr;
6010 } else {
6011 item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted);
6012 }
6013 touchEvent->m_spont = false;
6014 if (res && eventAccepted) {
6015 // the first item to accept the TouchBegin gets an implicit grab.
6016 const auto &touchPoints = touchEvent->points();
6017 for (const auto &touchPoint : touchPoints)
6018 itemForTouchPointId[touchPoint.id()] = item; // can be zero
6019 break;
6020 }
6021 if (item && item->isPanel())
6022 break;
6023 }
6024
6025 // don't override the acceptance state of the touch points
6026 touchEvent->QInputEvent::setAccepted(eventAccepted);
6027 return res;
6028}
6029
6031{
6032 for (QGraphicsView *view : std::as_const(views))
6033 view->viewport()->setAttribute(Qt::WA_AcceptTouchEvents, true);
6034}
6035
6037{
6038 for (auto view : std::as_const(views))
6039 view->d_func()->updateInputMethodSensitivity();
6040}
6041
6043{
6044 Q_Q(QGraphicsScene);
6045 Q_ASSERT(panel && panel->isPanel());
6046
6047 QGraphicsItem::PanelModality panelModality = panel->d_ptr->panelModality;
6048 if (previousModality != QGraphicsItem::NonModal) {
6049 // the panel is changing from one modality type to another... temporarily set it back so
6050 // that blockedPanels is populated correctly
6051 panel->d_ptr->panelModality = previousModality;
6052 }
6053
6054 QSet<QGraphicsItem *> blockedPanels;
6055 {
6056 const auto items_ = q->items();
6057 for (const auto &item : items_) {
6059 blockedPanels.insert(item);
6060 }
6061 }
6062 // blockedPanels contains all currently blocked panels
6063
6064 if (previousModality != QGraphicsItem::NonModal) {
6065 // reset the modality to the proper value, since we changed it above
6066 panel->d_ptr->panelModality = panelModality;
6067 // remove this panel so that it will be reinserted at the front of the stack
6069 }
6070
6072
6073 if (!hoverItems.isEmpty()) {
6074 // send GraphicsSceneHoverLeave events to newly blocked hoverItems
6075 QGraphicsSceneHoverEvent hoverEvent;
6076 hoverEvent.setScenePos(lastSceneMousePos);
6077 dispatchHoverEvent(&hoverEvent);
6078 }
6079
6083 ungrabMouse(item, /*itemIsDying =*/ false);
6084 }
6085
6086 QEvent windowBlockedEvent(QEvent::WindowBlocked);
6087 QEvent windowUnblockedEvent(QEvent::WindowUnblocked);
6088 const auto items_ = q->items();
6089 for (const auto &item : items_) {
6090 if (item->isPanel()) {
6091 if (!blockedPanels.contains(item) && item->isBlockedByModalPanel()) {
6092 // send QEvent::WindowBlocked to newly blocked panels
6093 sendEvent(item, &windowBlockedEvent);
6094 } else if (blockedPanels.contains(item) && !item->isBlockedByModalPanel()) {
6095 // send QEvent::WindowUnblocked to unblocked panels when downgrading
6096 // a panel from SceneModal to PanelModal
6097 sendEvent(item, &windowUnblockedEvent);
6098 }
6099 }
6100 }
6101}
6102
6104{
6105 Q_Q(QGraphicsScene);
6106 Q_ASSERT(panel && panel->isPanel());
6107
6108 QSet<QGraphicsItem *> blockedPanels;
6109 {
6110 const auto items_ = q->items();
6111 for (const auto &item : items_) {
6113 blockedPanels.insert(item);
6114 }
6115 }
6116
6118
6119 {
6121 const auto items_ = q->items();
6122 for (const auto &item : items_) {
6123 if (item->isPanel() && blockedPanels.contains(item) && !item->isBlockedByModalPanel())
6124 sendEvent(item, &e);
6125 }
6126 }
6127
6128 // send GraphicsSceneHoverEnter events to newly unblocked items
6129 QGraphicsSceneHoverEvent hoverEvent;
6130 hoverEvent.setScenePos(lastSceneMousePos);
6131 dispatchHoverEvent(&hoverEvent);
6132}
6133
6134#ifndef QT_NO_GESTURES
6135void QGraphicsScenePrivate::gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures,
6136 Qt::GestureFlag flag,
6137 QHash<QGraphicsObject *, QSet<QGesture *> > *targets,
6138 QSet<QGraphicsObject *> *itemsSet,
6139 QSet<QGesture *> *normal,
6140 QSet<QGesture *> *conflicts)
6141{
6142 QSet<QGesture *> normalGestures; // that are not in conflicted state.
6143 for (QGesture *gesture : gestures) {
6144 if (!gesture->hasHotSpot())
6145 continue;
6146 const Qt::GestureType gestureType = gesture->gestureType();
6147 const QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), gesture->d_func()->sceneHotSpot, nullptr);
6148 for (int j = 0; j < items.size(); ++j) {
6150
6151 // Check if the item is blocked by a modal panel and use it as
6152 // a target instead of this item.
6154
6155 if (QGraphicsObject *itemobj = item->toGraphicsObject()) {
6156 QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
6158 d->gestureContext.constFind(gestureType);
6159 if (it != d->gestureContext.constEnd() && (!flag || (it.value() & flag))) {
6160 if (normalGestures.contains(gesture)) {
6161 normalGestures.remove(gesture);
6162 if (conflicts)
6163 conflicts->insert(gesture);
6164 } else {
6165 normalGestures.insert(gesture);
6166 }
6167 if (targets)
6168 (*targets)[itemobj].insert(gesture);
6169 if (itemsSet)
6170 (*itemsSet).insert(itemobj);
6171 }
6172 }
6173 // Don't propagate through panels.
6174 if (item->isPanel())
6175 break;
6176 }
6177 }
6178 if (normal)
6179 *normal = normalGestures;
6180}
6181
6183{
6184 QWidget *viewport = event->widget();
6185 if (!viewport)
6186 return;
6187 QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(viewport->parent());
6188 if (!graphicsView)
6189 return;
6190
6191 const QList<QGesture *> allGestures = event->gestures();
6192 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6193 << "Gestures:" << allGestures;
6194
6195 QSet<QGesture *> startedGestures;
6196 QPoint delta = viewport->mapFromGlobal(QPoint());
6197 QTransform toScene = QTransform::fromTranslate(delta.x(), delta.y())
6198 * graphicsView->viewportTransform().inverted();
6199 for (QGesture *gesture : allGestures) {
6200 // cache scene coordinates of the hot spot
6201 if (gesture->hasHotSpot()) {
6202 gesture->d_func()->sceneHotSpot = toScene.map(gesture->hotSpot());
6203 } else {
6204 gesture->d_func()->sceneHotSpot = QPointF();
6205 }
6206
6208 if (!target) {
6209 // when we are not in started mode but don't have a target
6210 // then the only one interested in gesture is the view/scene
6211 if (gesture->state() == Qt::GestureStarted)
6212 startedGestures.insert(gesture);
6213 }
6214 }
6215
6216 if (!startedGestures.isEmpty()) {
6217 QSet<QGesture *> normalGestures; // that have just one target
6218 QSet<QGesture *> conflictedGestures; // that have multiple possible targets
6219 gestureTargetsAtHotSpots(startedGestures, Qt::GestureFlag(0), &cachedItemGestures, nullptr,
6220 &normalGestures, &conflictedGestures);
6223 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6224 << "Normal gestures:" << normalGestures
6225 << "Conflicting gestures:" << conflictedGestures;
6226
6227 // deliver conflicted gestures as override events AND remember
6228 // initial gesture targets
6229 if (!conflictedGestures.isEmpty()) {
6230 for (int i = 0; i < cachedTargetItems.size(); ++i) {
6231 QPointer<QGraphicsObject> item = cachedTargetItems.at(i);
6232
6233 // get gestures to deliver to the current item
6234 const QSet<QGesture *> gestures = conflictedGestures & cachedItemGestures.value(item.data());
6235 if (gestures.isEmpty())
6236 continue;
6237
6238 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6239 << "delivering override to"
6240 << item.data() << gestures;
6241 // send gesture override
6242 QGestureEvent ev(gestures.values());
6244 ev.setWidget(event->widget());
6245 // mark event and individual gestures as ignored
6246 ev.ignore();
6247 for (QGesture *g : gestures)
6248 ev.setAccepted(g, false);
6249 sendEvent(item.data(), &ev);
6250 // mark all accepted gestures to deliver them as normal gesture events
6251 for (QGesture *g : gestures) {
6252 if (ev.isAccepted() || ev.isAccepted(g)) {
6253 conflictedGestures.remove(g);
6254 // mark the item as a gesture target
6255 if (item) {
6257 QHash<QGraphicsObject *, QSet<QGesture *> >::iterator it, e;
6259 e = cachedItemGestures.end();
6260 for(; it != e; ++it)
6261 it.value().remove(g);
6263 }
6264 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6265 << "override was accepted:"
6266 << g << item.data();
6267 }
6268 // remember the first item that received the override event
6269 // as it most likely become a target if no one else accepts
6270 // the override event
6271 if (!gestureTargets.contains(g) && item)
6273
6274 }
6275 if (conflictedGestures.isEmpty())
6276 break;
6277 }
6278 }
6279 // remember the initial target item for each gesture that was not in
6280 // the conflicted state.
6281 if (!normalGestures.isEmpty()) {
6282 for (int i = 0; i < cachedTargetItems.size() && !normalGestures.isEmpty(); ++i) {
6284
6285 // get gestures to deliver to the current item
6286 const auto gestures = cachedItemGestures.value(item);
6287 for (QGesture *g : gestures) {
6288 if (!gestureTargets.contains(g)) {
6290 normalGestures.remove(g);
6291 }
6292 }
6293 }
6294 }
6295 }
6296
6297
6298 // deliver all gesture events
6299 QSet<QGesture *> undeliveredGestures;
6300 QSet<QGesture *> parentPropagatedGestures;
6301 for (QGesture *gesture : allGestures) {
6302 if (QGraphicsObject *target = gestureTargets.value(gesture, 0)) {
6305 undeliveredGestures.insert(gesture);
6306 QGraphicsItemPrivate *d = target->QGraphicsItem::d_func();
6307 const Qt::GestureFlags flags = d->gestureContext.value(gesture->gestureType());
6309 parentPropagatedGestures.insert(gesture);
6310 } else {
6311 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6312 << "no target for" << gesture << "at"
6313 << gesture->hotSpot() << gesture->d_func()->sceneHotSpot;
6314 }
6315 }
6317 for (int i = 0; i < cachedTargetItems.size(); ++i) {
6318 QPointer<QGraphicsObject> receiver = cachedTargetItems.at(i);
6319 const QSet<QGesture *> gestures = (undeliveredGestures
6320 & cachedItemGestures.value(receiver.data()))
6321 - cachedAlreadyDeliveredGestures.value(receiver.data());
6322
6323 if (gestures.isEmpty())
6324 continue;
6325
6326 cachedAlreadyDeliveredGestures[receiver.data()] += gestures;
6327 const bool isPanel = receiver.data()->isPanel();
6328
6329 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6330 << "delivering to"
6331 << receiver.data() << gestures;
6332 QGestureEvent ev(gestures.values());
6333 ev.setWidget(event->widget());
6334 sendEvent(receiver.data(), &ev);
6335 QSet<QGesture *> ignoredGestures;
6336 for (QGesture *g : gestures) {
6337 if (!ev.isAccepted() && !ev.isAccepted(g)) {
6338 // if the gesture was ignored by its target, we will update the
6339 // targetItems list with a possible target items (items that
6340 // want to receive partial gestures).
6341 // ### won't work if the target was destroyed in the event
6342 // we will just stop delivering it.
6343 if (receiver && receiver.data() == gestureTargets.value(g, 0))
6344 ignoredGestures.insert(g);
6345 } else {
6346 if (receiver && g->state() == Qt::GestureStarted) {
6347 // someone accepted the propagated initial GestureStarted
6348 // event, let it be the new target for all following events.
6349 gestureTargets[g] = receiver.data();
6350 }
6351 undeliveredGestures.remove(g);
6352 }
6353 }
6354 if (undeliveredGestures.isEmpty())
6355 break;
6356
6357 // ignoredGestures list is only filled when delivering to the gesture
6358 // target item, so it is safe to assume item == target.
6359 if (!ignoredGestures.isEmpty() && !isPanel) {
6360 // look for new potential targets for gestures that were ignored
6361 // and should be propagated.
6362
6363 QSet<QGraphicsObject *> targetsSet(cachedTargetItems.constBegin(), cachedTargetItems.constEnd());
6364
6365 if (receiver) {
6366 // first if the gesture should be propagated to parents only
6367 for (QSet<QGesture *>::iterator it = ignoredGestures.begin();
6368 it != ignoredGestures.end();) {
6369 if (parentPropagatedGestures.contains(*it)) {
6370 QGesture *gesture = *it;
6371 const Qt::GestureType gestureType = gesture->gestureType();
6372 QGraphicsItem *item = receiver.data();
6373 while (item) {
6375 if (item->d_func()->gestureContext.contains(gestureType)) {
6376 targetsSet.insert(obj);
6377 cachedItemGestures[obj].insert(gesture);
6378 }
6379 }
6380 if (item->isPanel())
6381 break;
6382 item = item->parentItem();
6383 }
6384
6385 it = ignoredGestures.erase(it);
6386 continue;
6387 }
6388 ++it;
6389 }
6390 }
6391
6393 &cachedItemGestures, &targetsSet, nullptr, nullptr);
6394
6395 cachedTargetItems = targetsSet.values();
6397 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
6398 << "new targets:" << cachedTargetItems;
6399 i = -1; // start delivery again
6400 continue;
6401 }
6402 }
6403
6404 for (QGesture *g : std::as_const(startedGestures)) {
6405 if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
6406 DEBUG() << "lets try to cancel some";
6407 // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
6409 }
6410 }
6411
6412 // forget about targets for gestures that have ended
6413 for (QGesture *g : allGestures) {
6414 switch (g->state()) {
6418 break;
6419 default:
6420 break;
6421 }
6422 }
6423
6427}
6428
6430{
6431 Q_ASSERT(original);
6432 QGraphicsItem *originalItem = gestureTargets.value(original);
6433 if (originalItem == nullptr) // we only act on accepted gestures, which implies it has a target.
6434 return;
6435
6436 // iterate over all active gestures and for each find the owner
6437 // if the owner is part of our sub-hierarchy, cancel it.
6438
6439 QSet<QGesture *> canceledGestures;
6441 while (iter != gestureTargets.end()) {
6442 QGraphicsObject *item = iter.value();
6443 // note that we don't touch the gestures for our originalItem
6444 if (item != originalItem && originalItem->isAncestorOf(item)) {
6445 DEBUG() << " found a gesture to cancel" << iter.key();
6446 iter.key()->d_func()->state = Qt::GestureCanceled;
6447 canceledGestures << iter.key();
6448 }
6449 ++iter;
6450 }
6451
6452 // sort them per target item by cherry picking from almostCanceledGestures and delivering
6453 QSet<QGesture *> almostCanceledGestures = canceledGestures;
6455 while (!almostCanceledGestures.isEmpty()) {
6456 QGraphicsObject *target = nullptr;
6457 QSet<QGesture*> gestures;
6458 setIter = almostCanceledGestures.begin();
6459 // sort per target item
6460 while (setIter != almostCanceledGestures.end()) {
6462 if (target == nullptr)
6463 target = item;
6464 if (target == item) {
6465 gestures << *setIter;
6466 setIter = almostCanceledGestures.erase(setIter);
6467 } else {
6468 ++setIter;
6469 }
6470 }
6472
6473 const QList<QGesture *> list = gestures.values();
6474 QGestureEvent ev(list);
6475 sendEvent(target, &ev);
6476
6477 if (!ev.isAccepted()) {
6478 for (QGesture *g : list) {
6479
6480 if (ev.isAccepted(g))
6481 continue;
6482
6483 if (!g->hasHotSpot())
6484 continue;
6485
6486 const QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), g->d_func()->sceneHotSpot, nullptr);
6487 for (const auto &item : items) {
6489 if (!object)
6490 continue;
6491 QGraphicsItemPrivate *d = object->QGraphicsItem::d_func();
6492 if (d->gestureContext.contains(g->gestureType())) {
6493 QList<QGesture *> list;
6494 list << g;
6495 QGestureEvent ev(list);
6496 sendEvent(object, &ev);
6497 if (ev.isAccepted() || ev.isAccepted(g))
6498 break; // successfully delivered
6499 }
6500 }
6501 }
6502 }
6503 }
6504
6505 QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
6506 Q_ASSERT(gestureManager); // it would be very odd if we got called without a manager.
6507 for (setIter = canceledGestures.begin(); setIter != canceledGestures.end(); ++setIter) {
6508 gestureManager->recycle(*setIter);
6509 gestureTargets.remove(*setIter);
6510 }
6511}
6512
6514{
6515 (void)QGestureManager::instance(); // create a gesture manager
6516 if (!grabbedGestures[gesture]++) {
6517 for (QGraphicsView *view : std::as_const(views))
6518 view->viewport()->grabGesture(gesture);
6519 }
6520}
6521
6523{
6524 // we know this can only be an object
6526 QGraphicsObject *obj = static_cast<QGraphicsObject *>(item);
6527 QGestureManager::instance()->cleanupCachedGestures(obj, gesture);
6528 if (!--grabbedGestures[gesture]) {
6529 for (QGraphicsView *view : std::as_const(views))
6530 view->viewport()->ungrabGesture(gesture);
6531 }
6532}
6533#endif // QT_NO_GESTURES
6534
6536
6537#include "moc_qgraphicsscene.cpp"
static QApplicationPrivate * instance()
static QStyle * style()
Returns the application's style object.
static QFont font()
Returns the default application font.
\inmodule QtGui
Definition qbrush.h:30
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
static QColor fromHsv(int h, int s, int v, int a=255)
Static convenience function that returns a QColor constructed from the HSV color values,...
Definition qcolor.cpp:2499
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
static QPoint pos()
Returns the position of the cursor (hot spot) of the primary screen in global screen coordinates.
Definition qcursor.cpp:188
The QEventPoint class provides information about a point in a QPointerEvent.
Definition qeventpoint.h:20
int id
the ID number of this event point.
Definition qeventpoint.h:24
\inmodule QtCore
Definition qcoreevent.h:45
virtual void setAccepted(bool accepted)
Definition qcoreevent.h:307
bool spontaneous() const
Returns true if the event originated outside the application (a system event); otherwise returns fals...
Definition qcoreevent.h:305
Type
This enum type defines the valid event types in Qt.
Definition qcoreevent.h:51
@ GraphicsSceneDragLeave
Definition qcoreevent.h:200
@ GraphicsSceneMouseMove
Definition qcoreevent.h:189
@ ApplicationPaletteChange
Definition qcoreevent.h:93
@ GestureOverride
Definition qcoreevent.h:254
@ GraphicsSceneContextMenu
Definition qcoreevent.h:193
@ GraphicsSceneMouseRelease
Definition qcoreevent.h:191
@ WindowBlocked
Definition qcoreevent.h:141
@ WindowUnblocked
Definition qcoreevent.h:142
@ GraphicsSceneDragEnter
Definition qcoreevent.h:198
@ GraphicsSceneDragMove
Definition qcoreevent.h:199
@ ShortcutOverride
Definition qcoreevent.h:158
@ FocusOut
Definition qcoreevent.h:67
@ InputMethod
Definition qcoreevent.h:120
@ GraphicsSceneMousePress
Definition qcoreevent.h:190
@ StyleChange
Definition qcoreevent.h:136
@ UngrabMouse
Definition qcoreevent.h:234
@ FontChange
Definition qcoreevent.h:133
@ KeyRelease
Definition qcoreevent.h:65
@ KeyPress
Definition qcoreevent.h:64
@ StyleAnimationUpdate
Definition qcoreevent.h:272
@ FocusIn
Definition qcoreevent.h:66
@ ActivationChange
Definition qcoreevent.h:135
@ TouchUpdate
Definition qcoreevent.h:242
@ TouchBegin
Definition qcoreevent.h:241
@ GraphicsSceneHoverLeave
Definition qcoreevent.h:196
@ WindowActivate
Definition qcoreevent.h:83
@ GraphicsSceneMouseDoubleClick
Definition qcoreevent.h:192
@ GraphicsSceneWheel
Definition qcoreevent.h:202
@ GraphicsSceneDrop
Definition qcoreevent.h:201
@ PaletteChange
Definition qcoreevent.h:94
@ GraphicsSceneHoverEnter
Definition qcoreevent.h:194
@ UngrabKeyboard
Definition qcoreevent.h:236
@ GraphicsSceneHoverMove
Definition qcoreevent.h:195
@ ApplicationFontChange
Definition qcoreevent.h:91
@ GraphicsSceneHelp
Definition qcoreevent.h:197
@ GrabKeyboard
Definition qcoreevent.h:235
@ WindowDeactivate
Definition qcoreevent.h:84
@ GrabMouse
Definition qcoreevent.h:233
@ GraphicsSceneLeave
Definition qcoreevent.h:203
Type type() const
Returns the event type.
Definition qcoreevent.h:304
void ignore()
Clears the accept flag parameter of the event object, the equivalent of calling setAccepted(false).
Definition qcoreevent.h:311
bool isAccepted() const
Definition qcoreevent.h:308
void accept()
Sets the accept flag of the event object, the equivalent of calling setAccepted(true).
Definition qcoreevent.h:310
The QFocusEvent class contains event parameters for widget focus events.
Definition qevent.h:470
Qt::FocusReason reason() const
Returns the reason for this focus event.
Definition qevent.cpp:1569
\reentrant
Definition qfont.h:22
QFont resolve(const QFont &) const
Returns a new QFont that has attributes copied from other that have not been previously set on this f...
Definition qfont.cpp:1893
uint resolveMask() const
Definition qfont.h:312
The QGestureEvent class provides the description of triggered gestures.
Definition qgesture.h:244
void recycle(QGesture *gesture)
bool filterEvent(QWidget *receiver, QEvent *event)
static QGestureManager * instance(InstanceCreation ic=ForceCreation)
The QGesture class represents a gesture, containing properties that describe the corresponding user i...
Definition qgesture.h:29
@ CancelAllInContext
Definition qgesture.h:55
Qt::GestureType gestureType
the type of the gesture
Definition qgesture.h:34
The QGraphicsEffectSource class represents the source on which a QGraphicsEffect is installed on.
QGraphicsEffectSource * source() const
virtual void draw(QPainter *painter)=0
This pure virtual function draws the effect and is called whenever the source needs to be drawn.
bool isEnabled() const
The QGraphicsEllipseItem class provides an ellipse item that you can add to a QGraphicsScene.
QList< QRectF > exposed
QPixmapCache::Key key
QHash< QPaintDevice *, DeviceData > deviceData
The QGraphicsItemGroup class provides a container that treats a group of items as a single item.
void invalidateChildrenSceneTransform()
QGraphicsScene * scene
static bool insertionOrder(QGraphicsItem *a, QGraphicsItem *b)
void initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform, const QRegion &exposedRegion, bool allItems=false) const
QGraphicsEffect * graphicsEffect
void markParentDirty(bool updateBoundingRect=false)
QMap< Qt::GestureType, Qt::GestureFlags > gestureContext
bool itemIsUntransformable() const
bool discardUpdateRequest(bool ignoreVisibleBit=false, bool ignoreDirtyBit=false, bool ignoreOpacity=false) const
bool childrenCombineOpacity() const
void clearSubFocus(QGraphicsItem *rootItem=nullptr, QGraphicsItem *stopItem=nullptr)
QList< QGraphicsItem * > children
QPointF genericMapFromScene(const QPointF &pos, const QWidget *viewport) const
virtual void updateSceneTransformFromParent()
QTransform genericMapFromSceneTransform(const QWidget *viewport=nullptr) const
quint32 paintedViewBoundingRectsNeedRepaint
QGraphicsItem * parent
virtual void resolvePalette(uint inheritedMask)
QHash< QWidget *, QRect > paintedViewBoundingRects
virtual void resolveFont(uint inheritedMask)
qreal combineOpacityFromParent(qreal parentOpacity) const
The QGraphicsItem class is the base class for all graphical items in a QGraphicsScene.
virtual bool contains(const QPointF &point) const
Returns true if this item contains point, which is in local coordinates; otherwise,...
QTransform deviceTransform(const QTransform &viewportTransform) const
bool isWidget() const
void setSelected(bool selected)
If selected is true and this item is selectable, this item is selected; otherwise,...
bool acceptDrops() const
Returns true if this item can accept drag and drop events; otherwise, returns false.
QScopedPointer< QGraphicsItemPrivate > d_ptr
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value)
This virtual function is called by QGraphicsItem to notify custom items that some part of the item's ...
qreal boundingRegionGranularity() const
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=nullptr)=0
This function, which is usually called by QGraphicsView, paints the contents of an item in local coor...
bool isWindow() const
void clearFocus()
Takes keyboard input focus from the item.
QGraphicsScene * scene() const
Returns the current scene for the item, or \nullptr if the item is not stored in a scene.
bool isSelected() const
Returns true if this item is selected; otherwise, false is returned.
virtual bool collidesWithItem(const QGraphicsItem *other, Qt::ItemSelectionMode mode=Qt::IntersectsItemShape) const
Returns true if this item collides with other; otherwise returns false.
virtual QPainterPath shape() const
Returns the shape of this item as a QPainterPath in local coordinates.
@ ItemContainsChildrenInShape
@ ItemSendsScenePositionChanges
@ ItemStopsClickFocusPropagation
QGraphicsWidget * window() const
QRectF sceneBoundingRect() const
Returns the bounding rect of this item in scene coordinates, by combining sceneTransform() with bound...
virtual QRectF boundingRect() const =0
This pure virtual function defines the outer bounds of the item as a rectangle; all painting must be ...
bool isEnabled() const
Returns true if the item is enabled; otherwise, false is returned.
bool isBlockedByModalPanel(QGraphicsItem **blockingPanel=nullptr) const
QGraphicsObject * toGraphicsObject()
virtual void advance(int phase)
This virtual function is called twice for all items by the QGraphicsScene::advance() slot.
void setParentItem(QGraphicsItem *parent)
Sets this item's parent item to newParent.
Qt::MouseButtons acceptedMouseButtons() const
Returns the mouse buttons that this item accepts mouse events for.
QVariant data(int key) const
Returns this item's custom data for the key key as a QVariant.
bool isPanel() const
QGraphicsItem * panel() const
QGraphicsItem * parentItem() const
Returns a pointer to this item's parent item.
QTransform sceneTransform() const
QGraphicsItem * commonAncestorItem(const QGraphicsItem *other) const
bool isVisible() const
Returns true if the item is visible; otherwise, false is returned.
QGraphicsItem * focusItem() const
PanelModality panelModality() const
void setFocus(Qt::FocusReason focusReason=Qt::OtherFocusReason)
Gives keyboard input focus to this item.
GraphicsItemFlags flags() const
Returns this item's flags.
virtual bool sceneEvent(QEvent *event)
This virtual function receives events to this item.
bool acceptTouchEvents() const
bool isAncestorOf(const QGraphicsItem *child) const
Returns true if this item is an ancestor of child (i.e., if this item is child's parent,...
The QGraphicsLineItem class provides a line item that you can add to a QGraphicsScene.
The QGraphicsObject class provides a base class for all graphics items that require signals,...
The QGraphicsPixmapItem class provides a pixmap item that you can add to a QGraphicsScene.
The QGraphicsPolygonItem class provides a polygon item that you can add to a QGraphicsScene.
The QGraphicsProxyWidget class provides a proxy layer for embedding a QWidget in a QGraphicsScene.
The QGraphicsRectItem class provides a rectangle item that you can add to a QGraphicsScene.
The QGraphicsSceneBspTreeIndex class provides an implementation of a BSP indexing algorithm for disco...
The QGraphicsSceneContextMenuEvent class provides context menu events in the graphics view framework.
The QGraphicsSceneDragDropEvent class provides events for drag and drop in the graphics view framewor...
void setButtons(Qt::MouseButtons buttons)
void setMimeData(const QMimeData *data)
void setPossibleActions(Qt::DropActions actions)
void setProposedAction(Qt::DropAction action)
void setModifiers(Qt::KeyboardModifiers modifiers)
void setDropAction(Qt::DropAction action)
This function lets the receiver of the drop set the drop action that was performed to action,...
void setScreenPos(const QPoint &pos)
void setPos(const QPointF &pos)
void setScenePos(const QPointF &pos)
The QGraphicsSceneEvent class provides a base class for all graphics view related events.
void setWidget(QWidget *widget)
QWidget * widget() const
Returns the widget where the event originated, or \nullptr if the event originates from another appli...
The QGraphicsSceneHelpEvent class provides events when a tooltip is requested.
The QGraphicsSceneHoverEvent class provides hover events in the graphics view framework.
void setScreenPos(const QPoint &pos)
void setPos(const QPointF &pos)
void setLastPos(const QPointF &pos)
QPoint screenPos() const
Returns the position of the mouse cursor in screen coordinates at the moment the hover event was sent...
void setScenePos(const QPointF &pos)
QPointF scenePos() const
Returns the position of the mouse cursor in scene coordinates at the moment the hover event was sent.
void setModifiers(Qt::KeyboardModifiers modifiers)
void setLastScenePos(const QPointF &pos)
void setLastScreenPos(const QPoint &pos)
Qt::KeyboardModifiers modifiers() const
The QGraphicsSceneLinearIndex class provides an implementation of a linear indexing algorithm for dis...
The QGraphicsSceneMouseEvent class provides mouse events in the graphics view framework.
Qt::MouseButton button() const
Returns the mouse button (if any) that caused the event.
QPointF pos() const
Returns the mouse cursor position in item coordinates.
void setButtonDownPos(Qt::MouseButton button, const QPointF &pos)
QPointF lastScenePos() const
Returns the last recorded mouse cursor position in scene coordinates.
QPointF buttonDownScenePos(Qt::MouseButton button) const
Returns the mouse cursor position in scene coordinates where the specified button was clicked.
QPoint buttonDownScreenPos(Qt::MouseButton button) const
Returns the mouse cursor position in screen coordinates where the specified button was clicked.
void setLastPos(const QPointF &pos)
QPoint lastScreenPos() const
Returns the last recorded mouse cursor position in screen coordinates.
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifiers in use at the time the event was sent.
QPoint screenPos() const
Returns the mouse cursor position in screen coordinates.
void setPos(const QPointF &pos)
Qt::MouseButtons buttons() const
Returns the combination of mouse buttons that were pressed at the time the event was sent.
void setButtonDownScenePos(Qt::MouseButton button, const QPointF &pos)
QPointF lastPos() const
Returns the last recorded mouse cursor position in item coordinates.
QPointF scenePos() const
Returns the mouse cursor position in scene coordinates.
void setButtonDownScreenPos(Qt::MouseButton button, const QPoint &pos)
QPointF buttonDownPos(Qt::MouseButton button) const
Returns the mouse cursor position in item coordinates where the specified button was clicked.
QList< QGraphicsItem * > cachedItemsUnderMouse
QMultiMap< QGraphicsItem *, QGraphicsItem * > sceneEventFilters
QList< QGraphicsView * > views
QHash< QGraphicsObject *, QSet< QGesture * > > cachedItemGestures
void removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
void setScenePosItemEnabled(QGraphicsItem *item, bool enabled)
void addView(QGraphicsView *view)
void resetDirtyItem(QGraphicsItem *item, bool recursive=false)
QList< QGraphicsItem * > itemsAtPosition(const QPoint &screenPos, const QPointF &scenePos, QWidget *widget) const
Returns all items for the screen position in event.
void registerScenePosItem(QGraphicsItem *item)
QHash< QGesture *, QGraphicsObject * > gestureTargets
QList< QGraphicsItem * > modalPanels
QList< QGraphicsItem * > mouseGrabberItems
void gestureEventHandler(QGestureEvent *event)
QHash< QGraphicsObject *, QSet< QGesture * > > cachedAlreadyDeliveredGestures
QSet< QGraphicsItem * > scenePosItems
int findClosestTouchPointId(const QPointF &scenePos)
void leaveModal(QGraphicsItem *item)
QGraphicsItem * lastFocusItem
QList< QGraphicsWidget * > popupWidgets
void ungrabMouse(QGraphicsItem *item, bool itemIsDying=false)
QStyleOptionGraphicsItem styleOptionTmp
bool sendEvent(QGraphicsItem *item, QEvent *event)
QMap< int, QEventPoint > sceneCurrentTouchPoints
void grabMouse(QGraphicsItem *item, bool implicit=false)
void addPopup(QGraphicsWidget *widget)
void markDirty(QGraphicsItem *item, const QRectF &rect=QRectF(), bool invalidateChildren=false, bool force=false, bool ignoreOpacity=false, bool removingItemFromScene=false, bool updateBoundingRect=false)
QList< QGraphicsItem * > unpolishedItems
static void updateTouchPointsForItem(QGraphicsItem *item, QTouchEvent *touchEvent)
void gestureTargetsAtHotSpots(const QSet< QGesture * > &gestures, Qt::GestureFlag flag, QHash< QGraphicsObject *, QSet< QGesture * > > *targets, QSet< QGraphicsObject * > *itemsSet=nullptr, QSet< QGesture * > *normal=nullptr, QSet< QGesture * > *conflicts=nullptr)
void removeView(QGraphicsView *view)
QMap< Qt::MouseButton, QPoint > mouseGrabberButtonDownScreenPos
QGraphicsWidget * tabFocusFirst
void ungrabGesture(QGraphicsItem *, Qt::GestureType gesture)
QHash< Qt::GestureType, int > grabbedGestures
void mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent)
QSet< QGraphicsItem * > selectedItems
void ungrabKeyboard(QGraphicsItem *item, bool itemIsDying=false)
void grabKeyboard(QGraphicsItem *item)
void installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
void updateFont(const QFont &font)
bool filterDescendantEvent(QGraphicsItem *item, QEvent *event)
void touchEventHandler(QTouchEvent *touchEvent)
QGraphicsItem * passiveFocusItem
QList< QGraphicsObject * > cachedTargetItems
QGraphicsItem * activePanel
void drawItems(QPainter *painter, const QTransform *const viewTransform, QRegion *exposedRegion, QWidget *widget)
void updatePalette(const QPalette &palette)
static QGraphicsScenePrivate * get(QGraphicsScene *q)
QList< QGraphicsItem * > hoverItems
void setFocusItemHelper(QGraphicsItem *item, Qt::FocusReason focusReason, bool emitFocusChanged=true)
void drawItemHelper(QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget, bool painterStateProtection)
bool sendTouchBeginEvent(QGraphicsItem *item, QTouchEvent *touchEvent)
QGraphicsItem * focusItem
void drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, const QTransform *const, QRegion *exposedRegion, QWidget *widget, qreal parentOpacity=qreal(1.0), const QTransform *const effectTransform=nullptr)
void setFont_helper(const QFont &font)
void unregisterTopLevelItem(QGraphicsItem *item)
void cancelGesturesForChildren(QGesture *original)
void sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent)
void enterModal(QGraphicsItem *item, QGraphicsItem::PanelModality panelModality=QGraphicsItem::NonModal)
void registerTopLevelItem(QGraphicsItem *item)
std::set< QRectF, UpdatedRectsCmp > updatedRects
QGraphicsItem * lastMouseGrabberItem
void leaveScene(QWidget *viewport)
bool dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent)
This event handler, for event hoverEvent, can be reimplemented in a subclass to receive hover enter e...
QGraphicsScene::ItemIndexMethod indexMethod
bool itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const
void grabGesture(QGraphicsItem *, Qt::GestureType gesture)
quint32 scenePosDescendantsUpdatePending
QGraphicsItem * lastActivePanel
bool filterEvent(QGraphicsItem *item, QEvent *event)
QMap< Qt::MouseButton, QPointF > mouseGrabberButtonDownScenePos
void processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren=false, qreal parentOpacity=qreal(1.0))
QGraphicsSceneIndex * index
QGraphicsItem * dragDropItem
QMap< int, QGraphicsItem * > itemForTouchPointId
void unregisterScenePosItem(QGraphicsItem *item)
void removeItemHelper(QGraphicsItem *item)
QList< QGraphicsItem * > keyboardGrabberItems
void sendHoverEvent(QEvent::Type type, QGraphicsItem *item, QGraphicsSceneHoverEvent *hoverEvent)
void draw(QGraphicsItem *, QPainter *, const QTransform *const, const QTransform *const, QRegion *, QWidget *, qreal, const QTransform *const, bool, bool)
void setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent)
void cloneDragDropEvent(QGraphicsSceneDragDropEvent *dest, QGraphicsSceneDragDropEvent *source)
void storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event)
QMap< Qt::MouseButton, QPointF > mouseGrabberButtonDownPos
quint32 lastMouseGrabberItemHasImplicitMouseGrab
void setPalette_helper(const QPalette &palette)
void removePopup(QGraphicsWidget *widget, bool itemIsDying=false)
void ensureSequentialTopLevelSiblingIndexes()
QList< QGraphicsItem * > topLevelItems
void sendDragDropEvent(QGraphicsItem *item, QGraphicsSceneDragDropEvent *dragDropEvent)
The QGraphicsSceneWheelEvent class provides wheel events in the graphics view framework.
The QGraphicsScene class provides a surface for managing a large number of 2D graphical items.
qreal minimumRenderSize
the minimal view-transformed size an item must have to be drawn
QList< QGraphicsItem * > items(Qt::SortOrder order=Qt::DescendingOrder) const
Returns an ordered list of all items on the scene.
void removeItem(QGraphicsItem *item)
Removes the item item and all its children from the scene.
void setFont(const QFont &font)
bool hasFocus() const
Returns true if the scene has focus; otherwise returns false.
void addItem(QGraphicsItem *item)
Adds or moves the item and all its children to this scene.
virtual void dragMoveEvent(QGraphicsSceneDragDropEvent *event)
This event handler, for event event, can be reimplemented in a subclass to receive drag move events f...
void changed(const QList< QRectF > &region)
This signal is emitted by QGraphicsScene when control reaches the event loop, if the scene content ch...
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event)
This event handler, for event mouseEvent, can be reimplemented in a subclass to receive mouse press e...
QGraphicsProxyWidget * addWidget(QWidget *widget, Qt::WindowFlags wFlags=Qt::WindowFlags())
Creates a new QGraphicsProxyWidget for widget, adds it to the scene, and returns a pointer to the pro...
void destroyItemGroup(QGraphicsItemGroup *group)
Reparents all items in group to group's parent item, then removes group from the scene,...
void clearSelection()
Clears the current selection.
virtual void helpEvent(QGraphicsSceneHelpEvent *event)
This event handler, for event helpEvent, can be reimplemented in a subclass to receive help events.
void setFocusItem(QGraphicsItem *item, Qt::FocusReason focusReason=Qt::OtherFocusReason)
Sets the scene's focus item to item, with the focus reason focusReason, after removing focus from any...
bool stickyFocus
whether clicking into the scene background will clear focus
virtual void dropEvent(QGraphicsSceneDragDropEvent *event)
This event handler, for event event, can be reimplemented in a subclass to receive drop events for th...
bool sendEvent(QGraphicsItem *item, QEvent *event)
virtual void drawItems(QPainter *painter, int numItems, QGraphicsItem *items[], const QStyleOptionGraphicsItem options[], QWidget *widget=nullptr)
QStyle * style() const
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event)
This event handler, for event mouseEvent, can be reimplemented in a subclass to receive mouse move ev...
void setFocusOnTouch(bool enabled)
bool isActive() const
QGraphicsPathItem * addPath(const QPainterPath &path, const QPen &pen=QPen(), const QBrush &brush=QBrush())
Creates and adds a path item to the scene, and returns the item pointer.
virtual void wheelEvent(QGraphicsSceneWheelEvent *event)
This event handler, for event wheelEvent, can be reimplemented in a subclass to receive mouse wheel e...
void setBspTreeDepth(int depth)
QGraphicsEllipseItem * addEllipse(const QRectF &rect, const QPen &pen=QPen(), const QBrush &brush=QBrush())
Creates and adds an ellipse item to the scene, and returns the item pointer.
void setStickyFocus(bool enabled)
virtual void dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
This event handler, for event event, can be reimplemented in a subclass to receive drag leave events ...
void setActivePanel(QGraphicsItem *item)
virtual void focusInEvent(QFocusEvent *event)
This event handler, for event focusEvent, can be reimplemented in a subclass to receive focus in even...
QList< QGraphicsItem * > selectedItems() const
Returns a list of all currently selected items.
QGraphicsScene(QObject *parent=nullptr)
Constructs a QGraphicsScene object.
bool eventFilter(QObject *watched, QEvent *event) override
\reimp
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
This event handler, for event mouseEvent, can be reimplemented in a subclass to receive mouse release...
QRectF sceneRect
the scene rectangle; the bounding rectangle of the scene
virtual void drawBackground(QPainter *painter, const QRectF &rect)
Draws the background of the scene using painter, before any items and the foreground are drawn.
void setForegroundBrush(const QBrush &brush)
void setStyle(QStyle *style)
QGraphicsItem * activePanel() const
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
This event handler, for event mouseEvent, can be reimplemented in a subclass to receive mouse double-...
void advance()
This slot advances the scene by one step, by calling QGraphicsItem::advance() for all items on the sc...
QBrush foregroundBrush
the foreground brush of the scene.
int bspTreeDepth
the depth of QGraphicsScene's BSP index tree
void invalidate(qreal x, qreal y, qreal w, qreal h, SceneLayers layers=AllLayers)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void setPalette(const QPalette &palette)
virtual ~QGraphicsScene()
Removes and deletes all items from the scene object before destroying the scene object.
QList< QGraphicsView * > views() const
Returns a list of all the views that display this scene.
QRectF itemsBoundingRect() const
Calculates and returns the bounding rect of all items on the scene.
void setSelectionArea(const QPainterPath &path, const QTransform &deviceTransform)
ItemIndexMethod itemIndexMethod
the item indexing method.
void update(qreal x, qreal y, qreal w, qreal h)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QGraphicsPixmapItem * addPixmap(const QPixmap &pixmap)
Creates and adds a pixmap item to the scene, and returns the item pointer.
QGraphicsPolygonItem * addPolygon(const QPolygonF &polygon, const QPen &pen=QPen(), const QBrush &brush=QBrush())
Creates and adds a polygon item to the scene, and returns the item pointer.
void setItemIndexMethod(ItemIndexMethod method)
void selectionChanged()
virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const
This method is used by input methods to query a set of properties of the scene to be able to support ...
void setSceneRect(const QRectF &rect)
QGraphicsRectItem * addRect(const QRectF &rect, const QPen &pen=QPen(), const QBrush &brush=QBrush())
Creates and adds a rectangle item to the scene, and returns the item pointer.
void sceneRectChanged(const QRectF &rect)
This signal is emitted by QGraphicsScene whenever the scene rect changes.
QBrush backgroundBrush
the background brush of the scene.
virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
This event handler, for event contextMenuEvent, can be reimplemented in a subclass to receive context...
virtual bool focusNextPrevChild(bool next)
bool focusOnTouch
whether items gain focus when receiving a {touch begin} event.
virtual void dragEnterEvent(QGraphicsSceneDragDropEvent *event)
This event handler, for event event, can be reimplemented in a subclass to receive drag enter events ...
QPalette palette
the scene's default palette
void setActiveWindow(QGraphicsWidget *widget)
QList< QGraphicsItem * > collidingItems(const QGraphicsItem *item, Qt::ItemSelectionMode mode=Qt::IntersectsItemShape) const
Returns a list of all items that collide with item.
ItemIndexMethod
This enum describes the indexing algorithms QGraphicsScene provides for managing positional informati...
QPainterPath selectionArea() const
Returns the selection area that was previously set with setSelectionArea(), or an empty QPainterPath ...
QFont font
the scene's default font
QGraphicsItemGroup * createItemGroup(const QList< QGraphicsItem * > &items)
Groups all items in items into a new QGraphicsItemGroup, and returns a pointer to the group.
void clearFocus()
Clears focus from the scene.
QGraphicsWidget * activeWindow() const
virtual void keyPressEvent(QKeyEvent *event)
This event handler, for event keyEvent, can be reimplemented in a subclass to receive keypress events...
QGraphicsLineItem * addLine(const QLineF &line, const QPen &pen=QPen())
Creates and adds a line item to the scene, and returns the item pointer.
friend class QGraphicsSceneBspTreeIndex
virtual void inputMethodEvent(QInputMethodEvent *event)
This event handler, for event event, can be reimplemented in a subclass to receive input method event...
void setBackgroundBrush(const QBrush &brush)
virtual void focusOutEvent(QFocusEvent *event)
This event handler, for event focusEvent, can be reimplemented in a subclass to receive focus out eve...
QGraphicsTextItem * addText(const QString &text, const QFont &font=QFont())
Creates and adds a text item to the scene, and returns the item pointer.
virtual void keyReleaseEvent(QKeyEvent *event)
This event handler, for event keyEvent, can be reimplemented in a subclass to receive key release eve...
void setMinimumRenderSize(qreal minSize)
void setFocus(Qt::FocusReason focusReason=Qt::OtherFocusReason)
Sets focus on the scene by sending a QFocusEvent to the scene, passing focusReason as the reason.
QGraphicsItem * focusItem() const
When the scene is active, this functions returns the scene's current focus item, or \nullptr if no it...
bool event(QEvent *event) override
Processes the event event, and dispatches it to the respective event handlers.
void render(QPainter *painter, const QRectF &target=QRectF(), const QRectF &source=QRectF(), Qt::AspectRatioMode aspectRatioMode=Qt::KeepAspectRatio)
Renders the source rect from scene into target, using painter.
QGraphicsSimpleTextItem * addSimpleText(const QString &text, const QFont &font=QFont())
Creates and adds a QGraphicsSimpleTextItem to the scene, and returns the item pointer.
QGraphicsItem * mouseGrabberItem() const
Returns the current mouse grabber item, or \nullptr if no item is currently grabbing the mouse.
virtual void drawForeground(QPainter *painter, const QRectF &rect)
Draws the foreground of the scene using painter, after the background and all items have been drawn.
QGraphicsItem * itemAt(const QPointF &pos, const QTransform &deviceTransform) const
The QGraphicsSimpleTextItem class provides a simple text path item that you can add to a QGraphicsSce...
The QGraphicsTextItem class provides a text item that you can add to a QGraphicsScene to display form...
The QGraphicsView class provides a widget for displaying the contents of a QGraphicsScene.
QTransform viewportTransform() const
Returns a matrix that maps scene coordinates to viewport coordinates.
QGraphicsWidget * focusNext
The QGraphicsWidget class is the base class for all widget items in a QGraphicsScene.
Qt::WindowFlags windowFlags
the widget's window flags
Qt::WindowType windowType() const
Returns the widgets window type.
Qt::LayoutDirection layoutDirection
the layout direction for this widget.
virtual void paintWindowFrame(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=nullptr)
This virtual function is called by QGraphicsScene to draw the window frame for windows using painter,...
bool autoFillBackground
whether the widget background is filled automatically
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=nullptr) override
\reimp
QPalette palette
the widget's palette
Qt::FocusPolicy focusPolicy
the way the widget accepts keyboard focus
static QPalette palette()
Returns the current application palette.
static QInputMethod * inputMethod()
returns the input method.
\inmodule QtCore
Definition qhash.h:1145
\inmodule QtCore
Definition qhash.h:1103
\inmodule QtCore
Definition qhash.h:820
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:958
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1212
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1219
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1215
QList< Key > keys() const
Returns a list containing all the keys in the hash, in an arbitrary order.
Definition qhash.h:1086
iterator erase(const_iterator it)
Definition qhash.h:1233
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:1007
T value(const Key &key) const noexcept
Definition qhash.h:1054
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1216
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:951
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
The QInputMethodEvent class provides parameters for input method events.
Definition qevent.h:625
The QKeyEvent class describes a key event.
Definition qevent.h:424
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately after the event occurred.
Definition qevent.cpp:1468
int key() const
Returns the code of the key that was pressed or released.
Definition qevent.h:434
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
qreal length() const
Returns the length of the line.
Definition qline.cpp:548
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
void removeAt(qsizetype i)
Definition qlist.h:590
const T & constLast() const noexcept
Definition qlist.h:650
bool removeOne(const AT &t)
Definition qlist.h:598
iterator end()
Definition qlist.h:626
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
T value(qsizetype i) const
Definition qlist.h:664
const_iterator constBegin() const noexcept
Definition qlist.h:632
void remove(qsizetype i, qsizetype n=1)
Definition qlist.h:794
value_type takeLast()
Definition qlist.h:567
qsizetype removeAll(const AT &t)
Definition qlist.h:592
void squeeze()
Definition qlist.h:774
void prepend(rvalue_ref t)
Definition qlist.h:473
iterator begin()
Definition qlist.h:625
const T & constFirst() const noexcept
Definition qlist.h:647
void append(parameter_type t)
Definition qlist.h:458
const_iterator constEnd() const noexcept
Definition qlist.h:633
void clear()
Definition qlist.h:434
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
iterator erase(const_iterator it)
Definition qmap.h:619
bool contains(const Key &key) const
Definition qmap.h:341
size_type remove(const Key &key)
Definition qmap.h:300
bool isEmpty() const
Definition qmap.h:269
T & first()
Definition qmap.h:419
iterator begin()
Definition qmap.h:598
iterator end()
Definition qmap.h:602
const_iterator constBegin() const
Definition qmap.h:600
const_iterator constEnd() const
Definition qmap.h:604
T take(const Key &key)
Definition qmap.h:322
\inmodule QtCore
Definition qmetaobject.h:19
iterator lowerBound(const Key &key)
Definition qmap.h:1424
bool contains(const Key &key) const
Definition qmap.h:1045
iterator end()
Definition qmap.h:1327
iterator insert(const Key &key, const T &value)
Definition qmap.h:1452
iterator erase(const_iterator it)
Definition qmap.h:1344
iterator upperBound(const Key &key)
Definition qmap.h:1438
iterator begin()
Definition qmap.h:1323
QObject * q_ptr
Definition qobject.h:72
QObjectList children
Definition qobject.h:74
QObject * parent
Definition qobject.h:73
bool isSignalConnected(uint signalIdx, bool checkDeclarative=true) const
Definition qobject.cpp:420
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1389
QScopedPointer< QObjectData > d_ptr
Definition qobject.h:373
qreal devicePixelRatio() const
virtual int devType() const
int width() const
int height() const
\inmodule QtGui
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
const QPen & pen() const
Returns the painter's current pen.
Qt::LayoutDirection layoutDirection() const
Returns the layout direction used by the painter when drawing text.
RenderHints renderHints() const
Returns a flag that specifies the rendering hints that are set for this painter.
void drawRect(const QRectF &rect)
Draws the current rectangle with the current pen and brush.
Definition qpainter.h:519
QPaintDevice * device() const
Returns the paint device on which this painter is currently painting, or \nullptr if the painter is n...
qreal opacity() const
void setClipRect(const QRectF &, Qt::ClipOperation op=Qt::ReplaceClip)
Enables clipping, and sets the clip region to the given rectangle using the given clip operation.
void setPen(const QColor &color)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void setBrushOrigin(int x, int y)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qpainter.h:698
void setClipPath(const QPainterPath &path, Qt::ClipOperation op=Qt::ReplaceClip)
Enables clipping, and sets the clip path for the painter to the given path, with the clip operation.
void setLayoutDirection(Qt::LayoutDirection direction)
Sets the layout direction used by the painter when drawing text, to the specified direction.
void restore()
Restores the current painter state (pops a saved state off the stack).
const QTransform & worldTransform() const
Returns the world transformation matrix.
const QBrush & brush() const
Returns the painter's current brush.
void setOpacity(qreal opacity)
void save()
Saves the current painter state (pushes the state onto a stack).
void setWorldTransform(const QTransform &matrix, bool combine=false)
Sets the world transformation matrix.
void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect)
Draws the rectangular portion source of the given pixmap into the given target in the paint device.
void setBrush(const QBrush &brush)
Sets the painter's brush to the given brush.
@ CompositionMode_Source
Definition qpainter.h:101
void fillRect(const QRectF &, const QBrush &)
Fills the given rectangle with the brush specified.
The QPalette class contains color groups for each widget state.
Definition qpalette.h:19
ResolveMask resolveMask() const
Definition qpalette.cpp:999
QPalette resolve(const QPalette &other) const
Returns a new QPalette that is a union of this instance and other.
Definition qpalette.cpp:963
const QBrush & window() const
Returns the window (general background) brush of the current color group.
Definition qpalette.h:93
static bool pathToRect(const QPainterPath &path, QRectF *rect=nullptr)
\inmodule QtGui
Definition qpen.h:28
The QPixmapCache::Key class can be used for efficient access to the QPixmapCache.
static bool find(const QString &key, QPixmap *pixmap)
Looks for a cached pixmap associated with the given key in the cache.
static void remove(const QString &key)
Removes the pixmap associated with key from the cache.
static bool insert(const QString &key, const QPixmap &pixmap)
Inserts a copy of the pixmap pixmap associated with the key into the cache.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
QSize size() const
Returns the size of the pixmap.
Definition qpixmap.cpp:493
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
Definition qpixmap.cpp:456
void setDevicePixelRatio(qreal scaleFactor)
Sets the device pixel ratio for the pixmap.
Definition qpixmap.cpp:604
QRect rect() const
Returns the pixmap's enclosing rectangle.
Definition qpixmap.cpp:505
void fill(const QColor &fillColor=Qt::white)
Fills the pixmap with the given color.
Definition qpixmap.cpp:850
qreal devicePixelRatio() const
Returns the device pixel ratio for the pixmap.
Definition qpixmap.cpp:576
\inmodule QtCore\reentrant
Definition qpoint.h:217
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
The QPolygonF class provides a list of points using floating point precision.
Definition qpolygon.h:96
void update()
Schedules the window to render another frame.
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:661
QRect toAlignedRect() const noexcept
Definition qrect.cpp:2338
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr QRectF translated(qreal dx, qreal dy) const noexcept
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis,...
Definition qrect.h:762
constexpr QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:813
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:497
constexpr bool isNull() const noexcept
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition qrect.h:658
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:498
constexpr void setRect(qreal x, qreal y, qreal w, qreal h) noexcept
Sets the coordinates of the rectangle's top-left corner to (x, y), and its size to the given width an...
Definition qrect.h:781
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:167
constexpr void adjust(int x1, int y1, int x2, int y2) noexcept
Adds dx1, dy1, dx2 and dy2 respectively to the existing coordinates of the rectangle.
Definition qrect.h:373
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:221
constexpr QRect adjusted(int x1, int y1, int x2, int y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:370
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:176
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:855
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:173
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:242
constexpr void translate(int dx, int dy) noexcept
Moves the rectangle dx along the x axis and dy along the y axis, relative to the current position.
Definition qrect.h:245
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:188
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
QRect boundingRect() const noexcept
Returns the bounding rectangle of this region.
bool intersects(const QRegion &r) const
Definition qregion.cpp:613
T * data() const noexcept
Returns the value of the pointer referenced by this object.
qsizetype size() const
Definition qset.h:50
bool remove(const T &value)
Definition qset.h:63
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
const_iterator constBegin() const noexcept
Definition qset.h:139
const_iterator constEnd() const noexcept
Definition qset.h:143
iterator erase(const_iterator i)
Definition qset.h:145
const_iterator constFind(const T &value) const
Definition qset.h:161
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
Definition qsize.h:208
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:124
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:127
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
The QStyleOptionGraphicsItem class is used to describe the parameters needed to draw a QGraphicsItem.
The QStyle class is an abstract base class that encapsulates the look and feel of a GUI.
Definition qstyle.h:29
QEventPoint & point(int touchId)
QMap< int, QEventPoint > points
static void showText(const QPoint &pos, const QString &text, QWidget *w=nullptr, const QRect &rect={}, int msecShowTime=-1)
Shows text as a tool tip, with the global position pos as the point of interest.
Definition qtooltip.cpp:439
static void hideText()
Definition qtooltip.h:19
The QTouchEvent class contains parameters that describe a touch event.
Definition qevent.h:917
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
QTransform & scale(qreal sx, qreal sy)
Scales the coordinate system by sx horizontally and sy vertically, and returns a reference to the mat...
qreal dx() const
Returns the horizontal translation factor.
Definition qtransform.h:235
QPoint map(const QPoint &p) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QTransform fromTranslate(qreal dx, qreal dy)
Creates a matrix which corresponds to a translation of dx along the x axis and dy along the y axis.
QTransform inverted(bool *invertible=nullptr) const
Returns an inverted copy of this matrix.
TransformationType type() const
Returns the transformation type of this matrix.
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
QRect mapRect(const QRect &) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
TransformationType
\value TxNone \value TxTranslate \value TxScale \value TxRotate \value TxShear \value TxProject
Definition qtransform.h:22
qreal dy() const
Returns the vertical translation factor.
Definition qtransform.h:239
\inmodule QtCore
Definition qvariant.h:65
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
bool isVisibleTo(const QWidget *) const
Returns true if this widget would become visible if ancestor is shown; otherwise returns false.
Definition qwidget.cpp:8643
QWidget * focusWidget() const
Returns the last child of this widget that setFocus had been called on.
Definition qwidget.cpp:6828
QRect rect
the internal geometry of the widget excluding any window frame
Definition qwidget.h:116
void setFocus()
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qwidget.h:423
bool isEnabled() const
Definition qwidget.h:814
Qt::FocusPolicy focusPolicy
the way the widget accepts keyboard focus
Definition qwidget.h:140
QWidget * parentWidget() const
Returns the parent of this widget, or \nullptr if it does not have any parent widget.
Definition qwidget.h:904
bool isWindow() const
Returns true if the widget is an independent window, otherwise returns false.
Definition qwidget.h:811
bool isVisible() const
Definition qwidget.h:874
QPointF mapFromGlobal(const QPointF &) const
Translates the global screen coordinate pos to widget coordinates.
bool testAttribute(Qt::WidgetAttribute) const
Returns true if attribute attribute is set on this widget; otherwise returns false.
Definition qwidget.h:910
QOpenGLWidget * widget
[1]
QString text
QPushButton * button
[2]
QSet< QString >::iterator it
auto signalIndex
rect
[4]
QPixmap pix
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
Definition qcompare.h:63
InputMethodQuery
MouseButton
Definition qnamespace.h:56
@ WA_AcceptTouchEvents
Definition qnamespace.h:404
@ WA_SetStyle
Definition qnamespace.h:356
@ IntersectClip
LayoutDirection
AspectRatioMode
@ KeepAspectRatioByExpanding
@ KeepAspectRatio
@ IgnoreAspectRatio
@ GestureCanceled
@ GestureStarted
@ GestureFinished
@ WheelFocus
Definition qnamespace.h:111
@ ClickFocus
Definition qnamespace.h:109
@ TabFocus
Definition qnamespace.h:108
ItemSelectionOperation
@ ReplaceSelection
@ transparent
Definition qnamespace.h:47
@ Key_Tab
Definition qnamespace.h:664
@ Key_Backtab
Definition qnamespace.h:665
SortOrder
Definition qnamespace.h:121
@ DescendingOrder
Definition qnamespace.h:123
@ AscendingOrder
Definition qnamespace.h:122
@ ShiftModifier
@ ControlModifier
@ AltModifier
ItemSelectionMode
@ IntersectsItemShape
@ IntersectsItemBoundingRect
@ NoBrush
@ IgnoreAction
@ QueuedConnection
@ DeviceCoordinates
@ LogicalCoordinates
GestureType
GestureFlag
@ ReceivePartialGestures
@ IgnoredGesturesPropagateToParent
constexpr Initialization Uninitialized
@ FramelessWindowHint
Definition qnamespace.h:225
@ ToolTip
Definition qnamespace.h:213
@ Popup
Definition qnamespace.h:211
FocusReason
@ PopupFocusReason
@ BacktabFocusReason
@ MouseFocusReason
@ OtherFocusReason
@ ActiveWindowFocusReason
@ TabFocusReason
Definition brush.cpp:5
#define qApp
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
const EGLAttrib EGLOutputLayerEXT * layers
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
bool qt_closestItemFirst(const QGraphicsItem *item1, const QGraphicsItem *item2)
Returns true if item1 is on top of item2.
bool qt_sendSpontaneousEvent(QObject *, QEvent *)
static void setClip(QPainter *painter, QGraphicsItem *item)
static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent)
static void setWorldTransform(QPainter *painter, const QTransform *const transformPtr, const QTransform *effectTransform)
static bool transformIsSimple(const QTransform &transform)
QT_BEGIN_NAMESPACE bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event)
#define ENSURE_TRANSFORM_PTR
static void _q_paintItem(QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget, bool useWindowOpacity, bool painterStateProtection)
static bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate *item, const QRectF &rect, bool itemIsUntransformable)
static void _q_paintIntoCache(QPixmap *pix, QGraphicsItem *item, const QRegion &pixmapExposed, const QTransform &itemToPixmap, QPainter::RenderHints renderHints, const QStyleOptionGraphicsItem *option, bool painterStateProtection)
static QRectF adjustedItemBoundingRect(const QGraphicsItem *item)
static QRectF adjustedItemEffectiveBoundingRect(const QGraphicsItem *item)
static void _q_adjustRect(QRectF *rect)
#define qWarning
Definition qlogging.h:166
return ret
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat z
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
GLint GLsizei GLsizei height
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLsizei GLsizei GLfloat distance
GLint GLsizei width
GLuint color
[2]
GLenum type
GLboolean GLuint group
GLenum target
GLbitfield flags
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLboolean GLboolean g
GLfloat n
GLint y
GLsizei GLsizei GLchar * source
struct _cl_event * event
GLuint GLenum GLenum transform
GLhandleARB obj
[2]
GLenum query
GLuint res
GLuint GLenum matrix
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLfloat GLfloat p
[1]
GLuint GLenum option
GLfixed GLfixed GLint GLint order
GLenum GLenum GLenum GLenum GLenum scale
static const QRectF boundingRect(const QPointF *points, int pointCount)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define emit
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
size_t quintptr
Definition qtypes.h:167
ptrdiff_t qsizetype
Definition qtypes.h:165
double qreal
Definition qtypes.h:187
#define enabled
#define disabled
QWidget * panel
Definition settings.cpp:7
QList< int > list
[14]
obj metaObject() -> className()
QObject::connect nullptr
QGraphicsItem * item
view viewport() -> scroll(dx, dy, deviceRect)
rect deviceTransform(view->viewportTransform()).map(QPointF(0
QList< QTreeWidgetItem * > items
QLayoutItem * child
[0]
widget render & pixmap
QPainter painter(this)
[7]
QHostInfo info
[0]
QNetworkProxy proxy
[0]
QQuickView * view
[0]
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:962
bool contains(const AT &t) const noexcept
Definition qlist.h:45
qsizetype lastIndexOf(const AT &t, qsizetype from=-1) const noexcept
Definition qlist.h:969
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...