25 __all__ = [
'WxDotWindow', 
'WxDotFrame']
    29 if wxversion.checkInstalled(
"2.8"):
    30     wxversion.select(
"2.8")
    32     print(
"wxversion 2.8 is not installed, installed versions are {}".format(wxversion.getInstalled()))
    34     gtk.remove_log_handlers()
    36 import wx.lib.wxcairo 
as wxcairo
    39 if 'wxMac' in wx.PlatformInfo:
    41 elif 'wxMSW' in wx.PlatformInfo:
    43 elif 'wxGTK' in wx.PlatformInfo:
    45   gdkLib = wx.lib.wxcairo._findGDKLib()
    46   gdkLib.gdk_cairo_create.restype = ctypes.c_void_p
    53     x,y = event.GetPositionTuple()
    59     x,y = event.GetPositionTuple()
    62     self.
drag(deltax, deltay)
    67     x,y = event.GetPositionTuple()
    78   def drag(self, deltax, deltay):
    87 class WxNullAction(WxDragAction):
    91 class WxPanAction(WxDragAction):
    93     self.dot_widget.set_cursor(wx.CURSOR_SIZING)
    95   def drag(self, deltax, deltay):
    96     self.dot_widget.x += deltax / self.dot_widget.zoom_ratio
    97     self.dot_widget.y += deltay / self.dot_widget.zoom_ratio
    98     self.dot_widget.Refresh()
   101     self.dot_widget.set_cursor(wx.CURSOR_ARROW)
   106   def drag(self, deltax, deltay):
   107     self.dot_widget.zoom_ratio *= 1.005 ** (deltax + deltay)
   108     self.dot_widget.zoom_to_fit_on_resize = 
False   109     self.dot_widget.Refresh()
   112     self.dot_widget.Refresh()
   115   def drag(self, deltax, deltay):
   116     self.dot_widget.Refresh()
   120     cr.set_source_rgba(.5, .5, 1.0, 0.25)
   125     cr.set_source_rgba(.5, .5, 1.0, 1.0)
   134     x1, y1 = self.dot_widget.window2graph(self.
startmousex,
   136     x2, y2 = self.dot_widget.window2graph(self.
stopmousex,
   138     self.dot_widget.zoom_to_area(x1, y1, x2, y2)
   141     self.dot_widget.Refresh()
   144   """wxpython Frame that draws dot graphs."""   149     wx.Panel.__init__(self, parent, id)
   154     self.
x, self.
y = 0.0, 0.0
   163     self.Bind(wx.EVT_PAINT, self.
OnPaint)
   164     self.Bind(wx.EVT_SIZE, self.
OnResize)
   166     self.Bind(wx.EVT_MOUSEWHEEL, self.
OnScroll)
   168     self.Bind(wx.EVT_MOUSE_EVENTS, self.
OnMouse)
   170     self.Bind(wx.EVT_KEY_DOWN, self.
OnKeyDown)
   180     self.select_cbs.append(cb)
   187     """Redraw the graph."""   188     dc = wx.PaintDC(self)
   191     ctx = wxcairo.ContextFromDC(dc)
   192     ctx = pangocairo.CairoContext(ctx)
   196     width, height = self.GetSize()
   199     ctx.rectangle(0,0,width,height)
   202     ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0)
   206     ctx.translate(0.5*width, 0.5*height)
   209     ctx.translate(-self.
x, -self.
y)
   210     self.graph.draw(ctx, highlight_items=self.
highlight)
   213     self.drag_action.draw(ctx)
   217     if event.GetWheelRotation() > 0:
   219           pos=(event.GetX(), event.GetY()))
   222           pos=(event.GetX(), event.GetY()))
   225     """Process key down event."""   226     key = event.GetKeyCode()
   227     if key == wx.WXK_LEFT:
   230     if key == wx.WXK_RIGHT:
   236     if key == wx.WXK_DOWN:
   239     if key == wx.WXK_PAGEUP:
   242     if key == wx.WXK_PAGEDOWN:
   245     if key == wx.WXK_ESCAPE:
   246       self.drag_action.abort()
   258     """Get the current graph position."""   259     return self.
