gloss-mc/ui_elements/rounded_rectangle.py

129 lines
4.1 KiB
Python

import cairo
import clutter
import gtk
from cluttercairo import CairoTexture
"""
This element is a Clutter Group that displays as a rectangle of arbitary size
with rounded corners. It is rendered using Cairo but maybe treated as per any other
Clutter element
"""
class RoundedRectangle(clutter.Group):
ARC_TO_BEZIER = 0.55228475
RADIUS = 5
MARGIN = 1
def __init__(self, width, height, colour = clutter.color_parse('Black')):
clutter.Group.__init__(self)
self.width = width
self.height = height
self.colour = colour
margin = self.MARGIN
radius = self.RADIUS
#CairoTexture.__init__(self, width, height)
#context = self.cairo_create()
self.texture = CairoTexture(self.width, self.height)
self.add(self.texture)
self.texture.show()
self.setup_rounded_context()
self.refresh()
def setup_rounded_context(self):
# Round corners
x = 0 + self.MARGIN
y = 0 + self.MARGIN
w = self.width - (self.MARGIN * 2)
h = self.height - (self.MARGIN * 2)
radius_x = self.RADIUS
radius_y = self.RADIUS
old_tex = self.texture
self.texture = CairoTexture(self.width, self.height)
self.add(self.texture)
self.texture.show()
self.remove(old_tex)
context = self.texture.cairo_create()
#Clear the texture
#if not self.context is None:
context.set_operator(cairo.OPERATOR_CLEAR)
context.paint()
context.set_operator(cairo.OPERATOR_OVER)
"""
Clip cairo texture with rounded rectangle.
"""
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 = self.ARC_TO_BEZIER * radius_x
c2 = self.ARC_TO_BEZIER * radius_y
context.new_path();
context.move_to ( x + radius_x, y)
context.rel_line_to ( w - 2 * radius_x, 0.0)
context.rel_curve_to ( c1, 0.0, radius_x, c2, radius_x, radius_y)
context.rel_line_to ( 0, h - 2 * radius_y)
context.rel_curve_to ( 0.0, c2, c1 - radius_x, radius_y, -radius_x, radius_y)
context.rel_line_to ( -w + 2 * radius_x, 0)
context.rel_curve_to ( -c1, 0, -radius_x, -c2, -radius_x, -radius_y)
context.rel_line_to (0, -h + 2 * radius_y)
context.rel_curve_to (0.0, -c2, radius_x - c1, -radius_y, radius_x, -radius_y)
context.close_path()
context.clip()
#context = self.get_rounded_context(x ,y, w1, h1, radius, radius)
self.ct = gtk.gdk.CairoContext(context)
# Scale context area
#wr = width / float(pixbuf.get_width())
#hr = height / float(pixbuf.get_height())
#context.scale(wr,hr)
self.ct.rectangle(
(0, 0, self.width, self.height)
)
self.context = context
#Set the colour
self.context.set_source_rgb(self.colour.red, self.colour.green, self.colour.blue)
def refresh(self):
self.context.paint()
del self.context # Update texture
del self.ct
def set_width(self, new_width):
#self.texture.set_width(new_width)
#self.texture.set_clip(0, 0, new_width, self.height)
self.width = new_width
self.setup_rounded_context()
self.refresh()
clutter.Group.set_width(self, new_width)
def set_height(self, new_height):
self.height = new_height
self.setup_rounded_context()
self.refresh()
clutter.Group.set_height(self,new_height)
def set_size(self, new_width, new_height):
self.set_width(new_width)
self.set_height(new_height)
def set_color(self, new_colour):
self.setup_rounded_context()
self.colour = new_colour
self.refresh()
#self.texture.set_color(new_colour)