32 from distutils.version
import LooseVersion
35 if sys.version_info[0] >= 3:
38 __all__ = [
'WxDotWindow',
'WxDotFrame']
43 if wxversion.checkInstalled(
"2.8"):
44 wxversion.select(
"2.8")
46 print(
"wxversion 2.8 is not installed, installed versions are {}".format(wxversion.getInstalled()))
51 import wx.lib.wxcairo
as wxcairo
55 if 'wxMac' in wx.PlatformInfo:
57 elif 'wxMSW' in wx.PlatformInfo:
59 elif 'wxGTK' in wx.PlatformInfo:
61 gdkLib = wx.lib.wxcairo._findGDKLib()
62 gdkLib.gdk_cairo_create.restype = ctypes.c_void_p
69 XDotParser.__init__(self,xdotcode)
73 shapes_before = set(self.
shapes)
75 id = XDotParser.parse_subgraph(self)
77 new_shapes = set(self.
shapes) - shapes_before
83 graph = XDotParser.parse(self)
92 x,y = event.GetPosition()
98 x,y = event.GetPosition()
101 self.
drag(deltax, deltay)
106 x,y = event.GetPosition()
117 def drag(self, deltax, deltay):
126 class WxNullAction(WxDragAction):
130 class WxPanAction(WxDragAction):
134 def drag(self, deltax, deltay):
145 def drag(self, deltax, deltay):
146 self.
dot_widget.zoom_ratio *= 1.005 ** (deltax + deltay)
154 def drag(self, deltax, deltay):
159 cr.set_source_rgba(.5, .5, 1.0, 0.25)
164 cr.set_source_rgba(.5, .5, 1.0, 1.0)
183 """wxpython Frame that draws dot graphs."""
188 wx.Panel.__init__(self, parent, id)
193 self.
x, self.
y = 0.0, 0.0
202 self.Bind(wx.EVT_PAINT, self.
OnPaint)
203 self.Bind(wx.EVT_SIZE, self.
OnResize)
205 self.Bind(wx.EVT_MOUSEWHEEL, self.
OnScroll)
207 self.Bind(wx.EVT_MOUSE_EVENTS, self.
OnMouse)
209 self.Bind(wx.EVT_KEY_DOWN, self.
OnKeyDown)
226 """Redraw the graph."""
227 dc = wx.PaintDC(self)
230 ctx = wxcairo.ContextFromDC(dc)
236 width, height = self.GetSize()
239 ctx.rectangle(0,0,width,height)
242 ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0)
246 ctx.translate(0.5*width, 0.5*height)
249 ctx.translate(-self.
x, -self.
y)
257 if event.GetWheelRotation() > 0:
259 pos=(event.GetX(), event.GetY()))
262 pos=(event.GetX(), event.GetY()))
265 """Process key down event."""
266 key = event.GetKeyCode()
267 if key == wx.WXK_LEFT:
270 if key == wx.WXK_RIGHT:
276 if key == wx.WXK_DOWN:
279 if key == wx.WXK_PAGEUP:
282 if key == wx.WXK_PAGEDOWN:
285 if key == wx.WXK_ESCAPE:
298 """Get the current graph position."""
299 return self.
x, self.
y
302 """Set the current graph position."""
308 """Set a number of items to be hilighted."""
315 if LooseVersion(wx.__version__) >= LooseVersion(
'4.0'):
318 self.
cursor = wx.StockCursor(cursor_type)
319 self.SetCursor(self.
cursor)
323 """Zoom the graph."""
325 self.
x = self.
graph.width/2
326 self.
y = self.
graph.height/2
327 elif pos
is not None:
328 width, height = self.GetSize()
339 """Zoom to an area of the graph."""
340 width, height = self.GetSize()
341 area_width = abs(x1 - x2)
342 area_height = abs(y1 - y2)
344 float(width)/float(area_width),
345 float(height)/float(area_height)
348 self.
x = (x1 + x2) / 2
349 self.
y = (y1 + y2) / 2
353 """Zoom to fit the size of the graph."""
354 width,height = self.GetSize()
360 if float(self.
graph.width) > 0
and float(self.
graph.height) > 0
and width > 0
and height > 0:
362 float(width)/float(self.
graph.width),
363 float(height)/float(self.
graph.height)
368 ZOOM_INCREMENT = 1.25
369 ZOOM_TO_FIT_MARGIN = 12
386 """Get a drag action for this click."""
388 button = event.GetButton()
390 control_down = event.ControlDown()
391 alt_down = event.AltDown()
392 shift_down = event.ShiftDown()
394 drag = event.Dragging()
395 motion = event.Moving()
398 if button
in (wx.MOUSE_BTN_LEFT, wx.MOUSE_BTN_MIDDLE):
410 x,y = event.GetPosition()
415 if not event.Dragging():
431 if event.ButtonDown():
442 if event.Dragging()
or event.Moving():
461 "Get the x,y coordinates in the graph from the x,y coordinates in the window."""
462 width, height = self.GetSize()
484 if sys.version_info[0] < 3
and isinstance(dotcode, unicode):
485 dotcode = dotcode.encode(
'utf8')
486 p = subprocess.Popen(
488 stdin=subprocess.PIPE,
489 stdout=subprocess.PIPE,
490 stderr=subprocess.PIPE,
492 universal_newlines=
True
494 xdotcode, error = p.communicate(dotcode)
495 if p.returncode != 0:
496 print(
"ERROR PARSING DOT CODE {}".format(error))
497 dialog = Gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
498 message_format=error,
499 buttons=gtk.BUTTONS_OK)
500 dialog.set_title(
'Dot Viewer')
509 for item
in self.
graph.nodes:
510 if item.url
is not None:
516 except ParseError
as ex:
517 print(
"ERROR PARSING XDOT CODE")
518 dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
519 message_format=str(ex),
520 buttons=gtk.BUTTONS_OK)
521 dialog.set_title(
'Dot Viewer')
532 if sys.version_info[0] >= 3:
536 self.
graph = parser.parse()
552 wx.Frame.__init__(self,
None, -1,
"Dot Viewer", size=(512,512))
554 vbox = wx.BoxSizer(wx.VERTICAL)
557 toolbar = wx.ToolBar(self, -1)
558 toolbar.AddLabelTool(wx.ID_OPEN,
'Open File',
559 wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN,wx.ART_OTHER,(16,16)))
560 toolbar.AddLabelTool(wx.ID_HELP,
'Help',
561 wx.ArtProvider.GetBitmap(wx.ART_HELP,wx.ART_OTHER,(16,16)) )
564 self.Bind(wx.EVT_TOOL, self.
DoOpenFile, id=wx.ID_OPEN)
571 vbox.Add(toolbar, 0, wx.EXPAND)
572 vbox.Add(self.
widget, 100, wx.EXPAND | wx.ALL)
578 dial = wx.MessageDialog(
None,
581 Zoom: PageUp / PageDown\n\
584 'Keyboard Controls', wx.OK)
588 wcd =
'All files (*)|*|GraphViz Dot Files(*.dot)|*.dot|'
590 open_dlg = wx.FileDialog(self, message=
'Choose a file', defaultDir=dir, defaultFile=
'',
591 wildcard=wcd, style=wx.OPEN|wx.CHANGE_DIR)
592 if open_dlg.ShowModal() == wx.ID_OK:
593 path = open_dlg.GetPath()
598 except IOError
as error:
599 dlg = wx.MessageDialog(self,
'Error opening file\n' + str(error))
602 except UnicodeDecodeError
as error:
603 dlg = wx.MessageDialog(self,
'Error opening file\n' + str(error))
613 self.SetTitle(os.path.basename(filename) +
' - Dot Viewer')
614 self.widget.zoom_to_fit()
618 self.SetTitle(os.path.basename(filename) +
' - Dot Viewer')
623 fp = file(filename,
'rt')
626 except IOError
as ex:
628 dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
629 message_format=str(ex),
630 buttons=gtk.BUTTONS_OK)
631 dlg.set_title('Dot Viewer')