1ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# general purpose 'tooltip' routines - currently unused in idlefork
2ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# (although the 'calltips' extension is partly based on this code)
3ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# may be useful for some purposes in (or almost in ;) the current project scope
4ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot# Ideas gleaned from PySol
5ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
6ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotfrom Tkinter import *
7ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
8ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass ToolTipBase:
9ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
10ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, button):
11ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.button = button
12ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.tipwindow = None
13ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.id = None
14ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.x = self.y = 0
15ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self._id1 = self.button.bind("<Enter>", self.enter)
16ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self._id2 = self.button.bind("<Leave>", self.leave)
17ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self._id3 = self.button.bind("<ButtonPress>", self.leave)
18ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
19ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def enter(self, event=None):
20ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.schedule()
21ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
22ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def leave(self, event=None):
23ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.unschedule()
24ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.hidetip()
25ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
26ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def schedule(self):
27ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.unschedule()
28ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.id = self.button.after(1500, self.showtip)
29ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
30ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def unschedule(self):
31ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        id = self.id
32ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.id = None
33ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if id:
34ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            self.button.after_cancel(id)
35ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
36ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def showtip(self):
37ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if self.tipwindow:
38ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            return
39ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # The tip window must be completely outside the button;
40ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # otherwise when the mouse enters the tip window we get
41ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # a leave event and it disappears, and then we get an enter
42ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # event and it reappears, and so on forever :-(
43ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        x = self.button.winfo_rootx() + 20
44ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        y = self.button.winfo_rooty() + self.button.winfo_height() + 1
45ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.tipwindow = tw = Toplevel(self.button)
46ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        tw.wm_overrideredirect(1)
47ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        tw.wm_geometry("+%d+%d" % (x, y))
48ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.showcontents()
49ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
50ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def showcontents(self, text="Your text here"):
51ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        # Override this in derived class
52ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        label = Label(self.tipwindow, text=text, justify=LEFT,
53ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot                      background="#ffffe0", relief=SOLID, borderwidth=1)
54ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        label.pack()
55ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
56ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def hidetip(self):
57ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        tw = self.tipwindow
58ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.tipwindow = None
59ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        if tw:
60ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            tw.destroy()
61ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
62ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass ToolTip(ToolTipBase):
63ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, button, text):
64ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        ToolTipBase.__init__(self, button)
65ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.text = text
66ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def showcontents(self):
67ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        ToolTipBase.showcontents(self, self.text)
68ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
69ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotclass ListboxToolTip(ToolTipBase):
70ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def __init__(self, button, items):
71ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        ToolTipBase.__init__(self, button)
72ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        self.items = items
73ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    def showcontents(self):
74ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        listbox = Listbox(self.tipwindow, background="#ffffe0")
75ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        listbox.pack()
76ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot        for item in self.items:
77ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot            listbox.insert(END, item)
78ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
79ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotdef main():
80ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    # Test code
81ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    root = Tk()
82ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    b = Button(root, text="Hello", command=root.destroy)
83ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    b.pack()
84ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    root.update()
85ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    tip = ListboxToolTip(b, ["Hello", "world"])
86ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    root.mainloop()
87ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot
88ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robotif __name__ == '__main__':
89ec1a0b3abe08fb9a3952e8f48231cda1f6d9b1fandroid-build-team Robot    main()
90