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 | |
4 | #include "qglobal.h" |
5 | |
6 | #include "qgraphicslayout.h" |
7 | #include "qgraphicsproxywidget.h" |
8 | #include "private/qgraphicsproxywidget_p.h" |
9 | #include "private/qwidget_p.h" |
10 | #include "private/qapplication_p.h" |
11 | |
12 | #include <QtCore/qdebug.h> |
13 | #include <QtGui/qevent.h> |
14 | #include <QtWidgets/qgraphicsscene.h> |
15 | #include <QtWidgets/qgraphicssceneevent.h> |
16 | #include <QtWidgets/qlayout.h> |
17 | #include <QtGui/qpainter.h> |
18 | #include <QtWidgets/qstyleoption.h> |
19 | #include <QtWidgets/qgraphicsview.h> |
20 | #if QT_CONFIG(lineedit) |
21 | #include <QtWidgets/qlineedit.h> |
22 | #endif |
23 | #if QT_CONFIG(textedit) |
24 | #include <QtWidgets/qtextedit.h> |
25 | #endif |
26 | |
27 | QT_BEGIN_NAMESPACE |
28 | |
29 | //#define GRAPHICSPROXYWIDGET_DEBUG |
30 | |
31 | /*! |
32 | \class QGraphicsProxyWidget |
33 | \brief The QGraphicsProxyWidget class provides a proxy layer for embedding |
34 | a QWidget in a QGraphicsScene. |
35 | \since 4.4 |
36 | \ingroup graphicsview-api |
37 | \inmodule QtWidgets |
38 | |
39 | QGraphicsProxyWidget embeds QWidget-based widgets, for example, a |
40 | QPushButton, QFontComboBox, or even QFileDialog, into |
41 | QGraphicsScene. It forwards events between the two objects and |
42 | translates between QWidget's integer-based geometry and |
43 | QGraphicsWidget's qreal-based geometry. QGraphicsProxyWidget |
44 | supports all core features of QWidget, including tab focus, |
45 | keyboard input, Drag & Drop, and popups. You can also embed |
46 | complex widgets, e.g., widgets with subwidgets. |
47 | |
48 | Example: |
49 | |
50 | \snippet code/src_gui_graphicsview_qgraphicsproxywidget.cpp 0 |
51 | |
52 | QGraphicsProxyWidget takes care of automatically embedding popup children |
53 | of embedded widgets through creating a child proxy for each popup. This |
54 | means that when an embedded QComboBox shows its popup list, a new |
55 | QGraphicsProxyWidget is created automatically, embedding the popup, and |
56 | positioning it correctly. This only works if the popup is child of the |
57 | embedded widget (for example QToolButton::setMenu() requires the QMenu instance |
58 | to be child of the QToolButton). |
59 | |
60 | \section1 Embedding a Widget with QGraphicsProxyWidget |
61 | |
62 | There are two ways to embed a widget using QGraphicsProxyWidget. The most |
63 | common way is to pass a widget pointer to QGraphicsScene::addWidget() |
64 | together with any relevant \l Qt::WindowFlags. This function returns a |
65 | pointer to a QGraphicsProxyWidget. You can then choose to reparent or |
66 | position either the proxy, or the embedded widget itself. |
67 | |
68 | For example, in the code snippet below, we embed a group box into the proxy: |
69 | |
70 | \snippet code/src_gui_graphicsview_qgraphicsproxywidget.cpp 1 |
71 | |
72 | The image below is the output obtained with its contents margin and |
73 | contents rect labeled. |
74 | |
75 | \image qgraphicsproxywidget-embed.png |
76 | |
77 | Alternatively, you can start by creating a new QGraphicsProxyWidget item, |
78 | and then call setWidget() to embed a QWidget later. The widget() function |
79 | returns a pointer to the embedded widget. QGraphicsProxyWidget shares |
80 | ownership with QWidget, so if either of the two widgets are destroyed, the |
81 | other widget will be automatically destroyed as well. |
82 | |
83 | \section1 Synchronizing Widget States |
84 | |
85 | QGraphicsProxyWidget keeps its state in sync with the embedded widget. For |
86 | example, if the proxy is hidden or disabled, the embedded widget will be |
87 | hidden or disabled as well, and vice versa. When the widget is embedded by |
88 | calling addWidget(), QGraphicsProxyWidget copies the state from the widget |
89 | into the proxy, and after that, the two will stay synchronized where |
90 | possible. By default, when you embed a widget into a proxy, both the widget |
91 | and the proxy will be visible because a QGraphicsWidget is visible when |
92 | created (you do not have to call show()). If you explicitly hide the |
93 | embedded widget, the proxy will also become invisible. |
94 | |
95 | Example: |
96 | |
97 | \snippet code/src_gui_graphicsview_qgraphicsproxywidget.cpp 2 |
98 | |
99 | QGraphicsProxyWidget maintains symmetry for the following states: |
100 | |
101 | \table |
102 | \header \li QWidget state \li QGraphicsProxyWidget state \li Notes |
103 | \row \li QWidget::enabled |
104 | \li QGraphicsProxyWidget::enabled |
105 | \li |
106 | \row \li QWidget::visible |
107 | \li QGraphicsProxyWidget::visible |
108 | \li The explicit state is also symmetric. |
109 | \row \li QWidget::geometry |
110 | \li QGraphicsProxyWidget::geometry |
111 | \li Geometry is only guaranteed to be symmetric while |
112 | the embedded widget is visible. |
113 | \row \li QWidget::layoutDirection |
114 | \li QGraphicsProxyWidget::layoutDirection |
115 | \li |
116 | \row \li QWidget::style |
117 | \li QGraphicsProxyWidget::style |
118 | \li |
119 | \row \li QWidget::palette |
120 | \li QGraphicsProxyWidget::palette |
121 | \li |
122 | \row \li QWidget::font |
123 | \li QGraphicsProxyWidget::font |
124 | \li |
125 | \row \li QWidget::cursor |
126 | \li QGraphicsProxyWidget::cursor |
127 | \li The embedded widget overrides the proxy widget |
128 | cursor. The proxy cursor changes depending on |
129 | which embedded subwidget is currently under the |
130 | mouse. |
131 | \row \li QWidget::sizeHint() |
132 | \li QGraphicsProxyWidget::sizeHint() |
133 | \li All size hint functionality from the embedded |
134 | widget is forwarded by the proxy. |
135 | \row \li QWidget::getContentsMargins() |
136 | \li QGraphicsProxyWidget::getContentsMargins() |
137 | \li Updated once by setWidget(). |
138 | \row \li QWidget::windowTitle |
139 | \li QGraphicsProxyWidget::windowTitle |
140 | \li Updated once by setWidget(). |
141 | \endtable |
142 | |
143 | \note QGraphicsScene keeps the embedded widget in a special state that |
144 | prevents it from disturbing other widgets (both embedded and not embedded) |
145 | while the widget is embedded. In this state, the widget may differ slightly |
146 | in behavior from when it is not embedded. |
147 | |
148 | \warning This class is provided for convenience when bridging |
149 | QWidgets and QGraphicsItems, it should not be used for |
150 | high-performance scenarios. In particular, embedding widgets into a scene |
151 | that is then displayed through a QGraphicsView that uses an OpenGL viewport |
152 | will not work for all combinations. |
153 | |
154 | \sa QGraphicsScene::addWidget(), QGraphicsWidget |
155 | */ |
156 | |
157 | extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); |
158 | Q_WIDGETS_EXPORT extern bool qt_tab_all_widgets(); |
159 | |
160 | /*! |
161 | \internal |
162 | */ |
163 | QGraphicsProxyWidgetPrivate::QGraphicsProxyWidgetPrivate() |
164 | : QGraphicsWidgetPrivate(), |
165 | dragDropWidget(nullptr), |
166 | posChangeMode(NoMode), |
167 | sizeChangeMode(NoMode), |
168 | visibleChangeMode(NoMode), |
169 | enabledChangeMode(NoMode), |
170 | styleChangeMode(NoMode), |
171 | paletteChangeMode(NoMode), |
172 | tooltipChangeMode(NoMode), |
173 | focusFromWidgetToProxy(false), |
174 | proxyIsGivingFocus(false) |
175 | { |
176 | } |
177 | |
178 | /*! |
179 | \internal |
180 | */ |
181 | QGraphicsProxyWidgetPrivate::~QGraphicsProxyWidgetPrivate() |
182 | { |
183 | } |
184 | |
185 | /*! |
186 | \internal |
187 | */ |
188 | void QGraphicsProxyWidgetPrivate::init() |
189 | { |
190 | Q_Q(QGraphicsProxyWidget); |
191 | q->setFocusPolicy(Qt::WheelFocus); |
192 | q->setAcceptDrops(true); |
193 | } |
194 | |
195 | /*! |
196 | \internal |
197 | */ |
198 | void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneHoverEvent *event) |
199 | { |
200 | QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove); |
201 | mouseEvent.setPos(event->pos()); |
202 | mouseEvent.setScreenPos(event->screenPos()); |
203 | mouseEvent.setButton(Qt::NoButton); |
204 | mouseEvent.setButtons({ }); |
205 | mouseEvent.setModifiers(event->modifiers()); |
206 | mouseEvent.setTimestamp(event->timestamp()); |
207 | sendWidgetMouseEvent(event: &mouseEvent); |
208 | event->setAccepted(mouseEvent.isAccepted()); |
209 | } |
210 | |
211 | /*! |
212 | \internal |
213 | */ |
214 | void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneMouseEvent *event) |
215 | { |
216 | if (!event || !widget || !widget->isVisible()) |
217 | return; |
218 | Q_Q(QGraphicsProxyWidget); |
219 | |
220 | // Find widget position and receiver. |
221 | QPointF pos = event->pos(); |
222 | QPointer<QWidget> alienWidget = widget->childAt(p: pos.toPoint()); |
223 | QPointer<QWidget> receiver = alienWidget ? alienWidget : widget; |
224 | |
225 | if (QWidgetPrivate::nearestGraphicsProxyWidget(origin: receiver) != q) |
226 | return; //another proxywidget will handle the events |
227 | |
228 | // Translate QGraphicsSceneMouse events to QMouseEvents. |
229 | QEvent::Type type = QEvent::None; |
230 | switch (event->type()) { |
231 | case QEvent::GraphicsSceneMousePress: |
232 | type = QEvent::MouseButtonPress; |
233 | if (!embeddedMouseGrabber) |
234 | embeddedMouseGrabber = receiver; |
235 | else |
236 | receiver = embeddedMouseGrabber; |
237 | break; |
238 | case QEvent::GraphicsSceneMouseRelease: |
239 | type = QEvent::MouseButtonRelease; |
240 | if (embeddedMouseGrabber) |
241 | receiver = embeddedMouseGrabber; |
242 | break; |
243 | case QEvent::GraphicsSceneMouseDoubleClick: |
244 | type = QEvent::MouseButtonDblClick; |
245 | if (!embeddedMouseGrabber) |
246 | embeddedMouseGrabber = receiver; |
247 | else |
248 | receiver = embeddedMouseGrabber; |
249 | break; |
250 | case QEvent::GraphicsSceneMouseMove: |
251 | type = QEvent::MouseMove; |
252 | if (embeddedMouseGrabber) |
253 | receiver = embeddedMouseGrabber; |
254 | break; |
255 | default: |
256 | Q_ASSERT_X(false, "QGraphicsProxyWidget", "internal error"); |
257 | break; |
258 | } |
259 | |
260 | if (!lastWidgetUnderMouse) { |
261 | QApplicationPrivate::dispatchEnterLeave(enter: embeddedMouseGrabber ? embeddedMouseGrabber : receiver, leave: nullptr, globalPosF: event->screenPos()); |
262 | lastWidgetUnderMouse = receiver; |
263 | } |
264 | |
265 | // Map event position from us to the receiver |
266 | pos = mapToReceiver(pos, receiver); |
267 | |
268 | // Send mouse event. |
269 | QMouseEvent mouseEvent(type, pos, receiver->mapTo(receiver->topLevelWidget(), pos.toPoint()), |
270 | receiver->mapToGlobal(pos.toPoint()), |
271 | event->button(), event->buttons(), event->modifiers(), event->source()); |
272 | mouseEvent.setTimestamp(event->timestamp()); |
273 | |
274 | QWidget *embeddedMouseGrabberPtr = (QWidget *)embeddedMouseGrabber; |
275 | QApplicationPrivate::sendMouseEvent(receiver, event: &mouseEvent, alienWidget, native: widget, |
276 | buttonDown: &embeddedMouseGrabberPtr, lastMouseReceiver&: lastWidgetUnderMouse, spontaneous: event->spontaneous()); |
277 | embeddedMouseGrabber = embeddedMouseGrabberPtr; |
278 | |
279 | // Handle enter/leave events when last button is released from mouse |
280 | // grabber child widget. |
281 | if (embeddedMouseGrabber && type == QEvent::MouseButtonRelease && !event->buttons()) { |
282 | Q_Q(QGraphicsProxyWidget); |
283 | if (q->rect().contains(p: event->pos()) && q->acceptHoverEvents()) |
284 | lastWidgetUnderMouse = alienWidget ? alienWidget : widget; |
285 | else // released on the frame our outside the item, or doesn't accept hover events. |
286 | lastWidgetUnderMouse = nullptr; |
287 | |
288 | QApplicationPrivate::dispatchEnterLeave(enter: lastWidgetUnderMouse, leave: embeddedMouseGrabber, globalPosF: event->screenPos()); |
289 | embeddedMouseGrabber = nullptr; |
290 | |
291 | #ifndef QT_NO_CURSOR |
292 | // ### Restore the cursor, don't override it. |
293 | if (!lastWidgetUnderMouse) |
294 | q->unsetCursor(); |
295 | #endif |
296 | } |
297 | |
298 | #ifndef QT_NO_CURSOR |
299 | // Keep cursor in sync |
300 | if (lastWidgetUnderMouse) { |
301 | QCursor widgetsCursor = lastWidgetUnderMouse->cursor(); |
302 | if (q->cursor() != widgetsCursor) |
303 | q->setCursor(widgetsCursor); |
304 | } |
305 | #endif |
306 | |
307 | event->setAccepted(mouseEvent.isAccepted()); |
308 | } |
309 | |
310 | void QGraphicsProxyWidgetPrivate::sendWidgetKeyEvent(QKeyEvent *event) |
311 | { |
312 | Q_Q(QGraphicsProxyWidget); |
313 | if (!event || !widget || !widget->isVisible()) |
314 | return; |
315 | |
316 | QPointer<QWidget> receiver = widget->focusWidget(); |
317 | if (!receiver) |
318 | receiver = widget; |
319 | Q_ASSERT(receiver); |
320 | |
321 | do { |
322 | bool res = QCoreApplication::sendEvent(receiver, event); |
323 | if ((res && event->isAccepted()) || (q->isWindow() && receiver == widget)) |
324 | break; |
325 | receiver = receiver->parentWidget(); |
326 | } while (receiver); |
327 | } |
328 | |
329 | /*! |
330 | \internal |
331 | */ |
332 | void QGraphicsProxyWidgetPrivate::removeSubFocusHelper(QWidget *widget, Qt::FocusReason reason) |
333 | { |
334 | QFocusEvent event(QEvent::FocusOut, reason); |
335 | QPointer<QWidget> widgetGuard = widget; |
336 | QCoreApplication::sendEvent(receiver: widget, event: &event); |
337 | if (widgetGuard && event.isAccepted()) |
338 | QCoreApplication::sendEvent(receiver: widget->style(), event: &event); |
339 | } |
340 | |
341 | /*! |
342 | \internal |
343 | Some of the logic is shared with QApplicationPrivate::focusNextPrevChild_helper |
344 | */ |
345 | QWidget *QGraphicsProxyWidgetPrivate::findFocusChild(QWidget *child, bool next) const |
346 | { |
347 | if (!widget) |
348 | return nullptr; |
349 | |
350 | // Run around the focus chain until we find a widget that can take tab focus. |
351 | if (!child) { |
352 | child = next ? widget.data() : widget->previousInFocusChain(); |
353 | } else { |
354 | child = next ? child->nextInFocusChain() : child->previousInFocusChain(); |
355 | if ((next && child == widget) || (!next && child == widget->previousInFocusChain())) { |
356 | return nullptr; |
357 | } |
358 | } |
359 | |
360 | if (!child) |
361 | return nullptr; |
362 | |
363 | QWidget *oldChild = child; |
364 | uint focus_flag = qt_tab_all_widgets() ? Qt::TabFocus : Qt::StrongFocus; |
365 | do { |
366 | if (child->isEnabled() |
367 | && child->isVisibleTo(widget) |
368 | && ((child->focusPolicy() & focus_flag) == focus_flag) |
369 | && !(child->d_func()->extra && child->d_func()->extra->focus_proxy)) { |
370 | return child; |
371 | } |
372 | child = next ? child->nextInFocusChain() : child->previousInFocusChain(); |
373 | } while (child != oldChild && !(next && child == widget) && !(!next && child == widget->previousInFocusChain())); |
374 | return nullptr; |
375 | } |
376 | |
377 | /*! |
378 | \internal |
379 | */ |
380 | void QGraphicsProxyWidgetPrivate::_q_removeWidgetSlot() |
381 | { |
382 | Q_Q(QGraphicsProxyWidget); |
383 | if (!widget.isNull()) { |
384 | if (const auto &extra = widget->d_func()->extra) |
385 | extra->proxyWidget = nullptr; |
386 | } |
387 | widget = nullptr; |
388 | delete q; |
389 | } |
390 | |
391 | /*! |
392 | \internal |
393 | */ |
394 | void QGraphicsProxyWidgetPrivate::updateWidgetGeometryFromProxy() |
395 | { |
396 | } |
397 | |
398 | /*! |
399 | \internal |
400 | */ |
401 | void QGraphicsProxyWidgetPrivate::updateProxyGeometryFromWidget() |
402 | { |
403 | Q_Q(QGraphicsProxyWidget); |
404 | if (!widget) |
405 | return; |
406 | |
407 | QRectF widgetGeometry = widget->geometry(); |
408 | QWidget *parentWidget = widget->parentWidget(); |
409 | if (widget->isWindow()) { |
410 | QGraphicsProxyWidget *proxyParent = nullptr; |
411 | if (parentWidget && (proxyParent = qobject_cast<QGraphicsProxyWidget *>(object: q->parentWidget()))) { |
412 | // Nested window proxy (e.g., combobox popup), map widget to the |
413 | // parent widget's global coordinates, and map that to the parent |
414 | // proxy's child coordinates. |
415 | widgetGeometry.moveTo(p: proxyParent->subWidgetRect(widget: parentWidget).topLeft() |
416 | + parentWidget->mapFromGlobal(widget->pos())); |
417 | } |
418 | } |
419 | |
420 | // Adjust to size hint if the widget has never been resized. |
421 | if (!widget->size().isValid()) |
422 | widgetGeometry.setSize(widget->sizeHint()); |
423 | |
424 | // Assign new geometry. |
425 | posChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode; |
426 | sizeChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode; |
427 | q->setGeometry(widgetGeometry); |
428 | posChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
429 | sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
430 | } |
431 | |
432 | /*! |
433 | \internal |
434 | */ |
435 | void QGraphicsProxyWidgetPrivate::updateProxyInputMethodAcceptanceFromWidget() |
436 | { |
437 | Q_Q(QGraphicsProxyWidget); |
438 | if (!widget) |
439 | return; |
440 | |
441 | QWidget *focusWidget = widget->focusWidget(); |
442 | if (!focusWidget) |
443 | focusWidget = widget; |
444 | q->setFlag(flag: QGraphicsItem::ItemAcceptsInputMethod, |
445 | enabled: focusWidget->testAttribute(attribute: Qt::WA_InputMethodEnabled)); |
446 | } |
447 | |
448 | /*! |
449 | \internal |
450 | |
451 | Embeds \a subWin as a subwindow of this proxy widget. \a subWin must be a top-level |
452 | widget and a descendant of the widget managed by this proxy. A separate subproxy |
453 | will be created as a child of this proxy widget to manage \a subWin. |
454 | */ |
455 | void QGraphicsProxyWidgetPrivate::embedSubWindow(QWidget *subWin) |
456 | { |
457 | const auto &extra = subWin->d_func()->extra; |
458 | if (!extra || !extra->proxyWidget) { |
459 | QGraphicsProxyWidget *subProxy = new QGraphicsProxyWidget(q_func(), subWin->windowFlags()); |
460 | subProxy->d_func()->setWidget_helper(widget: subWin, autoShow: false); |
461 | } |
462 | } |
463 | |
464 | /*! |
465 | \internal |
466 | |
467 | Removes ("unembeds") \a subWin and deletes the proxy holder item. This can |
468 | happen when QWidget::setParent() reparents the embedded window out of |
469 | "embedded space". |
470 | */ |
471 | void QGraphicsProxyWidgetPrivate::unembedSubWindow(QWidget *subWin) |
472 | { |
473 | for (QGraphicsItem *child : std::as_const(t&: children)) { |
474 | if (child->isWidget()) { |
475 | if (QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(object: static_cast<QGraphicsWidget *>(child))) { |
476 | if (proxy->widget() == subWin) { |
477 | proxy->setWidget(nullptr); |
478 | scene->removeItem(item: proxy); |
479 | delete proxy; |
480 | return; |
481 | } |
482 | } |
483 | } |
484 | } |
485 | } |
486 | |
487 | bool QGraphicsProxyWidgetPrivate::isProxyWidget() const |
488 | { |
489 | return true; |
490 | } |
491 | |
492 | /*! |
493 | \internal |
494 | */ |
495 | QPointF QGraphicsProxyWidgetPrivate::mapToReceiver(const QPointF &pos, const QWidget *receiver) const |
496 | { |
497 | QPointF p = pos; |
498 | // Map event position from us to the receiver, preserving its |
499 | // precision (don't use QWidget::mapFrom here). |
500 | while (receiver && receiver != widget) { |
501 | p -= QPointF(receiver->pos()); |
502 | receiver = receiver->parentWidget(); |
503 | } |
504 | return p; |
505 | } |
506 | |
507 | /*! |
508 | Constructs a new QGraphicsProxy widget. \a parent and \a wFlags are passed |
509 | to QGraphicsItem's constructor. |
510 | */ |
511 | QGraphicsProxyWidget::QGraphicsProxyWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags) |
512 | : QGraphicsWidget(*new QGraphicsProxyWidgetPrivate, parent, wFlags) |
513 | { |
514 | Q_D(QGraphicsProxyWidget); |
515 | d->init(); |
516 | } |
517 | |
518 | /*! |
519 | Destroys the proxy widget and any embedded widget. |
520 | */ |
521 | QGraphicsProxyWidget::~QGraphicsProxyWidget() |
522 | { |
523 | Q_D(QGraphicsProxyWidget); |
524 | if (d->widget) { |
525 | d->widget->removeEventFilter(obj: this); |
526 | QObject::disconnect(sender: d->widget, SIGNAL(destroyed()), receiver: this, SLOT(_q_removeWidgetSlot())); |
527 | delete d->widget; |
528 | } |
529 | } |
530 | |
531 | /*! |
532 | Embeds \a widget into this proxy widget. The embedded widget must reside |
533 | exclusively either inside or outside of Graphics View. You cannot embed a |
534 | widget as long as it is visible elsewhere in the UI, at the same time. |
535 | |
536 | \a widget must be a top-level widget whose parent is \nullptr. |
537 | |
538 | When the widget is embedded, its state (e.g., visible, enabled, geometry, |
539 | size hints) is copied into the proxy widget. If the embedded widget is |
540 | explicitly hidden or disabled, the proxy widget will become explicitly |
541 | hidden or disabled after embedding is complete. The class documentation |
542 | has a full overview over the shared state. |
543 | |
544 | QGraphicsProxyWidget's window flags determine whether the widget, after |
545 | embedding, will be given window decorations or not. |
546 | |
547 | After this function returns, QGraphicsProxyWidget will keep its state |
548 | synchronized with that of \a widget whenever possible. |
549 | |
550 | If a widget is already embedded by this proxy when this function is called, |
551 | that widget will first be automatically unembedded. Passing \nullptr for |
552 | the \a widget argument will only unembed the widget, and the ownership of |
553 | the currently embedded widget will be passed on to the caller. |
554 | Every child widget that are embedded will also be embedded and their proxy |
555 | widget destroyed. |
556 | |
557 | Note that widgets with the Qt::WA_PaintOnScreen widget attribute |
558 | set and widgets that wrap an external application or controller |
559 | cannot be embedded. Examples are QOpenGLWidget and QAxWidget. |
560 | |
561 | \sa widget() |
562 | */ |
563 | void QGraphicsProxyWidget::setWidget(QWidget *widget) |
564 | { |
565 | Q_D(QGraphicsProxyWidget); |
566 | d->setWidget_helper(widget, autoShow: true); |
567 | } |
568 | |
569 | void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool autoShow) |
570 | { |
571 | Q_Q(QGraphicsProxyWidget); |
572 | if (newWidget == widget) |
573 | return; |
574 | if (widget) { |
575 | QObject::disconnect(sender: widget, SIGNAL(destroyed()), receiver: q, SLOT(_q_removeWidgetSlot())); |
576 | widget->removeEventFilter(obj: q); |
577 | widget->setAttribute(Qt::WA_DontShowOnScreen, on: false); |
578 | widget->d_func()->extra->proxyWidget = nullptr; |
579 | resolveFont(inheritedMask: inheritedFontResolveMask); |
580 | resolvePalette(inheritedMask: inheritedPaletteResolveMask); |
581 | widget->update(); |
582 | |
583 | const auto childItems = q->childItems(); |
584 | for (QGraphicsItem *child : childItems) { |
585 | if (child->d_ptr->isProxyWidget()) { |
586 | QGraphicsProxyWidget *childProxy = static_cast<QGraphicsProxyWidget *>(child); |
587 | QWidget *parent = childProxy->widget(); |
588 | while (parent && parent->parentWidget()) { |
589 | if (parent == widget) |
590 | break; |
591 | parent = parent->parentWidget(); |
592 | } |
593 | if (!childProxy->widget() || parent != widget) |
594 | continue; |
595 | childProxy->setWidget(nullptr); |
596 | delete childProxy; |
597 | } |
598 | } |
599 | |
600 | widget = nullptr; |
601 | #ifndef QT_NO_CURSOR |
602 | q->unsetCursor(); |
603 | #endif |
604 | q->setAcceptHoverEvents(false); |
605 | if (!newWidget) |
606 | q->update(); |
607 | } |
608 | if (!newWidget) |
609 | return; |
610 | if (!newWidget->isWindow()) { |
611 | const auto &extra = newWidget->parentWidget()->d_func()->extra; |
612 | if (!extra || !extra->proxyWidget) { |
613 | qWarning(msg: "QGraphicsProxyWidget::setWidget: cannot embed widget %p " |
614 | "which is not a toplevel widget, and is not a child of an embedded widget", newWidget); |
615 | return; |
616 | } |
617 | } |
618 | |
619 | // Register this proxy within the widget's private. |
620 | // ### This is a bit backdoorish |
621 | QWExtra *extra = newWidget->d_func()->extra.get(); |
622 | if (!extra) { |
623 | newWidget->d_func()->createExtra(); |
624 | extra = newWidget->d_func()->extra.get(); |
625 | } |
626 | QGraphicsProxyWidget **proxyWidget = &extra->proxyWidget; |
627 | if (*proxyWidget) { |
628 | if (*proxyWidget != q) { |
629 | qWarning(msg: "QGraphicsProxyWidget::setWidget: cannot embed widget %p" |
630 | "; already embedded", newWidget); |
631 | } |
632 | return; |
633 | } |
634 | *proxyWidget = q; |
635 | |
636 | newWidget->setAttribute(Qt::WA_DontShowOnScreen); |
637 | newWidget->ensurePolished(); |
638 | // Do not wait for this widget to close before the app closes ### |
639 | // shouldn't this widget inherit the attribute? |
640 | newWidget->setAttribute(Qt::WA_QuitOnClose, on: false); |
641 | q->setAcceptHoverEvents(true); |
642 | |
643 | if (newWidget->testAttribute(attribute: Qt::WA_NoSystemBackground)) |
644 | q->setAttribute(attribute: Qt::WA_NoSystemBackground); |
645 | if (newWidget->testAttribute(attribute: Qt::WA_OpaquePaintEvent)) |
646 | q->setAttribute(attribute: Qt::WA_OpaquePaintEvent); |
647 | |
648 | widget = newWidget; |
649 | |
650 | // Changes only go from the widget to the proxy. |
651 | enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode; |
652 | visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode; |
653 | posChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode; |
654 | sizeChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode; |
655 | |
656 | if ((autoShow && !newWidget->testAttribute(attribute: Qt::WA_WState_ExplicitShowHide)) || !newWidget->testAttribute(attribute: Qt::WA_WState_Hidden)) { |
657 | newWidget->show(); |
658 | } |
659 | |
660 | // Copy the state from the widget onto the proxy. |
661 | #ifndef QT_NO_CURSOR |
662 | if (newWidget->testAttribute(attribute: Qt::WA_SetCursor)) |
663 | q->setCursor(widget->cursor()); |
664 | #endif |
665 | q->setEnabled(newWidget->isEnabled()); |
666 | q->setVisible(newWidget->isVisible()); |
667 | q->setLayoutDirection(newWidget->layoutDirection()); |
668 | if (newWidget->testAttribute(attribute: Qt::WA_SetStyle)) |
669 | q->setStyle(widget->style()); |
670 | |
671 | resolveFont(inheritedMask: inheritedFontResolveMask); |
672 | resolvePalette(inheritedMask: inheritedPaletteResolveMask); |
673 | |
674 | if (!newWidget->testAttribute(attribute: Qt::WA_Resized)) |
675 | newWidget->adjustSize(); |
676 | |
677 | q->setContentsMargins(newWidget->contentsMargins()); |
678 | q->setWindowTitle(newWidget->windowTitle()); |
679 | |
680 | // size policies and constraints.. |
681 | q->setSizePolicy(newWidget->sizePolicy()); |
682 | QSize sz = newWidget->minimumSize(); |
683 | q->setMinimumSize(sz.isNull() ? QSizeF() : QSizeF(sz)); |
684 | sz = newWidget->maximumSize(); |
685 | q->setMaximumSize(sz.isNull() ? QSizeF() : QSizeF(sz)); |
686 | |
687 | updateProxyGeometryFromWidget(); |
688 | |
689 | updateProxyInputMethodAcceptanceFromWidget(); |
690 | |
691 | // Hook up the event filter to keep the state up to date. |
692 | newWidget->installEventFilter(filterObj: q); |
693 | QObject::connect(sender: newWidget, SIGNAL(destroyed()), receiver: q, SLOT(_q_removeWidgetSlot())); |
694 | |
695 | // Changes no longer go only from the widget to the proxy. |
696 | enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
697 | visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
698 | posChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
699 | sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
700 | } |
701 | |
702 | /*! |
703 | Returns a pointer to the embedded widget. |
704 | |
705 | \sa setWidget() |
706 | */ |
707 | QWidget *QGraphicsProxyWidget::widget() const |
708 | { |
709 | Q_D(const QGraphicsProxyWidget); |
710 | return d->widget; |
711 | } |
712 | |
713 | /*! |
714 | Returns the rectangle for \a widget, which must be a descendant of |
715 | widget(), or widget() itself, in this proxy item's local coordinates. |
716 | |
717 | If no widget is embedded, \a widget is \nullptr, or \a widget is not a |
718 | descendant of the embedded widget, this function returns an empty QRectF. |
719 | |
720 | \sa widget() |
721 | */ |
722 | QRectF QGraphicsProxyWidget::subWidgetRect(const QWidget *widget) const |
723 | { |
724 | Q_D(const QGraphicsProxyWidget); |
725 | if (!widget || !d->widget) |
726 | return QRectF(); |
727 | if (d->widget == widget || d->widget->isAncestorOf(child: widget)) |
728 | return QRectF(widget->mapTo(d->widget, QPoint(0, 0)), widget->size()); |
729 | return QRectF(); |
730 | } |
731 | |
732 | /*! |
733 | \reimp |
734 | */ |
735 | void QGraphicsProxyWidget::setGeometry(const QRectF &rect) |
736 | { |
737 | Q_D(QGraphicsProxyWidget); |
738 | bool proxyResizesWidget = !d->posChangeMode && !d->sizeChangeMode; |
739 | if (proxyResizesWidget) { |
740 | d->posChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode; |
741 | d->sizeChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode; |
742 | } |
743 | QGraphicsWidget::setGeometry(rect); |
744 | if (proxyResizesWidget) { |
745 | d->posChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
746 | d->sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
747 | } |
748 | } |
749 | |
750 | /*! |
751 | \reimp |
752 | */ |
753 | QVariant QGraphicsProxyWidget::itemChange(GraphicsItemChange change, |
754 | const QVariant &value) |
755 | { |
756 | Q_D(QGraphicsProxyWidget); |
757 | |
758 | switch (change) { |
759 | case ItemPositionChange: |
760 | // The item's position is either changed directly on the proxy, in |
761 | // which case the position change should propagate to the widget, |
762 | // otherwise it happens as a side effect when filtering QEvent::Move. |
763 | if (!d->posChangeMode) |
764 | d->posChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode; |
765 | break; |
766 | case ItemPositionHasChanged: |
767 | // Move the internal widget if we're in widget-to-proxy |
768 | // mode. Otherwise the widget has already moved. |
769 | if (d->widget && d->posChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode) |
770 | d->widget->move(value.toPoint()); |
771 | if (d->posChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode) |
772 | d->posChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
773 | break; |
774 | case ItemVisibleChange: |
775 | if (!d->visibleChangeMode) |
776 | d->visibleChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode; |
777 | break; |
778 | case ItemVisibleHasChanged: |
779 | if (d->widget && d->visibleChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode) |
780 | d->widget->setVisible(isVisible()); |
781 | if (d->visibleChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode) |
782 | d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
783 | break; |
784 | case ItemEnabledChange: |
785 | if (!d->enabledChangeMode) |
786 | d->enabledChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode; |
787 | break; |
788 | case ItemEnabledHasChanged: |
789 | if (d->widget && d->enabledChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode) |
790 | d->widget->setEnabled(isEnabled()); |
791 | if (d->enabledChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode) |
792 | d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
793 | break; |
794 | default: |
795 | break; |
796 | } |
797 | return QGraphicsWidget::itemChange(change, value); |
798 | } |
799 | |
800 | /*! |
801 | \reimp |
802 | */ |
803 | bool QGraphicsProxyWidget::event(QEvent *event) |
804 | { |
805 | Q_D(QGraphicsProxyWidget); |
806 | if (!d->widget) |
807 | return QGraphicsWidget::event(event); |
808 | |
809 | switch (event->type()) { |
810 | case QEvent::WindowActivate: |
811 | case QEvent::WindowDeactivate: |
812 | QCoreApplication::sendEvent(receiver: d->widget, event); |
813 | break; |
814 | case QEvent::StyleChange: |
815 | // Propagate style changes to the embedded widget. |
816 | if (!d->styleChangeMode) { |
817 | d->styleChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode; |
818 | d->widget->setStyle(style()); |
819 | d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
820 | } |
821 | break; |
822 | case QEvent::FontChange: { |
823 | // Propagate to widget. |
824 | QWidgetPrivate *wd = d->widget->d_func(); |
825 | int mask = d->font.resolveMask() | d->inheritedFontResolveMask; |
826 | wd->inheritedFontResolveMask = mask; |
827 | wd->resolveFont(); |
828 | break; |
829 | } |
830 | case QEvent::PaletteChange: { |
831 | // Propagate to widget. |
832 | QWidgetPrivate *wd = d->widget->d_func(); |
833 | int mask = d->palette.resolveMask() | d->inheritedPaletteResolveMask; |
834 | wd->inheritedPaletteResolveMask = mask; |
835 | wd->resolvePalette(); |
836 | break; |
837 | } |
838 | case QEvent::InputMethod: { |
839 | inputMethodEvent(event: static_cast<QInputMethodEvent *>(event)); |
840 | if (event->isAccepted()) |
841 | return true; |
842 | return false; |
843 | } |
844 | case QEvent::ShortcutOverride: { |
845 | QWidget *focusWidget = d->widget->focusWidget(); |
846 | while (focusWidget) { |
847 | QCoreApplication::sendEvent(receiver: focusWidget, event); |
848 | if (event->isAccepted()) |
849 | return true; |
850 | focusWidget = focusWidget->parentWidget(); |
851 | } |
852 | return false; |
853 | } |
854 | case QEvent::KeyPress: { |
855 | QKeyEvent *k = static_cast<QKeyEvent *>(event); |
856 | if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) { |
857 | if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier? |
858 | QWidget *focusWidget = d->widget->focusWidget(); |
859 | while (focusWidget) { |
860 | const bool res = QCoreApplication::sendEvent(receiver: focusWidget, event); |
861 | if ((res && event->isAccepted()) || (isWindow() && focusWidget == d->widget)) { |
862 | event->accept(); |
863 | break; |
864 | } |
865 | focusWidget = focusWidget->parentWidget(); |
866 | } |
867 | return true; |
868 | } |
869 | } |
870 | break; |
871 | } |
872 | #if QT_CONFIG(tooltip) |
873 | case QEvent::GraphicsSceneHelp: { |
874 | // Propagate the help event (for tooltip) to the widget under mouse |
875 | if (d->lastWidgetUnderMouse) { |
876 | QGraphicsSceneHelpEvent *he = static_cast<QGraphicsSceneHelpEvent *>(event); |
877 | QPoint pos = d->mapToReceiver(pos: mapFromScene(point: he->scenePos()), receiver: d->lastWidgetUnderMouse).toPoint(); |
878 | QHelpEvent e(QEvent::ToolTip, pos, he->screenPos()); |
879 | QCoreApplication::sendEvent(receiver: d->lastWidgetUnderMouse, event: &e); |
880 | event->setAccepted(e.isAccepted()); |
881 | return e.isAccepted(); |
882 | } |
883 | break; |
884 | } |
885 | case QEvent::ToolTipChange: { |
886 | // Propagate tooltip change to the widget |
887 | if (!d->tooltipChangeMode) { |
888 | d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode; |
889 | d->widget->setToolTip(toolTip()); |
890 | d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
891 | } |
892 | break; |
893 | } |
894 | #endif |
895 | case QEvent::TouchBegin: |
896 | case QEvent::TouchUpdate: |
897 | case QEvent::TouchEnd: { |
898 | QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event); |
899 | bool res = QApplicationPrivate::translateRawTouchEvent(widget: d->widget, touchEvent); |
900 | if (res & touchEvent->isAccepted()) |
901 | return true; |
902 | |
903 | break; |
904 | } |
905 | default: |
906 | break; |
907 | } |
908 | return QGraphicsWidget::event(event); |
909 | } |
910 | |
911 | /*! |
912 | \reimp |
913 | */ |
914 | bool QGraphicsProxyWidget::eventFilter(QObject *object, QEvent *event) |
915 | { |
916 | Q_D(QGraphicsProxyWidget); |
917 | |
918 | if (object == d->widget) { |
919 | switch (event->type()) { |
920 | case QEvent::LayoutRequest: |
921 | updateGeometry(); |
922 | break; |
923 | case QEvent::Resize: |
924 | // If the widget resizes itself, we resize the proxy too. |
925 | // Prevent feed-back by checking the geometry change mode. |
926 | if (!d->sizeChangeMode) |
927 | d->updateProxyGeometryFromWidget(); |
928 | break; |
929 | case QEvent::Move: |
930 | // If the widget moves itself, we move the proxy too. Prevent |
931 | // feed-back by checking the geometry change mode. |
932 | if (!d->posChangeMode) |
933 | d->updateProxyGeometryFromWidget(); |
934 | break; |
935 | case QEvent::Hide: |
936 | case QEvent::Show: |
937 | // If the widget toggles its visible state, the proxy will follow. |
938 | if (!d->visibleChangeMode) { |
939 | d->visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode; |
940 | setVisible(event->type() == QEvent::Show); |
941 | d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
942 | } |
943 | break; |
944 | case QEvent::EnabledChange: |
945 | // If the widget toggles its enabled state, the proxy will follow. |
946 | if (!d->enabledChangeMode) { |
947 | d->enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode; |
948 | setEnabled(d->widget->isEnabled()); |
949 | d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
950 | } |
951 | break; |
952 | case QEvent::StyleChange: |
953 | // Propagate style changes to the proxy. |
954 | if (!d->styleChangeMode) { |
955 | d->styleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode; |
956 | setStyle(d->widget->style()); |
957 | d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
958 | } |
959 | break; |
960 | #if QT_CONFIG(tooltip) |
961 | case QEvent::ToolTipChange: |
962 | // Propagate tooltip change to the proxy. |
963 | if (!d->tooltipChangeMode) { |
964 | d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode; |
965 | setToolTip(d->widget->toolTip()); |
966 | d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::NoMode; |
967 | } |
968 | break; |
969 | #endif |
970 | default: |
971 | break; |
972 | } |
973 | } |
974 | return QGraphicsWidget::eventFilter(watched: object, event); |
975 | } |
976 | |
977 | /*! |
978 | \reimp |
979 | */ |
980 | void QGraphicsProxyWidget::showEvent(QShowEvent *event) |
981 | { |
982 | Q_UNUSED(event); |
983 | } |
984 | |
985 | /*! |
986 | \reimp |
987 | */ |
988 | void QGraphicsProxyWidget::hideEvent(QHideEvent *event) |
989 | { |
990 | Q_UNUSED(event); |
991 | } |
992 | |
993 | #ifndef QT_NO_CONTEXTMENU |
994 | /*! |
995 | \reimp |
996 | */ |
997 | void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) |
998 | { |
999 | Q_D(QGraphicsProxyWidget); |
1000 | if (!event || !d->widget || !d->widget->isVisible() || !hasFocus()) |
1001 | return; |
1002 | |
1003 | // Find widget position and receiver. |
1004 | QPointF pos = event->pos(); |
1005 | QPointer<QWidget> alienWidget = d->widget->childAt(p: pos.toPoint()); |
1006 | QPointer<QWidget> receiver = alienWidget ? alienWidget : d->widget; |
1007 | |
1008 | // Map event position from us to the receiver |
1009 | pos = d->mapToReceiver(pos, receiver); |
1010 | |
1011 | QPoint globalPos = receiver->mapToGlobal(pos.toPoint()); |
1012 | //If the receiver by-pass the proxy its popups |
1013 | //will be top level QWidgets therefore they need |
1014 | //the screen position. mapToGlobal expect the widget to |
1015 | //have proper coordinates in regards of the windowing system |
1016 | //but it's not true because the widget is embedded. |
1017 | if (bypassGraphicsProxyWidget(p: receiver)) |
1018 | globalPos = event->screenPos(); |
1019 | |
1020 | // Send mouse event. ### Doesn't propagate the event. |
1021 | QContextMenuEvent contextMenuEvent(QContextMenuEvent::Reason(event->reason()), |
1022 | pos.toPoint(), globalPos, event->modifiers()); |
1023 | contextMenuEvent.setTimestamp(event->timestamp()); |
1024 | QCoreApplication::sendEvent(receiver, event: &contextMenuEvent); |
1025 | |
1026 | event->setAccepted(contextMenuEvent.isAccepted()); |
1027 | } |
1028 | #endif // QT_NO_CONTEXTMENU |
1029 | |
1030 | #if QT_CONFIG(draganddrop) |
1031 | /*! |
1032 | \reimp |
1033 | */ |
1034 | void QGraphicsProxyWidget::dragEnterEvent(QGraphicsSceneDragDropEvent *event) |
1035 | { |
1036 | #if !QT_CONFIG(draganddrop) |
1037 | Q_UNUSED(event); |
1038 | #else |
1039 | Q_D(QGraphicsProxyWidget); |
1040 | if (!d->widget) |
1041 | return; |
1042 | |
1043 | QDragEnterEvent proxyDragEnter(event->pos().toPoint(), event->dropAction(), event->mimeData(), event->buttons(), event->modifiers()); |
1044 | proxyDragEnter.setAccepted(event->isAccepted()); |
1045 | QCoreApplication::sendEvent(receiver: d->widget, event: &proxyDragEnter); |
1046 | event->setAccepted(proxyDragEnter.isAccepted()); |
1047 | if (proxyDragEnter.isAccepted()) // we discard answerRect |
1048 | event->setDropAction(proxyDragEnter.dropAction()); |
1049 | #endif |
1050 | } |
1051 | /*! |
1052 | \reimp |
1053 | */ |
1054 | void QGraphicsProxyWidget::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) |
1055 | { |
1056 | Q_UNUSED(event); |
1057 | #if QT_CONFIG(draganddrop) |
1058 | Q_D(QGraphicsProxyWidget); |
1059 | if (!d->widget || !d->dragDropWidget) |
1060 | return; |
1061 | QDragLeaveEvent proxyDragLeave; |
1062 | QCoreApplication::sendEvent(receiver: d->dragDropWidget, event: &proxyDragLeave); |
1063 | d->dragDropWidget = nullptr; |
1064 | #endif |
1065 | } |
1066 | |
1067 | /*! |
1068 | \reimp |
1069 | */ |
1070 | void QGraphicsProxyWidget::dragMoveEvent(QGraphicsSceneDragDropEvent *event) |
1071 | { |
1072 | #if !QT_CONFIG(draganddrop) |
1073 | Q_UNUSED(event); |
1074 | #else |
1075 | Q_D(QGraphicsProxyWidget); |
1076 | if (!d->widget) |
1077 | return; |
1078 | QPointF p = event->pos(); |
1079 | event->ignore(); |
1080 | QPointer<QWidget> subWidget = d->widget->childAt(p: p.toPoint()); |
1081 | QPointer<QWidget> receiver = subWidget ? subWidget : d->widget; |
1082 | bool eventDelivered = false; |
1083 | for (; receiver; receiver = receiver->parentWidget()) { |
1084 | if (!receiver->isEnabled() || !receiver->acceptDrops()) |
1085 | continue; |
1086 | // Map event position from us to the receiver |
1087 | QPoint receiverPos = d->mapToReceiver(pos: p, receiver).toPoint(); |
1088 | if (receiver != d->dragDropWidget) { |
1089 | // Try to enter before we leave |
1090 | QDragEnterEvent dragEnter(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers()); |
1091 | dragEnter.setDropAction(event->proposedAction()); |
1092 | QCoreApplication::sendEvent(receiver, event: &dragEnter); |
1093 | event->setAccepted(dragEnter.isAccepted()); |
1094 | event->setDropAction(dragEnter.dropAction()); |
1095 | if (!event->isAccepted()) { |
1096 | // propagate to the parent widget |
1097 | continue; |
1098 | } |
1099 | |
1100 | d->lastDropAction = event->dropAction(); |
1101 | |
1102 | if (d->dragDropWidget) { |
1103 | QDragLeaveEvent dragLeave; |
1104 | QCoreApplication::sendEvent(receiver: d->dragDropWidget, event: &dragLeave); |
1105 | } |
1106 | d->dragDropWidget = receiver; |
1107 | } |
1108 | |
1109 | QDragMoveEvent dragMove(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers()); |
1110 | event->setDropAction(d->lastDropAction); |
1111 | QCoreApplication::sendEvent(receiver, event: &dragMove); |
1112 | event->setAccepted(dragMove.isAccepted()); |
1113 | event->setDropAction(dragMove.dropAction()); |
1114 | if (event->isAccepted()) |
1115 | d->lastDropAction = event->dropAction(); |
1116 | eventDelivered = true; |
1117 | break; |
1118 | } |
1119 | |
1120 | if (!eventDelivered) { |
1121 | if (d->dragDropWidget) { |
1122 | // Leave the last drag drop item |
1123 | QDragLeaveEvent dragLeave; |
1124 | QCoreApplication::sendEvent(receiver: d->dragDropWidget, event: &dragLeave); |
1125 | d->dragDropWidget = nullptr; |
1126 | } |
1127 | // Propagate |
1128 | event->setDropAction(Qt::IgnoreAction); |
1129 | } |
1130 | #endif |
1131 | } |
1132 | |
1133 | /*! |
1134 | \reimp |
1135 | */ |
1136 | void QGraphicsProxyWidget::dropEvent(QGraphicsSceneDragDropEvent *event) |
1137 | { |
1138 | #if !QT_CONFIG(draganddrop) |
1139 | Q_UNUSED(event); |
1140 | #else |
1141 | Q_D(QGraphicsProxyWidget); |
1142 | if (d->widget && d->dragDropWidget) { |
1143 | QPoint widgetPos = d->mapToReceiver(pos: event->pos(), receiver: d->dragDropWidget).toPoint(); |
1144 | QDropEvent dropEvent(widgetPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers()); |
1145 | QCoreApplication::sendEvent(receiver: d->dragDropWidget, event: &dropEvent); |
1146 | event->setAccepted(dropEvent.isAccepted()); |
1147 | d->dragDropWidget = nullptr; |
1148 | } |
1149 | #endif |
1150 | } |
1151 | #endif |
1152 | |
1153 | /*! |
1154 | \reimp |
1155 | */ |
1156 | void QGraphicsProxyWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event) |
1157 | { |
1158 | Q_UNUSED(event); |
1159 | } |
1160 | |
1161 | /*! |
1162 | \reimp |
1163 | */ |
1164 | void QGraphicsProxyWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) |
1165 | { |
1166 | Q_UNUSED(event); |
1167 | Q_D(QGraphicsProxyWidget); |
1168 | // If hoverMove was compressed away, make sure we update properly here. |
1169 | if (d->lastWidgetUnderMouse) { |
1170 | QApplicationPrivate::dispatchEnterLeave(enter: nullptr, leave: d->lastWidgetUnderMouse, globalPosF: event->screenPos()); |
1171 | d->lastWidgetUnderMouse = nullptr; |
1172 | } |
1173 | } |
1174 | |
1175 | /*! |
1176 | \reimp |
1177 | */ |
1178 | void QGraphicsProxyWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event) |
1179 | { |
1180 | Q_D(QGraphicsProxyWidget); |
1181 | #ifdef GRAPHICSPROXYWIDGET_DEBUG |
1182 | qDebug("QGraphicsProxyWidget::hoverMoveEvent"); |
1183 | #endif |
1184 | // Ignore events on the window frame. |
1185 | if (!d->widget || !rect().contains(p: event->pos())) { |
1186 | if (d->lastWidgetUnderMouse) { |
1187 | QApplicationPrivate::dispatchEnterLeave(enter: nullptr, leave: d->lastWidgetUnderMouse, globalPosF: event->screenPos()); |
1188 | d->lastWidgetUnderMouse = nullptr; |
1189 | } |
1190 | return; |
1191 | } |
1192 | |
1193 | d->embeddedMouseGrabber = nullptr; |
1194 | d->sendWidgetMouseEvent(event); |
1195 | } |
1196 | |
1197 | /*! |
1198 | \reimp |
1199 | */ |
1200 | void QGraphicsProxyWidget::grabMouseEvent(QEvent *event) |
1201 | { |
1202 | Q_UNUSED(event); |
1203 | } |
1204 | |
1205 | /*! |
1206 | \reimp |
1207 | */ |
1208 | void QGraphicsProxyWidget::ungrabMouseEvent(QEvent *event) |
1209 | { |
1210 | Q_D(QGraphicsProxyWidget); |
1211 | Q_UNUSED(event); |
1212 | d->embeddedMouseGrabber = nullptr; |
1213 | } |
1214 | |
1215 | /*! |
1216 | \reimp |
1217 | */ |
1218 | void QGraphicsProxyWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event) |
1219 | { |
1220 | Q_D(QGraphicsProxyWidget); |
1221 | #ifdef GRAPHICSPROXYWIDGET_DEBUG |
1222 | qDebug("QGraphicsProxyWidget::mouseMoveEvent"); |
1223 | #endif |
1224 | d->sendWidgetMouseEvent(event); |
1225 | } |
1226 | |
1227 | /*! |
1228 | \reimp |
1229 | */ |
1230 | void QGraphicsProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event) |
1231 | { |
1232 | Q_D(QGraphicsProxyWidget); |
1233 | #ifdef GRAPHICSPROXYWIDGET_DEBUG |
1234 | qDebug("QGraphicsProxyWidget::mousePressEvent"); |
1235 | #endif |
1236 | d->sendWidgetMouseEvent(event); |
1237 | } |
1238 | |
1239 | /*! |
1240 | \reimp |
1241 | */ |
1242 | void QGraphicsProxyWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) |
1243 | { |
1244 | Q_D(QGraphicsProxyWidget); |
1245 | #ifdef GRAPHICSPROXYWIDGET_DEBUG |
1246 | qDebug("QGraphicsProxyWidget::mouseDoubleClickEvent"); |
1247 | #endif |
1248 | d->sendWidgetMouseEvent(event); |
1249 | } |
1250 | |
1251 | /*! |
1252 | \reimp |
1253 | */ |
1254 | #if QT_CONFIG(wheelevent) |
1255 | void QGraphicsProxyWidget::wheelEvent(QGraphicsSceneWheelEvent *event) |
1256 | { |
1257 | Q_D(QGraphicsProxyWidget); |
1258 | #ifdef GRAPHICSPROXYWIDGET_DEBUG |
1259 | qDebug("QGraphicsProxyWidget::wheelEvent"); |
1260 | #endif |
1261 | if (!d->widget) |
1262 | return; |
1263 | |
1264 | QPointF pos = event->pos(); |
1265 | QPointer<QWidget> receiver = d->widget->childAt(p: pos.toPoint()); |
1266 | if (!receiver) |
1267 | receiver = d->widget; |
1268 | |
1269 | // high precision event streams go to the grabber, which will be the |
1270 | // QGraphicsView's viewport. We need to change that temporarily, otherwise |
1271 | // the event we send to the receiver get grabbed by the viewport, resulting |
1272 | // in infinite recursion |
1273 | QPointer<QWidget> prev_grabber = QApplicationPrivate::wheel_widget; |
1274 | if (event->phase() == Qt::ScrollBegin) { |
1275 | QApplicationPrivate::wheel_widget = receiver; |
1276 | } else if (event->phase() != Qt::NoScrollPhase && QApplicationPrivate::wheel_widget != receiver) { |
1277 | // this event is part of a stream that didn't start here, so ignore |
1278 | event->ignore(); |
1279 | return; |
1280 | } |
1281 | |
1282 | // Map event position from us to the receiver |
1283 | pos = d->mapToReceiver(pos, receiver); |
1284 | |
1285 | // Send mouse event. |
1286 | QPoint angleDelta; |
1287 | if (event->orientation() == Qt::Horizontal) |
1288 | angleDelta.setX(event->delta()); |
1289 | else |
1290 | angleDelta.setY(event->delta()); |
1291 | // pixelDelta, inverted, scrollPhase and source from the original QWheelEvent |
1292 | // were not preserved in the QGraphicsSceneWheelEvent unfortunately |
1293 | QWheelEvent wheelEvent(pos, event->screenPos(), event->pixelDelta(), angleDelta, |
1294 | event->buttons(), event->modifiers(), event->phase(), |
1295 | event->isInverted(), Qt::MouseEventSynthesizedByQt, |
1296 | QPointingDevice::primaryPointingDevice()); |
1297 | QPointer<QWidget> focusWidget = d->widget->focusWidget(); |
1298 | extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); |
1299 | qt_sendSpontaneousEvent(receiver, &wheelEvent); |
1300 | event->setAccepted(wheelEvent.isAccepted()); |
1301 | |
1302 | if (event->phase() == Qt::ScrollBegin) { |
1303 | // reset the wheel grabber if the event wasn't accepted |
1304 | if (!wheelEvent.isAccepted()) |
1305 | QApplicationPrivate::wheel_widget = prev_grabber; |
1306 | } |
1307 | |
1308 | // ### Remove, this should be done by proper focusIn/focusOut events. |
1309 | if (focusWidget && !focusWidget->hasFocus()) { |
1310 | focusWidget->update(); |
1311 | focusWidget = d->widget->focusWidget(); |
1312 | if (focusWidget && focusWidget->hasFocus()) |
1313 | focusWidget->update(); |
1314 | } |
1315 | } |
1316 | #endif |
1317 | |
1318 | /*! |
1319 | \reimp |
1320 | */ |
1321 | void QGraphicsProxyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) |
1322 | { |
1323 | Q_D(QGraphicsProxyWidget); |
1324 | #ifdef GRAPHICSPROXYWIDGET_DEBUG |
1325 | qDebug("QGraphicsProxyWidget::mouseReleaseEvent"); |
1326 | #endif |
1327 | d->sendWidgetMouseEvent(event); |
1328 | } |
1329 | |
1330 | /*! |
1331 | \reimp |
1332 | */ |
1333 | void QGraphicsProxyWidget::keyPressEvent(QKeyEvent *event) |
1334 | { |
1335 | Q_D(QGraphicsProxyWidget); |
1336 | #ifdef GRAPHICSPROXYWIDGET_DEBUG |
1337 | qDebug("QGraphicsProxyWidget::keyPressEvent"); |
1338 | #endif |
1339 | d->sendWidgetKeyEvent(event); |
1340 | } |
1341 | |
1342 | /*! |
1343 | \reimp |
1344 | */ |
1345 | void QGraphicsProxyWidget::keyReleaseEvent(QKeyEvent *event) |
1346 | { |
1347 | Q_D(QGraphicsProxyWidget); |
1348 | #ifdef GRAPHICSPROXYWIDGET_DEBUG |
1349 | qDebug("QGraphicsProxyWidget::keyReleaseEvent"); |
1350 | #endif |
1351 | d->sendWidgetKeyEvent(event); |
1352 | } |
1353 | |
1354 | /*! |
1355 | \reimp |
1356 | */ |
1357 | void QGraphicsProxyWidget::focusInEvent(QFocusEvent *event) |
1358 | { |
1359 | #ifdef GRAPHICSPROXYWIDGET_DEBUG |
1360 | qDebug("QGraphicsProxyWidget::focusInEvent"); |
1361 | #endif |
1362 | Q_D(QGraphicsProxyWidget); |
1363 | |
1364 | if (d->focusFromWidgetToProxy) { |
1365 | // Prevent recursion when the proxy autogains focus through the |
1366 | // embedded widget calling setFocus(). ### Could be done with event |
1367 | // filter on FocusIn instead? |
1368 | return; |
1369 | } |
1370 | |
1371 | d->proxyIsGivingFocus = true; |
1372 | |
1373 | switch (event->reason()) { |
1374 | case Qt::TabFocusReason: { |
1375 | if (QWidget *focusChild = d->findFocusChild(child: nullptr, next: true)) |
1376 | focusChild->setFocus(event->reason()); |
1377 | break; |
1378 | } |
1379 | case Qt::BacktabFocusReason: |
1380 | if (QWidget *focusChild = d->findFocusChild(child: nullptr, next: false)) |
1381 | focusChild->setFocus(event->reason()); |
1382 | break; |
1383 | default: |
1384 | if (d->widget && d->widget->focusWidget()) { |
1385 | d->widget->focusWidget()->setFocus(event->reason()); |
1386 | } |
1387 | break; |
1388 | } |
1389 | |
1390 | // QTBUG-88016 |
1391 | if (d->widget && d->widget->focusWidget() |
1392 | && d->widget->focusWidget()->testAttribute(attribute: Qt::WA_InputMethodEnabled)) |
1393 | QApplication::inputMethod()->reset(); |
1394 | |
1395 | d->proxyIsGivingFocus = false; |
1396 | } |
1397 | |
1398 | /*! |
1399 | \reimp |
1400 | */ |
1401 | void QGraphicsProxyWidget::focusOutEvent(QFocusEvent *event) |
1402 | { |
1403 | #ifdef GRAPHICSPROXYWIDGET_DEBUG |
1404 | qDebug("QGraphicsProxyWidget::focusOutEvent"); |
1405 | #endif |
1406 | Q_D(QGraphicsProxyWidget); |
1407 | if (d->widget) { |
1408 | // We need to explicitly remove subfocus from the embedded widget's |
1409 | // focus widget. |
1410 | if (QWidget *focusWidget = d->widget->focusWidget()) { |
1411 | // QTBUG-88016 proxyWidget set QTextEdit(QLineEdit etc.) when input preview text, |
1412 | // inputMethod should be reset when proxyWidget lost focus |
1413 | if (focusWidget->testAttribute(attribute: Qt::WA_InputMethodEnabled)) |
1414 | QApplication::inputMethod()->reset(); |
1415 | |
1416 | d->removeSubFocusHelper(widget: focusWidget, reason: event->reason()); |
1417 | } |
1418 | } |
1419 | } |
1420 | |
1421 | /*! |
1422 | \reimp |
1423 | */ |
1424 | bool QGraphicsProxyWidget::focusNextPrevChild(bool next) |
1425 | { |
1426 | Q_D(QGraphicsProxyWidget); |
1427 | if (!d->widget || !d->scene) |
1428 | return QGraphicsWidget::focusNextPrevChild(next); |
1429 | |
1430 | Qt::FocusReason reason = next ? Qt::TabFocusReason : Qt::BacktabFocusReason; |
1431 | QWidget *lastFocusChild = d->widget->focusWidget(); |
1432 | if (QWidget *newFocusChild = d->findFocusChild(child: lastFocusChild, next)) { |
1433 | newFocusChild->setFocus(reason); |
1434 | return true; |
1435 | } |
1436 | |
1437 | return QGraphicsWidget::focusNextPrevChild(next); |
1438 | } |
1439 | |
1440 | /*! |
1441 | \reimp |
1442 | */ |
1443 | QVariant QGraphicsProxyWidget::inputMethodQuery(Qt::InputMethodQuery query) const |
1444 | { |
1445 | Q_D(const QGraphicsProxyWidget); |
1446 | |
1447 | if (!d->widget || !hasFocus()) |
1448 | return QVariant(); |
1449 | |
1450 | QWidget *focusWidget = widget()->focusWidget(); |
1451 | if (!focusWidget) |
1452 | focusWidget = d->widget; |
1453 | QVariant v = focusWidget->inputMethodQuery(query); |
1454 | QPointF focusWidgetPos = subWidgetRect(widget: focusWidget).topLeft(); |
1455 | switch (v.userType()) { |
1456 | case QMetaType::QRectF: |
1457 | v = v.toRectF().translated(p: focusWidgetPos); |
1458 | break; |
1459 | case QMetaType::QPointF: |
1460 | v = v.toPointF() + focusWidgetPos; |
1461 | break; |
1462 | case QMetaType::QRect: |
1463 | v = v.toRect().translated(p: focusWidgetPos.toPoint()); |
1464 | break; |
1465 | case QMetaType::QPoint: |
1466 | v = v.toPoint() + focusWidgetPos.toPoint(); |
1467 | break; |
1468 | default: |
1469 | break; |
1470 | } |
1471 | return v; |
1472 | } |
1473 | |
1474 | /*! |
1475 | \reimp |
1476 | */ |
1477 | void QGraphicsProxyWidget::inputMethodEvent(QInputMethodEvent *event) |
1478 | { |
1479 | // Forward input method events if the focus widget enables input methods. |
1480 | Q_D(const QGraphicsProxyWidget); |
1481 | QWidget *focusWidget = d->widget->focusWidget(); |
1482 | if (focusWidget && focusWidget->testAttribute(attribute: Qt::WA_InputMethodEnabled)) |
1483 | QCoreApplication::sendEvent(receiver: focusWidget, event); |
1484 | } |
1485 | |
1486 | /*! |
1487 | \reimp |
1488 | */ |
1489 | QSizeF QGraphicsProxyWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const |
1490 | { |
1491 | Q_D(const QGraphicsProxyWidget); |
1492 | if (!d->widget) |
1493 | return QGraphicsWidget::sizeHint(which, constraint); |
1494 | |
1495 | QSizeF sh; |
1496 | switch (which) { |
1497 | case Qt::PreferredSize: |
1498 | if (QLayout *l = d->widget->layout()) |
1499 | sh = l->sizeHint(); |
1500 | else |
1501 | sh = d->widget->sizeHint(); |
1502 | break; |
1503 | case Qt::MinimumSize: |
1504 | if (QLayout *l = d->widget->layout()) |
1505 | sh = l->minimumSize(); |
1506 | else |
1507 | sh = d->widget->minimumSizeHint(); |
1508 | break; |
1509 | case Qt::MaximumSize: |
1510 | if (QLayout *l = d->widget->layout()) |
1511 | sh = l->maximumSize(); |
1512 | else |
1513 | sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); |
1514 | break; |
1515 | case Qt::MinimumDescent: |
1516 | sh = constraint; |
1517 | break; |
1518 | default: |
1519 | break; |
1520 | } |
1521 | return sh; |
1522 | } |
1523 | |
1524 | /*! |
1525 | \reimp |
1526 | */ |
1527 | void QGraphicsProxyWidget::resizeEvent(QGraphicsSceneResizeEvent *event) |
1528 | { |
1529 | Q_D(QGraphicsProxyWidget); |
1530 | if (d->widget) { |
1531 | if (d->sizeChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode) |
1532 | d->widget->resize(event->newSize().toSize()); |
1533 | } |
1534 | QGraphicsWidget::resizeEvent(event); |
1535 | } |
1536 | |
1537 | /*! |
1538 | \reimp |
1539 | */ |
1540 | void QGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) |
1541 | { |
1542 | Q_D(QGraphicsProxyWidget); |
1543 | Q_UNUSED(widget); |
1544 | if (!d->widget || !d->widget->isVisible()) |
1545 | return; |
1546 | |
1547 | // Filter out repaints on the window frame. |
1548 | const QRect exposedWidgetRect = (option->exposedRect & rect()).toAlignedRect(); |
1549 | if (exposedWidgetRect.isEmpty()) |
1550 | return; |
1551 | |
1552 | // When rendering to pdf etc. painting may go outside widget boundaries unless clipped |
1553 | if (painter->device()->devType() != QInternal::Widget && (flags() & ItemClipsChildrenToShape)) |
1554 | painter->setClipRect(d->widget->geometry(), op: Qt::IntersectClip); |
1555 | |
1556 | d->widget->render(painter, targetOffset: exposedWidgetRect.topLeft(), sourceRegion: exposedWidgetRect); |
1557 | } |
1558 | |
1559 | /*! |
1560 | \enum QGraphicsProxyWidget::anonymous |
1561 | |
1562 | The value returned by the virtual type() function. |
1563 | |
1564 | \value Type A graphics proxy widget |
1565 | */ |
1566 | |
1567 | /*! |
1568 | \reimp |
1569 | */ |
1570 | int QGraphicsProxyWidget::type() const |
1571 | { |
1572 | return Type; |
1573 | } |
1574 | |
1575 | /*! |
1576 | \since 4.5 |
1577 | |
1578 | Creates a proxy widget for the given \a child of the widget |
1579 | contained in this proxy. |
1580 | |
1581 | This function makes it possible to acquire proxies for |
1582 | non top-level widgets. For instance, you can embed a dialog, |
1583 | and then transform only one of its widgets. |
1584 | |
1585 | If the widget is already embedded, return the existing proxy widget. |
1586 | |
1587 | \sa newProxyWidget(), QGraphicsScene::addWidget() |
1588 | */ |
1589 | QGraphicsProxyWidget *QGraphicsProxyWidget::createProxyForChildWidget(QWidget *child) |
1590 | { |
1591 | QGraphicsProxyWidget *proxy = child->graphicsProxyWidget(); |
1592 | if (proxy) |
1593 | return proxy; |
1594 | if (!child->parentWidget()) { |
1595 | qWarning(msg: "QGraphicsProxyWidget::createProxyForChildWidget: top-level widget not in a QGraphicsScene"); |
1596 | return nullptr; |
1597 | } |
1598 | |
1599 | QGraphicsProxyWidget *parentProxy = createProxyForChildWidget(child: child->parentWidget()); |
1600 | if (!parentProxy) |
1601 | return nullptr; |
1602 | |
1603 | if (!QMetaObject::invokeMethod(obj: parentProxy, member: "newProxyWidget", c: Qt::DirectConnection, |
1604 | Q_RETURN_ARG(QGraphicsProxyWidget*, proxy), Q_ARG(const QWidget*, child))) |
1605 | return nullptr; |
1606 | proxy->setParent(parentProxy); |
1607 | proxy->setWidget(child); |
1608 | return proxy; |
1609 | } |
1610 | |
1611 | /*! |
1612 | \fn QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *child) |
1613 | \since 4.5 |
1614 | |
1615 | Creates a proxy widget for the given \a child of the widget contained in this |
1616 | proxy. |
1617 | |
1618 | You should not call this function directly; use |
1619 | QGraphicsProxyWidget::createProxyForChildWidget() instead. |
1620 | |
1621 | This function is a fake virtual slot that you can reimplement in |
1622 | your subclass in order to control how new proxy widgets are |
1623 | created. The default implementation returns a proxy created with |
1624 | the QGraphicsProxyWidget() constructor with this proxy widget as |
1625 | the parent. |
1626 | |
1627 | \sa createProxyForChildWidget() |
1628 | */ |
1629 | QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *) |
1630 | { |
1631 | return new QGraphicsProxyWidget(this); |
1632 | } |
1633 | |
1634 | |
1635 | |
1636 | QT_END_NAMESPACE |
1637 | |
1638 | #include "moc_qgraphicsproxywidget.cpp" |
1639 |
Definitions
- QGraphicsProxyWidgetPrivate
- ~QGraphicsProxyWidgetPrivate
- init
- sendWidgetMouseEvent
- sendWidgetMouseEvent
- sendWidgetKeyEvent
- removeSubFocusHelper
- findFocusChild
- _q_removeWidgetSlot
- updateWidgetGeometryFromProxy
- updateProxyGeometryFromWidget
- updateProxyInputMethodAcceptanceFromWidget
- embedSubWindow
- unembedSubWindow
- isProxyWidget
- mapToReceiver
- QGraphicsProxyWidget
- ~QGraphicsProxyWidget
- setWidget
- setWidget_helper
- widget
- subWidgetRect
- setGeometry
- itemChange
- event
- eventFilter
- showEvent
- hideEvent
- contextMenuEvent
- dragEnterEvent
- dragLeaveEvent
- dragMoveEvent
- dropEvent
- hoverEnterEvent
- hoverLeaveEvent
- hoverMoveEvent
- grabMouseEvent
- ungrabMouseEvent
- mouseMoveEvent
- mousePressEvent
- mouseDoubleClickEvent
- wheelEvent
- mouseReleaseEvent
- keyPressEvent
- keyReleaseEvent
- focusInEvent
- focusOutEvent
- focusNextPrevChild
- inputMethodQuery
- inputMethodEvent
- sizeHint
- resizeEvent
- paint
- type
- createProxyForChildWidget
Start learning QML with our Intro Training
Find out more