Browse code

Fix tooltip on Wayland

On Wayland, the following is logged into console and no tooltip is visible or it is displayed at the top left:

Gdk-Message: 06:04:40.431: Window 0x252d550 is a temporary window without parent, application will not be able to position it on screen.

Jan Tojnar authored on 27/11/2021 05:17:47 • José Fonseca committed on 27/11/2021 11:11:28
Showing 1 changed files
... ...
@@ -84,6 +84,7 @@ class NullAction(DragAction):
84 84
         if item is None:
85 85
             item = dot_widget.get_jump(x, y)
86 86
         if item is not None:
87
+            NullAction._tooltip_window.set_transient_for(dot_widget.get_toplevel())
87 88
             dot_widget.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2))
88 89
             dot_widget.set_highlight(item.highlight)
89 90
             if item is not NullAction._tooltip_item:
Browse code

Use Gtk.Window.new

Fixes https://github.com/jrfonseca/xdot.py/issues/84

John Vandenberg authored on 08/12/2020 04:16:32 • José Fonseca committed on 08/12/2020 10:42:12
Showing 1 changed files
... ...
@@ -67,7 +67,7 @@ class NullAction(DragAction):
67 67
 
68 68
     # FIXME: The NullAction class is probably not the best place to hold this
69 69
     # sort mutable global state.
70
-    _tooltip_window = Gtk.Window(Gtk.WindowType.POPUP)
70
+    _tooltip_window = Gtk.Window.new(Gtk.WindowType.POPUP)
71 71
     _tooltip_label = Gtk.Label(xalign=0, yalign=0)
72 72
     _tooltip_item = None
73 73
 
Browse code

Add some FIXME/TODO remarks.

See discussion https://github.com/jrfonseca/xdot.py/pull/81

Jose Fonseca authored on 17/08/2020 12:37:04
Showing 1 changed files
... ...
@@ -64,6 +64,9 @@ class DragAction(object):
64 64
 
65 65
 
66 66
 class NullAction(DragAction):
67
+
68
+    # FIXME: The NullAction class is probably not the best place to hold this
69
+    # sort mutable global state.
67 70
     _tooltip_window = Gtk.Window(Gtk.WindowType.POPUP)
68 71
     _tooltip_label = Gtk.Label(xalign=0, yalign=0)
69 72
     _tooltip_item = None
... ...
@@ -84,6 +87,7 @@ class NullAction(DragAction):
84 87
             dot_widget.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2))
85 88
             dot_widget.set_highlight(item.highlight)
86 89
             if item is not NullAction._tooltip_item:
90
+                # TODO: Should fold this into a method.
87 91
                 if isinstance(item, Jump) and item.item.tooltip is not None:
88 92
                     NullAction._tooltip_label.set_markup(item.item.tooltip.decode())
89 93
                     NullAction._tooltip_window.resize(
Browse code

Add support for tooltips.

- 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

notEvil authored on 06/07/2020 09:29:39 • Jose Fonseca committed on 20/07/2020 11:07:52
Showing 1 changed files
... ...
@@ -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):
Browse code

Cleaner splitting into separate modules

