00001
00002
00003 from bwi_tools import getImageFileLocationFromMapFile as getImageFileLocation, loadMapFromFile
00004 from python_qt_binding.QtCore import Qt
00005 from python_qt_binding.QtGui import QFrame, QHBoxLayout, QImage, QLabel, QMessageBox, QPainter, QPushButton, \
00006 QVBoxLayout, QWidget
00007 from qt_gui.plugin import Plugin
00008
00009 from .location_function import LocationFunction
00010 from .door_function import DoorFunction
00011 from .object_function import ObjectFunction
00012 from .utils import clearLayoutAndFixHeight, \
00013 getDoorsFileLocationFromDataDirectory, \
00014 getLocationsFileLocationFromDataDirectory, \
00015 getObjectsFileLocationFromDataDirectory
00016
00017 import rospy
00018
00019 class MapImage(QLabel):
00020
00021 def __init__(self, map_image_location, parent=None):
00022 super(MapImage, self).__init__(parent)
00023
00024
00025 self.setFixedHeight(700)
00026 self.setFixedWidth(1300)
00027 self.setObjectName("map_image")
00028
00029
00030
00031 self.enableDefaultMouseHooks()
00032
00033 map_image = QImage(map_image_location)
00034 self.map_image = map_image.scaled(1300, 700, Qt.KeepAspectRatio)
00035
00036
00037
00038 self.overlay_image = QImage(self.map_image.size(), QImage.Format_ARGB32_Premultiplied)
00039 self.overlay_image.fill(Qt.transparent)
00040
00041 self.update()
00042
00043 def defaultMouseHandler(self, event):
00044
00045 pass
00046
00047 def enableDefaultMouseHooks(self):
00048 self.mousePressEvent = self.defaultMouseHandler
00049 self.mouseMoveEvent = self.defaultMouseHandler
00050 self.mouseReleaseEvent = self.defaultMouseHandler
00051
00052 def paintEvent(self, event):
00053 painter = QPainter(self)
00054 painter.drawImage(event.rect(), self.map_image, event.rect())
00055 painter.drawImage(event.rect(), self.overlay_image, event.rect())
00056 painter.end()
00057
00058 class LogicalMarkerPlugin(Plugin):
00059
00060 def __init__(self, context):
00061 super(LogicalMarkerPlugin, self).__init__(context)
00062
00063
00064 try:
00065 self.map_yaml_file_str = rospy.get_param("~map_file")
00066 self.data_directory = rospy.get_param("~data_directory")
00067 except KeyError:
00068 rospy.logfatal("~map_file and ~data_directory need to be set to use the logical marker")
00069 return
00070
00071 map_image_location = getImageFileLocation(self.map_yaml_file_str)
00072 map = loadMapFromFile(self.map_yaml_file_str)
00073 locations_file = getLocationsFileLocationFromDataDirectory(self.data_directory)
00074 doors_file = getDoorsFileLocationFromDataDirectory(self.data_directory)
00075 objects_file = getObjectsFileLocationFromDataDirectory(self.data_directory)
00076
00077
00078 self.setObjectName('LogicalMarkerPlugin')
00079
00080
00081 self.master_widget = QWidget()
00082 self.master_layout = QVBoxLayout(self.master_widget)
00083
00084
00085 self.function_layout = QHBoxLayout()
00086 self.master_layout.addLayout(self.function_layout)
00087 self.function_buttons = []
00088 self.current_function = None
00089 for button_text in ['Locations', 'Doors', 'Objects']:
00090 button = QPushButton(button_text, self.master_widget)
00091 button.clicked[bool].connect(self.handle_function_button)
00092 button.setCheckable(True)
00093 self.function_layout.addWidget(button)
00094 self.function_buttons.append(button)
00095 self.function_layout.addStretch(1)
00096
00097 self.master_layout.addWidget(self.get_horizontal_line())
00098
00099
00100 self.subfunction_layout = QHBoxLayout()
00101 clearLayoutAndFixHeight(self.subfunction_layout)
00102 self.master_layout.addLayout(self.subfunction_layout)
00103 self.current_subfunction = None
00104
00105 self.master_layout.addWidget(self.get_horizontal_line())
00106
00107 self.image = MapImage(map_image_location, self.master_widget)
00108 self.master_layout.addWidget(self.image)
00109
00110 self.master_layout.addWidget(self.get_horizontal_line())
00111
00112
00113 self.configuration_layout = QHBoxLayout()
00114 clearLayoutAndFixHeight(self.configuration_layout)
00115 self.master_layout.addLayout(self.configuration_layout)
00116
00117
00118 self.master_layout.addStretch(1)
00119
00120 self.master_widget.setObjectName('LogicalMarkerPluginUI')
00121 if context.serial_number() > 1:
00122 self.master_widget.setWindowTitle(self.master_widget.windowTitle() + (' (%d)' % context.serial_number()))
00123 context.add_widget(self.master_widget)
00124
00125
00126
00127 self.functions = {}
00128 self.functions['Locations'] = LocationFunction(locations_file,
00129 map,
00130 self.master_widget,
00131 self.subfunction_layout,
00132 self.configuration_layout,
00133 self.image)
00134 self.functions['Doors'] = DoorFunction(doors_file,
00135 map,
00136 self.functions['Locations'],
00137 self.master_widget,
00138 self.subfunction_layout,
00139 self.configuration_layout,
00140 self.image)
00141 self.functions['Objects'] = ObjectFunction(objects_file,
00142 map,
00143 self.functions['Locations'],
00144 self.master_widget,
00145 self.subfunction_layout,
00146 self.configuration_layout,
00147 self.image)
00148 def construct_layout(self):
00149 pass
00150
00151 def get_horizontal_line(self):
00152 """
00153 http://stackoverflow.com/questions/5671354/how-to-programmatically-make-a-horizontal-line-in-qt
00154 """
00155 hline = QFrame()
00156 hline.setFrameShape(QFrame.HLine)
00157 hline.setFrameShadow(QFrame.Sunken)
00158 return hline
00159
00160 def handle_function_button(self):
00161 source = self.sender()
00162
00163 if source.text() == self.current_function:
00164 source.setChecked(True)
00165 return
00166
00167
00168 for button in self.function_buttons:
00169 if button != source:
00170 button.setChecked(False)
00171
00172 if self.current_function is not None:
00173 self.functions[self.current_function].deactivateFunction()
00174 self.current_function = source.text()
00175
00176
00177 clearLayoutAndFixHeight(self.subfunction_layout)
00178
00179 if self.current_function is not None:
00180 self.functions[self.current_function].activateFunction()
00181
00182 def shutdown_plugin(self):
00183 modified = False
00184 for function in self.functions:
00185 if self.functions[function].isModified():
00186 modified = True
00187 if modified:
00188 ret = QMessageBox.warning(self.master_widget, "Save",
00189 "The logical map has been modified.\n"
00190 "Do you want to save your changes?",
00191 QMessageBox.Save | QMessageBox.Discard)
00192 if ret == QMessageBox.Save:
00193 for function in self.functions:
00194 self.functions[function].saveConfiguration()
00195
00196 def save_settings(self, plugin_settings, instance_settings):
00197 pass
00198
00199 def restore_settings(self, plugin_settings, instance_settings):
00200 pass