00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 import roslib; roslib.load_manifest('tf2_visualization')
00038 import rospy
00039 
00040 import os
00041 import sys
00042 import yaml
00043 
00044 import wxversion
00045 WXVER = '2.8'
00046 if wxversion.checkInstalled(WXVER):
00047     wxversion.select(WXVER)
00048 else:
00049     print >> sys.stderr, 'This application requires wxPython version %s' % WXVER
00050     sys.exit(1)
00051 
00052 import wx
00053 import wx.richtext
00054 import xdot
00055 import threading
00056 
00057 class FrameViewerPanel(wx.Panel):
00058     def __init__(self, parent, tf_interface, auto_update_list=True):
00059         wx.Panel.__init__(self, parent, -1)
00060 
00061         self.tf_interface   = tf_interface
00062         self.namespace      = ('local', False)
00063         self.tf_namespaces = []
00064         self.loaded_files = []
00065         self.need_dot_zoom = True
00066         self.keep_running = True
00067         self.ns_list_lock = threading.RLock()
00068 
00069         
00070         vbox = wx.BoxSizer(wx.VERTICAL)
00071         
00072         
00073         self.content_splitter = wx.SplitterWindow(self, -1, style=wx.SP_LIVE_UPDATE)
00074         self.content_splitter.SetMinimumPaneSize(24)
00075         self.content_splitter.SetSashGravity(0.85)
00076 
00077         
00078         viewer = wx.Panel(self.content_splitter, -1)
00079 
00080         
00081         graph_viewer = wx.Panel(viewer, -1)
00082         gv_vbox = wx.BoxSizer(wx.VERTICAL)
00083         graph_viewer.SetSizer(gv_vbox)
00084 
00085         viewer_box = wx.BoxSizer()
00086         viewer_box.Add(graph_viewer,1,wx.EXPAND | wx.ALL, 4)
00087         viewer.SetSizer(viewer_box)
00088 
00089         
00090         toolbar = wx.ToolBar(graph_viewer, -1)
00091         toolbar.AddControl(wx.StaticText(toolbar, -1, "Graph:  "))
00092         self.namespaces = wx.ComboBox(toolbar, 1, value='local', choices=['local'], size=(-1, -1), style=wx.CB_DROPDOWN)
00093         self.namespaces.Editable = False
00094         toolbar.AddControl(self.namespaces)
00095         self.Bind(wx.EVT_COMBOBOX, self.on_select_ns, id=1)
00096 
00097         if auto_update_list:
00098             self.namespace_list_thread = threading.Thread(target=self._update_namespace_list)
00099             self.namespace_list_thread.start()
00100 
00101         toolbar.Realize();
00102 
00103         
00104         self.widget = xdot.wxxdot.WxDotWindow(graph_viewer, -1)
00105         self.widget.zoom_to_fit()
00106 
00107         gv_vbox.Add(toolbar,     0, wx.EXPAND)
00108         gv_vbox.Add(self.widget, 1, wx.EXPAND)
00109 
00110         nb = wx.Notebook(self.content_splitter, -1, style=wx.NB_TOP | wx.WANTS_CHARS)
00111         nb_box = wx.BoxSizer()
00112         nb_box.Add(nb, 1, wx.EXPAND | wx.ALL, 4)
00113 
00114         
00115         borders = wx.LEFT | wx.RIGHT | wx.TOP
00116         border = 4
00117         self.info_win = wx.ScrolledWindow(nb, -1)
00118         self.info_sizer = wx.BoxSizer(wx.VERTICAL)
00119         self.info_txt = wx.TextCtrl(self.info_win, -1, style=wx.TE_MULTILINE | wx.TE_READONLY)
00120         self.info_sizer.Add(self.info_txt, 1, wx.EXPAND | borders, border)
00121         self.info_win.SetSizer(self.info_sizer)
00122 
00123         
00124         echo_panel = wx.Panel(nb, -1)
00125         echo_box = wx.BoxSizer(wx.VERTICAL)
00126         echo_panel.SetSizer(echo_box)
00127         wx.StaticText(echo_panel, -1, "Target: ", pos=(5, 15))
00128         self.target_frame = wx.ComboBox(echo_panel, 2, value='Select Target', choices=['Select Target'], pos=(60, 10), size=(200, -1), style=wx.CB_DROPDOWN)
00129         self.target_frame.SetEditable(False)
00130         self.Bind(wx.EVT_COMBOBOX, self.on_select_target, id=2)
00131 
00132         wx.StaticText(echo_panel, -1, "Source: ", pos=(5, 55))
00133         self.source_frame = wx.ComboBox(echo_panel, 3, value='Select Source', choices=['Select Source'], pos=(60, 50), size=(200, -1), style=wx.CB_DROPDOWN)
00134         self.source_frame.SetEditable(False)
00135         self.Bind(wx.EVT_COMBOBOX, self.on_select_source, id=3)
00136 
00137         self.echo_txt = wx.TextCtrl(echo_panel, -1, style=wx.TE_MULTILINE | wx.TE_READONLY, pos=(5, 90), size=(255,500))
00138 
00139         
00140         nb.AddPage(self.info_win, "Info")
00141         nb.AddPage(echo_panel, "TF Echo")
00142 
00143         
00144         
00145 
00146         vbox.Add(self.content_splitter, 1, wx.EXPAND | wx.ALL)
00147         self.SetSizer(vbox)
00148         self.Center()
00149 
00150         self.content_splitter.SplitVertically(nb, viewer, 300)
00151 
00152         self.timer = wx.Timer(self)
00153 
00154         self.Bind(wx.EVT_TIMER, lambda event: self.update_tf_data(), self.timer)
00155         self.widget.register_select_callback(self.select_cb)
00156 
00157         self.timer.Start(1000)
00158 
00159     def update_file_list(self, file):
00160         if file:
00161             filename = file.rstrip('.tf')+'.tf'
00162             self.loaded_files.append(filename)
00163             self.refresh_list()
00164             self.namespaces.SetValue(filename)
00165             cmd = wx.CommandEvent(wx.EVT_COMBOBOX.evtType[0])
00166             cmd.SetEventObject(self.namespaces)
00167             cmd.SetId(self.namespaces.GetId())
00168             self.namespaces.GetEventHandler().ProcessEvent(cmd)
00169 
00170     def reset_frame_lists(self):
00171         self.source_frame.SetItems(['Select Source'])
00172         self.source_frame.SetValue('Select Source')
00173         self.target_frame.SetItems(['Select Target'])
00174         self.target_frame.SetValue('Select Target')
00175         self.set_echo_text("")
00176 
00177     def update_tf_data(self):
00178         self.tf_interface.update_data(*self.namespace)
00179 
00180         dotcode    = self.tf_interface.get_dot()
00181         frame_list = self.tf_interface.get_frame_list()
00182 
00183         if self.namespace[0] == 'local':
00184             self.source_frame.SetItems(frame_list)
00185             self.target_frame.SetItems(frame_list)
00186         else:
00187             self.reset_frame_lists()
00188 
00189         self.set_info_text(yaml.dump(self.tf_interface.get_info(), default_flow_style=False))
00190         self.set_dotcode(dotcode)
00191 
00192         self.check_echo()
00193         self.refresh_list()
00194 
00195     def set_dotcode(self, dotcode):
00196         if not dotcode:
00197             return
00198         
00199         self.widget.set_dotcode(dotcode, None)
00200 
00201         
00202         if self.need_dot_zoom:
00203             self.need_dot_zoom = False
00204             self.widget.zoom_to_fit()
00205 
00206         wx.CallAfter(self.Refresh)
00207 
00208     def set_info_text(self, text):
00209         self.info_txt.Value = text
00210         self.Refresh()
00211 
00212     def set_echo_text(self, text):
00213         self.echo_txt.Value = text
00214         self.Refresh()
00215 
00216     
00217 
00218     def select_cb(self, target, event):
00219         if event.ButtonDown(wx.MOUSE_BTN_LEFT) and target.url is not None:
00220             self.tf_interface.set_detail(target.url)
00221 
00222     def _update_namespace_list(self):
00223         r = rospy.Rate(0.5)
00224         while not rospy.is_shutdown() and self.keep_running:
00225             tf_namespaces = self.tf_interface.find_tf_namespaces()
00226             with self.ns_list_lock:
00227                 self.tf_namespaces = tf_namespaces
00228             r.sleep()
00229 
00230     def refresh_list(self):
00231         with self.ns_list_lock:
00232             self.namespaces.Items = ['local'] + self.tf_namespaces + self.loaded_files
00233         
00234     def on_select_ns(self, event):
00235         value = event.EventObject.Value
00236         
00237         if value == self.namespace[0]:
00238             return
00239 
00240         with self.ns_list_lock:
00241             if value == 'local' or self.tf_namespaces.count(value) > 0:
00242                 self.namespace = (value, False)
00243             else:
00244                 self.namespace = (value, True)
00245 
00246             self.tf_interface.clear_detail()
00247             self.reset_frame_lists()
00248             self.need_dot_zoom = True
00249         
00250     def on_select_target(self, event):
00251         print "target"
00252         print type(event)
00253         print event.EventObject.Value
00254 
00255     def on_select_source(self, event):
00256         print "source"
00257         print type(event)
00258         print event.EventObject.Value
00259 
00260     def check_echo(self):
00261         target = self.target_frame.GetValue()
00262         source = self.source_frame.GetValue()
00263         if source != 'Select Source' and target != 'Select Target':
00264             self.set_echo_text(self.tf_interface.get_echo_string(target, source))
00265