Browse code

Support "outputorder" attribute when drawing.

https://github.com/jrfonseca/xdot.py/pull/68

Tal Ben-Nun authored on 10/03/2019 16:55:23 • Jose Fonseca committed on 05/04/2019 12:56:33
Showing 3 changed files

1 1
new file mode 100644
... ...
@@ -0,0 +1,14 @@
1
+digraph draworder {
2
+	outputorder=nodesfirst;
3
+	size ="8.5, 11";
4
+	0 [shape = circle, style = filled, color = lightgrey ];
5
+	2 [ shape = trapezium, style = filled, color = lightgrey, label = <
6
+	     <table border='0' cellborder='0'>
7
+	            <tr><td port='a'>A</td><td port='b'>B</td></tr>
8
+		    <tr><td colspan='2'>Some label goes here</td></tr>
9
+	     </table>
10
+	>];
11
+
12
+	0 -> 2:a [ label = "a" ];
13
+	0 -> 2:b [ label = "b" ];
14
+}
... ...
@@ -437,6 +437,7 @@ class XDotParser(DotParser):
437 437
         self.top_graph = True
438 438
         self.width = 0
439 439
         self.height = 0
440
+        self.outputorder = 'breadthfirst'
440 441
 
441 442
     def handle_graph(self, attrs):
442 443
         if self.top_graph:
... ...
@@ -450,6 +451,12 @@ class XDotParser(DotParser):
450 451
                     sys.stderr.write('warning: xdot version %s, but supported is %s\n' %
451 452
                                      (xdotversion, self.XDOTVERSION))
452 453
 
454
+            # Parse output order
455
+            try:
456
+                self.outputorder = attrs['outputorder'].decode('utf-8')
457
+            except KeyError:
458
+                pass
459
+
453 460
             # Parse bounding box
454 461
             try:
455 462
                 bb = attrs['bb']
... ...
@@ -526,7 +533,7 @@ class XDotParser(DotParser):
526 533
     def parse(self):
527 534
         DotParser.parse(self)
528 535
         return elements.Graph(self.width, self.height, self.shapes,
529
-                              self.nodes, self.edges)
536
+                              self.nodes, self.edges, self.outputorder)
530 537
 
531 538
     def parse_node_pos(self, pos):
532 539
         x, y = pos.split(b",")
... ...
@@ -544,7 +544,7 @@ class Edge(Element):
544 544
 
545 545
 class Graph(Shape):
546 546
 
547
-    def __init__(self, width=1, height=1, shapes=(), nodes=(), edges=()):
547
+    def __init__(self, width=1, height=1, shapes=(), nodes=(), edges=(), outputorder='breadthfirst'):
548 548
         Shape.__init__(self)
549 549
 
550 550
         self.width = width
... ...
@@ -552,6 +552,7 @@ class Graph(Shape):
552 552
         self.shapes = shapes
553 553
         self.nodes = nodes
554 554
         self.edges = edges
555
+        self.outputorder = outputorder
555 556
 
556 557
         self.bounding = Shape._envelope_bounds(
557 558
             map(_get_bounding, self.shapes),
... ...
@@ -561,6 +562,23 @@ class Graph(Shape):
561 562
     def get_size(self):
562 563
         return self.width, self.height
563 564
 
565
+    def _draw_shapes(self, cr, bounding):
566
+        for shape in self.shapes:
567
+            if bounding is None or shape._intersects(bounding):
568
+                shape._draw(cr, highlight=False, bounding=bounding)
569
+
570
+    def _draw_nodes(self, cr, bounding, highlight_items):
571
+        for node in self.nodes:
572
+            if bounding is None or node._intersects(bounding):
573
+                node._draw(cr, highlight=(node in highlight_items), bounding=bounding)
574
+
575
+    def _draw_edges(self, cr, bounding, highlight_items):
576
+        for edge in self.edges:
577
+            if bounding is None or edge._intersects(bounding):
578
+                should_highlight = any(e in highlight_items
579
+                                       for e in (edge, edge.src, edge.dst))
580
+                edge._draw(cr, highlight=should_highlight, bounding=bounding)
581
+
564 582
     def draw(self, cr, highlight_items=None, bounding=None):
565 583
         if bounding is not None:
566 584
             if not self._intersects(bounding):
... ...
@@ -575,17 +593,13 @@ class Graph(Shape):
575 593
         cr.set_line_cap(cairo.LINE_CAP_BUTT)
576 594
         cr.set_line_join(cairo.LINE_JOIN_MITER)
577 595
 
578
-        for shape in self.shapes:
579
-            if bounding is None or shape._intersects(bounding):
580
-                shape._draw(cr, highlight=False, bounding=bounding)
581
-        for edge in self.edges:
582
-            if bounding is None or edge._intersects(bounding):
583
-                should_highlight = any(e in highlight_items
584
-                                       for e in (edge, edge.src, edge.dst))
585
-                edge._draw(cr, highlight=should_highlight, bounding=bounding)
586
-        for node in self.nodes:
587
-            if bounding is None or node._intersects(bounding):
588
-                node._draw(cr, highlight=(node in highlight_items), bounding=bounding)
596
+        self._draw_shapes(cr, bounding)
597
+        if self.outputorder == 'edgesfirst':
598
+            self._draw_edges(cr, bounding, highlight_items)
599
+            self._draw_nodes(cr, bounding, highlight_items)
600
+        else:
601
+            self._draw_nodes(cr, bounding, highlight_items)
602
+            self._draw_edges(cr, bounding, highlight_items)
589 603
 
590 604
     def get_element(self, x, y):
591 605
         for node in self.nodes: