def render_cell(self, context, bounds, widget, flags, really=True): if not bounds: return -1 x, y, cell_width, h = bounds self.selected_color = widget.get_style().text[gtk.STATE_SELECTED] self.normal_color = widget.get_style().text[gtk.STATE_NORMAL] g = graphics.Graphics(context) fact = self.data selected = flags and flags & gtk.CELL_RENDERER_SELECTED text_color = self.normal_color if selected: text_color = self.selected_color """ start time and end time at beginning of column """ interval = fact.start_time.strftime("%H:%M -") if fact.end_time: interval = "%s %s" % (interval, fact.end_time.strftime("%H:%M")) self.interval_label.text = interval self.interval_label.color = text_color self.interval_label.x = self.col_padding self.interval_label.y = 2 """ duration at the end """ self.duration_label.text = stuff.format_duration(fact.delta) self.duration_label.color = text_color self.duration_label.x = cell_width - self.duration_label.width self.duration_label.y = 2 """ activity, category, tags, description in middle """ # we want our columns look aligned, so we will do fixed offset from # both sides, in letter length cell_start = widget.longest_interval cell_width = cell_width - widget.longest_interval - widget.longest_duration # align activity and category (ellipsize activity if it does not fit) category_width = 0 self.category_label.text = "" if fact.category: self.category_label.text = " - <small>%s</small>" % stuff.escape_pango( fact.category) if not selected: category_color = graphics.Colors.contrast(text_color, 100) self.category_label.color = category_color else: self.category_label.color = text_color category_width = self.category_label.width self.activity_label.color = text_color self.activity_label.width = None self.activity_label.text = stuff.escape_pango(fact.name) # if activity label does not fit, we will shrink it if self.activity_label.width > cell_width - category_width: self.activity_label.width = (cell_width - category_width - self.col_padding) self.activity_label.ellipsize = pango.ELLIPSIZE_END else: self.activity_label.width = None #self.activity_label.ellipsize = None activity_width = self.activity_label.width y = 2 self.activity_label.x = cell_start self.activity_label.y = y self.category_label.x = cell_start + activity_width self.category_label.y = y x = cell_start + activity_width + category_width + 12 current_height = 0 if fact.tags: # try putting tags on same line if they fit # otherwise move to the next line tags_end = cell_start + cell_width tag = Tag(fact.tags[0]) if x + tag.width > tags_end: x = cell_start y = self.activity_label.height + 4 for i, tag in enumerate(fact.tags): tag = Tag(tag) if x + tag.width >= tags_end: x = cell_start y += tag.height + 4 tag.x, tag.y = x, y if really: tag._draw(context) x += tag.width + 4 current_height = y + tag.height + 4 current_height = max(self.activity_label.height + 2, current_height) # see if we can fit in single line # if not, put description under activity self.description_label.text = "" if fact.description: self.description_label.text = "<small>%s</small>" % stuff.escape_pango( fact.description) self.description_label.color = text_color self.description_label.wrap = pango.WRAP_WORD description_width = self.description_label.width width = cell_width - x if description_width > width: x = cell_start y = current_height self.description_label.width = cell_width else: self.description_label.width = None self.description_label.x = x self.description_label.y = y current_height = max( current_height, self.description_label.y + self.description_label.height + 5) self.labels._draw(context) return current_height
class FactCellRenderer(gtk.GenericCellRenderer): """ We need all kinds of wrapping and spanning and the treeview just does not cut it""" __gproperties__ = { "data": (gobject.TYPE_PYOBJECT, "Data", "Data", gobject.PARAM_READWRITE), } def __init__(self): gtk.GenericCellRenderer.__init__(self) self.height = 0 self.data = None font = gtk.Style().font_desc self.default_size = font.get_size() / pango.SCALE self.labels = graphics.Sprite() self.date_label = graphics.Label(size = self.default_size) self.interval_label = graphics.Label(size = self.default_size) self.labels.add_child(self.interval_label) self.activity_label = graphics.Label(size = self.default_size) self.labels.add_child(self.activity_label) self.category_label = graphics.Label(size = self.default_size) self.labels.add_child(self.category_label) self.description_label = graphics.Label(size = self.default_size) self.labels.add_child(self.description_label) self.duration_label = graphics.Label(size=self.default_size) self.labels.add_child(self.duration_label) default_font = gtk.Style().font_desc.to_string() self.tag = Tag("") self.selected_color = None self.normal_color = None self.col_padding = 10 self.row_padding = 4 def do_set_property (self, pspec, value): setattr(self, pspec.name, value) def do_get_property(self, pspec): return getattr (self, pspec.name) def on_render (self, window, widget, background_area, cell_area, expose_area, flags): if not self.data: return """ ASCII Art --------------+--------------------------------------------+-------+---+ 13:12 - 17:18 | Some activity - category tag, tag, tag, | 14:44 | E | | tag, tag, some description | | | --------------+--------------------------------------------+-------+---+ """ # set the colors self.selected_color = widget.get_style().text[gtk.STATE_SELECTED] self.normal_color = widget.get_style().text[gtk.STATE_NORMAL] context = window.cairo_create() if isinstance(self.data, FactRow): fact, parent = self.data, None else: parent, fact = self.data, None x, y, width, height = cell_area context.translate(x, y) if flags & gtk.CELL_RENDERER_SELECTED: text_color = self.selected_color else: text_color = self.normal_color self.date_label.color = text_color self.duration_label.color = text_color if parent: self.date_label.text = "<b>%s</b>" % stuff.escape_pango(parent.label) self.date_label.x = 5 if self.data.first: y = 5 else: y = 20 self.date_label.y = y self.duration_label.text = "<b>%s</b>" % stuff.format_duration(parent.duration) self.duration_label.x = width - self.duration_label.width self.duration_label.y = y self.date_label._draw(context) self.duration_label._draw(context) else: self.render_cell(context, (x,y,width,height), widget, flags) def render_cell(self, context, bounds, widget, flags, really = True): if not bounds: return -1 x, y, cell_width, h = bounds self.selected_color = widget.get_style().text[gtk.STATE_SELECTED] self.normal_color = widget.get_style().text[gtk.STATE_NORMAL] g = graphics.Graphics(context) fact = self.data selected = flags and flags & gtk.CELL_RENDERER_SELECTED text_color = self.normal_color if selected: text_color = self.selected_color """ start time and end time at beginning of column """ interval = fact.start_time.strftime("%H:%M -") if fact.end_time: interval = "%s %s" % (interval, fact.end_time.strftime("%H:%M")) self.interval_label.text = interval self.interval_label.color = text_color self.interval_label.x = self.col_padding self.interval_label.y = 2 """ duration at the end """ self.duration_label.text = stuff.format_duration(fact.delta) self.duration_label.color = text_color self.duration_label.x = cell_width - self.duration_label.width self.duration_label.y = 2 """ activity, category, tags, description in middle """ # we want our columns look aligned, so we will do fixed offset from # both sides, in letter length cell_start = widget.longest_interval cell_width = cell_width - widget.longest_interval - widget.longest_duration # align activity and category (ellipsize activity if it does not fit) category_width = 0 self.category_label.text = "" if fact.category: self.category_label.text = " - <small>%s</small>" % stuff.escape_pango(fact.category) if not selected: category_color = graphics.Colors.contrast(text_color, 100) self.category_label.color = category_color else: self.category_label.color = text_color category_width = self.category_label.width self.activity_label.color = text_color self.activity_label.width = None if isinstance(fact, RedmineFactRow): text = fact.name text += " " text += fact.fact.redmine_tag() self.activity_label.text = stuff.escape_pango(text) else: self.activity_label.text = stuff.escape_pango(fact.name) # if activity label does not fit, we will shrink it if self.activity_label.width > cell_width - category_width: self.activity_label.width = (cell_width - category_width - self.col_padding) self.activity_label.ellipsize = pango.ELLIPSIZE_END else: self.activity_label.width = None #self.activity_label.ellipsize = None activity_width = self.activity_label.width y = 2 self.activity_label.x = cell_start self.activity_label.y = y self.category_label.x = cell_start + activity_width self.category_label.y = y x = cell_start + activity_width + category_width + 12 current_height = 0 if fact.tags: # try putting tags on same line if they fit # otherwise move to the next line tags_end = cell_start + cell_width if x + self.tag.width > tags_end: x = cell_start y = self.activity_label.height + 4 for i, tag in enumerate(fact.tags): self.tag.text = tag if x + self.tag.width >= tags_end: x = cell_start y += self.tag.height + 4 self.tag.x, self.tag.y = x, y if really: self.tag._draw(context) x += self.tag.width + 4 current_height = y + self.tag.height + 4 current_height = max(self.activity_label.height + 2, current_height) # see if we can fit in single line # if not, put description under activity self.description_label.text = "" if fact.description: self.description_label.text = "<small>%s</small>" % stuff.escape_pango(fact.description) self.description_label.color = text_color self.description_label.wrap = pango.WRAP_WORD description_width = self.description_label.width width = cell_width - x if description_width > width: x = cell_start y = current_height self.description_label.width = cell_width else: self.description_label.width = None self.description_label.x = x self.description_label.y = y current_height = max(current_height, self.description_label.y + self.description_label.height + 5) self.labels._draw(context) return current_height def on_get_size(self, widget, cell_area): if isinstance(self.data, GroupRow): if self.data.first: return (0, 0, 0, int((self.default_size + 10) * 1.5)) else: return (0, 0, 0, (self.default_size + 10) * 2) context = gtk.gdk.CairoContext(cairo.Context(cairo.ImageSurface(cairo.FORMAT_A1, 0, 0))) area = widget.get_allocation() area.width -= 40 # minus the edit column, scrollbar and padding (and the scrollbar part is quite lame) cell_height = self.render_cell(context, area, widget, None, False) return (0, 0, -1, cell_height)
def render_cell(self, context, bounds, widget, flags, really = True): if not bounds: return -1 x, y, cell_width, h = bounds self.selected_color = widget.get_style().text[gtk.STATE_SELECTED] self.normal_color = widget.get_style().text[gtk.STATE_NORMAL] g = graphics.Graphics(context) fact = self.data selected = flags and flags & gtk.CELL_RENDERER_SELECTED text_color = self.normal_color if selected: text_color = self.selected_color """ start time and end time at beginning of column """ interval = fact.start_time.strftime("%H:%M -") if fact.end_time: interval = "%s %s" % (interval, fact.end_time.strftime("%H:%M")) self.interval_label.text = interval self.interval_label.color = text_color self.interval_label.x = self.col_padding self.interval_label.y = 2 """ duration at the end """ self.duration_label.text = stuff.format_duration(fact.delta) self.duration_label.color = text_color self.duration_label.x = cell_width - self.duration_label.width self.duration_label.y = 2 """ activity, category, tags, description in middle """ # we want our columns look aligned, so we will do fixed offset from # both sides, in letter length cell_start = widget.longest_interval cell_width = cell_width - widget.longest_interval - widget.longest_duration # align activity and category (ellipsize activity if it does not fit) category_width = 0 self.category_label.text = "" if fact.category: self.category_label.text = " - <small>%s</small>" % stuff.escape_pango(fact.category) if not selected: category_color = graphics.Colors.contrast(text_color, 100) self.category_label.color = category_color else: self.category_label.color = text_color category_width = self.category_label.width self.activity_label.color = text_color self.activity_label.width = None self.activity_label.text = stuff.escape_pango(fact.name) # if activity label does not fit, we will shrink it if self.activity_label.width > cell_width - category_width: self.activity_label.width = (cell_width - category_width - self.col_padding) self.activity_label.ellipsize = pango.ELLIPSIZE_END else: self.activity_label.width = None #self.activity_label.ellipsize = None activity_width = self.activity_label.width y = 2 self.activity_label.x = cell_start self.activity_label.y = y self.category_label.x = cell_start + activity_width self.category_label.y = y x = cell_start + activity_width + category_width + 12 current_height = 0 if fact.tags: # try putting tags on same line if they fit # otherwise move to the next line tags_end = cell_start + cell_width tag = Tag(fact.tags[0]) if x + tag.width > tags_end: x = cell_start y = self.activity_label.height + 4 for i, tag in enumerate(fact.tags): tag = Tag(tag) if x + tag.width >= tags_end: x = cell_start y += tag.height + 4 tag.x, tag.y = x, y if really: tag._draw(context) x += tag.width + 4 current_height = y + tag.height + 4 current_height = max(self.activity_label.height + 2, current_height) # see if we can fit in single line # if not, put description under activity self.description_label.text = "" if fact.description: self.description_label.text = "<small>%s</small>" % stuff.escape_pango(fact.description) self.description_label.color = text_color self.description_label.wrap = pango.WRAP_WORD description_width = self.description_label.width width = cell_width - x if description_width > width: x = cell_start y = current_height self.description_label.width = cell_width else: self.description_label.width = None self.description_label.x = x self.description_label.y = y current_height = max(current_height, self.description_label.y + self.description_label.height + 5) self.labels._draw(context) return current_height