]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/python/contrib/Lib/idlelib/CallTipWindow.py
Inital import
[l4.git] / l4 / pkg / python / contrib / Lib / idlelib / CallTipWindow.py
1 """A CallTip window class for Tkinter/IDLE.
2
3 After ToolTip.py, which uses ideas gleaned from PySol
4 Used by the CallTips IDLE extension.
5
6 """
7 from Tkinter import *
8
9 HIDE_VIRTUAL_EVENT_NAME = "<<calltipwindow-hide>>"
10 HIDE_SEQUENCES = ("<Key-Escape>", "<FocusOut>")
11 CHECKHIDE_VIRTUAL_EVENT_NAME = "<<calltipwindow-checkhide>>"
12 CHECKHIDE_SEQUENCES = ("<KeyRelease>", "<ButtonRelease>")
13 CHECKHIDE_TIME = 100 # miliseconds
14
15 MARK_RIGHT = "calltipwindowregion_right"
16
17 class CallTip:
18
19     def __init__(self, widget):
20         self.widget = widget
21         self.tipwindow = self.label = None
22         self.parenline = self.parencol = None
23         self.lastline = None
24         self.hideid = self.checkhideid = None
25
26     def position_window(self):
27         """Check if needs to reposition the window, and if so - do it."""
28         curline = int(self.widget.index("insert").split('.')[0])
29         if curline == self.lastline:
30             return
31         self.lastline = curline
32         self.widget.see("insert")
33         if curline == self.parenline:
34             box = self.widget.bbox("%d.%d" % (self.parenline,
35                                               self.parencol))
36         else:
37             box = self.widget.bbox("%d.0" % curline)
38         if not box:
39             box = list(self.widget.bbox("insert"))
40             # align to left of window
41             box[0] = 0
42             box[2] = 0
43         x = box[0] + self.widget.winfo_rootx() + 2
44         y = box[1] + box[3] + self.widget.winfo_rooty()
45         self.tipwindow.wm_geometry("+%d+%d" % (x, y))
46
47     def showtip(self, text, parenleft, parenright):
48         """Show the calltip, bind events which will close it and reposition it.
49         """
50         # truncate overly long calltip
51         if len(text) >= 79:
52             textlines = text.splitlines()
53             for i, line in enumerate(textlines):
54                 if len(line) > 79:
55                     textlines[i] = line[:75] + ' ...'
56             text = '\n'.join(textlines)
57         self.text = text
58         if self.tipwindow or not self.text:
59             return
60
61         self.widget.mark_set(MARK_RIGHT, parenright)
62         self.parenline, self.parencol = map(
63             int, self.widget.index(parenleft).split("."))
64
65         self.tipwindow = tw = Toplevel(self.widget)
66         self.position_window()
67         # remove border on calltip window
68         tw.wm_overrideredirect(1)
69         try:
70             # This command is only needed and available on Tk >= 8.4.0 for OSX
71             # Without it, call tips intrude on the typing process by grabbing
72             # the focus.
73             tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w,
74                        "help", "noActivates")
75         except TclError:
76             pass
77         self.label = Label(tw, text=self.text, justify=LEFT,
78                            background="#ffffe0", relief=SOLID, borderwidth=1,
79                            font = self.widget['font'])
80         self.label.pack()
81
82         self.checkhideid = self.widget.bind(CHECKHIDE_VIRTUAL_EVENT_NAME,
83                                             self.checkhide_event)
84         for seq in CHECKHIDE_SEQUENCES:
85             self.widget.event_add(CHECKHIDE_VIRTUAL_EVENT_NAME, seq)
86         self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
87         self.hideid = self.widget.bind(HIDE_VIRTUAL_EVENT_NAME,
88                                        self.hide_event)
89         for seq in HIDE_SEQUENCES:
90             self.widget.event_add(HIDE_VIRTUAL_EVENT_NAME, seq)
91
92     def checkhide_event(self, event=None):
93         if not self.tipwindow:
94             # If the event was triggered by the same event that unbinded
95             # this function, the function will be called nevertheless,
96             # so do nothing in this case.
97             return
98         curline, curcol = map(int, self.widget.index("insert").split('.'))
99         if curline < self.parenline or \
100            (curline == self.parenline and curcol <= self.parencol) or \
101            self.widget.compare("insert", ">", MARK_RIGHT):
102             self.hidetip()
103         else:
104             self.position_window()
105             self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
106
107     def hide_event(self, event):
108         if not self.tipwindow:
109             # See the explanation in checkhide_event.
110             return
111         self.hidetip()
112
113     def hidetip(self):
114         if not self.tipwindow:
115             return
116
117         for seq in CHECKHIDE_SEQUENCES:
118             self.widget.event_delete(CHECKHIDE_VIRTUAL_EVENT_NAME, seq)
119         self.widget.unbind(CHECKHIDE_VIRTUAL_EVENT_NAME, self.checkhideid)
120         self.checkhideid = None
121         for seq in HIDE_SEQUENCES:
122             self.widget.event_delete(HIDE_VIRTUAL_EVENT_NAME, seq)
123         self.widget.unbind(HIDE_VIRTUAL_EVENT_NAME, self.hideid)
124         self.hideid = None
125
126         self.label.destroy()
127         self.label = None
128         self.tipwindow.destroy()
129         self.tipwindow = None
130
131         self.widget.mark_unset(MARK_RIGHT)
132         self.parenline = self.parencol = self.lastline = None
133
134     def is_active(self):
135         return bool(self.tipwindow)
136
137
138
139 ###############################
140 #
141 # Test Code
142 #
143 class container: # Conceptually an editor_window
144     def __init__(self):
145         root = Tk()
146         text = self.text = Text(root)
147         text.pack(side=LEFT, fill=BOTH, expand=1)
148         text.insert("insert", "string.split")
149         root.update()
150         self.calltip = CallTip(text)
151
152         text.event_add("<<calltip-show>>", "(")
153         text.event_add("<<calltip-hide>>", ")")
154         text.bind("<<calltip-show>>", self.calltip_show)
155         text.bind("<<calltip-hide>>", self.calltip_hide)
156
157         text.focus_set()
158         root.mainloop()
159
160     def calltip_show(self, event):
161         self.calltip.showtip("Hello world")
162
163     def calltip_hide(self, event):
164         self.calltip.hidetip()
165
166 def main():
167     # Test code
168     c=container()
169
170 if __name__=='__main__':
171     main()