Unity 8
 All Classes Functions
Launcher.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 "../Components"
19 import Ubuntu.Components 0.1
20 import Ubuntu.Gestures 0.1
21 import Unity.Launcher 0.1
22 
23 Item {
24  id: root
25 
26  property bool available: true // can be used to disable all interactions
27 
28  property int panelWidth: units.gu(8)
29  property int dragAreaWidth: units.gu(1)
30  property int minimizeDistance: units.gu(26)
31  property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
32  (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0
33 
34  readonly property bool shown: panel.x > -panel.width
35 
36  // emitted when an application is selected
37  signal launcherApplicationSelected(string appId)
38 
39  // emitted when the apps dash should be shown because of a swipe gesture
40  signal dash()
41 
42  // emitted when the dash icon in the launcher has been tapped
43  signal showDashHome()
44 
45  onStateChanged: {
46  if (state == "") {
47  dismissTimer.stop()
48  } else {
49  dismissTimer.restart()
50  }
51  }
52 
53  function hide() {
54  switchToNextState("")
55  }
56 
57  function fadeOut() {
58  fadeOutAnimation.start();
59  }
60 
61  function switchToNextState(state) {
62  animateTimer.nextState = state
63  animateTimer.start();
64  }
65 
66  function tease() {
67  if (available) {
68  teaseTimer.start();
69  }
70  }
71 
72  Timer {
73  id: teaseTimer
74  interval: 200
75  }
76 
77  Timer {
78  id: dismissTimer
79  interval: 5000
80  onTriggered: {
81  if (!panel.preventHiding) {
82  root.state = ""
83  } else {
84  dismissTimer.restart()
85  }
86  }
87  }
88 
89  // Because the animation on x is disabled while dragging
90  // switching state directly in the drag handlers would not animate
91  // the completion of the hide/reveal gesture. Lets update the state
92  // machine and switch to the final state in the next event loop run
93  Timer {
94  id: animateTimer
95  interval: 1
96  property string nextState: ""
97  onTriggered: {
98  // switching to an intermediate state here to make sure all the
99  // values are restored, even if we were already in the target state
100  root.state = "tmp"
101  root.state = nextState
102  }
103  }
104 
105  SequentialAnimation {
106  id: fadeOutAnimation
107  ScriptAction {
108  script: {
109  panel.layer.enabled = true
110  }
111  }
112  UbuntuNumberAnimation {
113  target: panel
114  property: "opacity"
115  easing.type: Easing.InQuad
116  to: 0
117  }
118  ScriptAction {
119  script: {
120  panel.layer.enabled = false
121  panel.animate = false;
122  root.state = "";
123  panel.x = -panel.width
124  panel.opacity = 1;
125  panel.animate = true;
126  }
127  }
128  }
129 
130  MouseArea {
131  id: launcherDragArea
132  enabled: root.state == "visible"
133  anchors.fill: panel
134  anchors.rightMargin: -units.gu(2)
135  drag {
136  axis: Drag.XAxis
137  maximumX: 0
138  target: panel
139  }
140 
141  onReleased: {
142  if (panel.x < -panel.width/3) {
143  root.switchToNextState("")
144  } else {
145  root.switchToNextState("visible")
146  }
147  }
148 
149  }
150  MouseArea {
151  id: closeMouseArea
152  anchors {
153  left: launcherDragArea.right
154  top: parent.top
155  right: parent.right
156  bottom: parent.bottom
157  }
158  enabled: root.state == "visible"
159  onPressed: {
160  root.state = ""
161  }
162  }
163 
164  Rectangle {
165  id: backgroundShade
166  anchors.fill: parent
167  color: "black"
168  opacity: root.state == "visible" ? 0.6 : 0
169 
170  Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.BriskDuration } }
171  }
172 
173  LauncherPanel {
174  id: panel
175  objectName: "launcherPanel"
176  enabled: root.available
177  width: root.panelWidth
178  anchors {
179  top: parent.top
180  bottom: parent.bottom
181  }
182  x: -width
183  visible: x > -width || dragArea.status === DirectionalDragArea.Undecided
184  model: LauncherModel
185 
186  property bool animate: true
187 
188  onApplicationSelected: {
189  root.state = ""
190  launcherApplicationSelected(appId)
191  }
192  onShowDashHome: {
193  root.state = ""
194  root.showDashHome();
195  }
196 
197  onPreventHidingChanged: {
198  if (dismissTimer.running) {
199  dismissTimer.restart();
200  }
201  }
202 
203  Behavior on x {
204  enabled: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate;
205  NumberAnimation {
206  duration: 300
207  easing.type: Easing.OutCubic
208  }
209  }
210 
211  Behavior on opacity {
212  NumberAnimation {
213  duration: UbuntuAnimation.FastDuration; easing.type: Easing.OutCubic
214  }
215  }
216  }
217 
218  EdgeDragArea {
219  id: dragArea
220 
221  direction: Direction.Rightwards
222 
223  enabled: root.available
224  width: root.dragAreaWidth
225  height: root.height
226 
227  onTouchXChanged: {
228  if (status !== DirectionalDragArea.Recognized || launcher.state == "visible")
229  return;
230 
231  // When the gesture finally gets recognized, the finger will likely be
232  // reasonably far from the edge. If we made the panel immediately
233  // follow the finger position it would be visually unpleasant as it
234  // would appear right next to the user's finger out of nowhere.
235  // Instead, we make the panel go towards the user's finger in several
236  // steps. ie., in an animated way.
237  var targetPanelX = Math.min(0, touchX - panel.width)
238  var delta = targetPanelX - panel.x
239  // the trick is not to go all the way (1.0) as it would cause a sudden jump
240  panel.x += 0.4 * delta
241  }
242 
243  onDraggingChanged: {
244  if (!dragging) {
245  if (distance > panel.width / 2) {
246  if (distance > minimizeDistance) {
247  root.dash();
248  } else {
249  root.switchToNextState("visible")
250  }
251  } else {
252  root.switchToNextState("")
253  }
254  }
255  }
256  }
257 
258  states: [
259  State {
260  name: "" // hidden state. Must be the default state ("") because "when:" falls back to this.
261  PropertyChanges {
262  target: panel
263  x: -root.panelWidth
264  }
265  },
266  State {
267  name: "visible"
268  PropertyChanges {
269  target: panel
270  x: 0
271  }
272  },
273  State {
274  name: "teasing"
275  when: teaseTimer.running
276  PropertyChanges {
277  target: panel
278  x: -root.panelWidth + units.gu(2)
279  }
280  }
281  ]
282 }