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 }