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 }