Introduce MenuBar

MenuBar is an ordinary Item. It can be located basically anywhere, but
the idea is to introduce a new ApplicationWindow::menuBar property in a
follow-up commit. Currently the example snippets are using the header
property.

[ChangeLog][Controls][MenuBar] Introduced a MenuBar control.

Task-number: QTBUG-60350
Change-Id: Ie66dc457a3d8edbe8362fab2a591dc49442c95e2
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
This commit is contained in:
J-P Nurmi 2017-06-03 10:16:42 +02:00
parent 9484e47132
commit 66faa149db
37 changed files with 2848 additions and 13 deletions

1
.gitignore vendored
View File

@ -47,6 +47,7 @@
/tests/auto/qquickiconlabel/tst_qquickiconlabel
/tests/auto/qquickmaterialstyle/tst_qquickmaterialstyle
/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf
/tests/auto/qquickmenubar/tst_qquickmenubar
/tests/auto/qquickstyle/tst_qquickstyle
/tests/auto/qquickstyleselector/tst_qquickstyleselector
/tests/auto/qquickuniversalstyle/tst_qquickuniversalstyle

View File

@ -0,0 +1,63 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Controls 2 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$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Templates 2.3 as T
import QtQuick.Controls 2.3
import QtQuick.Controls.impl 2.3
T.MenuBar {
id: control
implicitWidth: Math.max(background ? background.implicitWidth : 0,
contentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(background ? background.implicitHeight : 0,
contentHeight + topPadding + bottomPadding)
delegate: MenuBarItem { }
contentItem: Row {
spacing: control.spacing
Repeater {
model: control.contentModel
}
}
background: Rectangle {
implicitHeight: 40
color: Default.delegateColor
}
}

View File

@ -0,0 +1,78 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Controls 2 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$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Templates 2.3 as T
import QtQuick.Controls 2.3
import QtQuick.Controls.impl 2.3
T.MenuBarItem {
id: control
implicitWidth: Math.max(background ? background.implicitWidth : 0,
contentItem.implicitWidth + leftPadding + rightPadding)
implicitHeight: Math.max(background ? background.implicitHeight : 0,
Math.max(contentItem.implicitHeight,
indicator ? indicator.implicitHeight : 0) + topPadding + bottomPadding)
baselineOffset: contentItem.y + contentItem.baselineOffset
spacing: 6
padding: 6
leftPadding: 12
rightPadding: 16
icon.width: 24
icon.height: 24
icon.color: enabled ? Default.textDarkColor : Default.textDisabledColor
contentItem: IconLabel {
spacing: control.spacing
mirrored: control.mirrored
display: control.display
alignment: Qt.AlignLeft
icon: control.icon
text: control.text
font: control.font
color: control.enabled ? Default.textDarkColor : Default.textDisabledColor
}
background: Rectangle {
implicitWidth: 40
implicitHeight: 40
color: control.highlighted || control.down ? Default.delegatePressedColor : "transparent"
}
}

View File

@ -36,6 +36,8 @@ QML_CONTROLS = \
$$PWD/ItemDelegate.qml \
$$PWD/Label.qml \
$$PWD/Menu.qml \
$$PWD/MenuBar.qml \
$$PWD/MenuBarItem.qml \
$$PWD/MenuItem.qml \
$$PWD/MenuSeparator.qml \
$$PWD/Page.qml \

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -0,0 +1,84 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Controls 2.3
ApplicationWindow {
id: window
visible: true
width: menuBar.implicitWidth
height: menuBar.height
Component.onCompleted: menuBar.itemAt(1).highlighted = true
header:
// Indent it like this so that the indenting in the generated doc is normal.
MenuBar {
id: menuBar
Menu { title: qsTr("File") }
Menu { title: qsTr("Edit") }
Menu { title: qsTr("View") }
Menu { title: qsTr("Help") }
delegate: MenuBarItem {
id: menuBarItem
contentItem: Text {
text: menuBarItem.text
font: menuBarItem.font
opacity: enabled ? 1.0 : 0.3
color: menuBarItem.highlighted ? "#ffffff" : "#21be2b"
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
background: Rectangle {
implicitWidth: 40
implicitHeight: 40
opacity: enabled ? 1 : 0.3
color: menuBarItem.highlighted ? "#21be2b" : "transparent"
}
}
background: Rectangle {
implicitWidth: 40
implicitHeight: 40
color: "#ffffff"
Rectangle {
color: "#21be2b"
width: parent.width
height: 1
anchors.bottom: parent.bottom
}
}
}
} //! [eof]

View File

@ -0,0 +1,67 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Controls 2.3
//! [begin]
ApplicationWindow {
id: window
width: 320
height: 260
visible: true
//! [skipfrom]
Component.onCompleted: {
header.itemAt(0).triggered()
header.itemAt(0).menu.itemAt(2).highlighted = true
}
//! [skipto]
header: MenuBar {
Menu {
title: qsTr("File")
Action { text: qsTr("New...") }
Action { text: qsTr("Open...") }
Action { text: qsTr("Save") }
Action { text: qsTr("Save As...") }
MenuSeparator { }
Action { text: qsTr("Quit") }
}
Menu {
title: qsTr("Edit")
Action { text: qsTr("Cut") }
Action { text: qsTr("Copy") }
Action { text: qsTr("Paste") }
}
Menu {
title: qsTr("Help")
Action { text: qsTr("About") }
}
}
}
//! [end]

View File

@ -560,6 +560,21 @@
\printto eof
\section2 Customizing MenuBar
MenuBar can have a visual \l {Control::background}{background} item,
and MenuBarItem consists of two visual items: \l {Control::background}
{background} and \l {Control::contentItem}{content item}.
\image qtquickcontrols2-menubar-custom.png
\quotefromfile qtquickcontrols2-menubar-custom.qml
\skipto import QtQuick 2.9
\printuntil import QtQuick.Controls 2.3
\skipto MenuBar
\printto eof
\section2 Customizing PageIndicator
PageIndicator consists of a \l {Control::background}{background}, \l {Control::contentItem}{content item}, and \l {PageIndicator::delegate}{delegate}.

View File

@ -52,4 +52,17 @@
\li is highlighted (for example, on keyboard navigation)
\li performs some action on activation
\endlist
\section1 MenuBar Control
\image qtquickcontrols2-menubar.png
\l MenuBar control can be used for window menu bars.
\l MenuBarItem is an item in the MenuBar control. Each item in a menu bar:
\list
\li displays text to the user
\li is highlighted (for example, on keyboard navigation)
\li pops up the respective menu on activation
\endlist
*/

View File

@ -0,0 +1,74 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Controls 2 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$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Templates 2.3 as T
import QtQuick.Controls 2.3
import QtQuick.Controls.impl 2.3
import QtQuick.Controls.Fusion 2.3
import QtQuick.Controls.Fusion.impl 2.3
T.MenuBar {
id: control
implicitWidth: Math.max(background ? background.implicitWidth : 0,
contentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(background ? background.implicitHeight : 0,
contentHeight + topPadding + bottomPadding)
delegate: MenuBarItem { }
contentItem: Row {
spacing: control.spacing
Repeater {
model: control.contentModel
}
}
background: Rectangle {
implicitHeight: 20
color: control.palette.window
Rectangle {
y: parent.height - height
width: parent.width
height: 1
color: Fusion.mergedColors(Qt.darker(control.palette.window, 1.2),
Qt.lighter(Fusion.outline(control.palette), 1.4), 60)
}
}
}

View File

@ -0,0 +1,79 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Controls 2 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$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Templates 2.3 as T
import QtQuick.Controls 2.3
import QtQuick.Controls.impl 2.3
import QtQuick.Controls.Fusion 2.3
import QtQuick.Controls.Fusion.impl 2.3
T.MenuBarItem {
id: control
implicitWidth: Math.max(background ? background.implicitWidth : 0,
contentItem.implicitWidth + leftPadding + rightPadding)
implicitHeight: Math.max(background ? background.implicitHeight : 0,
Math.max(contentItem.implicitHeight,
indicator ? indicator.implicitHeight : 0) + topPadding + bottomPadding)
baselineOffset: contentItem.y + contentItem.baselineOffset
padding: 6
spacing: 6
icon.width: 16
icon.height: 16
contentItem: IconLabel {
spacing: control.spacing
mirrored: control.mirrored
display: control.display
alignment: Qt.AlignLeft
icon: control.icon
text: control.text
font: control.font
color: control.down || control.highlighted ? Fusion.highlightedText(control.palette) : control.palette.text
}
background: Rectangle {
implicitWidth: 20
implicitHeight: 20
color: Fusion.highlight(control.palette)
visible: control.down || control.highlighted
}
}

View File

@ -31,6 +31,8 @@ QML_FILES += \
$$PWD/ItemDelegate.qml \
$$PWD/Label.qml \
$$PWD/Menu.qml \
$$PWD/MenuBar.qml \
$$PWD/MenuBarItem.qml \
$$PWD/MenuItem.qml \
$$PWD/MenuSeparator.qml \
$$PWD/Page.qml \

View File

@ -0,0 +1,65 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Controls 2 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$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Templates 2.3 as T
import QtQuick.Controls 2.3
import QtQuick.Controls.impl 2.3
import QtQuick.Controls.Material 2.3
import QtQuick.Controls.Material.impl 2.3
T.MenuBar {
id: control
implicitWidth: Math.max(background ? background.implicitWidth : 0,
contentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(background ? background.implicitHeight : 0,
contentHeight + topPadding + bottomPadding)
delegate: MenuBarItem { }
contentItem: Row {
spacing: control.spacing
Repeater {
model: control.contentModel
}
}
background: Rectangle {
implicitHeight: 40
color: control.Material.dialogColor
}
}

View File

@ -0,0 +1,90 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Controls 2 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$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Templates 2.3 as T
import QtQuick.Controls 2.3
import QtQuick.Controls.impl 2.3
import QtQuick.Controls.Material 2.3
import QtQuick.Controls.Material.impl 2.3
T.MenuBarItem {
id: control
implicitWidth: Math.max(background ? background.implicitWidth : 0,
contentItem.implicitWidth + leftPadding + rightPadding)
implicitHeight: Math.max(background ? background.implicitHeight : 0,
contentItem.implicitHeight + topPadding + bottomPadding)
baselineOffset: contentItem.y + contentItem.baselineOffset
padding: 16
topPadding: 12
bottomPadding: 12
spacing: 16
icon.width: 24
icon.height: 24
icon.color: enabled ? Material.foreground : Material.hintTextColor
contentItem: IconLabel {
spacing: control.spacing
mirrored: control.mirrored
display: control.display
alignment: Qt.AlignLeft
icon: control.icon
text: control.text
font: control.font
color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
}
background: Rectangle {
implicitWidth: 40
implicitHeight: 40
color: control.highlighted ? control.Material.listHighlightColor : "transparent"
Ripple {
width: parent.width
height: parent.height
clip: visible
pressed: control.pressed
anchor: control
active: control.down || control.highlighted
color: control.Material.rippleColor
}
}
}

View File

@ -33,6 +33,8 @@ QML_FILES += \
$$PWD/ItemDelegate.qml \
$$PWD/Label.qml \
$$PWD/Menu.qml \
$$PWD/MenuBar.qml \
$$PWD/MenuBarItem.qml \
$$PWD/MenuItem.qml \
$$PWD/MenuSeparator.qml \
$$PWD/Page.qml \

View File

@ -103,6 +103,7 @@ const QFont *QQuickMaterialTheme::font(QPlatformTheme::Font type) const
return &itemViewFont;
case QPlatformTheme::ListViewFont:
return &listViewFont;
case QPlatformTheme::MenuBarFont:
case QPlatformTheme::MenuItemFont:
case QPlatformTheme::ComboMenuItemFont:
return &menuItemFont;

View File

@ -158,6 +158,8 @@ void QtQuickControls2Plugin::registerTypes(const char *uri)
// QtQuick.Controls 2.3 (new types in Qt 5.10)
qmlRegisterType(selector.select(QStringLiteral("Action.qml")), uri, 2, 3, "Action");
qmlRegisterType(selector.select(QStringLiteral("ActionGroup.qml")), uri, 2, 3, "ActionGroup");
qmlRegisterType(selector.select(QStringLiteral("MenuBar.qml")), uri, 2, 3, "MenuBar");
qmlRegisterType(selector.select(QStringLiteral("MenuBarItem.qml")), uri, 2, 3, "MenuBarItem");
qmlRegisterUncreatableType<QQuickOverlay>(uri, 2, 3, "Overlay", QStringLiteral("Overlay is only available as an attached property."));
}

View File

@ -0,0 +1,64 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Controls 2 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$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Templates 2.3 as T
import QtQuick.Controls 2.3
import QtQuick.Controls.impl 2.3
import QtQuick.Controls.Universal 2.3
T.MenuBar {
id: control
implicitWidth: Math.max(background ? background.implicitWidth : 0,
contentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(background ? background.implicitHeight : 0,
contentHeight + topPadding + bottomPadding)
delegate: MenuBarItem { }
contentItem: Row {
spacing: control.spacing
Repeater {
model: control.contentModel
}
}
background: Rectangle {
implicitHeight: 40
color: control.Universal.chromeMediumColor
}
}

View File

@ -0,0 +1,92 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Controls 2 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$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Templates 2.3 as T
import QtQuick.Controls 2.3
import QtQuick.Controls.impl 2.3
import QtQuick.Controls.Universal 2.3
T.MenuBarItem {
id: control
implicitWidth: Math.max(background ? background.implicitWidth : 0,
contentItem.implicitWidth + leftPadding + rightPadding)
implicitHeight: Math.max(background ? background.implicitHeight : 0,
Math.max(contentItem.implicitHeight,
indicator ? indicator.implicitHeight : 0) + topPadding + bottomPadding)
baselineOffset: contentItem.y + contentItem.baselineOffset
padding: 12
topPadding: padding - 1
bottomPadding: padding + 1
spacing: 12
icon.width: 20
icon.height: 20
icon.color: !enabled ? Universal.baseLowColor : Universal.baseHighColor
contentItem: IconLabel {
spacing: control.spacing
mirrored: control.mirrored
display: control.display
alignment: Qt.AlignLeft
icon: control.icon
text: control.text
font: control.font
color: !control.enabled ? control.Universal.baseLowColor : control.Universal.baseHighColor
}
background: Rectangle {
implicitWidth: 40
implicitHeight: 40
color: !control.enabled ? control.Universal.baseLowColor :
control.down ? control.Universal.listMediumColor :
control.highlighted ? control.Universal.listLowColor : "transparent"
Rectangle {
x: 1; y: 1
width: parent.width - 2
height: parent.height - 2
visible: control.visualFocus
color: control.Universal.accent
opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6
}
}
}

View File

@ -16,6 +16,8 @@ QML_FILES += \
$$PWD/ItemDelegate.qml \
$$PWD/Label.qml \
$$PWD/Menu.qml \
$$PWD/MenuBar.qml \
$$PWD/MenuBarItem.qml \
$$PWD/MenuItem.qml \
$$PWD/MenuSeparator.qml \
$$PWD/Page.qml \

View File

@ -60,6 +60,8 @@
#include <QtQuickTemplates2/private/qquickitemdelegate_p.h>
#include <QtQuickTemplates2/private/qquicklabel_p.h>
#include <QtQuickTemplates2/private/qquickmenu_p.h>
#include <QtQuickTemplates2/private/qquickmenubar_p.h>
#include <QtQuickTemplates2/private/qquickmenubaritem_p.h>
#include <QtQuickTemplates2/private/qquickmenuitem_p.h>
#include <QtQuickTemplates2/private/qquickmenuseparator_p.h>
#include <QtQuickTemplates2/private/qquickoverlay_p.h>
@ -300,6 +302,8 @@ void QtQuickTemplates2Plugin::registerTypes(const char *uri)
qmlRegisterType<QQuickDialogButtonBox>(uri, 2, 3, "DialogButtonBox");
qRegisterMetaType<QQuickIcon>();
qmlRegisterType<QQuickMenu, 3>(uri, 2, 3, "Menu");
qmlRegisterType<QQuickMenuBar>(uri, 2, 3, "MenuBar");
qmlRegisterType<QQuickMenuBarItem>(uri, 2, 3, "MenuBarItem");
qmlRegisterType<QQuickMenuItem, 3>(uri, 2, 3, "MenuItem");
qmlRegisterUncreatableType<QQuickOverlay>(uri, 2, 3, "Overlay", QStringLiteral("Overlay is only available as an attached property."));
qmlRegisterType<QQuickOverlayAttached>();

View File

@ -37,6 +37,8 @@
#include "qquickmenu_p.h"
#include "qquickmenu_p_p.h"
#include "qquickmenuitem_p_p.h"
#include "qquickmenubaritem_p.h"
#include "qquickmenubar_p.h"
#include "qquickpopupitem_p_p.h"
#include "qquickaction_p.h"
@ -522,6 +524,19 @@ void QQuickMenuPrivate::resolveParentItem()
q->setParentItem(findParentMenuItem(q));
}
void QQuickMenuPrivate::propagateKeyEvent(QKeyEvent *event)
{
if (QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(parentItem)) {
if (QQuickMenu *menu = menuItem->menu())
QQuickMenuPrivate::get(menu)->propagateKeyEvent(event);
} else if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(parentItem)) {
if (QQuickMenuBar *menuBar = menuBarItem->menuBar()) {
event->accept();
QCoreApplication::sendEvent(menuBar, event);
}
}
}
void QQuickMenuPrivate::startHoverTimer()
{
Q_Q(QQuickMenu);
@ -567,7 +582,7 @@ void QQuickMenuPrivate::setCurrentIndex(int index, Qt::FocusReason reason)
emit q->currentIndexChanged();
}
void QQuickMenuPrivate::activateNextItem()
bool QQuickMenuPrivate::activateNextItem()
{
int index = currentIndex;
int count = contentModel->count();
@ -576,11 +591,12 @@ void QQuickMenuPrivate::activateNextItem()
if (!item || !item->activeFocusOnTab())
continue;
setCurrentIndex(index, Qt::TabFocusReason);
break;
return true;
}
return false;
}
void QQuickMenuPrivate::activatePreviousItem()
bool QQuickMenuPrivate::activatePreviousItem()
{
int index = currentIndex;
while (--index >= 0) {
@ -588,8 +604,9 @@ void QQuickMenuPrivate::activatePreviousItem()
if (!item || !item->activeFocusOnTab())
continue;
setCurrentIndex(index, Qt::BacktabFocusReason);
break;
return true;
}
return false;
}
void QQuickMenuPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
@ -1358,8 +1375,6 @@ void QQuickMenu::keyPressEvent(QKeyEvent *event)
{
Q_D(QQuickMenu);
QQuickPopup::keyPressEvent(event);
if (d->contentModel->count() == 0)
return;
// QTBUG-17051
// Work around the fact that ListView has no way of distinguishing between
@ -1369,7 +1384,8 @@ void QQuickMenu::keyPressEvent(QKeyEvent *event)
// shown at once.
switch (event->key()) {
case Qt::Key_Up:
d->activatePreviousItem();
if (!d->activatePreviousItem())
d->propagateKeyEvent(event);
break;
case Qt::Key_Down:
@ -1378,17 +1394,23 @@ void QQuickMenu::keyPressEvent(QKeyEvent *event)
case Qt::Key_Left:
case Qt::Key_Right:
event->ignore();
if (d->popupItem->isMirrored() == (event->key() == Qt::Key_Right)) {
if (d->parentMenu && d->currentItem) {
if (!d->cascade)
d->parentMenu->open();
close();
event->accept();
}
} else {
if (QQuickMenu *subMenu = d->currentSubMenu())
if (QQuickMenu *subMenu = d->currentSubMenu()) {
subMenu->popup(subMenu->itemAt(0));
event->accept();
}
}
return;
if (!event->isAccepted())
d->propagateKeyEvent(event);
break;
default:
break;

View File

@ -106,12 +106,14 @@ public:
void setParentMenu(QQuickMenu *parent);
void resolveParentItem();
void propagateKeyEvent(QKeyEvent *event);
void startHoverTimer();
void stopHoverTimer();
void setCurrentIndex(int index, Qt::FocusReason reason);
void activateNextItem();
void activatePreviousItem();
bool activateNextItem();
bool activatePreviousItem();
static void contentData_append(QQmlListProperty<QObject> *prop, QObject *obj);
static int contentData_count(QQmlListProperty<QObject> *prop);

View File

@ -0,0 +1,656 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Templates 2 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 "qquickmenubar_p.h"
#include "qquickmenubar_p_p.h"
#include "qquickmenubaritem_p_p.h"
#include "qquickmenu_p.h"
#include "qquickmenu_p_p.h"
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlengine.h>
QT_BEGIN_NAMESPACE
/*!
\qmltype MenuBar
\inherits Container
\instantiates QQuickMenuBar
\inqmlmodule QtQuick.Controls
\since 5.10
\ingroup qtquickcontrols2-menus
\brief Provides a window menu bar.
\image qtquickcontrols2-menubar.png
MenuBar consists of drop-down menus, and is normally located at the top
edge of the window.
\quotefromfile qtquickcontrols2-menubar.qml
\skipuntil begin
\printto skipfrom
\skipuntil skipto
\printto end
Typically, menus are statically declared as children of the menu bar, but
MenuBar also provides API to \l {addMenu}{add}, \l {insertMenu}{insert},
\l {removeMenu}{remove}, and \l {takeMenu}{take} menus dynamically. The
menus in a menu bar can be accessed using \l menuAt().
\sa {Customizing MenuBar}, Menu, MenuBarItem, {Menu Controls}
*/
QQuickMenuBarPrivate::QQuickMenuBarPrivate()
: popupMode(false),
triggering(false),
hasContentWidth(false),
hasContentHeight(false),
contentWidth(0),
contentHeight(0),
delegate(nullptr)
{
changeTypes |= Geometry;
}
QQuickItem *QQuickMenuBarPrivate::beginCreateItem()
{
Q_Q(QQuickMenuBar);
if (!delegate)
return nullptr;
QQmlContext *creationContext = delegate->creationContext();
if (!creationContext)
creationContext = qmlContext(q);
QQmlContext *context = new QQmlContext(creationContext, q);
context->setContextObject(q);
QObject *object = delegate->beginCreate(context);
QQuickItem *item = qobject_cast<QQuickItem *>(object);
if (!item)
delete object;
item->setParentItem(q);
QQml_setParent_noEvent(item, q);
return item;
}
void QQuickMenuBarPrivate::completeCreateItem()
{
if (!delegate)
return;
delegate->completeCreate();
}
QQuickItem *QQuickMenuBarPrivate::createItem(QQuickMenu *menu)
{
QQuickItem *item = beginCreateItem();
if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item))
menuBarItem->setMenu(menu);
completeCreateItem();
return item;
}
void QQuickMenuBarPrivate::toggleCurrentMenu(bool visible, bool activate)
{
if (!currentItem || visible == popupMode)
return;
QQuickMenu *menu = currentItem->menu();
triggering = true;
popupMode = visible;
if (menu)
menu->setVisible(visible);
if (!visible)
currentItem->forceActiveFocus();
else if (menu && activate)
menu->setCurrentIndex(0);
triggering = false;
}
void QQuickMenuBarPrivate::activateItem(QQuickMenuBarItem *item)
{
if (currentItem == item)
return;
if (currentItem) {
currentItem->setHighlighted(false);
if (popupMode) {
if (QQuickMenu *menu = currentItem->menu())
menu->dismiss();
}
}
if (item) {
item->setHighlighted(true);
if (popupMode) {
if (QQuickMenu *menu = item->menu())
menu->open();
}
}
currentItem = item;
}
void QQuickMenuBarPrivate::activateNextItem()
{
int index = currentItem ? contentModel->indexOf(currentItem, nullptr) : -1;
if (index >= contentModel->count() - 1)
index = -1;
activateItem(qobject_cast<QQuickMenuBarItem *>(itemAt(++index)));
}
void QQuickMenuBarPrivate::activatePreviousItem()
{
int index = currentItem ? contentModel->indexOf(currentItem, nullptr) : contentModel->count();
if (index <= 0)
index = contentModel->count();
activateItem(qobject_cast<QQuickMenuBarItem *>(itemAt(--index)));
}
void QQuickMenuBarPrivate::onItemHovered()
{
Q_Q(QQuickMenuBar);
QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(q->sender());
if (!item || item == currentItem || !item->isHovered() || QQuickMenuBarItemPrivate::get(item)->touchId != -1)
return;
activateItem(item);
}
void QQuickMenuBarPrivate::onItemTriggered()
{
Q_Q(QQuickMenuBar);
QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(q->sender());
if (!item)
return;
if (item == currentItem) {
toggleCurrentMenu(!popupMode, false);
} else {
popupMode = true;
activateItem(item);
}
}
void QQuickMenuBarPrivate::onMenuAboutToHide()
{
if (triggering || !currentItem || currentItem->isHovered() || !currentItem->isHighlighted())
return;
popupMode = false;
activateItem(nullptr);
}
void QQuickMenuBarPrivate::updateContentSize()
{
Q_Q(QQuickMenuBar);
if (hasContentWidth && hasContentHeight)
return;
const int count = contentModel->count();
if (count <= 0 || !contentItem)
return;
qreal maxHeight = 0;
qreal totalWidth = qMax(0, count - 1) * spacing;
for (int i = 0; i < count; ++i) {
QQuickItem *item = q->itemAt(i);
if (item) {
totalWidth += item->width();
maxHeight = qMax(maxHeight, item->implicitHeight());
}
}
bool contentWidthChange = false;
if (!hasContentWidth && !qFuzzyCompare(contentWidth, totalWidth)) {
contentWidth = totalWidth;
contentWidthChange = true;
}
bool contentHeightChange = false;
if (!hasContentHeight && !qFuzzyCompare(contentHeight, maxHeight)) {
contentHeight = maxHeight;
contentHeightChange = true;
}
if (contentWidthChange)
emit q->contentWidthChanged();
if (contentHeightChange)
emit q->contentHeightChanged();
}
void QQuickMenuBarPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &)
{
if ((change.widthChange() && !hasContentWidth) || (change.heightChange() && !hasContentHeight))
updateContentSize();
}
void QQuickMenuBarPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
{
QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(obj))
obj = QQuickMenuBarPrivate::get(menuBar)->createItem(menu);
QQuickContainerPrivate::contentData_append(prop, obj);
}
void QQuickMenuBarPrivate::menus_append(QQmlListProperty<QQuickMenu> *prop, QQuickMenu *obj)
{
QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
menuBar->addMenu(obj);
}
int QQuickMenuBarPrivate::menus_count(QQmlListProperty<QQuickMenu> *prop)
{
QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
return menuBar->count();
}
QQuickMenu *QQuickMenuBarPrivate::menus_at(QQmlListProperty<QQuickMenu> *prop, int index)
{
QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
return menuBar->menuAt(index);
}
void QQuickMenuBarPrivate::menus_clear(QQmlListProperty<QQuickMenu> *prop)
{
QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
QQuickMenuBarPrivate::get(menuBar)->contentModel->clear();
}
QQuickMenuBar::QQuickMenuBar(QQuickItem *parent)
: QQuickContainer(*(new QQuickMenuBarPrivate), parent)
{
setFlag(ItemIsFocusScope);
setFocusPolicy(Qt::ClickFocus);
}
/*!
\qmlproperty Component QtQuick.Controls::MenuBar::delegate
This property holds the component that is used to create menu bar
items to present menus in the menu bar.
\sa MenuBarItem
*/
QQmlComponent *QQuickMenuBar::delegate() const
{
Q_D(const QQuickMenuBar);
return d->delegate;
}
void QQuickMenuBar::setDelegate(QQmlComponent *delegate)
{
Q_D(QQuickMenuBar);
if (d->delegate == delegate)
return;
d->delegate = delegate;
emit delegateChanged();
}
/*!
\qmlmethod Menu QtQuick.Controls::MenuBar::menuAt(int index)
Returns the menu at \a index, or \c null if it does not exist.
*/
QQuickMenu *QQuickMenuBar::menuAt(int index) const
{
Q_D(const QQuickMenuBar);
QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(d->itemAt(index));
if (!item)
return nullptr;
return item->menu();
}
/*!
\qmlmethod void QtQuick.Controls::MenuBar::addMenu(Menu menu)
Adds \a menu to the end of the list of menus.
*/
void QQuickMenuBar::addMenu(QQuickMenu *menu)
{
Q_D(QQuickMenuBar);
addItem(d->createItem(menu));
}
/*!
\qmlmethod void QtQuick.Controls::MenuBar::insertMenu(int index, Menu menu)
Inserts \a menu at \a index.
*/
void QQuickMenuBar::insertMenu(int index, QQuickMenu *menu)
{
Q_D(QQuickMenuBar);
insertItem(index, d->createItem(menu));
}
/*!
\qmlmethod void QtQuick.Controls::MenuBar::removeMenu(Menu menu)
Removes and destroys the specified \a menu.
*/
void QQuickMenuBar::removeMenu(QQuickMenu *menu)
{
Q_D(QQuickMenuBar);
if (!menu)
return;
const int count = d->contentModel->count();
for (int i = 0; i < count; ++i) {
QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(itemAt(i));
if (!item || item->menu() != menu)
continue;
removeItem(item);
break;
}
menu->deleteLater();
}
/*!
\qmlmethod Menu QtQuick.Controls::MenuBar::takeMenu(int index)
Removes and returns the menu at \a index.
\note The ownership of the item is transferred to the caller.
*/
QQuickMenu *QQuickMenuBar::takeMenu(int index)
{
Q_D(QQuickMenuBar);
QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(itemAt(index));
if (!item)
return nullptr;
QQuickMenu *menu = item->menu();
if (!menu)
return nullptr;
d->removeItem(index, item);
item->deleteLater();
return menu;
}
/*!
\qmlproperty real QtQuick.Controls::MenuBar::contentWidth
This property holds the content width. It is used for calculating the total
implicit width of the menu bar.
Unless explicitly overridden, the content width is automatically calculated
based on the total implicit width of the items and the \l {Control::}{spacing}
of the menu bar.
\sa contentHeight
*/
qreal QQuickMenuBar::contentWidth() const
{
Q_D(const QQuickMenuBar);
return d->contentWidth;
}
void QQuickMenuBar::setContentWidth(qreal width)
{
Q_D(QQuickMenuBar);
d->hasContentWidth = true;
if (qFuzzyCompare(d->contentWidth, width))
return;
d->contentWidth = width;
emit contentWidthChanged();
}
void QQuickMenuBar::resetContentWidth()
{
Q_D(QQuickMenuBar);
if (!d->hasContentWidth)
return;
d->hasContentWidth = false;
if (isComponentComplete())
d->updateContentSize();
}
/*!
\qmlproperty real QtQuick.Controls::MenuBar::contentHeight
This property holds the content height. It is used for calculating the total
implicit height of the menu bar.
Unless explicitly overridden, the content height is automatically calculated
based on the maximum implicit height of the items.
\sa contentWidth
*/
qreal QQuickMenuBar::contentHeight() const
{
Q_D(const QQuickMenuBar);
return d->contentHeight;
}
void QQuickMenuBar::setContentHeight(qreal height)
{
Q_D(QQuickMenuBar);
d->hasContentHeight = true;
if (qFuzzyCompare(d->contentHeight, height))
return;
d->contentHeight = height;
emit contentHeightChanged();
}
void QQuickMenuBar::resetContentHeight()
{
Q_D(QQuickMenuBar);
if (!d->hasContentHeight)
return;
d->hasContentHeight = false;
if (isComponentComplete())
d->updateContentSize();
}
/*!
\qmlproperty list<Menu> QtQuick.Controls::MenuBar::menus
This property holds the list of menus.
The list contains all menus that have been declared in QML as children
of the menu bar, and also menus that have been dynamically added or
inserted using the \l addMenu() and \l insertMenu() methods, respectively.
*/
QQmlListProperty<QQuickMenu> QQuickMenuBar::menus()
{
return QQmlListProperty<QQuickMenu>(this, nullptr,
QQuickMenuBarPrivate::menus_append,
QQuickMenuBarPrivate::menus_count,
QQuickMenuBarPrivate::menus_at,
QQuickMenuBarPrivate::menus_clear);
}
QQmlListProperty<QObject> QQuickMenuBar::contentData()
{
return QQmlListProperty<QObject>(this, nullptr,
QQuickMenuBarPrivate::contentData_append,
QQuickContainerPrivate::contentData_count,
QQuickContainerPrivate::contentData_at,
QQuickContainerPrivate::contentData_clear);
}
void QQuickMenuBar::updatePolish()
{
Q_D(QQuickMenuBar);
QQuickContainer::updatePolish();
d->updateContentSize();
}
void QQuickMenuBar::componentComplete()
{
Q_D(QQuickMenuBar);
QQuickContainer::componentComplete();
d->updateContentSize();
}
bool QQuickMenuBar::eventFilter(QObject *object, QEvent *event)
{
return QObject::eventFilter(object, event);
}
void QQuickMenuBar::keyPressEvent(QKeyEvent *event)
{
Q_D(QQuickMenuBar);
QQuickContainer::keyReleaseEvent(event);
switch (event->key()) {
case Qt::Key_Up:
d->toggleCurrentMenu(false, false);
break;
case Qt::Key_Down:
d->toggleCurrentMenu(true, true);
break;
case Qt::Key_Left:
case Qt::Key_Right:
if (isMirrored() == (event->key() == Qt::Key_Left))
d->activateNextItem();
else
d->activatePreviousItem();
break;
case Qt::Key_Escape:
if (d->currentItem) {
d->activateItem(nullptr);
setFocus(false);
}
break;
default:
break;
}
}
void QQuickMenuBar::keyReleaseEvent(QKeyEvent *event)
{
QQuickContainer::keyReleaseEvent(event);
switch (event->key()) {
case Qt::Key_Up:
case Qt::Key_Down:
case Qt::Key_Left:
case Qt::Key_Right:
case Qt::Key_Escape:
event->accept();
break;
default:
event->ignore();
break;
}
}
void QQuickMenuBar::hoverLeaveEvent(QHoverEvent *event)
{
Q_D(QQuickMenuBar);
QQuickContainer::hoverLeaveEvent(event);
if (!d->popupMode && d->currentItem)
d->activateItem(nullptr);
}
bool QQuickMenuBar::isContent(QQuickItem *item) const
{
return qobject_cast<QQuickMenuBarItem *>(item);
}
void QQuickMenuBar::itemAdded(int index, QQuickItem *item)
{
Q_D(QQuickMenuBar);
QQuickContainer::itemAdded(index, item);
if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item)) {
QQuickMenuBarItemPrivate::get(menuBarItem)->setMenuBar(this);
QObjectPrivate::connect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered);
QObjectPrivate::connect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered);
if (QQuickMenu *menu = menuBarItem->menu())
QObjectPrivate::connect(menu, &QQuickPopup::aboutToHide, d, &QQuickMenuBarPrivate::onMenuAboutToHide);
}
if (isComponentComplete())
polish();
if (isComponentComplete())
polish();
emit menusChanged();
}
void QQuickMenuBar::itemMoved(int index, QQuickItem *item)
{
QQuickContainer::itemMoved(index, item);
emit menusChanged();
}
void QQuickMenuBar::itemRemoved(int index, QQuickItem *item)
{
Q_D(QQuickMenuBar);
QQuickContainer::itemRemoved(index, item);
if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item)) {
QQuickMenuBarItemPrivate::get(menuBarItem)->setMenuBar(nullptr);
QObjectPrivate::disconnect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered);
QObjectPrivate::disconnect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered);
if (QQuickMenu *menu = menuBarItem->menu())
QObjectPrivate::disconnect(menu, &QQuickPopup::aboutToHide, d, &QQuickMenuBarPrivate::onMenuAboutToHide);
}
emit menusChanged();
}
QFont QQuickMenuBar::defaultFont() const
{
return QQuickControlPrivate::themeFont(QPlatformTheme::MenuBarFont);
}
QPalette QQuickMenuBar::defaultPalette() const
{
return QQuickControlPrivate::themePalette(QPlatformTheme::MenuBarPalette);
}
#if QT_CONFIG(accessibility)
QAccessible::Role QQuickMenuBar::accessibleRole() const
{
return QAccessible::MenuBar;
}
#endif
QT_END_NAMESPACE

