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