Merge lp:~nick-dedekind/unity8/menu.width.fix into lp:unity8

Proposed by Nick Dedekind
Status: Merged
Approved by: Albert Astals Cid
Approved revision: 2771
Merged at revision: 2784
Proposed branch: lp:~nick-dedekind/unity8/menu.width.fix
Merge into: lp:unity8
Diff against target: 806 lines (+352/-194)
4 files modified
qml/ApplicationMenus/MenuPopup.qml (+178/-139)
tests/qmltests/ApplicationMenuDataLoader.qml (+13/-5)
tests/qmltests/ApplicationMenus/tst_MenuBar.qml (+5/-5)
tests/qmltests/ApplicationMenus/tst_MenuPopup.qml (+156/-45)
To merge this branch: bzr merge lp:~nick-dedekind/unity8/menu.width.fix
Reviewer Review Type Date Requested Status
Albert Astals Cid (community) Approve
Unity8 CI Bot continuous-integration Approve
Review via email: mp+315021@code.launchpad.net

Commit message

Fixed menu layout width calculations.

Description of the change

 * Are there any related MPs required for this MP to build/function as expected? Please list.
No

 * Did you perform an exploratory manual test run of your code change and any related functionality?
Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

 * If you changed the UI, has there been a design review?
N/A

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:2771
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2944/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3841
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/2234
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/2234
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3869
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3712
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3712/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3712
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3712/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3712
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3712/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3712
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3712/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3712
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3712/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3712
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3712/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2944/rebuild

