~ubuntu-branches/ubuntu/trusty/python3.4/trusty-proposed

« back to all changes in this revision

Viewing changes to Lib/idlelib/CallTipWindow.py

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-11-25 09:44:27 UTC
  • Revision ID: package-import@ubuntu.com-20131125094427-lzxj8ap5w01lmo7f
Tags: upstream-3.4~b1
ImportĀ upstreamĀ versionĀ 3.4~b1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""A CallTip window class for Tkinter/IDLE.
 
2
 
 
3
After ToolTip.py, which uses ideas gleaned from PySol
 
4
Used by the CallTips IDLE extension.
 
5
 
 
6
"""
 
7
from tkinter import *
 
8
 
 
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
 
14
 
 
15
MARK_RIGHT = "calltipwindowregion_right"
 
16
 
 
17
class CallTip:
 
18
 
 
19
    def __init__(self, widget):
 
20
        self.widget = widget
 
21
        self.tipwindow = self.label = None
 
22
        self.parenline = self.parencol = None
 
23
        self.lastline = None
 
24
        self.hideid = self.checkhideid = None
 
25
        self.checkhide_after_id = None
 
26
 
 
27
    def position_window(self):
 
28
        """Check if needs to reposition the window, and if so - do it."""
 
29
        curline = int(self.widget.index("insert").split('.')[0])
 
30
        if curline == self.lastline:
 
31
            return
 
32
        self.lastline = curline
 
33
        self.widget.see("insert")
 
34
        if curline == self.parenline:
 
35
            box = self.widget.bbox("%d.%d" % (self.parenline,
 
36
                                              self.parencol))
 
37
        else:
 
38
            box = self.widget.bbox("%d.0" % curline)
 
39
        if not box:
 
40
            box = list(self.widget.bbox("insert"))
 
41
            # align to left of window
 
42
            box[0] = 0
 
43
            box[2] = 0
 
44
        x = box[0] + self.widget.winfo_rootx() + 2
 
45
        y = box[1] + box[3] + self.widget.winfo_rooty()
 
46
        self.tipwindow.wm_geometry("+%d+%d" % (x, y))
 
47
 
 
48
    def showtip(self, text, parenleft, parenright):
 
49
        """Show the calltip, bind events which will close it and reposition it.
 
