on xenial help sign in
split up LauncherDelegate into a reusable item and ListView specific folding parts to be able to reuse it for the fakeDragItem

Add folding animation to dropping items

commitbd09d7614b3234240860f41b5b4408e3e99543c0 authorMichael Zanetti <michael.zanetti@canonical.com> dateTue 23 Jul 2013, 13:44 (13 years ago) parentdb432c9
3 files changed+177−160
Launcher/LauncherDelegate.qml+14−119 Launcher/LauncherListDelegate.qml+132 Launcher/LauncherPanel.qml+31−41
Launcher/LauncherDelegate.qml+14−119
@@ -26,109 +26,22 @@ Item {
2626 property real maxAngle: 0
2727 property bool inverted: false
2828
29− readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * height
30− readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * height
31−
32− signal clicked()
33− signal longtap()
34− signal released()
29+ readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
30+ readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
3531
32+ property int itemWidth
33+ property int itemHeight
3634 // The angle used for rotating
37− property real angle: {
38− // First/last items are special
39− if (index == 0 || index == priv.listView.count-1) {
40− if (priv.distanceFromEdge < 0) {
41− // proportion equation: distanceFromTopEdge : angle = totalUnfoldedHeight/2 : maxAngle
42− return Math.max(-maxAngle, priv.distanceFromEdge * maxAngle / (priv.listView.foldingAreaHeight)) * priv.orientationFlag
43− }
44− return 0; // Don't fold first/last item as long as inside the view
45− }
46−
47− // Are we in the already completely outside the flickable? Fold for the last 5 degrees
48− if (priv.distanceFromEdge < 0) {
49− // proportion equation: -distanceFromTopEdge : angle = totalUnfoldedHeight : 5
50− return Math.max(-maxAngle, (priv.distanceFromEdge * 5 / priv.listView.foldingAreaHeight) - (maxAngle-5)) * priv.orientationFlag
51− }
52−
53− // We are overlapping with the folding area, fold the icon to maxAngle - 5 degrees
54− if (priv.overlapWithFoldingArea > 0) {
55− // proportion equation: overlap: totalHeight = angle : (maxAngle - 5)
56− return -priv.overlapWithFoldingArea * (maxAngle -5) / priv.listView.foldingAreaHeight * priv.orientationFlag;
57− }
58− return 0;
59− }
60−
35+ property real angle: 0
6136 // This is the offset that keeps the items inside the panel
62− property real offset: {
63− // First/last items are special
64− if (index == 0 || index == priv.listView.count-1) {
65− // Just keep them bound to the edges in case they're outside of the visible area
66− if (priv.distanceFromEdge < 0) {
67− return (-priv.distanceFromEdge - (height - effectiveHeight)) * priv.orientationFlag;
68− }
69− return 0;
70− }
71−
72− // Are we already completely outside the flickable? Stop the icon here.
73− if (priv.distanceFromEdge < -priv.totalUnfoldedHeight) {
74− return (-priv.distanceFromEdge - (root.height - effectiveHeight)) * priv.orientationFlag;
75− }
76−
77− // We're touching the edge, move slower than the actual flicking speed.
78− if (priv.distanceFromEdge < 0) {
79− return (Math.abs(priv.distanceFromEdge) * priv.totalEffectiveHeight / priv.totalUnfoldedHeight) * priv.orientationFlag
80− }
81− return 0;
82− }
83−
84− property real itemOpacity: {
85− // First/last items are special
86− if (index == 0 || index == priv.listView.count-1) {
87− if (priv.distanceFromEdge < 0) {
88− // Fade from 1 to 0 in the distance of 3 * foldingAreaHeight (which is when the next item reaches the edge)
89− return 1.0 - (-priv.distanceFromEdge / (priv.listView.foldingAreaHeight * 3))
90− }
91− return 1; // Don't make first/last item transparent as long as inside the view
92− }
93−
94− // Are we already completely outside the flickable? Fade from 0.75 to 0 in 2 items height
95− if (priv.distanceFromEdge < 0) {
96− // proportion equation: -distanceFromEdge : 1-opacity = totalUnfoldedHeight : 0.75
97− return 0.75 - (-priv.distanceFromEdge * 0.75 / (priv.totalUnfoldedHeight*2))
98− }
99−
100− // We are overlapping with the folding area, fade out to 0.75
101− if (priv.overlapWithFoldingArea > 0) {
102− // proportion equation: overlap : totalHeight = 1-opacity : 0.25
103− return 1 - (priv.overlapWithFoldingArea * 0.25 / priv.listView.foldingAreaHeight)
104− }
105− return 1;
106− }
107−
108− property real brightness: {
109− // First/last items are special
110− if (index == 0 || index == priv.listView.count-1) {
111− if (priv.distanceFromEdge < 0) {
112− return -(-priv.distanceFromEdge / (priv.listView.foldingAreaHeight * 3))
113− }
114− return 0;
115− }
116− // Are we already completely outside the flickable? Fade from 0.7 to 0 in 2 items height
117− if (priv.distanceFromEdge < 0) {
118− return -0.3 - (-priv.distanceFromEdge * 0.1 / (priv.totalUnfoldedHeight*2))
119− }
120−
121− // We are overlapping with the folding area, fade out to 0.7
122− if (priv.overlapWithFoldingArea > 0) {
123− return - (priv.overlapWithFoldingArea * 0.3 / priv.listView.foldingAreaHeight)
124− }
125− return 0;
126− }
37+ property real offset: 0
38+ property real itemOpacity: 1
39+ property real brightness: 0
12740
12841 Item {
12942 id: iconItem
130− width: parent.width
131− height: parent.height
43+ width: parent.itemWidth
44+ height: parent.itemHeight
13245 anchors.centerIn: parent
13346
13447 UbuntuShape {
@@ -150,8 +63,8 @@ Item {
15063 anchors.centerIn: iconItem
15164 rotation: inverted ? 180 : 0
15265 source: isSelected ? "graphics/selected.sci" : "graphics/non-selected.sci"
153− width: root.width + units.gu(0.5)
154− height: width
66+ width: root.itemWidth + units.gu(0.5)
67+ height: root.itemHeight + units.gu(0.5)
15568 property bool isSelected: root.highlighted
15669 onIsSelectedChanged: shaderEffectSource.scheduleUpdate();
15770 }
@@ -161,8 +74,8 @@ Item {
16174 id: transformEffect
16275 anchors.centerIn: parent
16376 anchors.verticalCenterOffset: root.offset
164− width: parent.width
165− height: parent.height
77+ width: parent.itemWidth
78+ height: parent.itemHeight
16679 property real itemOpacity: root.itemOpacity
16780 property real brightness: root.brightness
16881 property real angle: root.angle
@@ -219,22 +132,4 @@ Item {
219132 gl_FragColor = sourceColor;
220133 }"
221134 }
222−
223− QtObject {
224− id: priv
225−
226− property ListView listView: root.ListView.view
227− property real totalUnfoldedHeight: listView.itemSize + listView.spacing
228− property real totalEffectiveHeight: effectiveHeight + listView.spacing
229− property real effectiveContentY: listView.contentY - listView.originY
230− property real effectiveY: y - listView.originY
231− property real distanceFromTopEdge: -(effectiveContentY + listView.topMargin - index*totalUnfoldedHeight)
232− property real distanceFromBottomEdge: listView.height - listView.bottomMargin - (effectiveY+height) + effectiveContentY
233−
234− property real distanceFromEdge: Math.abs(distanceFromBottomEdge) < Math.abs(distanceFromTopEdge) ? distanceFromBottomEdge : distanceFromTopEdge
235− property real orientationFlag: Math.abs(distanceFromBottomEdge) < Math.abs(distanceFromTopEdge) ? -1 : 1
236−
237− property real overlapWithFoldingArea: listView.foldingAreaHeight - distanceFromEdge
238− }
239−
240135}
Launcher/LauncherListDelegate.qmlnew file+132
@@ -0,0 +1,132 @@
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.0
18+import Ubuntu.Components 0.1
19+
20+LauncherDelegate {
21+ id: root
22+
23+ // The angle used for rotating
24+ angle: {
25+ // First/last items are special
26+ if (index == 0 || index == priv.listView.count-1) {
27+ if (priv.distanceFromEdge < 0) {
28+ // proportion equation: distanceFromTopEdge : angle = totalUnfoldedHeight/2 : maxAngle
29+ return Math.max(-maxAngle, priv.distanceFromEdge * maxAngle / (priv.listView.foldingAreaHeight)) * priv.orientationFlag
30+ }
31+ return 0; // Don't fold first/last item as long as inside the view
32+ }
33+
34+ // Are we in the already completely outside the flickable? Fold for the last 5 degrees
35+ if (priv.distanceFromEdge < 0) {
36+ // proportion equation: -distanceFromTopEdge : angle = totalUnfoldedHeight : 5
37+ return Math.max(-maxAngle, (priv.distanceFromEdge * 5 / priv.listView.foldingAreaHeight) - (maxAngle-5)) * priv.orientationFlag
38+ }
39+
40+ // We are overlapping with the folding area, fold the icon to maxAngle - 5 degrees
41+ if (priv.overlapWithFoldingArea > 0) {
42+ // proportion equation: overlap: totalHeight = angle : (maxAngle - 5)
43+ return -priv.overlapWithFoldingArea * (maxAngle -5) / priv.listView.foldingAreaHeight * priv.orientationFlag;
44+ }
45+ return 0;
46+ }
47+
48+ // This is the offset that keeps the items inside the panel
49+ offset: {
50+ // First/last items are special
51+ if (index == 0 || index == priv.listView.count-1) {
52+ // Just keep them bound to the edges in case they're outside of the visible area
53+ if (priv.distanceFromEdge < 0) {
54+ return (-priv.distanceFromEdge - (height - effectiveHeight)) * priv.orientationFlag;
55+ }
56+ return 0;
57+ }
58+
59+ // Are we already completely outside the flickable? Stop the icon here.
60+ if (priv.distanceFromEdge < -priv.totalUnfoldedHeight) {
61+ return (-priv.distanceFromEdge - (root.height - effectiveHeight)) * priv.orientationFlag;
62+ }
63+
64+ // We're touching the edge, move slower than the actual flicking speed.
65+ if (priv.distanceFromEdge < 0) {
66+ return (Math.abs(priv.distanceFromEdge) * priv.totalEffectiveHeight / priv.totalUnfoldedHeight) * priv.orientationFlag
67+ }
68+ return 0;
69+ }
70+
71+ itemOpacity: {
72+ // First/last items are special
73+ if (index == 0 || index == priv.listView.count-1) {
74+ if (priv.distanceFromEdge < 0) {
75+ // Fade from 1 to 0 in the distance of 3 * foldingAreaHeight (which is when the next item reaches the edge)
76+ return 1.0 - (-priv.distanceFromEdge / (priv.listView.foldingAreaHeight * 3))
77+ }
78+ return 1; // Don't make first/last item transparent as long as inside the view
79+ }
80+
81+ // Are we already completely outside the flickable? Fade from 0.75 to 0 in 2 items height
82+ if (priv.distanceFromEdge < 0) {
83+ // proportion equation: -distanceFromEdge : 1-opacity = totalUnfoldedHeight : 0.75
84+ return 0.75 - (-priv.distanceFromEdge * 0.75 / (priv.totalUnfoldedHeight*2))
85+ }
86+
87+ // We are overlapping with the folding area, fade out to 0.75
88+ if (priv.overlapWithFoldingArea > 0) {
89+ // proportion equation: overlap : totalHeight = 1-opacity : 0.25
90+ return 1 - (priv.overlapWithFoldingArea * 0.25 / priv.listView.foldingAreaHeight)
91+ }
92+ return 1;
93+ }
94+
95+ brightness: {
96+ // First/last items are special
97+ if (index == 0 || index == priv.listView.count-1) {
98+ if (priv.distanceFromEdge < 0) {
99+ return -(-priv.distanceFromEdge / (priv.listView.foldingAreaHeight * 3))
100+ }
101+ return 0;
102+ }
103+ // Are we already completely outside the flickable? Fade from 0.7 to 0 in 2 items height
104+ if (priv.distanceFromEdge < 0) {
105+ return -0.3 - (-priv.distanceFromEdge * 0.1 / (priv.totalUnfoldedHeight*2))
106+ }
107+
108+ // We are overlapping with the folding area, fade out to 0.7
109+ if (priv.overlapWithFoldingArea > 0) {
110+ return - (priv.overlapWithFoldingArea * 0.3 / priv.listView.foldingAreaHeight)
111+ }
112+ return 0;
113+ }
114+
115+ QtObject {
116+ id: priv
117+
118+ property ListView listView: root.ListView.view
119+ property real totalUnfoldedHeight: listView.itemSize + listView.spacing
120+ property real totalEffectiveHeight: effectiveHeight + listView.spacing
121+ property real effectiveContentY: listView.contentY - listView.originY
122+ property real effectiveY: y - listView.originY
123+ property real distanceFromTopEdge: -(effectiveContentY + listView.topMargin - index*totalUnfoldedHeight)
124+ property real distanceFromBottomEdge: listView.height - listView.bottomMargin - (effectiveY+height) + effectiveContentY
125+
126+ property real distanceFromEdge: Math.abs(distanceFromBottomEdge) < Math.abs(distanceFromTopEdge) ? distanceFromBottomEdge : distanceFromTopEdge
127+ property real orientationFlag: Math.abs(distanceFromBottomEdge) < Math.abs(distanceFromTopEdge) ? -1 : 1
128+
129+ property real overlapWithFoldingArea: listView.foldingAreaHeight - distanceFromEdge
130+ }
131+
132+}
Launcher/LauncherPanel.qml+31−41
@@ -127,11 +127,14 @@ Item {
127127 NumberAnimation { properties: "x,y"; duration: 100 }
128128 }
129129
130− delegate: LauncherDelegate {
130+ delegate: LauncherListDelegate {
131131 id: launcherDelegate
132132 objectName: "launcherDelegate" + index
133− width: launcherListView.itemSize
134− height: dragging ? units.gu(2) : launcherListView.itemSize
133+ itemHeight: launcherListView.itemSize
134+ itemWidth: launcherListView.itemSize
135+ width: itemWidth
136+// height: dragging ? units.gu(2) : launcherListView.itemSize
137+ height: itemHeight
135138 iconName: model.icon
136139 inverted: root.inverted
137140 highlighted: dragging && index === root.highlightIndex
@@ -139,11 +142,27 @@ Item {
139142 maxAngle: 60
140143 property bool dragging: false
141144
142− Behavior on height {
143− NumberAnimation { duration: 200 }
144− }
145+ states: [
146+ State {
147+ name: "dragging"
148+ when: dragging
149+ PropertyChanges {
150+ target: launcherDelegate
151+ angle: 80
152+ offset: effectiveHeight / 2
153+ height: effectiveHeight
154+ }
155+ }
156+ ]
157+ transitions: [
158+ Transition {
159+ from: "*"
160+ to: "*"
161+ NumberAnimation { properties: "angle,offset,height"; duration: 200 }
162+ }
163+ ]
145164
146− onClicked: {
165+/* onClicked: {
147166 // First/last item do the scrolling at more than 12 degrees
148167 if (index == 0 || index == launcherListView.count -1) {
149168 if (angle > 12) {
@@ -165,6 +184,7 @@ Item {
165184 root.applicationSelected(LauncherModel.get(index).desktopFile);
166185 }
167186 }
187+ */
168188 }
169189
170190 MouseArea {
@@ -178,43 +198,13 @@ Item {
178198 property int startX
179199 property int startY
180200
181−
182−/* Item {
183− id: fakeDragItem
184− width: launcherListView.itemSize
185− height: launcherListView.itemSize
186− visible: dndArea.draggedIndex >= 0
187− property string iconName
188−
189− UbuntuShape {
190− id: iconShape
191− anchors.fill: parent
192− anchors.margins: units.gu(0.5)
193− radius: "medium"
194−
195− image: Image {
196− id: iconImage
197− sourceSize.width: iconShape.width
198− sourceSize.height: iconShape.height
199− source: "../graphics/applicationIcons/" + fakeDragItem.iconName + ".png"
200− }
201− }
202− BorderImage {
203− id: overlayHighlight
204− anchors.centerIn: fakeDragItem
205− rotation: inverted ? 180 : 0
206− source: isSelected ? "graphics/selected.sci" : "graphics/non-selected.sci"
207− width: fakeDragItem.width + units.gu(0.5)
208− height: width
209− }
210− }
211−*/
212201 LauncherDelegate {
213202 id: fakeDragItem
214203 visible: dndArea.draggedIndex >= 0
215− iconName: "gmail"
216− height: launcherListView.itemSize
217− width: height
204+ itemWidth: launcherListView.itemSize
205+ itemHeight: launcherListView.itemSize
206+ height: itemHeight
207+ width: itemWidth
218208 rotation: root.rotation
219209 }
220210