2005-03-15 Richard Taylor <rjt-gramps@thegrindstone.me.uk>
* src/Makefile.am : Added TreeTip.py to list of installed modules. * src/TreeTip.py: New module that implements tooltips on TreeView rows. * src/plugins/Makefile.am: Added ScratchPad.py and scratchpad.glade. * src/plugins/ScratchPad.py: New module to implement a scratch pad for temporary storage of drag and drop objects. * src/plugins/scratchpad.glade: New glade file for ScratchPad window. svn: r4184
This commit is contained in:
248
src/TreeTips.py
Normal file
248
src/TreeTips.py
Normal file
@ -0,0 +1,248 @@
|
||||
# File: treetips.py
|
||||
# Author: Toshio Kuratomi <toshio@tiki-lounge.com>
|
||||
# Date: 6 April, 2004
|
||||
# Copyright: Toshio Kuratomi
|
||||
# License: GPL
|
||||
# Id: $Id$
|
||||
"""A tooltip class for TreeViews
|
||||
"""
|
||||
__revision__ = "$Rev$"
|
||||
|
||||
|
||||
#
|
||||
# Support for text markup added: March 05 - rjt-gramps <at> thegrindstone.me.uk
|
||||
#
|
||||
|
||||
import gtk
|
||||
import gobject
|
||||
|
||||
class TreeTips(gtk.Widget):
|
||||
''' A tooltips widget specialized to work with gtk.TreeView's.
|
||||
|
||||
TreeTips associates a column in a TreeStore with tooltips that will be
|
||||
displayed when the mouse is over the row the column is for. Each row can
|
||||
have one treetip.
|
||||
'''
|
||||
__gproperties__ = {
|
||||
'tip_window' : (gobject.TYPE_PYOBJECT,
|
||||
'The window that the tooltip is displayed in.',
|
||||
'The window that the tooltip is displayed in.',
|
||||
gobject.PARAM_READABLE),
|
||||
'tip_label' : (gobject.TYPE_PYOBJECT,
|
||||
'The label that displays the tooltip text.',
|
||||
'The label that displays the tooltip text.',
|
||||
gobject.PARAM_READABLE),
|
||||
'active_tips_data' : (gobject.TYPE_PYOBJECT,
|
||||
'The data associated with the active tooltip.',
|
||||
'The data associated with the active tooltip.',
|
||||
gobject.PARAM_READABLE),
|
||||
'delay' : (gobject.TYPE_INT,
|
||||
'MSecs before displaying the tooltip.',
|
||||
'The delay between the mouse pausing over the widget and the display of the tooltip in msec.',
|
||||
0, 60000, 500,
|
||||
gobject.PARAM_READWRITE),
|
||||
'enabled' : (gobject.TYPE_BOOLEAN,
|
||||
'If TRUE the tooltips are enabled',
|
||||
'If TRUE the tooltips are enabled',
|
||||
True,
|
||||
gobject.PARAM_READABLE),
|
||||
'view' : (gobject.TYPE_PYOBJECT,
|
||||
'gtk.TreeView that we get our data from.',
|
||||
'The tip data comes from a column in a gtk.TreeView.',
|
||||
gobject.PARAM_READWRITE),
|
||||
'column' : (gobject.TYPE_INT,
|
||||
'Column from the gtk.TreeView that holds tip data.',
|
||||
'The tip data for each row is held by a column in the row. This specifies which column that data is in.',
|
||||
0, 32000, 0,
|
||||
gobject.PARAM_READWRITE),
|
||||
'markup_enabled' : (gobject.TYPE_BOOLEAN,
|
||||
'If TRUE the tooltips are in Pango Markup',
|
||||
'If TRUE the tooltips are in Pango Markup',
|
||||
False,
|
||||
gobject.PARAM_READWRITE),
|
||||
|
||||
}
|
||||
|
||||
def __init__(self, treeview=None, column=None, markup_enabled=False):
|
||||
'''Create a new TreeTips Group.
|
||||
|
||||
:Parameters:
|
||||
treeview : gtk.TreeView === Treeview for which the tips display,
|
||||
default is None.
|
||||
column : integer === Column id in the Treemodel holding the treetip
|
||||
text, default is None.
|
||||
markup_enabled : bool === If True the tooltips are in Pango Markup,
|
||||
if False the tooltips are in plain text.
|
||||
'''
|
||||
if treeview:
|
||||
try:
|
||||
treeview.connect('leave-notify-event', self.__tree_leave_notify)
|
||||
treeview.connect('motion-notify-event', self.__tree_motion_notify)
|
||||
except (AttributeError, TypeError):
|
||||
raise TypeError, ('The value of view must be an object that'
|
||||
'implements leave-notify-event and motion-notify-event '
|
||||
'gsignals such as gtk.TreeStore.')
|
||||
|
||||
gobject.GObject.__init__(self)
|
||||
|
||||
self.view = treeview or None
|
||||
self.delay = 500
|
||||
self.enabled = True
|
||||
self.column = column or 0
|
||||
self.markup_enabled = markup_enabled
|
||||
self.tip_window = gtk.Window(gtk.WINDOW_POPUP)
|
||||
self.tip_window.set_app_paintable(True)
|
||||
self.tip_window.set_border_width(4)
|
||||
self.tip_window.connect('expose-event', self.__paint_window)
|
||||
self.tip_label = gtk.Label('')
|
||||
self.tip_label.set_line_wrap(True)
|
||||
self.tip_label.set_alignment(0.5, 0.5)
|
||||
self.active_tips_data = ''
|
||||
self.tip_window.add(self.tip_label)
|
||||
self.unique = 1 # Unique number used for timeouts
|
||||
self.timeoutID = 0
|
||||
self.path = None
|
||||
self.screenWidth = gtk.gdk.screen_width()
|
||||
self.screenHeight = gtk.gdk.screen_height()
|
||||
|
||||
def enable(self):
|
||||
'''Enable showing of tooltips'''
|
||||
self.enabled = True
|
||||
|
||||
def disable(self):
|
||||
'''Disable showing tooltips'''
|
||||
self.enabled = False
|
||||
|
||||
def do_get_property(self, prop):
|
||||
'''Return the gproperty's value.'''
|
||||
if prop.name == 'delay':
|
||||
return self.delay
|
||||
elif prop.name == 'enabled':
|
||||
return self.enabled
|
||||
elif prop.name == 'view':
|
||||
return self.view
|
||||
elif prop.name == 'column':
|
||||
return self.column
|
||||
elif prop.name == 'active-tips-data':
|
||||
return self.active_tips_data
|
||||
elif prop.name == 'tip-label':
|
||||
return self.tip_label
|
||||
elif prop.name == 'tip-window':
|
||||
return self.tip_window
|
||||
elif prop.name == 'markup_enabled':
|
||||
return self.markup_enabled
|
||||
else:
|
||||
raise AttributeError, 'unknown property %s' % prop.name
|
||||
|
||||
def do_set_property(self, prop, value):
|
||||
'''Set the property of writable properties.
|
||||
|
||||
'''
|
||||
if prop.name == 'delay':
|
||||
self.delay = value
|
||||
elif prop.name == 'view':
|
||||
try:
|
||||
value.connect('leave-notify-event', self.__tree_leave_notify)
|
||||
value.connect('motion-notify-event', self.__tree_motion_notify)
|
||||
except (AttributeError, TypeError):
|
||||
raise TypeError, ('The value of view must be an object that'
|
||||
'implements leave-notify-event and motion-notify-event '
|
||||
'gsignals')
|
||||
self.view = value
|
||||
elif prop.name == 'column':
|
||||
self.column = value
|
||||
elif prop.name == 'markup_enabled':
|
||||
self.markup_enabled = value
|
||||
else:
|
||||
raise AttributeError, 'unknown or read only property %s' % prop.name
|
||||
|
||||
def __paint_window(self, window, event):
|
||||
window.style.paint_flat_box(window.window, gtk.STATE_NORMAL,
|
||||
gtk.SHADOW_OUT, None, window,
|
||||
'tooltip', 0, 0, -1, -1)
|
||||
|
||||
def __tree_leave_notify(self, tree, event):
|
||||
'''Hide tooltips when we leave the tree.'''
|
||||
|
||||
self.timeoutID = 0
|
||||
self.path = None
|
||||
self.tip_window.hide()
|
||||
|
||||
def __tree_motion_notify(self, tree, event):
|
||||
'''Decide which tooltip to display when we move within the tree.'''
|
||||
|
||||
if not self.enabled:
|
||||
return
|
||||
self.tip_window.hide()
|
||||
self.path = None
|
||||
self.unique += 1
|
||||
self.timeoutID = self.unique
|
||||
gobject.timeout_add(self.delay, self.__treetip_show, tree,
|
||||
int(event.x), int(event.y), self.timeoutID)
|
||||
|
||||
def __treetip_show(self, tree, xEvent, yEvent, ID):
|
||||
'''Show the treetip window.'''
|
||||
if self.timeoutID != ID:
|
||||
return False
|
||||
pathReturn = tree.get_path_at_pos(xEvent, yEvent)
|
||||
model = tree.get_model()
|
||||
if pathReturn == None:
|
||||
self.path = None
|
||||
elif self.path != pathReturn[0]:
|
||||
self.path = pathReturn[0]
|
||||
rowIter = model.get_iter(self.path)
|
||||
text = model.get_value(rowIter, self.column)
|
||||
self.active_tips_data = text
|
||||
if not text:
|
||||
if self.markup_enabled:
|
||||
self.tip_label.set_markup('')
|
||||
else:
|
||||
self.tip_label.set_text('')
|
||||
return False
|
||||
|
||||
if self.markup_enabled:
|
||||
self.tip_label.set_markup(text)
|
||||
else:
|
||||
self.tip_label.set_text(text)
|
||||
x, y = self.tip_label.size_request()
|
||||
self.tip_window.resize(x, y)
|
||||
windowWidth, windowHeight = self.tip_window.get_size()
|
||||
cellInfo = tree.get_cell_area(self.path, pathReturn[1])
|
||||
x, y = self.__compute_tooltip_position(cellInfo, windowWidth, windowHeight)
|
||||
self.tip_window.move(int(x), int(y))
|
||||
self.tip_window.show_all()
|
||||
|
||||
return False
|
||||
|
||||
def __compute_tooltip_position(self, cellInfo, popupWidth, popupHeight):
|
||||
'''Figures out where the tooltip should be placed on the page::
|
||||
|
||||
[p] = pointer
|
||||
x = [p]
|
||||
+---------+
|
||||
(half on each side)
|
||||
|
||||
y = [p]
|
||||
+------------+
|
||||
|____________|
|
||||
If it fits else:
|
||||
+------------+
|
||||
|____________|
|
||||
[p]
|
||||
'''
|
||||
|
||||
xOrigin, yOrigin = self.view.get_bin_window().get_origin()
|
||||
x = xOrigin + cellInfo.x + cellInfo.width/2 - popupWidth/2
|
||||
if x < 0:
|
||||
x = 0
|
||||
elif x + popupWidth > self.screenWidth:
|
||||
x = self.screenWidth - popupWidth
|
||||
|
||||
y = yOrigin + cellInfo.y + cellInfo.height + 3
|
||||
if y + popupHeight > self.screenHeight:
|
||||
y = yOrigin + cellInfo.y - 3 - popupHeight
|
||||
if y < 0:
|
||||
y = 0
|
||||
|
||||
return x, y
|
||||
gobject.type_register(TreeTips)
|
Reference in New Issue
Block a user