Warning, /education/gcompris/src/activities/play_rhythm/PlayRhythm.qml is written in an unsupported language. File is not indexed.
0001 /* GCompris - PlayRhythm.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_rhythm.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 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 activity.start.connect(start) 0039 activity.stop.connect(stop) 0040 } 0041 0042 // Add here the QML items you need to access in javascript 0043 QtObject { 0044 id: items 0045 property Item main: activity.main 0046 property GCSfx audioEffects: activity.audioEffects 0047 property alias background: background 0048 property int currentLevel: activity.currentLevel 0049 property alias bonus: bonus 0050 property alias parser: parser 0051 property alias score: score 0052 property alias multipleStaff: multipleStaff 0053 property alias iAmReady: iAmReady 0054 property alias introductoryAudioTimer: introductoryAudioTimer 0055 property alias metronomeOscillation: metronomeOscillation 0056 property alias answerFeedbackTimer: answerFeedbackTimer 0057 property bool isMetronomeVisible: false 0058 property bool isWrongRhythm: false 0059 property bool buttonsBlocked: false 0060 property bool crashPlayed: false 0061 } 0062 0063 onStart: { 0064 if(!ApplicationSettings.isAudioVoicesEnabled || !ApplicationSettings.isAudioEffectsEnabled) { 0065 background.audioDisabled = true; 0066 } 0067 Activity.start(items); 0068 } 0069 onStop: { Activity.stop() } 0070 0071 property string clefType: "Treble" 0072 property bool isRhythmPlaying: false 0073 property int metronomeSpeed: 60000 / multipleStaff.bpmValue - 53 0074 property real weightOffset: metronome.height * multipleStaff.bpmValue * 0.004 0075 0076 Keys.onSpacePressed: if(!background.isRhythmPlaying && !items.buttonsBlocked) 0077 tempo.tempoPressed(); 0078 Keys.onTabPressed: if(metronome.visible && metronomeOscillation.running) 0079 metronomeOscillation.stop(); 0080 else if(metronome.visible && !metronomeOscillation.running) 0081 metronomeOscillation.start(); 0082 Keys.onEnterPressed: Activity.initSubLevel(); 0083 Keys.onReturnPressed: Activity.initSubLevel(); 0084 Keys.onUpPressed: optionsRow.bpmIncreased(); 0085 Keys.onDownPressed: optionsRow.bpmDecreased(); 0086 Keys.onReleased: { 0087 if(iAmReady.visible) { 0088 iAmReady.visible = false; 0089 Activity.initLevel(); 0090 } else if(event.key === Qt.Key_Up || event.key === Qt.Key_Down) { 0091 bpmChangeDelay.restart(); 0092 } 0093 } 0094 0095 Rectangle { 0096 id: instructionBox 0097 radius: 10 0098 width: background.width * 0.7 0099 height: background.height / 9 0100 anchors.horizontalCenter: parent.horizontalCenter 0101 opacity: 0.8 0102 border.width: 6 0103 color: "white" 0104 border.color: "#87A6DD" 0105 0106 GCText { 0107 id: instructionText 0108 color: "black" 0109 z: 3 0110 anchors.fill: parent 0111 anchors.rightMargin: parent.width * 0.02 0112 anchors.leftMargin: parent.width * 0.02 0113 horizontalAlignment: Text.AlignHCenter 0114 verticalAlignment: Text.AlignVCenter 0115 fontSizeMode: Text.Fit 0116 wrapMode: Text.WordWrap 0117 text: items.isMetronomeVisible ? qsTr("Use the metronome to estimate the time intervals and play the rhythm correctly.") 0118 : qsTr("Follow the vertical line and click on the drum or press space key to play the rhythm correctly.") 0119 } 0120 } 0121 0122 Timer { 0123 id: introductoryAudioTimer 0124 interval: 3500 0125 onRunningChanged: { 0126 if(running) 0127 Activity.isIntroductoryAudioPlaying = true 0128 else { 0129 Activity.isIntroductoryAudioPlaying = false 0130 Activity.initSubLevel() 0131 } 0132 } 0133 } 0134 0135 Timer { 0136 id: bpmChangeDelay 0137 interval: 500 0138 onTriggered: { 0139 Activity.initSubLevel(); 0140 background.isRhythmPlaying = true; 0141 } 0142 } 0143 0144 Timer { 0145 id: answerFeedbackTimer 0146 interval: 1000 0147 onRunningChanged: { 0148 if (!running) { 0149 if(!items.crashPlayed) 0150 Activity.answerFeedback(); 0151 else { 0152 items.crashPlayed = false; 0153 Activity.initSubLevel(); 0154 } 0155 } 0156 } 0157 } 0158 0159 JsonParser { 0160 id: parser 0161 } 0162 0163 Rectangle { 0164 anchors.fill: parent 0165 color: "black" 0166 opacity: 0.3 0167 visible: iAmReady.visible 0168 z: 10 0169 MouseArea { 0170 anchors.fill: parent 0171 } 0172 } 0173 0174 ReadyButton { 0175 id: iAmReady 0176 focus: true 0177 z: 10 0178 onClicked: { 0179 Activity.initLevel() 0180 } 0181 } 0182 0183 Score { 0184 id: score 0185 anchors.top: background.top 0186 anchors.bottom: undefined 0187 numberOfSubLevels: 3 0188 width: horizontalLayout ? parent.width / 10 : (parent.width - instructionBox.x - instructionBox.width - 1.5 * anchors.rightMargin) 0189 onStop: Activity.nextSubLevel() 0190 } 0191 0192 MultipleStaff { 0193 id: multipleStaff 0194 width: horizontalLayout ? parent.width * 0.6 : parent.width * 0.9 0195 height: horizontalLayout ? parent.height * 1.1 : parent.height * 0.76 0196 bpmValue: 90 0197 nbStaves: 1 0198 clef: clefType 0199 isFlickable: false 0200 anchors.horizontalCenter: parent.horizontalCenter 0201 anchors.top: parent.top 0202 anchors.topMargin: horizontalLayout ? 0 : parent.height * 0.1 0203 centerNotesPosition: true 0204 firstCenteredNotePosition: width / (2 * (musicElementModel.count - 1)) 0205 spaceBetweenNotes: width / (2.5 * (musicElementModel.count - 1)) 0206 enableNotesSound: false 0207 onPulseMarkerAnimationFinished: background.isRhythmPlaying = false 0208 onPlayDrumSound: { 0209 if(background.isRhythmPlaying && !metronomeOscillation.running) 0210 GSynth.generate(60, 100) 0211 } 0212 } 0213 0214 Image { 0215 id: tempo 0216 source: "qrc:/gcompris/src/activities/play_rhythm/resource/drumhead.svg" 0217 width: horizontalLayout ? parent.width / 7 : parent.width / 4 0218 sourceSize.width: width 0219 fillMode: Image.PreserveAspectFit 0220 anchors.top: metronome.top 0221 anchors.horizontalCenter: parent.horizontalCenter 0222 transform: Scale { 0223 id: tempoScale 0224 origin.y: tempo.height 0225 yScale: 1 0226 SequentialAnimation on yScale { 0227 id: tempoAnim 0228 PropertyAnimation { to: 0.5; duration: 50 } 0229 PropertyAnimation { to: 1; duration: 50 } 0230 } 0231 } 0232 MouseArea { 0233 anchors.fill: parent 0234 enabled: !background.isRhythmPlaying && !items.buttonsBlocked 0235 onPressed: tempo.tempoPressed() 0236 } 0237 0238 function tempoPressed() { 0239 tempoAnim.start() 0240 if(!multipleStaff.isMusicPlaying && Activity.currentNote == 0) { 0241 multipleStaff.play() 0242 } 0243 GSynth.generate(60, 100) 0244 Activity.checkAnswer(multipleStaff.pulseMarkerX) 0245 } 0246 } 0247 0248 Image { 0249 id: metronome 0250 source: "qrc:/gcompris/src/activities/play_rhythm/resource/metronome_stand.svg" 0251 fillMode: Image.PreserveAspectFit 0252 sourceSize.width: parent.width / 3 0253 sourceSize.height: parent.height / 4 0254 width: sourceSize.width 0255 height: sourceSize.height 0256 anchors.bottom: bar.top 0257 anchors.bottomMargin: 20 0258 visible: items.isMetronomeVisible 0259 MouseArea { 0260 anchors.fill: parent 0261 onClicked: { 0262 if(metronomeOscillation.running) 0263 metronomeOscillation.stop() 0264 else 0265 metronomeOscillation.start() 0266 } 0267 } 0268 0269 Image { 0270 id: metronomeNeedle 0271 source: "qrc:/gcompris/src/activities/play_rhythm/resource/metronome_needle.svg" 0272 fillMode: Image.PreserveAspectFit 0273 width: parent.height 0274 height: parent.height 0275 anchors.centerIn: parent 0276 transformOrigin: Item.Bottom 0277 SequentialAnimation { 0278 id: metronomeOscillation 0279 loops: Animation.Infinite 0280 onStarted: metronomeNeedle.rotation = 12 0281 onStopped: metronomeNeedle.rotation = 0 0282 ScriptAction { 0283 script: items.audioEffects.play("qrc:/gcompris/src/activities/play_rhythm/resource/click.wav") 0284 } 0285 RotationAnimator { 0286 target: metronomeNeedle 0287 from: 12 0288 to: 348 0289 direction: RotationAnimator.Shortest 0290 duration: metronomeSpeed 0291 } 0292 ScriptAction { 0293 script: items.audioEffects.play("qrc:/gcompris/src/activities/play_rhythm/resource/click.wav") 0294 } 0295 RotationAnimator { 0296 target: metronomeNeedle 0297 from: 348 0298 to: 12 0299 direction: RotationAnimator.Shortest 0300 duration: metronomeSpeed 0301 } 0302 } 0303 Image { 0304 id: metronomeWeight 0305 source: "qrc:/gcompris/src/activities/play_rhythm/resource/metronome_weight.svg" 0306 fillMode: Image.PreserveAspectFit 0307 width: parent.height 0308 height: parent.height 0309 anchors.horizontalCenter: parent.horizontalCenter 0310 anchors.verticalCenter: parent.verticalCenter 0311 anchors.verticalCenterOffset: weightOffset 0312 } 0313 0314 } 0315 Image { 0316 id: metronomeFront 0317 source: "qrc:/gcompris/src/activities/play_rhythm/resource/metronome_front.svg" 0318 fillMode: Image.PreserveAspectFit 0319 width: parent.height 0320 height: parent.height 0321 anchors.centerIn: parent 0322 } 0323 } 0324 0325 OptionsRow { 0326 id: optionsRow 0327 anchors.verticalCenter: tempo.verticalCenter 0328 anchors.left: tempo.right 0329 0330 bpmVisible: true 0331 onBpmDecreased: { 0332 if(multipleStaff.bpmValue >= 51) 0333 multipleStaff.bpmValue-- 0334 } 0335 onBpmIncreased: { 0336 if(multipleStaff.bpmValue <= 179) 0337 multipleStaff.bpmValue++ 0338 } 0339 onBpmChanged: { 0340 bpmChangeDelay.restart(); 0341 } 0342 } 0343 0344 DialogHelp { 0345 id: dialogHelp 0346 onClose: home() 0347 } 0348 0349 Bar { 0350 id: bar 0351 level: items.currentLevel + 1 0352 content: BarEnumContent { value: help | home | level | reload } 0353 onHelpClicked: { 0354 displayDialog(dialogHelp) 0355 } 0356 onPreviousLevelClicked: Activity.previousLevel() 0357 onNextLevelClicked: Activity.nextLevel() 0358 onHomeClicked: activity.home() 0359 onReloadClicked: { 0360 Activity.initSubLevel() 0361 } 0362 } 0363 0364 Bonus { 0365 id: bonus 0366 Component.onCompleted: { 0367 win.connect(Activity.nextLevel) 0368 } 0369 } 0370 0371 Loader { 0372 id: audioNeededDialog 0373 sourceComponent: GCDialog { 0374 parent: activity 0375 isDestructible: false 0376 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.") 0377 button1Text: qsTr("Quit") 0378 button2Text: qsTr("Continue") 0379 onButton1Hit: activity.home(); 0380 onClose: { 0381 background.audioDisabled = false; 0382 } 0383 } 0384 anchors.fill: parent 0385 focus: true 0386 active: background.audioDisabled 0387 onStatusChanged: if (status == Loader.Ready) item.start() 0388 } 0389 } 0390 }