on xenial help sign in
more!
commitc529357eee0d0e33b36cc77eef4d87181bb74146 authorNick Dedekind <nick.dedekind@canonical.com> dateMon 29 Sep 2014, 18:30 (12 years ago) parent2a3f68a
33 files changed+2512−1082
plugins/Unity/Indicators/unitymenumodelcache.cpp−1 plugins/Unity/Indicators/unitymenumodelcache.h+2−2 qml/Components/DragHandle.qml+6−1 qml/Components/ScrollCalculator.qml+97 qml/Panel/Handle.qml+27 qml/Panel/IndicatorItem.qml+229−23 qml/Panel/IndicatorItemRow.qml+244 qml/Panel/Indicators/IndicatorBase.qml+2−4 qml/Panel/IndicatorsBar.qml+252 qml/Panel/IndicatorsMenu.qml+277 qml/Panel/New/IndicatorItem.qml−252 qml/Panel/New/IndicatorsBar.qml−158 qml/Panel/New/IndicatorsRow.qml−142 qml/Panel/Old/IndicatorItem.qml+47 qml/Panel/IndicatorRow.qml → qml/Panel/Old/IndicatorRow.qml qml/Panel/Indicators.qml → qml/Panel/Old/Indicators.qml+1 qml/Panel/Old/Panel.qml+191 qml/Panel/Panel.qml+15−20 qml/Shell.qml+3−1 tests/mocks/Unity/Indicators/IndicatorsModel.qml+83−25 tests/mocks/Unity/Indicators/RootActionState.qml+1−1 tests/mocks/Unity/Indicators/fakeindicatorsmodel.cpp+33−5 tests/mocks/Unity/Indicators/fakeindicatorsmodel.h+2 tests/mocks/Unity/Indicators/fakeunitymenumodelcache.cpp+18−5 tests/mocks/Unity/Indicators/fakeunitymenumodelcache.h+10−2 tests/qmltests/CMakeLists.txt+3−4 tests/qmltests/Panel/New/IndicatorTest.qml+153 tests/qmltests/Panel/New/tst_NewIndicatorItem.qml+146−59 tests/qmltests/Panel/New/tst_NewIndicatorItemRow.qml+270 tests/qmltests/Panel/New/tst_NewIndicatorsBar.qml+131−195 tests/qmltests/Panel/New/tst_NewIndicatorsMenu.qml+171 tests/qmltests/Panel/New/tst_NewIndicatorsRow.qml−182 tests/qmltests/Panel/New/tst_NewPanel.qml+98
plugins/Unity/Indicators/unitymenumodelcache.cpp−1
@@ -24,7 +24,6 @@
2424
2525UnityMenuModelCache* UnityMenuModelCache::theCache = nullptr;
2626
27−
2827UnityMenuModelCache* UnityMenuModelCache::singleton()
2928{
3029 if (!theCache) {
plugins/Unity/Indicators/unitymenumodelcache.h+2−2
@@ -36,12 +36,12 @@ public:
3636
3737 static UnityMenuModelCache* singleton();
3838
39− QSharedPointer<UnityMenuModel> model(const QByteArray& bus,
39+ virtual QSharedPointer<UnityMenuModel> model(const QByteArray& bus,
4040 const QByteArray& path,
4141 const QVariantMap& actions);
4242
4343 // for tests use
44− Q_INVOKABLE bool contains(const QByteArray& path);
44+ Q_INVOKABLE virtual bool contains(const QByteArray& path);
4545
4646protected:
4747 QHash<QByteArray, QWeakPointer<UnityMenuModel>> m_registry;
qml/Components/DragHandle.qml+6−1
@@ -68,6 +68,7 @@ EdgeDragArea {
6868 }
6969
7070 property real hintDisplacement: 0
71+ property var overrideStartValue: undefined
7172 SmoothedAnimation {
7273 id: hintingAnimation
7374 target: hintingAnimation
@@ -196,7 +197,11 @@ EdgeDragArea {
196197 } else /* Undecided || Recognized */ {
197198 if (d.previousStatus === DirectionalDragArea.WaitingForTouch) {
198199 dragEvaluator.reset();
199− d.startValue = parent[d.targetProp];
200+ if (overrideStartValue !== undefined) {
201+ d.startValue = overrideStartValue;
202+ } else {
203+ d.startValue = parent[d.targetProp];
204+ }
200205
201206 if (hintDisplacement > 0) {
202207 hintingAnimation.targetValue = d.startValue;
qml/Components/ScrollCalculator.qmlnew file+97
@@ -0,0 +1,97 @@
1+import QtQuick 2.0
2+import Ubuntu.Components 0.1
3+
4+Item {
5+ id: scrollArea
6+
7+ property real __previousMouseX: -1
8+ property real __progression: 0
9+ property real __previousMouseXHelper: -1
10+ property real thresholdAreaWidth: units.gu(1)
11+ property bool showDebugRectangles: false
12+ property int direction: Qt.LeftToRight
13+ property real baseScrollAmount: units.dp(2)
14+ property real maximumScrollAmount: units.dp(6)
15+
16+ property real lateralPosition: -1
17+ readonly property bool areaActive: lateralPosition >= 0
18+ onAreaActiveChanged: {
19+ if (areaActive) {
20+ handleEnter()
21+ } else {
22+ handleExit()
23+ }
24+ }
25+
26+ // from 0 to 1
27+ property real forceScrollingPercentage: 0.4
28+ signal scroll(real scrollAmount)
29+
30+ width: 200
31+ height: 200
32+ rotation: direction == Qt.LeftToRight ? 0 : 180
33+
34+ function handleEnter() {
35+ thresholdRect.x = -scrollArea.thresholdAreaWidth
36+ scrollTimer.restart()
37+ }
38+ onLateralPositionChanged: {
39+ if (scrollArea.areaActive) {
40+
41+ // store the previous x value
42+ __previousMouseX = __previousMouseXHelper
43+ __previousMouseXHelper = lateralPosition
44+
45+ if (lateralPosition > width * (1 - forceScrollingPercentage)) {
46+ thresholdRect.x = width * (1 - forceScrollingPercentage)
47+ if (!scrollTimer.running) scrollTimer.restart()
48+ } else if (lateralPosition > thresholdRect.x + thresholdRect.width) {
49+ thresholdRect.x = lateralPosition - thresholdRect.width
50+ if (!scrollTimer.running) scrollTimer.restart()
51+ } else if (lateralPosition < thresholdRect.x) {
52+ thresholdRect.x = lateralPosition
53+ scrollTimer.stop()
54+ }
55+
56+ __progression = lateralPosition / width
57+ }
58+ }
59+
60+ function handleExit() {
61+ thresholdRect.x = -scrollArea.thresholdAreaWidth
62+ scrollTimer.stop()
63+ }
64+
65+ Timer {
66+ id: scrollTimer
67+ interval: 5
68+ repeat: true
69+ onTriggered: scrollArea.scroll(scrollArea.baseScrollAmount + scrollArea.maximumScrollAmount*scrollArea.__progression)
70+ }
71+
72+ Rectangle {
73+ color: "yellow"
74+ opacity: 0.2
75+ anchors.fill: scrollArea
76+ visible: showDebugRectangles
77+ }
78+
79+ Rectangle {
80+ color: "red"
81+ opacity: 0.2
82+ height: scrollArea.height
83+ width: scrollArea.width * forceScrollingPercentage
84+ anchors.right: parent.right
85+ visible: showDebugRectangles
86+ }
87+
88+ Rectangle {
89+ id: thresholdRect
90+ opacity: 0.4
91+ height: parent.height
92+ width: scrollArea.thresholdAreaWidth
93+ x: -scrollArea.thresholdAreaWidth
94+ color: showDebugRectangles ? "blue" : "transparent"
95+ }
96+
97+}
qml/Panel/Handle.qmlnew file+27
@@ -0,0 +1,27 @@
1+import QtQuick 2.0
2+import Ubuntu.Components 0.1
3+
4+Rectangle {
5+ id: handle
6+ color: "#333333"
7+ height: units.gu(2)
8+ property bool active: false
9+
10+ Row {
11+ id: dots
12+ width: childrenRect.width
13+ height: children.height
14+ anchors.centerIn: parent
15+ spacing: units.gu(0.5)
16+ Repeater {
17+ model: 3
18+ delegate: Rectangle {
19+ id: dot
20+ width: units.gu(0.33)
21+ height: width
22+ color: handle.active ? "#de4814" : "#717171"
23+ radius: units.dp(1)
24+ }
25+ }
26+ }
27+}
qml/Panel/IndicatorItem.qml+229−23
@@ -1,47 +1,253 @@
11/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright 2013 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
5+ * it under the terms of the GNU Lesser General Public License as published by
66 * the Free Software Foundation; version 3.
77 *
88 * This program is distributed in the hope that it will be useful,
99 * but WITHOUT ANY WARRANTY; without even the implied warranty of
1010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
11+ * GNU Lesser General Public License for more details.
1212 *
13− * You should have received a copy of the GNU General Public License
13+ * You should have received a copy of the GNU Lesser General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
1518 */
1619
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import Unity.Indicators 0.1 as Indicators
20−import "../Components"
20+import QtQuick 2.1
21+import Ubuntu.Components 1.1
22+import Ubuntu.Settings.Components 0.1
23+import "Indicators"
2124
22−Loader {
25+IndicatorDelegate {
2326 id: root
2427
25− property alias widgetSource: root.source
26− property bool dimmed: false
27− property var indicatorProperties: undefined
28− property bool indicatorVisible: item ? item.enabled : false
2928 property string identifier
29+ property string title: indicatorName.text
30+ property alias leftLabel: leftLabelItem.text
31+ property alias rightLabel: rightLabelItem.text
32+ property var icons: undefined
33+ property bool expanded: false
34+ property bool selected: false
35+ property real iconHeight: units.gu(2)
36+ readonly property color color: {
37+ if (!expanded) return Theme.palette.normal.foregroundText;
38+ if (!selected) return Theme.palette.selected.backgroundText;
39+ return Theme.palette.normal.foregroundText;
40+ }
41+
42+ signal clicked()
43+
44+ width: mainItems.width
45+
46+ MouseArea {
47+ anchors.fill: parent
48+ onClicked: parent.clicked()
49+ }
50+
51+ // FIXME: For now we will enable led indicator support only for messaging indicator
52+ // in the future we should export a led API insted of doing that,
53+ Loader {
54+ id: indicatorLed
55+ // only load source Component if the icons contains the new message icon
56+ source: (root.icons && (String(root.icons).indexOf("indicator-messages-new") != -1)) ? Qt.resolvedUrl("Indicators/IndicatorsLight.qml") : ""
57+ }
58+
59+ Item {
60+ id: mainItems
61+ anchors.centerIn: parent
62+
63+ width: leftLabelItem.width + iconsItem.width + rightLabelItem.width
64+ implicitHeight: units.gu(2)
65+
66+ Label {
67+ id: leftLabelItem
68+ objectName: "leftLabel"
3069
31− opacity: dimmed ? 0.4 : 1
32− Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.BriskDuration } }
70+ anchors {
71+ left: mainItems.left
72+ verticalCenter: parent.verticalCenter
73+ }
74+ width: contentWidth > 0 ? contentWidth + units.gu(1) : 0
75+ horizontalAlignment: Text.AlignHCenter
76+
77+ opacity: 1.0
78+ font.family: "Ubuntu"
79+ fontSize: "medium"
80+ color: root.color
81+ Behavior on color { ColorAnimation { duration: UbuntuAnimation.SnapDuration } }
82+ }
3383
34− onLoaded: {
35− for(var pName in indicatorProperties) {
36− if (item.hasOwnProperty(pName)) {
37− item[pName] = indicatorProperties[pName];
84+ Item {
85+ id: iconsItem
86+ objectName: "icons"
87+
88+ width: iconRow.width > 0 ? iconRow.width + units.gu(1) : 0
89+ anchors {
90+ left: leftLabelItem.right
91+ verticalCenter: parent.verticalCenter
92+ }
93+
94+ Row {
95+ id: iconRow
96+ anchors.centerIn: iconsItem
97+ spacing: units.gu(1)
98+
99+ Repeater {
100+ id: iconRepeater
101+ objectName: "iconRepeater"
102+
103+ model: d.useFallbackIcon ? [ "image://theme/settings" ] : root.icons
104+
105+ StatusIcon {
106+ id: itemImage
107+ height: iconHeight
108+ source: modelData
109+ sets: ["status", "actions"]
110+ color: root.color
111+ Behavior on color { ColorAnimation{ duration: UbuntuAnimation.SnapDuration } }
112+ }
113+ }
38114 }
39115 }
116+
117+ Label {
118+ id: rightLabelItem
119+ objectName: "rightLabel"
120+
121+ anchors {
122+ left: iconsItem.right
123+ verticalCenter: parent.verticalCenter
124+ }
125+ width: contentWidth > 0 ? contentWidth + units.gu(1) : 0
126+ horizontalAlignment: Text.AlignHCenter
127+
128+ opacity: 1.0
129+ font.family: "Ubuntu"
130+ fontSize: "medium"
131+ color: root.color
132+ Behavior on color { ColorAnimation{ duration: UbuntuAnimation.SnapDuration } }
133+ }
40134 }
41135
42− Binding {
43− target: item
44− property: "objectName"
45− value: identifier + "-widget"
136+ Label {
137+ id: indicatorName
138+ objectName: "indicatorName"
139+
140+ anchors.top: mainItems.bottom
141+ anchors.topMargin: units.gu(0.5)
142+ anchors.horizontalCenter: parent.horizontalCenter
143+ width: contentWidth > 0 ? contentWidth + units.gu(1) : 0
144+
145+ text: title !== "" ? title : identifier
146+ fontSize: "x-small"
147+ horizontalAlignment: Text.AlignHCenter
148+ opacity: 0
149+ color: root.color
150+ Behavior on color { ColorAnimation{ duration: UbuntuAnimation.SnapDuration } }
151+ }
152+
153+ StateGroup {
154+ id: d
155+ property bool useFallbackIcon: false
156+
157+ states: [
158+ State {
159+ name: "minimised"
160+ when: !expanded && ((icons && icons.length > 0) || leftLabel !== "" || rightLabel !== "")
161+ PropertyChanges { target: indicatorName; opacity: 0}
162+ },
163+
164+ State {
165+ name: "minimised_fallback"
166+ when: !expanded && (!icons || icons.length === 0) && leftLabel == "" && rightLabel == ""
167+ PropertyChanges { target: indicatorName; opacity: 0}
168+ PropertyChanges { target: d; useFallbackIcon: true }
169+ },
170+
171+ State {
172+ name: "expanded"
173+ PropertyChanges { target: indicatorName; visible: true; opacity: 1}
174+ PropertyChanges { target: mainItems; anchors.verticalCenterOffset: -units.gu(1) }
175+ },
176+
177+ State {
178+ name: "expanded_icon"
179+ extend: "expanded"
180+ when: expanded && (icons && icons.length > 0)
181+ AnchorChanges { target: iconsItem; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
182+ AnchorChanges { target: leftLabelItem; anchors.left: undefined; anchors.right: iconsItem.left }
183+ PropertyChanges { target: leftLabelItem; opacity: 0 }
184+ PropertyChanges { target: leftLabelItem; opacity: 0 }
185+ PropertyChanges { target: rightLabelItem; opacity: 0 }
186+ PropertyChanges { target: root; width: Math.max(units.gu(10), Math.max(iconsItem.width, indicatorName.width)) }
187+ },
188+
189+ State {
190+ name: "expanded_fallback"
191+ extend: "expanded"
192+ when: expanded && (!icons || icons.length === 0) && leftLabel == "" && rightLabel == ""
193+ PropertyChanges { target: d; useFallbackIcon: true }
194+ AnchorChanges { target: iconsItem; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
195+ AnchorChanges { target: leftLabelItem; anchors.left: undefined; anchors.right: iconsItem.left }
196+ PropertyChanges { target: leftLabelItem; opacity: 0 }
197+ PropertyChanges { target: leftLabelItem; opacity: 0 }
198+ PropertyChanges { target: rightLabelItem; opacity: 0 }
199+ PropertyChanges { target: root; width: Math.max(units.gu(10), Math.max(iconsItem.width, indicatorName.width)) }
200+ },
201+
202+ State {
203+ name: "expanded_rightLabel"
204+ extend: "expanded"
205+ when: expanded && (!icons || icons.length === 0) && rightLabel !== ""
206+ AnchorChanges { target: rightLabelItem; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
207+ PropertyChanges { target: iconsItem; opacity: 0 }
208+ PropertyChanges { target: leftLabelItem; opacity: 0 }
209+ PropertyChanges { target: root; width: Math.max(units.gu(10), Math.max(rightLabelItem.width, indicatorName.width)) }
210+ },
211+
212+ State {
213+ name: "expanded_leftLabel"
214+ extend: "expanded"
215+ when: expanded && (!icons || icons.length === 0) && leftLabel !== ""
216+ AnchorChanges { target: leftLabelItem; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
217+ PropertyChanges { target: iconsItem; opacity: 0 }
218+ PropertyChanges { target: rightLabelItem; opacity: 0 }
219+ PropertyChanges { target: root; width: Math.max(units.gu(10), Math.max(leftLabelItem.width, indicatorName.width)) }
220+ }
221+ ]
222+
223+ transitions: [
224+ Transition {
225+ PropertyAction { target: d; property: "useFallbackIcon" }
226+ AnchorAnimation {
227+ targets: [ mainItems, iconsItem, leftLabelItem, rightLabelItem ]
228+ duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing
229+ }
230+ PropertyAnimation {
231+ targets: [ root, mainItems, iconsItem, leftLabelItem, rightLabelItem, indicatorName ]
232+ properties: "width, opacity, anchors.verticalCenterOffset";
233+ duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing
234+ }
235+ }
236+ ]
237+ }
238+
239+ onRootActionStateChanged: {
240+ if (rootActionState == undefined) {
241+ title = "";
242+ leftLabel = "";
243+ rightLabel = "";
244+ icons = undefined;
245+ return;
246+ }
247+
248+ title = rootActionState.title ? rootActionState.title : "";
249+ leftLabel = rootActionState.leftLabel ? rootActionState.leftLabel : "";
250+ rightLabel = rootActionState.rightLabel ? rootActionState.rightLabel : "";
251+ icons = rootActionState.icons;
46252 }
47253}
qml/Panel/IndicatorItemRow.qmlnew file+244
@@ -0,0 +1,244 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.1
18+import Ubuntu.Components 0.1
19+
20+Item {
21+ id: root
22+
23+ property QtObject indicatorsModel: null
24+ property real overFlowWidth: width
25+ property bool showAll: false
26+ property bool expanded: false
27+ property var currentItem: null
28+ readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
29+
30+ property real unitProgress: 0.0
31+ property real selectionChangeBuffer: units.gu(2)
32+ property bool enableLateralChanges: false
33+
34+ property real lateralPosition: -1
35+ onLateralPositionChanged: {
36+ if (lateralPosition == -1) return;
37+
38+ if (!currentItem) {
39+ selectItemAt(lateralPosition);
40+ return;
41+ }
42+
43+ if (!enableLateralChanges) return;
44+
45+ var maximumBufferOffset = selectionChangeBuffer * unitProgress;
46+ var proposedItem = indicatorAt(lateralPosition, 0);
47+ if (proposedItem) {
48+ var bufferExceeded = false;
49+
50+ if (proposedItem !== currentItem) {
51+ if (Math.abs(currentItem.ownIndex - currentItem.ownIndex) > 1) {
52+ bufferExceeded = true;
53+ } else {
54+ var currentItemLateralPosition = root.mapToItem(proposedItem, lateralPosition, 0).x;
55+
56+ // is the distance into proposed item greater than max buffer?
57+ // proposed item is before current item
58+ if (proposedItem.x < currentItem.x) {
59+ bufferExceeded = (proposedItem.width - currentItemLateralPosition) > maximumBufferOffset;
60+ } else { // after
61+ bufferExceeded = currentItemLateralPosition > maximumBufferOffset;
62+ }
63+ }
64+ if (bufferExceeded) {
65+ selectItemAt(lateralPosition);
66+ }
67+ }
68+ } else {
69+ selectItemAt(lateralPosition);
70+ }
71+ }
72+
73+ width: row.width
74+ height: units.gu(3)
75+
76+ function indicatorAt(x, y) {
77+ var item = row.childAt(x, y);
78+ return item && item.hasOwnProperty("ownIndex") ? item : null
79+ }
80+
81+ function resetCurrentItem() {
82+ currentItem = null;
83+ d.previousItem = null;
84+ d.firstItemSwitch = true;
85+ }
86+
87+ function setCurrentItemIndex(index) {
88+ for (var i = 0; i < row.children.length; i++) {
89+ if (row.children[i].hasOwnProperty("ownIndex") &&
90+ row.children[i].ownIndex === index) {
91+ currentItem = item;
92+ break;
93+ }
94+ }
95+ }
96+
97+ function selectItemAt(lateralPosition) {
98+ var item = indicatorAt(lateralPosition, 0);
99+ if (item && item.opacity > 0) {
100+ currentItem = item;
101+ } else {
102+ var searchIndex = lateralPosition > width ? repeater.count-1 : 0;
103+
104+ for (var i = 0; i < row.children.length; i++) {
105+ if (row.children[i].hasOwnProperty("ownIndex") &&
106+ row.children[i].ownIndex === searchIndex) {
107+ item = row.children[i];
108+ break;
109+ }
110+ }
111+ currentItem = item;
112+ }
113+ }
114+
115+ QtObject {
116+ id: d
117+ property bool firstItemSwitch: true
118+ property var previousItem: null
119+ }
120+
121+ onCurrentItemChanged: {
122+ if (d.previousItem) {
123+ d.firstItemSwitch = false;
124+ }
125+ d.previousItem = currentItem;
126+ }
127+
128+ Timer {
129+ id: allVisible
130+ interval: 1000
131+
132+ onTriggered: {
133+ showAll = false;
134+ }
135+ }
136+
137+ Row {
138+ id: row
139+ anchors {
140+ top: parent.top
141+ bottom: parent.bottom
142+ }
143+
144+ Repeater {
145+ id: repeater
146+ model: indicatorsModel
147+ visible: false
148+
149+ delegate: IndicatorItem {
150+ id: item
151+ objectName: identifier+"-panelItem"
152+
153+ property int ownIndex: index
154+ property bool overflow: row.width - x > overFlowWidth
155+ property bool hidden: !item.expanded && overflow
156+
157+ height: row.height
158+ expanded: root.expanded
159+ selected: currentItem === this
160+
161+ identifier: model.identifier
162+ busName: indicatorProperties.busName
163+ actionsObjectPath: indicatorProperties.actionsObjectPath
164+ menuObjectPath: indicatorProperties.menuObjectPath
165+
166+ opacity: hidden ? 0.0 : 1.0
167+ Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
168+ }
169+ }
170+ }
171+
172+ Rectangle {
173+ id: highlight
174+ objectName: "highlight"
175+
176+ // micromovements of the highlight line when user moves the finger across the items while pulling
177+ // the handle downwards.
178+ property real highlightCenterOffset: {
179+ if (!currentItem || lateralPosition == -1) return 0;
180+ if (!enableLateralChanges) return 0;
181+
182+ var itemMapped = root.mapToItem(currentItem, lateralPosition, 0);
183+
184+ var distanceFromCenter = itemMapped.x - currentItem.width/2;
185+ if (distanceFromCenter > 0) {
186+ distanceFromCenter = Math.max(0, distanceFromCenter-currentItem.width/8);
187+ } else {
188+ distanceFromCenter = Math.min(0, distanceFromCenter+currentItem.width/8);
189+ }
190+
191+ if (currentItem && currentItem.ownIndex === 0 && distanceFromCenter < 0) {
192+ return 0;
193+ } else if (currentItem && currentItem.ownIndex == repeater.count-1 & distanceFromCenter > 0) {
194+ return 0;
195+ }
196+
197+ var shiftPercentageOffset = (distanceFromCenter / (currentItem.width/4));
198+ return shiftPercentageOffset * units.gu(1);
199+ }
200+ Behavior on highlightCenterOffset {
201+ SmoothedAnimation {duration:UbuntuAnimation.FastDuration; velocity: 50}
202+ }
203+
204+ anchors.bottom: row.bottom
205+ height: units.dp(2)
206+ width: currentItem ? currentItem.width : 0
207+ color: Theme.palette.normal.foregroundText
208+ visible: root.currentItem !== null
209+ opacity: 0.0
210+
211+ property real currentItemX: currentItem ? currentItem.x : 0 // having Behavior
212+ Behavior on x {
213+ id: currentItemXBehavior
214+ enabled: !d.firstItemSwitch && expanded
215+ UbuntuNumberAnimation {
216+ duration: UbuntuAnimation.FastDuration;
217+ easing: UbuntuAnimation.StandardEasing
218+ }
219+ }
220+ x: currentItemX + highlightCenterOffset
221+ }
222+
223+ states: [
224+ State {
225+ name: "minimised"
226+ when: !expanded
227+ },
228+ State {
229+ name: "expanded"
230+ when: expanded
231+ PropertyChanges { target: highlight; opacity: 0.9 }
232+ }
233+ ]
234+
235+ transitions: [
236+ Transition {
237+ PropertyAnimation {
238+ properties: "opacity";
239+ duration: UbuntuAnimation.SnapDuration;
240+ easing: UbuntuAnimation.StandardEasing
241+ }
242+ }
243+ ]
244+}
qml/Panel/Indicators/IndicatorBase.qml+2−4
@@ -23,7 +23,7 @@ import Unity.Indicators 0.1
2323Item {
2424 id: indicatorItem
2525
26− enabled: menuObjectPath != ""
26+ enabled: menuObjectPath !== ""
2727
2828 //const
2929 property string busName
@@ -31,8 +31,6 @@ Item {
3131 property string menuObjectPath
3232 property string rootMenuType: "com.canonical.indicator.root"
3333
34− property string deviceMenuObjectPath: menuObjectPath
35−
3634 property alias menuModel: cachedModel.model
3735 property alias rootActionState: rootAction
3836
@@ -40,7 +38,7 @@ Item {
4038 id: cachedModel
4139 busName: indicatorItem.busName
4240 actions: { "indicator": indicatorItem.actionsObjectPath }
43− menuObjectPath: indicatorItem.deviceMenuObjectPath
41+ menuObjectPath: indicatorItem.menuObjectPath
4442 }
4543
4644 RootActionState {
qml/Panel/IndicatorsBar.qmlnew file+252
@@ -0,0 +1,252 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import "../Components"
20+
21+Item {
22+ id: root
23+ property alias expanded: row.expanded
24+ property alias indicatorsModel: row.indicatorsModel
25+ property alias unitProgress: row.unitProgress
26+ property real lateralPosition: -1
27+ property alias enableLateralChanges: row.enableLateralChanges
28+ property alias overFlowWidth: row.overFlowWidth
29+
30+ function selectItemAt(lateralPosition) {
31+ if (!expanded) {
32+ row.resetCurrentItem();
33+ }
34+ var mapped = root.mapToItem(row, lateralPosition, 0);
35+ row.selectItemAt(mapped.x);
36+ }
37+
38+ function setCurrentItemIndex(index) {
39+ if (!expanded) {
40+ row.resetCurrentItem();
41+ }
42+ row.setCurrentItemIndex(index);
43+ }
44+
45+ function addScrollOffset(scrollAmmout) {
46+ var proposedScrollOffset = d.scrollOffset + scrollAmmout;
47+ var proposedCombinedOffset = d.combinedOffset - scrollAmmout
48+
49+ if (scrollAmmout < 0 && d.combinedOffset > (row.width - rowContainer.width)) return;
50+
51+ if (scrollAmmout > 0 && proposedCombinedOffset < 0) {
52+ // get the combined offset back to 0
53+ proposedScrollOffset = proposedScrollOffset + proposedCombinedOffset
54+ } else if (scrollAmmout < 0 && proposedCombinedOffset > row.width - rowContainer.width) {
55+ // get the combined offset back to max
56+ proposedScrollOffset = proposedScrollOffset + (proposedCombinedOffset - (row.width - rowContainer.width));
57+ }
58+
59+ d.scrollOffset = proposedScrollOffset;
60+ }
61+
62+ QtObject {
63+ id: d
64+ property var initialItem: null
65+ // the non-expanded distance from row offset to center of initial item
66+ property real originalDistanceFromRight: -1
67+ property real originalItemWidth: -1
68+
69+ // calculate the distance from row offset to center of initial item
70+ property real distanceFromRight: {
71+ if (originalDistanceFromRight == -1) return 0;
72+ if (!initialItem) return 0;
73+ return row.width - initialItem.x - initialItem.width /2;
74+ }
75+
76+ // offset to the intially selected expanded item
77+ property real rowOffset: 0
78+ property real rowOffsetAdjustment: 0
79+ property real scrollOffset: 0
80+ property real combinedOffset: rowOffset + rowOffsetAdjustment - scrollOffset
81+
82+ onInitialItemChanged: {
83+ if (initialItem) {
84+ originalItemWidth = initialItem.width;
85+ originalDistanceFromRight = row.width - initialItem.x - initialItem.width/2;
86+ } else {
87+ originalItemWidth = -1;
88+ originalDistanceFromRight = -1;
89+ }
90+ }
91+
92+ Behavior on rowOffsetAdjustment { NumberAnimation { duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing} }
93+ }
94+
95+ onExpandedChanged: {
96+ if (!expanded) flickable.moved = false;
97+ }
98+
99+ Connections {
100+ target: row
101+ onCurrentItemChanged: {
102+ if (!row.currentItem) d.initialItem = null;
103+ else if (!d.initialItem) d.initialItem = row.currentItem;
104+ }
105+ }
106+
107+ Rectangle {
108+ id: grayLine
109+ height: units.dp(2)
110+ width: parent.width
111+ anchors.bottom: parent.bottom
112+
113+ color: Theme.palette.selected.backgroundText
114+ opacity: expanded ? 1.0 : 0.0
115+ Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
116+ }
117+
118+ Item {
119+ id: rowContainer
120+ anchors.fill: parent
121+ clip: expanded || row.width > rowContainer.width
122+
123+ IndicatorItemRow {
124+ id: row
125+ objectName: "indicatorRow"
126+ anchors {
127+ top: parent.top
128+ bottom: parent.bottom
129+ right: parent.right
130+ rightMargin: -d.combinedOffset
131+ }
132+
133+ lateralPosition: {
134+ if (root.lateralPosition == -1) return -1;
135+ // just to automatically invoke this calculation when scrolling offset changes
136+ var dummyvar = d.scrollOffset + row.width;
137+
138+ var mapped = root.mapToItem(row, root.lateralPosition, 0);
139+ return mapped.x;
140+ }
141+ }
142+
143+ Flickable {
144+ id: flickable
145+ anchors.fill: parent
146+ contentWidth: row.width
147+ interactive: root.expanded
148+
149+ property bool moved: false
150+ onMovingChanged: { moved = true }
151+
152+ rebound: Transition {
153+ NumberAnimation {
154+ properties: "x"
155+ duration: 600
156+ easing.type: Easing.OutCubic
157+ }
158+ }
159+
160+ MouseArea {
161+ anchors.fill: parent
162+ enabled: root.expanded
163+ onClicked: row.selectItemAt(mouse.x);
164+ }
165+ }
166+ }
167+
168+ states: [
169+ State {
170+ name: "minimized"
171+ when: !expanded
172+ PropertyChanges {
173+ target: d
174+ rowOffset: 0
175+ rowOffsetAdjustment: 0
176+ scrollOffset: 0
177+ restoreEntryValues: false
178+ }
179+ },
180+ State {
181+ name: "expanded"
182+ when: expanded && !flickable.moved
183+
184+ PropertyChanges {
185+ target: d
186+ rowOffset: {
187+ if (!initialItem) return 0;
188+ if (distanceFromRight - initialItem.width <= 0) return 0;
189+
190+ var rowOffset = distanceFromRight - originalDistanceFromRight;
191+ return rowOffset;
192+ }
193+ rowOffsetAdjustment: {
194+ if (originalDistanceFromRight + originalItemWidth/2 > rowContainer.width) {
195+ return originalItemWidth;
196+ }
197+ return 0;
198+ }
199+ }
200+ // keep flickable inline with row
201+ PropertyChanges {
202+ target: flickable
203+ contentX: (flickable.contentWidth - flickable.width) - d.combinedOffset;
204+ restoreEntryValues: false
205+ }
206+ },
207+ State {
208+ name: "moved"
209+ when: expanded && flickable.moved
210+
211+ StateChangeScript {
212+ script: {
213+ // unbind contentX
214+ flickable.contentX = flickable.contentX;
215+ d.scrollOffset = 0;
216+ }
217+ }
218+ PropertyChanges {
219+ target: row
220+ anchors.rightMargin: - (flickable.contentWidth - flickable.width) + (flickable.contentX) + d.scrollOffset
221+ }
222+ }
223+ ]
224+
225+ transitions: [
226+ Transition {
227+ from: "expanded"
228+ to: "minimized"
229+ SequentialAnimation {
230+ PropertyAnimation {
231+ target: d;
232+ properties: "rowOffset, scrollOffset";
233+ duration: UbuntuAnimation.SnapDuration;
234+ easing: UbuntuAnimation.StandardEasing
235+ }
236+ }
237+ },
238+ Transition {
239+ from: "moved"
240+ to: "minimized"
241+ SequentialAnimation {
242+ PropertyAction { target: d; properties: "rowOffset, rowOffsetAdjustment, scrollOffset" }
243+ PropertyAnimation {
244+ target: row;
245+ properties: "anchors.rightMargin";
246+ duration: UbuntuAnimation.SnapDuration;
247+ easing: UbuntuAnimation.StandardEasing
248+ }
249+ }
250+ }
251+ ]
252+}
qml/Panel/IndicatorsMenu.qmlnew file+277
@@ -0,0 +1,277 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import Ubuntu.Gestures 0.1
20+import "../Components"
21+
22+Showable {
23+ id: root
24+ property int minimizedPanelHeight: units.gu(3)
25+ property int expandedPanelHeight: units.gu(7)
26+ property real openedHeight: units.gu(71)
27+ readonly property int lockThreshold: openedHeight / 2
28+ property alias indicatorsModel: bar.indicatorsModel
29+ property alias overFlowWidth: bar.overFlowWidth
30+ property bool enableHint: true
31+ property real showHintBottomMargin: 0
32+ readonly property bool fullyOpened: unitProgress >= 1
33+ readonly property bool partiallyOpened: unitProgress > 0 && unitProgress < 1.0
34+ readonly property bool fullyClosed: unitProgress == 0
35+ readonly property real unitProgress: Math.max(0, (height - minimizedPanelHeight - orangeLine.height) /
36+ (openedHeight - minimizedPanelHeight - orangeLine.height))
37+ property color panelColor: "black"
38+
39+ signal showTapped(point position)
40+
41+ // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
42+ // use its own values. Need to ask design about this.
43+ showAnimation: StandardAnimation {
44+ property: "height"
45+ to: openedHeight
46+ duration: UbuntuAnimation.SlowDuration
47+ easing.type: Easing.OutCubic
48+ }
49+
50+ hideAnimation: StandardAnimation {
51+ property: "height"
52+ to: minimizedPanelHeight + orangeLine.height
53+ duration: UbuntuAnimation.SlowDuration
54+ easing.type: Easing.OutCubic
55+ }
56+
57+ height: minimizedPanelHeight + orangeLine.height
58+ onHeightChanged: {
59+ var revealProgress = root.height - minimizedPanelHeight - orangeLine.height - showHintBottomMargin;
60+
61+ if (!showAnimation.running && !hideAnimation.running) {
62+ if (revealProgress === 0) {
63+ root.state = "initial";
64+ } else if ((revealProgress > 0) && revealProgress < lockThreshold) {
65+ root.state = "reveal";
66+ } else {
67+ root.state = "locked";
68+ }
69+ }
70+ }
71+
72+ Rectangle {
73+ id: content
74+ visible: !fullyClosed
75+ color: "#221e1c"
76+ anchors {
77+ left: parent.left
78+ right: parent.right
79+ bottom: handle.top
80+ }
81+ height: openedHeight - bar.height - handle.height - orangeLine.height
82+ }
83+
84+ Handle {
85+ id: handle
86+ anchors {
87+ left: parent.left
88+ right: parent.right
89+ bottom: orangeLine.top
90+ }
91+ height: units.gu(2)
92+ active: d.activeDragHandle ? true : false
93+ }
94+
95+ Rectangle {
96+ anchors.fill: bar
97+ color: panelColor
98+ }
99+
100+ IndicatorsBar {
101+ id: bar
102+ anchors {
103+ left: parent.left
104+ right: parent.right
105+ }
106+ expanded: false
107+ lateralPosition: -1
108+ unitProgress: root.unitProgress
109+
110+ height: expanded ? expandedPanelHeight : minimizedPanelHeight
111+ Behavior on height { NumberAnimation { duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing } }
112+ }
113+
114+ ScrollCalculator {
115+ id: leftScroller
116+ width: units.gu(5)
117+ anchors.left: bar.left
118+ height: bar.height
119+
120+ forceScrollingPercentage: 0.3
121+ thresholdAreaWidth: units.gu(0.5)
122+ direction: Qt.RightToLeft
123+ lateralPosition: -1
124+
125+ onScroll: bar.addScrollOffset(-scrollAmount);
126+ }
127+
128+ ScrollCalculator {
129+ id: rightScroller
130+ width: units.gu(5)
131+ anchors.right: bar.right
132+ height: bar.height
133+
134+ forceScrollingPercentage: 0.3
135+ thresholdAreaWidth: units.gu(0.5)
136+ direction: Qt.LeftToRight
137+ lateralPosition: -1
138+
139+ onScroll: bar.addScrollOffset(scrollAmount);
140+ }
141+
142+ PanelSeparatorLine {
143+ id: orangeLine
144+ width: parent.width
145+ anchors.bottom: parent.bottom
146+ }
147+
148+ DragHandle {
149+ id: showDragHandle
150+ anchors.bottom: parent.bottom
151+ // go beyond parent so that it stays reachable, at the top of the screen.
152+ anchors.bottomMargin: showHintBottomMargin
153+ anchors.left: parent.left
154+ anchors.right: parent.right
155+ height: minimizedPanelHeight
156+ direction: Direction.Downwards
157+ enabled: !root.shown && root.available
158+ autoCompleteDragThreshold: maxTotalDragDistance / 2
159+ stretch: true
160+ distanceThreshold: minimizedPanelHeight
161+
162+ // using hint regulates minimum to hint displacement, but in fullscreen mode, we need to do it manually.
163+ overrideStartValue: enableHint ? undefined : expandedPanelHeight + d.handleHeight
164+ maxTotalDragDistance: openedHeight - (enableHint ? minimizedPanelHeight : expandedPanelHeight + handle.height) - orangeLine.height
165+ hintDisplacement: enableHint ? expandedPanelHeight - minimizedPanelHeight + handle.height : 0
166+ onTapped: showTapped(Qt.point(touchSceneX, touchSceneY));
167+ }
168+
169+ DragHandle {
170+ id: hideDragHandle
171+ anchors.fill: handle
172+ direction: Direction.Upwards
173+ enabled: root.shown && root.available
174+ hintDisplacement: units.gu(3)
175+ autoCompleteDragThreshold: maxTotalDragDistance / 6
176+ stretch: true
177+ maxTotalDragDistance: openedHeight - expandedPanelHeight - d.handleHeight
178+ distanceThreshold: 0
179+ }
180+
181+ AxisVelocityCalculator {
182+ id: yVelocityCalculator
183+ }
184+
185+ Connections {
186+ target: showAnimation
187+ onRunningChanged: {
188+ if (showAnimation.running) {
189+ root.state = "commit";
190+ }
191+ }
192+ }
193+
194+ Connections {
195+ target: hideAnimation
196+ onRunningChanged: {
197+ if (hideAnimation.running) {
198+ root.state = "initial";
199+ }
200+ }
201+ }
202+
203+ QtObject {
204+ id: d
205+ property bool enableIndexChangeSignal: true
206+ property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
207+ property real handleHeight: handle.height + orangeLine.height
208+
209+ property real rowMappedLateralPosition: {
210+ if (!d.activeDragHandle) return -1;
211+ if (!d.activeDragHandle.dragging) return -1;
212+ return d.activeDragHandle.mapToItem(bar, d.activeDragHandle.touchX, 0).x;
213+ }
214+ }
215+
216+ states: [
217+ State {
218+ name: "initial"
219+ },
220+ State {
221+ name: "reveal"
222+ StateChangeScript {
223+ script: {
224+ yVelocityCalculator.reset();
225+
226+ // initial item selection
227+ bar.selectItemAt(d.activeDragHandle ? d.activeDragHandle.touchX : -1);
228+ }
229+ }
230+ PropertyChanges {
231+ target: bar
232+ expanded: true
233+ // changes to lateral touch position effect which indicator is selected
234+ lateralPosition: d.rowMappedLateralPosition
235+ // vertical velocity determines if changes in lateral position has an effect
236+ enableLateralChanges: {
237+ if (!d.activeDragHandle) return false;
238+ if (!d.activeDragHandle.dragging) return false;
239+
240+ yVelocityCalculator.trackedPosition = d.activeDragHandle ? d.activeDragHandle.touchSceneY : 0
241+ return Math.abs(yVelocityCalculator.calculate()) < 0.1;
242+ }
243+ }
244+ // left scroll bar handling
245+ PropertyChanges {
246+ target: leftScroller
247+ lateralPosition: {
248+ if (!d.activeDragHandle) return -1;
249+ if (!d.activeDragHandle.dragging) return -1;
250+
251+ var mapped = d.activeDragHandle.mapToItem(leftScroller, d.activeDragHandle.touchX, 0);
252+ return mapped.x
253+ }
254+ }
255+ // right scroll bar handling
256+ PropertyChanges {
257+ target: rightScroller
258+ lateralPosition: {
259+ if (!d.activeDragHandle) return -1;
260+ if (!d.activeDragHandle.dragging) return -1;
261+
262+ var mapped = d.activeDragHandle.mapToItem(rightScroller, d.activeDragHandle.touchX, 0);
263+ return mapped.x
264+ }
265+ }
266+ },
267+ State {
268+ name: "locked"
269+ PropertyChanges { target: bar; expanded: true }
270+ },
271+ State {
272+ name: "commit"
273+ extend: "locked"
274+ }
275+ ]
276+ state: "initial"
277+}
qml/Panel/New/IndicatorItem.qmldeleted−252
@@ -1,252 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU Lesser General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU Lesser General Public License for more details.
12− *
13− * You should have received a copy of the GNU Lesser General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors:
17− * Nick Dedekind <nick.dedekind@canonical.com>
18− */
19−
20−import QtQuick 2.1
21−import Ubuntu.Components 0.1
22−import Ubuntu.Settings.Components 0.1
23−import "../Indicators"
24−
25−IndicatorBase {
26− id: root
27−
28− property alias title: indicatorName.text
29− property alias leftLabel: itemLeftLabel.text
30− property alias rightLabel: itemRightLabel.text
31− property var icons: undefined
32− property bool expanded: false
33− property bool selected: false
34−
35− signal clicked()
36−
37− width: mainItems.width
38− enabled: false
39−
40− MouseArea {
41− anchors.fill: parent
42− onClicked: parent.clicked()
43− }
44−
45− // FIXME: For now we will enable led indicator support only for messaging indicator
46− // in the future we should export a led API insted of doing that,
47− Loader {
48− id: indicatorLed
49− // only load source Component if the icons contains the new message icon
50− source: (root.icons && (String(root.icons).indexOf("indicator-messages-new") != -1)) ? Qt.resolvedUrl("IndicatorsLight.qml") : ""
51− }
52−
53− Item {
54− id: mainItems
55− anchors.centerIn: parent
56−
57− width: itemLeftLabel.width + iconsItem.width + itemRightLabel.width
58− implicitHeight: units.gu(2)
59−
60− Label {
61− id: itemLeftLabel
62− anchors {
63− left: mainItems.left
64− verticalCenter: parent.verticalCenter
65− }
66− width: contentWidth > 0 ? contentWidth + units.gu(1) : 0
67− horizontalAlignment: Text.AlignHCenter
68−
69− objectName: "leftLabel"
70− opacity: 0.8
71− font.family: "Ubuntu"
72− fontSize: "medium"
73− color: {
74− if (!expanded) return Theme.palette.normal.foregroundText;
75− if (!selected) return Theme.palette.selected.backgroundText;
76− return Theme.palette.normal.foregroundText;
77− }
78− Behavior on color { ColorAnimation{ duration: UbuntuAnimation.SnapDuration } }
79− }
80−
81− Item {
82− id: iconsItem
83− width: iconRow.width > 0 ? iconRow.width + units.gu(1) : 0
84− anchors {
85− left: itemLeftLabel.right
86− verticalCenter: parent.verticalCenter
87− }
88−
89− Row {
90− id: iconRow
91− anchors.centerIn: iconsItem
92− spacing: units.gu(1)
93−
94− Repeater {
95− id: iconRepeater
96− model: d.useFallbackIcon ? [ "image://theme/settings" ] : root.icons
97−
98− StatusIcon {
99− id: itemImage
100− height: units.gu(2)
101− source: modelData
102− sets: ["status", "actions"]
103− color: {
104− if (!expanded) return Theme.palette.normal.foregroundText;
105− if (!selected) return Theme.palette.selected.backgroundText;
106− return Theme.palette.normal.foregroundText;
107− }
108− Behavior on color { ColorAnimation{ duration: UbuntuAnimation.SnapDuration } }
109− }
110− }
111− }
112− }
113−
114− Label {
115− id: itemRightLabel
116− anchors {
117− left: iconsItem.right
118− verticalCenter: parent.verticalCenter
119− }
120− width: contentWidth > 0 ? contentWidth + units.gu(1) : 0
121− horizontalAlignment: Text.AlignHCenter
122−
123− objectName: "rightLabel"
124− opacity: 0.8
125− font.family: "Ubuntu"
126− fontSize: "medium"
127− color: {
128− if (!expanded) return Theme.palette.normal.foregroundText;
129− if (!selected) return Theme.palette.selected.backgroundText;
130− return Theme.palette.normal.foregroundText;
131− }
132− Behavior on color { ColorAnimation{ duration: UbuntuAnimation.SnapDuration } }
133− }
134− }
135−
136− Label {
137− id: indicatorName
138−
139− anchors.top: mainItems.bottom
140− anchors.topMargin: units.gu(0.5)
141− anchors.horizontalCenter: parent.horizontalCenter
142− width: contentWidth > 0 ? contentWidth + units.gu(1) : 0
143−
144− text: rootActionState.title
145− fontSize: "x-small"
146− horizontalAlignment: Text.AlignHCenter
147− opacity: 0
148− color: {
149− if (!expanded) return Theme.palette.normal.foregroundText;
150− if (!selected) return Theme.palette.selected.backgroundText;
151− return Theme.palette.normal.foregroundText;
152− }
153− Behavior on color { ColorAnimation{ duration: UbuntuAnimation.SnapDuration } }
154− }
155−
156− StateGroup {
157− id: d
158− property bool useFallbackIcon: false
159−
160−
161− states: [
162− State {
163− name: "minimised"
164− when: !expanded && ((icons && icons.length > 0) || leftLabel !== "" || rightLabel !== "")
165− PropertyChanges { target: indicatorName; opacity: 0}
166− },
167−
168− State {
169− name: "minimised_fallback"
170− when: !expanded && (!icons || icons.length === 0) && leftLabel == "" && rightLabel == ""
171− PropertyChanges { target: indicatorName; opacity: 0}
172− PropertyChanges { target: d; useFallbackIcon: true }
173− },
174−
175− State {
176− name: "expanded_icon"
177− when: expanded && (icons && icons.length > 0)
178− PropertyChanges { target: indicatorName; visible: true; opacity: 1}
179− AnchorChanges { target: iconsItem; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
180− AnchorChanges { target: itemLeftLabel; anchors.left: undefined; anchors.right: iconsItem.left }
181− PropertyChanges { target: itemLeftLabel; opacity: 0 }
182− PropertyChanges { target: mainItems; width: Math.max(iconsItem.width, indicatorName.width) + units.gu(2); anchors.verticalCenterOffset: -units.gu(1) }
183− PropertyChanges { target: itemLeftLabel; opacity: 0 }
184− PropertyChanges { target: itemRightLabel; opacity: 0 }
185− },
186−
187− State {
188− name: "expanded_fallback"
189− when: expanded && (!icons || icons.length === 0) && leftLabel == "" && rightLabel == ""
190− PropertyChanges { target: d; useFallbackIcon: true }
191− PropertyChanges { target: indicatorName; visible: true; opacity: 1}
192− AnchorChanges { target: iconsItem; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
193− AnchorChanges { target: itemLeftLabel; anchors.left: undefined; anchors.right: iconsItem.left }
194− PropertyChanges { target: itemLeftLabel; opacity: 0 }
195− PropertyChanges { target: mainItems; width: Math.max(iconsItem.width, indicatorName.width) + units.gu(2); anchors.verticalCenterOffset: -units.gu(1) }
196− PropertyChanges { target: itemLeftLabel; opacity: 0 }
197− PropertyChanges { target: itemRightLabel; opacity: 0 }
198− },
199−
200− State {
201− name: "expanded_rightLabel"
202− when: expanded && (!icons || icons.length === 0) && rightLabel !== ""
203− PropertyChanges { target: indicatorName; visible: true; opacity: 1}
204− AnchorChanges { target: itemRightLabel; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
205− PropertyChanges { target: mainItems; width: Math.max(itemRightLabel.width, indicatorName.width) + units.gu(2); anchors.verticalCenterOffset: -units.gu(1) }
206− PropertyChanges { target: iconsItem; opacity: 0 }
207− PropertyChanges { target: itemLeftLabel; opacity: 0 }
208− },
209−
210− State {
211− name: "expanded_leftLabel"
212− when: expanded && (!icons || icons.length === 0) && leftLabel !== ""
213− PropertyChanges { target: indicatorName; visible: true; opacity: 1}
214− AnchorChanges { target: itemLeftLabel; anchors.left: undefined; anchors.horizontalCenter: parent.horizontalCenter }
215− PropertyChanges { target: mainItems; width: Math.max(itemLeftLabel.width, indicatorName.width) + units.gu(2); anchors.verticalCenterOffset: -units.gu(1) }
216− PropertyChanges { target: iconsItem; opacity: 0 }
217− PropertyChanges { target: itemRightLabel; opacity: 0 }
218− }
219− ]
220−
221− transitions: [
222− Transition {
223− PropertyAction { target: d; property: "useFallbackIcon"}
224− AnchorAnimation {
225− targets: [ mainItems, iconsItem, itemLeftLabel, itemRightLabel ]
226− duration: 1000; easing: UbuntuAnimation.StandardEasing
227− }
228− PropertyAnimation {
229− targets: [ mainItems, iconsItem, itemLeftLabel, itemRightLabel, indicatorName ]
230− properties: "width, opacity, anchors.verticalCenterOffset";
231− duration: 1000; easing: UbuntuAnimation.StandardEasing
232− }
233− }
234− ]
235− }
236−
237− onRootActionStateChanged: {
238− if (rootActionState == undefined) {
239− leftLabel = "";
240− rightLabel = "";
241− icons = undefined;
242− enabled = false;
243− return;
244− }
245−
246− title = rootActionState.title ? rootActionState.title : "";
247− leftLabel = rootActionState.leftLabel ? rootActionState.leftLabel : "";
248− rightLabel = rootActionState.rightLabel ? rootActionState.rightLabel : "";
249− icons = rootActionState.icons;
250− enabled = rootActionState.visible;
251− }
252−}
qml/Panel/New/IndicatorsBar.qmldeleted−158
@@ -1,158 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−Item {
21− id: root
22− property alias expanded: row.expanded
23− property alias indicatorsModel: row.indicatorsModel
24−
25− function selectItemAt(lateralPosition) {
26− if (!expanded)
27− d.initialItem = null;
28− var mapped = root.mapToItem(row, lateralPosition, 0);
29− row.selectItemAt(mapped.x);
30− }
31−
32− QtObject {
33− id: d
34− property var initialItem: null
35− // the non-expanded distance from row offset to center of initial item
36− property real originalDistanceFromRight: -1
37− property real originalItemWidth: -1
38−
39− // calculate the distance from row offset to center of initial item
40− property real distanceFromRight: {
41− if (originalDistanceFromRight == -1) return 0;
42− if (!initialItem) return 0;
43− return row.width - initialItem.x - initialItem.width /2;
44− }
45−
46− // offset to the intially selected expanded item
47− property real rowOffset: 0
48−
49− onInitialItemChanged: {
50− console.log("INITIAL CHANGED ", initialItem)
51− if (initialItem) {
52− originalItemWidth = initialItem.width;
53− originalDistanceFromRight = row.width - initialItem.x - initialItem.width/2;
54− } else {
55− originalItemWidth = -1;
56− originalDistanceFromRight = -1;
57− }
58− }
59− }
60−
61− onExpandedChanged: {
62− console.log("EXPANDED CHANGED ", expanded)
63− }
64−
65− Connections {
66− target: row
67− onCurrentItemChanged: {
68− if (!row.currentItem) d.initialItem = null;
69− else if (!d.initialItem) d.initialItem = row.currentItem;
70− }
71− }
72−
73− Flickable {
74− id: flickable
75− flickableDirection: Qt.Horizontal
76− anchors.fill: parent
77− contentWidth: row.width
78− interactive: expanded
79−// clip: true
80−
81− rebound: Transition {
82− NumberAnimation {
83− properties: "x"
84− duration: 600
85− easing.type: Easing.OutCubic
86− }
87− }
88−
89− IndicatorsRow {
90− id: row
91− enabled: false
92− anchors {
93− top: parent.top
94− bottom: parent.bottom
95− right: parent.right
96− }
97− }
98−
99− Behavior on contentX { enabled: !expanded; NumberAnimation { duration: 1000 } }
100− }
101−
102− states: [
103− State {
104− name: "minimized"
105− when: !expanded
106− PropertyChanges {
107− target: d
108− rowOffset: 0
109− }
110− PropertyChanges {
111− target: flickable
112− contentX: row.width - flickable.width > 0 ? row.width - flickable.width : 0
113− }
114− PropertyChanges {
115− target: row
116− anchors.rightMargin: row.width - flickable.width < 0 ? row.width - flickable.width : 0
117− }
118− },
119− State {
120− name: "expanded"
121− when: expanded
122−
123− PropertyChanges {
124− target: d
125− rowOffset: {
126− if (!initialItem) return 0;
127− if (distanceFromRight - initialItem.width <= 0) return 0;
128− if (originalDistanceFromRight + originalItemWidth/2 > flickable.width)
129− return distanceFromRight - originalDistanceFromRight + initialItem.width/2;
130−
131− var rowOffset = distanceFromRight - originalDistanceFromRight;
132− console.log(originalDistanceFromRight + " flickable.width: " +flickable.width)
133− return rowOffset;
134− }
135− }
136− PropertyChanges {
137− target: flickable
138− contentX: {
139− var cX = row.width - flickable.width > 0 ? row.width - flickable.width : 0
140− if (cX !== 0) {
141− cX -= d.rowOffset;
142− }
143− return cX;
144− }
145− }
146− PropertyChanges {
147− target: row
148− anchors.rightMargin: {
149− var rM = row.width - flickable.width < 0 ? row.width - flickable.width : 0;
150− if (rM !== 0) {
151− rM -= d.rowOffset;
152− }
153− return rM;
154− }
155− }
156− }
157− ]
158−}
qml/Panel/New/IndicatorsRow.qmldeleted−142
@@ -1,142 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.1
18−import Ubuntu.Components 0.1
19−import Unity.Indicators 0.1 as Indicators
20−
21−Item {
22− id: indicatorRow
23−
24− property QtObject indicatorsModel: null
25− property real overFlowWidth: width
26− property bool showAll: false
27− property bool expanded: false
28− property real currentItemOffset: 0.0
29− property real unitProgress: 0.0
30− property var currentItem: null
31−
32− width: row.width
33− height: units.gu(3)
34−
35− function indicatorAt(x, y) {
36− return row.childAt(x, y);
37− }
38−
39− function resetCurrentItem() {
40− currentItem = null
41− }
42−
43− function selectItemAt(lateralPosition) {
44− var item = indicatorAt(lateralPosition, 0);
45− if (item.opacity > 0) {
46− currentItem = item;
47− } else {
48− currentItem = null;
49− }
50− }
51−
52− Timer {
53− id: allVisible
54− interval: 1000
55−
56− onTriggered: {
57− showAll = false;
58− }
59− }
60−
61− Row {
62− id: row
63− anchors {
64− top: parent.top
65− bottom: parent.bottom
66− }
67−
68− Repeater {
69− id: repeater
70− model: indicatorsModel
71− visible: false
72−
73− delegate: IndicatorItem {
74− id: item
75− property bool overflow: row.width - x > overFlowWidth
76− property bool hidden: !item.expanded && overflow
77−
78− height: parent.height
79− expanded: indicatorRow.expanded
80− selected: currentItem === this
81−
82− busName: indicatorProperties.busName
83− actionsObjectPath: indicatorProperties.actionsObjectPath
84− menuObjectPath: indicatorProperties.menuObjectPath
85−
86− opacity: hidden ? 0.0 : 1.0
87− Behavior on opacity {NumberAnimation{duration: UbuntuAnimation.SnapDuration}}
88− }
89− }
90− }
91−
92− Rectangle {
93− id: grayLine
94− height: units.dp(2)
95− width: parent.width
96− anchors.bottom: row.bottom
97− color: Theme.palette.selected.backgroundText
98− opacity: 0.0
99− Behavior on opacity {NumberAnimation{duration: UbuntuAnimation.SnapDuration}}
100− }
101−
102− Rectangle {
103− id: highlight
104−
105− // micromovements of the highlight line when user moves the finger across the items while pulling
106− // the handle downwards.
107− property real highlightCenterOffset: 0
108−
109− anchors.bottom: row.bottom
110− height: units.dp(2)
111− width: currentItem ? currentItem.width : 0
112− color: Theme.palette.normal.foregroundText
113−
114− opacity: 0.0
115−
116− property real currentItemX: currentItem ? currentItem.x : 0 // having Behavior
117− x: currentItemX + highlightCenterOffset
118− }
119−
120− states: [
121− State {
122− name: "minimised"
123− when: !expanded
124− },
125− State {
126− name: "expanded"
127− when: expanded
128− PropertyChanges { target: grayLine; opacity: 1.0 }
129− PropertyChanges { target: highlight; opacity: 1.0 }
130− }
131− ]
132−
133− transitions: [
134− Transition {
135− PropertyAnimation {
136− properties: "opacity";
137− duration: UbuntuAnimation.SnapDuration;
138− easing: UbuntuAnimation.StandardEasing
139− }
140− }
141− ]
142−}
qml/Panel/Old/IndicatorItem.qmlnew file+47
@@ -0,0 +1,47 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import Unity.Indicators 0.1 as Indicators
20+import "../Components"
21+
22+Loader {
23+ id: root
24+
25+ property alias widgetSource: root.source
26+ property bool dimmed: false
27+ property var indicatorProperties: undefined
28+ property bool indicatorVisible: item ? item.enabled : false
29+ property string identifier
30+
31+ opacity: dimmed ? 0.4 : 1
32+ Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.BriskDuration } }
33+
34+ onLoaded: {
35+ for(var pName in indicatorProperties) {
36+ if (item.hasOwnProperty(pName)) {
37+ item[pName] = indicatorProperties[pName];
38+ }
39+ }
40+ }
41+
42+ Binding {
43+ target: item
44+ property: "objectName"
45+ value: identifier + "-widget"
46+ }
47+}
qml/Panel/IndicatorRow.qml → qml/Panel/Old/IndicatorRow.qmlrenamed

The content is the same.

qml/Panel/Indicators.qml → qml/Panel/Old/Indicators.qmlrenamed+1
@@ -137,6 +137,7 @@ Showable {
137137 if (currentItem) {
138138 itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
139139 distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width);
140+ console.log(distanceFromRightEdge);
140141 if (currentItem != indicatorRow.currentItem) {
141142 if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
142143 bufferExceeded = true;
qml/Panel/Old/Panel.qmlnew file+191
@@ -0,0 +1,191 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import Unity.Application 0.1
20+import "../Components"
21+import "../Components/ListItems"
22+
23+Item {
24+ id: root
25+ readonly property real panelHeight: indicatorArea.y + d.indicatorHeight
26+ property alias indicators: __indicators
27+ property alias callHint: __callHint
28+ property bool fullscreenMode: false
29+
30+ Rectangle {
31+ id: darkenedArea
32+ property real darkenedOpacity: 0.6
33+ anchors {
34+ top: parent.top
35+ topMargin: panelHeight
36+ left: parent.left
37+ right: parent.right
38+ bottom: parent.bottom
39+ }
40+ color: "black"
41+ opacity: indicators.unitProgress * darkenedOpacity
42+
43+ MouseArea {
44+ anchors.fill: parent
45+ enabled: indicators.shown
46+ onClicked: if (indicators.fullyOpened) indicators.hide();
47+ }
48+ }
49+
50+ Item {
51+ id: indicatorArea
52+ objectName: "indicatorArea"
53+
54+ anchors.fill: parent
55+
56+ Behavior on anchors.topMargin { StandardAnimation {} }
57+
58+ BorderImage {
59+ id: dropShadow
60+ anchors {
61+ fill: indicators
62+ leftMargin: -units.gu(1)
63+ bottomMargin: -units.gu(1)
64+ }
65+ visible: indicators.height > indicators.panelHeight
66+ source: "graphics/rectangular_dropshadow.sci"
67+ }
68+
69+ VerticalThinDivider {
70+ id: indicatorDividor
71+ anchors {
72+ top: indicators.top
73+ bottom: indicators.bottom
74+ right: indicators.left
75+
76+ topMargin: indicatorArea.anchors.topMargin + indicators.panelHeight
77+ }
78+
79+ width: units.dp(2)
80+ source: "graphics/VerticalDivider.png"
81+ }
82+
83+ Rectangle {
84+ id: indicatorAreaBackground
85+ color: callHint.visible ? "green" : "black"
86+ anchors {
87+ top: parent.top
88+ left: parent.left
89+ right: parent.right
90+ }
91+ height: indicators.panelHeight
92+
93+ Behavior on color { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
94+ }
95+
96+ PanelSeparatorLine {
97+ id: nonIndicatorAreaSeparatorLine
98+ anchors {
99+ top: indicatorAreaBackground.bottom
100+ left: parent.left
101+ right: indicators.left
102+ }
103+ saturation: 1 - indicators.unitProgress
104+ }
105+
106+ MouseArea {
107+ anchors {
108+ top: parent.top
109+ left: parent.left
110+ right: indicators.left
111+ }
112+ height: indicators.panelHeight
113+ enabled: callHint.visible
114+ onClicked: callHint.showLiveCall()
115+ }
116+
117+ Indicators {
118+ id: __indicators
119+ objectName: "indicators"
120+
121+ anchors {
122+ top: parent.top
123+ right: parent.right
124+ }
125+
126+ width: root.width
127+ shown: false
128+ panelHeight: units.gu(3)
129+ openedHeight: root.height
130+ overFlowWidth: {
131+ if (callHint.visible) {
132+ return Math.max(root.width - (callHint.width + units.gu(2)), 0)
133+ }
134+ return root.width
135+ }
136+
137+ enableHint: !callHint.active && !fullscreenMode
138+ showHintBottomMargin: fullscreenMode ? -panelHeight : 0
139+
140+ onShowTapped: {
141+ if (callHint.active) {
142+ callHint.showLiveCall();
143+ }
144+ }
145+ }
146+
147+ ActiveCallHint {
148+ id: __callHint
149+ anchors {
150+ top: parent.top
151+ left: parent.left
152+ }
153+ height: indicators.panelHeight
154+ visible: active && indicators.state == "initial"
155+ }
156+
157+ PanelSeparatorLine {
158+ id: indicatorsSeparatorLine
159+ visible: true
160+ anchors {
161+ top: indicators.bottom
162+ left: indicatorDividor.left
163+ right: indicators.right
164+ }
165+ }
166+ }
167+
168+ QtObject {
169+ id: d
170+ readonly property real indicatorHeight: indicators.panelHeight + indicatorsSeparatorLine.height
171+ }
172+
173+ states: [
174+ State {
175+ name: "onscreen" //fully opaque and visible at top edge of screen
176+ when: !fullscreenMode
177+ PropertyChanges {
178+ target: indicatorArea;
179+ anchors.topMargin: 0
180+ }
181+ },
182+ State {
183+ name: "offscreen" //pushed off screen
184+ when: fullscreenMode
185+ PropertyChanges {
186+ target: indicatorArea;
187+ anchors.topMargin: indicators.state === "initial" ? -d.indicatorHeight : 0
188+ }
189+ }
190+ ]
191+}
qml/Panel/Panel.qml+15−20
@@ -19,6 +19,7 @@ import Ubuntu.Components 0.1
1919import Unity.Application 0.1
2020import "../Components"
2121import "../Components/ListItems"
22+import ".."
2223
2324Item {
2425 id: root
@@ -53,7 +54,9 @@ Item {
5354
5455 anchors.fill: parent
5556
56− Behavior on anchors.topMargin { StandardAnimation {} }
57+ Behavior on anchors.topMargin {
58+ NumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
59+ }
5760
5861 BorderImage {
5962 id: dropShadow
@@ -62,7 +65,7 @@ Item {
6265 leftMargin: -units.gu(1)
6366 bottomMargin: -units.gu(1)
6467 }
65− visible: indicators.height > indicators.panelHeight
68+ visible: !indicators.fullyClosed
6669 source: "graphics/rectangular_dropshadow.sci"
6770 }
6871
@@ -94,7 +97,7 @@ Item {
9497 }
9598
9699 PanelSeparatorLine {
97− id: nonIndicatorAreaSeparatorLine
100+ id: orangeLine
98101 anchors {
99102 top: indicatorAreaBackground.bottom
100103 left: parent.left
@@ -114,7 +117,7 @@ Item {
114117 onClicked: callHint.showLiveCall()
115118 }
116119
117− Indicators {
120+ IndicatorsMenu {
118121 id: __indicators
119122 objectName: "indicators"
120123
@@ -123,19 +126,21 @@ Item {
123126 right: parent.right
124127 }
125128
126− width: root.width
127129 shown: false
128− panelHeight: units.gu(3)
130+ width: root.width
131+ minimuzedPanelHeight: units.gu(3)
132+ expandedPanelHeight: units.gu(7)
129133 openedHeight: root.height
134+
130135 overFlowWidth: {
131136 if (callHint.visible) {
132137 return Math.max(root.width - (callHint.width + units.gu(2)), 0)
133138 }
134139 return root.width
135140 }
136−
137141 enableHint: !callHint.active && !fullscreenMode
138− showHintBottomMargin: fullscreenMode ? -panelHeight : 0
142+ showHintBottomMargin: fullscreenMode ? -minimuzedPanelHeight : 0
143+ panelColor: indicatorAreaBackground.color
139144
140145 onShowTapped: {
141146 if (callHint.active) {
@@ -150,24 +155,14 @@ Item {
150155 top: parent.top
151156 left: parent.left
152157 }
153− height: indicators.panelHeight
158+ height: indicators.minimuzedPanelHeight
154159 visible: active && indicators.state == "initial"
155160 }
156−
157− PanelSeparatorLine {
158− id: indicatorsSeparatorLine
159− visible: true
160− anchors {
161− top: indicators.bottom
162− left: indicatorDividor.left
163− right: indicators.right
164− }
165− }
166161 }
167162
168163 QtObject {
169164 id: d
170− readonly property real indicatorHeight: indicators.panelHeight + indicatorsSeparatorLine.height
165+ readonly property real indicatorHeight: indicators.minimuzedPanelHeight + orangeLine.height
171166 }
172167
173168 states: [
qml/Shell.qml+3−1
@@ -540,7 +540,9 @@ Item {
540540 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && greeter.fakeActiveForApp === ""
541541 contentEnabled: edgeDemo.panelContentEnabled
542542 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
543− panelHeight: units.gu(3)
543+
544+ minimuzedPanelHeight: units.gu(3)
545+ expandedPanelHeight: units.gu(7)
544546 }
545547
546548 property bool topmostApplicationIsFullscreen:
tests/mocks/Unity/Indicators/IndicatorsModel.qml+83−25
@@ -19,42 +19,100 @@ import Unity.Indicators 0.1 as Indicators
1919
2020Indicators.FakeIndicatorsModel {
2121
22+ Component.onCompleted: {
23+ Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake1",
24+ "/com/canonical/indicators/fake1",
25+ "/com/canonical/indicators/fake1",
26+ {
27+ "title": "Bluetooth (F)",
28+ "icons": [ "image://theme/bluetooth-active" ],
29+ });
30+ Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake2",
31+ "/com/canonical/indicators/fake2",
32+ "/com/canonical/indicators/fake2",
33+ {
34+ "title": "Network (F)",
35+ "icons": [ "image://theme/simcard-error", "image://theme/wifi-high" ],
36+ });
37+ Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake3",
38+ "/com/canonical/indicators/fake3",
39+ "/com/canonical/indicators/fake3",
40+ {
41+ "title": "Sound (F)",
42+ "icons": [ "image://theme/audio-volume-high" ],
43+ });
44+ Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake4",
45+ "/com/canonical/indicators/fake4",
46+ "/com/canonical/indicators/fake4",
47+ {
48+ "title": "Battery (F)",
49+ "icons": [ "image://theme/battery-020" ],
50+ });
51+ Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake5",
52+ "/com/canonical/indicators/fake5",
53+ "/com/canonical/indicators/fake5",
54+ {
55+ "title": "Upcoming Events (F)",
56+ "label": "12:04",
57+ });
58+ }
59+
2260 function load(profile) {
2361 unload();
2462
25− append({ "identifier": "indicator-fake1",
26− "position": 0,
27− "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget1.qml",
28− "pageSource": "qrc:/tests/indciators/qml/fake_menu_page1.qml",
29− "indicatorProperties": { enabled: true }
63+ append({
64+ "identifier": "fake-indicator-bluetooth",
65+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page1.qml",
66+ "indicatorProperties": {
67+ "enabled": true,
68+ "busName": "com.canonical.indicators.fake1",
69+ "menuObjectPath": "/com/canonical/indicators/fake1",
70+ "actionsObjectPath": "/com/canonical/indicators/fake1"
71+ }
3072 });
3173
32− append({ "identifier": "indicator-fake2",
33− "position": 1,
34− "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget2.qml",
35− "pageSource": "qrc:/tests/indciators/qml/fake_menu_page2.qml",
36− "indicatorProperties": { enabled: true }
74+ append({
75+ "identifier": "fake-indicator-network",
76+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page2.qml",
77+ "indicatorProperties": {
78+ "enabled": true,
79+ "busName": "com.canonical.indicators.fake2",
80+ "menuObjectPath": "/com/canonical/indicators/fake2",
81+ "actionsObjectPath": "/com/canonical/indicators/fake2"
82+ }
3783 });
3884
39− append({ "identifier": "indicator-fake3",
40− "position": 2,
41− "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget3.qml",
42− "pageSource": "qrc:/tests/indciators/qml/fake_menu_page3.qml",
43− "indicatorProperties": { enabled: true }
85+ append({
86+ "identifier": "fake-indicator-sound",
87+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page3.qml",
88+ "indicatorProperties": {
89+ "enabled": true,
90+ "busName": "com.canonical.indicators.fake3",
91+ "menuObjectPath": "/com/canonical/indicators/fake3",
92+ "actionsObjectPath": "/com/canonical/indicators/fake3"
93+ }
4494 });
4595
46− append({ "identifier": "indicator-fake4",
47− "position": 3,
48− "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget4.qml",
49− "pageSource": "qrc:/tests/indciators/qml/fake_menu_page4.qml",
50− "indicatorProperties": { enabled: true }
96+ append({
97+ "identifier": "fake-indicator-battery",
98+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page4.qml",
99+ "indicatorProperties": {
100+ "enabled": true,
101+ "busName": "com.canonical.indicators.fake4",
102+ "menuObjectPath": "/com/canonical/indicators/fake4",
103+ "actionsObjectPath": "/com/canonical/indicators/fake4"
104+ }
51105 });
52106
53− append({ "identifier": "indicator-fake5",
54− "position": 4,
55− "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget5.qml",
56− "pageSource": "qrc:/tests/indciators/qml/fake_menu_page5.qml",
57− "indicatorProperties": { enabled: true }
107+ append({
108+ "identifier": "fake-indicator-datetime",
109+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page5.qml",
110+ "indicatorProperties": {
111+ "enabled": true,
112+ "busName": "com.canonical.indicators.fake5",
113+ "menuObjectPath": "/com/canonical/indicators/fake5",
114+ "actionsObjectPath": "/com/canonical/indicators/fake5"
115+ }
58116 });
59117 }
60118}
tests/mocks/Unity/Indicators/RootActionState.qml+1−1
@@ -27,7 +27,7 @@ Item {
2727 property string rightLabel: menu && menu.rootProperties.hasOwnProperty("label") ? menu.rootProperties["label"] : ""
2828 property var icons: menu && menu.rootProperties.hasOwnProperty("icons") ? menu.rootProperties["icons"] : []
2929 property string accessibleName: menu && menu.rootProperties.hasOwnProperty("accessible-desc") ? menu.rootProperties["accessible-desc"] : ""
30− visible: menu && menu.rootProperties.hasOwnProperty("visible") ? menu.rootProperties["visible"] : false
30+ visible: menu && menu.rootProperties.hasOwnProperty("visible") ? menu.rootProperties["visible"] : true
3131
3232 signal updated
3333
tests/mocks/Unity/Indicators/fakeindicatorsmodel.cpp+33−5
@@ -53,18 +53,46 @@ void FakeIndicatorsModel::unload()
5353}
5454
5555
56−void FakeIndicatorsModel::append(const QVariantMap& row)
56+void FakeIndicatorsModel::append(const QVariantMap& data)
5757{
58− QList<QVariant> data = m_indicatorData.toList();
59− beginInsertRows(QModelIndex(), data.count(), data.count());
58+ QList<QVariant> allData = m_indicatorData.toList();
59+ beginInsertRows(QModelIndex(), allData.count(), allData.count());
6060
61− data.append(row);
62− m_indicatorData = data;
61+ allData.append(data);
62+ m_indicatorData = allData;
6363 Q_EMIT indicatorDataChanged();
6464
6565 endInsertRows();
6666}
6767
68+void FakeIndicatorsModel::insert(int row, const QVariantMap& data)
69+{
70+ QList<QVariant> allData = m_indicatorData.toList();
71+ row = qMax(0, qMin(row, allData.count()));
72+
73+ beginInsertRows(QModelIndex(), row, row);
74+
75+ allData.insert(row, data);
76+ m_indicatorData = allData;
77+ Q_EMIT indicatorDataChanged();
78+
79+ endInsertRows();
80+}
81+
82+void FakeIndicatorsModel::remove(int row)
83+{
84+ QList<QVariant> allData = m_indicatorData.toList();
85+ row = qMax(0, qMin(row, allData.count()));
86+
87+ beginRemoveRows(QModelIndex(), row, row);
88+
89+ allData.removeAt(row);
90+ m_indicatorData = allData;
91+ Q_EMIT indicatorDataChanged();
92+
93+ endRemoveRows();
94+}
95+
6896void FakeIndicatorsModel::setIndicatorData(const QVariant& indicatorData)
6997{
7098 beginResetModel();
tests/mocks/Unity/Indicators/fakeindicatorsmodel.h+2
@@ -37,6 +37,8 @@ public:
3737 Q_INVOKABLE void unload();
3838
3939 Q_INVOKABLE void append(const QVariantMap& row);
40+ Q_INVOKABLE void insert(int row, const QVariantMap& data);
41+ Q_INVOKABLE void remove(int row);
4042
4143 Q_INVOKABLE QVariant data(int row, int role) const;
4244
tests/mocks/Unity/Indicators/fakeunitymenumodelcache.cpp+18−5
@@ -19,14 +19,15 @@
1919
2020#include "fakeunitymenumodelcache.h"
2121#include <unitymenumodel.h>
22−#include <QDebug>
2322
24−UnityMenuModelCache* FakeUnityMenuModelCache::singleton()
23+FakeUnityMenuModelCache* FakeUnityMenuModelCache::theFakeCache = nullptr;
24+
25+FakeUnityMenuModelCache* FakeUnityMenuModelCache::singleton()
2526{
26− if (!theCache) {
27− theCache = new UnityMenuModelCache();
27+ if (!theFakeCache) {
28+ theFakeCache = new FakeUnityMenuModelCache();
2829 }
29− return theCache;
30+ return theFakeCache;
3031}
3132
3233FakeUnityMenuModelCache::FakeUnityMenuModelCache(QObject* parent)
@@ -34,6 +35,18 @@ FakeUnityMenuModelCache::FakeUnityMenuModelCache(QObject* parent)
3435{
3536}
3637
38+QSharedPointer<UnityMenuModel> FakeUnityMenuModelCache::model(const QByteArray& bus,
39+ const QByteArray& path,
40+ const QVariantMap& actions)
41+{
42+ return UnityMenuModelCache::singleton()->model(bus, path, actions);
43+}
44+
45+bool FakeUnityMenuModelCache::contains(const QByteArray& path)
46+{
47+ return UnityMenuModelCache::singleton()->contains(path);
48+}
49+
3750void FakeUnityMenuModelCache::setCachedModelData(const QByteArray& bus,
3851 const QByteArray& path,
3952 const QVariantMap& actions,
tests/mocks/Unity/Indicators/fakeunitymenumodelcache.h+10−2
@@ -28,9 +28,16 @@ class FakeUnityMenuModelCache : public UnityMenuModelCache
2828{
2929 Q_OBJECT
3030public:
31− FakeUnityMenuModelCache(QObject*parent=nullptr);
31+ FakeUnityMenuModelCache(QObject* parent = nullptr);
32+
33+ static FakeUnityMenuModelCache* singleton();
34+
35+ QSharedPointer<UnityMenuModel> model(const QByteArray& bus,
36+ const QByteArray& path,
37+ const QVariantMap& actions) override;
38+ bool contains(const QByteArray& path) override;
39+
3240
33− static UnityMenuModelCache* singleton();
3441
3542 Q_INVOKABLE void setCachedModelData(const QByteArray& bus,
3643 const QByteArray& path,
@@ -38,6 +45,7 @@ public:
3845 const QVariantMap& properties);
3946
4047private:
48+ static FakeUnityMenuModelCache* theFakeCache;
4149 QHash<QByteArray, QSharedPointer<UnityMenuModel>> m_models;
4250};
4351
tests/qmltests/CMakeLists.txt+3−4
@@ -71,14 +71,13 @@ add_qml_test(Launcher Launcher)
7171add_qml_test(Notifications Notifications)
7272add_qml_test(Notifications VisualSnapDecisionsQueue)
7373add_qml_test(Panel ActiveCallHint)
74−add_qml_test(Panel IndicatorRow)
75−add_qml_test(Panel Indicators)
7674add_qml_test(Panel MenuContent)
77−add_qml_test(Panel Panel)
7875add_qml_test(Panel SearchIndicator)
7976add_qml_test(Panel/New NewIndicatorItem)
80−add_qml_test(Panel/New NewIndicatorsRow ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
77+add_qml_test(Panel/New NewIndicatorItemRow ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
8178add_qml_test(Panel/New NewIndicatorsBar ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
79+add_qml_test(Panel/New NewIndicatorsMenu ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
80+add_qml_test(Panel/New NewPanel ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
8281add_qml_test(Panel/Indicators DefaultIndicatorWidget ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
8382add_qml_test(Panel/Indicators DefaultIndicatorPage ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
8483# These MenuItemFactory tests need the test/mocks/ to come before plugins/
tests/qmltests/Panel/New/IndicatorTest.qmlnew file+153
@@ -0,0 +1,153 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.1
18+import QtQuick.Layouts 1.1
19+import QtTest 1.0
20+import "../../../../qml/Panel"
21+import Ubuntu.Components 0.1
22+import Unity.Test 0.1 as UT
23+import Unity.Indicators 0.1 as Indicators
24+
25+Rectangle {
26+ id: root
27+ color: "white"
28+
29+ Component.onCompleted: {
30+ Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake1",
31+ "/com/canonical/indicators/fake1",
32+ "/com/canonical/indicators/fake1",
33+ {
34+ "title": "Bluetooth (F)",
35+ "icons": [ "image://theme/bluetooth-active" ],
36+ });
37+ Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake2",
38+ "/com/canonical/indicators/fake2",
39+ "/com/canonical/indicators/fake2",
40+ {
41+ "title": "Network (F)",
42+ "icons": [ "image://theme/simcard-error", "image://theme/wifi-high" ],
43+ });
44+ Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake3",
45+ "/com/canonical/indicators/fake3",
46+ "/com/canonical/indicators/fake3",
47+ {
48+ "title": "Sound (F)",
49+ "icons": [ "image://theme/audio-volume-high" ],
50+ });
51+ Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake4",
52+ "/com/canonical/indicators/fake4",
53+ "/com/canonical/indicators/fake4",
54+ {
55+ "title": "Battery (F)",
56+ "icons": [ "image://theme/battery-020" ],
57+ });
58+ Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake5",
59+ "/com/canonical/indicators/fake5",
60+ "/com/canonical/indicators/fake5",
61+ {
62+ "title": "Upcoming Events (F)",
63+ "label": "12:04",
64+ });
65+ }
66+
67+ property var indicatorData: [
68+ {
69+ "identifier": "fake-indicator-bluetooth",
70+ "indicatorProperties": {
71+ "enabled": true,
72+ "busName": "com.canonical.indicators.fake1",
73+ "menuObjectPath": "/com/canonical/indicators/fake1",
74+ "actionsObjectPath": "/com/canonical/indicators/fake1"
75+ }
76+ },
77+ {
78+ "identifier": "fake-indicator-network",
79+ "indicatorProperties": {
80+ "enabled": true,
81+ "busName": "com.canonical.indicators.fake2",
82+ "menuObjectPath": "/com/canonical/indicators/fake2",
83+ "actionsObjectPath": "/com/canonical/indicators/fake2"
84+ }
85+ },
86+ {
87+ "identifier": "fake-indicator-sound",
88+ "indicatorProperties": {
89+ "enabled": true,
90+ "busName": "com.canonical.indicators.fake3",
91+ "menuObjectPath": "/com/canonical/indicators/fake3",
92+ "actionsObjectPath": "/com/canonical/indicators/fake3"
93+ }
94+ },
95+ {
96+ "identifier": "fake-indicator-battery",
97+ "indicatorProperties": {
98+ "enabled": true,
99+ "busName": "com.canonical.indicators.fake4",
100+ "menuObjectPath": "/com/canonical/indicators/fake4",
101+ "actionsObjectPath": "/com/canonical/indicators/fake4"
102+ }
103+ },
104+ {
105+ "identifier": "fake-indicator-datetime",
106+ "indicatorProperties": {
107+ "enabled": true,
108+ "busName": "com.canonical.indicators.fake5",
109+ "menuObjectPath": "/com/canonical/indicators/fake5",
110+ "actionsObjectPath": "/com/canonical/indicators/fake5"
111+ }
112+ }
113+ ]
114+
115+ property alias indicatorsModel: __indicatorsModel
116+ Indicators.FakeIndicatorsModel {
117+ id: __indicatorsModel
118+ indicatorData: root.indicatorData
119+ }
120+
121+ function insertIndicator(index) {
122+ var i;
123+ var insertIndex = 0;
124+ var done = false;
125+ for (i = index; !done && i >= 1; i--) {
126+
127+ var lookFor = root.indicatorData[i-1]["identifier"]
128+
129+ var j;
130+ for (j = indicatorsModel.indicatorData.length-1; !done && j >= 0; j--) {
131+ if (indicatorsModel.indicatorData[j]["identifier"] === lookFor) {
132+ insertIndex = j+1;
133+ done = true;
134+ }
135+ }
136+ }
137+ indicatorsModel.insert(insertIndex, root.indicatorData[index]);
138+ }
139+
140+ function removeIndicator(index) {
141+ var i;
142+ for (i = 0; i < indicatorsModel.indicatorData.length; i++) {
143+ if (indicatorsModel.indicatorData[i]["identifier"] === root.indicatorData[index]["identifier"]) {
144+ indicatorsModel.remove(i);
145+ break;
146+ }
147+ }
148+ }
149+
150+ function resetData() {
151+ indicatorsModel.indicatorData = root.indicatorData;
152+ }
153+}
tests/qmltests/Panel/New/tst_NewIndicatorItem.qml+146−59
@@ -17,93 +17,180 @@
1717import QtQuick 2.1
1818import QtQuick.Layouts 1.1
1919import QtTest 1.0
20−import ".."
21−import "../../../../qml/Panel/New"
2220import Ubuntu.Components 0.1
2321import Unity.Test 0.1 as UT
22+import "../../../../qml/Panel"
2423
2524Rectangle {
2625 width: units.gu(80)
2726 height: units.gu(30)
2827 color: "white"
2928
30− Rectangle {
31− id: itemArea
32− color: "blue"
33− anchors {
34− top: parent.top
35− bottom: parent.bottom
36− }
37− width: units.gu(30)
38−
29+ RowLayout {
30+ anchors.fill: parent
31+ anchors.margins: units.gu(1)
3932
4033 Rectangle {
41− color: "black"
42− anchors.fill: indicatorItem
43− }
34+ id: itemArea
35+ color: "blue"
36+ Layout.fillWidth: true
37+ Layout.fillHeight: true
38+
39+ Rectangle {
40+ color: "black"
41+ anchors.fill: indicatorItem
42+ }
43+
44+ IndicatorItem {
45+ id: indicatorItem
46+ height: expanded ? units.gu(7) : units.gu(3)
47+ anchors.centerIn: parent
48+ identifier: "indicator-test"
4449
45− IndicatorItem {
46− id: indicatorItem
47− height: expanded ? units.gu(7) : units.gu(3)
48− anchors.centerIn: parent
49−
50− rootActionState {
51− title: "Test Title"
52− leftLabel : leftLabel.text
53− rightLabel : rightLabel.text
54− icons : {
55− var icons = [];
56− var i = 0;
57− if (iconEnabled.checked) {
58− for (i = 0; i < String(iconCount.text); i++) {
59− icons.append("image://theme/audio-volume-high");
50+ rootActionState {
51+ title: titleLabel.text
52+ leftLabel : leftLabel.text
53+ rightLabel : rightLabel.text
54+ icons : {
55+ var icons = [];
56+ var i = 0;
57+ if (iconEnabled.checked) {
58+ for (i = 0; i < String(iconCount.text); i++) {
59+ icons.push("image://theme/audio-volume-high");
60+ }
6061 }
62+ return icons;
6163 }
62− return icons;
6364 }
65+
66+ Behavior on height {
67+ NumberAnimation {
68+ id: heightAnimation
69+ duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing
70+ }
71+ }
72+ }
73+ }
74+
75+ ColumnLayout {
76+ Layout.alignment: Qt.AlignTop
77+ Layout.fillWidth: false
78+
79+ Button {
80+ id: expandButton
81+ Layout.fillWidth: true
82+ text: indicatorItem.expanded ? "Collapse" : "Expand"
83+ onClicked: indicatorItem.expanded = !indicatorItem.expanded
84+ }
85+
86+ Button {
87+ id: selectButton
88+ Layout.fillWidth: true
89+ text: indicatorItem.selected ? "Unselect" : "Select"
90+ onClicked: indicatorItem.selected = !indicatorItem.selected
91+ }
92+
93+ Rectangle {
94+ Layout.preferredHeight: units.dp(1);
95+ Layout.fillWidth: true;
96+ color: "black"
97+ }
98+
99+ RowLayout {
100+ CheckBox { id: iconEnabled; checked: true }
101+ Label { text: "icons Count:" }
102+ TextField { id: iconCount; text: "1"; enabled: iconEnabled.checked }
103+ }
104+
105+ RowLayout {
106+ Label { text: "Left Label:" }
107+ TextField { id: leftLabel; text: "Left"}
64108 }
65109
66− Behavior on height {NumberAnimation{duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing}}
110+ RowLayout {
111+ Label { text: "Right Label:" }
112+ TextField { id: rightLabel; text: "Right"}
113+ }
114+
115+ RowLayout {
116+ Label { text: "Title:" }
117+ TextField { id: titleLabel; text: "Title"}
118+ }
67119 }
68120 }
69121
70− ColumnLayout {
71− anchors {
72− top: parent.top
73− bottom: button.top
74− left: itemArea.right
75− right: parent.right
122+ UT.UnityTestCase {
123+ name: "IndicatorItem"
124+ when: windowShown
125+
126+ function init() {
127+ indicatorItem.selected = false;
128+ indicatorItem.expanded = false;
129+ indicatorItem.rootActionState.title = "Test Title";
130+ indicatorItem.rootActionState.leftLabel = "TestRightLabel";
131+ indicatorItem.rootActionState.rightLabel = "TestRightLabel";
132+ indicatorItem.rootActionState.icons = [ "image://theme/audio-volume-high" ];
133+
134+ tryCompare(heightAnimation, "running", false);
76135 }
77136
78− RowLayout {
79− CheckBox { id: iconEnabled; checked: true }
80− Label { text: "icons Count:" }
81− TextField { id: iconCount; text: "1"; enabled: iconEnabled.checked }
137+ function test_expand() {
138+ indicatorItem.expanded = true;
139+ tryCompare(indicatorItem, "height", units.gu(7));
140+ indicatorItem.expanded = false;
141+ tryCompare(indicatorItem, "height", units.gu(3));
82142 }
83143
84− RowLayout {
85− Label { text: "Left Label:" }
86− TextField { id: leftLabel; text: "Left"}
144+ function test_minimizedVisibility() {
145+ compare(findChild(indicatorItem, "leftLabel").opacity, 1.0);
146+ compare(findChild(indicatorItem, "rightLabel").opacity, 1.0);
147+ compare(findChild(indicatorItem, "icons").opacity, 1.0);
148+ compare(findChild(indicatorItem, "indicatorName").opacity, 0.0);
87149 }
88150
89− RowLayout {
90− Label { text: "Right Label:" }
91− TextField { id: rightLabel; text: "Right"}
151+ function test_expandcon() {
152+ indicatorItem.expanded = true;
153+
154+ tryCompare(findChild(indicatorItem, "leftLabel"), "opacity", 0.0);
155+ tryCompare(findChild(indicatorItem, "rightLabel"), "opacity", 0.0);
156+ tryCompare(findChild(indicatorItem, "icons"), "opacity", 1.0);
157+ tryCompare(findChild(indicatorItem, "indicatorName"), "opacity", 1.0);
92158 }
93− }
94159
95− Button {
96− id: button
97− anchors {
98− left: parent.left
99− right: parent.right
100− bottom: parent.bottom
160+ function test_expandRightLabel() {
161+ indicatorItem.expanded = true;
162+
163+ indicatorItem.rootActionState.icons = [];
164+
165+ tryCompare(findChild(indicatorItem, "leftLabel"), "opacity", 0.0);
166+ tryCompare(findChild(indicatorItem, "rightLabel"), "opacity", 1.0);
167+ tryCompare(findChild(indicatorItem, "icons"), "opacity", 0.0);
168+ tryCompare(findChild(indicatorItem, "indicatorName"), "opacity", 1.0);
101169 }
102− text: indicatorItem.expanded ? "Collapse" : "Expand"
103− onClicked: indicatorItem.expanded = !indicatorItem.expanded
104− }
105170
106− UT.UnityTestCase {
107− name: "IndicatorItem"
171+ function test_expandLeftLabel() {
172+ indicatorItem.expanded = true;
173+
174+ indicatorItem.rootActionState.rightLabel = "";
175+ indicatorItem.rootActionState.icons = [];
176+
177+ tryCompare(findChild(indicatorItem, "rightLabel"), "opacity", 0.0);
178+ tryCompare(findChild(indicatorItem, "leftLabel"), "opacity", 1.0);
179+ tryCompare(findChild(indicatorItem, "icons"), "opacity", 0.0);
180+ tryCompare(findChild(indicatorItem, "indicatorName"), "opacity", 1.0);
181+ }
182+
183+ function test_select() {
184+ tryCompare(findChild(indicatorItem, "leftLabel"), "color", Theme.palette.normal.foregroundText);
185+ tryCompare(findChild(indicatorItem, "rightLabel"), "color", Theme.palette.normal.foregroundText);
186+
187+ indicatorItem.expanded = true;
188+ tryCompare(findChild(indicatorItem, "leftLabel"), "color", Theme.palette.selected.backgroundText);
189+ tryCompare(findChild(indicatorItem, "rightLabel"), "color", Theme.palette.selected.backgroundText);
190+
191+ indicatorItem.selected = true;
192+ tryCompare(findChild(indicatorItem, "leftLabel"), "color", Theme.palette.normal.foregroundText);
193+ tryCompare(findChild(indicatorItem, "rightLabel"), "color", Theme.palette.normal.foregroundText);
194+ }
108195 }
109196}
tests/qmltests/Panel/New/tst_NewIndicatorItemRow.qmlnew file+270
@@ -0,0 +1,270 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.1
18+import QtQuick.Layouts 1.1
19+import QtTest 1.0
20+import "../../../../qml/Panel"
21+import Ubuntu.Components 0.1
22+import Unity.Test 0.1 as UT
23+import Unity.Indicators 0.1 as Indicators
24+
25+IndicatorTest {
26+ id: root
27+ width: units.gu(100)
28+ height: units.gu(30)
29+ color: "white"
30+
31+ RowLayout {
32+ anchors.fill: parent
33+ anchors.margins: units.gu(1)
34+
35+ Rectangle {
36+ Layout.fillWidth: true
37+ Layout.fillHeight: true
38+
39+ id: itemArea
40+ color: "blue"
41+
42+ Rectangle {
43+ color: "black"
44+ anchors.fill: indicatorsRow
45+ }
46+
47+ IndicatorItemRow {
48+ id: indicatorsRow
49+ height: expanded ? units.gu(7) : units.gu(3)
50+ anchors.centerIn: parent
51+ indicatorsModel: root.indicatorsModel
52+ enableLateralChanges: ma.pressed
53+
54+ Behavior on height {
55+ NumberAnimation {
56+ id: heightAnimation
57+ duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing
58+ }
59+ }
60+
61+ MouseArea {
62+ id: ma
63+ anchors.fill: parent
64+ onPositionChanged: { indicatorsRow.lateralPosition = mouse.x }
65+ onPressed: {
66+ if (pressed) {
67+ indicatorsRow.selectItemAt(mouse.x);
68+ }
69+ }
70+ }
71+ }
72+ }
73+
74+ ColumnLayout {
75+ Layout.alignment: Qt.AlignTop
76+ Layout.fillWidth: false
77+
78+ Button {
79+ Layout.fillWidth: true
80+ text: indicatorsRow.expanded ? "Collapse" : "Expand"
81+ onClicked: indicatorsRow.expanded = !indicatorsRow.expanded
82+ }
83+
84+ Rectangle {
85+ Layout.preferredHeight: units.dp(1);
86+ Layout.fillWidth: true;
87+ color: "black"
88+ }
89+
90+ Repeater {
91+ model: root.indicatorData
92+ RowLayout {
93+ CheckBox {
94+ checked: true
95+ onCheckedChanged: checked ? insertIndicator(index) : removeIndicator(index);
96+ }
97+ Label { text: modelData["identifier"] }
98+ }
99+ }
100+ }
101+ }
102+
103+ UT.UnityTestCase {
104+ name: "IndicatorItemRow"
105+ when: windowShown
106+
107+ function init() {
108+ root.resetData();
109+
110+ indicatorsRow.resetCurrentItem();
111+ indicatorsRow.lateralPosition = -1;
112+
113+ indicatorsRow.expanded = false;
114+ tryCompare(heightAnimation, "running", false);
115+ tryCompare(findChild(indicatorsRow, "highlight"), "highlightCenterOffset", 0);
116+ wait(1); // row seems to take a bit of time for item x values to update.
117+ }
118+
119+ function test_indicatorRowChanges_data() {
120+ return [
121+ { remove: [0, 2] },
122+ { remove: [0, 1, 2, 3, 4] },
123+ ];
124+ }
125+
126+ // test the changes in the available indicators updates the
127+ // indicators that are visible.
128+ function test_indicatorRowChanges(data) {
129+ var i;
130+ var item;
131+ var itemsToRemove = [0, 2];
132+
133+ verify(root.indicatorData.length > 0);
134+ for (i = 0; i < root.indicatorData.length; i++) {
135+ item = findChild(indicatorsRow, root.indicatorData[i]["identifier"]+"-panelItem");
136+ verify(item);
137+
138+ compare(item.ownIndex, i, "Item at incorrect index");
139+ }
140+
141+ for (i = data.remove.length-1; i >= 0; i--) {
142+ removeIndicator(data.remove[i]);
143+ }
144+
145+ // test removals
146+ for (i = 0; i < root.indicatorData.length; i++) {
147+ item = findChild(indicatorsRow, root.indicatorData[i]["identifier"]+"-panelItem");
148+
149+ verify(data.remove.indexOf(i) !== -1 ? (item === null) : (item !== null));
150+ }
151+
152+ // test insertion
153+ for (i = 0; i < data.remove.length; i++) {
154+ insertIndicator(data.remove[i]);
155+ }
156+
157+ for (i = 0; i < root.indicatorData.length; i++) {
158+ item = findChild(indicatorsRow, root.indicatorData[i]["identifier"]+"-panelItem");
159+ verify(item);
160+
161+ compare(item.ownIndex, i, "Item at incorrect index");
162+ }
163+ }
164+
165+ function test_validCurrentItem_data() {
166+ return [
167+ { index: 0 },
168+ { index: 2 },
169+ { index: 4 }
170+ ];
171+ }
172+
173+ // test selecting the item at it's position sets the current item of the row.
174+ function test_validCurrentItem(data) {
175+ var dataItem = findChild(indicatorsRow, root.indicatorData[data.index]["identifier"]+"-panelItem");
176+ verify(dataItem !== null);
177+
178+ indicatorsRow.selectItemAt(dataItem.x + dataItem.width/2);
179+ compare(indicatorsRow.currentItem, dataItem);
180+ }
181+
182+ // tests item default selection (no item at position X)
183+ function test_invalidCurrentItem() {
184+ indicatorsRow.selectItemAt(-100);
185+ compare(indicatorsRow.currentItem, findChild(indicatorsRow, root.indicatorData[0]["identifier"]+"-panelItem"));
186+ }
187+
188+ // testing that changing the lateral position offset of the row changes the current item.
189+ function test_lateralPositionChangesCurrentItem_data() {
190+ return [
191+ { tag: "0 -> 4", from: 0, to: 4 },
192+ { tag: "3 -> 1", from: 3, to: 1 }
193+ ];
194+ }
195+
196+ function test_lateralPositionChangesCurrentItem(data) {
197+ indicatorsRow.expanded = true;
198+ tryCompare(heightAnimation, "running", false);
199+
200+ var fromItem = findChild(indicatorsRow, root.indicatorData[data.from]["identifier"]+"-panelItem");
201+ verify(fromItem !== null);
202+
203+ var toItem = findChild(indicatorsRow, root.indicatorData[data.to]["identifier"]+"-panelItem");
204+ verify(toItem !== null);
205+
206+ var fromPosition = indicatorsRow.mapFromItem(fromItem, fromItem.width/2, fromItem.height/2);
207+ var toPosition = indicatorsRow.mapFromItem(toItem, toItem.width/2, toItem.height/2);
208+
209+ mousePress(indicatorsRow, fromPosition.x, fromPosition.y);
210+ compare(indicatorsRow.currentItem, fromItem, "Initial item not selected");
211+
212+ // this uses the MouseArea above to change the indicatorRow lateralPosition
213+ mouseFlick(indicatorsRow, fromPosition.x, fromPosition.y, toPosition.x, toPosition.y, false, false, units.gu(5), 30);
214+
215+ mouseRelease(indicatorsRow, fromPosition.x, fromPosition.y);
216+ compare(indicatorsRow.currentItem, toItem, "Current item did not change to expected item");
217+ }
218+
219+ // testing that positive changes to the lateral position offset shifts the highlight offset to the right
220+ function test_positiveLateralPositionChangesHighlightOffset() {
221+ indicatorsRow.expanded = true;
222+ tryCompare(heightAnimation, "running", false);
223+
224+ var highlight = findChild(indicatorsRow, "highlight");
225+ var item = findChild(indicatorsRow, root.indicatorData[2]["identifier"]+"-panelItem");
226+ verify(item !== null);
227+ var mappedPosition = indicatorsRow.mapFromItem(item, item.width/2, item.height/2);
228+
229+ mousePress(indicatorsRow, mappedPosition.x, mappedPosition.y);
230+ var originalHightlightX = highlight.x
231+ var offset = 1;
232+ while((highlight.x - originalHightlightX) <= units.gu(0.5) && offset < units.gu(10)) {
233+ mouseMove(indicatorsRow, mappedPosition.x + offset, mappedPosition.y, 10);
234+ offset = offset + 2;
235+ }
236+ // verify that we hit the offset
237+ verify((highlight.x - originalHightlightX) >= units.gu(0.5));
238+ mouseRelease(indicatorsRow);
239+
240+ // should go back to 0
241+ tryCompare(highlight, "highlightCenterOffset", 0);
242+ }
243+
244+ // testing that negative changes to the lateral position offset shifts the highlight offset to the left
245+ function test_negativeLateralPositionChangesHighlightOffset() {
246+ indicatorsRow.expanded = true;
247+ tryCompare(heightAnimation, "running", false);
248+
249+ var highlight = findChild(indicatorsRow, "highlight");
250+ var item = findChild(indicatorsRow, root.indicatorData[2]["identifier"]+"-panelItem");
251+ verify(item !== null);
252+ var mappedPosition = indicatorsRow.mapFromItem(item, item.width/2, item.height/2);
253+
254+ mousePress(indicatorsRow, mappedPosition.x, mappedPosition.y);
255+ var originalHightlightX = highlight.x
256+ var offset = 1;
257+ while((highlight.x - originalHightlightX) >= -units.gu(0.5) && offset < units.gu(10)) {
258+ mouseMove(indicatorsRow, mappedPosition.x - offset, mappedPosition.y, 10);
259+ offset = offset + 2;
260+ }
261+
262+ // verify that we hit the offset
263+ verify((highlight.x - originalHightlightX) <= -units.gu(0.5));
264+ mouseRelease(indicatorsRow);
265+
266+ // should go back to 0
267+ tryCompare(findChild(indicatorsRow, "highlight"), "highlightCenterOffset", 0);
268+ }
269+ }
270+}
tests/qmltests/Panel/New/tst_NewIndicatorsBar.qml+131−195
@@ -17,222 +17,158 @@
1717import QtQuick 2.1
1818import QtQuick.Layouts 1.1
1919import QtTest 1.0
20−import ".."
21−import "../../../../qml/Panel/New"
20+import "../../../../qml/Panel"
2221import Ubuntu.Components 0.1
2322import Unity.Test 0.1 as UT
2423import Unity.Indicators 0.1 as Indicators
2524
26−Rectangle {
25+IndicatorTest {
26+ id: root
2727 width: units.gu(100)
2828 height: units.gu(30)
29− color: "white"
30−
31− Component.onCompleted: {
32− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake1",
33− "/com/canonical/indicators/fake1",
34− "/com/canonical/indicators/fake1",
35− {
36− "title": "Bluetooth",
37− "icons": [ "image://theme/bluetooth-active" ],
38− });
39− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake2",
40− "/com/canonical/indicators/fake2",
41− "/com/canonical/indicators/fake2",
42− {
43− "title": "Network",
44− "icons": [ "image://theme/simcard-error", "image://theme/wifi-high" ],
45− });
46− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake3",
47− "/com/canonical/indicators/fake3",
48− "/com/canonical/indicators/fake3",
49− {
50− "title": "Sound",
51− "icons": [ "image://theme/audio-volume-high" ],
52− });
53− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake4",
54− "/com/canonical/indicators/fake4",
55− "/com/canonical/indicators/fake4",
56− {
57− "title": "Battery",
58− "icons": [ "image://theme/battery-020" ],
59− });
60− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake5",
61− "/com/canonical/indicators/fake5",
62− "/com/canonical/indicators/fake5",
63− {
64− "title": "Location",
65− "icons": [ "image://theme/gps" ],
66− });
67− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake6",
68− "/com/canonical/indicators/fake6",
69− "/com/canonical/indicators/fake6",
70− {
71− "title": "Notifications",
72− "icons": [ "image://theme/messages-new" ],
73− });
74− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake7",
75− "/com/canonical/indicators/fake7",
76− "/com/canonical/indicators/fake7",
77− {
78− "title": "Upcoming Events",
79− "label": "12:04",
80− });
81− }
8229
83− Indicators.FakeIndicatorsModel {
84− id: indicatorsModel
85−
86− indicatorData: [
87− {
88− "identifier": "indicator-fake1",
89− "indicatorProperties": {
90− "enabled": true,
91− "busName": "com.canonical.indicators.fake1",
92− "menuObjectPath": "/com/canonical/indicators/fake1",
93− "actionsObjectPath": "/com/canonical/indicators/fake1"
94− }
95− },
96− {
97− "identifier": "indicator-fake2",
98− "indicatorProperties": {
99− "enabled": true,
100− "busName": "com.canonical.indicators.fake2",
101− "menuObjectPath": "/com/canonical/indicators/fake2",
102− "actionsObjectPath": "/com/canonical/indicators/fake2"
103− }
104− },
105− {
106− "identifier": "indicator-fake3",
107− "indicatorProperties": {
108− "enabled": true,
109− "busName": "com.canonical.indicators.fake3",
110− "menuObjectPath": "/com/canonical/indicators/fake3",
111− "actionsObjectPath": "/com/canonical/indicators/fake3"
112− }
113− },
114− {
115− "identifier": "indicator-fake4",
116− "indicatorProperties": {
117− "enabled": true,
118− "busName": "com.canonical.indicators.fake4",
119− "menuObjectPath": "/com/canonical/indicators/fake4",
120− "actionsObjectPath": "/com/canonical/indicators/fake4"
121− }
122− },
123− {
124− "identifier": "indicator-fake5",
125− "indicatorProperties": {
126− "enabled": true,
127− "busName": "com.canonical.indicators.fake5",
128− "menuObjectPath": "/com/canonical/indicators/fake5",
129− "actionsObjectPath": "/com/canonical/indicators/fake5"
130− }
131− },
132− {
133− "identifier": "indicator-fake6",
134− "indicatorProperties": {
135− "enabled": true,
136− "busName": "com.canonical.indicators.fake6",
137− "menuObjectPath": "/com/canonical/indicators/fake6",
138− "actionsObjectPath": "/com/canonical/indicators/fake6"
139− }
140− },
141− {
142− "identifier": "indicator-fake7",
143− "indicatorProperties": {
144− "enabled": true,
145− "busName": "com.canonical.indicators.fake7",
146− "menuObjectPath": "/com/canonical/indicators/fake7",
147− "actionsObjectPath": "/com/canonical/indicators/fake7"
148− }
149− },
150− {
151− "identifier": "indicator-fake8",
152− "indicatorProperties": {
153− "enabled": true,
154− "busName": "com.canonical.indicators.fake1",
155− "menuObjectPath": "/com/canonical/indicators/fake1",
156− "actionsObjectPath": "/com/canonical/indicators/fake1"
30+
31+ RowLayout {
32+ anchors.fill: parent
33+ anchors.margins: units.gu(1)
34+
35+ Rectangle {
36+ id: itemArea
37+ color: "blue"
38+ Layout.fillWidth: true
39+ Layout.fillHeight: true
40+
41+ Rectangle {
42+ color: "black"
43+ anchors.fill: indicatorsBar
44+ }
45+
46+ IndicatorsBar {
47+ id: indicatorsBar
48+ height: expanded ? units.gu(7) : units.gu(3)
49+ width: units.gu(30)
50+ anchors.centerIn: parent
51+ indicatorsModel: root.indicatorsModel
52+
53+ Behavior on height {
54+ NumberAnimation {
55+ id: heightAnimation
56+ duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing
57+ }
15758 }
158− },
159− {
160− "identifier": "indicator-fake9",
161− "indicatorProperties": {
162− "enabled": true,
163− "busName": "com.canonical.indicators.fake1",
164− "menuObjectPath": "/com/canonical/indicators/fake1",
165− "actionsObjectPath": "/com/canonical/indicators/fake1"
59+
60+ MouseArea {
61+ anchors.fill: parent
62+ enabled: !indicatorsBar.expanded
63+ onPressed: {
64+ indicatorsBar.selectItemAt(mouse.x);
65+ indicatorsBar.expanded = true
66+ }
16667 }
167− },
168− {
169− "identifier": "indicator-fake10",
170− "indicatorProperties": {
171− "enabled": true,
172− "busName": "com.canonical.indicators.fake1",
173− "menuObjectPath": "/com/canonical/indicators/fake1",
174− "actionsObjectPath": "/com/canonical/indicators/fake1"
68+ }
69+ }
70+
71+ ColumnLayout {
72+ Layout.alignment: Qt.AlignTop
73+ Layout.fillWidth: false
74+
75+ Button {
76+ Layout.fillWidth: true
77+ text: indicatorsBar.expanded ? "Collapse" : "Expand"
78+ onClicked: indicatorsBar.expanded = !indicatorsBar.expanded
79+ }
80+
81+ Rectangle {
82+ Layout.preferredHeight: units.dp(1);
83+ Layout.fillWidth: true;
84+ color: "black"
85+ }
86+
87+ Repeater {
88+ model: root.indicatorData
89+ RowLayout {
90+ CheckBox {
91+ checked: true
92+ onCheckedChanged: checked ? insertIndicator(index) : removeIndicator(index);
93+ }
94+ Label { text: modelData["identifier"] }
17595 }
176− },
177− ]
96+ }
97+ }
17898 }
17999
180− Rectangle {
181− id: itemArea
182− color: "blue"
183− anchors {
184− top: parent.top
185− bottom: parent.bottom
100+ UT.UnityTestCase {
101+ name: "IndicatorsBar"
102+ when: windowShown
103+
104+ function init() {
105+ indicatorsBar.expanded = false;
106+ tryCompare(heightAnimation, "running", false);
186107 }
187− width: units.gu(50)
188108
189− Rectangle {
190− color: "black"
191− anchors.fill: indicatorsBar
109+ function test_expandSelectedItem_data() {
110+ return [
111+ { index: 0 },
112+ { index: 2 },
113+ { index: 4 }
114+ ];
192115 }
193116
194− IndicatorsBar {
195− id: indicatorsBar
196− height: expanded ? units.gu(7) : units.gu(3)
197− width: units.gu(30)
198− anchors.centerIn: parent
199− indicatorsModel: indicatorsModel
200−
201− Behavior on height { NumberAnimation { duration: 1000; easing: UbuntuAnimation.StandardEasing } }
202−
203− MouseArea {
204− anchors.fill: parent
205− enabled: !indicatorsBar.expanded
206− onPressed: {
207− console.log("click")
208− indicatorsBar.selectItemAt(mouse.x);
209− indicatorsBar.expanded = true
210− }
211− }
117+ // Rough check that expanding a selected item keeps it within the area of the original item.
118+ function test_expandSelectedItem(data) {
119+ var dataItem = findChild(indicatorsBar, root.indicatorData[data.index]["identifier"]+"-panelItem");
120+ verify(dataItem !== null);
121+
122+ var mappedPosition = indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2);
123+
124+ indicatorsBar.selectItemAt(mappedPosition.x);
125+ indicatorsBar.expanded = true;
126+
127+ // wait for animations to finish
128+ tryCompare(heightAnimation, "running", false);
129+
130+ var mappedRect = indicatorsBar.mapFromItem(dataItem, 0, 0, dataItem.width, dataItem.height);
131+
132+ // mappedPosition contained within mappedRect
133+ verify(mappedRect.x <= mappedPosition.x)
134+ verify(mappedRect.x + mappedRect.width >= mappedPosition.x)
212135 }
213− }
214136
215− ColumnLayout {
216− anchors {
217− top: parent.top
218− bottom: button.top
219− left: itemArea.right
220− right: parent.right
137+ function test_scrollOffset() {
138+ indicatorsBar.expanded = true;
139+ tryCompare(heightAnimation, "running", false);
140+
141+ var dataItem = findChild(indicatorsBar, root.indicatorData[root.indicatorData.length-1]["identifier"]+"-panelItem");
142+ verify(dataItem !== null);
143+
144+ var row = findChild(indicatorsBar, "indicatorRow");
145+ // test will not work without these conditions
146+ verify(row.width >= indicatorsBar.width + dataItem.width);
147+
148+ var mappedPosition = indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2);
149+ indicatorsBar.addScrollOffset(-dataItem.width);
150+ var newMappedPosition = indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2);
151+
152+ compare(mappedPosition.x, newMappedPosition.x - dataItem.width);
221153 }
222− }
223154
224− Button {
225− id: button
226− anchors {
227− left: parent.left
228− right: parent.right
229− bottom: parent.bottom
155+ function test_selectItemWhenExpanded_data() {
156+ return [
157+ { index: 3 },
158+ { index: 4 }
159+ ];
230160 }
231− text: indicatorsBar.expanded ? "Collapse" : "Expand"
232− onClicked: indicatorsBar.expanded = !indicatorsBar.expanded
233− }
234161
235− UT.UnityTestCase {
236− name: "IndicatorsRow"
162+ function test_selectItemWhenExpanded(data) {
163+ indicatorsBar.expanded = true;
164+ tryCompare(heightAnimation, "running", false);
165+
166+ var dataItem = findChild(indicatorsBar, root.indicatorData[data.index]["identifier"]+"-panelItem");
167+ if (indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2).x < 0) {
168+ skip("Out of bounds");
169+ }
170+ mouseClick(dataItem, dataItem.width/2, dataItem.height/2);
171+ verify(dataItem.selected === true);
172+ }
237173 }
238174}
tests/qmltests/Panel/New/tst_NewIndicatorsMenu.qmlnew file+171
@@ -0,0 +1,171 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.1
18+import QtQuick.Layouts 1.1
19+import QtTest 1.0
20+import "../../../../qml/Panel"
21+import Ubuntu.Components 0.1
22+import Unity.Test 0.1 as UT
23+import Unity.Indicators 0.1 as Indicators
24+
25+IndicatorTest {
26+ id: root
27+ width: units.gu(80)
28+ height: units.gu(71)
29+ color: "white"
30+
31+ RowLayout {
32+ anchors.fill: parent
33+ anchors.margins: units.gu(1)
34+
35+ Rectangle {
36+ Layout.fillWidth: true
37+ Layout.fillHeight: true
38+
39+ id: itemArea
40+ color: "blue"
41+
42+ IndicatorsMenu {
43+ id: indicatorsMenu
44+ width: units.gu(40)
45+ anchors {
46+ top: parent.top
47+ right: parent.right
48+ }
49+ minimizedPanelHeight: units.gu(3)
50+ expandedPanelHeight: units.gu(7)
51+ openedHeight: parent.height
52+ indicatorsModel: root.indicatorsModel
53+ shown: false
54+ }
55+ }
56+
57+ ColumnLayout {
58+ Layout.alignment: Qt.AlignTop
59+ Layout.fillWidth: false
60+
61+ Button {
62+ Layout.fillWidth: true
63+ text: indicatorsMenu.shown ? "Hide" : "Show"
64+ onClicked: {
65+ if (indicatorsMenu.shown) {
66+ indicatorsMenu.hide();
67+ } else {
68+ indicatorsMenu.show();
69+ }
70+ }
71+ }
72+
73+ Rectangle {
74+ Layout.preferredHeight: units.dp(1);
75+ Layout.fillWidth: true;
76+ color: "black"
77+ }
78+
79+ Repeater {
80+ model: root.indicatorData
81+ RowLayout {
82+ CheckBox {
83+ checked: true
84+ onCheckedChanged: checked ? insertIndicator(index) : removeIndicator(index);
85+ }
86+ Label { text: modelData["identifier"] }
87+ }
88+ }
89+ }
90+ }
91+
92+ UT.UnityTestCase {
93+ id: testCase
94+ name: "IndicatorsMenu"
95+ when: windowShown
96+
97+ function init() {
98+ indicatorsMenu.hide();
99+ tryCompare(indicatorsMenu.hideAnimation, "running", false);
100+ compare(indicatorsMenu.state, "initial");
101+ }
102+
103+ // Showing the indicators should fully open the indicator panel.
104+ function test_showAndHide() {
105+ indicatorsMenu.show();
106+ tryCompare(indicatorsMenu, "fullyOpened", true);
107+
108+ indicatorsMenu.hide();
109+ tryCompare(indicatorsMenu, "fullyClosed", true);
110+ }
111+
112+ function test_progress_changes_state_to_reveal() {
113+ indicatorsMenu.height = indicatorsMenu.openedHeight / 2;
114+ compare(indicatorsMenu.state, "reveal", "Indicators should be locked when fully opened.");
115+ }
116+
117+ function test_progress_changes_state_to_locked() {
118+ indicatorsMenu.height = indicatorsMenu.openedHeight;
119+ compare(indicatorsMenu.state, "locked", "Indicators should be locked when fully opened.");
120+ }
121+
122+ function test_open_state() {
123+ compare(indicatorsMenu.fullyClosed, true, "Indicator should show as fully closed.");
124+ compare(indicatorsMenu.partiallyOpened, false, "Indicator should not show as partially opened");
125+ compare(indicatorsMenu.fullyOpened, false, "Indicator should not show as fully opened");
126+
127+ indicatorsMenu.height = indicatorsMenu.openedHeight / 2
128+ compare(indicatorsMenu.fullyClosed, false, "Indicator should not show as fully closed.");
129+ compare(indicatorsMenu.partiallyOpened, true, "Indicator should show as partially opened");
130+ compare(indicatorsMenu.fullyOpened, false, "Indicator should not show as fully opened");
131+
132+ indicatorsMenu.height = indicatorsMenu.openedHeight;
133+ compare(indicatorsMenu.fullyClosed, false, "Indicator should not show as fully closed.");
134+ compare(indicatorsMenu.partiallyOpened, false, "Indicator should show as partially opened");
135+ compare(indicatorsMenu.fullyOpened, true, "Indicator should not show as fully opened");
136+ }
137+
138+ // tests swiping on an indicator item activates the correct item.
139+ function test_swipeForCurrentItem()
140+ {
141+ var indicatorRow = findChild(indicatorsMenu, "indicatorRow")
142+ verify(indicatorRow !== null);
143+
144+ for (var i = 0; i < root.indicatorData.length; i++) {
145+ var indicatorItem = findChild(indicatorsMenu, root.indicatorData[i]["identifier"]+"-panelItem");
146+
147+ var mappedPosition = root.mapFromItem(indicatorItem,
148+ indicatorItem.width/2, indicatorItem.height/2);
149+
150+ console.log(mappedPosition.x, mappedPosition.y)
151+
152+ touchFlick(indicatorsMenu,
153+ mappedPosition.x, mappedPosition.y,
154+ mappedPosition.x, indicatorsMenu.openedHeight / 2,
155+ true /* beginTouch */, false /* endTouch */);
156+
157+ compare(indicatorRow.currentItem, indicatorItem,
158+ "Incorrect item activated at position " + i);
159+
160+ touchFlick(indicatorsMenu,
161+ mappedPosition.x, indicatorsMenu.openedHeight / 2,
162+ mappedPosition.x, mappedPosition.y,
163+ false /* beginTouch */, true /* endTouch */);
164+
165+ // wait until fully closed
166+ tryCompare(indicatorsMenu, "fullyClosed", true);
167+ }
168+ }
169+
170+ }
171+}
tests/qmltests/Panel/New/tst_NewIndicatorsRow.qmldeleted−182
@@ -1,182 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.1
18−import QtQuick.Layouts 1.1
19−import QtTest 1.0
20−import ".."
21−import "../../../../qml/Panel/New"
22−import Ubuntu.Components 0.1
23−import Unity.Test 0.1 as UT
24−import Unity.Indicators 0.1 as Indicators
25−
26−Rectangle {
27− width: units.gu(100)
28− height: units.gu(30)
29− color: "white"
30−
31− Component.onCompleted: {
32− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake1",
33− "/com/canonical/indicators/fake1",
34− "/com/canonical/indicators/fake1",
35− {
36− "title": "Bluetooth",
37− "icons": [ "image://theme/bluetooth-active" ],
38− });
39− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake2",
40− "/com/canonical/indicators/fake2",
41− "/com/canonical/indicators/fake2",
42− {
43− "title": "Network",
44− "icons": [ "image://theme/simcard-error", "image://theme/wifi-high" ],
45− });
46− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake3",
47− "/com/canonical/indicators/fake3",
48− "/com/canonical/indicators/fake3",
49− {
50− "title": "Sound",
51− "icons": [ "image://theme/audio-volume-high" ],
52− });
53− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake4",
54− "/com/canonical/indicators/fake4",
55− "/com/canonical/indicators/fake4",
56− {
57− "title": "Battery",
58− "icons": [ "image://theme/battery-020" ],
59− });
60− Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake5",
61− "/com/canonical/indicators/fake5",
62− "/com/canonical/indicators/fake5",
63− {
64− "title": "Upcoming Events",
65− "label": "12:04",
66− });
67− }
68−
69− Indicators.FakeIndicatorsModel {
70− id: indicatorsModel
71−
72− indicatorData: [
73− {
74− "identifier": "indicator-fake1",
75− "position": 0,
76− "indicatorProperties": {
77− "enabled": true,
78− "busName": "com.canonical.indicators.fake1",
79− "menuObjectPath": "/com/canonical/indicators/fake1",
80− "actionsObjectPath": "/com/canonical/indicators/fake1"
81− }
82− },
83− {
84− "identifier": "indicator-fake2",
85− "position": 1,
86− "indicatorProperties": {
87− "enabled": true,
88− "busName": "com.canonical.indicators.fake2",
89− "menuObjectPath": "/com/canonical/indicators/fake2",
90− "actionsObjectPath": "/com/canonical/indicators/fake2"
91− }
92− },
93− {
94− "identifier": "indicator-fake3",
95− "position": 2,
96− "indicatorProperties": {
97− "enabled": true,
98− "busName": "com.canonical.indicators.fake3",
99− "menuObjectPath": "/com/canonical/indicators/fake3",
100− "actionsObjectPath": "/com/canonical/indicators/fake3"
101− }
102− },
103− {
104− "identifier": "indicator-fake4",
105− "position": 3,
106− "indicatorProperties": {
107− "enabled": true,
108− "busName": "com.canonical.indicators.fake4",
109− "menuObjectPath": "/com/canonical/indicators/fake4",
110− "actionsObjectPath": "/com/canonical/indicators/fake4"
111− }
112− },
113− {
114− "identifier": "indicator-fake5",
115− "position": 4,
116− "indicatorProperties": {
117− "enabled": true,
118− "busName": "com.canonical.indicators.fake5",
119− "menuObjectPath": "/com/canonical/indicators/fake5",
120− "actionsObjectPath": "/com/canonical/indicators/fake5"
121− }
122− }
123− ]
124− }
125−
126− Rectangle {
127− id: itemArea
128− color: "blue"
129− anchors {
130− top: parent.top
131− bottom: parent.bottom
132− }
133− width: units.gu(50)
134−
135− Rectangle {
136− color: "black"
137− anchors.fill: indicatorsRow
138− }
139−
140− IndicatorsRow {
141− id: indicatorsRow
142− overFlowWidth: units.gu(20)
143− height: expanded ? units.gu(7) : units.gu(3)
144− anchors.centerIn: parent
145− indicatorsModel: indicatorsModel
146−
147− Behavior on height {NumberAnimation{duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing}}
148−
149− MouseArea {
150− anchors.fill: parent
151− onClicked: {
152− var item = indicatorsRow.indicatorAt(mouse.x, mouse.y);
153− indicatorsRow.currentItem = item;
154− }
155− }
156− }
157− }
158−
159− ColumnLayout {
160− anchors {
161− top: parent.top
162− bottom: button.top
163− left: itemArea.right
164− right: parent.right
165− }
166− }
167−
168− Button {
169− id: button
170− anchors {
171− left: parent.left
172− right: parent.right
173− bottom: parent.bottom
174− }
175− text: indicatorsRow.expanded ? "Collapse" : "Expand"
176− onClicked: indicatorsRow.expanded = !indicatorsRow.expanded
177− }
178−
179− UT.UnityTestCase {
180− name: "IndicatorsRow"
181− }
182−}
tests/qmltests/Panel/New/tst_NewPanel.qmlnew file+98
@@ -0,0 +1,98 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.1
18+import QtQuick.Layouts 1.1
19+import QtTest 1.0
20+import Unity.Test 0.1 as UT
21+import Ubuntu.Components 0.1
22+import Unity.Indicators 0.1 as Indicators
23+import "../../../../qml/Panel"
24+
25+IndicatorTest {
26+ id: root
27+ width: units.gu(100)
28+ height: units.gu(71)
29+ color: "white"
30+
31+ RowLayout {
32+ anchors.fill: parent
33+ anchors.margins: units.gu(1)
34+
35+ Rectangle {
36+ Layout.fillWidth: true
37+ Layout.fillHeight: true
38+
39+ id: itemArea
40+ color: "blue"
41+
42+ Panel {
43+ id: panel
44+ anchors.fill: parent
45+ indicators {
46+ width: parent.width > units.gu(60) ? units.gu(40) : parent.width
47+ indicatorsModel: root.indicatorsModel
48+ }
49+ }
50+ }
51+
52+ ColumnLayout {
53+ Layout.alignment: Qt.AlignTop
54+ Layout.fillWidth: false
55+
56+ Button {
57+ Layout.fillWidth: true
58+ text: panel.indicators.shown ? "Hide" : "Show"
59+ onClicked: {
60+ if (panel.indicators.shown) {
61+ panel.indicators.hide();
62+ } else {
63+ panel.indicators.show();
64+ }
65+ }
66+ }
67+
68+ Button {
69+ text: panel.fullscreenMode ? "Maximize" : "FullScreen"
70+ Layout.fillWidth: true
71+ onClicked: panel.fullscreenMode = !panel.fullscreenMode
72+ }
73+
74+
75+ Rectangle {
76+ Layout.preferredHeight: units.dp(1);
77+ Layout.fillWidth: true;
78+ color: "black"
79+ }
80+
81+ Repeater {
82+ model: root.indicatorData
83+ RowLayout {
84+ CheckBox {
85+ checked: true
86+ onCheckedChanged: checked ? insertIndicator(index) : removeIndicator(index);
87+ }
88+ Label { text: modelData["identifier"] }
89+ }
90+ }
91+ }
92+ }
93+
94+ UT.UnityTestCase {
95+ name: "Panel"
96+ when: windowShown
97+ }
98+}