def __init__(self): super(MainWindow, self).__init__() self.currentPath = '' # The car's model, shared between the different views self.car = Car() # Socket (to connect with the car/Rpi) self.carSocket = CarSocket(self.car) # Setting the views self.automaticView = AutoView(self.car) self.manualView = ManualView(self.car) # File menu fileMenu = QMenu("&File", self) openAction = fileMenu.addAction("&Open...") openAction.setShortcut("Ctrl+O") saveAction = fileMenu.addAction("&Save...") saveAction.setShortcut("Ctrl+S") setScale = fileMenu.addAction("Set map's scale") setAngle = fileMenu.addAction("Set map's orientation") quitAction = fileMenu.addAction("E&xit") quitAction.setShortcut("Ctrl+Q") openAction.triggered.connect(self.openFile) saveAction.triggered.connect(self.saveMap) setScale.triggered.connect(self.setScale) setAngle.triggered.connect(self.setAngle) quitAction.triggered.connect(qApp.quit) self.menuBar().addMenu(fileMenu) # View menu viewMenu = QMenu("&View", self) self.backgroundAction = viewMenu.addAction("&Background") self.backgroundAction.setEnabled(True) self.backgroundAction.setCheckable(True) self.backgroundAction.setChecked(True) self.backgroundAction.toggled.connect(self.automaticView.setViewBackground) self.menuBar().addMenu(viewMenu) # Mode switching (automatic-manual) menu modeMenu = QMenu("&Mode", self) manualAction = modeMenu.addAction("M&anual") manualAction.setShortcut("Ctrl+M") manualAction.triggered.connect(self.manualMode) automaticAction = modeMenu.addAction("A&utomatic") automaticAction.setShortcut("Ctrl+A") automaticAction.triggered.connect(self.automaticMode) self.menuBar().addMenu(modeMenu) # Stacked widget (containing the auto. and manual view) self.stackedWidget = QStackedWidget() self.stackedWidget.addWidget(self.automaticView) self.stackedWidget.addWidget(self.manualView) self.setCentralWidget(self.stackedWidget) self.setMinimumSize(800, 600) # Configuration dialog loader = QUiLoader() file = QFile("config.ui") file.open(QFile.ReadOnly) self.config = loader.load(file) file.close() self.config.connectButton.clicked.connect(self.connectCar) self.config.buttonBox.accepted.connect(self.acceptConfig) self.config.buttonBox.rejected.connect(self.config.reject) self.config.buttonBox.button(QDialogButtonBox.RestoreDefaults).clicked.connect(self.resetConfig) self.config.resetParticles.clicked.connect(self.resetParticles) # Log dialog file = QFile("log.ui") file.open(QFile.ReadOnly) self.log = loader.load(file) file.close() self.log.saveButton.clicked.connect(self.saveLog) self.connect(self.carSocket, SIGNAL("logSignal(str, str)"), self, SLOT("addToLog(str, str)")) self.initLog() # Configuration button self.configButton = QPushButton("Configuration panel", parent=self.automaticView) self.configButton.clicked.connect(self.openConfigPanel) # Configuration button self.logButton = QPushButton("Car's log", parent=self.automaticView) self.logButton.clicked.connect(self.log.show)
class MainWindow(QMainWindow): AUTO_MODE = 0 MANUAL_MODE = 1 def __init__(self): super(MainWindow, self).__init__() self.currentPath = '' # The car's model, shared between the different views self.car = Car() # Socket (to connect with the car/Rpi) self.carSocket = CarSocket(self.car) # Setting the views self.automaticView = AutoView(self.car) self.manualView = ManualView(self.car) # File menu fileMenu = QMenu("&File", self) openAction = fileMenu.addAction("&Open...") openAction.setShortcut("Ctrl+O") saveAction = fileMenu.addAction("&Save...") saveAction.setShortcut("Ctrl+S") setScale = fileMenu.addAction("Set map's scale") setAngle = fileMenu.addAction("Set map's orientation") quitAction = fileMenu.addAction("E&xit") quitAction.setShortcut("Ctrl+Q") openAction.triggered.connect(self.openFile) saveAction.triggered.connect(self.saveMap) setScale.triggered.connect(self.setScale) setAngle.triggered.connect(self.setAngle) quitAction.triggered.connect(qApp.quit) self.menuBar().addMenu(fileMenu) # View menu viewMenu = QMenu("&View", self) self.backgroundAction = viewMenu.addAction("&Background") self.backgroundAction.setEnabled(True) self.backgroundAction.setCheckable(True) self.backgroundAction.setChecked(True) self.backgroundAction.toggled.connect(self.automaticView.setViewBackground) self.menuBar().addMenu(viewMenu) # Mode switching (automatic-manual) menu modeMenu = QMenu("&Mode", self) manualAction = modeMenu.addAction("M&anual") manualAction.setShortcut("Ctrl+M") manualAction.triggered.connect(self.manualMode) automaticAction = modeMenu.addAction("A&utomatic") automaticAction.setShortcut("Ctrl+A") automaticAction.triggered.connect(self.automaticMode) self.menuBar().addMenu(modeMenu) # Stacked widget (containing the auto. and manual view) self.stackedWidget = QStackedWidget() self.stackedWidget.addWidget(self.automaticView) self.stackedWidget.addWidget(self.manualView) self.setCentralWidget(self.stackedWidget) self.setMinimumSize(800, 600) # Configuration dialog loader = QUiLoader() file = QFile("config.ui") file.open(QFile.ReadOnly) self.config = loader.load(file) file.close() self.config.connectButton.clicked.connect(self.connectCar) self.config.buttonBox.accepted.connect(self.acceptConfig) self.config.buttonBox.rejected.connect(self.config.reject) self.config.buttonBox.button(QDialogButtonBox.RestoreDefaults).clicked.connect(self.resetConfig) self.config.resetParticles.clicked.connect(self.resetParticles) # Log dialog file = QFile("log.ui") file.open(QFile.ReadOnly) self.log = loader.load(file) file.close() self.log.saveButton.clicked.connect(self.saveLog) self.connect(self.carSocket, SIGNAL("logSignal(str, str)"), self, SLOT("addToLog(str, str)")) self.initLog() # Configuration button self.configButton = QPushButton("Configuration panel", parent=self.automaticView) self.configButton.clicked.connect(self.openConfigPanel) # Configuration button self.logButton = QPushButton("Car's log", parent=self.automaticView) self.logButton.clicked.connect(self.log.show) # self.logButton.setVisible(False) def manualMode(self): self.stackedWidget.setCurrentWidget(self.manualView) self.setWindowTitle("Autonomee - Manual mode") self.car.mode = Car.Manual def automaticMode(self): self.stackedWidget.setCurrentWidget(self.automaticView) self.setWindowTitle("Autonomee - Automatic mode - Map : {}".format(self.currentPath)) self.car.mode = Car.Automatic def saveMap(self): self.automaticView.scene().map.save() def setAngle(self): self.automaticView.scene().setMapNorthAngle() self.car.updateMap() def setScale(self): self.automaticView.scene().setMapScale() self.car.updateMap() def saveLog(self): with open("log.html", 'w+') as logFile: logFile.write(self.log.logEdit.toHtml()) logFile.close() def initLog(self): curDate = datetime.date.today().strftime("%A %d. %B %Y") curTime = time.strftime('%H:%M:%S', time.localtime()) self.addToLog("<h3>Date : {} | Time: {}</h3>".format(curDate, curTime)) def addToLog(self, text, mode='NORMAL'): print "Got ", text if mode == 'RAW': toAdd = text else: toAdd = "<p>{}</p><hr> \n".format(text) self.log.logEdit.append(toAdd) def openConfigPanel(self): # Updating dialog with the configuration c = self.config c.widthValue.setValue(self.car.width) c.lengthValue.setValue(self.car.length) c.randomnessValue.setValue(int(self.automaticView.scene().particleFilter.randomness*100)) c.sensorSlider.setValue(int(self.car.sensor_noise)) c.rotationSlider.setValue(int(self.car.rotation_noise)) c.displacementSlider.setValue(int(self.car.displacement_noise)) self.config.show() def resetParticles(self): self.automaticView.scene().particleFilter.reset() self.automaticView.scene().heatmap.update() def notify(self, text, type=NotificationTooltip.normal): """ Creates a notification tooltip in the 'automatic' view """ self.automaticView.scene().notify(text, type) def connectCar(self): """ Connecting the app to the car """ ip = self.config.ipEdit.toPlainText() port = int(self.config.portEdit.toPlainText()) print "Connecting robot to {}:{}".format(ip, port) connected = self.carSocket.connect(ip, port) if connected: self.notify("Succesfully connected to the car !", type=NotificationTooltip.information) self.config.reject() else: self.notify("Couldn't connect to the car.", type=NotificationTooltip.error) def acceptConfig(self): """ Validating the parameters from the configuration dialog """ try: c = self.config self.car.width = c.widthValue.value() self.car.length = c.lengthValue.value() self.car.sensor_noise = float(c.sensorValue.text()) self.car.displacement_noise = float(c.displacementValue.text()) self.car.rotation_noise = float(c.rotationValue.text()) self.automaticView.scene().particleFilter.randomness = c.randomnessValue.value() / 100.0 if c.simpleProba.isChecked(): self.automaticView.scene().particleFilter.mode = ParticleFilter.simple elif c.markovProba.isChecked(): self.automaticView.scene().particleFilter.mode = ParticleFilter.markov self.car.update() self.car.updateMap() self.config.accept() self.notify("The application's configuration was updated") except ValueError: self.notify("Couldn't parse the given values !", type=NotificationTooltip.error) self.config.reject() # TODO : Do this in the status bar, not in the console def resetConfig(self): """ Reseting the parameters from the configuration dialog """ c = self.config c.widthValue.setPlainText(str(Car.def_width)) c.lengthValue.setPlainText(str(Car.def_length)) c.sensorSlider.setValue(int(Car.def_sensor)) c.rotationSlider.setValue(int(Car.def_rotation)) c.displacementSlider.setValue(int(Car.def_displacement)) self.notify("All parameters were reset to their default value", type=NotificationTooltip.information) def resizeEvent(self, event): h = 40 cW, lW = 200, 150 x, y = self.size().width(), self.size().height() y -= h + 35 x -= cW + 15 self.configButton.setGeometry(QRect(x, y, cW, h)) x -= lW + 15 self.logButton.setGeometry(QRect(x, y, lW, h)) def openFile(self, path=None): if not path: path = QFileDialog.getOpenFileName(self, "Open SVG File", self.currentPath, "SVG files (*.svg *.svgz *.svg.gz)")[0] if path: svgFile = QFile(path) if not svgFile.exists(): QMessageBox.critical(self, "Open SVG File", "Could not open file '%s'." % path) self.backgroundAction.setEnabled(True) return self.svgMap = SvgTree(svgFile.fileName(), radius=max(self.car.width, self.car.length)) self.automaticView.openMap(self.svgMap) if not path.startswith(':/'): self.currentPath = path self.setWindowTitle("Autonomee - Automatic mode - Map : {}".format(self.currentPath)) self.backgroundAction.setEnabled(True) self.resize(self.automaticView.sizeHint() + QSize(80, 80 + self.menuBar().height()))