ยปCore Development>Code coverage>Lib/idlelib/calltip_w.py

Python code coverage for Lib/idlelib/calltip_w.py

#countcontent
1n/a"""A CallTip window class for Tkinter/IDLE.
2n/a
3n/aAfter tooltip.py, which uses ideas gleaned from PySol
4n/aUsed by the calltips IDLE extension.
5n/a"""
6n/afrom tkinter import Toplevel, Label, LEFT, SOLID, TclError
7n/a
8n/aHIDE_VIRTUAL_EVENT_NAME = "<<calltipwindow-hide>>"
9n/aHIDE_SEQUENCES = ("<Key-Escape>", "<FocusOut>")
10n/aCHECKHIDE_VIRTUAL_EVENT_NAME = "<<calltipwindow-checkhide>>"
11n/aCHECKHIDE_SEQUENCES = ("<KeyRelease>", "<ButtonRelease>")
12n/aCHECKHIDE_TIME = 100 # milliseconds
13n/a
14n/aMARK_RIGHT = "calltipwindowregion_right"
15n/a
16n/aclass CallTip:
17n/a
18n/a def __init__(self, widget):
19n/a self.widget = widget
20n/a self.tipwindow = self.label = None
21n/a self.parenline = self.parencol = None
22n/a self.lastline = None
23n/a self.hideid = self.checkhideid = None
24n/a self.checkhide_after_id = None
25n/a
26n/a def position_window(self):
27n/a """Check if needs to reposition the window, and if so - do it."""
28n/a curline = int(self.widget.index("insert").split('.')[0])
29n/a if curline == self.lastline:
30n/a return
31n/a self.lastline = curline
32n/a self.widget.see("insert")
33n/a if curline == self.parenline:
34n/a box = self.widget.bbox("%d.%d" % (self.parenline,
35n/a self.parencol))
36n/a else:
37n/a box = self.widget.bbox("%d.0" % curline)
38n/a if not box:
39n/a box = list(self.widget.bbox("insert"))
40n/a # align to left of window
41n/a box[0] = 0
42n/a box[2] = 0
43n/a x = box[0] + self.widget.winfo_rootx() + 2
44n/a y = box[1] + box[3] + self.widget.winfo_rooty()
45n/a self.tipwindow.wm_geometry("+%d+%d" % (x, y))
46n/a
47n/a def showtip(self, text, parenleft, parenright):
48n/a """Show the calltip, bind events which will close it and reposition it.
49n/a """
50n/a # Only called in CallTips, where lines are truncated
51n/a self.text = text
52n/a if self.tipwindow or not self.text:
53n/a return
54n/a
55n/a self.widget.mark_set(MARK_RIGHT, parenright)
56n/a self.parenline, self.parencol = map(
57n/a int, self.widget.index(parenleft).split("."))
58n/a
59n/a self.tipwindow = tw = Toplevel(self.widget)
60n/a self.position_window()
61n/a # remove border on calltip window
62n/a tw.wm_overrideredirect(1)
63n/a try:
64n/a # This command is only needed and available on Tk >= 8.4.0 for OSX
65n/a # Without it, call tips intrude on the typing process by grabbing
66n/a # the focus.
67n/a tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w,
68n/a "help", "noActivates")
69n/a except TclError:
70n/a pass
71n/a self.label = Label(tw, text=self.text, justify=LEFT,
72n/a background="#ffffe0", relief=SOLID, borderwidth=1,
73n/a font = self.widget['font'])
74n/a self.label.pack()
75n/a tw.lift() # work around bug in Tk 8.5.18+ (issue #24570)
76n/a
77n/a self.checkhideid = self.widget.bind(CHECKHIDE_VIRTUAL_EVENT_NAME,
78n/a self.checkhide_event)
79n/a for seq in CHECKHIDE_SEQUENCES:
80n/a self.widget.event_add(CHECKHIDE_VIRTUAL_EVENT_NAME, seq)
81n/a self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
82n/a self.hideid = self.widget.bind(HIDE_VIRTUAL_EVENT_NAME,
83n/a self.hide_event)
84n/a for seq in HIDE_SEQUENCES:
85n/a self.widget.event_add(HIDE_VIRTUAL_EVENT_NAME, seq)
86n/a
87n/a def checkhide_event(self, event=None):
88n/a if not self.tipwindow:
89n/a # If the event was triggered by the same event that unbinded
90n/a # this function, the function will be called nevertheless,
91n/a # so do nothing in this case.
92n/a return
93n/a curline, curcol = map(int, self.widget.index("insert").split('.'))
94n/a if curline < self.parenline or \
95n/a (curline == self.parenline and curcol <= self.parencol) or \
96n/a self.widget.compare("insert", ">", MARK_RIGHT):
97n/a self.hidetip()
98n/a else:
99n/a self.position_window()
100n/a if self.checkhide_after_id is not None:
101n/a self.widget.after_cancel(self.checkhide_after_id)
102n/a self.checkhide_after_id = \
103n/a self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
104n/a
105n/a def hide_event(self, event):
106n/a if not self.tipwindow:
107n/a # See the explanation in checkhide_event.
108n/a return
109n/a self.hidetip()
110n/a
111n/a def hidetip(self):
112n/a if not self.tipwindow:
113n/a return
114n/a
115n/a for seq in CHECKHIDE_SEQUENCES:
116n/a self.widget.event_delete(CHECKHIDE_VIRTUAL_EVENT_NAME, seq)
117n/a self.widget.unbind(CHECKHIDE_VIRTUAL_EVENT_NAME, self.checkhideid)
118n/a self.checkhideid = None
119n/a for seq in HIDE_SEQUENCES:
120n/a self.widget.event_delete(HIDE_VIRTUAL_EVENT_NAME, seq)
121n/a self.widget.unbind(HIDE_VIRTUAL_EVENT_NAME, self.hideid)
122n/a self.hideid = None
123n/a
124n/a self.label.destroy()
125n/a self.label = None
126n/a self.tipwindow.destroy()
127n/a self.tipwindow = None
128n/a
129n/a self.widget.mark_unset(MARK_RIGHT)
130n/a self.parenline = self.parencol = self.lastline = None
131n/a
132n/a def is_active(self):
133n/a return bool(self.tipwindow)
134n/a
135n/a
136n/adef _calltip_window(parent): # htest #
137n/a from tkinter import Toplevel, Text, LEFT, BOTH
138n/a
139n/a top = Toplevel(parent)
140n/a top.title("Test calltips")
141n/a x, y = map(int, parent.geometry().split('+')[1:])
142n/a top.geometry("200x100+%d+%d" % (x + 250, y + 175))
143n/a text = Text(top)
144n/a text.pack(side=LEFT, fill=BOTH, expand=1)
145n/a text.insert("insert", "string.split")
146n/a top.update()
147n/a calltip = CallTip(text)
148n/a
149n/a def calltip_show(event):
150n/a calltip.showtip("(s=Hello world)", "insert", "end")
151n/a def calltip_hide(event):
152n/a calltip.hidetip()
153n/a text.event_add("<<calltip-show>>", "(")
154n/a text.event_add("<<calltip-hide>>", ")")
155n/a text.bind("<<calltip-show>>", calltip_show)
156n/a text.bind("<<calltip-hide>>", calltip_hide)
157n/a text.focus_set()
158n/a
159n/aif __name__=='__main__':
160n/a from idlelib.idle_test.htest import run
161n/a run(_calltip_window)