50
        """
 
51
        # truncate overly long calltip
 
52
        if len(text) >= 79:
 
53
            textlines = text.splitlines()
 
54
            for i, line in enumerate(textlines):
 
55
                if len(line) > 79:
 
56
                    textlines[i] = line[:75] + ' ...'
 
57
            text = '\n'.join(textlines)
 
58
        self.text = text
 
59
        if self.tipwindow or not self.text:
 
60
            return
 
61
 
 
62
        self.widget.mark_set(MARK_RIGHT, parenright)
 
63
        self.parenline, self.parencol = map(
 
64
            int, self.widget.index(parenleft).split("."))
 
65
 
 
66
        self.tipwindow = tw = Toplevel(self.widget)
 
67
        self.position_window()
 
68
        # remove border on calltip window
 
69
        tw.wm_overrideredirect(1)
 
70
        try:
 
71
            # This command is only needed and available on Tk >= 8.4.0 for OSX
 
72
            # Without it, call tips intrude on the typing process by grabbing
 
73
            # the focus.
 
74
            tw.tk.call("::tk::unsupported::MacWindowStyle", "style", tw._w,
 
75
                       "help", "noActivates")
 
76
        except TclError:
 
77
            pass
 
78
        self.label = Label(tw, text=self.text, justify=LEFT,
 
79
                           background="#ffffe0", relief=SOLID, borderwidth=1,
 
80
                           font = self.widget['font'])
 
81
        self.label.pack()
 
82
 
 
83
        self.checkhideid = self.widget.bind(CHECKHIDE_VIRTUAL_EVENT_NAME,
 
84
                                            self.checkhide_event)
 
85
        for seq in CHECKHIDE_SEQUENCES:
 
86
            self.widget.event_add(CHECKHIDE_VIRTUAL_EVENT_NAME, seq)
 
87
        self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
 
88
        self.hideid = self.widget.bind(HIDE_VIRTUAL_EVENT_NAME,
 
89
                                       self.hide_event)
 
90
        for seq in HIDE_SEQUENCES:
 
91
            self.widget.event_add(HIDE_VIRTUAL_EVENT_NAME, seq)
 
92
 
 
93
    def checkhide_event(self, event=None):
 
94
        if not self.tipwindow:
 
95
            # If the event was triggered by the same event that unbinded
 
96
            # this function, the function will be called nevertheless,
 
97
            # so do nothing in this case.
 
98
            return
 
99
        curline, curcol = map(int, self.widget.index("insert").split('.'))
 
100
        if curline < self.parenline or \
 
101
           (curline == self.parenline and curcol <= self.parencol) or \
 
102
           self.widget.compare("insert", ">", MARK_RIGHT):
 
103
            self.hidetip()
 
104
        else:
 
105
            self.position_window()
 
106
            if self.checkhide_after_id is not None:
 
107
                self.widget.after_cancel(self.checkhide_after_id)
 
108
            self.checkhide_after_id = \
 
109
                self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
 
110
 
 
111
    def hide_event(self, event):
 
112
        if not self.tipwindow:
 
113
            # See the explanation in checkhide_event.
 
114
            return
 
115
        self.hidetip()
 
116
 
 
117
    def hidetip(self):
 
118
        if not self.tipwindow:
 
119
            return
 
120
 
 
121
        for seq in CHECKHIDE_SEQUENCES:
 
122
            self.widget.event_delete(CHECKHIDE_VIRTUAL_EVENT_NAME, seq)
 
123
        self.widget.unbind(CHECKHIDE_VIRTUAL_EVENT_NAME, self.checkhideid)
 
124
        self.checkhideid = None
 
125
        for seq in HIDE_SEQUENCES:
 
126
            self.widget.event_delete(HIDE_VIRTUAL_EVENT_NAME, seq)
 
127
        self.widget.unbind(HIDE_VIRTUAL_EVENT_NAME, self.hideid)
 
128
        self.hideid = None
 
129
 
 
130
        self.label.destroy()
 
131
        self.label = None
 
132
        self.tipwindow.destroy()
 
133
        self.tipwindow = None
 
134
 
 
135
        self.widget.mark_unset(MARK_RIGHT)
 
136
        self.parenline = self.parencol = self.lastline = None
 
137
 
 
138
    def is_active(self):
 
139
        return bool(self.tipwindow)
 
140
 
 
141
 
 
142
 
 
143
###############################
 
144
#
 
145
# Test Code
 
146
#
 
147
class container: # Conceptually an editor_window
 
148
    def __init__(self):
 
149
        root = Tk()
 
150
        text = self.text = Text(root)
 
151
        text.pack(side=LEFT, fill=BOTH, expand=1)
 
152
        text.insert("insert", "string.split")
 
153
        root.update()
 
154
        self.calltip = CallTip(text)
 
155
 
 
156
        text.event_add("<<calltip-show>>", "(")
 
157
        text.event_add("<<calltip-hide>>", ")")
 
158
        text.bind("<<calltip-show>>", self.calltip_show)
 
159
        text.bind("<<calltip-hide>>", self.calltip_hide)
 
160
 
 
161
        text.focus_set()
 
162
        root.mainloop()
 
163
 
 
164
    def calltip_show(self, event):
 
165
        self.calltip.showtip("Hello world")
 
166
 
 
167
    def calltip_hide(self, event):
 
168
        self.calltip.hidetip()
 
169
 
 
170
def main():
 
171
    # Test code
 
172
    c=container()
 
173
 
 
174
if __name__=='__main__':
 
175
    main()