diff --git a/src/nootka-android.qrc b/src/nootka-android.qrc index dfebfe5ee888ae68ee41b5023008149f9affecba..4690aa93e17a55166e0841fdc55279b3ed305979 100644 --- a/src/nootka-android.qrc +++ b/src/nootka-android.qrc @@ -48,6 +48,8 @@ <file alias="gotit/GotIt.qml">qml/gotit/GotIt.qml</file> <file alias="gotit/SoundInfo.qml">qml/gotit/SoundInfo.qml</file> <file alias="gotit/ExamOrExercise.qml">qml/gotit/ExamOrExercise.qml</file> + <file alias="gotit/HandleScore.qml">qml/gotit/+android/HandleScore.qml</file> + <file alias="gotit/FirstTouchScore.qml">qml/gotit/+android/FirstTouchScore.qml</file> <!-- <file alias="PitchView.qml">qml/sound/PitchView.qml</file> --> <file alias="sound/VolumeBar.qml">qml/sound/VolumeBar.qml</file> diff --git a/src/qml/MainScore.qml b/src/qml/MainScore.qml index 65c30987ae71c09c48122be5540ec140e0b2cc6c..5faafcdfaf6c55ecb62d858962b7bf1d6117ce52 100644 --- a/src/qml/MainScore.qml +++ b/src/qml/MainScore.qml @@ -121,6 +121,8 @@ Score { createStatus() if (!GLOB.singleNoteMode) scoreObj.editModeAct.trigger() + if (Noo.isAndroid() && GLOB.gotIt("howToScore", true)) + Qt.createComponent("qrc:/gotit/FirstTouchScore.qml").createObject(mainScore) } } function createStatus() { diff --git a/src/qml/gotit/+android/FirstTouchScore.qml b/src/qml/gotit/+android/FirstTouchScore.qml new file mode 100644 index 0000000000000000000000000000000000000000..9978c71b6dfdd7b7f4d60454843bd148e4420a3e --- /dev/null +++ b/src/qml/gotit/+android/FirstTouchScore.qml @@ -0,0 +1,26 @@ +/** This file is part of Nootka (http://nootka.sf.net) * + * Copyright (C) 2021 by Tomasz Bojczuk (seelook@gmail.com) * + * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ + +import QtQuick 2.9 + + +Item { + property var handleScore: null + anchors.fill: parent + MouseArea { // cover score mouse/touch actions + anchors.fill: parent + hoverEnabled: true + onClicked: { + handleScore = Qt.createComponent("qrc:/gotit/HandleScore.qml").createObject(nootkaWindow) + handleScore.remaindChecked = GLOB.gotIt("howToScore", true) + handleScore.closed.connect(gotItDone) + } + + function gotItDone() { + GLOB.setGotIt("howToScore", handleScore.remaindChecked) + handleScore.destroy() + destroy() + } + } +} diff --git a/src/qml/gotit/+android/HandleScore.qml b/src/qml/gotit/+android/HandleScore.qml new file mode 100644 index 0000000000000000000000000000000000000000..3444a670b12ed92f29431c1e6a10d4326691c1b4 --- /dev/null +++ b/src/qml/gotit/+android/HandleScore.qml @@ -0,0 +1,246 @@ +/** This file is part of Nootka (http://nootka.sf.net) * + * Copyright (C) 2021 by Tomasz Bojczuk (seelook@gmail.com) * + * on the terms of GNU GPLv3 license (http://www.gnu.org/licenses) */ + +import QtQuick 2.9 + +import Nootka.Main 1.0 +import "../score" +import "../" + + +GotIt { + id: scoreHow + gotItType: TgotIt.GotHandleScore + visible: true + + onClicked: close() + + Image { + id: finger + z: 1050 // above everything and score toolbox + x: parent.width - width; y: parent.height - height + source: Noo.pix("fingerpoint") + width: parent.width * 0.05; height: width + opacity: 0 + } + + Rectangle { // under score + width: gotScore.width * 1.41; height: width; radius: width / 2 + x: width * -0.25; y: height * -0.25 + color: Noo.alpha(activPal.highlight, 50) + } + + MouseArea { // cover score mouse/touch actions + anchors.fill: gotScore + z: 1049 + hoverEnabled: true + } + + Score { + id: gotScore + height: parent.width * 0.3; width: height * 1.1 + bgColor: "transparent" + enableKeySign: true + enableDoubleAccids: true + scoreObj.enableDoubleAccidentals: true + firstStaff.scale: height / firstStaff.linesCount + readOnly: false; scoreObj.editMode: true; scoreObj.allowAdding: visible // HACK + Component.onCompleted: gotIt.score = scoreObj + } + + Rectangle { + width: parent.width * 0.5 + x: parent.width * 0.5 - Noo.factor() * 1.5; y: parent.height * 0.05 + Column { + anchors.horizontalCenter: parent.hozrizontalCenter + width: parent.width - Noo.factor() * 4 + spacing: Noo.factor() + Text { + anchors.horizontalCenter: parent.hozrizontalCenter + color: activPal.text + font { bold: true; pixelSize: scoreHow.width * 0.03 } + text: qsTr("Editing score with touch") + } + ListView { + id: descView + currentIndex: -1 + model: [ + qsTr("Touch and hold area of a note you want to edit."), + qsTr("Move finger left or right to see edited note."), + qsTr("Then move finger up or down to find desired note pitch."), + qsTr("Rise the finger."), + qsTr("If necessary, select accidental or rhythmic value."), + qsTr("Finally, tap selected note shortly.") + ] + width: parent.width - Noo.factor() * 2; height: contentHeight + spacing: Noo.factor() / 2 + delegate: Text { + width: parent.width - Noo.factor() * 2 + text: index + 1 + ". " + modelData + color: activPal.text; wrapMode: Text.WordWrap + font { bold: index === descView.currentIndex; pixelSize: scoreHow.width * 0.015 } + style: index === descView.currentIndex ? Text.Sunken : Text.Normal + styleColor: activPal.highlight + } + } + } + } + + /** + * NOTICE: QML animation is tricky... + * All x, y animated properties are saved before animation starts + * and are fixed during all cycle. + * So they has to be known and set properly. + * This is why we are 'imitating' score toolbox @p factor - it is not known yet when anim starts. + */ + property real factor: gotScore.scoreToobox.factor * 0.9 + property real editPosX: gotScore.x + 23 * gotScore.scale + property real editPosY: gotScore.y + (gotScore.upperLine + 8) * gotScore.scale // upperLine + 4 + property real boxPosX: gotScore.x + 2 + factor * 2.5 // in the middle of sharp control on score toolbox + property real boxPosY: (Noo.isAndroid() ? (height - factor * 27) / 2 : Noo.factor() / 2) + factor * 7.5 + + SequentialAnimation { + id: gotAnim + running: true + PauseAnimation { duration: 500 } + ParallelAnimation { + NumberAnimation { target: finger; property: "opacity"; to: 1 } + NumberAnimation { target: finger; property: "scale"; to: 3; easing.type: Easing.OutBack; duration: 1000 } + NumberAnimation { target: finger; property: "x"; to: editPosX; duration: 1000 } + NumberAnimation { target: finger; property: "y"; to: editPosY; easing.type: Easing.OutBack; duration: 1000 } + } + ScriptAction { + script: { + descView.currentIndex = 0 // touch and hold + gotScore.noteAdd.visible = true + gotScore.scoreToobox.active = false + gotScore.noteAdd.active = true + gotScore.noteAdd.yPos = gotScore.upperLine + 4 + } + } + PauseAnimation { duration: 1000 } + ScriptAction { script: descView.currentIndex = 1 } // Move left or right + ParallelAnimation { + NumberAnimation { target: finger; property: "x"; to: editPosX - scoreHow.width * 0.05; duration: 500 } + NumberAnimation { target: finger; property: "y"; to: editPosY; duration: 500 } + } + ParallelAnimation { + NumberAnimation { target: finger; property: "x"; to: editPosX + scoreHow.width * 0.05; duration: 1000 } + NumberAnimation { target: finger; property: "y"; to: editPosY; duration: 1000 } + } + PauseAnimation { duration: 1000 } + ScriptAction { script: descView.currentIndex = 2 } // Move up and down + ParallelAnimation { + NumberAnimation { target: finger; property: "y"; to: editPosY - 10 * gotScore.scale; duration: 1200 } + NumberAnimation { target: gotScore.noteAdd; property: "yPos"; to: gotScore.upperLine - 6; duration: 1200 } + } + PauseAnimation { duration: 500 } + ParallelAnimation { + NumberAnimation { target: finger; property: "y"; to: editPosY + 8 * gotScore.scale; duration: 2000 } + NumberAnimation { target: gotScore.noteAdd; property: "yPos"; to: gotScore.upperLine + 12; duration: 2000 } + } + PauseAnimation { duration: 500 } + ParallelAnimation { + NumberAnimation { target: finger; property: "y"; to: editPosY + 2 * gotScore.scale; duration: 600 } + NumberAnimation { target: gotScore.noteAdd; property: "yPos"; to: gotScore.upperLine + 6; duration: 600 } + } + ScriptAction { script: descView.currentIndex = 3 } // Rise finger + PauseAnimation { duration: 1000 } + ScriptAction { script: gotScore.scoreToobox.active = true } + ParallelAnimation { + NumberAnimation { target: finger; property: "scale"; to: 4; duration: 500 } + NumberAnimation { target: finger; property: "x"; to: editPosX + scoreHow.width * 0.07; duration: 500 } + } + ScriptAction { script: descView.currentIndex = 4 } // select accidental + PauseAnimation { duration: 1000 } + ParallelAnimation { + NumberAnimation { target: finger; property: "scale"; to: 3; duration: 750 } + NumberAnimation { target: finger; property: "x"; to: boxPosX; duration: 750 } + NumberAnimation { target: finger; property: "y"; to: boxPosY; duration: 750 } + } + ScriptAction { script: gotIt.setCursorAlter(1) } // select sharp + PauseAnimation { duration: 1000 } + ParallelAnimation { + NumberAnimation { target: finger; property: "scale"; to: 3; easing.type: Easing.OutBack; duration: 750 } + NumberAnimation { target: finger; property: "x"; to: boxPosX + factor * 2; easing.type: Easing.OutBack; duration: 750 } + NumberAnimation { target: finger; property: "y"; to: boxPosY + factor * 12; duration: 750 } + } + ScriptAction { script: gotIt.setWorkRtmValue(4) } // select eight + PauseAnimation { duration: 1000 } + ScriptAction { script: descView.currentIndex = 5 } // finally confirm note + ParallelAnimation { + NumberAnimation { target: finger; property: "scale"; to: 4; duration: 500 } + NumberAnimation { target: finger; property: "x"; to: boxPosX + (editPosX - boxPosX) / 2; duration: 500 } + NumberAnimation { target: finger; property: "y"; to: editPosY - gotScore.height * 0.2; duration: 500 } + } + ParallelAnimation { + NumberAnimation { target: finger; property: "scale"; to: 3; duration: 500 } + NumberAnimation { target: finger; property: "x"; to: editPosX; duration: 500 } + NumberAnimation { target: finger; property: "y"; to: editPosY; duration: 500 } + } + ScriptAction { + script: { + gotScore.addNote(Noo.note(5, 1, 1, 4)) // add note to e score (g#1 eight) + gotScore.scoreToobox.active = false + gotScore.noteAdd.active = false + } + } + PauseAnimation { duration: 150 } + ParallelAnimation { + NumberAnimation { target: finger; property: "scale"; to: 4; duration: 500 } + NumberAnimation { target: finger; property: "x"; to: scoreHow.width * 0.26; duration: 500 } + NumberAnimation { target: finger; property: "y"; to: scoreHow.height * 0.3; duration: 500 } + } + ParallelAnimation { + NumberAnimation { target: finger; property: "x"; to: scoreHow.width * 0.32; duration: 500 } + NumberAnimation { target: finger; property: "y"; to: scoreHow.height * 0.39; duration: 500 } + } + ScriptAction { script: gotScore.noteAdd.visible = false } + ParallelAnimation { + NumberAnimation { target: finger; property: "x"; to: scoreHow.width * 0.5; duration: 1000 } + NumberAnimation { target: finger; property: "y"; to: scoreHow.height * 0.8; duration: 1000 } + } + ScriptAction { script: descView.currentIndex = -1 } + } + + Row { + x: parent.width * 0.05; y: parent.height * 0.95 - height + spacing: Noo.factor() * 2 + TcuteButton { + text: Noo.TR("QShortcut", gotAnim.running ? "Stop" : "Play") + width: height * 3.5; height: Noo.factor() * 3 + font { pixelSize: Noo.factor() * 2; bold: true; capitalization: Font.AllUppercase } + onClicked: { + if (gotAnim.running) + gotAnim.running = false + else { + finger.opacity = 0 + finger.scale = 1 + finger.x = parent.width - finger.width + finger.y = parent.height - finger.height + gotScore.noteAdd.active = false + gotScore.scoreToobox.active = false + gotScore.clearScore() + gotScore.noteAdd.yPos = 0 + gotIt.setCursorAlter(0) + gotIt.setWorkRtmValue(3) + descView.currentIndex = -1 + gotAnim.running = true + } + } + } + TcuteButton { + enabled: gotAnim.running + text: gotAnim.paused ? Noo.TR("QWizard", "Continue") : Noo.TR("QShortcut", "Pause") + width: height * 3.5; height: Noo.factor() * 3 + font { pixelSize: Noo.factor() * 2; bold: true; capitalization: Font.AllUppercase } + onClicked: { + if (gotAnim.paused) + gotAnim.resume() + else + gotAnim.pause() + } + } + } +}