Browse code

Highlight the node under mouse.

Refactor get_url/get_jump methods to return objects instead of values.

Add infrastructure for indicating whether shapes and elements ought to
be highlighted or not. Only EllipseShape implements it now.

Add infrastructure for selecting the graph item to be highlighted.

From: Marius Gedminas <marius@gedmin.as>

Jose.R.Fonseca authored on 13/07/2008 03:21:57
Showing 1 changed files

  • xdot.py index 9e133e4..dd8a9e1 100755
... ...
@@ -68,6 +68,12 @@ class Pen:
68 68
         pen.__dict__ = self.__dict__.copy()
69 69
         return pen
70 70
 
71
+    def highlighted(self):
72
+        pen = self.copy()
73
+        pen.color = (1, 0, 0, 1)
74
+        pen.fillcolor = (.7, .2, .2, 1)
75
+        return pen
76
+
71 77
 
72 78
 class Shape:
73 79
     """Abstract base class for all the drawing shapes."""
... ...
@@ -75,7 +81,7 @@ class Shape:
75 81
     def __init__(self):
76 82
         pass
77 83
 
78
-    def draw(self, cr):
84
+    def draw(self, cr, highlight=False):
79 85
         """Draw this shape with the given cairo context"""
80 86
         raise NotImplementedError
81 87
 
... ...
@@ -97,7 +103,7 @@ class TextShape(Shape):
97 103
         self.w = w
98 104
         self.t = t
99 105
 
100
-    def draw(self, cr):
106
+    def draw(self, cr, highlight=False):
101 107
 
102 108
         try:
103 109
             layout = self.layout
... ...
@@ -181,26 +187,31 @@ class EllipseShape(Shape):
181 187
     def __init__(self, pen, x0, y0, w, h, filled=False):
182 188
         Shape.__init__(self)
183 189
         self.pen = pen.copy()
190
+        self.highlight_pen = pen.highlighted()
184 191
         self.x0 = x0
185 192
         self.y0 = y0
186 193
         self.w = w
187 194
         self.h = h
188 195
         self.filled = filled
189 196
 
190
-    def draw(self, cr):
197
+    def draw(self, cr, highlight=False):
191 198
         cr.save()
192 199
         cr.translate(self.x0, self.y0)
193 200
         cr.scale(self.w, self.h)
194 201
         cr.move_to(1.0, 0.0)
195 202
         cr.arc(0.0, 0.0, 1.0, 0, 2.0*math.pi)
196 203
         cr.restore()
204
+        if highlight:
205
+            pen = self.highlight_pen
206
+        else:
207
+            pen = self.pen
197 208
         if self.filled:
198
-            cr.set_source_rgba(*self.pen.fillcolor)
209
+            cr.set_source_rgba(*pen.fillcolor)
199 210
             cr.fill()
200 211
         else:
201
-            cr.set_dash(self.pen.dash)
202
-            cr.set_line_width(self.pen.linewidth)
203
-            cr.set_source_rgba(*self.pen.color)
212
+            cr.set_dash(pen.dash)
213
+            cr.set_line_width(pen.linewidth)
214
+            cr.set_source_rgba(*pen.color)
204 215
             cr.stroke()
205 216
 
206 217
 
... ...
@@ -212,7 +223,7 @@ class PolygonShape(Shape):
212 223
         self.points = points
213 224
         self.filled = filled
214 225
 
215
-    def draw(self, cr):
226
+    def draw(self, cr, highlight=False):
216 227
         x0, y0 = self.points[-1]
217 228
         cr.move_to(x0, y0)
218 229
         for x, y in self.points:
... ...
@@ -236,7 +247,7 @@ class BezierShape(Shape):
236 247
         self.pen = pen.copy()
237 248
         self.points = points
238 249
 
239
-    def draw(self, cr):
250
+    def draw(self, cr, highlight=False):
240 251
         x0, y0 = self.points[0]
241 252
         cr.move_to(x0, y0)
242 253
         for i in xrange(1, len(self.points), 3):
... ...
@@ -256,9 +267,24 @@ class CompoundShape(Shape):
256 267
         Shape.__init__(self)
257 268
         self.shapes = shapes
258 269
 
259
-    def draw(self, cr):
270
+    def draw(self, cr, highlight=False):
260 271
         for shape in self.shapes:
261
-            shape.draw(cr)
272
+            shape.draw(cr, highlight=highlight)
273
+
274
+
275
+class Url(object):
276
+
277
+    def __init__(self, item, url):
278
+        self.item = item
279
+        self.url = url
280
+
281
+
282
+class Jump(object):
283
+
284
+    def __init__(self, item, x, y):
285
+        self.item = item
286
+        self.x = x
287
+        self.y = y
262 288
 
263 289
 
264 290
 class Element(CompoundShape):
