2
* This file is part of unity-2d
4
* Copyright 2010-2011 Canonical Ltd.
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; version 3.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22
/* This component represents a single "tile" in the launcher and the surrounding
25
The tile is square in size, with a side determined by the 'tileSize' property,
27
It is composed by a colored background layer, an icon (with 'icon' as source),
28
and a layer on top that provides a "shine" effect.
29
The main color of the background layer may be calculated based on the icon color
30
or may be fixed (depending on the 'backgroundFromIcon' property).
32
There's also an additional layer which contains only the outline of the tile
33
that is only appearing during the launching animation (when the 'launching' property is
34
true). During this animation the background fades out and the outline fades in,
35
giving a "pulsing" appearance to the tile.
37
Around the tile we may have on the left a number of "pips" between zero and three.
38
Pips are small icons used to indicate how many windows we have open for the current tile
39
(based on the 'windowCount' property).
40
The rule is: if there's only one window, we just display an arrow. If there are
41
two we display 2 pips, if there are 3 or more display 3 pips.
43
On the right of the tile there's an arrow that appears if the tile is currently 'active'.
45
Additionally, when the tile is marked as 'urgent' it will start an animation where the
46
rotation is changed so that it appears to be "shaking".
3
/* Item displaying an application.
6
- a generic bordered background image
7
- an icon representing the application
8
- a text describing the application
10
When an application is launched, the border changes appearance.
11
It supports mouse hover by changing the appearance of the background image.
13
The 'icon' property holds the source of the image to load as an icon.
14
The 'label' property holds the text to display.
15
The 'running' property is a boolean indicating whether or not the
16
application is launched.
18
The 'clicked' signal is emitted upon clicking on the item.
51
Accessible.role: Accessible.PushButton
53
anchors.horizontalCenter: parent.horizontalCenter
55
height: selectionOutlineSize
57
property bool isBfb: false
59
property int selectionOutlineSize
60
property alias name: looseItem.objectName
61
property string desktopFile: ""
62
21
property alias icon: icon.source
63
property alias urgentAnimation: urgentAnimation
22
property alias label: label.text
64
23
property bool running: false
65
24
property bool active: false
66
25
property bool urgent: false
26
property bool sticky: false
67
27
property bool launching: false
68
property alias interactive: mouse.enabled
70
property int counter: 0
71
property bool counterVisible: false
72
property real progress: 0.0
73
property bool progressBarVisible: false
74
property alias emblem: emblemIcon.source
75
property bool emblemVisible: false
77
property bool backgroundFromIcon
78
property color defaultBackgroundColor: "#333333"
79
property color selectedBackgroundColor: "#dddddd"
81
property alias shortcutVisible: shortcut.visible
82
property alias shortcutText: shortcutText.text
84
property bool isBeingDragged: false
85
property int dragPosition
88
property string pipSource: "launcher/artwork/launcher_" +
89
((pips <= 1) ? "arrow" : "pip") + "_ltr.png"
90
function getPipOffset(index) {
91
/* Pips need to always be centered, regardless if they are an even or odd
92
number. The following simple conditional code works and is less
93
convoluted than a generic formula. It's ok since we always work with at
94
most three pips anyway. */
95
if (pips == 1) return 0
96
if (pips == 2) return (index == 0) ? -2 : +2
97
else return (index == 0) ? 0 : (index == 1) ? -4 : +4
100
function isRightToLeft() {
101
return Qt.application.layoutDirection == Qt.RightToLeft
104
29
signal clicked(variant mouse)
105
signal pressed(variant mouse)
36
acceptedButtons: Qt.LeftButton | Qt.RightButton
39
onClicked: parent.clicked(mouse)
40
onEntered: parent.entered()
41
onExited: parent.exited()
45
if (event.key == Qt.Key_Return) {
47
event.accepted = true;
54
source: "artwork/shadow.png"
61
anchors.horizontalCenter: parent.horizontalCenter
62
anchors.verticalCenter: parent.verticalCenter
64
source: "artwork/glow.png"
68
SequentialAnimation on opacity {
69
loops: Animation.Infinite
72
NumberAnimation { to: 1.0; duration: 1000; easing.type: Easing.InOutQuad }
73
NumberAnimation { to: 0.0; duration: 1000; easing.type: Easing.InOutQuad }
110
/* The actual item, reparented so its y coordinate can be animated. */
112
LayoutMirroring.enabled: isRightToLeft()
113
LayoutMirroring.childrenInherit: true
118
y: -item.ListView.view.contentY + item.y
119
/* The item is above the list's contentItem.
120
Top and bottom gradients, ListViewDragAndDrop and autoscroll areas
121
are above the item */
122
z: list.contentItem.z + 1
124
/* Bind to the scale of the delegate so that it is animated upon insertion/removal */
127
/* The y coordinate is initially not animated, as it would result in an
128
unwanted effect of every single item popping out from the top of the
129
launcher (even when they are supposed to be coming from the bottom).
130
This property is later set to true once the item has taken its
132
property bool animateY: false
134
/* This is the arrow shown at the right of the tile when the application is
138
anchors.right: parent.right
139
y: item.height - item.selectionOutlineSize / 2 - height / 2
140
mirror: isRightToLeft()
142
source: "image://blended/%1color=%2alpha=%3"
143
.arg("launcher/artwork/launcher_arrow_rtl.png")
147
visible: active && (looseItem.state != "beingDragged")
150
/* This is the area on the left of the tile where the pips/arrow end up.
152
I'd rather use a Column here, but the pip images have an halo
153
around them, so they are pretty tall and would mess up the column.
154
As a workaround I center all of them, then shift up or down
155
depending on the index. */
159
objectName: "pips-" + index
160
/* FIXME: It seems that when the image is created (or re-used) by the Repeater
161
for a moment it doesn't have any parent, and therefore warnings are
162
printed for the following two anchor assignements. This fixes the
163
problem, but I'm not sure if it should happen in the first place. */
164
anchors.left: (parent) ? parent.left : undefined
165
y: item.height - item.selectionOutlineSize / 2 - height / 2 + getPipOffset(index)
166
mirror: isRightToLeft()
168
source: "image://blended/%1color=%2alpha=%3"
169
.arg(pipSource).arg("lightgrey").arg(1.0)
171
visible: looseItem.state != "beingDragged"
179
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MidButton
181
onClicked: item.clicked(mouse)
182
onEntered: item.entered()
183
onExited: item.exited()
184
onPressed: item.pressed(mouse)
187
/* This is the for centering the actual tile in the launcher */
191
height: item.tileSize
192
anchors.centerIn: parent
194
/* This is the image providing the background image. The
195
color blended with this image is obtained from the color of the icon when it's
197
While the application is launching, this will fade out and in. */
200
objectName: "tileBackground"
201
property color color: defaultBackgroundColor
206
SequentialAnimation on opacity {
207
NumberAnimation { to: 0.0; duration: 1000; easing.type: Easing.InOutQuad }
208
NumberAnimation { to: 1.0; duration: 1000; easing.type: Easing.InOutQuad }
210
loops: Animation.Infinite
215
sourceSize.width: item.tileSize
216
sourceSize.height: item.tileSize
219
if (declarativeView.focus && item.activeFocus) {
220
return "artwork/squircle_base_selected_54.png"
222
return "artwork/squircle_base_54.png"
226
var actualColor = declarativeView.focus && item.activeFocus ? selectedBackgroundColor : color
227
return "image://blended/%1color=%2alpha=%3"
228
.arg("launcher/artwork/round_corner_54x54.png")
229
.arg(actualColor.toString().replace("#", ""))
234
/* This image appears only while launching, and pulses in and out in counterpoint
235
to the background, so that the outline of the tile is always visible. */
241
sourceSize.width: item.tileSize
242
sourceSize.height: item.tileSize
243
source: "artwork/round_outline_54x54.png"
247
SequentialAnimation on opacity {
248
NumberAnimation { to: 1.0; duration: 1000; easing.type: Easing.InOutQuad }
249
NumberAnimation { to: 0.0; duration: 1000; easing.type: Easing.InOutQuad }
251
loops: Animation.Infinite
257
/* This is just the main icon of the tile */
261
anchors.centerIn: parent
265
sourceSize.height: 48
267
/* Whenever one of the parameters used in calculating the background color of
268
the icon changes, recalculate its value */
269
onWidthChanged: updateColors()
270
onHeightChanged: updateColors()
271
onSourceChanged: updateColors()
272
onStatusChanged: if (status == Image.Error) source = "image://icons/unknown"
274
function updateColors() {
275
if (!item.backgroundFromIcon) return;
277
var colors = iconUtilities.getColorsFromIcon(icon.source, icon.sourceSize)
278
if (colors && colors.length > 0) tileBackground.color = colors[0]
282
/* This just adds some shiny effect to the tile */
288
source: isBfb ? "artwork/squircle_shine_54.png" : "artwork/round_shine_54x54.png"
289
sourceSize.width: item.tileSize
290
sourceSize.height: item.tileSize
295
objectName: "selectionOutline"
296
anchors.centerIn: parent
298
source: isBfb ? "artwork/squircle_glow_54.png" : "artwork/round_selected_66x66.png"
299
visible: declarativeView.focus && item.activeFocus
304
height: 16 - border.width
306
// Using anchors the item will be 1 pixel off with respect to Unity
309
radius: height / 2 - 1
312
border.color: "white"
314
visible: launcherItem.counterVisible
317
anchors.centerIn: parent
318
font.pixelSize: parent.height - 3
319
width: parent.width - 5
321
elide: Text.ElideRight
322
horizontalAlignment: Text.AlignHCenter
324
text: launcherItem.counter
330
objectName: "progressBar"
331
source: "artwork/progress_bar_trough.png"
332
anchors.verticalCenter: parent.verticalCenter
333
anchors.left: parent.left
336
state: launcherItem.progressBarVisible ? "" : "hidden"
340
source: "artwork/progress_bar_fill.png"
341
anchors.verticalCenter: parent.verticalCenter
343
width: sourceSize.width * launcherItem.progress
347
NumberAnimation { duration: 200; easing.type: Easing.InOutSine }
352
NumberAnimation { duration: 200; easing.type: Easing.InOutSine }
361
// This, combined with anchors.left: parent.left in the default state
362
// makes the bar seem to come in from the left and go away at the right
365
anchors.left: undefined
366
anchors.right: tile.right
373
anchors.centerIn: parent
374
color: "#B3000000" // 0.7 opacity on black
382
anchors.centerIn: parent
390
anchors.left: parent.left
391
anchors.top: parent.top
392
visible: launcherItem.emblemVisible && !counter.visible
397
/* The entire tile will "shake" when the window is marked as "urgent", to attract
398
the user's attention */
82
anchors.horizontalCenter: parent.horizontalCenter
83
anchors.verticalCenter: parent.verticalCenter
88
opacity: mouse.containsMouse ? 1.0 : 0.9
91
anchors.horizontalCenter: parent.horizontalCenter
92
anchors.verticalCenter: parent.verticalCenter
94
color: if(icon.source != "")
95
return launcherView.iconAverageColor(icon.source,
96
Qt.size(icon.width, icon.height))
105
anchors.horizontalCenter: parent.horizontalCenter
106
anchors.verticalCenter: parent.verticalCenter
107
fillMode: Image.PreserveAspectFit
108
sourceSize.width: width
109
sourceSize.height: height
113
opacity: status == Image.Ready ? 1 : 0
114
Behavior on opacity {NumberAnimation {duration: 200; easing.type: Easing.InOutQuad}}
121
anchors.horizontalCenter: parent.horizontalCenter
122
anchors.verticalCenter: parent.verticalCenter
123
fillMode: Image.PreserveAspectFit
124
sourceSize.width: width
125
sourceSize.height: height
128
source: "/usr/share/unity/themes/prism_icon_foreground.png"
131
opacity: status == Image.Ready ? 1 : 0
132
Behavior on opacity {NumberAnimation {duration: 200; easing.type: Easing.InOutQuad}}
135
SequentialAnimation {
399
138
SequentialAnimation {
404
SequentialAnimation {
405
loops: (urgent) ? 30 : 0
406
NumberAnimation { target: tile; property: "rotation"; to: 15; duration: 150 }
407
NumberAnimation { target: tile; property: "rotation"; to: -15; duration: 150 }
409
NumberAnimation { target: tile; property: "rotation"; to: 0; duration: 75 }
415
when: item.isBeingDragged
418
y: item.dragPosition - tile.height / 2
419
/* When dragging an item, stack it on top of all its siblings */
420
z: list.contentItem.z + 2
424
enabled: /* do not animate during initial positioning */
426
/* do not animate while dragging to re-order applications */
427
&& (looseItem.state != "beingDragged")
428
/* do not animate during insertion/removal */
429
&& (looseItem.scale == 1)
430
/* do not animate while flicking the list */
431
&& !item.ListView.view.moving
432
&& !item.ListView.view.autoScrolling
435
easing.type: Easing.OutBack
439
/* Delay the animation on y to when the item has been initially positioned. */
442
/* This ensures that the trigger will be executed in the next
443
iteration of the event loop, at which point the item will have
444
taken its initial position. */
445
triggeredOnStart: true
448
looseItem.animateY = true
451
Component.onCompleted: canAnimateY.start()
140
NumberAnimation { target: container; property: "rotation"; to: 15; duration: 150 }
141
NumberAnimation { target: container; property: "rotation"; to: -15; duration: 150 }
143
NumberAnimation { target: container; property: "rotation"; to: 0; duration: 75 }
161
width: sourceSize.width
162
height: sourceSize.height
163
anchors.rightMargin: -2
164
anchors.right: container.left
165
anchors.verticalCenter: container.verticalCenter
166
opacity: running ? 1.0 : 0.0
167
source: urgent ? "/usr/share/unity/themes/application-running-notify.png" : "/usr/share/unity/themes/application-running.png"
169
Behavior on opacity {NumberAnimation {duration: 200; easing.type: Easing.InOutQuad}}
176
width: sourceSize.width
177
height: sourceSize.height
178
anchors.leftMargin: -2
179
anchors.left: container.right
180
anchors.verticalCenter: container.verticalCenter
181
opacity: active ? 1.0 : 0.0
182
source: "/usr/share/unity/themes/application-selected.png"
184
Behavior on opacity {NumberAnimation {duration: 200; easing.type: Easing.InOutQuad}}
191
wrapMode: Text.WordWrap
192
horizontalAlignment: Text.AlignHCenter
193
anchors.top: parent.bottom
195
anchors.right: parent.right
196
anchors.bottom: parent.bottom
197
anchors.left: parent.left
198
font.underline: parent.focus