summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel de Dietrich <gabriel.dedietrich@digia.com>2013-06-05 21:45:04 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-19 16:35:08 +0200
commit1f8ee02fbc06f822ee131fdd395c8e8cd244601d (patch)
tree8846593196d96701741a5a5fba046d13e851ca43
parent7adeff65148a3967af7b2ec44764a2c275dcd3fe (diff)
downloadqtquickcontrols-1f8ee02fbc06f822ee131fdd395c8e8cd244601d.tar.gz
ComboBox: Make popup scrollable
We factor out part the menu item container logic from Menu into ColumnMenuContent, which takes care of scrolling and mouse hovering, and selection. This makes possible to extend the menu items layout. The pop-over and pull-down look is specified by the menu style component by overriding the ScrollView style. The popup's maximum height is also specified by the menu style. The gallery example can finally use a font families combo box. Task-number: QTBUG-31568 Change-Id: I34a7278f476471c0eb51ef51dde3dd83e13002fe Reviewed-by: J-P Nurmi <jpnurmi@digia.com>
-rw-r--r--examples/quick/controls/gallery/content/Controls.qml5
-rw-r--r--src/controls/Menu.qml209
-rw-r--r--src/controls/Private/ColumnMenuContent.qml160
-rw-r--r--src/controls/Private/MenuContentScroller.qml74
-rw-r--r--src/controls/Private/ScrollBar.qml2
-rw-r--r--src/controls/Private/private.pri2
-rw-r--r--src/controls/Private/qmldir2
-rw-r--r--src/controls/Private/qquickstyleitem.cpp23
-rw-r--r--src/controls/ScrollView.qml3
-rw-r--r--src/controls/Styles/Base/ComboBoxStyle.qml16
-rw-r--r--src/controls/Styles/Base/MenuStyle.qml22
-rw-r--r--src/controls/Styles/Desktop/ComboBoxStyle.qml8
-rw-r--r--src/controls/Styles/Desktop/MenuStyle.qml13
-rw-r--r--src/controls/Styles/Desktop/ScrollViewStyle.qml2
-rw-r--r--src/controls/qquickmenu.cpp2
-rw-r--r--src/controls/qquickmenu_p.h3
-rw-r--r--src/controls/qquickmenupopupwindow.cpp10
-rw-r--r--src/controls/qquickmenupopupwindow_p.h1
18 files changed, 423 insertions, 134 deletions
diff --git a/examples/quick/controls/gallery/content/Controls.qml b/examples/quick/controls/gallery/content/Controls.qml
index 98945675..7f6ea9aa 100644
--- a/examples/quick/controls/gallery/content/Controls.qml
+++ b/examples/quick/controls/gallery/content/Controls.qml
@@ -87,6 +87,11 @@ Item {
currentIndex: 2
}
ComboBox {
+ model: Qt.fontFamilies()
+ width: parent.width
+ currentIndex: 47
+ }
+ ComboBox {
id: editableCombo
editable: true
model: choices
diff --git a/src/controls/Menu.qml b/src/controls/Menu.qml
index 4c3bc1be..949b6a91 100644
--- a/src/controls/Menu.qml
+++ b/src/controls/Menu.qml
@@ -152,14 +152,14 @@ MenuPrivate {
property Component __menuComponent: Loader {
id: menuFrameLoader
- property Style __style: styleLoader.item
- property Component menuItemStyle: __style ? __style.menuItem : null
+ readonly property Style __style: styleLoader.item
+ readonly property Component menuItemStyle: __style ? __style.menuItem : null
- property var control: root
- property alias contentWidth: column.width
- property alias contentHeight: column.height
+ readonly property var control: root
+ property alias contentWidth: content.width
+ property alias contentHeight: content.height
- property int subMenuXPos: width + (item && item["subMenuOverlap"] || 0)
+ readonly property int subMenuXPos: width + (item && item["subMenuOverlap"] || 0)
visible: status === Loader.Ready
sourceComponent: __style ? __style.frame : undefined
@@ -204,17 +204,19 @@ MenuPrivate {
for (var i = root.__currentIndex + 1;
i < root.items.length && !canBeHovered(i); i++)
;
+ event.accepted = true
}
Keys.onUpPressed: {
for (var i = root.__currentIndex - 1;
i >= 0 && !canBeHovered(i); i--)
;
+ event.accepted = true
}
function canBeHovered(index) {
- var item = itemsRepeater.itemAt(index)
- if (!item["isSeparator"] && item.enabled) {
+ var item = content.menuItemAt(index)
+ if (item && !item["isSeparator"] && item.enabled) {
root.__currentIndex = index
return true
}
@@ -227,20 +229,24 @@ MenuPrivate {
}
Keys.onRightPressed: {
- var item = itemsRepeater.itemAt(root.__currentIndex)
+ var item = content.menuItemAt(root.__currentIndex)
if ((event.accepted = (item && item.isSubmenu))) {
item.showSubMenu(true)
item.menuItem.__currentIndex = 0
}
}
- Keys.onSpacePressed: menuFrameLoader.triggerAndDismiss()
- Keys.onReturnPressed: menuFrameLoader.triggerAndDismiss()
- Keys.onEnterPressed: menuFrameLoader.triggerAndDismiss()
+ Keys.onSpacePressed: triggerCurrent()
+ Keys.onReturnPressed: triggerCurrent()
+ Keys.onEnterPressed: triggerCurrent()
+
+ function triggerCurrent() {
+ var item = content.menuItemAt(root.__currentIndex)
+ if (item)
+ content.triggered(item)
+ }
function triggerAndDismiss(item) {
- if (!item)
- item = itemsRepeater.itemAt(root.__currentIndex)
if (item && !item.isSeparator) {
root.__dismissMenu()
if (!item.isSubmenu)
@@ -250,126 +256,85 @@ MenuPrivate {
Binding {
// Make sure the styled frame is in the background
- target: menuFrameLoader.item
+ target: item
property: "z"
- value: menuMouseArea.z - 1
+ value: content.z - 1
}
- MouseArea {
- id: menuMouseArea
- anchors.fill: parent
- hoverEnabled: true
- acceptedButtons: Qt.AllButtons
-
- onPositionChanged: updateCurrentItem(mouse)
- onReleased: menuFrameLoader.triggerAndDismiss()
- onExited: {
- if (currentItem && !currentItem.menuItem.__popupVisible) {
- currentItem = null
- root.__currentIndex = -1
- }
- }
-
- property Item currentItem: null
-
- function updateCurrentItem(mouse) {
- var pos = mapToItem(column, mouse.x, mouse.y)
- if (!currentItem || !currentItem.contains(Qt.point(pos.x - currentItem.x, pos.y - currentItem.y))) {
- if (currentItem && !pressed && currentItem.isSubmenu)
- currentItem.closeSubMenu()
- var itemUnderMouse = column.childAt(pos.x, pos.y)
- if (itemUnderMouse) {
- currentItem = itemUnderMouse
- } else if (currentItem) {
- var itemItem = currentItem.item
- if (!itemItem.contains(itemItem.mapFromItem(column, pos)))
- currentItem = null
- }
+ ColumnMenuContent {
+ id: content
+ menuItemDelegate: menuItemComponent
+ scrollerStyle: __style ? __style.scrollerStyle : undefined
+ itemsModel: root.items
+ margin: menuFrameLoader.item ? menuFrameLoader.item.margin : 0
+ minWidth: root.__minimumWidth
+ maxHeight: menuFrameLoader.item ? menuFrameLoader.item.maxHeight : 0
+ onTriggered: triggerAndDismiss(item)
+ }
- if (currentItem) {
- root.__currentIndex = currentItem.menuItemIndex
- if (currentItem.isSubmenu && !currentItem.menuItem.__popupVisible)
- currentItem.showSubMenu(false)
+ Component {
+ id: menuItemComponent
+ Loader {
+ id: menuItemLoader
+
+ property var menuItem: modelData
+ readonly property bool isSeparator: !!menuItem && menuItem.type === MenuItemType.Separator
+ readonly property bool isSubmenu: !!menuItem && menuItem.type === MenuItemType.Menu
+ property bool selected: !(isSeparator || !!scrollerDirection) && root.__currentIndex === index
+ property string text: isSubmenu ? menuItem.title : !(isSeparator || !!scrollerDirection) ? menuItem.text : ""
+ property bool showUnderlined: __contentItem.altPressed
+ readonly property var scrollerDirection: menuItem["scrollerDirection"]
+
+ property int menuItemIndex: index
+
+ sourceComponent: menuFrameLoader.menuItemStyle
+ enabled: visible && !isSeparator && !!menuItem && menuItem.enabled
+ visible: menuItem.visible
+ active: visible
+
+ function showSubMenu(immediately) {
+ if (immediately) {
+ if (root.__currentIndex === menuItemIndex)
+ menuItem.__popup(menuFrameLoader.subMenuXPos, 0, -1)
} else {
- root.__currentIndex = -1
+ openMenuTimer.start()
}
}
- }
- // Each menu item has its own mouse area, and for events to be
- // propagated to the menu mouse area, they need to be embedded.
- Column {
- id: column
-
- Repeater {
- id: itemsRepeater
- model: root.items
-
- Loader {
- id: menuItemLoader
-
- property var menuItem: modelData
- readonly property bool isSeparator: !!menuItem && menuItem.type === MenuItemType.Separator
- readonly property bool isSubmenu: !!menuItem && menuItem.type === MenuItemType.Menu
- property bool selected: !isSeparator && root.__currentIndex === index
- property string text: isSubmenu ? menuItem.title : !isSeparator ? menuItem.text : ""
- property bool showUnderlined: __contentItem.altPressed
-
- property int menuItemIndex: index
-
- sourceComponent: menuFrameLoader.menuItemStyle
- enabled: visible && !isSeparator && !!menuItem && menuItem.enabled
- visible: menuItem.visible
- active: visible
-
- function showSubMenu(immediately) {
- if (immediately) {
- if (root.__currentIndex === menuItemIndex) {
- if (Qt.application.layoutDirection === Qt.RightToLeft)
- menuItem.__popup(0, 0, -1)
- else
- menuItem.__popup(menuFrameLoader.subMenuXPos, 0, -1)
- }
- } else {
- openMenuTimer.start()
- }
- }
-
- Timer {
- id: openMenuTimer
- interval: 50
- onTriggered: menuItemLoader.showSubMenu(true)
- }
-
- function closeSubMenu() { closeMenuTimer.start() }
-
- Timer {
- id: closeMenuTimer
- interval: 1
- onTriggered: {
- if (root.__currentIndex !== menuItemIndex)
- menuItem.__closeMenu()
- }
- }
-
- Component.onCompleted: {
- menuItem.__visualItem = menuItemLoader
-
- var title = text
- var ampersandPos = title.indexOf("&")
- if (ampersandPos !== -1)
- menuFrameLoader.mnemonicsMap[title[ampersandPos + 1].toUpperCase()] = menuItemLoader
- }
- }
+ Timer {
+ id: openMenuTimer
+ interval: 50
+ onTriggered: menuItemLoader.showSubMenu(true)
}
- onWidthChanged: {
- for (var i = 0; i < children.length; i++) {
- var item = children[i]["item"]
- if (item)
- item.implicitWidth = Math.max(root.__minimumWidth, implicitWidth)
+ function closeSubMenu() { closeMenuTimer.start() }
+
+ Timer {
+ id: closeMenuTimer
+ interval: 1
+ onTriggered: {
+ if (root.__currentIndex !== menuItemIndex)
+ menuItem.__closeMenu()
}
}
+
+ onLoaded: {
+ menuItem.__visualItem = menuItemLoader
+
+ if (content.width < item.implicitWidth)
+ content.width = item.implicitWidth
+
+ var title = text
+ var ampersandPos = title.indexOf("&")
+ if (ampersandPos !== -1)
+ menuFrameLoader.mnemonicsMap[title[ampersandPos + 1].toUpperCase()] = menuItemLoader
+ }
+
+ Binding {
+ target: menuItemLoader.item
+ property: "width"
+ value: Math.max(root.__minimumWidth, content.width)
+ }
}
}
}
diff --git a/src/controls/Private/ColumnMenuContent.qml b/src/controls/Private/ColumnMenuContent.qml
new file mode 100644
index 00000000..505756d1
--- /dev/null
+++ b/src/controls/Private/ColumnMenuContent.qml
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Quick Controls module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Digia Plc and its Subsidiary(-ies) 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.1
+import QtQuick.Controls 1.1
+
+Item {
+ id: content
+
+ property Component menuItemDelegate
+ property Component scrollerStyle
+ property var itemsModel
+ property int minWidth: 100
+ property real maxHeight: 800
+ property int margin: 1
+
+ signal triggered(var item)
+
+ function menuItemAt(index) {
+ list.currentIndex = index
+ return list.currentItem
+ }
+
+ width: Math.max(list.contentWidth, minWidth)
+ height: Math.min(list.contentHeight, fittedMaxHeight) + 2 * margin
+
+ readonly property int currentIndex: root.__currentIndex
+ property Item currentItem: null
+ readonly property int itemHeight: list.count > 0 ? list.contentItem.children[0].height : 23
+ readonly property int fittingItems: Math.floor((maxHeight - downScroller.height) / itemHeight)
+ readonly property real fittedMaxHeight: itemHeight * fittingItems + downScroller.height
+ readonly property bool shouldUseScrollers: scrollView.__style.useScrollers && itemsModel.length > fittingItems
+ readonly property real upScrollerHeight: upScroller.visible ? upScroller.height : 0
+ readonly property real downScrollerHeight: downScroller.visible ? downScroller.height : 0
+
+ function updateCurrentItem(mouse) {
+ var pos = mapToItem(list.contentItem, mouse.x, mouse.y)
+ if (!currentItem || !currentItem.contains(Qt.point(pos.x - currentItem.x, pos.y - currentItem.y))) {
+ if (currentItem && !hoverArea.pressed && currentItem.isSubmenu)
+ currentItem.closeSubMenu()
+ currentItem = list.itemAt(pos.x, pos.y)
+ if (currentItem) {
+ root.__currentIndex = currentItem.menuItemIndex
+ if (currentItem.isSubmenu && !currentItem.menuItem.__popupVisible)
+ currentItem.showSubMenu(false)
+ } else {
+ root.__currentIndex = -1
+ }
+ }
+ }
+
+ MouseArea {
+ id: hoverArea
+ anchors.left: scrollView.left
+ width: scrollView.width - scrollView.__verticalScrollBar.width
+ height: parent.height
+
+ hoverEnabled: true
+ acceptedButtons: Qt.AllButtons
+
+ onPositionChanged: updateCurrentItem(mouse)
+ onReleased: content.triggered(currentItem)
+ onExited: {
+ if (currentItem && !currentItem.menuItem.__popupVisible) {
+ currentItem = null
+ root.__currentIndex = -1
+ }
+ }
+
+ MenuContentScroller {
+ id: upScroller
+ direction: "up"
+ visible: shouldUseScrollers && !list.atYBeginning
+ x: margin
+ function scrollABit() { list.contentY -= itemHeight }
+ }
+
+ MenuContentScroller {
+ id: downScroller
+ direction: "down"
+ visible: shouldUseScrollers && !list.atYEnd
+ x: margin
+ function scrollABit() { list.contentY += itemHeight }
+ }
+ }
+
+ ScrollView {
+ id: scrollView
+ anchors {
+ fill: parent
+ topMargin: content.margin + upScrollerHeight
+ bottomMargin: downScrollerHeight - content.margin - 1
+ rightMargin: -1
+ }
+
+ style: scrollerStyle
+ __wheelAreaScrollSpeed: itemHeight
+
+ ListView {
+ id: list
+ model: itemsModel
+ delegate: menuItemDelegate
+ snapMode: ListView.SnapToItem
+ boundsBehavior: Flickable.StopAtBounds
+ highlightFollowsCurrentItem: true
+ highlightMoveDuration: 0
+ }
+ }
+
+ Timer {
+ interval: 1
+ running: true
+ repeat: false
+ onTriggered: list.positionViewAtIndex(currentIndex, scrollView.__style.useScrollers
+ ? ListView.Center : ListView.Beginning)
+ }
+
+ Binding {
+ target: scrollView.__verticalScrollBar
+ property: "singleStep"
+ value: itemHeight
+ }
+}
diff --git a/src/controls/Private/MenuContentScroller.qml b/src/controls/Private/MenuContentScroller.qml
new file mode 100644
index 00000000..30a8825a
--- /dev/null
+++ b/src/controls/Private/MenuContentScroller.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Quick Controls module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 Digia Plc and its Subsidiary(-ies) 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.1
+
+MouseArea {
+ property string direction
+
+ anchors {
+ top: direction === "up" ? parent.top : undefined
+ bottom: direction === "down" ? parent.bottom : undefined
+ }
+
+ hoverEnabled: visible
+ height: scrollerLoader.item.height
+ width: parent.width
+
+ Loader {
+ id: scrollerLoader
+
+ sourceComponent: menuItemDelegate
+ property int index: -1
+ property var modelData: {
+ "visible": true,
+ "scrollerDirection": direction,
+ "enabled": true
+ }
+ }
+
+ Timer {
+ interval: 100
+ repeat: true
+ triggeredOnStart: true
+ running: parent.containsMouse
+ onTriggered: scrollABit()
+ }
+}
diff --git a/src/controls/Private/ScrollBar.qml b/src/controls/Private/ScrollBar.qml
index 9ee330d3..49dd20a4 100644
--- a/src/controls/Private/ScrollBar.qml
+++ b/src/controls/Private/ScrollBar.qml
@@ -56,6 +56,7 @@ Item {
property alias minimumValue: slider.minimumValue
property alias maximumValue: slider.maximumValue
property alias value: slider.value
+ property int singleStep: 20
activeFocusOnTab: false
@@ -89,7 +90,6 @@ Item {
id: internal
property bool horizontal: orientation === Qt.Horizontal
property int pageStep: internal.horizontal ? width : height
- property int singleStep: 20
property bool scrollToClickposition: internal.scrollToClickPosition
anchors.fill: parent
cursorShape: __panel.visible ? Qt.ArrowCursor : Qt.IBeamCursor // forces a cursor change
diff --git a/src/controls/Private/private.pri b/src/controls/Private/private.pri
index bd001c0a..58cc7f11 100644
--- a/src/controls/Private/private.pri
+++ b/src/controls/Private/private.pri
@@ -37,6 +37,8 @@ PRIVATE_QML_FILES += \
$$PWD/ScrollViewHelper.qml \
$$PWD/ScrollBar.qml \
$$PWD/FocusFrame.qml \
+ $$PWD/ColumnMenuContent.qml \
+ $$PWD/MenuContentScroller.qml \
$$PWD/qmldir
QML_FILES += $$PRIVATE_QML_FILES
diff --git a/src/controls/Private/qmldir b/src/controls/Private/qmldir
index 1ee66461..a49401dc 100644
--- a/src/controls/Private/qmldir
+++ b/src/controls/Private/qmldir
@@ -16,3 +16,5 @@ SpinBoxStyle 1.0 ../Styles/Base/SpinBoxStyle.qml
ToolBarStyle 1.0 ../Styles/Base/ToolBarStyle.qml
StatusBarStyle 1.0 ../Styles/Base/StatusBarStyle.qml
ToolButtonStyle 1.0 ../Styles/Base/ToolButtonStyle.qml
+MenuContentScroller 1.0 MenuContentScroller.qml
+ColumnMenuContent 1.0 ColumnMenuContent.qml
diff --git a/src/controls/Private/qquickstyleitem.cpp b/src/controls/Private/qquickstyleitem.cpp
index 4101f90f..82e503dd 100644
--- a/src/controls/Private/qquickstyleitem.cpp
+++ b/src/controls/Private/qquickstyleitem.cpp
@@ -418,7 +418,13 @@ void QQuickStyleItem::initStyleOption()
QStyleOptionMenuItem *opt = qstyleoption_cast<QStyleOptionMenuItem*>(m_styleoption);
// For GTK style. See below, in setElementType()
setProperty("_q_isComboBoxPopupItem", m_itemType == ComboBoxItem);
- if (text().isEmpty()) {
+
+ QString scrollerDirection = m_properties["scrollerDirection"].toString();
+ if (!scrollerDirection.isEmpty()) {
+ opt->menuItemType = QStyleOptionMenuItem::Scroller;
+ opt->state |= scrollerDirection == "up" ?
+ QStyle::State_UpArrow : QStyle::State_DownArrow;
+ } else if (text().isEmpty()) {
opt->menuItemType = QStyleOptionMenuItem::Separator;
} else {
opt->text = text();
@@ -861,7 +867,12 @@ QSize QQuickStyleItem::sizeFromContents(int width, int height)
break;
case MenuItem:
case ComboBoxItem:
- size = qApp->style()->sizeFromContents(QStyle::CT_MenuItem, m_styleoption, QSize(width,height));
+ if (static_cast<QStyleOptionMenuItem *>(m_styleoption)->menuItemType == QStyleOptionMenuItem::Scroller) {
+ size.setHeight(qMax(QApplication::globalStrut().height(),
+ qApp->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, 0)));
+ } else {
+ size = qApp->style()->sizeFromContents(QStyle::CT_MenuItem, m_styleoption, QSize(width,height));
+ }
break;
default:
break;
@@ -1286,8 +1297,12 @@ void QQuickStyleItem::paint(QPainter *painter)
qApp->style()->drawControl(QStyle::CE_MenuBarItem, m_styleoption, painter);
break;
case MenuItem:
- case ComboBoxItem: // fall through
- qApp->style()->drawControl(QStyle::CE_MenuItem, m_styleoption, painter);
+ case ComboBoxItem: { // fall through
+ QStyle::ControlElement menuElement =
+ static_cast<QStyleOptionMenuItem *>(m_styleoption)->menuItemType == QStyleOptionMenuItem::Scroller ?
+ QStyle::CE_MenuScroller : QStyle::CE_MenuItem;
+ qApp->style()->drawControl(menuElement, m_styleoption, painter);
+ }
break;
case CheckBox:
qApp->style()->drawControl(QStyle::CE_CheckBox, m_styleoption, painter);
diff --git a/src/controls/ScrollView.qml b/src/controls/ScrollView.qml
index 5717d70f..06343b74 100644
--- a/src/controls/ScrollView.qml
+++ b/src/controls/ScrollView.qml
@@ -137,6 +137,8 @@ FocusScope {
/*! \internal */
property Item __scroller: scroller
/*! \internal */
+ property alias __wheelAreaScrollSpeed: wheelArea.scrollSpeed
+ /*! \internal */
property int __scrollBarTopMargin: 0
/*! \internal */
property int __viewTopMargin: 0
@@ -287,7 +289,6 @@ FocusScope {
verticalScrollBar.width + scrollBarSpacing : 0
property int horizontalScrollbarOffset: horizontalScrollBar.visible && !horizontalScrollBar.isTransient ?
horizontalScrollBar.height + scrollBarSpacing : 0
-
Loader {
id: frameLoader
sourceComponent: __style ? __style.frame : null
diff --git a/src/controls/Styles/Base/ComboBoxStyle.qml b/src/controls/Styles/Base/ComboBoxStyle.qml
index 2011b219..b49d8f97 100644
--- a/src/controls/Styles/Base/ComboBoxStyle.qml
+++ b/src/controls/Styles/Base/ComboBoxStyle.qml
@@ -38,6 +38,7 @@
**
****************************************************************************/
import QtQuick 2.1
+import QtQuick.Window 2.1
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Controls.Private 1.0
@@ -188,7 +189,11 @@ Style {
/*! \internal */
property Component __dropDownStyle: MenuStyle {
+ maxPopupHeight: 600
__menuItemType: "comboboxitem"
+ scrollerStyle: ScrollViewStyle {
+ property bool useScrollers: false
+ }
}
/*! \internal */
@@ -198,6 +203,8 @@ Style {
width: (parent ? parent.contentWidth : 0)
height: (parent ? parent.contentHeight : 0) + 2
border.color: "#777"
+ property real maxHeight: Math.min(500, Screen.desktopAvailableHeight)
+ property int margin: 1
}
property Component menuItem: Rectangle {
@@ -211,5 +218,14 @@ Style {
text: textRef
}
}
+
+ property Component scrollerStyle: Style {
+ padding { left: 0; right: 0; top: 0; bottom: 0 }
+ property bool scrollToClickedPosition: false
+ property Component frame: Item { visible: false }
+ property Component corner: Item { visible: false }
+ property Component __scrollbar: Item { visible: false }
+ property bool useScrollers: true
+ }
}
}
diff --git a/src/controls/Styles/Base/MenuStyle.qml b/src/controls/Styles/Base/MenuStyle.qml
index 9be32459..c05c6a6d 100644
--- a/src/controls/Styles/Base/MenuStyle.qml
+++ b/src/controls/Styles/Base/MenuStyle.qml
@@ -39,6 +39,7 @@
****************************************************************************/
import QtQuick 2.1
+import QtQuick.Window 2.1
import QtQuick.Controls 1.1
import QtQuick.Controls.Private 1.0
@@ -53,6 +54,7 @@ Style {
id: styleRoot
property string __menuItemType: "menuitem"
+ property real maxPopupHeight: 600 // ### FIXME Screen.desktopAvailableHeight * 0.99
property Component frame: Rectangle {
width: (parent ? parent.contentWidth : 0) + 2
@@ -62,6 +64,8 @@ Style {
border { width: 1; color: "darkgray" }
property int subMenuOverlap: -1
+ property real maxHeight: maxPopupHeight
+ property int margin: 1
}
property Component menuItem: Rectangle {
@@ -69,7 +73,7 @@ Style {
y: 1
implicitWidth: Math.max((parent ? parent.width : 0),
18 + text.paintedWidth + (rightDecoration.visible ? rightDecoration.width + 40 : 12))
- implicitHeight: isSeparator ? text.font.pixelSize / 2 : text.paintedHeight + 4
+ implicitHeight: isSeparator ? text.font.pixelSize / 2 : !!scrollerDirection ? text.font.pixelSize * 0.75 : text.paintedHeight + 4
color: selected && enabled ? "" : backgroundColor
gradient: selected && enabled ? selectedGradient : undefined
border.width: 1
@@ -188,6 +192,13 @@ Style {
style: selected || !isSubmenu ? Text.Normal : Text.Raised; styleColor: Qt.lighter(color, 4)
}
+ Image {
+ id: scrollerDecoration
+ visible: !!scrollerDirection
+ anchors.centerIn: parent
+ source: scrollerDirection === "up" ? "images/arrow-up.png" : "images/arrow-down.png"
+ }
+
Rectangle {
visible: isSeparator
width: parent.width - 2
@@ -197,4 +208,13 @@ Style {
color: "darkgray"
}
}
+
+ property Component scrollerStyle: Style {
+ padding { left: 0; right: 0; top: 0; bottom: 0 }
+ property bool scrollToClickedPosition: false
+ property Component frame: Item { visible: false }
+ property Component corner: Item { visible: false }
+ property Component __scrollbar: Item { visible: false }
+ property bool useScrollers: true
+ }
}
diff --git a/src/controls/Styles/Desktop/ComboBoxStyle.qml b/src/controls/Styles/Desktop/ComboBoxStyle.qml
index e6495ceb..2c1cd7c2 100644
--- a/src/controls/Styles/Desktop/ComboBoxStyle.qml
+++ b/src/controls/Styles/Desktop/ComboBoxStyle.qml
@@ -38,9 +38,11 @@
**
****************************************************************************/
import QtQuick 2.1
+import QtQuick.Window 2.1
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Controls.Private 1.0
+import "." as Desktop
Style {
readonly property ComboBox control: __control
@@ -86,6 +88,8 @@ Style {
width: (parent ? parent.contentWidth : 0)
height: (parent ? parent.contentHeight : 0) + 2 * pixelMetric("defaultframewidth")
+ property real maxHeight: 600
+ property int margin: pixelMetric("menuvmargin") + pixelMetric("menupanelwidth")
}
property Component menuItem: StyleItem {
@@ -107,5 +111,9 @@ Style {
selected: parent ? parent.selected : false
}
}
+
+ property Component scrollerStyle: Desktop.ScrollViewStyle {
+ property bool useScrollers: false
+ }
}
}
diff --git a/src/controls/Styles/Desktop/MenuStyle.qml b/src/controls/Styles/Desktop/MenuStyle.qml
index b1f5e9cf..a3f3e8fa 100644
--- a/src/controls/Styles/Desktop/MenuStyle.qml
+++ b/src/controls/Styles/Desktop/MenuStyle.qml
@@ -39,6 +39,7 @@
****************************************************************************/
import QtQuick 2.1
+import QtQuick.Window 2.1
import QtQuick.Controls 1.1
import QtQuick.Controls.Private 1.0
@@ -56,6 +57,8 @@ Style {
height: implicitHeight + 2 * (pixelMetric("menuvmargin") + pixelMetric("menupanelwidth"))
property int subMenuOverlap: pixelMetric("submenuoverlap")
+ property real maxHeight: Screen.desktopAvailableHeight * 0.99
+ property int margin: pixelMetric("menuvmargin") + pixelMetric("menupanelwidth")
Rectangle {
visible: anchors.margins > 0
@@ -90,10 +93,20 @@ Style {
"exclusive": !!menuItem && !!menuItem["exclusiveGroup"],
"shortcut": !!menuItem && menuItem["shortcut"] || "",
"isSubmenu": isSubmenu,
+ "scrollerDirection": scrollerDirection,
"icon": !!menuItem && menuItem.__icon
}
Accessible.role: Accessible.MenuItem
Accessible.name: StyleHelpers.removeMnemonics(text)
}
+
+ property Component scrollerStyle: Style {
+ padding { left: 0; right: 0; top: 0; bottom: 0 }
+ property bool scrollToClickedPosition: false
+ property Component frame: Item { visible: false }
+ property Component corner: Item { visible: false }
+ property Component __scrollbar: Item { visible: false }
+ property bool useScrollers: true
+ }
}
diff --git a/src/controls/Styles/Desktop/ScrollViewStyle.qml b/src/controls/Styles/Desktop/ScrollViewStyle.qml
index 9342d524..cd8a2a04 100644
--- a/src/controls/Styles/Desktop/ScrollViewStyle.qml
+++ b/src/controls/Styles/Desktop/ScrollViewStyle.qml
@@ -58,7 +58,7 @@ Style {
id: styleitem
elementType: "frame"
sunken: true
- visible: frameVisible
+ visible: control.frameVisible
}
property Component corner: StyleItem { elementType: "scrollareacorner" }
diff --git a/src/controls/qquickmenu.cpp b/src/controls/qquickmenu.cpp
index 62e7a7bd..600dbe79 100644
--- a/src/controls/qquickmenu.cpp
+++ b/src/controls/qquickmenu.cpp
@@ -298,6 +298,8 @@ void QQuickMenu::setMinimumWidth(int w)
m_minimumWidth = w;
if (m_platformMenu)
m_platformMenu->setMinimumWidth(w);
+
+ emit minimumWidthChanged();
}
void QQuickMenu::setFont(const QFont &arg)
diff --git a/src/controls/qquickmenu_p.h b/src/controls/qquickmenu_p.h
index f15e6caa..c1fab0b5 100644
--- a/src/controls/qquickmenu_p.h
+++ b/src/controls/qquickmenu_p.h
@@ -69,7 +69,7 @@ class QQuickMenu : public QQuickMenuText
Q_PROPERTY(int __selectedIndex READ selectedIndex WRITE setSelectedIndex NOTIFY __selectedIndexChanged)
Q_PROPERTY(bool __popupVisible READ popupVisible NOTIFY popupVisibleChanged)
Q_PROPERTY(QQuickItem *__contentItem READ menuContentItem WRITE setMenuContentItem NOTIFY menuContentItemChanged)
- Q_PROPERTY(int __minimumWidth READ minimumWidth WRITE setMinimumWidth)
+ Q_PROPERTY(int __minimumWidth READ minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged)
Q_PROPERTY(QFont __font READ font WRITE setFont)
Q_PROPERTY(qreal __xOffset READ xOffset WRITE setXOffset)
Q_PROPERTY(qreal __yOffset READ yOffset WRITE setYOffset)
@@ -100,6 +100,7 @@ Q_SIGNALS:
void __menuClosed();
void popupVisibleChanged();
void menuContentItemChanged();
+ void minimumWidthChanged();
public:
QQuickMenu(QObject *parent = 0);
diff --git a/src/controls/qquickmenupopupwindow.cpp b/src/controls/qquickmenupopupwindow.cpp
index d21bd0d5..e06b5f03 100644
--- a/src/controls/qquickmenupopupwindow.cpp
+++ b/src/controls/qquickmenupopupwindow.cpp
@@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE
QQuickMenuPopupWindow::QQuickMenuPopupWindow(QWindow *parent) :
QQuickWindow(parent), m_mouseMoved(false), m_needsActivatedEvent(true),
- m_itemAt(0), m_parentItem(0), m_menuContentItem(0)
+ m_dismissed(false), m_itemAt(0), m_parentItem(0), m_menuContentItem(0)
{
setFlags(Qt::Popup);
setModality(Qt::WindowModal);
@@ -176,6 +176,7 @@ void QQuickMenuPopupWindow::setGeometry(int posx, int posy, int w, int h)
void QQuickMenuPopupWindow::dismissMenu()
{
+ m_dismissed = true;
emit menuDismissed();
close();
}
@@ -210,7 +211,9 @@ void QQuickMenuPopupWindow::mouseMoveEvent(QMouseEvent *e)
void QQuickMenuPopupWindow::mousePressEvent(QMouseEvent *e)
{
QRect rect = QRect(QPoint(), size());
- if (!rect.contains(e->pos()))
+ if (rect.contains(e->pos()))
+ QQuickWindow::mousePressEvent(e);
+ else
forwardEventToTransientParent(e);
}
@@ -221,7 +224,8 @@ void QQuickMenuPopupWindow::mouseReleaseEvent(QMouseEvent *e)
if (m_mouseMoved) {
QMouseEvent pe = QMouseEvent(QEvent::MouseButtonPress, e->pos(), e->button(), e->buttons(), e->modifiers());
QQuickWindow::mousePressEvent(&pe);
- QQuickWindow::mouseReleaseEvent(e);
+ if (!m_dismissed)
+ QQuickWindow::mouseReleaseEvent(e);
}
m_mouseMoved = true; // Initial mouse release counts as move.
} else {
diff --git a/src/controls/qquickmenupopupwindow_p.h b/src/controls/qquickmenupopupwindow_p.h
index 4407fdec..4c629219 100644
--- a/src/controls/qquickmenupopupwindow_p.h
+++ b/src/controls/qquickmenupopupwindow_p.h
@@ -89,6 +89,7 @@ private:
bool m_mouseMoved;
bool m_needsActivatedEvent;
+ bool m_dismissed;
QQuickItem *m_itemAt;
QPointF m_oldItemPos;
QQuickItem *m_parentItem;