View File

@ -0,0 +1,126 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Templates 2 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 QQUICKMENUBAR_P_H
#define QQUICKMENUBAR_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 <QtQuickTemplates2/private/qquickcontainer_p.h>
QT_BEGIN_NAMESPACE
class QQuickMenu;
class QQuickMenuBarPrivate;
class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuBar : public QQuickContainer
{
Q_OBJECT
Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL)
Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth RESET resetContentWidth NOTIFY contentWidthChanged FINAL)
Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight RESET resetContentHeight NOTIFY contentHeightChanged FINAL)
Q_PROPERTY(QQmlListProperty<QQuickMenu> menus READ menus NOTIFY menusChanged FINAL)
Q_PROPERTY(QQmlListProperty<QObject> contentData READ contentData FINAL)
public:
explicit QQuickMenuBar(QQuickItem *parent = nullptr);
QQmlComponent *delegate() const;
void setDelegate(QQmlComponent *delegate);
Q_INVOKABLE QQuickMenu *menuAt(int index) const;
Q_INVOKABLE void addMenu(QQuickMenu *menu);
Q_INVOKABLE void insertMenu(int index, QQuickMenu *menu);
Q_INVOKABLE void removeMenu(QQuickMenu *menu);
Q_INVOKABLE QQuickMenu *takeMenu(int index);
qreal contentWidth() const;
void setContentWidth(qreal width);
void resetContentWidth();
qreal contentHeight() const;
void setContentHeight(qreal height);
void resetContentHeight();
QQmlListProperty<QQuickMenu> menus();
QQmlListProperty<QObject> contentData();
Q_SIGNALS:
void delegateChanged();
void contentWidthChanged();
void contentHeightChanged();
void menusChanged();
protected:
void updatePolish() override;
void componentComplete() override;
bool eventFilter(QObject *object, QEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event) override;
void hoverLeaveEvent(QHoverEvent *event) override;
bool isContent(QQuickItem *item) const override;
void itemAdded(int index, QQuickItem *item) override;
void itemMoved(int index, QQuickItem *item) override;
void itemRemoved(int index, QQuickItem *item) override;
QFont defaultFont() const override;
QPalette defaultPalette() const override;
#if QT_CONFIG(accessibility)
QAccessible::Role accessibleRole() const override;
#endif
private:
Q_DISABLE_COPY(QQuickMenuBar)
Q_DECLARE_PRIVATE(QQuickMenuBar)
};
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickMenuBar)
#endif // QQUICKMENUBAR_P_H

View File

@ -0,0 +1,107 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Templates 2 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 QQUICKMENUBAR_P_P_H
#define QQUICKMENUBAR_P_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 <QtQuickTemplates2/private/qquickmenubar_p.h>
#include <QtQuickTemplates2/private/qquickcontainer_p_p.h>
QT_BEGIN_NAMESPACE
class QQmlComponent;
class QQuickMenuBarItem;
class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuBarPrivate : public QQuickContainerPrivate
{
Q_DECLARE_PUBLIC(QQuickMenuBar)
public:
QQuickMenuBarPrivate();
static QQuickMenuBarPrivate *get(QQuickMenuBar *menuBar)
{
return menuBar->d_func();
}
QQuickItem *beginCreateItem();
void completeCreateItem();
QQuickItem *createItem(QQuickMenu *menu);
void toggleCurrentMenu(bool visible, bool activate);
void activateItem(QQuickMenuBarItem *item);
void activateNextItem();
void activatePreviousItem();
void onItemHovered();
void onItemTriggered();
void onMenuAboutToHide();
void updateContentSize();
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
static void contentData_append(QQmlListProperty<QObject> *prop, QObject *obj);
static void menus_append(QQmlListProperty<QQuickMenu> *prop, QQuickMenu *obj);
static int menus_count(QQmlListProperty<QQuickMenu> *prop);
static QQuickMenu *menus_at(QQmlListProperty<QQuickMenu> *prop, int index);
static void menus_clear(QQmlListProperty<QQuickMenu> *prop);
bool popupMode;
bool triggering;
bool hasContentWidth;
bool hasContentHeight;
qreal contentWidth;
qreal contentHeight;
QQmlComponent *delegate;
QPointer<QQuickMenuBarItem> currentItem;
};
QT_END_NAMESPACE
#endif // QQUICKMENUBAR_P_P_H

