Warning, /education/gcompris/src/activities/clockgame/Clockgame.qml is written in an unsupported language. File is not indexed.

0001 /* GCompris - Clockgame.qml
0002 *
0003 * SPDX-FileCopyrightText: 2014 Stephane Mankowski <stephane@mankowski.fr>
0004 *
0005 * Authors:
0006 *   Bruno Coudoin <bruno.coudoin@gcompris.net> (GTK+ version)
0007 *   Stephane Mankowski <stephane@mankowski.fr> (Qt Quick port)
0008 *
0009 *   SPDX-License-Identifier: GPL-3.0-or-later
0010 */
0011 import QtQuick 2.12
0012 import QtGraphicalEffects 1.0
0013 import GCompris 1.0
0014 
0015 import "../../core"
0016 import "clockgame.js" as Activity
0017 
0018 ActivityBase {
0019     id: activity
0020 
0021     onStart: focus = true
0022     onStop: {
0023 
0024     }
0025 
0026     pageComponent: Image {
0027         id: background
0028         source: "qrc:/gcompris/src/activities/menu/resource/background.svg"
0029         sourceSize.width: width
0030         sourceSize.height: height
0031         fillMode: Image.PreserveAspectCrop
0032         anchors.fill: parent
0033         signal start
0034         signal stop
0035 
0036         Component.onCompleted: {
0037             dialogActivityConfig.initialize()
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 alias background: background
0046             property alias errorRectangle: errorRectangle
0047             property GCSfx audioEffects: activity.audioEffects
0048             property int currentLevel: activity.currentLevel
0049             property alias bonus: bonus
0050             property alias score: score
0051             property int targetH: 12
0052             property int targetM: 0
0053             property int targetS: 0
0054             property int currentH: 1
0055             property int currentM: 25
0056             property int currentS: 43
0057             property int numberOfTry: 3
0058             property int currentTry: 0
0059             readonly property var levels: activity.datasetLoader.data
0060             property bool minutesHandVisible
0061             property bool secondsHandVisible
0062             property bool zonesVisible
0063             property bool hoursMarksVisible
0064             property bool hoursVisible
0065             property bool minutesVisible
0066             property bool noHint
0067             property bool useTwelveHourFormat: true
0068             property bool buttonsBlocked: false
0069         }
0070 
0071         onStart: {
0072             Activity.start(items)
0073         }
0074         onStop: {
0075             Activity.stop()
0076         }
0077 
0078         Score {
0079             id: score
0080             anchors {
0081                 bottom: bar.top
0082                 bottomMargin: 10 * ApplicationInfo.ratio
0083                 left: parent.left
0084                 leftMargin: 10 * ApplicationInfo.ratio
0085                 right: undefined
0086                 top: undefined
0087             }
0088             onStop: { Activity.nextSubLevel() }
0089         }
0090 
0091         /* Target text */
0092         Rectangle {
0093             id: questionItemBackground
0094             color: "#c0ceb339"
0095             border.width: 0
0096             radius: 10
0097             z: 10
0098             anchors {
0099                 horizontalCenter: parent.horizontalCenter
0100                 top: parent.top
0101                 margins: 10
0102             }
0103             height: questionItem.height + anchors.margins * 2
0104             width: questionItem.width + anchors.margins * 2
0105             Behavior on height { PropertyAnimation { duration: 100 } }
0106 
0107             GCText {
0108                 id: questionItem
0109                 text: qsTr("Set the watch to:") + " " +
0110                       //~ singular %n hour
0111                       //~ plural %n hours
0112                       addNbsp(qsTr("%n hour(s)", "", items.targetH)) + " " +
0113                       //~ singular %n minute
0114                       //~ plural %n minutes
0115                       addNbsp(qsTr("%n minute(s)", "", items.targetM)) +
0116                       //~ singular %n second
0117                       //~ plural %n seconds
0118                       (s.visible ? " " + addNbsp(qsTr("%n second(s)", "", items.targetS)) : "")
0119                 fontSize: mediumSize
0120                 textFormat: Text.RichText
0121                 font.weight: Font.DemiBold
0122                 color: "white"
0123                 horizontalAlignment: Text.AlignHCenter
0124                 wrapMode: Text.WordWrap
0125                 width: background.width
0126                 anchors {
0127                     horizontalCenter: parent.horizontalCenter
0128                     top: parent.top
0129                     margins: 10
0130                 }
0131                 // We don't want the wrapping to happen anywhere, set no break space
0132                 function addNbsp(str) {
0133                     return str.replace(" ", "&nbsp;");
0134                 }
0135             }
0136         }
0137 
0138         /* The clock */
0139         Image {
0140             id: clock
0141             source: activity.resourceUrl + "clock_bg.svg"
0142             anchors.centerIn: parent
0143             fillMode: Image.PreserveAspectFit
0144             sourceSize.width: radius * 0.9
0145 
0146             property int radius: Math.min(background.width, background.height - bar.height)
0147 
0148             /* The grey zones */
0149             Image {
0150                 id: zones
0151                 source: activity.resourceUrl + "clock_zones.svg"
0152                 anchors.centerIn: parent
0153                 fillMode: Image.PreserveAspectFit
0154                 sourceSize.width: parent.width * 0.8
0155                 visible: items.zonesVisible
0156                 z: 2
0157             }
0158 
0159             /* The setter */
0160             Image {
0161                 id: setter
0162                 source: activity.resourceUrl + "clock_setter.svg"
0163                 anchors {
0164                     verticalCenter: parent.verticalCenter
0165                     left: parent.right
0166                     leftMargin: -10
0167                 }
0168                 z: 1
0169             }
0170 
0171             /* The minutes */
0172             Repeater {
0173                 model: 60
0174                 GCText {
0175                     text: index + 1
0176                     font {
0177                         pointSize: NaN  // need to clear font.pointSize explicitly
0178                         pixelSize: Math.max(
0179                                        (index + 1) % 5
0180                                        === 0 ? clock.radius / 40 : clock.radius / 45,
0181                                                1)
0182                         bold: items.currentM === ((index + 1) % 60) || (items.currentS === ((index + 1) % 60) && s.visible)
0183                         underline: items.currentM === ((index + 1) % 60) || (items.currentS === ((index + 1) % 60) && s.visible)
0184                     }
0185                     anchors {
0186                         verticalCenter: clock.verticalCenter
0187                         horizontalCenter: clock.horizontalCenter
0188                         verticalCenterOffset: -clock.radius * 0.33 * Math.cos(
0189                                                   (index + 1) * 2 * Math.PI / 60)
0190                         horizontalCenterOffset: clock.radius * 0.33 * Math.sin(
0191                                                     (index + 1) * 2 * Math.PI / 60)
0192                     }
0193                     z: 4
0194                     color: "#d56a3a"
0195                     visible: items.minutesHandVisible && items.minutesVisible
0196                 }
0197             }
0198             /* The seconds */
0199             Repeater {
0200                 model: 60
0201 
0202                 Rectangle {
0203                     color: "#d56a3a"
0204                     width: clock.radius * 0.02
0205                     height: 2
0206                     rotation: 90 + (index + 1) * 360 / 60
0207                     radius: 1
0208                     anchors {
0209                         verticalCenter: clock.verticalCenter
0210                         horizontalCenter: clock.horizontalCenter
0211                         verticalCenterOffset: -clock.radius * 0.3 * Math.cos(
0212                                                   (index + 1) * 2 * Math.PI / 60)
0213                         horizontalCenterOffset: clock.radius * 0.3 * Math.sin(
0214                                                     (index + 1) * 2 * Math.PI / 60)
0215                     }
0216                     z: 4
0217                     visible: items.secondsHandVisible
0218                 }
0219             }
0220 
0221             /* The hours */
0222             Repeater {
0223                 model: 12
0224                 GCText {
0225                     text: index + 1
0226                     font {
0227                         pointSize: NaN  // need to clear font.pointSize explicitly
0228                         pixelSize: Math.max(clock.radius / 30, 1)
0229                         bold: items.currentH === ((index + 1) % 12)
0230                         underline: items.currentH === ((index + 1) % 12)
0231                     }
0232                     anchors {
0233                         verticalCenter: clock.verticalCenter
0234                         horizontalCenter: clock.horizontalCenter
0235                         verticalCenterOffset: -clock.radius * 0.26 * Math.cos(
0236                                                   (index + 1) * 2 * Math.PI / 12)
0237                         horizontalCenterOffset: clock.radius * 0.26 * Math.sin(
0238                                                     (index + 1) * 2 * Math.PI / 12)
0239                     }
0240                     z: 4
0241                     color: "#3a81d5"
0242                     visible: items.hoursVisible
0243                 }
0244             }
0245 
0246             Repeater {
0247                 model: 12
0248 
0249                 Rectangle {
0250                     color: "#3a81d5"
0251                     width: clock.radius * 0.03
0252                     height: 4
0253                     rotation: 90 + (index + 1) * 360 / 12
0254                     radius: 1
0255                     anchors {
0256                         verticalCenter: clock.verticalCenter
0257                         horizontalCenter: clock.horizontalCenter
0258                         verticalCenterOffset: -clock.radius * 0.3 * Math.cos(
0259                                                   (index + 1) * 2 * Math.PI / 12)
0260                         horizontalCenterOffset: clock.radius * 0.3 * Math.sin(
0261                                                     (index + 1) * 2 * Math.PI / 12)
0262                     }
0263                     z: 4
0264                     visible: items.hoursMarksVisible || !items.hoursMarksVisible && (index + 1) % 3 === 0
0265                 }
0266             }
0267 
0268             /* Help text */
0269             GCText {
0270                 id: helper
0271                 text:  Activity.get2CharValue(items.useTwelveHourFormat ? items.currentH : items.currentH+12) + ":" +
0272                        Activity.get2CharValue(items.currentM) + ":" +
0273                        Activity.get2CharValue(items.currentS)
0274                 font.pointSize: NaN
0275                 font.pixelSize: Math.max(clock.radius / 30, 1)
0276                 anchors {
0277                     verticalCenter: clock.verticalCenter
0278                     horizontalCenter: clock.horizontalCenter
0279                     verticalCenterOffset: clock.radius * 0.2
0280                 }
0281                 z: 4
0282                 opacity: items.noHint ? 0 : 1
0283                 color: "#2a2a2a"
0284                 visible: false
0285             }
0286 
0287             /* Arrow H */
0288             Rectangle {
0289                 id: h
0290                 property alias angle: roth.angle
0291                 height: clock.radius * 0.2
0292                 width: height / 10
0293                 radius: width / 2
0294                 color: "#3a81d5"
0295                 transform: Rotation {
0296                     id: roth
0297                     origin.x: h.width / 2
0298                     origin.y: 0
0299                     angle: (180 + 360 * (items.currentH / 12 + items.currentM / 60 / 12)) % 360
0300                     Behavior on angle {
0301                         RotationAnimation {
0302                             duration: 100
0303                             direction: RotationAnimation.Shortest
0304                         }
0305                     }
0306                 }
0307 
0308                 anchors {
0309                     verticalCenter: clock.verticalCenter
0310                     horizontalCenter: clock.horizontalCenter
0311                     verticalCenterOffset: h.height / 2
0312                 }
0313                 z: 5
0314             }
0315 
0316             /* Arrow M */
0317             Rectangle {
0318                 id: m
0319                 property alias angle: rotm.angle
0320                 height: clock.radius * 0.28
0321                 width: height / 20
0322                 radius: width / 2
0323                 color: "#d56a3a"
0324                 visible: items.minutesHandVisible
0325                 transform: Rotation {
0326                     id: rotm
0327                     origin.x: m.width / 2
0328                     origin.y: 0
0329                     angle: (180 + 360 * (items.currentM / 60 + items.currentS / 60 / 60)) % 360
0330                     Behavior on angle {
0331                         RotationAnimation {
0332                             duration: 100
0333                             direction: RotationAnimation.Shortest
0334                         }
0335                     }
0336                 }
0337 
0338                 anchors {
0339                     verticalCenter: clock.verticalCenter
0340                     horizontalCenter: clock.horizontalCenter
0341                     verticalCenterOffset: m.height / 2
0342                 }
0343                 z: 6
0344             }
0345 
0346             /* Arrow S */
0347             Rectangle {
0348                 id: s
0349                 property alias angle: rots.angle
0350                 height: clock.radius * 0.32
0351                 width: height / 30
0352                 radius: width / 2
0353                 color: "#2ccf4b"
0354                 visible: items.secondsHandVisible
0355                 transform: Rotation {
0356                     id: rots
0357                     origin.x: s.width / 2
0358                     origin.y: 0
0359                     angle: (180 + 360 * items.currentS / 60) % 360
0360                     Behavior on angle {
0361                         RotationAnimation {
0362                             duration: 100
0363                             direction: RotationAnimation.Shortest
0364                         }
0365                     }
0366                 }
0367 
0368                 anchors {
0369                     verticalCenter: clock.verticalCenter
0370                     horizontalCenter: clock.horizontalCenter
0371                     verticalCenterOffset: s.height / 2
0372                 }
0373                 z: 7
0374             }
0375 
0376             /* Center */
0377             Rectangle {
0378                 id: center
0379                 color: "#2a2a2a"
0380                 height: clock.radius / 25
0381                 width: height
0382                 radius: width / 2
0383                 anchors.centerIn: clock
0384                 z: 8
0385             }
0386 
0387             /* Manage the move */
0388             MouseArea {
0389                 anchors.fill: parent
0390                 enabled: !items.buttonsBlocked
0391                 acceptedButtons: Qt.LeftButton
0392                 onPressed: {
0393                     /* Find the closer Arrow */
0394                     var a = (270 + 360 + 180 * Math.atan2(
0395                                  mouseY - (center.y + center.height / 2),
0396                                  mouseX - (center.x + center.width / 2)) / Math.PI) % 360
0397                     var agnh = h.angle
0398                     var angm = m.angle
0399                     var angs = s.angle
0400                     var dh = Math.min(Math.abs(a - agnh),
0401                                       Math.abs(a - agnh - 360),
0402                                       Math.abs(a - agnh + 360))
0403                     var dm = m.visible ? Math.min(Math.abs(a - angm),
0404                                              Math.abs(a - angm - 360),
0405                                              Math.abs(a - angm + 360)) : 9999
0406                     var ds = s.visible ? Math.min(
0407                                              Math.abs(a - angs),
0408                                              Math.abs(a - angs - 360),
0409                                              Math.abs(a - angs + 360)) : 9999
0410                     var dmin = Math.min(dh, dm, ds)
0411 
0412                     if (dh === dmin) {
0413                         Activity.selectedArrow = h
0414                     } else if (dm === dmin) {
0415                         Activity.selectedArrow = m
0416                     } else {
0417                         Activity.selectedArrow = s
0418                     }
0419                 }
0420 
0421                 onMouseXChanged: {
0422                     /* Move */
0423                     if (Activity.selectedArrow !== null) {
0424                         var a = (270 + 360 + 180 * Math.atan2(
0425                                      mouseY - (center.y + center.height / 2),
0426                                      mouseX - (center.x + center.width / 2)) / Math.PI) % 360
0427 
0428                         var previousM = items.currentM
0429                         var previousS = items.currentS
0430 
0431                         if (Activity.selectedArrow === h) {
0432                             items.currentH = Math.round(
0433                                         12 * ((a - 180) / 360 - items.currentM / 60 / 12) + 12) % 12
0434                         } else if (Activity.selectedArrow === m) {
0435                             items.currentM = Math.round(
0436                                         60 * ((a - 180) / 360 - items.currentS / 60 / 60) + 60) % 60
0437                         } else {
0438                             items.currentS = Math.round(
0439                                         60 * (a - 180) / 360 + 60) % 60
0440                         }
0441 
0442                         if (previousS > 45 && items.currentS < 15)
0443                             items.currentM = (items.currentM + 1 + 60) % 60
0444                         if (previousS < 15 && items.currentS > 45)
0445                             items.currentM = (items.currentM - 1 + 60) % 60
0446                         if (previousM > 45 && items.currentM < 15)
0447                             items.currentH = (items.currentH + 1 + 12) % 12
0448                         if (previousM < 15 && items.currentM > 45)
0449                             items.currentH = (items.currentH - 1 + 12) % 12
0450                     }
0451                 }
0452             }
0453         }
0454 
0455         ErrorRectangle {
0456             id: errorRectangle
0457             anchors.centerIn: clock
0458             width: zones.width
0459             height: zones.height
0460             radius: width * 0.5
0461             imageSize: okButton.width
0462             function releaseControls() {
0463                 items.buttonsBlocked = false;
0464             }
0465         }
0466 
0467         BarButton {
0468             id: okButton
0469             source: "qrc:/gcompris/src/core/resource/bar_ok.svg"
0470             sourceSize.width: 60 * ApplicationInfo.ratio
0471             anchors.bottom: bar.top
0472             anchors.bottomMargin: 20 * ApplicationInfo.ratio
0473             anchors.right: parent.right
0474             anchors.rightMargin: 10 * ApplicationInfo.ratio
0475             enabled: !items.buttonsBlocked
0476             ParticleSystemStarLoader {
0477                 id: okButtonParticles
0478                 clip: false
0479             }
0480             MouseArea {
0481                 id: okButtonMouseArea
0482                 anchors.fill: parent
0483                 onClicked: {
0484                     Activity.checkAnswer()
0485                 }
0486             }
0487         }
0488 
0489         DialogChooseLevel {
0490             id: dialogActivityConfig
0491             currentActivity: activity.activityInfo
0492 
0493             onSaveData: {
0494                 levelFolder = dialogActivityConfig.chosenLevels
0495                 currentActivity.currentLevels = dialogActivityConfig.chosenLevels
0496                 ApplicationSettings.setCurrentLevels(currentActivity.name, dialogActivityConfig.chosenLevels)
0497             }
0498             onLoadData: {
0499                 if(activityData && activityData["mode"]) {
0500                     if(activityData["mode"] == 1) {
0501                         items.useTwelveHourFormat = true;
0502                     }
0503                     else {
0504                         items.useTwelveHourFormat = false;
0505                     }
0506                 }
0507             }
0508             onClose: {
0509                 home()
0510             }
0511             onStartActivity: {
0512                 background.stop()
0513                 background.start()
0514             }
0515         }
0516 
0517         DialogHelp {
0518             id: dialogHelp
0519             onClose: home()
0520         }
0521 
0522         Bar {
0523             id: bar
0524             level: items.currentLevel + 1
0525             content: items.noHint ? withoutHint : withHint
0526 
0527             property BarEnumContent withHint: BarEnumContent { value: help | home | level | hint | activityConfig }
0528             property BarEnumContent withoutHint: BarEnumContent { value: help | home | level | activityConfig }
0529 
0530             onHelpClicked: {
0531                 displayDialog(dialogHelp)
0532             }
0533             onHintClicked: {
0534                 helper.visible = !helper.visible
0535             }
0536             onActivityConfigClicked: {
0537                 displayDialog(dialogActivityConfig)
0538             }
0539             onPreviousLevelClicked: Activity.previousLevel()
0540             onNextLevelClicked: Activity.nextLevel()
0541             onHomeClicked: activity.home()
0542         }
0543 
0544         Bonus {
0545             id: bonus
0546             Component.onCompleted: win.connect(Activity.nextLevel)
0547         }
0548     }
0549 }