@@ -19,6 +19,7 @@ import Ubuntu.Components 1.3
19import Ubuntu.Components.ListItems 1.3 as ListItems
19import Ubuntu.Components.ListItems 1.3 as ListItems
20import Unity.Launcher 0.1
20import Unity.Launcher 0.1
21import Ubuntu.Components.Popups 1.3
21import Ubuntu.Components.Popups 1.3
22+import GlobalShortcut 1.0
22import "../Components/ListItems"
23import "../Components/ListItems"
23import "../Components/"
24import "../Components/"
@@ -33,7 +34,7 @@ Rectangle {
33 property bool dragging: false
34 property bool dragging: false
34 property bool moving: launcherListView.moving || launcherListView.flicking
35 property bool moving: launcherListView.moving || launcherListView.flicking
35 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || quickList.state === "open" || dndArea.pressed
36 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || quickList.state === "open" || dndArea.pressed
36− property int highlightIndex: -1
37+ property int highlightIndex: -2
38 signal applicationSelected(string appId)
39 signal applicationSelected(string appId)
39 signal showDashHome()
40 signal showDashHome()
@@ -44,6 +45,26 @@ Rectangle {
48+ function highlightNext() {
50+ if (highlightIndex >= launcherListView.count) {
53+ moveAnimation.moveToIndex(Math.max(highlightIndex, 0));
55+ function highlightPrevious() {
57+ if (highlightIndex <= -2) {
58+ highlightIndex = launcherListView.count - 1;
60+ moveAnimation.moveToIndex(Math.max(highlightIndex, 0));
62+ function openQuicklist(index) {
63+ quickList.open(index);
64+ quickList.selectedIndex = 0;
65+ quickList.focus = true;
48 id: mainColumn
69 id: mainColumn
@@ -172,6 +193,16 @@ Rectangle {
172 to = contentY;
193 to = contentY;
196+ function moveToIndex(index) {
197+ var itemPosition = index * launcherListView.itemHeight;
198+ var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
199+ var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : launcherListView.itemHeight
200+ if (itemPosition + launcherListView.itemHeight + distanceToEnd > launcherListView.contentY + launcherListView.topMargin + height) {
201+ moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd);
202+ } else if (itemPosition - distanceToEnd < launcherListView.contentY + launcherListView.topMargin) {
203+ moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin);
177 displaced: Transition {
208 displaced: Transition {
@@ -197,6 +228,7 @@ Rectangle {
197 itemFocused: model.focused
228 itemFocused: model.focused
198 inverted: root.inverted
229 inverted: root.inverted
199 alerting: model.alerting
230 alerting: model.alerting
231+ highlighted: root.highlightIndex == index
200 z: -Math.abs(offset)
232 z: -Math.abs(offset)
201 maxAngle: 55
233 maxAngle: 55
202 property bool dragging: false
234 property bool dragging: false
@@ -234,14 +266,7 @@ Rectangle {
234 onAlertingChanged: {
266 onAlertingChanged: {
235 if(alerting) {
267 if(alerting) {
236 if (!dragging && (launcherListView.peekingIndex === -1 || launcher.visibleWidth > 0)) {
268 if (!dragging && (launcherListView.peekingIndex === -1 || launcher.visibleWidth > 0)) {
237− var itemPosition = index * launcherListView.itemHeight;
269+ moveAnimation.moveToIndex(index)
238− var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
239− var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : launcherListView.itemHeight
240− if (itemPosition + launcherListView.itemHeight + distanceToEnd > launcherListView.contentY + launcherListView.topMargin + height) {
241− moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd);
242− } else if (itemPosition - distanceToEnd < launcherListView.contentY + launcherListView.topMargin) {
243− moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin);
245 if (!dragging && launcher.state !== "visible") {
270 if (!dragging && launcher.state !== "visible") {
246 peekingAnimation.start()
271 peekingAnimation.start()
@@ -392,10 +417,7 @@ Rectangle {
393 if (mouse.button & Qt.RightButton) { // context menu
418 if (mouse.button & Qt.RightButton) { // context menu
394 // Opening QuickList
419 // Opening QuickList
395− quickList.item = clickedItem;
420+ quickList.open(index);
396− quickList.model = launcherListView.model.get(index).quickList;
397− quickList.appId = launcherListView.model.get(index).appId;
398− quickList.state = "open";
@@ -465,11 +487,7 @@ Rectangle {
466 draggedIndex = Math.floor((mouseY + launcherListView.realContentY) / launcherListView.realItemHeight);
488 draggedIndex = Math.floor((mouseY + launcherListView.realContentY) / launcherListView.realItemHeight);
468− // Opening QuickList
469− quickList.item = selectedItem;
470− quickList.model = launcherListView.model.get(draggedIndex).quickList;
471− quickList.appId = launcherListView.model.get(draggedIndex).appId;
472− quickList.state = "open";
490+ quickList.open(draggedIndex)
474 launcherListView.interactive = false
492 launcherListView.interactive = false
@@ -647,12 +665,55 @@ Rectangle {
647 property var model
665 property var model
648 property string appId
666 property string appId
649 property var item
667 property var item
668+ property int selectedIndex: -1
671+ switch (event.key) {
674+ if (selectedIndex >= popoverRepeater.count) {
677+ event.accepted = true;
681+ if (selectedIndex < 0) {
682+ selectedIndex = popoverRepeater.count - 1;
684+ event.accepted = true;
688+ quickList.selectedIndex = -1;
689+ // Falling through intentionally
693+ if (quickList.selectedIndex >= 0) {
694+ LauncherModel.quickListActionInvoked(quickList.appId, quickList.selectedIndex)
696+ quickList.focus = false;
697+ quickList.state = ""
698+ // Don't consume the event. We want to close the Launcher too, not just the quicklist.
651 // internal
703 // internal
652 property int itemCenter: item ? root.mapFromItem(quickList.item).y + (item.height / 2) : units.gu(1)
704 property int itemCenter: item ? root.mapFromItem(quickList.item).y + (item.height / 2) : units.gu(1)
653 property int offset: itemCenter + (height/2) + units.gu(1) > parent.height ? -itemCenter - (height/2) - units.gu(1) + parent.height :
705 property int offset: itemCenter + (height/2) + units.gu(1) > parent.height ? -itemCenter - (height/2) - units.gu(1) + parent.height :
654 itemCenter - (height/2) < units.gu(1) ? (height/2) - itemCenter + units.gu(1) : 0
706 itemCenter - (height/2) < units.gu(1) ? (height/2) - itemCenter + units.gu(1) : 0
708+ function open(index) {
709+ var itemPosition = index * launcherListView.itemHeight;
710+ var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
711+ item = launcherListView.itemAt(launcherListView.width / 2, itemPosition + launcherListView.itemHeight / 2);
712+ quickList.model = launcherListView.model.get(index).quickList;
713+ quickList.appId = launcherListView.model.get(index).appId;
714+ quickList.state = "open";
657 id: quickListColumn
718 id: quickListColumn
658 width: parent.width
719 width: parent.width
@@ -666,6 +727,7 @@ Rectangle {
666 objectName: "quickListEntry" + index
727 objectName: "quickListEntry" + index
667 text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>")
728 text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>")
668 highlightWhenPressed: model.clickable
729 highlightWhenPressed: model.clickable
730+ selected: index === quickList.selectedIndex
670 // FIXME: This is a workaround for the theme not being context sensitive. I.e. the
732 // FIXME: This is a workaround for the theme not being context sensitive. I.e. the
671 // ListItems don't know that they are sitting in a themed Popover where the color
733 // ListItems don't know that they are sitting in a themed Popover where the color