1// Copyright (C) 2017 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 "qquickpopup_p.h"
5#include "qquickpopup_p_p.h"
6#include "qquickpopupanchors_p.h"
7#include "qquickpopupitem_p_p.h"
8#include "qquickpopupwindow_p_p.h"
9#include "qquickpopuppositioner_p_p.h"
10#include "qquickapplicationwindow_p.h"
11#include "qquickoverlay_p_p.h"
12#include "qquickcontrol_p_p.h"
13#if QT_CONFIG(quicktemplates2_container)
14#include "qquickdialog_p.h"
15#endif
16
17#include <QtCore/qloggingcategory.h>
18#include <QtQml/qqmlinfo.h>
19#include <QtQuick/qquickitem.h>
20#include <QtQuick/private/qquickaccessibleattached_p.h>
21#include <QtQuick/private/qquicktransition_p.h>
22#include <QtQuick/private/qquickitem_p.h>
23#include <qpa/qplatformintegration.h>
24#include <private/qguiapplication_p.h>
25
26QT_BEGIN_NAMESPACE
27
28Q_LOGGING_CATEGORY(lcDimmer, "qt.quick.controls.popup.dimmer")
29Q_LOGGING_CATEGORY(lcQuickPopup, "qt.quick.controls.popup")
30
31/*!
32 \qmltype Popup
33 \inherits QtObject
34//! \nativetype QQuickPopup
35 \inqmlmodule QtQuick.Controls
36 \since 5.7
37 \ingroup qtquickcontrols-popups
38 \ingroup qtquickcontrols-focusscopes
39 \brief Base type of popup-like user interface controls.
40
41 Popup is the base type of popup-like user interface controls. It can be
42 used with \l Window or \l ApplicationWindow.
43
44 \qml
45 import QtQuick.Window
46 import QtQuick.Controls
47
48 ApplicationWindow {
49 id: window
50 width: 400
51 height: 400
52 visible: true
53
54 Button {
55 text: "Open"
56 onClicked: popup.open()
57 }
58
59 Popup {
60 id: popup
61 x: 100
62 y: 100
63 width: 200
64 height: 300
65 modal: true
66 focus: true
67 closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
68 }
69 }
70 \endqml
71
72 Popup does not provide a layout of its own, but requires you to position
73 its contents, for instance by creating a \l RowLayout or a \l ColumnLayout.
74
75 Items declared as children of a Popup are automatically parented to the
76 Popups's \l contentItem. Items created dynamically need to be explicitly
77 parented to the contentItem.
78
79 \section1 Popup Layout
80
81 The following diagram illustrates the layout of a popup within a window:
82
83 \image qtquickcontrols-popup.png
84
85 The \l implicitWidth and \l implicitHeight of a popup are typically based
86 on the implicit sizes of the background and the content item plus any insets
87 and paddings. These properties determine how large the popup will be when no
88 explicit \l width or \l height is specified.
89
90 The geometry of the \l contentItem is determined by the padding. The following
91 example reserves 10px padding between the boundaries of the popup and its content:
92
93 \code
94 Popup {
95 padding: 10
96
97 contentItem: Text {
98 text: "Content"
99 }
100 }
101 \endcode
102
103 The \l background item fills the entire width and height of the popup,
104 unless insets or an explicit size have been given for it.
105
106 Negative insets can be used to make the background larger than the popup.
107 The following example uses negative insets to place a shadow outside the
108 popup's boundaries:
109
110 \code
111 Popup {
112 topInset: -2
113 leftInset: -2
114 rightInset: -6
115 bottomInset: -6
116
117 background: BorderImage {
118 source: ":/images/shadowed-background.png"
119 }
120 }
121 \endcode
122
123 \section1 Popup type
124
125 Since Qt 6.8, some popups, such as \l Menu, offer three different implementations,
126 depending on the platform. You can choose which one you prefer by setting \l popupType.
127
128 Whether a popup will be able to use the preferred type depends on the platform.
129 \c Popup.Item is supported on all platforms, but \c Popup.Window and \c Popup.Native
130 are normally only supported on desktop platforms. Additionally, if a popup is a
131 \l Menu inside a \l {Native menu bars}{native menubar}, the menu will be native as
132 well. And if the menu is a sub-menu inside another menu, the parent (or root) menu
133 will decide the type.
134
135 \section2 Showing a popup as an item
136
137 By setting \l popupType to \c Popup.Item, the popup will \e not be shown as a separate
138 window, but as an item inside the same scene as the parent. This item is parented
139 to that scene's \l{Overlay::overlay}{overlay}, and styled to look like an actual window.
140
141 This option is especially useful on platforms that doesn't support multiple windows.
142 This was also the only option before Qt 6.8.
143
144 In order to ensure that a popup is displayed above other items in the
145 scene, it is recommended to use ApplicationWindow. ApplicationWindow also
146 provides background dimming effects.
147
148 \section2 Showing a popup as a separate window
149
150 By setting \l popupType to \c Popup.Window, the popup will be shown inside a top-level
151 \l {QQuickWindow}{window} configured with the \l Qt::Popup flag. Using a window to show a
152 popup has the advantage that the popup will float on top of the parent window, and
153 can be placed outside of its geometry. The popup will otherwise look the same as when
154 using \c Popup.Item, that is, it will use the same QML delegates and styling as
155 when using \c Popup.Item.
156
157 \note If the platform doesn't support \c Popup.Window, \c Popup.Item will be used as fallback.
158
159 \section2 Showing a native popup
160
161 By setting \l popupType to \c Popup.Native, the popup will be shown using a platform
162 native popup window. This window, and all its contents, will be rendered by the
163 platform, and not by QML. This means that the QML delegates assigned to the popup
164 will \e not be used for rendering. If you for example
165 use this option on a \l Menu, it will be implemented using platform-specific
166 menu APIs. This will normally make the popup look and feel more native than for example
167 \c Popup.Window, but at the same time, suffer from platform limitations and differences
168 related to appearance and behavior. Such limitations are documented in more detail
169 in the subclasses that are affected, such as for a
170 \l {Limitations when using native menus}{Menu}).
171
172 \note If the platform doesn't support \c Popup.Native, \c Popup.Window will be used as fallback.
173
174 \section1 Popup Sizing
175
176 If only a single item is used within a Popup, it will resize to fit the
177 implicit size of its contained item. This makes it particularly suitable
178 for use together with layouts.
179
180 \code
181 Popup {
182 ColumnLayout {
183 anchors.fill: parent
184 CheckBox { text: qsTr("E-mail") }
185 CheckBox { text: qsTr("Calendar") }
186 CheckBox { text: qsTr("Contacts") }
187 }
188 }
189 \endcode
190
191 Sometimes there might be two items within the popup:
192
193 \code
194 Popup {
195 SwipeView {
196 // ...
197 }
198 PageIndicator {
199 anchors.horizontalCenter: parent.horizontalCenter
200 anchors.bottom: parent.bottom
201 }
202 }
203 \endcode
204
205 In this case, Popup cannot calculate a sensible implicit size. Since we're
206 anchoring the \l PageIndicator over the \l SwipeView, we can simply set the
207 content size to the view's implicit size:
208
209 \code
210 Popup {
211 contentWidth: view.implicitWidth
212 contentHeight: view.implicitHeight
213
214 SwipeView {
215 id: view
216 // ...
217 }
218 PageIndicator {
219 anchors.horizontalCenter: parent.horizontalCenter
220 anchors.bottom: parent.bottom
221 }
222 }
223 \endcode
224
225 \note When using \l {Showing a popup as an item}{popup items}, the popup's
226 \l{contentItem}{content item} gets parented to the \l{Overlay::}{overlay},
227 and does not live within the popup's parent. Because of that, a \l{Item::}
228 {scale} applied to the tree in which the popup lives does not apply to the
229 visual popup. To make the popup of e.g. a \l{ComboBox} follow the scale of
230 the combobox, apply the same scale to the \l{Overlay::}{overlay} as well:
231
232 \code
233 Window {
234 property double scaleFactor: 2.0
235
236 Scale {
237 id: scale
238 xScale: scaleFactor
239 yScale: scaleFactor
240 }
241 Item {
242 id: scaledContent
243 transform: scale
244
245 ComboBox {
246 id: combobox
247 // ...
248 }
249 }
250
251 Overlay.overlay.transform: scale
252 }
253 \endcode
254
255 \section1 Popup Positioning
256
257 Similar to items in Qt Quick, Popup's \l x and \l y coordinates are
258 relative to its parent. This means that opening a popup that is a
259 child of a \l Button, for example, will cause the popup to be positioned
260 relative to the button.
261
262 \include qquickoverlay-popup-parent.qdocinc
263
264 Another way to center a popup in the window regardless of its parent item
265 is to use \l {anchors.centerIn}:
266
267 \snippet qtquickcontrols-popup.qml centerIn
268
269 To ensure that the popup is positioned within the bounds of the enclosing
270 window, the \l margins property can be set to a non-negative value.
271
272 \section1 Showing Non-Child Items in Front of Popup
273
274 In cases where \l {Showing a popup as an item}{popup windows} are not being used,
275 Popup sets its contentItem's \l{qtquick-visualcanvas-visualparent.html}{visual parent}
276 to be the window's \l{Overlay::overlay}{overlay}, in order to ensure that
277 the popup appears in front of everything else in the scene.
278 In some cases, it might be useful to put an item in front of a popup,
279 such as a \l [QML QtVirtualKeyboard] {InputPanel} {virtual keyboard}.
280 This can be done by setting the item's parent to the overlay,
281 and giving the item a positive z value. The same result can also be
282 achieved by waiting until the popup is opened, before re-parenting the item
283 to the overlay.
284
285 \omit
286 This shouldn't be a snippet, since we don't want VKB to be a dependency to controls.
287 \endomit
288 \qml
289 Popup {
290 id: popup
291 visible: true
292 anchors.centerIn: parent
293 margins: 10
294 closePolicy: Popup.CloseOnEscape
295 ColumnLayout {
296 TextField {
297 placeholderText: qsTr("Username")
298 }
299 TextField {
300 placeholderText: qsTr("Password")
301 echoMode: TextInput.Password
302 }
303 }
304 }
305 InputPanel {
306 parent: Overlay.overlay
307 width: parent.width
308 y: popup.y + popup.topMargin + (window.activeFocusItem?.y ?? 0) + (window.activeFocusItem?.height ?? 0)
309 z: 1
310 }
311 \endqml
312
313 \section1 Popup Transitions
314
315 Since Qt 5.15.3 the following properties are restored to their original values from before
316 the enter transition after the exit transition is completed.
317
318 \list
319 \li \l opacity
320 \li \l scale
321 \endlist
322
323 This allows the built-in styles to animate on these properties without losing any explicitly
324 defined value.
325
326 \section1 Back/Escape Event Handling
327
328 By default, a Popup will close if:
329 \list
330 \li It has \l activeFocus,
331 \li Its \l closePolicy is \c {Popup.CloseOnEscape}, and
332 \li The user presses the key sequence for QKeySequence::Cancel (typically
333 the Escape key)
334 \endlist
335
336 To prevent this from happening, either:
337
338 \list
339 \li Don't give the popup \l focus.
340 \li Set the popup's \l closePolicy to a value that does not include
341 \c {Popup.CloseOnEscape}.
342 \li Handle \l {Keys}' \l {Keys::}{escapePressed} signal in a child item of
343 the popup so that it gets the event before the Popup.
344 \endlist
345
346 \sa {Popup Controls}, {Customizing Popup}, ApplicationWindow
347
348 \section1 Property Propagation
349
350 Popup inherits fonts, palettes and attached properties through its parent
351 window, not its \l {Visual Parent}{object or visual parent}:
352
353 \snippet qtquickcontrols-popup-property-propagation.qml file
354
355 \image qtquickcontrols-basic-popup-property-propagation.png
356
357 In addition, popups do not propagate their properties to child popups. This
358 behavior is modelled on Qt Widgets, where a \c Qt::Popup widget is a
359 top-level window. Top-level windows do not propagate their properties to
360 child windows.
361
362 Certain derived types like ComboBox are typically implemented in such a way
363 that the popup is considered an integral part of the control, and as such,
364 may inherit things like attached properties. For example, in the
365 \l {Material Style}{Material style} ComboBox, the theme and other attached
366 properties are explicitly inherited by the Popup from the ComboBox itself:
367
368 \code
369 popup: T.Popup {
370 // ...
371
372 Material.theme: control.Material.theme
373 Material.accent: control.Material.accent
374 Material.primary: control.Material.primary
375 }
376 \endcode
377
378 So, to ensure that a child popup has the same property values as its parent
379 popup, explicitly set those properties:
380
381 \code
382 Popup {
383 id: parentPopup
384 // ...
385
386 Popup {
387 palette: parentPopup.palette
388 }
389 }
390 \endcode
391
392 \section1 Polish Behavior of Closed Popups
393
394 When a popup is closed, it has no associated window, and neither do its
395 child items. This means that any child items will not be
396 \l {QQuickItem::polish}{polished} until the popup is shown. For this
397 reason, you cannot, for example, rely on a \l ListView within a closed
398 \c Popup to update its \c count property:
399
400 \code
401 import QtQuick
402 import QtQuick.Controls
403
404 ApplicationWindow {
405 width: 640
406 height: 480
407 visible: true
408
409 SomeModel {
410 id: someModel
411 }
412
413 Button {
414 text: view.count
415 onClicked: popup.open()
416 }
417
418 Popup {
419 id: popup
420 width: 400
421 height: 400
422 contentItem: ListView {
423 id: view
424 model: someModel
425 delegate: Label {
426 text: display
427
428 required property string display
429 }
430 }
431 }
432 }
433 \endcode
434
435 In the example above, the Button's text will not update when rows are added
436 to or removed from \c someModel after \l {Component::completed}{component
437 completion} while the popup is closed.
438
439 Instead, a \c count property can be added to \c SomeModel that is updated
440 whenever the \l {QAbstractItemModel::}{rowsInserted}, \l
441 {QAbstractItemModel::}{rowsRemoved}, and \l
442 {QAbstractItemModel::}{modelReset} signals are emitted. The \c Button can
443 then bind this property to its \c text.
444*/
445
446/*!
447 \qmlsignal void QtQuick.Controls::Popup::opened()
448
449 This signal is emitted when the popup is opened.
450
451 \sa aboutToShow()
452*/
453
454/*!
455 \qmlsignal void QtQuick.Controls::Popup::closed()
456
457 This signal is emitted when the popup is closed.
458
459 \sa aboutToHide()
460*/
461
462/*!
463 \qmlsignal void QtQuick.Controls::Popup::aboutToShow()
464
465 This signal is emitted when the popup is about to show.
466
467 \sa opened()
468*/
469
470/*!
471 \qmlsignal void QtQuick.Controls::Popup::aboutToHide()
472
473 This signal is emitted when the popup is about to hide.
474
475 \sa closed()
476*/
477
478QQuickItem *QQuickPopup::findParentItem() const
479{
480 QObject *obj = parent();
481 while (obj) {
482 QQuickItem *item = qobject_cast<QQuickItem *>(o: obj);
483 if (item)
484 return item;
485 obj = obj->parent();
486 }
487 return nullptr;
488}
489
490const QQuickPopup::ClosePolicy QQuickPopupPrivate::DefaultClosePolicy = QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutside;
491
492QQuickPopupPrivate::QQuickPopupPrivate()
493 : transitionManager(this)
494{
495}
496
497void QQuickPopupPrivate::init()
498{
499 Q_Q(QQuickPopup);
500 popupItem = new QQuickPopupItem(q);
501 popupItem->setVisible(false);
502 QObject::connect(sender: popupItem, signal: &QQuickControl::paddingChanged, context: q, slot: &QQuickPopup::paddingChanged);
503 QObject::connect(sender: popupItem, signal: &QQuickControl::backgroundChanged, context: q, slot: &QQuickPopup::backgroundChanged);
504 QObject::connect(sender: popupItem, signal: &QQuickControl::contentItemChanged, context: q, slot: &QQuickPopup::contentItemChanged);
505 QObject::connect(sender: popupItem, signal: &QQuickControl::implicitContentWidthChanged, context: q, slot: &QQuickPopup::implicitContentWidthChanged);
506 QObject::connect(sender: popupItem, signal: &QQuickControl::implicitContentHeightChanged, context: q, slot: &QQuickPopup::implicitContentHeightChanged);
507 QObject::connect(sender: popupItem, signal: &QQuickControl::implicitBackgroundWidthChanged, context: q, slot: &QQuickPopup::implicitBackgroundWidthChanged);
508 QObject::connect(sender: popupItem, signal: &QQuickControl::implicitBackgroundHeightChanged, context: q, slot: &QQuickPopup::implicitBackgroundHeightChanged);
509}
510
511void QQuickPopupPrivate::closeOrReject()
512{
513 Q_Q(QQuickPopup);
514#if QT_CONFIG(quicktemplates2_container)
515 if (QQuickDialog *dialog = qobject_cast<QQuickDialog*>(object: q))
516 dialog->reject();
517 else
518#endif
519 q->close();
520 touchId = -1;
521}
522
523bool QQuickPopupPrivate::tryClose(const QPointF &pos, QQuickPopup::ClosePolicy flags)
524{
525 if (!interactive)
526 return false;
527
528 static const QQuickPopup::ClosePolicy outsideFlags = QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnReleaseOutside;
529 static const QQuickPopup::ClosePolicy outsideParentFlags = QQuickPopup::CloseOnPressOutsideParent | QQuickPopup::CloseOnReleaseOutsideParent;
530
531 const bool onOutside = closePolicy & (flags & outsideFlags);
532 const bool onOutsideParent = closePolicy & (flags & outsideParentFlags);
533
534 if ((onOutside && outsidePressed) || (onOutsideParent && outsideParentPressed)) {
535 if (!contains(scenePos: pos) && (!dimmer || dimmer->contains(point: dimmer->mapFromScene(point: pos)))) {
536 if (!onOutsideParent || !parentItem || !parentItem->contains(point: parentItem->mapFromScene(point: pos))) {
537 closeOrReject();
538 return true;
539 }
540 }
541 }
542 return false;
543}
544
545bool QQuickPopupPrivate::contains(const QPointF &scenePos) const
546{
547 return popupItem->contains(point: popupItem->mapFromScene(point: scenePos));
548}
549
550#if QT_CONFIG(quicktemplates2_multitouch)
551bool QQuickPopupPrivate::acceptTouch(const QTouchEvent::TouchPoint &point)
552{
553 if (point.id() == touchId)
554 return true;
555
556 if (touchId == -1 && point.state() != QEventPoint::Released) {
557 touchId = point.id();
558 return true;
559 }
560
561 return false;
562}
563#endif
564
565bool QQuickPopupPrivate::blockInput(QQuickItem *item, const QPointF &point) const
566{
567 // don't propagate events within the popup beyond the overlay
568 if (popupItem->contains(point: popupItem->mapFromScene(point))
569 && item == QQuickOverlay::overlay(window)) {
570 return true;
571 }
572
573 // don't block presses and releases
574 // a) outside a non-modal popup,
575 // b) to popup children/content, or
576 // c) outside a modal popups's background dimming
577
578 return modal && ((popupItem != item) && !popupItem->isAncestorOf(child: item)) && (!dimmer || dimmer->contains(point: dimmer->mapFromScene(point)));
579}
580
581bool QQuickPopupPrivate::handlePress(QQuickItem *item, const QPointF &point, ulong timestamp)
582{
583 Q_UNUSED(timestamp);
584 pressPoint = point;
585 outsidePressed = !contains(scenePos: point);
586
587 if (outsidePressed && parentItem) {
588 // Note that the parentItem (e.g a menuBarItem, in case of a MenuBar) will
589 // live inside another window when using popup windows. We therefore need to
590 // map to and from global.
591 const QPointF globalPoint = item->mapToGlobal(point);
592 const QPointF localPoint = parentItem->mapFromGlobal(point: globalPoint);
593 outsideParentPressed = !parentItem->contains(point: localPoint);
594 }
595
596 tryClose(pos: point, flags: QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent);
597 return blockInput(item, point);
598}
599
600bool QQuickPopupPrivate::handleMove(QQuickItem *item, const QPointF &point, ulong timestamp)
601{
602 Q_UNUSED(timestamp);
603 return blockInput(item, point);
604}
605
606bool QQuickPopupPrivate::handleRelease(QQuickItem *item, const QPointF &point, ulong timestamp)
607{
608 Q_UNUSED(timestamp);
609 if (item != popupItem && !contains(scenePos: pressPoint))
610 tryClose(pos: point, flags: QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent);
611 pressPoint = QPointF();
612 outsidePressed = false;
613 outsideParentPressed = false;
614 touchId = -1;
615 return blockInput(item, point);
616}
617
618void QQuickPopupPrivate::handleUngrab()
619{
620 Q_Q(QQuickPopup);
621 QQuickOverlay *overlay = QQuickOverlay::overlay(window);
622 if (overlay) {
623 QQuickOverlayPrivate *p = QQuickOverlayPrivate::get(overlay);
624 if (p->mouseGrabberPopup == q)
625 p->mouseGrabberPopup = nullptr;
626 }
627 pressPoint = QPointF();
628 touchId = -1;
629}
630
631bool QQuickPopupPrivate::handleMouseEvent(QQuickItem *item, QMouseEvent *event)
632{
633 switch (event->type()) {
634 case QEvent::MouseButtonPress:
635 return handlePress(item, point: event->scenePosition(), timestamp: event->timestamp());
636 case QEvent::MouseMove:
637 return handleMove(item, point: event->scenePosition(), timestamp: event->timestamp());
638 case QEvent::MouseButtonRelease:
639 return handleRelease(item, point: event->scenePosition(), timestamp: event->timestamp());
640 default:
641 Q_UNREACHABLE_RETURN(false);
642 }
643}
644
645bool QQuickPopupPrivate::handleHoverEvent(QQuickItem *item, QHoverEvent *event)
646{
647 switch (event->type()) {
648 case QEvent::HoverEnter:
649 case QEvent::HoverMove:
650 case QEvent::HoverLeave:
651 return blockInput(item, point: event->scenePosition());
652 default:
653 Q_UNREACHABLE_RETURN(false);
654 }
655}
656
657QMarginsF QQuickPopupPrivate::windowInsets() const
658{
659 Q_Q(const QQuickPopup);
660 // If the popup has negative insets, it means that its background is pushed
661 // outside the bounds of the popup. This is fine when the popup is an item in the
662 // scene (Popup.Item), but will result in the background being clipped when using
663 // a window (Popup.Window). To avoid this, the window will been made bigger than
664 // the popup (according to the insets), to also include the part that ends up
665 // outside (which is usually a drop-shadow).
666 // Note that this also means that we need to take those extra margins into account
667 // whenever we resize or position the menu, so that the top-left of the popup ends
668 // up at the requested position, and not the top-left of the window.
669
670 const auto *popupItemPrivate = QQuickControlPrivate::get(control: popupItem);
671 if (!usePopupWindow() || (popupItemPrivate->background.isExecuting() && popupItemPrivate->background->clip())) {
672 // Items in the scene are allowed to draw out-of-bounds, so we don't
673 // need to do anything if we're not using popup windows. The same is
674 // also true for popup windows if the background is clipped.
675 return {0, 0, 0, 0};
676 }
677
678 return {
679 q->leftInset() < 0 ? -q->leftInset() : 0,
680 q->rightInset() < 0 ? -q->rightInset() : 0,
681 q->topInset() < 0 ? -q->topInset() : 0,
682 q->bottomInset() < 0 ? -q->bottomInset() : 0
683 };
684}
685
686QPointF QQuickPopupPrivate::windowInsetsTopLeft() const
687{
688 const QMarginsF windowMargins = windowInsets();
689 return {windowMargins.left(), windowMargins.top()};
690}
691
692void QQuickPopupPrivate::setEffectivePosFromWindowPos(const QPointF &windowPos)
693{
694 // Popup operates internally with three different positions; requested
695 // position, effective position, and window position. The first is the
696 // position requested by the application, and the second is where the popup
697 // is actually placed. The reason for placing it on a different position than
698 // the one requested, is to keep it inside the window (in case of Popup.Item),
699 // or the screen (in case of Popup.Window).
700 // Additionally, since a popup can set Qt::FramelessWindowHint and draw the
701 // window frame from the background delegate, the effective position in that
702 // case is adjusted to be the top-left corner of the background delegate, rather
703 // than the top-left corner of the window. This allowes the background delegate
704 // to render a drop-shadow between the edge of the window and the background frame.
705 // Finally, the window position is the actual position of the window, including
706 // any drop-shadow effects. This posision can be calculated by taking
707 // the effective position and subtract the dropShadowOffset().
708 Q_Q(QQuickPopup);
709 const QPointF oldEffectivePos = effectivePos;
710 effectivePos = windowPos + windowInsetsTopLeft();
711 if (!qFuzzyCompare(p1: oldEffectivePos.x(), p2: effectivePos.x()))
712 emit q->xChanged();
713 if (!qFuzzyCompare(p1: oldEffectivePos.y(), p2: effectivePos.y()))
714 emit q->yChanged();
715}
716
717#if QT_CONFIG(quicktemplates2_multitouch)
718bool QQuickPopupPrivate::handleTouchEvent(QQuickItem *item, QTouchEvent *event)
719{
720 switch (event->type()) {
721 case QEvent::TouchBegin:
722 case QEvent::TouchUpdate:
723 case QEvent::TouchEnd:
724 for (const QTouchEvent::TouchPoint &point : event->points()) {
725 if (event->type() != QEvent::TouchEnd && !acceptTouch(point))
726 return blockInput(item, point: point.position());
727
728 switch (point.state()) {
729 case QEventPoint::Pressed:
730 return handlePress(item, point: item->mapToScene(point: point.position()), timestamp: event->timestamp());
731 case QEventPoint::Updated:
732 return handleMove(item, point: item->mapToScene(point: point.position()), timestamp: event->timestamp());
733 case QEventPoint::Released:
734 return handleRelease(item, point: item->mapToScene(point: point.position()), timestamp: event->timestamp());
735 default:
736 break;
737 }
738 }
739 break;
740
741 case QEvent::TouchCancel:
742 handleUngrab();
743 break;
744
745 default:
746 break;
747 }
748
749 return false;
750}
751#endif
752
753bool QQuickPopupPrivate::prepareEnterTransition()
754{
755 Q_Q(QQuickPopup);
756 if (!window) {
757 qmlWarning(me: q) << "cannot find any window to open popup in.";
758 return false;
759 }
760
761 if (transitionState == EnterTransition && transitionManager.isRunning())
762 return false;
763
764 if (transitionState != EnterTransition) {
765 visible = true;
766 adjustPopupItemParentAndWindow();
767 if (dim)
768 createOverlay();
769 showDimmer();
770 emit q->aboutToShow();
771 transitionState = EnterTransition;
772 getPositioner()->setParentItem(parentItem);
773 emit q->visibleChanged();
774
775 QQuickOverlay *overlay = QQuickOverlay::overlay(window);
776 auto *overlayPrivate = QQuickOverlayPrivate::get(overlay);
777 if (overlayPrivate->lastActiveFocusItem.isNull())
778 overlayPrivate->lastActiveFocusItem = window->activeFocusItem();
779
780 if (focus)
781 popupItem->setFocus(focus: true, reason: Qt::PopupFocusReason);
782 }
783 return true;
784}
785
786bool QQuickPopupPrivate::prepareExitTransition()
787{
788 Q_Q(QQuickPopup);
789 if (transitionState == ExitTransition && transitionManager.isRunning())
790 return false;
791
792 Q_ASSERT(popupItem);
793
794 // We need to cache the original scale and opacity values so we can reset it after
795 // the exit transition is done so they have the original values again
796 prevScale = popupItem->scale();
797 prevOpacity = popupItem->opacity();
798
799 if (transitionState != ExitTransition) {
800 // The setFocus(false) call below removes any active focus before we're
801 // able to check it in finalizeExitTransition.
802 if (!hadActiveFocusBeforeExitTransition) {
803 const auto *da = QQuickItemPrivate::get(item: popupItem)->deliveryAgentPrivate();
804 hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus() || (da && da->focusTargetItem() == popupItem);
805 }
806
807 if (focus)
808 popupItem->setFocus(focus: false, reason: Qt::PopupFocusReason);
809 transitionState = ExitTransition;
810 hideDimmer();
811 emit q->aboutToHide();
812 emit q->openedChanged();
813 }
814 return true;
815}
816
817void QQuickPopupPrivate::finalizeEnterTransition()
818{
819 Q_Q(QQuickPopup);
820 transitionState = NoTransition;
821 reposition();
822 emit q->openedChanged();
823 opened();
824}
825
826void QQuickPopupPrivate::finalizeExitTransition()
827{
828 Q_Q(QQuickPopup);
829 getPositioner()->setParentItem(nullptr);
830 if (popupItem) {
831 popupItem->setParentItem(nullptr);
832 popupItem->setVisible(false);
833 }
834 destroyDimmer();
835
836 if (hadActiveFocusBeforeExitTransition && window) {
837 // restore focus to the next popup in chain, or to the window content if there are no other popups open
838 QQuickPopup *nextFocusPopup = nullptr;
839 if (QQuickOverlay *overlay = QQuickOverlay::overlay(window)) {
840 const auto stackingOrderPopups = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
841 for (auto popup : stackingOrderPopups) {
842 if (QQuickPopupPrivate::get(popup)->transitionState != ExitTransition
843 && popup->hasFocus()) {
844 nextFocusPopup = popup;
845 break;
846 }
847 }
848 }
849 if (nextFocusPopup) {
850 nextFocusPopup->forceActiveFocus(reason: Qt::PopupFocusReason);
851 } else {
852 auto *appWindow = qobject_cast<QQuickApplicationWindow*>(object: window);
853 auto *contentItem = appWindow ? appWindow->contentItem() : window->contentItem();
854 auto *overlay = QQuickOverlay::overlay(window);
855 auto *overlayPrivate = QQuickOverlayPrivate::get(overlay);
856 if (!contentItem->scopedFocusItem()
857 && !overlayPrivate->lastActiveFocusItem.isNull()) {
858 overlayPrivate->lastActiveFocusItem->setFocus(focus: true, reason: Qt::OtherFocusReason);
859 } else {
860 contentItem->setFocus(focus: true, reason: Qt::PopupFocusReason);
861 }
862 overlayPrivate->lastActiveFocusItem = nullptr;
863 }
864 }
865 visible = false;
866 adjustPopupItemParentAndWindow();
867 transitionState = NoTransition;
868 hadActiveFocusBeforeExitTransition = false;
869 emit q->visibleChanged();
870 emit q->closed();
871#if QT_CONFIG(accessibility)
872 const auto type = q->effectiveAccessibleRole() == QAccessible::PopupMenu
873 ? QAccessible::PopupMenuEnd
874 : QAccessible::DialogEnd;
875 QAccessibleEvent ev(q->popupItem(), type);
876 QAccessible::updateAccessibility(event: &ev);
877#endif
878 if (popupItem) {
879 popupItem->setScale(prevScale);
880 popupItem->setOpacity(prevOpacity);
881 }
882}
883
884void QQuickPopupPrivate::opened()
885{
886 Q_Q(QQuickPopup);
887 emit q->opened();
888#if QT_CONFIG(accessibility)
889 const auto type = q->effectiveAccessibleRole() == QAccessible::PopupMenu
890 ? QAccessible::PopupMenuStart
891 : QAccessible::DialogStart;
892 QAccessibleEvent ev(q->popupItem(), type);
893 QAccessible::updateAccessibility(event: &ev);
894#endif
895}
896
897Qt::WindowFlags QQuickPopupPrivate::popupWindowType() const
898{
899 return Qt::Popup | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint;
900}
901
902QMarginsF QQuickPopupPrivate::getMargins() const
903{
904 Q_Q(const QQuickPopup);
905 return QMarginsF(q->leftMargin(), q->topMargin(), q->rightMargin(), q->bottomMargin());
906}
907
908void QQuickPopupPrivate::setTopMargin(qreal value, bool reset)
909{
910 Q_Q(QQuickPopup);
911 qreal oldMargin = q->topMargin();
912 topMargin = value;
913 hasTopMargin = !reset;
914 if ((!reset && !qFuzzyCompare(p1: oldMargin, p2: value)) || (reset && !qFuzzyCompare(p1: oldMargin, p2: margins))) {
915 emit q->topMarginChanged();
916 q->marginsChange(newMargins: QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
917 oldMargins: QMarginsF(leftMargin, oldMargin, rightMargin, bottomMargin));
918 }
919}
920
921void QQuickPopupPrivate::setLeftMargin(qreal value, bool reset)
922{
923 Q_Q(QQuickPopup);
924 qreal oldMargin = q->leftMargin();
925 leftMargin = value;
926 hasLeftMargin = !reset;
927 if ((!reset && !qFuzzyCompare(p1: oldMargin, p2: value)) || (reset && !qFuzzyCompare(p1: oldMargin, p2: margins))) {
928 emit q->leftMarginChanged();
929 q->marginsChange(newMargins: QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
930 oldMargins: QMarginsF(oldMargin, topMargin, rightMargin, bottomMargin));
931 }
932}
933
934void QQuickPopupPrivate::setRightMargin(qreal value, bool reset)
935{
936 Q_Q(QQuickPopup);
937 qreal oldMargin = q->rightMargin();
938 rightMargin = value;
939 hasRightMargin = !reset;
940 if ((!reset && !qFuzzyCompare(p1: oldMargin, p2: value)) || (reset && !qFuzzyCompare(p1: oldMargin, p2: margins))) {
941 emit q->rightMarginChanged();
942 q->marginsChange(newMargins: QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
943 oldMargins: QMarginsF(leftMargin, topMargin, oldMargin, bottomMargin));
944 }
945}
946
947void QQuickPopupPrivate::setBottomMargin(qreal value, bool reset)
948{
949 Q_Q(QQuickPopup);
950 qreal oldMargin = q->bottomMargin();
951 bottomMargin = value;
952 hasBottomMargin = !reset;
953 if ((!reset && !qFuzzyCompare(p1: oldMargin, p2: value)) || (reset && !qFuzzyCompare(p1: oldMargin, p2: margins))) {
954 emit q->bottomMarginChanged();
955 q->marginsChange(newMargins: QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
956 oldMargins: QMarginsF(leftMargin, topMargin, rightMargin, oldMargin));
957 }
958}
959
960/*!
961 \since QtQuick.Controls 2.5 (Qt 5.12)
962 \qmlproperty Item QtQuick.Controls::Popup::anchors.centerIn
963
964 Anchors provide a way to position an item by specifying its
965 relationship with other items.
966
967 A common use case is to center a popup within its parent. One way to do
968 this is with the \l[QtQuick]{Item::}{x} and \l[QtQuick]{Item::}{y} properties. Anchors offer
969 a more convenient approach:
970
971 \qml
972 Pane {
973 // ...
974
975 Popup {
976 anchors.centerIn: parent
977 }
978 }
979 \endqml
980
981 It is also possible to center the popup in the window by using \l Overlay:
982
983 \snippet qtquickcontrols-popup.qml centerIn
984
985 This makes it easy to center a popup in the window from any component.
986
987 \note Popups can only be centered within their immediate parent or
988 the window overlay; trying to center in other items will produce a warning.
989
990 \sa {Popup Positioning}, {Item::}{anchors}, {Using Qt Quick Controls types
991 in property declarations}
992*/
993QQuickPopupAnchors *QQuickPopupPrivate::getAnchors()
994{
995 Q_Q(QQuickPopup);
996 if (!anchors)
997 anchors = new QQuickPopupAnchors(q);
998 return anchors;
999}
1000
1001QQuickPopupPositioner *QQuickPopupPrivate::getPositioner()
1002{
1003 Q_Q(QQuickPopup);
1004 if (!positioner)
1005 positioner = new QQuickPopupPositioner(q);
1006 return positioner;
1007}
1008
1009void QQuickPopupPrivate::setWindow(QQuickWindow *newWindow)
1010{
1011 Q_Q(QQuickPopup);
1012 if (window == newWindow)
1013 return;
1014
1015 if (window) {
1016 QQuickOverlay *overlay = QQuickOverlay::overlay(window);
1017 if (overlay)
1018 QQuickOverlayPrivate::get(overlay)->removePopup(popup: q);
1019 }
1020
1021 window = newWindow;
1022
1023 if (newWindow) {
1024 QQuickOverlay *overlay = QQuickOverlay::overlay(window: newWindow);
1025 if (overlay)
1026 QQuickOverlayPrivate::get(overlay)->addPopup(popup: q);
1027
1028 QQuickControlPrivate *p = QQuickControlPrivate::get(control: popupItem);
1029 p->resolveFont();
1030 if (QQuickApplicationWindow *appWindow = qobject_cast<QQuickApplicationWindow *>(object: newWindow))
1031 p->updateLocale(l: appWindow->locale(), e: false); // explicit=false
1032 }
1033
1034 emit q->windowChanged(window: newWindow);
1035
1036 if (complete && visible && window)
1037 transitionManager.transitionEnter();
1038}
1039
1040void QQuickPopupPrivate::itemDestroyed(QQuickItem *item)
1041{
1042 Q_Q(QQuickPopup);
1043 if (item == parentItem)
1044 q->setParentItem(nullptr);
1045}
1046
1047void QQuickPopupPrivate::reposition()
1048{
1049 getPositioner()->reposition();
1050}
1051
1052QPalette QQuickPopupPrivate::defaultPalette() const
1053{
1054 return QQuickTheme::palette(scope: QQuickTheme::System);
1055}
1056
1057QQuickPopup::PopupType QQuickPopupPrivate::resolvedPopupType() const
1058{
1059 // Whether or not the resolved popup type ends up the same as the preferred popup type
1060 // depends on platform capabilities, the popup subclass, and sometimes also the location
1061 // of the popup in the parent hierarchy (menus). This function can therefore be overridden
1062 // to return the actual popup type that should be used, based on the knowledge the popup
1063 // has just before it's about to be shown.
1064
1065 // PopupType::Native is not directly supported by QQuickPopup (only by subclasses).
1066 // So for that case, we fall back to use PopupType::Window, if supported.
1067 if (m_popupType == QQuickPopup::PopupType::Window
1068 || m_popupType == QQuickPopup::PopupType::Native) {
1069 if (QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::Capability::MultipleWindows))
1070 return QQuickPopup::PopupType::Window;
1071 }
1072
1073 return QQuickPopup::PopupType::Item;
1074}
1075
1076bool QQuickPopupPrivate::usePopupWindow() const
1077{
1078 return resolvedPopupType() == QQuickPopup::PopupType::Window;
1079}
1080
1081void QQuickPopupPrivate::adjustPopupItemParentAndWindow()
1082{
1083 Q_Q(QQuickPopup);
1084 QQuickOverlay *overlay = QQuickOverlay::overlay(window);
1085
1086 if (visible && popupWindowDirty) {
1087 popupItem->setParentItem(overlay);
1088 if (popupWindow) {
1089 popupWindow->deleteLater();
1090 popupWindow = nullptr;
1091 }
1092 popupWindowDirty = false;
1093 }
1094
1095 if (usePopupWindow()) {
1096 if (visible) {
1097 if (!popupWindow) {
1098 popupWindow = new QQuickPopupWindow(q, window);
1099 popupWindow->setWidth(popupItem->width() + windowInsets().left() + windowInsets().right());
1100 popupWindow->setHeight(popupItem->height() + windowInsets().top() + windowInsets().bottom());
1101 popupWindow->setModality(modal ? Qt::ApplicationModal : Qt::NonModal);
1102 popupItem->resetTitle();
1103 popupWindow->setTitle(m_title);
1104 }
1105 popupItem->setParentItem(popupWindow->contentItem());
1106 popupItem->forceActiveFocus(reason: Qt::PopupFocusReason);
1107 }
1108 popupWindow->setVisible(visible);
1109 } else {
1110 if (visible) {
1111 popupItem->setParentItem(overlay);
1112 const auto popupStack = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
1113 // if there is a stack of popups, and the current top popup item belongs to an
1114 // ancestor of this popup, then make sure that this popup's item is at the top
1115 // of the stack.
1116 const QQuickPopup *topPopup = popupStack.isEmpty() ? nullptr : popupStack.first();
1117 const QObject *ancestor = q;
1118 while (ancestor && topPopup) {
1119 if (ancestor == topPopup)
1120 break;
1121 ancestor = ancestor->parent();
1122 }
1123 if (topPopup && topPopup != q && ancestor) {
1124 QQuickItem *topPopupItem = popupStack.first()->popupItem();
1125 popupItem->stackAfter(topPopupItem);
1126 // If the popup doesn't have an explicit z value set, set it to be at least as
1127 // high as the current top popup item so that later opened popups are on top.
1128 if (!hasZ)
1129 popupItem->setZ(qMax(a: topPopupItem->z(), b: popupItem->z()));
1130 }
1131 }
1132
1133 popupItem->setTitle(m_title);
1134 }
1135 popupItem->setVisible(visible);
1136}
1137
1138QQuickItem *QQuickPopupPrivate::createDimmer(QQmlComponent *component, QQuickPopup *popup, QQuickItem *parent) const
1139{
1140 QQuickItem *item = nullptr;
1141 if (component) {
1142 QQmlContext *context = component->creationContext();
1143 if (!context)
1144 context = qmlContext(popup);
1145 item = qobject_cast<QQuickItem*>(o: component->beginCreate(context));
1146 }
1147
1148 // when there is no overlay component available (with plain QQuickWindow),
1149 // use a plain QQuickItem as a fallback to block hover events
1150 if (!item && popup->isModal())
1151 item = new QQuickItem;
1152
1153 if (item) {
1154 item->setParentItem(parent);
1155 if (resolvedPopupType() != QQuickPopup::PopupType::Window)
1156 item->stackBefore(popup->popupItem());
1157 item->setZ(popup->z());
1158 // needed for the virtual keyboard to set a containment mask on the dimmer item
1159 qCDebug(lcDimmer) << "dimmer" << item << "registered with" << parent;
1160 parent->setProperty(name: "_q_dimmerItem", value: QVariant::fromValue<QQuickItem*>(value: item));
1161 if (popup->isModal()) {
1162 item->setAcceptedMouseButtons(Qt::AllButtons);
1163#if QT_CONFIG(cursor)
1164 item->setCursor(Qt::ArrowCursor);
1165#endif
1166#if QT_CONFIG(quicktemplates2_hover)
1167 // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8
1168 item->setAcceptHoverEvents(true);
1169 // item->setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects());
1170 // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, item, &QQuickItem::setAcceptHoverEvents);
1171#endif
1172 }
1173 if (component)
1174 component->completeCreate();
1175 }
1176 qCDebug(lcDimmer) << "finished creating dimmer from component" << component
1177 << "for popup" << popup << "with parent" << parent << "- item is:" << item;
1178 return item;
1179}
1180
1181void QQuickPopupPrivate::createOverlay()
1182{
1183 Q_Q(QQuickPopup);
1184 QQuickOverlay *overlay = QQuickOverlay::overlay(window);
1185 if (!overlay)
1186 return;
1187
1188 QQmlComponent *component = nullptr;
1189 QQuickOverlayAttached *overlayAttached = qobject_cast<QQuickOverlayAttached *>(object: qmlAttachedPropertiesObject<QQuickOverlay>(obj: q, create: false));
1190 if (overlayAttached)
1191 component = modal ? overlayAttached->modal() : overlayAttached->modeless();
1192
1193 if (!component)
1194 component = modal ? overlay->modal() : overlay->modeless();
1195
1196 if (!dimmer) {
1197 dimmer = createDimmer(component, popup: q, parent: overlay);
1198 if (!dimmer)
1199 return;
1200 // We cannot update explicitDimmerOpacity when dimmer's opacity changes,
1201 // as it is expected to do so when we fade the dimmer in and out in
1202 // show/hideDimmer, and any binding of the dimmer's opacity will be
1203 // implicitly broken anyway.
1204 explicitDimmerOpacity = dimmer->opacity();
1205 // initially fully transparent, showDimmer fades the dimmer in.
1206 dimmer->setOpacity(0);
1207 if (q->isVisible())
1208 showDimmer();
1209 }
1210 resizeDimmer();
1211}
1212
1213void QQuickPopupPrivate::destroyDimmer()
1214{
1215 if (dimmer) {
1216 qCDebug(lcDimmer) << "destroying dimmer" << dimmer;
1217 if (QObject *dimmerParentItem = dimmer->parentItem()) {
1218 if (dimmerParentItem->property(name: "_q_dimmerItem").value<QQuickItem*>() == dimmer)
1219 dimmerParentItem->setProperty(name: "_q_dimmerItem", value: QVariant());
1220 }
1221 dimmer->setParentItem(nullptr);
1222 dimmer->deleteLater();
1223 dimmer = nullptr;
1224 }
1225}
1226
1227void QQuickPopupPrivate::toggleOverlay()
1228{
1229 destroyDimmer();
1230 if (dim)
1231 createOverlay();
1232}
1233
1234void QQuickPopupPrivate::updateContentPalettes(const QPalette& parentPalette)
1235{
1236 // Inherit parent palette to all child objects
1237 inheritPalette(parentPalette);
1238
1239 // Inherit parent palette to items within popup (such as headers and footers)
1240 QQuickItemPrivate::get(item: popupItem)->updateChildrenPalettes(parentPalette);
1241}
1242
1243void QQuickPopupPrivate::showDimmer()
1244{
1245 // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors
1246 if (dim && dimmer)
1247 QQmlProperty::write(dimmer, QStringLiteral("opacity"), explicitDimmerOpacity);
1248}
1249
1250void QQuickPopupPrivate::hideDimmer()
1251{
1252 // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors
1253 if (dim && dimmer)
1254 QQmlProperty::write(dimmer, QStringLiteral("opacity"), 0.0);
1255}
1256
1257void QQuickPopupPrivate::resizeDimmer()
1258{
1259 if (!dimmer)
1260 return;
1261
1262 const QQuickOverlay *overlay = QQuickOverlay::overlay(window);
1263
1264 qreal w = overlay ? overlay->width() : 0;
1265 qreal h = overlay ? overlay->height() : 0;
1266 dimmer->setSize(QSizeF(w, h));
1267}
1268
1269QQuickPopupTransitionManager::QQuickPopupTransitionManager(QQuickPopupPrivate *popup)
1270 : popup(popup)
1271{
1272}
1273
1274void QQuickPopupTransitionManager::transitionEnter()
1275{
1276 if (popup->transitionState == QQuickPopupPrivate::ExitTransition)
1277 cancel();
1278
1279 if (!popup->prepareEnterTransition())
1280 return;
1281
1282 if (popup->window)
1283 transition(popup->enterActions, transition: popup->enter, defaultTarget: popup->q_func());
1284 else
1285 finished();
1286}
1287
1288void QQuickPopupTransitionManager::transitionExit()
1289{
1290 if (!popup->prepareExitTransition())
1291 return;
1292
1293 if (popup->window)
1294 transition(popup->exitActions, transition: popup->exit, defaultTarget: popup->q_func());
1295 else
1296 finished();
1297}
1298
1299void QQuickPopupTransitionManager::finished()
1300{
1301 if (popup->transitionState == QQuickPopupPrivate::EnterTransition)
1302 popup->finalizeEnterTransition();
1303 else if (popup->transitionState == QQuickPopupPrivate::ExitTransition)
1304 popup->finalizeExitTransition();
1305}
1306
1307QQuickPopup::QQuickPopup(QObject *parent)
1308 : QObject(*(new QQuickPopupPrivate), parent)
1309{
1310 Q_D(QQuickPopup);
1311 d->init();
1312 // By default, allow popup to move beyond window edges
1313 d->relaxEdgeConstraint = true;
1314}
1315
1316QQuickPopup::QQuickPopup(QQuickPopupPrivate &dd, QObject *parent)
1317 : QObject(dd, parent)
1318{
1319 Q_D(QQuickPopup);
1320 d->init();
1321}
1322
1323QQuickPopup::~QQuickPopup()
1324{
1325 Q_D(QQuickPopup);
1326 d->inDestructor = true;
1327
1328 QQuickItem *currentContentItem = d->popupItem->d_func()->contentItem.data();
1329 if (currentContentItem) {
1330 disconnect(sender: currentContentItem, signal: &QQuickItem::childrenChanged,
1331 receiver: this, slot: &QQuickPopup::contentChildrenChanged);
1332 }
1333
1334 setParentItem(nullptr);
1335
1336 // If the popup is destroyed before the exit transition finishes,
1337 // the necessary cleanup (removing modal dimmers that block mouse events,
1338 // emitting closed signal, etc.) won't happen. That's why we do it manually here.
1339 if (d->transitionState == QQuickPopupPrivate::ExitTransition && d->transitionManager.isRunning())
1340 d->finalizeExitTransition();
1341
1342 delete d->popupItem;
1343 d->popupItem = nullptr;
1344 delete d->positioner;
1345 d->positioner = nullptr;
1346 if (d->popupWindow)
1347 delete d->popupWindow;
1348 d->popupWindow = nullptr;
1349}
1350
1351/*!
1352 \qmlmethod void QtQuick.Controls::Popup::open()
1353
1354 Opens the popup.
1355
1356 \sa visible
1357*/
1358void QQuickPopup::open()
1359{
1360 setVisible(true);
1361}
1362
1363/*!
1364 \qmlmethod void QtQuick.Controls::Popup::close()
1365
1366 Closes the popup.
1367
1368 \sa visible
1369*/
1370void QQuickPopup::close()
1371{
1372 setVisible(false);
1373}
1374
1375/*!
1376 \qmlproperty real QtQuick.Controls::Popup::x
1377
1378 This property holds the x-coordinate of the popup.
1379
1380 \sa y, z
1381*/
1382qreal QQuickPopup::x() const
1383{
1384 return d_func()->effectivePos.x();
1385}
1386
1387void QQuickPopup::setX(qreal x)
1388{
1389 Q_D(QQuickPopup);
1390 setPosition(QPointF(x, d->y));
1391}
1392
1393/*!
1394 \qmlproperty real QtQuick.Controls::Popup::y
1395
1396 This property holds the y-coordinate of the popup.
1397
1398 \sa x, z
1399*/
1400qreal QQuickPopup::y() const
1401{
1402 return d_func()->effectivePos.y();
1403}
1404
1405void QQuickPopup::setY(qreal y)
1406{
1407 Q_D(QQuickPopup);
1408 setPosition(QPointF(d->x, y));
1409}
1410
1411QPointF QQuickPopup::position() const
1412{
1413 return d_func()->effectivePos;
1414}
1415
1416void QQuickPopup::setPosition(const QPointF &pos)
1417{
1418 Q_D(QQuickPopup);
1419 const bool xChange = !qFuzzyCompare(p1: d->x, p2: pos.x());
1420 const bool yChange = !qFuzzyCompare(p1: d->y, p2: pos.y());
1421 if (!xChange && !yChange)
1422 return;
1423
1424 d->x = pos.x();
1425 d->y = pos.y();
1426 if (d->popupItem->isVisible()) {
1427 d->reposition();
1428 } else {
1429 if (xChange)
1430 emit xChanged();
1431 if (yChange)
1432 emit yChanged();
1433 }
1434}
1435
1436/*!
1437 \qmlproperty real QtQuick.Controls::Popup::z
1438
1439 This property holds the z-value of the popup. Z-value determines
1440 the stacking order of popups.
1441
1442 If two visible popups have the same z-value, the last one that
1443 was opened will be on top.
1444
1445 If a popup has no explicitly set z-value when opened, and is a child
1446 of an already open popup, then it will be stacked on top of its parent.
1447 This ensures that children are never hidden under their parents.
1448
1449 If the popup has its own window, the z-value will determine the window
1450 stacking order instead.
1451
1452 The default z-value is \c 0.
1453
1454 \sa x, y
1455*/
1456qreal QQuickPopup::z() const
1457{
1458 Q_D(const QQuickPopup);
1459 return d->popupItem->z();
1460}
1461
1462void QQuickPopup::setZ(qreal z)
1463{
1464 Q_D(QQuickPopup);
1465 d->hasZ = true;
1466 bool previousZ = d->popupWindow ? d->popupWindow->z() : d->popupItem->z();
1467 if (qFuzzyCompare(p1: z, p2: previousZ))
1468 return;
1469 if (d->popupWindow)
1470 d->popupWindow->setZ(z);
1471 else
1472 d->popupItem->setZ(z);
1473 emit zChanged();
1474}
1475
1476void QQuickPopup::resetZ()
1477{
1478 Q_D(QQuickPopup);
1479 setZ(0);
1480 d->hasZ = false;
1481}
1482
1483/*!
1484 \qmlproperty real QtQuick.Controls::Popup::width
1485
1486 This property holds the width of the popup.
1487*/
1488qreal QQuickPopup::width() const
1489{
1490 Q_D(const QQuickPopup);
1491 return d->popupItem->width();
1492}
1493
1494void QQuickPopup::setWidth(qreal width)
1495{
1496 Q_D(QQuickPopup);
1497 d->hasWidth = true;
1498
1499 // QQuickPopupWindow::setWidth() triggers a window resize event.
1500 // This will cause QQuickPopupWindow::resizeEvent() to resize
1501 // the popupItem. QQuickPopupItem::geometryChanged() calls QQuickPopup::geometryChange(),
1502 // which emits widthChanged().
1503
1504 if (d->popupWindow)
1505 d->popupWindow->setWidth(width + d->windowInsets().left() + d->windowInsets().right());
1506 else
1507 d->popupItem->setWidth(width);
1508}
1509
1510void QQuickPopup::resetWidth()
1511{
1512 Q_D(QQuickPopup);
1513 if (!d->hasWidth)
1514 return;
1515
1516 d->hasWidth = false;
1517 d->popupItem->resetWidth();
1518 if (d->popupItem->isVisible())
1519 d->reposition();
1520}
1521
1522/*!
1523 \qmlproperty real QtQuick.Controls::Popup::height
1524
1525 This property holds the height of the popup.
1526*/
1527qreal QQuickPopup::height() const
1528{
1529 Q_D(const QQuickPopup);
1530 return d->popupItem->height();
1531}
1532
1533void QQuickPopup::setHeight(qreal height)
1534{
1535 Q_D(QQuickPopup);
1536 d->hasHeight = true;
1537
1538 // QQuickPopupWindow::setHeight() triggers a window resize event.
1539 // This will cause QQuickPopupWindow::resizeEvent() to resize
1540 // the popupItem. QQuickPopupItem::geometryChanged() calls QQuickPopup::geometryChange(),
1541 // which emits heightChanged().
1542
1543 if (d->popupWindow)
1544 d->popupWindow->setHeight(height + d->windowInsets().top() + d->windowInsets().bottom());
1545 else
1546 d->popupItem->setHeight(height);
1547}
1548
1549void QQuickPopup::resetHeight()
1550{
1551 Q_D(QQuickPopup);
1552 if (!d->hasHeight)
1553 return;
1554
1555 d->hasHeight = false;
1556 d->popupItem->resetHeight();
1557 if (d->popupItem->isVisible())
1558 d->reposition();
1559}
1560
1561/*!
1562 \qmlproperty real QtQuick.Controls::Popup::implicitWidth
1563
1564 This property holds the implicit width of the popup.
1565*/
1566qreal QQuickPopup::implicitWidth() const
1567{
1568 Q_D(const QQuickPopup);
1569 return d->popupItem->implicitWidth();
1570}
1571
1572void QQuickPopup::setImplicitWidth(qreal width)
1573{
1574 Q_D(QQuickPopup);
1575 d->popupItem->setImplicitWidth(width);
1576}
1577
1578/*!
1579 \qmlproperty real QtQuick.Controls::Popup::implicitHeight
1580
1581 This property holds the implicit height of the popup.
1582*/
1583qreal QQuickPopup::implicitHeight() const
1584{
1585 Q_D(const QQuickPopup);
1586 return d->popupItem->implicitHeight();
1587}
1588
1589void QQuickPopup::setImplicitHeight(qreal height)
1590{
1591 Q_D(QQuickPopup);
1592 d->popupItem->setImplicitHeight(height);
1593}
1594
1595/*!
1596 \qmlproperty real QtQuick.Controls::Popup::contentWidth
1597
1598 This property holds the content width. It is used for calculating the
1599 total implicit width of the Popup.
1600
1601 For more information, see \l {Popup Sizing}.
1602
1603 \sa contentHeight
1604*/
1605qreal QQuickPopup::contentWidth() const
1606{
1607 Q_D(const QQuickPopup);
1608 return d->popupItem->contentWidth();
1609}
1610
1611void QQuickPopup::setContentWidth(qreal width)
1612{
1613 Q_D(QQuickPopup);
1614 d->popupItem->setContentWidth(width);
1615}
1616
1617/*!
1618 \qmlproperty real QtQuick.Controls::Popup::contentHeight
1619
1620 This property holds the content height. It is used for calculating the
1621 total implicit height of the Popup.
1622
1623 For more information, see \l {Popup Sizing}.
1624
1625 \sa contentWidth
1626*/
1627qreal QQuickPopup::contentHeight() const
1628{
1629 Q_D(const QQuickPopup);
1630 return d->popupItem->contentHeight();
1631}
1632
1633void QQuickPopup::setContentHeight(qreal height)
1634{
1635 Q_D(QQuickPopup);
1636 d->popupItem->setContentHeight(height);
1637}
1638
1639/*!
1640 \qmlproperty real QtQuick.Controls::Popup::availableWidth
1641 \readonly
1642
1643 This property holds the width available to the \l contentItem after
1644 deducting horizontal padding from the \l {Item::}{width} of the popup.
1645
1646 \sa padding, leftPadding, rightPadding
1647*/
1648qreal QQuickPopup::availableWidth() const
1649{
1650 Q_D(const QQuickPopup);
1651 return d->popupItem->availableWidth();
1652}
1653
1654/*!
1655 \qmlproperty real QtQuick.Controls::Popup::availableHeight
1656 \readonly
1657
1658 This property holds the height available to the \l contentItem after
1659 deducting vertical padding from the \l {Item::}{height} of the popup.
1660
1661 \sa padding, topPadding, bottomPadding
1662*/
1663qreal QQuickPopup::availableHeight() const
1664{
1665 Q_D(const QQuickPopup);
1666 return d->popupItem->availableHeight();
1667}
1668
1669/*!
1670 \since QtQuick.Controls 2.1 (Qt 5.8)
1671 \qmlproperty real QtQuick.Controls::Popup::spacing
1672
1673 This property holds the spacing.
1674
1675 Spacing is useful for popups that have multiple or repetitive building
1676 blocks. For example, some styles use spacing to determine the distance
1677 between the header, content, and footer of \l Dialog. Spacing is not
1678 enforced by Popup, so each style may interpret it differently, and some
1679 may ignore it altogether.
1680*/
1681qreal QQuickPopup::spacing() const
1682{
1683 Q_D(const QQuickPopup);
1684 return d->popupItem->spacing();
1685}
1686
1687void QQuickPopup::setSpacing(qreal spacing)
1688{
1689 Q_D(QQuickPopup);
1690 d->popupItem->setSpacing(spacing);
1691}
1692
1693void QQuickPopup::resetSpacing()
1694{
1695 setSpacing(0);
1696}
1697
1698/*!
1699 \qmlproperty real QtQuick.Controls::Popup::margins
1700
1701 This property holds the distance between the edges of the popup and the
1702 edges of its window.
1703
1704 A popup with negative margins is not pushed within the bounds
1705 of the enclosing window. The default value is \c -1.
1706
1707 \sa topMargin, leftMargin, rightMargin, bottomMargin, {Popup Layout}
1708*/
1709qreal QQuickPopup::margins() const
1710{
1711 Q_D(const QQuickPopup);
1712 return d->margins;
1713}
1714
1715void QQuickPopup::setMargins(qreal margins)
1716{
1717 Q_D(QQuickPopup);
1718 if (qFuzzyCompare(p1: d->margins, p2: margins))
1719 return;
1720 QMarginsF oldMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin());
1721 d->margins = margins;
1722 emit marginsChanged();
1723 QMarginsF newMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin());
1724 if (!qFuzzyCompare(p1: newMargins.top(), p2: oldMargins.top()))
1725 emit topMarginChanged();
1726 if (!qFuzzyCompare(p1: newMargins.left(), p2: oldMargins.left()))
1727 emit leftMarginChanged();
1728 if (!qFuzzyCompare(p1: newMargins.right(), p2: oldMargins.right()))
1729 emit rightMarginChanged();
1730 if (!qFuzzyCompare(p1: newMargins.bottom(), p2: oldMargins.bottom()))
1731 emit bottomMarginChanged();
1732 marginsChange(newMargins, oldMargins);
1733}
1734
1735void QQuickPopup::resetMargins()
1736{
1737 setMargins(-1);
1738}
1739
1740/*!
1741 \qmlproperty real QtQuick.Controls::Popup::topMargin
1742
1743 This property holds the distance between the top edge of the popup and
1744 the top edge of its window.
1745
1746 A popup with a negative top margin is not pushed within the top edge
1747 of the enclosing window. The default value is \c -1.
1748
1749 \sa margins, bottomMargin, {Popup Layout}
1750*/
1751qreal QQuickPopup::topMargin() const
1752{
1753 Q_D(const QQuickPopup);
1754 if (d->hasTopMargin)
1755 return d->topMargin;
1756 return d->margins;
1757}
1758
1759void QQuickPopup::setTopMargin(qreal margin)
1760{
1761 Q_D(QQuickPopup);
1762 d->setTopMargin(value: margin);
1763}
1764
1765void QQuickPopup::resetTopMargin()
1766{
1767 Q_D(QQuickPopup);
1768 d->setTopMargin(value: -1, reset: true);
1769}
1770
1771/*!
1772 \qmlproperty real QtQuick.Controls::Popup::leftMargin
1773
1774 This property holds the distance between the left edge of the popup and
1775 the left edge of its window.
1776
1777 A popup with a negative left margin is not pushed within the left edge
1778 of the enclosing window. The default value is \c -1.
1779
1780 \sa margins, rightMargin, {Popup Layout}
1781*/
1782qreal QQuickPopup::leftMargin() const
1783{
1784 Q_D(const QQuickPopup);
1785 if (d->hasLeftMargin)
1786 return d->leftMargin;
1787 return d->margins;
1788}
1789
1790void QQuickPopup::setLeftMargin(qreal margin)
1791{
1792 Q_D(QQuickPopup);
1793 d->setLeftMargin(value: margin);
1794}
1795
1796void QQuickPopup::resetLeftMargin()
1797{
1798 Q_D(QQuickPopup);
1799 d->setLeftMargin(value: -1, reset: true);
1800}
1801
1802/*!
1803 \qmlproperty real QtQuick.Controls::Popup::rightMargin
1804
1805 This property holds the distance between the right edge of the popup and
1806 the right edge of its window.
1807
1808 A popup with a negative right margin is not pushed within the right edge
1809 of the enclosing window. The default value is \c -1.
1810
1811 \sa margins, leftMargin, {Popup Layout}
1812*/
1813qreal QQuickPopup::rightMargin() const
1814{
1815 Q_D(const QQuickPopup);
1816 if (d->hasRightMargin)
1817 return d->rightMargin;
1818 return d->margins;
1819}
1820
1821void QQuickPopup::setRightMargin(qreal margin)
1822{
1823 Q_D(QQuickPopup);
1824 d->setRightMargin(value: margin);
1825}
1826
1827void QQuickPopup::resetRightMargin()
1828{
1829 Q_D(QQuickPopup);
1830 d->setRightMargin(value: -1, reset: true);
1831}
1832
1833/*!
1834 \qmlproperty real QtQuick.Controls::Popup::bottomMargin
1835
1836 This property holds the distance between the bottom edge of the popup and
1837 the bottom edge of its window.
1838
1839 A popup with a negative bottom margin is not pushed within the bottom edge
1840 of the enclosing window. The default value is \c -1.
1841
1842 \sa margins, topMargin, {Popup Layout}
1843*/
1844qreal QQuickPopup::bottomMargin() const
1845{
1846 Q_D(const QQuickPopup);
1847 if (d->hasBottomMargin)
1848 return d->bottomMargin;
1849 return d->margins;
1850}
1851
1852void QQuickPopup::setBottomMargin(qreal margin)
1853{
1854 Q_D(QQuickPopup);
1855 d->setBottomMargin(value: margin);
1856}
1857
1858void QQuickPopup::resetBottomMargin()
1859{
1860 Q_D(QQuickPopup);
1861 d->setBottomMargin(value: -1, reset: true);
1862}
1863
1864/*!
1865 \qmlproperty real QtQuick.Controls::Popup::padding
1866
1867 This property holds the default padding.
1868
1869 \include qquickpopup-padding.qdocinc
1870
1871 \sa availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding
1872*/
1873qreal QQuickPopup::padding() const
1874{
1875 Q_D(const QQuickPopup);
1876 return d->popupItem->padding();
1877}
1878
1879void QQuickPopup::setPadding(qreal padding)
1880{
1881 Q_D(QQuickPopup);
1882 d->popupItem->setPadding(padding);
1883}
1884
1885void QQuickPopup::resetPadding()
1886{
1887 Q_D(QQuickPopup);
1888 d->popupItem->resetPadding();
1889}
1890
1891/*!
1892 \qmlproperty real QtQuick.Controls::Popup::topPadding
1893
1894 This property holds the top padding. Unless explicitly set, the value
1895 is equal to \c verticalPadding.
1896
1897 \include qquickpopup-padding.qdocinc
1898
1899 \sa padding, bottomPadding, verticalPadding, availableHeight
1900*/
1901qreal QQuickPopup::topPadding() const
1902{
1903 Q_D(const QQuickPopup);
1904 return d->popupItem->topPadding();
1905}
1906
1907void QQuickPopup::setTopPadding(qreal padding)
1908{
1909 Q_D(QQuickPopup);
1910 d->popupItem->setTopPadding(padding);
1911}
1912
1913void QQuickPopup::resetTopPadding()
1914{
1915 Q_D(QQuickPopup);
1916 d->popupItem->resetTopPadding();
1917}
1918
1919/*!
1920 \qmlproperty real QtQuick.Controls::Popup::leftPadding
1921
1922 This property holds the left padding. Unless explicitly set, the value
1923 is equal to \c horizontalPadding.
1924
1925 \include qquickpopup-padding.qdocinc
1926
1927 \sa padding, rightPadding, horizontalPadding, availableWidth
1928*/
1929qreal QQuickPopup::leftPadding() const
1930{
1931 Q_D(const QQuickPopup);
1932 return d->popupItem->leftPadding();
1933}
1934
1935void QQuickPopup::setLeftPadding(qreal padding)
1936{
1937 Q_D(QQuickPopup);
1938 d->popupItem->setLeftPadding(padding);
1939}
1940
1941void QQuickPopup::resetLeftPadding()
1942{
1943 Q_D(QQuickPopup);
1944 d->popupItem->resetLeftPadding();
1945}
1946
1947/*!
1948 \qmlproperty real QtQuick.Controls::Popup::rightPadding
1949
1950 This property holds the right padding. Unless explicitly set, the value
1951 is equal to \c horizontalPadding.
1952
1953 \include qquickpopup-padding.qdocinc
1954
1955 \sa padding, leftPadding, horizontalPadding, availableWidth
1956*/
1957qreal QQuickPopup::rightPadding() const
1958{
1959 Q_D(const QQuickPopup);
1960 return d->popupItem->rightPadding();
1961}
1962
1963void QQuickPopup::setRightPadding(qreal padding)
1964{
1965 Q_D(QQuickPopup);
1966 d->popupItem->setRightPadding(padding);
1967}
1968
1969void QQuickPopup::resetRightPadding()
1970{
1971 Q_D(QQuickPopup);
1972 d->popupItem->resetRightPadding();
1973}
1974
1975/*!
1976 \qmlproperty real QtQuick.Controls::Popup::bottomPadding
1977
1978 This property holds the bottom padding. Unless explicitly set, the value
1979 is equal to \c verticalPadding.
1980
1981 \include qquickpopup-padding.qdocinc
1982
1983 \sa padding, topPadding, verticalPadding, availableHeight
1984*/
1985qreal QQuickPopup::bottomPadding() const
1986{
1987 Q_D(const QQuickPopup);
1988 return d->popupItem->bottomPadding();
1989}
1990
1991void QQuickPopup::setBottomPadding(qreal padding)
1992{
1993 Q_D(QQuickPopup);
1994 d->popupItem->setBottomPadding(padding);
1995}
1996
1997void QQuickPopup::resetBottomPadding()
1998{
1999 Q_D(QQuickPopup);
2000 d->popupItem->resetBottomPadding();
2001}
2002
2003/*!
2004 \qmlproperty Locale QtQuick.Controls::Popup::locale
2005
2006 This property holds the locale of the popup.
2007
2008 \sa mirrored, {LayoutMirroring}{LayoutMirroring}
2009*/
2010QLocale QQuickPopup::locale() const
2011{
2012 Q_D(const QQuickPopup);
2013 return d->popupItem->locale();
2014}
2015
2016void QQuickPopup::setLocale(const QLocale &locale)
2017{
2018 Q_D(QQuickPopup);
2019 d->popupItem->setLocale(locale);
2020}
2021
2022void QQuickPopup::resetLocale()
2023{
2024 Q_D(QQuickPopup);
2025 d->popupItem->resetLocale();
2026}
2027
2028/*!
2029 \since QtQuick.Controls 2.3 (Qt 5.10)
2030 \qmlproperty bool QtQuick.Controls::Popup::mirrored
2031 \readonly
2032
2033 This property holds whether the popup is mirrored.
2034
2035 This property is provided for convenience. A popup is considered mirrored
2036 when its visual layout direction is right-to-left; that is, when using a
2037 right-to-left locale.
2038
2039 \sa locale, {Right-to-left User Interfaces}
2040*/
2041bool QQuickPopup::isMirrored() const
2042{
2043 Q_D(const QQuickPopup);
2044 return d->popupItem->isMirrored();
2045}
2046
2047/*!
2048 \qmlproperty font QtQuick.Controls::Popup::font
2049
2050 This property holds the font currently set for the popup.
2051
2052 Popup propagates explicit font properties to its children. If you change a specific
2053 property on a popup's font, that property propagates to all of the popup's children,
2054 overriding any system defaults for that property.
2055
2056 \code
2057 Popup {
2058 font.family: "Courier"
2059
2060 Column {
2061 Label {
2062 text: qsTr("This will use Courier...")
2063 }
2064
2065 Switch {
2066 text: qsTr("... and so will this")
2067 }
2068 }
2069 }
2070 \endcode
2071
2072 \sa Control::font, ApplicationWindow::font
2073*/
2074QFont QQuickPopup::font() const
2075{
2076 Q_D(const QQuickPopup);
2077 return d->popupItem->font();
2078}
2079
2080void QQuickPopup::setFont(const QFont &font)
2081{
2082 Q_D(QQuickPopup);
2083 d->popupItem->setFont(font);
2084}
2085
2086void QQuickPopup::resetFont()
2087{
2088 Q_D(QQuickPopup);
2089 d->popupItem->resetFont();
2090}
2091
2092QQuickWindow *QQuickPopup::window() const
2093{
2094 Q_D(const QQuickPopup);
2095 return d->window;
2096}
2097
2098QQuickItem *QQuickPopup::popupItem() const
2099{
2100 Q_D(const QQuickPopup);
2101 return d->popupItem;
2102}
2103
2104/*!
2105 \qmlproperty Item QtQuick.Controls::Popup::parent
2106
2107 This property holds the parent item.
2108*/
2109QQuickItem *QQuickPopup::parentItem() const
2110{
2111 Q_D(const QQuickPopup);
2112 return d->parentItem;
2113}
2114
2115void QQuickPopup::setParentItem(QQuickItem *parent)
2116{
2117 Q_D(QQuickPopup);
2118 if (d->parentItem == parent)
2119 return;
2120
2121 if (d->parentItem) {
2122 QObjectPrivate::disconnect(sender: d->parentItem, signal: &QQuickItem::windowChanged, receiverPrivate: d, slot: &QQuickPopupPrivate::setWindow);
2123 QQuickItemPrivate::get(item: d->parentItem)->removeItemChangeListener(d, types: QQuickItemPrivate::Destroyed);
2124 }
2125 d->parentItem = parent;
2126 QQuickPopupPositioner *positioner = d->getPositioner();
2127 if (positioner->parentItem())
2128 positioner->setParentItem(parent);
2129 if (parent) {
2130 QObjectPrivate::connect(sender: parent, signal: &QQuickItem::windowChanged, receiverPrivate: d, slot: &QQuickPopupPrivate::setWindow);
2131 QQuickItemPrivate::get(item: d->parentItem)->addItemChangeListener(listener: d, types: QQuickItemPrivate::Destroyed);
2132 } else if (d->inDestructor) {
2133 d->destroyDimmer();
2134 } else {
2135 // Reset transition manager state when its parent window destroyed
2136 if (!d->window && d->transitionManager.isRunning()) {
2137 if (d->transitionState == QQuickPopupPrivate::EnterTransition)
2138 d->finalizeEnterTransition();
2139 else if (d->transitionState == QQuickPopupPrivate::ExitTransition)
2140 d->finalizeExitTransition();
2141 }
2142 // NOTE: if setParentItem is called from the dtor, this bypasses virtual dispatch and calls
2143 // QQuickPopup::close() directly
2144 close();
2145 }
2146 d->setWindow(parent ? parent->window() : nullptr);
2147 emit parentChanged();
2148}
2149
2150void QQuickPopup::resetParentItem()
2151{
2152 if (QQuickWindow *window = qobject_cast<QQuickWindow *>(object: parent()))
2153 setParentItem(window->contentItem());
2154 else
2155 setParentItem(findParentItem());
2156}
2157
2158/*!
2159 \qmlproperty Item QtQuick.Controls::Popup::background
2160
2161 This property holds the background item.
2162
2163 \note If the background item has no explicit size specified, it automatically
2164 follows the popup's size. In most cases, there is no need to specify
2165 width or height for a background item.
2166
2167 \note Most popups use the implicit size of the background item to calculate
2168 the implicit size of the popup itself. If you replace the background item
2169 with a custom one, you should also consider providing a sensible implicit
2170 size for it (unless it is an item like \l Image which has its own implicit
2171 size).
2172
2173 \sa {Customizing Popup}
2174*/
2175QQuickItem *QQuickPopup::background() const
2176{
2177 Q_D(const QQuickPopup);
2178 return d->popupItem->background();
2179}
2180
2181void QQuickPopup::setBackground(QQuickItem *background)
2182{
2183 Q_D(QQuickPopup);
2184 // The __notCustomizable property won't be on "this" when the popup item's setBackground function
2185 // is called, so it won't warn. That's why we do a check here.
2186 QQuickControlPrivate::warnIfCustomizationNotSupported(control: this, item: background, QStringLiteral("background"));
2187 d->popupItem->setBackground(background);
2188}
2189
2190/*!
2191 \qmlproperty Item QtQuick.Controls::Popup::contentItem
2192
2193 This property holds the content item of the popup.
2194
2195 The content item is the visual implementation of the popup. When the
2196 popup is made visible, the content item is automatically reparented to
2197 the \l {Overlay::overlay}{overlay item}.
2198
2199 \note The content item is automatically resized to fit within the
2200 \l padding of the popup.
2201
2202 \note Most popups use the implicit size of the content item to calculate
2203 the implicit size of the popup itself. If you replace the content item
2204 with a custom one, you should also consider providing a sensible implicit
2205 size for it (unless it is an item like \l Text which has its own implicit
2206 size).
2207
2208 \sa {Customizing Popup}
2209*/
2210QQuickItem *QQuickPopup::contentItem() const
2211{
2212 Q_D(const QQuickPopup);
2213 return d->popupItem->contentItem();
2214}
2215
2216void QQuickPopup::setContentItem(QQuickItem *item)
2217{
2218 Q_D(QQuickPopup);
2219 // See comment in setBackground for why we do this.
2220 QQuickControlPrivate::warnIfCustomizationNotSupported(control: this, item, QStringLiteral("contentItem"));
2221 QQuickItem *oldContentItem = d->complete ? d->popupItem->d_func()->contentItem.data()
2222 : nullptr;
2223 if (oldContentItem)
2224 disconnect(sender: oldContentItem, signal: &QQuickItem::childrenChanged, receiver: this, slot: &QQuickPopup::contentChildrenChanged);
2225 d->popupItem->setContentItem(item);
2226 if (d->complete) {
2227 QQuickItem *newContentItem = d->popupItem->d_func()->contentItem.data();
2228 connect(sender: newContentItem, signal: &QQuickItem::childrenChanged, context: this, slot: &QQuickPopup::contentChildrenChanged);
2229 if (oldContentItem != newContentItem)
2230 emit contentChildrenChanged();
2231 }
2232}
2233
2234/*!
2235 \qmlproperty list<QtObject> QtQuick.Controls::Popup::contentData
2236 \qmldefault
2237
2238 This property holds the list of content data.
2239
2240 The list contains all objects that have been declared in QML as children
2241 of the popup.
2242
2243 \note Unlike \c contentChildren, \c contentData does include non-visual QML
2244 objects.
2245
2246 \sa Item::data, contentChildren
2247*/
2248QQmlListProperty<QObject> QQuickPopupPrivate::contentData()
2249{
2250 QQuickControlPrivate *p = QQuickControlPrivate::get(control: popupItem);
2251 if (!p->contentItem)
2252 p->executeContentItem();
2253 return QQmlListProperty<QObject>(popupItem->contentItem(), nullptr,
2254 QQuickItemPrivate::data_append,
2255 QQuickItemPrivate::data_count,
2256 QQuickItemPrivate::data_at,
2257 QQuickItemPrivate::data_clear);
2258}
2259
2260/*!
2261 \qmlproperty list<Item> QtQuick.Controls::Popup::contentChildren
2262
2263 This property holds the list of content children.
2264
2265 The list contains all items that have been declared in QML as children
2266 of the popup.
2267
2268 \note Unlike \c contentData, \c contentChildren does not include non-visual
2269 QML objects.
2270
2271 \sa Item::children, contentData
2272*/
2273QQmlListProperty<QQuickItem> QQuickPopupPrivate::contentChildren()
2274{
2275 return QQmlListProperty<QQuickItem>(popupItem->contentItem(), nullptr,
2276 QQuickItemPrivate::children_append,
2277 QQuickItemPrivate::children_count,
2278 QQuickItemPrivate::children_at,
2279 QQuickItemPrivate::children_clear);
2280}
2281
2282/*!
2283 \qmlproperty bool QtQuick.Controls::Popup::clip
2284
2285 This property holds whether clipping is enabled. The default value is \c false.
2286 Clipping only works when the popup isn't in its own window.
2287*/
2288bool QQuickPopup::clip() const
2289{
2290 Q_D(const QQuickPopup);
2291 return d->popupItem->clip() && !d->usePopupWindow();
2292}
2293
2294void QQuickPopup::setClip(bool clip)
2295{
2296 Q_D(QQuickPopup);
2297 if (clip == d->popupItem->clip() || d->usePopupWindow())
2298 return;
2299 d->popupItem->setClip(clip);
2300 emit clipChanged();
2301}
2302
2303/*!
2304 \qmlproperty bool QtQuick.Controls::Popup::focus
2305
2306 This property holds whether the popup wants focus.
2307
2308 When the popup actually receives focus, \l activeFocus will be \c true.
2309 For more information, see \l {Keyboard Focus in Qt Quick}.
2310
2311 The default value is \c false.
2312
2313 \sa activeFocus
2314*/
2315bool QQuickPopup::hasFocus() const
2316{
2317 Q_D(const QQuickPopup);
2318 return d->focus;
2319}
2320
2321void QQuickPopup::setFocus(bool focus)
2322{
2323 Q_D(QQuickPopup);
2324 if (d->focus == focus)
2325 return;
2326 d->focus = focus;
2327 emit focusChanged();
2328}
2329
2330/*!
2331 \qmlproperty bool QtQuick.Controls::Popup::activeFocus
2332 \readonly
2333
2334 This property holds whether the popup has active focus.
2335
2336 \sa focus, {Keyboard Focus in Qt Quick}
2337*/
2338bool QQuickPopup::hasActiveFocus() const
2339{
2340 Q_D(const QQuickPopup);
2341 return d->popupItem->hasActiveFocus();
2342}
2343
2344/*!
2345 \qmlproperty bool QtQuick.Controls::Popup::modal
2346
2347 This property holds whether the popup is modal.
2348
2349 Modal popups often have a distinctive background dimming effect defined
2350 in \l {Overlay::modal}{Overlay.modal}, and do not allow press
2351 or release events through to items beneath them. For example, if the user
2352 accidentally clicks outside of a popup, any item beneath that popup at
2353 the location of the click will not receive the event.
2354
2355 On desktop platforms, it is common for modal popups to be closed only when
2356 the escape key is pressed. To achieve this behavior, set
2357 \l closePolicy to \c Popup.CloseOnEscape. By default, \c closePolicy
2358 is set to \c {Popup.CloseOnEscape | Popup.CloseOnPressOutside}, which
2359 means that clicking outside of a modal popup will close it.
2360
2361 The default value is \c false.
2362
2363 \sa dim
2364*/
2365bool QQuickPopup::isModal() const
2366{
2367 Q_D(const QQuickPopup);
2368 return d->modal;
2369}
2370
2371void QQuickPopup::setModal(bool modal)
2372{
2373 Q_D(QQuickPopup);
2374 if (d->modal == modal)
2375 return;
2376 d->modal = modal;
2377 d->popupWindowDirty = true;
2378 if (d->complete && d->visible)
2379 d->toggleOverlay();
2380 emit modalChanged();
2381
2382 QQuickItemPrivate::get(item: d->popupItem)->isTabFence = modal;
2383
2384 if (!d->hasDim) {
2385 setDim(modal);
2386 d->hasDim = false;
2387 }
2388}
2389
2390/*!
2391 \qmlproperty bool QtQuick.Controls::Popup::dim
2392
2393 This property holds whether the popup dims the background.
2394
2395 Unless explicitly set, this property follows the value of \l modal. To
2396 return to the default value, set this property to \c undefined.
2397
2398 \sa modal, {Overlay::modeless}{Overlay.modeless}
2399*/
2400bool QQuickPopup::dim() const
2401{
2402 Q_D(const QQuickPopup);
2403 return d->dim;
2404}
2405
2406void QQuickPopup::setDim(bool dim)
2407{
2408 Q_D(QQuickPopup);
2409 d->hasDim = true;
2410
2411 if (d->dim == dim)
2412 return;
2413
2414 d->dim = dim;
2415 if (d->complete && d->visible)
2416 d->toggleOverlay();
2417 emit dimChanged();
2418}
2419
2420void QQuickPopup::resetDim()
2421{
2422 Q_D(QQuickPopup);
2423 if (!d->hasDim)
2424 return;
2425
2426 setDim(d->modal);
2427 d->hasDim = false;
2428}
2429
2430/*!
2431 \qmlproperty bool QtQuick.Controls::Popup::visible
2432
2433 This property holds whether the popup is visible. The default value is \c false.
2434
2435 \sa open(), close(), opened
2436*/
2437bool QQuickPopup::isVisible() const
2438{
2439 Q_D(const QQuickPopup);
2440 return d->visible && d->popupItem->isVisible();
2441}
2442
2443void QQuickPopup::setVisible(bool visible)
2444{
2445 Q_D(QQuickPopup);
2446 // During an exit transition, d->visible == true until the transition has completed.
2447 // Therefore, this guard must not return early if setting visible to true while
2448 // d->visible is true.
2449 if (d->visible && visible && d->transitionState != QQuickPopupPrivate::ExitTransition)
2450 return;
2451 if (!d->visible && !visible)
2452 return;
2453
2454 if (!d->complete || (visible && !d->window)) {
2455 d->visible = visible;
2456 return;
2457 }
2458
2459 if (visible)
2460 d->transitionManager.transitionEnter();
2461 else
2462 d->transitionManager.transitionExit();
2463}
2464
2465/*!
2466 \since QtQuick.Controls 2.3 (Qt 5.10)
2467 \qmlproperty bool QtQuick.Controls::Popup::enabled
2468
2469 This property holds whether the popup is enabled. The default value is \c true.
2470
2471 \sa visible, Item::enabled
2472*/
2473bool QQuickPopup::isEnabled() const
2474{
2475 Q_D(const QQuickPopup);
2476 return d->popupItem->isEnabled();
2477}
2478
2479void QQuickPopup::setEnabled(bool enabled)
2480{
2481 Q_D(QQuickPopup);
2482 d->popupItem->setEnabled(enabled);
2483}
2484
2485/*!
2486 \since QtQuick.Controls 2.3 (Qt 5.10)
2487 \qmlproperty bool QtQuick.Controls::Popup::opened
2488
2489 This property holds whether the popup is fully open. The popup is considered opened
2490 when it's visible and neither the \l enter nor \l exit transitions are running.
2491
2492 \sa open(), close(), visible
2493*/
2494bool QQuickPopup::isOpened() const
2495{
2496 Q_D(const QQuickPopup);
2497 return d->transitionState == QQuickPopupPrivate::NoTransition && isVisible();
2498}
2499
2500/*!
2501 \qmlproperty real QtQuick.Controls::Popup::opacity
2502
2503 This property holds the opacity of the popup. Opacity is specified as a number between
2504 \c 0.0 (fully transparent) and \c 1.0 (fully opaque). The default value is \c 1.0.
2505
2506 \sa visible
2507*/
2508qreal QQuickPopup::opacity() const
2509{
2510 Q_D(const QQuickPopup);
2511 return d->popupItem->opacity();
2512}
2513
2514void QQuickPopup::setOpacity(qreal opacity)
2515{
2516 Q_D(QQuickPopup);
2517 d->popupItem->setOpacity(opacity);
2518}
2519
2520/*!
2521 \qmlproperty real QtQuick.Controls::Popup::scale
2522
2523 This property holds the scale factor of the popup. The default value is \c 1.0.
2524
2525 A scale of less than \c 1.0 causes the popup to be rendered at a smaller size,
2526 and a scale greater than \c 1.0 renders the popup at a larger size. Negative
2527 scales are not supported.
2528*/
2529qreal QQuickPopup::scale() const
2530{
2531 Q_D(const QQuickPopup);
2532 return d->popupItem->scale();
2533}
2534
2535void QQuickPopup::setScale(qreal scale)
2536{
2537 Q_D(QQuickPopup);
2538 if (qFuzzyCompare(p1: scale, p2: d->popupItem->scale()))
2539 return;
2540 d->popupItem->setScale(scale);
2541 emit scaleChanged();
2542}
2543
2544/*!
2545 \qmlproperty enumeration QtQuick.Controls::Popup::closePolicy
2546
2547 This property determines the circumstances under which the popup closes.
2548 The flags can be combined to allow several ways of closing the popup.
2549
2550 The available values are:
2551 \value Popup.NoAutoClose The popup will only close when manually instructed to do so.
2552 \value Popup.CloseOnPressOutside The popup will close when the mouse is pressed outside of it.
2553 \value Popup.CloseOnPressOutsideParent The popup will close when the mouse is pressed outside of its parent.
2554 \value Popup.CloseOnReleaseOutside The popup will close when the mouse is released outside of it.
2555 \value Popup.CloseOnReleaseOutsideParent The popup will close when the mouse is released outside of its parent.
2556 \value Popup.CloseOnEscape The popup will close when the escape key is pressed while the popup
2557 has active focus.
2558
2559 The \c {CloseOnPress*} and \c {CloseOnRelease*} policies only apply for events
2560 outside of popups. That is, if there are two popups open and the first has
2561 \c Popup.CloseOnPressOutside as its policy, clicking on the second popup will
2562 not result in the first closing.
2563
2564 The default value is \c {Popup.CloseOnEscape | Popup.CloseOnPressOutside}.
2565
2566 \note There is a known limitation that the \c Popup.CloseOnReleaseOutside
2567 and \c Popup.CloseOnReleaseOutsideParent policies only work with
2568 \l modal popups.
2569*/
2570QQuickPopup::ClosePolicy QQuickPopup::closePolicy() const
2571{
2572 Q_D(const QQuickPopup);
2573 return d->closePolicy;
2574}
2575
2576void QQuickPopup::setClosePolicy(ClosePolicy policy)
2577{
2578 Q_D(QQuickPopup);
2579 d->hasClosePolicy = true;
2580 if (d->closePolicy == policy)
2581 return;
2582 d->closePolicy = policy;
2583 emit closePolicyChanged();
2584}
2585
2586void QQuickPopup::resetClosePolicy()
2587{
2588 Q_D(QQuickPopup);
2589 setClosePolicy(QQuickPopupPrivate::DefaultClosePolicy);
2590 d->hasClosePolicy = false;
2591}
2592
2593/*!
2594 \qmlproperty enumeration QtQuick.Controls::Popup::transformOrigin
2595
2596 This property holds the origin point for transformations in enter and exit transitions.
2597
2598 Nine transform origins are available, as shown in the image below.
2599 The default transform origin is \c Popup.Center.
2600
2601 \image qtquickcontrols-popup-transformorigin.png
2602
2603 \sa enter, exit, Item::transformOrigin
2604*/
2605QQuickPopup::TransformOrigin QQuickPopup::transformOrigin() const
2606{
2607 Q_D(const QQuickPopup);
2608 return static_cast<TransformOrigin>(d->popupItem->transformOrigin());
2609}
2610
2611void QQuickPopup::setTransformOrigin(TransformOrigin origin)
2612{
2613 Q_D(QQuickPopup);
2614 d->popupItem->setTransformOrigin(static_cast<QQuickItem::TransformOrigin>(origin));
2615}
2616
2617/*!
2618 \qmlproperty Transition QtQuick.Controls::Popup::enter
2619
2620 This property holds the transition that is applied to the popup item
2621 when the popup is opened and enters the screen.
2622
2623 The following example animates the opacity of the popup when it enters
2624 the screen:
2625 \code
2626 Popup {
2627 enter: Transition {
2628 NumberAnimation { property: "opacity"; from: 0.0; to: 1.0 }
2629 }
2630 }
2631 \endcode
2632
2633 \sa exit
2634*/
2635QQuickTransition *QQuickPopup::enter() const
2636{
2637 Q_D(const QQuickPopup);
2638 return d->enter;
2639}
2640
2641void QQuickPopup::setEnter(QQuickTransition *transition)
2642{
2643 Q_D(QQuickPopup);
2644 if (d->enter == transition)
2645 return;
2646 d->enter = transition;
2647 emit enterChanged();
2648}
2649
2650/*!
2651 \qmlproperty Transition QtQuick.Controls::Popup::exit
2652
2653 This property holds the transition that is applied to the popup item
2654 when the popup is closed and exits the screen.
2655
2656 The following example animates the opacity of the popup when it exits
2657 the screen:
2658 \code
2659 Popup {
2660 exit: Transition {
2661 NumberAnimation { property: "opacity"; from: 1.0; to: 0.0 }
2662 }
2663 }
2664 \endcode
2665
2666 \sa enter
2667*/
2668QQuickTransition *QQuickPopup::exit() const
2669{
2670 Q_D(const QQuickPopup);
2671 return d->exit;
2672}
2673
2674void QQuickPopup::setExit(QQuickTransition *transition)
2675{
2676 Q_D(QQuickPopup);
2677 if (d->exit == transition)
2678 return;
2679 d->exit = transition;
2680 emit exitChanged();
2681}
2682
2683/*!
2684 \since QtQuick.Controls 2.5 (Qt 5.12)
2685 \qmlproperty real QtQuick.Controls::Popup::horizontalPadding
2686
2687 This property holds the horizontal padding. Unless explicitly set, the value
2688 is equal to \c padding.
2689
2690 \include qquickpopup-padding.qdocinc
2691
2692 \sa padding, leftPadding, rightPadding, verticalPadding
2693*/
2694qreal QQuickPopup::horizontalPadding() const
2695{
2696 Q_D(const QQuickPopup);
2697 return d->popupItem->horizontalPadding();
2698}
2699
2700void QQuickPopup::setHorizontalPadding(qreal padding)
2701{
2702 Q_D(QQuickPopup);
2703 d->popupItem->setHorizontalPadding(padding);
2704}
2705
2706void QQuickPopup::resetHorizontalPadding()
2707{
2708 Q_D(QQuickPopup);
2709 d->popupItem->resetHorizontalPadding();
2710}
2711
2712/*!
2713 \since QtQuick.Controls 2.5 (Qt 5.12)
2714 \qmlproperty real QtQuick.Controls::Popup::verticalPadding
2715
2716 This property holds the vertical padding. Unless explicitly set, the value
2717 is equal to \c padding.
2718
2719 \include qquickpopup-padding.qdocinc
2720
2721 \sa padding, topPadding, bottomPadding, horizontalPadding
2722*/
2723qreal QQuickPopup::verticalPadding() const
2724{
2725 Q_D(const QQuickPopup);
2726 return d->popupItem->verticalPadding();
2727}
2728
2729void QQuickPopup::setVerticalPadding(qreal padding)
2730{
2731 Q_D(QQuickPopup);
2732 d->popupItem->setVerticalPadding(padding);
2733}
2734
2735void QQuickPopup::resetVerticalPadding()
2736{
2737 Q_D(QQuickPopup);
2738 d->popupItem->resetVerticalPadding();
2739}
2740
2741/*!
2742 \since QtQuick.Controls 2.5 (Qt 5.12)
2743 \qmlproperty real QtQuick.Controls::Popup::implicitContentWidth
2744 \readonly
2745
2746 This property holds the implicit content width.
2747
2748 The value is calculated based on the content children.
2749
2750 \sa implicitContentHeight, implicitBackgroundWidth
2751*/
2752qreal QQuickPopup::implicitContentWidth() const
2753{
2754 Q_D(const QQuickPopup);
2755 return d->popupItem->implicitContentWidth();
2756}
2757
2758/*!
2759 \since QtQuick.Controls 2.5 (Qt 5.12)
2760 \qmlproperty real QtQuick.Controls::Popup::implicitContentHeight
2761 \readonly
2762
2763 This property holds the implicit content height.
2764
2765 The value is calculated based on the content children.
2766
2767 \sa implicitContentWidth, implicitBackgroundHeight
2768*/
2769qreal QQuickPopup::implicitContentHeight() const
2770{
2771 Q_D(const QQuickPopup);
2772 return d->popupItem->implicitContentHeight();
2773}
2774
2775/*!
2776 \since QtQuick.Controls 2.5 (Qt 5.12)
2777 \qmlproperty real QtQuick.Controls::Popup::implicitBackgroundWidth
2778 \readonly
2779
2780 This property holds the implicit background width.
2781
2782 The value is equal to \c {background ? background.implicitWidth : 0}.
2783
2784 \sa implicitBackgroundHeight, implicitContentWidth
2785*/
2786qreal QQuickPopup::implicitBackgroundWidth() const
2787{
2788 Q_D(const QQuickPopup);
2789 return d->popupItem->implicitBackgroundWidth();
2790}
2791
2792/*!
2793 \since QtQuick.Controls 2.5 (Qt 5.12)
2794 \qmlproperty real QtQuick.Controls::Popup::implicitBackgroundHeight
2795 \readonly
2796
2797 This property holds the implicit background height.
2798
2799 The value is equal to \c {background ? background.implicitHeight : 0}.
2800
2801 \sa implicitBackgroundWidth, implicitContentHeight
2802*/
2803qreal QQuickPopup::implicitBackgroundHeight() const
2804{
2805 Q_D(const QQuickPopup);
2806 return d->popupItem->implicitBackgroundHeight();
2807}
2808
2809/*!
2810 \since QtQuick.Controls 2.5 (Qt 5.12)
2811 \qmlproperty real QtQuick.Controls::Popup::topInset
2812
2813 This property holds the top inset for the background.
2814
2815 \sa {Popup Layout}, bottomInset
2816*/
2817qreal QQuickPopup::topInset() const
2818{
2819 Q_D(const QQuickPopup);
2820 return d->popupItem->topInset();
2821}
2822
2823void QQuickPopup::setTopInset(qreal inset)
2824{
2825 Q_D(QQuickPopup);
2826 d->popupItem->setTopInset(inset);
2827}
2828
2829void QQuickPopup::resetTopInset()
2830{
2831 Q_D(QQuickPopup);
2832 d->popupItem->resetTopInset();
2833}
2834
2835/*!
2836 \since QtQuick.Controls 2.5 (Qt 5.12)
2837 \qmlproperty real QtQuick.Controls::Popup::leftInset
2838
2839 This property holds the left inset for the background.
2840
2841 \sa {Popup Layout}, rightInset
2842*/
2843qreal QQuickPopup::leftInset() const
2844{
2845 Q_D(const QQuickPopup);
2846 return d->popupItem->leftInset();
2847}
2848
2849void QQuickPopup::setLeftInset(qreal inset)
2850{
2851 Q_D(QQuickPopup);
2852 d->popupItem->setLeftInset(inset);
2853}
2854
2855void QQuickPopup::resetLeftInset()
2856{
2857 Q_D(QQuickPopup);
2858 d->popupItem->resetLeftInset();
2859}
2860
2861/*!
2862 \since QtQuick.Controls 2.5 (Qt 5.12)
2863 \qmlproperty real QtQuick.Controls::Popup::rightInset
2864
2865 This property holds the right inset for the background.
2866
2867 \sa {Popup Layout}, leftInset
2868*/
2869qreal QQuickPopup::rightInset() const
2870{
2871 Q_D(const QQuickPopup);
2872 return d->popupItem->rightInset();
2873}
2874
2875void QQuickPopup::setRightInset(qreal inset)
2876{
2877 Q_D(QQuickPopup);
2878 d->popupItem->setRightInset(inset);
2879}
2880
2881void QQuickPopup::resetRightInset()
2882{
2883 Q_D(QQuickPopup);
2884 d->popupItem->resetRightInset();
2885}
2886
2887/*!
2888 \since QtQuick.Controls 2.5 (Qt 5.12)
2889 \qmlproperty real QtQuick.Controls::Popup::bottomInset
2890
2891 This property holds the bottom inset for the background.
2892
2893 \sa {Popup Layout}, topInset
2894*/
2895qreal QQuickPopup::bottomInset() const
2896{
2897 Q_D(const QQuickPopup);
2898 return d->popupItem->bottomInset();
2899}
2900
2901void QQuickPopup::setBottomInset(qreal inset)
2902{
2903 Q_D(QQuickPopup);
2904 d->popupItem->setBottomInset(inset);
2905}
2906
2907void QQuickPopup::resetBottomInset()
2908{
2909 Q_D(QQuickPopup);
2910 d->popupItem->resetBottomInset();
2911}
2912
2913
2914/*!
2915 \qmlproperty enumeration QtQuick.Controls::Popup::popupType
2916 \since 6.8
2917
2918 This property determines the type of popup that is preferred.
2919
2920 Available options:
2921 \value Item The popup will be embedded into the
2922 \l{Showing a popup as an item}{same scene as the parent},
2923 without the use of a separate window.
2924 \value Window The popup will be presented in a \l {Popup type}
2925 {separate window}. If the platform doesn't support
2926 multiple windows, \c Popup.Item will be used instead.
2927 \value Native The popup will be native to the platform. If the
2928 platform doesn't support native popups, \c Popup.Window
2929 will be used instead.
2930
2931 Whether a popup will be able to use the preferred type depends on the platform.
2932 \c Popup.Item is supported on all platforms, but \c Popup.Window and \c Popup.Native
2933 are normally only supported on desktop platforms. Additionally, if a popup is a
2934 \l Menu inside a \l {Native menu bars}{native menubar}, the menu will be native as
2935 well. And if the menu is a sub-menu inside another menu, the parent (or root) menu
2936 will decide the type.
2937
2938 The default value is usually \c Popup.Item, with some exceptions, mentioned above.
2939 This might change in future versions of Qt, for certain styles and platforms that benefit
2940 from using other popup types.
2941 If you always want to use native menus for all styles on macOS, for example, you can do:
2942
2943 \code
2944 Menu {
2945 popupType: Qt.platform.os === "osx" ? Popup.Native : Popup.Window
2946 }
2947 \endcode
2948
2949 Also, if you choose to customize a popup (by for example changing any of the
2950 delegates), you should consider setting the popup type to be \c Popup.Window
2951 as well. This will ensure that your changes will be visible on all platforms
2952 and for all styles. Otherwise, when native menus are being used, the delegates
2953 will \e not be used for rendering.
2954
2955 \sa {Popup type}
2956*/
2957QQuickPopup::PopupType QQuickPopup::popupType() const
2958{
2959 Q_D(const QQuickPopup);
2960 return d->m_popupType;
2961}
2962
2963void QQuickPopup::setPopupType(PopupType popupType)
2964{
2965 Q_D(QQuickPopup);
2966 if (d->m_popupType == popupType)
2967 return;
2968
2969 d->m_popupType = popupType;
2970
2971 emit popupTypeChanged();
2972}
2973
2974/*!
2975 \since QtQuick.Controls 2.3 (Qt 5.10)
2976 \qmlproperty palette QtQuick.Controls::Popup::palette
2977
2978 This property holds the palette currently set for the popup.
2979
2980 Popup propagates explicit palette properties to its children. If you change a specific
2981 property on a popup's palette, that property propagates to all of the popup's children,
2982 overriding any system defaults for that property.
2983
2984 \code
2985 Popup {
2986 palette.text: "red"
2987
2988 Column {
2989 Label {
2990 text: qsTr("This will use red color...")
2991 }
2992
2993 Switch {
2994 text: qsTr("... and so will this")
2995 }
2996 }
2997 }
2998 \endcode
2999
3000 \b {See also}: \l Item::palette, \l Window::palette, \l ColorGroup,
3001 \l [QML] {Palette}
3002*/
3003
3004bool QQuickPopup::filtersChildMouseEvents() const
3005{
3006 Q_D(const QQuickPopup);
3007 return d->popupItem->filtersChildMouseEvents();
3008}
3009
3010void QQuickPopup::setFiltersChildMouseEvents(bool filter)
3011{
3012 Q_D(QQuickPopup);
3013 d->popupItem->setFiltersChildMouseEvents(filter);
3014}
3015
3016/*!
3017 \qmlmethod QtQuick.Controls::Popup::forceActiveFocus(enumeration reason = Qt.OtherFocusReason)
3018
3019 Forces active focus on the popup with the given \a reason.
3020
3021 This method sets focus on the popup and ensures that all ancestor
3022 \l FocusScope objects in the object hierarchy are also given \l focus.
3023
3024 \sa activeFocus, Qt::FocusReason
3025*/
3026void QQuickPopup::forceActiveFocus(Qt::FocusReason reason)
3027{
3028 Q_D(QQuickPopup);
3029 d->popupItem->forceActiveFocus(reason);
3030}
3031
3032void QQuickPopup::classBegin()
3033{
3034 Q_D(QQuickPopup);
3035 d->complete = false;
3036 QQmlContext *context = qmlContext(this);
3037 if (context)
3038 QQmlEngine::setContextForObject(d->popupItem, context);
3039 d->popupItem->classBegin();
3040}
3041
3042void QQuickPopup::componentComplete()
3043{
3044 Q_D(QQuickPopup);
3045 qCDebug(lcQuickPopup) << "componentComplete" << this;
3046 if (!parentItem())
3047 resetParentItem();
3048
3049 if (d->visible && d->window)
3050 d->transitionManager.transitionEnter();
3051
3052 d->complete = true;
3053 d->popupItem->componentComplete();
3054
3055 if (auto currentContentItem = d->popupItem->d_func()->contentItem.data()) {
3056 connect(sender: currentContentItem, signal: &QQuickItem::childrenChanged,
3057 context: this, slot: &QQuickPopup::contentChildrenChanged);
3058 }
3059}
3060
3061bool QQuickPopup::isComponentComplete() const
3062{
3063 Q_D(const QQuickPopup);
3064 return d->complete;
3065}
3066
3067bool QQuickPopup::childMouseEventFilter(QQuickItem *child, QEvent *event)
3068{
3069 Q_UNUSED(child);
3070 Q_UNUSED(event);
3071 return false;
3072}
3073
3074void QQuickPopup::focusInEvent(QFocusEvent *event)
3075{
3076 event->accept();
3077}
3078
3079void QQuickPopup::focusOutEvent(QFocusEvent *event)
3080{
3081 event->accept();
3082}
3083
3084void QQuickPopup::keyPressEvent(QKeyEvent *event)
3085{
3086 Q_D(QQuickPopup);
3087 if (!hasActiveFocus())
3088 return;
3089
3090#if QT_CONFIG(shortcut)
3091 if (d->closePolicy.testFlag(flag: QQuickPopup::CloseOnEscape)
3092 && (event->matches(key: QKeySequence::Cancel)
3093#if defined(Q_OS_ANDROID)
3094 || event->key() == Qt::Key_Back
3095#endif
3096 )) {
3097 event->accept();
3098 if (d->interactive)
3099 d->closeOrReject();
3100 return;
3101 }
3102#endif
3103
3104 if (hasActiveFocus() && (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab)) {
3105 event->accept();
3106 QQuickItemPrivate::focusNextPrev(item: d->popupItem, forward: event->key() == Qt::Key_Tab);
3107 }
3108}
3109
3110void QQuickPopup::keyReleaseEvent(QKeyEvent *event)
3111{
3112 event->accept();
3113}
3114
3115void QQuickPopup::mousePressEvent(QMouseEvent *event)
3116{
3117 Q_D(QQuickPopup);
3118 event->setAccepted(d->handleMouseEvent(item: d->popupItem, event));
3119}
3120
3121void QQuickPopup::mouseMoveEvent(QMouseEvent *event)
3122{
3123 Q_D(QQuickPopup);
3124 event->setAccepted(d->handleMouseEvent(item: d->popupItem, event));
3125}
3126
3127void QQuickPopup::mouseReleaseEvent(QMouseEvent *event)
3128{
3129 Q_D(QQuickPopup);
3130 event->setAccepted(d->handleMouseEvent(item: d->popupItem, event));
3131}
3132
3133void QQuickPopup::mouseDoubleClickEvent(QMouseEvent *event)
3134{
3135 event->accept();
3136}
3137
3138void QQuickPopup::mouseUngrabEvent()
3139{
3140 Q_D(QQuickPopup);
3141 d->handleUngrab();
3142}
3143
3144/*!
3145 \internal
3146
3147 Called whenever the window receives a Wheel/Hover/Mouse/Touch event,
3148 and has an active popup (with popupType: Popup.Item) in its scene.
3149
3150 The purpose is to close popups when the press/release event happened outside of it,
3151 and the closePolicy allows for it to happen.
3152
3153 If the function is called from childMouseEventFilter, then the return value of this
3154 function will determine whether the event will be filtered, or delivered to \a item.
3155*/
3156bool QQuickPopup::overlayEvent(QQuickItem *item, QEvent *event)
3157{
3158 Q_D(QQuickPopup);
3159 switch (event->type()) {
3160 case QEvent::KeyPress:
3161 case QEvent::KeyRelease:
3162 case QEvent::MouseMove:
3163 case QEvent::Wheel:
3164 if (d->modal)
3165 event->accept();
3166 return d->modal;
3167
3168#if QT_CONFIG(quicktemplates2_multitouch)
3169 case QEvent::TouchBegin:
3170 case QEvent::TouchUpdate:
3171 case QEvent::TouchEnd:
3172 return d->handleTouchEvent(item, event: static_cast<QTouchEvent *>(event));
3173#endif
3174 case QEvent::HoverEnter:
3175 case QEvent::HoverMove:
3176 case QEvent::HoverLeave:
3177 return d->handleHoverEvent(item, event: static_cast<QHoverEvent *>(event));
3178
3179 case QEvent::MouseButtonPress:
3180 case QEvent::MouseButtonRelease:
3181 return d->handleMouseEvent(item, event: static_cast<QMouseEvent *>(event));
3182
3183 default:
3184 return false;
3185 }
3186}
3187
3188#if QT_CONFIG(quicktemplates2_multitouch)
3189void QQuickPopup::touchEvent(QTouchEvent *event)
3190{
3191 Q_D(QQuickPopup);
3192 d->handleTouchEvent(item: d->popupItem, event);
3193}
3194
3195void QQuickPopup::touchUngrabEvent()
3196{
3197 Q_D(QQuickPopup);
3198 d->handleUngrab();
3199}
3200#endif
3201
3202#if QT_CONFIG(wheelevent)
3203void QQuickPopup::wheelEvent(QWheelEvent *event)
3204{
3205 event->accept();
3206}
3207#endif
3208
3209void QQuickPopup::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
3210{
3211 Q_UNUSED(newItem);
3212 Q_UNUSED(oldItem);
3213}
3214
3215void QQuickPopup::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
3216{
3217 qCDebug(lcQuickPopup) << "contentSizeChange called on" << this << "with newSize" << newSize << "oldSize" << oldSize;
3218 if (!qFuzzyCompare(p1: newSize.width(), p2: oldSize.width()))
3219 emit contentWidthChanged();
3220 if (!qFuzzyCompare(p1: newSize.height(), p2: oldSize.height()))
3221 emit contentHeightChanged();
3222}
3223
3224void QQuickPopup::fontChange(const QFont &newFont, const QFont &oldFont)
3225{
3226 Q_UNUSED(newFont);
3227 Q_UNUSED(oldFont);
3228 emit fontChanged();
3229}
3230
3231void QQuickPopup::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
3232{
3233 Q_D(QQuickPopup);
3234 qCDebug(lcQuickPopup) << "geometryChange called on" << this << "with newGeometry" << newGeometry << "oldGeometry" << oldGeometry;
3235 d->reposition();
3236 if (!qFuzzyCompare(p1: newGeometry.width(), p2: oldGeometry.width())) {
3237 emit widthChanged();
3238 emit availableWidthChanged();
3239 }
3240 if (!qFuzzyCompare(p1: newGeometry.height(), p2: oldGeometry.height())) {
3241 emit heightChanged();
3242 emit availableHeightChanged();
3243 }
3244}
3245
3246void QQuickPopup::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &)
3247{
3248 switch (change) {
3249 case QQuickItem::ItemActiveFocusHasChanged:
3250 emit activeFocusChanged();
3251 break;
3252 case QQuickItem::ItemOpacityHasChanged:
3253 emit opacityChanged();
3254 break;
3255 default:
3256 break;
3257 }
3258}
3259
3260void QQuickPopup::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
3261{
3262 Q_UNUSED(newLocale);
3263 Q_UNUSED(oldLocale);
3264 emit localeChanged();
3265}
3266
3267void QQuickPopup::marginsChange(const QMarginsF &newMargins, const QMarginsF &oldMargins)
3268{
3269 Q_D(QQuickPopup);
3270 Q_UNUSED(newMargins);
3271 Q_UNUSED(oldMargins);
3272 d->reposition();
3273}
3274
3275void QQuickPopup::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
3276{
3277 const bool tp = !qFuzzyCompare(p1: newPadding.top(), p2: oldPadding.top());
3278 const bool lp = !qFuzzyCompare(p1: newPadding.left(), p2: oldPadding.left());
3279 const bool rp = !qFuzzyCompare(p1: newPadding.right(), p2: oldPadding.right());
3280 const bool bp = !qFuzzyCompare(p1: newPadding.bottom(), p2: oldPadding.bottom());
3281
3282 if (tp)
3283 emit topPaddingChanged();
3284 if (lp)
3285 emit leftPaddingChanged();
3286 if (rp)
3287 emit rightPaddingChanged();
3288 if (bp)
3289 emit bottomPaddingChanged();
3290
3291 if (lp || rp) {
3292 emit horizontalPaddingChanged();
3293 emit availableWidthChanged();
3294 }
3295 if (tp || bp) {
3296 emit verticalPaddingChanged();
3297 emit availableHeightChanged();
3298 }
3299}
3300
3301void QQuickPopup::spacingChange(qreal newSpacing, qreal oldSpacing)
3302{
3303 Q_UNUSED(newSpacing);
3304 Q_UNUSED(oldSpacing);
3305 emit spacingChanged();
3306}
3307
3308void QQuickPopup::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset)
3309{
3310 if (!qFuzzyCompare(p1: newInset.top(), p2: oldInset.top()))
3311 emit topInsetChanged();
3312 if (!qFuzzyCompare(p1: newInset.left(), p2: oldInset.left()))
3313 emit leftInsetChanged();
3314 if (!qFuzzyCompare(p1: newInset.right(), p2: oldInset.right()))
3315 emit rightInsetChanged();
3316 if (!qFuzzyCompare(p1: newInset.bottom(), p2: oldInset.bottom()))
3317 emit bottomInsetChanged();
3318}
3319
3320QFont QQuickPopup::defaultFont() const
3321{
3322 return QQuickTheme::font(scope: QQuickTheme::System);
3323}
3324
3325#if QT_CONFIG(accessibility)
3326QAccessible::Role QQuickPopup::effectiveAccessibleRole() const
3327{
3328 auto *attached = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj: this, create: false);
3329
3330 auto role = QAccessible::NoRole;
3331 if (auto *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(object: attached))
3332 role = accessibleAttached->role();
3333 if (role == QAccessible::NoRole)
3334 role = accessibleRole();
3335
3336 return role;
3337}
3338
3339QAccessible::Role QQuickPopup::accessibleRole() const
3340{
3341 return QAccessible::Dialog;
3342}
3343
3344void QQuickPopup::accessibilityActiveChanged(bool active)
3345{
3346 Q_UNUSED(active);
3347}
3348#endif
3349
3350QString QQuickPopup::accessibleName() const
3351{
3352 Q_D(const QQuickPopup);
3353 return d->popupItem->accessibleName();
3354}
3355
3356void QQuickPopup::maybeSetAccessibleName(const QString &name)
3357{
3358 Q_D(QQuickPopup);
3359 d->popupItem->maybeSetAccessibleName(name);
3360}
3361
3362QVariant QQuickPopup::accessibleProperty(const char *propertyName)
3363{
3364 Q_D(const QQuickPopup);
3365 return d->popupItem->accessibleProperty(propertyName);
3366}
3367
3368bool QQuickPopup::setAccessibleProperty(const char *propertyName, const QVariant &value)
3369{
3370 Q_D(QQuickPopup);
3371 return d->popupItem->setAccessibleProperty(propertyName, value);
3372}
3373
3374QT_END_NAMESPACE
3375
3376#include "moc_qquickpopup_p.cpp"
3377

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/quicktemplates/qquickpopup.cpp