annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/calltip_w.py @ 69:33d812a61356

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