on bbbdccd help sign in
unity8/qml/Panel/IndicatorsBar.qml
279 lines 9.7 kB history raw
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 */
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19import "../Components"
21Item {
22 id: root
23 property alias expanded: row.expanded
24 property alias interactive: flickable.interactive
25 property alias indicatorsModel: row.indicatorsModel
26 property alias unitProgress: row.unitProgress
27 property alias enableLateralChanges: row.enableLateralChanges
28 property alias overFlowWidth: row.overFlowWidth
29 readonly property alias currentItemIndex: row.currentItemIndex
30 property real lateralPosition: -1
31 readonly property string currentIndicator: row.currentItem ? row.currentItem.identifier : ""
33 function selectItemAt(lateralPosition) {
34 if (!expanded) {
35 row.resetCurrentItem();
36 }
37 var mapped = root.mapToItem(row, lateralPosition, 0);
38 row.selectItemAt(mapped.x);
39 }
41 function setCurrentItemIndex(index) {
42 if (!expanded) {
43 row.resetCurrentItem();
44 }
45 row.setCurrentItemIndex(index);
46 }
48 function addScrollOffset(scrollAmmout) {
49 if (scrollAmmout < 0) { // left scroll
50 if (flickable.contentX + flickable.width > row.width) return; // already off the left.
52 if (flickable.contentX + flickable.width - scrollAmmout > row.width) { // going to be off the right
53 scrollAmmout = (flickable.contentX + flickable.width) - row.width;
54 }
55 } else { // right scroll
56 if (flickable.contentX < 0) return; // already off the right.
57 if (flickable.contentX - scrollAmmout < 0) scrollAmmout = flickable.contentX; // going to be off the right
58 }
59 d.scrollOffset = d.scrollOffset + scrollAmmout;
60 }
62 QtObject {
63 id: d
64 property var initialItem
65 // the non-expanded distance from row offset to center of initial item
66 property real originalDistanceFromRight: -1
68 // calculate the distance from row offset to center of initial item
69 property real distanceFromRight: {
70 if (originalDistanceFromRight == -1) return 0;
71 if (!initialItem) return 0;
72 return row.width - initialItem.x - initialItem.width /2;
73 }
75 // offset to the intially selected expanded item
76 property real rowOffset: 0
77 property real scrollOffset: 0
78 property real alignmentAdjustment: 0
79 property real combinedOffset: 0
81 // when the scroll offset changes, we need to reclaculate the relative lateral position
82 onScrollOffsetChanged: root.lateralPositionChanged()
84 onInitialItemChanged: {
85 originalDistanceFromRight = initialItem ? (row.width - initialItem.x - initialItem.width/2) : -1;
86 }
88 Behavior on alignmentAdjustment {
89 NumberAnimation { duration: UbuntuAnimation.BriskDuration; easing: UbuntuAnimation.StandardEasing}
90 }
92 function alignIndicators() {
93 flickable.resetContentXComponents();
95 if (expanded && !flickable.moving) {
96 // gap between left and row?
97 if (flickable.contentX + flickable.width > row.width) {
98 // row width is less than flickable
99 if (row.width < flickable.width) {
100 d.alignmentAdjustment -= flickable.contentX;
101 } else {
102 d.alignmentAdjustment -= ((flickable.contentX + flickable.width) - row.width);
103 }
105 // gap between right and row?
106 } else if (flickable.contentX < 0) {
107 d.alignmentAdjustment -= flickable.contentX;
109 // current item overlap on left
110 } else if (row.currentItem && (flickable.contentX + flickable.width) < (row.width - row.currentItem.x)) {
111 d.alignmentAdjustment += ((row.width - row.currentItem.x) - (flickable.contentX + flickable.width));
113 // current item overlap on right
114 } else if (row.currentItem && flickable.contentX > (row.width - row.currentItem.x - row.currentItem.width)) {
115 d.alignmentAdjustment -= flickable.contentX - (row.width - row.currentItem.x - row.currentItem.width);
116 }
117 }
118 }
119 }
121 Rectangle {
122 id: grayLine
123 height: units.dp(2)
124 width: parent.width
125 anchors.bottom: parent.bottom
127 color: "#888888"
128 opacity: expanded ? 1.0 : 0.0
129 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
130 }
132 Item {
133 id: rowContainer
134 anchors.fill: parent
135 clip: expanded || row.width > rowContainer.width
137 Flickable {
138 id: flickable
139 objectName: "flickable"
141 // we rotate it because we want the Flickable to align its content item
142 // on the right instead of on the left
143 rotation: 180
145 anchors.fill: parent
146 contentWidth: row.width
147 contentX: d.combinedOffset
148 interactive: false
150 // contentX can change by user interaction as well as user offset changes
151 // This function re-aligns the offsets so that the offsets match the contentX
152 function resetContentXComponents() {
153 d.scrollOffset += d.combinedOffset - flickable.contentX;
154 }
156 rebound: Transition {
157 NumberAnimation {
158 properties: "x"
159 duration: 600
160 easing.type: Easing.OutCubic
161 }
162 }
164 IndicatorItemRow {
165 id: row
166 objectName: "indicatorItemRow"
167 anchors {
168 top: parent.top
169 bottom: parent.bottom
170 }
172 // Compensate for the Flickable rotation (ie, counter-rotate)
173 rotation: 180
175 lateralPosition: {
176 if (root.lateralPosition == -1) return -1;
178 var mapped = root.mapToItem(row, root.lateralPosition, 0);
179 return Math.min(Math.max(mapped.x, 0), row.width);
180 }
182 onCurrentItemChanged: {
183 if (!currentItem) d.initialItem = undefined;
184 else if (!d.initialItem) d.initialItem = currentItem;
185 }
187 MouseArea {
188 anchors.fill: parent
189 enabled: root.expanded
190 onClicked: {
191 row.selectItemAt(mouse.x);
192 d.alignIndicators();
193 }
194 }
195 }
197 }
198 }
200 Timer {
201 id: alignmentTimer
202 interval: UbuntuAnimation.FastDuration // enough for row animation.
203 repeat: false
205 onTriggered: d.alignIndicators();
206 }
208 states: [
209 State {
210 name: "minimized"
211 when: !expanded
212 PropertyChanges {
213 target: d
214 rowOffset: 0
215 scrollOffset: 0
216 alignmentAdjustment: 0
217 combinedOffset: 0
218 restoreEntryValues: false
219 }
220 },
221 State {
222 name: "expanded"
223 when: expanded && !interactive
225 PropertyChanges {
226 target: d
227 combinedOffset: rowOffset + alignmentAdjustment - scrollOffset
228 }
229 PropertyChanges {
230 target: d
231 rowOffset: {
232 if (!initialItem) return 0;
233 if (distanceFromRight - initialItem.width <= 0) return 0;
235 var rowOffset = distanceFromRight - originalDistanceFromRight;
236 return rowOffset;
237 }
238 restoreEntryValues: false
239 }
240 }
241 , State {
242 name: "interactive"
243 when: expanded && interactive
245 StateChangeScript {
246 script: {
247 // don't use row offset anymore.
248 d.scrollOffset -= d.rowOffset;
249 d.rowOffset = 0;
250 d.initialItem = undefined;
251 alignmentTimer.start();
252 }
253 }
254 PropertyChanges {
255 target: d
256 combinedOffset: rowOffset + alignmentAdjustment - scrollOffset
257 restoreEntryValues: false
258 }
259 }
260 ]
262 transitions: [
263 Transition {
264 from: "expanded"
265 to: "minimized"
266 PropertyAction {
267 target: d
268 properties: "rowOffset, scrollOffset, alignmentAdjustment"
269 value: 0
270 }
271 PropertyAnimation {
272 target: d
273 properties: "combinedOffset"
274 duration: UbuntuAnimation.SnapDuration
275 easing: UbuntuAnimation.StandardEasing
276 }
277 }
278 ]