1 """A CallTip window class for Tkinter/IDLE.
3 After ToolTip.py, which uses ideas gleaned from PySol
4 Used by the CallTips IDLE extension.
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
15 MARK_RIGHT
= "calltipwindowregion_right"
19 def __init__(self
, widget
):
21 self
.tipwindow
= self
.label
= None
22 self
.parenline
= self
.parencol
= None
24 self
.hideid
= self
.checkhideid
= None
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
:
31 self
.lastline
= curline
32 self
.widget
.see("insert")
33 if curline
== self
.parenline
:
34 box
= self
.widget
.bbox("%d.%d" % (self
.parenline
,
37 box
= self
.widget
.bbox("%d.0" % curline
)
39 box
= list(self
.widget
.bbox("insert"))
40 # align to left of window
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
))
47 def showtip(self
, text
, parenleft
, parenright
):
48 """Show the calltip, bind events which will close it and reposition it.
50 # truncate overly long calltip
52 textlines
= text
.splitlines()
53 for i
, line
in enumerate(textlines
):
55 textlines
[i
] = line
[:75] + ' ...'
56 text
= '\n'.join(textlines
)
58 if self
.tipwindow
or not self
.text
:
61 self
.widget
.mark_set(MARK_RIGHT
, parenright
)
62 self
.parenline
, self
.parencol
= map(
63 int, self
.widget
.index(parenleft
).split("."))
65 self
.tipwindow
= tw
= Toplevel(self
.widget
)
66 self
.position_window()
67 # remove border on calltip window
68 tw
.wm_overrideredirect(1)
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
73 tw
.tk
.call("::tk::unsupported::MacWindowStyle", "style", tw
._w
,
74 "help", "noActivates")
77 self
.label
= Label(tw
, text
=self
.text
, justify
=LEFT
,
78 background
="#ffffe0", relief
=SOLID
, borderwidth
=1,
79 font
= self
.widget
['font'])
82 self
.checkhideid
= self
.widget
.bind(CHECKHIDE_VIRTUAL_EVENT_NAME
,
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
,
89 for seq
in HIDE_SEQUENCES
:
90 self
.widget
.event_add(HIDE_VIRTUAL_EVENT_NAME
, seq
)
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.
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
):
104 self
.position_window()
105 self
.widget
.after(CHECKHIDE_TIME
, self
.checkhide_event
)
107 def hide_event(self
, event
):
108 if not self
.tipwindow
:
109 # See the explanation in checkhide_event.
114 if not self
.tipwindow
:
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
)
128 self
.tipwindow
.destroy()
129 self
.tipwindow
= None
131 self
.widget
.mark_unset(MARK_RIGHT
)
132 self
.parenline
= self
.parencol
= self
.lastline
= None
135 return bool(self
.tipwindow
)
139 ###############################
143 class container
: # Conceptually an editor_window
146 text
= self
.text
= Text(root
)
147 text
.pack(side
=LEFT
, fill
=BOTH
, expand
=1)
148 text
.insert("insert", "string.split")
150 self
.calltip
= CallTip(text
)
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
)
160 def calltip_show(self
, event
):
161 self
.calltip
.showtip("Hello world")
163 def calltip_hide(self
, event
):
164 self
.calltip
.hidetip()
170 if __name__
=='__main__':