2 * Copyright (C) 2013-2015 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/>.
18 import "../Components"
19 import Ubuntu.Components 1.3
20 import Ubuntu.Gestures 0.1
21 import Unity.Launcher 0.1
26 property bool autohideEnabled: false
27 property bool lockedVisible: false
28 property bool available: true // can be used to disable all interactions
29 property alias inverted: panel.inverted
31 property int panelWidth: units.gu(10)
32 property int dragAreaWidth: units.gu(1)
33 property int minimizeDistance: units.gu(26)
34 property real progress: dragArea.dragging && dragArea.touchPosition.x > panelWidth ?
35 (width * (dragArea.touchPosition.x-panelWidth) / (width - panelWidth)) : 0
37 property bool superPressed: false
38 property bool superTabPressed: false
40 readonly property bool dragging: dragArea.dragging
41 readonly property real dragDistance: dragArea.dragging ? dragArea.touchPosition.x : 0
42 readonly property real visibleWidth: panel.width + panel.x
44 readonly property bool shown: panel.x > -panel.width
46 // emitted when an application is selected
47 signal launcherApplicationSelected(string appId)
49 // emitted when the apps dash should be shown because of a swipe gesture
52 // emitted when the dash icon in the launcher has been tapped
57 panel.dismissTimer.stop()
59 panel.dismissTimer.restart()
63 onSuperPressedChanged: {
65 superPressTimer.start();
66 superLongPressTimer.start();
68 superPressTimer.stop();
69 superLongPressTimer.stop();
70 launcher.switchToNextState("");
71 panel.shortcutHintsShown = false;
75 onSuperTabPressedChanged: {
76 if (superTabPressed) {
77 switchToNextState("visible")
78 panel.highlightIndex = -1;
80 superPressTimer.stop();
81 superLongPressTimer.stop();
83 if (panel.highlightIndex == -1) {
85 } else if (panel.highlightIndex >= 0){
86 launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
88 panel.highlightIndex = -2;
89 switchToNextState("");
94 onLockedVisibleChanged: {
95 if (lockedVisible && state == "") {
96 panel.dismissTimer.stop();
97 fadeOutAnimation.stop();
98 switchToNextState("visible")
99 } else if (!lockedVisible && state == "visible") {
105 switchToNextState("")
109 if (!root.lockedVisible) {
110 fadeOutAnimation.start();
114 function switchToNextState(state) {
115 animateTimer.nextState = state
116 animateTimer.start();
120 if (available && !dragArea.dragging) {
121 teaseTimer.mode = "teasing"
127 if (available && root.state == "") {
128 teaseTimer.mode = "hinting"
133 function pushEdge(amount) {
134 if (root.state === "") {
135 edgeBarrier.push(amount);
139 function openForKeyboardNavigation() {
140 panel.highlightIndex = -1; // The BFB
142 switchToNextState("visible")
148 panel.highlightPrevious();
149 event.accepted = true;
153 panel.highlightNext()
155 panel.highlightPrevious();
157 event.accepted = true;
160 panel.highlightNext();
161 event.accepted = true;
165 panel.highlightPrevious();
167 panel.highlightNext();
169 event.accepted = true;
172 panel.openQuicklist(panel.highlightIndex)
173 event.accepted = true;
176 panel.highlightIndex = -2;
177 // Falling through intentionally
181 if (panel.highlightIndex == -1) {
183 } else if (panel.highlightIndex >= 0) {
184 launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
187 panel.highlightIndex = -2
188 event.accepted = true;
197 switchToNextState("visible")
202 id: superLongPressTimer
205 switchToNextState("visible")
206 panel.shortcutHintsShown = true;
212 interval: mode == "teasing" ? 200 : 300
213 property string mode: "teasing"
216 // Because the animation on x is disabled while dragging
217 // switching state directly in the drag handlers would not animate
218 // the completion of the hide/reveal gesture. Lets update the state
219 // machine and switch to the final state in the next event loop run
222 objectName: "animateTimer"
224 property string nextState: ""
226 if (root.lockedVisible && nextState == "") {
227 // Due to binding updates when switching between modes
228 // it could happen that our request to show will be overwritten
229 // with a hide request. Rewrite it when we know hiding is not allowed.
230 nextState = "visible"
233 // switching to an intermediate state here to make sure all the
234 // values are restored, even if we were already in the target state
236 root.state = nextState
241 target: LauncherModel
247 onLanguageChanged: LauncherModel.refresh()
250 SequentialAnimation {
254 animateTimer.stop(); // Don't change the state behind our back
255 panel.layer.enabled = true
258 UbuntuNumberAnimation {
261 easing.type: Easing.InQuad
266 panel.layer.enabled = false
267 panel.animate = false;
269 panel.x = -panel.width
271 panel.animate = true;
279 enabled: root.state == "visible" && (!root.lockedVisible || panel.highlightIndex >= -1)
282 mouse.accepted = false;
283 panel.highlightIndex = -2;
290 enabled: root.available && (root.state == "visible" || root.state == "visibleTemporary") && !root.lockedVisible
292 anchors.rightMargin: -units.gu(2)
300 if (panel.x < -panel.width/3) {
301 root.switchToNextState("")
303 root.switchToNextState("visible")
312 enabled: root.available
313 onPassed: { root.switchToNextState("visibleTemporary"); }
314 material: Component {
320 anchors.centerIn: parent
322 GradientStop { position: 0.0; color: Qt.rgba(panel.color.r, panel.color.g, panel.color.b, .5)}
323 GradientStop { position: 1.0; color: Qt.rgba(panel.color.r,panel.color.g,panel.color.b,0)}
332 objectName: "launcherPanel"
333 enabled: root.available && root.state == "visible" || root.state == "visibleTemporary"
334 width: root.panelWidth
337 bottom: parent.bottom
340 visible: root.x > 0 || x > -width || dragArea.pressed
343 property var dismissTimer: Timer { interval: 500 }
345 target: panel.dismissTimer
347 if (root.autohideEnabled && !root.lockedVisible) {
348 if (!panel.preventHiding) {
351 panel.dismissTimer.restart()
357 property bool animate: true
359 onApplicationSelected: {
361 launcherApplicationSelected(appId)
368 onPreventHidingChanged: {
369 if (panel.dismissTimer.running) {
370 panel.dismissTimer.restart();
374 onKbdNavigationCancelled: {
375 panel.highlightIndex = -2;
381 enabled: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate;
384 easing.type: Easing.OutCubic
388 Behavior on opacity {
390 duration: UbuntuAnimation.FastDuration; easing.type: Easing.OutCubic
397 objectName: "launcherDragArea"
399 direction: Direction.Rightwards
401 enabled: root.available
402 x: -root.x // so if launcher is adjusted relative to screen, we stay put (like tutorial does when teasing)
403 width: root.dragAreaWidth
407 if (!dragging || launcher.state == "visible")
410 panel.x = -panel.width + Math.min(Math.max(0, distance), panel.width);
415 if (distance > panel.width / 2) {
416 root.switchToNextState("visible")
417 if (distance > minimizeDistance) {
420 } else if (root.state === "") {
421 // didn't drag far enough. rollback
422 root.switchToNextState("")
430 name: "" // hidden state. Must be the default state ("") because "when:" falls back to this.
440 x: -root.x // so we never go past panelWidth, even when teased by tutorial
444 name: "visibleTemporary"
448 autohideEnabled: true
453 when: teaseTimer.running && teaseTimer.mode == "teasing"
456 x: -root.panelWidth + units.gu(2)
461 when: teaseTimer.running && teaseTimer.mode == "hinting"