on 7235b09 help sign in
unity8/qml/Panel/IndicatorsMenu.qml
322 lines 10 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 Ubuntu.Gestures 0.1
20import "../Components"
22Showable {
23 id: root
24 property alias indicatorsModel: bar.indicatorsModel
25 property alias showDragHandle: __showDragHandle
26 property alias hideDragHandle: __hideDragHandle
27 property alias overFlowWidth: bar.overFlowWidth
28 property alias verticalVelocityThreashold: yVelocityCalculator.velocityThreashold
30 property int minimizedPanelHeight: units.gu(3)
31 property int expandedPanelHeight: units.gu(7)
32 property real openedHeight: units.gu(71)
33 readonly property real unitProgress: Math.max(0, (height - minimizedPanelHeight) / (openedHeight - minimizedPanelHeight))
34 readonly property bool fullyOpened: unitProgress >= 1
35 readonly property bool partiallyOpened: unitProgress > 0 && unitProgress < 1.0
36 readonly property bool fullyClosed: unitProgress == 0
38 property bool enableHint: true
39 property bool contentEnabled: true
40 property color panelColor: "black"
42 signal showTapped(point position)
45 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
46 // use its own values. Need to ask design about this.
47 showAnimation: StandardAnimation {
48 property: "height"
49 to: openedHeight
50 duration: UbuntuAnimation.BriskDuration
51 easing.type: Easing.OutCubic
52 }
54 hideAnimation: StandardAnimation {
55 property: "height"
56 to: minimizedPanelHeight
57 duration: UbuntuAnimation.BriskDuration
58 easing.type: Easing.OutCubic
59 }
61 height: minimizedPanelHeight
62 onHeightChanged: {
63 var revealProgress = root.height - minimizedPanelHeight;
65 if (!showAnimation.running && !hideAnimation.running) {
66 if (revealProgress <= 0) {
67 root.state = "initial";
68 } else {
69 root.state = "reveal";
70 }
71 }
72 }
73 clip: root.partiallyOpened
75 // eater
76 MouseArea {
77 anchors.fill: parent
78 }
80 MenuContent {
81 id: content
82 objectName: "menuContent"
84 anchors {
85 left: parent.left
86 right: parent.right
87 top: bar.bottom
88 }
89 height: openedHeight - bar.height - handle.height
90 indicatorsModel: root.indicatorsModel
91 visible: root.unitProgress > 0
92 enabled: contentEnabled
93 }
95 Handle {
96 id: handle
97 anchors {
98 left: parent.left
99 right: parent.right
100 bottom: parent.bottom
101 }
102 height: units.gu(2)
103 active: d.activeDragHandle ? true : false
105 //small shadow gradient at bottom of menu
106 Rectangle {
107 anchors {
108 left: parent.left
109 right: parent.right
110 bottom: parent.top
111 }
112 height: units.gu(0.5)
113 gradient: Gradient {
114 GradientStop { position: 0.0; color: "transparent" }
115 GradientStop { position: 1.0; color: "black" }
116 }
117 opacity: 0.3
118 }
119 }
121 Rectangle {
122 anchors.fill: bar
123 color: panelColor
124 }
126 IndicatorsBar {
127 id: bar
128 objectName: "indicatorsBar"
130 anchors {
131 left: parent.left
132 right: parent.right
133 }
134 expanded: false
135 enableLateralChanges: false
136 lateralPosition: -1
137 unitProgress: root.unitProgress
139 height: expanded ? expandedPanelHeight : minimizedPanelHeight
140 Behavior on height { NumberAnimation { duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing } }
141 }
143 ScrollCalculator {
144 id: leftScroller
145 width: units.gu(5)
146 anchors.left: bar.left
147 height: bar.height
149 forceScrollingPercentage: 0.33
150 stopScrollThreshold: units.gu(0.75)
151 direction: Qt.RightToLeft
152 lateralPosition: -1
154 onScroll: bar.addScrollOffset(-scrollAmount);
155 }
157 ScrollCalculator {
158 id: rightScroller
159 width: units.gu(5)
160 anchors.right: bar.right
161 height: bar.height
163 forceScrollingPercentage: 0.33
164 stopScrollThreshold: units.gu(0.75)
165 direction: Qt.LeftToRight
166 lateralPosition: -1
168 onScroll: bar.addScrollOffset(scrollAmount);
169 }
171 DragHandle {
172 id: __showDragHandle
173 anchors.bottom: parent.bottom
174 anchors.left: parent.left
175 anchors.right: parent.right
176 height: minimizedPanelHeight
177 direction: Direction.Downwards
178 enabled: !root.shown && root.available
179 autoCompleteDragThreshold: maxTotalDragDistance / 2
180 stretch: true
181 distanceThreshold: minimizedPanelHeight
182 onTapped: showTapped(Qt.point(touchSceneX, touchSceneY));
184 // using hint regulates minimum to hint displacement, but in fullscreen mode, we need to do it manually.
185 overrideStartValue: enableHint ? minimizedPanelHeight : expandedPanelHeight + handle.height
186 maxTotalDragDistance: openedHeight - (enableHint ? minimizedPanelHeight : expandedPanelHeight + handle.height)
187 hintDisplacement: enableHint ? expandedPanelHeight - minimizedPanelHeight + handle.height : 0
188 }
190 DragHandle {
191 id: __hideDragHandle
192 anchors.fill: handle
193 direction: Direction.Upwards
194 enabled: root.shown && root.available
195 hintDisplacement: units.gu(3)
196 autoCompleteDragThreshold: maxTotalDragDistance / 6
197 stretch: true
198 maxTotalDragDistance: openedHeight - expandedPanelHeight - handle.height
199 distanceThreshold: 0
200 }
202 PanelVelocityCalculator {
203 id: yVelocityCalculator
204 velocityThreashold: 0.5
205 trackedValue: d.activeDragHandle ? d.activeDragHandle.touchSceneY : 0
207 onVelocityThreasholdTriggered: bar.updateItemFromLateralPosition(bar.lateralPosition);
208 }
210 Connections {
211 target: showAnimation
212 onRunningChanged: {
213 if (showAnimation.running) {
214 root.state = "commit";
215 bar.alignIndicatorsToLeft();
216 }
217 }
218 }
220 Connections {
221 target: hideAnimation
222 onRunningChanged: {
223 if (hideAnimation.running) {
224 root.state = "initial";
225 }
226 }
227 }
229 Connections {
230 target: content
231 onCurrentMenuIndexChanged: {
232 var oldActive = d.enableIndexChangeSignal;
233 if (!oldActive) return;
234 d.enableIndexChangeSignal = false;
236 bar.setCurrentItemIndex(content.currentMenuIndex);
238 d.enableIndexChangeSignal = oldActive;
239 }
240 }
242 Connections {
243 target: bar
244 onCurrentItemIndexChanged: {
245 var oldActive = d.enableIndexChangeSignal;
246 if (!oldActive) return;
247 d.enableIndexChangeSignal = false;
249 content.setCurrentMenuIndex(bar.currentItemIndex);
251 d.enableIndexChangeSignal = oldActive;
252 }
253 }
255 QtObject {
256 id: d
257 property bool enableIndexChangeSignal: true
258 property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
260 property real rowMappedLateralPosition: {
261 if (!d.activeDragHandle) return -1;
262 if (!d.activeDragHandle.dragging) return -1;
263 return d.activeDragHandle.mapToItem(bar, d.activeDragHandle.touchX, 0).x;
264 }
265 }
267 states: [
268 State {
269 name: "initial"
270 },
271 State {
272 name: "reveal"
273 StateChangeScript {
274 script: {
275 yVelocityCalculator.reset();
276 // initial item selection
277 bar.selectItemAt(d.activeDragHandle ? d.activeDragHandle.touchX : -1);
278 }
279 }
280 PropertyChanges {
281 target: bar
282 expanded: true
283 // changes to lateral touch position effect which indicator is selected
284 lateralPosition: d.rowMappedLateralPosition
285 // vertical velocity determines if changes in lateral position has an effect
286 enableLateralChanges: {
287 if (!d.activeDragHandle) return false;
288 if (!d.activeDragHandle.dragging) return false;
290 return !yVelocityCalculator.stopLateralChanges;
291 }
292 }
293 // left scroll bar handling
294 PropertyChanges {
295 target: leftScroller
296 lateralPosition: {
297 if (!d.activeDragHandle) return -1;
298 if (!d.activeDragHandle.dragging) return -1;
300 var mapped = d.activeDragHandle.mapToItem(leftScroller, d.activeDragHandle.touchX, 0);
301 return mapped.x;
302 }
303 }
304 // right scroll bar handling
305 PropertyChanges {
306 target: rightScroller
307 lateralPosition: {
308 if (!d.activeDragHandle) return -1;
309 if (!d.activeDragHandle.dragging) return -1;
311 var mapped = d.activeDragHandle.mapToItem(rightScroller, d.activeDragHandle.touchX, 0);
312 return mapped.x;
313 }
314 }
315 },
316 State {
317 name: "commit"
318 PropertyChanges { target: bar; expanded: true }
319 }
320 ]
321 state: "initial"