diff options
Diffstat (limited to 'examples/gtk/cairo-knockout.py')
-rwxr-xr-x | examples/gtk/cairo-knockout.py | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/examples/gtk/cairo-knockout.py b/examples/gtk/cairo-knockout.py new file mode 100755 index 0000000..e8c2c90 --- /dev/null +++ b/examples/gtk/cairo-knockout.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python +"""Based on gtk+/test/testcairo.c +""" + +from __future__ import division +import math +import sys + +import cairo +import gtk + + +def oval_path(ctx, xc, yc, xr, yr): + ctx.save() + + ctx.translate (xc, yc) + ctx.scale (1.0, yr / xr) + ctx.move_to (xr, 0.0) + ctx.arc (0, 0, xr, 0, 2 * math.pi) + ctx.close_path () + + ctx.restore() + +def fill_checks(ctx, x, y, width, height): + CHECK_SIZE = 32 + + ctx.rectangle (x, y, width, height) + ctx.set_source_rgb (0.4, 0.4, 0.4) + ctx.fill () + + # Only works for CHECK_SIZE a power of 2 + for j in range (x & -CHECK_SIZE, height, CHECK_SIZE): + for i in range (y & -CHECK_SIZE, width, CHECK_SIZE): + if ((i / CHECK_SIZE + j / CHECK_SIZE) % 2 == 0): + ctx.rectangle (i, j, CHECK_SIZE, CHECK_SIZE) + + ctx.set_source_rgb (0.7, 0.7, 0.7) + ctx.fill () + +def draw_3circles(ctx, xc, yc, radius, alpha): + subradius = radius * (2 / 3. - 0.1) + + ctx.set_source_rgba(1, 0, 0, alpha) + oval_path(ctx, + xc + radius / 3. * math.cos(math.pi * 0.5), + yc - radius / 3. * math.sin(math.pi * 0.5), + subradius, subradius) + ctx.fill() + + ctx.set_source_rgba(0, 1, 0, alpha) + oval_path(ctx, + xc + radius / 3. * math.cos(math.pi * (0.5 + 2/.3)), + yc - radius / 3. * math.sin(math.pi * (0.5 + 2/.3)), + subradius, subradius) + ctx.fill() + + ctx.set_source_rgba(0, 0, 1, alpha) + oval_path(ctx, + xc + radius / 3. * math.cos(math.pi * (0.5 + 4/.3)), + yc - radius / 3. * math.sin(math.pi * (0.5 + 4/.3)), + subradius, subradius) + ctx.fill() + +def draw (ctx, width, height): + radius = 0.5 * min(width, height) - 10 + xc = width / 2. + yc = height / 2. + + target = ctx.get_target() + overlay = target.create_similar(cairo.CONTENT_COLOR_ALPHA, width, height) + punch = target.create_similar(cairo.CONTENT_ALPHA, width, height) + circles = target.create_similar(cairo.CONTENT_COLOR_ALPHA, width, height) + + fill_checks(ctx, 0, 0, width, height) + + # Draw a black circle on the overlay + overlay_cr = cairo.Context (overlay) + overlay_cr.set_source_rgb (0, 0, 0) + oval_path (overlay_cr, xc, yc, radius, radius) + overlay_cr.fill() + + # Draw 3 circles to the punch surface, then cut + # that out of the main circle in the overlay + punch_cr = cairo.Context (punch) + draw_3circles (punch_cr, xc, yc, radius, 1.0) + + overlay_cr.set_operator (cairo.OPERATOR_DEST_OUT) + overlay_cr.set_source_surface (punch, 0, 0) + overlay_cr.paint() + + # Now draw the 3 circles in a subgroup again + # at half intensity, and use OperatorAdd to join up + # without seams. + circles_cr = cairo.Context (circles) + + circles_cr.set_operator (cairo.OPERATOR_OVER) + draw_3circles (circles_cr, xc, yc, radius, 0.5) + + overlay_cr.set_operator (cairo.OPERATOR_ADD) + overlay_cr.set_source_surface (circles, 0, 0) + overlay_cr.paint() + + ctx.set_source_surface (overlay, 0, 0) + ctx.paint() + +def expose(drawingarea, event): + ctx = drawingarea.window.cairo_create() + + _, _, width, height = drawingarea.allocation + draw (ctx, width, height) + + return False + +def main(): + win = gtk.Window() + win.connect('destroy', gtk.main_quit) + win.set_title('Knockout Groups') + win.set_default_size(400, 400) + + drawingarea = gtk.DrawingArea() + win.add(drawingarea) + drawingarea.connect('expose_event', expose) + + win.show_all() + gtk.main() + +if __name__ == '__main__': + main() |