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) + } } }