on xenial help sign in
clip the corner of pinned icons in the launcher as per new design
41d1e09Michael Zanetti
plugins/Unity/Launcher/launchermodel.cpp+3−1
@@ -128,7 +128,7 @@ void LauncherModel::pin(const QString &appId, int index)
128 if (index == -1 || index == currentIndex) {
128 if (index == -1 || index == currentIndex) {
129 m_list.at(currentIndex)->setPinned(true);
129 m_list.at(currentIndex)->setPinned(true);
130 QModelIndex modelIndex = this->index(currentIndex);
130 QModelIndex modelIndex = this->index(currentIndex);
131− Q_EMIT dataChanged(modelIndex, modelIndex);
131+ Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RolePinned);
132 } else {
132 } else {
133 move(currentIndex, index);
133 move(currentIndex, index);
134 // move() will store the list to the backend itself, so just exit at this point.
134 // move() will store the list to the backend itself, so just exit at this point.
@@ -159,6 +159,8 @@ void LauncherModel::requestRemove(const QString &appId)
159
159
160 if (m_appManager->findApplication(appId)) {
160 if (m_appManager->findApplication(appId)) {
161 m_list.at(index)->setPinned(false);
161 m_list.at(index)->setPinned(false);
162+ QModelIndex modelIndex = this->index(index);
163+ Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RolePinned);
162 return;
164 return;
163 }
165 }
164
166
qml/Launcher/LauncherDelegate.qml+31
@@ -26,6 +26,7 @@ Item {
26 property bool itemFocused: false
26 property bool itemFocused: false
27 property real maxAngle: 0
27 property real maxAngle: 0
28 property bool inverted: false
28 property bool inverted: false
29+ property bool clipCorner: false
29
30
30 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
31 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
31 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
32 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
@@ -143,6 +144,24 @@ Item {
143 }
144 }
144 }
145 }
145
146
147+ Item {
148+ id: clipper
149+ anchors.centerIn: parent
150+ width: iconItem.width
151+ height: iconItem.height
152+ Rectangle {
153+ anchors {
154+ fill: parent
155+ topMargin: -units.gu(2)
156+ leftMargin: -units.gu(2)
157+ rightMargin: -units.gu(2)
158+ bottomMargin: units.gu(1.2)
159+ }
160+ color: "red"
161+ rotation: root.rotation + 45
162+ }
163+ }
164+
146 ShaderEffect {
165 ShaderEffect {
147 id: transformEffect
166 id: transformEffect
148 anchors.centerIn: parent
167 anchors.centerIn: parent
@@ -152,6 +171,7 @@ Item {
152 property real itemOpacity: root.itemOpacity
171 property real itemOpacity: root.itemOpacity
153 property real brightness: Math.max(-1, root.brightness)
172 property real brightness: Math.max(-1, root.brightness)
154 property real angle: root.angle
173 property real angle: root.angle
174+ property bool clipCorner: root.clipCorner
155 rotation: root.inverted ? 180 : 0
175 rotation: root.inverted ? 180 : 0
156
176
157 property variant source: ShaderEffectSource {
177 property variant source: ShaderEffectSource {
@@ -160,6 +180,11 @@ Item {
160 hideSource: true
180 hideSource: true
161 }
181 }
162
182
183+ property var mask: ShaderEffectSource {
184+ sourceItem: clipper
185+ hideSource: true
186+ }
187+
163 transform: [
188 transform: [
164 // Rotating 3 times at top/bottom because that increases the perspective.
189 // Rotating 3 times at top/bottom because that increases the perspective.
165 // This is a hack, but as QML does not support real 3D coordinates
190 // This is a hack, but as QML does not support real 3D coordinates
@@ -194,13 +219,19 @@ Item {
194 fragmentShader: "
219 fragmentShader: "
195 varying highp vec2 qt_TexCoord0;
220 varying highp vec2 qt_TexCoord0;
196 uniform sampler2D source;
221 uniform sampler2D source;
222+ uniform sampler2D mask;
197 uniform lowp float brightness;
223 uniform lowp float brightness;
198 uniform lowp float itemOpacity;
224 uniform lowp float itemOpacity;
225+ uniform bool clipCorner;
199 void main(void)
226 void main(void)
200 {
227 {
201 highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
228 highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
229+ highp vec4 maskColor = texture2D(mask, qt_TexCoord0);
202 sourceColor.rgb = mix(sourceColor.rgb, vec3(step(0.0, brightness)), abs(brightness));
230 sourceColor.rgb = mix(sourceColor.rgb, vec3(step(0.0, brightness)), abs(brightness));
203 sourceColor *= itemOpacity;
231 sourceColor *= itemOpacity;
232+ if (clipCorner) {
233+ sourceColor *= maskColor.a;
234+ }
204 gl_FragColor = sourceColor;
235 gl_FragColor = sourceColor;
205 }"
236 }"
206 }
237 }
qml/Launcher/LauncherPanel.qml+5−1
@@ -155,6 +155,7 @@ Item {
155 iconName: model.icon
155 iconName: model.icon
156 count: model.count
156 count: model.count
157 progress: model.progress
157 progress: model.progress
158+ clipCorner: model.pinned
158 itemFocused: model.focused
159 itemFocused: model.focused
159 inverted: root.inverted
160 inverted: root.inverted
160 z: -Math.abs(offset)
161 z: -Math.abs(offset)
@@ -465,6 +466,10 @@ Item {
465 width: itemWidth
466 width: itemWidth
466 rotation: root.rotation
467 rotation: root.rotation
467 itemOpacity: 0.9
468 itemOpacity: 0.9
469+ clipCorner: dndArea.draggedIndex > -1 &&
470+ LauncherModel.get(dndArea.draggedIndex).pinned &&
471+ !dndArea.preDragging &&
472+ !dndArea.dragging
468
473
469 function flatten() {
474 function flatten() {
470 fakeDragItemAnimation.start();
475 fakeDragItemAnimation.start();
@@ -528,7 +533,6 @@ Item {
528 left: root.inverted ? undefined : parent.right
533 left: root.inverted ? undefined : parent.right
529 right: root.inverted ? parent.left : undefined
534 right: root.inverted ? parent.left : undefined
530 margins: units.gu(1)
535 margins: units.gu(1)
531−
532 }
536 }
533 y: itemCenter - (height / 2) + offset
537 y: itemCenter - (height / 2) + offset
534 rotation: root.rotation
538 rotation: root.rotation
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+6−1
@@ -24,10 +24,12 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
24{
24{
25 MockLauncherItem *item = new MockLauncherItem("dialer-app", "/usr/share/applications/dialer-app.desktop", "Dialer", "dialer-app", this);
25 MockLauncherItem *item = new MockLauncherItem("dialer-app", "/usr/share/applications/dialer-app.desktop", "Dialer", "dialer-app", this);
26 item->setProgress(0);
26 item->setProgress(0);
27− m_list.append(item);
27+ item->setPinned(true);
28 item->setFocused(true);
28 item->setFocused(true);
29+ m_list.append(item);
29 item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
30 item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
30 item->setProgress(10);
31 item->setProgress(10);
32+ item->setPinned(true);
31 m_list.append(item);
33 m_list.append(item);
32 item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
34 item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
33 item->setProgress(50);
35 item->setProgress(50);
@@ -40,6 +42,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
40 m_list.append(item);
42 m_list.append(item);
41 item = new MockLauncherItem("twitter-webapp", "/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter", this);
43 item = new MockLauncherItem("twitter-webapp", "/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter", this);
42 item->setCount(12);
44 item->setCount(12);
45+ item->setPinned(true);
43 m_list.append(item);
46 m_list.append(item);
44 item = new MockLauncherItem("gmail-webapp", "/usr/share/applications/gmail-webapp.desktop", "GMail", "gmail", this);
47 item = new MockLauncherItem("gmail-webapp", "/usr/share/applications/gmail-webapp.desktop", "GMail", "gmail", this);
45 item->setCount(123);
48 item->setCount(123);
@@ -51,8 +54,10 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
51 item->setProgress(50);
54 item->setProgress(50);
52 item->setCount(5);
55 item->setCount(5);
53 item->setFocused(true);
56 item->setFocused(true);
57+ item->setPinned(true);
54 m_list.append(item);
58 m_list.append(item);
55 item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
59 item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
60+ item->setPinned(true);
56 m_list.append(item);
61 m_list.append(item);
57}
62}
58
63
tests/plugins/Unity/Launcher/launchermodeltest.cpp+9
@@ -156,11 +156,20 @@ private Q_SLOTS:
156 }
156 }
157
157
158 void testPinning() {
158 void testPinning() {
159+ QSignalSpy spy(launcherModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)));
159 QCOMPARE(launcherModel->get(0)->pinned(), false);
160 QCOMPARE(launcherModel->get(0)->pinned(), false);
160 QCOMPARE(launcherModel->get(1)->pinned(), false);
161 QCOMPARE(launcherModel->get(1)->pinned(), false);
161 launcherModel->pin(launcherModel->get(0)->appId());
162 launcherModel->pin(launcherModel->get(0)->appId());
162 QCOMPARE(launcherModel->get(0)->pinned(), true);
163 QCOMPARE(launcherModel->get(0)->pinned(), true);
163 QCOMPARE(launcherModel->get(1)->pinned(), false);
164 QCOMPARE(launcherModel->get(1)->pinned(), false);
165+ QCOMPARE(spy.count(), 1);
166+ QCOMPARE(spy.at(0).at(2).value<QVector<int>>().first(), (int)LauncherModelInterface::RolePinned);
167+
168+ launcherModel->requestRemove(launcherModel->get(0)->appId());
169+ QCOMPARE(launcherModel->get(0)->pinned(), false);
170+ QCOMPARE(launcherModel->get(1)->pinned(), false);
171+ QCOMPARE(spy.count(), 2);
172+ QCOMPARE(spy.at(1).at(2).value<QVector<int>>().first(), (int)LauncherModelInterface::RolePinned);
164 }
173 }
165
174
166 void testRemove_data() {
175 void testRemove_data() {