View File

@ -0,0 +1,185 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Templates 2 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 "qquickmenubaritem_p.h"
#include "qquickmenubaritem_p_p.h"
#include "qquickmenubar_p.h"
#include "qquickmenu_p.h"
QT_BEGIN_NAMESPACE
/*!
\qmltype MenuBarItem
\inherits AbstractButton
\instantiates QQuickMenuBarItem
\inqmlmodule QtQuick.Controls
\since 5.10
\ingroup qtquickcontrols2-menus
\brief Presents a drop-down menu within a MenuBar.
MenuBarItem presents a Menu within a MenuBar. The respective drop-down menu
is shown when a MenuBarItem is \l triggered via keyboard, mouse, or touch.
\image qtquickcontrols2-menubar.png
MenuBarItem is used as a default \l {MenuBar::}{delegate} type for MenuBar.
Notice that it is not necessary to declare MenuBarItem instances by hand when
using MenuBar. It is sufficient to declare Menu instances as children of the
MenuBar and the respective items are created automatically.
\sa {Customizing MenuBar}, MenuBar, {Menu Controls}
*/
/*!
\qmlsignal void QtQuick.Controls::MenuBarItem::triggered()
This signal is emitted when the menu bar item is triggered by the user.
*/
void QQuickMenuBarItemPrivate::setMenuBar(QQuickMenuBar *newMenuBar)
{
Q_Q(QQuickMenuBarItem);
if (menuBar == newMenuBar)
return;
menuBar = newMenuBar;
emit q->menuBarChanged();
}
QQuickMenuBarItem::QQuickMenuBarItem(QQuickItem *parent)
: QQuickAbstractButton(*(new QQuickMenuBarItemPrivate), parent)
{
setFocusPolicy(Qt::NoFocus);
connect(this, &QQuickAbstractButton::clicked, this, &QQuickMenuBarItem::triggered);
}
/*!
\qmlproperty Menu QtQuick.Controls::MenuBarItem::menuBar
\readonly
This property holds the menu bar that contains this item,
or \c null if the item is not in a menu bar.
*/
QQuickMenuBar *QQuickMenuBarItem::menuBar() const
{
Q_D(const QQuickMenuBarItem);
return d->menuBar;
}
/*!
\qmlproperty Menu QtQuick.Controls::MenuBarItem::menu
This property holds the menu that this item presents in a
menu bar, or \c null if this item does not have a menu.
*/
QQuickMenu *QQuickMenuBarItem::menu() const
{
Q_D(const QQuickMenuBarItem);
return d->menu;
}
void QQuickMenuBarItem::setMenu(QQuickMenu *menu)
{
Q_D(QQuickMenuBarItem);
if (d->menu == menu)
return;
if (d->menu)
disconnect(d->menu, &QQuickMenu::titleChanged, this, &QQuickAbstractButton::setText);
if (menu) {
setText(menu->title());
menu->setY(height());
menu->setParentItem(this);
menu->setClosePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutsideParent | QQuickPopup::CloseOnReleaseOutsideParent);
connect(menu, &QQuickMenu::titleChanged, this, &QQuickAbstractButton::setText);
}
d->menu = menu;
emit menuChanged();
}
/*!
\qmlproperty bool QtQuick.Controls::MenuBarItem::highlighted
This property holds whether the menu bar item is highlighted by the user.
A menu bar item can be highlighted by mouse hover or keyboard navigation.
The default value is \c false.
*/
bool QQuickMenuBarItem::isHighlighted() const
{
Q_D(const QQuickMenuBarItem);
return d->highlighted;
}
void QQuickMenuBarItem::setHighlighted(bool highlighted)
{
Q_D(QQuickMenuBarItem);
if (highlighted == d->highlighted)
return;
d->highlighted = highlighted;
emit highlightedChanged();
}
void QQuickMenuBarItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
Q_D(QQuickMenuBarItem);
QQuickAbstractButton::geometryChanged(newGeometry, oldGeometry);
if (d->menu)
d->menu->setY(newGeometry.height());
}
QFont QQuickMenuBarItem::defaultFont() const
{
return QQuickControlPrivate::themeFont(QPlatformTheme::MenuBarFont);
}
QPalette QQuickMenuBarItem::defaultPalette() const
{
return QQuickControlPrivate::themePalette(QPlatformTheme::MenuBarPalette);
}
#if QT_CONFIG(accessibility)
QAccessible::Role QQuickMenuBarItem::accessibleRole() const
{
return QAccessible::MenuBar;
}
#endif
QT_END_NAMESPACE

