Initial commit - MSMD Player with bug fixes
This is the Monkey See Monkey Do (MSMD) educational game application. Bug fixes applied: - Fixed AttributeError when showReferenceCreator is disabled in config - Fixed keyboard input with modifiers (Shift+key) not being recognized by making scancode table lookup case-insensitive 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
12
.claude/settings.local.json
Normal file
12
.claude/settings.local.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(python3:*)",
|
||||||
|
"Bash(source venv/bin/activate)",
|
||||||
|
"Bash(pip install:*)",
|
||||||
|
"Bash(python:*)",
|
||||||
|
"Bash(git init:*)",
|
||||||
|
"Bash(git add:*)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
|
||||||
|
# Virtual Environment
|
||||||
|
venv/
|
||||||
|
env/
|
||||||
|
ENV/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Application specific
|
||||||
|
*.pyc
|
||||||
778
MSMD_multiLevel.py
Normal file
778
MSMD_multiLevel.py
Normal file
@@ -0,0 +1,778 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Created on Sat Feb 24 17:36:10 2018
|
||||||
|
|
||||||
|
@author: JohnPaul
|
||||||
|
|
||||||
|
@version: 1.2.4 - updated to be compatible with all screen sizes
|
||||||
|
|
||||||
|
Version History:
|
||||||
|
1.2.3 - added multiple base station capability
|
||||||
|
1.2.2 - added reference file creation tool
|
||||||
|
1.2.1 - added game mode that changes the amount of time the robot can move instead of the robots speed
|
||||||
|
1.2.0 - added config file. created option to upgrade robot after every hotspot or every level. Added refresh port button. Added different robot upgrade modes (selectable only in config file)
|
||||||
|
1.1.1 - fixed left and right alt key bugs
|
||||||
|
1.1.0 - Added keyboard input
|
||||||
|
1.0.0 - Initial release (only includes mouse clicks)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from PyQt5.QtWidgets import (QApplication, QWidget, QLineEdit, QFileDialog,
|
||||||
|
QPushButton, QLabel, QHBoxLayout, QVBoxLayout, QMessageBox, QStackedLayout,
|
||||||
|
QGraphicsScene, QGraphicsView, QDesktopWidget, QGraphicsEllipseItem,
|
||||||
|
QGraphicsItem)
|
||||||
|
from PyQt5.QtGui import QIcon, QImage, QPixmap, QColor, QBrush, QPen
|
||||||
|
from PyQt5.QtCore import Qt, QRect, pyqtSignal, QThread
|
||||||
|
#this is the pyserial package (can be installed using pip)
|
||||||
|
import serial
|
||||||
|
import serial.tools.list_ports
|
||||||
|
import json
|
||||||
|
import configparser
|
||||||
|
from Settings import Settings
|
||||||
|
try:
|
||||||
|
import pyautogui
|
||||||
|
except :
|
||||||
|
pass
|
||||||
|
import pyaudio
|
||||||
|
import wave
|
||||||
|
import glob
|
||||||
|
|
||||||
|
textToScanCodeTable = {}
|
||||||
|
def buildScanCodeTranslationTable (hotSpotDict):
|
||||||
|
for imageName,metadata in hotSpotDict.items():
|
||||||
|
hType = metadata.get('type','')
|
||||||
|
if hType == "key":
|
||||||
|
scancode = metadata.get("scancode",0)
|
||||||
|
name = metadata.get("name",'')
|
||||||
|
textToScanCodeTable[name] = scancode
|
||||||
|
print('name: %s, scancode %s' % (name,scancode))
|
||||||
|
|
||||||
|
class GraphicsView(QGraphicsView):
|
||||||
|
itemClickedEvent = pyqtSignal(QGraphicsItem, Qt.KeyboardModifiers, Qt.MouseButton)
|
||||||
|
keyPressed = pyqtSignal(int, str, Qt.KeyboardModifiers)
|
||||||
|
|
||||||
|
def __inti__(self, parent=None):
|
||||||
|
super(GraphicsView, self).__init__(parent)
|
||||||
|
|
||||||
|
def mousePressEvent(self, event):
|
||||||
|
scenePosition = self.mapToScene(event.pos()).toPoint()
|
||||||
|
#print ('moserPressEvent pos %s scenePosition %s' % (event.pos(), scenePosition))
|
||||||
|
itemClicked = self.itemAt(scenePosition)
|
||||||
|
keyModifiers = event.modifiers()
|
||||||
|
mouseButton = event.button()
|
||||||
|
self.itemClickedEvent.emit(itemClicked, keyModifiers, mouseButton)
|
||||||
|
|
||||||
|
def keyPressEvent(self, event):
|
||||||
|
super(GraphicsView, self).keyPressEvent(event)
|
||||||
|
text = event.text()
|
||||||
|
code = event.key()
|
||||||
|
modifiers = event.modifiers()
|
||||||
|
try:
|
||||||
|
if code == 16777220:
|
||||||
|
textFromCode = 'enter'
|
||||||
|
elif code == 16777217:
|
||||||
|
textFromCode = 'tab'
|
||||||
|
else:
|
||||||
|
textFromCode = chr(code)
|
||||||
|
except :
|
||||||
|
textFromCode = text
|
||||||
|
|
||||||
|
translatedScanCode = textToScanCodeTable.get(text.lower(),textToScanCodeTable.get(textFromCode.lower(),0))
|
||||||
|
print('keyPressEvent text "%s" textFromCode %s scanCode %s key %s modifiers %s' % (
|
||||||
|
text,
|
||||||
|
textFromCode,
|
||||||
|
translatedScanCode,
|
||||||
|
code,
|
||||||
|
self.convertModifier(modifiers)))
|
||||||
|
|
||||||
|
self.keyPressed.emit(translatedScanCode, textFromCode, modifiers)
|
||||||
|
|
||||||
|
def convertModifier(self, pressedModifiers):
|
||||||
|
modifierTextList = []
|
||||||
|
if(pressedModifiers & Qt.ShiftModifier):
|
||||||
|
modifierTextList.append('shift')
|
||||||
|
if(pressedModifiers & Qt.AltModifier):
|
||||||
|
modifierTextList.append('alt')
|
||||||
|
if(pressedModifiers & Qt.ControlModifier):
|
||||||
|
modifierTextList.append('cmd') # on the mac this is the command key
|
||||||
|
if(pressedModifiers & Qt.MetaModifier):
|
||||||
|
modifierTextList.append('ctrl')# on the mac this is the control key
|
||||||
|
|
||||||
|
return modifierTextList
|
||||||
|
|
||||||
|
|
||||||
|
class App(QWidget):
|
||||||
|
cleanupEvent = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.versionNumber = '1.2.4'
|
||||||
|
self.title = 'Monkey See Monkey Do v'+self.versionNumber
|
||||||
|
self.left = 10
|
||||||
|
self.top = 80
|
||||||
|
self.width = 640
|
||||||
|
self.height = 100
|
||||||
|
self.folderName = ''
|
||||||
|
self.imageList = []
|
||||||
|
self.numImages = 0
|
||||||
|
self.currentImageNumber = 0
|
||||||
|
self.currentTotalImageNumber = 0
|
||||||
|
self.hotSpotFilename = 'hotspots.json'
|
||||||
|
self.hotSpotFile = None
|
||||||
|
self.hotSpotSize = 50
|
||||||
|
self.currentHotSpot = None
|
||||||
|
self.startTime = None
|
||||||
|
self.endTime = None
|
||||||
|
self.screen = QDesktopWidget().availableGeometry()
|
||||||
|
print(self.screen)
|
||||||
|
print('width', self.screen.width(), 'height', self.screen.height())
|
||||||
|
self.initUI()
|
||||||
|
|
||||||
|
|
||||||
|
def initUI(self):
|
||||||
|
|
||||||
|
self.readConfig()
|
||||||
|
|
||||||
|
self.portLabel = QLabel('Port(s): ', self)
|
||||||
|
self.portDisplay = QLineEdit(self)
|
||||||
|
self.portDisplay.setEnabled(False)
|
||||||
|
self.portRefreshButton = QPushButton(self)
|
||||||
|
self.portRefreshButton.setToolTip('Press to detect port of connected base station')
|
||||||
|
self.portRefreshButton.clicked.connect(self.refreshPorts)
|
||||||
|
self.portRefreshButton.setIcon(QIcon('refresh.png'))
|
||||||
|
self.portRefreshButton.setFixedWidth(24)
|
||||||
|
|
||||||
|
self.settingsButton = QPushButton()
|
||||||
|
self.settingsButton.setToolTip('Open the Settings Dialog')
|
||||||
|
self.settingsButton.setIcon(QIcon('settings.png'))
|
||||||
|
self.settingsButton.setMaximumWidth(24)
|
||||||
|
self.settingsButton.clicked.connect(self.openSettings)
|
||||||
|
|
||||||
|
self.connected = False
|
||||||
|
self.refreshPorts()
|
||||||
|
if self.showReferenceCreator:
|
||||||
|
self.referenceCreator = QPushButton('Create Reference', self)
|
||||||
|
self.referenceCreator.setToolTip('Create a reference file from the selected image set')
|
||||||
|
self.referenceCreator.clicked.connect(self.createReferenceFile)
|
||||||
|
self.referenceCreator.setEnabled(False)
|
||||||
|
|
||||||
|
self.folderButton = QPushButton('Select Folder', self)
|
||||||
|
self.folderButton.setToolTip('Select the folder that contains the content you would like to play')
|
||||||
|
self.folderButton.clicked.connect(self.folderButtonClicked)
|
||||||
|
|
||||||
|
self.folderLabel = QLabel('Selected Folder:', self)
|
||||||
|
|
||||||
|
self.selectedFolder = QLineEdit(self)
|
||||||
|
self.selectedFolder.setEnabled(False)
|
||||||
|
|
||||||
|
self.numLevelsLabel = QLabel('Number of Levels:', self)
|
||||||
|
self.numLevelsDisplay = QLineEdit(self)
|
||||||
|
self.numLevelsDisplay.setEnabled(False)
|
||||||
|
|
||||||
|
self.numImagesLabel = QLabel('Number of Images:', self)
|
||||||
|
self.numImagesDisplay = QLineEdit(self)
|
||||||
|
self.numImagesDisplay.setEnabled(False)
|
||||||
|
|
||||||
|
self.startLabel = QLabel('Press "Start" to begin game', self)
|
||||||
|
|
||||||
|
self.startButton = QPushButton('Start', self)
|
||||||
|
self.startButton.setToolTip('Start Game')
|
||||||
|
self.startButton.clicked.connect(self.startButtonClicked)
|
||||||
|
self.startButton.setEnabled(False)
|
||||||
|
|
||||||
|
self.hboxPort = QHBoxLayout()
|
||||||
|
self.hboxPort.addWidget(self.portLabel)
|
||||||
|
self.hboxPort.addWidget(self.portDisplay)
|
||||||
|
self.hboxPort.addWidget(self.portRefreshButton)
|
||||||
|
self.hboxPort.addWidget(self.settingsButton)
|
||||||
|
|
||||||
|
self.hbox = QHBoxLayout()
|
||||||
|
self.hbox.addWidget(self.folderLabel)
|
||||||
|
self.hbox.addWidget(self.selectedFolder)
|
||||||
|
|
||||||
|
self.hboxNumLevels = QHBoxLayout()
|
||||||
|
self.hboxNumLevels.addWidget(self.numLevelsLabel)
|
||||||
|
self.hboxNumLevels.addWidget(self.numLevelsDisplay)
|
||||||
|
|
||||||
|
self.hboxNumImages = QHBoxLayout()
|
||||||
|
self.hboxNumImages.addWidget(self.numImagesLabel)
|
||||||
|
self.hboxNumImages.addWidget(self.numImagesDisplay)
|
||||||
|
|
||||||
|
self.vbox = QVBoxLayout()
|
||||||
|
self.vbox.addLayout(self.hboxPort)
|
||||||
|
self.vbox.addWidget(self.folderButton)
|
||||||
|
self.vbox.addLayout(self.hbox)
|
||||||
|
self.vbox.addLayout(self.hboxNumLevels)
|
||||||
|
self.vbox.addLayout(self.hboxNumImages)
|
||||||
|
if self.showReferenceCreator:
|
||||||
|
self.vbox.addWidget(self.referenceCreator)
|
||||||
|
self.vbox.addWidget(self.startLabel)
|
||||||
|
self.vbox.addWidget(self.startButton)
|
||||||
|
self.vbox.addStretch(4)
|
||||||
|
|
||||||
|
self.startPage = QWidget()
|
||||||
|
self.startPage.setLayout(self.vbox)
|
||||||
|
|
||||||
|
self.scene = QGraphicsScene()
|
||||||
|
self.graphicsView = GraphicsView(self.scene)
|
||||||
|
self.graphicsView.itemClickedEvent.connect(self.hotSpotClickedHandler)
|
||||||
|
self.graphicsView.keyPressed.connect(self.keyPressedHandler)
|
||||||
|
|
||||||
|
self.graphicsLayout = QVBoxLayout()
|
||||||
|
self.graphicsLayout.addWidget(self.graphicsView)
|
||||||
|
self.graphicsLayout.setContentsMargins(0,0,0,0)
|
||||||
|
|
||||||
|
self.gamePage = QWidget()
|
||||||
|
self.gamePage.setLayout(self.graphicsLayout)
|
||||||
|
|
||||||
|
self.stackedLayout = QStackedLayout()
|
||||||
|
self.stackedLayout.addWidget(self.startPage)
|
||||||
|
self.stackedLayout.addWidget(self.gamePage)
|
||||||
|
self.stackedLayout.setCurrentIndex(0)
|
||||||
|
|
||||||
|
self.setLayout(self.stackedLayout)
|
||||||
|
self.setWindowTitle(self.title)
|
||||||
|
self.setGeometry(self.left, self.top, self.width, self.height)
|
||||||
|
self.setWindowIcon(QIcon('MSMD32.png'))
|
||||||
|
self.cleanupEvent.connect(self.cleanupStuff)
|
||||||
|
self.show()
|
||||||
|
self.bringToFront()
|
||||||
|
|
||||||
|
|
||||||
|
def readConfig(self):
|
||||||
|
self.config = configparser.ConfigParser()
|
||||||
|
fileCheck = self.config.read('config.ini')
|
||||||
|
if(fileCheck == []):
|
||||||
|
QMessageBox.critical(self, 'Config Error!', 'config.ini was not found', QMessageBox.Ok)
|
||||||
|
self.robotSettings = self.config['robot']
|
||||||
|
self.upgradeTrigger = self.robotSettings['upgradeTrigger']
|
||||||
|
self.upgradeMode = self.robotSettings['upgradeMode']
|
||||||
|
self.minPowerToMove = self.robotSettings['minPowerToMove']
|
||||||
|
self.maxPowerToMove = self.robotSettings['maxPowerToMove']
|
||||||
|
self.showReferenceCreator = int(self.robotSettings.get('showReferenceCreator', '1'))
|
||||||
|
|
||||||
|
def writeConfig(self):
|
||||||
|
self.robotSettings['upgradeTrigger'] = self.upgradeTrigger
|
||||||
|
self.robotSettings['upgradeMode'] = self.upgradeMode
|
||||||
|
self.robotSettings['minPowerToMove'] = self.minPowerToMove
|
||||||
|
self.robotSettings['maxPowerToMove'] = self.maxPowerToMove
|
||||||
|
with open('config.ini', 'w') as configFile:
|
||||||
|
self.config.write(configFile)
|
||||||
|
|
||||||
|
def openSettings(self):
|
||||||
|
try:
|
||||||
|
SettingsIn = {'upgradeTrigger': 'hotspot',
|
||||||
|
'upgradeMode': 'left',
|
||||||
|
'minPowerToMove': '80'}
|
||||||
|
self.settingsWindow = Settings(self.robotSettings)
|
||||||
|
self.settingsWindow.Closing.connect(self.settingsClosed)
|
||||||
|
self.settingsWindow.show()
|
||||||
|
self.setDisabled(True)
|
||||||
|
except:
|
||||||
|
print ('ERROR - Setting.py Load Failed!')
|
||||||
|
|
||||||
|
def settingsClosed(self, message):
|
||||||
|
if(message == 'Abort'):
|
||||||
|
print ('Settigns Aborted!')
|
||||||
|
elif(message == 'Closed'):
|
||||||
|
print ('Settings Closed!')
|
||||||
|
#Set New Settings
|
||||||
|
newSettings = self.settingsWindow.getSettings()
|
||||||
|
self.upgradeTrigger = newSettings['upgradeTrigger']
|
||||||
|
self.upgradeMode = newSettings['upgradeMode']
|
||||||
|
self.minPowerToMove = newSettings['minPowerToMove']
|
||||||
|
self.maxPowerToMove = newSettings['maxPowerToMove']
|
||||||
|
self.writeConfig()
|
||||||
|
else:
|
||||||
|
print ('ERROR - Unknown message returned from Settings.py Window!')
|
||||||
|
self.setDisabled(False)
|
||||||
|
|
||||||
|
def bringToFront(self):
|
||||||
|
self.setWindowState(self.windowState() & ~Qt.WindowMinimized | Qt.WindowActive)
|
||||||
|
self.activateWindow()
|
||||||
|
|
||||||
|
def refreshPorts(self):
|
||||||
|
if(self.connected):
|
||||||
|
for baseStation in self.robot:
|
||||||
|
baseStation.close()
|
||||||
|
comPorts = self.findPorts()
|
||||||
|
if(comPorts):
|
||||||
|
self.robot = []
|
||||||
|
self.portDisplayText = ''
|
||||||
|
for i, port in enumerate(comPorts):
|
||||||
|
self.robot.append(serial.Serial(port))
|
||||||
|
self.robot[i].baudrate = 115200
|
||||||
|
self.robot[i].timeout = 0.05
|
||||||
|
self.portDisplayText += (port + ' ')
|
||||||
|
|
||||||
|
self.portDisplay.setText(self.portDisplayText)
|
||||||
|
self.connected = True
|
||||||
|
else:
|
||||||
|
self.robot = []
|
||||||
|
self.connected = False
|
||||||
|
|
||||||
|
def folderButtonClicked(self):
|
||||||
|
self.folderName = QFileDialog.getExistingDirectory(self, "Select Folder Location for Recorded Content")
|
||||||
|
print(self.folderName)
|
||||||
|
if os.path.isdir(self.folderName):
|
||||||
|
self.numLevels = 0
|
||||||
|
self.numTotalImages = 0
|
||||||
|
self.listOfFilesInSelectedFolder = os.listdir(self.folderName)
|
||||||
|
self.folderList = []
|
||||||
|
self.folderListNameOnly = []
|
||||||
|
for name in self.listOfFilesInSelectedFolder:
|
||||||
|
fullFileName = os.path.join(self.folderName, name)
|
||||||
|
if os.path.isdir(fullFileName):
|
||||||
|
result = self.loadLevel(fullFileName)
|
||||||
|
if(result<0):
|
||||||
|
return
|
||||||
|
self.folderList.append(fullFileName)
|
||||||
|
self.folderListNameOnly.append(name)
|
||||||
|
self.numLevels += 1
|
||||||
|
self.numTotalImages += result
|
||||||
|
|
||||||
|
if(self.numLevels>0):
|
||||||
|
#multiLevel game selected
|
||||||
|
self.loadLevel(self.folderList[0])
|
||||||
|
self.numLevelsDisplay.setText(str(self.numLevels))
|
||||||
|
else:
|
||||||
|
result = self.loadLevel(self.folderName)
|
||||||
|
if(result<0):
|
||||||
|
return
|
||||||
|
self.numTotalImages = result
|
||||||
|
self.numLevelsDisplay.setText('1')
|
||||||
|
|
||||||
|
self.currentLevel = 0
|
||||||
|
self.numImagesDisplay.setText(str(self.numTotalImages))
|
||||||
|
self.startButton.setEnabled(True)
|
||||||
|
if self.showReferenceCreator:
|
||||||
|
self.referenceCreator.setEnabled(True)
|
||||||
|
self.selectedFolder.setText(self.folderName)
|
||||||
|
else:
|
||||||
|
QMessageBox.warning(self, 'Folder Error!', 'The folder does not exist!\nPlease select a valid folder', QMessageBox.Ok)
|
||||||
|
|
||||||
|
def loadLevel(self, levelToLoad):
|
||||||
|
try:
|
||||||
|
print('Trying to load '+levelToLoad)
|
||||||
|
print('%s' % levelToLoad+os.path.sep+self.hotSpotFilename)
|
||||||
|
self.hotSpotFile = open(levelToLoad+os.path.sep+self.hotSpotFilename, 'r')
|
||||||
|
self.hotSpotDict = json.load(self.hotSpotFile)
|
||||||
|
self.numHotSpotRecords = len(self.hotSpotDict)
|
||||||
|
#self.hotSpotCsv = csv.reader(self.hotSpotFile)
|
||||||
|
#next(self.hotSpotCsv)
|
||||||
|
#self.numHotSpotRecords = sum(1 for row in self.hotSpotCsv)
|
||||||
|
#self.hotSpotFile.seek(0)
|
||||||
|
#next(self.hotSpotCsv) #skip column labels on first line
|
||||||
|
self.hotSpotFile.close()
|
||||||
|
buildScanCodeTranslationTable(self.hotSpotDict)
|
||||||
|
except IOError:
|
||||||
|
QMessageBox.critical(self, 'Error: No hotspots.json', 'hotspots.json does not exist\nA Hot Spot file is required to play the game. Please select a complete and valid content folder', QMessageBox.Ok)
|
||||||
|
self.selectedFolder.setText('Error: No hotspots.json')
|
||||||
|
return -1
|
||||||
|
self.imageList = []
|
||||||
|
try:
|
||||||
|
for imageFile in sorted((imfile for imfile in os.listdir(levelToLoad) if imfile.endswith('.png'))):
|
||||||
|
|
||||||
|
self.imageList.append(QImage(levelToLoad+os.path.sep+imageFile))
|
||||||
|
|
||||||
|
except IOError:
|
||||||
|
QMessageBox.critical(self, 'Error: images reading', 'Images could not be read\nPlease select a complete and valid content folder', QMessageBox.Ok)
|
||||||
|
return -1
|
||||||
|
self.numImages = len(self.imageList)-1
|
||||||
|
if(self.numImages != self.numHotSpotRecords):
|
||||||
|
QMessageBox.critical(self, 'Error: number of images in level "'+str(levelToLoad)+'" do not match the number of hot spot records', QMessageBox.Ok)
|
||||||
|
return -1
|
||||||
|
return self.numImages
|
||||||
|
|
||||||
|
def startButtonClicked(self):
|
||||||
|
print('start')
|
||||||
|
self.stackedLayout.setCurrentIndex(1)
|
||||||
|
self.paintImageIndex(0)
|
||||||
|
self.showMaximized()
|
||||||
|
|
||||||
|
if(self.upgradeTrigger == 'level'):
|
||||||
|
self.setPower((int(self.minPowerToMove)*100)//255)
|
||||||
|
|
||||||
|
self.startTime = time.time()
|
||||||
|
|
||||||
|
def paintImageIndex(self, imageNumber):
|
||||||
|
if(self.upgradeTrigger == 'hotspot'):
|
||||||
|
powerLevel = (self.currentTotalImageNumber/(self.numTotalImages-1))*100
|
||||||
|
print('power:', powerLevel, ' currentTotalImageNum:', self.currentTotalImageNumber, ' numTotalImages:', self.numTotalImages)
|
||||||
|
self.setPower(powerLevel)
|
||||||
|
|
||||||
|
self.scene.clear()
|
||||||
|
print('current image number:', imageNumber)
|
||||||
|
self.nextHotSpotInput = self.hotSpotDict[str(self.currentImageNumber).zfill(6)]
|
||||||
|
print('nextHotSpotInput', self.nextHotSpotInput)
|
||||||
|
self.currentPixmap = QPixmap.fromImage(self.imageList[imageNumber]).copy(QRect(0,0,1920,1020)).scaled(self.screen.width(), self.screen.height(), aspectRatioMode=Qt.IgnoreAspectRatio)
|
||||||
|
|
||||||
|
self.scene.addPixmap(self.currentPixmap)
|
||||||
|
|
||||||
|
self.currentInputModifiers = self.simplifyModifierList(self.nextHotSpotInput['modifiers'])
|
||||||
|
|
||||||
|
if(self.nextHotSpotInput['type'] == 'mouse'):
|
||||||
|
commandString = ''
|
||||||
|
if self.currentInputModifiers != []:
|
||||||
|
commandString += 'Press '
|
||||||
|
for mod in self.currentInputModifiers:
|
||||||
|
commandString += mod + ' + '
|
||||||
|
commandString += 'Click '
|
||||||
|
self.currentMouseButton = self.nextHotSpotInput['button']
|
||||||
|
if(self.currentMouseButton == 'right'):
|
||||||
|
pen = QPen(QColor(0,0,255,128))
|
||||||
|
commandString += 'right mouse button'
|
||||||
|
elif(self.currentMouseButton == 'left'):
|
||||||
|
pen = QPen(QColor(255,0,0,128))
|
||||||
|
commandString += 'left mouse button'
|
||||||
|
elif(self.currentMouseButton == 'middle'):
|
||||||
|
pen = QPen(QColor(0,255,0,128))
|
||||||
|
commandString += 'scroll wheel (middle mouse button)'
|
||||||
|
else:
|
||||||
|
pen = QPen(QColor(0,0,0,128))
|
||||||
|
xScale = self.screen.width()/1920
|
||||||
|
yScale = self.screen.height()/1020
|
||||||
|
if(xScale>yScale):
|
||||||
|
minScale = yScale
|
||||||
|
else:
|
||||||
|
minScale = xScale
|
||||||
|
scaledHotSpotSize = self.hotSpotSize*minScale
|
||||||
|
xPosition = self.nextHotSpotInput['position'][0]*xScale
|
||||||
|
yPosition = self.nextHotSpotInput['position'][1]*yScale
|
||||||
|
print('next hotspot pos x %s y %s' %(xPosition,yPosition))
|
||||||
|
brush = QBrush(QColor(180, 180, 180, 100))
|
||||||
|
self.currentHotSpot = QGraphicsEllipseItem()
|
||||||
|
self.currentHotSpot.setRect(xPosition-scaledHotSpotSize/2, yPosition-scaledHotSpotSize/2, scaledHotSpotSize, scaledHotSpotSize)
|
||||||
|
self.currentHotSpot.setBrush(brush)
|
||||||
|
self.currentHotSpot.setPen(pen)
|
||||||
|
self.scene.addItem(self.currentHotSpot)
|
||||||
|
self.currentInputKey = -1
|
||||||
|
elif(self.nextHotSpotInput['type'] == 'key'):
|
||||||
|
#print('key')
|
||||||
|
self.currentInputKey = self.nextHotSpotInput['scancode']
|
||||||
|
commandString = 'Press '
|
||||||
|
for mod in self.currentInputModifiers:
|
||||||
|
commandString += mod
|
||||||
|
commandString += ' + '
|
||||||
|
commandString += self.nextHotSpotInput['name']
|
||||||
|
self.currentHotSpot = 'not a hotspot'
|
||||||
|
else:
|
||||||
|
QMessageBox.critical(self, 'Error: hotSpotInput type is incorrect. got: "'+self.nextHotSpotInput['type']+'" expected: "key" or "mouse"', QMessageBox.Ok)
|
||||||
|
|
||||||
|
self.setWindowTitle(self.title + ' ' + commandString)
|
||||||
|
|
||||||
|
def playSound(self):
|
||||||
|
|
||||||
|
class SoundThread(QThread):
|
||||||
|
signal = pyqtSignal('PyQt_PyObject')
|
||||||
|
def __init__ (self, soundFilename):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.soundFilename = soundFilename
|
||||||
|
|
||||||
|
def run (self):
|
||||||
|
|
||||||
|
#define stream chunk
|
||||||
|
chunk = 1024
|
||||||
|
|
||||||
|
#open a wav format music
|
||||||
|
f = wave.open(self.soundFilename,"rb")
|
||||||
|
#instantiate PyAudio
|
||||||
|
p = pyaudio.PyAudio()
|
||||||
|
#open stream
|
||||||
|
stream = p.open(format = p.get_format_from_width(f.getsampwidth()),
|
||||||
|
channels = f.getnchannels(),
|
||||||
|
rate = f.getframerate(),
|
||||||
|
output = True)
|
||||||
|
#read data
|
||||||
|
data = f.readframes(chunk)
|
||||||
|
|
||||||
|
#play stream
|
||||||
|
while data:
|
||||||
|
stream.write(data)
|
||||||
|
data = f.readframes(chunk)
|
||||||
|
|
||||||
|
#stop stream
|
||||||
|
stream.stop_stream()
|
||||||
|
stream.close()
|
||||||
|
|
||||||
|
#close PyAudio
|
||||||
|
p.terminate()
|
||||||
|
self.signal.emit(soundFilename)
|
||||||
|
|
||||||
|
soundFilename = '%s%ssound%s.wav'% (self.folderName, os.path.sep, self.currentImageNumber)
|
||||||
|
if not os.path.isfile(soundFilename):
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
self.soundThread = SoundThread(soundFilename)
|
||||||
|
self.soundThread.signal.connect(self.soundFinished)
|
||||||
|
self.soundThread.start()
|
||||||
|
except:
|
||||||
|
print('something when wrong with the sound thread')
|
||||||
|
|
||||||
|
def soundFinished (self, soundFile):
|
||||||
|
print('finished playing %s' % soundFile)
|
||||||
|
|
||||||
|
def hotSpotClickedHandler(self, itemClicked, modifiers, mouseButton):
|
||||||
|
|
||||||
|
print('itemClicked %s, self.currentHotSpot %s, mouseButton %s' % (itemClicked, self.currentHotSpot, mouseButton))
|
||||||
|
|
||||||
|
if itemClicked is self.currentHotSpot:
|
||||||
|
if self.checkModifierMatch(modifiers):
|
||||||
|
if self.checkButtonMatch(mouseButton):
|
||||||
|
#print('clicked on hot spot!')
|
||||||
|
|
||||||
|
self.playSound()
|
||||||
|
|
||||||
|
self.currentImageNumber += 1
|
||||||
|
self.currentTotalImageNumber += 1
|
||||||
|
if self.currentImageNumber >= self.numImages:
|
||||||
|
self.levelCompleted()
|
||||||
|
else:
|
||||||
|
self.paintImageIndex(self.currentImageNumber)
|
||||||
|
else:
|
||||||
|
#print('wrong mouse button clicked')
|
||||||
|
a = 0
|
||||||
|
else:
|
||||||
|
#print("modifiers don't match")
|
||||||
|
a = 0
|
||||||
|
else:
|
||||||
|
#print('wrong spot clicked')
|
||||||
|
a = 0
|
||||||
|
|
||||||
|
def checkButtonMatch(self, pressedMouseButton):
|
||||||
|
if pressedMouseButton == Qt.LeftButton:
|
||||||
|
pressedMouseButtonString = 'left'
|
||||||
|
if pressedMouseButton == Qt.RightButton:
|
||||||
|
pressedMouseButtonString = 'right'
|
||||||
|
if pressedMouseButton == Qt.MiddleButton:
|
||||||
|
pressedMouseButtonString = 'middle'
|
||||||
|
|
||||||
|
return self.currentMouseButton == pressedMouseButtonString
|
||||||
|
|
||||||
|
|
||||||
|
def keyPressedHandler(self, nativeScanCode, keyText, modifiers):
|
||||||
|
print('scanCode %s, currentInputKey %s' % (nativeScanCode, self.currentInputKey))
|
||||||
|
if (nativeScanCode == self.currentInputKey) and self.checkModifierMatch(modifiers):
|
||||||
|
#print('pressed correct key (or key combination)')
|
||||||
|
|
||||||
|
self.playSound()
|
||||||
|
|
||||||
|
self.currentImageNumber += 1
|
||||||
|
self.currentTotalImageNumber += 1
|
||||||
|
if self.currentImageNumber >= self.numImages:
|
||||||
|
self.levelCompleted()
|
||||||
|
else:
|
||||||
|
self.paintImageIndex(self.currentImageNumber)
|
||||||
|
else:
|
||||||
|
#print('wrong key or key combination pressed')
|
||||||
|
a = 0
|
||||||
|
|
||||||
|
def checkModifierMatch(self, pressedModifiers):
|
||||||
|
modifierTextList = []
|
||||||
|
if(pressedModifiers & Qt.ShiftModifier):
|
||||||
|
modifierTextList.append('shift')
|
||||||
|
if(pressedModifiers & Qt.AltModifier):
|
||||||
|
modifierTextList.append('alt')
|
||||||
|
if(pressedModifiers & Qt.ControlModifier):
|
||||||
|
#modifierTextList.append('ctrl')
|
||||||
|
modifierTextList.append('cmd') # on the mac this is the command key
|
||||||
|
if(pressedModifiers & Qt.MetaModifier):
|
||||||
|
modifierTextList.append('ctrl')# on the mac this is the control key
|
||||||
|
#modifierTextList.append('win')
|
||||||
|
return set(modifierTextList) == set(self.currentInputModifiers)
|
||||||
|
|
||||||
|
def simplifyModifierList(self, modifierList):
|
||||||
|
tempSet = set()
|
||||||
|
for item in modifierList:
|
||||||
|
if item == 'left shift':
|
||||||
|
tempSet.add('shift')
|
||||||
|
elif item == 'right shift':
|
||||||
|
tempSet.add('shift')
|
||||||
|
elif item == 'left ctrl':
|
||||||
|
tempSet.add('ctrl')
|
||||||
|
elif item == 'right ctrl':
|
||||||
|
tempSet.add('ctrl')
|
||||||
|
elif item == 'left alt':
|
||||||
|
tempSet.add('alt')
|
||||||
|
elif item == 'right alt':
|
||||||
|
tempSet.add('alt')
|
||||||
|
else:
|
||||||
|
tempSet.add(item)
|
||||||
|
return list(tempSet)
|
||||||
|
|
||||||
|
def levelCompleted(self):
|
||||||
|
print('completed level: ', self.currentLevel+1)
|
||||||
|
if(self.upgradeTrigger == 'level'):
|
||||||
|
powerLevel = (self.currentLevel/(self.numLevels-1))*100
|
||||||
|
self.setPower(powerLevel)
|
||||||
|
|
||||||
|
self.currentLevel += 1
|
||||||
|
if(self.currentLevel>=self.numLevels):
|
||||||
|
self.gameCompleted()
|
||||||
|
else:
|
||||||
|
self.currentImageNumber = 0
|
||||||
|
self.loadLevel(self.folderList[self.currentLevel])
|
||||||
|
self.paintImageIndex(0)
|
||||||
|
|
||||||
|
def gameCompleted(self):
|
||||||
|
self.endTime = time.time()
|
||||||
|
self.scene.clear()
|
||||||
|
self.currentHotSpot = None
|
||||||
|
self.currentImageNumber = 0
|
||||||
|
self.currentTotalImageNumber = 0
|
||||||
|
self.currentPixmap = None
|
||||||
|
self.currentPixmap = QPixmap.fromImage(self.imageList[self.numImages]).copy(QRect(0,0,1920,1020)).scaled(self.screen.width(), self.screen.height(), aspectRatioMode=Qt.IgnoreAspectRatio)
|
||||||
|
self.scene.addPixmap(self.currentPixmap)
|
||||||
|
buttonReply = QMessageBox.information(self, 'You Win!', 'Congradulations, You Won!\nYou completed the game in ' + "%.2f" % (self.endTime-self.startTime) + ' seconds', QMessageBox.Ok | QMessageBox.Close)
|
||||||
|
if buttonReply == QMessageBox.Ok:
|
||||||
|
self.stackedLayout.setCurrentIndex(0)
|
||||||
|
self.showNormal()
|
||||||
|
if(self.numLevels>0):
|
||||||
|
self.loadLevel(self.folderList[0])
|
||||||
|
else:
|
||||||
|
self.loadLevel(self.folderName)
|
||||||
|
self.currentLevel = 0
|
||||||
|
|
||||||
|
def findPorts(self):
|
||||||
|
ports = glob.glob('/dev/tty.SLAB_USB*')
|
||||||
|
|
||||||
|
comPortsList = ports
|
||||||
|
#microcontrollerPort = None
|
||||||
|
#for port in ports:
|
||||||
|
# if 'Silicon Labs' in str(port[1]):
|
||||||
|
# comPortsList.append(port[0])
|
||||||
|
return comPortsList
|
||||||
|
|
||||||
|
def setPower(self, powerLevel):
|
||||||
|
if(powerLevel>100):
|
||||||
|
raise ValueError('powerLevel cannot be set above 100')
|
||||||
|
if(powerLevel<0):
|
||||||
|
raise ValueError('powerLevel cannot be set below 0')
|
||||||
|
|
||||||
|
minPower = int(self.minPowerToMove)
|
||||||
|
mode = self.upgradeMode
|
||||||
|
leftPower = minPower
|
||||||
|
rightPower = minPower
|
||||||
|
maxPower = int(self.maxPowerToMove)
|
||||||
|
if(mode == "left"):
|
||||||
|
if(powerLevel<=50):
|
||||||
|
leftPower = self.interpolate( powerLevel, 0, 100, minPower, maxPower)
|
||||||
|
rightPower = self.interpolate(powerLevel, 0, 50, minPower, maxPower)
|
||||||
|
else:
|
||||||
|
leftPower = self.interpolate(powerLevel, 0, 100, minPower, maxPower)
|
||||||
|
rightPower = self.interpolate(powerLevel,50, 100, minPower, maxPower)
|
||||||
|
elif(mode == "right"):
|
||||||
|
if(powerLevel<=50):
|
||||||
|
rightPower = self.interpolate(powerLevel, 0,100, minPower, maxPower)
|
||||||
|
leftPower = self.interpolate(powerLevel, 0, 50, minPower, maxPower)
|
||||||
|
else:
|
||||||
|
rightPower = self.interpolate(powerLevel, 0,100, minPower, maxPower)
|
||||||
|
leftPower = self.interpolate(powerLevel, 50,100, minPower, maxPower)
|
||||||
|
elif(mode == "both"):
|
||||||
|
leftPower = self.interpolate(powerLevel, 0,100, minPower, maxPower)
|
||||||
|
rightPower = leftPower
|
||||||
|
elif(mode == "distance"):
|
||||||
|
#add fuel to the robot "tank"
|
||||||
|
a=None
|
||||||
|
else:
|
||||||
|
raise ValueError('upgradeMode in config.ini does not match any accepted value')
|
||||||
|
|
||||||
|
iLP = int(leftPower)
|
||||||
|
iRP = int(rightPower)
|
||||||
|
|
||||||
|
#desiredPowerLevel -= 45
|
||||||
|
if self.robot:
|
||||||
|
print('\nconnected to BaseStation, attempting to set power to', powerLevel, ' L:', leftPower, 'R:', rightPower,'\n')
|
||||||
|
for baseStation in self.robot:
|
||||||
|
baseStation.write(bytes([0,0,iLP,iRP])+b'\n')
|
||||||
|
baseStation.write(bytes([0,0,iLP,iRP])+b'\n')
|
||||||
|
else:
|
||||||
|
print('BaseStation not connected, cannot change power level')
|
||||||
|
|
||||||
|
def interpolate(self, inputValue, inputMin, inputMax, outputMin, outputMax):
|
||||||
|
ratio = (inputValue - inputMin)/(inputMax - inputMin)
|
||||||
|
outputValue = (outputMax - outputMin) * ratio + outputMin
|
||||||
|
return outputValue
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
print('emitting cleanup event')
|
||||||
|
try:
|
||||||
|
self.settingsWindow.Abort()
|
||||||
|
except:
|
||||||
|
print('ERROR - Could not properly close settings window!')
|
||||||
|
self.cleanupEvent.emit()
|
||||||
|
|
||||||
|
def cleanupStuff(self):
|
||||||
|
if self.robot:
|
||||||
|
for baseStation in self.robot:
|
||||||
|
baseStation.close()
|
||||||
|
print('closing')
|
||||||
|
|
||||||
|
def createReferenceFile(self):
|
||||||
|
referenceFolder = QFileDialog.getExistingDirectory(self, "Select Folder Location for Reference")
|
||||||
|
self.startTime = time.time()
|
||||||
|
if os.path.isdir(referenceFolder):
|
||||||
|
|
||||||
|
if(self.numLevels>0):
|
||||||
|
#multiLevel game selected
|
||||||
|
print('multiLevelGame Reference started')
|
||||||
|
for i in range(0,self.numLevels):
|
||||||
|
#create folder to hold level in reference file
|
||||||
|
levelFolderName = referenceFolder+os.path.sep+self.folderListNameOnly[i]
|
||||||
|
os.mkdir(levelFolderName)
|
||||||
|
|
||||||
|
self.loadLevel(self.folderList[i])
|
||||||
|
|
||||||
|
#start msmd level
|
||||||
|
self.stackedLayout.setCurrentIndex(1)
|
||||||
|
self.showMaximized()
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
|
for j in range(0, self.numImages):
|
||||||
|
print('next image: '+str(j))
|
||||||
|
self.paintImageIndex(j)
|
||||||
|
QApplication.processEvents()
|
||||||
|
|
||||||
|
time.sleep(0.05)
|
||||||
|
imageName = str(self.currentImageNumber).zfill(6)
|
||||||
|
pyautogui.screenshot(levelFolderName+os.path.sep+imageName+'.png')
|
||||||
|
|
||||||
|
self.currentImageNumber += 1
|
||||||
|
self.currentTotalImageNumber += 1
|
||||||
|
|
||||||
|
self.currentImageNumber = 0
|
||||||
|
else:
|
||||||
|
print('singleLevelGame Reference Started')
|
||||||
|
self.loadLevel(self.folderName)
|
||||||
|
self.stackedLayout.setCurrentIndex(1)
|
||||||
|
self.showMaximized()
|
||||||
|
|
||||||
|
for j in range(0, self.numImages):
|
||||||
|
print('next image: '+str(j))
|
||||||
|
self.paintImageIndex(j)
|
||||||
|
QApplication.processEvents()
|
||||||
|
|
||||||
|
time.sleep(0.05)
|
||||||
|
imageName = str(self.currentImageNumber).zfill(6)
|
||||||
|
pyautogui.screenshot(levelFolderName+os.path.sep+imageName+'.png')
|
||||||
|
|
||||||
|
self.currentImageNumber += 1
|
||||||
|
self.currentTotalImageNumber += 1
|
||||||
|
|
||||||
|
self.currentImageNumber = 0
|
||||||
|
|
||||||
|
self.gameCompleted()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = 0
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
ex = App()
|
||||||
|
sys.exit(app.exec_())
|
||||||
171
Settings.py
Normal file
171
Settings.py
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Created on Fri Apr 20 18:11:20 2018
|
||||||
|
|
||||||
|
@author: Nick
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PyQt5.QtCore import Qt, pyqtSignal
|
||||||
|
from PyQt5.QtGui import QIcon
|
||||||
|
from PyQt5.QtWidgets import (QHBoxLayout, QVBoxLayout, QGridLayout, QComboBox, QLabel, QSpinBox, QGroupBox, QPushButton, QWidget, QFrame, QSpacerItem, QSizePolicy)
|
||||||
|
|
||||||
|
class QHLine(QFrame):
|
||||||
|
def __init__(self):
|
||||||
|
super(QHLine, self).__init__()
|
||||||
|
self.setFrameShape(QFrame.HLine)
|
||||||
|
self.setFrameShadow(QFrame.Sunken)
|
||||||
|
|
||||||
|
class Settings(QWidget):
|
||||||
|
|
||||||
|
Closing = pyqtSignal(str)
|
||||||
|
|
||||||
|
def __init__(self, SettingsIn):
|
||||||
|
super(QWidget, self).__init__()
|
||||||
|
|
||||||
|
self.__UserAbort = True
|
||||||
|
|
||||||
|
#-----Widget Settings-----
|
||||||
|
self.setWindowIcon(QIcon('MSMD32.png'))
|
||||||
|
self.setWindowTitle('MSMD Settings')
|
||||||
|
|
||||||
|
#Remove Maximize and Minimize buttons
|
||||||
|
self.setWindowFlags(self.windowFlags() & ~Qt.WindowMinMaxButtonsHint)
|
||||||
|
|
||||||
|
#-----Widget Lists-----
|
||||||
|
|
||||||
|
MasterUpgradeTriggers = ['Folder', 'Hotspot']
|
||||||
|
MasterUpgradeMode = ['Both', 'Left', 'Right', 'Distance']
|
||||||
|
|
||||||
|
TriggerIdx = [x.lower() for x in MasterUpgradeTriggers].index(SettingsIn['upgradeTrigger'])
|
||||||
|
ModeIdx = [x.lower() for x in MasterUpgradeMode].index(SettingsIn['upgradeMode'])
|
||||||
|
|
||||||
|
#-----Widgets-----
|
||||||
|
|
||||||
|
UpgradeFrame = QGroupBox()
|
||||||
|
UpgradeFrame.setTitle('Upgrades')
|
||||||
|
|
||||||
|
SpeedFrame = QGroupBox()
|
||||||
|
SpeedFrame.setTitle('Speed')
|
||||||
|
|
||||||
|
self.UpgradeTrigger = QComboBox()
|
||||||
|
self.UpgradeTrigger.setToolTip('Set robot upgrade interval to hotspots or levels')
|
||||||
|
self.UpgradeTrigger.setFixedWidth(80)
|
||||||
|
for Trigger in MasterUpgradeTriggers:
|
||||||
|
self.UpgradeTrigger.addItem(Trigger)
|
||||||
|
self.UpgradeTrigger.setCurrentIndex(TriggerIdx)
|
||||||
|
|
||||||
|
self.UpgradeMode = QComboBox()
|
||||||
|
self.UpgradeMode.setToolTip('Set robot upgrade mode')
|
||||||
|
self.UpgradeMode.setFixedWidth(80)
|
||||||
|
for Mode in MasterUpgradeMode:
|
||||||
|
self.UpgradeMode.addItem(Mode)
|
||||||
|
self.UpgradeMode.setCurrentIndex(ModeIdx)
|
||||||
|
|
||||||
|
self.MinPower = QSpinBox()
|
||||||
|
self.MinPower.setToolTip('Set minimum power for robot to start moving')
|
||||||
|
self.MinPower.setMaximum(255)
|
||||||
|
self.MinPower.setMinimum(0)
|
||||||
|
self.MinPower.setSingleStep(5)
|
||||||
|
self.MinPower.setFixedWidth(60)
|
||||||
|
self.MinPower.setValue(int(SettingsIn['minPowerToMove']))
|
||||||
|
|
||||||
|
self.MaxPower = QSpinBox()
|
||||||
|
self.MaxPower.setToolTip('Set maximum power for robot to start moving')
|
||||||
|
self.MaxPower.setMaximum(255)
|
||||||
|
self.MaxPower.setMinimum(0)
|
||||||
|
self.MaxPower.setSingleStep(5)
|
||||||
|
self.MaxPower.setFixedWidth(60)
|
||||||
|
self.MaxPower.setValue(int(SettingsIn['maxPowerToMove']))
|
||||||
|
|
||||||
|
SetButton = QPushButton()
|
||||||
|
SetButton.setToolTip('Use the current settings')
|
||||||
|
SetButton.setText('Set')
|
||||||
|
SetButton.setFixedWidth(80)
|
||||||
|
SetButton.clicked.connect(self.__Close)
|
||||||
|
|
||||||
|
CancelButton = QPushButton()
|
||||||
|
CancelButton.setToolTip('Cancel')
|
||||||
|
CancelButton.setText('Cancel')
|
||||||
|
CancelButton.setFixedWidth(80)
|
||||||
|
CancelButton.clicked.connect(self.Abort)
|
||||||
|
|
||||||
|
#-----Layouts-----
|
||||||
|
|
||||||
|
hlayout1 = QHBoxLayout()
|
||||||
|
hlayout2 = QHBoxLayout()
|
||||||
|
glayout1 = QGridLayout()
|
||||||
|
glayout2 = QGridLayout()
|
||||||
|
vlayout3 = QVBoxLayout()
|
||||||
|
|
||||||
|
glayout1.addWidget(QLabel('Upgrade Trigger'), 1, 1)
|
||||||
|
glayout1.addWidget(self.UpgradeTrigger, 1, 3)
|
||||||
|
glayout1.addWidget(QLabel('Upgrade Mode'), 3, 1)
|
||||||
|
glayout1.addWidget(self.UpgradeMode, 3, 3)
|
||||||
|
|
||||||
|
UpgradeFrame.setLayout(glayout1)
|
||||||
|
|
||||||
|
space = QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding)
|
||||||
|
|
||||||
|
glayout2.addWidget(QLabel('Min Power to Move'), 1, 1)
|
||||||
|
glayout2.addWidget(self.MinPower, 1, 3)
|
||||||
|
glayout2.addWidget(QLabel('Max Power to Move'), 3, 1)
|
||||||
|
glayout2.addWidget(self.MaxPower, 3, 3)
|
||||||
|
|
||||||
|
SpeedFrame.setLayout(glayout2)
|
||||||
|
|
||||||
|
hlayout1.addWidget(UpgradeFrame)
|
||||||
|
hlayout1.addWidget(SpeedFrame)
|
||||||
|
|
||||||
|
hlayout2.addStretch(1)
|
||||||
|
hlayout2.addWidget(SetButton)
|
||||||
|
hlayout2.addWidget(CancelButton)
|
||||||
|
|
||||||
|
vlayout3.addLayout(hlayout1)
|
||||||
|
vlayout3.addStretch(1)
|
||||||
|
vlayout3.addWidget(QHLine())
|
||||||
|
vlayout3.addLayout(hlayout2)
|
||||||
|
|
||||||
|
self.setLayout(vlayout3)
|
||||||
|
|
||||||
|
def getSettings(self):
|
||||||
|
out = {'upgradeTrigger': str(self.UpgradeTrigger.currentText()).lower(),
|
||||||
|
'upgradeMode': str(self.UpgradeMode.currentText()).lower(),
|
||||||
|
'minPowerToMove': str(self.MinPower.value()),
|
||||||
|
'maxPowerToMove': str(self.MaxPower.value())}
|
||||||
|
return(out)
|
||||||
|
|
||||||
|
#==============================================================================
|
||||||
|
# Input Parameters: none
|
||||||
|
# Output Returns: none
|
||||||
|
#
|
||||||
|
# Description: This function closes the window and emits 'Abort' when the 'x'
|
||||||
|
# is pressed.
|
||||||
|
#==============================================================================
|
||||||
|
def closeEvent(self, event):
|
||||||
|
if(self.__UserAbort):
|
||||||
|
self.Closing.emit('Abort')
|
||||||
|
event.accept()
|
||||||
|
|
||||||
|
#==============================================================================
|
||||||
|
# Input Parameters: none
|
||||||
|
# Output Returns: none
|
||||||
|
#
|
||||||
|
# Description: This function closes the window and sets the user abort to false
|
||||||
|
#==============================================================================
|
||||||
|
def Abort(self):
|
||||||
|
#Close the application
|
||||||
|
self.__UserAbort = False
|
||||||
|
self.Closing.emit('Abort')
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
#==============================================================================
|
||||||
|
# Input Parameters: none
|
||||||
|
# Output Returns: none
|
||||||
|
#
|
||||||
|
# Description: This function closes the window and sets the user abort to false
|
||||||
|
#==============================================================================
|
||||||
|
def __Close(self):
|
||||||
|
#Close the application
|
||||||
|
self.__UserAbort = False
|
||||||
|
self.Closing.emit('Closed')
|
||||||
|
self.close()
|
||||||
6
config.ini
Normal file
6
config.ini
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[robot]
|
||||||
|
upgradetrigger = hotspot
|
||||||
|
upgrademode = both
|
||||||
|
minpowertomove = 55
|
||||||
|
maxpowertomove = 95
|
||||||
|
showReferenceCreator = 0
|
||||||
Reference in New Issue
Block a user