... ...
@@ -297,12 +323,12 @@ class Node(Element):
297 323
             return None
298 324
         #print (x, y), (self.x1, self.y1), "-", (self.x2, self.y2)
299 325
         if self.is_inside(x, y):
300
-            return self.url
326
+            return Url(self, self.url)
301 327
         return None
302 328
 
303 329
     def get_jump(self, x, y):
304 330
         if self.is_inside(x, y):
305
-            return self.x, self.y
331
+            return Jump(self, self.x, self.y)
306 332
         return None
307 333
 
308 334
 
... ...
@@ -323,9 +349,9 @@ class Edge(Element):
323 349
 
324 350
     def get_jump(self, x, y):
325 351
         if square_distance(x, y, *self.points[0]) <= self.RADIUS*self.RADIUS:
326
-            return self.points[-1]
352
+            return Jump(self, *self.points[-1])
327 353
         if square_distance(x, y, *self.points[-1]) <= self.RADIUS*self.RADIUS:
328
-            return self.points[0]
354
+            return Jump(self, *self.points[0])
329 355
         return None
330 356
 
331 357
 
... ...
@@ -342,16 +368,16 @@ class Graph(Shape):
342 368
     def get_size(self):
343 369
         return self.width, self.height
344 370
 
345
-    def draw(self, cr):
371
+    def draw(self, cr, highlight_item=None):
346 372
         cr.set_source_rgba(0.0, 0.0, 0.0, 1.0)
347 373
 
348 374
         cr.set_line_cap(cairo.LINE_CAP_BUTT)
349 375
         cr.set_line_join(cairo.LINE_JOIN_MITER)
350 376
 
351 377
         for edge in self.edges:
352
-            edge.draw(cr)
378
+            edge.draw(cr, highlight=(edge is highlight_item))
353 379
         for node in self.nodes:
354
-            node.draw(cr)
380
+            node.draw(cr, highlight=(node is highlight_item))
355 381
 
356 382
     def get_url(self, x, y):
357 383
         for node in self.nodes:
... ...
@@ -730,12 +756,15 @@ class NullAction(DragAction):
730 756
 
731 757
     def on_motion_notify(self, event):
732 758
         dot_widget = self.dot_widget
733
-        if dot_widget.get_url(event.x, event.y) is not None:
759
+        item = dot_widget.get_url(event.x, event.y)
760
+        if item is None:
761
+            item = dot_widget.get_jump(event.x, event.y)
762
+        if item is not None:
734 763
             dot_widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
735
-        elif dot_widget.get_jump(event.x, event.y) is not None:
736
-            dot_widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1))
764
+            dot_widget.set_highlight(item.item)
737 765
         else:
738 766
             dot_widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.ARROW))
767
+            dot_widget.set_highlight(None)
739 768
 
740 769
 
741 770
 class PanAction(DragAction):
... ...
@@ -824,6 +853,7 @@ class DotWidget(gtk.DrawingArea):
824 853
         self.animation = NoAnimation(self)
825 854
         self.drag_action = NullAction(self)
826 855
         self.presstime = None
856
+        self.highlight = None
827 857
 
828 858
     def set_dotcode(self, dotcode):
829 859
         p = subprocess.Popen(
... ...
@@ -861,7 +891,7 @@ class DotWidget(gtk.DrawingArea):
861 891
         cr.scale(self.zoom_ratio, self.zoom_ratio)
862 892
         cr.translate(-self.x, -self.y)
863 893
 
864
-        self.graph.draw(cr)
894
+        self.graph.draw(cr, highlight_item=self.highlight)
865 895
         cr.restore()
866 896
 
867 897
         self.drag_action.draw(cr)
... ...
@@ -876,6 +906,11 @@ class DotWidget(gtk.DrawingArea):
876 906
         self.y = y
877 907
         self.queue_draw()
878 908
 
909
+    def set_highlight(self, item):
910
+        if self.highlight != item:
911
+            self.highlight = item
912
+            self.queue_draw()
913
+
879 914
     def zoom_image(self, zoom_ratio, center=False):
880 915
         if center:
881 916
             self.x = self.graph.width/2
... ...
@@ -988,12 +1023,11 @@ class DotWidget(gtk.DrawingArea):
988 1023
             x, y = int(event.x), int(event.y)
989 1024
             url = self.get_url(x, y)
990 1025
             if url is not None:
991
-                self.emit('clicked', unicode(url), event)
1026
+                self.emit('clicked', unicode(url.url), event)
992 1027
             else:
993 1028
                 jump = self.get_jump(x, y)
994 1029
                 if jump is not None:
995
-                    jumpx, jumpy = jump
996
-                    self.animate_to(jumpx, jumpy)
1030
+                    self.animate_to(jump.x, jump.y)
997 1031
 
998 1032
             return True
999 1033
         if event.button == 1 or event.button == 2: