14adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# general purpose 'tooltip' routines - currently unused in idlefork
24adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# (although the 'calltips' extension is partly based on this code)
34adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# may be useful for some purposes in (or almost in ;) the current project scope
44adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao# Ideas gleaned from PySol
54adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
64adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaofrom Tkinter import *
74adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
84adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass ToolTipBase:
94adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
104adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, button):
114adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.button = button
124adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.tipwindow = None
134adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.id = None
144adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.x = self.y = 0
154adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._id1 = self.button.bind("<Enter>", self.enter)
164adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._id2 = self.button.bind("<Leave>", self.leave)
174adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self._id3 = self.button.bind("<ButtonPress>", self.leave)
184adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
194adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def enter(self, event=None):
204adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.schedule()
214adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
224adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def leave(self, event=None):
234adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.unschedule()
244adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.hidetip()
254adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
264adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def schedule(self):
274adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.unschedule()
284adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.id = self.button.after(1500, self.showtip)
294adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
304adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def unschedule(self):
314adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        id = self.id
324adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.id = None
334adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if id:
344adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            self.button.after_cancel(id)
354adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
364adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def showtip(self):
374adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if self.tipwindow:
384adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            return
394adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # The tip window must be completely outside the button;
404adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # otherwise when the mouse enters the tip window we get
414adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # a leave event and it disappears, and then we get an enter
424adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # event and it reappears, and so on forever :-(
434adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        x = self.button.winfo_rootx() + 20
444adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        y = self.button.winfo_rooty() + self.button.winfo_height() + 1
454adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.tipwindow = tw = Toplevel(self.button)
464adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        tw.wm_overrideredirect(1)
474adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        tw.wm_geometry("+%d+%d" % (x, y))
484adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.showcontents()
494adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
504adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def showcontents(self, text="Your text here"):
514adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        # Override this in derived class
524adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        label = Label(self.tipwindow, text=text, justify=LEFT,
534adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao                      background="#ffffe0", relief=SOLID, borderwidth=1)
544adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        label.pack()
554adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
564adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def hidetip(self):
574adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        tw = self.tipwindow
584adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.tipwindow = None
594adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        if tw:
604adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            tw.destroy()
614adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
624adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass ToolTip(ToolTipBase):
634adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, button, text):
644adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ToolTipBase.__init__(self, button)
654adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.text = text
664adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def showcontents(self):
674adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ToolTipBase.showcontents(self, self.text)
684adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
694adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoclass ListboxToolTip(ToolTipBase):
704adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def __init__(self, button, items):
714adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        ToolTipBase.__init__(self, button)
724adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        self.items = items
734adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    def showcontents(self):
744adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        listbox = Listbox(self.tipwindow, background="#ffffe0")
754adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        listbox.pack()
764adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao        for item in self.items:
774adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao            listbox.insert(END, item)
784adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
794adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaodef main():
804adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    # Test code
814adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    root = Tk()
824adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    b = Button(root, text="Hello", command=root.destroy)
834adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    b.pack()
844adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    root.update()
854adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    tip = ListboxToolTip(b, ["Hello", "world"])
864adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    root.mainloop()
874adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao
884adfde8bc82dd39f59e0445588c3e599ada477dJosh Gaoif __name__ == '__main__':
894adfde8bc82dd39f59e0445588c3e599ada477dJosh Gao    main()
90