Merged 0.51.1 branch
[zeroinstall/zeroinstall-afb.git] / zeroinstall / gtkui / treetips.py
blob084781f00fd7c30c0897b0a4a6b90efa89217184
1 """Add tooltips to a TreeView."""
2 # Copyright (C) 2009, Thomas Leonard
3 # See the README file for details, or visit http://0install.net.
5 from zeroinstall import _
6 import time, gobject, gtk
8 class TreeTips:
9 """This object allows you to set location-dependent tooltips on a TreeView.
10 Connect your TreeView's leave-notify-event to the L{hide} method.
11 In your motion-notify-event handler, call L{prime} when the pointer moves
12 to an area with a new message. The message will be shown after a delay.
13 If calculation of the message is expensive, override L{get_tooltip_text}
14 instead.
15 """
16 timeout = None
17 widget = None
18 item = None
19 time = 0
21 def show(self, parent):
22 if self.timeout:
23 gobject.source_remove(self.timeout)
24 self.timeout = None
26 if self.widget:
27 self.widget.destroy()
28 self.widget = None
30 if self.item is None:
31 return
33 text = self.get_tooltip_text()
34 if not text:
35 return
37 self.widget = gtk.Window(gtk.WINDOW_POPUP)
38 self.widget.set_app_paintable(True)
39 self.widget.set_name('gtk-tooltips')
41 self.widget.connect('expose-event', self.tooltip_draw)
43 label = gtk.Label(text)
44 label.set_line_wrap(True)
45 label.set_padding(4, 2)
46 self.widget.add(label)
47 label.show()
49 w, h = self.widget.size_request()
50 if hasattr(parent, 'get_screen'):
51 screen = parent.get_screen()
52 root = screen.get_root_window()
53 else:
54 root = gtk.gdk.get_default_root_window()
55 px, py, mask = gtk.gdk.Window.get_pointer(root)
57 #m = gtk.gdk.screen_get_default().get_monitor_at_point(px, py)
59 x = px - w / 2
60 y = py + 12
62 # Test if pointer is over the tooltip window
63 if py >= y and py <= y + h:
64 y = py - h - 2
65 self.widget.move(x, y)
66 self.widget.show()
68 self.widget.connect('destroy', self.tooltip_destroyed)
69 self.time = time.time()
71 def prime(self, parent, item):
72 """Call this whenever the pointer moves to an area with a different
73 tooltip.
74 @param parent: the TreeView widget
75 @param item: the text to display
76 @see L{get_tooltip_text}"""
77 self.hide()
78 assert self.timeout is None
79 self.item = item
81 now = time.time()
82 if now - self.time > 2:
83 delay = 1000
84 else:
85 delay = 100
87 self.timeout = gobject.timeout_add(delay, lambda: self.show(parent))
89 def tooltip_draw(self, widget, ev):
90 widget.window.draw_rectangle(widget.style.fg_gc[widget.state],
91 False, 0, 0,
92 widget.allocation.width - 1,
93 widget.allocation.height - 1)
95 def tooltip_destroyed(self, widget):
96 pass
98 def hide(self):
99 """Hide the tooltip, if any.
100 Sets L{item} to None."""
101 self.item = None
102 self.show(None)
104 def get_tooltip_text(self):
105 """"Converts the object passed to L{prime} to a string for display.
106 The default implementation just calls C{str}, but subclasses can override it.
107 @return: the tooltip message"""
108 return str(self.item)