on xenial help sign in
Fixed menu layout width calculations. (LP: #1657050)
df8c9d5Nick Dedekind
qml/ApplicationMenus/MenuPopup.qml+162−123
@@ -26,19 +26,7 @@ UbuntuShape {
26 objectName: "menu"
26 objectName: "menu"
27 backgroundColor: theme.palette.normal.overlay
27 backgroundColor: theme.palette.normal.overlay
28
28
29− property alias unityMenuModel: listView.model
29+ 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
42
30
43 function show() {
31 function show() {
44 visible = true;
32 visible = true;
@@ -63,18 +51,23 @@ UbuntuShape {
63 d.dismissAll();
51 d.dismissAll();
64 }
52 }
65
53
66− implicitWidth: container.width
54+ implicitWidth: focusScope.width
67− implicitHeight: MathUtils.clamp(listView.contentHeight, __ajustedMinimumHeight, __maximumHeight)
55+ implicitHeight: focusScope.height
68
56
69 MenuNavigator {
57 MenuNavigator {
70 id: d
58 id: d
71 objectName: "d"
59 objectName: "d"
72− itemView: listView
60+ itemView: repeater
73
61
74 property Item currentItem: null
62 property Item currentItem: null
75 property Item hoveredItem: null
63 property Item hoveredItem: null
76 readonly property int currentIndex: currentItem ? currentItem.__ownIndex : -1
64 readonly property int currentIndex: currentItem ? currentItem.__ownIndex : -1
77
65
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()
79
72
80 onCurrentItemChanged: {
73 onCurrentItemChanged: {
@@ -86,13 +79,26 @@ UbuntuShape {
86 }
79 }
87
80
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 }
92
92
93+ MouseArea {
94+ // Eat events.
95+ anchors.fill: parent
96+ }
97+
93 Item {
98 Item {
94 id: focusScope
99 id: focusScope
95− anchors.fill: parent
100+ width: container.width
101+ height: container.height
96 focus: visible
102 focus: visible
97
103
98 Keys.onUpPressed: d.selectPrevious(d.currentIndex)
104 Keys.onUpPressed: d.selectPrevious(d.currentIndex)
@@ -108,17 +114,17 @@ UbuntuShape {
108 id: container
114 id: container
109 objectName: "container"
115 objectName: "container"
110
116
111− width: listView.contentWidth
117+ height: MathUtils.clamp(listView.contentHeight, d.__minimumHeight, d.__maximumHeight)
112− height: parent.height
118+ width: menuColumn.width
113 spacing: 0
119 spacing: 0
114
120
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.height
125 visible: listView.contentHeight > root.height
121 enabled: !listView.atYBeginning
126 enabled: !listView.atYBeginning
127+ z: 1
122
128
123 Rectangle {
129 Rectangle {
124 color: enabled ? theme.palette.normal.overlayText :
130 color: enabled ? theme.palette.normal.overlayText :
@@ -143,47 +149,35 @@ UbuntuShape {
143 MouseArea {
149 MouseArea {
144 anchors.fill: parent
150 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 }
151
168
152− ListView {
169+ // Menu Items
170+ Flickable {
153 id: listView
171 id: listView
154− objectName: "listView"
155− Layout.fillHeight: true
156− Layout.fillWidth: true
157− contentWidth: MathUtils.clamp(contentItem.childrenRect.width,
158− __minimumWidth,
159− __maximumWidth)
160−
161− orientation: Qt.Vertical
162− interactive: contentHeight > height
163 clip: interactive
172 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
173
172− width: listView.width
174+ Layout.fillHeight: true
173− height: d.currentItem ? d.currentItem.height : 0
175+ Layout.fillWidth: true
174− y: d.currentItem ? d.currentItem.y : 0
176+ contentHeight: menuColumn.height
175− visible: d.currentItem
177+ interactive: height < contentHeight
176− }
177−
178− function itemAt(index) {
179− if (index > count || index < 0) return null;
180− currentIndex = index;
181− return currentItem;
182− }
183
178
184 MouseArea {
179 MouseArea {
185− id: menuMouseArea
186− anchors.fill: listView
180+ anchors.fill: parent
187 hoverEnabled: true
181 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 hovers
183 z: 1 // on top so we override any other hovers
@@ -195,7 +189,7 @@ UbuntuShape {
195
189
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 @@ UbuntuShape {
216 }
210 }
217 }
211 }
218
212
219− delegate: Loader {
213+ ColumnLayout {
220− id: loader
214+ id: menuColumn
221− objectName: root.objectName + "-item" + __ownIndex
215+ spacing: 0
222
216
223− property int __ownIndex: index
217+ width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
224
218
225− width: root.width
219+ Repeater {
226− enabled: model.isSeparator ? false : model.sensitive
220+ id: repeater
227
221
228− sourceComponent: {
222+ Loader {
229− if (model.isSeparator) {
223+ id: loader
230− return separatorComponent;
224+ objectName: root.objectName + "-item" + __ownIndex
231− }
232− return menuItemComponent;
233− }
234
225
235− property Item popup: null
226+ property int __ownIndex: index
236−
227+ property bool __isSeparator: model.isSeparator
237− Component {
228+
238− id: menuItemComponent
229+ enabled: __isSeparator ? false : model.sensitive
239− MenuItem {
230+
240− id: menuItem
231+ sourceComponent: {
241− menuData: model
232+ if (model.isSeparator) {
242− objectName: loader.objectName + "-actionItem"
233+ return separatorComponent;
243−
244− action.onTriggered: {
245− d.currentItem = loader;
246−
247− if (hasSubmenu) {
248− if (!popup) {
249− var model = root.unityMenuModel.submenu(__ownIndex);
250− popup = submenuComponent.createObject(focusScope, {
251− objectName: loader.objectName + "-",
252− unityMenuModel: model,
253− x: Qt.binding(function() { return root.width }),
254− y: Qt.binding(function() { return loader.y })
255− });
256− } else if (popup) {
257− popup.visible = true;
258− }
259− popup.retreat.connect(function() {
260− popup.destroy();
261− popup = null;
262− menuItem.forceActiveFocus();
263− })
264− } else {
265− root.unityMenuModel.activate(__ownIndex);
266 }
234 }
235+ return menuItemComponent;
267 }
236 }
268
237
269− Connections {
238+ property Item popup: null
270− target: d
239+
271− onCurrentIndexChanged: {
240+ Layout.fillWidth: true
272− if (popup && d.currentIndex != __ownIndex) {
241+
242+ Component {
243+ id: menuItemComponent
244+ MenuItem {
245+ id: menuItem
246+ menuData: model
247+ objectName: loader.objectName + "-actionItem"
248+
249+ width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
250+
251+ action.onTriggered: {
252+ d.currentItem = loader;
253+
254+ if (hasSubmenu) {
255+ if (!popup) {
256+ var model = root.unityMenuModel.submenu(__ownIndex);
257+ popup = submenuComponent.createObject(focusScope, {
258+ objectName: loader.objectName + "-",
259+ unityMenuModel: model,
260+ x: Qt.binding(function() { return root.width }),
261+ y: Qt.binding(function() {
262+ var dummy = listView.contentY; // force a recalc on contentY change.
263+ return mapToItem(container, 0, y).y;
264+ })
265+ });
266+ } else if (popup) {
273− popup.visible = false;
267+ popup.visible = true;
268+ }
269+ popup.retreat.connect(function() {
270+ popup.destroy();
271+ popup = null;
272+ menuItem.forceActiveFocus();
273+ })
274+ } else {
275+ root.unityMenuModel.activate(__ownIndex);
276+ }
274 }
277 }
278+
279+ Connections {
280+ target: d
281+ onCurrentIndexChanged: {
282+ if (popup && d.currentIndex != __ownIndex) {
283+ popup.visible = false;
284+ }
275− }
285+ }
276− onDismissAll: {
286+ onDismissAll: {
277− if (popup) {
287+ if (popup) {
278− popup.destroy();
288+ popup.destroy();
279− popup = null;
289+ popup = null;
290+ }
291+ }
280 }
292 }
281 }
293 }
282 }
294 }
283− }
284− }
285
295
286− Component {
296+ Component {
287− id: separatorComponent
297+ id: separatorComponent
288− ListItems.ThinDivider {
298+ ListItems.ThinDivider {
289− objectName: loader.objectName + "-separator"
299+ objectName: loader.objectName + "-separator"
300+ implicitHeight: units.dp(2)
301+ }
302+ }
290 }
303 }
304+
291 }
305 }
292 }
306 }
293− } // ListView
294
307
295− // FIXME use ListView.footer - tried but was flaky with positionViewAtIndex.
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.height
327 visible: listView.contentHeight > root.height
301 enabled: !listView.atYEnd
328 enabled: !listView.atYEnd
329+ z: 1
302
330
303 Rectangle {
331 Rectangle {
304 color: enabled ? theme.palette.normal.overlayText :
332 color: enabled ? theme.palette.normal.overlayText :
@@ -323,8 +351,19 @@ UbuntuShape {
323 MouseArea {
351 MouseArea {
324 anchors.fill: parent
352 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 }
tests/qmltests/ApplicationMenuDataLoader.qml+13−5
@@ -10,6 +10,7 @@ Object {
10
10
11 Connections {
11 Connections {
12 id: sMgrHandler
12 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, "");
15
16
@@ -25,21 +26,28 @@ Object {
25 var data = [];
26 var data = [];
26 if (root === undefined) root = true;
27 if (root === undefined) root = true;
27
28
28− if (prefix === undefined) prefix = "menu"
29−
30 for (var i = 0; i < length; i++) {
29 for (var i = 0; i < length; i++) {
31
30
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);
33
41
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": { // 1
44 "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 @@ Object {
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 }
tests/qmltests/ApplicationMenus/tst_MenuBar.qml+5−5
@@ -65,7 +65,7 @@ Item {
65
65
66 unityMenuModel: UnityMenuModel {
66 unityMenuModel: UnityMenuModel {
67 id: menuBackend
67 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 @@ Item {
83
83
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 }
89
89
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 build
92 wait(50) // wait for row to build
93 var priv = findInvisibleChild(menuBar, "d");
93 var priv = findInvisibleChild(menuBar, "d");
94
94
@@ -114,7 +114,7 @@ Item {
114 }
114 }
115
115
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");
119
119
120 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
120 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
@@ -139,7 +139,7 @@ Item {
139 }
139 }
140
140
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");
144
144
145 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
145 var menuItem0 = findChild(menuBar, "menuBar-item0"); verify(menuItem0);
tests/qmltests/ApplicationMenus/tst_MenuPopup.qml+148−37
@@ -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 modify
4 * This program is free software; you can redistribute it and/or modify
@@ -28,8 +28,8 @@ import ".."
28
28
29Item {
29Item {
30 id: root
30 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))
33
33
34 Binding {
34 Binding {
35 target: MouseTouchAdaptor
35 target: MouseTouchAdaptor
@@ -39,25 +39,37 @@ Item {
39
39
40 ApplicationMenuDataLoader { id: appMenuData }
40 ApplicationMenuDataLoader { id: appMenuData }
41
41
42+ Loader {
43+ id: loader
42− MenuPopup {
44+ sourceComponent: MenuPopup {
43− id: page
45+ anchors {
46+ left: parent ? parent.left : undefined
47+ top: parent ? parent.top : undefined
48+ leftMargin: units.gu(3)
49+ topMargin: units.gu(3)
50+ }
44
51
45− anchors {
52+ unityMenuModel: UnityMenuModel {
46− left: parent.left
53+ modelData: [{
47− top: parent.top
54+ "rowData": {
48− leftMargin: units.gu(3)
55+ "label": "Short",
49− topMargin: units.gu(3)
56+ }}, {
57+ "rowData": {
58+ "label": "This is a long menu item which tests width",
59+ }}
60+ ]
50− }
61+ }
51
62
52− unityMenuModel: UnityMenuModel {
63+ Binding {
53− id: menuBackend
64+ target: activatedSpy
54− modelData: appMenuData.generateTestData(7,5,2,3,"menu")
65+ property: "target"
66+ value: unityMenuModel
67+ }
55 }
68 }
56 }
69 }
57
70
58 SignalSpy {
71 SignalSpy {
59 id: activatedSpy
72 id: activatedSpy
60− target: menuBackend
61 signalName: "activated"
73 signalName: "activated"
62 }
74 }
63
75
@@ -66,14 +78,20 @@ Item {
66 name: "MenuPopup"
78 name: "MenuPopup"
67 when: windowShown
79 when: windowShown
68
80
81+ property var menu: loader.status === Loader.Ready ? loader.item : null
82+
69 function init() {
83 function init() {
84+ loader.active = true;
70− page.show();
85+ menu.show();
71 }
86 }
72
87
73 function cleanup() {
88 function cleanup() {
74− page.reset();
89+ menu.reset();
75 wait(100); // let the page dismiss
90 wait(100); // let the page dismiss
76 activatedSpy.clear();
91 activatedSpy.clear();
92+
93+ loader.active = false;
94+ tryCompare(loader, "item", null);
77 }
95 }
78
96
79 // visit and verify that all the backend menus have been created
97 // visit and verify that all the backend menus have been created
@@ -90,6 +108,7 @@ Item {
90 // recurse into submenu
108 // 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);
95
114
@@ -113,15 +132,15 @@ Item {
113 }
132 }
114
133
115 function test_mouseNavigation(data) {
134 function test_mouseNavigation(data) {
116− menuBackend.modelData = data.testData;
135+ menu.unityMenuModel.modelData = data.testData;
117
136
118− recurseMenuConstruction(data.testData, page);
137+ recurseMenuConstruction(data.testData, menu);
119 }
138 }
120
139
121 function test_checkableMenuTogglesOnClick() {
140 function test_checkableMenuTogglesOnClick() {
122− menuBackend.modelData = appMenuData.singleCheckable;
141+ menu.unityMenuModel.modelData = appMenuData.singleCheckable;
123
142
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 @@ Item {
132 }
151 }
133
152
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);
136
155
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);
140
159
141− var priv = findInvisibleChild(page, "d");
160+ var priv = findInvisibleChild(menu, "d");
142
161
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 @@ Item {
154 }
173 }
155
174
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);
158
177
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);
162
181
163− var priv = findInvisibleChild(page, "d");
182+ var priv = findInvisibleChild(menu, "d");
164
183
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 @@ Item {
176 }
195 }
177
196
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);
180
199
181− var menuItem = findChild(page, "menu-item0");
200+ var menuItem = findChild(menu, "menu-item0");
182
201
183− var priv = findInvisibleChild(page, "d");
202+ var priv = findInvisibleChild(menu, "d");
184 priv.currentItem = menuItem;
203 priv.currentItem = menuItem;
185
204
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);
188
207
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);
191
210
192 var submenu0Priv = findInvisibleChild(submenu0, "d"); verify(submenu0Priv);
211 var submenu0Priv = findInvisibleChild(submenu0, "d"); verify(submenu0Priv);
@@ -194,14 +213,106 @@ Item {
194 }
213 }
195
214
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);
198
217
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);
202
221
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}