Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/calltip_w.py @ 68:5028fdace37b
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 16:23:26 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 68:5028fdace37b |
---|---|
1 """A call-tip window class for Tkinter/IDLE. | |
2 | |
3 After tooltip.py, which uses ideas gleaned from PySol. | |
4 Used by calltip.py. | |
5 """ | |
6 from tkinter import Label, LEFT, SOLID, TclError | |
7 | |
8 from idlelib.tooltip import TooltipBase | |
9 | |
10 HIDE_EVENT = "<<calltipwindow-hide>>" | |
11 HIDE_SEQUENCES = ("<Key-Escape>", "<FocusOut>") | |
12 CHECKHIDE_EVENT = "<<calltipwindow-checkhide>>" | |
13 CHECKHIDE_SEQUENCES = ("<KeyRelease>", "<ButtonRelease>") | |
14 CHECKHIDE_TIME = 100 # milliseconds | |
15 | |
16 MARK_RIGHT = "calltipwindowregion_right" | |
17 | |
18 | |
19 class CalltipWindow(TooltipBase): | |
20 """A call-tip widget for tkinter text widgets.""" | |
21 | |
22 def __init__(self, text_widget): | |
23 """Create a call-tip; shown by showtip(). | |
24 | |
25 text_widget: a Text widget with code for which call-tips are desired | |
26 """ | |
27 # Note: The Text widget will be accessible as self.anchor_widget | |
28 super(CalltipWindow, self).__init__(text_widget) | |
29 | |
30 self.label = self.text = None | |
31 self.parenline = self.parencol = self.lastline = None | |
32 self.hideid = self.checkhideid = None | |
33 self.checkhide_after_id = None | |
34 | |
35 def get_position(self): | |
36 """Choose the position of the call-tip.""" | |
37 curline = int(self.anchor_widget.index("insert").split('.')[0]) | |
38 if curline == self.parenline: | |
39 anchor_index = (self.parenline, self.parencol) | |
40 else: | |
41 anchor_index = (curline, 0) | |
42 box = self.anchor_widget.bbox("%d.%d" % anchor_index) | |
43 if not box: | |
44 box = list(self.anchor_widget.bbox("insert")) | |
45 # align to left of window | |
46 box[0] = 0 | |
47 box[2] = 0 | |
48 return box[0] + 2, box[1] + box[3] | |
49 | |
50 def position_window(self): | |
51 "Reposition the window if needed." | |
52 curline = int(self.anchor_widget.index("insert").split('.')[0]) | |
53 if curline == self.lastline: | |
54 return | |
55 self.lastline = curline | |
56 self.anchor_widget.see("insert") | |
57 super(CalltipWindow, self).position_window() | |
58 | |
59 def showtip(self, text, parenleft, parenright): | |
60 """Show the call-tip, bind events which will close it and reposition it. | |
61 | |
62 text: the text to display in the call-tip | |
63 parenleft: index of the opening parenthesis in the text widget | |
64 parenright: index of the closing parenthesis in the text widget, | |
65 or the end of the line if there is no closing parenthesis | |
66 """ | |
67 # Only called in calltip.Calltip, where lines are truncated | |
68 self.text = text | |
69 if self.tipwindow or not self.text: | |
70 return | |
71 | |
72 self.anchor_widget.mark_set(MARK_RIGHT, parenright) | |
73 self.parenline, self.parencol = map( | |
74 int, self.anchor_widget.index(parenleft).split(".")) | |
75 | |
76 super(CalltipWindow, self).showtip() | |
77 | |
78 self._bind_events() | |
79 | |
80 def showcontents(self): | |
81 """Create the call-tip widget.""" | |
82 self.label = Label(self.tipwindow, text=self.text, justify=LEFT, | |
83 background="#ffffd0", foreground="black", | |
84 relief=SOLID, borderwidth=1, | |
85 font=self.anchor_widget['font']) | |
86 self.label.pack() | |
87 | |
88 def checkhide_event(self, event=None): | |
89 """Handle CHECK_HIDE_EVENT: call hidetip or reschedule.""" | |
90 if not self.tipwindow: | |
91 # If the event was triggered by the same event that unbound | |
92 # this function, the function will be called nevertheless, | |
93 # so do nothing in this case. | |
94 return None | |
95 | |
96 # Hide the call-tip if the insertion cursor moves outside of the | |
97 # parenthesis. | |
98 curline, curcol = map(int, self.anchor_widget.index("insert").split('.')) | |
99 if curline < self.parenline or \ | |
100 (curline == self.parenline and curcol <= self.parencol) or \ | |
101 self.anchor_widget.compare("insert", ">", MARK_RIGHT): | |
102 self.hidetip() | |
103 return "break" | |
104 | |
105 # Not hiding the call-tip. | |
106 | |
107 self.position_window() | |
108 # Re-schedule this function to be called again in a short while. | |
109 if self.checkhide_after_id is not None: | |
110 self.anchor_widget.after_cancel(self.checkhide_after_id) | |
111 self.checkhide_after_id = \ | |
112 self.anchor_widget.after(CHECKHIDE_TIME, self.checkhide_event) | |
113 return None | |
114 | |
115 def hide_event(self, event): | |
116 """Handle HIDE_EVENT by calling hidetip.""" | |
117 if not self.tipwindow: | |
118 # See the explanation in checkhide_event. | |
119 return None | |
120 self.hidetip() | |
121 return "break" | |
122 | |
123 def hidetip(self): | |
124 """Hide the call-tip.""" | |
125 if not self.tipwindow: | |
126 return | |
127 | |
128 try: | |
129 self.label.destroy() | |
130 except TclError: | |
131 pass | |
132 self.label = None | |
133 | |
134 self.parenline = self.parencol = self.lastline = None | |
135 try: | |
136 self.anchor_widget.mark_unset(MARK_RIGHT) | |
137 except TclError: | |
138 pass | |
139 | |
140 try: | |
141 self._unbind_events() | |
142 except (TclError, ValueError): | |
143 # ValueError may be raised by MultiCall | |
144 pass | |
145 | |
146 super(CalltipWindow, self).hidetip() | |
147 | |
148 def _bind_events(self): | |
149 """Bind event handlers.""" | |
150 self.checkhideid = self.anchor_widget.bind(CHECKHIDE_EVENT, | |
151 self.checkhide_event) | |
152 for seq in CHECKHIDE_SEQUENCES: | |
153 self.anchor_widget.event_add(CHECKHIDE_EVENT, seq) | |
154 self.anchor_widget.after(CHECKHIDE_TIME, self.checkhide_event) | |
155 self.hideid = self.anchor_widget.bind(HIDE_EVENT, | |
156 self.hide_event) | |
157 for seq in HIDE_SEQUENCES: | |
158 self.anchor_widget.event_add(HIDE_EVENT, seq) | |
159 | |
160 def _unbind_events(self): | |
161 """Unbind event handlers.""" | |
162 for seq in CHECKHIDE_SEQUENCES: | |
163 self.anchor_widget.event_delete(CHECKHIDE_EVENT, seq) | |
164 self.anchor_widget.unbind(CHECKHIDE_EVENT, self.checkhideid) | |
165 self.checkhideid = None | |
166 for seq in HIDE_SEQUENCES: | |
167 self.anchor_widget.event_delete(HIDE_EVENT, seq) | |
168 self.anchor_widget.unbind(HIDE_EVENT, self.hideid) | |
169 self.hideid = None | |
170 | |
171 | |
172 def _calltip_window(parent): # htest # | |
173 from tkinter import Toplevel, Text, LEFT, BOTH | |
174 | |
175 top = Toplevel(parent) | |
176 top.title("Test call-tips") | |
177 x, y = map(int, parent.geometry().split('+')[1:]) | |
178 top.geometry("250x100+%d+%d" % (x + 175, y + 150)) | |
179 text = Text(top) | |
180 text.pack(side=LEFT, fill=BOTH, expand=1) | |
181 text.insert("insert", "string.split") | |
182 top.update() | |
183 | |
184 calltip = CalltipWindow(text) | |
185 def calltip_show(event): | |
186 calltip.showtip("(s='Hello world')", "insert", "end") | |
187 def calltip_hide(event): | |
188 calltip.hidetip() | |
189 text.event_add("<<calltip-show>>", "(") | |
190 text.event_add("<<calltip-hide>>", ")") | |
191 text.bind("<<calltip-show>>", calltip_show) | |
192 text.bind("<<calltip-hide>>", calltip_hide) | |
193 | |
194 text.focus_set() | |
195 | |
196 if __name__ == '__main__': | |
197 from unittest import main | |
198 main('idlelib.idle_test.test_calltip_w', verbosity=2, exit=False) | |
199 | |
200 from idlelib.idle_test.htest import run | |
201 run(_calltip_window) |