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(" ", " "); 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 }