x, self.
y   262     """Set the current graph position."""   268     """Set a number of items to be hilighted."""   275     self.
cursor = wx.StockCursor(cursor_type)
   276     self.SetCursor(self.
cursor)
   280     """Zoom the graph."""   282       self.
x = self.graph.width/2
   283       self.
y = self.graph.height/2
   284     elif pos 
is not None:
   285       width, height = self.GetSize()
   296     """Zoom to an area of the graph."""   297     width, height = self.GetSize()
   298     area_width = abs(x1 - x2)
   299     area_height = abs(y1 - y2)
   301       float(width)/float(area_width),
   302       float(height)/float(area_height)
   305     self.
x = (x1 + x2) / 2
   306     self.
y = (y1 + y2) / 2
   310     """Zoom to fit the size of the graph."""   311     width,height = self.GetSize()
   317     if float(self.graph.width) > 0 
and float(self.graph.height) > 0 
and width > 0 
and height > 0:
   319         float(width)/float(self.graph.width),
   320         float(height)/float(self.graph.height)
   325   ZOOM_INCREMENT = 1.25
   326   ZOOM_TO_FIT_MARGIN = 12
   343     """Get a drag action for this click."""   345     button = event.GetButton()
   347     control_down  = event.ControlDown()
   348     alt_down = event.AltDown()
   349     shift_down = event.ShiftDown()
   351     drag = event.Dragging()
   352     motion = event.Moving()
   355     if button 
in (wx.MOUSE_BTN_LEFT, wx.MOUSE_BTN_MIDDLE): 
   367     x,y = event.GetPositionTuple()
   372     if not event.Dragging():
   388       if event.ButtonDown():
   389         self.animation.stop()
   390         self.drag_action.abort()
   394         self.drag_action.on_button_press(event)
   399       if event.Dragging() 
