- 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 |
|