diff --git a/changes b/changes
index ee76538363aecc250ba474f2c5ce73c72ad97a41..2749d9fd9830c107d7b5267474c5e80ded3c97e5 100644
--- a/changes
+++ b/changes
@@ -1,5 +1,6 @@
 1.7.3 git
      - exam melodies can be played in order from melody set
+     - melodies order in set is editable
      - user can define repeats number of melodies from the set
      - updated SoundTouch library version to 2.2 (Windows&Android)
 
diff --git a/src/dialogs/tmelodylistview.cpp b/src/dialogs/tmelodylistview.cpp
index ec669b6fbf3bed0f037d15f065c32ade8e11faeb..3db773d4fc129323959eadf46b554aa711fb44d7 100644
--- a/src/dialogs/tmelodylistview.cpp
+++ b/src/dialogs/tmelodylistview.cpp
@@ -111,6 +111,16 @@ void TmelodyListView::removeMelody(int id) {
 }
 
 
+void TmelodyListView::swapMelodies(int from, int to) {
+  if (from > -1 && from < m_melodies.count() && to > -1 && to < m_melodies.count()) {
+      m_melodies.move(from, to);
+      m_listWasChanged = true;
+      emit melodiesChanged();
+  } else
+      qDebug() << "[TmelodyListView] FIXME! Wrong melodies to swap";
+}
+
+
 Tmelody* TmelodyListView::getMelody(int melId) {
   return melId > -1 && melId < m_melodies.count() ? m_melodies[melId].melody : nullptr;
 }
diff --git a/src/dialogs/tmelodylistview.h b/src/dialogs/tmelodylistview.h
index 8c6473b23cf0396140c66f736284f7ce116d1d17..cc86f77f5b9a28661f3ab358b25ea619f17ea1f7 100644
--- a/src/dialogs/tmelodylistview.h
+++ b/src/dialogs/tmelodylistview.h
@@ -57,6 +57,7 @@ public:
 
   Q_INVOKABLE void loadMelody();
   Q_INVOKABLE void removeMelody(int id);
+  Q_INVOKABLE void swapMelodies(int from, int to);
 
   Tmelody* getMelody(int melId);
 
diff --git a/src/qml/level/MelodyListView.qml b/src/qml/level/MelodyListView.qml
index 56e048e17d862298af13366d7c8c7ae0f17cfede..a426dda0ffb93a8f6fe412604819f1b6e09d1867 100644
--- a/src/qml/level/MelodyListView.qml
+++ b/src/qml/level/MelodyListView.qml
@@ -16,6 +16,7 @@ TmelodyListView {
   id: melListView
 
   property int currentMelody: -1
+  property alias viewRoot: viewItem
 
   melodyModel: ListModel {
     id: melMod
@@ -28,33 +29,37 @@ TmelodyListView {
       text: "\n\n" + qsTr("Add here melodies from Music XML files.\nConsider to divide long pieces on parts in external software first.")
       horizontalAlignment: Text.AlignHCenter; wrapMode: Text.WordWrap
     }
-    ListView {
-      id: melView
-      visible: count > 0
-      clip: true; spacing: 1
+    Item {
+      id: viewItem
       width: melListView.width - Noo.fontSize() * 4; height: melListView.height
-      add: Transition {
-        enabled: GLOB.useAnimations
-        NumberAnimation { property: "x"; from: -melListView.width; to: 5 }
-      }
-      remove: Transition {
-        enabled: GLOB.useAnimations
-        NumberAnimation { property: "x"; to: -melListView.width }
-      }
-      populate: Transition {
-        enabled: GLOB.useAnimations
-        NumberAnimation { property: "x"; from: -melListView.width; to: 5 }
-      }
-      move: Transition {
-        enabled: GLOB.useAnimations
-        NumberAnimation { property: "y"; to: -Noo.fontSize() * 4 }
-      }
-      model: melMod
-      delegate: MelodyWrapper {
-        nr: index
-        width: melView.width - 10
-        Component.onCompleted: {
-          updateMelody()
+      ListView {
+        id: melView
+        visible: count > 0
+        clip: true; spacing: 1
+        anchors { fill: parent; margins: 5 }
+        add: Transition {
+          enabled: GLOB.useAnimations
+          NumberAnimation { property: "x"; from: -melListView.width; to: 0 }
+        }
+        remove: Transition {
+          enabled: GLOB.useAnimations
+          NumberAnimation { property: "x"; to: -melListView.width }
+        }
+        populate: Transition {
+          enabled: GLOB.useAnimations
+          NumberAnimation { property: "x"; from: -melListView.width; to: 0 }
+        }
+        move: Transition {
+          enabled: GLOB.useAnimations
+          NumberAnimation { property: "y"; from: -Noo.fontSize() * 4 }
+        }
+        model: melMod
+        delegate: MelodyWrapper {
+          nr: index
+          width: melView.width - 10
+          Component.onCompleted: {
+            updateMelody()
+          }
         }
       }
     }
@@ -70,7 +75,7 @@ TmelodyListView {
       TcuteButton {
         width: Noo.fontSize() * 3
         font { pixelSize: Noo.fontSize() * 2; bold: true; family: "Sans" }
-        text: "-"; textColor: "red"
+        text: "-"; textColor: enabled ? "red" : disdPal.text
         enabled: currentMelody > -1
         onClicked: removeWrapper(currentMelody)
       }
@@ -86,4 +91,8 @@ TmelodyListView {
     removeMelody(id)
     currentMelody = -1
   }
+  function moveMelody(from, to) {
+    melMod.move(from, to, 1)
+    swapMelodies(from, to)
+  }
 }
diff --git a/src/qml/level/MelodyWrapper.qml b/src/qml/level/MelodyWrapper.qml
index e968dc0a1e35962cf6eafd59ebc9b2cb0db9e14a..0480bde9d302cd798ae56c16d62c849928a178e5 100644
--- a/src/qml/level/MelodyWrapper.qml
+++ b/src/qml/level/MelodyWrapper.qml
@@ -8,66 +8,107 @@ import Nootka.Dialogs 1.0
 import Score 1.0
 import "../score"
 
-
-TmelodyWrapper {
-  score: sc.scoreObj
-  melodyView: melListView
+MouseArea {
+  id: wrapArea
 
   height: Noo.fontSize() * 10
-  x: 5
 
-  Score {
-    id: sc
-    anchors.fill: parent
-    readOnly: true
-    bgColor: nr === melListView.currentMelody ? Qt.tint(activPal.base, Noo.alpha(activPal.highlight, 50)) : activPal.base
-  }
+  property bool held: false
+  property alias nr: wrapper.nr
+
+  function updateMelody() { wrapper.updateMelody() }
+
+  hoverEnabled: true
+  drag.target: wrapArea.held ? wrapper : undefined
+  drag.axis: Drag.YAxis
+
+  onPressAndHold: wrapArea.held = true
+  onReleased: wrapArea.held = false
+  onClicked: melListView.currentMelody = nr
+
+  TmelodyWrapper {
+    id: wrapper
+
+    score: sc.scoreObj
+    melodyView: melListView
 
-  Rectangle { // this is part of covering rectangle
-    height: parent.height; width: parent.height
-    rotation: -90;
-    x: parent.width - scoreCover.width - width
-    gradient: Gradient {
-      GradientStop { position: 0.0; color: "transparent" }
-      GradientStop { position: 0.75; color: sc.bgColor }
+    width: wrapArea.width; height: wrapArea.height
+
+    Drag.active: wrapArea.held
+    Drag.source: wrapArea
+    Drag.hotSpot.x: width / 2
+    Drag.hotSpot.y: height / 2
+
+    anchors {
+      horizontalCenter: parent.horizontalCenter
+      verticalCenter: parent.verticalCenter
     }
-  }
-  Rectangle {
-    id: scoreCover
-    height: parent.height; width: parent.width - parent.height * 4
-    anchors { right: parent.right }
-    color: sc.bgColor
-  }
 
-  Text {
-    x: Noo.fontSize() / 2; y: Noo.fontSize() / 2
-    font { family: "Sans"; bold: true }
-    text: nr + 1; color: Noo.alpha(activPal.text, 150)
-  }
+    states: State {
+      when: wrapArea.held
+      ParentChange { target: wrapper; parent: melListView.viewRoot }
+      AnchorChanges {
+        target: wrapper
+        anchors { horizontalCenter: undefined; verticalCenter: undefined }
+      }
+    }
 
-  Text {
-    text: title
-    x: parent.width - scoreCover.width
-    y: Noo.fontSize() / 4
-    font { bold: true; pixelSize: Noo.fontSize() * 1.3 }
-    color: wrapArea.containsMouse ? activPal.text : Noo.alpha(activPal.text, 150)
-    width: Noo.fontSize() * 25; elide: Text.ElideRight
-    Behavior on color { enabled: GLOB.useAnimations; ColorAnimation {} }
-  }
+    Score {
+      id: sc
+      anchors.fill: parent
+      interactive: false
+      readOnly: true
+      bgColor: wrapArea.held ? Qt.tint(activPal.base, Noo.alpha(activPal.text, 50)) : (nr === melListView.currentMelody ? Qt.tint(activPal.base, Noo.alpha(activPal.highlight, 50)) : activPal.base)
+      //bgColor: nr === melListView.currentMelody ? Qt.tint(activPal.base, Noo.alpha(activPal.highlight, 50)) : activPal.base
+    }
 
-  Text {
-    text: composer
-    anchors { right: parent.right; rightMargin: Noo.fontSize() / 4 }
-    y: Noo.fontSize() * 1.5
-    color: wrapArea.containsMouse ? activPal.text : Noo.alpha(activPal.text, 150)
-    maximumLineCount: 1
-    Behavior on color { enabled: GLOB.useAnimations; ColorAnimation {} }
-  }
+    Rectangle { // this is part of covering rectangle
+      height: parent.height; width: parent.height
+      rotation: -90;
+      x: parent.width - scoreCover.width - width
+      gradient: Gradient {
+        GradientStop { position: 0.0; color: "transparent" }
+        GradientStop { position: 0.75; color: sc.bgColor }
+      }
+    }
+    Rectangle {
+      id: scoreCover
+      height: parent.height; width: parent.width - parent.height * 4
+      anchors { right: parent.right }
+      color: sc.bgColor
+    }
+
+    Text {
+      x: Noo.fontSize() / 2; y: Noo.fontSize() / 2
+      font { family: "Sans"; bold: true }
+      text: nr + 1; color: Noo.alpha(activPal.text, 150)
+    }
+
+    Text {
+      text: wrapper.title
+      x: parent.width - scoreCover.width
+      y: Noo.fontSize() / 4
+      font { bold: true; pixelSize: Noo.fontSize() * 1.3 }
+      color: wrapArea.containsMouse ? activPal.text : Noo.alpha(activPal.text, 150)
+      width: Noo.fontSize() * 25; elide: Text.ElideRight
+      Behavior on color { enabled: GLOB.useAnimations; ColorAnimation {} }
+    }
 
-  MouseArea {
-    id: wrapArea
-    anchors.fill: parent
-    hoverEnabled: true
-    onClicked: melListView.currentMelody = nr
+    Text {
+      text: wrapper.composer
+      anchors { right: parent.right; rightMargin: Noo.fontSize() / 4 }
+      y: Noo.fontSize() * 1.5
+      color: wrapArea.containsMouse ? activPal.text : Noo.alpha(activPal.text, 150)
+      maximumLineCount: 1
+      Behavior on color { enabled: GLOB.useAnimations; ColorAnimation {} }
+    }
+  } // TmelodyWrapper
+
+  DropArea {
+    anchors { fill: parent; margins: 10 }
+    onEntered: {
+      if (drag.source.nr !== wrapArea.nr)
+        melListView.moveMelody(drag.source.nr, wrapArea.nr)
+    }
   }
 }