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  ProportionalShape {
129  id: iconShape
130  anchors.centerIn: parent
131  width: parent.width - units.gu(2)
132  aspect: UbuntuShape.DropShadow
133  source: Image {
134  id: iconImage
135  sourceSize.width: iconShape.width
136  sourceSize.height: iconShape.height
137  source: root.iconName
138  }
139  }
140 
141  UbuntuShape {
142  id: countEmblem
143  objectName: "countEmblem"
144  anchors {
145  right: parent.right
146  bottom: parent.bottom
147  margins: units.dp(3)
148  }
149  width: Math.min(root.itemWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1)))
150  height: units.gu(2)
151  backgroundColor: UbuntuColors.orange
152  visible: root.countVisible
153  aspect: UbuntuShape.Flat
154 
155  Label {
156  id: countLabel
157  objectName: "countLabel"
158  text: root.count
159  anchors.centerIn: parent
160  // FIXME: verticalCenter seems to be off wee bit and QML doesn't have a centerLine
161  // property for Text: https://bugreports.qt-project.org/browse/QTBUG-40479
162  anchors.verticalCenterOffset: -units.dp(.5)
163  width: root.itemWidth - units.gu(1)
164  horizontalAlignment: Text.AlignHCenter
165  elide: Text.ElideRight
166  color: "white"
167  fontSize: "x-small"
168  }
169  }
170 
171  UbuntuShape {
172  id: progressOverlay
173  objectName: "progressOverlay"
174 
175  anchors {
176  left: iconItem.left
177  right: iconItem.right
178  verticalCenter: parent.verticalCenter
179  leftMargin: units.gu(1.5)
180  rightMargin: units.gu(1.5)
181  }
182  height: units.gu(1)
183  visible: root.progress > -1
184  color: UbuntuColors.darkGrey
185  borderSource: "none"
186 
187  Item {
188  anchors {
189  left: parent.left
190  top: parent.top
191  bottom: parent.bottom
192  }
193  width: Math.min(100, root.progress) / 100 * parent.width
194  clip: true
195 
196  UbuntuShape {
197  anchors {
198  left: parent.left
199  top: parent.top
200  bottom: parent.bottom
201  }
202  color: "white"
203  borderSource: "none"
204  width: progressOverlay.width
205  }
206  }
207  }
208 
209  Image {
210  objectName: "runningHighlight"
211  anchors {
212  left: parent.left
213  verticalCenter: parent.verticalCenter
214  }
215  visible: root.itemRunning
216  rotation: 180
217  source: "graphics/focused_app_arrow.png"
218  }
219 
220  Image {
221  objectName: "focusedHighlight"
222  anchors {
223  right: parent.right
224  verticalCenter: parent.verticalCenter
225  }
226  visible: root.itemFocused
227  source: "graphics/focused_app_arrow.png"
228  }
229  }
230 
231  ShaderEffect {
232  id: transformEffect
233  anchors.centerIn: parent
234  anchors.verticalCenterOffset: root.offset
235  width: iconItem.width
236  height: iconItem.height
237  property real itemOpacity: root.itemOpacity
238  property real brightness: Math.max(-1, root.brightness)
239  property real angle: root.angle
240  rotation: root.inverted ? 180 : 0
241 
242  property variant source: ShaderEffectSource {
243  id: shaderEffectSource
244  sourceItem: iconItem
245  hideSource: true
246  }
247 
248  transform: [
249  // The rotation about the icon's center/z-axis for the wiggle
250  // needs to happen here too, because there's no other way to
251  // align the wiggle with the icon-folding otherwise
252  Rotation {
253  axis { x: 0; y: 0; z: 1 }
254  origin { x: iconItem.width / 2; y: iconItem.height / 2; z: 0 }
255  angle: priv.wiggleAngle
256  },
257  // Rotating 3 times at top/bottom because that increases the perspective.
258  // This is a hack, but as QML does not support real 3D coordinates
259  // getting a higher perspective can only be done by a hack. This is the most
260  // readable/understandable one I could come up with.
261  Rotation {
262  axis { x: 1; y: 0; z: 0 }
263  origin { x: iconItem.width / 2; y: angle > 0 ? 0 : iconItem.height; z: 0 }
264  angle: root.angle * 0.7
265  },
266  Rotation {
267  axis { x: 1; y: 0; z: 0 }
268  origin { x: iconItem.width / 2; y: angle > 0 ? 0 : iconItem.height; z: 0 }
269  angle: root.angle * 0.7
270  },
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  // Because rotating it 3 times moves it more to the front/back, i.e. it gets
277  // bigger/smaller and we need a scale to compensate that again.
278  Scale {
279  xScale: 1 - (Math.abs(angle) / 500)
280  yScale: 1 - (Math.abs(angle) / 500)
281  origin { x: iconItem.width / 2; y: iconItem.height / 2}
282  }
283  ]
284 
285  // Using a fragment shader instead of QML's opacity and BrightnessContrast
286  // to be able to do both in one step which gives quite some better performance
287  fragmentShader: "
288  varying highp vec2 qt_TexCoord0;
289  uniform sampler2D source;
290  uniform lowp float brightness;
291  uniform lowp float itemOpacity;
292  void main(void)
293  {
294  highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
295  sourceColor.rgb = mix(sourceColor.rgb, vec3(step(0.0, brightness)), abs(brightness));
296  sourceColor *= itemOpacity;
297  gl_FragColor = sourceColor;
298  }"
299  }
300 }