on bb09f86 help sign in
unity8/qml/Panel/PanelBar.qml
313 lines 11 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 model: row.model
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 property int alignment: Qt.AlignRight
33 property alias showRowTitle: row.showRowTitle
34 property alias rowTitle: row.rowTitle
35 property alias rowItemDelegate: row.delegate
37 implicitWidth: flickable.contentWidth
39 function selectItemAt(lateralPosition) {
40 if (!expanded) {
41 row.resetCurrentItem();
42 }
43 var mapped = root.mapToItem(row, lateralPosition, 0);
44 row.selectItemAt(mapped.x);
45 }
47 function setCurrentItemIndex(index) {
48 if (!expanded) {
49 row.resetCurrentItem();
50 }
51 row.setCurrentItemIndex(index);
52 d.alignIndicators();
53 }
55 function addScrollOffset(scrollAmmout) {
56 if (root.alignment == Qt.AlignLeft) {
57 scrollAmmout = -scrollAmmout;
58 }
60 if (scrollAmmout < 0) { // left scroll
61 if (flickable.contentX + flickable.width > row.width) return; // already off the left.
63 if (flickable.contentX + flickable.width - scrollAmmout > row.width) { // going to be off the left
64 scrollAmmout = (flickable.contentX + flickable.width) - row.width;
65 }
66 } else { // right scroll
67 if (flickable.contentX < 0) return; // already off the right.
68 if (flickable.contentX - scrollAmmout < 0) { // going to be off the right
69 scrollAmmout = flickable.contentX;
70 }
71 }
72 d.scrollOffset = d.scrollOffset + scrollAmmout;
73 }
75 QtObject {
76 id: d
77 property var initialItem
78 // the non-expanded distance from alignment edge to center of initial item
79 property real originalDistanceFromEdge: -1
81 // calculate the distance from row alignment edge edge to center of initial item
82 property real distanceFromEdge: {
83 if (originalDistanceFromEdge == -1) return 0;
84 if (!initialItem) return 0;
86 if (root.alignment == Qt.AlignLeft) {
87 return initialItem.x - initialItem.width / 2;
88 } else {
89 return row.width - initialItem.x - initialItem.width / 2;
90 }
91 }
93 // offset to the intially selected expanded item
94 property real rowOffset: 0
95 property real scrollOffset: 0
96 property real alignmentAdjustment: 0
97 property real combinedOffset: 0
99 // when the scroll offset changes, we need to reclaculate the relative lateral position
100 onScrollOffsetChanged: root.lateralPositionChanged()
102 onInitialItemChanged: {
103 if (root.alignment == Qt.AlignLeft) {
104 originalDistanceFromEdge = initialItem ? (initialItem.x - initialItem.width/2) : -1;
105 } else {
106 originalDistanceFromEdge = initialItem ? (row.width - initialItem.x - initialItem.width/2) : -1;
107 }
108 }
110 Behavior on alignmentAdjustment {
111 NumberAnimation { duration: UbuntuAnimation.BriskDuration; easing: UbuntuAnimation.StandardEasing}
112 }
114 function alignIndicators() {
115 flickable.resetContentXComponents();
117 if (expanded && !flickable.moving) {
119 if (root.alignment == Qt.AlignLeft) {
120 // current item overlap on left
121 if (row.currentItem && flickable.contentX > row.currentItem.x) {
122 d.alignmentAdjustment -= (flickable.contentX - row.currentItem.x);
124 // current item overlap on right
125 } else if (row.currentItem && flickable.contentX + flickable.width < row.currentItem.x + row.currentItem.width) {
126 d.alignmentAdjustment += (row.currentItem.x + row.currentItem.width) - (flickable.contentX + flickable.width);
127 }
128 } else {
129 // gap between left and row?
130 if (flickable.contentX + flickable.width > row.width) {
131 // row width is less than flickable
132 if (row.width < flickable.width) {
133 d.alignmentAdjustment -= flickable.contentX;
134 } else {
135 d.alignmentAdjustment -= ((flickable.contentX + flickable.width) - row.width);
136 }
138 // gap between right and row?
139 } else if (flickable.contentX < 0) {
140 d.alignmentAdjustment -= flickable.contentX;
142 // current item overlap on left
143 } else if (row.currentItem && (flickable.contentX + flickable.width) < (row.width - row.currentItem.x)) {
144 d.alignmentAdjustment += ((row.width - row.currentItem.x) - (flickable.contentX + flickable.width));
146 // current item overlap on right
147 } else if (row.currentItem && flickable.contentX > (row.width - row.currentItem.x - row.currentItem.width)) {
148 d.alignmentAdjustment -= flickable.contentX - (row.width - row.currentItem.x - row.currentItem.width);
149 }
150 }
151 }
152 }
153 }
155 Rectangle {
156 id: grayLine
157 height: units.dp(2)
158 width: parent.width
159 anchors.bottom: parent.bottom
161 color: "#888888"
162 opacity: expanded ? 1.0 : 0.0
163 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
164 }
166 Item {
167 id: rowContainer
168 anchors.fill: parent
169 clip: expanded || row.width > rowContainer.width
171 Flickable {
172 id: flickable
173 objectName: "flickable"
175 // we rotate it because we want the Flickable to align its content item
176 // on the right instead of on the left
177 rotation: root.alignment != Qt.AlignRight ? 0 : 180
179 anchors.fill: parent
180 contentWidth: row.width
181 contentX: d.combinedOffset
182 interactive: false
184 // contentX can change by user interaction as well as user offset changes
185 // This function re-aligns the offsets so that the offsets match the contentX
186 function resetContentXComponents() {
187 d.scrollOffset += d.combinedOffset - flickable.contentX;
188 }
190 rebound: Transition {
191 NumberAnimation {
192 properties: "x"
193 duration: 600
194 easing.type: Easing.OutCubic
195 }
196 }
198 PanelItemRow {
199 id: row
200 objectName: "panelItemRow"
201 anchors {
202 top: parent.top
203 bottom: parent.bottom
204 }
206 // Compensate for the Flickable rotation (ie, counter-rotate)
207 rotation: root.alignment != Qt.AlignRight ? 0 : 180
209 lateralPosition: {
210 if (root.lateralPosition == -1) return -1;
212 var mapped = root.mapToItem(row, root.lateralPosition, 0);
213 return Math.min(Math.max(mapped.x, 0), row.width);
214 }
216 onCurrentItemChanged: {
217 if (!currentItem) d.initialItem = undefined;
218 else if (!d.initialItem) d.initialItem = currentItem;
219 }
221 MouseArea {
222 anchors.fill: parent
223 enabled: root.expanded
224 onClicked: {
225 row.selectItemAt(mouse.x);
226 d.alignIndicators();
227 }
228 }
229 }
231 }
232 }
234 Timer {
235 id: alignmentTimer
236 interval: UbuntuAnimation.FastDuration // enough for row animation.
237 repeat: false
239 onTriggered: d.alignIndicators();
240 }
242 states: [
243 State {
244 name: "minimized"
245 when: !expanded
246 PropertyChanges {
247 target: d
248 rowOffset: 0
249 scrollOffset: 0
250 alignmentAdjustment: 0
251 combinedOffset: 0
252 restoreEntryValues: false
253 }
254 },
255 State {
256 name: "expanded"
257 when: expanded && !interactive
259 PropertyChanges {
260 target: d
261 combinedOffset: rowOffset + alignmentAdjustment - scrollOffset
262 }
263 PropertyChanges {
264 target: d
265 rowOffset: {
266 if (!initialItem) return 0;
267 if (distanceFromEdge - initialItem.width <= 0) return 0;
269 var rowOffset = distanceFromEdge - originalDistanceFromEdge;
270 return rowOffset;
271 }
272 restoreEntryValues: false
273 }
274 },
275 State {
276 name: "interactive"
277 when: expanded && interactive
279 StateChangeScript {
280 script: {
281 // don't use row offset anymore.
282 d.scrollOffset -= d.rowOffset;
283 d.rowOffset = 0;
284 d.initialItem = undefined;
285 alignmentTimer.start();
286 }
287 }
288 PropertyChanges {
289 target: d
290 combinedOffset: rowOffset + alignmentAdjustment - scrollOffset
291 restoreEntryValues: false
292 }
293 }
294 ]
296 transitions: [
297 Transition {
298 from: "expanded"
299 to: "minimized"
300 PropertyAction {
301 target: d
302 properties: "rowOffset, scrollOffset, alignmentAdjustment"
303 value: 0
304 }
305 PropertyAnimation {
306 target: d
307 properties: "combinedOffset"
308 duration: UbuntuAnimation.SnapDuration
309 easing: UbuntuAnimation.StandardEasing
310 }
311 }
312 ]