diff options
author | J-P Nurmi <jpnurmi@qt.io> | 2016-05-22 19:04:03 +0200 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2016-06-16 06:50:30 +0000 |
commit | e9e68baf652eca70c6a4c080ed9e49c70c8c9984 (patch) | |
tree | 33e4c8b3ffe5e1be597c4fe6fa87ed65239ed7b2 /src/imports/platform | |
parent | 30d931b866bf6cdf7900d0c7f85734e0bfe03a6f (diff) |
Platform menus
Change-Id: Ifbca41ef384ca8fe8afefc61869f85c17db0f8c7
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'src/imports/platform')
-rw-r--r-- | src/imports/platform/doc/images/qtlabsplatform-menu.png | bin | 0 -> 6377 bytes | |||
-rw-r--r-- | src/imports/platform/doc/images/qtlabsplatform-menubar.png | bin | 0 -> 71036 bytes | |||
-rw-r--r-- | src/imports/platform/platform.pri | 12 | ||||
-rw-r--r-- | src/imports/platform/qquickplatformmenu.cpp | 792 | ||||
-rw-r--r-- | src/imports/platform/qquickplatformmenu_p.h | 206 | ||||
-rw-r--r-- | src/imports/platform/qquickplatformmenubar.cpp | 326 | ||||
-rw-r--r-- | src/imports/platform/qquickplatformmenubar_p.h | 120 | ||||
-rw-r--r-- | src/imports/platform/qquickplatformmenuitem.cpp | 605 | ||||
-rw-r--r-- | src/imports/platform/qquickplatformmenuitem_p.h | 191 | ||||
-rw-r--r-- | src/imports/platform/qquickplatformmenuitemgroup.cpp | 390 | ||||
-rw-r--r-- | src/imports/platform/qquickplatformmenuitemgroup_p.h | 123 | ||||
-rw-r--r-- | src/imports/platform/qtlabsplatformplugin.cpp | 10 |
12 files changed, 2772 insertions, 3 deletions
diff --git a/src/imports/platform/doc/images/qtlabsplatform-menu.png b/src/imports/platform/doc/images/qtlabsplatform-menu.png Binary files differnew file mode 100644 index 00000000..120d263b --- /dev/null +++ b/src/imports/platform/doc/images/qtlabsplatform-menu.png diff --git a/src/imports/platform/doc/images/qtlabsplatform-menubar.png b/src/imports/platform/doc/images/qtlabsplatform-menubar.png Binary files differnew file mode 100644 index 00000000..685d03b3 --- /dev/null +++ b/src/imports/platform/doc/images/qtlabsplatform-menubar.png diff --git a/src/imports/platform/platform.pri b/src/imports/platform/platform.pri index 453ed447..a0ba0450 100644 --- a/src/imports/platform/platform.pri +++ b/src/imports/platform/platform.pri @@ -1,5 +1,13 @@ HEADERS += \ - $$PWD/qquickplatformiconloader_p.h + $$PWD/qquickplatformiconloader_p.h \ + $$PWD/qquickplatformmenu_p.h \ + $$PWD/qquickplatformmenubar_p.h \ + $$PWD/qquickplatformmenuitem_p.h \ + $$PWD/qquickplatformmenuitemgroup_p.h SOURCES += \ - $$PWD/qquickplatformiconloader.cpp + $$PWD/qquickplatformiconloader.cpp \ + $$PWD/qquickplatformmenu.cpp \ + $$PWD/qquickplatformmenubar.cpp \ + $$PWD/qquickplatformmenuitem.cpp \ + $$PWD/qquickplatformmenuitemgroup.cpp diff --git a/src/imports/platform/qquickplatformmenu.cpp b/src/imports/platform/qquickplatformmenu.cpp new file mode 100644 index 00000000..7849adf0 --- /dev/null +++ b/src/imports/platform/qquickplatformmenu.cpp @@ -0,0 +1,792 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "qquickplatformmenu_p.h" +#include "qquickplatformmenubar_p.h" +#include "qquickplatformmenuitem_p.h" +#include "qquickplatformiconloader_p.h" + +#include <QtGui/qicon.h> +#include <QtGui/qcursor.h> +#include <QtGui/qpa/qplatformtheme.h> +#include <QtGui/private/qguiapplication_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> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Menu + \inherits QtObject + \instantiates QQuickPlatformMenu + \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 + + Menu is currently available on the following platforms: + + \list + \li OS X + \li iOS + \li Android + \li Linux (only available as a stand-alone context menu when running with the GTK platform theme) + \endlist + + \labs + + \sa MenuItem, 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. +*/ + +QQuickPlatformMenu::QQuickPlatformMenu(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_menuItem(nullptr), + m_iconLoader(nullptr), + m_handle(nullptr) +{ +} + +QQuickPlatformMenu::~QQuickPlatformMenu() +{ + if (m_menuBar) + m_menuBar->removeMenu(this); + if (m_parentMenu) + m_parentMenu->removeMenu(this); + for (QQuickPlatformMenuItem *item : m_items) { + if (QQuickPlatformMenu *subMenu = item->subMenu()) + subMenu->setParentMenu(nullptr); + item->setMenu(nullptr); + } + delete m_iconLoader; + m_iconLoader = nullptr; + delete m_handle; + m_handle = nullptr; +} + +QPlatformMenu *QQuickPlatformMenu::handle() const +{ + return m_handle; +} + +QPlatformMenu * QQuickPlatformMenu::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(); + + // TODO: implement ^ + // - QCocoaMenuBar::createMenu() + // - QCocoaMenu::createSubMenu() + if (!m_handle) + m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformMenu(); + + if (m_handle) { + connect(m_handle, &QPlatformMenu::aboutToShow, this, &QQuickPlatformMenu::aboutToShow); + connect(m_handle, &QPlatformMenu::aboutToHide, this, &QQuickPlatformMenu::aboutToHide); + + for (QQuickPlatformMenuItem *item : 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 QQuickPlatformMenu::destroy() +{ + if (!m_handle) + return; + + delete m_handle; + m_handle = nullptr; +} + +void QQuickPlatformMenu::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); + + for (QQuickPlatformMenuItem *item : m_items) + item->sync(); +} + +/*! + \default + \qmlproperty list<Object> 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> QQuickPlatformMenu::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<QQuickPlatformMenuItem> QQuickPlatformMenu::items() +{ + return QQmlListProperty<QQuickPlatformMenuItem>(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. +*/ +QQuickPlatformMenuBar *QQuickPlatformMenu::menuBar() const +{ + return m_menuBar; +} + +void QQuickPlatformMenu::setMenuBar(QQuickPlatformMenuBar *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. +*/ +QQuickPlatformMenu *QQuickPlatformMenu::parentMenu() const +{ + return m_parentMenu; +} + +void QQuickPlatformMenu::setParentMenu(QQuickPlatformMenu *menu) +{ + if (m_parentMenu == menu) + return; + + m_parentMenu = menu; + destroy(); + emit parentMenuChanged(); +} + +/*! + \readonly + \qmlproperty MenuItem Qt.labs.platform::Menu::menuItem + + This property holds the item that presents the menu (in a parent menu). +*/ +QQuickPlatformMenuItem *QQuickPlatformMenu::menuItem() const +{ + if (!m_menuItem) { + QQuickPlatformMenu *that = const_cast<QQuickPlatformMenu *>(this); + m_menuItem = new QQuickPlatformMenuItem(that); + m_menuItem->setSubMenu(that); + m_menuItem->setText(m_title); + m_menuItem->setIconName(iconName()); + m_menuItem->setIconSource(iconSource()); + 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 QQuickPlatformMenu::isEnabled() const +{ + return m_enabled; +} + +void QQuickPlatformMenu::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 QQuickPlatformMenu::isVisible() const +{ + return m_visible; +} + +void QQuickPlatformMenu::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 QQuickPlatformMenu::minimumWidth() const +{ + return m_minimumWidth; +} + +void QQuickPlatformMenu::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 QQuickPlatformMenu::type() const +{ + return m_type; +} + +void QQuickPlatformMenu::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 QQuickPlatformMenu::title() const +{ + return m_title; +} + +void QQuickPlatformMenu::setTitle(const QString &title) +{ + if (m_title == title) + return; + + m_title = title; + sync(); + emit titleChanged(); +} + +/*! + \qmlproperty url Qt.labs.platform::Menu::iconSource + + This property holds the url of the menu's icon. + + \sa iconName +*/ +QUrl QQuickPlatformMenu::iconSource() const +{ + if (!m_iconLoader) + return QUrl(); + + return m_iconLoader->iconSource(); +} + +void QQuickPlatformMenu::setIconSource(const QUrl& source) +{ + if (source == iconSource()) + return; + + if (m_menuItem) + m_menuItem->setIconSource(source); + + iconLoader()->setIconSource(source); + emit iconSourceChanged(); +} + +/*! + \qmlproperty string Qt.labs.platform::Menu::iconName + + This property holds the theme name of the menu's icon. + + \sa iconSource, QIcon::fromTheme() +*/ +QString QQuickPlatformMenu::iconName() const +{ + if (!m_iconLoader) + return QString(); + + return m_iconLoader->iconName(); +} + +void QQuickPlatformMenu::setIconName(const QString& name) +{ + if (name == iconName()) + return; + + if (m_menuItem) + m_menuItem->setIconName(name); + + iconLoader()->setIconName(name); + emit iconNameChanged(); +} + +/*! + \qmlproperty font Qt.labs.platform::Menu::font + + This property holds the menu's font. + + \sa text +*/ +QFont QQuickPlatformMenu::font() const +{ + return m_font; +} + +void QQuickPlatformMenu::setFont(const QFont& font) +{ + if (m_font == font) + return; + + m_font = font; + sync(); + emit fontChanged(); +} + +/*! + \qmlmethod void Qt.labs.platform::Menu::addItem(MenuItem item) + + Adds an \a item to the end of the menu. +*/ +void QQuickPlatformMenu::addItem(QQuickPlatformMenuItem *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 QQuickPlatformMenu::insertItem(int index, QQuickPlatformMenuItem *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()) { + QQuickPlatformMenuItem *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 QQuickPlatformMenu::removeItem(QQuickPlatformMenuItem *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 QQuickPlatformMenu::addMenu(QQuickPlatformMenu *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 QQuickPlatformMenu::insertMenu(int index, QQuickPlatformMenu *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 QQuickPlatformMenu::removeMenu(QQuickPlatformMenu *menu) +{ + if (!menu) + return; + + menu->setParentMenu(nullptr); + removeItem(menu->menuItem()); +} + +/*! + \qmlmethod void Qt.labs.platform::Menu::clear() + + Removes all items from the menu. +*/ +void QQuickPlatformMenu::clear() +{ + if (m_items.isEmpty()) + return; + + for (QQuickPlatformMenuItem *item : 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 QQuickPlatformMenu::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()); + } + + QQuickPlatformMenuItem *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<QQuickPlatformMenuItem *>(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 { +#ifndef QT_NO_CURSOR + QPoint pos = QCursor::pos(); + if (window) + pos = window->mapFromGlobal(pos); + targetRect.moveTo(pos); +#endif + } + + m_handle->showPopup(window, targetRect, menuItem ? menuItem->handle() : nullptr); +} + +/*! + \qmlmethod void Qt.labs.platform::Menu::close() + + Closes the menu. +*/ +void QQuickPlatformMenu::close() +{ + if (m_handle) + m_handle->dismiss(); +} + +void QQuickPlatformMenu::classBegin() +{ +} + +void QQuickPlatformMenu::componentComplete() +{ + m_complete = true; + if (m_handle && m_iconLoader) + m_iconLoader->setEnabled(true); + sync(); +} + +QQuickPlatformIconLoader *QQuickPlatformMenu::iconLoader() const +{ + if (!m_iconLoader) { + QQuickPlatformMenu *that = const_cast<QQuickPlatformMenu *>(this); + static int slot = staticMetaObject.indexOfSlot("updateIcon()"); + m_iconLoader = new QQuickPlatformIconLoader(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 *QQuickPlatformMenu::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 QQuickPlatformMenu::data_append(QQmlListProperty<QObject> *property, QObject *object) +{ + QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object); + if (QQuickPlatformMenuItem *item = qobject_cast<QQuickPlatformMenuItem *>(object)) + menu->addItem(item); + else if (QQuickPlatformMenu *subMenu = qobject_cast<QQuickPlatformMenu *>(object)) + menu->addMenu(subMenu); + else + menu->m_data.append(object); +} + +int QQuickPlatformMenu::data_count(QQmlListProperty<QObject> *property) +{ + QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object); + return menu->m_data.count(); +} + +QObject *QQuickPlatformMenu::data_at(QQmlListProperty<QObject> *property, int index) +{ + QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object); + return menu->m_data.value(index); +} + +void QQuickPlatformMenu::data_clear(QQmlListProperty<QObject> *property) +{ + QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object); + menu->m_data.clear(); +} + +void QQuickPlatformMenu::items_append(QQmlListProperty<QQuickPlatformMenuItem> *property, QQuickPlatformMenuItem *item) +{ + QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object); + menu->addItem(item); +} + +int QQuickPlatformMenu::items_count(QQmlListProperty<QQuickPlatformMenuItem> *property) +{ + QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object); + return menu->m_items.count(); +} + +QQuickPlatformMenuItem *QQuickPlatformMenu::items_at(QQmlListProperty<QQuickPlatformMenuItem> *property, int index) +{ + QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object); + return menu->m_items.value(index); +} + +void QQuickPlatformMenu::items_clear(QQmlListProperty<QQuickPlatformMenuItem> *property) +{ + QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object); + menu->clear(); +} + +void QQuickPlatformMenu::updateIcon() +{ + if (!m_handle || !m_iconLoader) + return; + + m_handle->setIcon(m_iconLoader->icon()); + sync(); +} + +QT_END_NAMESPACE diff --git a/src/imports/platform/qquickplatformmenu_p.h b/src/imports/platform/qquickplatformmenu_p.h new file mode 100644 index 00000000..2846c628 --- /dev/null +++ b/src/imports/platform/qquickplatformmenu_p.h @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +#ifndef QQUICKPLATFORMMENU_P_H +#define QQUICKPLATFORMMENU_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include <QtGui/qfont.h> +#include <QtGui/qpa/qplatformmenu.h> +#include <QtQml/qqmlparserstatus.h> +#include <QtQml/qqmllist.h> +#include <QtQml/qqml.h> + +QT_BEGIN_NAMESPACE + +class QIcon; +class QWindow; +class QQuickItem; +class QPlatformMenu; +class QQmlV4Function; +class QQuickPlatformMenuBar; +class QQuickPlatformMenuItem; +class QQuickPlatformIconLoader; + +class QQuickPlatformMenu : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + Q_PROPERTY(QQmlListProperty<QObject> data READ data FINAL) + Q_PROPERTY(QQmlListProperty<QQuickPlatformMenuItem> items READ items NOTIFY itemsChanged FINAL) + Q_PROPERTY(QQuickPlatformMenuBar *menuBar READ menuBar NOTIFY menuBarChanged FINAL) + Q_PROPERTY(QQuickPlatformMenu *parentMenu READ parentMenu NOTIFY parentMenuChanged FINAL) + Q_PROPERTY(QQuickPlatformMenuItem *menuItem READ menuItem CONSTANT FINAL) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL) + Q_PROPERTY(int minimumWidth READ minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged FINAL) + Q_PROPERTY(QPlatformMenu::MenuType type READ type WRITE setType NOTIFY typeChanged FINAL) + Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged FINAL) + Q_PROPERTY(QUrl iconSource READ iconSource WRITE setIconSource NOTIFY iconSourceChanged FINAL) + Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged FINAL) + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged FINAL) + Q_ENUMS(QPlatformMenu::MenuType) + Q_CLASSINFO("DefaultProperty", "data") + +public: + explicit QQuickPlatformMenu(QObject *parent = nullptr); + ~QQuickPlatformMenu(); + + QPlatformMenu *handle() const; + QPlatformMenu *create(); + void destroy(); + void sync(); + + QQmlListProperty<QObject> data(); + QQmlListProperty<QQuickPlatformMenuItem> items(); + + QQuickPlatformMenuBar *menuBar() const; + void setMenuBar(QQuickPlatformMenuBar *menuBar); + + QQuickPlatformMenu *parentMenu() const; + void setParentMenu(QQuickPlatformMenu *menu); + + QQuickPlatformMenuItem *menuItem() const; + + bool isEnabled() const; + void setEnabled(bool enabled); + + bool isVisible() const; + void setVisible(bool visible); + + int minimumWidth() const; + void setMinimumWidth(int width); + + QPlatformMenu::MenuType type() const; + void setType(QPlatformMenu::MenuType type); + + QString title() const; + void setTitle(const QString &title); + + QUrl iconSource() const; + void setIconSource(const QUrl &source); + + QString iconName() const; + void setIconName(const QString &name); + + QFont font() const; + void setFont(const QFont &font); + + Q_INVOKABLE void addItem(QQuickPlatformMenuItem *item); + Q_INVOKABLE void insertItem(int index, QQuickPlatformMenuItem *item); + Q_INVOKABLE void removeItem(QQuickPlatformMenuItem *item); + + Q_INVOKABLE void addMenu(QQuickPlatformMenu *menu); + Q_INVOKABLE void insertMenu(int index, QQuickPlatformMenu *menu); + Q_INVOKABLE void removeMenu(QQuickPlatformMenu *menu); + + Q_INVOKABLE void clear(); + +public Q_SLOTS: + void open(QQmlV4Function *args); + void close(); + +Q_SIGNALS: + void aboutToShow(); + void aboutToHide(); + + void itemsChanged(); + void menuBarChanged(); + void parentMenuChanged(); + void titleChanged(); + void iconSourceChanged(); + void iconNameChanged(); + void enabledChanged(); + void visibleChanged(); + void minimumWidthChanged(); + void fontChanged(); + void typeChanged(); + +protected: + void classBegin() override; + void componentComplete() override; + + QQuickPlatformIconLoader *iconLoader() const; + + QWindow *findWindow(QQuickItem *target, QPoint *offset) const; + + static void data_append(QQmlListProperty<QObject> *property, QObject *object); + static int data_count(QQmlListProperty<QObject> *property); + static QObject *data_at(QQmlListProperty<QObject> *property, int index); + static void data_clear(QQmlListProperty<QObject> *property); + + static void items_append(QQmlListProperty<QQuickPlatformMenuItem> *property, QQuickPlatformMenuItem *item); + static int items_count(QQmlListProperty<QQuickPlatformMenuItem> *property); + static QQuickPlatformMenuItem *items_at(QQmlListProperty<QQuickPlatformMenuItem> *property, int index); + static void items_clear(QQmlListProperty<QQuickPlatformMenuItem> *property); + +private Q_SLOTS: + void updateIcon(); + +private: + bool m_complete; + bool m_enabled; + bool m_visible; + int m_minimumWidth; + QPlatformMenu::MenuType m_type; + QString m_title; + QFont m_font; + QList<QObject *> m_data; + QList<QQuickPlatformMenuItem *> m_items; + QQuickPlatformMenuBar *m_menuBar; + QQuickPlatformMenu *m_parentMenu; + mutable QQuickPlatformMenuItem *m_menuItem; + mutable QQuickPlatformIconLoader *m_iconLoader; + QPlatformMenu *m_handle; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPlatformMenu) + +#endif // QQUICKPLATFORMMENU_P_H diff --git a/src/imports/platform/qquickplatformmenubar.cpp b/src/imports/platform/qquickplatformmenubar.cpp new file mode 100644 index 00000000..249bb014 --- /dev/null +++ b/src/imports/platform/qquickplatformmenubar.cpp @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "qquickplatformmenubar_p.h" +#include "qquickplatformmenu_p.h" + +#include <QtGui/qpa/qplatformmenu.h> +#include <QtGui/qpa/qplatformtheme.h> +#include <QtGui/private/qguiapplication_p.h> +#include <QtQuick/qquickwindow.h> +#include <QtQuick/qquickitem.h> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype MenuBar + \inherits QtObject + \instantiates QQuickPlatformMenuBar + \inqmlmodule Qt.labs.platform + \since 5.8 + \brief A native menubar. + + The MenuBar type provides a QML API for native platform menubars. + + \image qtlabsplatform-menubar.png + + A menubar consists of a list of drop-down menus. + + \code + MenuBar { + id: menuBar + + Menu { + id: fileMenu + title: qsTr("File") + // ... + } + + Menu { + id: editMenu + title: qsTr("&Edit") + // ... + } + + Menu { + id: viewMenu + title: qsTr("&View") + // ... + } + + Menu { + id: helpMenu + title: qsTr("&Help") + // ... + } + } + \endcode + + MenuBar is currently available on the following platforms: + + \list + \li OS X + \li Android + \li Linux (only available on desktop environments that provide a global D-Bus menu bar) + \endlist + + \labs + + \sa Menu +*/ + +QQuickPlatformMenuBar::QQuickPlatformMenuBar(QObject *parent) + : QObject(parent), + m_complete(false), + m_window(nullptr), + m_handle(nullptr) +{ + m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar(); +} + +QQuickPlatformMenuBar::~QQuickPlatformMenuBar() +{ + for (QQuickPlatformMenu *menu : m_menus) + menu->setMenuBar(nullptr); + delete m_handle; + m_handle = nullptr; +} + +QPlatformMenuBar *QQuickPlatformMenuBar::handle() const +{ + return m_handle; +} + +/*! + \default + \qmlproperty list<Object> Qt.labs.platform::MenuBar::data + + This default property holds the list of all objects declared as children of + the menubar. The data property includes objects that are not \l Menu instances, + such as \l Timer and \l QtObject. + + \sa menus +*/ +QQmlListProperty<QObject> QQuickPlatformMenuBar::data() +{ + return QQmlListProperty<QObject>(this, nullptr, data_append, data_count, data_at, data_clear); +} + +/*! + \qmlproperty list<Menu> Qt.labs.platform::MenuBar::menus + + This property holds the list of menus in the menubar. +*/ +QQmlListProperty<QQuickPlatformMenu> QQuickPlatformMenuBar::menus() +{ + return QQmlListProperty<QQuickPlatformMenu>(this, nullptr, menus_append, menus_count, menus_at, menus_clear); +} + +/*! + \qmlproperty Window Qt.labs.platform::MenuBar::window + + This property holds the menubar's window. + + Unless explicitly set, the window is automatically resolved by iterating + the QML parent objects until a \l Window or an \l Item that has a window + is found. +*/ +QWindow *QQuickPlatformMenuBar::window() const +{ + return m_window; +} + +void QQuickPlatformMenuBar::setWindow(QWindow *window) +{ + if (m_window == window) + return; + + if (m_handle) + m_handle->handleReparent(window); + + m_window = window; + emit windowChanged(); +} + +/*! + \qmlmethod void Qt.labs.platform::MenuBar::addMenu(Menu menu) + + Adds a \a menu to end of the menubar. +*/ +void QQuickPlatformMenuBar::addMenu(QQuickPlatformMenu *menu) +{ + insertMenu(m_menus.count(), menu); +} + +/*! + \qmlmethod void Qt.labs.platform::MenuBar::insertMenu(int index, Menu menu) + + Inserts a \a menu at the specified \a index in the menubar. +*/ +void QQuickPlatformMenuBar::insertMenu(int index, QQuickPlatformMenu *menu) +{ + if (!menu || m_menus.contains(menu)) + return; + + QQuickPlatformMenu *before = m_menus.value(index); + m_menus.insert(index, menu); + m_data.append(menu); + menu->setMenuBar(this); + if (m_handle) + m_handle->insertMenu(menu->create(), before ? before->handle() : nullptr); + emit menusChanged(); +} + +/*! + \qmlmethod void Qt.labs.platform::MenuBar::removeMenu(Menu menu) + + Removes a \a menu from the menubar. +*/ +void QQuickPlatformMenuBar::removeMenu(QQuickPlatformMenu *menu) +{ + if (!menu || !m_menus.removeOne(menu)) + return; + + m_data.removeOne(menu); + if (m_handle) + m_handle->removeMenu(menu->handle()); + menu->setMenuBar(nullptr); + emit menusChanged(); +} + +/*! + \qmlmethod void Qt.labs.platform::MenuBar::clear() + + Removes all menus from the menubar. +*/ +void QQuickPlatformMenuBar::clear() +{ + if (m_menus.isEmpty()) + return; + + for (QQuickPlatformMenu *menu : m_menus) { + m_data.removeOne(menu); + if (m_handle) + m_handle->removeMenu(menu->handle()); + menu->setMenuBar(nullptr); + delete menu; + } + + m_menus.clear(); + emit menusChanged(); +} + +void QQuickPlatformMenuBar::classBegin() +{ +} + +void QQuickPlatformMenuBar::componentComplete() +{ + m_complete = true; + for (QQuickPlatformMenu *menu : m_menus) + menu->sync(); + if (!m_window) + setWindow(findWindow()); +} + +QWindow *QQuickPlatformMenuBar::findWindow() const +{ + QObject *obj = parent(); + while (obj) { + QWindow *window = qobject_cast<QWindow *>(obj); + if (window) + return window; + QQuickItem *item = qobject_cast<QQuickItem *>(obj); + if (item && item->window()) + return item->window(); + obj = obj->parent(); + } + return nullptr; +} + +void QQuickPlatformMenuBar::data_append(QQmlListProperty<QObject> *property, QObject *object) +{ + QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object); + QQuickPlatformMenu *menu = qobject_cast<QQuickPlatformMenu *>(object); + if (menu) + menuBar->addMenu(menu); + else + menuBar->m_data.append(object); +} + +int QQuickPlatformMenuBar::data_count(QQmlListProperty<QObject> *property) +{ + QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object); + return menuBar->m_data.count(); +} + +QObject *QQuickPlatformMenuBar::data_at(QQmlListProperty<QObject> *property, int index) +{ + QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object); + return menuBar->m_data.value(index); +} + +void QQuickPlatformMenuBar::data_clear(QQmlListProperty<QObject> *property) +{ + QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object); + menuBar->m_data.clear(); +} + +void QQuickPlatformMenuBar::menus_append(QQmlListProperty<QQuickPlatformMenu> *property, QQuickPlatformMenu *menu) +{ + QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object); + menuBar->addMenu(menu); +} + +int QQuickPlatformMenuBar::menus_count(QQmlListProperty<QQuickPlatformMenu> *property) +{ + QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object); + return menuBar->m_menus.count(); +} + +QQuickPlatformMenu *QQuickPlatformMenuBar::menus_at(QQmlListProperty<QQuickPlatformMenu> *property, int index) +{ + QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object); + return menuBar->m_menus.value(index); +} + +void QQuickPlatformMenuBar::menus_clear(QQmlListProperty<QQuickPlatformMenu> *property) +{ + QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object); + menuBar->clear(); +} + +QT_END_NAMESPACE diff --git a/src/imports/platform/qquickplatformmenubar_p.h b/src/imports/platform/qquickplatformmenubar_p.h new file mode 100644 index 00000000..059acfe6 --- /dev/null +++ b/src/imports/platform/qquickplatformmenubar_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +#ifndef QQUICKPLATFORMMENUBAR_P_H +#define QQUICKPLATFORMMENUBAR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtQml/qqmlparserstatus.h> +#include <QtQml/qqmllist.h> +#include <QtQml/qqml.h> + +QT_BEGIN_NAMESPACE + +class QWindow; +class QPlatformMenuBar; +class QQuickPlatformMenu; + +class QQuickPlatformMenuBar : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + Q_PROPERTY(QQmlListProperty<QObject> data READ data FINAL) + Q_PROPERTY(QQmlListProperty<QQuickPlatformMenu> menus READ menus NOTIFY menusChanged FINAL) + Q_PROPERTY(QWindow *window READ window WRITE setWindow NOTIFY windowChanged FINAL) + Q_CLASSINFO("DefaultProperty", "data") + +public: + explicit QQuickPlatformMenuBar(QObject *parent = nullptr); + ~QQuickPlatformMenuBar(); + + QPlatformMenuBar *handle() const; + + QQmlListProperty<QObject> data(); + QQmlListProperty<QQuickPlatformMenu> menus(); + + QWindow *window() const; + void setWindow(QWindow *window); + + Q_INVOKABLE void addMenu(QQuickPlatformMenu *menu); + Q_INVOKABLE void insertMenu(int index, QQuickPlatformMenu *menu); + Q_INVOKABLE void removeMenu(QQuickPlatformMenu *menu); + Q_INVOKABLE void clear(); + +Q_SIGNALS: + void menusChanged(); + void windowChanged(); + +protected: + void classBegin() override; + void componentComplete() override; + + QWindow *findWindow() const; + + static void data_append(QQmlListProperty<QObject> *property, QObject *object); + static int data_count(QQmlListProperty<QObject> *property); + static QObject *data_at(QQmlListProperty<QObject> *property, int index); + static void data_clear(QQmlListProperty<QObject> *property); + + static void menus_append(QQmlListProperty<QQuickPlatformMenu> *property, QQuickPlatformMenu *menu); + static int menus_count(QQmlListProperty<QQuickPlatformMenu> *property); + static QQuickPlatformMenu *menus_at(QQmlListProperty<QQuickPlatformMenu> *property, int index); + static void menus_clear(QQmlListProperty<QQuickPlatformMenu> *property); + +private: + bool m_complete; + QWindow *m_window; + QList<QObject *> m_data; + QList<QQuickPlatformMenu *> m_menus; + QPlatformMenuBar *m_handle; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPlatformMenuBar) + +#endif // QQUICKPLATFORMMENUBAR_P_H diff --git a/src/imports/platform/qquickplatformmenuitem.cpp b/src/imports/platform/qquickplatformmenuitem.cpp new file mode 100644 index 00000000..115714f8 --- /dev/null +++ b/src/imports/platform/qquickplatformmenuitem.cpp @@ -0,0 +1,605 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 "qquickplatformmenuitem_p.h" +#include "qquickplatformmenu_p.h" +#include "qquickplatformmenuitemgroup_p.h" +#include "qquickplatformiconloader_p.h" + +#include <QtGui/qicon.h> +#include <QtGui/qkeysequence.h> +#include <QtGui/qpa/qplatformtheme.h> +#include <QtGui/private/qguiapplication_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype MenuItem + \inherits QtObject + \instantiates QQuickPlatformMenuItem + \inqmlmodule Qt.labs.platform + \since 5.8 + \brief A native menu item. + + The MenuItem type provides a QML API for native platform menu items. + + \image qtlabsplatform-menu.png + + A menu item consists of an \l {iconSource}{icon}, \l text, and \l shortcut. + + \code + Menu { + id: zoomMenu + + MenuItem { + text: qsTr("Zoom In") + shortcut: StandardKey.ZoomIn + onTriggered: zoomIn() + } + + MenuItem { + text: qsTr("Zoom Out") + shortcut: StandardKey.ZoomOut + onTriggered: zoomOut() + } + } + \endcode + + \labs + + \sa Menu, MenuItemGroup +*/ + +/*! + \qmlsignal Qt.labs.platform::MenuItem::triggered() + + This signal is emitted when the menu item is triggered by the user. +*/ + +/*! + \qmlsignal Qt.labs.platform::MenuItem::hovered() + + This signal is emitted when the menu item is hovered by the user. +*/ + +QQuickPlatformMenuItem::QQuickPlatformMenuItem(QObject *parent) + : QObject(parent), + m_complete(false), + m_enabled(true), + m_visible(true), + m_separator(false), + m_checkable(false), + m_checked(false), + m_role(QPlatformMenuItem::TextHeuristicRole), + m_menu(nullptr), + m_subMenu(nullptr), + m_group(nullptr), + m_iconLoader(nullptr), + m_handle(nullptr) +{ +} + +QQuickPlatformMenuItem::~QQuickPlatformMenuItem() +{ + if (m_menu) + m_menu->removeItem(this); + if (m_group) + m_group->removeItem(this); + delete m_iconLoader; + m_iconLoader = nullptr; + delete m_handle; + m_handle = nullptr; +} + +QPlatformMenuItem *QQuickPlatformMenuItem::handle() const +{ + return m_handle; +} + +QPlatformMenuItem *QQuickPlatformMenuItem::create() +{ + if (!m_handle && m_menu && m_menu->handle()) { + m_handle = m_menu->handle()->createMenuItem(); + + // TODO: implement QCocoaMenu::createMenuItem() + if (!m_handle) + m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem(); + + if (m_handle) { + connect(m_handle, &QPlatformMenuItem::activated, this, &QQuickPlatformMenuItem::triggered); + connect(m_handle, &QPlatformMenuItem::hovered, this, &QQuickPlatformMenuItem::hovered); + if (m_checkable) + connect(m_handle, &QPlatformMenuItem::activated, this, &QQuickPlatformMenuItem::toggle); + } + } + return m_handle; +} + +void QQuickPlatformMenuItem::sync() +{ + if (!m_complete || !create()) + return; + + m_handle->setEnabled(isEnabled()); + m_handle->setVisible(isVisible()); + m_handle->setIsSeparator(m_separator); + m_handle->setCheckable(m_checkable); + m_handle->setChecked(m_checked); + m_handle->setRole(m_role); + m_handle->setText(m_text); + m_handle->setFont(m_font); + m_handle->setHasExclusiveGroup(m_group && m_group->isExclusive()); + if (m_subMenu && m_subMenu->handle()) + m_handle->setMenu(m_subMenu->handle()); + + QKeySequence sequence; + if (m_shortcut.type() == QVariant::Int) + sequence = QKeySequence(static_cast<QKeySequence::StandardKey>(m_shortcut.toInt())); + else + sequence = QKeySequence::fromString(m_shortcut.toString()); + m_handle->setShortcut(sequence.toString()); + + if (m_menu && m_menu->handle()) + m_menu->handle()->syncMenuItem(m_handle); +} + +/*! + \readonly + \qmlproperty Menu Qt.labs.platform::MenuItem::menu + + This property holds the menu that the item belongs to, or \c null if the + item is not in a menu. +*/ +QQuickPlatformMenu *QQuickPlatformMenuItem::menu() const +{ + return m_menu; +} + +void QQuickPlatformMenuItem::setMenu(QQuickPlatformMenu *menu) +{ + if (m_menu == menu) + return; + + m_menu = menu; + emit menuChanged(); +} + +/*! + \readonly + \qmlproperty Menu Qt.labs.platform::MenuItem::subMenu + + This property holds the sub-menu that the item contains, or \c null if + the item is not a sub-menu item. +*/ +QQuickPlatformMenu *QQuickPlatformMenuItem::subMenu() const +{ + return m_subMenu; +} + +void QQuickPlatformMenuItem::setSubMenu(QQuickPlatformMenu *menu) +{ + if (m_subMenu == menu) + return; + + m_subMenu = menu; + sync(); + emit subMenuChanged(); +} + +/*! + \qmlproperty MenuItemGroup Qt.labs.platform::MenuItem::group + + This property holds the group that the item belongs to, or \c null if the + item is not in a group. +*/ +QQuickPlatformMenuItemGroup *QQuickPlatformMenuItem::group() const +{ + return m_group; +} + +void QQuickPlatformMenuItem::setGroup(QQuickPlatformMenuItemGroup *group) +{ + if (m_group == group) + return; + + bool wasEnabled = isEnabled(); + bool wasVisible = isVisible(); + + if (group) + group->addItem(this); + + m_group = group; + sync(); + emit groupChanged(); + + if (isEnabled() != wasEnabled) + emit enabledChanged(); + if (isVisible() != wasVisible) + emit visibleChanged(); +} + +/*! + \qmlproperty bool Qt.labs.platform::MenuItem::enabled + + This property holds whether the item is enabled. The default value is \c true. + + Disabled items cannot be triggered by the user. They do not disappear from menus, + but they are displayed in a way which indicates that they are unavailable. For + example, they might be displayed using only shades of gray. + + When an item is disabled, it is not possible to trigger it through its \l shortcut. +*/ +bool QQuickPlatformMenuItem::isEnabled() const +{ + return m_enabled && (!m_group || m_group->isEnabled()); +} + +void QQuickPlatformMenuItem::setEnabled(bool enabled) +{ + if (m_enabled == enabled) + return; + + bool wasEnabled = isEnabled(); + m_enabled = enabled; + sync(); + if (isEnabled() != wasEnabled) + emit enabledChanged(); +} + +/*! + \qmlproperty bool Qt.labs.platform::MenuItem::visible + + This property holds whether the item is visible. The default value is \c true. +*/ +bool QQuickPlatformMenuItem::isVisible() const +{ + return m_visible && (!m_group || m_group->isVisible()); +} + +void QQuickPlatformMenuItem::setVisible(bool visible) +{ + if (m_visible == visible) + return; + + bool wasVisible = isVisible(); + m_visible = visible; + sync(); + if (isVisible() != wasVisible) + emit visibleChanged(); +} + +/*! + \qmlproperty bool Qt.labs.platform::MenuItem::separator + + This property holds whether the item is a separator line. The default value + is \c false. +*/ +bool QQuickPlatformMenuItem::isSeparator() const +{ + return m_separator; +} + +void QQuickPlatformMenuItem::setSeparator(bool separator) +{ + if (m_separator == separator) + return; + + m_separator = separator; + sync(); + emit separatorChanged(); +} + +/*! + \qmlproperty bool Qt.labs.platform::MenuItem::checkable + + This property holds whether the item is checkable. + + A checkable menu item has an on/off state. For example, in a word processor, + a "Bold" menu item may be either on or off. A menu item that is not checkable + is a command item that is simply executed, e.g. file save. + + The default value is \c false. + + \sa checked, MenuItemGroup +*/ +bool QQuickPlatformMenuItem::isCheckable() const +{ + return m_checkable; +} + +void QQuickPlatformMenuItem::setCheckable(bool checkable) +{ + if (m_checkable == checkable) + return; + + if (m_handle) { + if (checkable) + connect(m_handle, &QPlatformMenuItem::activated, this, &QQuickPlatformMenuItem::toggle); + else + disconnect(m_handle, &QPlatformMenuItem::activated, this, &QQuickPlatformMenuItem::toggle); + } + + m_checkable = checkable; + sync(); + emit checkableChanged(); +} + +/*! + \qmlproperty bool Qt.labs.platform::MenuItem::checked + + This property holds whether the item is checked (on) or unchecked (off). + The default value is \c false. + + \sa checkable, MenuItemGroup +*/ +bool QQuickPlatformMenuItem::isChecked() const +{ + return m_checked; +} + +void QQuickPlatformMenuItem::setChecked(bool checked) +{ + if (m_checked == checked) + return; + + if (checked && !m_checkable) + setCheckable(true); + + m_checked = checked; + sync(); + emit checkedChanged(); +} + +/*! + \qmlproperty enumeration Qt.labs.platform::MenuItem::role + + This property holds the role of the item. The role determines whether + the item should be placed into the application menu on OS X. + + Available values: + \value MenuItem.NoRole The item should not be put into the application menu + \value MenuItem.TextHeuristicRole The item should be put in the application menu based on the action's text (default) + \value MenuItem.ApplicationSpecificRole The item should be put in the application menu with an application-specific role + \value MenuItem.AboutQtRole The item handles the "About Qt" menu item. + \value MenuItem.AboutRole The item should be placed where the "About" menu item is in the application menu. The text of + the menu item will be set to "About <application name>". The application name is fetched from the + \c{Info.plist} file in the application's bundle (See \l{Qt for OS X - Deployment}). + \value MenuItem.PreferencesRole The item should be placed where the "Preferences..." menu item is in the application menu. + \value MenuItem.QuitRole The item should be placed where the Quit menu item is in the application menu. + + Specifying the role only has effect on items that are in the immediate + menus of a menubar, not in the submenus of those menus. For example, if + you have a "File" menu in your menubar and the "File" menu has a submenu, + specifying a role for the items in that submenu has no effect. They will + never be moved to the application menu. +*/ +QPlatformMenuItem::MenuRole QQuickPlatformMenuItem::role() const +{ + return m_role; +} + +void QQuickPlatformMenuItem::setRole(QPlatformMenuItem::MenuRole role) +{ + if (m_role == role) + return; + + m_role = role; + sync(); + emit roleChanged(); +} + +/*! + \qmlproperty string Qt.labs.platform::MenuItem::text + + This property holds the menu item's text. +*/ +QString QQuickPlatformMenuItem::text() const +{ + return m_text; +} + +void QQuickPlatformMenuItem::setText(const QString &text) +{ + if (m_text == text) + return; + + m_text = text; + sync(); + emit textChanged(); +} + +/*! + \qmlproperty url Qt.labs.platform::MenuItem::iconSource + + This property holds the url of the menu item's icon. + + \code + MenuItem { + iconName: "edit-undo" + iconSource: "qrc:/images/undo.png" + } + \endcode + + \sa iconName +*/ +QUrl QQuickPlatformMenuItem::iconSource() const +{ + if (!m_iconLoader) + return QUrl(); + + return m_iconLoader->iconSource(); +} + +void QQuickPlatformMenuItem::setIconSource(const QUrl& source) +{ + if (source == iconSource()) + return; + + iconLoader()->setIconSource(source); + emit iconSourceChanged(); +} + +/*! + \qmlproperty string Qt.labs.platform::MenuItem::iconName + + This property holds the theme name of the menu item's icon. + + \code + MenuItem { + iconName: "edit-undo" + iconSource: "qrc:/images/undo.png" + } + \endcode + + \sa iconSource, QIcon::fromTheme() +*/ +QString QQuickPlatformMenuItem::iconName() const +{ + if (!m_iconLoader) + return QString(); + + return m_iconLoader->iconName(); +} + +void QQuickPlatformMenuItem::setIconName(const QString& name) +{ + if (name == iconName()) + return; + + iconLoader()->setIconName(name); + emit iconNameChanged(); +} + +/*! + \qmlproperty keysequence Qt.labs.platform::MenuItem::shortcut + + This property holds the menu item's shortcut. + + The shortcut key sequence can be set to one of the + \l{QKeySequence::StandardKey}{standard keyboard shortcuts}, or it can be + specified by a string containing a sequence of up to four key presses + that are needed to \l{triggered}{trigger} the shortcut. + + The default value is an empty key sequence. + + \code + MenuItem { + shortcut: "Ctrl+E,Ctrl+W" + onTriggered: edit.wrapMode = TextEdit.Wrap + } + \endcode +*/ +QVariant QQuickPlatformMenuItem::shortcut() const +{ + return m_shortcut; +} + +void QQuickPlatformMenuItem::setShortcut(const QVariant& shortcut) +{ + if (m_shortcut == shortcut) + return; + + m_shortcut = shortcut; + sync(); + emit shortcutChanged(); +} + +/*! + \qmlproperty font Qt.labs.platform::MenuItem::font + + This property holds the menu item's font. + + \sa text +*/ +QFont QQuickPlatformMenuItem::font() const +{ + return m_font; +} + +void QQuickPlatformMenuItem::setFont(const QFont& font) +{ + if (m_font == font) + return; + + m_font = font; + sync(); + emit fontChanged(); +} + +/*! + \qmlmethod void Qt.labs.platform::MenuItem::toggle() + + Toggles the \l checked state to its opposite state. +*/ +void QQuickPlatformMenuItem::toggle() +{ + if (m_checkable) + setChecked(!m_checked); +} + +void QQuickPlatformMenuItem::classBegin() +{ +} + +void QQuickPlatformMenuItem::componentComplete() +{ + if (m_handle && m_iconLoader) + m_iconLoader->setEnabled(true); + m_complete = true; + sync(); +} + +QQuickPlatformIconLoader *QQuickPlatformMenuItem::iconLoader() const +{ + if (!m_iconLoader) { + QQuickPlatformMenuItem *that = const_cast<QQuickPlatformMenuItem *>(this); + static int slot = staticMetaObject.indexOfSlot("updateIcon()"); + m_iconLoader = new QQuickPlatformIconLoader(slot, that); + m_iconLoader->setEnabled(m_complete); + } + return m_iconLoader; +} + +void QQuickPlatformMenuItem::updateIcon() +{ + if (!m_handle || !m_iconLoader) + return; + + m_handle->setIcon(m_iconLoader->icon()); + sync(); +} + +QT_END_NAMESPACE diff --git a/src/imports/platform/qquickplatformmenuitem_p.h b/src/imports/platform/qquickplatformmenuitem_p.h new file mode 100644 index 00000000..48a5603e --- /dev/null +++ b/src/imports/platform/qquickplatformmenuitem_p.h @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +#ifndef QQUICKPLATFORMMENUITEM_P_H +#define QQUICKPLATFORMMENUITEM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include <QtGui/qfont.h> +#include <QtGui/qpa/qplatformmenu.h> +#include <QtQml/qqmlparserstatus.h> +#include <QtQml/qqml.h> + +QT_BEGIN_NAMESPACE + +class QPlatformMenuItem; +class QQuickPlatformMenu; +class QQuickPlatformIconLoader; +class QQuickPlatformMenuItemGroup; + +class QQuickPlatformMenuItem : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + Q_PROPERTY(QQuickPlatformMenu *menu READ menu NOTIFY menuChanged FINAL) + Q_PROPERTY(QQuickPlatformMenu *subMenu READ subMenu NOTIFY subMenuChanged FINAL) + Q_PROPERTY(QQuickPlatformMenuItemGroup *group READ group WRITE setGroup NOTIFY groupChanged FINAL) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL) + Q_PROPERTY(bool separator READ isSeparator WRITE setSeparator NOTIFY separatorChanged FINAL) + Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY checkableChanged FINAL) + Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY checkedChanged FINAL) + Q_PROPERTY(QPlatformMenuItem::MenuRole role READ role WRITE setRole NOTIFY roleChanged FINAL) + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL) + Q_PROPERTY(QUrl iconSource READ iconSource WRITE setIconSource NOTIFY iconSourceChanged FINAL) + Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged FINAL) + Q_PROPERTY(QVariant shortcut READ shortcut WRITE setShortcut NOTIFY shortcutChanged FINAL) + Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged FINAL) + Q_ENUMS(QPlatformMenuItem::MenuRole) + +public: + explicit QQuickPlatformMenuItem(QObject *parent = nullptr); + ~QQuickPlatformMenuItem(); + + QPlatformMenuItem *handle() const; + QPlatformMenuItem *create(); + void sync(); + + QQuickPlatformMenu *menu() const; + void setMenu(QQuickPlatformMenu* menu); + + QQuickPlatformMenu *subMenu() const; + void setSubMenu(QQuickPlatformMenu *menu); + + QQuickPlatformMenuItemGroup *group() const; + void setGroup(QQuickPlatformMenuItemGroup *group); + + bool isEnabled() const; + void setEnabled(bool enabled); + + bool isVisible() const; + void setVisible(bool visible); + + bool isSeparator() const; + void setSeparator(bool separator); + + bool isCheckable() const; + void setCheckable(bool checkable); + + bool isChecked() const; + void setChecked(bool checked); + + QPlatformMenuItem::MenuRole role() const; + void setRole(QPlatformMenuItem::MenuRole role); + + QString text() const; + void setText(const QString &text); + + QUrl iconSource() const; + void setIconSource(const QUrl &source); + + QString iconName() const; + void setIconName(const QString &name); + + QVariant shortcut() const; + void setShortcut(const QVariant& shortcut); + + QFont font() const; + void setFont(const QFont &font); + +public Q_SLOTS: + void toggle(); + +Q_SIGNALS: + void triggered(); + void hovered(); + + void menuChanged(); + void subMenuChanged(); + void groupChanged(); + void enabledChanged(); + void visibleChanged(); + void separatorChanged(); + void checkableChanged(); + void checkedChanged(); + void roleChanged(); + void textChanged(); + void iconSourceChanged(); + void iconNameChanged(); + void shortcutChanged(); + void fontChanged(); + +protected: + void classBegin() override; + void componentComplete() override; + + QQuickPlatformIconLoader *iconLoader() const; + +private Q_SLOTS: + void updateIcon(); + +private: + bool m_complete; + bool m_enabled; + bool m_visible; + bool m_separator; + bool m_checkable; + bool m_checked; + QPlatformMenuItem::MenuRole m_role; + QString m_text; + QVariant m_shortcut; + QFont m_font; + QQuickPlatformMenu *m_menu; + QQuickPlatformMenu *m_subMenu; + QQuickPlatformMenuItemGroup *m_group; + mutable QQuickPlatformIconLoader *m_iconLoader; + QPlatformMenuItem *m_handle; + + friend class QQuickPlatformMenu; + friend class QQuickPlatformMenuItemGroup; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPlatformMenuItem) + +#endif // QQUICKPLATFORMMENUITEM_P_H diff --git a/src/imports/platform/qquickplatformmenuitemgroup.cpp b/src/imports/platform/qquickplatformmenuitemgroup.cpp new file mode 100644 index 00000000..1f4dda3c --- /dev/null +++ b/src/imports/platform/qquickplatformmenuitemgroup.cpp @@ -0,0 +1,390 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates 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 "qquickplatformmenuitemgroup_p.h" +#include "qquickplatformmenuitem_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype MenuItemGroup + \inherits QtObject + \instantiates QQuickPlatformMenuItemGroup + \inqmlmodule Qt.labs.platform + \since 5.8 + \brief A group for managing native menu items. + + The MenuItemGroup groups native menu items together. + + MenuItemGroup is exclusive by default. In an exclusive menu item + group, only one item can be checked at any time; checking another + item automatically unchecks the previously checked one. MenuItemGroup + can be configured as non-exclusive, which is particularly useful for + showing, hiding, enabling and disabling items together as a group. + + The most straight-forward way to use MenuItemGroup is to assign + a list of items. + + \code + Menu { + id: verticalMenu + title: qsTr("Vertical") + + MenuItemGroup { + id: verticalGroup + items: verticalMenu.items + } + + MenuItem { text: qsTr("Top"); checkable: true } + MenuItem { text: qsTr("Center"); checked: true } + MenuItem { text: qsTr("Bottom"); checkable: true } + } + \endcode + + The same menu may sometimes contain items that should not be included + in the same exclusive group. Such cases are best handled using the + \l {MenuItem::group}{group} property. + + \code + Menu { + id: horizontalMenu + title: qsTr("Horizontal") + + MenuItemGroup { + id: horizontalGroup + } + + MenuItem { + checked: true + text: qsTr("Left") + group: horizontalGroup + } + MenuItem { + checkable: true + text: qsTr("Center") + group: horizontalGroup + } + MenuItem { + text: qsTr("Right") + checkable: true + group: horizontalGroup + } + + MenuItem { separator: true } + MenuItem { text: qsTr("Justify"); checkable: true } + MenuItem { text: qsTr("Absolute"); checkable: true } + } + \endcode + + More advanced use cases can be handled using the addItem() and + removeItem() methods. + + \labs + + \sa MenuItem +*/ + +/*! + \qmlsignal Qt.labs.platform::MenuItemGroup::triggered(MenuItem item) + + This signal is emitted when an \a item in the group is triggered by the user. + + \sa MenuItem::triggered() +*/ + +/*! + \qmlsignal Qt.labs.platform::MenuItemGroup::hovered(MenuItem item) + + This signal is emitted when an \a item in the group is hovered by the user. + + \sa MenuItem::hovered() +*/ + +QQuickPlatformMenuItemGroup::QQuickPlatformMenuItemGroup(QObject *parent) + : QObject(parent), m_enabled(true), m_visible(true), m_exclusive(true), m_checkedItem(nullptr) +{ +} + +QQuickPlatformMenuItemGroup::~QQuickPlatformMenuItemGroup() +{ + clear(); +} + +/*! + \qmlproperty bool Qt.labs.platform::MenuItemGroup::enabled + + This property holds whether the group is enabled. The default value is \c true. + + The enabled state of the group affects the enabled state of each item in the group, + except that explicitly disabled items are not enabled even if the group is enabled. +*/ +bool QQuickPlatformMenuItemGroup::isEnabled() const +{ + return m_enabled; +} + +void QQuickPlatformMenuItemGroup::setEnabled(bool enabled) +{ + if (m_enabled == enabled) + return; + + m_enabled = enabled; + emit enabledChanged(); + + for (QQuickPlatformMenuItem *item : m_items) { + if (item->m_enabled) { + item->sync(); + emit item->enabledChanged(); + } + } +} + +/*! + \qmlproperty bool Qt.labs.platform::MenuItemGroup::visible + + This property holds whether the group is visible. The default value is \c true. + + The visibility of the group affects the visibility of each item in the group, + except that explicitly hidden items are not visible even if the group is visible. +*/ +bool QQuickPlatformMenuItemGroup::isVisible() const +{ + return m_visible; +} + +void QQuickPlatformMenuItemGroup::setVisible(bool visible) +{ + if (m_visible == visible) + return; + + m_visible = visible; + emit visibleChanged(); + + for (QQuickPlatformMenuItem *item : m_items) { + if (item->m_visible) { + item->sync(); + emit item->visibleChanged(); + } + } +} + +/*! + \qmlproperty bool Qt.labs.platform::MenuItemGroup::exclusive + + This property holds whether the group is exclusive. The default value is \c true. + + In an exclusive menu item group, only one item can be checked at any time; + checking another item automatically unchecks the previously checked one. +*/ +bool QQuickPlatformMenuItemGroup::isExclusive() const +{ + return m_exclusive; +} + +void QQuickPlatformMenuItemGroup::setExclusive(bool exclusive) +{ + if (m_exclusive == exclusive) + return; + + m_exclusive = exclusive; + emit exclusiveChanged(); + + for (QQuickPlatformMenuItem *item : m_items) + item->sync(); +} + +/*! + \qmlproperty MenuItem Qt.labs.platform::MenuItemGroup::checkedItem + + This property holds the currently checked item in the group, or \c null if no item is checked. +*/ +QQuickPlatformMenuItem *QQuickPlatformMenuItemGroup::checkedItem() const +{ + return m_checkedItem; +} + +void QQuickPlatformMenuItemGroup::setCheckedItem(QQuickPlatformMenuItem *item) +{ + if (m_checkedItem == item) + return; + + if (m_checkedItem) + m_checkedItem->setChecked(false); + + m_checkedItem = item; + emit checkedItemChanged(); + + if (item) + item->setChecked(true); +} + +/*! + \qmlproperty list<MenuItem> Qt.labs.platform::MenuItemGroup::items + + This property holds the list of items in the group. +*/ +QQmlListProperty<QQuickPlatformMenuItem> QQuickPlatformMenuItemGroup::items() +{ + return QQmlListProperty<QQuickPlatformMenuItem>(this, nullptr, items_append, items_count, items_at, items_clear); +} + +/*! + \qmlmethod void Qt.labs.platform::MenuItemGroup::addItem(MenuItem item) + + Adds an \a item to the group. +*/ +void QQuickPlatformMenuItemGroup::addItem(QQuickPlatformMenuItem *item) +{ + if (!item || m_items.contains(item)) + return; + + m_items.append(item); + item->setGroup(this); + + connect(item, &QQuickPlatformMenuItem::checkedChanged, this, &QQuickPlatformMenuItemGroup::updateCurrent); + connect(item, &QQuickPlatformMenuItem::triggered, this, &QQuickPlatformMenuItemGroup::activateItem); + connect(item, &QQuickPlatformMenuItem::hovered, this, &QQuickPlatformMenuItemGroup::hoverItem); + + if (m_exclusive && item->isChecked()) + setCheckedItem(item); + + emit itemsChanged(); +} + +/*! + \qmlmethod void Qt.labs.platform::MenuItemGroup::removeItem(MenuItem item) + + Removes an \a item from the group. +*/ +void QQuickPlatformMenuItemGroup::removeItem(QQuickPlatformMenuItem *item) +{ + if (!item || !m_items.contains(item)) + return; + + m_items.removeOne(item); + item->setGroup(nullptr); + + disconnect(item, &QQuickPlatformMenuItem::checkedChanged, this, &QQuickPlatformMenuItemGroup::updateCurrent); + disconnect(item, &QQuickPlatformMenuItem::triggered, this, &QQuickPlatformMenuItemGroup::activateItem); + disconnect(item, &QQuickPlatformMenuItem::hovered, this, &QQuickPlatformMenuItemGroup::hoverItem); + + if (m_checkedItem == item) + setCheckedItem(nullptr); + + emit itemsChanged(); +} + +/*! + \qmlmethod void Qt.labs.platform::MenuItemGroup::clear() + + Removes all items from the group. +*/ +void QQuickPlatformMenuItemGroup::clear() +{ + if (m_items.isEmpty()) + return; + + for (QQuickPlatformMenuItem *item : m_items) { + item->setGroup(nullptr); + disconnect(item, &QQuickPlatformMenuItem::checkedChanged, this, &QQuickPlatformMenuItemGroup::updateCurrent); + disconnect(item, &QQuickPlatformMenuItem::triggered, this, &QQuickPlatformMenuItemGroup::activateItem); + disconnect(item, &QQuickPlatformMenuItem::hovered, this, &QQuickPlatformMenuItemGroup::hoverItem); + } + + setCheckedItem(nullptr); + + m_items.clear(); + emit itemsChanged(); +} + +QQuickPlatformMenuItem *QQuickPlatformMenuItemGroup::findCurrent() const +{ + for (QQuickPlatformMenuItem *item : m_items) { + if (item->isChecked()) + return item; + } + return nullptr; +} + +void QQuickPlatformMenuItemGroup::updateCurrent() +{ + if (!m_exclusive) + return; + + QQuickPlatformMenuItem *item = qobject_cast<QQuickPlatformMenuItem*>(sender()); + if (item && item->isChecked()) + setCheckedItem(item); +} + +void QQuickPlatformMenuItemGroup::activateItem() +{ + QQuickPlatformMenuItem *item = qobject_cast<QQuickPlatformMenuItem*>(sender()); + if (item) + emit triggered(item); +} + +void QQuickPlatformMenuItemGroup::hoverItem() +{ + QQuickPlatformMenuItem *item = qobject_cast<QQuickPlatformMenuItem*>(sender()); + if (item) + emit hovered(item); +} + +void QQuickPlatformMenuItemGroup::items_append(QQmlListProperty<QQuickPlatformMenuItem> *prop, QQuickPlatformMenuItem *item) +{ + QQuickPlatformMenuItemGroup *group = static_cast<QQuickPlatformMenuItemGroup *>(prop->object); + group->addItem(item); +} + +int QQuickPlatformMenuItemGroup::items_count(QQmlListProperty<QQuickPlatformMenuItem> *prop) +{ + QQuickPlatformMenuItemGroup *group = static_cast<QQuickPlatformMenuItemGroup *>(prop->object); + return group->m_items.count(); +} + +QQuickPlatformMenuItem *QQuickPlatformMenuItemGroup::items_at(QQmlListProperty<QQuickPlatformMenuItem> *prop, int index) +{ + QQuickPlatformMenuItemGroup *group = static_cast<QQuickPlatformMenuItemGroup *>(prop->object); + return group->m_items.value(index); +} + +void QQuickPlatformMenuItemGroup::items_clear(QQmlListProperty<QQuickPlatformMenuItem> *prop) +{ + QQuickPlatformMenuItemGroup *group = static_cast<QQuickPlatformMenuItemGroup *>(prop->object); + group->clear(); +} + +QT_END_NAMESPACE diff --git a/src/imports/platform/qquickplatformmenuitemgroup_p.h b/src/imports/platform/qquickplatformmenuitemgroup_p.h new file mode 100644 index 00000000..f5797eff --- /dev/null +++ b/src/imports/platform/qquickplatformmenuitemgroup_p.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Labs Templates 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$ +** +****************************************************************************/ + +#ifndef QQUICKPLATFORMMENUITEMGROUP_P_H +#define QQUICKPLATFORMMENUITEMGROUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qobject.h> +#include <QtCore/qvector.h> +#include <QtQml/qqml.h> + +QT_BEGIN_NAMESPACE + +class QQuickPlatformMenuItem; +class QQuickPlatformMenuItemGroupPrivate; + +class QQuickPlatformMenuItemGroup : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL) + Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL) + Q_PROPERTY(bool exclusive READ isExclusive WRITE setExclusive NOTIFY exclusiveChanged FINAL) + Q_PROPERTY(QQuickPlatformMenuItem *checkedItem READ checkedItem WRITE setCheckedItem NOTIFY checkedItemChanged FINAL) + Q_PROPERTY(QQmlListProperty<QQuickPlatformMenuItem> items READ items NOTIFY itemsChanged FINAL) + +public: + explicit QQuickPlatformMenuItemGroup(QObject *parent = nullptr); + ~QQuickPlatformMenuItemGroup(); + + bool isEnabled() const; + void setEnabled(bool enabled); + + bool isVisible() const; + void setVisible(bool visible); + + bool isExclusive() const; + void setExclusive(bool exclusive); + + QQuickPlatformMenuItem *checkedItem() const; + void setCheckedItem(QQuickPlatformMenuItem *item); + + QQmlListProperty<QQuickPlatformMenuItem> items(); + + Q_INVOKABLE void addItem(QQuickPlatformMenuItem *item); + Q_INVOKABLE void removeItem(QQuickPlatformMenuItem *item); + Q_INVOKABLE void clear(); + +Q_SIGNALS: + void triggered(QQuickPlatformMenuItem *item); + void hovered(QQuickPlatformMenuItem *item); + + void enabledChanged(); + void visibleChanged(); + void exclusiveChanged(); + void checkedItemChanged(); + void itemsChanged(); + +private: + QQuickPlatformMenuItem *findCurrent() const; + void updateCurrent(); + void activateItem(); + void hoverItem(); + + static void items_append(QQmlListProperty<QQuickPlatformMenuItem> *prop, QQuickPlatformMenuItem *obj); + static int items_count(QQmlListProperty<QQuickPlatformMenuItem> *prop); + static QQuickPlatformMenuItem *items_at(QQmlListProperty<QQuickPlatformMenuItem> *prop, int index); + static void items_clear(QQmlListProperty<QQuickPlatformMenuItem> *prop); + + bool m_enabled; + bool m_visible; + bool m_exclusive; + QQuickPlatformMenuItem *m_checkedItem; + QVector<QQuickPlatformMenuItem*> m_items; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPlatformMenuItemGroup) + +#endif // QQUICKPLATFORMMENUITEMGROUP_P_H diff --git a/src/imports/platform/qtlabsplatformplugin.cpp b/src/imports/platform/qtlabsplatformplugin.cpp index c691e1cf..05199971 100644 --- a/src/imports/platform/qtlabsplatformplugin.cpp +++ b/src/imports/platform/qtlabsplatformplugin.cpp @@ -37,6 +37,11 @@ #include <QtQml/qqmlextensionplugin.h> #include <QtQml/qqml.h> +#include "qquickplatformmenu_p.h" +#include "qquickplatformmenubar_p.h" +#include "qquickplatformmenuitem_p.h" +#include "qquickplatformmenuitemgroup_p.h" + static inline void initResources() { #ifdef QT_STATIC @@ -63,7 +68,10 @@ QtLabsPlatformPlugin::QtLabsPlatformPlugin(QObject *parent) : QQmlExtensionPlugi void QtLabsPlatformPlugin::registerTypes(const char *uri) { - Q_UNUSED(uri) + qmlRegisterType<QQuickPlatformMenu>(uri, 1, 0, "Menu"); + qmlRegisterType<QQuickPlatformMenuBar>(uri, 1, 0, "MenuBar"); + qmlRegisterType<QQuickPlatformMenuItem>(uri, 1, 0, "MenuItem"); + qmlRegisterType<QQuickPlatformMenuItemGroup>(uri, 1, 0, "MenuItemGroup"); } QT_END_NAMESPACE |