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