@@ -1,416 +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.0
18−import Ubuntu.Components 0.1
19−import Ubuntu.Gestures 0.1
20−import Unity.Indicators 0.1 as Indicators
21−
22−import "../Components"
23−import "../Components/ListItems"
24−import "Indicators"
25−
26−Showable {
27− id: indicators
28−
29− property real openedHeight: units.gu(71)
30− property int panelHeight: units.gu(3)
31− property alias overFlowWidth: indicatorRow.overFlowWidth
32− property alias showAll: indicatorRow.showAll
33− // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
34− property string profile: indicatorProfile
35−
36− readonly property real hintValue: panelHeight + menuContent.headerHeight
37− readonly property int lockThreshold: openedHeight / 2
38− property bool fullyOpened: height == openedHeight
39− property bool partiallyOpened: height > panelHeight && !fullyOpened
40− property bool fullyClosed: height <= panelHeight
41− property bool contentEnabled: true
42− property bool initalizeItem: true
43− readonly property alias content: menuContent
44− property real unitProgress: (height - panelHeight) / (openedHeight - panelHeight)
45− property bool enableHint: true
46− property real showHintBottomMargin: 0
47−
48− signal showTapped(point position)
49−
50− // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
51− // use its own values. Need to ask design about this.
52− showAnimation: StandardAnimation {
53− property: "height"
54− to: openedHeight
55− }
56−
57− hideAnimation: StandardAnimation {
58− property: "height"
59− duration: 350
60− to: panelHeight
61− easing.type: Easing.OutCubic
62− }
63−
64− onOpenedHeightChanged: {
65− if (showAnimation.running) {
66− showAnimation.restart();
67− } else if (indicators.shown) {
68− height = openedHeight;
69− }
70− }
71−
72− height: panelHeight
73− onHeightChanged: updateRevealProgressState(indicators.height - panelHeight - showHintBottomMargin, true)
74−
75− function updateRevealProgressState(revealProgress, enableRelease) {
76− if (!showAnimation.running && !hideAnimation.running) {
77− if (revealProgress === 0) {
78− indicators.state = "initial";
79− } else if (enableHint && revealProgress > 0 && revealProgress <= hintValue) {
80− indicators.state = "hint";
81− } else if ((!enableHint || revealProgress > hintValue) && revealProgress < lockThreshold) {
82− indicators.state = "reveal";
83− } else if (revealProgress >= lockThreshold && lockThreshold > 0) {
84− indicators.state = "locked";
85− }
86− }
87− }
88−
89− function calculateCurrentItem(xValue, useBuffer) {
90− var rowCoordinates;
91− var itemCoordinates;
92− var currentItem;
93− var distanceFromRightEdge;
94− var bufferExceeded = false;
95−
96− if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return;
97−
98− /*
99− If user drags the indicator handle bar down a distance hintValue or less, this is 0.
100− If bar is dragged down a distance greater than or equal to lockThreshold, this is 1.
101− Otherwise it contains the bar's location as a fraction of the distance between hintValue (is 0) and lockThreshold (is 1).
102− */
103− var verticalProgress =
104− MathUtils.clamp((indicators.height - handle.height - hintValue) /
105− (lockThreshold - hintValue), 0, 1);
106−
107− /*
108− Vertical velocity check. Don't change the indicator if we're moving too quickly.
109− */
110− var verticalSpeed = Math.abs(yVelocityCalculator.calculate());
111− if (verticalSpeed >= 0.05 && !initalizeItem) {
112− return;
113− }
114−
115− /*
116− Percentage of an indicator icon's width the user's press can stray horizontally from the
117− focused icon before we change focus to another icon. E.g. a value of 0.5 means you must
118− go right a distance of half an icon's width before focus moves to the icon on the right
119− */
120− var maxBufferThreshold = 0.5;
121−
122− /*
123− To help users find the indicator of their choice while opening the indicators, we add logic to add a
124− left/right buffer to each icon so it is harder for the focus to be moved accidentally to another icon,
125− as the user moves their finger down, but yet allows them to switch indicator if they want.
126− This buffer is wider the further the user's finger is from the top of the screen.
127− */
128− var effectiveBufferThreshold = maxBufferThreshold * verticalProgress;
129−
130− rowCoordinates = indicatorRow.mapToItem(indicatorRow.row, xValue, 0);
131− // get the current delegate
132− currentItem = indicatorRow.row.itemAt(rowCoordinates.x, 0);
133− if (currentItem) {
134− itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
135− distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width);
136− console.log(distanceFromRightEdge);
137− if (currentItem != indicatorRow.currentItem) {
138− if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
139− bufferExceeded = true;
140− } else {
141− if (indicatorRow.currentItemIndex < currentItem.ownIndex && distanceFromRightEdge < (1 - effectiveBufferThreshold)) {
142− bufferExceeded = true;
143− } else if (indicatorRow.currentItemIndex > currentItem.ownIndex && distanceFromRightEdge > effectiveBufferThreshold) {
144− bufferExceeded = true;
145− }
146− }
147− if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItemIndex < 0 || indicatorRow.currentItem == null) {
148− indicatorRow.setCurrentItem(currentItem);
149− }
150−
151− // need to re-init the distanceFromRightEdge for offset calculation
152− itemCoordinates = indicatorRow.row.mapToItem(indicatorRow.currentItem, rowCoordinates.x, 0);
153− distanceFromRightEdge = (indicatorRow.currentItem.width - itemCoordinates.x) / (indicatorRow.currentItem.width);
154− }
155− indicatorRow.currentItemOffset = 1 - (distanceFromRightEdge * 2);
156− } else if (initalizeItem) {
157− indicatorRow.setDefaultItem();
158− indicatorRow.currentItemOffset = 0;
159− }
160− initalizeItem = indicatorRow.currentItem == null;
161− }
162−
163− // eater
164− MouseArea {
165− anchors {
166− top: parent.top
167− bottom: handle.bottom
168− left: parent.left
169− right: parent.right
170− }
171− }
172−
173− VisibleIndicators {
174− id: visibleIndicators
175− }
176−
177− MenuContent {
178− id: menuContent
179− objectName: "menuContent"
180−
181− anchors {
182− left: parent.left
183− right: parent.right
184− top: indicatorRow.bottom
185− bottom: handle.top
186− }
187− indicatorsModel: visibleIndicators.model
188− visible: indicators.partiallyOpened || indicators.fullyOpened
189− clip: indicators.partiallyOpened
190− enabled: contentEnabled
191−
192− //small shadow gradient at bottom of menu
193− Rectangle {
194− anchors {
195− left: parent.left
196− right: parent.right
197− bottom: parent.bottom
198− }
199− height: units.gu(0.5)
200− gradient: Gradient {
201− GradientStop { position: 0.0; color: "transparent" }
202− GradientStop { position: 1.0; color: "black" }
203− }
204− opacity: 0.4
205− }
206− }
207−
208− Rectangle {
209− id: handle
210−
211− color: menuContent.color
212−
213− anchors {
214− left: parent.left
215− right: parent.right
216− bottom: parent.bottom
217− }
218− height: Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0)
219− clip: height < handleImage.height
220− visible: menuContent.visible
221−
222− BorderImage {
223− id: handleImage
224− source: "graphics/handle.sci"
225− height: panelHeight
226− anchors {
227− left: parent.left
228− right: parent.right
229− bottom: parent.bottom
230− }
231− }
232− MouseArea { //prevent clicks passing through
233− anchors.fill: parent
234− }
235− }
236−
237− IndicatorRow {
238− id: indicatorRow
239− objectName: "indicatorRow"
240− anchors {
241− left: parent.left
242− right: parent.right
243− }
244− height: indicators.panelHeight
245− indicatorsModel: visibleIndicators.model
246− state: indicators.state
247− unitProgress: indicators.unitProgress
248−
249− EdgeDragArea {
250− id: rowDragArea
251− anchors.fill: indicatorRow
252− direction: Direction.Downwards
253− maxSilenceTime: 2000
254− distanceThreshold: 0
255−
256− enabled: fullyOpened
257− onDraggingChanged: {
258− if (dragging) {
259− initalizeItem = true;
260− updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
261− indicators.calculateCurrentItem(touchX, false);
262− } else {
263− indicators.state = "commit";
264− indicatorRow.currentItemOffset = 0;
265− }
266− }
267−
268− onTouchXChanged: {
269− indicators.calculateCurrentItem(touchX, true);
270− }
271− onTouchSceneYChanged: {
272− updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
273− yVelocityCalculator.trackedPosition = touchSceneY;
274− }
275− }
276− }
277−
278− Connections {
279− target: showAnimation
280− onRunningChanged: {
281− if (showAnimation.running) {
282− indicators.state = "commit";
283− indicatorRow.currentItemOffset = 0;
284− }
285− }
286− }
287−
288− Connections {
289− target: hideAnimation
290− onRunningChanged: {
291− if (hideAnimation.running) {
292− indicators.state = "initial";
293− initalizeItem = true;
294− indicatorRow.currentItemOffset = 0;
295− }
296− }
297− }
298−
299− QtObject {
300− id: d
301− property bool enableIndexChangeSignal: true
302− property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
303− }
304−
305− Connections {
306− target: menuContent
307− onCurrentMenuIndexChanged: {
308− var oldActive = d.enableIndexChangeSignal;
309− if (!oldActive) return;
310− d.enableIndexChangeSignal = false;
311−
312− indicatorRow.setCurrentItemIndex(menuContent.currentMenuIndex);
313−
314− d.enableIndexChangeSignal = oldActive;
315− }
316− }
317−
318− Connections {
319− target: indicatorRow
320− onCurrentItemIndexChanged: {
321− var oldActive = d.enableIndexChangeSignal;
322− if (!oldActive) return;
323− d.enableIndexChangeSignal = false;
324−
325− menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex, fullyOpened || partiallyOpened);
326−
327− d.enableIndexChangeSignal = oldActive;
328− }
329− }
330− // connections to the active drag handle
331− Connections {
332− target: d.activeDragHandle
333− onTouchXChanged: {
334− indicators.calculateCurrentItem(d.activeDragHandle.touchX, true);
335− }
336− onTouchSceneYChanged: {
337− yVelocityCalculator.trackedPosition = d.activeDragHandle.touchSceneY;
338− }
339− }
340−
341− DragHandle {
342− id: showDragHandle
343− anchors.bottom: parent.bottom
344− // go beyond parent so that it stays reachable, at the top of the screen.
345− anchors.bottomMargin: showHintBottomMargin
346− anchors.left: parent.left
347− anchors.right: parent.right
348− height: panelHeight
349− direction: Direction.Downwards
350− enabled: !indicators.shown && indicators.available
351− hintDisplacement: enableHint ? indicators.hintValue : 0
352− autoCompleteDragThreshold: maxTotalDragDistance / 2
353− stretch: true
354− maxTotalDragDistance: openedHeight - panelHeight
355− distanceThreshold: panelHeight
356−
357− onTapped: showTapped(Qt.point(touchSceneX, touchSceneY));
358− }
359−
360− DragHandle {
361− id: hideDragHandle
362− anchors.fill: handle
363− direction: Direction.Upwards
364− enabled: indicators.shown && indicators.available
365− hintDisplacement: indicators.hintValue
366− autoCompleteDragThreshold: maxTotalDragDistance / 6
367− stretch: true
368− maxTotalDragDistance: openedHeight - panelHeight
369− distanceThreshold: 0
370− }
371−
372− AxisVelocityCalculator {
373− id: yVelocityCalculator
374− }
375−
376− states: [
377− State {
378− name: "initial"
379− },
380− State {
381− name: "hint"
382− StateChangeScript {
383− script: {
384− if (d.activeDragHandle) {
385− calculateCurrentItem(d.activeDragHandle.touchX, false);
386− }
387− }
388− }
389− },
390− State {
391− name: "reveal"
392− extend: "hint"
393− },
394− State {
395− name: "locked"
396− extend: "hint"
397− },
398− State {
399− name: "commit"
400− extend: "hint"
401− }
402− ]
403− state: "initial"
404−
405− transitions: [
406− Transition {
407− NumberAnimation {targets: [indicatorRow, menuContent]; property: "y"; duration: 300; easing.type: Easing.OutCubic}
408− }
409− ]
410−
411− Component.onCompleted: initialise();
412− function initialise() {
413− visibleIndicators.load(profile);
414− indicatorRow.setDefaultItem();
415− }
416−}