on xenial help sign in
Fixes visible indicator misalignment in indicator items/menus (lp#1264678). Fixes: https://bugs.launchpad.net/bugs/1264678.
0e7091dNick Dedekind
qml/Panel/IndicatorRow.qml+51−29
@@ -26,7 +26,7 @@ Item {
26 readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
26 readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
27 property alias row: row
27 property alias row: row
28 property QtObject indicatorsModel: null
28 property QtObject indicatorsModel: null
29− property var visibleIndicators: defined
29+ property var visibleIndicators: undefined
30 property int overFlowWidth: width
30 property int overFlowWidth: width
31 property bool showAll: false
31 property bool showAll: false
32 property real currentItemOffset: 0.0
32 property real currentItemOffset: 0.0
@@ -94,34 +94,56 @@ Item {
94 property real opacityMultiplier: highlighted ? 1 : (1 - indicatorRow.unitProgress)
94 property real opacityMultiplier: highlighted ? 1 : (1 - indicatorRow.unitProgress)
95
95
96 IndicatorItem {
96 IndicatorItem {
97− id: indicatorItem
97+ id: indicatorItem
98− identifier: model.identifier
98+ identifier: model.identifier
99− height: parent.height
99+ height: parent.height
100−
100+
101− dimmed: itemWrapper.dimmed
101+ dimmed: itemWrapper.dimmed
102−
102+
103− widgetSource: model.widgetSource
103+ widgetSource: model.widgetSource
104− indicatorProperties : model.indicatorProperties
104+ indicatorProperties : model.indicatorProperties
105−
105+
106− Component.onCompleted: {
106+ Component.onCompleted: {
107− if (visibleIndicators == undefined) {
107+ updateVisiblility();
108− visibleIndicators = {}
109− }
110− indicatorRow.visibleIndicators[model.identifier] = indicatorVisible;
111− indicatorRow.visibleIndicatorsChanged();
112− }
108+ }
113− onIndicatorVisibleChanged: {
109+ onIndicatorVisibleChanged: {
114− if (visibleIndicators == undefined) {
110+ updateVisiblility();
115− visibleIndicators = {}
111+
116− }
117− indicatorRow.visibleIndicators[model.identifier] = indicatorVisible;
118− indicatorRow.visibleIndicatorsChanged();
119−
120− if (indicatorVisible) {
112+ if (indicatorVisible) {
121− showAll = true;
113+ showAll = true;
122− allVisible.start();
114+ allVisible.start();
115+ }
116+ }
117+
118+ function updateVisiblility() {
119+ if (visibleIndicators == undefined) {
120+ visibleIndicators = {}
121+ }
122+ indicatorRow.visibleIndicators[model.identifier] = indicatorVisible;
123+
124+ // removed current index?
125+ if (indicatorRow.currentItemIndex === index && !indicatorVisible) {
126+ // find the next closest visible indicator (after current, else before)
127+ var newIndex = -1;
128+ for (var i = index+1; i < rowRepeater.count; i++) {
129+ if (indicatorRow.visibleIndicators[i] === undefined || indicatorRow.visibleIndicators[model.identifier]) {
130+ newIndex = i;
131+ break;
123− }
132+ }
133+ }
134+ if (newIndex === -1) {
135+ for (i = index - 1; i >= 0; i--) {
136+ if (indicatorRow.visibleIndicators[i] === undefined || indicatorRow.visibleIndicators[model.identifier]) {
137+ newIndex = i;
138+ break;
139+ }
140+ }
141+ }
142+ indicatorRow.setCurrentItem(newIndex);
143+ }
144+
145+ indicatorRow.visibleIndicatorsChanged();
124− }
146+ }
125 }
147 }
126
148
127 states: [
149 states: [
qml/Panel/Indicators.qml+46−34
@@ -193,21 +193,6 @@ Showable {
193 clip: !indicators.fullyOpened
193 clip: !indicators.fullyOpened
194 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
194 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
195 enabled: contentEnabled
195 enabled: contentEnabled
196− visibleIndicators: indicatorRow.visibleIndicators
197−
198− Connections {
199− property bool enableIndexChangeSignal: true
200−
201− target: enableIndexChangeSignal ? indicatorRow : null
202− onCurrentItemIndexChanged: {
203− var oldActive = enableIndexChangeSignal;
204− enableIndexChangeSignal = false;
205−
206− menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
207−
208− enableIndexChangeSignal = oldActive;
209− }
210− }
211
196
212 //small shadow gradient at bottom of menu
197 //small shadow gradient at bottom of menu
213 Rectangle {
198 Rectangle {
@@ -263,8 +248,6 @@ Showable {
263
248
264 Indicators.IndicatorsModel {
249 Indicators.IndicatorsModel {
265 id: indicatorsModel
250 id: indicatorsModel
266−
267− Component.onCompleted: load()
268 }
251 }
269
252
270 IndicatorRow {
253 IndicatorRow {
@@ -279,17 +262,11 @@ Showable {
279 state: indicators.state
262 state: indicators.state
280 unitProgress: indicators.unitProgress
263 unitProgress: indicators.unitProgress
281
264
282− Connections {
265+ onVisibleIndicatorsChanged: {
283− property bool enableIndexChangeSignal: true
266+ // need to do it here so we can control sequence
284−
267+ if (visibleIndicators !== undefined) {
285− target: enableIndexChangeSignal ? menuContent : null
268+ menuContent.visibleIndicators = visibleIndicators;
286− onCurrentMenuIndexChanged: {
269+ menuContent.setCurrentMenuIndex(currentItemIndex);
287− var oldActive = enableIndexChangeSignal;
288− enableIndexChangeSignal = false;
289−
290− indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
291−
292− enableIndexChangeSignal = oldActive;
293 }
270 }
294 }
271 }
295
272
@@ -341,15 +318,45 @@ Showable {
341 }
318 }
342 }
319 }
343
320
321+ QtObject {
322+ id: d
323+ property bool enableIndexChangeSignal: true
344− property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
324+ property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
325+ }
326+
327+ Connections {
328+ target: menuContent
329+ onCurrentMenuIndexChanged: {
330+ var oldActive = d.enableIndexChangeSignal;
331+ if (!oldActive) return;
332+ d.enableIndexChangeSignal = false;
333+
334+ indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
335+
336+ d.enableIndexChangeSignal = oldActive;
337+ }
338+ }
339+
340+ Connections {
341+ target: indicatorRow
342+ onCurrentItemIndexChanged: {
343+ var oldActive = d.enableIndexChangeSignal;
344+ if (!oldActive) return;
345+ d.enableIndexChangeSignal = false;
346+
347+ menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
348+
349+ d.enableIndexChangeSignal = oldActive;
350+ }
351+ }
345 // connections to the active drag handle
352 // connections to the active drag handle
346 Connections {
353 Connections {
347− target: activeDragHandle
354+ target: d.activeDragHandle
348 onTouchXChanged: {
355 onTouchXChanged: {
349− indicators.calculateCurrentItem(activeDragHandle.touchX, true);
356+ indicators.calculateCurrentItem(d.activeDragHandle.touchX, true);
350 }
357 }
351 onTouchSceneYChanged: {
358 onTouchSceneYChanged: {
352− yVelocityCalculator.trackedPosition = activeDragHandle.touchSceneY;
359+ yVelocityCalculator.trackedPosition = d.activeDragHandle.touchSceneY;
353 }
360 }
354 }
361 }
355
362
@@ -403,8 +410,8 @@ Showable {
403 }
410 }
404 StateChangeScript {
411 StateChangeScript {
405 script: {
412 script: {
406− if (activeDragHandle) {
413+ if (d.activeDragHandle) {
407− calculateCurrentItem(activeDragHandle.touchX, false);
414+ calculateCurrentItem(d.activeDragHandle.touchX, false);
408 }
415 }
409 }
416 }
410 }
417 }
@@ -429,4 +436,9 @@ Showable {
429 NumberAnimation {targets: [indicatorRow, menuContent]; property: "y"; duration: 300; easing.type: Easing.OutCubic}
436 NumberAnimation {targets: [indicatorRow, menuContent]; property: "y"; duration: 300; easing.type: Easing.OutCubic}
430 }
437 }
431 ]
438 ]
439+
440+ Component.onCompleted: initialise();
441+ function initialise() {
442+ indicatorsModel.load();
443+ }
432}
444}
qml/Panel/MenuContent.qml+2−2
@@ -39,10 +39,10 @@ MainView {
39 height: units.gu(42)
39 height: units.gu(42)
40
40
41 function setCurrentMenuIndex(index) {
41 function setCurrentMenuIndex(index) {
42− var filteredIndex = filteredIndicators.mapFromSource(index)
42+ var filteredIndex = filteredIndicators.mapFromSource(index);
43
43
44 if (tabs.selectedTabIndex !== filteredIndex) {
44 if (tabs.selectedTabIndex !== filteredIndex) {
45− if (tabs.selectedTabIndex == -1 || !animateNextMenuChange) {
45+ if (tabs.selectedTabIndex === -1 || !animateNextMenuChange) {
46 tabs.tabBar.animate = false;
46 tabs.tabBar.animate = false;
47 }
47 }
48 tabs.selectedTabIndex = filteredIndex;
48 tabs.selectedTabIndex = filteredIndex;
tests/mocks/Unity/Indicators/IndicatorsModel.qml+2−5
@@ -21,12 +21,9 @@ ListModel {
21
21
22 property var indicatorData : undefined
22 property var indicatorData : undefined
23
23
24− function load() {}
24+ function load() {
25+ clear();
25
26
26− // Need to do this dynamically.
27− // Apparently ListModels dont order roles visually when using ListElement
28− // which throws off the filter for non-visible indicators.
29− Component.onCompleted: {
30 append({ "identifier": "indicator-fake1",
27 append({ "identifier": "indicator-fake1",
31 "position": 0,
28 "position": 0,
32 "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget1.qml",
29 "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget1.qml",
tests/mocks/Unity/Indicators/qml/fake_menu_widget2.qml+1−3
@@ -19,7 +19,5 @@ import QtQuick 2.0
19Rectangle {
19Rectangle {
20 width: 40
20 width: 40
21 height: 40
21 height: 40
22− color : "yellow"
22+ color : "blue"
23−
24− enabled: false
25}
23}
tests/mocks/Unity/Indicators/qml/fake_menu_widget3.qml+1−1
@@ -19,5 +19,5 @@ import QtQuick 2.0
19Rectangle {
19Rectangle {
20 width: 40
20 width: 40
21 height: 40
21 height: 40
22− color : "blue"
22+ color : "yellow"
23}
23}
tests/qmltests/Panel/tst_IndicatorRow.qml+2−1
@@ -32,6 +32,8 @@ Item {
32
32
33 function init_test()
33 function init_test()
34 {
34 {
35+ indicatorModel.load();
36+
35 indicatorRow.state = "initial";
37 indicatorRow.state = "initial";
36 indicatorRow.currentItem = null;
38 indicatorRow.currentItem = null;
37 indicatorRow.unitProgress = 0.0;
39 indicatorRow.unitProgress = 0.0;
@@ -53,7 +55,6 @@ Item {
53
55
54 Indicators.IndicatorsModel {
56 Indicators.IndicatorsModel {
55 id: indicatorModel
57 id: indicatorModel
56− Component.onCompleted: load()
57 }
58 }
58
59
59 UT.UnityTestCase {
60 UT.UnityTestCase {
tests/qmltests/Panel/tst_Indicators.qml+59−8
@@ -83,6 +83,8 @@ Item {
83 when: windowShown
83 when: windowShown
84
84
85 function init() {
85 function init() {
86+ indicators.initialise();
87+
86 indicators.hide();
88 indicators.hide();
87 tryCompare(indicators.hideAnimation, "running", false);
89 tryCompare(indicators.hideAnimation, "running", false);
88 tryCompare(indicators, "state", "initial");
90 tryCompare(indicators, "state", "initial");
@@ -161,21 +163,70 @@ Item {
161 compare(indicators.fullyOpened, true);
163 compare(indicators.fullyOpened, true);
162 }
164 }
163
165
166+ function init_invisible_indicator(identifier) {
167+ tryCompareFunction(function() { return findChild(indicators, identifier+"-widget") !== null }, true);
168+ var item = findChild(indicators, identifier+"-widget");
169+
170+ item.enabled = false;
171+ }
172+
164 function test_row_visible_menuContent_visible_data() { return [
173 function test_row_visible_menuContent_visible_data() { return [
165− {tag: "visible", index: 0, name: "indicator-fake1", visible: true },
174+ {tag: "first", visible: [false, true, true, true, true] },
166− {tag: "invisible", index: 1, name: "indicator-fake2", visible: false }]
175+ {tag: "adjacent", visible: [true, false, false, true, true] },
176+ {tag: "bounds", visible: [false, true, true, true, false] },
177+ {tag: "disjoint", visible: [true, false, true, false, true] },
178+ {tag: "last", visible: [true, true, true, true, false] }];
167 }
179 }
168
180
169 function test_row_visible_menuContent_visible(data) {
181 function test_row_visible_menuContent_visible(data) {
182+
183+ indicators.show();
184+
170 var indicatorTabs = findChild(indicators, "tabs");
185 var indicatorTabs = findChild(indicators, "tabs");
171− var rowRepeater = findChild(indicators, "rowRepeater");
186+ var rowRepeater = findChild(indicators, "rowRepeater")
187+
188+
189+ for (var i = 0; i< data.visible.length; i++) {
190+ if (data.visible[i] === false)
191+ init_invisible_indicator("indicator-fake" + (i + 1));
192+ }
193+
194+ for (i = 0; i < data.visible.length; i++) {
195+ var shouldBeVisible = data.visible[i];
172
196
197+ // check item visibility
173− var indicatorItem = rowRepeater.itemAt(data.index);
198+ var indicatorItem = rowRepeater.itemAt(i);
199+ tryCompare(indicatorItem, "visible", shouldBeVisible);
200+ // check tab visibility
174− tryCompareFunction(function() { return indicatorItem.width > 0}, true);
201+ tryCompareFunction(function() { return findChild(indicatorTabs, "indicator-fake" + (i + 1)) !== null }, shouldBeVisible);
175− tryCompare(indicatorItem, "visible", data.visible);
202+ }
203+ }
204+
205+ function test_indicator_visible_correct_tabs_data() { return [
206+ {tag: "current-first", currentIndex: 0, visible: [false, true, true, true, true], expected: 1 },
207+ {tag: "current-last", currentIndex: 4, visible: [true, true, true, true, false], expected: 3 },
208+ {tag: "after", currentIndex: 0, visible: [true, false, true, true, true], expected: 0 },
209+ {tag: "before", currentIndex: 1, visible: [false, true, true, true, true], expected: 1 }];
210+ }
211+
212+ function test_indicator_visible_correct_tabs(data) {
213+
214+ var indicatorTabs = findChild(indicators, "tabs");
215+ var indicatorRow = findChild(indicators, "indicatorRow");
216+
217+ indicators.show();
218+ indicatorRow.setCurrentItem(data.currentIndex);
219+ tryCompare(indicators, "fullyOpened", true);
220+
221+ for (var i = 0; i< data.visible.length; i++) {
222+ if (data.visible[i] === false)
223+ init_invisible_indicator("indicator-fake" + (i + 1));
224+ }
176
225
177− var indicatorTab = findChild(indicatorTabs, data.name)
226+ // check for current selected item
178− tryCompareFunction(function() { return indicatorTab !== null }, data.visible);
227+ tryCompare(indicatorRow, "currentItemIndex", data.expected);
228+ // check for current selected tab
229+ tryCompareFunction(function() { return findChild(indicatorTabs, "indicator-fake" + (data.expected + 1)) === indicatorTabs.selectedTab }, true);
179 }
230 }
180 }
231 }
181}
232}
tests/qmltests/Panel/tst_MenuContent.qml+2−2
@@ -103,13 +103,13 @@ Item {
103
103
104 function selected_tab_equals_test_tab() {
104 function selected_tab_equals_test_tab() {
105 var currentTab = menu_content_test.findChild(menuContent, "tabs").selectedTab
105 var currentTab = menu_content_test.findChild(menuContent, "tabs").selectedTab
106− if (currentTab == undefined) {
106+ if (currentTab === null) {
107 console.log("selected tab undefined");
107 console.log("selected tab undefined");
108 return false;
108 return false;
109 }
109 }
110
110
111 var testTab = menu_content_test.findChild(menuContent, testTabObjectName);
111 var testTab = menu_content_test.findChild(menuContent, testTabObjectName);
112− if (testTab == undefined) {
112+ if (testTab === null) {
113 console.log("test_tab " + testTabObjectName + " undefined");
113 console.log("test_tab " + testTabObjectName + " undefined");
114 return false;
114 return false;
115 }
115 }
tests/qmltests/Panel/tst_Panel.qml+14−12
@@ -56,6 +56,8 @@ Item {
56 }
56 }
57
57
58 function init() {
58 function init() {
59+ panel.indicators.initialise();
60+
59 searchClicked = false;
61 searchClicked = false;
60 panel.indicators.hide();
62 panel.indicators.hide();
61 tryCompare(panel.indicators.hideAnimation, "running", false);
63 tryCompare(panel.indicators.hideAnimation, "running", false);
@@ -64,16 +66,16 @@ Item {
64
66
65 function get_indicator_item(index) {
67 function get_indicator_item(index) {
66 var rowRepeater = findChild(panel.indicators, "rowRepeater");
68 var rowRepeater = findChild(panel.indicators, "rowRepeater");
67− verify(rowRepeater != undefined);
69+ verify(rowRepeater !== null);
68 return rowRepeater.itemAt(index);
70 return rowRepeater.itemAt(index);
69 }
71 }
70
72
71 function get_indicator_item_position(index) {
73 function get_indicator_item_position(index) {
72 var indicatorRow = findChild(panel.indicators, "indicatorRow");
74 var indicatorRow = findChild(panel.indicators, "indicatorRow");
73− verify(indicatorRow != undefined);
75+ verify(indicatorRow !== null);
74
76
75 var indicatorItem = get_indicator_item(index);
77 var indicatorItem = get_indicator_item(index);
76− verify(indicatorItem != undefined);
78+ verify(indicatorItem !== null);
77
79
78 return panel.mapFromItem(indicatorItem, indicatorItem.width/2, indicatorItem.height/2);
80 return panel.mapFromItem(indicatorItem, indicatorItem.width/2, indicatorItem.height/2);
79 }
81 }
@@ -118,7 +120,7 @@ Item {
118 // no hint animation when fullscreen
120 // no hint animation when fullscreen
119 compare(panel.indicators.y, -panel.panelHeight);
121 compare(panel.indicators.y, -panel.panelHeight);
120 var indicatorRow = findChild(panel.indicators, "indicatorRow");
122 var indicatorRow = findChild(panel.indicators, "indicatorRow");
121− verify(indicatorRow != undefined);
123+ verify(indicatorRow !== null);
122 compare(indicatorRow.y, 0);
124 compare(indicatorRow.y, 0);
123 compare(panel.indicators.height, panel.indicators.panelHeight);
125 compare(panel.indicators.height, panel.indicators.panelHeight);
124 compare(panel.indicators.partiallyOpened, false,
126 compare(panel.indicators.partiallyOpened, false,
@@ -143,13 +145,13 @@ Item {
143 }
145 }
144
146
145 var indicatorRow = findChild(panel.indicators, "indicatorRow");
147 var indicatorRow = findChild(panel.indicators, "indicatorRow");
146− verify(indicatorRow != undefined);
148+ verify(indicatorRow !== null);
147
149
148 var rowRepeater = findChild(panel.indicators, "rowRepeater");
150 var rowRepeater = findChild(panel.indicators, "rowRepeater");
149− verify(indicatorRow != undefined);
151+ verify(indicatorRow !== null);
150
152
151 var menuContent = findChild(panel.indicators, "menuContent");
153 var menuContent = findChild(panel.indicators, "menuContent");
152− verify(indicatorRow != undefined);
154+ verify(indicatorRow !== null);
153
155
154 // Wait for the indicators to get into position.
156 // Wait for the indicators to get into position.
155 // (switches between normal and fullscreen modes are animated)
157 // (switches between normal and fullscreen modes are animated)
@@ -203,7 +205,7 @@ Item {
203 panel.searchVisible = true;
205 panel.searchVisible = true;
204
206
205 var searchIndicator = findChild(panel, "search");
207 var searchIndicator = findChild(panel, "search");
206− verify(searchIndicator != undefined);
208+ verify(searchIndicator !== null);
207
209
208 tap(searchIndicator, 1, 1);
210 tap(searchIndicator, 1, 1);
209
211
@@ -216,7 +218,7 @@ Item {
216 panel.searchVisible = false;
218 panel.searchVisible = false;
217
219
218 var searchIndicator = findChild(panel, "search");
220 var searchIndicator = findChild(panel, "search");
219− verify(searchIndicator != undefined);
221+ verify(searchIndicator !== null);
220
222
221 tap(searchIndicator, 1, 1);
223 tap(searchIndicator, 1, 1);
222
224
@@ -232,14 +234,14 @@ Item {
232 panel.searchVisible = false;
234 panel.searchVisible = false;
233
235
234 var indicatorRow = findChild(panel.indicators, "indicatorRow");
236 var indicatorRow = findChild(panel.indicators, "indicatorRow");
235− verify(indicatorRow != undefined);
237+ verify(indicatorRow !== null);
236
238
237 var rowRepeater = findChild(panel.indicators, "rowRepeater");
239 var rowRepeater = findChild(panel.indicators, "rowRepeater");
238− verify(indicatorRow != undefined);
240+ verify(indicatorRow !== null);
239
241
240 // Get the first indicator
242 // Get the first indicator
241 var indicatorItemFirst = get_indicator_item(0);
243 var indicatorItemFirst = get_indicator_item(0);
242− verify(indicatorItemFirst != undefined);
244+ verify(indicatorItemFirst !== undefined);
243
245
244 var indicatorItemCoordFirst = get_indicator_item_position(0);
246 var indicatorItemCoordFirst = get_indicator_item_position(0);
245 var indicatorItemCoordNext = get_indicator_item_position(indicatorRow.count - 1);
247 var indicatorItemCoordNext = get_indicator_item_position(indicatorRow.count - 1);