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