Warning, /education/gcompris/src/activities/graph-coloring/GraphColoring.qml is written in an unsupported language. File is not indexed.
0001 /* GCompris - graph-coloring.qml
0002 *
0003 * SPDX-FileCopyrightText: 2015 Akshat Tandon <akshat.tandon@research.iiit.ac.in>
0004 *
0005 * Authors:
0006 *
0007 * Akshat Tandon <akshat.tandon@research.iiit.ac.in> (Qt Quick version)
0008 *
0009 * SPDX-License-Identifier: GPL-3.0-or-later
0010 */
0011 import QtQuick 2.12
0012
0013 import "../../core"
0014 import "graph-coloring.js" as Activity
0015 import GCompris 1.0
0016
0017 ActivityBase {
0018 id: activity
0019
0020 onStart: focus = true
0021 onStop: {}
0022
0023 // When opening a dialog, it steals the focus and re set it to the activity.
0024 // We need to set it back to the eventHandler item in order to have key events.
0025 onFocusChanged: {
0026 if(focus) {
0027 Activity.focusEventInput()
0028 }
0029 }
0030
0031 pageComponent: Image {
0032 id: background
0033 anchors.fill: parent
0034 source: "qrc:/gcompris/src/activities/tic_tac_toe/resource/background.svg"
0035 sourceSize.width: width
0036 sourceSize.height: height
0037 fillMode: Image.PreserveAspectCrop
0038
0039 signal start
0040 signal stop
0041
0042 Component.onCompleted: {
0043 dialogActivityConfig.initialize()
0044 activity.start.connect(start)
0045 activity.stop.connect(stop)
0046 }
0047
0048 MouseArea {
0049 anchors.fill: parent
0050 onClicked: showChooser(false);
0051 }
0052
0053 // Add here the QML items you need to access in javascript
0054 QtObject {
0055 id: items
0056 property Item main: activity.main
0057 property alias background: background
0058 property int currentLevel: activity.currentLevel
0059 property alias bonus: bonus
0060 property alias colorsRepeater: colorsRepeater
0061 property alias nodesRepeater: nodesRepeater
0062 property alias edgesRepeater: edgesRepeater
0063 property alias chooserGrid: chooserGrid
0064 property alias nodeHighlight: nodeHighlight
0065 property string mode: "color"
0066 property var currentKeyZone: graphRect
0067 property bool keyNavigationMode: false
0068 property alias eventHandler: eventHandler
0069 }
0070
0071 onStart: {
0072 Activity.start(items);
0073 eventHandler.forceActiveFocus();
0074 }
0075 onStop: { Activity.stop() }
0076
0077 Item {
0078 id: eventHandler
0079 focus: true
0080 Keys.enabled: !bonus.isPlaying && !dialogActivityConfig.visible
0081 Keys.onPressed: {
0082 items.keyNavigationMode = true;
0083 items.currentKeyZone.handleKeys(event);
0084 }
0085 }
0086
0087 Column {
0088 id: colorsColumn
0089
0090 anchors.left: parent.left
0091 anchors.leftMargin: 5 * ApplicationInfo.ratio
0092 anchors.top: parent.top
0093 anchors.topMargin: 5 * ApplicationInfo.ratio
0094
0095 spacing: 3 * ApplicationInfo.ratio
0096
0097 add: Transition {
0098 NumberAnimation { properties: "y"; duration: 1000; easing.type: Easing.OutBounce }
0099 }
0100
0101 Repeater {
0102 id: colorsRepeater
0103
0104 model: ListModel {}
0105
0106 delegate:
0107 Node {
0108 width: 40 * ApplicationInfo.ratio
0109 height: 40 * ApplicationInfo.ratio
0110 border.width: 2
0111 border.color: "white"
0112 searchItemIndex: itemIndex
0113 }
0114 }
0115 }
0116
0117 Item {
0118 id: graphRect
0119 anchors.left: parent.left
0120 anchors.leftMargin: 100 * ApplicationInfo.ratio
0121 anchors.bottom: parent.bottom
0122 anchors.bottomMargin: 50 * ApplicationInfo.ratio
0123 anchors.top: parent.top
0124 anchors.topMargin: 50 * ApplicationInfo.ratio
0125 height: background.height - 100 * ApplicationInfo.ratio
0126 width: background.width - 150 * ApplicationInfo.ratio
0127 property int diameter: graphRect.width/11
0128 property int minDiameter: 40 * ApplicationInfo.ratio
0129 property int maxDiameter: 80 * ApplicationInfo.ratio
0130 property int optDiameter: diameter < minDiameter ? minDiameter : ( diameter > maxDiameter ? maxDiameter : diameter)
0131 Repeater {
0132 id: edgesRepeater
0133 model: ListModel {}
0134 delegate: Rectangle {
0135 id: line
0136 opacity: 1
0137 antialiasing: true
0138 color: highlight == true ? "red" : "#373737"
0139
0140 transformOrigin: Item.TopLeft
0141 x: xp * graphRect.width
0142 y: yp * graphRect.height
0143 property var x2: xpp * graphRect.width
0144 property var y2: ypp * graphRect.height
0145 width: Math.sqrt(Math.pow(x - x2, 2) + Math.pow(y- y2, 2))
0146 height: highlight == true ? 7 * ApplicationInfo.ratio : 3 * ApplicationInfo.ratio
0147 rotation: (Math.atan((y2 - y)/(x2-x)) * 180 / Math.PI) + (((y2-y) < 0 && (x2-x) < 0) * 180) + (((y2-y) >= 0 && (x2-x) < 0) * 180)
0148 Behavior on color {
0149 ColorAnimation {
0150 duration: 2000
0151 easing.type: Easing.OutExpo
0152 }
0153 }
0154 Behavior on height {
0155 NumberAnimation {
0156 duration: 2000
0157 easing.type: Easing.OutExpo
0158 }
0159 }
0160 }
0161
0162
0163 }
0164 Repeater{
0165 id: nodesRepeater
0166
0167 model: ListModel {}
0168
0169 delegate:
0170 Node{
0171 id: currentNode
0172
0173 x: posX * graphRect.width - width/2
0174 y: posY * graphRect.height - height/2
0175 width: graphRect.optDiameter
0176 height: width
0177 radius: width/2
0178 border.color: highlight ? "red" : "black"
0179 border.width: highlight ? 7 : 4
0180 symbolRotation: highlight
0181 searchItemIndex: colIndex
0182 Behavior on border.color {
0183 ColorAnimation {
0184 duration: 2000
0185 easing.type: Easing.OutExpo
0186 }
0187 }
0188
0189 Behavior on border.width {
0190 NumberAnimation {
0191 duration: 2000
0192 easing.type: Easing.OutExpo
0193 }
0194 }
0195
0196
0197 MouseArea {
0198 id: mouseArea
0199 anchors.fill: parent
0200 acceptedButtons: Qt.LeftButton | Qt.RightButton
0201 enabled: !bonus.isPlaying
0202 z: 3
0203 hoverEnabled: ApplicationInfo.isMobile ? false : true
0204
0205 onClicked:{
0206 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav');
0207 items.currentKeyZone = chooser;
0208 items.nodeHighlight.setHighlight(index);
0209 showChooser(true, index, parent);
0210 }
0211 }
0212 states: State {
0213 name: "scaled"; when: mouseArea.containsMouse
0214 PropertyChanges {
0215 target: currentNode
0216 scale: 1.1
0217 }
0218 }
0219 transitions: Transition {
0220 NumberAnimation { properties: "scale"; easing.type: Easing.OutCubic }
0221 }
0222
0223 }
0224 }
0225
0226 Rectangle {
0227 id: nodeHighlight
0228 z: -1
0229 width: graphRect.optDiameter * 1.5
0230 height: width
0231 radius: width * 0.5
0232 color: "#80ffffff"
0233 visible: items.currentKeyZone === graphRect && items.keyNavigationMode
0234 anchors.centerIn: nodesRepeater.itemAt(0)
0235 property int index: -1
0236 function setHighlight(toIndex) {
0237 index = toIndex;
0238 anchors.centerIn = nodesRepeater.itemAt(index);
0239 }
0240 }
0241
0242 function handleKeys(event) {
0243 if(event.key === Qt.Key_Right) {
0244 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav');
0245 nodeHighlight.index += 1;
0246 if(nodeHighlight.index > nodesRepeater.count - 1) {
0247 nodeHighlight.index = 0;
0248 }
0249 }
0250 if(event.key === Qt.Key_Left) {
0251 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav');
0252 nodeHighlight.index -= 1;
0253 if(nodeHighlight.index < 0) {
0254 nodeHighlight.index = nodesRepeater.count - 1;
0255 }
0256 }
0257 //if space is used before direction keys, init index at 0
0258 if(nodeHighlight.index === -1) {
0259 nodeHighlight.index = 0;
0260 }
0261 nodeHighlight.anchors.centerIn = nodesRepeater.itemAt(nodeHighlight.index);
0262 if(event.key === Qt.Key_Space) {
0263 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav');
0264 showChooser(true, nodeHighlight.index, nodesRepeater.itemAt(nodeHighlight.index));
0265 items.currentKeyZone = chooser;
0266 items.chooserGrid.currentIndex = 0;
0267 }
0268 }
0269 }
0270 function showChooser(visible, guessIndex, item)
0271 {
0272 if (!visible) {
0273 chooser.visible = false;
0274 return;
0275 }
0276 var modelObj = items.nodesRepeater.model.get(guessIndex);
0277 var absolute = graphRect.mapToItem(background, item.x, item.y);
0278 chooserGrid.colIndex = modelObj.colIndex;
0279 chooserGrid.guessIndex = guessIndex;
0280 var targetX = absolute.x + item.width;
0281 var targetY = absolute.y - item.height/2;
0282 if (targetX < 0) {
0283 targetX = 0;
0284 }
0285 if (targetX + chooser.width > background.width) {
0286 targetX = background.width - chooser.width - 10;
0287 }
0288 if (targetY < 0) {
0289 targetY = 0;
0290 }
0291 if (targetY + chooser.height > background.height) {
0292 targetY = background.height - chooser.height - 10;
0293 }
0294 chooser.x = targetX;
0295 chooser.y = targetY;
0296 chooser.visible = true;
0297 //console.log(" item.x = " + item.x + " item.y" + item.y+" absolute.x" + absolute.x +" absolute.y" + absolute.y)
0298 }
0299
0300 Rectangle {
0301 id: chooser
0302
0303 width: chooserGrid.width + 5
0304 height: chooserGrid.height + 5
0305
0306 color: "darkgray"
0307 border.width: 0
0308 border.color: "white"
0309
0310 opacity: 1
0311 visible: false
0312 z: 10
0313
0314 GridView {
0315 id: chooserGrid
0316
0317 cellWidth: graphRect.optDiameter - 2
0318 cellHeight: cellWidth
0319 width: Math.ceil(count / 2) * cellWidth
0320 height: 2 * cellHeight
0321 anchors.centerIn: parent
0322 z: 11
0323
0324 clip: false
0325 interactive: false
0326 verticalLayoutDirection: GridView.TopToBottom
0327 layoutDirection: Qt.LeftToRight
0328 flow: GridView.FlowLeftToRight
0329 highlight: Rectangle {
0330 color: "#80ffffff"
0331 visible: items.currentKeyZone === chooser && items.keyNavigationMode
0332 }
0333
0334 property int gridCount : count
0335 property int colIndex: 0
0336 property int guessIndex: 0
0337
0338 model: new Array()
0339
0340 delegate: Node {
0341 id: chooserItem
0342 width: graphRect.optDiameter - 5
0343 height: width
0344 border.width: index == chooserGrid.colIndex ? 3 : 1
0345 border.color: index == chooserGrid.colIndex ? "white" : "darkgray"
0346 searchItemIndex: modelData
0347 highlightSymbol: index == chooserGrid.colIndex
0348 radius: width * 0.5
0349
0350 MouseArea {
0351 id: chooserMouseArea
0352 anchors.fill: parent
0353 acceptedButtons: Qt.LeftButton
0354 enabled: !bonus.isPlaying
0355 z: 11
0356 hoverEnabled: ApplicationInfo.isMobile ? false : true
0357
0358 onClicked: {
0359 chooserGrid.colIndex = chooserItem.searchItemIndex;
0360 chooser.selectItem();
0361 }
0362 }
0363 }
0364 }
0365
0366 function handleKeys(event) {
0367 if(event.key === Qt.Key_Right) {
0368 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav');
0369 chooserGrid.currentIndex += 1;
0370 if(chooserGrid.currentIndex > chooserGrid.count - 1) {
0371 chooserGrid.currentIndex = 0;
0372 }
0373 }
0374 if(event.key === Qt.Key_Left) {
0375 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav');
0376 chooserGrid.currentIndex -= 1;
0377 if(chooserGrid.currentIndex < 0) {
0378 chooserGrid.currentIndex = chooserGrid.count - 1;
0379 }
0380 }
0381 if(event.key === Qt.Key_Space) {
0382 chooserGrid.colIndex = chooserGrid.currentItem.searchItemIndex;
0383 selectItem();
0384 }
0385 }
0386
0387 function selectItem() {
0388 activity.audioEffects.play('qrc:/gcompris/src/core/resource/sounds/smudge.wav');
0389 var obj = items.nodesRepeater.model;
0390 obj.setProperty(chooserGrid.guessIndex, "colIndex", chooserGrid.colIndex);
0391 showChooser(false);
0392 Activity.checkAdjacent();
0393 Activity.checkGuess();
0394 items.currentKeyZone = graphRect;
0395 }
0396 }
0397
0398 DialogHelp {
0399 id: dialogHelp
0400 onClose: home()
0401 }
0402
0403 DialogChooseLevel {
0404 id: dialogActivityConfig
0405 currentActivity: activity.activityInfo
0406
0407 onClose: {
0408 home();
0409 eventHandler.forceActiveFocus();
0410 }
0411 onLoadData: {
0412 if(activityData && activityData["mode"]) {
0413 items.mode = activityData["mode"];
0414 }
0415 }
0416 onStartActivity: {
0417 eventHandler.forceActiveFocus();
0418 }
0419 }
0420
0421 Bar {
0422 id: bar
0423 level: items.currentLevel + 1
0424 content: BarEnumContent { value: activityConfig | help | home | level }
0425 onHelpClicked: {
0426 displayDialog(dialogHelp)
0427 }
0428 onPreviousLevelClicked: Activity.previousLevel()
0429 onNextLevelClicked: Activity.nextLevel()
0430 onHomeClicked: activity.home()
0431 onActivityConfigClicked: {
0432 displayDialog(dialogActivityConfig)
0433 }
0434 }
0435
0436 Bonus {
0437 id: bonus
0438 Component.onCompleted: win.connect(Activity.nextLevel)
0439 }
0440 }
0441
0442 }