View File

@ -0,0 +1,102 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Templates 2 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 QQUICKMENUBARITEM_P_H
#define QQUICKMENUBARITEM_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
QT_BEGIN_NAMESPACE
class QQuickMenu;
class QQuickMenuBar;
class QQuickMenuBarItemPrivate;
class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuBarItem : public QQuickAbstractButton
{
Q_OBJECT
Q_PROPERTY(QQuickMenuBar *menuBar READ menuBar NOTIFY menuBarChanged FINAL)
Q_PROPERTY(QQuickMenu *menu READ menu WRITE setMenu NOTIFY menuChanged FINAL)
Q_PROPERTY(bool highlighted READ isHighlighted WRITE setHighlighted NOTIFY highlightedChanged FINAL)
public:
explicit QQuickMenuBarItem(QQuickItem *parent = nullptr);
QQuickMenuBar *menuBar() const;
QQuickMenu *menu() const;
void setMenu(QQuickMenu *menu);
bool isHighlighted() const;
void setHighlighted(bool highlighted);
Q_SIGNALS:
void triggered();
void menuBarChanged();
void menuChanged();
void highlightedChanged();
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
QFont defaultFont() const override;
QPalette defaultPalette() const override;
#if QT_CONFIG(accessibility)
QAccessible::Role accessibleRole() const override;
#endif
private:
Q_DISABLE_COPY(QQuickMenuBarItem)
Q_DECLARE_PRIVATE(QQuickMenuBarItem)
};
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickMenuBarItem)
#endif // QQUICKMENUBARITEM_P_H

View File

@ -0,0 +1,85 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Templates 2 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 QQUICKMENUBARITEM_P_P_H
#define QQUICKMENUBARITEM_P_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 <QtQuickTemplates2/private/qquickmenubaritem_p.h>
#include <QtQuickTemplates2/private/qquickabstractbutton_p_p.h>
QT_BEGIN_NAMESPACE
class QQuickMenu;
class QQuickMenuBar;
class QQuickMenuBarItemPrivate : public QQuickAbstractButtonPrivate
{
Q_DECLARE_PUBLIC(QQuickMenuBarItem)
public:
QQuickMenuBarItemPrivate()
: highlighted(false),
menu(nullptr),
menuBar(nullptr)
{
}
static QQuickMenuBarItemPrivate *get(QQuickMenuBarItem *item)
{
return item->d_func();
}
void setMenuBar(QQuickMenuBar *menuBar);
bool highlighted;
QQuickMenu *menu;
QQuickMenuBar *menuBar;
};
QT_END_NAMESPACE
#endif // QQUICKMENUBARITEM_P_P_H

View File

@ -38,6 +38,8 @@
#include "qquickoverlay_p_p.h"
#include "qquicktooltip_p.h"
#include "qquickpopup_p.h"
#include "qquickmenu_p.h"
#include "qquickmenubaritem_p.h"
#include <QtGui/qguiapplication.h>
@ -53,8 +55,13 @@ static bool isBlockedByPopup(QQuickItem *item)
for (QQuickPopup *popup : popups) {
if (qobject_cast<QQuickToolTip *>(popup))
continue; // ignore tooltips (QTBUG-60492)
if (popup->isModal() || popup->closePolicy() & QQuickPopup::CloseOnEscape)
if (popup->isModal() || popup->closePolicy() & QQuickPopup::CloseOnEscape) {
if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(popup)) {
if (qobject_cast<QQuickMenuBarItem *>(menu->parentItem()))
continue;
}
return item != popup->popupItem() && !popup->popupItem()->isAncestorOf(item);
}
}
return false;

