on e63da72 help sign in
unity8/qml/Components/DragHandle.qml
208 lines 6.4 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 1.3
19import Ubuntu.Gestures 0.1
21/*
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.
28 Showable {
29 x: 0
30 y: 0
31 width: ... // screen width
32 height: ... // screen height
33 shown: true
34 ...
35 DragHandle {
36 anchors.right: parent.right
37 anchors.top: parent.top
38 anchors.bottom: parent.bottom
39 width: units.gu(2)
41 direction: DirectionalDragArea::Leftwards
42 }
43 }
45 */
46DirectionalDragArea {
47 id: dragArea
49 property bool stretch: false
51 property alias autoCompleteDragThreshold: dragEvaluator.dragThreshold
53 // How far you can drag
54 property real maxTotalDragDistance: {
55 if (stretch) {
56 0; // not enough context information to set a sensible default
57 } else {
58 Direction.isHorizontal(direction) ? parent.width : parent.height;
59 }
60 }
62 property real hintDisplacement: 0
64 immediateRecognition: hintDisplacement > 0
66 property var overrideStartValue: undefined
67 SmoothedAnimation {
68 id: hintingAnimation
69 target: hintingAnimation
70 property: "targetValue"
71 duration: 150
72 velocity: -1
73 to: Direction.isPositive(direction) ? d.startValue + hintDisplacement
74 : d.startValue - hintDisplacement
75 property real targetValue
76 onTargetValueChanged: {
77 if (!running) {
78 return;
79 }
81 if (Direction.isPositive(direction)) {
82 if (parent[d.targetProp] < targetValue) {
83 parent[d.targetProp] = targetValue;
84 }
85 } else {
86 if (parent[d.targetProp] > targetValue) {
87 parent[d.targetProp] = targetValue;
88 }
89 }
90 }
91 }
93 // Private stuff
94 QtObject {
95 id: d
96 property real startValue
97 property real minValue: {
98 if (direction == Direction.Horizontal) {
99 return startValue - maxTotalDragDistance;
100 } else if (Direction.isPositive(direction)) {
101 return startValue;
102 } else {
103 return startValue - maxTotalDragDistance;
104 }
105 }
107 property real maxValue: Direction.isPositive(direction) ? startValue + maxTotalDragDistance
108 : startValue
110 property var dragParent: dragArea.parent
112 // The property of DragHandle's parent that will be modified
113 property string targetProp: {
114 if (stretch) {
115 Direction.isHorizontal(direction) ? "width" : "height";
116 } else {
117 Direction.isHorizontal(direction) ? "x" : "y";
118 }
119 }
121 function limitMovement(inputStep) {
122 var targetValue = MathUtils.clamp(dragParent[targetProp] + inputStep, minValue, maxValue);
123 var step = targetValue - dragParent[targetProp];
125 if (hintDisplacement == 0) {
126 return step;
127 }
129 // we should not go behind hintingAnimation's current value
130 if (Direction.isPositive(direction)) {
131 if (dragParent[targetProp] + step < hintingAnimation.targetValue) {
132 step = hintingAnimation.targetValue - dragParent[targetProp];
133 }
134 } else {
135 if (dragParent[targetProp] + step > hintingAnimation.targetValue) {
136 step = hintingAnimation.targetValue - dragParent[targetProp];
137 }
138 }
140 return step;
141 }
143 function onFinishedRecognizedGesture() {
144 if (dragEvaluator.shouldAutoComplete()) {
145 completeDrag();
146 } else {
147 rollbackDrag();
148 }
149 }
151 function completeDrag() {
152 if (dragParent.shown) {
153 dragParent.hide();
154 } else {
155 dragParent.show();
156 }
157 }
159 function rollbackDrag() {
160 if (dragParent.shown) {
161 dragParent.show();
162 } else {
163 dragParent.hide();
164 }
165 }
166 }
168 property alias edgeDragEvaluator: dragEvaluator
170 EdgeDragEvaluator {
171 objectName: "edgeDragEvaluator"
172 id: dragEvaluator
173 // Effectively convert distance into the drag position projected onto the gesture direction axis
174 trackedPosition: Direction.isPositive(dragArea.direction) ? sceneDistance : -sceneDistance
175 maxDragDistance: maxTotalDragDistance
176 direction: dragArea.direction
177 }
179 onDistanceChanged: {
180 if (dragging) {
181 // don't go the whole distance in order to smooth out the movement
182 var step = distance * 0.3;
184 step = d.limitMovement(step);
186 parent[d.targetProp] += step;
187 }
188 }
190 onDraggingChanged: {
191 if (dragging) {
192 dragEvaluator.reset();
193 if (overrideStartValue !== undefined) {
194 d.startValue = overrideStartValue;
195 } else {
196 d.startValue = parent[d.targetProp];
197 }
199 if (hintDisplacement > 0) {
200 hintingAnimation.targetValue = d.startValue;
201 hintingAnimation.start();
202 }
203 } else {
204 hintingAnimation.stop();
205 d.onFinishedRecognizedGesture();
206 }
207 }