Unity 8
 All Classes Functions Properties
Revealer.qml
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 
20 Item {
21  id: revealer
22 
23  property Showable target
24  property var hintingAnimation: hintingAnimation
25  property string boundProperty: orientation == Qt.Vertical ? "y" : "x"
26  property int orientation: Qt.Vertical
27  property int direction: Qt.LeftToRight
28  property real openedValue: orientation == Qt.Vertical ? y : x
29  property real closedValue: orientation == Qt.Vertical ? y + (direction == Qt.LeftToRight ? -height : height) : x + (direction == Qt.LeftToRight ? -width : width)
30  property real hintDisplacement: 0
31  property real handleSize: units.gu(2)
32  property real dragVelocity: draggingArea.dragVelocity != 0 ? Math.abs(draggingArea.dragVelocity) : -1
33  property real dragVelocityThreshold: units.gu(5)
34  property bool dragging: false
35  property bool pressed: draggingArea.pressed
36  property int lateralPosition: draggingArea.lateralPosition
37  property real dragPosition
38  property bool openOnPress: true
39 
40  signal openPressed(int mouseX, int mouseY)
41  signal openReleased(int mouseX, int mouseY)
42  signal closePressed
43  signal openClicked
44  signal closeClicked
45 
46  dragPosition: {
47  var value
48  if (orientation == Qt.Vertical) {
49  value = draggingArea.dragValue + draggingArea.y
50  if (direction == Qt.RightToLeft) {
51  value += draggingArea.height - height
52  }
53  } else {
54  value = draggingArea.dragValue + draggingArea.x
55  if (direction == Qt.RightToLeft) {
56  value += draggingArea.width - width
57  }
58  }
59  if (__opened) {
60  if (direction == Qt.LeftToRight) {
61  value += handleSize
62  } else {
63  value -= handleSize
64  }
65  } else if (dragging) {
66  if (direction == Qt.LeftToRight) {
67  value += hintDisplacement
68  } else {
69  value -= hintDisplacement
70  }
71  }
72 
73  return value
74  }
75  property var draggingArea: leftDraggingArea.enabled ? leftDraggingArea : rightDraggingArea
76 
77  property real __hintValue: closedValue + (direction == Qt.LeftToRight ? hintDisplacement : -hintDisplacement)
78 
79  function dragToValue(dragPosition) {
80  return dragPosition + closedValue
81  }
82 
83  property bool __opened: target.shown
84  enabled: target.available
85 
86  // Can be replaced with a fake implementation during tests
87  // property var __getCurrentTimeMs: function () { return new Date().getTime() }
88  property var __dateTime: new function() {
89  this.getCurrentTimeMs = function() {return new Date().getTime()}
90  }
91 
92  Component.onCompleted: target[boundProperty] = __opened ? openedValue : closedValue
93  onOpenedValueChanged: if (__opened && !dragging) target[boundProperty] = openedValue
94  onClosedValueChanged: if (!__opened && !dragging) target[boundProperty] = closedValue
95 
96  function __computeValue(dragPosition) {
97  return MathUtils.clamp(dragToValue(dragPosition), __hintValue, openedValue)
98  }
99 
100  function __open() {
101  hintingAnimation.stop()
102  target.show()
103  }
104 
105  function __close() {
106  hintingAnimation.stop()
107  target.hide()
108  }
109 
110  function __hint() {
111  target.showAnimation.stop()
112  target.hideAnimation.stop()
113  hintingAnimation.restart()
114  }
115 
116  function __settle() {
117  hintingAnimation.stop()
118  if (__opened) target.show()
119  else target.hide()
120  }
121 
122  function __startDragging() {
123  hintingAnimation.stop()
124  dragging = true
125  }
126 
127  function __endDragging(dragVelocity) {
128  dragging = false
129  if (revealer.direction == Qt.RightToLeft) {
130  dragVelocity = -dragVelocity
131  }
132  if (Math.abs(dragVelocity) >= dragVelocityThreshold) {
133  if (dragVelocity > 0) __open()
134  else __close()
135  } else {
136  __settle()
137  }
138  }
139 
140  Binding {
141  id: dragBinding
142 
143  target: revealer.target
144  property: revealer.boundProperty
145  value: __computeValue(dragPosition)
146  when: dragging
147  }
148 
149  SmoothedAnimation {
150  id: hintingAnimation
151 
152  target: revealer.target
153  property: revealer.boundProperty
154  duration: 150
155  to: revealer.__hintValue
156  }
157 
158  DraggingArea {
159  id: leftDraggingArea
160 
161  property bool isOpeningArea: revealer.direction == Qt.LeftToRight
162 
163  height: orientation == Qt.Vertical ? handleSize : parent.height
164  width: orientation == Qt.Horizontal ? handleSize : parent.width
165  orientation: revealer.orientation
166  enabled: isOpeningArea ? !revealer.__opened : revealer.__opened
167 
168  __dateTime: revealer.__dateTime
169 
170  onPressed: {
171  if (isOpeningArea) {
172  if (revealer.openOnPress) {
173  revealer.openPressed(mouseX, mouseY)
174  __hint()
175  }
176  } else {
177  revealer.closePressed()
178  }
179  }
180  onReleased: {
181  if (isOpeningArea && revealer.openOnPress) {
182  revealer.openReleased(mouseX, mouseY)
183  __settle()
184  }
185  }
186  onDragStart: __startDragging()
187  onDragEnd: __endDragging(dragVelocity)
188  onClicked: {
189  if (clickValidated) {
190  if (isOpeningArea) {
191  if (revealer.openOnPress) revealer.openClicked()
192  } else {
193  revealer.closeClicked()
194  }
195  }
196  }
197  }
198 
199  DraggingArea {
200  id: rightDraggingArea
201 
202  property bool isOpeningArea: revealer.direction == Qt.RightToLeft
203 
204  x: orientation == Qt.Vertical ? 0 : parent.width - width
205  y: orientation == Qt.Vertical ? parent.height - height : 0
206  height: orientation == Qt.Vertical ? handleSize : parent.height
207  width: orientation == Qt.Horizontal ? handleSize : parent.width
208  orientation: revealer.orientation
209  enabled: isOpeningArea ? !revealer.__opened : revealer.__opened
210 
211  __dateTime: revealer.__dateTime
212 
213  onPressed: {
214  if (isOpeningArea) {
215  if (revealer.openOnPress) {
216  revealer.openPressed(mouseX, mouseY)
217  __hint()
218  }
219  } else {
220  revealer.closePressed()
221  }
222  }
223  onReleased: {
224  if (isOpeningArea && revealer.openOnPress) {
225  revealer.openReleased(mouseX, mouseY)
226  __settle()
227  }
228  }
229  onDragStart: __startDragging()
230  onDragEnd: __endDragging(dragVelocity)
231  onClicked: {
232  if (clickValidated) {
233  if (isOpeningArea) {
234  if (revealer.openOnPress) revealer.openClicked()
235  } else {
236  revealer.closeClicked()
237  }
238  }
239  }
240  }
241 }