View File

@ -35,6 +35,10 @@ HEADERS += \
$$PWD/qquicklabel_p_p.h \
$$PWD/qquickmenu_p.h \
$$PWD/qquickmenu_p_p.h \
$$PWD/qquickmenubar_p.h \
$$PWD/qquickmenubar_p_p.h \
$$PWD/qquickmenubaritem_p.h \
$$PWD/qquickmenubaritem_p_p.h \
$$PWD/qquickmenuitem_p.h \
$$PWD/qquickmenuitem_p_p.h \
$$PWD/qquickmenuseparator_p.h \
@ -109,6 +113,8 @@ SOURCES += \
$$PWD/qquickitemdelegate.cpp \
$$PWD/qquicklabel.cpp \
$$PWD/qquickmenu.cpp \
$$PWD/qquickmenubar.cpp \
$$PWD/qquickmenubaritem.cpp \
$$PWD/qquickmenuitem.cpp \
$$PWD/qquickmenuseparator.cpp \
$$PWD/qquickoverlay.cpp \

View File

@ -18,6 +18,7 @@ SUBDIRS += \
qquickiconlabel \
qquickmaterialstyle \
qquickmaterialstyleconf \
qquickmenubar \
qquickstyle \
qquickstyleselector \
qquickuniversalstyle \
@ -31,4 +32,4 @@ boot2qt: SUBDIRS -= applicationwindow calendar controls cursor \
drawer focus font menu platform palette popup \
qquickmaterialstyle qquickmaterialstyleconf \
qquickuniversalstyle qquickuniversalstyleconf \
snippets
snippets qquickmenubar

View File

@ -0,0 +1,54 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Controls 2.3
MenuBar { }

View File

@ -0,0 +1,106 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.9
import QtQuick.Controls 2.3
ApplicationWindow {
width: 400
height: 400
visible: true
header: MenuBar {
MenuBarItem {
menu: Menu {
title: "&File"
MenuItem { text: "&Open..." }
MenuItem { text: "&Save" }
MenuItem { text: "Save &As..." }
MenuSeparator { }
MenuItem { text: "&Quit" }
}
}
MenuBarItem {
menu: Menu {
title: "&Edit"
MenuItem { text: "&Cut" }
MenuItem { text: "&Copy" }
MenuItem { text: "&Paste" }
}
}
MenuBarItem {
menu: Menu {
title: "&View"
Menu {
title: "&Alignment"
Menu {
title: "&Horizontal"
MenuItem { text: "&Left" }
MenuItem { text: "&Center" }
MenuItem { text: "&Right" }
}
Menu {
title: "&Vertical"
MenuItem { text: "&Top" }
MenuItem { text: "&Center" }
MenuItem { text: "&Bottom" }
}
}
}
}
MenuBarItem {
menu: Menu {
title: "&Help"
MenuItem { text: "&About" }
}
}
}
}

View File

