Merge lp:~uriboni/unity-2d/launcher-shelf into lp:unity-2d/3.0
- launcher-shelf
- Merge into natty
Status: | Merged |
---|---|
Approved by: | Ugo Riboni |
Approved revision: | 393 |
Merged at revision: | 393 |
Proposed branch: | lp:~uriboni/unity-2d/launcher-shelf |
Merge into: | lp:unity-2d/3.0 |
Diff against target: |
338 lines (+142/-121) 4 files modified
launcher/AutoScrollingListView.qml (+2/-0) launcher/Launcher.qml (+21/-120) launcher/LauncherItem.qml (+2/-1) launcher/LauncherList.qml (+117/-0) |
To merge this branch: | bzr merge lp:~uriboni/unity-2d/launcher-shelf |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ugo Riboni (community) | Approve | ||
Florian Boucault (community) | Approve | ||
Review via email: mp+49863@code.launchpad.net |
Commit message
Description of the change
[launcher] New "shelf" area at the bottom of the launcher, which is essentially a second list of items which stays fixed in place and is always as tall as all the items it contains. For now it only contain the trash.
Ugo Riboni (uriboni) wrote : | # |
Olivier Tilloy (osomon) wrote : | # |
This may also be of interest to the reviewer(s): I haven’t looked at the code, but from the description of the changes, this branch very likely breaks and/or conflicts with the changes this other merge request: https:/
Florian Boucault (fboucault) wrote : | # |
> This may also be of interest to the reviewer(s): I haven’t looked at the code,
> but from the description of the changes, this branch very likely breaks and/or
> conflicts with the changes this other merge request:
> https:/
Indeed though the conflicts will be easy to solve I believe. Now the question is, who will be first in? :)
Florian Boucault (fboucault) wrote : | # |
There is a conflict in Launcher.qml introduced by revision 391. I believe it's resolved by:
- keeping the code from the launcher-shelf branch
- adding the 3 lines of code introduced by revision 391:
/* Drag’n’drop handling */
Florian Boucault (fboucault) wrote : | # |
Very clean job. Good to go.
Please approve the MR once the conflict is resolved.
- 393. By Ugo Riboni
-
Merge changes from trunk
Ugo Riboni (uriboni) wrote : | # |
Fixed conflicts. Self-approving as requested.
Preview Diff
1 | === modified file 'launcher/AutoScrollingListView.qml' | |||
2 | --- launcher/AutoScrollingListView.qml 2011-02-15 18:33:55 +0000 | |||
3 | +++ launcher/AutoScrollingListView.qml 2011-02-18 13:38:21 +0000 | |||
4 | @@ -84,6 +84,7 @@ | |||
5 | 84 | Connections { | 84 | Connections { |
6 | 85 | target: scrollZoneTop | 85 | target: scrollZoneTop |
7 | 86 | onEntered: updateItemBelow(scrollZoneTop) | 86 | onEntered: updateItemBelow(scrollZoneTop) |
8 | 87 | onExited: { if (itemBelow) itemBelow.exited(); itemBelow = null } | ||
9 | 87 | onPositionChanged: updateItemBelow(scrollZoneTop) | 88 | onPositionChanged: updateItemBelow(scrollZoneTop) |
10 | 88 | onClicked: forwardClick(scrollZoneTop, mouse) | 89 | onClicked: forwardClick(scrollZoneTop, mouse) |
11 | 89 | } | 90 | } |
12 | @@ -91,6 +92,7 @@ | |||
13 | 91 | Connections { | 92 | Connections { |
14 | 92 | target: scrollZoneBottom | 93 | target: scrollZoneBottom |
15 | 93 | onEntered: updateItemBelow(scrollZoneBottom) | 94 | onEntered: updateItemBelow(scrollZoneBottom) |
16 | 95 | onExited: { if (itemBelow) itemBelow.exited(); itemBelow = null } | ||
17 | 94 | onPositionChanged: updateItemBelow(scrollZoneBottom) | 96 | onPositionChanged: updateItemBelow(scrollZoneBottom) |
18 | 95 | onClicked: forwardClick(scrollZoneBottom, mouse) | 97 | onClicked: forwardClick(scrollZoneBottom, mouse) |
19 | 96 | } | 98 | } |
20 | 97 | 99 | ||
21 | === modified file 'launcher/Launcher.qml' | |||
22 | --- launcher/Launcher.qml 2011-02-16 16:12:23 +0000 | |||
23 | +++ launcher/Launcher.qml 2011-02-18 13:38:21 +0000 | |||
24 | @@ -13,129 +13,30 @@ | |||
25 | 13 | source: "artwork/background.png" | 13 | source: "artwork/background.png" |
26 | 14 | } | 14 | } |
27 | 15 | 15 | ||
30 | 16 | AutoScrollingListView { | 16 | LauncherList { |
31 | 17 | id: list | 17 | id: main |
32 | 18 | anchors.top: parent.top | ||
33 | 19 | anchors.bottom: shelf.top | ||
34 | 20 | width: parent.width | ||
35 | 18 | 21 | ||
36 | 19 | spacing: 5 | ||
37 | 20 | paddingTop: 5 | 22 | paddingTop: 5 |
38 | 21 | paddingBottom: 5 | 23 | paddingBottom: 5 |
44 | 22 | 24 | autoScrollSize: tileSize / 2 | |
40 | 23 | anchors.fill: parent | ||
41 | 24 | focus: true | ||
42 | 25 | property int itemHeight: 54 | ||
43 | 26 | autoScrollSize: itemHeight / 2 | ||
45 | 27 | autoScrollVelocity: 200 | 25 | autoScrollVelocity: 200 |
46 | 28 | 26 | ||
47 | 29 | /* Keep a reference to the currently visible contextual menu */ | ||
48 | 30 | property variant visibleMenu | ||
49 | 31 | |||
50 | 32 | model: ListAggregatorModel { | 27 | model: ListAggregatorModel { |
51 | 33 | id: items | 28 | id: items |
52 | 34 | } | 29 | } |
157 | 35 | 30 | } | |
158 | 36 | delegate: LauncherItem { | 31 | |
159 | 37 | id: launcherItem | 32 | LauncherList { |
160 | 38 | 33 | id: shelf | |
161 | 39 | width: launcher.width | 34 | anchors.bottom: parent.bottom; |
162 | 40 | height: tileSize | 35 | height: tileSize * count + spacing * Math.max(0, count - 1) |
163 | 41 | 36 | width: parent.width | |
164 | 42 | icon: "image://icons/" + item.icon | 37 | |
165 | 43 | running: item.running | 38 | model: ListAggregatorModel { |
166 | 44 | active: item.active | 39 | id: shelfItems |
63 | 45 | urgent: item.urgent | ||
64 | 46 | launching: item.launching | ||
65 | 47 | pips: Math.min(item.windowCount, 3) | ||
66 | 48 | tileSize: list.itemHeight | ||
67 | 49 | |||
68 | 50 | /* Best way I could find to check if the item is an application or the | ||
69 | 51 | workspaces switcher. There may be something cleaner and better. */ | ||
70 | 52 | backgroundFromIcon: item.toString().indexOf("LauncherApplication") == 0 || | ||
71 | 53 | item.toString().indexOf("Workspaces") == 0 | ||
72 | 54 | |||
73 | 55 | Binding { target: item.menu; property: "title"; value: item.name } | ||
74 | 56 | |||
75 | 57 | /* Drag’n’drop handling */ | ||
76 | 58 | function dragEnterEvent(event) { item.onDragEnter(event) } | ||
77 | 59 | function dropEvent(event) { item.onDrop(event) } | ||
78 | 60 | |||
79 | 61 | function showMenu() { | ||
80 | 62 | /* Prevent the simultaneous display of multiple menus */ | ||
81 | 63 | if (list.visibleMenu != item.menu && list.visibleMenu != undefined) { | ||
82 | 64 | list.visibleMenu.hide() | ||
83 | 65 | } | ||
84 | 66 | list.visibleMenu = item.menu | ||
85 | 67 | // The extra 4 pixels are needed to center exactly with the arrow | ||
86 | 68 | // that indicated the active tile. | ||
87 | 69 | item.menu.show(width, | ||
88 | 70 | y + height / 2 - list.contentY + | ||
89 | 71 | panel.y - list.paddingTop + 4) | ||
90 | 72 | } | ||
91 | 73 | |||
92 | 74 | onClicked: { | ||
93 | 75 | if (mouse.button == Qt.LeftButton) { | ||
94 | 76 | item.menu.hide() | ||
95 | 77 | item.activate() | ||
96 | 78 | } | ||
97 | 79 | else if (mouse.button == Qt.RightButton) { | ||
98 | 80 | item.menu.folded = false | ||
99 | 81 | showMenu() | ||
100 | 82 | } | ||
101 | 83 | } | ||
102 | 84 | |||
103 | 85 | /* Display the tooltip when hovering the item only when the list | ||
104 | 86 | is not moving */ | ||
105 | 87 | onEntered: if (!list.moving && !list.autoScrolling) showMenu() | ||
106 | 88 | onExited: { | ||
107 | 89 | /* When unfolded, leave enough time for the user to reach the | ||
108 | 90 | menu. Necessary because there is some void between the item | ||
109 | 91 | and the menu. Also it fixes the case when the user | ||
110 | 92 | overshoots. */ | ||
111 | 93 | if (!item.menu.folded) | ||
112 | 94 | item.menu.hideWithDelay(400) | ||
113 | 95 | else | ||
114 | 96 | item.menu.hide() | ||
115 | 97 | } | ||
116 | 98 | |||
117 | 99 | Connections { | ||
118 | 100 | target: list | ||
119 | 101 | onMovementStarted: item.menu.hide() | ||
120 | 102 | onAutoScrollingChanged: if (list.autoScrolling) item.menu.hide() | ||
121 | 103 | } | ||
122 | 104 | |||
123 | 105 | function setIconGeometry() { | ||
124 | 106 | if (running) { | ||
125 | 107 | item.setIconGeometry(x + panel.x, y + panel.y, width, height) | ||
126 | 108 | } | ||
127 | 109 | } | ||
128 | 110 | |||
129 | 111 | ListView.onAdd: SequentialAnimation { | ||
130 | 112 | PropertyAction { target: launcherItem; property: "scale"; value: 0 } | ||
131 | 113 | NumberAnimation { target: launcherItem; property: "height"; | ||
132 | 114 | from: 0; to: launcherItem.tileSize; duration: 250; easing.type: Easing.InOutQuad } | ||
133 | 115 | NumberAnimation { target: launcherItem; property: "scale"; to: 1; duration: 250; easing.type: Easing.InOutQuad } | ||
134 | 116 | } | ||
135 | 117 | |||
136 | 118 | ListView.onRemove: SequentialAnimation { | ||
137 | 119 | PropertyAction { target: launcherItem; property: "ListView.delayRemove"; value: true } | ||
138 | 120 | NumberAnimation { target: launcherItem; property: "scale"; to: 0; duration: 250; easing.type: Easing.InOutQuad } | ||
139 | 121 | NumberAnimation { target: launcherItem; property: "height"; to: 0; duration: 250; easing.type: Easing.InOutQuad } | ||
140 | 122 | PropertyAction { target: launcherItem; property: "ListView.delayRemove"; value: false } | ||
141 | 123 | } | ||
142 | 124 | |||
143 | 125 | onRunningChanged: setIconGeometry() | ||
144 | 126 | /* Note: this doesn’t work as expected for the first favorite | ||
145 | 127 | application in the list if it is already running when the | ||
146 | 128 | launcher is started, because its y property doesn’t change. | ||
147 | 129 | This isn’t too bad though, as the launcher is supposed to be | ||
148 | 130 | started before any other regular application. */ | ||
149 | 131 | onYChanged: setIconGeometry() | ||
150 | 132 | |||
151 | 133 | Connections { | ||
152 | 134 | target: item | ||
153 | 135 | onWindowAdded: item.setIconGeometry(x + panel.x, y + panel.y, width, height, xid) | ||
154 | 136 | /* Not all items are applications. */ | ||
155 | 137 | ignoreUnknownSignals: true | ||
156 | 138 | } | ||
167 | 139 | } | 40 | } |
168 | 140 | } | 41 | } |
169 | 141 | 42 | ||
170 | @@ -151,20 +52,20 @@ | |||
171 | 151 | id: devices | 52 | id: devices |
172 | 152 | } | 53 | } |
173 | 153 | 54 | ||
174 | 55 | WorkspacesList { | ||
175 | 56 | id: workspaces | ||
176 | 57 | } | ||
177 | 58 | |||
178 | 154 | Trashes { | 59 | Trashes { |
179 | 155 | id: trashes | 60 | id: trashes |
180 | 156 | } | 61 | } |
181 | 157 | 62 | ||
182 | 158 | WorkspacesList { | ||
183 | 159 | id: workspaces | ||
184 | 160 | } | ||
185 | 161 | |||
186 | 162 | Component.onCompleted: { | 63 | Component.onCompleted: { |
187 | 163 | items.appendModel(applications); | 64 | items.appendModel(applications); |
188 | 164 | items.appendModel(workspaces); | 65 | items.appendModel(workspaces); |
189 | 165 | items.appendModel(places); | 66 | items.appendModel(places); |
190 | 166 | items.appendModel(devices); | 67 | items.appendModel(devices); |
192 | 167 | items.appendModel(trashes); | 68 | shelfItems.appendModel(trashes); |
193 | 168 | } | 69 | } |
194 | 169 | 70 | ||
195 | 170 | Connections { | 71 | Connections { |
196 | 171 | 72 | ||
197 | === modified file 'launcher/LauncherItem.qml' | |||
198 | --- launcher/LauncherItem.qml 2011-02-16 11:11:46 +0000 | |||
199 | +++ launcher/LauncherItem.qml 2011-02-18 13:38:21 +0000 | |||
200 | @@ -34,6 +34,7 @@ | |||
201 | 34 | objectName: "launcherItem" | 34 | objectName: "launcherItem" |
202 | 35 | 35 | ||
203 | 36 | anchors.horizontalCenter: parent.horizontalCenter | 36 | anchors.horizontalCenter: parent.horizontalCenter |
204 | 37 | height: tileSize | ||
205 | 37 | 38 | ||
206 | 38 | property int tileSize | 39 | property int tileSize |
207 | 39 | property alias icon: icon.source | 40 | property alias icon: icon.source |
208 | @@ -108,7 +109,7 @@ | |||
209 | 108 | id: tile | 109 | id: tile |
210 | 109 | anchors.centerIn: parent | 110 | anchors.centerIn: parent |
211 | 110 | width: item.tileSize | 111 | width: item.tileSize |
213 | 111 | height: parent.height | 112 | height: item.height |
214 | 112 | 113 | ||
215 | 113 | /* This is the image providing the background image. The | 114 | /* This is the image providing the background image. The |
216 | 114 | color blended with this image is obtained from the color of the icon when it's | 115 | color blended with this image is obtained from the color of the icon when it's |
217 | 115 | 116 | ||
218 | === added file 'launcher/LauncherList.qml' | |||
219 | --- launcher/LauncherList.qml 1970-01-01 00:00:00 +0000 | |||
220 | +++ launcher/LauncherList.qml 2011-02-18 13:38:21 +0000 | |||
221 | @@ -0,0 +1,117 @@ | |||
222 | 1 | import Qt 4.7 | ||
223 | 2 | import UnityApplications 1.0 | ||
224 | 3 | import Unity2d 1.0 /* required for drag’n’drop handling */ | ||
225 | 4 | |||
226 | 5 | AutoScrollingListView { | ||
227 | 6 | id: list | ||
228 | 7 | spacing: 5 | ||
229 | 8 | property int tileSize: 54 | ||
230 | 9 | |||
231 | 10 | /* Keep a reference to the currently visible contextual menu */ | ||
232 | 11 | property variant visibleMenu | ||
233 | 12 | |||
234 | 13 | delegate: LauncherItem { | ||
235 | 14 | id: launcherItem | ||
236 | 15 | |||
237 | 16 | width: list.width | ||
238 | 17 | tileSize: list.tileSize | ||
239 | 18 | |||
240 | 19 | icon: "image://icons/" + item.icon | ||
241 | 20 | running: item.running | ||
242 | 21 | active: item.active | ||
243 | 22 | urgent: item.urgent | ||
244 | 23 | launching: item.launching | ||
245 | 24 | pips: Math.min(item.windowCount, 3) | ||
246 | 25 | |||
247 | 26 | /* Best way I could find to check if the item is an application or the | ||
248 | 27 | workspaces switcher. There may be something cleaner and better. */ | ||
249 | 28 | backgroundFromIcon: item.toString().indexOf("LauncherApplication") == 0 || | ||
250 | 29 | item.toString().indexOf("Workspaces") == 0 | ||
251 | 30 | |||
252 | 31 | Binding { target: item.menu; property: "title"; value: item.name } | ||
253 | 32 | |||
254 | 33 | /* Drag’n’drop handling */ | ||
255 | 34 | function dragEnterEvent(event) { item.onDragEnter(event) } | ||
256 | 35 | function dropEvent(event) { item.onDrop(event) } | ||
257 | 36 | |||
258 | 37 | function showMenu() { | ||
259 | 38 | /* Prevent the simultaneous display of multiple menus */ | ||
260 | 39 | if (list.visibleMenu != item.menu && list.visibleMenu != undefined) { | ||
261 | 40 | list.visibleMenu.hide() | ||
262 | 41 | } | ||
263 | 42 | list.visibleMenu = item.menu | ||
264 | 43 | // The extra 4 pixels are needed to center exactly with the arrow | ||
265 | 44 | // indicating the active tile. | ||
266 | 45 | item.menu.show(width, panel.y + list.y + | ||
267 | 46 | y + height / 2 - list.contentY | ||
268 | 47 | - list.paddingTop + 4) | ||
269 | 48 | |||
270 | 49 | } | ||
271 | 50 | |||
272 | 51 | onClicked: { | ||
273 | 52 | if (mouse.button == Qt.LeftButton) { | ||
274 | 53 | item.menu.hide() | ||
275 | 54 | item.activate() | ||
276 | 55 | } | ||
277 | 56 | else if (mouse.button == Qt.RightButton) { | ||
278 | 57 | item.menu.folded = false | ||
279 | 58 | showMenu() | ||
280 | 59 | } | ||
281 | 60 | } | ||
282 | 61 | |||
283 | 62 | /* Display the tooltip when hovering the item only when the list | ||
284 | 63 | is not moving */ | ||
285 | 64 | onEntered: if (!list.moving && !list.autoScrolling) showMenu() | ||
286 | 65 | onExited: { | ||
287 | 66 | /* When unfolded, leave enough time for the user to reach the | ||
288 | 67 | menu. Necessary because there is some void between the item | ||
289 | 68 | and the menu. Also it fixes the case when the user | ||
290 | 69 | overshoots. */ | ||
291 | 70 | if (!item.menu.folded) | ||
292 | 71 | item.menu.hideWithDelay(400) | ||
293 | 72 | else | ||
294 | 73 | item.menu.hide() | ||
295 | 74 | } | ||
296 | 75 | |||
297 | 76 | Connections { | ||
298 | 77 | target: list | ||
299 | 78 | onMovementStarted: item.menu.hide() | ||
300 | 79 | onAutoScrollingChanged: if (list.autoScrolling) item.menu.hide() | ||
301 | 80 | } | ||
302 | 81 | |||
303 | 82 | function setIconGeometry() { | ||
304 | 83 | if (running) { | ||
305 | 84 | item.setIconGeometry(x + panel.x, y + panel.y, width, height) | ||
306 | 85 | } | ||
307 | 86 | } | ||
308 | 87 | |||
309 | 88 | ListView.onAdd: SequentialAnimation { | ||
310 | 89 | PropertyAction { target: launcherItem; property: "scale"; value: 0 } | ||
311 | 90 | NumberAnimation { target: launcherItem; property: "height"; | ||
312 | 91 | from: 0; to: launcherItem.tileSize; duration: 250; easing.type: Easing.InOutQuad } | ||
313 | 92 | NumberAnimation { target: launcherItem; property: "scale"; to: 1; duration: 250; easing.type: Easing.InOutQuad } | ||
314 | 93 | } | ||
315 | 94 | |||
316 | 95 | ListView.onRemove: SequentialAnimation { | ||
317 | 96 | PropertyAction { target: launcherItem; property: "ListView.delayRemove"; value: true } | ||
318 | 97 | NumberAnimation { target: launcherItem; property: "scale"; to: 0; duration: 250; easing.type: Easing.InOutQuad } | ||
319 | 98 | NumberAnimation { target: launcherItem; property: "height"; to: 0; duration: 250; easing.type: Easing.InOutQuad } | ||
320 | 99 | PropertyAction { target: launcherItem; property: "ListView.delayRemove"; value: false } | ||
321 | 100 | } | ||
322 | 101 | |||
323 | 102 | onRunningChanged: setIconGeometry() | ||
324 | 103 | /* Note: this doesn’t work as expected for the first favorite | ||
325 | 104 | application in the list if it is already running when the | ||
326 | 105 | launcher is started, because its y property doesn’t change. | ||
327 | 106 | This isn’t too bad though, as the launcher is supposed to be | ||
328 | 107 | started before any other regular application. */ | ||
329 | 108 | onYChanged: setIconGeometry() | ||
330 | 109 | |||
331 | 110 | Connections { | ||
332 | 111 | target: item | ||
333 | 112 | onWindowAdded: item.setIconGeometry(x + panel.x, y + panel.y, width, height, xid) | ||
334 | 113 | /* Not all items are applications. */ | ||
335 | 114 | ignoreUnknownSignals: true | ||
336 | 115 | } | ||
337 | 116 | } | ||
338 | 117 | } |
Please note that is one issue that I have not been able to solve.
In some cases (which i can't repro consistently) the menu for some items stop to appear on mouse over.
The items are always those close to the bottom of the normal list or the item in the shelf (i.e. trash).
The way I seem to get this issue the most often is when i very quickly move the mouse up and down over the seam between the launcher and shelf, making sure to go in and out of the bottom autoscroll area of the main list in both directions.
Then going over these items will consistently stop showing a menu.
The menu doesn't show because of the check for isVisible() in LauncherContext ualMenu: :show() finds that the menu isVisible() is true even though there's no menu actually visible on screen.