Warning, /education/gcompris/src/activities/piano_composition/MusicElement.qml is written in an unsupported language. File is not indexed.
0001 /* GCompris - musicElement.qml
0002 *
0003 * SPDX-FileCopyrightText: 2016 Johnny Jazeix <jazeix@gmail.com>
0004 * SPDX-FileCopyrightText: 2018 Aman Kumar Gupta <gupta2140@gmail.com>
0005 *
0006 * Authors:
0007 * Beth Hadley <bethmhadley@gmail.com> (GTK+ version)
0008 * Johnny Jazeix <jazeix@gmail.com> (Qt Quick port)
0009 * Aman Kumar Gupta <gupta2140@gmail.com> (Qt Quick port)
0010 *
0011 * SPDX-License-Identifier: GPL-3.0-or-later
0012 */
0013 import QtQuick 2.12
0014 import QtGraphicalEffects 1.0
0015 import GCompris 1.0
0016
0017 import "../../core"
0018
0019 Item {
0020 id: musicElement
0021 width: noteImageWidth
0022 height: multipleStaff.height / 5
0023
0024 signal stop
0025
0026 Component.onCompleted: {
0027 activity.stop.connect(stop);
0028 }
0029
0030 onStop: {
0031 highlightTimer.stop();
0032 }
0033
0034 property string noteName
0035 property string noteType
0036 property string soundPitch
0037 property string clefType
0038 property string elementType
0039 property bool noteIsColored: true
0040 property bool isDefaultClef: false
0041 property string blackType: noteName === "" ? ""
0042 : noteName[1] === "#" ? "sharp"
0043 : noteName[1] === "b" ? "flat" : ""// empty, "flat" or "sharp"
0044
0045 /**
0046 * Calculates and assign the timer interval for a note.
0047 */
0048 function calculateTimerDuration(noteType) {
0049 noteType = noteType.toLowerCase()
0050 if(noteType === "whole")
0051 return 240000 / multipleStaff.bpmValue
0052 else if(noteType === "half")
0053 return 120000 / multipleStaff.bpmValue
0054 else if(noteType === "quarter")
0055 return 60000 / multipleStaff.bpmValue
0056 else
0057 return 30000 / multipleStaff.bpmValue
0058 }
0059
0060 readonly property int duration: {
0061 if(elementType != "clef") {
0062 if(noteType === "Rest")
0063 return calculateTimerDuration(noteName)
0064 else
0065 return calculateTimerDuration(noteType)
0066 }
0067 return 0
0068 }
0069
0070 readonly property real noteImageWidth: (multipleStaff.width - 15 - clefImageWidth) / 10
0071
0072 readonly property var noteColorMap: { "1": "#FF0000", "2": "#FF7F00", "3": "#FFFF00",
0073 "4": "#32CD32", "5": "#6495ED", "6": "#D02090", "7": "#FF1493", "8": "#FF0000",
0074 "-1": "#FF6347", "-2": "#FFD700", "-3": "#20B2AA", "-4": "#8A2BE2",
0075 "-5": "#FF00FF" }
0076
0077 readonly property var whiteNoteName: { "C": "1", "D": "2", "E": "3", "F": "4", "G": "5", "A": "6", "B": "7", "C": "8" }
0078
0079 readonly property var sharpNoteName: { "C#": "-1", "D#": "-2", "F#": "-3", "G#": "-4", "A#": "-5" }
0080 readonly property var flatNoteName: { "Db": "-1", "Eb": "-2", "Gb": "-3", "Ab": "-4", "Bb": "-5" }
0081 readonly property var blackNoteName: blackType == "" ? blackType
0082 : blackType == "flat" ? flatNoteName : sharpNoteName
0083
0084 property bool highlightWhenPlayed: false
0085 property alias highlightTimer: highlightTimer
0086
0087 property var noteDetails
0088
0089 property bool noteAnswered: false
0090 property bool isCorrectlyAnswered: false
0091
0092 rotation: {
0093 if((noteDetails === undefined) || elementType === "clef")
0094 return 0
0095 else if((noteDetails.positionOnStaff < 0) && (noteType === "Whole"))
0096 return 180
0097 else
0098 return noteDetails.rotation
0099 }
0100
0101 Image {
0102 id: blackTypeImage
0103 source: blackType !== "" ? "qrc:/gcompris/src/activities/piano_composition/resource/black" + blackType + ".svg" : ""
0104 sourceSize.width: noteImage.width / 2
0105 anchors.right: parent.rotation === 180 ? undefined : noteImage.left
0106 anchors.left: parent.rotation === 180 ? noteImage.right : undefined
0107 rotation: parent.rotation === 180 ? 180 : 0
0108 anchors.rightMargin: -noteImage.width / 4
0109 anchors.leftMargin: -noteImage.width / 2.5
0110 anchors.bottom: noteImage.bottom
0111 anchors.bottomMargin: parent.height / 6
0112 fillMode: Image.PreserveAspectFit
0113 }
0114
0115 Rectangle {
0116 id: highlightRectangle
0117 width: musicElement.width
0118 height: musicElement.height * 0.9
0119 color: "transparent"
0120 opacity: 1
0121 border.color: "#373737"
0122 border.width: radius * 0.5
0123 radius: width * 0.1
0124 visible: (multipleStaff.noteHoverEnabled && noteMouseArea.containsMouse) || highlightTimer.running
0125 }
0126
0127 Rectangle {
0128 id: selectedNoteIndicator
0129 width: musicElement.width
0130 height: musicElement.height * 0.9
0131 color: "blue"
0132 opacity: 0.6
0133 border.color: "white"
0134 radius: width / 5
0135 visible: selectedIndex == index
0136 }
0137
0138 Image {
0139 id: noteImage
0140 source: (noteDetails === undefined) ? ""
0141 : noteType != "Rest" ? "qrc:/gcompris/src/activities/piano_composition/resource/" + noteDetails.imageName + noteType + ".svg"
0142 : "qrc:/gcompris/src/activities/piano_composition/resource/" + noteDetails.imageName + ".svg"
0143 sourceSize.width: 200
0144 width: musicElement.width
0145 height: musicElement.height
0146 mirror: parent.rotation == 180 && parent.noteType == "Eighth" ? true : false
0147 }
0148
0149 Image {
0150 id: clefImage
0151 source: (elementType === "clef") ? "qrc:/gcompris/src/activities/piano_composition/resource/" + clefType.toLowerCase() + "Clef.svg" : ""
0152 sourceSize.width: multipleStaff.clefImageWidth
0153 }
0154
0155 Image {
0156 id: correctOrWrongAnswerIndicator
0157 visible: noteAnswered
0158 source: isCorrectlyAnswered ? "qrc:/gcompris/src/activities/piano_composition/resource/passed.svg"
0159 : "qrc:/gcompris/src/activities/piano_composition/resource/failed.svg"
0160 sourceSize.width: noteImage.width / 2.5
0161 anchors.right: parent.rotation === 180 ? undefined : noteImage.right
0162 anchors.left: parent.rotation === 180 ? noteImage.left : undefined
0163 rotation: parent.rotation === 180 ? 180 : 0
0164 anchors.rightMargin: 12
0165 anchors.bottom: noteImage.bottom
0166 anchors.bottomMargin: parent.height / 6
0167 fillMode: Image.PreserveAspectFit
0168 z: 3
0169 }
0170
0171 Rectangle {
0172 id:softColor
0173 readonly property int invalidConditionNumber: -6
0174 readonly property int noteColorNumber: {
0175 if(noteDetails === undefined || noteType === "" || noteType === "Rest" || noteName === "")
0176 return invalidConditionNumber
0177 else if((blackType === "") && (whiteNoteName[noteName[0]] != undefined))
0178 return whiteNoteName[noteName[0]]
0179 else if((noteName.length > 2) && (blackNoteName[noteName.substring(0,2)] != undefined))
0180 return blackNoteName[noteName.substring(0,2)]
0181 else
0182 return invalidConditionNumber
0183 }
0184 color: {
0185 if(multipleStaff.notesColor === "inbuilt")
0186 return (noteColorNumber > invalidConditionNumber) ? noteColorMap[noteColorNumber] : "white"
0187 else
0188 return multipleStaff.notesColor
0189 }
0190 z: -1
0191 width: noteImage.width * 0.8
0192 height: width
0193 radius: width * 0.5
0194 anchors.centerIn: noteImage
0195 opacity: softColorOpacity
0196 visible: noteIsColored && (elementType != "clef")
0197 }
0198
0199 Timer {
0200 id: highlightTimer
0201 interval: duration
0202 }
0203 }