Ticket #41: ToolTip.py

File ToolTip.py, 3.9 KB (added by davidkofler, 15 years ago)

The tooltip class

Line 
1class ToolTip:
2
3        def __init__(self, master, text='No informations found', delay=1500, **opts):
4                self.master = master
5                self._opts = {'anchor':'center', 'bd':1, 'bg':'lightyellow', 'delay':delay, 'fg':'black',\
6                      'follow_mouse':0, 'font':None, 'justify':'left', 'padx':4, 'pady':2,\
7                      'relief':'solid', 'state':'normal', 'text':text, 'textvariable':None,\
8                      'width':0, 'wraplength':150}
9                self.configure(**opts)
10                self._tipwindow = None
11                self._id = None
12                self._id1 = self.master.bind("<Enter>", self.enter, '+')
13                self._id2 = self.master.bind("<Leave>", self.leave, '+')
14                self._id3 = self.master.bind("<ButtonPress>", self.leave, '+')
15                self._follow_mouse = 0
16                if self._opts['follow_mouse']:
17                        self._id4 = self.master.bind("<Motion>", self.motion, '+')
18                        self._follow_mouse = 1
19
20        def configure(self, **opts):
21                for key in opts:
22                        if self._opts.has_key(key):
23                                self._opts[key] = opts[key]
24                        else:
25                                KeyError = 'KeyError: Unknown option: "%s"' %key
26                                raise KeyError
27
28        ## These methods handle the callbacks on "<Enter>", "<Leave>" and "<Motion>" ##
29        ## Events on the parent widget; override them if you want to change the widget's behavior--##
30
31        def enter(self, event=None):
32                self._schedule()
33
34        def leave(self, event=None):
35                self._unschedule()
36                self._hide()
37
38        def motion(self, event=None):
39                if self._tipwindow and self._follow_mouse:
40                        x, y = self.coords()
41                        self._tipwindow.wm_geometry("+%d+%d" % (x, y))
42
43        ## The methods that do the work ##
44
45        def _schedule(self):
46                self._unschedule()
47                if self._opts['state'] == 'disabled':
48                        return
49                self._id = self.master.after(self._opts['delay'], self._show)
50
51        def _unschedule(self):
52                id = self._id
53                self._id = None
54                if id:
55                        self.master.after_cancel(id)
56
57        def _show(self):
58                if self._opts['state'] == 'disabled':
59                        self._unschedule()
60                        return
61                if not self._tipwindow:
62                        self._tipwindow = tw = Tkinter.Toplevel(self.master)
63                        # Hide the window until we know the geometry
64                        tw.withdraw()
65                        tw.wm_overrideredirect(1)
66
67                        if tw.tk.call("tk", "windowingsystem") == 'aqua':
68                                tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w, "help", "none")
69
70                        self.create_contents()
71                        tw.update_idletasks()
72                        x, y = self.coords()
73                        tw.wm_geometry("+%d+%d" % (x, y))
74                        tw.deiconify()
75
76        def _hide(self):
77                tw = self._tipwindow
78                self._tipwindow = None
79                if tw:
80                        tw.destroy()
81
82        ## These methods might be overridden in derived classes ##
83
84        def coords(self):
85                # The tip window must be completely outside the master widget;
86                # otherwise when the mouse enters the tip window we get
87                # a leave event and it disappears, and then we get an enter
88                # event and it reappears, and so on forever
89                # or we take care that the mouse pointer is always outside the tipwindow
90                tw = self._tipwindow
91                twx, twy = tw.winfo_reqwidth(), tw.winfo_reqheight()
92                w, h = tw.winfo_screenwidth(), tw.winfo_screenheight()
93                # Calculate the y coordinate
94                if self._follow_mouse:
95                        y = tw.winfo_pointery() + 20
96                        # Make sure the tipwindow is never outside the screen
97                        if y + twy > h:
98                                y = y - twy - 30
99                else:
100                        y = self.master.winfo_rooty() + self.master.winfo_height() + 3
101                        if y + twy > h:
102                                y = self.master.winfo_rooty() - twy - 3
103                # We can use the same x coordinate in both cases
104                x = tw.winfo_pointerx() - twx / 2
105                if x < 0:
106                        x = 0
107                elif x + twx > w:
108                        x = w - twx
109                return x, y
110
111        def create_contents(self):
112                opts = self._opts.copy()
113                for opt in ('delay', 'follow_mouse', 'state'):
114                        del opts[opt]
115                label = Tkinter.Label(self._tipwindow, **opts)
116                label.pack()
117
118        ## This method generates the informations about the site ##
119
120        def get_info(url):
121                o = urlparse(url)
122                return ('Network location: ' + o.netloc + '\n' +
123                                'Path: ' + o.path + '\n' +
124                                'Parameters: ' + o.params + '\n' +
125                                'Query: ' + o.query + '\n' +
126                                'Fragment: ' + o.fragment + '\n' +
127                                'Username: ' + o.username + '\n' +
128                                'Host name: ' + o.hostname + '\n' +
129                                'Port: ' + o.port + '\n')