or event.Moving():
   400         self.drag_action.on_motion_notify(event)
   403         self.drag_action.on_button_release(event)
   415     self.animation.start()
   418     "Get the x,y coordinates in the graph from the x,y coordinates in the window."""   419     width, height = self.GetSize()   428   def get_url(self, x, y):   429     x, y = self.window2graph(x, y)   430     return self.graph.get_url(x, y)   432   def get_jump(self, x, y):   433     x, y = self.window2graph(x, y)   434     return self.graph.get_jump(x, y)   436   def set_filter(self, filter):   439   def set_dotcode(self, dotcode, filename='<stdin>'):   440     if isinstance(dotcode, unicode):   441       dotcode = dotcode.encode('utf8')   442     p = subprocess.Popen(   443       [self.filter, '-Txdot'],   444       stdin=subprocess.PIPE,   445       stdout=subprocess.PIPE,   446       stderr=subprocess.PIPE,   448       universal_newlines=True   450     xdotcode, error = p.communicate(dotcode)   451     if p.returncode != 0:   452       print "ERROR PARSING DOT CODE", error   453       dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,   454                      message_format=error,   455                      buttons=gtk.BUTTONS_OK)   456       dialog.set_title('Dot Viewer')   461       self.set_xdotcode(xdotcode)   463       # Store references to all the items   464       self.items_by_url = {}   465       for item in self.graph.nodes + self.graph.edges:   466         if item.url is not None:   467           self.items_by_url[item.url] = item   469       # Store references to subgraph states   470       self.subgraph_shapes = self.graph.subgraph_shapes   472     except ParseError, ex:   473       print "ERROR PARSING XDOT CODE"   474       dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,   475                      message_format=str(ex),   476                      buttons=gtk.BUTTONS_OK)   477       dialog.set_title('Dot Viewer')   482       self.openfilename = filename   485   def set_xdotcode(self, xdotcode):   488     parser = XDotParser(xdotcode)   489     self.graph = parser.parse()   490     self.highlight = None   491     #self.zoom_image(self.zoom_ratio, center=True)   494     if self.openfilename is not None:   496         fp = file(self.openfilename, 'rt')   497         self.set_dotcode(fp.read(), self.openfilename)   503 class WxDotFrame(wx.Frame):   505     wx.Frame.__init__(self, None, -1, "Dot Viewer", size=(512,512))   507     vbox = wx.BoxSizer(wx.VERTICAL)   510     toolbar = wx.ToolBar(self, -1)   511     toolbar.AddLabelTool(wx.ID_OPEN, 'Open File',   512         wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN,wx.ART_OTHER,(16,16)))   513     toolbar.AddLabelTool(wx.ID_HELP, 'Help',   514         wx.ArtProvider.GetBitmap(wx.ART_HELP,wx.ART_OTHER,(16,16)) )   517     self.Bind(wx.EVT_TOOL, self.DoOpenFile, id=wx.ID_OPEN)   518     self.Bind(wx.EVT_TOOL, self.ShowControlsDialog, id=wx.ID_HELP)   521     self.widget = WxDotWindow(self, -1)   523     # Add elements to sizer   524     vbox.Add(toolbar, 0, wx.EXPAND)   525     vbox.Add(self.widget, 100, wx.EXPAND | wx.ALL)   530   def ShowControlsDialog(self,event):   531     dial = wx.MessageDialog(None,   534 Zoom: PageUp / PageDown\n\   537         'Keyboard Controls', wx.OK)   540   def DoOpenFile(self,event):   541     wcd = 'All files (*)|*|GraphViz Dot Files(*.dot)|*.dot|'   543     open_dlg = wx.FileDialog(self, message='Choose a file', defaultDir=dir, defaultFile='',   544     wildcard=wcd, style=wx.OPEN|wx.CHANGE_DIR)   545     if open_dlg.ShowModal() == wx.ID_OK:   546       path = open_dlg.GetPath()   551       except IOError, error:   552         dlg = wx.MessageDialog(self, 'Error opening file\n' + str(error))   555       except UnicodeDecodeError, error:   556         dlg = wx.MessageDialog(self, 'Error opening file\n' + str(error))   561   def OnExit(self, event):   564   def set_dotcode(self, dotcode, filename='<stdin>'):   565     if self.widget.set_dotcode(dotcode, filename):   566       self.SetTitle(os.path.basename(filename) + ' - Dot Viewer')   567       self.widget.zoom_to_fit()   569   def set_xdotcode(self, xdotcode, filename='<stdin>'):   570     if self.widget.set_xdotcode(xdotcode):   571       self.SetTitle(os.path.basename(filename) + ' - Dot Viewer')   572       self.widget.zoom_to_fit()   574   def open_file(self, filename):   576       fp = file(filename, 'rt')   577       self.set_dotcode(fp.read(), filename)   581       dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
   582                   message_format=str(ex),
   583                   buttons=gtk.BUTTONS_OK)
   584       dlg.set_title(
'Dot Viewer')
   589   def set_filter(self, filter):   590     self.widget.set_filter(filter) def on_area_size_allocate(self, area, allocation)
def on_motion_notify(self, event)
def zoom_image(self, zoom_ratio, center=False, pos=None)
Zooming methods. 
def on_zoom_fit(self, action)
def register_select_callback(self, cb)
User callbacks. 
def zoom_to_area(self, x1, y1, x2, y2)
def __init__(self, parent, id)
def animate_to(self, x, y)
def drag(self, deltax, deltay)
def get_drag_action(self, event)
def OnKeyDown(self, event)
def set_highlight(self, items)
def window2graph(self, x, y)
def on_zoom_in(self, action)
def drag(self, deltax, deltay)
def on_motion_notify(self, event)
def on_button_release(self, event)
def on_zoom_100(self, action)
def get_current_pos(self)
Helper functions. 
def OnResize(self, event)
Event handlers. 
def set_cursor(self, cursor_type)
Cursor manipulation. 
def on_zoom_out(self, action)
def set_current_pos(self, x, y)
def __init__(self, dot_widget)
def drag(self, deltax, deltay)
def OnScroll(self, event)
def on_button_press(self, event)
def drag(self, deltax, deltay)