on a142f21 help sign in
unity8/qml/Panel/IndicatorsBar.qml
278 lines 9.6 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.2
18import Ubuntu.Components 1.1
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
32 function selectItemAt(lateralPosition) {
33 if (!expanded) {
34 row.resetCurrentItem();
35 }
36 var mapped = root.mapToItem(row, lateralPosition, 0);
37 row.selectItemAt(mapped.x);
38 }
40 function setCurrentItemIndex(index) {
41 if (!expanded) {
42 row.resetCurrentItem();
43 }
44 row.setCurrentItemIndex(index);
45 }
47 function addScrollOffset(scrollAmmout) {
48 if (scrollAmmout < 0) { // left scroll
49 if (flickable.contentX + flickable.width > row.width) return; // already off the left.
51 if (flickable.contentX + flickable.width - scrollAmmout > row.width) { // going to be off the right
52 scrollAmmout = (flickable.contentX + flickable.width) - row.width;
53 }
54 } else { // right scroll
55 if (flickable.contentX < 0) return; // already off the right.
56 if (flickable.contentX - scrollAmmout < 0) scrollAmmout = flickable.contentX; // going to be off the right
57 }
58 d.scrollOffset = d.scrollOffset + scrollAmmout;
59 }
61 QtObject {
62 id: d
63 property var initialItem
64 // the non-expanded distance from row offset to center of initial item
65 property real originalDistanceFromRight: -1
67 // calculate the distance from row offset to center of initial item
68 property real distanceFromRight: {
69 if (originalDistanceFromRight == -1) return 0;
70 if (!initialItem) return 0;
71 return row.width - initialItem.x - initialItem.width /2;
72 }
74 // offset to the intially selected expanded item
75 property real rowOffset: 0
76 property real scrollOffset: 0
77 property real alignmentAdjustment: 0
78 property real combinedOffset: 0
80 // when the scroll offset changes, we need to reclaculate the relative lateral position
81 onScrollOffsetChanged: root.lateralPositionChanged()
83 onInitialItemChanged: {
84 originalDistanceFromRight = initialItem ? (row.width - initialItem.x - initialItem.width/2) : -1;
85 }
87 Behavior on alignmentAdjustment {
88 NumberAnimation { duration: UbuntuAnimation.BriskDuration; easing: UbuntuAnimation.StandardEasing}
89 }
91 function alignIndicators() {
92 flickable.resetContentXComponents();
94 if (expanded && !flickable.moving) {
95 // gap between left and row?
96 if (flickable.contentX + flickable.width > row.width) {
97 // row width is less than flickable
98 if (row.width < flickable.width) {
99 d.alignmentAdjustment -= flickable.contentX;
100 } else {
101 d.alignmentAdjustment -= ((flickable.contentX + flickable.width) - row.width);
102 }
104 // gap between right and row?
105 } else if (flickable.contentX < 0) {
106 d.alignmentAdjustment -= flickable.contentX;
108 // current item overlap on left
109 } else if (row.currentItem && (flickable.contentX + flickable.width) < (row.width - row.currentItem.x)) {
110 d.alignmentAdjustment += ((row.width - row.currentItem.x) - (flickable.contentX + flickable.width));
112 // current item overlap on right
113 } else if (row.currentItem && flickable.contentX > (row.width - row.currentItem.x - row.currentItem.width)) {
114 d.alignmentAdjustment -= flickable.contentX - (row.width - row.currentItem.x - row.currentItem.width);
115 }
116 }
117 }
118 }
120 Rectangle {
121 id: grayLine
122 height: units.dp(2)
123 width: parent.width
124 anchors.bottom: parent.bottom
126 color: "#888888"
127 opacity: expanded ? 1.0 : 0.0
128 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
129 }
131 Item {
132 id: rowContainer
133 anchors.fill: parent
134 clip: expanded || row.width > rowContainer.width
136 Flickable {
137 id: flickable
138 objectName: "flickable"
140 // we rotate it because we want the Flickable to align its content item
141 // on the right instead of on the left
142 rotation: 180
144 anchors.fill: parent
145 contentWidth: row.width
146 contentX: d.combinedOffset
147 interactive: false
149 // contentX can change by user interaction as well as user offset changes
150 // This function re-aligns the offsets so that the offsets match the contentX
151 function resetContentXComponents() {
152 d.scrollOffset += d.combinedOffset - flickable.contentX;
153 }
155 rebound: Transition {
156 NumberAnimation {
157 properties: "x"
158 duration: 600
159 easing.type: Easing.OutCubic
160 }
161 }
163 IndicatorItemRow {
164 id: row
165 objectName: "indicatorItemRow"
166 anchors {
167 top: parent.top
168 bottom: parent.bottom
169 }
171 // Compensate for the Flickable rotation (ie, counter-rotate)
172 rotation: 180
174 lateralPosition: {
175 if (root.lateralPosition == -1) return -1;
177 var mapped = root.mapToItem(row, root.lateralPosition, 0);
178 return Math.min(Math.max(mapped.x, 0), row.width);
179 }
181 onCurrentItemChanged: {
182 if (!currentItem) d.initialItem = undefined;
183 else if (!d.initialItem) d.initialItem = currentItem;
184 }
186 MouseArea {
187 anchors.fill: parent
188 enabled: root.expanded
189 onClicked: {
190 row.selectItemAt(mouse.x);
191 d.alignIndicators();
192 }
193 }
194 }
196 }
197 }
199 Timer {
200 id: alignmentTimer
201 interval: UbuntuAnimation.FastDuration // enough for row animation.
202 repeat: false
204 onTriggered: d.alignIndicators();
205 }
207 states: [
208 State {
209 name: "minimized"
210 when: !expanded
211 PropertyChanges {
212 target: d
213 rowOffset: 0
214 scrollOffset: 0
215 alignmentAdjustment: 0
216 combinedOffset: 0
217 restoreEntryValues: false
218 }
219 },
220 State {
221 name: "expanded"
222 when: expanded && !interactive
224 PropertyChanges {
225 target: d
226 combinedOffset: rowOffset + alignmentAdjustment - scrollOffset
227 }
228 PropertyChanges {
229 target: d
230 rowOffset: {
231 if (!initialItem) return 0;
232 if (distanceFromRight - initialItem.width <= 0) return 0;
234 var rowOffset = distanceFromRight - originalDistanceFromRight;
235 return rowOffset;
236 }
237 restoreEntryValues: false
238 }
239 }
240 , State {
241 name: "interactive"
242 when: expanded && interactive
244 StateChangeScript {
245 script: {
246 // don't use row offset anymore.
247 d.scrollOffset -= d.rowOffset;
248 d.rowOffset = 0;
249 d.initialItem = undefined;
250 alignmentTimer.start();
251 }
252 }
253 PropertyChanges {
254 target: d
255 combinedOffset: rowOffset + alignmentAdjustment - scrollOffset
256 restoreEntryValues: false
257 }
258 }
259 ]
261 transitions: [
262 Transition {
263 from: "expanded"
264 to: "minimized"
265 PropertyAction {
266 target: d
267 properties: "rowOffset, scrollOffset, alignmentAdjustment"
268 value: 0
269 }
270 PropertyAnimation {
271 target: d
272 properties: "combinedOffset"
273 duration: UbuntuAnimation.SnapDuration
274 easing: UbuntuAnimation.StandardEasing
275 }
276 }
277 ]