on 68669d9 help sign in
unity8/Components/DragHandle.qml
208 lines 6.3 kB history raw
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 */
17import QtQuick 2.0
18import Ubuntu.Components 0.1
19import Ubuntu.Gestures 0.1
20import "Math.js" as MathLocal
22/*
23 Put a DragHandle inside a Showable to enable the user to drag it from that handle.
24 Main use case is to drag fullscreen Showables into the screen or off the screen.
26 This example shows a DragHandle placed on the right corner of a Showable, used
27 to slide it away, off the screen.
29 Showable {
30 x: 0
31 y: 0
32 width: ... // screen width
33 height: ... // screen height
34 shown: true
35 ...
36 DragHandle {
37 anchors.right: parent.right
38 anchors.top: parent.top
39 anchors.bottom: parent.bottom
40 width: units.gu(2)
42 direction: DirectionalDragArea::Leftwards
43 }
44 }
46 */
47EdgeDragArea {
48 id: dragArea
49 objectName: "dragHandle"
51 property bool stretch: false
53 property alias autoCompleteDragThreshold: dragEvaluator.dragThreshold
55 // How far you can drag
56 property real maxTotalDragDistance: {
57 if (stretch) {
58 0; // not enough context information to set a sensible default
59 } else {
60 Direction.isHorizontal(direction) ? parent.width : parent.height;
61 }
62 }
64 property real hintDisplacement: 0
65 SmoothedAnimation {
66 id: hintingAnimation
67 target: hintingAnimation
68 property: "targetValue"
69 duration: 150
70 velocity: -1
71 to: Direction.isPositive(direction) ? d.startValue + hintDisplacement
72 : d.startValue - hintDisplacement
73 property real targetValue
74 onTargetValueChanged: {
75 if (!running) {
76 return;
77 }
79 if (Direction.isPositive(direction)) {
80 if (parent[d.targetProp] < targetValue) {
81 parent[d.targetProp] = targetValue;
82 }
83 } else {
84 if (parent[d.targetProp] > targetValue) {
85 parent[d.targetProp] = targetValue;
86 }
87 }
88 }
89 }
91 // Private stuff
92 QtObject {
93 id: d
94 property var previousStatus: undefined
95 property real startValue
96 property real minValue: Direction.isPositive(direction) ? startValue
97 : startValue - maxTotalDragDistance
98 property real maxValue: Direction.isPositive(direction) ? startValue + maxTotalDragDistance
99 : startValue
101 property var dragParent: dragArea.parent
103 // The property of DragHandle's parent that will be modified
104 property string targetProp: {
105 if (stretch) {
106 Direction.isHorizontal(direction) ? "width" : "height";
107 } else {
108 Direction.isHorizontal(direction) ? "x" : "y";
109 }
110 }
112 function limitMovement(step) {
113 var targetValue = MathLocal.clamp(dragParent[targetProp] + step, minValue, maxValue);
114 var step = targetValue - dragParent[targetProp];
116 if (hintDisplacement == 0) {
117 return step;
118 }
120 // we should not go behind hintingAnimation's current value
121 if (Direction.isPositive(direction)) {
122 if (dragParent[targetProp] + step < hintingAnimation.targetValue) {
123 step = hintingAnimation.targetValue - dragParent[targetProp];
124 }
125 } else {
126 if (dragParent[targetProp] + step > hintingAnimation.targetValue) {
127 step = hintingAnimation.targetValue - dragParent[targetProp];
128 }
129 }
131 return step;
132 }
134 function onFinishedRecognizedGesture() {
135 if (dragEvaluator.shouldAutoComplete()) {
136 completeDrag();
137 } else {
138 rollbackDrag();
139 }
140 }
142 function completeDrag() {
143 if (dragParent.shown) {
144 dragParent.hide();
145 } else {
146 dragParent.show();
147 }
148 }
150 function rollbackDrag() {
151 if (dragParent.shown) {
152 dragParent.show();
153 } else {
154 dragParent.hide();
155 }
156 }
157 }
159 property alias edgeDragEvaluator: dragEvaluator
161 EdgeDragEvaluator {
162 objectName: "edgeDragEvaluator"
163 id: dragEvaluator
164 trackedPosition: sceneDistance
165 maxDragDistance: maxTotalDragDistance
166 direction: dragArea.direction
167 }
169 onDistanceChanged: {
170 if (status === DirectionalDragArea.Recognized) {
171 // don't go the whole distance in order to smooth out the movement
172 var step = distance * 0.3;
174 step = d.limitMovement(step);
176 parent[d.targetProp] += step;
177 }
178 }
180 onDraggingChanged: {
181 if (dragging) {
182 if (hintDisplacement > 0) {
183 hintingAnimation.targetValue = d.startValue;
184 hintingAnimation.start();
185 }
186 } else {
187 hintingAnimation.stop();
188 }
189 }
191 onStatusChanged: {
192 if (status === DirectionalDragArea.WaitingForTouch) {
193 if (d.previousStatus === DirectionalDragArea.Recognized) {
194 d.onFinishedRecognizedGesture();
195 }
196 d.startValue = parent[d.targetProp];
197 }
199 if (d.previousStatus === DirectionalDragArea.WaitingForTouch ||
200 d.previousStatus === undefined) {
201 dragEvaluator.reset();
202 d.startValue = parent[d.targetProp];
203 }
205 d.previousStatus = status;
206 }