review: Approve (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Yes

 * Did CI run pass? If not, please explain why.
Yes

review: Approve
2772. By Nick Dedekind

color fixes

2773. By Nick Dedekind

Auto scroll. Maximum height to bottom of screen

2774. By Nick Dedekind

Added overflow button

2775. By Nick Dedekind

enabled only when item enabled

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'qml/ApplicationMenus/MenuPopup.qml'
--- qml/ApplicationMenus/MenuPopup.qml 2017-01-09 15:26:05 +0000
+++ qml/ApplicationMenus/MenuPopup.qml 2017-01-18 14:44:04 +0000
@@ -26,19 +26,7 @@
26 objectName: "menu"26 objectName: "menu"
27 backgroundColor: theme.palette.normal.overlay27 backgroundColor: theme.palette.normal.overlay
2828
29 property alias unityMenuModel: listView.model29 property alias unityMenuModel: repeater.model
30
31 readonly property real __ajustedMinimumHeight: {
32 if (listView.contentHeight > __minimumHeight) {
33 return units.gu(30);
34 }
35 return Math.max(listView.contentHeight, units.gu(2));
36 }
37
38 readonly property real __minimumWidth: units.gu(20)
39 readonly property real __minimumHeight: units.gu(30)
40 readonly property real __maximumWidth: Screen.width * 0.7
41 readonly property real __maximumHeight: Screen.height * 0.7
4230
43 function show() {31 function show() {
44 visible = true;32 visible = true;
@@ -63,18 +51,23 @@
63 d.dismissAll();51 d.dismissAll();
64 }52 }
6553
66 implicitWidth: container.width54 implicitWidth: focusScope.width
67 implicitHeight: MathUtils.clamp(listView.contentHeight, __ajustedMinimumHeight, __maximumHeight)55 implicitHeight: focusScope.height
6856
69 MenuNavigator {57 MenuNavigator {
70 id: d58 id: d
71 objectName: "d"59 objectName: "d"
72 itemView: listView60 itemView: repeater
7361
74 property Item currentItem: null62 property Item currentItem: null
75 property Item hoveredItem: null63 property Item hoveredItem: null
76 readonly property int currentIndex: currentItem ? currentItem.__ownIndex : -164 readonly property int currentIndex: currentItem ? currentItem.__ownIndex : -1
7765
66 property real __minimumWidth: units.gu(20)
67 property real __maximumWidth: Screen.width * 0.7
68 property real __minimumHeight: units.gu(2)
69 property real __maximumHeight: Screen.height * 0.7
70
78 signal dismissAll()71 signal dismissAll()
7972
80 onCurrentItemChanged: {73 onCurrentItemChanged: {
@@ -86,13 +79,26 @@
86 }79 }
8780
88 onSelect: {81 onSelect: {
89 currentItem = listView.itemAt(index);82 currentItem = repeater.itemAt(index);
83 if (currentItem) {
84 if (currentItem.y < listView.contentY) {
85 listView.contentY = currentItem.y;
86 } else if (currentItem.y + currentItem.height > listView.contentY + listView.height) {
87 listView.contentY = currentItem.y + currentItem.height - listView.height;
88 }
89 }
90 }90 }
91 }91 }
9292
93 MouseArea {
94 // Eat events.
95 anchors.fill: parent
96 }
97
93 Item {98 Item {
94 id: focusScope99 id: focusScope
95 anchors.fill: parent100 width: container.width
101 height: container.height
96 focus: visible102 focus: visible
97103
98 Keys.onUpPressed: d.selectPrevious(d.currentIndex)104 Keys.onUpPressed: d.selectPrevious(d.currentIndex)
@@ -108,17 +114,17 @@
108 id: container114 id: container
109 objectName: "container"115 objectName: "container"
110116
111 width: listView.contentWidth117 height: MathUtils.clamp(listView.contentHeight, d.__minimumHeight, d.__maximumHeight)
112 height: parent.height118 width: menuColumn.width
113 spacing: 0119 spacing: 0
114120
115 // FIXME use ListView.header - tried but was flaky with positionViewAtIndex.121 // Header - scroll up
116 Item {122 Item {
117 Layout.fillWidth: true;123 Layout.fillWidth: true
118 Layout.maximumHeight: units.gu(3)124 height: units.gu(3)
119 Layout.minimumHeight: units.gu(3)
120 visible: listView.contentHeight > root.height125 visible: listView.contentHeight > root.height
121 enabled: !listView.atYBeginning126 enabled: !listView.atYBeginning
127 z: 1
122128
123 Rectangle {129 Rectangle {
124 color: enabled ? theme.palette.normal.overlayText :130 color: enabled ? theme.palette.normal.overlayText :
@@ -143,47 +149,35 @@
143 MouseArea {149 MouseArea {
144 anchors.fill: parent150 anchors.fill: parent
145 onPressed: {151 onPressed: {
146 var index = listView.indexAt(0, listView.contentY);152 var item = menuColumn.childAt(0, listView.contentY);
147 listView.positionViewAtIndex(index-1, ListView.Beginning);153 if (item) {
154 var previousItem = item;
155 do {
156 previousItem = repeater.itemAt(previousItem.__ownIndex-1);
157 if (!previousItem) {
158 listView.contentY = 0;
159 return;
160 }
161 } while (previousItem.__isSeparator);
162
163 listView.contentY = previousItem.y
164 }
148 }165 }
149 }166 }
150 }167 }
151168
152 ListView {169 // Menu Items
170 Flickable {
153 id: listView171 id: listView
154 objectName: "listView"172 clip: interactive
173
155 Layout.fillHeight: true174 Layout.fillHeight: true
156 Layout.fillWidth: true175 Layout.fillWidth: true
157 contentWidth: MathUtils.clamp(contentItem.childrenRect.width,176 contentHeight: menuColumn.height
158 __minimumWidth,177 interactive: height < contentHeight
159 __maximumWidth)
160
161 orientation: Qt.Vertical
162 interactive: contentHeight > height
163 clip: interactive
164 highlightFollowsCurrentItem: false
165
166 highlight: Rectangle {
167 color: "transparent"
168 border.width: units.dp(1)
169 border.color: UbuntuColors.orange
170 z: 1
171
172 width: listView.width
173 height: d.currentItem ? d.currentItem.height : 0
174 y: d.currentItem ? d.currentItem.y : 0
175 visible: d.currentItem
176 }
177
178 function itemAt(index) {
179 if (index > count || index < 0) return null;
180 currentIndex = index;
181 return currentItem;
182 }
183178
184 MouseArea {179 MouseArea {
185 id: menuMouseArea180 anchors.fill: parent
186 anchors.fill: listView
187 hoverEnabled: true181 hoverEnabled: true
188 propagateComposedEvents: true // propogate events so we send clicks to children.182 propagateComposedEvents: true // propogate events so we send clicks to children.
189 z: 1 // on top so we override any other hovers183 z: 1 // on top so we override any other hovers
@@ -195,7 +189,7 @@
195189
196 if (!d.hoveredItem || !d.currentItem ||190 if (!d.hoveredItem || !d.currentItem ||
197 !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {191 !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
198 d.hoveredItem = listView.itemAt(listView.indexAt(pos.x, pos.y));192 d.hoveredItem = menuColumn.childAt(pos.x, pos.y)
199 if (!d.hoveredItem || !d.hoveredItem.enabled)193 if (!d.hoveredItem || !d.hoveredItem.enabled)
200 return false;194 return false;
201 d.currentItem = d.hoveredItem;195 d.currentItem = d.hoveredItem;
@@ -216,89 +210,123 @@
216 }210 }
217 }211 }
218212
219 delegate: Loader {213 ColumnLayout {
220 id: loader214 id: menuColumn
221 objectName: root.objectName + "-item" + __ownIndex215 spacing: 0
222216
223 property int __ownIndex: index217 width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
224218
225 width: root.width219 Repeater {
226 enabled: model.isSeparator ? false : model.sensitive220 id: repeater
227221
228 sourceComponent: {222 Loader {
229 if (model.isSeparator) {223 id: loader
230 return separatorComponent;224 objectName: root.objectName + "-item" + __ownIndex
231 }225
232 return menuItemComponent;226 property int __ownIndex: index
233 }227 property bool __isSeparator: model.isSeparator
234228
235 property Item popup: null229 enabled: __isSeparator ? false : model.sensitive
236230
237 Component {231 sourceComponent: {
238 id: menuItemComponent232 if (model.isSeparator) {
239 MenuItem {233 return separatorComponent;
240 id: menuItem234 }
241 menuData: model235 return menuItemComponent;
242 objectName: loader.objectName + "-actionItem"236 }
243237
244 action.onTriggered: {238 property Item popup: null
245 d.currentItem = loader;239
246240 Layout.fillWidth: true
247 if (hasSubmenu) {241
248 if (!popup) {242 Component {
249 var model = root.unityMenuModel.submenu(__ownIndex);243 id: menuItemComponent
250 popup = submenuComponent.createObject(focusScope, {244 MenuItem {
251 objectName: loader.objectName + "-",245 id: menuItem
252 unityMenuModel: model,246 menuData: model
253 x: Qt.binding(function() { return root.width }),247 objectName: loader.objectName + "-actionItem"
254 y: Qt.binding(function() { return loader.y })248
255 });249 width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
256 } else if (popup) {250
257 popup.visible = true;251 action.onTriggered: {
258 }252 d.currentItem = loader;
259 popup.retreat.connect(function() {253
260 popup.destroy();254 if (hasSubmenu) {
261 popup = null;255 if (!popup) {
262 menuItem.forceActiveFocus();256 var model = root.unityMenuModel.submenu(__ownIndex);
263 })257 popup = submenuComponent.createObject(focusScope, {
264 } else {258 objectName: loader.objectName + "-",
265 root.unityMenuModel.activate(__ownIndex);259 unityMenuModel: model,
266 }260 x: Qt.binding(function() { return root.width }),
267 }261 y: Qt.binding(function() {
268262 var dummy = listView.contentY; // force a recalc on contentY change.
269 Connections {263 return mapToItem(container, 0, y).y;
270 target: d264 })
271 onCurrentIndexChanged: {265 });
272 if (popup && d.currentIndex != __ownIndex) {266 } else if (popup) {
273 popup.visible = false;267 popup.visible = true;
274 }268 }
275 }269 popup.retreat.connect(function() {
276 onDismissAll: {270 popup.destroy();
277 if (popup) {271 popup = null;
278 popup.destroy();272 menuItem.forceActiveFocus();
279 popup = null;273 })
280 }274 } else {
281 }275 root.unityMenuModel.activate(__ownIndex);
282 }276 }
283 }277 }
284 }278
285279 Connections {
286 Component {280 target: d
287 id: separatorComponent281 onCurrentIndexChanged: {
288 ListItems.ThinDivider {282 if (popup && d.currentIndex != __ownIndex) {
289 objectName: loader.objectName + "-separator"283 popup.visible = false;
290 }284 }
291 }285 }
292 }286 onDismissAll: {
293 } // ListView287 if (popup) {
294288 popup.destroy();
295 // FIXME use ListView.footer - tried but was flaky with positionViewAtIndex.289 popup = null;
290 }
291 }
292 }
293 }
294 }
295
296 Component {
297 id: separatorComponent
298 ListItems.ThinDivider {
299 objectName: loader.objectName + "-separator"
300 implicitHeight: units.dp(2)
301 }
302 }
303 }
304
305 }
306 }
307
308 // Highlight
309 Rectangle {
310 color: "transparent"
311 border.width: units.dp(1)
312 border.color: UbuntuColors.orange
313 z: 1
314
315 width: listView.width
316 height: d.currentItem ? d.currentItem.height : 0
317 y: d.currentItem ? d.currentItem.y : 0
318 visible: d.currentItem
319 }
320
321 } // Flickable
322
323 // Header - scroll down
296 Item {324 Item {
297 Layout.fillWidth: true;325 Layout.fillWidth: true
298 Layout.maximumHeight: units.gu(3)326 height: units.gu(3)
299 Layout.minimumHeight: units.gu(3)
300 visible: listView.contentHeight > root.height327 visible: listView.contentHeight > root.height
301 enabled: !listView.atYEnd328 enabled: !listView.atYEnd
329 z: 1
302330
303 Rectangle {331 Rectangle {
304 color: enabled ? theme.palette.normal.overlayText :332 color: enabled ? theme.palette.normal.overlayText :
@@ -323,8 +351,19 @@
323 MouseArea {351 MouseArea {
324 anchors.fill: parent352 anchors.fill: parent
325 onPressed: {353 onPressed: {
326 var index = listView.indexAt(0, listView.contentY);354 var item = menuColumn.childAt(0, listView.contentY + listView.height);
327 listView.positionViewAtIndex(index+1, ListView.Beginning);355 if (item) {
356 var nextItem = item;
357 do {
358 nextItem = repeater.itemAt(nextItem.__ownIndex+1);
359 if (!nextItem) {
360 listView.contentY = listView.contentHeight - listView.height;
361 return;
362 }
363 } while (nextItem.__isSeparator);
364
365 listView.contentY = nextItem.y - listView.height
366 }
328 }367 }
329 }368 }
330 }369 }
331370
=== modified file 'tests/qmltests/ApplicationMenuDataLoader.qml'
--- tests/qmltests/ApplicationMenuDataLoader.qml 2017-01-06 14:07:36 +0000
+++ tests/qmltests/ApplicationMenuDataLoader.qml 2017-01-18 14:44:04 +0000
@@ -10,6 +10,7 @@
1010
11 Connections {11 Connections {
12 id: sMgrHandler12 id: sMgrHandler
13 target: null
13 onSurfaceCreated: {14 onSurfaceCreated: {
14 var fakeMenuPath = "/" + surface.persistentId.replace(/\W+/g, "");15 var fakeMenuPath = "/" + surface.persistentId.replace(/\W+/g, "");
1516
@@ -25,21 +26,28 @@
25 var data = [];26 var data = [];
26 if (root === undefined) root = true;27 if (root === undefined) root = true;
2728
28 if (prefix === undefined) prefix = "menu"
29
30 for (var i = 0; i < length; i++) {29 for (var i = 0; i < length; i++) {
3130
31 var menuName = prefix;
32 if (menuName === undefined) {
33 var chars = Math.random() * 20;
34 menuName = "";
35 for (var x = 0; x < chars; x++) {
36 menuName += String.fromCharCode((Math.random() * 26) + 65);
37 }
38 }
39
32 var menuCode = String.fromCharCode(i+65);40 var menuCode = String.fromCharCode(i+65);
3341
34 var isSeparator = !root && separatorInterval > 0 && ((i+1) % separatorInterval == 0);42 var isSeparator = !root && separatorInterval > 0 && ((i+1) % separatorInterval == 0);
35 var row = {43 var row = {
36 "rowData": { // 144 "rowData": { // 1
37 "label": prefix + "&" + menuCode,45 "label": menuName + "&" + menuCode,
38 "sensitive": true,46 "sensitive": true,
39 "isSeparator": isSeparator,47 "isSeparator": isSeparator,
40 "icon": "",48 "icon": "",
41 "ext": {},49 "ext": {},
42 "action": prefix + menuCode,50 "action": menuName + menuCode,
43 "actionState": {},51 "actionState": {},
44 "isCheck": false,52 "isCheck": false,
45 "isRadio": false,53 "isRadio": false,
@@ -49,7 +57,7 @@
49 }57 }
50 var isSubmenu = root === undefined || root === true || (submenuInterval > 0 && ((i+1) % submenuInterval == 0));58 var isSubmenu = root === undefined || root === true || (submenuInterval > 0 && ((i+1) % submenuInterval == 0));
51 if (isSubmenu && !isSeparator && depth > 1) {59 if (isSubmenu && !isSeparator && depth > 1) {
52 row["submenu"] = generateTestData(length, depth-1, submenuInterval, separatorInterval, prefix + menuCode + ".", false);60 row["submenu"] = generateTestData(length, depth-1, submenuInterval, separatorInterval,prefix, false);
53 }61 }
54 data[i] = row;62 data[i] = row;
55 }63 }
5664
=== modified file 'tests/qmltests/ApplicationMenus/tst_MenuBar.qml'
--- tests/qmltests/ApplicationMenus/tst_MenuBar.qml 2017-01-09 15:26:05 +0000
+++ tests/qmltests/ApplicationMenus/tst_MenuBar.qml 2017-01-18 14:44:04 +0000
@@ -65,7 +65,7 @@
6565
66 unityMenuModel: UnityMenuModel {66 unityMenuModel: UnityMenuModel {
67 id: menuBackend67 id: menuBackend
68 modelData: appMenuData.generateTestData(7,5,2,3,"menu")68 modelData: appMenuData.generateTestData(17,5,2,3)
69 }69 }
70 }70 }
71 }71 }
@@ -83,12 +83,12 @@
8383
84 function init() {84 function init() {
85 menuBar.dismiss();85 menuBar.dismiss();
86 menuBackend.modelData = appMenuData.generateTestData(5,5,2,3,"menu")86 menuBackend.modelData = appMenuData.generateTestData(5,5,2,3)
87 activatedSpy.clear();87 activatedSpy.clear();
88 }88 }
8989
90 function test_mouseNavigation() {90 function test_mouseNavigation() {
91 menuBackend.modelData = appMenuData.generateTestData(3,3,0,0,"menu");91 menuBackend.modelData = appMenuData.generateTestData(3,3,0,0);
92 wait(50) // wait for row to build92 wait(50) // wait for row to build
93 var priv = findInvisibleChild(menuBar, "d");93 var priv = findInvisibleChild(menuBar, "d");
9494
@@ -114,7 +114,7 @@
114 }114 }
115115
116 function test_keyboardNavigation_RightKeySelectsNextMenuItem(data) {116 function test_keyboardNavigation_RightKeySelectsNextMenuItem(data) {
117 menuBackend.modelData = appMenuData.generateTestData(3,3,0,0,"menu");117 menuBackend.modelData = appMenuData.generateTestData(3,3,0,0);
118 var priv = findInvisibleChild(menuBar, "d");118 var priv = findInvisibleChild(menuBar, "d");
119119
120 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);120 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
@@ -139,7 +139,7 @@
139 }139 }
140140
141 function test_keyboardNavigation_LeftKeySelectsPreviousMenuItem(data) {141 function test_keyboardNavigation_LeftKeySelectsPreviousMenuItem(data) {
142 menuBackend.modelData = appMenuData.generateTestData(3,3,0,0,"menu");142 menuBackend.modelData = appMenuData.generateTestData(3,3,0,0);
143 var priv = findInvisibleChild(menuBar, "d");143 var priv = findInvisibleChild(menuBar, "d");
144144
145 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);145 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
146146
=== modified file 'tests/qmltests/ApplicationMenus/tst_MenuPopup.qml'
--- tests/qmltests/ApplicationMenus/tst_MenuPopup.qml 2017-01-09 15:26:05 +0000
+++ tests/qmltests/ApplicationMenus/tst_MenuPopup.qml 2017-01-18 14:44:04 +0000
@@ -1,4 +1,4 @@
1/*1/*
2 * Copyright (C) 2016 Canonical, Ltd.2 * Copyright (C) 2016 Canonical, Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
@@ -28,8 +28,8 @@
2828
29Item {29Item {
30 id: root30 id: root
31 width: Math.max(units.gu(100), page.width + units.gu(6))31 width: Math.max(units.gu(100), loader.width + units.gu(6))
32 height: Math.max(units.gu(50), page.height + units.gu(6))32 height: Math.max(units.gu(50), loader.height + units.gu(6))
3333
34 Binding {34 Binding {
35 target: MouseTouchAdaptor35 target: MouseTouchAdaptor
@@ -39,25 +39,37 @@
3939
40 ApplicationMenuDataLoader { id: appMenuData }40 ApplicationMenuDataLoader { id: appMenuData }
4141
42 MenuPopup {42 Loader {
43 id: page43 id: loader
4444 sourceComponent: MenuPopup {
45 anchors {45 anchors {
46 left: parent.left46 left: parent ? parent.left : undefined
47 top: parent.top47 top: parent ? parent.top : undefined
48 leftMargin: units.gu(3)48 leftMargin: units.gu(3)
49 topMargin: units.gu(3)49 topMargin: units.gu(3)
50 }50 }
5151
52 unityMenuModel: UnityMenuModel {52 unityMenuModel: UnityMenuModel {
53 id: menuBackend53 modelData: [{
54 modelData: appMenuData.generateTestData(7,5,2,3,"menu")54 "rowData": {
55 "label": "Short",
56 }}, {
57 "rowData": {
58 "label": "This is a long menu item which tests width",
59 }}
60 ]
61 }
62
63 Binding {
64 target: activatedSpy
65 property: "target"
66 value: unityMenuModel
67 }
55 }68 }
56 }69 }
5770
58 SignalSpy {71 SignalSpy {
59 id: activatedSpy72 id: activatedSpy
60 target: menuBackend
61 signalName: "activated"73 signalName: "activated"
62 }74 }
6375
@@ -66,14 +78,20 @@
66 name: "MenuPopup"78 name: "MenuPopup"
67 when: windowShown79 when: windowShown
6880
81 property var menu: loader.status === Loader.Ready ? loader.item : null
82
69 function init() {83 function init() {
70 page.show();84 loader.active = true;
85 menu.show();
71 }86 }
7287
73 function cleanup() {88 function cleanup() {
74 page.reset();89 menu.reset();
75 wait(100); // let the page dismiss90 wait(100); // let the page dismiss
76 activatedSpy.clear();91 activatedSpy.clear();
92
93 loader.active = false;
94 tryCompare(loader, "item", null);
77 }95 }
7896
79 // visit and verify that all the backend menus have been created97 // visit and verify that all the backend menus have been created
@@ -90,6 +108,7 @@
90 // recurse into submenu108 // recurse into submenu
91 var submenu = rows[i]["submenu"];109 var submenu = rows[i]["submenu"];
92 if (submenu) {110 if (submenu) {
111 waitForRendering(menuItem);
93 mouseClick(menuItem, menuItem.width/2, menuItem.height/2);112 mouseClick(menuItem, menuItem.width/2, menuItem.height/2);
94 tryCompare(menuPriv, "currentItem", menuItem);113 tryCompare(menuPriv, "currentItem", menuItem);
95114
@@ -113,15 +132,15 @@
113 }132 }
114133
115 function test_mouseNavigation(data) {134 function test_mouseNavigation(data) {
116 menuBackend.modelData = data.testData;135 menu.unityMenuModel.modelData = data.testData;
117136
118 recurseMenuConstruction(data.testData, page);137 recurseMenuConstruction(data.testData, menu);
119 }138 }
120139
121 function test_checkableMenuTogglesOnClick() {140 function test_checkableMenuTogglesOnClick() {
122 menuBackend.modelData = appMenuData.singleCheckable;141 menu.unityMenuModel.modelData = appMenuData.singleCheckable;
123142
124 var menuItem = findChild(page, "menu-item0-actionItem");143 var menuItem = findChild(menu, "menu-item0-actionItem");
125 verify(menuItem);144 verify(menuItem);
126 compare(menuItem.action.checkable, true, "Menu item should be checkable");145 compare(menuItem.action.checkable, true, "Menu item should be checkable");
127 compare(menuItem.action.checked, false, "Menu item should not be checked");146 compare(menuItem.action.checked, false, "Menu item should not be checked");
@@ -132,13 +151,13 @@
132 }151 }
133152
134 function test_keyboardNavigation_DownKeySelectsAndOpensNextMenuItemAndRotates() {153 function test_keyboardNavigation_DownKeySelectsAndOpensNextMenuItemAndRotates() {
135 menuBackend.modelData = appMenuData.generateTestData(3,3,0,0,"menu",false);154 menu.unityMenuModel.modelData = appMenuData.generateTestData(3,3,0,0,"menu",false);
136155
137 var item0 = findChild(page, "menu-item0"); verify(item0);156 var item0 = findChild(menu, "menu-item0"); verify(item0);
138 var item1 = findChild(page, "menu-item1"); verify(item1);157 var item1 = findChild(menu, "menu-item1"); verify(item1);
139 var item2 = findChild(page, "menu-item2"); verify(item2);158 var item2 = findChild(menu, "menu-item2"); verify(item2);
140159
141 var priv = findInvisibleChild(page, "d");160 var priv = findInvisibleChild(menu, "d");
142161
143 keyClick(Qt.Key_Down, Qt.NoModifier);162 keyClick(Qt.Key_Down, Qt.NoModifier);
144 compare(priv.currentItem, item0, "CurrentItem should have moved to item 0");163 compare(priv.currentItem, item0, "CurrentItem should have moved to item 0");
@@ -154,13 +173,13 @@
154 }173 }
155174
156 function test_keyboardNavigation_UpKeySelectsAndOpensPreviousMenuItemAndRotates() {175 function test_keyboardNavigation_UpKeySelectsAndOpensPreviousMenuItemAndRotates() {
157 menuBackend.modelData = appMenuData.generateTestData(3,3,0,0,"menu",false);176 menu.unityMenuModel.modelData = appMenuData.generateTestData(3,3,0,0,"menu",false);
158177
159 var item0 = findChild(page, "menu-item0"); verify(item0);178 var item0 = findChild(menu, "menu-item0"); verify(item0);
160 var item1 = findChild(page, "menu-item1"); verify(item1);179 var item1 = findChild(menu, "menu-item1"); verify(item1);
161 var item2 = findChild(page, "menu-item2"); verify(item2);180 var item2 = findChild(menu, "menu-item2"); verify(item2);
162181
163 var priv = findInvisibleChild(page, "d");182 var priv = findInvisibleChild(menu, "d");
164183
165 keyClick(Qt.Key_Down, Qt.NoModifier);184 keyClick(Qt.Key_Down, Qt.NoModifier);
166 compare(priv.currentItem, item0, "CurrentItem should have moved to item 2");185 compare(priv.currentItem, item0, "CurrentItem should have moved to item 2");
@@ -176,17 +195,17 @@
176 }195 }
177196
178 function test_keyboardNavigation_RightKeyEntersSubMenu() {197 function test_keyboardNavigation_RightKeyEntersSubMenu() {
179 menuBackend.modelData = appMenuData.generateTestData(3,3,1,0,"menu",false);198 menu.unityMenuModel.modelData = appMenuData.generateTestData(3,3,1,0,"menu",false);
180199
181 var menuItem = findChild(page, "menu-item0");200 var menuItem = findChild(menu, "menu-item0");
182201
183 var priv = findInvisibleChild(page, "d");202 var priv = findInvisibleChild(menu, "d");
184 priv.currentItem = menuItem;203 priv.currentItem = menuItem;
185204
186 keyClick(Qt.Key_Right, Qt.NoModifier);205 keyClick(Qt.Key_Right, Qt.NoModifier);
187 tryCompareFunction(function() { return menuItem.popup !== null && menuItem.popup.visible }, true);206 tryCompareFunction(function() { return menuItem.popup !== null && menuItem.popup.visible }, true);
188207
189 var submenu0 = findChild(page, "menu-item0-menu"); verify(submenu0);208 var submenu0 = findChild(menu, "menu-item0-menu"); verify(submenu0);
190 var submenu0item0 = findChild(submenu0, "menu-item0-menu-item0"); verify(submenu0item0);209 var submenu0item0 = findChild(submenu0, "menu-item0-menu-item0"); verify(submenu0item0);
191210
192 var submenu0Priv = findInvisibleChild(submenu0, "d"); verify(submenu0Priv);211 var submenu0Priv = findInvisibleChild(submenu0, "d"); verify(submenu0Priv);
@@ -194,14 +213,106 @@
194 }213 }
195214
196 function test_keyboardNavigation_LeftKeyClosesSubMenu() {215 function test_keyboardNavigation_LeftKeyClosesSubMenu() {
197 menuBackend.modelData = appMenuData.generateTestData(3,3,1,0,"menu",false);216 menu.unityMenuModel.modelData = appMenuData.generateTestData(3,3,1,0,"menu",false);
198217
199 var menuItem = findChild(page, "menu-item0"); verify(menuItem);218 var menuItem = findChild(menu, "menu-item0"); verify(menuItem);
200 mouseClick(menuItem, menuItem.width/2, menuItem.height/2);219 mouseClick(menuItem, menuItem.width/2, menuItem.height/2);
201 tryCompareFunction(function() { return menuItem.popup !== null && menuItem.popup.visible }, true);220 tryCompareFunction(function() { return menuItem.popup !== null && menuItem.popup.visible }, true);
202221
203 keyClick(Qt.Key_Left, Qt.NoModifier);222 keyClick(Qt.Key_Left, Qt.NoModifier);
204 tryCompareFunction(function() { return menuItem.popup !== null && menuItem.popup.visible }, false);223 tryCompareFunction(function() { return menuItem.popup !== null && menuItem.popup.visible }, false);
205 }224 }
225
226 function test_differentSizes() {
227 var differentSizesMenu = [{
228 "rowData": { "label": "Short" }}, {
229 "rowData": { "label": "This is a long menu item which tests width" }
230 }];
231
232 menu.unityMenuModel.modelData = differentSizesMenu;
233
234 waitForRendering(menu);
235 var longWidth = menu.width;
236 differentSizesMenu.pop();
237 menu.unityMenuModel.modelData = differentSizesMenu;
238
239 waitForRendering(menu);
240 verify(menu.width < longWidth);
241 }
242
243 function test_minimumWidth() {
244 var shortMenu = [{
245 "rowData": { "label": "Short" }
246 }];
247 menu.unityMenuModel.modelData = shortMenu;
248
249 var priv = findInvisibleChild(menu, "d");
250 priv.__minimumWidth = 0;
251 priv.__maximumWidth = 1000;
252 tryCompareFunction(function() { return menu.width > priv.__minimumWidth; }, true);
253
254 priv.__minimumWidth = 300;
255 tryCompare(menu, "width", priv.__minimumWidth);
256 }
257
258 function test_maximumWidth() {
259 var longMenu = [{
260 "rowData": { "label": "This is a long menu item which tests width" }
261 }];
262
263 var priv = findInvisibleChild(menu, "d");
264 priv.__minimumWidth = 0;
265 priv.__maximumWidth = 100;
266
267 menu.unityMenuModel.modelData = longMenu;
268 tryCompare(menu, "width", priv.__maximumWidth);
269
270 priv.__maximumWidth = 200;
271 tryCompare(menu, "width", priv.__maximumWidth);
272
273 priv.__maximumWidth = 1200;
274 tryCompareFunction(function() { return menu.width < priv.__maximumWidth; }, true);
275 }
276
277 function test_minimumHeight() {
278 var shortMenu = [{
279 "rowData": { "label": "menu1" }
280 }];
281 menu.unityMenuModel.modelData = shortMenu;
282
283 var priv = findInvisibleChild(menu, "d");
284 priv.__minimumHeight = 0;
285 priv.__maximumHeight = 1000;
286 tryCompareFunction(function() { return menu.height > priv.__minimumHeight; }, true);
287
288 priv.__minimumHeight = 300;
289 tryCompare(menu, "height", priv.__minimumHeight);
290 }
291
292 function test_maximumHeight() {
293 var shortMenu = [{
294 "rowData": { "label": "menu1" }}, {
295 "rowData": { "label": "menu2" }}, {
296 "rowData": { "label": "menu3" }}, {
297 "rowData": { "label": "menu4" }}, {
298 "rowData": { "label": "menu5" }}, {
299 "rowData": { "label": "menu6" }}, {
300 "rowData": { "label": "menu7" }}, {
301 "rowData": { "label": "menu8" }}, {
302 "rowData": { "label": "menu9" }
303 }];
304 menu.unityMenuModel.modelData = shortMenu;
305
306 var priv = findInvisibleChild(menu, "d");
307 priv.__minimumHeight = 0;
308 priv.__maximumHeight = 100;
309 tryCompare(menu, "height", priv.__maximumHeight);
310
311 priv.__maximumHeight = 200;
312 tryCompare(menu, "height", priv.__maximumHeight);
313
314 priv.__maximumHeight = 1200;
315 tryCompareFunction(function() { return menu.height < priv.__maximumHeight; }, true);
316 }
206 }317 }
207}318}

Subscribers

People subscribed via source and target branches