#!/usr/bin/env python #**************************************************************************** # mapview.py, provides a map window # # FlyWay, a VFR/IFR Route Planner for Pilots # Copyright (C) 2002, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, Version 2. This program is # distributed in the hope that it will be useful, but WITTHOUT ANY WARRANTY. #***************************************************************************** from mapdata import MapData from waypoint import Airport, Navaid, Fixpoint import flymainwin from xpm import * from qt import * import sys class MapView(QWidget): """A view that shows a rough map of the route""" def __init__(self, parent=None, name=None, flags=0): QWidget.__init__(self, parent, name, flags) self.setFocusPolicy(QWidget.StrongFocus) if sys.platform == 'win32': self.setCaption('Route Map (PyQt)') else: self.setCaption('Route Map') self.setIcon(QPixmap(fly_xpm)) topLayout = QVBoxLayout(self, 5) ctrlLayout = QHBoxLayout(topLayout) self.infoLabel = QLabel(self) self.infoLabel.setFrameStyle(QFrame.Panel | QFrame.Sunken) self.mapDrawing = MapDrawing(self.infoLabel, self) topLayout.addWidget(self.mapDrawing, 1) topLayout.addWidget(self.infoLabel) self.airportButton = QToolButton(self) self.airportButton.setTextLabel('Show All Airports') self.airportButton.setUsesTextLabel(1) self.airportButton.setFocusPolicy(QWidget.TabFocus) self.airportButton.setPixmap(QPixmap(map_apt_xpm)) self.airportButton.setToggleButton(1) self.connect(self.airportButton, SIGNAL('toggled(bool)'), \ self.mapDrawing.addAirports) ctrlLayout.addWidget(self.airportButton) self.navaidButton = QToolButton(self) self.navaidButton.setTextLabel('Show All Navaids') self.navaidButton.setUsesTextLabel(1) self.navaidButton.setFocusPolicy(QWidget.TabFocus) self.navaidButton.setPixmap(QPixmap(map_nav_xpm)) self.navaidButton.setToggleButton(1) self.connect(self.navaidButton, SIGNAL('toggled(bool)'), \ self.mapDrawing.addNavaids) ctrlLayout.addWidget(self.navaidButton) self.fixesButton = QToolButton(self) self.fixesButton.setTextLabel('Show All Fixes') self.fixesButton.setUsesTextLabel(1) self.fixesButton.setFocusPolicy(QWidget.TabFocus) self.fixesButton.setPixmap(QPixmap(map_fix_xpm)) self.fixesButton.setToggleButton(1) self.connect(self.fixesButton, SIGNAL('toggled(bool)'), \ self.mapDrawing.addFixes) ctrlLayout.addWidget(self.fixesButton) self.mapDrawing.updateAll() def updateMap(self): """Update the map data and view""" mapData = flymainwin.FlyMainWin.route.mapData mapData.calcBounds() mapData.addRouteWp() if self.mapDrawing.inclAirports: mapData.addAirports() if self.mapDrawing.inclNavaids: mapData.addNavaids() if self.mapDrawing.inclFixes: mapData.addFixes() self.mapDrawing.updateAll() def closeEvent(self, event): """Signal that view is closing""" self.emit(PYSIGNAL('viewClosed'), ()) event.accept() def hideEvent(self, event): """Reset show all on map close""" self.mapDrawing.inclAirports = 0 self.mapDrawing.inclNavaids = 0 self.mapDrawing.inclFixes = 0 self.airportButton.setOn(0) self.navaidButton.setOn(0) self.fixesButton.setOn(0) class MapDrawing(QWidget): """Shows a rough map of the route""" mapBorder = 10 mapSize = MapData.mapPixels + 2 * mapBorder labelOffset = 10 infoDistance = 10 def __init__(self, infoLabel, parent=None, name=None, flags=0): QWidget.__init__(self, parent, name, flags) self.infoLabel = infoLabel self.setMouseTracking(1) self.setMinimumSize(300, 300) self.inclAirports = 0 self.inclNavaids = 0 self.inclFixes = 0 self.fullItemList = [] self.viewSize = 0 self.zero = (0, 0) def sizeHint(self): """Set prefered size""" return QSize(MapDrawing.mapSize, MapDrawing.mapSize) def updateAll(self): """Update full item list and the map""" QApplication.setOverrideCursor(Qt.waitCursor) mapData = flymainwin.FlyMainWin.route.mapData self.fullItemList = mapData.routeList[:] if self.inclAirports: self.fullItemList.extend(mapData.airportList) if self.inclNavaids: self.fullItemList.extend(mapData.navaidList) if self.inclFixes: self.fullItemList.extend(mapData.fixList) self.update() QApplication.restoreOverrideCursor() def addAirports(self, show): """Add or remove other airports from map""" self.inclAirports = show if show: QApplication.setOverrideCursor(Qt.waitCursor) self.infoLabel.setText('Working...') self.infoLabel.repaint() flymainwin.FlyMainWin.route.mapData.addAirports() self.infoLabel.setText('') QApplication.restoreOverrideCursor() self.updateAll() def addNavaids(self, show): """Add or remove other navaids from map""" self.inclNavaids = show if show: QApplication.setOverrideCursor(Qt.waitCursor) self.infoLabel.setText('Working...') self.infoLabel.repaint() flymainwin.FlyMainWin.route.mapData.addNavaids() self.infoLabel.setText('') QApplication.restoreOverrideCursor() self.updateAll() def addFixes(self, show): """Add or remove other airports from map""" self.inclFixes = show if show: QApplication.setOverrideCursor(Qt.waitCursor) self.infoLabel.setText('Working...') self.infoLabel.repaint() flymainwin.FlyMainWin.route.mapData.addFixes() self.infoLabel.setText('') QApplication.restoreOverrideCursor() self.updateAll() def paintEvent(self, event): """Paint the map""" QApplication.setOverrideCursor(Qt.waitCursor) mapData = flymainwin.FlyMainWin.route.mapData paint = QPainter() # problem in win with QPainter(self) paint.begin(self) paint.setWindow(0, 0, MapDrawing.mapSize, MapDrawing.mapSize) viewRect = paint.viewport() self.viewSize = min(viewRect.width(), viewRect.height()) self.zero = (viewRect.left() + (viewRect.width() - self.viewSize) / 2, \ viewRect.top() + (viewRect.height() - self.viewSize) / 2) paint.setViewport(self.zero[0], self.zero[1], self.viewSize, \ self.viewSize) paint.setPen(QPen(QColor(0, 0, 0), 2)) paint.drawRect(paint.window()) paint.translate(MapDrawing.mapBorder, MapDrawing.mapBorder) if mapData.routeList: if self.inclFixes: for item in mapData.fixList: paint.drawPixmap(item.xCoord - 3, item.yCoord - 3, \ QPixmap(map_fix_xpm)) if self.inclNavaids: for item in mapData.navaidList: paint.drawPixmap(item.xCoord - 3, item.yCoord - 3, \ QPixmap(map_nav_xpm)) if self.inclAirports: for item in mapData.airportList: paint.drawPixmap(item.xCoord - 3, item.yCoord - 3, \ QPixmap(map_apt_xpm)) item = mapData.routeList[0] paint.drawPixmap(item.xCoord - 3, item.yCoord - 3, \ self.getPixmap(item)) self.drawName(paint, item) paint.moveTo(item.xCoord, item.yCoord) for item in mapData.routeList[1:]: paint.lineTo(item.xCoord, item.yCoord) paint.drawPixmap(item.xCoord - 3, item.yCoord - 3, \ self.getPixmap(item)) self.drawName(paint, item) paint.end() QApplication.restoreOverrideCursor() def getPixmap(self, item): """Return pixmap for a given map item""" if item.waypoint.__class__ == Airport: return QPixmap(map_apt_xpm) elif item.waypoint.__class__ == Navaid: return QPixmap(map_nav_xpm) else: return QPixmap(map_fix_xpm) def drawName(self, paint, item): """Draw ID as legend for item""" textRect = QFontMetrics(self.font()).boundingRect(item.\ waypoint.ident()) pos = [item.xCoord, item.yCoord + textRect.height() / 2] if item.labelOctant in (0, 4): pos[0] -= textRect.width() / 2 elif item.labelOctant in (5, 7): pos[0] -= textRect.width() elif item.labelOctant == 2: pos[0] += MapDrawing.labelOffset elif item.labelOctant == 6: pos[0] -= textRect.width() + MapDrawing.labelOffset if item.labelOctant in (0, 1, 7): pos[1] -= MapDrawing.labelOffset elif item.labelOctant in (3, 4, 5): pos[1] += MapDrawing.labelOffset paint.drawText(pos[0], pos[1], item.waypoint.ident()) def calcSqDist(self, point, item): """Return distance in pixels from QPoint to item""" return (point.x() - item.xCoord)**2 + (point.y() - item.yCoord)**2 def mouseMoveEvent(self, event): """Called to track mouse & update waypoint label""" pos = QPoint((event.x() - self.zero[0]) * MapDrawing.mapSize / \ self.viewSize - MapDrawing.mapBorder, \ (event.y() - self.zero[1]) * MapDrawing.mapSize / \ self.viewSize - MapDrawing.mapBorder) distList = [self.calcSqDist(pos, item) for item in self.fullItemList] text = '' if distList and min(distList) <= MapDrawing.infoDistance**2: wp = self.fullItemList[distList.index(min(distList))].waypoint text = '%s - %s' % (wp.ident(), wp.description()) self.infoLabel.setText(text)