diff --git a/src/activities/digital_electricity/Dataset.qml b/src/activities/digital_electricity/Dataset.qml index f31060a46..05ceed553 100644 --- a/src/activities/digital_electricity/Dataset.qml +++ b/src/activities/digital_electricity/Dataset.qml @@ -1,82 +1,80 @@ /* GCompris - Dataset.qml * * Copyright (C) 2017 Rudra Nil Basu * * Authors: * Bruno Coudoin (GTK+ version) * Rudra Nil Basu (Qt Quick port) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ import QtQuick 2.6 QtObject { - property variant zero: { + property var zero: { 'imageName': 'zero.svg', 'componentSource': 'Zero.qml', 'width': 0.12, 'height': 0.2, 'toolTipText': qsTr("Zero input") } - property variant one: { + property var one: { 'imageName': 'one.svg', 'componentSource': 'One.qml', 'width': 0.12, 'height': 0.2, 'toolTipText': qsTr("One input") } - property variant digitalLight: { + property var digitalLight: { 'imageName': 'DigitalLightOff.svg', 'componentSource': 'DigitalLight.qml', 'width': 0.12, 'height': 0.12, 'toolTipText': qsTr("Digital Light") } - property variant andGate: { + property var andGate: { 'imageName': 'gateAnd.svg', 'componentSource': 'AndGate.qml', 'width': 0.15, 'height': 0.12, 'toolTipText': qsTr("AND gate") } // tutorial levels property var tutorialLevels: [ // level 1 { - totalComponents: 3, imageName: [zero.imageName, one.imageName, digitalLight.imageName], componentSource: [zero.componentSource, one.componentSource, digitalLight.componentSource], imgWidth: [zero.width, one.width, digitalLight.width], imgHeight: [zero.height, one.height, digitalLight.height], toolTipText: [zero.toolTipText, one.toolTipText, digitalLight.toolTipText], introMessage: [ qsTr("The Digital light will glow when it's terminal is connected with an input of 1"), qsTr("Turn the Digital light on using the inputs provided") ] }, // level 2 { - totalComponents: 4, imageName: [zero.imageName, one.imageName, andGate.imageName, digitalLight.imageName], componentSource: [zero.componentSource, one.componentSource, andGate.componentSource, digitalLight.componentSource], imgWidth: [zero.width, one.width, andGate.width, digitalLight.width], imgHeight: [zero.height, one.height, andGate.height, digitalLight.height], toolTipText: [zero.toolTipText, one.toolTipText, andGate.toolTipText, digitalLight.toolTipText], introMessage: [ qsTr("The AND Gate"), qsTr("Turn the Digital light on using an AND gate and the inputs provided") ] } ] } diff --git a/src/activities/digital_electricity/DigitalElectricity.qml b/src/activities/digital_electricity/DigitalElectricity.qml index 05196d4fc..dc83b4a35 100644 --- a/src/activities/digital_electricity/DigitalElectricity.qml +++ b/src/activities/digital_electricity/DigitalElectricity.qml @@ -1,394 +1,425 @@ /* GCompris - DigitalElectricity.qml * * Copyright (C) 2016 Pulkit Gupta * * Authors: * Bruno Coudoin (GTK+ version) * Pulkit Gupta (Qt Quick port) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ import QtQuick 2.3 import GCompris 1.0 import "../../core" import "digital_electricity.js" as Activity ActivityBase { id: activity onStart: focus = true onStop: {} - property bool isTutorialMode: true + property string mode: "tutorial" + property bool isTutorialMode: mode == "tutorial" ? true : false pageComponent: Rectangle { id: background anchors.fill: parent color: "#ffffb3" signal start signal stop property bool vert: background.width > background.height Component.onCompleted: { + dialogActivityConfig.getInitialConfiguration() activity.start.connect(start) activity.stop.connect(stop) } // Add here the QML items you need to access in javascript QtObject { id: items property Item main: activity.main property alias playArea: playArea property alias bar: bar property alias bonus: bonus property alias availablePieces: availablePieces property alias toolTip: toolTip property alias infoTxt: infoTxt property alias truthTablesModel: truthTablesModel property alias displayTruthTable: inputOutputTxt.displayTruthTable property alias dataset: dataset property alias tutorialDataset: tutorialDataset property alias infoImage: infoImage property bool isTutorialMode: activity.isTutorialMode property alias tutorialInstruction: tutorialInstruction } Loader { id: dataset asynchronous: false } Dataset { id: tutorialDataset } IntroMessage { id: tutorialInstruction visible: activity.isTutorialMode anchors { top: background.vert ? parent.top : inputComponentsContainer.bottom topMargin: 10 right: parent.right rightMargin: 5 left: background.vert ? inputComponentsContainer.right : parent.left leftMargin: 5 } z: 100 onIntroDone: tutorialInstruction.visible = false } onStart: { Activity.start(items) } onStop: { Activity.stop() } Rectangle { id: playArea color: "#ffffb3" x: background.vert ? 90 * ApplicationInfo.ratio : 0 y: background.vert ? 0 : 90 * ApplicationInfo.ratio width: background.vert ? background.width - 90 * ApplicationInfo.ratio : background.width height: background.vert ? background.height - (bar.height * 1.1) : background.height - (bar.height * 1.1) - 90 * ApplicationInfo.ratio MouseArea { anchors.fill: parent onClicked: Activity.deselect() } GCText { id: infoTxt anchors { horizontalCenter: parent.horizontalCenter top: infoTxtContainer.top topMargin: 2 } fontSizeMode: Text.Fit minimumPixelSize: 10 color: "white" style: Text.Outline styleColor: "black" horizontalAlignment: Text.AlignHLeft width: Math.min(implicitWidth, 0.90 * parent.width) height: inputOutputTxt.visible == false ? Math.min(implicitHeight, 0.9 * parent.height) : Math.min(implicitHeight, (inputOutputTxt.inputs > 2 ? 0.3 : 0.4) * parent.height) wrapMode: TextEdit.WordWrap visible: false z: 4 } Rectangle { id: infoTxtContainer anchors.centerIn: parent width: infoTxt.width + 20 height: inputOutputTxt.visible == false ? infoTxt.height + infoImage.height + 6 : infoTxt.height + inputOutputTxt.height + truthTable.height + 8 opacity: 0.8 radius: 10 border.width: 2 border.color: "black" visible: infoTxt.visible gradient: Gradient { GradientStop { position: 0.0; color: "#000" } GradientStop { position: 0.9; color: "#666" } GradientStop { position: 1.0; color: "#AAA" } } MouseArea { anchors.fill: parent onClicked: infoTxt.visible = false } z: 3 } Image { id: infoImage property int heightNeed: parent.height - infoTxt.height property bool imgVisible: false height: source == "" ? 0 : parent.height - infoTxt.height - 10 width: source == "" ? 0 : parent.width - 10 fillMode: Image.PreserveAspectFit visible: infoTxt.visible && imgVisible anchors { top: infoTxt.bottom horizontalCenter: parent.horizontalCenter } z: 5 } ListModel { id: truthTablesModel property int rows property int columns property int inputs property int outputs } Row { id: inputOutputTxt z: 5 property bool displayTruthTable visible: infoTxt.visible && displayTruthTable property int inputs: truthTablesModel.inputs property int outputs: truthTablesModel.outputs property int cellSize: Math.min(parent.height - infoTxt.height - 10, (inputs > 2 ? 0.6 : 0.45) * parent.height) / truthTablesModel.rows property int minSize: 2 * cellSize height: cellSize anchors { top: infoTxt.bottom horizontalCenter: parent.horizontalCenter } Rectangle { color: "#c7ecfb" width: Math.max(inputOutputTxt.minSize, inputOutputTxt.cellSize * inputOutputTxt.inputs) height: inputOutputTxt.cellSize border.color: "black" border.width: 1 GCText { anchors.centerIn: parent fontSizeMode: Text.Fit minimumPixelSize: 10 color: "white" style: Text.Outline styleColor: "black" horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter height: parent.height width: parent.width text: qsTr("Input") } } Rectangle { color: "#47ffc2" width: Math.max(inputOutputTxt.minSize, inputOutputTxt.cellSize * inputOutputTxt.outputs) * 1.5 height: inputOutputTxt.cellSize border.color: "black" border.width: 1 GCText { anchors.centerIn: parent fontSizeMode: Text.Fit minimumPixelSize: 10 color: "white" style: Text.Outline styleColor: "black" horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter height: parent.height width: parent.width text: qsTr("Output") } } } Grid { id: truthTable rows: truthTablesModel.rows columns: truthTablesModel.columns height: rows * inputOutputTxt.cellSize z: 5 visible: inputOutputTxt.visible anchors { top: inputOutputTxt.bottom horizontalCenter: parent.horizontalCenter } Repeater { id: repeater model: truthTablesModel delegate: blueSquare Component { id: blueSquare Rectangle { width: ((index % truthTable.columns) / (truthTablesModel.inputs - 1)) <= 1 ? (inputOutputTxt.inputs > 1 ? inputOutputTxt.cellSize : inputOutputTxt.minSize) : (inputOutputTxt.outputs > 1 ? inputOutputTxt.cellSize : inputOutputTxt.minSize) * 1.5 height: inputOutputTxt.cellSize border.color: "black" border.width: 1 color: ((index % truthTable.columns) / (truthTablesModel.inputs - 1)) <= 1 ? "#c7ecfb" : "#47ffc2" GCText { id: truthTableValue anchors.centerIn: parent fontSizeMode: Text.Fit minimumPixelSize: 10 color: "white" style: Text.Outline styleColor: "black" horizontalAlignment: Text.AlignHCenter height: parent.height width: parent.width text: value } } } } } } Rectangle { id: inputComponentsContainer width: background.vert ? 90 * ApplicationInfo.ratio : background.width height: background.vert ? background.height : 90 * ApplicationInfo.ratio color: "#FFFF42" border.color: "#FFD85F" border.width: 4 anchors.left: parent.left ListWidget { id: availablePieces vert: background.vert ? true : false } } Rectangle { id: toolTip anchors { bottom: bar.top bottomMargin: 10 left: inputComponentsContainer.left leftMargin: 5 } width: toolTipTxt.width + 10 height: toolTipTxt.height + 5 opacity: 1 radius: 10 z: 100 border.width: 2 border.color: "black" gradient: Gradient { GradientStop { position: 0.0; color: "#000" } GradientStop { position: 0.9; color: "#666" } GradientStop { position: 1.0; color: "#AAA" } } property alias text: toolTipTxt.text Behavior on opacity { NumberAnimation { duration: 120 } } function show(newText) { if(newText) { text = newText opacity = 0.8 } else { opacity = 0 } } GCText { id: toolTipTxt anchors.centerIn: parent fontSize: regularSize color: "white" style: Text.Outline styleColor: "black" horizontalAlignment: Text.AlignHCenter wrapMode: TextEdit.WordWrap } } DialogActivityConfig { id: dialogActivityConfig + currentActivity: activity content: Component { - Column { - id: column - spacing: 5 - width: dialogActivityConfig.width - height: dialogActivityConfig.height - GCDialogCheckBox { - id: mode - width: column.width - 50 - text: qsTr("Tutorial Mode") - checked: activity.isTutorialMode - onClicked: { - activity.isTutorialMode = !activity.isTutorialMode - Activity.changeMode() + Item { + property alias modesComboBox: modesComboBox + + property var availableModes: [ + { "text": qsTr("Tutorial Mode"), "value": "tutorial" }, + { "text": qsTr("Free Mode"), "value": "free" }, + ] + + Flow { + id: flow + spacing: 5 + width: dialogActivityConfig.width + GCComboBox { + id: modesComboBox + model: availableModes + background: dialogActivityConfig + label: qsTr("Select your Mode") } } } + } + + onClose: home(); + onLoadData: { + if(dataToSave && dataToSave["modes"]) { + activity.mode = dataToSave["modes"]; + } } - onClose: home() + onSaveData: { + var newMode = dialogActivityConfig.configItem.availableModes[dialogActivityConfig.configItem.modesComboBox.currentIndex].value; + if (newMode !== activity.mode) { + activity.mode = newMode; + dataToSave = {"modes": activity.mode}; + Activity.reset() + } + } + + function setDefaultValues() { + for(var i = 0 ; i < dialogActivityConfig.configItem.availableModes.length; i ++) { + if(dialogActivityConfig.configItem.availableModes[i].value === activity.levelSet) { + dialogActivityConfig.configItem.modesComboBox.currentIndex = i; + break; + } + } + } } DialogHelp { id: dialogHelp onClose: home() } Bar { id: bar content: BarEnumContent { value: help | home | ( activity.isTutorialMode ? level : 0) | reload | config} onHelpClicked: {displayDialog(dialogHelp)} onPreviousLevelClicked: Activity.previousLevel() onNextLevelClicked: Activity.nextLevel() onHomeClicked: activity.home() onReloadClicked: Activity.reset() onConfigClicked: { dialogActivityConfig.active = true + dialogActivityConfig.setDefaultValues() displayDialog(dialogActivityConfig) } } Bonus { id: bonus Component.onCompleted: win.connect(Activity.nextLevel) } } } diff --git a/src/activities/digital_electricity/digital_electricity.js b/src/activities/digital_electricity/digital_electricity.js index 3159a89c3..0d5c7f566 100644 --- a/src/activities/digital_electricity/digital_electricity.js +++ b/src/activities/digital_electricity/digital_electricity.js @@ -1,493 +1,483 @@ /* GCompris - digital_electricity.js * * Copyright (C) 2016 Pulkit Gupta * * Authors: * Bruno Coudoin (GTK+ version) * Pulkit Gupta (Qt Quick port) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ .pragma library .import QtQuick 2.3 as Quick var currentLevel = 1 var numberOfLevel var items var url = "qrc:/gcompris/src/activities/digital_electricity/resource/" var toolDelete var toolDeleteSticky var selectedIndex var animationInProgress var selectedTerminal var deletedIndex = [] var components = [] var connected = [] function start(items_) { items = items_ currentLevel = 1 - numberOfLevel = items.isTutorialMode ? items.tutorialDataset.tutorialLevels.length : 1 + numberOfLevel = items.tutorialDataset.tutorialLevels.length initLevel() } function stop() { for(var i = 0 ; i < components.length ; ++i) { var j for(j = 0 ; j < deletedIndex.length ; ++j) { if(deletedIndex[j] == i) break } if(j == deletedIndex.length) removeComponent(i) } } function initLevel() { items.bar.level = currentLevel var sizeMultiplier = 1 + (1 / (1.5 * currentLevel)) if (!items.isTutorialMode) { items.tutorialInstruction.visible = false loadFreeMode(sizeMultiplier) } else { // load tutorial levels from dataset var levelProperties = items.tutorialDataset.tutorialLevels[currentLevel - 1] - for (var i = 0; i < levelProperties.totalComponents; i++) { + for (var i = 0; i < levelProperties.imageName.length; i++) { items.availablePieces.model.append( { "imgName": levelProperties.imageName[i], "componentSrc": levelProperties.componentSource[i], "imgWidth": levelProperties.imgWidth[i] * sizeMultiplier, "imgHeight": levelProperties.imgHeight[i] * sizeMultiplier, "toolTipText": levelProperties.toolTipText[i] }) items.tutorialInstruction.visible = true items.tutorialInstruction.index = 0 items.tutorialInstruction.intro = levelProperties.introMessage } } items.availablePieces.view.currentDisplayedGroup = 0 items.availablePieces.view.previousNavigation = 1 items.availablePieces.view.nextNavigation = 1 deletedIndex = [] components = [] connected = [] animationInProgress = false toolDelete = false toolDeleteSticky = false deselect() updateToolTip("") } function loadFreeMode(sizeMultiplier) { items.availablePieces.model.append( { "imgName": "zero.svg", "componentSrc": "Zero.qml", "imgWidth": sizeMultiplier * 0.12, "imgHeight": sizeMultiplier * 0.2, "toolTipText": qsTr("Zero input") }) items.availablePieces.model.append( { "imgName": "one.svg", "componentSrc": "One.qml", "imgWidth": sizeMultiplier * 0.12, "imgHeight": sizeMultiplier * 0.2, "toolTipText": qsTr("One input") }) items.availablePieces.model.append( { "imgName": "DigitalLightOff.svg", "componentSrc": "DigitalLight.qml", "imgWidth": sizeMultiplier * 0.12, "imgHeight": sizeMultiplier * 0.12, "toolTipText": qsTr("Digital Light") }) items.availablePieces.model.append( { "imgName": "gateAnd.svg", "componentSrc": "AndGate.qml", "imgWidth": sizeMultiplier * 0.15, "imgHeight": sizeMultiplier * 0.12, "toolTipText": qsTr("AND gate") }) items.availablePieces.model.append( { "imgName": "gateNand.svg", "componentSrc": "NandGate.qml", "imgWidth": sizeMultiplier * 0.15, "imgHeight": sizeMultiplier * 0.12, "toolTipText": qsTr("NAND gate") }) items.availablePieces.model.append( { "imgName": "gateNor.svg", "componentSrc": "NorGate.qml", "imgWidth": sizeMultiplier * 0.15, "imgHeight": sizeMultiplier * 0.12, "toolTipText": qsTr("NOR gate") }) items.availablePieces.model.append( { "imgName": "gateNot.svg", "componentSrc": "NotGate.qml", "imgWidth": sizeMultiplier * 0.15, "imgHeight": sizeMultiplier * 0.12, "toolTipText": qsTr("NOT gate") }) items.availablePieces.model.append( { "imgName": "gateOr.svg", "componentSrc": "OrGate.qml", "imgWidth": sizeMultiplier * 0.15, "imgHeight": sizeMultiplier * 0.12, "toolTipText": qsTr("OR gate") }) items.availablePieces.model.append( { "imgName": "gateXor.svg", "componentSrc": "XorGate.qml", "imgWidth": sizeMultiplier * 0.15, "imgHeight": sizeMultiplier * 0.12, "toolTipText": qsTr("XOR gate") }) items.availablePieces.model.append( { "imgName": "comparator.svg", "componentSrc": "Comparator.qml", "imgWidth": sizeMultiplier * 0.3, "imgHeight": sizeMultiplier * 0.25, "toolTipText": qsTr("Comparator") }) items.availablePieces.model.append( { "imgName": "BCDTo7Segment.svg", "componentSrc": "BCDToSevenSegment.qml", "imgWidth": sizeMultiplier * 0.3, "imgHeight": sizeMultiplier * 0.4, "toolTipText": qsTr("BCD To 7 Segment") }) items.availablePieces.model.append( { "imgName": "sevenSegmentDisplay.svgz", "componentSrc": "SevenSegment.qml", "imgWidth": sizeMultiplier * 0.18, "imgHeight": sizeMultiplier * 0.4, "toolTipText": qsTr("7 Segment Display") }) items.availablePieces.model.append( { "imgName": "switchOff.svg", "componentSrc": "Switch.qml", "imgWidth": sizeMultiplier * 0.18, "imgHeight": sizeMultiplier * 0.15, "toolTipText": qsTr("Switch") }) items.availablePieces.model.append( { "imgName": "signalGenerator.svg", "componentSrc": "SignalGenerator.qml", "imgWidth": sizeMultiplier * 0.25, "imgHeight": sizeMultiplier * 0.18, "toolTipText": qsTr("Signal Generator") }) items.availablePieces.model.append( { "imgName": "bcdCounter.svg", "componentSrc": "BcdCounter.qml", "imgWidth": sizeMultiplier * 0.3, "imgHeight": sizeMultiplier * 0.4, "toolTipText": qsTr("BCD Counter") }) } -function changeMode() { - if (items.isTutorialMode) { - numberOfLevel = items.tutorialDataset.tutorialLevels.length - } else { - numberOfLevel = 1 - } - currentLevel = 1 - reset() -} - function nextLevel() { if(numberOfLevel < ++currentLevel ) { currentLevel = 1 } reset(); } function previousLevel() { if(--currentLevel < 1) { currentLevel = numberOfLevel } reset(); } function reset() { deselect() stop() items.availablePieces.model.clear() initLevel() } // Creates component from ListWidget to the drawing board area function createComponent(x, y, componentIndex) { x = x / items.playArea.width y = y / items.playArea.height var index if(deletedIndex.length > 0) { index = deletedIndex[deletedIndex.length - 1] deletedIndex.pop() } else index = components.length var component = items.availablePieces.repeater.itemAt(componentIndex) var electricComponent = Qt.createComponent("qrc:/gcompris/src/activities/digital_electricity/components/" + component.source) //console.log("Error loading component:", electricComponent.errorString()) components[index] = electricComponent.createObject( items.playArea, { "index": index, "posX": x, "posY": y, "imgSrc": component.imageName, "toolTipTxt": component.toolTipTxt, "imgWidth": component.imageWidth, "imgHeight": component.imageHeight }); toolDeleteSticky = false deselect() componentSelected(index) updateComponent(index) } /* Creates wire between two terminals. Condition for creation of wire is that an input terminal * can only be connected to 1 wire, output terminals can be connected by any number of wires, and * an input terminal can be connected with an output terminal only. 'connected' variable is used * to make sure that an input is connected by only 1 wire. */ function terminalPointSelected(terminal) { if(selectedTerminal == -1 || selectedTerminal == terminal) selectedTerminal = terminal else if((selectedTerminal.type != terminal.type) && (selectedTerminal.parent != terminal.parent)) { var inTerminal = terminal.type == "In" ? terminal : selectedTerminal var outTerminal = terminal.type == "Out" ? terminal : selectedTerminal if(connected[inTerminal] == undefined || connected[inTerminal] == -1) { var wireComponent = Qt.createComponent("qrc:/gcompris/src/activities/digital_electricity/Wire.qml") var wire = wireComponent.createObject( items.playArea, { "from": outTerminal, "to": inTerminal }); inTerminal.value = outTerminal.value inTerminal.wires.push(wire) outTerminal.wires.push(wire) updateWires(inTerminal.parent.index) updateWires(outTerminal.parent.index) updateComponent(inTerminal.parent.index) connected[inTerminal] = outTerminal } deselect() } else { deselect() selectedTerminal = terminal terminal.selected = true } } /* Updates the output of the component. 'wireVisited' is used to update the value of * each wire once which will avoid updating the outputs of components in an infinite loop. */ function updateComponent(index) { var wireVisited = [] components[index].updateOutput(wireVisited) } /* Updates the orientation of the wire. It is called whenever a new wire is created or * an object is rotated. */ function updateWires(index) { var component = components[index] if(component == undefined || component.noOfInputs == undefined || component.noOfOutputs == undefined) return var rotatedAngle = component.initialAngle * Math.PI / 180 for(var i = 0 ; i < component.noOfInputs ; ++i) { var terminal = component.inputTerminals.itemAt(i) if(terminal.wires.length != 0) { var wire = terminal.wires[0] var otherAngle = wire.from.parent.initialAngle * Math.PI / 180 var x = wire.from.xCenterFromComponent var y = wire.from.yCenterFromComponent var x1 = wire.from.xCenter - x + x * Math.cos(otherAngle) - y * Math.sin(otherAngle) var y1 = wire.from.yCenter - y + x * Math.sin(otherAngle) + y * Math.cos(otherAngle) x = terminal.xCenterFromComponent y = terminal.yCenterFromComponent var x2 = terminal.xCenter - x + x * Math.cos(rotatedAngle) - y * Math.sin(rotatedAngle) var y2 = terminal.yCenter - y + x * Math.sin(rotatedAngle) + y * Math.cos(rotatedAngle) var width = Math.pow((Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)),0.5) + 2 var angle = (180/Math.PI)*Math.atan((y2-y1)/(x2-x1)) if(x2 - x1 < 0) angle = angle - 180 wire.x = x1 wire.y = y1 wire.width = width wire.rotation = angle } } for(var i = 0 ; i < component.noOfOutputs ; ++i) { var terminal = component.outputTerminals.itemAt(i) for(var j = 0 ; j < terminal.wires.length ; ++j) { var x = terminal.xCenterFromComponent var y = terminal.yCenterFromComponent var x1 = terminal.xCenter - x + x * Math.cos(rotatedAngle) - y * Math.sin(rotatedAngle) var y1 = terminal.yCenter - y + x * Math.sin(rotatedAngle) + y * Math.cos(rotatedAngle) var wire = terminal.wires[j] var otherAngle = wire.to.parent.initialAngle * Math.PI / 180 x = wire.to.xCenterFromComponent y = wire.to.yCenterFromComponent var x2 = wire.to.xCenter - x + x * Math.cos(otherAngle) - y * Math.sin(otherAngle) var y2 = wire.to.yCenter - y + x * Math.sin(otherAngle) + y * Math.cos(otherAngle) var width = Math.pow((Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)),0.5) + 2 var angle = (180/Math.PI)*Math.atan((y2-y1)/(x2-x1)) if(x2 - x1 < 0) angle = angle - 180 wire.x = x1 wire.y = y1 wire.width = width wire.rotation = angle } } } function deselect() { if(toolDeleteSticky == false) { toolDelete = false items.availablePieces.toolDelete.state = "notSelected" } items.availablePieces.rotateLeft.state = "canNotBeSelected" items.availablePieces.rotateRight.state = "canNotBeSelected" items.availablePieces.info.state = "canNotBeSelected" items.infoTxt.visible = false selectedIndex = -1 selectedTerminal = -1 for(var i = 0 ; i < components.length ; ++i) { var component = components[i] for(var j = 0 ; j < component.noOfInputs ; ++j) component.inputTerminals.itemAt(j).selected = false for(var j = 0 ; j < component.noOfOutputs ; ++j) component.outputTerminals.itemAt(j).selected = false } } function removeComponent(index) { var component = components[index] for(var i = 0 ; i < component.noOfInputs ; ++i) { var terminal = component.inputTerminals.itemAt(i) if(terminal.wires.length != 0) // Input Terminal can have only 1 wire removeWire(terminal.wires[0]) } for(var i = 0 ; i < component.noOfOutputs ; ++i) { var terminal = component.outputTerminals.itemAt(i) while (terminal.wires.length != 0) { removeWire(terminal.wires[0]) // Output Terminal can have more than 1 wire } } components[index].destroy() deletedIndex.push(index) deselect() } function removeWire(wire) { var inTerminal = wire.to var outTerminal = wire.from var removeIndex = inTerminal.wires.indexOf(wire) inTerminal.wires.splice(removeIndex,1) removeIndex = outTerminal.wires.indexOf(wire) outTerminal.wires.splice(removeIndex,1) connected[wire.to] = -1 inTerminal.value = 0 wire.destroy() updateComponent(inTerminal.parent.index) deselect() } function componentSelected(index) { selectedIndex = index items.availablePieces.rotateLeft.state = "canBeSelected" items.availablePieces.rotateRight.state = "canBeSelected" items.availablePieces.info.state = "canBeSelected" } function rotateLeft() { components[selectedIndex].rotationAngle = -2 components[selectedIndex].rotateComponent.start() } function rotateRight() { components[selectedIndex].rotationAngle = 2 components[selectedIndex].rotateComponent.start() } function displayInfo() { var component = components[selectedIndex] var componentTruthTable = component.truthTable deselect() items.infoTxt.visible = true items.infoTxt.text = component.information if(component.infoImageSrc != undefined) { items.infoImage.imgVisible = true items.infoImage.source = url + component.infoImageSrc } else { items.infoImage.imgVisible = false items.infoImage.source = "" } if(componentTruthTable.length == 0) items.displayTruthTable = false else { items.displayTruthTable = true var truthTable = items.truthTablesModel truthTable.clear() truthTable.rows = componentTruthTable.length truthTable.columns = componentTruthTable[0].length truthTable.inputs = component.noOfInputs truthTable.outputs = component.noOfOutputs for(var i = 0 ; i < componentTruthTable.length ; ++i) for(var j = 0 ; j < componentTruthTable[i].length ; ++j) truthTable.append({'value': componentTruthTable[i][j]}) } } function updateToolTip(toolTipTxt) { items.toolTip.show(toolTipTxt) }