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 if (popupWindow)
1109 popupWindow->setVisible(visible);
1110 } else {
1111 if (visible) {
1112 popupItem->setParentItem(overlay);
1113 const auto popupStack = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
1114 // if there is a stack of popups, and the current top popup item belongs to an
1115 // ancestor of this popup, then make sure that this popup's item is at the top
1116 // of the stack.
1117 const QQuickPopup *topPopup = popupStack.isEmpty() ? nullptr : popupStack.first();
1118 const QObject *ancestor = q;
1119 while (ancestor && topPopup) {
1120 if (ancestor == topPopup)
1121 break;
1122 ancestor = ancestor->parent();
1123 }
1124 if (topPopup && topPopup != q && ancestor) {
1125 QQuickItem *topPopupItem = popupStack.first()->popupItem();
1126 popupItem->stackAfter(topPopupItem);
1127 // If the popup doesn't have an explicit z value set, set it to be at least as
1128 // high as the current top popup item so that later opened popups are on top.
1129 if (!hasZ)
1130 popupItem->setZ(qMax(a: topPopupItem->z(), b: popupItem->z()));
1131 }
1132 }
1133
1134 popupItem->setTitle(m_title);
1135 }
1136 popupItem->setVisible(visible);
1137}
1138
1139QQuickItem *QQuickPopupPrivate::createDimmer(QQmlComponent *component, QQuickPopup *popup, QQuickItem *parent) const
1140{
1141 QQuickItem *item = nullptr;
1142 if (component) {
1143 QQmlContext *context = component->creationContext();
1144 if (!context)
1145 context = qmlContext(popup);
1146 item = qobject_cast<QQuickItem*>(o: component->beginCreate(context));
1147 }
1148
1149 // when there is no overlay component available (with plain QQuickWindow),
1150 // use a plain QQuickItem as a fallback to block hover events
1151 if (!item && popup->isModal())
1152 item = new QQuickItem;
1153
1154 if (item) {
1155 item->setParentItem(parent);
1156 if (resolvedPopupType() != QQuickPopup::PopupType::Window)
1157 item->stackBefore(popup->popupItem());
1158 item->setZ(popup->z());
1159 // needed for the virtual keyboard to set a containment mask on the dimmer item
1160 qCDebug(lcDimmer) << "dimmer" << item << "registered with" << parent;
1161 parent->setProperty(name: "_q_dimmerItem", value: QVariant::fromValue<QQuickItem*>(value: item));
1162 if (popup->isModal()) {
1163 item->setAcceptedMouseButtons(Qt::AllButtons);
1164#if QT_CONFIG(cursor)
1165 item->setCursor(Qt::ArrowCursor);
1166#endif
1167#if QT_CONFIG(quicktemplates2_hover)
1168 // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8
1169 item->setAcceptHoverEvents(true);
1170 // item->setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects());
1171 // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, item, &QQuickItem::setAcceptHoverEvents);
1172#endif
1173 }
1174 if (component)
1175 component->completeCreate();
1176 }
1177 qCDebug(lcDimmer) << "finished creating dimmer from component" << component
1178 << "for popup" << popup << "with parent" << parent << "- item is:" << item;
1179 return item;
1180}
1181
1182void QQuickPopupPrivate::createOverlay()
1183{
1184 Q_Q(QQuickPopup);
1185 QQuickOverlay *overlay = QQuickOverlay::overlay(window);
1186 if (!overlay)
1187 return;
1188
1189 QQmlComponent *component = nullptr;
1190 QQuickOverlayAttached *overlayAttached = qobject_cast<QQuickOverlayAttached *>(object: qmlAttachedPropertiesObject<QQuickOverlay>(obj: q, create: false));
1191 if (overlayAttached)
1192 component = modal ? overlayAttached->modal() : overlayAttached->modeless();
1193
1194 if (!component)
1195 component = modal ? overlay->modal() : overlay->modeless();
1196
1197 if (!dimmer) {
1198 dimmer = createDimmer(component, popup: q, parent: overlay);
1199 if (!dimmer)
1200 return;
1201 // We cannot update explicitDimmerOpacity when dimmer's opacity changes,
1202 // as it is expected to do so when we fade the dimmer in and out in
1203 // show/hideDimmer, and any binding of the dimmer's opacity will be
1204 // implicitly broken anyway.
1205 explicitDimmerOpacity = dimmer->opacity();
1206 // initially fully transparent, showDimmer fades the dimmer in.
1207 dimmer->setOpacity(0);
1208 if (q->isVisible())
1209 showDimmer();
1210 }
1211 resizeDimmer();
1212}
1213
1214void QQuickPopupPrivate::destroyDimmer()
1215{
1216 if (dimmer) {
1217 qCDebug(lcDimmer) << "destroying dimmer" << dimmer;
1218 if (QObject *dimmerParentItem = dimmer->parentItem()) {
1219 if (dimmerParentItem->property(name: "_q_dimmerItem").value<QQuickItem*>() == dimmer)
1220 dimmerParentItem->setProperty(name: "_q_dimmerItem", value: QVariant());
1221 }
1222 dimmer->setParentItem(nullptr);
1223 dimmer->deleteLater();
1224 dimmer = nullptr;
1225 }
1226}
1227
1228void QQuickPopupPrivate::toggleOverlay()
1229{
1230 destroyDimmer();
1231 if (dim)
1232 createOverlay();
1233}
1234
1235void QQuickPopupPrivate::updateContentPalettes(const QPalette& parentPalette)
1236{
1237 // Inherit parent palette to all child objects
1238 if (providesPalette())
1239 inheritPalette(parentPalette);
1240 // Inherit parent palette to items within popup (such as headers and footers)
1241 QQuickItemPrivate::get(item: popupItem)->updateChildrenPalettes(parentPalette);
1242}
1243
1244void QQuickPopupPrivate::updateChildrenPalettes(const QPalette& parentPalette)
1245{
1246 updateContentPalettes(parentPalette);
1247}
1248
1249void QQuickPopupPrivate::showDimmer()
1250{
1251 // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors
1252 if (dim && dimmer)
1253 QQmlProperty::write(dimmer, QStringLiteral("opacity"), explicitDimmerOpacity);
1254}
1255
1256void QQuickPopupPrivate::hideDimmer()
1257{
1258 // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors
1259 if (dim && dimmer)
1260 QQmlProperty::write(dimmer, QStringLiteral("opacity"), 0.0);
1261}
1262
1263void QQuickPopupPrivate::resizeDimmer()
1264{
1265 if (!dimmer)
1266 return;
1267
1268 const QQuickOverlay *overlay = QQuickOverlay::overlay(window);
1269
1270 qreal w = overlay ? overlay->width() : 0;
1271 qreal h = overlay ? overlay->height() : 0;
1272 dimmer->setSize(QSizeF(w, h));
1273}
1274
1275QQuickPopupTransitionManager::QQuickPopupTransitionManager(QQuickPopupPrivate *popup)
1276 : popup(popup)
1277{
1278}
1279
1280void QQuickPopupTransitionManager::transitionEnter()
1281{
1282 if (popup->transitionState == QQuickPopupPrivate::ExitTransition)
1283 cancel();
1284
1285 if (!popup->prepareEnterTransition())
1286 return;
1287
1288 if (popup->window)
1289 transition(popup->enterActions, transition: popup->enter, defaultTarget: popup->q_func());
1290 else
1291 finished();
1292}
1293
1294void QQuickPopupTransitionManager::transitionExit()
1295{
1296 if (!popup->prepareExitTransition())
1297 return;
1298
1299 if (popup->window)
1300 transition(popup->exitActions, transition: popup->exit, defaultTarget: popup->q_func());
1301 else
1302 finished();
1303}
1304
1305void QQuickPopupTransitionManager::finished()
1306{
1307 if (popup->transitionState == QQuickPopupPrivate::EnterTransition)
1308 popup->finalizeEnterTransition();
1309 else if (popup->transitionState == QQuickPopupPrivate::ExitTransition)
1310 popup->finalizeExitTransition();
1311}
1312
1313QQuickPopup::QQuickPopup(QObject *parent)
1314 : QObject(*(new QQuickPopupPrivate), parent)
1315{
1316 Q_D(QQuickPopup);
1317 d->init();
1318 // By default, allow popup to move beyond window edges
1319 d->relaxEdgeConstraint = true;
1320}
1321
1322QQuickPopup::QQuickPopup(QQuickPopupPrivate &dd, QObject *parent)
1323 : QObject(dd, parent)
1324{
1325 Q_D(QQuickPopup);
1326 d->init();
1327}
1328
1329QQuickPopup::~QQuickPopup()
1330{
1331 Q_D(QQuickPopup);
1332 d->inDestructor = true;
1333
1334 QQuickItem *currentContentItem = d->popupItem->d_func()->contentItem.data();
1335 if (currentContentItem) {
1336 disconnect(sender: currentContentItem, signal: &QQuickItem::childrenChanged,
1337 receiver: this, slot: &QQuickPopup::contentChildrenChanged);
1338 }
1339
1340 setParentItem(nullptr);
1341
1342 // If the popup is destroyed before the exit transition finishes,
1343 // the necessary cleanup (removing modal dimmers that block mouse events,
1344 // emitting closed signal, etc.) won't happen. That's why we do it manually here.
1345 if (d->transitionState == QQuickPopupPrivate::ExitTransition && d->transitionManager.isRunning())
1346 d->finalizeExitTransition();
1347
1348 delete d->popupItem;
1349 d->popupItem = nullptr;
1350 delete d->positioner;
1351 d->positioner = nullptr;
1352 if (d->popupWindow)
1353 delete d->popupWindow;
1354 d->popupWindow = nullptr;
1355}
1356
1357/*!
1358 \qmlmethod void QtQuick.Controls::Popup::open()
1359
1360 Opens the popup.
1361
1362 \sa visible
1363*/
1364void QQuickPopup::open()
1365{
1366 setVisible(true);
1367}
1368
1369/*!
1370 \qmlmethod void QtQuick.Controls::Popup::close()
1371
1372 Closes the popup.
1373
1374 \sa visible
1375*/
1376void QQuickPopup::close()
1377{
1378 setVisible(false);
1379}
1380
1381/*!
1382 \qmlproperty real QtQuick.Controls::Popup::x
1383
1384 This property holds the x-coordinate of the popup.
1385
1386 \sa y, z
1387*/
1388qreal QQuickPopup::x() const
1389{
1390 return d_func()->effectivePos.x();
1391}
1392
1393void QQuickPopup::setX(qreal x)
1394{
1395 Q_D(QQuickPopup);
1396 setPosition(QPointF(x, d->y));
1397}
1398
1399/*!
1400 \qmlproperty real QtQuick.Controls::Popup::y
1401
1402 This property holds the y-coordinate of the popup.
1403
1404 \sa x, z
1405*/
1406qreal QQuickPopup::y() const
1407{
1408 return d_func()->effectivePos.y();
1409}
1410
1411void QQuickPopup::setY(qreal y)
1412{
1413 Q_D(QQuickPopup);
1414 setPosition(QPointF(d->x, y));
1415}
1416
1417QPointF QQuickPopup::position() const
1418{
1419 return d_func()->effectivePos;
1420}
1421
1422void QQuickPopup::setPosition(const QPointF &pos)
1423{
1424 Q_D(QQuickPopup);
1425 const bool xChange = !qFuzzyCompare(p1: d->x, p2: pos.x());
1426 const bool yChange = !qFuzzyCompare(p1: d->y, p2: pos.y());
1427 if (!xChange && !yChange)
1428 return;
1429
1430 d->x = pos.x();
1431 d->y = pos.y();
1432 if (d->popupItem->isVisible()) {
1433 d->reposition();
1434 } else {
1435 if (xChange)
1436 emit xChanged();
1437 if (yChange)
1438 emit yChanged();
1439 }
1440}
1441
1442/*!
1443 \qmlproperty real QtQuick.Controls::Popup::z
1444
1445 This property holds the z-value of the popup. Z-value determines
1446 the stacking order of popups.
1447
1448 If two visible popups have the same z-value, the last one that
1449 was opened will be on top.
1450
1451 If a popup has no explicitly set z-value when opened, and is a child
1452 of an already open popup, then it will be stacked on top of its parent.
1453 This ensures that children are never hidden under their parents.
1454
1455 If the popup has its own window, the z-value will determine the window
1456 stacking order instead.
1457
1458 The default z-value is \c 0.
1459
1460 \sa x, y
1461*/
1462qreal QQuickPopup::z() const
1463{
1464 Q_D(const QQuickPopup);
1465 return d->popupItem->z();
1466}
1467
1468void QQuickPopup::setZ(qreal z)
1469{
1470 Q_D(QQuickPopup);
1471 d->hasZ = true;
1472 bool previousZ = d->popupWindow ? d->popupWindow->z() : d->popupItem->z();
1473 if (qFuzzyCompare(p1: z, p2: previousZ))
1474 return;
1475 if (d->popupWindow)
1476 d->popupWindow->setZ(z);
1477 else
1478 d->popupItem->setZ(z);
1479 emit zChanged();
1480}
1481
1482void QQuickPopup::resetZ()
1483{
1484 Q_D(QQuickPopup);
1485 setZ(0);
1486 d->hasZ = false;
1487}
1488
1489/*!
1490 \qmlproperty real QtQuick.Controls::Popup::width
1491
1492 This property holds the width of the popup.
1493*/
1494qreal QQuickPopup::width() const
1495{
1496 Q_D(const QQuickPopup);
1497 return d->popupItem->width();
1498}
1499
1500void QQuickPopup::setWidth(qreal width)
1501{
1502 Q_D(QQuickPopup);
1503 d->hasWidth = true;
1504
1505 // QQuickPopupWindow::setWidth() triggers a window resize event.
1506 // This will cause QQuickPopupWindow::resizeEvent() to resize
1507 // the popupItem. QQuickPopupItem::geometryChanged() calls QQuickPopup::geometryChange(),
1508 // which emits widthChanged().
1509
1510 if (d->popupWindow)
1511 d->popupWindow->setWidth(width + d->windowInsets().left() + d->windowInsets().right());
1512 else
1513 d->popupItem->setWidth(width);
1514}
1515
1516void QQuickPopup::resetWidth()
1517{
1518 Q_D(QQuickPopup);
1519 if (!d->hasWidth)
1520 return;
1521
1522 d->hasWidth = false;
1523 d->popupItem->resetWidth();
1524 if (d->popupItem->isVisible())
1525 d->reposition();
1526}
1527
1528/*!
1529 \qmlproperty real QtQuick.Controls::Popup::height
1530
1531 This property holds the height of the popup.
1532*/
1533qreal QQuickPopup::height() const
1534{
1535 Q_D(const QQuickPopup);
1536 return d->popupItem->height();
1537}
1538
1539void QQuickPopup::setHeight(qreal height)
1540{
1541 Q_D(QQuickPopup);
1542 d->hasHeight = true;
1543
1544 // QQuickPopupWindow::setHeight() triggers a window resize event.
1545 // This will cause QQuickPopupWindow::resizeEvent() to resize
1546 // the popupItem. QQuickPopupItem::geometryChanged() calls QQuickPopup::geometryChange(),
1547 // which emits heightChanged().
1548
1549 if (d->popupWindow)
1550 d->popupWindow->setHeight(height + d->windowInsets().top() + d->windowInsets().bottom());
1551 else
1552 d->popupItem->setHeight(height);
1553}
1554
1555void QQuickPopup::resetHeight()
1556{
1557 Q_D(QQuickPopup);
1558 if (!d->hasHeight)
1559 return;
1560
1561 d->hasHeight = false;
1562 d->popupItem->resetHeight();
1563 if (d->popupItem->isVisible())
1564 d->reposition();
1565}
1566
1567/*!
1568 \qmlproperty real QtQuick.Controls::Popup::implicitWidth
1569
1570 This property holds the implicit width of the popup.
1571*/
1572qreal QQuickPopup::implicitWidth() const
1573{
1574 Q_D(const QQuickPopup);
1575 return d->popupItem->implicitWidth();
1576}
1577
1578void QQuickPopup::setImplicitWidth(qreal width)
1579{
1580 Q_D(QQuickPopup);
1581 d->popupItem->setImplicitWidth(width);
1582}
1583
1584/*!
1585 \qmlproperty real QtQuick.Controls::Popup::implicitHeight
1586
1587 This property holds the implicit height of the popup.
1588*/
1589qreal QQuickPopup::implicitHeight() const
1590{
1591 Q_D(const QQuickPopup);
1592 return d->popupItem->implicitHeight();
1593}
1594
1595void QQuickPopup::setImplicitHeight(qreal height)
1596{
1597 Q_D(QQuickPopup);
1598 d->popupItem->setImplicitHeight(height);
1599}
1600
1601/*!
1602 \qmlproperty real QtQuick.Controls::Popup::contentWidth
1603
1604 This property holds the content width. It is used for calculating the
1605 total implicit width of the Popup.
1606
1607 For more information, see \l {Popup Sizing}.
1608
1609 \sa contentHeight
1610*/
1611qreal QQuickPopup::contentWidth() const
1612{
1613 Q_D(const QQuickPopup);
1614 return d->popupItem->contentWidth();
1615}
1616
1617void QQuickPopup::setContentWidth(qreal width)
1618{
1619 Q_D(QQuickPopup);
1620 d->popupItem->setContentWidth(width);
1621}
1622
1623/*!
1624 \qmlproperty real QtQuick.Controls::Popup::contentHeight
1625
1626 This property holds the content height. It is used for calculating the
1627 total implicit height of the Popup.
1628
1629 For more information, see \l {Popup Sizing}.
1630
1631 \sa contentWidth
1632*/
1633qreal QQuickPopup::contentHeight() const
1634{
1635 Q_D(const QQuickPopup);
1636 return d->popupItem->contentHeight();
1637}
1638
1639void QQuickPopup::setContentHeight(qreal height)
1640{
1641 Q_D(QQuickPopup);
1642 d->popupItem->setContentHeight(height);
1643}
1644
1645/*!
1646 \qmlproperty real QtQuick.Controls::Popup::availableWidth
1647 \readonly
1648
1649 This property holds the width available to the \l contentItem after
1650 deducting horizontal padding from the \l {Item::}{width} of the popup.
1651
1652 \sa padding, leftPadding, rightPadding
1653*/
1654qreal QQuickPopup::availableWidth() const
1655{
1656 Q_D(const QQuickPopup);
1657 return d->popupItem->availableWidth();
1658}
1659
1660/*!
1661 \qmlproperty real QtQuick.Controls::Popup::availableHeight
1662 \readonly
1663
1664 This property holds the height available to the \l contentItem after
1665 deducting vertical padding from the \l {Item::}{height} of the popup.
1666
1667 \sa padding, topPadding, bottomPadding
1668*/
1669qreal QQuickPopup::availableHeight() const
1670{
1671 Q_D(const QQuickPopup);
1672 return d->popupItem->availableHeight();
1673}
1674
1675/*!
1676 \since QtQuick.Controls 2.1 (Qt 5.8)
1677 \qmlproperty real QtQuick.Controls::Popup::spacing
1678
1679 This property holds the spacing.
1680
1681 Spacing is useful for popups that have multiple or repetitive building
1682 blocks. For example, some styles use spacing to determine the distance
1683 between the header, content, and footer of \l Dialog. Spacing is not
1684 enforced by Popup, so each style may interpret it differently, and some
1685 may ignore it altogether.
1686*/
1687qreal QQuickPopup::spacing() const
1688{
1689 Q_D(const QQuickPopup);
1690 return d->popupItem->spacing();
1691}
1692
1693void QQuickPopup::setSpacing(qreal spacing)
1694{
1695 Q_D(QQuickPopup);
1696 d->popupItem->setSpacing(spacing);
1697}
1698
1699void QQuickPopup::resetSpacing()
1700{
1701 setSpacing(0);
1702}
1703
1704/*!
1705 \qmlproperty real QtQuick.Controls::Popup::margins
1706
1707 This property holds the distance between the edges of the popup and the
1708 edges of its window.
1709
1710 A popup with negative margins is not pushed within the bounds
1711 of the enclosing window. The default value is \c -1.
1712
1713 \sa topMargin, leftMargin, rightMargin, bottomMargin, {Popup Layout}
1714*/
1715qreal QQuickPopup::margins() const
1716{
1717 Q_D(const QQuickPopup);
1718 return d->margins;
1719}
1720
1721void QQuickPopup::setMargins(qreal margins)
1722{
1723 Q_D(QQuickPopup);
1724 if (qFuzzyCompare(p1: d->margins, p2: margins))
1725 return;
1726 QMarginsF oldMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin());
1727 d->margins = margins;
1728 emit marginsChanged();
1729 QMarginsF newMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin());
1730 if (!qFuzzyCompare(p1: newMargins.top(), p2: oldMargins.top()))
1731 emit topMarginChanged();
1732 if (!qFuzzyCompare(p1: newMargins.left(), p2: oldMargins.left()))
1733 emit leftMarginChanged();
1734 if (!qFuzzyCompare(p1: newMargins.right(), p2: oldMargins.right()))
1735 emit rightMarginChanged();
1736 if (!qFuzzyCompare(p1: newMargins.bottom(), p2: oldMargins.bottom()))
1737 emit bottomMarginChanged();
1738 marginsChange(newMargins, oldMargins);
1739}
1740
1741void QQuickPopup::resetMargins()
1742{
1743 setMargins(-1);
1744}
1745
1746/*!
1747 \qmlproperty real QtQuick.Controls::Popup::topMargin
1748
1749 This property holds the distance between the top edge of the popup and
1750 the top edge of its window.
1751
1752 A popup with a negative top margin is not pushed within the top edge
1753 of the enclosing window. The default value is \c -1.
1754
1755 \sa margins, bottomMargin, {Popup Layout}
1756*/
1757qreal QQuickPopup::topMargin() const
1758{
1759 Q_D(const QQuickPopup);
1760 if (d->hasTopMargin)
1761 return d->topMargin;
1762 return d->margins;
1763}
1764
1765void QQuickPopup::setTopMargin(qreal margin)
1766{
1767 Q_D(QQuickPopup);
1768 d->setTopMargin(value: margin);
1769}
1770
1771void QQuickPopup::resetTopMargin()
1772{
1773 Q_D(QQuickPopup);
1774 d->setTopMargin(value: -1, reset: true);
1775}
1776
1777/*!
1778 \qmlproperty real QtQuick.Controls::Popup::leftMargin
1779
1780 This property holds the distance between the left edge of the popup and
1781 the left edge of its window.
1782
1783 A popup with a negative left margin is not pushed within the left edge
1784 of the enclosing window. The default value is \c -1.
1785
1786 \sa margins, rightMargin, {Popup Layout}
1787*/
1788qreal QQuickPopup::leftMargin() const
1789{
1790 Q_D(const QQuickPopup);
1791 if (d->hasLeftMargin)
1792 return d->leftMargin;
1793 return d->margins;
1794}
1795
1796void QQuickPopup::setLeftMargin(qreal margin)
1797{
1798 Q_D(QQuickPopup);
1799 d->setLeftMargin(value: margin);
1800}
1801
1802void QQuickPopup::resetLeftMargin()
1803{
1804 Q_D(QQuickPopup);
1805 d->setLeftMargin(value: -1, reset: true);
1806}
1807
1808/*!
1809 \qmlproperty real QtQuick.Controls::Popup::rightMargin
1810
1811 This property holds the distance between the right edge of the popup and
1812 the right edge of its window.
1813
1814 A popup with a negative right margin is not pushed within the right edge
1815 of the enclosing window. The default value is \c -1.
1816
1817 \sa margins, leftMargin, {Popup Layout}
1818*/
1819qreal QQuickPopup::rightMargin() const
1820{
1821 Q_D(const QQuickPopup);
1822 if (d->hasRightMargin)
1823 return d->rightMargin;
1824 return d->margins;
1825}
1826
1827void QQuickPopup::setRightMargin(qreal margin)
1828{
1829 Q_D(QQuickPopup);
1830 d->setRightMargin(value: margin);
1831}
1832
1833void QQuickPopup::resetRightMargin()
1834{
1835 Q_D(QQuickPopup);
1836 d->setRightMargin(value: -1, reset: true);
1837}
1838
1839/*!
1840 \qmlproperty real QtQuick.Controls::Popup::bottomMargin
1841
1842 This property holds the distance between the bottom edge of the popup and
1843 the bottom edge of its window.
1844
1845 A popup with a negative bottom margin is not pushed within the bottom edge
1846 of the enclosing window. The default value is \c -1.
1847
1848 \sa margins, topMargin, {Popup Layout}
1849*/
1850qreal QQuickPopup::bottomMargin() const
1851{
1852 Q_D(const QQuickPopup);
1853 if (d->hasBottomMargin)
1854 return d->bottomMargin;
1855 return d->margins;
1856}
1857
1858void QQuickPopup::setBottomMargin(qreal margin)
1859{
1860 Q_D(QQuickPopup);
1861 d->setBottomMargin(value: margin);
1862}
1863
1864void QQuickPopup::resetBottomMargin()
1865{
1866 Q_D(QQuickPopup);
1867 d->setBottomMargin(value: -1, reset: true);
1868}
1869
1870/*!
1871 \qmlproperty real QtQuick.Controls::Popup::padding
1872
1873 This property holds the default padding.
1874
1875 \include qquickpopup-padding.qdocinc
1876
1877 \sa availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding
1878*/
1879qreal QQuickPopup::padding() const
1880{
1881 Q_D(const QQuickPopup);
1882 return d->popupItem->padding();
1883}
1884
1885void QQuickPopup::setPadding(qreal padding)
1886{
1887 Q_D(QQuickPopup);
1888 d->popupItem->setPadding(padding);
1889}
1890
1891void QQuickPopup::resetPadding()
1892{
1893 Q_D(QQuickPopup);
1894 d->popupItem->resetPadding();
1895}
1896
1897/*!
1898 \qmlproperty real QtQuick.Controls::Popup::topPadding
1899
1900 This property holds the top padding. Unless explicitly set, the value
1901 is equal to \c verticalPadding.
1902
1903 \include qquickpopup-padding.qdocinc
1904
1905 \sa padding, bottomPadding, verticalPadding, availableHeight
1906*/
1907qreal QQuickPopup::topPadding() const
1908{
1909 Q_D(const QQuickPopup);
1910 return d->popupItem->topPadding();
1911}
1912
1913void QQuickPopup::setTopPadding(qreal padding)
1914{
1915 Q_D(QQuickPopup);
1916 d->popupItem->setTopPadding(padding);
1917}
1918
1919void QQuickPopup::resetTopPadding()
1920{
1921 Q_D(QQuickPopup);
1922 d->popupItem->resetTopPadding();
1923}
1924
1925/*!
1926 \qmlproperty real QtQuick.Controls::Popup::leftPadding
1927
1928 This property holds the left padding. Unless explicitly set, the value
1929 is equal to \c horizontalPadding.
1930
1931 \include qquickpopup-padding.qdocinc
1932
1933 \sa padding, rightPadding, horizontalPadding, availableWidth
1934*/
1935qreal QQuickPopup::leftPadding() const
1936{
1937 Q_D(const QQuickPopup);
1938 return d->popupItem->leftPadding();
1939}
1940
1941void QQuickPopup::setLeftPadding(qreal padding)
1942{
1943 Q_D(QQuickPopup);
1944 d->popupItem->setLeftPadding(padding);
1945}
1946
1947void QQuickPopup::resetLeftPadding()
1948{
1949 Q_D(QQuickPopup);
1950 d->popupItem->resetLeftPadding();
1951}
1952
1953/*!
1954 \qmlproperty real QtQuick.Controls::Popup::rightPadding
1955
1956 This property holds the right padding. Unless explicitly set, the value
1957 is equal to \c horizontalPadding.
1958
1959 \include qquickpopup-padding.qdocinc
1960
1961 \sa padding, leftPadding, horizontalPadding, availableWidth
1962*/
1963qreal QQuickPopup::rightPadding() const
1964{
1965 Q_D(const QQuickPopup);
1966 return d->popupItem->rightPadding();
1967}
1968
1969void QQuickPopup::setRightPadding(qreal padding)
1970{
1971 Q_D(QQuickPopup);
1972 d->popupItem->setRightPadding(padding);
1973}
1974
1975void QQuickPopup::resetRightPadding()
1976{
1977 Q_D(QQuickPopup);
1978 d->popupItem->resetRightPadding();
1979}
1980
1981/*!
1982 \qmlproperty real QtQuick.Controls::Popup::bottomPadding
1983
1984 This property holds the bottom padding. Unless explicitly set, the value
1985 is equal to \c verticalPadding.
1986
1987 \include qquickpopup-padding.qdocinc
1988
1989 \sa padding, topPadding, verticalPadding, availableHeight
1990*/
1991qreal QQuickPopup::bottomPadding() const
1992{
1993 Q_D(const QQuickPopup);
1994 return d->popupItem->bottomPadding();
1995}
1996
1997void QQuickPopup::setBottomPadding(qreal padding)
1998{
1999 Q_D(QQuickPopup);
2000 d->popupItem->setBottomPadding(padding);
2001}
2002
2003void QQuickPopup::resetBottomPadding()
2004{
2005 Q_D(QQuickPopup);
2006 d->popupItem->resetBottomPadding();
2007}
2008
2009/*!
2010 \qmlproperty Locale QtQuick.Controls::Popup::locale
2011
2012 This property holds the locale of the popup.
2013
2014 \sa mirrored, {LayoutMirroring}{LayoutMirroring}
2015*/
2016QLocale QQuickPopup::locale() const
2017{
2018 Q_D(const QQuickPopup);
2019 return d->popupItem->locale();
2020}
2021
2022void QQuickPopup::setLocale(const QLocale &locale)
2023{
2024 Q_D(QQuickPopup);
2025 d->popupItem->setLocale(locale);
2026}
2027
2028void QQuickPopup::resetLocale()
2029{
2030 Q_D(QQuickPopup);
2031 d->popupItem->resetLocale();
2032}
2033
2034/*!
2035 \since QtQuick.Controls 2.3 (Qt 5.10)
2036 \qmlproperty bool QtQuick.Controls::Popup::mirrored
2037 \readonly
2038
2039 This property holds whether the popup is mirrored.
2040
2041 This property is provided for convenience. A popup is considered mirrored
2042 when its visual layout direction is right-to-left; that is, when using a
2043 right-to-left locale.
2044
2045 \sa locale, {Right-to-left User Interfaces}
2046*/
2047bool QQuickPopup::isMirrored() const
2048{
2049 Q_D(const QQuickPopup);
2050 return d->popupItem->isMirrored();
2051}
2052
2053/*!
2054 \qmlproperty font QtQuick.Controls::Popup::font
2055
2056 This property holds the font currently set for the popup.
2057
2058 Popup propagates explicit font properties to its children. If you change a specific
2059 property on a popup's font, that property propagates to all of the popup's children,
2060 overriding any system defaults for that property.
2061
2062 \code
2063 Popup {
2064 font.family: "Courier"
2065
2066 Column {
2067 Label {
2068 text: qsTr("This will use Courier...")
2069 }
2070
2071 Switch {
2072 text: qsTr("... and so will this")
2073 }
2074 }
2075 }
2076 \endcode
2077
2078 \sa Control::font, ApplicationWindow::font
2079*/
2080QFont QQuickPopup::font() const
2081{
2082 Q_D(const QQuickPopup);
2083 return d->popupItem->font();
2084}
2085
2086void QQuickPopup::setFont(const QFont &font)
2087{
2088 Q_D(QQuickPopup);
2089 d->popupItem->setFont(font);
2090}
2091
2092void QQuickPopup::resetFont()
2093{
2094 Q_D(QQuickPopup);
2095 d->popupItem->resetFont();
2096}
2097
2098QQuickWindow *QQuickPopup::window() const
2099{
2100 Q_D(const QQuickPopup);
2101 return d->window;
2102}
2103
2104QQuickItem *QQuickPopup::popupItem() const
2105{
2106 Q_D(const QQuickPopup);
2107 return d->popupItem;
2108}
2109
2110/*!
2111 \qmlproperty Item QtQuick.Controls::Popup::parent
2112
2113 This property holds the parent item.
2114*/
2115QQuickItem *QQuickPopup::parentItem() const
2116{
2117 Q_D(const QQuickPopup);
2118 return d->parentItem;
2119}
2120
2121void QQuickPopup::setParentItem(QQuickItem *parent)
2122{
2123 Q_D(QQuickPopup);
2124 if (d->parentItem == parent)
2125 return;
2126
2127 if (d->parentItem) {
2128 QObjectPrivate::disconnect(sender: d->parentItem, signal: &QQuickItem::windowChanged, receiverPrivate: d, slot: &QQuickPopupPrivate::setWindow);
2129 QQuickItemPrivate::get(item: d->parentItem)->removeItemChangeListener(d, types: QQuickItemPrivate::Destroyed);
2130 }
2131 d->parentItem = parent;
2132 QQuickPopupPositioner *positioner = d->getPositioner();
2133 if (positioner->parentItem())
2134 positioner->setParentItem(parent);
2135 if (parent) {
2136 QObjectPrivate::connect(sender: parent, signal: &QQuickItem::windowChanged, receiverPrivate: d, slot: &QQuickPopupPrivate::setWindow);
2137 QQuickItemPrivate::get(item: d->parentItem)->addItemChangeListener(listener: d, types: QQuickItemPrivate::Destroyed);
2138 } else if (d->inDestructor) {
2139 d->destroyDimmer();
2140 } else {
2141 // Reset transition manager state when its parent window destroyed
2142 if (!d->window && d->transitionManager.isRunning()) {
2143 if (d->transitionState == QQuickPopupPrivate::EnterTransition)
2144 d->finalizeEnterTransition();
2145 else if (d->transitionState == QQuickPopupPrivate::ExitTransition)
2146 d->finalizeExitTransition();
2147 }
2148 // NOTE: if setParentItem is called from the dtor, this bypasses virtual dispatch and calls
2149 // QQuickPopup::close() directly
2150 close();
2151 }
2152 d->setWindow(parent ? parent->window() : nullptr);
2153 emit parentChanged();
2154}
2155
2156void QQuickPopup::resetParentItem()
2157{
2158 if (QQuickWindow *window = qobject_cast<QQuickWindow *>(object: parent()))
2159 setParentItem(window->contentItem());
2160 else
2161 setParentItem(findParentItem());
2162}
2163
2164/*!
2165 \qmlproperty Item QtQuick.Controls::Popup::background
2166
2167 This property holds the background item.
2168
2169 \note If the background item has no explicit size specified, it automatically
2170 follows the popup's size. In most cases, there is no need to specify
2171 width or height for a background item.
2172
2173 \note Most popups use the implicit size of the background item to calculate
2174 the implicit size of the popup itself. If you replace the background item
2175 with a custom one, you should also consider providing a sensible implicit
2176 size for it (unless it is an item like \l Image which has its own implicit
2177 size).
2178
2179 \sa {Customizing Popup}
2180*/
2181QQuickItem *QQuickPopup::background() const
2182{
2183 Q_D(const QQuickPopup);
2184 return d->popupItem->background();
2185}
2186
2187void QQuickPopup::setBackground(QQuickItem *background)
2188{
2189 Q_D(QQuickPopup);
2190 // The __notCustomizable property won't be on "this" when the popup item's setBackground function
2191 // is called, so it won't warn. That's why we do a check here.
2192 QQuickControlPrivate::warnIfCustomizationNotSupported(control: this, item: background, QStringLiteral("background"));
2193 d->popupItem->setBackground(background);
2194}
2195
2196/*!
2197 \qmlproperty Item QtQuick.Controls::Popup::contentItem
2198
2199 This property holds the content item of the popup.
2200
2201 The content item is the visual implementation of the popup. When the
2202 popup is made visible, the content item is automatically reparented to
2203 the \l {Overlay::overlay}{overlay item}.
2204
2205 \note The content item is automatically resized to fit within the
2206 \l padding of the popup.
2207
2208 \note Most popups use the implicit size of the content item to calculate
2209 the implicit size of the popup itself. If you replace the content item
2210 with a custom one, you should also consider providing a sensible implicit
2211 size for it (unless it is an item like \l Text which has its own implicit
2212 size).
2213
2214 \sa {Customizing Popup}
2215*/
2216QQuickItem *QQuickPopup::contentItem() const
2217{
2218 Q_D(const QQuickPopup);
2219 return d->popupItem->contentItem();
2220}
2221
2222void QQuickPopup::setContentItem(QQuickItem *item)
2223{
2224 Q_D(QQuickPopup);
2225 // See comment in setBackground for why we do this.
2226 QQuickControlPrivate::warnIfCustomizationNotSupported(control: this, item, QStringLiteral("contentItem"));
2227 QQuickItem *oldContentItem = d->complete ? d->popupItem->d_func()->contentItem.data()
2228 : nullptr;
2229 if (oldContentItem)
2230 disconnect(sender: oldContentItem, signal: &QQuickItem::childrenChanged, receiver: this, slot: &QQuickPopup::contentChildrenChanged);
2231 d->popupItem->setContentItem(item);
2232 if (d->complete) {
2233 QQuickItem *newContentItem = d->popupItem->d_func()->contentItem.data();
2234 connect(sender: newContentItem, signal: &QQuickItem::childrenChanged, context: this, slot: &QQuickPopup::contentChildrenChanged);
2235 if (oldContentItem != newContentItem)
2236 emit contentChildrenChanged();
2237 }
2238}
2239
2240/*!
2241 \qmlproperty list<QtObject> QtQuick.Controls::Popup::contentData
2242 \qmldefault
2243
2244 This property holds the list of content data.
2245
2246 The list contains all objects that have been declared in QML as children
2247 of the popup.
2248
2249 \note Unlike \c contentChildren, \c contentData does include non-visual QML
2250 objects.
2251
2252 \sa Item::data, contentChildren
2253*/
2254QQmlListProperty<QObject> QQuickPopupPrivate::contentData()
2255{
2256 QQuickControlPrivate *p = QQuickControlPrivate::get(control: popupItem);
2257 if (!p->contentItem)
2258 p->executeContentItem();
2259 return QQmlListProperty<QObject>(popupItem->contentItem(), nullptr,
2260 QQuickItemPrivate::data_append,
2261 QQuickItemPrivate::data_count,
2262 QQuickItemPrivate::data_at,
2263 QQuickItemPrivate::data_clear);
2264}
2265
2266/*!
2267 \qmlproperty list<Item> QtQuick.Controls::Popup::contentChildren
2268
2269 This property holds the list of content children.
2270
2271 The list contains all items that have been declared in QML as children
2272 of the popup.
2273
2274 \note Unlike \c contentData, \c contentChildren does not include non-visual
2275 QML objects.
2276
2277 \sa Item::children, contentData
2278*/
2279QQmlListProperty<QQuickItem> QQuickPopupPrivate::contentChildren()
2280{
2281 return QQmlListProperty<QQuickItem>(popupItem->contentItem(), nullptr,
2282 QQuickItemPrivate::children_append,
2283 QQuickItemPrivate::children_count,
2284 QQuickItemPrivate::children_at,
2285 QQuickItemPrivate::children_clear);
2286}
2287
2288/*!
2289 \qmlproperty bool QtQuick.Controls::Popup::clip
2290
2291 This property holds whether clipping is enabled. The default value is \c false.
2292 Clipping only works when the popup isn't in its own window.
2293*/
2294bool QQuickPopup::clip() const
2295{
2296 Q_D(const QQuickPopup);
2297 return d->popupItem->clip() && !d->usePopupWindow();
2298}
2299
2300void QQuickPopup::setClip(bool clip)
2301{
2302 Q_D(QQuickPopup);
2303 if (clip == d->popupItem->clip() || d->usePopupWindow())
2304 return;
2305 d->popupItem->setClip(clip);
2306 emit clipChanged();
2307}
2308
2309/*!
2310 \qmlproperty bool QtQuick.Controls::Popup::focus
2311
2312 This property holds whether the popup wants focus.
2313
2314 When the popup actually receives focus, \l activeFocus will be \c true.
2315 For more information, see \l {Keyboard Focus in Qt Quick}.
2316
2317 The default value is \c false.
2318
2319 \sa activeFocus
2320*/
2321bool QQuickPopup::hasFocus() const
2322{
2323 Q_D(const QQuickPopup);
2324 return d->focus;
2325}
2326
2327void QQuickPopup::setFocus(bool focus)
2328{
2329 Q_D(QQuickPopup);
2330 if (d->focus == focus)
2331 return;
2332 d->focus = focus;
2333 emit focusChanged();
2334}
2335
2336/*!
2337 \qmlproperty bool QtQuick.Controls::Popup::activeFocus
2338 \readonly
2339
2340 This property holds whether the popup has active focus.
2341
2342 \sa focus, {Keyboard Focus in Qt Quick}
2343*/
2344bool QQuickPopup::hasActiveFocus() const
2345{
2346 Q_D(const QQuickPopup);
2347 return d->popupItem->hasActiveFocus();
2348}
2349
2350/*!
2351 \qmlproperty bool QtQuick.Controls::Popup::modal
2352
2353 This property holds whether the popup is modal.
2354
2355 Modal popups often have a distinctive background dimming effect defined
2356 in \l {Overlay::modal}{Overlay.modal}, and do not allow press
2357 or release events through to items beneath them. For example, if the user
2358 accidentally clicks outside of a popup, any item beneath that popup at
2359 the location of the click will not receive the event.
2360
2361 On desktop platforms, it is common for modal popups to be closed only when
2362 the escape key is pressed. To achieve this behavior, set
2363 \l closePolicy to \c Popup.CloseOnEscape. By default, \c closePolicy
2364 is set to \c {Popup.CloseOnEscape | Popup.CloseOnPressOutside}, which
2365 means that clicking outside of a modal popup will close it.
2366
2367 The default value is \c false.
2368
2369 \sa dim
2370*/
2371bool QQuickPopup::isModal() const
2372{
2373 Q_D(const QQuickPopup);
2374 return d->modal;
2375}
2376
2377void QQuickPopup::setModal(bool modal)
2378{
2379 Q_D(QQuickPopup);
2380 if (d->modal == modal)
2381 return;
2382 d->modal = modal;
2383 d->popupWindowDirty = true;
2384 if (d->complete && d->visible)
2385 d->toggleOverlay();
2386 emit modalChanged();
2387
2388 QQuickItemPrivate::get(item: d->popupItem)->isTabFence = modal;
2389
2390 if (!d->hasDim) {
2391 setDim(modal);
2392 d->hasDim = false;
2393 }
2394}
2395
2396/*!
2397 \qmlproperty bool QtQuick.Controls::Popup::dim
2398
2399 This property holds whether the popup dims the background.
2400
2401 Unless explicitly set, this property follows the value of \l modal. To
2402 return to the default value, set this property to \c undefined.
2403
2404 \sa modal, {Overlay::modeless}{Overlay.modeless}
2405*/
2406bool QQuickPopup::dim() const
2407{
2408 Q_D(const QQuickPopup);
2409 return d->dim;
2410}
2411
2412void QQuickPopup::setDim(bool dim)
2413{
2414 Q_D(QQuickPopup);
2415 d->hasDim = true;
2416
2417 if (d->dim == dim)
2418 return;
2419
2420 d->dim = dim;
2421 if (d->complete && d->visible)
2422 d->toggleOverlay();
2423 emit dimChanged();
2424}
2425
2426void QQuickPopup::resetDim()
2427{
2428 Q_D(QQuickPopup);
2429 if (!d->hasDim)
2430 return;
2431
2432 setDim(d->modal);
2433 d->hasDim = false;
2434}
2435
2436/*!
2437 \qmlproperty bool QtQuick.Controls::Popup::visible
2438
2439 This property holds whether the popup is visible. The default value is \c false.
2440
2441 \sa open(), close(), opened
2442*/
2443bool QQuickPopup::isVisible() const
2444{
2445 Q_D(const QQuickPopup);
2446 return d->visible && d->popupItem->isVisible();
2447}
2448
2449void QQuickPopup::setVisible(bool visible)
2450{
2451 Q_D(QQuickPopup);
2452 // During an exit transition, d->visible == true until the transition has completed.
2453 // Therefore, this guard must not return early if setting visible to true while
2454 // d->visible is true.
2455 if (d->visible && visible && d->transitionState != QQuickPopupPrivate::ExitTransition)
2456 return;
2457 if (!d->visible && !visible)
2458 return;
2459
2460 if (!d->complete || (visible && !d->window)) {
2461 d->visible = visible;
2462 return;
2463 }
2464
2465 if (visible)
2466 d->transitionManager.transitionEnter();
2467 else
2468 d->transitionManager.transitionExit();
2469}
2470
2471/*!
2472 \since QtQuick.Controls 2.3 (Qt 5.10)
2473 \qmlproperty bool QtQuick.Controls::Popup::enabled
2474
2475 This property holds whether the popup is enabled. The default value is \c true.
2476
2477 \sa visible, Item::enabled
2478*/
2479bool QQuickPopup::isEnabled() const
2480{
2481 Q_D(const QQuickPopup);
2482 return d->popupItem->isEnabled();
2483}
2484
2485void QQuickPopup::setEnabled(bool enabled)
2486{
2487 Q_D(QQuickPopup);
2488 d->popupItem->setEnabled(enabled);
2489}
2490
2491/*!
2492 \since QtQuick.Controls 2.3 (Qt 5.10)
2493 \qmlproperty bool QtQuick.Controls::Popup::opened
2494
2495 This property holds whether the popup is fully open. The popup is considered opened
2496 when it's visible and neither the \l enter nor \l exit transitions are running.
2497
2498 \sa open(), close(), visible
2499*/
2500bool QQuickPopup::isOpened() const
2501{
2502 Q_D(const QQuickPopup);
2503 return d->transitionState == QQuickPopupPrivate::NoTransition && isVisible();
2504}
2505
2506/*!
2507 \qmlproperty real QtQuick.Controls::Popup::opacity
2508
2509 This property holds the opacity of the popup. Opacity is specified as a number between
2510 \c 0.0 (fully transparent) and \c 1.0 (fully opaque). The default value is \c 1.0.
2511
2512 \sa visible
2513*/
2514qreal QQuickPopup::opacity() const
2515{
2516 Q_D(const QQuickPopup);
2517 return d->popupItem->opacity();
2518}
2519
2520void QQuickPopup::setOpacity(qreal opacity)
2521{
2522 Q_D(QQuickPopup);
2523 d->popupItem->setOpacity(opacity);
2524}
2525
2526/*!
2527 \qmlproperty real QtQuick.Controls::Popup::scale
2528
2529 This property holds the scale factor of the popup. The default value is \c 1.0.
2530
2531 A scale of less than \c 1.0 causes the popup to be rendered at a smaller size,
2532 and a scale greater than \c 1.0 renders the popup at a larger size. Negative
2533 scales are not supported.
2534*/
2535qreal QQuickPopup::scale() const
2536{
2537 Q_D(const QQuickPopup);
2538 return d->popupItem->scale();
2539}
2540
2541void QQuickPopup::setScale(qreal scale)
2542{
2543 Q_D(QQuickPopup);
2544 if (qFuzzyCompare(p1: scale, p2: d->popupItem->scale()))
2545 return;
2546 d->popupItem->setScale(scale);
2547 emit scaleChanged();
2548}
2549
2550/*!
2551 \qmlproperty enumeration QtQuick.Controls::Popup::closePolicy
2552
2553 This property determines the circumstances under which the popup closes.
2554 The flags can be combined to allow several ways of closing the popup.
2555
2556 The available values are:
2557 \value Popup.NoAutoClose The popup will only close when manually instructed to do so.
2558 \value Popup.CloseOnPressOutside The popup will close when the mouse is pressed outside of it.
2559 \value Popup.CloseOnPressOutsideParent The popup will close when the mouse is pressed outside of its parent.
2560 \value Popup.CloseOnReleaseOutside The popup will close when the mouse is released outside of it.
2561 \value Popup.CloseOnReleaseOutsideParent The popup will close when the mouse is released outside of its parent.
2562 \value Popup.CloseOnEscape The popup will close when the escape key is pressed while the popup
2563 has active focus.
2564
2565 The \c {CloseOnPress*} and \c {CloseOnRelease*} policies only apply for events
2566 outside of popups. That is, if there are two popups open and the first has
2567 \c Popup.CloseOnPressOutside as its policy, clicking on the second popup will
2568 not result in the first closing.
2569
2570 The default value is \c {Popup.CloseOnEscape | Popup.CloseOnPressOutside}.
2571
2572 \note There is a known limitation that the \c Popup.CloseOnReleaseOutside
2573 and \c Popup.CloseOnReleaseOutsideParent policies only work with
2574 \l modal popups.
2575*/
2576QQuickPopup::ClosePolicy QQuickPopup::closePolicy() const
2577{
2578 Q_D(const QQuickPopup);
2579 return d->closePolicy;
2580}
2581
2582void QQuickPopup::setClosePolicy(ClosePolicy policy)
2583{
2584 Q_D(QQuickPopup);
2585 d->hasClosePolicy = true;
2586 if (d->closePolicy == policy)
2587 return;
2588 d->closePolicy = policy;
2589 emit closePolicyChanged();
2590}
2591
2592void QQuickPopup::resetClosePolicy()
2593{
2594 Q_D(QQuickPopup);
2595 setClosePolicy(QQuickPopupPrivate::DefaultClosePolicy);
2596 d->hasClosePolicy = false;
2597}
2598
2599/*!
2600 \qmlproperty enumeration QtQuick.Controls::Popup::transformOrigin
2601
2602 This property holds the origin point for transformations in enter and exit transitions.
2603
2604 Nine transform origins are available, as shown in the image below.
2605 The default transform origin is \c Popup.Center.
2606
2607 \image qtquickcontrols-popup-transformorigin.png
2608
2609 \sa enter, exit, Item::transformOrigin
2610*/
2611QQuickPopup::TransformOrigin QQuickPopup::transformOrigin() const
2612{
2613 Q_D(const QQuickPopup);
2614 return static_cast<TransformOrigin>(d->popupItem->transformOrigin());
2615}
2616
2617void QQuickPopup::setTransformOrigin(TransformOrigin origin)
2618{
2619 Q_D(QQuickPopup);
2620 d->popupItem->setTransformOrigin(static_cast<QQuickItem::TransformOrigin>(origin));
2621}
2622
2623/*!
2624 \qmlproperty Transition QtQuick.Controls::Popup::enter
2625
2626 This property holds the transition that is applied to the popup item
2627 when the popup is opened and enters the screen.
2628
2629 The following example animates the opacity of the popup when it enters
2630 the screen:
2631 \code
2632 Popup {
2633 enter: Transition {
2634 NumberAnimation { property: "opacity"; from: 0.0; to: 1.0 }
2635 }
2636 }
2637 \endcode
2638
2639 \sa exit
2640*/
2641QQuickTransition *QQuickPopup::enter() const
2642{
2643 Q_D(const QQuickPopup);
2644 return d->enter;
2645}
2646
2647void QQuickPopup::setEnter(QQuickTransition *transition)
2648{
2649 Q_D(QQuickPopup);
2650 if (d->enter == transition)
2651 return;
2652 d->enter = transition;
2653 emit enterChanged();
2654}
2655
2656/*!
2657 \qmlproperty Transition QtQuick.Controls::Popup::exit
2658
2659 This property holds the transition that is applied to the popup item
2660 when the popup is closed and exits the screen.
2661
2662 The following example animates the opacity of the popup when it exits
2663 the screen:
2664 \code
2665 Popup {
2666 exit: Transition {
2667 NumberAnimation { property: "opacity"; from: 1.0; to: 0.0 }
2668 }
2669 }
2670 \endcode
2671
2672 \sa enter
2673*/
2674QQuickTransition *QQuickPopup::exit() const
2675{
2676 Q_D(const QQuickPopup);
2677 return d->exit;
2678}
2679
2680void QQuickPopup::setExit(QQuickTransition *transition)
2681{
2682 Q_D(QQuickPopup);
2683 if (d->exit == transition)
2684 return;
2685 d->exit = transition;
2686 emit exitChanged();
2687}
2688
2689/*!
2690 \since QtQuick.Controls 2.5 (Qt 5.12)
2691 \qmlproperty real QtQuick.Controls::Popup::horizontalPadding
2692
2693 This property holds the horizontal padding. Unless explicitly set, the value
2694 is equal to \c padding.
2695
2696 \include qquickpopup-padding.qdocinc
2697
2698 \sa padding, leftPadding, rightPadding, verticalPadding
2699*/
2700qreal QQuickPopup::horizontalPadding() const
2701{
2702 Q_D(const QQuickPopup);
2703 return d->popupItem->horizontalPadding();
2704}
2705
2706void QQuickPopup::setHorizontalPadding(qreal padding)
2707{
2708 Q_D(QQuickPopup);
2709 d->popupItem->setHorizontalPadding(padding);
2710}
2711
2712void QQuickPopup::resetHorizontalPadding()
2713{
2714 Q_D(QQuickPopup);
2715 d->popupItem->resetHorizontalPadding();
2716}
2717
2718/*!
2719 \since QtQuick.Controls 2.5 (Qt 5.12)
2720 \qmlproperty real QtQuick.Controls::Popup::verticalPadding
2721
2722 This property holds the vertical padding. Unless explicitly set, the value
2723 is equal to \c padding.
2724
2725 \include qquickpopup-padding.qdocinc
2726
2727 \sa padding, topPadding, bottomPadding, horizontalPadding
2728*/
2729qreal QQuickPopup::verticalPadding() const
2730{
2731 Q_D(const QQuickPopup);
2732 return d->popupItem->verticalPadding();
2733}
2734
2735void QQuickPopup::setVerticalPadding(qreal padding)
2736{
2737 Q_D(QQuickPopup);
2738 d->popupItem->setVerticalPadding(padding);
2739}
2740
2741void QQuickPopup::resetVerticalPadding()
2742{
2743 Q_D(QQuickPopup);
2744 d->popupItem->resetVerticalPadding();
2745}
2746
2747/*!
2748 \since QtQuick.Controls 2.5 (Qt 5.12)
2749 \qmlproperty real QtQuick.Controls::Popup::implicitContentWidth
2750 \readonly
2751
2752 This property holds the implicit content width.
2753
2754 The value is calculated based on the content children.
2755
2756 \sa implicitContentHeight, implicitBackgroundWidth
2757*/
2758qreal QQuickPopup::implicitContentWidth() const
2759{
2760 Q_D(const QQuickPopup);
2761 return d->popupItem->implicitContentWidth();
2762}
2763
2764/*!
2765 \since QtQuick.Controls 2.5 (Qt 5.12)
2766 \qmlproperty real QtQuick.Controls::Popup::implicitContentHeight
2767 \readonly
2768
2769 This property holds the implicit content height.
2770
2771 The value is calculated based on the content children.
2772
2773 \sa implicitContentWidth, implicitBackgroundHeight
2774*/
2775qreal QQuickPopup::implicitContentHeight() const
2776{
2777 Q_D(const QQuickPopup);
2778 return d->popupItem->implicitContentHeight();
2779}
2780
2781/*!
2782 \since QtQuick.Controls 2.5 (Qt 5.12)
2783 \qmlproperty real QtQuick.Controls::Popup::implicitBackgroundWidth
2784 \readonly
2785
2786 This property holds the implicit background width.
2787
2788 The value is equal to \c {background ? background.implicitWidth : 0}.
2789
2790 \sa implicitBackgroundHeight, implicitContentWidth
2791*/
2792qreal QQuickPopup::implicitBackgroundWidth() const
2793{
2794 Q_D(const QQuickPopup);
2795 return d->popupItem->implicitBackgroundWidth();
2796}
2797
2798/*!
2799 \since QtQuick.Controls 2.5 (Qt 5.12)
2800 \qmlproperty real QtQuick.Controls::Popup::implicitBackgroundHeight
2801 \readonly
2802
2803 This property holds the implicit background height.
2804
2805 The value is equal to \c {background ? background.implicitHeight : 0}.
2806
2807 \sa implicitBackgroundWidth, implicitContentHeight
2808*/
2809qreal QQuickPopup::implicitBackgroundHeight() const
2810{
2811 Q_D(const QQuickPopup);
2812 return d->popupItem->implicitBackgroundHeight();
2813}
2814
2815/*!
2816 \since QtQuick.Controls 2.5 (Qt 5.12)
2817 \qmlproperty real QtQuick.Controls::Popup::topInset
2818
2819 This property holds the top inset for the background.
2820
2821 \sa {Popup Layout}, bottomInset
2822*/
2823qreal QQuickPopup::topInset() const
2824{
2825 Q_D(const QQuickPopup);
2826 return d->popupItem->topInset();
2827}
2828
2829void QQuickPopup::setTopInset(qreal inset)
2830{
2831 Q_D(QQuickPopup);
2832 d->popupItem->setTopInset(inset);
2833}
2834
2835void QQuickPopup::resetTopInset()
2836{
2837 Q_D(QQuickPopup);
2838 d->popupItem->resetTopInset();
2839}
2840
2841/*!
2842 \since QtQuick.Controls 2.5 (Qt 5.12)
2843 \qmlproperty real QtQuick.Controls::Popup::leftInset
2844
2845 This property holds the left inset for the background.
2846
2847 \sa {Popup Layout}, rightInset
2848*/
2849qreal QQuickPopup::leftInset() const
2850{
2851 Q_D(const QQuickPopup);
2852 return d->popupItem->leftInset();
2853}
2854
2855void QQuickPopup::setLeftInset(qreal inset)
2856{
2857 Q_D(QQuickPopup);
2858 d->popupItem->setLeftInset(inset);
2859}
2860
2861void QQuickPopup::resetLeftInset()
2862{
2863 Q_D(QQuickPopup);
2864 d->popupItem->resetLeftInset();
2865}
2866
2867/*!
2868 \since QtQuick.Controls 2.5 (Qt 5.12)
2869 \qmlproperty real QtQuick.Controls::Popup::rightInset
2870
2871 This property holds the right inset for the background.
2872
2873 \sa {Popup Layout}, leftInset
2874*/
2875qreal QQuickPopup::rightInset() const
2876{
2877 Q_D(const QQuickPopup);
2878 return d->popupItem->rightInset();
2879}
2880
2881void QQuickPopup::setRightInset(qreal inset)
2882{
2883 Q_D(QQuickPopup);
2884 d->popupItem->setRightInset(inset);
2885}
2886
2887void QQuickPopup::resetRightInset()
2888{
2889 Q_D(QQuickPopup);
2890 d->popupItem->resetRightInset();
2891}
2892
2893/*!
2894 \since QtQuick.Controls 2.5 (Qt 5.12)
2895 \qmlproperty real QtQuick.Controls::Popup::bottomInset
2896
2897 This property holds the bottom inset for the background.
2898
2899 \sa {Popup Layout}, topInset
2900*/
2901qreal QQuickPopup::bottomInset() const
2902{
2903 Q_D(const QQuickPopup);
2904 return d->popupItem->bottomInset();
2905}
2906
2907void QQuickPopup::setBottomInset(qreal inset)
2908{
2909 Q_D(QQuickPopup);
2910 d->popupItem->setBottomInset(inset);
2911}
2912
2913void QQuickPopup::resetBottomInset()
2914{
2915 Q_D(QQuickPopup);
2916 d->popupItem->resetBottomInset();
2917}
2918
2919
2920/*!
2921 \qmlproperty enumeration QtQuick.Controls::Popup::popupType
2922 \since 6.8
2923
2924 This property determines the type of popup that is preferred.
2925
2926 Available options:
2927 \value Item The popup will be embedded into the
2928 \l{Showing a popup as an item}{same scene as the parent},
2929 without the use of a separate window.
2930 \value Window The popup will be presented in a \l {Popup type}
2931 {separate window}. If the platform doesn't support
2932 multiple windows, \c Popup.Item will be used instead.
2933 \value Native The popup will be native to the platform. If the
2934 platform doesn't support native popups, \c Popup.Window
2935 will be used instead.
2936
2937 Whether a popup will be able to use the preferred type depends on the platform.
2938 \c Popup.Item is supported on all platforms, but \c Popup.Window and \c Popup.Native
2939 are normally only supported on desktop platforms. Additionally, if a popup is a
2940 \l Menu inside a \l {Native menu bars}{native menubar}, the menu will be native as
2941 well. And if the menu is a sub-menu inside another menu, the parent (or root) menu
2942 will decide the type.
2943
2944 The default value is usually \c Popup.Item, with some exceptions, mentioned above.
2945 This might change in future versions of Qt, for certain styles and platforms that benefit
2946 from using other popup types.
2947 If you always want to use native menus for all styles on macOS, for example, you can do:
2948
2949 \code
2950 Menu {
2951 popupType: Qt.platform.os === "osx" ? Popup.Native : Popup.Window
2952 }
2953 \endcode
2954
2955 Also, if you choose to customize a popup (by for example changing any of the
2956 delegates), you should consider setting the popup type to be \c Popup.Window
2957 as well. This will ensure that your changes will be visible on all platforms
2958 and for all styles. Otherwise, when native menus are being used, the delegates
2959 will \e not be used for rendering.
2960
2961 \sa {Popup type}
2962*/
2963QQuickPopup::PopupType QQuickPopup::popupType() const
2964{
2965 Q_D(const QQuickPopup);
2966 return d->m_popupType;
2967}
2968
2969void QQuickPopup::setPopupType(PopupType popupType)
2970{
2971 Q_D(QQuickPopup);
2972 if (d->m_popupType == popupType)
2973 return;
2974
2975 d->m_popupType = popupType;
2976
2977 emit popupTypeChanged();
2978}
2979
2980/*!
2981 \since QtQuick.Controls 2.3 (Qt 5.10)
2982 \qmlproperty palette QtQuick.Controls::Popup::palette
2983
2984 This property holds the palette currently set for the popup.
2985
2986 Popup propagates explicit palette properties to its children. If you change a specific
2987 property on a popup's palette, that property propagates to all of the popup's children,
2988 overriding any system defaults for that property.
2989
2990 \code
2991 Popup {
2992 palette.text: "red"
2993
2994 Column {
2995 Label {
2996 text: qsTr("This will use red color...")
2997 }
2998
2999 Switch {
3000 text: qsTr("... and so will this")
3001 }
3002 }
3003 }
3004 \endcode
3005
3006 \b {See also}: \l Item::palette, \l Window::palette, \l ColorGroup,
3007 \l [QML] {Palette}
3008*/
3009
3010bool QQuickPopup::filtersChildMouseEvents() const
3011{
3012 Q_D(const QQuickPopup);
3013 return d->popupItem->filtersChildMouseEvents();
3014}
3015
3016void QQuickPopup::setFiltersChildMouseEvents(bool filter)
3017{
3018 Q_D(QQuickPopup);
3019 d->popupItem->setFiltersChildMouseEvents(filter);
3020}
3021
3022/*!
3023 \qmlmethod QtQuick.Controls::Popup::forceActiveFocus(enumeration reason = Qt.OtherFocusReason)
3024
3025 Forces active focus on the popup with the given \a reason.
3026
3027 This method sets focus on the popup and ensures that all ancestor
3028 \l FocusScope objects in the object hierarchy are also given \l focus.
3029
3030 \sa activeFocus, Qt::FocusReason
3031*/
3032void QQuickPopup::forceActiveFocus(Qt::FocusReason reason)
3033{
3034 Q_D(QQuickPopup);
3035 d->popupItem->forceActiveFocus(reason);
3036}
3037
3038void QQuickPopup::classBegin()
3039{
3040 Q_D(QQuickPopup);
3041 d->complete = false;
3042 QQmlContext *context = qmlContext(this);
3043 if (context)
3044 QQmlEngine::setContextForObject(d->popupItem, context);
3045 d->popupItem->classBegin();
3046}
3047
3048void QQuickPopup::componentComplete()
3049{
3050 Q_D(QQuickPopup);
3051 qCDebug(lcQuickPopup) << "componentComplete" << this;
3052 if (!parentItem())
3053 resetParentItem();
3054
3055 if (d->visible && d->window)
3056 d->transitionManager.transitionEnter();
3057
3058 d->complete = true;
3059 d->popupItem->componentComplete();
3060
3061 if (auto currentContentItem = d->popupItem->d_func()->contentItem.data()) {
3062 connect(sender: currentContentItem, signal: &QQuickItem::childrenChanged,
3063 context: this, slot: &QQuickPopup::contentChildrenChanged);
3064 }
3065}
3066
3067bool QQuickPopup::isComponentComplete() const
3068{
3069 Q_D(const QQuickPopup);
3070 return d->complete;
3071}
3072
3073bool QQuickPopup::childMouseEventFilter(QQuickItem *child, QEvent *event)
3074{
3075 Q_UNUSED(child);
3076 Q_UNUSED(event);
3077 return false;
3078}
3079
3080void QQuickPopup::focusInEvent(QFocusEvent *event)
3081{
3082 event->accept();
3083}
3084
3085void QQuickPopup::focusOutEvent(QFocusEvent *event)
3086{
3087 event->accept();
3088}
3089
3090void QQuickPopup::keyPressEvent(QKeyEvent *event)
3091{
3092 Q_D(QQuickPopup);
3093 if (!hasActiveFocus())
3094 return;
3095
3096#if QT_CONFIG(shortcut)
3097 if (d->closePolicy.testFlag(flag: QQuickPopup::CloseOnEscape)
3098 && (event->matches(key: QKeySequence::Cancel)
3099#if defined(Q_OS_ANDROID)
3100 || event->key() == Qt::Key_Back
3101#endif
3102 )) {
3103 event->accept();
3104 if (d->interactive)
3105 d->closeOrReject();
3106 return;
3107 }
3108#endif
3109
3110 if (hasActiveFocus() && (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab)) {
3111 event->accept();
3112 QQuickItemPrivate::focusNextPrev(item: d->popupItem, forward: event->key() == Qt::Key_Tab);
3113 }
3114}
3115
3116void QQuickPopup::keyReleaseEvent(QKeyEvent *event)
3117{
3118 event->accept();
3119}
3120
3121void QQuickPopup::mousePressEvent(QMouseEvent *event)
3122{
3123 Q_D(QQuickPopup);
3124 event->setAccepted(d->handleMouseEvent(item: d->popupItem, event));
3125}
3126
3127void QQuickPopup::mouseMoveEvent(QMouseEvent *event)
3128{
3129 Q_D(QQuickPopup);
3130 event->setAccepted(d->handleMouseEvent(item: d->popupItem, event));
3131}
3132
3133void QQuickPopup::mouseReleaseEvent(QMouseEvent *event)
3134{
3135 Q_D(QQuickPopup);
3136 event->setAccepted(d->handleMouseEvent(item: d->popupItem, event));
3137}
3138
3139void QQuickPopup::mouseDoubleClickEvent(QMouseEvent *event)
3140{
3141 event->accept();
3142}
3143
3144void QQuickPopup::mouseUngrabEvent()
3145{
3146 Q_D(QQuickPopup);
3147 d->handleUngrab();
3148}
3149
3150/*!
3151 \internal
3152
3153 Called whenever the window receives a Wheel/Hover/Mouse/Touch event,
3154 and has an active popup (with popupType: Popup.Item) in its scene.
3155
3156 The purpose is to close popups when the press/release event happened outside of it,
3157 and the closePolicy allows for it to happen.
3158
3159 If the function is called from childMouseEventFilter, then the return value of this
3160 function will determine whether the event will be filtered, or delivered to \a item.
3161*/
3162bool QQuickPopup::overlayEvent(QQuickItem *item, QEvent *event)
3163{
3164 Q_D(QQuickPopup);
3165 switch (event->type()) {
3166 case QEvent::KeyPress:
3167 case QEvent::KeyRelease:
3168 case QEvent::MouseMove:
3169 case QEvent::Wheel:
3170 if (d->modal)
3171 event->accept();
3172 return d->modal;
3173
3174#if QT_CONFIG(quicktemplates2_multitouch)
3175 case QEvent::TouchBegin:
3176 case QEvent::TouchUpdate:
3177 case QEvent::TouchEnd:
3178 return d->handleTouchEvent(item, event: static_cast<QTouchEvent *>(event));
3179#endif
3180 case QEvent::HoverEnter:
3181 case QEvent::HoverMove:
3182 case QEvent::HoverLeave:
3183 return d->handleHoverEvent(item, event: static_cast<QHoverEvent *>(event));
3184
3185 case QEvent::MouseButtonPress:
3186 case QEvent::MouseButtonRelease:
3187 return d->handleMouseEvent(item, event: static_cast<QMouseEvent *>(event));
3188
3189 default:
3190 return false;
3191 }
3192}
3193
3194#if QT_CONFIG(quicktemplates2_multitouch)
3195void QQuickPopup::touchEvent(QTouchEvent *event)
3196{
3197 Q_D(QQuickPopup);
3198 d->handleTouchEvent(item: d->popupItem, event);
3199}
3200
3201void QQuickPopup::touchUngrabEvent()
3202{
3203 Q_D(QQuickPopup);
3204 d->handleUngrab();
3205}
3206#endif
3207
3208#if QT_CONFIG(wheelevent)
3209void QQuickPopup::wheelEvent(QWheelEvent *event)
3210{
3211 event->accept();
3212}
3213#endif
3214
3215void QQuickPopup::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
3216{
3217 Q_UNUSED(newItem);
3218 Q_UNUSED(oldItem);
3219}
3220
3221void QQuickPopup::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
3222{
3223 qCDebug(lcQuickPopup) << "contentSizeChange called on" << this << "with newSize" << newSize << "oldSize" << oldSize;
3224 if (!qFuzzyCompare(p1: newSize.width(), p2: oldSize.width()))
3225 emit contentWidthChanged();
3226 if (!qFuzzyCompare(p1: newSize.height(), p2: oldSize.height()))
3227 emit contentHeightChanged();
3228}
3229
3230void QQuickPopup::fontChange(const QFont &newFont, const QFont &oldFont)
3231{
3232 Q_UNUSED(newFont);
3233 Q_UNUSED(oldFont);
3234 emit fontChanged();
3235}
3236
3237void QQuickPopup::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
3238{
3239 Q_D(QQuickPopup);
3240 qCDebug(lcQuickPopup) << "geometryChange called on" << this << "with newGeometry" << newGeometry << "oldGeometry" << oldGeometry;
3241 if (!d->usePopupWindow())
3242 d->reposition();
3243 if (!qFuzzyCompare(p1: newGeometry.width(), p2: oldGeometry.width())) {
3244 emit widthChanged();
3245 emit availableWidthChanged();
3246 }
3247 if (!qFuzzyCompare(p1: newGeometry.height(), p2: oldGeometry.height())) {
3248 emit heightChanged();
3249 emit availableHeightChanged();
3250 }
3251}
3252
3253void QQuickPopup::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &)
3254{
3255 switch (change) {
3256 case QQuickItem::ItemActiveFocusHasChanged:
3257 emit activeFocusChanged();
3258 break;
3259 case QQuickItem::ItemOpacityHasChanged:
3260 emit opacityChanged();
3261 break;
3262 default:
3263 break;
3264 }
3265}
3266
3267void QQuickPopup::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
3268{
3269 Q_UNUSED(newLocale);
3270 Q_UNUSED(oldLocale);
3271 emit localeChanged();
3272}
3273
3274void QQuickPopup::marginsChange(const QMarginsF &newMargins, const QMarginsF &oldMargins)
3275{
3276 Q_D(QQuickPopup);
3277 Q_UNUSED(newMargins);
3278 Q_UNUSED(oldMargins);
3279 d->reposition();
3280}
3281
3282void QQuickPopup::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
3283{
3284 const bool tp = !qFuzzyCompare(p1: newPadding.top(), p2: oldPadding.top());
3285 const bool lp = !qFuzzyCompare(p1: newPadding.left(), p2: oldPadding.left());
3286 const bool rp = !qFuzzyCompare(p1: newPadding.right(), p2: oldPadding.right());
3287 const bool bp = !qFuzzyCompare(p1: newPadding.bottom(), p2: oldPadding.bottom());
3288
3289 if (tp)
3290 emit topPaddingChanged();
3291 if (lp)
3292 emit leftPaddingChanged();
3293 if (rp)
3294 emit rightPaddingChanged();
3295 if (bp)
3296 emit bottomPaddingChanged();
3297
3298 if (lp || rp) {
3299 emit horizontalPaddingChanged();
3300 emit availableWidthChanged();
3301 }
3302 if (tp || bp) {
3303 emit verticalPaddingChanged();
3304 emit availableHeightChanged();
3305 }
3306}
3307
3308void QQuickPopup::spacingChange(qreal newSpacing, qreal oldSpacing)
3309{
3310 Q_UNUSED(newSpacing);
3311 Q_UNUSED(oldSpacing);
3312 emit spacingChanged();
3313}
3314
3315void QQuickPopup::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset)
3316{
3317 if (!qFuzzyCompare(p1: newInset.top(), p2: oldInset.top()))
3318 emit topInsetChanged();
3319 if (!qFuzzyCompare(p1: newInset.left(), p2: oldInset.left()))
3320 emit leftInsetChanged();
3321 if (!qFuzzyCompare(p1: newInset.right(), p2: oldInset.right()))
3322 emit rightInsetChanged();
3323 if (!qFuzzyCompare(p1: newInset.bottom(), p2: oldInset.bottom()))
3324 emit bottomInsetChanged();
3325}
3326
3327QFont QQuickPopup::defaultFont() const
3328{
3329 return QQuickTheme::font(scope: QQuickTheme::System);
3330}
3331
3332#if QT_CONFIG(accessibility)
3333QAccessible::Role QQuickPopup::effectiveAccessibleRole() const
3334{
3335 auto *attached = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(obj: this, create: false);
3336
3337 auto role = QAccessible::NoRole;
3338 if (auto *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(object: attached))
3339 role = accessibleAttached->role();
3340 if (role == QAccessible::NoRole)
3341 role = accessibleRole();
3342
3343 return role;
3344}
3345
3346QAccessible::Role QQuickPopup::accessibleRole() const
3347{
3348 return QAccessible::Dialog;
3349}
3350
3351void QQuickPopup::accessibilityActiveChanged(bool active)
3352{
3353 Q_UNUSED(active);
3354}
3355#endif
3356
3357QString QQuickPopup::accessibleName() const
3358{
3359 Q_D(const QQuickPopup);
3360 return d->popupItem->accessibleName();
3361}
3362
3363void QQuickPopup::maybeSetAccessibleName(const QString &name)
3364{
3365 Q_D(QQuickPopup);
3366 d->popupItem->maybeSetAccessibleName(name);
3367}
3368
3369QVariant QQuickPopup::accessibleProperty(const char *propertyName)
3370{
3371 Q_D(const QQuickPopup);
3372 return d->popupItem->accessibleProperty(propertyName);
3373}
3374
3375bool QQuickPopup::setAccessibleProperty(const char *propertyName, const QVariant &value)
3376{
3377 Q_D(QQuickPopup);
3378 return d->popupItem->setAccessibleProperty(propertyName, value);
3379}
3380
3381QT_END_NAMESPACE
3382
3383#include "moc_qquickpopup_p.cpp"
3384

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