@ -0,0 +1,14 @@
CONFIG += testcase
TARGET = tst_qquickmenubar
SOURCES += tst_qquickmenubar.cpp
macos:CONFIG -= app_bundle
QT += core-private gui-private qml-private quick-private testlib quicktemplates2-private
include (../shared/util.pri)
TESTDATA = data/*
OTHER_FILES += \
data/*.qml

View File

@ -0,0 +1,562 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the test suite 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 <QtTest>
#include <QtQml>
#include "../shared/util.h"
#include "../shared/visualtestutil.h"
#include "../shared/qtest_quickcontrols.h"
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
#include <QtQuickTemplates2/private/qquickmenu_p.h>
#include <QtQuickTemplates2/private/qquickmenubar_p.h>
#include <QtQuickTemplates2/private/qquickmenubaritem_p.h>
#include <QtQuickTemplates2/private/qquickmenuitem_p.h>
using namespace QQuickVisualTestUtil;
class tst_qquickmenubar : public QQmlDataTest
{
Q_OBJECT
public:
private slots:
void delegate();
void mouse();
void keys();
void mnemonics();
void addRemove();
};
void tst_qquickmenubar::delegate()
{
QQmlApplicationEngine engine(testFileUrl("empty.qml"));
QScopedPointer<QQuickMenuBar> menuBar(qobject_cast<QQuickMenuBar *>(engine.rootObjects().value(0)));
QVERIFY(menuBar);
QQmlComponent *delegate = menuBar->delegate();
QVERIFY(delegate);
QScopedPointer<QQuickMenuBarItem> item(qobject_cast<QQuickMenuBarItem *>(delegate->create()));
QVERIFY(item);
}
void tst_qquickmenubar::mouse()
{
QQmlApplicationEngine engine(testFileUrl("menubar.qml"));
QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
QVERIFY(window);
QVERIFY(QTest::qWaitForWindowActive(window.data()));
moveMouseAway(window.data());
QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>();
QVERIFY(menuBar);
QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0);
QQuickMenu *editMenuBarMenu = menuBar->menuAt(1);
QQuickMenu *viewMenuBarMenu = menuBar->menuAt(2);
QQuickMenu *helpMenuBarMenu = menuBar->menuAt(3);
QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu);
QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(fileMenuBarMenu->parentItem());
QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(editMenuBarMenu->parentItem());
QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(viewMenuBarMenu->parentItem());
QQuickMenuBarItem *helpMenuBarItem = qobject_cast<QQuickMenuBarItem *>(helpMenuBarMenu->parentItem());
QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem);
// highlight a menubar item
QTest::mouseMove(window.data(), fileMenuBarItem->mapToScene(QPointF(fileMenuBarItem->width() / 2, fileMenuBarItem->height() / 2)).toPoint());
QVERIFY(fileMenuBarItem->isHighlighted());
QVERIFY(!fileMenuBarMenu->isVisible());
// highlight another menubar item
QTest::mouseMove(window.data(), editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint());
QVERIFY(!fileMenuBarItem->isHighlighted());
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(!fileMenuBarMenu->isVisible());
QVERIFY(!editMenuBarMenu->isVisible());
// trigger a menubar item to open a menu
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint());
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(editMenuBarMenu->isVisible());
QTRY_VERIFY(editMenuBarMenu->isOpened());
// re-trigger a menubar item to hide the menu
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint());
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(editMenuBarItem->hasActiveFocus());
QTRY_VERIFY(!editMenuBarMenu->isVisible());
// re-trigger a menubar item to show the menu again
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint());
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(editMenuBarMenu->isVisible());
QTRY_VERIFY(editMenuBarMenu->isOpened());
// highlight another menubar item to open another menu
QTest::mouseMove(window.data(), helpMenuBarItem->mapToScene(QPointF(helpMenuBarItem->width() / 2, helpMenuBarItem->height() / 2)).toPoint());
QVERIFY(!fileMenuBarItem->isHighlighted());
QVERIFY(!editMenuBarItem->isHighlighted());
QVERIFY(!viewMenuBarItem->isHighlighted());
QVERIFY(helpMenuBarItem->isHighlighted());
QVERIFY(!fileMenuBarMenu->isVisible());
QVERIFY(!viewMenuBarMenu->isVisible());
QVERIFY(helpMenuBarMenu->isVisible());
QTRY_VERIFY(!editMenuBarMenu->isVisible());
QTRY_VERIFY(helpMenuBarMenu->isOpened());
// trigger a menu item to close the menu
QQuickMenuItem *aboutMenuItem = qobject_cast<QQuickMenuItem *>(helpMenuBarMenu->itemAt(0));
QVERIFY(aboutMenuItem);
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, aboutMenuItem->mapToScene(QPointF(aboutMenuItem->width() / 2, aboutMenuItem->height() / 2)).toPoint());
QVERIFY(!helpMenuBarItem->isHighlighted());
QTRY_VERIFY(!helpMenuBarMenu->isVisible());
// highlight a menubar item
QTest::mouseMove(window.data(), editMenuBarItem->mapToScene(QPointF(editMenuBarItem->width() / 2, editMenuBarItem->height() / 2)).toPoint());
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(!helpMenuBarItem->isHighlighted());
QVERIFY(!editMenuBarMenu->isVisible());
QVERIFY(!helpMenuBarMenu->isVisible());
// trigger a menubar item to open a menu
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, viewMenuBarItem->mapToScene(QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint());
QVERIFY(!editMenuBarItem->isHighlighted());
QVERIFY(viewMenuBarItem->isHighlighted());
QVERIFY(viewMenuBarMenu->isVisible());
QTRY_VERIFY(viewMenuBarMenu->isOpened());
// trigger a menu item to open a sub-menu
QQuickMenuItem *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(viewMenuBarMenu->itemAt(0));
QVERIFY(alignmentSubMenuItem);
QQuickMenu *alignmentSubMenu = alignmentSubMenuItem->subMenu();
QVERIFY(alignmentSubMenu);
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, alignmentSubMenuItem->mapToScene(QPointF(alignmentSubMenuItem->width() / 2, alignmentSubMenuItem->height() / 2)).toPoint());
QVERIFY(viewMenuBarMenu->isVisible());
QVERIFY(alignmentSubMenu->isVisible());
QTRY_VERIFY(alignmentSubMenu->isOpened());
// trigger a menu item to open a sub-sub-menu
QQuickMenuItem *verticalSubMenuItem = qobject_cast<QQuickMenuItem *>(alignmentSubMenu->itemAt(1));
QVERIFY(verticalSubMenuItem);
QQuickMenu *verticalSubMenu = verticalSubMenuItem->subMenu();
QVERIFY(verticalSubMenu);
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, verticalSubMenuItem->mapToScene(QPointF(verticalSubMenuItem->width() / 2, verticalSubMenuItem->height() / 2)).toPoint());
QVERIFY(viewMenuBarMenu->isVisible());
QVERIFY(alignmentSubMenu->isVisible());
QVERIFY(verticalSubMenu->isVisible());
QTRY_VERIFY(verticalSubMenu->isOpened());
// trigger a menu item to close the whole chain of menus
QQuickMenuItem *centerMenuItem = qobject_cast<QQuickMenuItem *>(verticalSubMenu->itemAt(1));
QVERIFY(centerMenuItem);
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, centerMenuItem->mapToScene(QPointF(centerMenuItem->width() / 2, centerMenuItem->height() / 2)).toPoint());
QVERIFY(!viewMenuBarItem->isHighlighted());
QTRY_VERIFY(!viewMenuBarMenu->isVisible());
QTRY_VERIFY(!alignmentSubMenu->isVisible());
QTRY_VERIFY(!verticalSubMenu->isVisible());
// re-highlight the same menubar item
QTest::mouseMove(window.data(), viewMenuBarItem->mapToScene(QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint());
QVERIFY(viewMenuBarItem->isHighlighted());
// re-open the chain of menus
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, viewMenuBarItem->mapToScene(QPointF(viewMenuBarItem->width() / 2, viewMenuBarItem->height() / 2)).toPoint());
QTRY_VERIFY(viewMenuBarMenu->isOpened());
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, alignmentSubMenuItem->mapToScene(QPointF(alignmentSubMenuItem->width() / 2, alignmentSubMenuItem->height() / 2)).toPoint());
QTRY_VERIFY(alignmentSubMenu->isOpened());
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, verticalSubMenuItem->mapToScene(QPointF(verticalSubMenuItem->width() / 2, verticalSubMenuItem->height() / 2)).toPoint());
QTRY_VERIFY(verticalSubMenu->isOpened());
// click outside to close the whole chain of menus
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - 1, window->height() - 1));
QVERIFY(!viewMenuBarItem->isHighlighted());
QTRY_VERIFY(!viewMenuBarMenu->isVisible());
QTRY_VERIFY(!alignmentSubMenu->isVisible());
QTRY_VERIFY(!verticalSubMenu->isVisible());
}
void tst_qquickmenubar::keys()
{
QQmlApplicationEngine engine(testFileUrl("menubar.qml"));
QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
QVERIFY(window);
QVERIFY(QTest::qWaitForWindowActive(window.data()));
moveMouseAway(window.data());
QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>();
QVERIFY(menuBar);
QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0);
QQuickMenu *editMenuBarMenu = menuBar->menuAt(1);
QQuickMenu *viewMenuBarMenu = menuBar->menuAt(2);
QQuickMenu *helpMenuBarMenu = menuBar->menuAt(3);
QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu);
QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(fileMenuBarMenu->parentItem());
QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(editMenuBarMenu->parentItem());
QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(viewMenuBarMenu->parentItem());
QQuickMenuBarItem *helpMenuBarItem = qobject_cast<QQuickMenuBarItem *>(helpMenuBarMenu->parentItem());
QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem);
// trigger a menubar item to open a menu
editMenuBarItem->forceActiveFocus();
QTest::keyClick(window.data(), Qt::Key_Space);
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(editMenuBarMenu->isVisible());
QTRY_VERIFY(editMenuBarMenu->isOpened());
QVERIFY(editMenuBarMenu->hasActiveFocus());
// navigate down to the menu
QQuickMenuItem *cutMenuItem = qobject_cast<QQuickMenuItem *>(editMenuBarMenu->itemAt(0));
QVERIFY(cutMenuItem);
QVERIFY(!cutMenuItem->isHighlighted());
QVERIFY(!cutMenuItem->hasActiveFocus());
QTest::keyClick(window.data(), Qt::Key_Down);
QVERIFY(cutMenuItem->isHighlighted());
QVERIFY(cutMenuItem->hasActiveFocus());
// navigate up, back to the menubar
QTest::keyClick(window.data(), Qt::Key_Up);
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(editMenuBarItem->hasActiveFocus());
QTRY_VERIFY(!editMenuBarMenu->isVisible());
QVERIFY(!cutMenuItem->isHighlighted());
QVERIFY(!cutMenuItem->hasActiveFocus());
// navigate down to re-open the menu
QTest::keyClick(window.data(), Qt::Key_Down);
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(!editMenuBarItem->hasActiveFocus());
QVERIFY(editMenuBarMenu->isVisible());
QTRY_VERIFY(editMenuBarMenu->isOpened());
QVERIFY(editMenuBarMenu->hasActiveFocus());
QVERIFY(cutMenuItem->isHighlighted());
QVERIFY(cutMenuItem->hasActiveFocus());
// navigate left in popup mode (menu open)
QTest::keyClick(window.data(), Qt::Key_Left);
QVERIFY(fileMenuBarItem->isHighlighted());
QVERIFY(!editMenuBarItem->isHighlighted());
QVERIFY(fileMenuBarMenu->isVisible());
QTRY_VERIFY(fileMenuBarMenu->isOpened());
QTRY_VERIFY(!editMenuBarMenu->isVisible());
// navigate left in popup mode (wrap)
QTest::keyClick(window.data(), Qt::Key_Left);
QVERIFY(helpMenuBarItem->isHighlighted());
QVERIFY(!fileMenuBarItem->isHighlighted());
QVERIFY(helpMenuBarMenu->isVisible());
QTRY_VERIFY(helpMenuBarMenu->isOpened());
QTRY_VERIFY(!fileMenuBarMenu->isVisible());
// navigate up to close the menu
QTest::keyClick(window.data(), Qt::Key_Up);
QVERIFY(helpMenuBarItem->isHighlighted());
QTRY_VERIFY(!helpMenuBarMenu->isVisible());
// navigate right in non-popup mode (wrap)
QTest::keyClick(window.data(), Qt::Key_Right);
QVERIFY(fileMenuBarItem->isHighlighted());
QVERIFY(!helpMenuBarItem->isHighlighted());
QVERIFY(!fileMenuBarMenu->isVisible());
QVERIFY(!helpMenuBarMenu->isVisible());
// navigate right in non-popup mode (menu closed)
QTest::keyClick(window.data(), Qt::Key_Right);
QVERIFY(!fileMenuBarItem->isHighlighted());
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(!fileMenuBarMenu->isVisible());
QVERIFY(!editMenuBarMenu->isVisible());
// open a menu
viewMenuBarItem->forceActiveFocus();
QTest::keyClick(window.data(), Qt::Key_Space);
QVERIFY(viewMenuBarItem->isHighlighted());
QVERIFY(viewMenuBarMenu->isVisible());
QTRY_VERIFY(viewMenuBarMenu->isOpened());
QVERIFY(!viewMenuBarItem->hasActiveFocus());
QVERIFY(viewMenuBarMenu->hasActiveFocus());
// open a sub-menu
QQuickMenuItem *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(viewMenuBarMenu->itemAt(0));
QVERIFY(alignmentSubMenuItem);
QQuickMenu *alignmentSubMenu = alignmentSubMenuItem->subMenu();
QVERIFY(alignmentSubMenu);
QTest::keyClick(window.data(), Qt::Key_Down);
QVERIFY(alignmentSubMenuItem->isHighlighted());
QVERIFY(!alignmentSubMenu->isVisible());
QTest::keyClick(window.data(), Qt::Key_Right);
QVERIFY(alignmentSubMenu->isVisible());
QTRY_VERIFY(alignmentSubMenu->isOpened());
// open a sub-sub-menu
QQuickMenuItem *horizontalSubMenuItem = qobject_cast<QQuickMenuItem *>(alignmentSubMenu->itemAt(0));
QVERIFY(horizontalSubMenuItem);
QVERIFY(horizontalSubMenuItem->isHighlighted());
QQuickMenu *horizontalSubMenu = horizontalSubMenuItem->subMenu();
QVERIFY(horizontalSubMenu);
QTest::keyClick(window.data(), Qt::Key_Right);
QVERIFY(viewMenuBarMenu->isVisible());
QVERIFY(alignmentSubMenu->isVisible());
QVERIFY(horizontalSubMenu->isVisible());
QTRY_VERIFY(horizontalSubMenu->isOpened());
// navigate left to close a sub-menu
QTest::keyClick(window.data(), Qt::Key_Left);
QTRY_VERIFY(!horizontalSubMenu->isVisible());
QVERIFY(viewMenuBarMenu->isVisible());
QVERIFY(alignmentSubMenu->isVisible());
// navigate right to re-open the sub-menu
QTest::keyClick(window.data(), Qt::Key_Right);
QVERIFY(horizontalSubMenuItem->isHighlighted());
QVERIFY(horizontalSubMenu->isVisible());
QTRY_VERIFY(horizontalSubMenu->isOpened());
// navigate right to the next menubar menu
QTest::keyClick(window.data(), Qt::Key_Right);
QVERIFY(!viewMenuBarItem->isHighlighted());
QVERIFY(helpMenuBarItem->isHighlighted());
QVERIFY(helpMenuBarMenu->isVisible());
QTRY_VERIFY(!viewMenuBarMenu->isVisible());
QTRY_VERIFY(!alignmentSubMenu->isVisible());
QTRY_VERIFY(!horizontalSubMenu->isVisible());
QTRY_VERIFY(helpMenuBarMenu->isOpened());
// navigate back
QTest::keyClick(window.data(), Qt::Key_Left);
QVERIFY(!helpMenuBarItem->isHighlighted());
QVERIFY(viewMenuBarItem->isHighlighted());
QVERIFY(viewMenuBarMenu->isVisible());
QTRY_VERIFY(!helpMenuBarMenu->isVisible());
QTRY_VERIFY(viewMenuBarMenu->isOpened());
// re-open the chain of menus
QTest::keyClick(window.data(), Qt::Key_Down);
QVERIFY(alignmentSubMenuItem->isHighlighted());
QTest::keyClick(window.data(), Qt::Key_Right);
QTRY_VERIFY(alignmentSubMenu->isOpened());
QTest::keyClick(window.data(), Qt::Key_Right);
QTRY_VERIFY(horizontalSubMenu->isOpened());
// repeat escape to close the whole chain of menus one by one
QTest::keyClick(window.data(), Qt::Key_Escape);
QTRY_VERIFY(!horizontalSubMenu->isVisible());
QVERIFY(viewMenuBarItem->isHighlighted());
QVERIFY(viewMenuBarMenu->isVisible());
QVERIFY(alignmentSubMenu->isVisible());
QTest::keyClick(window.data(), Qt::Key_Escape);
QTRY_VERIFY(!alignmentSubMenu->isVisible());
QVERIFY(viewMenuBarItem->isHighlighted());
QVERIFY(viewMenuBarMenu->isVisible());
QTest::keyClick(window.data(), Qt::Key_Escape);
QVERIFY(!viewMenuBarItem->isHighlighted());
QTRY_VERIFY(!viewMenuBarMenu->isVisible());
}
void tst_qquickmenubar::mnemonics()
{
#ifdef Q_OS_MACOS
QSKIP("Mnemonics are not used on macOS");
#endif
QQmlApplicationEngine engine(testFileUrl("menubar.qml"));
QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
QVERIFY(window);
QVERIFY(QTest::qWaitForWindowActive(window.data()));
moveMouseAway(window.data());
QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>();
QVERIFY(menuBar);
QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0);
QQuickMenu *editMenuBarMenu = menuBar->menuAt(1);
QQuickMenu *viewMenuBarMenu = menuBar->menuAt(2);
QQuickMenu *helpMenuBarMenu = menuBar->menuAt(3);
QVERIFY(fileMenuBarMenu && editMenuBarMenu && viewMenuBarMenu && helpMenuBarMenu);
QQuickMenuBarItem *fileMenuBarItem = qobject_cast<QQuickMenuBarItem *>(fileMenuBarMenu->parentItem());
QQuickMenuBarItem *editMenuBarItem = qobject_cast<QQuickMenuBarItem *>(editMenuBarMenu->parentItem());
QQuickMenuBarItem *viewMenuBarItem = qobject_cast<QQuickMenuBarItem *>(viewMenuBarMenu->parentItem());
QQuickMenuBarItem *helpMenuBarItem = qobject_cast<QQuickMenuBarItem *>(helpMenuBarMenu->parentItem());
QVERIFY(fileMenuBarItem && editMenuBarItem && viewMenuBarItem && helpMenuBarItem);
// trigger a menubar item to open a menu
QTest::keyClick(window.data(), Qt::Key_E, Qt::AltModifier); // "&Edit"
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(!editMenuBarItem->hasActiveFocus());
QVERIFY(editMenuBarMenu->isVisible());
QTRY_VERIFY(editMenuBarMenu->isOpened());
QVERIFY(editMenuBarMenu->hasActiveFocus());
// re-trigger a menubar item to hide the menu
QTest::keyClick(window.data(), Qt::Key_E, Qt::AltModifier); // "&Edit"
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(editMenuBarItem->hasActiveFocus());
QVERIFY(!editMenuBarMenu->hasActiveFocus());
QTRY_VERIFY(!editMenuBarMenu->isVisible());
// re-trigger a menubar item to show the menu again
QTest::keyClick(window.data(), Qt::Key_E, Qt::AltModifier); // "&Edit"
QVERIFY(editMenuBarItem->isHighlighted());
QVERIFY(editMenuBarMenu->isVisible());
QTRY_VERIFY(editMenuBarMenu->isOpened());
QVERIFY(editMenuBarMenu->hasActiveFocus());
QVERIFY(!editMenuBarItem->hasActiveFocus());
// trigger another menubar item to open another menu
QTest::keyClick(window.data(), Qt::Key_H, Qt::AltModifier); // "&Help"
QVERIFY(!editMenuBarItem->isHighlighted());
QVERIFY(helpMenuBarItem->isHighlighted());
QVERIFY(!viewMenuBarMenu->isVisible());
QVERIFY(helpMenuBarMenu->isVisible());
QTRY_VERIFY(helpMenuBarMenu->isOpened());
// trigger a menu item to close the menu
QTest::keyClick(window.data(), Qt::Key_A, Qt::AltModifier); // "&About"
QVERIFY(!helpMenuBarItem->isHighlighted());
QTRY_VERIFY(!helpMenuBarMenu->isVisible());
// trigger a menubar item to open a menu
QTest::keyClick(window.data(), Qt::Key_V, Qt::AltModifier); // "&View"
QVERIFY(!editMenuBarItem->isHighlighted());
QVERIFY(viewMenuBarItem->isHighlighted());
QVERIFY(viewMenuBarMenu->isVisible());
QTRY_VERIFY(viewMenuBarMenu->isOpened());
// trigger a menu item to open a sub-menu
QQuickMenuItem *alignmentSubMenuItem = qobject_cast<QQuickMenuItem *>(viewMenuBarMenu->itemAt(0));
QVERIFY(alignmentSubMenuItem);
QQuickMenu *alignmentSubMenu = alignmentSubMenuItem->subMenu();
QVERIFY(alignmentSubMenu);
QTest::keyClick(window.data(), Qt::Key_A, Qt::AltModifier); // "&Alignment"
QVERIFY(viewMenuBarMenu->isVisible());
QVERIFY(alignmentSubMenu->isVisible());
QTRY_VERIFY(alignmentSubMenu->isOpened());
// trigger a menu item to open a sub-sub-menu
QQuickMenuItem *verticalSubMenuItem = qobject_cast<QQuickMenuItem *>(alignmentSubMenu->itemAt(1));
QVERIFY(verticalSubMenuItem);
QQuickMenu *verticalSubMenu = verticalSubMenuItem->subMenu();
QVERIFY(verticalSubMenu);
QTest::keyClick(window.data(), Qt::Key_V, Qt::AltModifier); // "&Vertical"
QVERIFY(viewMenuBarMenu->isVisible());
QVERIFY(alignmentSubMenu->isVisible());
QVERIFY(verticalSubMenu->isVisible());
QTRY_VERIFY(verticalSubMenu->isOpened());
// trigger a menu item to close the whole chain of menus
QTest::keyClick(window.data(), Qt::Key_C, Qt::AltModifier); // "&Center"
QVERIFY(!viewMenuBarItem->isHighlighted());
QTRY_VERIFY(!viewMenuBarMenu->isVisible());
QTRY_VERIFY(!alignmentSubMenu->isVisible());
QTRY_VERIFY(!verticalSubMenu->isVisible());
}
void tst_qquickmenubar::addRemove()
{
QQmlApplicationEngine engine(testFileUrl("empty.qml"));
QScopedPointer<QQuickMenuBar> menuBar(qobject_cast<QQuickMenuBar *>(engine.rootObjects().value(0)));
QVERIFY(menuBar);
QQmlComponent component(&engine);
component.setData("import QtQuick.Controls 2.0; Menu { }", QUrl());
QPointer<QQuickMenu> menu1(qobject_cast<QQuickMenu *>(component.create()));
QVERIFY(!menu1.isNull());
menuBar->addMenu(menu1.data());
QCOMPARE(menuBar->count(), 1);
QCOMPARE(menuBar->menuAt(0), menu1.data());
QPointer<QQuickMenuBarItem> menuBarItem1(qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(0)));
QVERIFY(menuBarItem1);
QCOMPARE(menuBarItem1->menu(), menu1.data());
QCOMPARE(menuBar->itemAt(0), menuBarItem1.data());
QScopedPointer<QQuickMenu> menu2(qobject_cast<QQuickMenu *>(component.create()));
QVERIFY(!menu2.isNull());
menuBar->insertMenu(0, menu2.data());
QCOMPARE(menuBar->count(), 2);
QCOMPARE(menuBar->menuAt(0), menu2.data());
QCOMPARE(menuBar->menuAt(1), menu1.data());
QPointer<QQuickMenuBarItem> menuBarItem2(qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(0)));
QVERIFY(menuBarItem2);
QCOMPARE(menuBarItem2->menu(), menu2.data());
QCOMPARE(menuBar->itemAt(0), menuBarItem2.data());
QCOMPARE(menuBar->itemAt(1), menuBarItem1.data());
// takeMenu(int) does not destroy the menu, but does destroy the respective item in the menubar
QCOMPARE(menuBar->takeMenu(1), menu1.data());
QCOMPARE(menuBar->count(), 1);
QVERIFY(!menuBar->menuAt(1));
QVERIFY(!menuBar->itemAt(1));
QCoreApplication::sendPostedEvents(menu1.data(), QEvent::DeferredDelete);
QVERIFY(!menu1.isNull());
QCoreApplication::sendPostedEvents(menuBarItem1, QEvent::DeferredDelete);
QVERIFY(menuBarItem1.isNull());
// addMenu(Menu) re-creates the respective item in the menubar
menuBar->addMenu(menu1.data());
QCOMPARE(menuBar->count(), 2);
menuBarItem1 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(1));
QVERIFY(!menuBarItem1.isNull());
// removeMenu(Menu) destroys both the menu and the respective item in the menubar
menuBar->removeMenu(menu1.data());
QCOMPARE(menuBar->count(), 1);
QVERIFY(!menuBar->itemAt(1));
QCoreApplication::sendPostedEvents(menu1.data(), QEvent::DeferredDelete);
QVERIFY(menu1.isNull());
QCoreApplication::sendPostedEvents(menuBarItem1, QEvent::DeferredDelete);
QVERIFY(menuBarItem1.isNull());
}
QTEST_QUICKCONTROLS_MAIN(tst_qquickmenubar)
#include "tst_qquickmenubar.moc"