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