Warning, /education/gcompris/src/activities/programmingMaze/CodeArea.qml is written in an unsupported language. File is not indexed.
0001 /* GCompris - CodeArea.qml 0002 * 0003 * SPDX-FileCopyrightText: 2015 Siddhesh Suthar <siddhesh.it@gmail.com> 0004 * SPDX-FileCopyrightText: 2018 Aman Kumar Gupta <gupta2140@gmail.com> 0005 * 0006 * Authors: 0007 * Siddhesh Suthar <siddhesh.it@gmail.com> 0008 * Aman Kumar Gupta <gupta2140@gmail.com> 0009 * Timothée Giet <animtim@gcompris.net> (Layout and graphics rework) 0010 * 0011 * SPDX-License-Identifier: GPL-3.0-or-later 0012 */ 0013 import QtQuick 2.12 0014 import GCompris 1.0 0015 0016 import "programmingMaze.js" as Activity 0017 0018 GridView { 0019 id: codeArea 0020 z: 1 0021 width: background.width * 0.4 0022 height: background.height * 0.29 0023 cellWidth: background.buttonWidth 0024 cellHeight: background.buttonHeight 0025 0026 interactive: false 0027 model: currentModel 0028 0029 highlight: Rectangle { 0030 width: buttonWidth 0031 height: buttonHeight 0032 color: "#00ffffff" 0033 border.width: 3.5 * ApplicationInfo.ratio 0034 border.color: "#e77935" 0035 z: 11 0036 radius: width / 18 0037 } 0038 highlightFollowsCurrentItem: true 0039 keyNavigationWraps: true 0040 focus: true 0041 0042 property ListModel currentModel 0043 property int draggedItemIndex: -1 0044 property int possibleDropIndex: -1 0045 property int possibleDropRemoveIndex: -1 0046 property int xCoordinateInPossibleDrop: -1 0047 property int yCoordinateInPossibleDrop: -1 0048 0049 /** 0050 * Stores the index of the item which is clicked to edit. 0051 * 0052 * If the index of the item on 2nd click is same as initialEditItemIndex , then the indicator will become invisible, as it means that initially wanted to edit that instruction, but now we want to deselect it. 0053 * 0054 * If the index of the item on 2nd click is different from initialEditItemIndex, the edit indicator moves to the new item as we now want to edit that one. 0055 */ 0056 property int initialEditItemIndex: -1 0057 0058 // Tells if any instruction is selected for editing. 0059 property bool isEditingInstruction: false 0060 0061 signal spaceKeyPressed 0062 signal tabKeyPressed 0063 signal deleteKeyPressed 0064 0065 /** 0066 * There can be three possibilities here: 0067 * 0068 * 1. We want to insert an instruction at the currentIndex position. 0069 * 2. We want to select an instruction to edit, or deselect it. 0070 * 3. We want to append an instruction. 0071 */ 0072 onSpaceKeyPressed: { 0073 if(currentIndex != -1) { 0074 if(instructionArea.instructionToInsert && (items.numberOfInstructionsAdded < items.maxNumberOfInstructionsAllowed)) { 0075 var isInstructionInserted = appendInstruction() 0076 if(isInstructionInserted) 0077 currentModel.move(currentModel.count - 1, currentIndex, 1) 0078 } 0079 else { 0080 if((initialEditItemIndex == currentIndex) || (initialEditItemIndex == -1 && currentIndex != -1)) { 0081 codeArea.isEditingInstruction = !codeArea.isEditingInstruction 0082 } 0083 if(!codeArea.isEditingInstruction) 0084 codeArea.initialEditItemIndex = -1 0085 else 0086 initialEditItemIndex = currentIndex 0087 0088 var calculatedX = (initialEditItemIndex % 4) * codeArea.cellWidth 0089 var calculatedY = Math.floor(initialEditItemIndex / 4) * codeArea.cellHeight 0090 editInstructionIndicator.x = calculatedX + 1.5 * ApplicationInfo.ratio 0091 editInstructionIndicator.y = calculatedY + 1.5 * ApplicationInfo.ratio 0092 } 0093 } 0094 0095 else if((items.numberOfInstructionsAdded < items.maxNumberOfInstructionsAllowed) && instructionArea.instructionToInsert) 0096 appendInstruction() 0097 } 0098 0099 onDeleteKeyPressed: { 0100 if(currentIndex != -1) { 0101 currentModel.remove(currentIndex) 0102 items.numberOfInstructionsAdded-- 0103 } 0104 resetEditingValues() 0105 } 0106 0107 function appendInstruction() { 0108 if(background.insertIntoMain || (instructionArea.instructionToInsert != "call-procedure") || (instructionArea.instructionToInsert != "execute-loop")) { 0109 currentModel.append({ "name": instructionArea.instructionToInsert }) 0110 items.numberOfInstructionsAdded++ 0111 instructionArea.instructionToInsert = "" 0112 return true 0113 } 0114 return false 0115 } 0116 0117 function resetEditingValues() { 0118 initialEditItemIndex = -1 0119 isEditingInstruction = false 0120 } 0121 0122 Item { 0123 id: dropPositionIndicator 0124 visible: false 0125 height: background.buttonHeight 0126 width: 3 * ApplicationInfo.ratio 0127 0128 Rectangle { 0129 visible: parent.visible 0130 anchors.centerIn: parent 0131 width: parent.width 0132 height: parent.height - 3 * ApplicationInfo.ratio 0133 color: "#e77935" 0134 } 0135 0136 states: [ 0137 State { 0138 name: "shown" 0139 when: codeArea.possibleDropIndex != -1 0140 PropertyChanges { 0141 target: dropPositionIndicator 0142 visible: true 0143 x: Math.floor(codeArea.xCoordinateInPossibleDrop / codeArea.cellWidth) * 0144 codeArea.cellWidth - 1.5 * ApplicationInfo.ratio 0145 y: Math.floor(codeArea.yCoordinateInPossibleDrop / codeArea.cellHeight) * 0146 codeArea.cellHeight + 1.5 * ApplicationInfo.ratio 0147 } 0148 } 0149 ] 0150 } 0151 0152 Rectangle { 0153 id: editInstructionIndicator 0154 visible: codeArea.isEditingInstruction && codeArea.count != 0 0155 width: background.buttonWidth - 3 * ApplicationInfo.ratio 0156 height: background.buttonHeight - 3 * ApplicationInfo.ratio 0157 color: "red" 0158 border.color: "red" 0159 border.width: 1.5 * ApplicationInfo.ratio 0160 opacity: 0.2 0161 radius: width / 18 0162 } 0163 0164 MouseArea { 0165 id: codeAreaMouse 0166 anchors.fill: parent 0167 enabled: items.isRunCodeEnabled 0168 onPressed: { 0169 codeArea.currentIndex = -1 0170 codeArea.draggedItemIndex = codeArea.indexAt(mouseX,mouseY) 0171 if(codeArea.draggedItemIndex === -1) { 0172 constraintInstruction.changeConstraintInstructionOpacity() 0173 codeArea.isEditingInstruction = false 0174 } 0175 else if(!codeArea.isEditingInstruction) 0176 codeArea.initialEditItemIndex = codeArea.draggedItemIndex 0177 } 0178 0179 onPositionChanged: { 0180 var newPos = codeArea.indexAt(mouseX, mouseY) 0181 var calculatedX = Math.floor(mouseX / codeArea.cellWidth) * codeArea.cellWidth 0182 var previousIndexPosition = codeArea.indexAt(calculatedX - 1, mouseY) 0183 0184 // If the user want to move an item to the end, then the new position will be after the last instruction. 0185 if(newPos == -1 && previousIndexPosition != -1) 0186 newPos = previousIndexPosition + 1 0187 0188 codeArea.isEditingInstruction = false 0189 codeArea.xCoordinateInPossibleDrop = mouseX 0190 codeArea.yCoordinateInPossibleDrop = mouseY 0191 codeArea.possibleDropIndex = newPos 0192 } 0193 0194 onReleased: { 0195 if(codeArea.draggedItemIndex != -1) { 0196 var draggedIndex = codeArea.draggedItemIndex 0197 var dropIndex = codeArea.indexAt(mouseX,mouseY) 0198 var calculatedX = Math.floor(mouseX / codeArea.cellWidth) * codeArea.cellWidth 0199 var calculatedY = Math.floor(mouseY / codeArea.cellHeight) * codeArea.cellHeight 0200 codeArea.draggedItemIndex = -1 0201 0202 if(dropIndex == -1) { 0203 var previousIndexPosition = codeArea.indexAt(calculatedX - 1, mouseY) 0204 if(previousIndexPosition == -1) { 0205 currentModel.remove(draggedIndex) 0206 items.numberOfInstructionsAdded-- 0207 } 0208 else { 0209 currentModel.append(currentModel.get(draggedIndex)) 0210 currentModel.remove(draggedIndex) 0211 } 0212 codeArea.initialEditItemIndex = -1 0213 } 0214 else if(draggedIndex != dropIndex) { 0215 if(dropIndex <= draggedIndex) { 0216 // Moving instruction from right to left 0217 currentModel.move(draggedIndex, dropIndex, 1) 0218 } 0219 else { 0220 // Moving instruction from left to right 0221 currentModel.move(draggedIndex, dropIndex - 1, 1) 0222 } 0223 codeArea.initialEditItemIndex = -1 0224 } 0225 else { 0226 /** 0227 * If the index of the initially selected instruction (if any) is same as the currently selected instruction, 0228 * deselect it for editing, else make the current instruction as the initially editable item and move the edit indicator to that position. 0229 */ 0230 if(codeArea.initialEditItemIndex == dropIndex) { 0231 codeArea.isEditingInstruction = !codeArea.isEditingInstruction 0232 if(!codeArea.isEditingInstruction) 0233 codeArea.initialEditItemIndex = -1 0234 } 0235 else 0236 codeArea.initialEditItemIndex = draggedIndex 0237 0238 editInstructionIndicator.x = calculatedX + 1.5 * ApplicationInfo.ratio 0239 editInstructionIndicator.y = calculatedY + 1.5 * ApplicationInfo.ratio 0240 } 0241 codeArea.possibleDropIndex = -1 0242 } 0243 } 0244 } 0245 0246 delegate: Item { 0247 id: itemParent 0248 width: background.buttonWidth 0249 height: background.buttonHeight 0250 0251 Item { 0252 id: item 0253 width: background.buttonWidth 0254 height: background.buttonHeight 0255 state: "inactive" 0256 opacity: 1 0257 0258 Behavior on width { NumberAnimation { duration: 300; easing.type: Easing.InOutQuad } } 0259 Behavior on height { NumberAnimation { duration: 300; easing.type: Easing.InOutQuad } } 0260 Behavior on opacity {NumberAnimation { duration: 300; easing.type: Easing.InOutQuad } } 0261 0262 states: [ 0263 State { 0264 name: "inDrag" 0265 when: index == codeArea.draggedItemIndex 0266 0267 PropertyChanges { target: item; parent: codeArea } 0268 PropertyChanges { target: item; width: background.buttonWidth * 0.80 } 0269 PropertyChanges { target: item; height: background.buttonHeight * 0.80 } 0270 PropertyChanges { target: item; anchors.centerIn: undefined } 0271 PropertyChanges { target: item; x: codeAreaMouse.mouseX - item.width / 2 } 0272 PropertyChanges { target: item; y: codeAreaMouse.mouseY - item.height / 2 } 0273 }, 0274 State { 0275 name: "greyedOut" 0276 when: (codeArea.draggedItemIndex != -1) && (codeArea.draggedItemIndex != index) 0277 0278 PropertyChanges { target: item; opacity: 0.7 } 0279 }, 0280 State { 0281 name: "inactive" 0282 when: (codeArea.draggedItemIndex == -1) || (codeArea.draggedItemIndex == index) 0283 0284 PropertyChanges { target: item; opacity: 1.0 } 0285 } 0286 ] 0287 0288 transitions: [ 0289 Transition { 0290 from: "inDrag" 0291 to: "*" 0292 PropertyAnimation { 0293 target: item 0294 properties: "scale, opacity" 0295 from: 0.7 0296 to: 1.0 0297 duration: 200 0298 } 0299 } 0300 ] 0301 0302 Rectangle { 0303 width: parent.width - 3 * ApplicationInfo.ratio 0304 height: parent.height - 3 * ApplicationInfo.ratio 0305 border.width: 1.2 * ApplicationInfo.ratio 0306 border.color: "#2a2a2a" 0307 anchors.centerIn: parent 0308 radius: width / 18 0309 0310 Image { 0311 id: codeAreaIcon 0312 source: Activity.url + name + ".svg" 0313 width: Math.round(parent.width / 1.2) 0314 height: Math.round(parent.height / 1.2) 0315 sourceSize.width: height 0316 sourceSize.height: height 0317 anchors.centerIn: parent 0318 fillMode: Image.PreserveAspectFit 0319 mipmap: true 0320 } 0321 } 0322 } 0323 } 0324 }