diff --git a/src/activities/note_names/NoteNames.qml b/src/activities/note_names/NoteNames.qml index 6b010abf8..31bb6fd63 100755 --- a/src/activities/note_names/NoteNames.qml +++ b/src/activities/note_names/NoteNames.qml @@ -1,382 +1,444 @@ /* GCompris - NoteNames.qml * * Copyright (C) 2016 Johnny Jazeix * * Authors: * Beth Hadley (GTK+ version) * Johnny Jazeix (Qt Quick port) * * 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 3 of the License, or * (at your option) any later version. * * 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.1 import QtQuick.Controls 1.0 import GCompris 1.0 import "../../core" import "../playpiano" import "note_names.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} pageComponent: Rectangle { id: background anchors.fill: parent color: "#ABCDEF" property bool keyboardMode: false property bool horizontalLayout: background.width > background.height ? true : false signal start signal stop Component.onCompleted: { activity.start.connect(start) activity.stop.connect(stop) } // Add here the QML items you need to access in javascript QtObject { id: items property Item main: activity.main property alias background: background property GCAudio audioEffects: activity.audioEffects property alias staff: staff property alias bar: bar property alias bonus: bonus property alias gridRepeater: gridRepeater property alias bottomNotesRepeater: bottomNotesRepeater property alias okButton: okButton property alias score: score } onStart: { Activity.start(items) } onStop: { Activity.stop() } Rectangle { id: instructionBox radius: 10 width: background.width / 1.9 height: horizontalLayout ? background.height / 5 : background.height / 4 anchors.horizontalCenter: parent.horizontalCenter opacity: 0.8 border.width: 6 color: "white" border.color: "#87A6DD" GCText { id: instructionText visible: !staffText.visible color: "black" z: 3 anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter fontSizeMode: Text.Fit wrapMode: Text.WordWrap text: [2, 3, 4, 12, 13, 14].indexOf(bar.level) !== -1 ? qsTr("Click on the note name to match the pitch. Then click OK to check.") : [5, 6, 7, 15, 16, 17].indexOf(bar.level) !== -1 ? qsTr("Now there are sharp notes. These pitches are raised a half step.") : // [8, 9, 10, 18, 19, 20] qsTr("Now there are flat notes. These pitches are lowered a half step.") } GCText { id: staffText visible: bar.level == 1 || bar.level == 11 height: background.height / 5 width: background.width / 1.5 z: 3 color: "black" fontSizeMode: Text.Fit anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap text: bar.level == 1 ? qsTr("These are the eight basic notes in treble clef. They form the C Major Scale.") : qsTr("These are the eight basic notes in bass clef. They also form the C Major Scale. Notice that the note positions are different than in treble clef.") } } + Rectangle { + id: playScale + width: horizontalLayout ? parent.width * 0.3 : parent.width * 0.35 + height: 30 * ApplicationInfo.ratio + color: "#d8ffffff" + border.color: "#2a2a2a" + border.width: 3 + radius: 8 + z: 5 + anchors.top: instructionBox.bottom + anchors.topMargin: 15 + anchors.left: background.left + anchors.leftMargin: background.width * 0.15 + visible: bar.level == 1 || bar.level == 11 + + GCText { + id: playScaleText + anchors.centerIn: parent + text: qsTr("Play scale") + fontSizeMode: Text.Fit + wrapMode: Text.Wrap + } + + MouseArea { + id: playScaleArea + anchors.fill: parent + onClicked: { + for(var i = 0; i < Activity.bottomNotes.length; i++) { + var noteToPlay = 'qrc:/gcompris/src/activities/playpiano/resource/' + 'bass' + '_pitches/' + '1' + '/' + Activity.bottomNotes[i].note + '.wav'; + print(noteToPlay) + items.audioEffects.play(noteToPlay) + } + } + } + states: [ + State { + name: "notclicked" + PropertyChanges { + target: playScale + scale: 1.0 + } + }, + State { + name: "clicked" + when: playScaleArea.pressed + PropertyChanges { + target: playScale + scale: 0.9 + } + }, + State { + name: "hover" + when: playScaleArea.containsMouse + PropertyChanges { + target: playScale + scale: 1.1 + } + } + ] + Behavior on scale { NumberAnimation { duration: 70 } } + } + Rectangle { id: playButton - width: horizontalLayout ? parent.width * 0.3 : parent.width * 0.45 + width: horizontalLayout ? parent.width * 0.3 : parent.width * 0.35 height: 30 * ApplicationInfo.ratio color: "#d8ffffff" border.color: "#2a2a2a" border.width: 3 radius: 8 z: 5 anchors.top: instructionBox.bottom anchors.topMargin: 15 - anchors.horizontalCenter: parent.horizontalCenter + anchors.leftMargin: 30 + anchors.left: playScale.right visible: bar.level == 1 || bar.level == 11 GCText { id: playButtonText anchors.centerIn: parent text: qsTr("Start levels") fontSizeMode: Text.Fit wrapMode: Text.Wrap } MouseArea { id: playButtonArea anchors.fill: parent onClicked: { - Activity.nextLevel() + Activity.nextLevel() } } states: [ State { name: "notclicked" PropertyChanges { target: playButton scale: 1.0 } }, State { name: "clicked" when: playButtonArea.pressed PropertyChanges { target: playButton scale: 0.9 } }, State { name: "hover" when: playButtonArea.containsMouse PropertyChanges { target: playButton scale: 1.1 } } ] Behavior on scale { NumberAnimation { duration: 70 } } } MultipleStaff { id: staff nbStaves: 1 clef: bar.level <= 10 ? "treble" : "bass" height: background.height / 4 width: bar.level == 1 || bar.level == 11 ? background.width * 0.8 : background.width / 2 anchors.bottom: bar.top anchors.bottomMargin: bar.height anchors.horizontalCenter: bar.level == 1 || bar.level == 11 ? parent.horizontalCenter : undefined nbMaxNotesPerStaff: bar.level == 1 || bar.level == 11 ? 8 : 1 firstNoteX: bar.level == 1 || bar.level == 11 ? width / 5 : width / 2 } Grid { id: bottomNotesGrid rows: 1 spacing: horizontalLayout ? background.width * 0.03 : background.width * 0.01 anchors.bottom: background.bottom anchors.bottomMargin: background.height * 0.01 anchors.horizontalCenter: parent.horizontalCenter height: staff.height visible: (bar.level == 1 || bar.level == 11) ? true : false property int itemWidth: horizontalLayout ? background.width * 0.05 : background.width * 0.1 property int itemHeight: itemWidth Repeater { id: bottomNotesRepeater model: Activity.bottomNotes Rectangle { id: notes color: dummyNote.noteColorMap[Activity.bottomNotes[index].note] width: bottomNotesGrid.itemWidth height: bottomNotesGrid.itemHeight radius: width / 5 border.color: "black" GCText { id: bottomNotesText text: parseInt(Activity.bottomNotes[0].note) > 0 ? dummyNote.whiteNoteName[Activity.bottomNotes[index].note] : dummyNote.blackNoteName[Activity.bottomNotes[index].note] anchors.centerIn: parent fontSizeMode: Text.Fit horizontalAlignment: Text.AlignHCenter } MouseArea { id: buttonClick anchors.fill: parent onClicked: { - print(JSON.stringify(Activity.bottomNotes[index].note)) select() } } function select() { grid.currentIndex = index - var noteToPlay = 'qrc:/gcompris/src/activities/playpiano/resource/' + 'bass' + '_pitches/' + '1' + '/' + note + '.wav'; + var noteToPlay = 'qrc:/gcompris/src/activities/playpiano/resource/' + 'bass' + '_pitches/' + '1' + '/' + Activity.bottomNotes[index].note + '.wav'; items.audioEffects.play(noteToPlay); } } } } DialogHelp { id: dialogHelp onClose: home() } Keys.onPressed: { if(event.key === Qt.Key_Space) { grid.currentItem.select() } } Keys.onReleased: { keyboardMode = true event.accepted = false } Keys.onEnterPressed: { - print(grid) grid.currentItem.select(); } Keys.onReturnPressed: { grid.currentItem.select(); Activity.checkAnswer(okButton.currentAnswer); } Keys.onRightPressed: grid.moveCurrentIndexRight(); Keys.onLeftPressed: grid.moveCurrentIndexLeft(); Keys.onDownPressed: grid.moveCurrentIndexDown(); Keys.onUpPressed: grid.moveCurrentIndexUp(); ListModel { id: gridRepeater } GridView { id: grid visible: instructionText.visible anchors { left: staff.right right: background.right leftMargin: 15 * ApplicationInfo.ratio rightMargin: 50 * ApplicationInfo.ratio top: playButton.bottom } keyNavigationWraps: true interactive: false model: gridRepeater cellWidth: itemWidth + 10 cellHeight: itemHeight + 10 height: staff.height property int itemWidth: 60 property int itemHeight: itemWidth delegate: Rectangle { id: highlightRectangle width: grid.itemWidth * 1.15 height: grid.itemHeight * 1.15 radius: width / 5 - color: "transparent" + color: index === grid.currentIndex ? "red" : "transparent" + border.color: index === grid.currentIndex ? "white" : "transparent" + Rectangle { id: noteRectangle color: staff.noteIsColored ? dummyNote.noteColorMap[note] : "white" width: grid.itemWidth height: grid.itemHeight radius: width / 5 border.color: "black" anchors.centerIn: parent visible: true GCText { id: noteText text: parseInt(note) > 0 ? dummyNote.whiteNoteName[note] : dummyNote.blackNoteName[note] anchors.centerIn: parent fontSizeMode: Text.Fit horizontalAlignment: Text.AlignHCenter } MouseArea { id: buttonClick anchors.fill: parent onClicked: select() } } function select() { - highlightRectangle.color = "red" grid.currentIndex = index var noteToPlay = 'qrc:/gcompris/src/activities/playpiano/resource/' + 'bass' + '_pitches/' + '1' + '/' + note + '.wav'; items.audioEffects.play(noteToPlay); okButton.currentAnswer = note } } } // Never visible, only used to access the note names, colors Note { id: dummyNote visible: false value: "1" blackType: [8, 9, 10, 18, 19, 20].indexOf(bar.level) === -1 ? "sharp" : "flat" } Image { id: okButton visible: instructionText.visible source:"qrc:/gcompris/src/core/resource/bar_ok.svg" width: parent.width * 0.1 height: parent.width * 0.1 anchors { right: background.right bottom: score.top bottomMargin: 20 rightMargin: 20 } property string currentAnswer: "" MouseArea { anchors.fill: parent onClicked: { if(okButton.currentAnswer !== "") Activity.checkAnswer(okButton.currentAnswer); okButton.currentAnswer = "" } } } Bar { id: bar content: BarEnumContent { value: (bar.level == 1 || bar.level == 11) ? (help | home) : (help | home | level | reload) } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() onReloadClicked: Activity.reloadLevel() } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextLevel) } Score { id: score anchors.bottom: background.bottom anchors.right: background.right visible: bar.level !== 1 && bar.level !== 11 } } } diff --git a/src/activities/playpiano/Playpiano.qml b/src/activities/playpiano/Playpiano.qml index d9f7e8a52..eb7f9c56e 100644 --- a/src/activities/playpiano/Playpiano.qml +++ b/src/activities/playpiano/Playpiano.qml @@ -1,202 +1,204 @@ /* GCompris - playpiano.qml * * Copyright (C) 2016 Johnny Jazeix * * Authors: * Beth Hadley (GTK+ version) * Johnny Jazeix (Qt Quick port) * * 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 3 of the License, or * (at your option) any later version. * * 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.1 import QtQuick.Controls 1.0 import "../../core" import "playpiano.js" as Activity import "melodies.js" as Dataset ActivityBase { id: activity onStart: focus = true onStop: {} + property bool horizontalLayout: background.width > background.height ? true : false + pageComponent: Rectangle { id: background anchors.fill: parent color: "#ABCDEF" signal start signal stop Component.onCompleted: { activity.start.connect(start) activity.stop.connect(stop) } // Add here the QML items you need to access in javascript QtObject { id: items property Item main: activity.main property alias background: background property GCAudio audioEffects: activity.audioEffects property alias bar: bar property alias bonus: bonus } onStart: { Activity.start(items) } onStop: { Activity.stop() } property int currentType: 1 MultipleStaff { id: staff2 - width: 400 - height: 400 + width: parent.width * 0.35 + height: parent.height * 0.5 nbStaves: 2 clef: "bass" nbMaxNotesPerStaff: 10 noteIsColored: true isMetronomeDisplayed: true anchors.right: parent.right - anchors.rightMargin: 100 anchors.top: parent.top anchors.topMargin: 100 + anchors.rightMargin: 20 } Piano { id: piano - width: background.width * 0.5 - height: background.height * 0.5 + width: horizontalLayout ? parent.width * 0.6 : parent.width * 0.55 + height: horizontalLayout ? parent.height * 0.65 : parent.width * 0.45 anchors.right: staff2.left - anchors.rightMargin: 100 + anchors.rightMargin: 30 anchors.top: parent.top anchors.topMargin: 100 onNoteClicked: { onlyNote.value = note; staff2.addNote(note, currentType, piano.useSharpNotation ? "sharp" : "flat", false) var noteToPlay = 'qrc:/gcompris/src/activities/playpiano/resource/' + 'bass' + '_pitches/' + currentType + '/' + note + '.wav'; items.audioEffects.play(noteToPlay); } Note { id: onlyNote value: "1" type: currentType visible: false } } Row { id: optionsRow anchors.top: staff2.bottom anchors.right: parent.right anchors.rightMargin: 50 Image { source: "qrc:/gcompris/src/activities/playpiano/resource/whole-note.svg" sourceSize.width: 50 MouseArea{ anchors.fill: parent onClicked: currentType = onlyNote.wholeNote } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/half-note.svg" sourceSize.width: 50 MouseArea{ anchors.fill: parent onClicked: currentType = onlyNote.halfNote } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/quarter-note.svg" sourceSize.width: 50 MouseArea{ anchors.fill: parent onClicked: currentType = onlyNote.quarterNote } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/eighth-note.svg" sourceSize.width: 50 MouseArea{ anchors.fill: parent onClicked: currentType = onlyNote.eighthNote } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/play.svg" sourceSize.width: 75 MouseArea{ anchors.fill: parent onClicked: staff2.play() } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/edit-clear.svg" sourceSize.width: 75 MouseArea{ anchors.fill: parent onClicked: staff2.eraseAllNotes() } } Image { source: "qrc:/gcompris/src/activities/playpiano/resource/open.svg" sourceSize.width: 50 MouseArea{ anchors.fill: parent onClicked: loadMelody() } } } // GCDialogCheckBox { // id: button // onClicked: piano.useSharpNotation = !piano.useSharpNotation // } // GCText { // text: qsTr("Change accidental style") // } // // Image { // source: piano.useSharpNotation ? "qrc:/gcompris/src/activities/playpiano/resource/blacksharp.svg" : "qrc:/gcompris/src/activities/playpiano/resource/blackflat.svg" // } function loadMelody() { var data = Dataset.get(); var selectedMusic = data.filter(function(item) { return item.title === 'Frère jacques'; }); staff2.loadFromData(selectedMusic[0]["melody"]); } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: help | home | level } onHelpClicked: { displayDialog(dialogHelp) } onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextLevel) } } }