Peter Hill authored on 02/07/2016 09:45:05 • Jose Fonseca committed on 10/07/2016 08:40:15
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,139 @@
1
+# Copyright 2008-2015 Jose Fonseca
2
+#
3
+# This program is free software: you can redistribute it and/or modify it
4
+# under the terms of the GNU Lesser General Public License as published
5
+# by the Free Software Foundation, either version 3 of the License, or
6
+# (at your option) any later version.
7
+#
8
+# This program is distributed in the hope that it will be useful,
9
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+# GNU Lesser General Public License for more details.
12
+#
13
+# You should have received a copy of the GNU Lesser General Public License
14
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
+#
16
+import gi
17
+gi.require_version('Gtk', '3.0')
18
+gi.require_version('PangoCairo', '1.0')
19
+
20
+from gi.repository import Gdk
21
+
22
+
23
+class DragAction(object):
24
+
25
+    def __init__(self, dot_widget):
26
+        self.dot_widget = dot_widget
27
+
28
+    def on_button_press(self, event):
29
+        self.startmousex = self.prevmousex = event.x
30
+        self.startmousey = self.prevmousey = event.y
31
+        self.start()
32
+
33
+    def on_motion_notify(self, event):
34
+        if event.is_hint:
35
+            window, x, y, state = event.window.get_device_position(event.device)
36
+        else:
37
+            x, y, state = event.x, event.y, event.state
38
+        deltax = self.prevmousex - x
39
+        deltay = self.prevmousey - y
40
+        self.drag(deltax, deltay)
41
+        self.prevmousex = x
42
+        self.prevmousey = y
43
+
44
+    def on_button_release(self, event):
45
+        self.stopmousex = event.x
46
+        self.stopmousey = event.y
47
+        self.stop()
48
+
49
+    def draw(self, cr):
50
+        pass
51
+
52
+    def start(self):
53
+        pass
54
+
55
+    def drag(self, deltax, deltay):
56
+        pass
57
+
58
+    def stop(self):
59
+        pass
60
+
61
+    def abort(self):
62
+        pass
63
+
64
+
65
+class NullAction(DragAction):
66
+
67
+    def on_motion_notify(self, event):
68
+        if event.is_hint:
69
+            window, x, y, state = event.window.get_device_position(event.device)
70
+        else:
71
+            x, y, state = event.x, event.y, event.state
72
+        dot_widget = self.dot_widget
73
+        item = dot_widget.get_url(x, y)
74
+        if item is None:
75
+            item = dot_widget.get_jump(x, y)
76
+        if item is not None:
77
+            dot_widget.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2))
78
+            dot_widget.set_highlight(item.highlight)
79
+        else:
80
+            dot_widget.get_window().set_cursor(None)
81
+            dot_widget.set_highlight(None)
82
+
83
+
84
+class PanAction(DragAction):
85
+
86
+    def start(self):
87
+        self.dot_widget.get_window().set_cursor(Gdk.Cursor(Gdk.CursorType.FLEUR))
88
+
89
+    def drag(self, deltax, deltay):
90
+        self.dot_widget.x += deltax / self.dot_widget.zoom_ratio
91
+        self.dot_widget.y += deltay / self.dot_widget.zoom_ratio
92
+        self.dot_widget.queue_draw()
93
+
94
+    def stop(self):
95
+        self.dot_widget.get_window().set_cursor(None)
96
+
97
+    abort = stop
98
+
99
+
100
+class ZoomAction(DragAction):
101
+
102
+    def drag(self, deltax, deltay):
103
+        self.dot_widget.zoom_ratio *= 1.005 ** (deltax + deltay)
104
+        self.dot_widget.zoom_to_fit_on_resize = False
105
+        self.dot_widget.queue_draw()
106
+
107
+    def stop(self):
108
+        self.dot_widget.queue_draw()
109
+
110
+
111
+class ZoomAreaAction(DragAction):
112
+
113
+    def drag(self, deltax, deltay):
114
+        self.dot_widget.queue_draw()
115
+
116
+    def draw(self, cr):
117
+        cr.save()
118
+        cr.set_source_rgba(.5, .5, 1.0, 0.25)
119
+        cr.rectangle(self.startmousex, self.startmousey,
120
+                     self.prevmousex - self.startmousex,
121
+                     self.prevmousey - self.startmousey)
122
+        cr.fill()
123
+        cr.set_source_rgba(.5, .5, 1.0, 1.0)
124
+        cr.set_line_width(1)
125
+        cr.rectangle(self.startmousex - .5, self.startmousey - .5,
126
+                     self.prevmousex - self.startmousex + 1,
127
+                     self.prevmousey - self.startmousey + 1)
128
+        cr.stroke()
129
+        cr.restore()
130
+
131
+    def stop(self):
132
+        x1, y1 = self.dot_widget.window2graph(self.startmousex,
133
+                                              self.startmousey)
134
+        x2, y2 = self.dot_widget.window2graph(self.stopmousex,
135
+                                              self.stopmousey)
136
+        self.dot_widget.zoom_to_area(x1, y1, x2, y2)
137
+
138
+    def abort(self):
139
+        self.dot_widget.queue_draw()