on xenial help sign in
Allow dragging launcher items with the quicklist open
2416f5fAlbert Astals Cid
qml/Launcher/LauncherPanel.qml+54−18
@@ -384,7 +384,11 @@ Rectangle {
384 property int startY
384 property int startY
385
385
386 onPressed: {
386 onPressed: {
387+ processPress(mouse);
388+ }
389+
390+ function processPress(mouse) {
387− selectedItem = launcherListView.itemAt(mouseX, mouseY + launcherListView.realContentY)
391+ selectedItem = launcherListView.itemAt(mouse.x, mouse.y + launcherListView.realContentY)
388 }
392 }
389
393
390 onClicked: {
394 onClicked: {
@@ -429,14 +433,14 @@ Rectangle {
429 }
433 }
430
434
431 onCanceled: {
435 onCanceled: {
432− endDrag();
436+ endDrag(drag);
433 }
437 }
434
438
435 onReleased: {
439 onReleased: {
436− endDrag();
440+ endDrag(drag);
437 }
441 }
438
442
439− function endDrag() {
443+ function endDrag(dragItem) {
440 var droppedIndex = draggedIndex;
444 var droppedIndex = draggedIndex;
441 if (dragging) {
445 if (dragging) {
442 postDragging = true;
446 postDragging = true;
@@ -452,7 +456,7 @@ Rectangle {
452 selectedItem = undefined;
456 selectedItem = undefined;
453 preDragging = false;
457 preDragging = false;
454
458
455− drag.target = undefined
459+ dragItem.target = undefined
456
460
457 progressiveScrollingTimer.stop();
461 progressiveScrollingTimer.stop();
458 launcherListView.interactive = true;
462 launcherListView.interactive = true;
@@ -464,13 +468,17 @@ Rectangle {
464 }
468 }
465
469
466 onPressAndHold: {
470 onPressAndHold: {
471+ processPressAndHold(mouse, drag);
472+ }
473+
474+ function processPressAndHold(mouse, dragItem) {
467 if (Math.abs(selectedItem.angle) > 30) {
475 if (Math.abs(selectedItem.angle) > 30) {
468 return;
476 return;
469 }
477 }
470
478
471 Haptics.play();
479 Haptics.play();
472
480
473− draggedIndex = Math.floor((mouseY + launcherListView.realContentY) / launcherListView.realItemHeight);
481+ draggedIndex = Math.floor((mouse.y + launcherListView.realContentY) / launcherListView.realItemHeight);
474
482
475 // Opening QuickList
483 // Opening QuickList
476 quickList.item = selectedItem;
484 quickList.item = selectedItem;
@@ -480,26 +488,30 @@ Rectangle {
480
488
481 launcherListView.interactive = false
489 launcherListView.interactive = false
482
490
483− var yOffset = draggedIndex > 0 ? (mouseY + launcherListView.realContentY) % (draggedIndex * launcherListView.realItemHeight) : mouseY + launcherListView.realContentY
491+ var yOffset = draggedIndex > 0 ? (mouse.y + launcherListView.realContentY) % (draggedIndex * launcherListView.realItemHeight) : mouse.y + launcherListView.realContentY
484
492
485 fakeDragItem.iconName = launcherListView.model.get(draggedIndex).icon
493 fakeDragItem.iconName = launcherListView.model.get(draggedIndex).icon
486 fakeDragItem.x = units.gu(0.5)
494 fakeDragItem.x = units.gu(0.5)
487− fakeDragItem.y = mouseY - yOffset + launcherListView.anchors.topMargin + launcherListView.topMargin
495+ fakeDragItem.y = mouse.y - yOffset + launcherListView.anchors.topMargin + launcherListView.topMargin
488 fakeDragItem.angle = selectedItem.angle * (root.inverted ? -1 : 1)
496 fakeDragItem.angle = selectedItem.angle * (root.inverted ? -1 : 1)
489 fakeDragItem.offset = selectedItem.offset * (root.inverted ? -1 : 1)
497 fakeDragItem.offset = selectedItem.offset * (root.inverted ? -1 : 1)
490 fakeDragItem.count = LauncherModel.get(draggedIndex).count
498 fakeDragItem.count = LauncherModel.get(draggedIndex).count
491 fakeDragItem.progress = LauncherModel.get(draggedIndex).progress
499 fakeDragItem.progress = LauncherModel.get(draggedIndex).progress
492 fakeDragItem.flatten()
500 fakeDragItem.flatten()
493− drag.target = fakeDragItem
501+ dragItem.target = fakeDragItem
494
502
495− startX = mouseX
503+ startX = mouse.x
496− startY = mouseY
504+ startY = mouse.y
497 }
505 }
498
506
499 onPositionChanged: {
507 onPositionChanged: {
508+ processPositionChanged(mouse)
509+ }
510+
511+ function processPositionChanged(mouse) {
500 if (draggedIndex >= 0) {
512 if (draggedIndex >= 0) {
501 if (!selectedItem.dragging) {
513 if (!selectedItem.dragging) {
502− var distance = Math.max(Math.abs(mouseX - startX), Math.abs(mouseY - startY))
514+ var distance = Math.max(Math.abs(mouse.x - startX), Math.abs(mouse.y - startY))
503 if (!preDragging && distance > units.gu(1.5)) {
515 if (!preDragging && distance > units.gu(1.5)) {
504 preDragging = true;
516 preDragging = true;
505 quickList.state = "";
517 quickList.state = "";
@@ -623,15 +635,39 @@ Rectangle {
623 source: "graphics/quicklist_tooltip.png"
635 source: "graphics/quicklist_tooltip.png"
624 rotation: 90
636 rotation: 90
625 }
637 }
638+ }
639+ InverseMouseArea {
640+ anchors.fill: quickListShape
641+ enabled: quickList.state == "open" || pressed
626
642
627− InverseMouseArea {
628− anchors.fill: parent
629− enabled: quickList.state == "open"
630− onClicked: {
643+ onClicked: {
631− quickList.state = ""
644+ quickList.state = ""
632− }
633 }
645 }
634
646
647+ // Forward for dragging to work when quickList is open
648+
649+ onPressed: {
650+ var m = mapToItem(dndArea, mouseX, mouseY)
651+ dndArea.processPress(m)
652+ }
653+
654+ onPressAndHold: {
655+ var m = mapToItem(dndArea, mouseX, mouseY)
656+ dndArea.processPressAndHold(m, drag)
657+ }
658+
659+ onPositionChanged: {
660+ var m = mapToItem(dndArea, mouseX, mouseY)
661+ dndArea.processPositionChanged(m)
662+ }
663+
664+ onCanceled: {
665+ dndArea.endDrag(drag);
666+ }
667+
668+ onReleased: {
669+ dndArea.endDrag(drag);
670+ }
635 }
671 }
636
672
637 Rectangle {
673 Rectangle {
tests/qmltests/Launcher/tst_Launcher.qml+116−5
@@ -467,9 +467,12 @@ Item {
467
467
468 function test_dragndrop_data() {
468 function test_dragndrop_data() {
469 return [
469 return [
470− {tag: "startDrag", fullDrag: false },
470+ {tag: "startDrag", fullDrag: false, releaseBeforeDrag: false },
471+ {tag: "fullDrag horizontal", fullDrag: true, releaseBeforeDrag: false, orientation: ListView.Horizontal },
472+ {tag: "fullDrag vertical", fullDrag: true, releaseBeforeDrag: false, orientation: ListView.Vertical },
473+ {tag: "startDrag with quicklist open", fullDrag: false, releaseBeforeDrag: true },
471− {tag: "fullDrag horizontal", fullDrag: true, orientation: ListView.Horizontal },
474+ {tag: "fullDrag horizontal with quicklist open", fullDrag: true, releaseBeforeDrag: true, orientation: ListView.Horizontal },
472− {tag: "fullDrag vertical", fullDrag: true, orientation: ListView.Vertical },
475+ {tag: "fullDrag vertical with quicklist open", fullDrag: true, releaseBeforeDrag: true, orientation: ListView.Vertical },
473 ];
476 ];
474 }
477 }
475
478
@@ -502,6 +505,15 @@ Item {
502 tryCompare(draggedItem, "itemOpacity", 0)
505 tryCompare(draggedItem, "itemOpacity", 0)
503 tryCompare(fakeDragItem, "visible", true)
506 tryCompare(fakeDragItem, "visible", true)
504
507
508+ if (data.releaseBeforeDrag) {
509+ mouseRelease(launcher);
510+ tryCompare(fakeDragItem, "visible", false)
511+
512+ mousePress(launcher, currentMouseX, currentMouseY);
513+ // DraggedItem needs to hide and fakeDragItem become visible
514+ tryCompare(fakeDragItem, "visible", true);
515+ }
516+
505 // Dragging a bit (> 1.5 gu)
517 // Dragging a bit (> 1.5 gu)
506 newMouseX -= units.gu(2)
518 newMouseX -= units.gu(2)
507 mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false, 100)
519 mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false, 100)
@@ -552,8 +564,10 @@ Item {
552
564
553 function test_dragndrop_cancel_data() {
565 function test_dragndrop_cancel_data() {
554 return [
566 return [
555− {tag: "by mouse", mouse: true},
567+ {tag: "by mouse", mouse: true, releaseBeforeDrag: false},
568+ {tag: "by touch", mouse: false, releaseBeforeDrag: false},
569+ {tag: "by mouse with quicklist open", mouse: true, releaseBeforeDrag: true},
556− {tag: "by touch", mouse: false}
570+ {tag: "by touch with quicklist open", mouse: false, releaseBeforeDrag: true}
557 ]
571 ]
558 }
572 }
559
573
@@ -577,6 +591,22 @@ Item {
577 tryCompare(draggedItem, "itemOpacity", 0)
591 tryCompare(draggedItem, "itemOpacity", 0)
578 tryCompare(fakeDragItem, "visible", true)
592 tryCompare(fakeDragItem, "visible", true)
579
593
594+ if (data.releaseBeforeDrag) {
595+ if(data.mouse) {
596+ mouseRelease(draggedItem)
597+ } else {
598+ touchRelease(draggedItem)
599+ }
600+ tryCompare(fakeDragItem, "visible", false)
601+
602+ if(data.mouse) {
603+ mousePress(draggedItem, currentMouseX, currentMouseY)
604+ } else {
605+ touchPress(draggedItem, currentMouseX, currentMouseY)
606+ }
607+ tryCompare(fakeDragItem, "visible", true);
608+ }
609+
580 // Dragging
610 // Dragging
581 currentMouseX -= units.gu(20)
611 currentMouseX -= units.gu(20)
582
612
@@ -604,6 +634,87 @@ Item {
604 tryCompare(dndArea, "drag.target", undefined)
634 tryCompare(dndArea, "drag.target", undefined)
605 }
635 }
606
636
637+ function test_dragndrop_with_other_quicklist_open() {
638+ dragLauncherIntoView();
639+ var draggedItem = findChild(launcher, "launcherDelegate4")
640+ var item0 = findChild(launcher, "launcherDelegate0")
641+ var fakeDragItem = findChild(launcher, "fakeDragItem")
642+ var initialItemHeight = draggedItem.height
643+ var item4 = LauncherModel.get(4).appId
644+ var item3 = LauncherModel.get(3).appId
645+
646+ var listView = findChild(launcher, "launcherListView");
647+ listView.flick(0, units.gu(200));
648+ tryCompare(listView, "flicking", false);
649+
650+ // Initial state
651+ compare(draggedItem.itemOpacity, 1, "Item's opacity is not 1 at beginning")
652+ compare(fakeDragItem.visible, false, "FakeDragItem isn't invisible at the beginning")
653+ tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 0)
654+
655+ // Doing longpress
656+ var mouseOnLauncher = launcher.mapFromItem(draggedItem, draggedItem.width / 2, draggedItem.height / 2)
657+ var currentMouseX = mouseOnLauncher.x
658+ var currentMouseY = mouseOnLauncher.y
659+ var newMouseX = currentMouseX
660+ var newMouseY = currentMouseY
661+ mousePress(launcher, currentMouseX, currentMouseY)
662+ // DraggedItem needs to hide and fakeDragItem become visible
663+ tryCompare(draggedItem, "itemOpacity", 0)
664+ tryCompare(fakeDragItem, "visible", true)
665+
666+ mouseRelease(launcher);
667+ tryCompare(fakeDragItem, "visible", false)
668+
669+ // Now let's longpress and drag a different item
670+
671+ var draggedItem = findChild(launcher, "launcherDelegate3")
672+ compare(draggedItem.itemOpacity, 1, "Item's opacity is not 1 at beginning")
673+ tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 0)
674+
675+ // Doing longpress
676+ var mouseOnLauncher = launcher.mapFromItem(draggedItem, draggedItem.width / 2, draggedItem.height / 2)
677+ var currentMouseX = mouseOnLauncher.x
678+ var currentMouseY = mouseOnLauncher.y
679+ var newMouseX = currentMouseX
680+ var newMouseY = currentMouseY
681+ mousePress(launcher, currentMouseX, currentMouseY)
682+ // DraggedItem needs to hide and fakeDragItem become visible
683+ tryCompare(draggedItem, "itemOpacity", 0)
684+ tryCompare(fakeDragItem, "visible", true)
685+
686+ // Dragging a bit (> 1.5 gu)
687+ newMouseX -= units.gu(2)
688+ mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false, 100)
689+ currentMouseX = newMouseX
690+
691+ // Other items need to expand and become 0.6 opaque
692+ tryCompare(item0, "angle", 0)
693+ tryCompare(item0, "itemOpacity", 0.6)
694+
695+ // Dragging a bit more
696+ newMouseY += initialItemHeight * 1.5
697+ mouseFlick(launcher, currentMouseX, currentMouseY, newMouseX, newMouseY, false, false, 100)
698+ currentMouseY = newMouseY
699+
700+ tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 1)
701+ tryCompare(draggedItem, "height", units.gu(1))
702+
703+ waitForRendering(draggedItem)
704+ compare(LauncherModel.get(4).appId, item3)
705+ compare(LauncherModel.get(3).appId, item4)
706+
707+ // Releasing and checking if initial values are restored
708+ mouseRelease(launcher)
709+ tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 0)
710+ tryCompare(draggedItem, "itemOpacity", 1)
711+ tryCompare(fakeDragItem, "visible", false)
712+
713+ // Click somewhere in the empty space to make it hide in case it isn't
714+ mouseClick(launcher, launcher.width - units.gu(1), units.gu(1));
715+ waitUntilLauncherDisappears();
716+ }
717+
607 function test_quicklist_dismiss() {
718 function test_quicklist_dismiss() {
608 dragLauncherIntoView();
719 dragLauncherIntoView();
609 var draggedItem = findChild(launcher, "launcherDelegate5")
720 var draggedItem = findChild(launcher, "launcherDelegate5")