summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel de Dietrich <gabriel.dedietrich@digia.com>2013-02-22 21:15:52 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-02-25 13:39:38 +0100
commit4cc6b22c51a5b42e8a19c7b30475dacb537e02a1 (patch)
tree130bc20c64f84d56687eb6245bd875783b98c36c
parent28b73e87fdaf9738f14c36e62940215658ec01ac (diff)
downloadqtquickcontrols-4cc6b22c51a5b42e8a19c7b30475dacb537e02a1.tar.gz
Menu: Enable "click-select-release" behavior
Some limitations in MouseArea force us to abandon the "one mouse area per menu item" implementation in favor of a menu-wide mouse area, where we track the position changes to highlight the menu item under the mouse cursor. This makes possible updating the highlighted menu item while keeping the mouse pressed. Also, we need to emit an extra mouse press event, from the menu popup window, so that the menu mouse area will receive any mouse release event the user may have triggered. This is because the initial mouse press event popping up the menu was made in another window, and MouseArea would only emit 'released' signals if the released button was already pressed. Change-Id: Id10dd61fcf9e38ef3d34a61b7172301802e9646c Reviewed-by: J-P Nurmi <jpnurmi@digia.com>
-rw-r--r--examples/gallery/main.qml2
-rw-r--r--src/controls/Menu.qml72
-rw-r--r--src/controls/qtmenupopupwindow.cpp46
-rw-r--r--src/controls/qtmenupopupwindow_p.h3
4 files changed, 56 insertions, 67 deletions
diff --git a/examples/gallery/main.qml b/examples/gallery/main.qml
index 450fe5a0..455ed1d4 100644
--- a/examples/gallery/main.qml
+++ b/examples/gallery/main.qml
@@ -141,7 +141,7 @@ ApplicationWindow {
exclusiveGroup: textFormatGroup
}
- ContextMenu {
+ Menu {
id: editmenu
MenuItem { action: cutAction }
MenuItem { action: copyAction }
diff --git a/src/controls/Menu.qml b/src/controls/Menu.qml
index 1d2ca474..270c7869 100644
--- a/src/controls/Menu.qml
+++ b/src/controls/Menu.qml
@@ -94,6 +94,8 @@ MenuPrivate {
property var menuBar: null
//! internal
property int currentIndex: -1
+ //! internal
+ onMenuClosed: currentIndex = -1
//! internal
menuContentItem: Loader {
@@ -166,7 +168,7 @@ MenuPrivate {
Keys.onRightPressed: {
var item = itemsRepeater.itemAt(root.currentIndex)
if (item && item.hasSubmenu) {
- item.menuItem.showPopup(menuFrameLoader.subMenuXPos, 0, -1, item)
+ item.showSubMenu()
item.menuItem.currentIndex = 0
}
}
@@ -195,8 +197,28 @@ MenuPrivate {
id: menuMouseArea
anchors.fill: parent
hoverEnabled: true
-
- onExited: root.currentIndex = -1 // TODO Test for any submenu open
+ acceptedButtons: Qt.AllButtons
+
+ onPositionChanged: updateCurrentItem(mouse)
+ onReleased: menuFrameLoader.triggerAndDismiss()
+
+ 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.hasSubmenu)
+ currentItem.closeSubMenu()
+ currentItem = column.childAt(pos.x, pos.y)
+ if (currentItem) {
+ root.currentIndex = currentItem.menuItemIndex
+ if (currentItem.hasSubmenu && !currentItem.menuItem.popupVisible)
+ currentItem.showSubMenu()
+ } else {
+ root.currentIndex = -1
+ }
+ }
+ }
// Each menu item has its own mouse area, and for events to be
// propagated to the menu mouse area, they need to be embedded.
@@ -211,63 +233,33 @@ MenuPrivate {
id: menuItemLoader
property var menuItem: modelData
- property int contentWidth: column.width
- property int contentHeight: column.height
property bool isSeparator: menuItem ? !menuItem.hasOwnProperty("text") : false
property bool hasSubmenu: menuItem ? !!menuItem["menuItems"] : false
property bool selected: !isSeparator && root.currentIndex === index
+ property int menuItemIndex: index
+
sourceComponent: menuFrameLoader.menuItemStyle
enabled: !isSeparator && !!menuItem && menuItem.enabled
- MouseArea {
- id: itemMouseArea
- width: menuFrameLoader.width
- height: parent.height
- y: menuItemLoader.item ? menuItemLoader.item.y : 0 // Adjust mouse area for style offset
- hoverEnabled: true
-
- onClicked: {
- if (hasSubmenu)
- menuItem.closeMenu()
- menuFrameLoader.triggerAndDismiss()
- }
-
- onEntered: {
- if (menuItemLoader.hasSubmenu && !menuItem.popupVisible)
- openMenuTimer.start()
- }
-
- onExited: {
- if (!pressed && menuItemLoader.hasSubmenu)
- closeMenuTimer.start()
- }
-
- onPositionChanged: root.currentIndex = index
-
- Connections {
- target: menuMouseArea
- onEntered: {
- if (!itemMouseArea.containsMouse && menuItemLoader.hasSubmenu)
- closeMenuTimer.start()
- }
- }
- }
+ function showSubMenu() { openMenuTimer.start() }
Timer {
id: openMenuTimer
interval: 50
onTriggered: {
- if (itemMouseArea.containsMouse)
+ if (root.currentIndex === menuItemIndex)
menuItem.showPopup(menuFrameLoader.subMenuXPos, 0, -1, menuItemLoader)
}
}
+ function closeSubMenu() { closeMenuTimer.start() }
+
Timer {
id: closeMenuTimer
interval: 1
onTriggered: {
- if (menuMouseArea.containsMouse && !itemMouseArea.pressed && !itemMouseArea.containsMouse)
+ if (root.currentIndex !== menuItemIndex)
menuItem.closeMenu()
}
}
diff --git a/src/controls/qtmenupopupwindow.cpp b/src/controls/qtmenupopupwindow.cpp
index 7825f3bf..8b3bed45 100644
--- a/src/controls/qtmenupopupwindow.cpp
+++ b/src/controls/qtmenupopupwindow.cpp
@@ -47,7 +47,7 @@
QT_BEGIN_NAMESPACE
QtMenuPopupWindow::QtMenuPopupWindow(QWindow *parent) :
- QQuickWindow(parent), m_pressedInside(true), m_itemAt(0)
+ QQuickWindow(parent), m_mouseMoved(false), m_itemAt(0)
{
setFlags(Qt::Popup);
setModality(Qt::WindowModal);
@@ -111,41 +111,39 @@ void QtMenuPopupWindow::updatePosition()
void QtMenuPopupWindow::mouseMoveEvent(QMouseEvent *e)
{
QRect rect = QRect(QPoint(), size());
- QWindow *parentMenuWindow = /*qobject_cast<QtMenuPopupWindow*>*/(transientParent());
- if (parentMenuWindow && !rect.contains(e->pos())) {
- forwardEventToTransientParent(e);
- } else {
+ if (rect.contains(e->pos())) {
+ m_mouseMoved = true;
QQuickWindow::mouseMoveEvent(e);
+ } else {
+ forwardEventToTransientParent(e);
}
}
-void QtMenuPopupWindow::mousePressEvent(QMouseEvent *e)
-{
- QRect rect = QRect(QPoint(), size());
- m_pressedInside = rect.contains(e->pos());
- if (m_pressedInside)
- QQuickWindow::mousePressEvent(e);
-}
-
void QtMenuPopupWindow::mouseReleaseEvent(QMouseEvent *e)
{
QRect rect = QRect(QPoint(), size());
- if (rect.contains(e->pos()))
- QQuickWindow::mouseReleaseEvent(e);
- else if (!m_pressedInside)
- dismissMenu();
- else
+ if (rect.contains(e->pos())) {
+ if (m_mouseMoved) {
+ QMouseEvent pe = QMouseEvent(QEvent::MouseButtonPress, e->pos(), e->button(), e->buttons(), e->modifiers());
+ QQuickWindow::mousePressEvent(&pe);
+ QQuickWindow::mouseReleaseEvent(e);
+ }
+ } else {
forwardEventToTransientParent(e);
+ }
}
void QtMenuPopupWindow::forwardEventToTransientParent(QMouseEvent *e)
{
- QWindow *parentMenuWindow = /*qobject_cast<QtMenuPopupWindow*>*/(transientParent());
- if (!parentMenuWindow)
- return;
- QPoint parentPos = parentMenuWindow->mapFromGlobal(mapToGlobal(e->pos()));
- QMouseEvent pe = QMouseEvent(e->type(), parentPos, e->button(), e->buttons(), e->modifiers());
- QGuiApplication::sendEvent(parentMenuWindow, &pe);
+ QWindow *parentMenuWindow = qobject_cast<QtMenuPopupWindow*>(transientParent());
+ if (!parentMenuWindow) {
+ if (m_mouseMoved && e->type() == QEvent::MouseButtonRelease)
+ dismissMenu();
+ } else {
+ QPoint parentPos = parentMenuWindow->mapFromGlobal(mapToGlobal(e->pos()));
+ QMouseEvent pe = QMouseEvent(e->type(), parentPos, e->button(), e->buttons(), e->modifiers());
+ QGuiApplication::sendEvent(parentMenuWindow, &pe);
+ }
}
QT_END_NAMESPACE
diff --git a/src/controls/qtmenupopupwindow_p.h b/src/controls/qtmenupopupwindow_p.h
index 6c3fa19f..82a2a30e 100644
--- a/src/controls/qtmenupopupwindow_p.h
+++ b/src/controls/qtmenupopupwindow_p.h
@@ -67,14 +67,13 @@ Q_SIGNALS:
void menuDismissed();
protected:
- void mousePressEvent(QMouseEvent *);
void mouseReleaseEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);
private:
void forwardEventToTransientParent(QMouseEvent *);
- bool m_pressedInside;
+ bool m_mouseMoved;
const QQuickItem *m_itemAt;
QPointF m_oldItemPos;
};