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 }