2 * Copyright (C) 2013 Canonical, Ltd.
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.
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.
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/>.
18 import Ubuntu.Components 0.1
19 import Ubuntu.Gestures 0.1
22 Put a DragHandle inside a Showable to enable the user to drag it from that handle.
23 Main use case is to drag fullscreen Showables into the screen or off the screen.
25 This example shows a DragHandle placed on the right corner of a Showable, used
26 to slide it away, off the screen.
31 width: ... // screen width
32 height: ... // screen height
36 anchors.right: parent.right
37 anchors.top: parent.top
38 anchors.bottom: parent.bottom
41 direction: DirectionalDragArea::Leftwards
48 objectName: "dragHandle"
50 // Disable gesture recognition by default when hinting is used as
51 // it conflicts with the hinting idea.
52 distanceThreshold: hintDisplacement > 0 ? 0 : defaultDistanceThreshold
53 maxSilenceTime: hintDisplacement > 0 ? 60*60*1000 : defaultMaxSilenceTime
54 maxDeviation: hintDisplacement > 0 ? 999999 : defaultMaxDeviation
55 compositionTime: hintDisplacement > 0 ? 0 : defaultCompositionTime
57 property bool stretch: false
59 property alias autoCompleteDragThreshold: dragEvaluator.dragThreshold
61 // How far you can drag
62 property real maxTotalDragDistance: {
64 0; // not enough context information to set a sensible default
66 Direction.isHorizontal(direction) ? parent.width : parent.height;
70 property real hintDisplacement: 0
71 property var overrideStartValue: undefined
74 target: hintingAnimation
75 property: "targetValue"
78 to: Direction.isPositive(direction) ? d.startValue + hintDisplacement
79 : d.startValue - hintDisplacement
80 property real targetValue
81 onTargetValueChanged: {
86 if (Direction.isPositive(direction)) {
87 if (parent[d.targetProp] < targetValue) {
88 parent[d.targetProp] = targetValue;
91 if (parent[d.targetProp] > targetValue) {
92 parent[d.targetProp] = targetValue;
101 property var previousStatus: DirectionalDragArea.WaitingForTouch
102 property real startValue
103 property real minValue: Direction.isPositive(direction) ? startValue
104 : startValue - maxTotalDragDistance
105 property real maxValue: Direction.isPositive(direction) ? startValue + maxTotalDragDistance
108 property var dragParent: dragArea.parent
110 // The property of DragHandle's parent that will be modified
111 property string targetProp: {
113 Direction.isHorizontal(direction) ? "width" : "height";
115 Direction.isHorizontal(direction) ? "x" : "y";
119 function limitMovement(inputStep) {
120 var targetValue = MathUtils.clamp(dragParent[targetProp] + inputStep, minValue, maxValue);
121 var step = targetValue - dragParent[targetProp];
123 if (hintDisplacement == 0) {
127 // we should not go behind hintingAnimation's current value
128 if (Direction.isPositive(direction)) {
129 if (dragParent[targetProp] + step < hintingAnimation.targetValue) {
130 step = hintingAnimation.targetValue - dragParent[targetProp];
133 if (dragParent[targetProp] + step > hintingAnimation.targetValue) {
134 step = hintingAnimation.targetValue - dragParent[targetProp];
141 function onFinishedRecognizedGesture() {
142 if (dragEvaluator.shouldAutoComplete()) {
149 function completeDrag() {
150 if (dragParent.shown) {
157 function rollbackDrag() {
158 if (dragParent.shown) {
166 property alias edgeDragEvaluator: dragEvaluator
169 objectName: "edgeDragEvaluator"
171 // Effectively convert distance into the drag position projected onto the gesture direction axis
172 trackedPosition: Direction.isPositive(dragArea.direction) ? sceneDistance : -sceneDistance
173 maxDragDistance: maxTotalDragDistance
174 direction: dragArea.direction
178 if (status === DirectionalDragArea.Recognized) {
179 // don't go the whole distance in order to smooth out the movement
180 var step = distance * 0.3;
182 step = d.limitMovement(step);
184 parent[d.targetProp] += step;
189 if (status === DirectionalDragArea.WaitingForTouch) {
190 hintingAnimation.stop();
191 if (d.previousStatus === DirectionalDragArea.Recognized) {
192 d.onFinishedRecognizedGesture();
193 } else /* d.previousStatus === DirectionalDragArea.Undecided */ {
194 // Gesture was rejected.
197 } else /* Undecided || Recognized */ {
198 if (d.previousStatus === DirectionalDragArea.WaitingForTouch) {
199 dragEvaluator.reset();
200 if (overrideStartValue !== undefined) {
201 d.startValue = overrideStartValue;
203 d.startValue = parent[d.targetProp];
206 if (hintDisplacement > 0) {
207 hintingAnimation.targetValue = d.startValue;
208 hintingAnimation.start();
213 d.previousStatus = status;