aboutsummaryrefslogtreecommitdiffstats
path: root/src/labs/platform/qquicklabsplatformmenu.cpp
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2021-10-18 12:01:20 +0200
committerMitch Curtis <mitch.curtis@qt.io>2021-10-26 15:02:17 +0200
commitd0507b6d5eab28f36cc39c1f46d8a87ab76bb88e (patch)
tree57d3d76c3807f5d2a46b082838b32d8564a0e55b /src/labs/platform/qquicklabsplatformmenu.cpp
parentc61cfa84875442ced136653f3734bbdf249098dc (diff)
Rename labs platform types to avoid duplicate type names
Qt Labs Platform and Qt Quick Dialogs contain the same type names, which may cause issues when both modules are imported from QML. This may be the cause of the linker error when building Qt for Web Assembly: wasm-ld: error: duplicate symbol: vtable for QQuickPlatformFontDialog >>> defined in /home/qt/RTA/qt5/6.2.1/wasm_32/./qml/Qt/labs/platform/libqtlabsplatformplugin.a(mocs_compilation.cpp.o) >>> defined in /home/qt/RTA/qt5/6.2.1/wasm_32/lib/libQt6QuickDialogs2QuickImpl.a(mocs_compilation.cpp.o) Fixes: QTBUG-97465 Pick-to: 6.2 Change-Id: I43dfab7cf4f56e4bfcdd4262dcf7d99f82351434 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/labs/platform/qquicklabsplatformmenu.cpp')
-rw-r--r--src/labs/platform/qquicklabsplatformmenu.cpp895
1 files changed, 895 insertions, 0 deletions
diff --git a/src/labs/platform/qquicklabsplatformmenu.cpp b/src/labs/platform/qquicklabsplatformmenu.cpp
new file mode 100644
index 0000000000..e5cf45d386
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmenu.cpp
@@ -0,0 +1,895 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformmenu_p.h"
+#include "qquicklabsplatformmenubar_p.h"
+#include "qquicklabsplatformmenuitem_p.h"
+#include "qquicklabsplatformiconloader_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/qicon.h>
+#include <QtGui/qcursor.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/private/qv4scopedvalue_p.h>
+#include <QtQml/private/qv4qobjectwrapper_p.h>
+#include <QtQuick/qquickrendercontrol.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qquickitem.h>
+
+#include "widgets/qwidgetplatform_p.h"
+
+#if QT_CONFIG(systemtrayicon)
+#include "qquicklabsplatformsystemtrayicon_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Menu
+ \inherits QtObject
+//! \instantiates QQuickLabsPlatformMenu
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native menu.
+
+ The Menu type provides a QML API for native platform menu popups.
+
+ \image qtlabsplatform-menu.png
+
+ Menu can be used in a \l MenuBar, or as a stand-alone context menu.
+ The following example shows how to open a context menu on right mouse
+ click:
+
+ \code
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ onClicked: zoomMenu.open()
+ }
+
+ Menu {
+ id: zoomMenu
+
+ MenuItem {
+ text: qsTr("Zoom In")
+ shortcut: StandardKey.ZoomIn
+ onTriggered: zoomIn()
+ }
+
+ MenuItem {
+ text: qsTr("Zoom Out")
+ shortcut: StandardKey.ZoomOut
+ onTriggered: zoomOut()
+ }
+ }
+ \endcode
+
+ \section2 Submenus
+
+ To create submenus, declare a Menu as a child of another Menu:
+
+ \qml
+ Menu {
+ title: qsTr("Edit")
+
+ Menu {
+ title: qsTr("Advanced")
+
+ MenuItem {
+ text: qsTr("Auto-indent Selection")
+ onTriggered: autoIndentSelection()
+ }
+
+ MenuItem {
+ text: qsTr("Rewrap Paragraph")
+ onTriggered: rewrapParagraph()
+ }
+ }
+ }
+ \endqml
+
+ \section2 Dynamically Generating Menu Items
+
+ It is possible to dynamically generate menu items. One of the easiest ways
+ to do so is with \l Instantiator. For example, to implement a
+ "Recent Files" submenu, where the items are based on a list of files stored
+ in settings, the following code could be used:
+
+ \qml
+ Menu {
+ title: qsTr("File")
+
+ Menu {
+ id: recentFilesSubMenu
+ title: qsTr("Recent Files")
+ enabled: recentFilesInstantiator.count > 0
+
+ Instantiator {
+ id: recentFilesInstantiator
+ model: settings.recentFiles
+ delegate: MenuItem {
+ text: settings.displayableFilePath(modelData)
+ onTriggered: loadFile(modelData)
+ }
+
+ onObjectAdded: recentFilesSubMenu.insertItem(index, object)
+ onObjectRemoved: recentFilesSubMenu.removeItem(object)
+ }
+
+ MenuSeparator {}
+
+ MenuItem {
+ text: qsTr("Clear Recent Files")
+ onTriggered: settings.clearRecentFiles()
+ }
+ }
+ }
+ \endqml
+
+ \section2 Availability
+
+ A native platform menu is currently available on the following platforms:
+
+ \list
+ \li macOS
+ \li iOS
+ \li Android
+ \li Linux (only available as a stand-alone context menu when running with the GTK+ platform theme)
+ \endlist
+
+ \input includes/widgets.qdocinc 1
+
+ \labs
+
+ \sa MenuItem, MenuSeparator, MenuBar
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::Menu::aboutToShow()
+
+ This signal is emitted when the menu is about to be shown to the user.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::Menu::aboutToHide()
+
+ This signal is emitted when the menu is about to be hidden from the user.
+*/
+
+Q_DECLARE_LOGGING_CATEGORY(qtLabsPlatformMenus)
+
+QQuickLabsPlatformMenu::QQuickLabsPlatformMenu(QObject *parent)
+ : QObject(parent),
+ m_complete(false),
+ m_enabled(true),
+ m_visible(true),
+ m_minimumWidth(-1),
+ m_type(QPlatformMenu::DefaultMenu),
+ m_menuBar(nullptr),
+ m_parentMenu(nullptr),
+ m_systemTrayIcon(nullptr),
+ m_menuItem(nullptr),
+ m_iconLoader(nullptr),
+ m_handle(nullptr)
+{
+}
+
+QQuickLabsPlatformMenu::~QQuickLabsPlatformMenu()
+{
+ if (m_menuBar)
+ m_menuBar->removeMenu(this);
+ if (m_parentMenu)
+ m_parentMenu->removeMenu(this);
+
+ unparentSubmenus();
+
+ delete m_iconLoader;
+ m_iconLoader = nullptr;
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+void QQuickLabsPlatformMenu::unparentSubmenus()
+{
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items)) {
+ if (QQuickLabsPlatformMenu *subMenu = item->subMenu())
+ subMenu->setParentMenu(nullptr);
+ item->setMenu(nullptr);
+ }
+}
+
+QPlatformMenu *QQuickLabsPlatformMenu::handle() const
+{
+ return m_handle;
+}
+
+QPlatformMenu * QQuickLabsPlatformMenu::create()
+{
+ if (!m_handle) {
+ if (m_menuBar && m_menuBar->handle())
+ m_handle = m_menuBar->handle()->createMenu();
+ else if (m_parentMenu && m_parentMenu->handle())
+ m_handle = m_parentMenu->handle()->createSubMenu();
+#if QT_CONFIG(systemtrayicon)
+ else if (m_systemTrayIcon && m_systemTrayIcon->handle())
+ m_handle = m_systemTrayIcon->handle()->createMenu();
+#endif
+
+ // TODO: implement ^
+ // - QCocoaMenuBar::createMenu()
+ // - QCocoaMenu::createSubMenu()
+ // - QCocoaSystemTrayIcon::createMenu()
+ if (!m_handle)
+ m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformMenu();
+
+ if (!m_handle)
+ m_handle = QWidgetPlatform::createMenu();
+
+ qCDebug(qtLabsPlatformMenus) << "Menu ->" << m_handle;
+
+ if (m_handle) {
+ connect(m_handle, &QPlatformMenu::aboutToShow, this, &QQuickLabsPlatformMenu::aboutToShow);
+ connect(m_handle, &QPlatformMenu::aboutToHide, this, &QQuickLabsPlatformMenu::aboutToHide);
+
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items))
+ m_handle->insertMenuItem(item->create(), nullptr);
+
+ if (m_menuItem) {
+ if (QPlatformMenuItem *handle = m_menuItem->create())
+ handle->setMenu(m_handle);
+ }
+ }
+ }
+ return m_handle;
+}
+
+void QQuickLabsPlatformMenu::destroy()
+{
+ if (!m_handle)
+ return;
+
+ // Ensure that all submenus are unparented before we are destroyed,
+ // so that they don't try to access a destroyed menu.
+ unparentSubmenus();
+
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+void QQuickLabsPlatformMenu::sync()
+{
+ if (!m_complete || !create())
+ return;
+
+ m_handle->setText(m_title);
+ m_handle->setEnabled(m_enabled);
+ m_handle->setVisible(m_visible);
+ m_handle->setMinimumWidth(m_minimumWidth);
+ m_handle->setMenuType(m_type);
+ m_handle->setFont(m_font);
+
+ if (m_menuBar && m_menuBar->handle())
+ m_menuBar->handle()->syncMenu(m_handle);
+#if QT_CONFIG(systemtrayicon)
+ else if (m_systemTrayIcon && m_systemTrayIcon->handle())
+ m_systemTrayIcon->handle()->updateMenu(m_handle);
+#endif
+
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items))
+ item->sync();
+}
+
+/*!
+ \qmldefault
+ \qmlproperty list<QtObject> Qt.labs.platform::Menu::data
+
+ This default property holds the list of all objects declared as children of
+ the menu. The data property includes objects that are not \l MenuItem instances,
+ such as \l Timer and \l QtObject.
+
+ \sa items
+*/
+QQmlListProperty<QObject> QQuickLabsPlatformMenu::data()
+{
+ return QQmlListProperty<QObject>(this, nullptr, data_append, data_count, data_at, data_clear);
+}
+
+/*!
+ \qmlproperty list<MenuItem> Qt.labs.platform::Menu::items
+
+ This property holds the list of items in the menu.
+*/
+QQmlListProperty<QQuickLabsPlatformMenuItem> QQuickLabsPlatformMenu::items()
+{
+ return QQmlListProperty<QQuickLabsPlatformMenuItem>(this, nullptr, items_append, items_count, items_at, items_clear);
+}
+
+/*!
+ \readonly
+ \qmlproperty MenuBar Qt.labs.platform::Menu::menuBar
+
+ This property holds the menubar that the menu belongs to, or \c null if the
+ menu is not in a menubar.
+*/
+QQuickLabsPlatformMenuBar *QQuickLabsPlatformMenu::menuBar() const
+{
+ return m_menuBar;
+}
+
+void QQuickLabsPlatformMenu::setMenuBar(QQuickLabsPlatformMenuBar *menuBar)
+{
+ if (m_menuBar == menuBar)
+ return;
+
+ m_menuBar = menuBar;
+ destroy();
+ emit menuBarChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty Menu Qt.labs.platform::Menu::parentMenu
+
+ This property holds the parent menu that the menu belongs to, or \c null if the
+ menu is not a sub-menu.
+*/
+QQuickLabsPlatformMenu *QQuickLabsPlatformMenu::parentMenu() const
+{
+ return m_parentMenu;
+}
+
+void QQuickLabsPlatformMenu::setParentMenu(QQuickLabsPlatformMenu *menu)
+{
+ if (m_parentMenu == menu)
+ return;
+
+ m_parentMenu = menu;
+ destroy();
+ emit parentMenuChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty SystemTrayIcon Qt.labs.platform::Menu::systemTrayIcon
+
+ This property holds the system tray icon that the menu belongs to, or \c null
+ if the menu is not in a system tray icon.
+*/
+QQuickLabsPlatformSystemTrayIcon *QQuickLabsPlatformMenu::systemTrayIcon() const
+{
+ return m_systemTrayIcon;
+}
+
+void QQuickLabsPlatformMenu::setSystemTrayIcon(QQuickLabsPlatformSystemTrayIcon *icon)
+{
+ if (m_systemTrayIcon == icon)
+ return;
+
+ m_systemTrayIcon = icon;
+ destroy();
+ emit systemTrayIconChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty MenuItem Qt.labs.platform::Menu::menuItem
+
+ This property holds the item that presents the menu (in a parent menu).
+*/
+QQuickLabsPlatformMenuItem *QQuickLabsPlatformMenu::menuItem() const
+{
+ if (!m_menuItem) {
+ QQuickLabsPlatformMenu *that = const_cast<QQuickLabsPlatformMenu *>(this);
+ m_menuItem = new QQuickLabsPlatformMenuItem(that);
+ m_menuItem->setSubMenu(that);
+ m_menuItem->setText(m_title);
+ m_menuItem->setIcon(icon());
+ m_menuItem->setVisible(m_visible);
+ m_menuItem->setEnabled(m_enabled);
+ m_menuItem->componentComplete();
+ }
+ return m_menuItem;
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::Menu::enabled
+
+ This property holds whether the menu is enabled. The default value is \c true.
+*/
+bool QQuickLabsPlatformMenu::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QQuickLabsPlatformMenu::setEnabled(bool enabled)
+{
+ if (m_enabled == enabled)
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setEnabled(enabled);
+
+ m_enabled = enabled;
+ sync();
+ emit enabledChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::Menu::visible
+
+ This property holds whether the menu is visible. The default value is \c true.
+*/
+bool QQuickLabsPlatformMenu::isVisible() const
+{
+ return m_visible;
+}
+
+void QQuickLabsPlatformMenu::setVisible(bool visible)
+{
+ if (m_visible == visible)
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setVisible(visible);
+
+ m_visible = visible;
+ sync();
+ emit visibleChanged();
+}
+
+/*!
+ \qmlproperty int Qt.labs.platform::Menu::minimumWidth
+
+ This property holds the minimum width of the menu. The default value is \c -1 (no minimum width).
+*/
+int QQuickLabsPlatformMenu::minimumWidth() const
+{
+ return m_minimumWidth;
+}
+
+void QQuickLabsPlatformMenu::setMinimumWidth(int width)
+{
+ if (m_minimumWidth == width)
+ return;
+
+ m_minimumWidth = width;
+ sync();
+ emit minimumWidthChanged();
+}
+
+/*!
+ \qmlproperty enumeration Qt.labs.platform::Menu::type
+
+ This property holds the type of the menu.
+
+ Available values:
+ \value Menu.DefaultMenu A normal menu (default).
+ \value Menu.EditMenu An edit menu with pre-populated cut, copy and paste items.
+*/
+QPlatformMenu::MenuType QQuickLabsPlatformMenu::type() const
+{
+ return m_type;
+}
+
+void QQuickLabsPlatformMenu::setType(QPlatformMenu::MenuType type)
+{
+ if (m_type == type)
+ return;
+
+ m_type = type;
+ sync();
+ emit typeChanged();
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::Menu::title
+
+ This property holds the menu's title.
+*/
+QString QQuickLabsPlatformMenu::title() const
+{
+ return m_title;
+}
+
+void QQuickLabsPlatformMenu::setTitle(const QString &title)
+{
+ if (m_title == title)
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setText(title);
+
+ m_title = title;
+ sync();
+ emit titleChanged();
+}
+
+/*!
+ \qmlproperty font Qt.labs.platform::Menu::font
+
+ This property holds the menu's font.
+
+ \sa title
+*/
+QFont QQuickLabsPlatformMenu::font() const
+{
+ return m_font;
+}
+
+void QQuickLabsPlatformMenu::setFont(const QFont& font)
+{
+ if (m_font == font)
+ return;
+
+ m_font = font;
+ sync();
+ emit fontChanged();
+}
+
+/*!
+ \since Qt.labs.platform 1.1 (Qt 5.12)
+ \qmlproperty url Qt.labs.platform::Menu::icon.source
+ \qmlproperty string Qt.labs.platform::Menu::icon.name
+ \qmlproperty bool Qt.labs.platform::Menu::icon.mask
+
+ This property holds the menu item's icon.
+*/
+QQuickLabsPlatformIcon QQuickLabsPlatformMenu::icon() const
+{
+ if (!m_iconLoader)
+ return QQuickLabsPlatformIcon();
+
+ return iconLoader()->icon();
+}
+
+void QQuickLabsPlatformMenu::setIcon(const QQuickLabsPlatformIcon &icon)
+{
+ if (iconLoader()->icon() == icon)
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setIcon(icon);
+
+ iconLoader()->setIcon(icon);
+ emit iconChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::addItem(MenuItem item)
+
+ Adds an \a item to the end of the menu.
+*/
+void QQuickLabsPlatformMenu::addItem(QQuickLabsPlatformMenuItem *item)
+{
+ insertItem(m_items.count(), item);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::insertItem(int index, MenuItem item)
+
+ Inserts an \a item at the specified \a index in the menu.
+*/
+void QQuickLabsPlatformMenu::insertItem(int index, QQuickLabsPlatformMenuItem *item)
+{
+ if (!item || m_items.contains(item))
+ return;
+
+ m_items.insert(index, item);
+ m_data.append(item);
+ item->setMenu(this);
+ if (m_handle && item->create()) {
+ QQuickLabsPlatformMenuItem *before = m_items.value(index + 1);
+ m_handle->insertMenuItem(item->handle(), before ? before->create() : nullptr);
+ }
+ sync();
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::removeItem(MenuItem item)
+
+ Removes an \a item from the menu.
+*/
+void QQuickLabsPlatformMenu::removeItem(QQuickLabsPlatformMenuItem *item)
+{
+ if (!item || !m_items.removeOne(item))
+ return;
+
+ m_data.removeOne(item);
+ if (m_handle)
+ m_handle->removeMenuItem(item->handle());
+ item->setMenu(nullptr);
+ sync();
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::addMenu(Menu submenu)
+
+ Adds a \a submenu to the end of the menu.
+*/
+void QQuickLabsPlatformMenu::addMenu(QQuickLabsPlatformMenu *menu)
+{
+ insertMenu(m_items.count(), menu);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::insertMenu(int index, Menu submenu)
+
+ Inserts a \a submenu at the specified \a index in the menu.
+*/
+void QQuickLabsPlatformMenu::insertMenu(int index, QQuickLabsPlatformMenu *menu)
+{
+ if (!menu)
+ return;
+
+ menu->setParentMenu(this);
+ insertItem(index, menu->menuItem());
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::removeMenu(Menu submenu)
+
+ Removes a \a submenu from the menu.
+*/
+void QQuickLabsPlatformMenu::removeMenu(QQuickLabsPlatformMenu *menu)
+{
+ if (!menu)
+ return;
+
+ menu->setParentMenu(nullptr);
+ removeItem(menu->menuItem());
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::clear()
+
+ Removes all items from the menu.
+*/
+void QQuickLabsPlatformMenu::clear()
+{
+ if (m_items.isEmpty())
+ return;
+
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items)) {
+ m_data.removeOne(item);
+ if (m_handle)
+ m_handle->removeMenuItem(item->handle());
+ item->setMenu(nullptr);
+ delete item;
+ }
+
+ m_items.clear();
+ sync();
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::open(MenuItem item)
+
+ Opens the menu at the current mouse position, optionally aligned to a menu \a item.
+*/
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::open(Item target, MenuItem item)
+
+ Opens the menu at the specified \a target item, optionally aligned to a menu \a item.
+*/
+void QQuickLabsPlatformMenu::open(QQmlV4Function *args)
+{
+ if (!m_handle)
+ return;
+
+ if (args->length() > 2) {
+ args->v4engine()->throwTypeError();
+ return;
+ }
+
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ QV4::Scope scope(v4);
+
+ QQuickItem *targetItem = nullptr;
+ if (args->length() > 0) {
+ QV4::ScopedValue value(scope, (*args)[0]);
+ QV4::Scoped<QV4::QObjectWrapper> object(scope, value->as<QV4::QObjectWrapper>());
+ if (object)
+ targetItem = qobject_cast<QQuickItem *>(object->object());
+ }
+
+ QQuickLabsPlatformMenuItem *menuItem = nullptr;
+ if (args->length() > 1) {
+ QV4::ScopedValue value(scope, (*args)[1]);
+ QV4::Scoped<QV4::QObjectWrapper> object(scope, value->as<QV4::QObjectWrapper>());
+ if (object)
+ menuItem = qobject_cast<QQuickLabsPlatformMenuItem *>(object->object());
+ }
+
+ QPoint offset;
+ QWindow *window = findWindow(targetItem, &offset);
+
+ QRect targetRect;
+ if (targetItem) {
+ QRectF sceneBounds = targetItem->mapRectToScene(targetItem->boundingRect());
+ targetRect = sceneBounds.toAlignedRect().translated(offset);
+ } else {
+#if QT_CONFIG(cursor)
+ QPoint pos = QCursor::pos();
+ if (window)
+ pos = window->mapFromGlobal(pos);
+ targetRect.moveTo(pos);
+#endif
+ }
+ m_handle->showPopup(window,
+ QHighDpi::toNativePixels(targetRect, window),
+ menuItem ? menuItem->handle() : nullptr);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::close()
+
+ Closes the menu.
+*/
+void QQuickLabsPlatformMenu::close()
+{
+ if (m_handle)
+ m_handle->dismiss();
+}
+
+void QQuickLabsPlatformMenu::classBegin()
+{
+}
+
+void QQuickLabsPlatformMenu::componentComplete()
+{
+ m_complete = true;
+ if (m_handle && m_iconLoader)
+ m_iconLoader->setEnabled(true);
+ sync();
+}
+
+QQuickLabsPlatformIconLoader *QQuickLabsPlatformMenu::iconLoader() const
+{
+ if (!m_iconLoader) {
+ QQuickLabsPlatformMenu *that = const_cast<QQuickLabsPlatformMenu *>(this);
+ static int slot = staticMetaObject.indexOfSlot("updateIcon()");
+ m_iconLoader = new QQuickLabsPlatformIconLoader(slot, that);
+ m_iconLoader->setEnabled(m_complete);
+ }
+ return m_iconLoader;
+}
+
+static QWindow *effectiveWindow(QWindow *window, QPoint *offset)
+{
+ QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(window);
+ if (quickWindow) {
+ QWindow *renderWindow = QQuickRenderControl::renderWindowFor(quickWindow, offset);
+ if (renderWindow)
+ return renderWindow;
+ }
+ return window;
+}
+
+QWindow *QQuickLabsPlatformMenu::findWindow(QQuickItem *target, QPoint *offset) const
+{
+ if (target)
+ return effectiveWindow(target->window(), offset);
+
+ if (m_menuBar && m_menuBar->window())
+ return effectiveWindow(m_menuBar->window(), offset);
+
+ QObject *obj = parent();
+ while (obj) {
+ QWindow *window = qobject_cast<QWindow *>(obj);
+ if (window)
+ return effectiveWindow(window, offset);
+
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item && item->window())
+ return effectiveWindow(item->window(), offset);
+
+ obj = obj->parent();
+ }
+ return nullptr;
+}
+
+void QQuickLabsPlatformMenu::data_append(QQmlListProperty<QObject> *property, QObject *object)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ if (QQuickLabsPlatformMenuItem *item = qobject_cast<QQuickLabsPlatformMenuItem *>(object))
+ menu->addItem(item);
+ else if (QQuickLabsPlatformMenu *subMenu = qobject_cast<QQuickLabsPlatformMenu *>(object))
+ menu->addMenu(subMenu);
+ else
+ menu->m_data.append(object);
+}
+
+qsizetype QQuickLabsPlatformMenu::data_count(QQmlListProperty<QObject> *property)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ return menu->m_data.count();
+}
+
+QObject *QQuickLabsPlatformMenu::data_at(QQmlListProperty<QObject> *property, qsizetype index)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ return menu->m_data.value(index);
+}
+
+void QQuickLabsPlatformMenu::data_clear(QQmlListProperty<QObject> *property)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ menu->m_data.clear();
+}
+
+void QQuickLabsPlatformMenu::items_append(QQmlListProperty<QQuickLabsPlatformMenuItem> *property, QQuickLabsPlatformMenuItem *item)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ menu->addItem(item);
+}
+
+qsizetype QQuickLabsPlatformMenu::items_count(QQmlListProperty<QQuickLabsPlatformMenuItem> *property)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ return menu->m_items.count();
+}
+
+QQuickLabsPlatformMenuItem *QQuickLabsPlatformMenu::items_at(QQmlListProperty<QQuickLabsPlatformMenuItem> *property, qsizetype index)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ return menu->m_items.value(index);
+}
+
+void QQuickLabsPlatformMenu::items_clear(QQmlListProperty<QQuickLabsPlatformMenuItem> *property)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ menu->clear();
+}
+
+void QQuickLabsPlatformMenu::updateIcon()
+{
+ if (!m_handle || !m_iconLoader)
+ return;
+
+ m_handle->setIcon(m_iconLoader->toQIcon());
+ sync();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformmenu_p.cpp"