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 }