2 * Copyright (C) 2016 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/>.
18import Lomiri.Components 1.3
19import Lomiri.Gestures 0.1
20import "../../Components"
25 property bool closeable: true
26 readonly property real minSpeedToClose: units.gu(40)
27 property bool zeroVelocityCounts: false
29 readonly property alias distance: d.distance
31 property var stage: null
32 property var dragDelegate: null
39 property real distance: 0
40 property bool moving: false
41 property var dragEvents: []
42 property real dragVelocity: 0
43 property int threshold: units.gu(2)
45 // Can be replaced with a fake implementation during tests
46 // property var __getCurrentTimeMs: function () { return new Date().getTime() }
47 property var __dateTime: new function() {
48 this.getCurrentTimeMs = function() {return new Date().getTime()}
51 function pushDragEvent(event) {
52 var currentTime = __dateTime.getCurrentTimeMs()
53 dragEvents.push([currentTime, event.x - event.startX, event.y - event.startY, getEventSpeed(currentTime, event)])
54 cullOldDragEvents(currentTime)
58 function cullOldDragEvents(currentTime) {
59 // cull events older than 50 ms but always keep the latest 2 events
60 for (var numberOfCulledEvents = 0; numberOfCulledEvents < dragEvents.length-2; numberOfCulledEvents++) {
61 // dragEvents[numberOfCulledEvents][0] is the dragTime
62 if (currentTime - dragEvents[numberOfCulledEvents][0] <= 50) break
65 dragEvents.splice(0, numberOfCulledEvents)
68 function updateSpeed() {
70 for (var i = 0; i < dragEvents.length; i++) {
71 totalSpeed += dragEvents[i][3]
74 if (zeroVelocityCounts || Math.abs(totalSpeed) > 0.001) {
75 dragVelocity = totalSpeed / dragEvents.length * 1000
79 function getEventSpeed(currentTime, event) {
80 if (dragEvents.length != 0) {
81 var lastDrag = dragEvents[dragEvents.length-1]
82 var duration = Math.max(1, currentTime - lastDrag[0])
83 return (event.y - event.startY - lastDrag[2]) / duration
93 property int offset: 0
95 // tp.startY seems to be broken for mouse interaction... lets track it ourselves
96 property int startY: 0
110 dragDelegate.Drag.active = false;
111 dragDelegate.surface = null;
113 animation.animate("center");
115 } else if (!d.moving) {
116 if (Math.abs(startY - tp.y) > d.threshold) {
119 offset = tp.y - tp.startY;
125 var value = tp.y - tp.startY - offset;
126 if (value < 0 && stage.workspaceEnabled) {
127 var coords = mapToItem(stage, tp.x, tp.y);
128 dragDelegate.Drag.hotSpot.x = dragDelegate.width / 2
129 dragDelegate.Drag.hotSpot.y = units.gu(2)
130 dragDelegate.x = coords.x - dragDelegate.Drag.hotSpot.x
131 dragDelegate.y = coords.y - dragDelegate.Drag.hotSpot.y
132 dragDelegate.Drag.active = true;
133 dragDelegate.surface = model.window.surface;
135 if (root.closeable) {
139 d.distance = Math.sqrt(Math.abs(value)) * (value < 0 ? -1 : 1) * 3
147 var result = dragDelegate.Drag.drop();
148 dragDelegate.surface = null;
154 if (!root.closeable) {
155 animation.animate("center")
159 if ((d.dragVelocity < -root.minSpeedToClose && d.distance < -units.gu(8)) || d.distance < -root.height / 2) {
160 animation.animate("up")
161 } else if ((d.dragVelocity > root.minSpeedToClose && d.distance > units.gu(8)) || d.distance > root.height / 2) {
162 animation.animate("down")
164 animation.animate("center")
169 dragDelegate.Drag.active = false;
170 dragDelegate.surface = null;
172 animation.animate("center");
176 LomiriNumberAnimation {
178 objectName: "closeAnimation"
181 property bool requestClose: false
183 function animate(direction) {
184 animation.from = d.distance;
187 animation.to = -root.height * 1.5;
191 animation.to = root.height * 1.5;