on bbbdccd help sign in
unity8/qml/Launcher/Launcher.qml
345 lines 10.0 kB history raw
1/*
2 * Copyright (C) 2013-2015 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.4
18import "../Components"
19import Ubuntu.Components 1.3
20import Ubuntu.Gestures 0.1
21import Unity.Launcher 0.1
23Item {
24 id: root
26 property bool autohideEnabled: false
27 property bool available: true // can be used to disable all interactions
28 property alias inverted: panel.inverted
29 property bool shadeBackground: true // can be used to disable background shade when launcher is visible
31 property int panelWidth: units.gu(8)
32 property int dragAreaWidth: units.gu(1)
33 property int minimizeDistance: units.gu(26)
34 property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
35 (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0
37 readonly property bool dragging: dragArea.dragging
38 readonly property real dragDistance: dragArea.dragging ? dragArea.touchX : 0
39 readonly property real visibleWidth: panel.width + panel.x
41 readonly property bool shown: panel.x > -panel.width
43 // emitted when an application is selected
44 signal launcherApplicationSelected(string appId)
46 // emitted when the apps dash should be shown because of a swipe gesture
47 signal dash()
49 // emitted when the dash icon in the launcher has been tapped
50 signal showDashHome()
52 onStateChanged: {
53 if (state == "") {
54 panel.dismissTimer.stop()
55 } else {
56 panel.dismissTimer.restart()
57 }
58 }
60 function hide() {
61 switchToNextState("")
62 }
64 function fadeOut() {
65 fadeOutAnimation.start();
66 }
68 function switchToNextState(state) {
69 animateTimer.nextState = state
70 animateTimer.start();
71 }
73 function tease() {
74 if (available && !dragArea.dragging) {
75 teaseTimer.mode = "teasing"
76 teaseTimer.start();
77 }
78 }
80 function hint() {
81 if (available && root.state == "") {
82 teaseTimer.mode = "hinting"
83 teaseTimer.start();
84 }
85 }
87 function pushEdge(amount) {
88 if (root.state === "") {
89 edgeBarrier.push(amount);
90 }
91 }
93 Timer {
94 id: teaseTimer
95 interval: mode == "teasing" ? 200 : 300
96 property string mode: "teasing"
97 }
99 // Because the animation on x is disabled while dragging
100 // switching state directly in the drag handlers would not animate
101 // the completion of the hide/reveal gesture. Lets update the state
102 // machine and switch to the final state in the next event loop run
103 Timer {
104 id: animateTimer
105 objectName: "animateTimer"
106 interval: 1
107 property string nextState: ""
108 onTriggered: {
109 // switching to an intermediate state here to make sure all the
110 // values are restored, even if we were already in the target state
111 root.state = "tmp"
112 root.state = nextState
113 }
114 }
116 Connections {
117 target: LauncherModel
118 onHint: hint();
119 }
121 Connections {
122 target: i18n
123 onLanguageChanged: LauncherModel.refresh()
124 }
126 SequentialAnimation {
127 id: fadeOutAnimation
128 ScriptAction {
129 script: {
130 animateTimer.stop(); // Don't change the state behind our back
131 panel.layer.enabled = true
132 }
133 }
134 UbuntuNumberAnimation {
135 target: panel
136 property: "opacity"
137 easing.type: Easing.InQuad
138 to: 0
139 }
140 ScriptAction {
141 script: {
142 panel.layer.enabled = false
143 panel.animate = false;
144 root.state = "";
145 panel.x = -panel.width
146 panel.opacity = 1;
147 panel.animate = true;
148 }
149 }
150 }
152 MouseArea {
153 id: launcherDragArea
154 enabled: root.available && (root.state == "visible" || root.state == "visibleTemporary")
155 anchors.fill: panel
156 anchors.rightMargin: -units.gu(2)
157 drag {
158 axis: Drag.XAxis
159 maximumX: 0
160 target: panel
161 }
163 onReleased: {
164 if (panel.x < -panel.width/3) {
165 root.switchToNextState("")
166 } else {
167 root.switchToNextState("visible")
168 }
169 }
170 }
172 InverseMouseArea {
173 id: closeMouseArea
174 anchors.fill: panel
175 enabled: root.shadeBackground && root.state == "visible"
176 visible: enabled
177 onPressed: {
178 root.hide();
179 }
180 }
182 Rectangle {
183 id: backgroundShade
184 anchors.fill: parent
185 color: "black"
186 opacity: root.shadeBackground && root.state == "visible" ? 0.6 : 0
188 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.BriskDuration } }
189 }
191 EdgeBarrier {
192 id: edgeBarrier
193 edge: Qt.LeftEdge
194 target: parent
195 enabled: root.available
196 onPassed: { root.switchToNextState("visibleTemporary"); }
197 material: Component {
198 Item {
199 Rectangle {
200 width: parent.height
201 height: parent.width
202 rotation: -90
203 anchors.centerIn: parent
204 gradient: Gradient {
205 GradientStop { position: 0.0; color: panel.color}
206 GradientStop { position: 1.0; color: Qt.rgba(panel.r,panel.g,panel.b,0)}
207 }
208 }
209 }
210 }
211 }
213 LauncherPanel {
214 id: panel
215 objectName: "launcherPanel"
216 enabled: root.available && root.state == "visible" || root.state == "visibleTemporary"
217 width: root.panelWidth
218 anchors {
219 top: parent.top
220 bottom: parent.bottom
221 }
222 x: -width
223 visible: root.x > 0 || x > -width || dragArea.pressed
224 model: LauncherModel
226 property var dismissTimer: Timer { interval: 500 }
227 Connections {
228 target: panel.dismissTimer
229 onTriggered: {
230 if (root.autohideEnabled) {
231 if (!panel.preventHiding) {
232 root.state = ""
233 } else {
234 panel.dismissTimer.restart()
235 }
236 }
237 }
238 }
240 property bool animate: true
242 onApplicationSelected: {
243 root.state = ""
244 launcherApplicationSelected(appId)
245 }
246 onShowDashHome: {
247 root.state = ""
248 root.showDashHome();
249 }
251 onPreventHidingChanged: {
252 if (panel.dismissTimer.running) {
253 panel.dismissTimer.restart();
254 }
255 }
257 Behavior on x {
258 enabled: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate;
259 NumberAnimation {
260 duration: 300
261 easing.type: Easing.OutCubic
262 }
263 }
265 Behavior on opacity {
266 NumberAnimation {
267 duration: UbuntuAnimation.FastDuration; easing.type: Easing.OutCubic
268 }
269 }
270 }
272 DirectionalDragArea {
273 id: dragArea
274 objectName: "launcherDragArea"
276 direction: Direction.Rightwards
278 enabled: root.available
279 x: -root.x // so if launcher is adjusted relative to screen, we stay put (like tutorial does when teasing)
280 width: root.dragAreaWidth
281 height: root.height
283 onDistanceChanged: {
284 if (!dragging || launcher.state == "visible")
285 return;
287 panel.x = -panel.width + Math.min(Math.max(0, distance), panel.width);
288 }
290 onDraggingChanged: {
291 if (!dragging) {
292 if (distance > panel.width / 2) {
293 root.switchToNextState("visible")
294 if (distance > minimizeDistance) {
295 root.dash();
296 }
297 } else if (root.state === "") {
298 // didn't drag far enough. rollback
299 root.switchToNextState("")
300 }
301 }
302 }
303 }
305 states: [
306 State {
307 name: "" // hidden state. Must be the default state ("") because "when:" falls back to this.
308 PropertyChanges {
309 target: panel
310 x: -root.panelWidth
311 }
312 },
313 State {
314 name: "visible"
315 PropertyChanges {
316 target: panel
317 x: -root.x // so we never go past panelWidth, even when teased by tutorial
318 }
319 },
320 State {
321 name: "visibleTemporary"
322 extend: "visible"
323 PropertyChanges {
324 target: root
325 autohideEnabled: true
326 }
327 },
328 State {
329 name: "teasing"
330 when: teaseTimer.running && teaseTimer.mode == "teasing"
331 PropertyChanges {
332 target: panel
333 x: -root.panelWidth + units.gu(2)
334 }
335 },
336 State {
337 name: "hinting"
338 when: teaseTimer.running && teaseTimer.mode == "hinting"
339 PropertyChanges {
340 target: panel
341 x: 0
342 }
343 }
344 ]