Merge lp:~uriboni/unity-2d/launcher-shelf into lp:unity-2d/3.0

Proposed by Ugo Riboni
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
Reviewer Review Type Date Requested Status
Ugo Riboni (community) Approve
Florian Boucault (community) Approve
Review via email: mp+49863@code.launchpad.net

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.

To post a comment you must log in.
Revision history for this message
Ugo Riboni (uriboni) wrote :

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 LauncherContextualMenu::show() finds that the menu isVisible() is true even though there's no menu actually visible on screen.

Revision history for this message
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://code.launchpad.net/~osomon/unity-2d/dnd2/+merge/49782.

Revision history for this message
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://code.launchpad.net/~osomon/unity-2d/dnd2/+merge/49782.

Indeed though the conflicts will be easy to solve I believe. Now the question is, who will be first in? :)

Revision history for this message
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 */
            function dragEnterEvent(event) { item.onDragEnter(event) }
            function dropEvent(event) { item.onDrop(event) }

review: Needs Fixing
Revision history for this message
Florian Boucault (fboucault) wrote :

Very clean job. Good to go.

Please approve the MR once the conflict is resolved.

review: Approve
lp:~uriboni/unity-2d/launcher-shelf updated
393. By Ugo Riboni

Merge changes from trunk

Revision history for this message
Ugo Riboni (uriboni) wrote :

Fixed conflicts. Self-approving as requested.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'launcher/AutoScrollingListView.qml'
--- launcher/AutoScrollingListView.qml 2011-02-15 18:33:55 +0000
+++ launcher/AutoScrollingListView.qml 2011-02-18 13:38:21 +0000
@@ -84,6 +84,7 @@
84 Connections {84 Connections {
85 target: scrollZoneTop85 target: scrollZoneTop
86 onEntered: updateItemBelow(scrollZoneTop)86 onEntered: updateItemBelow(scrollZoneTop)
87 onExited: { if (itemBelow) itemBelow.exited(); itemBelow = null }
87 onPositionChanged: updateItemBelow(scrollZoneTop)88 onPositionChanged: updateItemBelow(scrollZoneTop)
88 onClicked: forwardClick(scrollZoneTop, mouse)89 onClicked: forwardClick(scrollZoneTop, mouse)
89 }90 }
@@ -91,6 +92,7 @@
91 Connections {92 Connections {
92 target: scrollZoneBottom93 target: scrollZoneBottom
93 onEntered: updateItemBelow(scrollZoneBottom)94 onEntered: updateItemBelow(scrollZoneBottom)
95 onExited: { if (itemBelow) itemBelow.exited(); itemBelow = null }
94 onPositionChanged: updateItemBelow(scrollZoneBottom)96 onPositionChanged: updateItemBelow(scrollZoneBottom)
95 onClicked: forwardClick(scrollZoneBottom, mouse)97 onClicked: forwardClick(scrollZoneBottom, mouse)
96 }98 }
9799
=== modified file 'launcher/Launcher.qml'
--- launcher/Launcher.qml 2011-02-16 16:12:23 +0000
+++ launcher/Launcher.qml 2011-02-18 13:38:21 +0000
@@ -13,129 +13,30 @@
13 source: "artwork/background.png"13 source: "artwork/background.png"
14 }14 }
1515
16 AutoScrollingListView {16 LauncherList {
17 id: list17 id: main
18 anchors.top: parent.top
19 anchors.bottom: shelf.top
20 width: parent.width
1821
19 spacing: 5
20 paddingTop: 522 paddingTop: 5
21 paddingBottom: 523 paddingBottom: 5
2224 autoScrollSize: tileSize / 2
23 anchors.fill: parent
24 focus: true
25 property int itemHeight: 54
26 autoScrollSize: itemHeight / 2
27 autoScrollVelocity: 20025 autoScrollVelocity: 200
2826
29 /* Keep a reference to the currently visible contextual menu */
30 property variant visibleMenu
31
32 model: ListAggregatorModel {27 model: ListAggregatorModel {
33 id: items28 id: items
34 }29 }
3530 }
36 delegate: LauncherItem {31
37 id: launcherItem32 LauncherList {
3833 id: shelf
39 width: launcher.width34 anchors.bottom: parent.bottom;
40 height: tileSize35 height: tileSize * count + spacing * Math.max(0, count - 1)
4136 width: parent.width
42 icon: "image://icons/" + item.icon37
43 running: item.running38 model: ListAggregatorModel {
44 active: item.active39 id: shelfItems
45 urgent: item.urgent
46 launching: item.launching
47 pips: Math.min(item.windowCount, 3)
48 tileSize: list.itemHeight
49
50 /* Best way I could find to check if the item is an application or the
51 workspaces switcher. There may be something cleaner and better. */
52 backgroundFromIcon: item.toString().indexOf("LauncherApplication") == 0 ||
53 item.toString().indexOf("Workspaces") == 0
54
55 Binding { target: item.menu; property: "title"; value: item.name }
56
57 /* Drag’n’drop handling */
58 function dragEnterEvent(event) { item.onDragEnter(event) }
59 function dropEvent(event) { item.onDrop(event) }
60
61 function showMenu() {
62 /* Prevent the simultaneous display of multiple menus */
63 if (list.visibleMenu != item.menu && list.visibleMenu != undefined) {
64 list.visibleMenu.hide()
65 }
66 list.visibleMenu = item.menu
67 // The extra 4 pixels are needed to center exactly with the arrow
68 // that indicated the active tile.
69 item.menu.show(width,
70 y + height / 2 - list.contentY +
71 panel.y - list.paddingTop + 4)
72 }
73
74 onClicked: {
75 if (mouse.button == Qt.LeftButton) {
76 item.menu.hide()
77 item.activate()
78 }
79 else if (mouse.button == Qt.RightButton) {
80 item.menu.folded = false
81 showMenu()
82 }
83 }
84
85 /* Display the tooltip when hovering the item only when the list
86 is not moving */
87 onEntered: if (!list.moving && !list.autoScrolling) showMenu()
88 onExited: {
89 /* When unfolded, leave enough time for the user to reach the
90 menu. Necessary because there is some void between the item
91 and the menu. Also it fixes the case when the user
92 overshoots. */
93 if (!item.menu.folded)
94 item.menu.hideWithDelay(400)
95 else
96 item.menu.hide()
97 }
98
99 Connections {
100 target: list
101 onMovementStarted: item.menu.hide()
102 onAutoScrollingChanged: if (list.autoScrolling) item.menu.hide()
103 }
104
105 function setIconGeometry() {
106 if (running) {
107 item.setIconGeometry(x + panel.x, y + panel.y, width, height)
108 }
109 }
110
111 ListView.onAdd: SequentialAnimation {
112 PropertyAction { target: launcherItem; property: "scale"; value: 0 }
113 NumberAnimation { target: launcherItem; property: "height";
114 from: 0; to: launcherItem.tileSize; duration: 250; easing.type: Easing.InOutQuad }
115 NumberAnimation { target: launcherItem; property: "scale"; to: 1; duration: 250; easing.type: Easing.InOutQuad }
116 }
117
118 ListView.onRemove: SequentialAnimation {
119 PropertyAction { target: launcherItem; property: "ListView.delayRemove"; value: true }
120 NumberAnimation { target: launcherItem; property: "scale"; to: 0; duration: 250; easing.type: Easing.InOutQuad }
121 NumberAnimation { target: launcherItem; property: "height"; to: 0; duration: 250; easing.type: Easing.InOutQuad }
122 PropertyAction { target: launcherItem; property: "ListView.delayRemove"; value: false }
123 }
124
125 onRunningChanged: setIconGeometry()
126 /* Note: this doesn’t work as expected for the first favorite
127 application in the list if it is already running when the
128 launcher is started, because its y property doesn’t change.
129 This isn’t too bad though, as the launcher is supposed to be
130 started before any other regular application. */
131 onYChanged: setIconGeometry()
132
133 Connections {
134 target: item
135 onWindowAdded: item.setIconGeometry(x + panel.x, y + panel.y, width, height, xid)
136 /* Not all items are applications. */
137 ignoreUnknownSignals: true
138 }
139 }40 }
140 }41 }
14142
@@ -151,20 +52,20 @@
151 id: devices52 id: devices
152 }53 }
15354
55 WorkspacesList {
56 id: workspaces
57 }
58
154 Trashes {59 Trashes {
155 id: trashes60 id: trashes
156 }61 }
15762
158 WorkspacesList {
159 id: workspaces
160 }
161
162 Component.onCompleted: {63 Component.onCompleted: {
163 items.appendModel(applications);64 items.appendModel(applications);
164 items.appendModel(workspaces);65 items.appendModel(workspaces);
165 items.appendModel(places);66 items.appendModel(places);
166 items.appendModel(devices);67 items.appendModel(devices);
167 items.appendModel(trashes);68 shelfItems.appendModel(trashes);
168 }69 }
16970
170 Connections {71 Connections {
17172
=== modified file 'launcher/LauncherItem.qml'
--- launcher/LauncherItem.qml 2011-02-16 11:11:46 +0000
+++ launcher/LauncherItem.qml 2011-02-18 13:38:21 +0000
@@ -34,6 +34,7 @@
34 objectName: "launcherItem"34 objectName: "launcherItem"
3535
36 anchors.horizontalCenter: parent.horizontalCenter36 anchors.horizontalCenter: parent.horizontalCenter
37 height: tileSize
3738
38 property int tileSize39 property int tileSize
39 property alias icon: icon.source40 property alias icon: icon.source
@@ -108,7 +109,7 @@
108 id: tile109 id: tile
109 anchors.centerIn: parent110 anchors.centerIn: parent
110 width: item.tileSize111 width: item.tileSize
111 height: parent.height112 height: item.height
112113
113 /* This is the image providing the background image. The114 /* This is the image providing the background image. The
114 color blended with this image is obtained from the color of the icon when it's115 color blended with this image is obtained from the color of the icon when it's
115116
=== added file 'launcher/LauncherList.qml'
--- launcher/LauncherList.qml 1970-01-01 00:00:00 +0000
+++ launcher/LauncherList.qml 2011-02-18 13:38:21 +0000
@@ -0,0 +1,117 @@
1import Qt 4.7
2import UnityApplications 1.0
3import Unity2d 1.0 /* required for drag’n’drop handling */
4
5AutoScrollingListView {
6 id: list
7 spacing: 5
8 property int tileSize: 54
9
10 /* Keep a reference to the currently visible contextual menu */
11 property variant visibleMenu
12
13 delegate: LauncherItem {
14 id: launcherItem
15
16 width: list.width
17 tileSize: list.tileSize
18
19 icon: "image://icons/" + item.icon
20 running: item.running
21 active: item.active
22 urgent: item.urgent
23 launching: item.launching
24 pips: Math.min(item.windowCount, 3)
25
26 /* Best way I could find to check if the item is an application or the
27 workspaces switcher. There may be something cleaner and better. */
28 backgroundFromIcon: item.toString().indexOf("LauncherApplication") == 0 ||
29 item.toString().indexOf("Workspaces") == 0
30
31 Binding { target: item.menu; property: "title"; value: item.name }
32
33 /* Drag’n’drop handling */
34 function dragEnterEvent(event) { item.onDragEnter(event) }
35 function dropEvent(event) { item.onDrop(event) }
36
37 function showMenu() {
38 /* Prevent the simultaneous display of multiple menus */
39 if (list.visibleMenu != item.menu && list.visibleMenu != undefined) {
40 list.visibleMenu.hide()
41 }
42 list.visibleMenu = item.menu
43 // The extra 4 pixels are needed to center exactly with the arrow
44 // indicating the active tile.
45 item.menu.show(width, panel.y + list.y +
46 y + height / 2 - list.contentY
47 - list.paddingTop + 4)
48
49 }
50
51 onClicked: {
52 if (mouse.button == Qt.LeftButton) {
53 item.menu.hide()
54 item.activate()
55 }
56 else if (mouse.button == Qt.RightButton) {
57 item.menu.folded = false
58 showMenu()
59 }
60 }
61
62 /* Display the tooltip when hovering the item only when the list
63 is not moving */
64 onEntered: if (!list.moving && !list.autoScrolling) showMenu()
65 onExited: {
66 /* When unfolded, leave enough time for the user to reach the
67 menu. Necessary because there is some void between the item
68 and the menu. Also it fixes the case when the user
69 overshoots. */
70 if (!item.menu.folded)
71 item.menu.hideWithDelay(400)
72 else
73 item.menu.hide()
74 }
75
76 Connections {
77 target: list
78 onMovementStarted: item.menu.hide()
79 onAutoScrollingChanged: if (list.autoScrolling) item.menu.hide()
80 }
81
82 function setIconGeometry() {
83 if (running) {
84 item.setIconGeometry(x + panel.x, y + panel.y, width, height)
85 }
86 }
87
88 ListView.onAdd: SequentialAnimation {
89 PropertyAction { target: launcherItem; property: "scale"; value: 0 }
90 NumberAnimation { target: launcherItem; property: "height";
91 from: 0; to: launcherItem.tileSize; duration: 250; easing.type: Easing.InOutQuad }
92 NumberAnimation { target: launcherItem; property: "scale"; to: 1; duration: 250; easing.type: Easing.InOutQuad }
93 }
94
95 ListView.onRemove: SequentialAnimation {
96 PropertyAction { target: launcherItem; property: "ListView.delayRemove"; value: true }
97 NumberAnimation { target: launcherItem; property: "scale"; to: 0; duration: 250; easing.type: Easing.InOutQuad }
98 NumberAnimation { target: launcherItem; property: "height"; to: 0; duration: 250; easing.type: Easing.InOutQuad }
99 PropertyAction { target: launcherItem; property: "ListView.delayRemove"; value: false }
100 }
101
102 onRunningChanged: setIconGeometry()
103 /* Note: this doesn’t work as expected for the first favorite
104 application in the list if it is already running when the
105 launcher is started, because its y property doesn’t change.
106 This isn’t too bad though, as the launcher is supposed to be
107 started before any other regular application. */
108 onYChanged: setIconGeometry()
109
110 Connections {
111 target: item
112 onWindowAdded: item.setIconGeometry(x + panel.x, y + panel.y, width, height, xid)
113 /* Not all items are applications. */
114 ignoreUnknownSignals: true
115 }
116 }
117}

Subscribers

People subscribed via source and target branches

to all changes: