Mercurial and Git clients can push and pull from this alias URL to interact with this repository. You can change to which repository an alias points by going to the Aliases link on the project page.
"""Cell renderer for directed graph.This module contains the implementation of a custom GtkCellRenderer thatdraws part of the directed graph based on the lines suggested by the codein graph.py.Because we're shiny, we use Cairo to do this, and because we're naughtywe cheat and draw over the bits of the TreeViewColumn that are supposed tojust be for the background."""__copyright__="Copyright 2005 Canonical Ltd."__author__="Scott James Remnant <scott@ubuntu.com>"importmathimportgtkimportgobjectimportpangoimportcairo# Styles used when rendering revision graph edgesstyle_SOLID=0style_DASHED=1classCellRendererGraph(gtk.GenericCellRenderer):"""Cell renderer for directed graph. Properties: node (column, colour) tuple to draw revision node, in_lines (start, end, colour, style) tuple list to draw inward lines, out_lines (start, end, colour, style) tuple list to draw outward lines. """columns_len=0__gproperties__={"node":(gobject.TYPE_PYOBJECT,"node","revision node instruction",gobject.PARAM_WRITABLE),"in-lines":(gobject.TYPE_PYOBJECT,"in-lines","instructions to draw lines into the cell",gobject.PARAM_WRITABLE),"out-lines":(gobject.TYPE_PYOBJECT,"out-lines","instructions to draw lines out of the cell",gobject.PARAM_WRITABLE),}defdo_set_property(self,property,value):"""Set properties from GObject properties."""ifproperty.name=="node":self.node=valueelifproperty.name=="in-lines":self.in_lines=valueelifproperty.name=="out-lines":self.out_lines=valueelse:raiseAttributeError,"no such property: '%s'"%property.namedefbox_size(self,widget):"""Calculate box size based on widget's font. Cache this as it's probably expensive to get. It ensures that we draw the graph at least as large as the text. """try:returnself._box_sizeexceptAttributeError:pango_ctx=widget.get_pango_context()font_desc=widget.get_style().font_descmetrics=pango_ctx.get_metrics(font_desc)ascent=pango.PIXELS(metrics.get_ascent())descent=pango.PIXELS(metrics.get_descent())self._box_size=ascent+descent+1returnself._box_sizedefset_colour(self,ctx,colour,bg,fg):"""Set the context source colour. Picks a distinct colour based on an internal wheel; the bg parameter provides the value that should be assigned to the 'zero' colours and the fg parameter provides the multiplier that should be applied to the foreground colours. """mainline_color=(0.0,0.0,0.0)colours=[(1.0,0.0,0.0),(1.0,1.0,0.0),(0.0,1.0,0.0),(0.0,1.0,1.0),(0.0,0.0,1.0),(1.0,0.0,1.0),]ifisinstance(colour,str):r,g,b=colour[1:3],colour[3:5],colour[5:7]colour_rgb=int(r,16)/255.,int(g,16)/255.,int(b,16)/255.else:ifcolour==0:colour_rgb=mainline_colorelse:colour_rgb=colours[colour%len(colours)]red=(colour_rgb[0]*fg)orbggreen=(colour_rgb[1]*fg)orbgblue=(colour_rgb[2]*fg)orbgctx.set_source_rgb(red,green,blue)defon_get_size(self,widget,cell_area):"""Return the size we need for this cell. Each cell is drawn individually and is only as wide as it needs to be, we let the TreeViewColumn take care of making them all line up. """box_size=self.box_size(widget)+1width=box_size*(self.columns_len+1)height=box_size# FIXME I have no idea how to use cell_area properlyreturn(0,0,width,height)defon_render(self,window,widget,bg_area,cell_area,exp_area,flags):"""Render an individual cell. Draws the cell contents using cairo, taking care to clip what we do to within the background area so we don't draw over other cells. Note that we're a bit naughty there and should really be drawing in the cell_area (or even the exposed area), but we explicitly don't want any gutter. We try and be a little clever, if the line we need to draw is going to cross other columns we actually draw it as in the .---' style instead of a pure diagonal ... this reduces confusion by an incredible amount. """ctx=window.cairo_create()ctx.rectangle(bg_area.x,bg_area.y,bg_area.width,bg_area.height)ctx.clip()box_size=self.box_size(widget)ctx.set_line_width(box_size/8)ctx.set_line_cap(cairo.LINE_CAP_ROUND)# Draw lines into the cellforstart,end,colour,typeinself.in_lines:style=style_SOLIDiftype&1:style=style_DASHEDself.render_line(ctx,cell_area,box_size,bg_area.y,bg_area.height,start,end,colour,style)# Draw lines out of the cellforstart,end,colour,typeinself.out_lines:style=style_SOLIDiftype&2:style=style_DASHEDself.render_line(ctx,cell_area,box_size,bg_area.y+bg_area.height,bg_area.height,start,end,colour,style)# Draw the revision node in the right column(column,colour,status)=self.nodearc_start_position_x=cell_area.x+box_size*column+box_size/2;arc_start_position_y=cell_area.y+cell_area.height/2;ifstatus>=4:# working directory parentctx.arc(arc_start_position_x,arc_start_position_y,box_size/4,0,2*math.pi)status-=4else:ctx.arc(arc_start_position_x,arc_start_position_y, box_size / 5, 0, 2 * math.pi)
self.set_colour(ctx, colour, 0.0, 0.5)
ctx.stroke_preserve()
+ self.set_colour(ctx, colour, 0.5, 1.0)+ ctx.fill() # Possible node status
if status != 0:
- def draw_arrow(x, y, inc):- ctx.move_to(x - 2, y)
- ctx.line_to(x + 4, y)
- ctx.line_to(x + 1, y + inc)
- ctx.line_to(x - 2, y)+ def draw_arrow(x, y, dir):+ self.set_colour(ctx, '#2e3436', 0.0, 1.0)+ ctx.rectangle(x, y, 2, 5)+ ax, ay = x, y + (dir == 'down' and 5 or 0)+inc = 3 * (dir == 'up' and -1 or 1)+ ctx.move_to(ax - 2, ay)
+ ctx.line_to(ax + 4, ay)
+ ctx.line_to(ax + 1, ay + inc)
+ ctx.line_to(ax - 2, ay) ctx.stroke_preserve()
-- def draw_star(x, y, radius, nodes):
+ fillcolor = dir == 'up' and '#feaf3e' or '#8ae234'+ self.set_colour(ctx, fillcolor, 0.0, 1.0)+ ctx.fill()++ def draw_star(x, y, radius, nodes, offset=False):
+ self.set_colour(ctx, '#2e3436', 0.0, 1.0) total_nodes = nodes * 2 #inner + outer nodes
angle = 2 * math.pi / total_nodes;
+ offset = offset and angle / 2 or 0 for value in range(total_nodes + 1): # + 1 = backing to the start to close
radius_point = radius
if value % 2:
radius_point = 0.4 * radius_point;
- arc_y = y - math.sin(angle * value) * radius_point
- arc_x = x - math.cos(angle * value) * radius_point+ arc_y = y - math.sin(angle * value + offset) * radius_point
+ arc_x = x - math.cos(angle * value + offset) * radius_point
if value == 0:
ctx.move_to(arc_x,arc_y)
else:
ctx.line_to(arc_x, arc_y)
-+ctx.stroke_preserve()+self.set_colour(ctx, '#fce94f', 0.0, 1.0)+ ctx.fill()+ arrow_y = arc_start_position_y - box_size / 4
arrow_x = arc_start_position_x + 7;
if status == 1: # Outgoing arrow
- ctx.rectangle(arrow_x, arrow_y, 2, 5)- draw_arrow(arrow_x, arrow_y, -3)
+ draw_arrow(arrow_x, arrow_y, 'up')
elif status == 2: # New changeset, recently added to tip
- ctx.set_source_rgb(0, 1, 0)- draw_star(arrow_x + box_size / 4, arc_start_position_y, 4, 6)
+ draw_star(arrow_x + box_size / 4 - 1,
+ arc_start_position_y, 4, 5, True)
elif status == 3: # Incoming (bundle preview) arrow
- ctx.rectangle(arrow_x, arrow_y, 2, 5)- draw_arrow(arrow_x, arrow_y + 5, 3)
- ctx.stroke_preserve()-- self.set_colour(ctx, colour, 0.5, 1.0)- ctx.fill()+ draw_arrow(arrow_x, arrow_y, 'down')
def render_line (self, ctx, cell_area, box_size, mid,
height, start, end, colour, style):
ifstartisNone:x=cell_area.x+box_size*end+box_size/2ctx.move_to(x,mid+height/3)ctx.line_to(x,mid+height/3)ctx.move_to(x,mid+height/6)ctx.line_to(x,mid+height/6)elifendisNone:x=cell_area.x+box_size*start+box_size/2ctx.move_to(x,mid-height/3)ctx.line_to(x,mid-height/3)ctx.move_to(x,mid-height/6)ctx.line_to(x,mid-height/6)else:startx=cell_area.x+box_size*start+box_size/2endx=cell_area.x+box_size*end+box_size/2ctx.move_to(startx,mid-height/2)ifstart-end==0:ctx.line_to(endx,mid+height/2)else:ctx.curve_to(startx,mid-height/5,startx,mid-height/5,startx+(endx-startx)/2,mid)ctx.curve_to(endx,mid+height/5,endx,mid+height/5,endx,mid+height/2)self.set_colour(ctx,colour,0.0,0.65)ifstyle==style_DASHED:dashes=[1,2]ctx.set_dash(dashes)ctx.stroke()ctx.set_dash([])
Attach a Trello Card
Add a tag
Your session has expired
You are no longer logged in. Please log in and try your request again.
Filter RSS Feed
This RSS feed URL allows you to see the contents of your current filter using any feed reader.
This link includes a special authentication token. If you share the URL with anyone else, they can see this RSS feed's activity. You can disable these tokens when needed.
Your current filter is unsaved; changing it won't affect this RSS feed.