diff options
| author | Gabriel de Dietrich <gabriel.dedietrich@digia.com> | 2013-06-05 21:45:04 +0200 |
|---|---|---|
| committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 16:35:08 +0200 |
| commit | 1f8ee02fbc06f822ee131fdd395c8e8cd244601d (patch) | |
| tree | 8846593196d96701741a5a5fba046d13e851ca43 /src/controls/Menu.qml | |
| parent | 7adeff65148a3967af7b2ec44764a2c275dcd3fe (diff) | |
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>
Diffstat (limited to 'src/controls/Menu.qml')
| -rw-r--r-- | src/controls/Menu.qml | 209 |
1 files changed, 87 insertions, 122 deletions
diff --git a/src/controls/Menu.qml b/src/controls/Menu.qml index 4c3bc1be7..949b6a915 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) + } } } } |
