2 * Copyright (C) 2013-2014 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 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
49 // emitted when the dash icon in the launcher has been tapped
56 dismissTimer.restart()
65 fadeOutAnimation.start();
68 function switchToNextState(state) {
69 animateTimer.nextState = state
74 if (available && !dragArea.dragging) {
75 teaseTimer.mode = "teasing"
81 if (available && root.state == "") {
82 teaseTimer.mode = "hinting"
89 interval: mode == "teasing" ? 200 : 300
90 property string mode: "teasing"
95 objectName: "dismissTimer"
98 if (root.autohideEnabled) {
99 if (!panel.preventHiding && !hoverArea.containsMouse) {
102 dismissTimer.restart()
108 // Because the animation on x is disabled while dragging
109 // switching state directly in the drag handlers would not animate
110 // the completion of the hide/reveal gesture. Lets update the state
111 // machine and switch to the final state in the next event loop run
114 objectName: "animateTimer"
116 property string nextState: ""
118 // switching to an intermediate state here to make sure all the
119 // values are restored, even if we were already in the target state
121 root.state = nextState
126 target: LauncherModel
132 onLanguageChanged: LauncherModel.refresh()
135 SequentialAnimation {
139 animateTimer.stop(); // Don't change the state behind our back
140 panel.layer.enabled = true
143 UbuntuNumberAnimation {
146 easing.type: Easing.InQuad
151 panel.layer.enabled = false
152 panel.animate = false;
154 panel.x = -panel.width
156 panel.animate = true;
163 enabled: root.available && (root.state == "visible" || root.state == "visibleTemporary")
165 anchors.rightMargin: -units.gu(2)
173 if (panel.x < -panel.width/3) {
174 root.switchToNextState("")
176 root.switchToNextState("visible")
182 MultiPointTouchArea {
185 left: launcherDragArea.right
188 bottom: parent.bottom
190 enabled: root.shadeBackground && root.state == "visible"
191 visible: enabled // otherwise it will get in the way of cursor selection for some reason
201 opacity: root.shadeBackground && root.state == "visible" ? 0.6 : 0
203 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.BriskDuration } }
208 objectName: "launcherPanel"
209 enabled: root.available && root.state == "visible" || root.state == "visibleTemporary"
210 width: root.panelWidth
213 bottom: parent.bottom
216 visible: root.x > 0 || x > -width || dragArea.pressed
219 property bool animate: true
221 onApplicationSelected: {
223 launcherApplicationSelected(appId)
230 onPreventHidingChanged: {
231 if (dismissTimer.running) {
232 dismissTimer.restart();
237 enabled: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate;
240 easing.type: Easing.OutCubic
244 Behavior on opacity {
246 duration: UbuntuAnimation.FastDuration; easing.type: Easing.OutCubic
251 // TODO: This should be replaced by some mechanism that reveals the launcher
252 // after a certain resistance has been overcome, like unity7 does. However,
253 // as we don't get relative mouse coordinates yet, this will do for now.
256 anchors { fill: panel; rightMargin: -1 }
258 propagateComposedEvents: true
259 onContainsMouseChanged: {
261 root.switchToNextState("visibleTemporary");
263 dismissTimer.restart();
266 onPressed: mouse.accepted = false;
268 // We need to eat touch events here in order to make sure that
269 // we don't trigger both, the dragArea and the hoverArea
270 MultiPointTouchArea {
271 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
274 enabled: parent.enabled
278 DirectionalDragArea {
280 objectName: "launcherDragArea"
282 direction: Direction.Rightwards
284 enabled: root.available
285 x: -root.x // so if launcher is adjusted relative to screen, we stay put (like tutorial does when teasing)
286 width: root.dragAreaWidth
290 if (!dragging || launcher.state == "visible")
293 panel.x = -panel.width + Math.min(Math.max(0, distance), panel.width);
298 if (distance > panel.width / 2) {
299 root.switchToNextState("visible")
300 if (distance > minimizeDistance) {
303 } else if (root.state === "") {
304 // didn't drag far enough. rollback
305 root.switchToNextState("")
313 name: "" // hidden state. Must be the default state ("") because "when:" falls back to this.
323 x: -root.x // so we never go past panelWidth, even when teased by tutorial
325 PropertyChanges { target: hoverArea; enabled: false }
328 name: "visibleTemporary"
332 autohideEnabled: true
334 PropertyChanges { target: hoverArea; enabled: true }
338 when: teaseTimer.running && teaseTimer.mode == "teasing"
341 x: -root.panelWidth + units.gu(2)
346 when: teaseTimer.running && teaseTimer.mode == "hinting"