on d45fc13 help sign in
unity8/qml/Launcher/LauncherDelegate.qml
329 lines 11 kB history raw
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 */
17import QtQuick 2.4
18import Ubuntu.Components 1.3
20Item {
21 id: root
23 property int itemIndex: 0
24 property string iconName
25 property int count: 0
26 property bool countVisible: false
27 property int progress: -1
28 property bool itemRunning: false
29 property bool itemFocused: false
30 property real maxAngle: 0
31 property bool inverted: false
32 property bool alerting: false
33 property bool highlighted: false
34 property bool shortcutHintShown: false
35 property int surfaceCount: 1
37 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
38 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
39 readonly property alias wiggling: wiggleAnim.running
41 property int itemWidth
42 property int itemHeight
43 // The angle used for rotating
44 property real angle: 0
45 // This is the offset that keeps the items inside the panel
46 property real offset: 0
47 property real itemOpacity: 1
48 property real brightness: 0
49 property double maxWiggleAngle: 5.0
51 QtObject {
52 id: priv
54 readonly property int wiggleDuration: UbuntuAnimation.SnapDuration
55 property real wiggleAngle: 0
56 }
58 SequentialAnimation {
59 id: wiggleAnim
61 running: alerting
62 loops: 1
63 alwaysRunToEnd: true
65 NumberAnimation {
66 target: priv
67 property: "wiggleAngle"
68 from: 0
69 to: maxWiggleAngle
70 duration: priv.wiggleDuration
71 easing.type: Easing.InQuad
72 }
74 NumberAnimation {
75 target: priv
76 property: "wiggleAngle"
77 from: maxWiggleAngle
78 to: -maxWiggleAngle
79 duration: priv.wiggleDuration
80 easing.type: Easing.InOutQuad
81 }
83 NumberAnimation {
84 target: priv
85 property: "wiggleAngle"
86 from: -maxWiggleAngle
87 to: maxWiggleAngle
88 duration: priv.wiggleDuration
89 easing.type: Easing.InOutQuad
90 }
92 NumberAnimation {
93 target: priv
94 property: "wiggleAngle"
95 from: maxWiggleAngle
96 to: -maxWiggleAngle
97 duration: priv.wiggleDuration
98 easing.type: Easing.InOutQuad
99 }
101 NumberAnimation {
102 target: priv
103 property: "wiggleAngle"
104 from: -maxWiggleAngle
105 to: maxWiggleAngle
106 duration: priv.wiggleDuration
107 easing.type: Easing.InOutQuad
108 }
110 NumberAnimation {
111 target: priv
112 property: "wiggleAngle"
113 from: maxWiggleAngle
114 to: 0
115 duration: priv.wiggleDuration
116 easing.type: Easing.OutQuad
117 }
118 }
120 Item {
121 id: iconItem
122 width: root.width
123 height: parent.itemHeight + units.gu(1)
124 anchors.centerIn: parent
126 Image {
127 objectName: "focusRing"
128 anchors.centerIn: iconShape
129 height: width * 15 / 16
130 width: iconShape.width + units.gu(1)
131 source: "graphics/launcher-app-focus-ring.svg"
132 sourceSize.width: width
133 sourceSize.height: height
134 visible: root.highlighted
135 }
137 ProportionalShape {
138 id: iconShape
139 anchors.centerIn: parent
140 width: root.itemWidth
141 aspect: UbuntuShape.DropShadow
142 source: Image {
143 id: iconImage
144 sourceSize.width: iconShape.width
145 sourceSize.height: iconShape.height
146 source: root.iconName
147 cache: false // see lpbug#1543290 why no cache
148 }
149 }
151 UbuntuShape {
152 id: countEmblem
153 objectName: "countEmblem"
154 anchors {
155 right: parent.right
156 bottom: parent.bottom
157 rightMargin: (iconItem.width - root.itemWidth) / 2 - units.dp(2)
158 margins: units.dp(5)
159 }
160 width: Math.min(root.itemWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1)))
161 height: units.gu(2)
162 backgroundColor: theme.palette.normal.positive
163 visible: root.countVisible
164 aspect: UbuntuShape.Flat
166 Label {
167 id: countLabel
168 objectName: "countLabel"
169 text: root.count
170 anchors.centerIn: parent
171 width: root.itemWidth - units.gu(1)
172 horizontalAlignment: Text.AlignHCenter
173 elide: Text.ElideRight
174 color: "white"
175 fontSize: "x-small"
176 }
177 }
179 UbuntuShape {
180 id: progressOverlay
181 objectName: "progressOverlay"
183 anchors.centerIn: parent
184 width: root.itemWidth * .8
185 height: units.dp(3)
186 visible: root.progress > -1
187 backgroundColor: "white"
188 borderSource: "none"
190 Item {
191 anchors {
192 left: parent.left
193 top: parent.top
194 bottom: parent.bottom
195 }
196 width: Math.min(100, root.progress) / 100 * parent.width
197 clip: true
199 UbuntuShape {
200 anchors {
201 left: parent.left
202 top: parent.top
203 bottom: parent.bottom
204 }
205 backgroundColor: theme.palette.normal.activity
206 borderSource: "none"
207 width: progressOverlay.width
208 }
209 }
210 }
212 Column {
213 anchors {
214 left: parent.left
215 verticalCenter: parent.verticalCenter
216 }
217 spacing: units.gu(.5)
218 Repeater {
219 objectName: "surfacePipRepeater"
220 model: Math.min(3, root.surfaceCount)
221 Rectangle {
222 objectName: "runningHighlight" + index
223 width: units.gu(0.25)
224 height: units.gu(.5)
225 color: root.alerting ? theme.palette.normal.activity : "white"
226 visible: root.itemRunning
227 }
228 }
229 }
231 Rectangle {
232 objectName: "focusedHighlight"
233 anchors {
234 right: parent.right
235 verticalCenter: parent.verticalCenter
236 }
237 width: units.gu(0.25)
238 height: units.gu(.5)
239 color: "white"
240 visible: root.itemFocused
241 }
243 UbuntuShape {
244 objectName: "shortcutHint"
245 anchors.centerIn: parent
246 width: units.gu(2.5)
247 height: width
248 backgroundColor: "#F2111111"
249 visible: root.shortcutHintShown
250 aspect: UbuntuShape.Flat
251 Label {
252 anchors.centerIn: parent
253 text: (itemIndex + 1) % 10
254 color: "white"
255 font.weight: Font.Light
256 }
257 }
258 }
260 ShaderEffect {
261 id: transformEffect
262 anchors.centerIn: parent
263 anchors.verticalCenterOffset: root.offset
264 width: iconItem.width
265 height: iconItem.height
266 property real itemOpacity: root.itemOpacity
267 property real brightness: Math.max(-1, root.brightness)
268 property real angle: root.angle
269 rotation: root.inverted ? 180 : 0
271 property variant source: ShaderEffectSource {
272 id: shaderEffectSource
273 sourceItem: iconItem
274 hideSource: true
275 }
277 transform: [
278 // The rotation about the icon's center/z-axis for the wiggle
279 // needs to happen here too, because there's no other way to
280 // align the wiggle with the icon-folding otherwise
281 Rotation {
282 axis { x: 0; y: 0; z: 1 }
283 origin { x: iconItem.width / 2; y: iconItem.height / 2; z: 0 }
284 angle: priv.wiggleAngle
285 },
286 // Rotating 3 times at top/bottom because that increases the perspective.
287 // This is a hack, but as QML does not support real 3D coordinates
288 // getting a higher perspective can only be done by a hack. This is the most
289 // readable/understandable one I could come up with.
290 Rotation {
291 axis { x: 1; y: 0; z: 0 }
292 origin { x: iconItem.width / 2; y: angle > 0 ? 0 : iconItem.height; z: 0 }
293 angle: root.angle * 0.7
294 },
295 Rotation {
296 axis { x: 1; y: 0; z: 0 }
297 origin { x: iconItem.width / 2; y: angle > 0 ? 0 : iconItem.height; z: 0 }
298 angle: root.angle * 0.7
299 },
300 Rotation {
301 axis { x: 1; y: 0; z: 0 }
302 origin { x: iconItem.width / 2; y: angle > 0 ? 0 : iconItem.height; z: 0 }
303 angle: root.angle * 0.7
304 },
305 // Because rotating it 3 times moves it more to the front/back, i.e. it gets
306 // bigger/smaller and we need a scale to compensate that again.
307 Scale {
308 xScale: 1 - (Math.abs(angle) / 500)
309 yScale: 1 - (Math.abs(angle) / 500)
310 origin { x: iconItem.width / 2; y: iconItem.height / 2}
311 }
312 ]
314 // Using a fragment shader instead of QML's opacity and BrightnessContrast
315 // to be able to do both in one step which gives quite some better performance
316 fragmentShader: "
317 varying highp vec2 qt_TexCoord0;
318 uniform sampler2D source;
319 uniform lowp float brightness;
320 uniform lowp float itemOpacity;
321 void main(void)
322 {
323 highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
324 sourceColor.rgb = mix(sourceColor.rgb, vec3(step(0.0, brightness)), abs(brightness));
325 sourceColor *= itemOpacity;
326 gl_FragColor = sourceColor;
327 }"
328 }