gtk/tests/testcairo.c

235 lines
6.0 KiB
C
Raw Normal View History

/* testimage.c
* Copyright (C) 2005 Red Hat, Inc.
* Based on cairo-demo/X11/cairo-knockout.c
*
* Author: Owen Taylor
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <math.h>
#include <gtk/gtk.h>
static void
oval_path (cairo_t *cr,
double xc, double yc,
double xr, double yr)
{
cairo_save (cr);
cairo_translate (cr, xc, yc);
cairo_scale (cr, 1.0, yr / xr);
cairo_move_to (cr, xr, 0.0);
cairo_arc (cr,
0, 0,
xr,
0, 2 * G_PI);
cairo_close_path (cr);
cairo_restore (cr);
}
/* Create a path that is a circular oval with radii xr, yr at xc,
* yc.
*/
/* Fill the given area with checks in the standard style
* for showing compositing effects.
*
* It would make sense to do this as a repeating surface,
* but most implementations of RENDER currently have broken
* implementations of repeat + transform, even when the
* transform is a translation.
*/
static void
fill_checks (cairo_t *cr,
int x, int y,
int width, int height)
{
int i, j;
#define CHECK_SIZE 32
cairo_rectangle (cr, x, y, width, height);
cairo_set_source_rgb (cr, 0.4, 0.4, 0.4);
cairo_fill (cr);
/* Only works for CHECK_SIZE a power of 2 */
j = x & (-CHECK_SIZE);
for (; j < height; j += CHECK_SIZE)
{
i = y & (-CHECK_SIZE);
for (; i < width; i += CHECK_SIZE)
if ((i / CHECK_SIZE + j / CHECK_SIZE) % 2 == 0)
cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE);
}
cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
cairo_fill (cr);
}
/* Draw a red, green, and blue circle equally spaced inside
* the larger circle of radius r at (xc, yc)
*/
static void
draw_3circles (cairo_t *cr,
double xc, double yc,
double radius,
double alpha)
{
double subradius = radius * (2 / 3. - 0.1);
cairo_set_source_rgba (cr, 1., 0., 0., alpha);
oval_path (cr,
xc + radius / 3. * cos (G_PI * (0.5)),
yc - radius / 3. * sin (G_PI * (0.5)),
subradius, subradius);
cairo_fill (cr);
cairo_set_source_rgba (cr, 0., 1., 0., alpha);
oval_path (cr,
xc + radius / 3. * cos (G_PI * (0.5 + 2/.3)),
yc - radius / 3. * sin (G_PI * (0.5 + 2/.3)),
subradius, subradius);
cairo_fill (cr);
cairo_set_source_rgba (cr, 0., 0., 1., alpha);
oval_path (cr,
xc + radius / 3. * cos (G_PI * (0.5 + 4/.3)),
yc - radius / 3. * sin (G_PI * (0.5 + 4/.3)),
subradius, subradius);
cairo_fill (cr);
}
static void
draw (cairo_t *cr,
int width,
int height)
{
cairo_surface_t *overlay, *punch, *circles;
cairo_t *overlay_cr, *punch_cr, *circles_cr;
/* Fill the background */
double radius = 0.5 * (width < height ? width : height) - 10;
double xc = width / 2.;
double yc = height / 2.;
overlay = cairo_surface_create_similar (cairo_get_target (cr),
CAIRO_FORMAT_ARGB32,
width, height);
if (overlay == NULL)
return;
punch = cairo_surface_create_similar (cairo_get_target (cr),
CAIRO_FORMAT_A8,
width, height);
if (punch == NULL)
return;
circles = cairo_surface_create_similar (cairo_get_target (cr),
CAIRO_FORMAT_ARGB32,
width, height);
if (circles == NULL)
return;
fill_checks (cr, 0, 0, width, height);
/* Draw a black circle on the overlay
*/
overlay_cr = cairo_create (overlay);
cairo_set_source_rgb (overlay_cr, 0., 0., 0.);
oval_path (overlay_cr, xc, yc, radius, radius);
cairo_fill (overlay_cr);
/* Draw 3 circles to the punch surface, then cut
* that out of the main circle in the overlay
*/
punch_cr = cairo_create (punch);
draw_3circles (punch_cr, xc, yc, radius, 1.0);
cairo_destroy (punch_cr);
cairo_set_operator (overlay_cr, CAIRO_OPERATOR_DEST_OUT);
cairo_set_source_surface (overlay_cr, punch, 0, 0);
cairo_paint (overlay_cr);
/* Now draw the 3 circles in a subgroup again
* at half intensity, and use OperatorAdd to join up
* without seams.
*/
circles_cr = cairo_create (circles);
cairo_set_operator (circles_cr, CAIRO_OPERATOR_OVER);
draw_3circles (circles_cr, xc, yc, radius, 0.5);
cairo_destroy (circles_cr);
cairo_set_operator (overlay_cr, CAIRO_OPERATOR_ADD);
cairo_set_source_surface (overlay_cr, circles, 0, 0);
cairo_paint (overlay_cr);
cairo_destroy (overlay_cr);
cairo_set_source_surface (cr, overlay, 0, 0);
cairo_paint (cr);
cairo_surface_destroy (overlay);
cairo_surface_destroy (punch);
cairo_surface_destroy (circles);
}
static gboolean
on_expose_event (GtkWidget *widget,
GdkEventExpose *event,
gpointer data)
{
cairo_t *cr;
Use a GtkAlignment rather than a GtkDrawingArea to draw the swatch in to 2005-05-11 Owen Taylor <otaylor@redhat.com> * gtk/gtkcolorbutton.c: Use a GtkAlignment rather than a GtkDrawingArea to draw the swatch in to avoid having an extraneous window. * gtk/gtkcolorsel.c (color_sample_draw_sample): Actually se tthe color when !has_opacity. 2005-05-10 Owen Taylor <otaylor@redhat.com> * gdk/gdkcairo.[ch] gdk/gdkcolor.[ch] gdk/Makefile.am: Add source files for Cairo convenience functionality. * gdk/gdkcairo.h (gdk_cairo_rectangle, gdk_cairo_region): Add a convenience functions to add GdkRectangle, GdkRegion to a cairo path. * gdk/gdkwindow.c gdk/gdkgc.c gtk/gtkcolorsel.c gtk/gtkiconview.c gtk/gtkstyle.c: Use gdk_cairo_rectangle/region(). * gdk/gdkcairo.[ch] gdk/gdkdrawable.h gdk/gdkdraw.c: Rename gdk_drawable_create_cairo_context() to gdk_cairo_create(). * gdk/gdkcairo.c gdk/gdkpixbuf.h gdk/gdkpixbuf-render.c: Rename gdk_pixbuf_set_as_cairo_source() to gdk_cairo_set_source_pixbuf(). * gdk/gdkdraw.c gdk/gdkpango.c gtk/gtkcolorsel.c gtk/gtkhruler.c gtk/gtkhsv.c gtk/gtkiconview.c gtk/gtkstyle.c gtk/gtkvruler.c: Adjust for renames. * gdk/gdk.symbols: Update. * gtk/gtkwidget.c (gtk_widget_queue_shallow_draw): Fix coordinate system problem that was causing the wrong portions to be invalidated. * gtk/gtkcellrenderer.c (gtk_cell_renderer_render) gtk/gtkcellrendererpixbuf.c (gtk_cell_renderer_pixbuf_render) gtk/gtkcellrendererprogress.c (gtk_cell_renderer_progress_render) gtk/gtkcellrenderertext.c (gtk_cell_renderer_text_render) gtk/gtkcellview.c (gtk_cell_view_expose) gtk/gtkdnd.c (gtk_drag_highlight_expose) gtk/gtkentry.c (gtk_entry_draw_text) gtk/gtktextview.c (text_window_invalidate_rect): Some cairoization. * gtk/gtkcalendar.[ch]: Beat into something roughly resembling GTK+ style ... use instance-private data and standard names for private structure, etc. Move function docs inline. * gtk/gtkcalendar.[ch]: Switch to drawing everything in expose. Switch drawing to Cairo. * gtk/gtkcalendar.c (gtk_calendar_freeze): Deprecate gtk_calendar_freeze/thaw
2005-05-11 19:16:19 +00:00
cr = gdk_cairo_create (widget->window);
draw (cr, widget->allocation.width, widget->allocation.height);
cairo_destroy (cr);
return FALSE;
}
int
main (int argc, char **argv)
{
GtkWidget *window, *darea;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
gtk_window_set_title (GTK_WINDOW (window), "cairo: Knockout Groups");
darea = gtk_drawing_area_new ();
gtk_container_add (GTK_CONTAINER (window), darea);
g_signal_connect (darea, "expose-event",
G_CALLBACK (on_expose_event), NULL);
g_signal_connect (window, "destroy-event",
G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}