diff options
Diffstat (limited to 'src/quicktemplates/qquickpopup.cpp')
-rw-r--r-- | src/quicktemplates/qquickpopup.cpp | 3005 |
1 files changed, 3005 insertions, 0 deletions
diff --git a/src/quicktemplates/qquickpopup.cpp b/src/quicktemplates/qquickpopup.cpp new file mode 100644 index 0000000000..6aa88a465e --- /dev/null +++ b/src/quicktemplates/qquickpopup.cpp @@ -0,0 +1,3005 @@ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qquickpopup_p.h" +#include "qquickpopup_p_p.h" +#include "qquickpopupanchors_p.h" +#include "qquickpopupitem_p_p.h" +#include "qquickpopuppositioner_p_p.h" +#include "qquickapplicationwindow_p.h" +#include "qquickoverlay_p_p.h" +#include "qquickcontrol_p_p.h" +#if QT_CONFIG(quicktemplates2_container) +#include "qquickdialog_p.h" +#endif + +#include <QtCore/qloggingcategory.h> +#include <QtQml/qqmlinfo.h> +#include <QtQuick/qquickitem.h> +#include <QtQuick/private/qquickaccessibleattached_p.h> +#include <QtQuick/private/qquicktransition_p.h> +#include <QtQuick/private/qquickitem_p.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcDimmer, "qt.quick.controls.popup.dimmer") +Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup") + +/*! + \qmltype Popup + \inherits QtObject +//! \instantiates QQuickPopup + \inqmlmodule QtQuick.Controls + \since 5.7 + \ingroup qtquickcontrols-popups + \ingroup qtquickcontrols-focusscopes + \brief Base type of popup-like user interface controls. + + Popup is the base type of popup-like user interface controls. It can be + used with \l Window or \l ApplicationWindow. + + \qml + import QtQuick.Window 2.2 + import QtQuick.Controls 2.12 + + ApplicationWindow { + id: window + width: 400 + height: 400 + visible: true + + Button { + text: "Open" + onClicked: popup.open() + } + + Popup { + id: popup + x: 100 + y: 100 + width: 200 + height: 300 + modal: true + focus: true + closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent + } + } + \endqml + + In order to ensure that a popup is displayed above other items in the + scene, it is recommended to use ApplicationWindow. ApplicationWindow also + provides background dimming effects. + + Popup does not provide a layout of its own, but requires you to position + its contents, for instance by creating a \l RowLayout or a \l ColumnLayout. + + Items declared as children of a Popup are automatically parented to the + Popups's \l contentItem. Items created dynamically need to be explicitly + parented to the contentItem. + + \section1 Popup Layout + + The following diagram illustrates the layout of a popup within a window: + + \image qtquickcontrols-popup.png + + The \l implicitWidth and \l implicitHeight of a popup are typically based + on the implicit sizes of the background and the content item plus any insets + and paddings. These properties determine how large the popup will be when no + explicit \l width or \l height is specified. + + The geometry of the \l contentItem is determined by the padding. The following + example reserves 10px padding between the boundaries of the popup and its content: + + \code + Popup { + padding: 10 + + contentItem: Text { + text: "Content" + } + } + \endcode + + The \l background item fills the entire width and height of the popup, + unless insets or an explicit size have been given for it. + + Negative insets can be used to make the background larger than the popup. + The following example uses negative insets to place a shadow outside the + popup's boundaries: + + \code + Popup { + topInset: -2 + leftInset: -2 + rightInset: -6 + bottomInset: -6 + + background: BorderImage { + source: ":/images/shadowed-background.png" + } + } + \endcode + + \section1 Popup Sizing + + If only a single item is used within a Popup, it will resize to fit the + implicit size of its contained item. This makes it particularly suitable + for use together with layouts. + + \code + Popup { + ColumnLayout { + anchors.fill: parent + CheckBox { text: qsTr("E-mail") } + CheckBox { text: qsTr("Calendar") } + CheckBox { text: qsTr("Contacts") } + } + } + \endcode + + Sometimes there might be two items within the popup: + + \code + Popup { + SwipeView { + // ... + } + PageIndicator { + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + } + } + \endcode + + In this case, Popup cannot calculate a sensible implicit size. Since we're + anchoring the \l PageIndicator over the \l SwipeView, we can simply set the + content size to the view's implicit size: + + \code + Popup { + contentWidth: view.implicitWidth + contentHeight: view.implicitHeight + + SwipeView { + id: view + // ... + } + PageIndicator { + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + } + } + \endcode + + \note The popup's \l{contentItem}{content item} gets parented to the + \l{Overlay::overlay}{overlay}, and does not live within the popup's parent. + Because of that, a \l{Item::scale}{scale} applied to the tree in which + the popup lives does not apply to the visual popup. To make the popup + of e.g. a \l{ComboBox} follow the scale of the combobox, apply the same scale + to the \l{Overlay::overlay}{overlay} as well: + + \code + Window { + property double scaleFactor: 2.0 + + Scale { + id: scale + xScale: scaleFactor + yScale: scaleFactor + } + Item { + id: scaledContent + transform: scale + + ComboBox { + id: combobox + // ... + } + } + + Overlay.overlay.transform: scale + } + \endcode + + \section1 Popup Positioning + + Similar to items in Qt Quick, Popup's \l x and \l y coordinates are + relative to its parent. This means that opening a popup that is a + child of a \l Button, for example, will cause the popup to be positioned + relative to the button. + + \include qquickoverlay-popup-parent.qdocinc + + Another way to center a popup in the window regardless of its parent item + is to use \l {anchors.centerIn}: + + \snippet qtquickcontrols-popup.qml centerIn + + To ensure that the popup is positioned within the bounds of the enclosing + window, the \l margins property can be set to a non-negative value. + + \section1 Showing Non-Child Items in Front of Popup + + Popup sets its contentItem's + \l{qtquick-visualcanvas-visualparent.html}{visual parent} + to be the window's \l{Overlay::overlay}{overlay}, in order to ensure that + the popup appears in front of everything else in the scene. + In some cases, it might be useful to put an item in front of a popup, + such as a \l [QML QtVirtualKeyboard] {InputPanel} {virtual keyboard}. + This can be done by setting the item's parent to the overlay, + and giving the item a positive z value. The same result can also be + achieved by waiting until the popup is opened, before re-parenting the item + to the overlay. + + \omit + This shouldn't be a snippet, since we don't want VKB to be a dependency to controls. + \endomit + \qml + Popup { + id: popup + visible: true + anchors.centerIn: parent + margins: 10 + closePolicy: Popup.CloseOnEscape + ColumnLayout { + TextField { + placeholderText: qsTr("Username") + } + TextField { + placeholderText: qsTr("Password") + echoMode: TextInput.Password + } + } + } + InputPanel { + parent: Overlay.overlay + width: parent.width + y: popup.y + popup.topMargin + (window.activeFocusItem?.y ?? 0) + (window.activeFocusItem?.height ?? 0) + z: 1 + } + \endqml + + \section1 Popup Transitions + + Since Qt 5.15.3 the following properties are restored to their original values from before + the enter transition after the exit transition is completed. + + \list + \li \l opacity + \li \l scale + \endlist + + This allows the built-in styles to animate on these properties without losing any explicitly + defined value. + + \section1 Back/Escape Event Handling + + By default, a Popup will close if: + \list + \li It has \l activeFocus, + \li Its \l closePolicy is \c {Popup.CloseOnEscape}, and + \li The user presses the key sequence for QKeySequence::Cancel (typically + the Escape key) + \endlist + + To prevent this from happening, either: + + \list + \li Don't give the popup \l focus. + \li Set the popup's \l closePolicy to a value that does not include + \c {Popup.CloseOnEscape}. + \li Handle \l {Keys}' \l {Keys::}{escapePressed} signal in a child item of + the popup so that it gets the event before the Popup. + \endlist + + \sa {Popup Controls}, {Customizing Popup}, ApplicationWindow + + \section1 Property Propagation + + Popup inherits fonts, palettes and attached properties through its parent + window, not its \l {Visual Parent}{object or visual parent}: + + \snippet qtquickcontrols-popup-property-propagation.qml file + + \image qtquickcontrols-basic-popup-property-propagation.png + + In addition, popups do not propagate their properties to child popups. This + behavior is modelled on Qt Widgets, where a \c Qt::Popup widget is a + top-level window. Top-level windows do not propagate their properties to + child windows. + + Certain derived types like ComboBox are typically implemented in such a way + that the popup is considered an integral part of the control, and as such, + may inherit things like attached properties. For example, in the + \l {Material Style}{Material style} ComboBox, the theme and other attached + properties are explicitly inherited by the Popup from the ComboBox itself: + + \code + popup: T.Popup { + // ... + + Material.theme: control.Material.theme + Material.accent: control.Material.accent + Material.primary: control.Material.primary + } + \endcode + + So, to ensure that a child popup has the same property values as its parent + popup, explicitly set those properties: + + \code + Popup { + id: parentPopup + // ... + + Popup { + palette: parentPopup.palette + } + } + \endcode +*/ + +/*! + \qmlsignal void QtQuick.Controls::Popup::opened() + + This signal is emitted when the popup is opened. + + \sa aboutToShow() +*/ + +/*! + \qmlsignal void QtQuick.Controls::Popup::closed() + + This signal is emitted when the popup is closed. + + \sa aboutToHide() +*/ + +/*! + \qmlsignal void QtQuick.Controls::Popup::aboutToShow() + + This signal is emitted when the popup is about to show. + + \sa opened() +*/ + +/*! + \qmlsignal void QtQuick.Controls::Popup::aboutToHide() + + This signal is emitted when the popup is about to hide. + + \sa closed() +*/ + +const QQuickPopup::ClosePolicy QQuickPopupPrivate::DefaultClosePolicy = QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutside; + +QQuickPopupPrivate::QQuickPopupPrivate() + : transitionManager(this) +{ +} + +void QQuickPopupPrivate::init() +{ + Q_Q(QQuickPopup); + popupItem = new QQuickPopupItem(q); + popupItem->setVisible(false); + q->setParentItem(qobject_cast<QQuickItem *>(parent)); + QObject::connect(popupItem, &QQuickControl::paddingChanged, q, &QQuickPopup::paddingChanged); + QObject::connect(popupItem, &QQuickControl::backgroundChanged, q, &QQuickPopup::backgroundChanged); + QObject::connect(popupItem, &QQuickControl::contentItemChanged, q, &QQuickPopup::contentItemChanged); + QObject::connect(popupItem, &QQuickControl::implicitContentWidthChanged, q, &QQuickPopup::implicitContentWidthChanged); + QObject::connect(popupItem, &QQuickControl::implicitContentHeightChanged, q, &QQuickPopup::implicitContentHeightChanged); + QObject::connect(popupItem, &QQuickControl::implicitBackgroundWidthChanged, q, &QQuickPopup::implicitBackgroundWidthChanged); + QObject::connect(popupItem, &QQuickControl::implicitBackgroundHeightChanged, q, &QQuickPopup::implicitBackgroundHeightChanged); +} + +void QQuickPopupPrivate::closeOrReject() +{ + Q_Q(QQuickPopup); +#if QT_CONFIG(quicktemplates2_container) + if (QQuickDialog *dialog = qobject_cast<QQuickDialog*>(q)) + dialog->reject(); + else +#endif + q->close(); + touchId = -1; +} + +bool QQuickPopupPrivate::tryClose(const QPointF &pos, QQuickPopup::ClosePolicy flags) +{ + if (!interactive) + return false; + + static const QQuickPopup::ClosePolicy outsideFlags = QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnReleaseOutside; + static const QQuickPopup::ClosePolicy outsideParentFlags = QQuickPopup::CloseOnPressOutsideParent | QQuickPopup::CloseOnReleaseOutsideParent; + + const bool onOutside = closePolicy & (flags & outsideFlags); + const bool onOutsideParent = closePolicy & (flags & outsideParentFlags); + + if ((onOutside && outsidePressed) || (onOutsideParent && outsideParentPressed)) { + if (!contains(pos) && (!dimmer || dimmer->contains(dimmer->mapFromScene(pos)))) { + if (!onOutsideParent || !parentItem || !parentItem->contains(parentItem->mapFromScene(pos))) { + closeOrReject(); + return true; + } + } + } + return false; +} + +bool QQuickPopupPrivate::contains(const QPointF &scenePos) const +{ + return popupItem->contains(popupItem->mapFromScene(scenePos)); +} + +#if QT_CONFIG(quicktemplates2_multitouch) +bool QQuickPopupPrivate::acceptTouch(const QTouchEvent::TouchPoint &point) +{ + if (point.id() == touchId) + return true; + + if (touchId == -1 && point.state() != QEventPoint::Released) { + touchId = point.id(); + return true; + } + + return false; +} +#endif + +bool QQuickPopupPrivate::blockInput(QQuickItem *item, const QPointF &point) const +{ + // don't propagate events within the popup beyond the overlay + if (popupItem->contains(popupItem->mapFromScene(point)) + && item == QQuickOverlay::overlay(window)) { + return true; + } + + // don't block presses and releases + // a) outside a non-modal popup, + // b) to popup children/content, or + // b) outside a modal popups's background dimming + return modal && ((popupItem != item) && !popupItem->isAncestorOf(item)) && (!dimmer || dimmer->contains(dimmer->mapFromScene(point))); +} + +bool QQuickPopupPrivate::handlePress(QQuickItem *item, const QPointF &point, ulong timestamp) +{ + Q_UNUSED(timestamp); + pressPoint = point; + outsidePressed = !contains(point); + outsideParentPressed = outsidePressed && parentItem && !parentItem->contains(parentItem->mapFromScene(point)); + tryClose(point, QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent); + return blockInput(item, point); +} + +bool QQuickPopupPrivate::handleMove(QQuickItem *item, const QPointF &point, ulong timestamp) +{ + Q_UNUSED(timestamp); + return blockInput(item, point); +} + +bool QQuickPopupPrivate::handleRelease(QQuickItem *item, const QPointF &point, ulong timestamp) +{ + Q_UNUSED(timestamp); + if (item != popupItem && !contains(pressPoint)) + tryClose(point, QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent); + pressPoint = QPointF(); + outsidePressed = false; + outsideParentPressed = false; + touchId = -1; + return blockInput(item, point); +} + +void QQuickPopupPrivate::handleUngrab() +{ + Q_Q(QQuickPopup); + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + if (overlay) { + QQuickOverlayPrivate *p = QQuickOverlayPrivate::get(overlay); + if (p->mouseGrabberPopup == q) + p->mouseGrabberPopup = nullptr; + } + pressPoint = QPointF(); + touchId = -1; +} + +bool QQuickPopupPrivate::handleMouseEvent(QQuickItem *item, QMouseEvent *event) +{ + switch (event->type()) { + case QEvent::MouseButtonPress: + return handlePress(item, event->scenePosition(), event->timestamp()); + case QEvent::MouseMove: + return handleMove(item, event->scenePosition(), event->timestamp()); + case QEvent::MouseButtonRelease: + return handleRelease(item, event->scenePosition(), event->timestamp()); + default: + Q_UNREACHABLE_RETURN(false); + } +} + +bool QQuickPopupPrivate::handleHoverEvent(QQuickItem *item, QHoverEvent *event) +{ + switch (event->type()) { + case QEvent::HoverEnter: + case QEvent::HoverMove: + case QEvent::HoverLeave: + return blockInput(item, event->scenePosition()); + default: + Q_UNREACHABLE_RETURN(false); + } +} + +#if QT_CONFIG(quicktemplates2_multitouch) +bool QQuickPopupPrivate::handleTouchEvent(QQuickItem *item, QTouchEvent *event) +{ + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + for (const QTouchEvent::TouchPoint &point : event->points()) { + if (event->type() != QEvent::TouchEnd && !acceptTouch(point)) + return blockInput(item, point.position()); + + switch (point.state()) { + case QEventPoint::Pressed: + return handlePress(item, item->mapToScene(point.position()), event->timestamp()); + case QEventPoint::Updated: + return handleMove(item, item->mapToScene(point.position()), event->timestamp()); + case QEventPoint::Released: + return handleRelease(item, item->mapToScene(point.position()), event->timestamp()); + default: + break; + } + } + break; + + case QEvent::TouchCancel: + handleUngrab(); + break; + + default: + break; + } + + return false; +} +#endif + +bool QQuickPopupPrivate::prepareEnterTransition() +{ + Q_Q(QQuickPopup); + if (!window) { + qmlWarning(q) << "cannot find any window to open popup in."; + return false; + } + + if (transitionState == EnterTransition && transitionManager.isRunning()) + return false; + + if (transitionState != EnterTransition) { + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + const auto popupStack = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups(); + popupItem->setParentItem(overlay); + // if there is a stack of popups, and the current top popup item belongs to an + // ancestor of this popup, then make sure that this popup's item is at the top + // of the stack. + const QQuickPopup *topPopup = popupStack.isEmpty() ? nullptr : popupStack.first(); + const QObject *ancestor = q; + while (ancestor && topPopup) { + if (ancestor == topPopup) + break; + ancestor = ancestor->parent(); + } + if (topPopup && topPopup != q && ancestor) { + QQuickItem *topPopupItem = popupStack.first()->popupItem(); + popupItem->stackAfter(topPopupItem); + // If the popup doesn't have an explicit z value set, set it to be at least as + // high as the current top popup item so that later opened popups are on top. + if (!hasZ) + popupItem->setZ(qMax(topPopupItem->z(), popupItem->z())); + } + if (dim) + createOverlay(); + showDimmer(); + emit q->aboutToShow(); + visible = true; + transitionState = EnterTransition; + popupItem->setVisible(true); + getPositioner()->setParentItem(parentItem); + emit q->visibleChanged(); + + auto *overlayPrivate = QQuickOverlayPrivate::get(overlay); + if (overlayPrivate->lastActiveFocusItem.isNull()) + overlayPrivate->lastActiveFocusItem = window->activeFocusItem(); + + if (focus) + popupItem->setFocus(true, Qt::PopupFocusReason); + } + return true; +} + +bool QQuickPopupPrivate::prepareExitTransition() +{ + Q_Q(QQuickPopup); + if (transitionState == ExitTransition && transitionManager.isRunning()) + return false; + + Q_ASSERT(popupItem); + + // We need to cache the original scale and opacity values so we can reset it after + // the exit transition is done so they have the original values again + prevScale = popupItem->scale(); + prevOpacity = popupItem->opacity(); + + if (transitionState != ExitTransition) { + // The setFocus(false) call below removes any active focus before we're + // able to check it in finalizeExitTransition. + if (!hadActiveFocusBeforeExitTransition) { + const auto *da = QQuickItemPrivate::get(popupItem)->deliveryAgentPrivate(); + hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus() || (da && da->focusTargetItem() == popupItem); + } + + if (focus) + popupItem->setFocus(false, Qt::PopupFocusReason); + transitionState = ExitTransition; + hideDimmer(); + emit q->aboutToHide(); + emit q->openedChanged(); + } + return true; +} + +void QQuickPopupPrivate::finalizeEnterTransition() +{ + Q_Q(QQuickPopup); + transitionState = NoTransition; + getPositioner()->reposition(); + emit q->openedChanged(); + opened(); +} + +void QQuickPopupPrivate::finalizeExitTransition() +{ + Q_Q(QQuickPopup); + getPositioner()->setParentItem(nullptr); + if (popupItem) { + popupItem->setParentItem(nullptr); + popupItem->setVisible(false); + } + destroyDimmer(); + + if (hadActiveFocusBeforeExitTransition && window) { + // restore focus to the next popup in chain, or to the window content if there are no other popups open + QQuickPopup *nextFocusPopup = nullptr; + if (QQuickOverlay *overlay = QQuickOverlay::overlay(window)) { + const auto stackingOrderPopups = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups(); + for (auto popup : stackingOrderPopups) { + if (QQuickPopupPrivate::get(popup)->transitionState != ExitTransition + && popup->hasFocus()) { + nextFocusPopup = popup; + break; + } + } + } + if (nextFocusPopup) { + nextFocusPopup->forceActiveFocus(Qt::PopupFocusReason); + } else { + auto *appWindow = qobject_cast<QQuickApplicationWindow*>(window); + auto *contentItem = appWindow ? appWindow->contentItem() : window->contentItem(); + auto *overlay = QQuickOverlay::overlay(window); + auto *overlayPrivate = QQuickOverlayPrivate::get(overlay); + if (!contentItem->scopedFocusItem() + && !overlayPrivate->lastActiveFocusItem.isNull()) { + overlayPrivate->lastActiveFocusItem->setFocus(true, Qt::OtherFocusReason); + } else { + contentItem->setFocus(true, Qt::PopupFocusReason); + } + overlayPrivate->lastActiveFocusItem = nullptr; + } + } + + visible = false; + transitionState = NoTransition; + hadActiveFocusBeforeExitTransition = false; + emit q->visibleChanged(); + emit q->closed(); + if (popupItem) { + popupItem->setScale(prevScale); + popupItem->setOpacity(prevOpacity); + } +} + +void QQuickPopupPrivate::opened() +{ + Q_Q(QQuickPopup); + emit q->opened(); +} + +QMarginsF QQuickPopupPrivate::getMargins() const +{ + Q_Q(const QQuickPopup); + return QMarginsF(q->leftMargin(), q->topMargin(), q->rightMargin(), q->bottomMargin()); +} + +void QQuickPopupPrivate::setTopMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->topMargin(); + topMargin = value; + hasTopMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->topMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(leftMargin, oldMargin, rightMargin, bottomMargin)); + } +} + +void QQuickPopupPrivate::setLeftMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->leftMargin(); + leftMargin = value; + hasLeftMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->leftMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(oldMargin, topMargin, rightMargin, bottomMargin)); + } +} + +void QQuickPopupPrivate::setRightMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->rightMargin(); + rightMargin = value; + hasRightMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->rightMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(leftMargin, topMargin, oldMargin, bottomMargin)); + } +} + +void QQuickPopupPrivate::setBottomMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->bottomMargin(); + bottomMargin = value; + hasBottomMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->bottomMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(leftMargin, topMargin, rightMargin, oldMargin)); + } +} + +/*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty Item QtQuick.Controls::Popup::anchors.centerIn + + Anchors provide a way to position an item by specifying its + relationship with other items. + + A common use case is to center a popup within its parent. One way to do + this is with the \l[QtQuick]{Item::}{x} and \l[QtQuick]{Item::}{y} properties. Anchors offer + a more convenient approach: + + \qml + Pane { + // ... + + Popup { + anchors.centerIn: parent + } + } + \endqml + + It is also possible to center the popup in the window by using \l Overlay: + + \snippet qtquickcontrols-popup.qml centerIn + + This makes it easy to center a popup in the window from any component. + + \note Popups can only be centered within their immediate parent or + the window overlay; trying to center in other items will produce a warning. + + \sa {Popup Positioning}, {Item::}{anchors}, {Using Qt Quick Controls types + in property declarations} +*/ +QQuickPopupAnchors *QQuickPopupPrivate::getAnchors() +{ + Q_Q(QQuickPopup); + if (!anchors) + anchors = new QQuickPopupAnchors(q); + return anchors; +} + +QQuickPopupPositioner *QQuickPopupPrivate::getPositioner() +{ + Q_Q(QQuickPopup); + if (!positioner) + positioner = new QQuickPopupPositioner(q); + return positioner; +} + +void QQuickPopupPrivate::setWindow(QQuickWindow *newWindow) +{ + Q_Q(QQuickPopup); + if (window == newWindow) + return; + + if (window) { + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + if (overlay) + QQuickOverlayPrivate::get(overlay)->removePopup(q); + } + + window = newWindow; + + if (newWindow) { + QQuickOverlay *overlay = QQuickOverlay::overlay(newWindow); + if (overlay) + QQuickOverlayPrivate::get(overlay)->addPopup(q); + + QQuickControlPrivate *p = QQuickControlPrivate::get(popupItem); + p->resolveFont(); + if (QQuickApplicationWindow *appWindow = qobject_cast<QQuickApplicationWindow *>(newWindow)) + p->updateLocale(appWindow->locale(), false); // explicit=false + } + + emit q->windowChanged(newWindow); + + if (complete && visible && window) + transitionManager.transitionEnter(); +} + +void QQuickPopupPrivate::itemDestroyed(QQuickItem *item) +{ + Q_Q(QQuickPopup); + if (item == parentItem) + q->setParentItem(nullptr); +} + +void QQuickPopupPrivate::reposition() +{ + getPositioner()->reposition(); +} + +QPalette QQuickPopupPrivate::defaultPalette() const +{ + return QQuickTheme::palette(QQuickTheme::System); +} + +static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQuickItem *parent) +{ + QQuickItem *item = nullptr; + if (component) { + QQmlContext *context = component->creationContext(); + if (!context) + context = qmlContext(popup); + item = qobject_cast<QQuickItem*>(component->beginCreate(context)); + } + + // when there is no overlay component available (with plain QQuickWindow), + // use a plain QQuickItem as a fallback to block hover events + if (!item && popup->isModal()) + item = new QQuickItem; + + if (item) { + item->setParentItem(parent); + item->stackBefore(popup->popupItem()); + item->setZ(popup->z()); + // needed for the virtual keyboard to set a containment mask on the dimmer item + qCDebug(lcDimmer) << "dimmer" << item << "registered with" << parent; + parent->setProperty("_q_dimmerItem", QVariant::fromValue<QQuickItem*>(item)); + if (popup->isModal()) { + item->setAcceptedMouseButtons(Qt::AllButtons); +#if QT_CONFIG(cursor) + item->setCursor(Qt::ArrowCursor); +#endif +#if QT_CONFIG(quicktemplates2_hover) + // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8 + item->setAcceptHoverEvents(true); + // item->setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects()); + // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, item, &QQuickItem::setAcceptHoverEvents); +#endif + } + if (component) + component->completeCreate(); + } + qCDebug(lcDimmer) << "finished creating dimmer from component" << component + << "for popup" << popup << "with parent" << parent << "- item is:" << item; + return item; +} + +void QQuickPopupPrivate::createOverlay() +{ + Q_Q(QQuickPopup); + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + if (!overlay) + return; + + QQmlComponent *component = nullptr; + QQuickOverlayAttached *overlayAttached = qobject_cast<QQuickOverlayAttached *>(qmlAttachedPropertiesObject<QQuickOverlay>(q, false)); + if (overlayAttached) + component = modal ? overlayAttached->modal() : overlayAttached->modeless(); + + if (!component) + component = modal ? overlay->modal() : overlay->modeless(); + + if (!dimmer) { + dimmer = createDimmer(component, q, overlay); + if (!dimmer) + return; + // We cannot update explicitDimmerOpacity when dimmer's opacity changes, + // as it is expected to do so when we fade the dimmer in and out in + // show/hideDimmer, and any binding of the dimmer's opacity will be + // implicitly broken anyway. + explicitDimmerOpacity = dimmer->opacity(); + // initially fully transparent, showDimmer fades the dimmer in. + dimmer->setOpacity(0); + if (q->isVisible()) + showDimmer(); + } + resizeDimmer(); +} + +void QQuickPopupPrivate::destroyDimmer() +{ + if (dimmer) { + qCDebug(lcDimmer) << "destroying dimmer" << dimmer; + if (QObject *dimmerParentItem = dimmer->parentItem()) { + if (dimmerParentItem->property("_q_dimmerItem").value<QQuickItem*>() == dimmer) + dimmerParentItem->setProperty("_q_dimmerItem", QVariant()); + } + dimmer->setParentItem(nullptr); + dimmer->deleteLater(); + dimmer = nullptr; + } +} + +void QQuickPopupPrivate::toggleOverlay() +{ + destroyDimmer(); + if (dim) + createOverlay(); +} + +void QQuickPopupPrivate::updateContentPalettes(const QPalette& parentPalette) +{ + // Inherit parent palette to all child objects + inheritPalette(parentPalette); + + // Inherit parent palette to items within popup (such as headers and footers) + QQuickItemPrivate::get(popupItem)->updateChildrenPalettes(parentPalette); +} + +void QQuickPopupPrivate::showDimmer() +{ + // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors + if (dim && dimmer) + QQmlProperty::write(dimmer, QStringLiteral("opacity"), explicitDimmerOpacity); +} + +void QQuickPopupPrivate::hideDimmer() +{ + // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors + if (dim && dimmer) + QQmlProperty::write(dimmer, QStringLiteral("opacity"), 0.0); +} + +void QQuickPopupPrivate::resizeDimmer() +{ + if (!dimmer) + return; + + const QQuickOverlay *overlay = QQuickOverlay::overlay(window); + + qreal w = overlay ? overlay->width() : 0; + qreal h = overlay ? overlay->height() : 0; + dimmer->setSize(QSizeF(w, h)); +} + +QQuickPopupTransitionManager::QQuickPopupTransitionManager(QQuickPopupPrivate *popup) + : popup(popup) +{ +} + +void QQuickPopupTransitionManager::transitionEnter() +{ + if (popup->transitionState == QQuickPopupPrivate::ExitTransition) + cancel(); + + if (!popup->prepareEnterTransition()) + return; + + if (popup->window) + transition(popup->enterActions, popup->enter, popup->q_func()); + else + finished(); +} + +void QQuickPopupTransitionManager::transitionExit() +{ + if (!popup->prepareExitTransition()) + return; + + if (popup->window) + transition(popup->exitActions, popup->exit, popup->q_func()); + else + finished(); +} + +void QQuickPopupTransitionManager::finished() +{ + if (popup->transitionState == QQuickPopupPrivate::EnterTransition) + popup->finalizeEnterTransition(); + else if (popup->transitionState == QQuickPopupPrivate::ExitTransition) + popup->finalizeExitTransition(); +} + +QQuickPopup::QQuickPopup(QObject *parent) + : QObject(*(new QQuickPopupPrivate), parent) +{ + Q_D(QQuickPopup); + d->init(); + // By default, allow popup to move beyond window edges + d->relaxEdgeConstraint = true; +} + +QQuickPopup::QQuickPopup(QQuickPopupPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ + Q_D(QQuickPopup); + d->init(); +} + +QQuickPopup::~QQuickPopup() +{ + Q_D(QQuickPopup); + d->inDestructor = true; + + QQuickItem *currentContentItem = d->popupItem->d_func()->contentItem.data(); + if (currentContentItem) { + disconnect(currentContentItem, &QQuickItem::childrenChanged, + this, &QQuickPopup::contentChildrenChanged); + } + + setParentItem(nullptr); + + // If the popup is destroyed before the exit transition finishes, + // the necessary cleanup (removing modal dimmers that block mouse events, + // emitting closed signal, etc.) won't happen. That's why we do it manually here. + if (d->transitionState == QQuickPopupPrivate::ExitTransition && d->transitionManager.isRunning()) + d->finalizeExitTransition(); + + delete d->popupItem; + d->popupItem = nullptr; + delete d->positioner; + d->positioner = nullptr; +} + +/*! + \qmlmethod void QtQuick.Controls::Popup::open() + + Opens the popup. + + \sa visible +*/ +void QQuickPopup::open() +{ + setVisible(true); +} + +/*! + \qmlmethod void QtQuick.Controls::Popup::close() + + Closes the popup. + + \sa visible +*/ +void QQuickPopup::close() +{ + setVisible(false); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::x + + This property holds the x-coordinate of the popup. + + \sa y, z +*/ +qreal QQuickPopup::x() const +{ + Q_D(const QQuickPopup); + return d->effectiveX; +} + +void QQuickPopup::setX(qreal x) +{ + Q_D(QQuickPopup); + setPosition(QPointF(x, d->y)); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::y + + This property holds the y-coordinate of the popup. + + \sa x, z +*/ +qreal QQuickPopup::y() const +{ + Q_D(const QQuickPopup); + return d->effectiveY; +} + +void QQuickPopup::setY(qreal y) +{ + Q_D(QQuickPopup); + setPosition(QPointF(d->x, y)); +} + +QPointF QQuickPopup::position() const +{ + Q_D(const QQuickPopup); + return QPointF(d->effectiveX, d->effectiveY); +} + +void QQuickPopup::setPosition(const QPointF &pos) +{ + Q_D(QQuickPopup); + const bool xChange = !qFuzzyCompare(d->x, pos.x()); + const bool yChange = !qFuzzyCompare(d->y, pos.y()); + if (!xChange && !yChange) + return; + + d->x = pos.x(); + d->y = pos.y(); + if (d->popupItem->isVisible()) { + d->reposition(); + } else { + if (xChange) + emit xChanged(); + if (yChange) + emit yChanged(); + } +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::z + + This property holds the z-value of the popup. Z-value determines + the stacking order of popups. + + If two visible popups have the same z-value, the last one that + was opened will be on top. + + If a popup has no explicitly set z-value when opened, and is a child + of an already open popup, then it will be stacked on top of its parent. + This ensures that children are never hidden under their parents. + + The default z-value is \c 0. + + \sa x, y +*/ +qreal QQuickPopup::z() const +{ + Q_D(const QQuickPopup); + return d->popupItem->z(); +} + +void QQuickPopup::setZ(qreal z) +{ + Q_D(QQuickPopup); + d->hasZ = true; + if (qFuzzyCompare(z, d->popupItem->z())) + return; + d->popupItem->setZ(z); + emit zChanged(); +} + +void QQuickPopup::resetZ() +{ + Q_D(QQuickPopup); + setZ(0); + d->hasZ = false; +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::width + + This property holds the width of the popup. +*/ +qreal QQuickPopup::width() const +{ + Q_D(const QQuickPopup); + return d->popupItem->width(); +} + +void QQuickPopup::setWidth(qreal width) +{ + Q_D(QQuickPopup); + d->hasWidth = true; + d->popupItem->setWidth(width); +} + +void QQuickPopup::resetWidth() +{ + Q_D(QQuickPopup); + if (!d->hasWidth) + return; + + d->hasWidth = false; + d->popupItem->resetWidth(); + if (d->popupItem->isVisible()) + d->reposition(); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::height + + This property holds the height of the popup. +*/ +qreal QQuickPopup::height() const +{ + Q_D(const QQuickPopup); + return d->popupItem->height(); +} + +void QQuickPopup::setHeight(qreal height) +{ + Q_D(QQuickPopup); + d->hasHeight = true; + d->popupItem->setHeight(height); +} + +void QQuickPopup::resetHeight() +{ + Q_D(QQuickPopup); + if (!d->hasHeight) + return; + + d->hasHeight = false; + d->popupItem->resetHeight(); + if (d->popupItem->isVisible()) + d->reposition(); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::implicitWidth + + This property holds the implicit width of the popup. +*/ +qreal QQuickPopup::implicitWidth() const +{ + Q_D(const QQuickPopup); + return d->popupItem->implicitWidth(); +} + +void QQuickPopup::setImplicitWidth(qreal width) +{ + Q_D(QQuickPopup); + d->popupItem->setImplicitWidth(width); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::implicitHeight + + This property holds the implicit height of the popup. +*/ +qreal QQuickPopup::implicitHeight() const +{ + Q_D(const QQuickPopup); + return d->popupItem->implicitHeight(); +} + +void QQuickPopup::setImplicitHeight(qreal height) +{ + Q_D(QQuickPopup); + d->popupItem->setImplicitHeight(height); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::contentWidth + + This property holds the content width. It is used for calculating the + total implicit width of the Popup. + + For more information, see \l {Popup Sizing}. + + \sa contentHeight +*/ +qreal QQuickPopup::contentWidth() const +{ + Q_D(const QQuickPopup); + return d->popupItem->contentWidth(); +} + +void QQuickPopup::setContentWidth(qreal width) +{ + Q_D(QQuickPopup); + d->popupItem->setContentWidth(width); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::contentHeight + + This property holds the content height. It is used for calculating the + total implicit height of the Popup. + + For more information, see \l {Popup Sizing}. + + \sa contentWidth +*/ +qreal QQuickPopup::contentHeight() const +{ + Q_D(const QQuickPopup); + return d->popupItem->contentHeight(); +} + +void QQuickPopup::setContentHeight(qreal height) +{ + Q_D(QQuickPopup); + d->popupItem->setContentHeight(height); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::availableWidth + \readonly + + This property holds the width available to the \l contentItem after + deducting horizontal padding from the \l {Item::}{width} of the popup. + + \sa padding, leftPadding, rightPadding +*/ +qreal QQuickPopup::availableWidth() const +{ + Q_D(const QQuickPopup); + return d->popupItem->availableWidth(); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::availableHeight + \readonly + + This property holds the height available to the \l contentItem after + deducting vertical padding from the \l {Item::}{height} of the popup. + + \sa padding, topPadding, bottomPadding +*/ +qreal QQuickPopup::availableHeight() const +{ + Q_D(const QQuickPopup); + return d->popupItem->availableHeight(); +} + +/*! + \since QtQuick.Controls 2.1 (Qt 5.8) + \qmlproperty real QtQuick.Controls::Popup::spacing + + This property holds the spacing. + + Spacing is useful for popups that have multiple or repetitive building + blocks. For example, some styles use spacing to determine the distance + between the header, content, and footer of \l Dialog. Spacing is not + enforced by Popup, so each style may interpret it differently, and some + may ignore it altogether. +*/ +qreal QQuickPopup::spacing() const +{ + Q_D(const QQuickPopup); + return d->popupItem->spacing(); +} + +void QQuickPopup::setSpacing(qreal spacing) +{ + Q_D(QQuickPopup); + d->popupItem->setSpacing(spacing); +} + +void QQuickPopup::resetSpacing() +{ + setSpacing(0); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::margins + + This property holds the distance between the edges of the popup and the + edges of its window. + + A popup with negative margins is not pushed within the bounds + of the enclosing window. The default value is \c -1. + + \sa topMargin, leftMargin, rightMargin, bottomMargin, {Popup Layout} +*/ +qreal QQuickPopup::margins() const +{ + Q_D(const QQuickPopup); + return d->margins; +} + +void QQuickPopup::setMargins(qreal margins) +{ + Q_D(QQuickPopup); + if (qFuzzyCompare(d->margins, margins)) + return; + QMarginsF oldMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin()); + d->margins = margins; + emit marginsChanged(); + QMarginsF newMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin()); + if (!qFuzzyCompare(newMargins.top(), oldMargins.top())) + emit topMarginChanged(); + if (!qFuzzyCompare(newMargins.left(), oldMargins.left())) + emit leftMarginChanged(); + if (!qFuzzyCompare(newMargins.right(), oldMargins.right())) + emit rightMarginChanged(); + if (!qFuzzyCompare(newMargins.bottom(), oldMargins.bottom())) + emit bottomMarginChanged(); + marginsChange(newMargins, oldMargins); +} + +void QQuickPopup::resetMargins() +{ + setMargins(-1); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::topMargin + + This property holds the distance between the top edge of the popup and + the top edge of its window. + + A popup with a negative top margin is not pushed within the top edge + of the enclosing window. The default value is \c -1. + + \sa margins, bottomMargin, {Popup Layout} +*/ +qreal QQuickPopup::topMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasTopMargin) + return d->topMargin; + return d->margins; +} + +void QQuickPopup::setTopMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setTopMargin(margin); +} + +void QQuickPopup::resetTopMargin() +{ + Q_D(QQuickPopup); + d->setTopMargin(-1, true); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::leftMargin + + This property holds the distance between the left edge of the popup and + the left edge of its window. + + A popup with a negative left margin is not pushed within the left edge + of the enclosing window. The default value is \c -1. + + \sa margins, rightMargin, {Popup Layout} +*/ +qreal QQuickPopup::leftMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasLeftMargin) + return d->leftMargin; + return d->margins; +} + +void QQuickPopup::setLeftMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setLeftMargin(margin); +} + +void QQuickPopup::resetLeftMargin() +{ + Q_D(QQuickPopup); + d->setLeftMargin(-1, true); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::rightMargin + + This property holds the distance between the right edge of the popup and + the right edge of its window. + + A popup with a negative right margin is not pushed within the right edge + of the enclosing window. The default value is \c -1. + + \sa margins, leftMargin, {Popup Layout} +*/ +qreal QQuickPopup::rightMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasRightMargin) + return d->rightMargin; + return d->margins; +} + +void QQuickPopup::setRightMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setRightMargin(margin); +} + +void QQuickPopup::resetRightMargin() +{ + Q_D(QQuickPopup); + d->setRightMargin(-1, true); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::bottomMargin + + This property holds the distance between the bottom edge of the popup and + the bottom edge of its window. + + A popup with a negative bottom margin is not pushed within the bottom edge + of the enclosing window. The default value is \c -1. + + \sa margins, topMargin, {Popup Layout} +*/ +qreal QQuickPopup::bottomMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasBottomMargin) + return d->bottomMargin; + return d->margins; +} + +void QQuickPopup::setBottomMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setBottomMargin(margin); +} + +void QQuickPopup::resetBottomMargin() +{ + Q_D(QQuickPopup); + d->setBottomMargin(-1, true); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::padding + + This property holds the default padding. + + \include qquickpopup-padding.qdocinc + + \sa availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding +*/ +qreal QQuickPopup::padding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->padding(); +} + +void QQuickPopup::setPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setPadding(padding); +} + +void QQuickPopup::resetPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetPadding(); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::topPadding + + This property holds the top padding. Unless explicitly set, the value + is equal to \c verticalPadding. + + \include qquickpopup-padding.qdocinc + + \sa padding, bottomPadding, verticalPadding, availableHeight +*/ +qreal QQuickPopup::topPadding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->topPadding(); +} + +void QQuickPopup::setTopPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setTopPadding(padding); +} + +void QQuickPopup::resetTopPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetTopPadding(); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::leftPadding + + This property holds the left padding. Unless explicitly set, the value + is equal to \c horizontalPadding. + + \include qquickpopup-padding.qdocinc + + \sa padding, rightPadding, horizontalPadding, availableWidth +*/ +qreal QQuickPopup::leftPadding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->leftPadding(); +} + +void QQuickPopup::setLeftPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setLeftPadding(padding); +} + +void QQuickPopup::resetLeftPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetLeftPadding(); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::rightPadding + + This property holds the right padding. Unless explicitly set, the value + is equal to \c horizontalPadding. + + \include qquickpopup-padding.qdocinc + + \sa padding, leftPadding, horizontalPadding, availableWidth +*/ +qreal QQuickPopup::rightPadding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->rightPadding(); +} + +void QQuickPopup::setRightPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setRightPadding(padding); +} + +void QQuickPopup::resetRightPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetRightPadding(); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::bottomPadding + + This property holds the bottom padding. Unless explicitly set, the value + is equal to \c verticalPadding. + + \include qquickpopup-padding.qdocinc + + \sa padding, topPadding, verticalPadding, availableHeight +*/ +qreal QQuickPopup::bottomPadding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->bottomPadding(); +} + +void QQuickPopup::setBottomPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setBottomPadding(padding); +} + +void QQuickPopup::resetBottomPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetBottomPadding(); +} + +/*! + \qmlproperty Locale QtQuick.Controls::Popup::locale + + This property holds the locale of the popup. + + \sa mirrored, {LayoutMirroring}{LayoutMirroring} +*/ +QLocale QQuickPopup::locale() const +{ + Q_D(const QQuickPopup); + return d->popupItem->locale(); +} + +void QQuickPopup::setLocale(const QLocale &locale) +{ + Q_D(QQuickPopup); + d->popupItem->setLocale(locale); +} + +void QQuickPopup::resetLocale() +{ + Q_D(QQuickPopup); + d->popupItem->resetLocale(); +} + +/*! + \since QtQuick.Controls 2.3 (Qt 5.10) + \qmlproperty bool QtQuick.Controls::Popup::mirrored + \readonly + + This property holds whether the popup is mirrored. + + This property is provided for convenience. A popup is considered mirrored + when its visual layout direction is right-to-left; that is, when using a + right-to-left locale. + + \sa locale, {Right-to-left User Interfaces} +*/ +bool QQuickPopup::isMirrored() const +{ + Q_D(const QQuickPopup); + return d->popupItem->isMirrored(); +} + +/*! + \qmlproperty font QtQuick.Controls::Popup::font + + This property holds the font currently set for the popup. + + Popup propagates explicit font properties to its children. If you change a specific + property on a popup's font, that property propagates to all of the popup's children, + overriding any system defaults for that property. + + \code + Popup { + font.family: "Courier" + + Column { + Label { + text: qsTr("This will use Courier...") + } + + Switch { + text: qsTr("... and so will this") + } + } + } + \endcode + + \sa Control::font, ApplicationWindow::font +*/ +QFont QQuickPopup::font() const +{ + Q_D(const QQuickPopup); + return d->popupItem->font(); +} + +void QQuickPopup::setFont(const QFont &font) +{ + Q_D(QQuickPopup); + d->popupItem->setFont(font); +} + +void QQuickPopup::resetFont() +{ + Q_D(QQuickPopup); + d->popupItem->resetFont(); +} + +QQuickWindow *QQuickPopup::window() const +{ + Q_D(const QQuickPopup); + return d->window; +} + +QQuickItem *QQuickPopup::popupItem() const +{ + Q_D(const QQuickPopup); + return d->popupItem; +} + +/*! + \qmlproperty Item QtQuick.Controls::Popup::parent + + This property holds the parent item. +*/ +QQuickItem *QQuickPopup::parentItem() const +{ + Q_D(const QQuickPopup); + return d->parentItem; +} + +void QQuickPopup::setParentItem(QQuickItem *parent) +{ + Q_D(QQuickPopup); + if (d->parentItem == parent) + return; + + if (d->parentItem) { + QObjectPrivate::disconnect(d->parentItem, &QQuickItem::windowChanged, d, &QQuickPopupPrivate::setWindow); + QQuickItemPrivate::get(d->parentItem)->removeItemChangeListener(d, QQuickItemPrivate::Destroyed); + } + d->parentItem = parent; + QQuickPopupPositioner *positioner = d->getPositioner(); + if (positioner->parentItem()) + positioner->setParentItem(parent); + if (parent) { + QObjectPrivate::connect(parent, &QQuickItem::windowChanged, d, &QQuickPopupPrivate::setWindow); + QQuickItemPrivate::get(d->parentItem)->addItemChangeListener(d, QQuickItemPrivate::Destroyed); + } else if (d->inDestructor) { + d->destroyDimmer(); + } else { + // Reset transition manager state when its parent window destroyed + if (!d->window && d->transitionManager.isRunning()) { + if (d->transitionState == QQuickPopupPrivate::EnterTransition) + d->finalizeEnterTransition(); + else if (d->transitionState == QQuickPopupPrivate::ExitTransition) + d->finalizeExitTransition(); + } + // NOTE: if setParentItem is called from the dtor, this bypasses virtual dispatch and calls + // QQuickPopup::close() directly + close(); + } + d->setWindow(parent ? parent->window() : nullptr); + emit parentChanged(); +} + +void QQuickPopup::resetParentItem() +{ + if (QQuickWindow *window = qobject_cast<QQuickWindow *>(parent())) + setParentItem(window->contentItem()); + else + setParentItem(qobject_cast<QQuickItem *>(parent())); +} + +/*! + \qmlproperty Item QtQuick.Controls::Popup::background + + This property holds the background item. + + \note If the background item has no explicit size specified, it automatically + follows the popup's size. In most cases, there is no need to specify + width or height for a background item. + + \note Most popups use the implicit size of the background item to calculate + the implicit size of the popup itself. If you replace the background item + with a custom one, you should also consider providing a sensible implicit + size for it (unless it is an item like \l Image which has its own implicit + size). + + \sa {Customizing Popup} +*/ +QQuickItem *QQuickPopup::background() const +{ + Q_D(const QQuickPopup); + return d->popupItem->background(); +} + +void QQuickPopup::setBackground(QQuickItem *background) +{ + Q_D(QQuickPopup); + // The __notCustomizable property won't be on "this" when the popup item's setBackground function + // is called, so it won't warn. That's why we do a check here. + QQuickControlPrivate::warnIfCustomizationNotSupported(this, background, QStringLiteral("background")); + d->popupItem->setBackground(background); +} + +/*! + \qmlproperty Item QtQuick.Controls::Popup::contentItem + + This property holds the content item of the popup. + + The content item is the visual implementation of the popup. When the + popup is made visible, the content item is automatically reparented to + the \l {Overlay::overlay}{overlay item}. + + \note The content item is automatically resized to fit within the + \l padding of the popup. + + \note Most popups use the implicit size of the content item to calculate + the implicit size of the popup itself. If you replace the content item + with a custom one, you should also consider providing a sensible implicit + size for it (unless it is an item like \l Text which has its own implicit + size). + + \sa {Customizing Popup} +*/ +QQuickItem *QQuickPopup::contentItem() const +{ + Q_D(const QQuickPopup); + return d->popupItem->contentItem(); +} + +void QQuickPopup::setContentItem(QQuickItem *item) +{ + Q_D(QQuickPopup); + // See comment in setBackground for why we do this. + QQuickControlPrivate::warnIfCustomizationNotSupported(this, item, QStringLiteral("contentItem")); + QQuickItem *oldContentItem = d->complete ? d->popupItem->d_func()->contentItem.data() + : nullptr; + if (oldContentItem) + disconnect(oldContentItem, &QQuickItem::childrenChanged, this, &QQuickPopup::contentChildrenChanged); + d->popupItem->setContentItem(item); + if (d->complete) { + QQuickItem *newContentItem = d->popupItem->d_func()->contentItem.data(); + connect(newContentItem, &QQuickItem::childrenChanged, this, &QQuickPopup::contentChildrenChanged); + if (oldContentItem != newContentItem) + emit contentChildrenChanged(); + } +} + +/*! + \qmlproperty list<QtObject> QtQuick.Controls::Popup::contentData + \qmldefault + + This property holds the list of content data. + + The list contains all objects that have been declared in QML as children + of the popup. + + \note Unlike \c contentChildren, \c contentData does include non-visual QML + objects. + + \sa Item::data, contentChildren +*/ +QQmlListProperty<QObject> QQuickPopupPrivate::contentData() +{ + QQuickControlPrivate *p = QQuickControlPrivate::get(popupItem); + if (!p->contentItem) + p->executeContentItem(); + return QQmlListProperty<QObject>(popupItem->contentItem(), nullptr, + QQuickItemPrivate::data_append, + QQuickItemPrivate::data_count, + QQuickItemPrivate::data_at, + QQuickItemPrivate::data_clear); +} + +/*! + \qmlproperty list<Item> QtQuick.Controls::Popup::contentChildren + + This property holds the list of content children. + + The list contains all items that have been declared in QML as children + of the popup. + + \note Unlike \c contentData, \c contentChildren does not include non-visual + QML objects. + + \sa Item::children, contentData +*/ +QQmlListProperty<QQuickItem> QQuickPopupPrivate::contentChildren() +{ + return QQmlListProperty<QQuickItem>(popupItem->contentItem(), nullptr, + QQuickItemPrivate::children_append, + QQuickItemPrivate::children_count, + QQuickItemPrivate::children_at, + QQuickItemPrivate::children_clear); +} + +/*! + \qmlproperty bool QtQuick.Controls::Popup::clip + + This property holds whether clipping is enabled. The default value is \c false. +*/ +bool QQuickPopup::clip() const +{ + Q_D(const QQuickPopup); + return d->popupItem->clip(); +} + +void QQuickPopup::setClip(bool clip) +{ + Q_D(QQuickPopup); + if (clip == d->popupItem->clip()) + return; + d->popupItem->setClip(clip); + emit clipChanged(); +} + +/*! + \qmlproperty bool QtQuick.Controls::Popup::focus + + This property holds whether the popup wants focus. + + When the popup actually receives focus, \l activeFocus will be \c true. + For more information, see \l {Keyboard Focus in Qt Quick}. + + The default value is \c false. + + \sa activeFocus +*/ +bool QQuickPopup::hasFocus() const +{ + Q_D(const QQuickPopup); + return d->focus; +} + +void QQuickPopup::setFocus(bool focus) +{ + Q_D(QQuickPopup); + if (d->focus == focus) + return; + d->focus = focus; + emit focusChanged(); +} + +/*! + \qmlproperty bool QtQuick.Controls::Popup::activeFocus + \readonly + + This property holds whether the popup has active focus. + + \sa focus, {Keyboard Focus in Qt Quick} +*/ +bool QQuickPopup::hasActiveFocus() const +{ + Q_D(const QQuickPopup); + return d->popupItem->hasActiveFocus(); +} + +/*! + \qmlproperty bool QtQuick.Controls::Popup::modal + + This property holds whether the popup is modal. + + Modal popups often have a distinctive background dimming effect defined + in \l {Overlay::modal}{Overlay.modal}, and do not allow press + or release events through to items beneath them. For example, if the user + accidentally clicks outside of a popup, any item beneath that popup at + the location of the click will not receive the event. + + On desktop platforms, it is common for modal popups to be closed only when + the escape key is pressed. To achieve this behavior, set + \l closePolicy to \c Popup.CloseOnEscape. By default, \c closePolicy + is set to \c {Popup.CloseOnEscape | Popup.CloseOnPressOutside}, which + means that clicking outside of a modal popup will close it. + + The default value is \c false. + + \sa dim +*/ +bool QQuickPopup::isModal() const +{ + Q_D(const QQuickPopup); + return d->modal; +} + +void QQuickPopup::setModal(bool modal) +{ + Q_D(QQuickPopup); + if (d->modal == modal) + return; + d->modal = modal; + if (d->complete && d->visible) + d->toggleOverlay(); + emit modalChanged(); + + QQuickItemPrivate::get(d->popupItem)->isTabFence = modal; + + if (!d->hasDim) { + setDim(modal); + d->hasDim = false; + } +} + +/*! + \qmlproperty bool QtQuick.Controls::Popup::dim + + This property holds whether the popup dims the background. + + Unless explicitly set, this property follows the value of \l modal. To + return to the default value, set this property to \c undefined. + + \sa modal, {Overlay::modeless}{Overlay.modeless} +*/ +bool QQuickPopup::dim() const +{ + Q_D(const QQuickPopup); + return d->dim; +} + +void QQuickPopup::setDim(bool dim) +{ + Q_D(QQuickPopup); + d->hasDim = true; + + if (d->dim == dim) + return; + + d->dim = dim; + if (d->complete && d->visible) + d->toggleOverlay(); + emit dimChanged(); +} + +void QQuickPopup::resetDim() +{ + Q_D(QQuickPopup); + if (!d->hasDim) + return; + + setDim(d->modal); + d->hasDim = false; +} + +/*! + \qmlproperty bool QtQuick.Controls::Popup::visible + + This property holds whether the popup is visible. The default value is \c false. + + \sa open(), close(), opened +*/ +bool QQuickPopup::isVisible() const +{ + Q_D(const QQuickPopup); + return d->visible && d->popupItem->isVisible(); +} + +void QQuickPopup::setVisible(bool visible) +{ + Q_D(QQuickPopup); + if (d->visible == visible && d->transitionState != QQuickPopupPrivate::ExitTransition) + return; + + if (!d->complete || (visible && !d->window)) { + d->visible = visible; + return; + } + + if (visible) + d->transitionManager.transitionEnter(); + else + d->transitionManager.transitionExit(); +} + +/*! + \since QtQuick.Controls 2.3 (Qt 5.10) + \qmlproperty bool QtQuick.Controls::Popup::enabled + + This property holds whether the popup is enabled. The default value is \c true. + + \sa visible, Item::enabled +*/ +bool QQuickPopup::isEnabled() const +{ + Q_D(const QQuickPopup); + return d->popupItem->isEnabled(); +} + +void QQuickPopup::setEnabled(bool enabled) +{ + Q_D(QQuickPopup); + d->popupItem->setEnabled(enabled); +} + +/*! + \since QtQuick.Controls 2.3 (Qt 5.10) + \qmlproperty bool QtQuick.Controls::Popup::opened + + This property holds whether the popup is fully open. The popup is considered opened + when it's visible and neither the \l enter nor \l exit transitions are running. + + \sa open(), close(), visible +*/ +bool QQuickPopup::isOpened() const +{ + Q_D(const QQuickPopup); + return d->transitionState == QQuickPopupPrivate::NoTransition && isVisible(); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::opacity + + This property holds the opacity of the popup. Opacity is specified as a number between + \c 0.0 (fully transparent) and \c 1.0 (fully opaque). The default value is \c 1.0. + + \sa visible +*/ +qreal QQuickPopup::opacity() const +{ + Q_D(const QQuickPopup); + return d->popupItem->opacity(); +} + +void QQuickPopup::setOpacity(qreal opacity) +{ + Q_D(QQuickPopup); + d->popupItem->setOpacity(opacity); +} + +/*! + \qmlproperty real QtQuick.Controls::Popup::scale + + This property holds the scale factor of the popup. The default value is \c 1.0. + + A scale of less than \c 1.0 causes the popup to be rendered at a smaller size, + and a scale greater than \c 1.0 renders the popup at a larger size. Negative + scales are not supported. +*/ +qreal QQuickPopup::scale() const +{ + Q_D(const QQuickPopup); + return d->popupItem->scale(); +} + +void QQuickPopup::setScale(qreal scale) +{ + Q_D(QQuickPopup); + if (qFuzzyCompare(scale, d->popupItem->scale())) + return; + d->popupItem->setScale(scale); + emit scaleChanged(); +} + +/*! + \qmlproperty enumeration QtQuick.Controls::Popup::closePolicy + + This property determines the circumstances under which the popup closes. + The flags can be combined to allow several ways of closing the popup. + + The available values are: + \value Popup.NoAutoClose The popup will only close when manually instructed to do so. + \value Popup.CloseOnPressOutside The popup will close when the mouse is pressed outside of it. + \value Popup.CloseOnPressOutsideParent The popup will close when the mouse is pressed outside of its parent. + \value Popup.CloseOnReleaseOutside The popup will close when the mouse is released outside of it. + \value Popup.CloseOnReleaseOutsideParent The popup will close when the mouse is released outside of its parent. + \value Popup.CloseOnEscape The popup will close when the escape key is pressed while the popup + has active focus. + + The \c {CloseOnPress*} and \c {CloseOnRelease*} policies only apply for events + outside of popups. That is, if there are two popups open and the first has + \c Popup.CloseOnPressOutside as its policy, clicking on the second popup will + not result in the first closing. + + The default value is \c {Popup.CloseOnEscape | Popup.CloseOnPressOutside}. + + \note There is a known limitation that the \c Popup.CloseOnReleaseOutside + and \c Popup.CloseOnReleaseOutsideParent policies only work with + \l modal popups. +*/ +QQuickPopup::ClosePolicy QQuickPopup::closePolicy() const +{ + Q_D(const QQuickPopup); + return d->closePolicy; +} + +void QQuickPopup::setClosePolicy(ClosePolicy policy) +{ + Q_D(QQuickPopup); + d->hasClosePolicy = true; + if (d->closePolicy == policy) + return; + d->closePolicy = policy; + emit closePolicyChanged(); +} + +void QQuickPopup::resetClosePolicy() +{ + Q_D(QQuickPopup); + setClosePolicy(QQuickPopupPrivate::DefaultClosePolicy); + d->hasClosePolicy = false; +} + +/*! + \qmlproperty enumeration QtQuick.Controls::Popup::transformOrigin + + This property holds the origin point for transformations in enter and exit transitions. + + Nine transform origins are available, as shown in the image below. + The default transform origin is \c Popup.Center. + + \image qtquickcontrols-popup-transformorigin.png + + \sa enter, exit, Item::transformOrigin +*/ +QQuickPopup::TransformOrigin QQuickPopup::transformOrigin() const +{ + Q_D(const QQuickPopup); + return static_cast<TransformOrigin>(d->popupItem->transformOrigin()); +} + +void QQuickPopup::setTransformOrigin(TransformOrigin origin) +{ + Q_D(QQuickPopup); + d->popupItem->setTransformOrigin(static_cast<QQuickItem::TransformOrigin>(origin)); +} + +/*! + \qmlproperty Transition QtQuick.Controls::Popup::enter + + This property holds the transition that is applied to the popup item + when the popup is opened and enters the screen. + + The following example animates the opacity of the popup when it enters + the screen: + \code + Popup { + enter: Transition { + NumberAnimation { property: "opacity"; from: 0.0; to: 1.0 } + } + } + \endcode + + \sa exit +*/ +QQuickTransition *QQuickPopup::enter() const +{ + Q_D(const QQuickPopup); + return d->enter; +} + +void QQuickPopup::setEnter(QQuickTransition *transition) +{ + Q_D(QQuickPopup); + if (d->enter == transition) + return; + d->enter = transition; + emit enterChanged(); +} + +/*! + \qmlproperty Transition QtQuick.Controls::Popup::exit + + This property holds the transition that is applied to the popup item + when the popup is closed and exits the screen. + + The following example animates the opacity of the popup when it exits + the screen: + \code + Popup { + exit: Transition { + NumberAnimation { property: "opacity"; from: 1.0; to: 0.0 } + } + } + \endcode + + \sa enter +*/ +QQuickTransition *QQuickPopup::exit() const +{ + Q_D(const QQuickPopup); + return d->exit; +} + +void QQuickPopup::setExit(QQuickTransition *transition) +{ + Q_D(QQuickPopup); + if (d->exit == transition) + return; + d->exit = transition; + emit exitChanged(); +} + +/*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty real QtQuick.Controls::Popup::horizontalPadding + + This property holds the horizontal padding. Unless explicitly set, the value + is equal to \c padding. + + \include qquickpopup-padding.qdocinc + + \sa padding, leftPadding, rightPadding, verticalPadding +*/ +qreal QQuickPopup::horizontalPadding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->horizontalPadding(); +} + +void QQuickPopup::setHorizontalPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setHorizontalPadding(padding); +} + +void QQuickPopup::resetHorizontalPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetHorizontalPadding(); +} + +/*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty real QtQuick.Controls::Popup::verticalPadding + + This property holds the vertical padding. Unless explicitly set, the value + is equal to \c padding. + + \include qquickpopup-padding.qdocinc + + \sa padding, topPadding, bottomPadding, horizontalPadding +*/ +qreal QQuickPopup::verticalPadding() const +{ + Q_D(const QQuickPopup); + return d->popupItem->verticalPadding(); +} + +void QQuickPopup::setVerticalPadding(qreal padding) +{ + Q_D(QQuickPopup); + d->popupItem->setVerticalPadding(padding); +} + +void QQuickPopup::resetVerticalPadding() +{ + Q_D(QQuickPopup); + d->popupItem->resetVerticalPadding(); +} + +/*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty real QtQuick.Controls::Popup::implicitContentWidth + \readonly + + This property holds the implicit content width. + + The value is calculated based on the content children. + + \sa implicitContentHeight, implicitBackgroundWidth +*/ +qreal QQuickPopup::implicitContentWidth() const +{ + Q_D(const QQuickPopup); + return d->popupItem->implicitContentWidth(); +} + +/*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty real QtQuick.Controls::Popup::implicitContentHeight + \readonly + + This property holds the implicit content height. + + The value is calculated based on the content children. + + \sa implicitContentWidth, implicitBackgroundHeight +*/ +qreal QQuickPopup::implicitContentHeight() const +{ + Q_D(const QQuickPopup); + return d->popupItem->implicitContentHeight(); +} + +/*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty real QtQuick.Controls::Popup::implicitBackgroundWidth + \readonly + + This property holds the implicit background width. + + The value is equal to \c {background ? background.implicitWidth : 0}. + + \sa implicitBackgroundHeight, implicitContentWidth +*/ +qreal QQuickPopup::implicitBackgroundWidth() const +{ + Q_D(const QQuickPopup); + return d->popupItem->implicitBackgroundWidth(); +} + +/*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty real QtQuick.Controls::Popup::implicitBackgroundHeight + \readonly + + This property holds the implicit background height. + + The value is equal to \c {background ? background.implicitHeight : 0}. + + \sa implicitBackgroundWidth, implicitContentHeight +*/ +qreal QQuickPopup::implicitBackgroundHeight() const +{ + Q_D(const QQuickPopup); + return d->popupItem->implicitBackgroundHeight(); +} + +/*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty real QtQuick.Controls::Popup::topInset + + This property holds the top inset for the background. + + \sa {Popup Layout}, bottomInset +*/ +qreal QQuickPopup::topInset() const +{ + Q_D(const QQuickPopup); + return d->popupItem->topInset(); +} + +void QQuickPopup::setTopInset(qreal inset) +{ + Q_D(QQuickPopup); + d->popupItem->setTopInset(inset); +} + +void QQuickPopup::resetTopInset() +{ + Q_D(QQuickPopup); + d->popupItem->resetTopInset(); +} + +/*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty real QtQuick.Controls::Popup::leftInset + + This property holds the left inset for the background. + + \sa {Popup Layout}, rightInset +*/ +qreal QQuickPopup::leftInset() const +{ + Q_D(const QQuickPopup); + return d->popupItem->leftInset(); +} + +void QQuickPopup::setLeftInset(qreal inset) +{ + Q_D(QQuickPopup); + d->popupItem->setLeftInset(inset); +} + +void QQuickPopup::resetLeftInset() +{ + Q_D(QQuickPopup); + d->popupItem->resetLeftInset(); +} + +/*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty real QtQuick.Controls::Popup::rightInset + + This property holds the right inset for the background. + + \sa {Popup Layout}, leftInset +*/ +qreal QQuickPopup::rightInset() const +{ + Q_D(const QQuickPopup); + return d->popupItem->rightInset(); +} + +void QQuickPopup::setRightInset(qreal inset) +{ + Q_D(QQuickPopup); + d->popupItem->setRightInset(inset); +} + +void QQuickPopup::resetRightInset() +{ + Q_D(QQuickPopup); + d->popupItem->resetRightInset(); +} + +/*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty real QtQuick.Controls::Popup::bottomInset + + This property holds the bottom inset for the background. + + \sa {Popup Layout}, topInset +*/ +qreal QQuickPopup::bottomInset() const +{ + Q_D(const QQuickPopup); + return d->popupItem->bottomInset(); +} + +void QQuickPopup::setBottomInset(qreal inset) +{ + Q_D(QQuickPopup); + d->popupItem->setBottomInset(inset); +} + +void QQuickPopup::resetBottomInset() +{ + Q_D(QQuickPopup); + d->popupItem->resetBottomInset(); +} + +/*! + \since QtQuick.Controls 2.3 (Qt 5.10) + \qmlproperty palette QtQuick.Controls::Popup::palette + + This property holds the palette currently set for the popup. + + Popup propagates explicit palette properties to its children. If you change a specific + property on a popup's palette, that property propagates to all of the popup's children, + overriding any system defaults for that property. + + \code + Popup { + palette.text: "red" + + Column { + Label { + text: qsTr("This will use red color...") + } + + Switch { + text: qsTr("... and so will this") + } + } + } + \endcode + + \sa Item::palette, Window::palette, ColorGroup, Palette +*/ + +bool QQuickPopup::filtersChildMouseEvents() const +{ + Q_D(const QQuickPopup); + return d->popupItem->filtersChildMouseEvents(); +} + +void QQuickPopup::setFiltersChildMouseEvents(bool filter) +{ + Q_D(QQuickPopup); + d->popupItem->setFiltersChildMouseEvents(filter); +} + +/*! + \qmlmethod QtQuick.Controls::Popup::forceActiveFocus(enumeration reason = Qt.OtherFocusReason) + + Forces active focus on the popup with the given \a reason. + + This method sets focus on the popup and ensures that all ancestor + \l FocusScope objects in the object hierarchy are also given \l focus. + + \sa activeFocus, Qt::FocusReason +*/ +void QQuickPopup::forceActiveFocus(Qt::FocusReason reason) +{ + Q_D(QQuickPopup); + d->popupItem->forceActiveFocus(reason); +} + +void QQuickPopup::classBegin() +{ + Q_D(QQuickPopup); + d->complete = false; + QQmlContext *context = qmlContext(this); + if (context) + QQmlEngine::setContextForObject(d->popupItem, context); + d->popupItem->classBegin(); +} + +void QQuickPopup::componentComplete() +{ + Q_D(QQuickPopup); + qCDebug(lcPopup) << "componentComplete" << this; + if (!parentItem()) + resetParentItem(); + + if (d->visible && d->window) + d->transitionManager.transitionEnter(); + + d->complete = true; + d->popupItem->componentComplete(); + + if (auto currentContentItem = d->popupItem->d_func()->contentItem.data()) { + connect(currentContentItem, &QQuickItem::childrenChanged, + this, &QQuickPopup::contentChildrenChanged); + } +} + +bool QQuickPopup::isComponentComplete() const +{ + Q_D(const QQuickPopup); + return d->complete; +} + +bool QQuickPopup::childMouseEventFilter(QQuickItem *child, QEvent *event) +{ + Q_UNUSED(child); + Q_UNUSED(event); + return false; +} + +void QQuickPopup::focusInEvent(QFocusEvent *event) +{ + event->accept(); +} + +void QQuickPopup::focusOutEvent(QFocusEvent *event) +{ + event->accept(); +} + +void QQuickPopup::keyPressEvent(QKeyEvent *event) +{ + Q_D(QQuickPopup); + if (!hasActiveFocus()) + return; + +#if QT_CONFIG(shortcut) + if (d->closePolicy.testFlag(QQuickPopup::CloseOnEscape) + && (event->matches(QKeySequence::Cancel) +#if defined(Q_OS_ANDROID) + || event->key() == Qt::Key_Back +#endif + )) { + event->accept(); + if (d->interactive) + d->closeOrReject(); + return; + } +#endif + + if (hasActiveFocus() && (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab)) { + event->accept(); + QQuickItemPrivate::focusNextPrev(d->popupItem, event->key() == Qt::Key_Tab); + } +} + +void QQuickPopup::keyReleaseEvent(QKeyEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mousePressEvent(QMouseEvent *event) +{ + Q_D(QQuickPopup); + event->setAccepted(d->handleMouseEvent(d->popupItem, event)); +} + +void QQuickPopup::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickPopup); + event->setAccepted(d->handleMouseEvent(d->popupItem, event)); +} + +void QQuickPopup::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickPopup); + event->setAccepted(d->handleMouseEvent(d->popupItem, event)); +} + +void QQuickPopup::mouseDoubleClickEvent(QMouseEvent *event) +{ + event->accept(); +} + +void QQuickPopup::mouseUngrabEvent() +{ + Q_D(QQuickPopup); + d->handleUngrab(); +} + +bool QQuickPopup::overlayEvent(QQuickItem *item, QEvent *event) +{ + Q_D(QQuickPopup); + switch (event->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::MouseMove: + case QEvent::Wheel: + if (d->modal) + event->accept(); + return d->modal; + +#if QT_CONFIG(quicktemplates2_multitouch) + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + return d->handleTouchEvent(item, static_cast<QTouchEvent *>(event)); +#endif + case QEvent::HoverEnter: + case QEvent::HoverMove: + case QEvent::HoverLeave: + return d->handleHoverEvent(item, static_cast<QHoverEvent *>(event)); + + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + return d->handleMouseEvent(item, static_cast<QMouseEvent *>(event)); + + default: + return false; + } +} + +#if QT_CONFIG(quicktemplates2_multitouch) +void QQuickPopup::touchEvent(QTouchEvent *event) +{ + Q_D(QQuickPopup); + d->handleTouchEvent(d->popupItem, event); +} + +void QQuickPopup::touchUngrabEvent() +{ + Q_D(QQuickPopup); + d->handleUngrab(); +} +#endif + +#if QT_CONFIG(wheelevent) +void QQuickPopup::wheelEvent(QWheelEvent *event) +{ + event->accept(); +} +#endif + +void QQuickPopup::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) +{ + Q_UNUSED(newItem); + Q_UNUSED(oldItem); +} + +void QQuickPopup::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize) +{ + qCDebug(lcPopup) << "contentSizeChange called on" << this << "with newSize" << newSize << "oldSize" << oldSize; + if (!qFuzzyCompare(newSize.width(), oldSize.width())) + emit contentWidthChanged(); + if (!qFuzzyCompare(newSize.height(), oldSize.height())) + emit contentHeightChanged(); +} + +void QQuickPopup::fontChange(const QFont &newFont, const QFont &oldFont) +{ + Q_UNUSED(newFont); + Q_UNUSED(oldFont); + emit fontChanged(); +} + +void QQuickPopup::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickPopup); + qCDebug(lcPopup) << "geometryChange called on" << this << "with newGeometry" << newGeometry << "oldGeometry" << oldGeometry; + d->reposition(); + if (!qFuzzyCompare(newGeometry.width(), oldGeometry.width())) { + emit widthChanged(); + emit availableWidthChanged(); + } + if (!qFuzzyCompare(newGeometry.height(), oldGeometry.height())) { + emit heightChanged(); + emit availableHeightChanged(); + } +} + +void QQuickPopup::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &) +{ + switch (change) { + case QQuickItem::ItemActiveFocusHasChanged: + emit activeFocusChanged(); + break; + case QQuickItem::ItemOpacityHasChanged: + emit opacityChanged(); + break; + default: + break; + } +} + +void QQuickPopup::localeChange(const QLocale &newLocale, const QLocale &oldLocale) +{ + Q_UNUSED(newLocale); + Q_UNUSED(oldLocale); + emit localeChanged(); +} + +void QQuickPopup::marginsChange(const QMarginsF &newMargins, const QMarginsF &oldMargins) +{ + Q_D(QQuickPopup); + Q_UNUSED(newMargins); + Q_UNUSED(oldMargins); + d->reposition(); +} + +void QQuickPopup::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) +{ + const bool tp = !qFuzzyCompare(newPadding.top(), oldPadding.top()); + const bool lp = !qFuzzyCompare(newPadding.left(), oldPadding.left()); + const bool rp = !qFuzzyCompare(newPadding.right(), oldPadding.right()); + const bool bp = !qFuzzyCompare(newPadding.bottom(), oldPadding.bottom()); + + if (tp) + emit topPaddingChanged(); + if (lp) + emit leftPaddingChanged(); + if (rp) + emit rightPaddingChanged(); + if (bp) + emit bottomPaddingChanged(); + + if (lp || rp) { + emit horizontalPaddingChanged(); + emit availableWidthChanged(); + } + if (tp || bp) { + emit verticalPaddingChanged(); + emit availableHeightChanged(); + } +} + +void QQuickPopup::spacingChange(qreal newSpacing, qreal oldSpacing) +{ + Q_UNUSED(newSpacing); + Q_UNUSED(oldSpacing); + emit spacingChanged(); +} + +void QQuickPopup::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset) +{ + if (!qFuzzyCompare(newInset.top(), oldInset.top())) + emit topInsetChanged(); + if (!qFuzzyCompare(newInset.left(), oldInset.left())) + emit leftInsetChanged(); + if (!qFuzzyCompare(newInset.right(), oldInset.right())) + emit rightInsetChanged(); + if (!qFuzzyCompare(newInset.bottom(), oldInset.bottom())) + emit bottomInsetChanged(); +} + +QFont QQuickPopup::defaultFont() const +{ + return QQuickTheme::font(QQuickTheme::System); +} + +#if QT_CONFIG(accessibility) +QAccessible::Role QQuickPopup::effectiveAccessibleRole() const +{ + auto *attached = qmlAttachedPropertiesObject<QQuickAccessibleAttached>(this, false); + + auto role = QAccessible::NoRole; + if (auto *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(attached)) + role = accessibleAttached->role(); + if (role == QAccessible::NoRole) + role = accessibleRole(); + + return role; +} + +QAccessible::Role QQuickPopup::accessibleRole() const +{ + return QAccessible::Dialog; +} + +void QQuickPopup::accessibilityActiveChanged(bool active) +{ + Q_UNUSED(active); +} +#endif + +QString QQuickPopup::accessibleName() const +{ + Q_D(const QQuickPopup); + return d->popupItem->accessibleName(); +} + +void QQuickPopup::maybeSetAccessibleName(const QString &name) +{ + Q_D(QQuickPopup); + d->popupItem->maybeSetAccessibleName(name); +} + +QVariant QQuickPopup::accessibleProperty(const char *propertyName) +{ + Q_D(const QQuickPopup); + return d->popupItem->accessibleProperty(propertyName); +} + +bool QQuickPopup::setAccessibleProperty(const char *propertyName, const QVariant &value) +{ + Q_D(QQuickPopup); + return d->popupItem->setAccessibleProperty(propertyName, value); +} + +QT_END_NAMESPACE + +#include "moc_qquickpopup_p.cpp" |