#!/usr/bin/env python
import gtk, gobject
from warnings import warn
class CellRendererProgressMaskStateWarning(UserWarning): pass
class CellRendererProgressMask(gtk.GenericCellRenderer):
__gproperties__ = {
'slots': (object, 'slots', 'Mask of filled bins',
gobject.PARAM_READWRITE),
}
def on_get_size(self, widget, cell):
return 0, 0, -1, self.props.ypad + 6
def do_get_property(self, property):
return getattr(self, '_CellRendererProgressMask__' + property.name)
def do_set_property(self, property, value):
setattr(self, '_CellRendererProgressMask__' + property.name, value)
def set_states(self, states):
self.__states = states
def on_render(self, window, widget, bg_area, cell, expose, flags):
cr = window.cairo_create()
cr.rectangle(expose.x, expose.y, expose.width, expose.height)
cr.clip()
xpad = self.props.xpad
xalign = self.props.xalign
ypad = self.props.ypad
yalign = self.props.yalign
cr.translate(cell.x + xpad * xalign, cell.y + ypad * yalign)
slots = self.props.slots
if not slots: return
bins = len(slots)
def draw(start, width, cr=cr, a=[1.0]):
try:
cr.set_source_rgba(*(list(self.__states[start[0]]) + a)[:4])
except (IndexError, KeyError):
warn('Invalid State %r in slot %d' % start,
CellRendererProgressMaskStateWarning)
else:
cr.rectangle(start[1], 0, width, 1)
cr.fill()
cr.save()
cr.scale(float(cell.width - xpad) / bins, cell.height - ypad)
start = slots[0], 0
for i, val in enumerate(slots):
if val != start[0]: # collect like-bins to avoid striping
draw(start, i - start[1])
start = val, i
else:
draw(start, i + 1 - start[1])
def round(x, y, cr=cr):
x, y = map(int, cr.user_to_device(x, y))
return cr.device_to_user(x + 0.5, y + 0.5)
one_pixel = cr.device_to_user_distance(1, 1)
if max(one_pixel) < 0.25:
cr.set_line_width(min(one_pixel))
cr.set_source_rgba(0, 0, 0, 0.9)
for i in xrange(1, bins):
cr.move_to(*round(i, 0))
cr.line_to(*round(i, 1))
cr.stroke()
cr.restore()
cr.rectangle(0.5, 0.5, cell.width - xpad, cell.height - ypad)
if flags & gtk.CELL_RENDERER_PRELIT:
cr.set_source_rgba(1, 1, 1, 0.25)
cr.fill_preserve()
cr.set_source_rgba(0, 0, 0, 0.9)
cr.set_line_width(1)
cr.stroke()
def __main__():
model = gtk.ListStore(int, object)
model.append([5, [1, 0, 2, 0, 1]])
model.append([6, [0, 1, 0, 1, 0, 1]])
model.append([7, [1, 0] * 4])
model.append([8, [0, 1] * 4])
model.append([31, [1, 1] * 16])
model.append([63, [1, 1] * 32])
model.append([1023, [1, 1, 1, 0, 2, 2, 2, 0] * 128])
crpm = CellRendererProgressMask()
tv = gtk.TreeView(model)
#tv.append_column(gtk.TreeViewColumn('bins', gtk.CellRendererText(), text=0))
tv.append_column(gtk.TreeViewColumn('progress', crpm, slots=1))
crpm.set_states([(1, 1, 1, 0.3), (0, 0.5, 0), (0.8, 0, 0)])
#crpm.props.xpad = 10
#crpm.props.xalign = 0.0
crpm.props.ypad = 8
#crpm.props.yalign = 0.5
for column in tv.get_columns():
column.set_resizable(True)
win = gtk.Window()
win.add(tv)
tv.show()
win.connect('delete-event', gtk.main_quit)
win.present()
gtk.main()
if __name__ == '__main__': __main__()