Warning, /education/gcompris/src/activities/play_piano/PlayPiano.qml is written in an unsupported language. File is not indexed.
0001 /* GCompris - PlayPiano.qml
0002 *
0003 * SPDX-FileCopyrightText: 2018 Aman Kumar Gupta <gupta2140@gmail.com>
0004 *
0005 * Authors:
0006 * Beth Hadley <bethmhadley@gmail.com> (GTK+ version)
0007 * Aman Kumar Gupta <gupta2140@gmail.com> (Qt Quick port)
0008 *
0009 * SPDX-License-Identifier: GPL-3.0-or-later
0010 */
0011 import QtQuick 2.12
0012 import GCompris 1.0
0013
0014 import "../../core"
0015 import "../piano_composition"
0016 import "play_piano.js" as Activity
0017
0018 ActivityBase {
0019 id: activity
0020
0021 onStart: focus = true
0022 onStop: {}
0023 isMusicalActivity: true
0024
0025 property bool horizontalLayout: width >= height * 1.2
0026
0027 pageComponent: Rectangle {
0028 id: background
0029 anchors.fill: parent
0030 color: "#ABCDEF"
0031 signal start
0032 signal stop
0033
0034 // if audio is disabled, we display a dialog to tell users this activity requires audio anyway
0035 property bool audioDisabled: false
0036
0037 Component.onCompleted: {
0038 dialogActivityConfig.initialize()
0039 activity.start.connect(start)
0040 activity.stop.connect(stop)
0041 }
0042
0043 Keys.onPressed: {
0044 if(items.buttonsBlocked)
0045 return;
0046
0047 var keyboardBindings = {}
0048 keyboardBindings[Qt.Key_1] = 0
0049 keyboardBindings[Qt.Key_2] = 1
0050 keyboardBindings[Qt.Key_3] = 2
0051 keyboardBindings[Qt.Key_4] = 3
0052 keyboardBindings[Qt.Key_5] = 4
0053 keyboardBindings[Qt.Key_6] = 5
0054 keyboardBindings[Qt.Key_7] = 6
0055 keyboardBindings[Qt.Key_8] = 7
0056 keyboardBindings[Qt.Key_F2] = 1
0057 keyboardBindings[Qt.Key_F3] = 2
0058 keyboardBindings[Qt.Key_F5] = 4
0059 keyboardBindings[Qt.Key_F6] = 5
0060 keyboardBindings[Qt.Key_F7] = 6
0061
0062 if(piano.whiteKeysEnabled && !iAmReady.visible) {
0063 if(event.key >= Qt.Key_1 && event.key <= Qt.Key_8) {
0064 piano.keyRepeater.playKey(keyboardBindings[event.key], "white");
0065 }
0066 else if(event.key >= Qt.Key_F2 && event.key <= Qt.Key_F7) {
0067 if(piano.blackKeysEnabled)
0068 piano.keyRepeater.playKey(keyboardBindings[event.key], "black");
0069 }
0070 else if(event.key === Qt.Key_Space) {
0071 multipleStaff.play()
0072 }
0073 else if(event.key === Qt.Key_Backspace || event.key === Qt.Key_Delete) {
0074 Activity.undoPreviousAnswer()
0075 }
0076 } else if(iAmReady.visible) {
0077 iAmReady.visible = false;
0078 iAmReady.clicked();
0079 }
0080 }
0081
0082 // Add here the QML items you need to access in javascript
0083 QtObject {
0084 id: items
0085 property Item main: activity.main
0086 property alias background: background
0087 property GCSfx audioEffects: activity.audioEffects
0088 property alias multipleStaff: multipleStaff
0089 property alias piano: piano
0090 property int currentLevel: activity.currentLevel
0091 property alias bonus: bonus
0092 property alias score: score
0093 property alias iAmReady: iAmReady
0094 property alias introductoryAudioTimer: introductoryAudioTimer
0095 property alias parser: parser
0096 property alias answerFeedbackTimer: answerFeedbackTimer
0097 property string mode: "coloredNotes"
0098 property bool buttonsBlocked: false
0099 }
0100
0101 onStart: {
0102 if(!ApplicationSettings.isAudioVoicesEnabled || !ApplicationSettings.isAudioEffectsEnabled) {
0103 background.audioDisabled = true;
0104 }
0105 Activity.start(items);
0106 }
0107 onStop: { Activity.stop() }
0108
0109 property string clefType: (items.bar.level <= 5) ? "Treble" : "Bass"
0110
0111 Timer {
0112 id: introductoryAudioTimer
0113 interval: 4000
0114 onRunningChanged: {
0115 if(running)
0116 Activity.isIntroductoryAudioPlaying = true
0117 else {
0118 Activity.isIntroductoryAudioPlaying = false
0119 Activity.initSubLevel()
0120 }
0121 }
0122 }
0123
0124 Timer {
0125 id: answerFeedbackTimer
0126 interval: 1000
0127 onRunningChanged: {
0128 if(!running)
0129 Activity.answerFeedback()
0130 }
0131 }
0132
0133 JsonParser {
0134 id: parser
0135 }
0136
0137 Rectangle {
0138 anchors.fill: parent
0139 color: "black"
0140 opacity: 0.3
0141 visible: iAmReady.visible
0142 z: 10
0143 MouseArea {
0144 anchors.fill: parent
0145 }
0146 }
0147
0148 ReadyButton {
0149 id: iAmReady
0150 focus: true
0151 z: 10
0152 onClicked: {
0153 Activity.initLevel()
0154 }
0155 }
0156
0157 Score {
0158 id: score
0159 anchors.top: background.top
0160 anchors.bottom: undefined
0161 numberOfSubLevels: 5
0162 width: horizontalLayout ? parent.width / 10 : (parent.width - instruction.x - instruction.width - 1.5 * anchors.rightMargin)
0163 onStop: Activity.nextSubLevel()
0164 }
0165
0166 Rectangle {
0167 id: instruction
0168 radius: 10
0169 width: background.width * 0.6
0170 height: background.height / 9
0171 anchors.horizontalCenter: parent.horizontalCenter
0172 opacity: 0.8
0173 border.width: 6
0174 color: "white"
0175 border.color: "#87A6DD"
0176
0177 GCText {
0178 color: "black"
0179 z: 3
0180 anchors.fill: parent
0181 anchors.rightMargin: parent.width * 0.02
0182 anchors.leftMargin: parent.width * 0.02
0183 horizontalAlignment: Text.AlignHCenter
0184 verticalAlignment: Text.AlignVCenter
0185 fontSizeMode: Text.Fit
0186 wrapMode: Text.WordWrap
0187 text: qsTr("Click on the piano keys that match the given notes.")
0188 }
0189 }
0190
0191 MultipleStaff {
0192 id: multipleStaff
0193 width: horizontalLayout ? parent.width * 0.5 : parent.width * 0.8
0194 height: horizontalLayout ? parent.height * 0.85 : parent.height * 0.58
0195 nbStaves: 1
0196 clef: clefType
0197 coloredNotes: (items.mode === "coloredNotes") ? ['C', 'D', 'E', 'F', 'G', 'A', 'B'] : []
0198 isFlickable: false
0199 anchors.horizontalCenter: parent.horizontalCenter
0200 anchors.top: instruction.bottom
0201 anchors.topMargin: horizontalLayout ? parent.height * 0.02 : parent.height * 0.15
0202 onNoteClicked: {
0203 playNoteAudio(musicElementModel.get(noteIndex).noteName_, musicElementModel.get(noteIndex).noteType_, musicElementModel.get(noteIndex).soundPitch_)
0204 }
0205 centerNotesPosition: true
0206 }
0207
0208 PianoOctaveKeyboard {
0209 id: piano
0210 width: horizontalLayout ? parent.width * 0.5 : parent.width * 0.7
0211 height: parent.height * 0.3
0212 anchors.horizontalCenter: parent.horizontalCenter
0213 anchors.bottom: bar.top
0214 anchors.bottomMargin: 20
0215 blackLabelsVisible: ([4, 5, 9, 10].indexOf(bar.level) != -1)
0216 blackKeysEnabled: blackLabelsVisible && !multipleStaff.isMusicPlaying && !introductoryAudioTimer.running && !items.buttonsBlocked
0217 whiteKeysEnabled: !multipleStaff.isMusicPlaying && !introductoryAudioTimer.running && !items.buttonsBlocked
0218 whiteKeyNoteLabelsTreble: [ whiteKeyNoteLabelsArray.slice(18, 26) ]
0219 whiteKeyNoteLabelsBass: [ whiteKeyNoteLabelsArray.slice(11, 19)]
0220 onNoteClicked: {
0221 multipleStaff.playNoteAudio(note, "Quarter", clefType, 500)
0222 Activity.checkAnswer(note)
0223 }
0224 useSharpNotation: true
0225 playPianoActivity: true
0226 }
0227
0228 Rectangle {
0229 id: optionDeck
0230 width: optionsRow.changeAccidentalStyleButtonVisible ? optionsRow.iconsWidth * 3.3 : optionsRow.iconsWidth * 2.2
0231 height: optionsRow.iconsWidth * 1.1
0232 color: "white"
0233 opacity: 0.5
0234 radius: 10
0235 y: horizontalLayout ? piano.y : multipleStaff.y / 2 + instruction.height - height / 2
0236 x: horizontalLayout ? multipleStaff.x + multipleStaff.width + 25 : background.width / 2 - width / 2
0237 }
0238
0239 OptionsRow {
0240 id: optionsRow
0241 anchors.centerIn: optionDeck
0242
0243 playButtonVisible: true
0244 undoButtonVisible: true
0245
0246 onUndoButtonClicked: Activity.undoPreviousAnswer()
0247 }
0248 MouseArea {
0249 id: optionsRowLock
0250 anchors.fill: optionsRow
0251 enabled: items.buttonsBlocked
0252 }
0253
0254 DialogChooseLevel {
0255 id: dialogActivityConfig
0256 currentActivity: activity.activityInfo
0257
0258 onClose: {
0259 home()
0260 }
0261 onLoadData: {
0262 if(activityData && activityData["mode"]) {
0263 items.mode = activityData["mode"];
0264 }
0265 }
0266 onVisibleChanged: {
0267 multipleStaff.eraseAllNotes()
0268 iAmReady.visible = true
0269 }
0270 }
0271
0272 DialogHelp {
0273 id: dialogHelp
0274 onClose: home()
0275 }
0276
0277 Bar {
0278 id: bar
0279 level: items.currentLevel + 1
0280 content: BarEnumContent { value: help | home | level | activityConfig }
0281 onHelpClicked: displayDialog(dialogHelp)
0282 onPreviousLevelClicked: Activity.previousLevel()
0283 onNextLevelClicked: Activity.nextLevel()
0284 onHomeClicked: activity.home()
0285 onActivityConfigClicked: {
0286 displayDialog(dialogActivityConfig)
0287 }
0288 }
0289
0290 Bonus {
0291 id: bonus
0292 Component.onCompleted: win.connect(Activity.nextLevel)
0293 }
0294
0295 Loader {
0296 id: audioNeededDialog
0297 sourceComponent: GCDialog {
0298 parent: activity
0299 isDestructible: false
0300 message: qsTr("This activity requires sound, so it will play some sounds even if the audio voices or effects are disabled in the main configuration.")
0301 button1Text: qsTr("Quit")
0302 button2Text: qsTr("Continue")
0303 onButton1Hit: activity.home();
0304 onClose: {
0305 background.audioDisabled = false;
0306 }
0307 }
0308 anchors.fill: parent
0309 focus: true
0310 active: background.audioDisabled
0311 onStatusChanged: if (status == Loader.Ready) item.start()
0312 }
0313 }
0314 }