roundedrectangles

Method A

From the cairo samples, modified. Gives a very nice shape but takes width and height only as guides.

def roundedrecA(self,cr,x,y,width,height,radius=5):
    #/* a custom shape, that could be wrapped in a function */
    #radius = 5  #/*< and an approximate curvature radius */        
    x0       = x+radius/2.0   #/*< parameters like cairo_rectangle */
    y0       = y+radius/2.0
    rect_width  = width - radius
    rect_height = height - radius

    cr.save()
    #cr.set_line_width (0.04)
    #self.snippet_normalize (cr, width, height)

    x1=x0+rect_width
    y1=y0+rect_height
    #if (!rect_width || !rect_height)
    #    return
    if rect_width/2<radius:
        if rect_height/2<radius:
            cr.move_to  (x0, (y0 + y1)/2)
            cr.curve_to (x0 ,y0, x0, y0, (x0 + x1)/2, y0)
            cr.curve_to (x1, y0, x1, y0, x1, (y0 + y1)/2)
            cr.curve_to (x1, y1, x1, y1, (x1 + x0)/2, y1)
            cr.curve_to (x0, y1, x0, y1, x0, (y0 + y1)/2)
        else:
            cr.move_to  (x0, y0 + radius)
            cr.curve_to (x0 ,y0, x0, y0, (x0 + x1)/2, y0)
            cr.curve_to (x1, y0, x1, y0, x1, y0 + radius)
            cr.line_to (x1 , y1 - radius)
            cr.curve_to (x1, y1, x1, y1, (x1 + x0)/2, y1)
            cr.curve_to (x0, y1, x0, y1, x0, y1- radius)

    else:
        if rect_height/2<radius:
            cr.move_to  (x0, (y0 + y1)/2)
            cr.curve_to (x0 , y0, x0 , y0, x0 + radius, y0)
            cr.line_to (x1 - radius, y0)
            cr.curve_to (x1, y0, x1, y0, x1, (y0 + y1)/2)
            cr.curve_to (x1, y1, x1, y1, x1 - radius, y1)
            cr.line_to (x0 + radius, y1)
            cr.curve_to (x0, y1, x0, y1, x0, (y0 + y1)/2)
        else:
            cr.move_to  (x0, y0 + radius)
            cr.curve_to (x0 , y0, x0 , y0, x0 + radius, y0)
            cr.line_to (x1 - radius, y0)
            cr.curve_to (x1, y0, x1, y0, x1, y0 + radius)
            cr.line_to (x1 , y1 - radius)
            cr.curve_to (x1, y1, x1, y1, x1 - radius, y1)
            cr.line_to (x0 + radius, y1)
            cr.curve_to (x0, y1, x0, y1, x0, y1- radius)

    cr.close_path ()

    cr.restore()

Method B

From mono moonlight aka mono silverlight. Works very well on larger shapes.

def roundedrecMoonlight(self,cr,x,y,w,h,radius_x=5,radius_y=5):
    #from mono moonlight aka mono silverlight
    #test limits (without using multiplications)
    # http://graphics.stanford.edu/courses/cs248-98-fall/Final/q1.html
    ARC_TO_BEZIER = 0.55228475
    if radius_x > w - radius_x:
        radius_x = w / 2
    if radius_y > h - radius_y:
        radius_y = h / 2

    #approximate (quite close) the arc using a bezier curve
    c1 = ARC_TO_BEZIER * radius_x
    c2 = ARC_TO_BEZIER * radius_y

    cr.new_path();
    cr.move_to ( x + radius_x, y)
    cr.rel_line_to ( w - 2 * radius_x, 0.0)
    cr.rel_curve_to ( c1, 0.0, radius_x, c2, radius_x, radius_y)
    cr.rel_line_to ( 0, h - 2 * radius_y)
    cr.rel_curve_to ( 0.0, c2, c1 - radius_x, radius_y, -radius_x, radius_y)
    cr.rel_line_to ( -w + 2 * radius_x, 0)
    cr.rel_curve_to ( -c1, 0, -radius_x, -c2, -radius_x, -radius_y)
    cr.rel_line_to (0, -h + 2 * radius_y)
    cr.rel_curve_to (0.0, -c2, radius_x - c1, -radius_y, radius_x, -radius_y)
    cr.close_path ()

Method C

I can't remember where I got this. If you are the author please add your name. Works well on smaller shapes.

def roundedrec(self,context,x,y,w,h,r = 10):
    "Draw a rounded rectangle"
    #   A****BQ
    #  H      C
    #  *      *
    #  G      D
    #   F****E

    context.move_to(x+r,y)                      # Move to A
    context.line_to(x+w-r,y)                    # Straight line to B
    context.curve_to(x+w,y,x+w,y,x+w,y+r)       # Curve to C, Control points are both at Q
    context.line_to(x+w,y+h-r)                  # Move to D
    context.curve_to(x+w,y+h,x+w,y+h,x+w-r,y+h) # Curve to E
    context.line_to(x+r,y+h)                    # Line to F
    context.curve_to(x,y+h,x,y+h,x,y+h-r)       # Curve to G
    context.line_to(x,y+r)                      # Line to H
    context.curve_to(x,y,x,y,x+r,y)             # Curve to A
    return