| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 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 QtTest 1.0 |
| import QtQuick 2.1 |
| import QtQuick.Controls 1.1 |
| import QtQuick.Controls.Private 1.0 |
| import QtQuick.Extras 1.4 |
| import QtQuick.Extras.Private 1.0 |
| import QtQuick.Extras.Private.CppUtils 1.0 |
| |
| // Have to have Item here otherwise mouse clicks don't work. |
| Item { |
| id: container |
| width: 400 |
| height: 400 |
| |
| TestCase { |
| id: testcase |
| name: "Tests_PieMenu" |
| when: windowShown |
| anchors.fill: parent |
| |
| readonly property real menuWidth: 200 |
| readonly property real menuHeight: 200 |
| |
| SignalSpy { |
| id: currentIndexSignalSpy |
| } |
| |
| SignalSpy { |
| id: actionSignalSpy |
| } |
| |
| SignalSpy { |
| id: selectedAngleChangedSpy |
| } |
| |
| Component { |
| id: pieMenuComponent |
| |
| PieMenu {} |
| } |
| |
| function cleanup() { |
| currentIndexSignalSpy.clear(); |
| actionSignalSpy.clear(); |
| selectedAngleChangedSpy.clear(); |
| } |
| |
| function mouseButtonToString(button) { |
| return button === Qt.LeftButton ? "Qt.LeftButton" : "Qt.RightButton"; |
| } |
| |
| function triggerModeToString(triggerMode) { |
| return triggerMode === TriggerMode.TriggerOnPress ? "TriggerOnPress" |
| : (triggerMode === TriggerMode.TriggerOnRelease ? "TriggerOnRelease" : "TriggerOnClick"); |
| } |
| |
| function test_instance() { |
| var pieMenu = createTemporaryObject(pieMenuComponent, container); |
| verify(pieMenu, "PieMenu: failed to create an instance"); |
| verify(pieMenu.__style); |
| compare(pieMenu.triggerMode, TriggerMode.TriggerOnClick); |
| pieMenu.destroy(); |
| |
| // Ensure setting visible = true; visible = false; in onCompleted doesn't cause any problems. |
| var visibleOnCompletedComponent = Qt.createComponent("PieMenuVisibleOnCompleted.qml"); |
| tryCompare(visibleOnCompletedComponent, "status", Component.Ready); |
| pieMenu = createTemporaryObject(visibleOnCompletedComponent, container); |
| verify(pieMenu, "PieMenu: failed to create an instance"); |
| pieMenu.destroy(); |
| |
| // Ensure constructing a menu as a property (and hence no parent) |
| // with visible = true doesn't cause any problems. |
| var visibleButNoParentComponent = Qt.createComponent("PieMenuVisibleButNoParent.qml"); |
| tryCompare(visibleButNoParentComponent, "status", Component.Ready); |
| pieMenu = createTemporaryObject(visibleButNoParentComponent, container); |
| verify(pieMenu, "PieMenu: failed to create an instance"); |
| pieMenu.destroy(); |
| } |
| |
| function test_triggerMode() { |
| var pieMenuComponent = Qt.createComponent("PieMenu3Items.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var mouseArea = root.mouseArea; |
| var pieMenu = root.pieMenu; |
| currentIndexSignalSpy.signalName = "currentIndexChanged" |
| currentIndexSignalSpy.target = pieMenu; |
| actionSignalSpy.signalName = "actionTriggered"; |
| actionSignalSpy.target = root; |
| |
| compare(pieMenu.triggerMode, TriggerMode.TriggerOnClick); |
| |
| var triggerModes = [ |
| TriggerMode.TriggerOnClick, |
| TriggerMode.TriggerOnPress, |
| TriggerMode.TriggerOnRelease |
| ]; |
| // Our root mouse area will accept either left click or right click, |
| // and the menu should accept either to select items or close it. |
| var buttonVariations = [ |
| [Qt.LeftButton, Qt.LeftButton], |
| [Qt.RightButton, Qt.RightButton], |
| [Qt.LeftButton, Qt.RightButton], |
| [Qt.RightButton, Qt.LeftButton] |
| ]; |
| for (var modeIndex = 0; modeIndex < triggerModes.length; ++modeIndex) { |
| for (var i = 0; i < buttonVariations.length; ++i) { |
| var openButton = buttonVariations[i][0]; |
| var closeButton = buttonVariations[i][1]; |
| |
| pieMenu.triggerMode = triggerModes[modeIndex]; |
| compare(pieMenu.triggerMode, triggerModes[modeIndex]); |
| |
| // Make the menu visible. |
| if (pieMenu.triggerMode !== TriggerMode.TriggerOnRelease) { |
| mouseClick(root, 0, 0, openButton); |
| } else { |
| mousePress(root, 0, 0, openButton); |
| } |
| tryCompare(pieMenu, "visible", true); |
| |
| // Click/press outside the menu to close it. |
| switch (pieMenu.triggerMode) { |
| case TriggerMode.TriggerOnClick: |
| mouseClick(root, 0, 0, closeButton); |
| tryCompare(currentIndexSignalSpy, "count", 0); |
| compare(pieMenu.visible, false, "Menu isn't closed when clicking " |
| + mouseButtonToString(closeButton) + " outside (triggerMode: " |
| + triggerModeToString(pieMenu.triggerMode) + ", openButton: " |
| + mouseButtonToString(openButton) + ")"); |
| break; |
| case TriggerMode.TriggerOnPress: |
| mousePress(root, 0, 0, closeButton); |
| tryCompare(currentIndexSignalSpy, "count", 0); |
| compare(pieMenu.visible, false, "Menu isn't closed when pressing " |
| + mouseButtonToString(closeButton) + " outside (triggerMode: " |
| + triggerModeToString(pieMenu.triggerMode) + ", openButton: " |
| + mouseButtonToString(openButton) + ")"); |
| mouseRelease(root, 0, 0, closeButton); |
| tryCompare(currentIndexSignalSpy, "count", 0); |
| compare(pieMenu.visible, false, "Menu shouldn't be opened when releasing " |
| + mouseButtonToString(closeButton) + " outside (triggerMode: " |
| + triggerModeToString(pieMenu.triggerMode) + ", openButton: " |
| + mouseButtonToString(openButton) + ")"); |
| break; |
| case TriggerMode.TriggerOnRelease: |
| mouseRelease(root, 0, 0, closeButton); |
| tryCompare(currentIndexSignalSpy, "count", 0); |
| compare(pieMenu.visible, false, "Menu is closed when releasing " |
| + mouseButtonToString(closeButton) + " outside"); |
| break; |
| } |
| |
| // Make the menu visible again. |
| if (pieMenu.triggerMode !== TriggerMode.TriggerOnRelease) { |
| mouseClick(root, 0, 0, openButton); |
| } else { |
| mousePress(root, 0, 0, openButton); |
| } |
| tryCompare(pieMenu, "visible", true); |
| |
| switch (pieMenu.triggerMode) { |
| case TriggerMode.TriggerOnClick: |
| // Click on a section of the menu (index 1); it should trigger the item and then close the menu. |
| mouseClick(root, pieMenu.x + pieMenu.width / 2, pieMenu.y + pieMenu.height / 4, closeButton); |
| // The current index changes once when the item is selected (1) and once when the menu closes (-1). |
| tryCompare(currentIndexSignalSpy, "count", 2); |
| compare(actionSignalSpy.count, 1); |
| compare(actionSignalSpy.signalArguments[0][0], 1); |
| compare(pieMenu.currentIndex, -1); |
| compare(pieMenu.visible, false); |
| break; |
| case TriggerMode.TriggerOnPress: |
| // Press on a section of the menu (index 1); it should trigger the item and then close the menu. |
| mousePress(root, pieMenu.x + pieMenu.width / 2, pieMenu.y + pieMenu.height / 4, closeButton); |
| // The current index changes once when the item is selected (1) and once when the menu closes (-1). |
| tryCompare(currentIndexSignalSpy, "count", 2); |
| compare(actionSignalSpy.count, 1); |
| compare(actionSignalSpy.signalArguments[0][0], 1); |
| compare(pieMenu.currentIndex, -1); |
| compare(pieMenu.visible, false); |
| |
| mouseRelease(root, pieMenu.x + pieMenu.width / 2, pieMenu.y + pieMenu.height / 4, closeButton); |
| // None of these should change after releasing. |
| tryCompare(currentIndexSignalSpy, "count", 2); |
| compare(actionSignalSpy.count, 1); |
| compare(pieMenu.currentIndex, -1); |
| compare(pieMenu.visible, false); |
| break; |
| case TriggerMode.TriggerOnRelease: |
| // Click/press on a section of the menu (index 1); it should trigger the item and then close the menu. |
| mouseRelease(root, pieMenu.x + pieMenu.width / 2, pieMenu.y + pieMenu.height / 4, closeButton); |
| // The current index changes once when the item is selected (1) and once when the menu closes (-1). |
| tryCompare(currentIndexSignalSpy, "count", 2); |
| compare(actionSignalSpy.count, 1); |
| compare(actionSignalSpy.signalArguments[0][0], 1); |
| compare(pieMenu.currentIndex, -1); |
| compare(pieMenu.visible, false); |
| } |
| |
| currentIndexSignalSpy.clear(); |
| actionSignalSpy.clear(); |
| } |
| } |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function test_selectionAngle_data() { |
| var data = []; |
| |
| var dataRow = {}; |
| dataRow.startAngle = -90; |
| dataRow.endAngle = 90; |
| dataRow.mouseX = 1; |
| dataRow.mouseY = 1; |
| dataRow.expectedAngle = -Math.PI / 4; |
| dataRow.expectedCurrentIndex = -1; |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", top left"; |
| data.push(dataRow); |
| |
| dataRow = {}; |
| dataRow.startAngle = -90; |
| dataRow.endAngle = 90; |
| dataRow.mouseX = menuWidth - 1; |
| dataRow.mouseY = menuHeight - 1; |
| dataRow.expectedAngle = Math.PI * 0.75; |
| dataRow.expectedCurrentIndex = -1; |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", bottom right"; |
| data.push(dataRow); |
| |
| dataRow = {}; |
| dataRow.startAngle = -90; |
| dataRow.endAngle = -270; |
| dataRow.mouseX = menuWidth / 2 - 1; |
| dataRow.mouseY = menuHeight * 0.75; |
| dataRow.expectedAngle = -3.1215953196166426; |
| dataRow.expectedCurrentIndex = 1; |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", bottom left edge"; |
| data.push(dataRow); |
| |
| dataRow = {}; |
| dataRow.startAngle = -90; |
| dataRow.endAngle = -270; |
| dataRow.mouseX = menuWidth / 2 + 1; |
| dataRow.mouseY = menuHeight * 0.75; |
| dataRow.expectedAngle = 3.1215953196166426; |
| dataRow.expectedCurrentIndex = 1; |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", bottom right edge"; |
| data.push(dataRow); |
| |
| dataRow = {}; |
| dataRow.startAngle = 0; |
| dataRow.endAngle = 190; |
| dataRow.mouseX = menuWidth / 2 - 1; |
| dataRow.mouseY = menuHeight * 0.75; |
| dataRow.expectedAngle = -3.1215953196166426; |
| dataRow.expectedCurrentIndex = 2; |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", bottom left edge"; |
| data.push(dataRow); |
| |
| dataRow = {}; |
| dataRow.startAngle = 0; |
| dataRow.endAngle = -90; |
| dataRow.mouseX = menuWidth / 4; |
| dataRow.mouseY = menuHeight / 2 - 1; |
| dataRow.expectedAngle = -1.550798992821746; |
| dataRow.expectedCurrentIndex = 2; |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", section 2"; |
| data.push(dataRow); |
| |
| dataRow = {}; |
| dataRow.startAngle = 0; |
| dataRow.endAngle = -90; |
| dataRow.mouseX = menuWidth / 4; |
| dataRow.mouseY = menuHeight / 4; |
| dataRow.expectedAngle = -0.7853981633974483; |
| dataRow.expectedCurrentIndex = 1; |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", section 1"; |
| data.push(dataRow); |
| |
| dataRow = {}; |
| dataRow.startAngle = 0; |
| dataRow.endAngle = -90; |
| dataRow.mouseX = menuWidth / 2 - 1; |
| dataRow.mouseY = menuHeight / 4; |
| dataRow.expectedAngle = -0.01999733397315053; |
| dataRow.expectedCurrentIndex = 0; |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", section 0"; |
| data.push(dataRow); |
| |
| dataRow = {}; |
| dataRow.startAngle = -190; |
| dataRow.endAngle = -90; |
| dataRow.mouseX = menuWidth / 2 + 1; |
| dataRow.mouseY = menuHeight * 0.75; |
| dataRow.expectedAngle = 3.1215953196166426; |
| dataRow.expectedCurrentIndex = 0; |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", bottom right edge"; |
| data.push(dataRow); |
| |
| dataRow = {}; |
| dataRow.startAngle = -90; |
| dataRow.endAngle = -190; |
| dataRow.mouseX = menuWidth / 2 + 1; |
| dataRow.mouseY = menuHeight * 0.75; |
| dataRow.expectedAngle = 3.1215953196166426; |
| dataRow.expectedCurrentIndex = 2; |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", bottom right edge"; |
| data.push(dataRow); |
| |
| return data; |
| } |
| |
| function test_selectionAngle(data) { |
| if (Settings.hasTouchScreen) |
| skip("Fails with touch screens"); |
| var pieMenuComponent = Qt.createComponent("PieMenu3Items.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var mouseArea = root.mouseArea; |
| var pieMenu = root.pieMenu; |
| |
| compare(pieMenu.selectionAngle, 0); |
| |
| pieMenu.__style.startAngle = data.startAngle; |
| pieMenu.__style.endAngle = data.endAngle; |
| |
| waitForRendering(root); |
| root.forceActiveFocus(); |
| // Don't allow bounds snapping by always opening within bounds. |
| mouseClick(root, menuWidth / 2, menuHeight / 2); |
| tryCompare(pieMenu, "visible", true); |
| |
| mouseMove(root, data.mouseX, data.mouseY); |
| compare(pieMenu.selectionAngle, data.expectedAngle); |
| compare(pieMenu.currentIndex, data.expectedCurrentIndex); |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function test_sectionAngles_data() { |
| var data = []; |
| var angleOrigin = 90; |
| |
| var dataRow = {}; |
| dataRow.startAngle = -90; |
| dataRow.endAngle = 90; |
| dataRow.section = 0; |
| dataRow.expectedSectionSize = MathUtils.degToRadOffset(60 + angleOrigin); |
| dataRow.expectedSectionStartAngle = MathUtils.degToRadOffset(-90); |
| dataRow.expectedSectionCenterAngle = MathUtils.degToRadOffset(-60); |
| dataRow.expectedSectionEndAngle = MathUtils.degToRadOffset(-30); |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", section=" + dataRow.section; |
| data.push(dataRow); |
| |
| dataRow = {}; |
| dataRow.startAngle = 270; |
| dataRow.endAngle = 90; |
| dataRow.section = 0; |
| dataRow.expectedSectionSize = MathUtils.degToRadOffset(-60 + angleOrigin); |
| dataRow.expectedSectionStartAngle = MathUtils.degToRadOffset(270); |
| dataRow.expectedSectionCenterAngle = MathUtils.degToRadOffset(240); |
| dataRow.expectedSectionEndAngle = MathUtils.degToRadOffset(210); |
| dataRow.tag = "startAngle=" + dataRow.startAngle + ", endAngle=" + dataRow.endAngle + ", section=" + dataRow.section; |
| data.push(dataRow); |
| |
| return data; |
| } |
| |
| function test_sectionAngles(data) { |
| var pieMenuComponent = Qt.createComponent("PieMenu3Items.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var pieMenu = root.pieMenu; |
| |
| pieMenu.__style.startAngle = data.startAngle; |
| pieMenu.__style.endAngle = data.endAngle; |
| compare(pieMenu.__protectedScope.sectionSize, data.expectedSectionSize); |
| compare(pieMenu.__protectedScope.sectionStartAngle(data.section), data.expectedSectionStartAngle); |
| compare(pieMenu.__protectedScope.sectionCenterAngle(data.section), data.expectedSectionCenterAngle); |
| compare(pieMenu.__protectedScope.sectionEndAngle(data.section), data.expectedSectionEndAngle); |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function test_bounds_data() { |
| return [ |
| { tag: "noSnapCenter", mouseX: container.width / 2, mouseY: container.height / 2, |
| expectedX: container.width / 2 - 100, expectedY: container.height / 2 - 100 }, |
| { tag: "noSnapNearLeft", mouseX: 100, mouseY: container.height / 2, |
| expectedX: 0, expectedY: container.height / 2 - 100 }, |
| { tag: "noSnapNearRight", mouseX: container.width - 100, mouseY: container.height / 2, |
| expectedX: container.width - menuWidth, expectedY: container.height / 2 - 100 }, |
| { tag: "noSnapNearTop", mouseX: container.width / 2, mouseY: 100, |
| expectedX: container.width / 2 - 100, expectedY: 0 }, |
| { tag: "noSnapNearBottom", mouseX: container.width / 2, mouseY: container.height - 100, |
| expectedX: container.width / 2 - 100, expectedY: container.height - menuHeight }, |
| { tag: "noSnapNearTopLeft", mouseX: 100, mouseY: 100, |
| expectedX: 0, expectedY: 0 }, |
| { tag: "noSnapNearTopRight", mouseX: container.width - 100, mouseY: 100, |
| expectedX: container.width - menuWidth, expectedY: 0 }, |
| { tag: "noSnapNearBottomRight", mouseX: container.width - 100, mouseY: container.height - 100, |
| expectedX: container.width - menuWidth, expectedY: container.height - menuHeight }, |
| { tag: "noSnapNearBottomLeft", mouseX: 100, mouseY: container.height - 100, |
| expectedX: 0, expectedY: container.height - menuHeight }, |
| { tag: "leftEdge", mouseX: 10, mouseY: container.height / 2, |
| expectedX: 0, expectedY: container.height / 2 - 100 }, |
| { tag: "rightEdge", mouseX: container.width - 10, mouseY: container.height / 2, |
| expectedX: container.width - menuHeight, expectedY: container.height / 2 - 100 }, |
| { tag: "topEdge", mouseX: container.width / 2, mouseY: 10, |
| expectedX: container.width / 2 - 100, expectedY: 0 }, |
| // The default start and end angles mean that the bottom edge won't snap. |
| { tag: "bottomEdge", mouseX: container.width / 2, mouseY: container.height - 10, |
| expectedX: container.width / 2 - 100, expectedY: container.height - 100 - 10 }, |
| { tag: "topLeftCorner", mouseX: 10, mouseY: 10, |
| expectedX: 0, expectedY: 0 }, |
| { tag: "topRightCorner", mouseX: container.width - 10, mouseY: 10, |
| expectedX: container.width - menuHeight, expectedY: 0 }, |
| { tag: "bottomRightCorner", mouseX: container.width - 10, mouseY: container.height - 10, |
| expectedX: container.width - menuHeight, expectedY: container.height - 100 - 10 }, |
| { tag: "bottomLeftCorner", mouseX: 10, mouseY: container.height - 10, |
| expectedX: 0, expectedY: container.height - 100 - 10 } |
| ] |
| } |
| |
| function test_bounds(data) { |
| var pieMenuComponent = Qt.createComponent("PieMenu3Items.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var mouseArea = root.mouseArea; |
| var pieMenu = root.pieMenu; |
| |
| var rootParent = pieMenu; |
| while (rootParent.parent) { |
| rootParent = rootParent.parent; |
| } |
| // Necessary due to QTBUG-36938 |
| rootParent.width = 400; |
| rootParent.height = 400; |
| |
| var originalStartAngle = pieMenu.__style.startAngle; |
| var originalEndAngle = pieMenu.__style.endAngle; |
| |
| mouseClick(root, data.mouseX, data.mouseY); |
| tryCompare(pieMenu, "visible", true); |
| |
| compare(pieMenu.x, data.expectedX); |
| compare(pieMenu.y, data.expectedY); |
| |
| // Angles shouldn't change. |
| compare(pieMenu.__style.startAngle, originalStartAngle); |
| compare(pieMenu.__style.endAngle, originalEndAngle); |
| |
| // Cancel the menu. Even if it's at the top left, this will land on the cancel area. |
| mouseClick(root, pieMenu.x + pieMenu.width / 2, pieMenu.y + pieMenu.height / 2); |
| compare(pieMenu.visible, false); |
| |
| // Angles shouldn't change. |
| compare(pieMenu.__style.startAngle, originalStartAngle); |
| compare(pieMenu.__style.endAngle, originalEndAngle); |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function test_hideItem_data() { |
| return [ |
| { tag: "hideFirst", indexVisibility: [false, true, true], expectedIndexHits: [0, 1, 1], expectedText: ["item1", "item1", "item2"] }, |
| { tag: "hideSecond", indexVisibility: [true, false, true], expectedIndexHits: [0, 1, 1], expectedText: ["item0", "item0", "item2"] }, |
| { tag: "hideThird", indexVisibility: [true, true, false], expectedIndexHits: [0, 1, 1], expectedText: ["item0", "item0", "item1"] }, |
| ]; |
| } |
| |
| function test_hideItem(data) { |
| if (Settings.hasTouchScreen) |
| skip("Fails with touch screens"); |
| var pieMenuComponent = Qt.createComponent("PieMenu3Items.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var mouseArea = root.mouseArea; |
| var pieMenu = root.pieMenu; |
| |
| var originalStartAngle = pieMenu.__style.startAngle; |
| var originalEndAngle = pieMenu.__style.endAngle; |
| |
| // Store the positions at which we should click before we remove any items. |
| var mousePositions = [Qt.point(40, 70), Qt.point(90, 30), Qt.point(160, 70)]; |
| |
| while (pieMenu.menuItems.length > 0) { |
| pieMenu.removeItem(pieMenu.menuItems[pieMenu.menuItems.length - 1]); |
| } |
| |
| for (var i = 0; i < data.indexVisibility.length; ++i) { |
| var item = pieMenu.addItem("item" + i); |
| item.triggered.connect(function (){ root.actionTriggered(data.expectedIndexHits[i]) }) |
| item.visible = data.indexVisibility[i]; |
| } |
| |
| // Angles shouldn't change. |
| compare(pieMenu.__style.startAngle, originalStartAngle); |
| compare(pieMenu.__style.endAngle, originalEndAngle); |
| |
| for (i = 0; i < data.indexVisibility.length; ++i) { |
| actionSignalSpy.signalName = "actionTriggered"; |
| actionSignalSpy.target = root; |
| |
| compare(pieMenu.visible, false); |
| |
| // Make the menu visible. |
| mouseClick(root, 100, 100, Qt.LeftButton); |
| tryCompare(pieMenu, "visible", true); |
| |
| var pos = mousePositions[i]; |
| |
| mouseMove(root, pos.x, pos.y); |
| // Not all styles have titles. |
| if (pieMenu.__style.title) |
| tryCompare(pieMenu.__panel.titleItem, "text", data.expectedText[i]); |
| |
| mouseClick(root, pos.x, pos.y, Qt.LeftButton); |
| |
| tryCompare(pieMenu, "visible", false); |
| compare(actionSignalSpy.count, 1); |
| compare(actionSignalSpy.signalArguments[0][0], data.expectedIndexHits[i]); |
| |
| actionSignalSpy.clear(); |
| } |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function test_addItem() { |
| var pieMenu = createTemporaryObject(pieMenuComponent, container); |
| verify(pieMenu); |
| compare(pieMenu.menuItems.length, 0); |
| |
| pieMenu.addItem("Action 1"); |
| compare(pieMenu.menuItems.length, 1); |
| } |
| |
| function test_insertItem() { |
| var pieMenu = createTemporaryObject(pieMenuComponent, container); |
| verify(pieMenu); |
| compare(pieMenu.menuItems.length, 0); |
| |
| pieMenu.insertItem(0, "Action 1"); |
| compare(pieMenu.menuItems.length, 1); |
| compare(pieMenu.menuItems[0].text, "Action 1"); |
| |
| pieMenu.insertItem(1, "Action 2"); |
| compare(pieMenu.menuItems.length, 2); |
| compare(pieMenu.menuItems[0].text, "Action 1"); |
| compare(pieMenu.menuItems[1].text, "Action 2"); |
| } |
| |
| function test_removeItem() { |
| var pieMenuComponent = Qt.createComponent("PieMenu3Items.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var pieMenu = root.pieMenu; |
| |
| var originalLength = pieMenu.menuItems.length; |
| for (var i = 0; i < originalLength; ++i) { |
| pieMenu.removeItem(pieMenu.menuItems[pieMenu.menuItems.length - 1]); |
| compare(pieMenu.menuItems.length, originalLength - (i + 1)); |
| } |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function debugMousePosition(pieMenu, mouseX, mouseY, positionText) { |
| var rectItem = createTemporaryQmlObject("import QtQuick 2.0; Rectangle { width: 10; height: 10; radius: 5; color: 'red' }", pieMenu); |
| rectItem.x = mouseX - rectItem.width / 2; |
| rectItem.y = mouseY - rectItem.height / 2; |
| |
| var textItem = createTemporaryQmlObject("import QtQuick 2.0; Text {}", rectItem); |
| textItem.text = positionText; |
| textItem.font.pixelSize = 8; |
| textItem.anchors.centerIn = textItem.parent; |
| } |
| |
| function test_selectionItemOnMouseMove_QTRD3024() { |
| if (Settings.hasTouchScreen) |
| skip("Fails with touch screens"); |
| // Check when an item is hovered by the mouse, it gets made current |
| // as expected and the current item is cleared when the mouse moves outside the menu |
| var pieMenuComponent = Qt.createComponent("PieMenu3Items.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var mouseArea = root.mouseArea; |
| var pieMenu = root.pieMenu; |
| |
| // Make the menu visible at (0,0) |
| waitForRendering(root); |
| root.forceActiveFocus(); |
| mouseClick(root, 0, 0); |
| tryCompare(pieMenu, "visible", true); |
| |
| // Move the mouse over the menu |
| mouseMove(root, 0, 0); |
| compare(pieMenu.currentIndex, -1); |
| |
| // We would use a data function for this, but we need access to properties |
| // of the style that change with each style. |
| var data = []; |
| var xCenter = pieMenu.width / 2; |
| var yCenter = pieMenu.height / 2; |
| var startAngleFunction = pieMenu.__protectedScope.sectionStartAngle; |
| var centerAngleFunction = pieMenu.__protectedScope.sectionCenterAngle; |
| var endAngleFunction = pieMenu.__protectedScope.sectionEndAngle; |
| |
| var pos = MathUtils.centerAlongCircle(xCenter, yCenter, 0, 0, centerAngleFunction(0), 90) |
| data.push({ name: "inside", mouseX: pos.x, mouseY: pos.y, expectedCurrentIndex: 0 }); |
| |
| pos = MathUtils.centerAlongCircle(xCenter, yCenter, 0, 0, startAngleFunction(0) + MathUtils.degToRad(1), pieMenu.__style.cancelRadius + 10); |
| data.push({ name: "bottom", mouseX: pos.x, mouseY: pos.y, expectedCurrentIndex: 0 }); |
| |
| pos = MathUtils.centerAlongCircle(xCenter, yCenter, 0, 0, centerAngleFunction(0), pieMenu.__style.cancelRadius + 10); |
| data.push({ name: "outside", mouseX: pos.x, mouseY: pos.y, expectedCurrentIndex: 0 }); |
| |
| pos = MathUtils.centerAlongCircle(xCenter, yCenter, 0, 0, endAngleFunction(0) - MathUtils.degToRad(1), pieMenu.__style.radius - 1); |
| data.push({ name: "close to second", mouseX: pos.x, mouseY: pos.y, expectedCurrentIndex: 0 }); |
| |
| pos = MathUtils.centerAlongCircle(xCenter, yCenter, 0, 0, centerAngleFunction(1), pieMenu.__style.radius - 1); |
| data.push({ name: "outside", mouseX: pos.x, mouseY: pos.y, expectedCurrentIndex: 1 }); |
| |
| pos = MathUtils.centerAlongCircle(xCenter, yCenter, 0, 0, centerAngleFunction(1) - MathUtils.degToRad(10), |
| pieMenu.__style.cancelRadius + (pieMenu.__style.radius - pieMenu.__style.cancelRadius) / 2); |
| data.push({ name: "inside", mouseX: pos.x, mouseY: pos.y, expectedCurrentIndex: 1 }); |
| |
| pos = MathUtils.centerAlongCircle(xCenter, yCenter, 0, 0, startAngleFunction(1) + MathUtils.degToRad(1), |
| pieMenu.__style.radius - 1); |
| data.push({ name: "close to first", mouseX: pos.x, mouseY: pos.y, expectedCurrentIndex: 1 }); |
| |
| pos = MathUtils.centerAlongCircle(xCenter, yCenter, 0, 0, centerAngleFunction(1), pieMenu.__style.cancelRadius + 10); |
| data.push({ name: "low center", mouseX: 100, mouseY: 50, expectedCurrentIndex: 1 }); |
| |
| for (var i = 0; i < data.length; ++i) { |
| var mouseX = data[i].mouseX; |
| var mouseY = data[i].mouseY; |
| var expectedCurrentIndex = data[i].expectedCurrentIndex; |
| |
| // Illustrates the positions. |
| // debugMousePosition(pieMenu, mouseX, mouseY, i); |
| // wait(1000) |
| |
| mouseMove(root, mouseX, mouseY); |
| compare(pieMenu.currentIndex, expectedCurrentIndex, data[i].name + ": current index should be " |
| + expectedCurrentIndex + " when mouse is at " + mouseX + ", " + mouseY); |
| } |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function test_QTRD3027() { |
| // Check that an item's selection is cleared when the mouse moves outside |
| // its boundaries without changing the selectionAngle |
| if (Settings.hasTouchScreen) |
| skip("Fails with touch screens"); |
| var pieMenuComponent = Qt.createComponent("PieMenu3Items.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var mouseArea = root.mouseArea; |
| var pieMenu = root.pieMenu; |
| |
| // Make the menu visible at (0,0) |
| root.forceActiveFocus(); |
| mouseClick(root, 0, 0); |
| tryCompare(pieMenu, "visible", true); |
| |
| // Move the mouse over the menu |
| mouseMove(root, 0, 0) |
| compare(pieMenu.currentIndex, -1) |
| // Move over middle item |
| mouseMove(root, 100, 50) |
| compare(pieMenu.currentIndex, 1) |
| selectedAngleChangedSpy.signalName = "selectionAngleChanged" |
| selectedAngleChangedSpy.target = pieMenu; |
| // Move outside the middle item without changing angle |
| mouseMove(root, 100, 98) |
| compare(pieMenu.currentIndex, -1) |
| compare(selectedAngleChangedSpy.count, 0) |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function test_rotatedBoundingItem() { |
| if (Settings.hasTouchScreen) |
| skip("Fails with touch screens"); |
| var pieMenuComponent = Qt.createComponent("PieMenuRotatedBoundingItem.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var mouseArea = root.mouseArea; |
| var pieMenu = root.pieMenu; |
| |
| mouseClick(root, root.width / 2, root.height / 2, Qt.RightButton); |
| tryCompare(pieMenu, "visible", true); |
| |
| mouseMove(root, 230, 145); |
| // Not all styles have titles. |
| if (pieMenu.__style.title) |
| tryCompare(pieMenu.__panel.titleItem, "text", "Action 1"); |
| |
| actionSignalSpy.signalName = "actionTriggered"; |
| actionSignalSpy.target = root; |
| mouseClick(root, 230, 145); |
| compare(actionSignalSpy.count, 1); |
| compare(actionSignalSpy.signalArguments[0][0], 0); |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function test_boundingItem() { |
| var oldContainerWidth = container.width; |
| var oldContainerHeight = container.height; |
| container.width = 560; |
| container.height = 560; |
| |
| // Tests boundingItem when there are nested margins. |
| var pieMenuComponent = Qt.createComponent("PieMenuBoundingItem.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var mouseArea = root.mouseArea; |
| var pieMenu = root.pieMenu; |
| |
| var mouseAreaAbsolutePos = mouseArea.mapToItem(root, 0, 0); |
| mouseClick(root, mouseAreaAbsolutePos.x + mouseArea.width / 2, mouseAreaAbsolutePos.y, Qt.RightButton); |
| compare(pieMenu.visible, true); |
| compare(pieMenu.y, -root.margins); |
| |
| mouseClick(root, 0, 0); |
| compare(pieMenu.visible, false); |
| |
| var mouseAreaCenterAbsolutePos = mouseArea.mapToItem(root, mouseArea.width / 2, mouseArea.height / 2); |
| mouseClick(root, mouseAreaCenterAbsolutePos.x, mouseAreaCenterAbsolutePos.y, Qt.RightButton); |
| compare(pieMenu.visible, true); |
| compare(pieMenu.mapToItem(root, 0, 0).x, mouseAreaCenterAbsolutePos.x - pieMenu.width / 2); |
| compare(pieMenu.mapToItem(root, 0, 0).y, mouseAreaCenterAbsolutePos.y - pieMenu.height / 2); |
| |
| container.width = oldContainerWidth; |
| container.height = oldContainerHeight; |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function test_longPressTriggerOnClick() { |
| // Tests that a menu that is opened on press or long press does not |
| // get closed by a release event when the triggerMode requires a |
| // press before the release (TriggerOnClick). |
| var pieMenuComponent = Qt.createComponent("PieMenu3ItemsLongPress.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var pieMenu = root.pieMenu; |
| |
| mousePress(root, 0, 0, Qt.LeftButton); |
| tryCompare(pieMenu, "visible", true); |
| compare(pieMenu.__mouseThief.receivedPressEvent, false); |
| compare(pieMenu.__protectedScope.pressedIndex, -1); |
| |
| mouseRelease(root, 0, 0, Qt.LeftButton); |
| compare(pieMenu.visible, true); |
| compare(pieMenu.__mouseThief.receivedPressEvent, false); |
| compare(pieMenu.__protectedScope.pressedIndex, -1); |
| |
| mousePress(root, 0, 0, Qt.LeftButton); |
| compare(pieMenu.visible, true); |
| compare(pieMenu.__mouseThief.receivedPressEvent, true); |
| compare(pieMenu.__protectedScope.pressedIndex, -1); |
| |
| mouseRelease(root, 0, 0, Qt.LeftButton); |
| compare(pieMenu.visible, false); |
| compare(pieMenu.__mouseThief.receivedPressEvent, false); |
| compare(pieMenu.__protectedScope.pressedIndex, -1); |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function test_keepMenuOpenWhenTriggered() { |
| // This functionality is used in the flat example. |
| var pieMenuComponent = Qt.createComponent("PieMenu3ItemsKeepOpen.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var pieMenu = root.pieMenu; |
| actionSignalSpy.signalName = "actionTriggered"; |
| actionSignalSpy.target = root; |
| |
| mouseClick(root, 0, 0, Qt.LeftButton); |
| tryCompare(pieMenu, "visible", true); |
| |
| mouseClick(root, pieMenu.x + pieMenu.width / 4, pieMenu.y + pieMenu.height / 4, Qt.LeftButton); |
| tryCompare(pieMenu, "visible", true); |
| compare(actionSignalSpy.count, 1); |
| compare(actionSignalSpy.signalArguments[0][0], 0); |
| |
| actionSignalSpy.clear(); |
| mouseClick(root, pieMenu.x + pieMenu.width / 2, pieMenu.y + pieMenu.height / 4, Qt.LeftButton); |
| tryCompare(pieMenu, "visible", true); |
| compare(actionSignalSpy.count, 1); |
| compare(actionSignalSpy.signalArguments[0][0], 1); |
| |
| actionSignalSpy.clear(); |
| mouseClick(root, pieMenu.x + pieMenu.width * 0.75, pieMenu.y + pieMenu.height / 4, Qt.LeftButton); |
| tryCompare(pieMenu, "visible", true); |
| compare(actionSignalSpy.count, 1); |
| compare(actionSignalSpy.signalArguments[0][0], 2); |
| |
| pieMenuComponent.destroy() |
| } |
| |
| function test_pressedIndex() { |
| var pieMenuComponent = Qt.createComponent("PieMenu3Items.qml"); |
| tryCompare(pieMenuComponent, "status", Component.Ready); |
| var root = createTemporaryObject(pieMenuComponent, container); |
| var pieMenu = root.pieMenu; |
| actionSignalSpy.signalName = "actionTriggered"; |
| actionSignalSpy.target = root; |
| |
| mouseClick(root, 0, 0, Qt.LeftButton); |
| tryCompare(pieMenu, "visible", true); |
| compare(pieMenu.__protectedScope.pressedIndex, -1); |
| |
| mousePress(root, pieMenu.x + pieMenu.width / 4, pieMenu.y + pieMenu.height / 4, Qt.LeftButton); |
| tryCompare(pieMenu, "visible", true); |
| compare(pieMenu.__protectedScope.pressedIndex, 0); |
| |
| mouseRelease(root, pieMenu.x + pieMenu.width / 4, pieMenu.y + pieMenu.height / 4, Qt.LeftButton); |
| tryCompare(pieMenu, "visible", false); |
| compare(actionSignalSpy.count, 1); |
| compare(actionSignalSpy.signalArguments[0][0], 0); |
| compare(pieMenu.__protectedScope.pressedIndex, -1); |
| |
| pieMenuComponent.destroy() |
| } |
| } |
| } |