- added support for tooltips
- fixed issue related to residual tooltip windows
- added tooltip window resize to label size
See https://github.com/jrfonseca/xdot.py/pull/81
Fixes https://github.com/jrfonseca/xdot.py/issues/71
... | ... |
@@ -491,7 +491,7 @@ class XDotParser(DotParser): |
491 | 491 |
# create a Node object nevertheless, so that any edges to/from it |
492 | 492 |
# don't get lost. |
493 | 493 |
# TODO: Extract the position from subgraph > graph > bb attribute. |
494 |
- node = elements.Node(id, 0.0, 0.0, 0.0, 0.0, [], None) |
|
494 |
+ node = elements.Node(id, 0.0, 0.0, 0.0, 0.0, [], None, None) |
|
495 | 495 |
self.node_by_name[id] = node |
496 | 496 |
return |
497 | 497 |
|
... | ... |
@@ -509,7 +509,7 @@ class XDotParser(DotParser): |
509 | 509 |
url = None |
510 | 510 |
else: |
511 | 511 |
url = url.decode('utf-8') |
512 |
- node = elements.Node(id, x, y, w, h, shapes, url) |
|
512 |
+ node = elements.Node(id, x, y, w, h, shapes, url, attrs.get("tooltip")) |
|
513 | 513 |
self.node_by_name[id] = node |
514 | 514 |
if shapes: |
515 | 515 |
self.nodes.append(node) |
... | ... |
@@ -529,7 +529,7 @@ class XDotParser(DotParser): |
529 | 529 |
if shapes: |
530 | 530 |
src = self.node_by_name[src_id] |
531 | 531 |
dst = self.node_by_name[dst_id] |
532 |
- self.edges.append(elements.Edge(src, dst, points, shapes)) |
|
532 |
+ self.edges.append(elements.Edge(src, dst, points, shapes, attrs.get("tooltip"))) |
|
533 | 533 |
|
534 | 534 |
def parse(self): |
535 | 535 |
DotParser.parse(self) |
... | ... |
@@ -17,7 +17,8 @@ import gi |
17 | 17 |
gi.require_version('Gtk', '3.0') |
18 | 18 |
gi.require_version('PangoCairo', '1.0') |
19 | 19 |
|
20 |
-from gi.repository import Gdk |
|
20 |
+from gi.repository import Gdk, Gtk |
|
21 |
+from xdot.ui.elements import Jump |
|
21 | 22 |
|
22 | 23 |
|
23 | 24 |
class DragAction(object): |
... | ... |
@@ -63,6 +64,12 @@ class DragAction(object): |
63 | 64 |
|
64 | 65 |
|
65 | 66 |
class NullAction(DragAction): |
67 |
+ _tooltip_window = Gtk.Window(Gtk.WindowType.POPUP) |
|
68 |
+ _tooltip_label = Gtk.Label(xalign=0, yalign=0) |
|
69 |
+ _tooltip_item = None |
|
70 |
+ |
|
71 |
+ _tooltip_window.add(_tooltip_label) |
|
72 |
+ _tooltip_label.show() |
|
66 | 73 |
|
67 | 74 |
def on_motion_notify(self, event): |
68 | 75 |
if event.is_hint: |
... | ... |
@@ -76,9 +83,27 @@ class NullAction(DragAction): |
76 | 83 |
if item is not None: |
77 | 84 |
dot_widget.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2)) |
78 | 85 |
dot_widget.set_highlight(item.highlight) |
86 |
+ if item is not NullAction._tooltip_item: |
|
87 |
+ if isinstance(item, Jump) and item.item.tooltip is not None: |
|
88 |
+ NullAction._tooltip_label.set_markup(item.item.tooltip.decode()) |
|
89 |
+ NullAction._tooltip_window.resize( |
|
90 |
+ NullAction._tooltip_label.get_preferred_width().natural_width, |
|
91 |
+ NullAction._tooltip_label.get_preferred_height().natural_height |
|
92 |
+ ) |
|
93 |
+ NullAction._tooltip_window.show() |
|
94 |
+ else: |
|
95 |
+ NullAction._tooltip_window.hide() |
|
96 |
+ NullAction._tooltip_label.set_markup("") |
|
97 |
+ NullAction._tooltip_item = item |
|
98 |
+ if NullAction._tooltip_window.is_visible: |
|
99 |
+ pointer = NullAction._tooltip_window.get_screen().get_root_window().get_pointer() |
|
100 |
+ NullAction._tooltip_window.move(pointer.x + 15, pointer.y + 10) |
|
79 | 101 |
else: |
80 | 102 |
dot_widget.get_window().set_cursor(None) |
81 | 103 |
dot_widget.set_highlight(None) |
104 |
+ NullAction._tooltip_window.hide() |
|
105 |
+ NullAction._tooltip_label.set_markup("") |
|
106 |
+ NullAction._tooltip_item = None |
|
82 | 107 |
|
83 | 108 |
|
84 | 109 |
class PanAction(DragAction): |
... | ... |
@@ -469,7 +469,7 @@ class Element(CompoundShape): |
469 | 469 |
|
470 | 470 |
class Node(Element): |
471 | 471 |
|
472 |
- def __init__(self, id, x, y, w, h, shapes, url): |
|
472 |
+ def __init__(self, id, x, y, w, h, shapes, url, tooltip): |
|
473 | 473 |
Element.__init__(self, shapes) |
474 | 474 |
|
475 | 475 |
self.id = id |
... | ... |
@@ -482,6 +482,7 @@ class Node(Element): |
482 | 482 |
self.y2 = y + 0.5*h |
483 | 483 |
|
484 | 484 |
self.url = url |
485 |
+ self.tooltip = tooltip |
|
485 | 486 |
|
486 | 487 |
def is_inside(self, x, y): |
487 | 488 |
return self.x1 <= x and x <= self.x2 and self.y1 <= y and y <= self.y2 |
... | ... |
@@ -510,11 +511,12 @@ def square_distance(x1, y1, x2, y2): |
510 | 511 |
|
511 | 512 |
class Edge(Element): |
512 | 513 |
|
513 |
- def __init__(self, src, dst, points, shapes): |
|
514 |
+ def __init__(self, src, dst, points, shapes, tooltip): |
|
514 | 515 |
Element.__init__(self, shapes) |
515 | 516 |
self.src = src |
516 | 517 |
self.dst = dst |
517 | 518 |
self.points = points |
519 |
+ self.tooltip = tooltip |
|
518 | 520 |
|
519 | 521 |
RADIUS = 10 |
520 | 522 |
|