diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -71,3 +71,5 @@ install(PROGRAMS org.kde.minuet.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) install(TARGETS minuet RUNTIME DESTINATION bin) ENDIF(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Android") + +add_subdirectory(plugins) \ No newline at end of file diff --git a/src/app/plugins/CMakeLists.txt b/src/app/plugins/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/src/app/plugins/CMakeLists.txt @@ -0,0 +1,9 @@ +set(minuet_PLUGINS + PianoView.json + GuitarView.json +) + +add_subdirectory(PianoView) +add_subdirectory(GuitarView) + +install(FILES ${minuet_PLUGINS} DESTINATION ${KDE_INSTALL_DATADIR}/minuet/plugins) diff --git a/src/app/plugins/GuitarView.json b/src/app/plugins/GuitarView.json new file mode 100644 --- /dev/null +++ b/src/app/plugins/GuitarView.json @@ -0,0 +1,5 @@ +{ + "menuName": "GuitarView", + "iconName": "group", + "mainPage": "GuitarView.qml" +} diff --git a/src/app/plugins/GuitarView/CMakeLists.txt b/src/app/plugins/GuitarView/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/src/app/plugins/GuitarView/CMakeLists.txt @@ -0,0 +1,6 @@ +set(minuet_GUITAR + GuitarView.qml + FretBoard.qml +) + +install(FILES ${minuet_GUITAR} DESTINATION ${KDE_INSTALL_DATADIR}/minuet/plugins/GuitarView) diff --git a/src/app/plugins/GuitarView/FretBoard.qml b/src/app/plugins/GuitarView/FretBoard.qml new file mode 100644 --- /dev/null +++ b/src/app/plugins/GuitarView/FretBoard.qml @@ -0,0 +1,60 @@ +import QtQuick 2.7 + +Rectangle { + width: 70; height: (string1.height + string1.anchors.topMargin) * 6 + string1.anchors.topMargin + color: "#4b3020" + property int string_size: 3 + property string string_color: "#FFFFFF" + + Rectangle { + id: string1 + width: parent.width; height: string_size + anchors { left: parent.left; top: parent.top; topMargin: 3 * height} + color: string_color + } + + Rectangle { + id: string2 + width: parent.width; height: string_size + anchors { left: parent.left; top: string1.bottom; topMargin: 3 * height} + color: string_color + } + Rectangle { + id: string3 + width: parent.width; height: string_size + anchors { left: parent.left; top: string2.bottom; topMargin: 3 * height} + color: string_color + } + Rectangle { + id: string4 + width: parent.width; height: string_size + anchors { left: parent.left; top: string3.bottom; topMargin: 3 * height} + color: string_color + } + Rectangle { + id: string5 + width: parent.width; height: string_size + anchors { left: parent.left; top: string4.bottom; topMargin: 3 * height} + color: string_color + } + Rectangle { + id: string6 + width: parent.width; height: string_size + anchors { left: parent.left; top: string5.bottom; topMargin: 3 * height} + color: string_color + } + + Rectangle { + id: leftBar + width: string_size; height: parent.height + anchors {left: parent.left; leftMargin: -string_size/3; top: parent.top; bottom: parent.bottom} + color: string_color + } + + Rectangle { + id: rightBar + width: string_size; height: parent.height + anchors {right: parent.right; top: parent.top; bottom: parent.bottom} + color: string_color + } +} diff --git a/src/app/plugins/GuitarView/GuitarView.qml b/src/app/plugins/GuitarView/GuitarView.qml new file mode 100644 --- /dev/null +++ b/src/app/plugins/GuitarView/GuitarView.qml @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2016 by Sandro S. Andrade +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License or (at your option) version 3 or any later version +** accepted by the membership of KDE e.V. (or its successor approved +** by the membership of KDE e.V.), which shall act as a proxy +** defined in Section 14 of version 3 of the license. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +Flickable { + id: flickable + + width: Math.min(parent.width, guitar.width) + height: keyHeight + 30 + contentWidth: guitar.width + boundsBehavior: Flickable.OvershootBounds + clip: true + + property int keyWidth: Math.max(16, (parent.width - 80) / 52) + property int keyHeight: 3.4 * keyWidth + + function noteOn(chan, pitch, vel) { + } + function noteOff(chan, pitch, vel) { + } + function noteMark(chan, pitch, vel, color) { + } + function noteUnmark(chan, pitch, vel, color) { + } + function clearAllMarks() { + } + function scrollToNote(pitch) { + } + function highlightKey(pitch, color) { + } + function itemForPitch(pitch) { + } + + Rectangle { + id: guitar + + width: fretBoard1.width * 10 + 55*4+40*6; height: parent.height + anchors.horizontalCenter: parent.horizontalCenter + radius: 5 + color: "#141414" + + Row { + id: fretBoardNumber + width: parent.width; height: 18 + anchors.left: parent.left + + Repeater { + model: 20 + + Label { + text: modelData < 10 ? i18nc("technical term, do you have a musician friend?", "Octave") + " " + (1 + modelData) : + i18nc("technical term, do you have a musician friend?", "Oct") + (1 + modelData) + width: modelData < 10 ? board.fretBoard_width : modelData < 14 ? 55 : 40; + color: "white" + height: parent.height + } + } + } + + Item { + id: board + anchors {top: fretBoardNumber.bottom; left: parent.left; right: parent.right} + height: fretBoard1.height * 1.1 + + property alias fretBoard_width: fretBoard1.width + + FretBoard { id: fretBoard1; anchors.left: parent.left} + FretBoard { id: fretBoard2; anchors.left: fretBoard1.right} + FretBoard { id: fretBoard3; anchors.left: fretBoard2.right} + FretBoard { id: fretBoard4; anchors.left: fretBoard3.right} + FretBoard { id: fretBoard5; anchors.left: fretBoard4.right} + FretBoard { id: fretBoard6; anchors.left: fretBoard5.right} + FretBoard { id: fretBoard7; anchors.left: fretBoard6.right} + FretBoard { id: fretBoard8; anchors.left: fretBoard7.right} + FretBoard { id: fretBoard9; anchors.left: fretBoard8.right} + FretBoard { id: fretBoard10; anchors.left: fretBoard9.right} + FretBoard { id: fretBoard11; anchors.left: fretBoard10.right; width: 55} + FretBoard { id: fretBoard12; anchors.left: fretBoard11.right; width: 55} + FretBoard { id: fretBoard13; anchors.left: fretBoard12.right; width: 55} + FretBoard { id: fretBoard14; anchors.left: fretBoard13.right; width: 55} + FretBoard { id: fretBoard15; anchors.left: fretBoard14.right; width: 40} + FretBoard { id: fretBoard16; anchors.left: fretBoard15.right; width: 40} + FretBoard { id: fretBoard17; anchors.left: fretBoard16.right; width: 40} + FretBoard { id: fretBoard18; anchors.left: fretBoard17.right; width: 40} + FretBoard { id: fretBoard19; anchors.left: fretBoard18.right; width: 40} + FretBoard { id: fretBoard20; anchors.left: fretBoard19.right; width: 40} + } + } + + ScrollIndicator.horizontal: ScrollIndicator { active: true } +} diff --git a/src/app/plugins/PianoView.json b/src/app/plugins/PianoView.json new file mode 100644 --- /dev/null +++ b/src/app/plugins/PianoView.json @@ -0,0 +1,5 @@ +{ + "menuName": "PianoView", + "iconName": "group", + "mainPage": "PianoView.qml" +} diff --git a/src/app/plugins/PianoView/BlackKey.qml b/src/app/plugins/PianoView/BlackKey.qml new file mode 100644 --- /dev/null +++ b/src/app/plugins/PianoView/BlackKey.qml @@ -0,0 +1,33 @@ +/**************************************************************************** +** +** Copyright (C) 2016 by Sandro S. Andrade +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License or (at your option) version 3 or any later version +** accepted by the membership of KDE e.V. (or its successor approved +** by the membership of KDE e.V.), which shall act as a proxy +** defined in Section 14 of version 3 of the license. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +** +****************************************************************************/ + +import QtQuick 2.7 + +Rectangle { + property Item anchor + + width: 0.6 * keyWidth; height: 0.6 * keyHeight + anchors { left: anchor.right; leftMargin: -(0.6 * keyWidth) / 2; top: anchor.top } + border { width: 1; color: "black" } + color: "black" + z: 1 +} diff --git a/src/app/plugins/PianoView/CMakeLists.txt b/src/app/plugins/PianoView/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/src/app/plugins/PianoView/CMakeLists.txt @@ -0,0 +1,8 @@ +set(minuet_PIANO + BlackKey.qml + Octave.qml + PianoView.qml + WhiteKey.qml +) + +install(FILES ${minuet_PIANO} DESTINATION ${KDE_INSTALL_DATADIR}/minuet/plugins/PianoView) diff --git a/src/app/plugins/PianoView/Octave.qml b/src/app/plugins/PianoView/Octave.qml new file mode 100644 --- /dev/null +++ b/src/app/plugins/PianoView/Octave.qml @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2016 by Sandro S. Andrade +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License or (at your option) version 3 or any later version +** accepted by the membership of KDE e.V. (or its successor approved +** by the membership of KDE e.V.), which shall act as a proxy +** defined in Section 14 of version 3 of the license. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +** +****************************************************************************/ + +import QtQuick 2.7 + +Item { + property Item initialAnchor + + width: 7 * keyWidth; height: keyHeight - 10 + anchors.left: initialAnchor.right + + WhiteKey { id: whiteKey1 } + BlackKey { anchor: whiteKey1 } + WhiteKey { id: whiteKey2; anchor: whiteKey1 } + BlackKey { anchor: whiteKey2 } + WhiteKey { id: whiteKey3; anchor: whiteKey2 } + WhiteKey { id: whiteKey4; anchor: whiteKey3 } + BlackKey { anchor: whiteKey4 } + WhiteKey { id: whiteKey5; anchor: whiteKey4 } + BlackKey { anchor: whiteKey5 } + WhiteKey { id: whiteKey6; anchor: whiteKey5 } + BlackKey { anchor: whiteKey6 } + WhiteKey { anchor: whiteKey6 } +} diff --git a/src/app/plugins/PianoView/PianoView.qml b/src/app/plugins/PianoView/PianoView.qml new file mode 100644 --- /dev/null +++ b/src/app/plugins/PianoView/PianoView.qml @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2016 by Sandro S. Andrade +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License or (at your option) version 3 or any later version +** accepted by the membership of KDE e.V. (or its successor approved +** by the membership of KDE e.V.), which shall act as a proxy +** defined in Section 14 of version 3 of the license. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +** +****************************************************************************/ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 + +Flickable { + id: flickable + + width: Math.min(parent.width, piano.width) + height: keyHeight + 30 + contentWidth: piano.width + boundsBehavior: Flickable.OvershootBounds + clip: true + + property int keyWidth: Math.max(16, (parent.width - 80) / 52) + property int keyHeight: 3.4 * keyWidth + + function noteOn(chan, pitch, vel) { + if (vel > 0) + highlightKey(pitch, "#778692") + else + noteOff(chan, pitch, vel) + } + function noteOff(chan, pitch, vel) { + highlightKey(pitch, ([1,3,6,8,10].indexOf(pitch % 12) > -1) ? "black":"white") + } + function noteMark(chan, pitch, vel, color) { + noteMark.createObject(itemForPitch(pitch), { color: color }) + } + function noteUnmark(chan, pitch, vel, color) { + if(itemForPitch(pitch)!= undefined){ + var item = itemForPitch(pitch).children[0] + if (item != undefined) + item.destroy() + } + } + function clearAllMarks() { + for (var index = 21; index <= 108; ++index) { + noteOff(0, index, 0) + var markItem = itemForPitch(index).children[0] + if (markItem != undefined) + markItem.destroy() + } + } + function scrollToNote(pitch) { + flickable.contentX = flickable.contentWidth/88*(pitch-21) - flickable.width/2 + } + function highlightKey(pitch, color) { + itemForPitch(pitch).color = color + } + function itemForPitch(pitch) { + var noteItem + if (pitch < 24) { + noteItem = keyboard.children[pitch-21] + } else if (pitch == 108) { + noteItem = whiteKeyC + } else { + var note = (pitch - 24) % 12 + var octave = (pitch - 24 - note) / 12 + noteItem = keyboard.children[3+octave].children[note] + } + return noteItem + } + + Rectangle { + id: piano + + width: 3 * keyWidth + 7 * (7 * keyWidth); height: parent.height + anchors.horizontalCenter: parent.horizontalCenter + radius: 5 + color: "#141414" + + Row { + id: octaveNumber + width: parent.width; height: 18 + anchors.left: parent.left + anchors.leftMargin: 2 * keyWidth + + Repeater { + model: 7 + + Label { + text: i18nc("technical term, do you have a musician friend?", "Octave") + " " + (1 + modelData) + width: 7 * keyWidth + color: "white" + height: parent.height + } + } + } + + Item { + id: keyboard + + anchors { top: octaveNumber.bottom; horizontalCenter: parent.horizontalCenter; bottom: parent.bottom; bottomMargin: 5 } + width: 3 * keyWidth + 7 * (7 * keyWidth); height: keyHeight - octaveNumber.height + + WhiteKey { id: whiteKeyA } + BlackKey { anchor: whiteKeyA } + WhiteKey { id: whiteKeyB; anchor: whiteKeyA } + Octave { id: octave1; initialAnchor: whiteKeyB } + Octave { id: octave2; initialAnchor: octave1 } + Octave { id: octave3; initialAnchor: octave2 } + Octave { id: octave4; initialAnchor: octave3 } + Octave { id: octave5; initialAnchor: octave4 } + Octave { id: octave6; initialAnchor: octave5 } + Octave { id: octave7; initialAnchor: octave6 } + WhiteKey { id: whiteKeyC; anchor: octave7 } + Rectangle { + width: 3 * keyWidth + 7 * (7 * keyWidth); height: 2 + anchors { left: whiteKeyA.left; bottom: whiteKeyA.top } + color: "#A40E09" + } + } + + Component { + id: noteMark + + Rectangle { + width: keyWidth - 4; height: keyWidth - 4 + radius: (keyWidth - 4) / 2 + border.color: "black" + anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom; bottomMargin: 2 } + } + } + } + ScrollIndicator.horizontal: ScrollIndicator { active: true } +} diff --git a/src/app/plugins/PianoView/WhiteKey.qml b/src/app/plugins/PianoView/WhiteKey.qml new file mode 100644 --- /dev/null +++ b/src/app/plugins/PianoView/WhiteKey.qml @@ -0,0 +1,33 @@ +/**************************************************************************** +** +** Copyright (C) 2016 by Sandro S. Andrade +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License or (at your option) version 3 or any later version +** accepted by the membership of KDE e.V. (or its successor approved +** by the membership of KDE e.V.), which shall act as a proxy +** defined in Section 14 of version 3 of the license. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +** +****************************************************************************/ + +import QtQuick 2.7 + +Rectangle { + property Item anchor + + width: keyWidth; height: keyHeight + border { width: 1; color: "black" } + color: "white" + + Component.onCompleted: if (anchor != null) anchors.left = anchor.right +} diff --git a/src/app/qml.qrc b/src/app/qml.qrc --- a/src/app/qml.qrc +++ b/src/app/qml.qrc @@ -8,19 +8,16 @@ qml/ImageItemDelegate.qml +android/qml/MinuetMenuContainer.qml qml/ExerciseView.qml - qml/PianoView/BlackKey.qml - qml/PianoView/Octave.qml - qml/PianoView/PianoView.qml - qml/PianoView/WhiteKey.qml - qml/SheetMusicView/Bravura.otf - qml/SheetMusicView/BravuraText.qml - qml/SheetMusicView/Clef.qml - qml/SheetMusicView/Note.qml - qml/SheetMusicView/Score.qml - qml/SheetMusicView/Sequence.qml - qml/SheetMusicView/SheetMusicView.qml + qml/InstrumentView/InstrumentView.qml + qml/SheetMusicView/Bravura.otf + qml/SheetMusicView/BravuraText.qml + qml/SheetMusicView/Clef.qml + qml/SheetMusicView/Note.qml + qml/SheetMusicView/Score.qml + qml/SheetMusicView/Sequence.qml + qml/SheetMusicView/SheetMusicView.qml qml/images/minuet-background.png diff --git a/src/app/qml/ExerciseView.qml b/src/app/qml/ExerciseView.qml --- a/src/app/qml/ExerciseView.qml +++ b/src/app/qml/ExerciseView.qml @@ -31,6 +31,7 @@ visible: currentExercise != undefined property var currentExercise + property var chosenExercises QtObject { id: internal @@ -74,7 +75,7 @@ } function clearUserAnswers() { - pianoView.clearAllMarks() + instrumentView.clearAllMarks() sheetMusicView.clearAllMarks() for (var i = 0; i < yourAnswersParent.children.length; ++i) yourAnswersParent.children[i].destroy() @@ -123,7 +124,7 @@ } var array = [core.exerciseController.chosenRootNote()] internal.rightAnswerRectangle.model.sequence.split(' ').forEach(function(note) { - pianoView.noteMark(0, core.exerciseController.chosenRootNote() + parseInt(note), 0, internal.rightAnswerRectangle.color) + instrumentView.noteMark(0, core.exerciseController.chosenRootNote() + parseInt(note), 0, internal.rightAnswerRectangle.color) array.push(core.exerciseController.chosenRootNote() + parseInt(note)) }) sheetMusicView.model = array @@ -139,7 +140,7 @@ function nextTestExercise() { for (var i = 0; i < answerGrid.children.length; ++i) answerGrid.children[i].opacity = 1 - pianoView.clearAllMarks() + instrumentView.clearAllMarks() sheetMusicView.clearAllMarks() clearUserAnswers() generateNewQuestion(true) @@ -153,11 +154,11 @@ else messageText.text = "" core.exerciseController.randomlySelectExerciseOptions() - var chosenExercises = core.exerciseController.selectedExerciseOptions + chosenExercises = core.exerciseController.selectedExerciseOptions core.soundController.prepareFromExerciseOptions(chosenExercises) if (currentExercise["playMode"] != "rhythm") { - pianoView.noteMark(0, core.exerciseController.chosenRootNote(), 0, "white") - pianoView.scrollToNote(core.exerciseController.chosenRootNote()) + instrumentView.noteMark(0, core.exerciseController.chosenRootNote(), 0, "white") + instrumentView.scrollToNote(core.exerciseController.chosenRootNote()) sheetMusicView.model = [core.exerciseController.chosenRootNote()] sheetMusicView.clef.type = (core.exerciseController.chosenRootNote() >= 60) ? 0:1 } @@ -166,6 +167,15 @@ internal.currentExercise++ } + function applyCurrentQuestion() { + core.soundController.prepareFromExerciseOptions(chosenExercises) + if (currentExercise["playMode"] != "rhythm") { + instrumentView.noteMark(0, core.exerciseController.chosenRootNote(), 0, "white") + instrumentView.scrollToNote(core.exerciseController.chosenRootNote()) + sheetMusicView.model = [core.exerciseController.chosenRootNote()] + sheetMusicView.clef.type = (core.exerciseController.chosenRootNote() >= 60) ? 0:1 + } + } ColumnLayout { anchors.fill: parent @@ -328,7 +338,7 @@ var array = [core.exerciseController.chosenRootNote()] model.sequence.split(' ').forEach(function(note) { array.push(core.exerciseController.chosenRootNote() + parseInt(note)) - pianoView.noteMark(0, core.exerciseController.chosenRootNote() + parseInt(note), 0, internal.colors[answerRectangle.index]) + instrumentView.noteMark(0, core.exerciseController.chosenRootNote() + parseInt(note), 0, internal.colors[answerRectangle.index]) }) sheetMusicView.model = array } @@ -353,7 +363,7 @@ if (parent.parent == answerGrid) { if (!animation.running) model.sequence.split(' ').forEach(function(note) { - pianoView.noteUnmark(0, core.exerciseController.chosenRootNote() + parseInt(note), 0) + instrumentView.noteUnmark(0, core.exerciseController.chosenRootNote() + parseInt(note), 0) }) sheetMusicView.model = [core.exerciseController.chosenRootNote()] } @@ -414,16 +424,23 @@ anchors.horizontalCenter: parent.horizontalCenter Layout.preferredWidth: parent.width spacing: (parent.width/2 - sheetMusicView.width)/2 - PianoView { - id: pianoView + + InstrumentView { + id: instrumentView width: parent.width/2 - 10 + height: 150 visible: currentExercise != undefined && currentExercise["playMode"] != "rhythm" - ScrollIndicator.horizontal: ScrollIndicator { active: true } + + onSourceChanged: { + if (chosenExercises) + applyCurrentQuestion() + } } + SheetMusicView { id: sheetMusicView - height: pianoView.height + height: instrumentView.height anchors { bottom: parent.bottom; bottomMargin: 15 } visible: currentExercise != undefined && currentExercise["playMode"] != "rhythm" } @@ -470,7 +487,7 @@ } Connections { target: core.exerciseController - onSelectedExerciseOptionsChanged: pianoView.clearAllMarks() + onSelectedExerciseOptionsChanged: instrumentView.clearAllMarks() } Connections { target: core.exerciseController diff --git a/src/app/qml/InstrumentView/InstrumentView.qml b/src/app/qml/InstrumentView/InstrumentView.qml new file mode 100644 --- /dev/null +++ b/src/app/qml/InstrumentView/InstrumentView.qml @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 by Stefan Toncu +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License or (at your option) version 3 or any later version +** accepted by the membership of KDE e.V. (or its successor approved +** by the membership of KDE e.V.), which shall act as a proxy +** defined in Section 14 of version 3 of the license. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +** +****************************************************************************/ +import QtQuick.Controls 2.2 +import QtQuick 2.7 + +Item { + id: instrumentView + + property alias source: pluginMainPageLoader2.source + + function noteOn(chan, pitch, vel) { + if (pluginMainPageLoader2.item) + pluginMainPageLoader2.item.noteOn(chan, pitch, vel) + } + function noteOff(chan, pitch, vel) { + if (pluginMainPageLoader2.item) + pluginMainPageLoader2.item.noteOff(chan, pitch, vel) + } + function noteMark(chan, pitch, vel, color) { + if (pluginMainPageLoader2.item) + pluginMainPageLoader2.item.noteMark(chan, pitch, vel, color) + } + function noteUnmark(chan, pitch, vel, color) { + if (pluginMainPageLoader2.item) + pluginMainPageLoader2.item.noteUnmark(chan, pitch, vel, color) + } + function clearAllMarks() { + if (pluginMainPageLoader2.item) + pluginMainPageLoader2.item.clearAllMarks() + } + function scrollToNote(pitch) { + if (pluginMainPageLoader2.item) + pluginMainPageLoader2.item.scrollToNote(pitch) + } + function highlightKey(pitch, color) { + if (pluginMainPageLoader2.item) + pluginMainPageLoader2.item.highlightKey(pitch, color) + } + function itemForPitch(pitch) { + if (pluginMainPageLoader2.item) + pluginMainPageLoader2.item.itemForPitch(pitch) + } + + TabBar { + id: tabBar + anchors.top: parent.top + Repeater { + id: tabBar_repeater + model: contents + TabButton { + id: button + text: qsTr(modelData.menuName) + onClicked: { + console.log(modelData.pluginName + "/" + modelData.mainPage) + pluginMainPageLoader2.setSource("file://" + modelData.pluginName + "/" + modelData.mainPage) + } + } + } + } + + Rectangle { + id: frame + width: parent.width + height: parent.height - tabBar.height + anchors.bottom: parent.bottom + color: "grey" + Loader { + anchors.fill: parent + id: pluginMainPageLoader2 + } + } + + Component.onCompleted: { + //load the first available plugin instrument + if (!contents[0]) + console.log("No plugin available!") + else + pluginMainPageLoader2.source = "file://" + contents[0].pluginName + "/" + contents[0].mainPage + } +} diff --git a/src/app/qml/Main.qml b/src/app/qml/Main.qml --- a/src/app/qml/Main.qml +++ b/src/app/qml/Main.qml @@ -21,7 +21,7 @@ ****************************************************************************/ import QtQuick 2.7 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtQuick.Window 2.0 import QtQuick.Controls.Material 2.0 diff --git a/src/app/uicontroller.h b/src/app/uicontroller.h --- a/src/app/uicontroller.h +++ b/src/app/uicontroller.h @@ -24,6 +24,7 @@ #define MINUET_UICONTROLLER_H #include +#include #ifdef Q_OS_ANDROID #include @@ -59,8 +60,10 @@ public: UiController(QObject *parent = 0); ~UiController() override; + QQmlApplicationEngine *engine; bool initialize(Core *core); + bool initializePlugins(); virtual QString errorString() const; private: diff --git a/src/app/uicontroller.cpp b/src/app/uicontroller.cpp --- a/src/app/uicontroller.cpp +++ b/src/app/uicontroller.cpp @@ -29,6 +29,17 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #ifndef Q_OS_ANDROID #include #endif @@ -45,10 +56,33 @@ { } +bool UiController::initializePlugins() +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + QString directoryName = "plugins"; + QString minuet_dir = QStandardPaths::locate(QStandardPaths::AppDataLocation, directoryName, QStandardPaths::LocateDirectory); + QDir dir(minuet_dir); + qDebug()<applicationDirPath(); + QString contents; + QJsonArray mergedArray; + foreach(const QString &fileName, dir.entryList(QStringList() << "*.json")) { + QFile dfile(dir.absoluteFilePath(fileName)); + dfile.open(QIODevice::ReadOnly); + QJsonObject jsonObject = QJsonDocument::fromJson(dfile.readAll()).object(); + QDir pluginDir(dir); + pluginDir.cd(fileName.split('.').first()); + jsonObject["pluginName"] = pluginDir.absolutePath(); + mergedArray.append(jsonObject); + dfile.close(); + } + engine->rootContext()->setContextProperty("contents", mergedArray); +} + bool UiController::initialize(Core *core) { m_errorString.clear(); - QQmlApplicationEngine *engine = new QQmlApplicationEngine(this); + engine = new QQmlApplicationEngine(this); QQmlContext *rootContext = engine->rootContext(); rootContext->setContextProperty(QStringLiteral("core"), core); #ifndef Q_OS_ANDROID @@ -56,6 +90,8 @@ #else rootContext->setContextObject(new DummyAndroidLocalizer(engine)); #endif + + initializePlugins(); engine->load(QUrl("qrc:/Main.qml")); return true;