goocanvas r24 - in trunk: . demo docs src



Author: damon
Date: Mon Nov  3 11:31:46 2008
New Revision: 24
URL: http://svn.gnome.org/viewvc/goocanvas?rev=24&view=rev

Log:

2008-11-03  Damon Chaplin  <damon gnome org>

	    * src/goocanvasgrid.[hc]: new grid item.

	    * demo/mv-demo.c (setup_grids): 
	    * demo/demo.c (setup_grids): added a grid.

	    * src/Makefile.am: added grid.

	    * src/goocanvas.[hc] (goo_canvas_convert_bounds_to_item_space): new
	    function to convert a bounding box in device space to a bounding box
	    in item space. Useful in paint() methods to optimize painting.

	    * src/goocanvasutils.c (goo_canvas_convert_colors_to_rgba)
	    (goo_canvas_get_rgba_value_from_pattern)
	    (goo_canvas_set_style_property_from_pattern)
	    (goo_canvas_create_pattern_from_color_value)
	    (goo_canvas_create_pattern_from_rgba_value)
	    (goo_canvas_create_pattern_from_pixbuf_value): new private utility
	    functions taken out of goocanvasitemsimple.c code.

	    * src/goocanvasitemsimple.c: use above utility functions.



Added:
   trunk/src/goocanvasgrid.c
   trunk/src/goocanvasgrid.h
Modified:
   trunk/ChangeLog
   trunk/demo/demo.c
   trunk/demo/mv-demo.c
   trunk/docs/goocanvas-docs.sgml
   trunk/docs/goocanvas-sections.txt
   trunk/docs/goocanvas.types
   trunk/src/Makefile.am
   trunk/src/goocanvas.c
   trunk/src/goocanvas.h
   trunk/src/goocanvasitemsimple.c
   trunk/src/goocanvasprivate.h
   trunk/src/goocanvasutils.c

Modified: trunk/demo/demo.c
==============================================================================
--- trunk/demo/demo.c	(original)
+++ trunk/demo/demo.c	Mon Nov  3 11:31:46 2008
@@ -1438,6 +1438,25 @@
 #endif
 }
 
+
+static void
+setup_grids (GooCanvasItem *root)
+{
+  GooCanvasItem *item;
+
+  item = goo_canvas_grid_new (root, 80, 310, 90, 90, 10, 10, 5, 5,
+			      "stroke-color", "yellow",
+			      "fill-color", "pink",
+			      "border-width", 2.0,
+			      "border-color", "red",
+			      "vert-grid-line-color", "lightblue",
+			      "horz-grid-line-width", 1.0,
+			      "vert-grid-line-width", 1.0,
+			      "vert-grid-lines-on-top", TRUE,
+			      NULL);
+}
+
+
 static void
 setup_canvas (GooCanvas *canvas)
 {
@@ -1458,6 +1477,7 @@
   setup_images (root);
   setup_invisible_texts (root);
   setup_static_items (canvas);
+  setup_grids (root);
 #endif
 
   test_color_properties (root);

Modified: trunk/demo/mv-demo.c
==============================================================================
--- trunk/demo/mv-demo.c	(original)
+++ trunk/demo/mv-demo.c	Mon Nov  3 11:31:46 2008
@@ -1292,6 +1292,24 @@
 }
 
 
+static void
+setup_grids (GooCanvasItemModel *root)
+{
+  GooCanvasItemModel *item;
+
+  item = goo_canvas_grid_model_new (root, 80, 310, 90, 90, 10, 10, 5, 5,
+				    "stroke-color", "yellow",
+				    "fill-color", "pink",
+				    "border-width", 2.0,
+				    "border-color", "red",
+				    "vert-grid-line-color", "lightblue",
+				    "horz-grid-line-width", 1.0,
+				    "vert-grid-line-width", 1.0,
+				    "vert-grid-lines-on-top", TRUE,
+				    NULL);
+}
+
+
 static GooCanvasItemModel*
 create_model (void)
 {
@@ -1309,6 +1327,7 @@
   setup_texts (root); 
   setup_images (root);
   setup_invisible_texts (root);
+  setup_grids (root);
 #endif
 #if 0
   setup_widgets (root);

Modified: trunk/docs/goocanvas-docs.sgml
==============================================================================
--- trunk/docs/goocanvas-docs.sgml	(original)
+++ trunk/docs/goocanvas-docs.sgml	Mon Nov  3 11:31:46 2008
@@ -31,6 +31,7 @@
     <title>Standard Canvas Items</title>
     <xi:include href="xml/goocanvasgroup.xml"/>
     <xi:include href="xml/goocanvasellipse.xml"/>
+    <xi:include href="xml/goocanvasgrid.xml"/>
     <xi:include href="xml/goocanvasimage.xml"/>
     <xi:include href="xml/goocanvaspath.xml"/>
     <xi:include href="xml/goocanvaspolyline.xml"/>
@@ -44,6 +45,7 @@
     <title>Standard Canvas Item Models</title>
     <xi:include href="xml/goocanvasgroupmodel.xml"/>
     <xi:include href="xml/goocanvasellipsemodel.xml"/>
+    <xi:include href="xml/goocanvasgridmodel.xml"/>
     <xi:include href="xml/goocanvasimagemodel.xml"/>
     <xi:include href="xml/goocanvaspathmodel.xml"/>
     <xi:include href="xml/goocanvaspolylinemodel.xml"/>

Modified: trunk/docs/goocanvas-sections.txt
==============================================================================
--- trunk/docs/goocanvas-sections.txt	(original)
+++ trunk/docs/goocanvas-sections.txt	Mon Nov  3 11:31:46 2008
@@ -387,6 +387,7 @@
 goo_canvas_convert_from_pixels
 goo_canvas_convert_to_item_space
 goo_canvas_convert_from_item_space
+goo_canvas_convert_bounds_to_item_space
 
 <SUBSECTION>
 goo_canvas_pointer_grab
@@ -592,6 +593,45 @@
 </SECTION>
 
 <SECTION>
+<FILE>goocanvasgrid</FILE>
+<TITLE>GooCanvasGrid</TITLE>
+GooCanvasGrid
+goo_canvas_grid_new
+
+<SUBSECTION Standard>
+GOO_CANVAS_GRID
+GOO_IS_CANVAS_GRID
+GOO_TYPE_CANVAS_GRID
+goo_canvas_grid_get_type
+GOO_CANVAS_GRID_CLASS
+GOO_IS_CANVAS_GRID_CLASS
+GOO_CANVAS_GRID_GET_CLASS
+
+<SUBSECTION Private>
+GooCanvasGridData
+GooCanvasGridClass
+</SECTION>
+
+<SECTION>
+<FILE>goocanvasgridmodel</FILE>
+<TITLE>GooCanvasGridModel</TITLE>
+GooCanvasGridModel
+goo_canvas_grid_model_new
+
+<SUBSECTION Standard>
+GOO_CANVAS_GRID_MODEL
+GOO_IS_CANVAS_GRID_MODEL
+GOO_TYPE_CANVAS_GRID_MODEL
+goo_canvas_grid_model_get_type
+GOO_CANVAS_GRID_MODEL_CLASS
+GOO_IS_CANVAS_GRID_MODEL_CLASS
+GOO_CANVAS_GRID_MODEL_GET_CLASS
+
+<SUBSECTION Private>
+GooCanvasGridModelClass
+</SECTION>
+
+<SECTION>
 <FILE>goocanvaswidget</FILE>
 <TITLE>GooCanvasWidget</TITLE>
 GooCanvasWidget

Modified: trunk/docs/goocanvas.types
==============================================================================
--- trunk/docs/goocanvas.types	(original)
+++ trunk/docs/goocanvas.types	Mon Nov  3 11:31:46 2008
@@ -37,3 +37,5 @@
 goo_canvas_image_model_get_type
 goo_canvas_table_get_type
 goo_canvas_table_model_get_type
+goo_canvas_grid_get_type
+goo_canvas_grid_model_get_type

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Mon Nov  3 11:31:46 2008
@@ -29,6 +29,7 @@
 
 libgoocanvas_public_headers =		\
 	goocanvasellipse.h		\
+	goocanvasgrid.h			\
 	goocanvasgroup.h		\
 	goocanvasimage.h		\
 	goocanvasitem.h			\
@@ -49,6 +50,7 @@
 	goocanvasatk.c			\
 	goocanvasellipse.c		\
 	goocanvasenumtypes.c		\
+	goocanvasgrid.c			\
 	goocanvasgroup.c		\
 	goocanvasimage.c		\
 	goocanvasitem.c			\

Modified: trunk/src/goocanvas.c
==============================================================================
--- trunk/src/goocanvas.c	(original)
+++ trunk/src/goocanvas.c	Mon Nov  3 11:31:46 2008
@@ -3486,22 +3486,9 @@
 }
 
 
-/**
- * goo_canvas_convert_to_item_space:
- * @canvas: a #GooCanvas.
- * @item: a #GooCanvasItem.
- * @x: a pointer to the x coordinate to convert.
- * @y: a pointer to the y coordinate to convert.
- * 
- * Converts a coordinate from the canvas coordinate space to the given
- * item's coordinate space, applying all transformation matrices including the
- * item's own transformation matrix, if it has one.
- **/
-void
-goo_canvas_convert_to_item_space (GooCanvas     *canvas,
-				  GooCanvasItem *item,
-				  gdouble       *x,
-				  gdouble       *y)
+static void
+get_transform_to_item_space (GooCanvasItem  *item,
+			     cairo_matrix_t *transform)
 {
   GooCanvasItem *tmp = item, *parent, *child;
   GList *list = NULL, *l;
@@ -3530,8 +3517,31 @@
     }
   g_list_free (list);
 
-  /* Now convert the coordinates. */
-  cairo_matrix_transform_point (&inverse, x, y);
+  *transform = inverse;
+}
+
+
+/**
+ * goo_canvas_convert_to_item_space:
+ * @canvas: a #GooCanvas.
+ * @item: a #GooCanvasItem.
+ * @x: a pointer to the x coordinate to convert.
+ * @y: a pointer to the y coordinate to convert.
+ * 
+ * Converts a coordinate from the canvas coordinate space to the given
+ * item's coordinate space, applying all transformation matrices including the
+ * item's own transformation matrix, if it has one.
+ **/
+void
+goo_canvas_convert_to_item_space (GooCanvas     *canvas,
+				  GooCanvasItem *item,
+				  gdouble       *x,
+				  gdouble       *y)
+{
+  cairo_matrix_t transform;
+
+  get_transform_to_item_space (item, &transform);
+  cairo_matrix_transform_point (&transform, x, y);
 }
 
 
@@ -3583,6 +3593,56 @@
 }
 
 
+/**
+ * goo_canvas_convert_bounds_to_item_space:
+ * @canvas: a #GooCanvas.
+ * @item: a #GooCanvasItem.
+ * @bounds: the bounds in device space.
+ * 
+ * Converts the bound in device space to a bounding box in item space.
+ * This is useful in the item paint() methods to convert the bounds to be
+ * painted to the item's coordinate space.
+ **/
+void
+goo_canvas_convert_bounds_to_item_space (GooCanvas           *canvas,
+					 GooCanvasItem       *item,
+					 GooCanvasBounds     *bounds)
+{
+  GooCanvasBounds tmp_bounds = *bounds, tmp_bounds2 = *bounds;
+  cairo_matrix_t transform;
+
+  get_transform_to_item_space (item, &transform);
+
+  /* Convert the top-left and bottom-right corners to device coords. */
+  cairo_matrix_transform_point (&transform, &tmp_bounds.x1, &tmp_bounds.y1);
+  cairo_matrix_transform_point (&transform, &tmp_bounds.x2, &tmp_bounds.y2);
+
+  /* Now convert the top-right and bottom-left corners. */
+  cairo_matrix_transform_point (&transform, &tmp_bounds2.x1, &tmp_bounds2.y2);
+  cairo_matrix_transform_point (&transform, &tmp_bounds2.x2, &tmp_bounds2.y1);
+
+  /* Calculate the minimum x coordinate seen and put in x1. */
+  bounds->x1 = MIN (tmp_bounds.x1, tmp_bounds.x2);
+  bounds->x1 = MIN (bounds->x1, tmp_bounds2.x1);
+  bounds->x1 = MIN (bounds->x1, tmp_bounds2.x2);
+
+  /* Calculate the maximum x coordinate seen and put in x2. */
+  bounds->x2 = MAX (tmp_bounds.x1, tmp_bounds.x2);
+  bounds->x2 = MAX (bounds->x2, tmp_bounds2.x1);
+  bounds->x2 = MAX (bounds->x2, tmp_bounds2.x2);
+
+  /* Calculate the minimum y coordinate seen and put in y1. */
+  bounds->y1 = MIN (tmp_bounds.y1, tmp_bounds.y2);
+  bounds->y1 = MIN (bounds->y1, tmp_bounds2.y1);
+  bounds->y1 = MIN (bounds->y1, tmp_bounds2.y2);
+
+  /* Calculate the maximum y coordinate seen and put in y2. */
+  bounds->y2 = MAX (tmp_bounds.y1, tmp_bounds.y2);
+  bounds->y2 = MAX (bounds->y2, tmp_bounds2.y1);
+  bounds->y2 = MAX (bounds->y2, tmp_bounds2.y2);
+}
+
+
 /*
  * Keyboard focus navigation.
  */

Modified: trunk/src/goocanvas.h
==============================================================================
--- trunk/src/goocanvas.h	(original)
+++ trunk/src/goocanvas.h	Mon Nov  3 11:31:46 2008
@@ -10,6 +10,7 @@
 #include <gtk/gtk.h>
 #include <goocanvasenumtypes.h>
 #include <goocanvasellipse.h>
+#include <goocanvasgrid.h>
 #include <goocanvasgroup.h>
 #include <goocanvasimage.h>
 #include <goocanvaspath.h>
@@ -272,6 +273,9 @@
 						    GooCanvasItem   *item,
 						    gdouble         *x,
 						    gdouble         *y);
+void		goo_canvas_convert_bounds_to_item_space (GooCanvas           *canvas,
+							 GooCanvasItem       *item,
+							 GooCanvasBounds     *bounds);
 
 
 /*

Added: trunk/src/goocanvasgrid.c
==============================================================================
--- (empty file)
+++ trunk/src/goocanvasgrid.c	Mon Nov  3 11:31:46 2008
@@ -0,0 +1,1075 @@
+/*
+ * GooCanvas. Copyright (C) 2005-8 Damon Chaplin.
+ * Released under the GNU LGPL license. See COPYING for details.
+ *
+ * goocanvasgrid.c - a grid item.
+ */
+
+/**
+ * SECTION:goocanvasgrid
+ * @Title: GooCanvasGrid
+ * @Short_Description: a grid item.
+ *
+ * GooCanvasGrid represents a grid item.
+ *
+ * It is a subclass of #GooCanvasItemSimple and so inherits all of the style
+ * properties such as "stroke-color", "fill-color" and "line-width".
+ *
+ * It also implements the #GooCanvasItem interface, so you can use the
+ * #GooCanvasItem functions such as goo_canvas_item_raise() and
+ * goo_canvas_item_rotate().
+ *
+ * To create a #GooCanvasGrid use goo_canvas_grid_new().
+ *
+ * To get or set the properties of an existing #GooCanvasGrid, use
+ * g_object_get() and g_object_set().
+ */
+#include <config.h>
+#include <math.h>
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+#include "goocanvasprivate.h"
+#include "goocanvas.h"
+
+
+enum {
+  PROP_0,
+
+  PROP_X,
+  PROP_Y,
+  PROP_WIDTH,
+  PROP_HEIGHT,
+  PROP_X_STEP,
+  PROP_Y_STEP,
+  PROP_X_OFFSET,
+  PROP_Y_OFFSET,
+  PROP_HORZ_GRID_LINE_WIDTH,
+  PROP_VERT_GRID_LINE_WIDTH,
+  PROP_HORZ_GRID_LINE_PATTERN,
+  PROP_VERT_GRID_LINE_PATTERN,
+  PROP_BORDER_WIDTH,
+  PROP_BORDER_PATTERN,
+  PROP_VERT_GRID_LINES_ON_TOP,
+
+  /* Convenience properties. */
+  PROP_HORZ_GRID_LINE_COLOR,
+  PROP_HORZ_GRID_LINE_COLOR_RGBA,
+  PROP_HORZ_GRID_LINE_PIXBUF,
+  PROP_VERT_GRID_LINE_COLOR,
+  PROP_VERT_GRID_LINE_COLOR_RGBA,
+  PROP_VERT_GRID_LINE_PIXBUF,
+  PROP_BORDER_COLOR,
+  PROP_BORDER_COLOR_RGBA,
+  PROP_BORDER_PIXBUF
+};
+
+
+GooCanvasItemIface *goo_canvas_grid_parent_iface;
+
+static void canvas_item_interface_init      (GooCanvasItemIface  *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GooCanvasGrid, goo_canvas_grid,
+                         GOO_TYPE_CANVAS_ITEM_SIMPLE,
+			 G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM,
+						canvas_item_interface_init))
+
+
+static void
+goo_canvas_grid_install_common_properties (GObjectClass *gobject_class)
+{
+  g_object_class_install_property (gobject_class, PROP_X,
+				   g_param_spec_double ("x",
+							"X",
+							_("The x coordinate of the grid"),
+							-G_MAXDOUBLE,
+							G_MAXDOUBLE, 0.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_Y,
+				   g_param_spec_double ("y",
+							"Y",
+							_("The y coordinate of the grid"),
+							-G_MAXDOUBLE,
+							G_MAXDOUBLE, 0.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_WIDTH,
+				   g_param_spec_double ("width",
+							_("Width"),
+							_("The width of the grid"),
+							0.0, G_MAXDOUBLE, 0.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_HEIGHT,
+				   g_param_spec_double ("height",
+							_("Height"),
+							_("The height of the grid"),
+							0.0, G_MAXDOUBLE, 0.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_X_STEP,
+				   g_param_spec_double ("x-step",
+							"X Step",
+							_("The distance between the vertical grid lines"),
+							0.0, G_MAXDOUBLE, 10.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_Y_STEP,
+				   g_param_spec_double ("y-step",
+							"Y Step",
+							_("The distance between the horizontal grid lines"),
+							0.0, G_MAXDOUBLE, 10.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_X_OFFSET,
+				   g_param_spec_double ("x-offset",
+							"X Offset",
+							_("The distance before the first vertical grid line"),
+							0.0, G_MAXDOUBLE, 0.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_Y_OFFSET,
+				   g_param_spec_double ("y-offset",
+							"Y Offset",
+							_("The distance before the first horizontal grid line"),
+							0.0, G_MAXDOUBLE, 0.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_HORZ_GRID_LINE_WIDTH,
+                                   g_param_spec_double ("horz-grid-line-width",
+                                                        _("Horizontal Grid Line Width"),
+                                                        _("The width of the horizontal grid lines"),
+							-G_MAXDOUBLE,
+							G_MAXDOUBLE, -1.0,
+                                                        G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_VERT_GRID_LINE_WIDTH,
+                                   g_param_spec_double ("vert-grid-line-width",
+							_("Vertical Grid Line Width"),
+							_("The width of the vertical grid lines"),
+							-G_MAXDOUBLE,
+							G_MAXDOUBLE, -1.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_HORZ_GRID_LINE_PATTERN,
+                                   g_param_spec_boxed ("horz-grid-line-pattern",
+						       _("Horizontal Grid Line Pattern"),
+						       _("The cairo pattern to paint the horizontal grid lines with"),
+						       GOO_TYPE_CAIRO_PATTERN,
+						       G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_VERT_GRID_LINE_PATTERN,
+                                   g_param_spec_boxed ("vert-grid-line-pattern",
+						       _("Vertical Grid Line Pattern"),
+						       _("The cairo pattern to paint the vertical grid lines with"),
+						       GOO_TYPE_CAIRO_PATTERN,
+						       G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_BORDER_WIDTH,
+				   g_param_spec_double ("border-width",
+							_("Border Width"),
+							_("The width of the border around the grid"),
+							-G_MAXDOUBLE,
+							G_MAXDOUBLE, -1.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_BORDER_PATTERN,
+                                   g_param_spec_boxed ("border-pattern",
+						       _("Border Pattern"),
+						       _("The cairo pattern to paint the border with"),
+						       GOO_TYPE_CAIRO_PATTERN,
+						       G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_VERT_GRID_LINES_ON_TOP,
+                                   g_param_spec_boolean ("vert-grid-lines-on-top",
+							 _("Vertical Grid Lines On Top"),
+							 _("If the vertical grid lines are painted above the horizontal grid lines"),
+							 FALSE,
+							 G_PARAM_READWRITE));
+
+
+  /* Convenience properties - some are writable only. */
+  g_object_class_install_property (gobject_class, PROP_HORZ_GRID_LINE_COLOR,
+				   g_param_spec_string ("horz-grid-line-color",
+							_("Horizontal Grid Line Color"),
+							_("The color to use for the horizontal grid lines"),
+							NULL,
+							G_PARAM_WRITABLE));
+
+  g_object_class_install_property (gobject_class, PROP_HORZ_GRID_LINE_COLOR_RGBA,
+				   g_param_spec_uint ("horz-grid-line-color-rgba",
+						      _("Horizontal Grid Line Color RGBA"),
+						      _("The color to use for the horizontal grid lines, specified as a 32-bit integer value"),
+						      0, G_MAXUINT, 0,
+						      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_HORZ_GRID_LINE_PIXBUF,
+                                   g_param_spec_object ("horz-grid-line-pixbuf",
+							_("Horizontal Grid Line Pixbuf"),
+							_("The pixbuf to use to draw the horizontal grid lines"),
+                                                        GDK_TYPE_PIXBUF,
+                                                        G_PARAM_WRITABLE));
+
+  g_object_class_install_property (gobject_class, PROP_VERT_GRID_LINE_COLOR,
+				   g_param_spec_string ("vert-grid-line-color",
+							_("Vertical Grid Line Color"),
+							_("The color to use for the vertical grid lines"),
+							NULL,
+							G_PARAM_WRITABLE));
+
+  g_object_class_install_property (gobject_class, PROP_VERT_GRID_LINE_COLOR_RGBA,
+				   g_param_spec_uint ("vert-grid-line-color-rgba",
+						      _("Vertical Grid Line Color RGBA"),
+						      _("The color to use for the vertical grid lines, specified as a 32-bit integer value"),
+						      0, G_MAXUINT, 0,
+						      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_VERT_GRID_LINE_PIXBUF,
+                                   g_param_spec_object ("vert-grid-line-pixbuf",
+							_("Vertical Grid Line Pixbuf"),
+							_("The pixbuf to use to draw the vertical grid lines"),
+                                                        GDK_TYPE_PIXBUF,
+                                                        G_PARAM_WRITABLE));
+
+  g_object_class_install_property (gobject_class, PROP_BORDER_COLOR,
+				   g_param_spec_string ("border-color",
+							_("Border Color"),
+							_("The color to use for the border"),
+							NULL,
+							G_PARAM_WRITABLE));
+
+  g_object_class_install_property (gobject_class, PROP_BORDER_COLOR_RGBA,
+				   g_param_spec_uint ("border-color-rgba",
+						      _("Border Color RGBA"),
+						      _("The color to use for the border, specified as a 32-bit integer value"),
+						      0, G_MAXUINT, 0,
+						      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_BORDER_PIXBUF,
+                                   g_param_spec_object ("border-pixbuf",
+							_("Border Pixbuf"),
+							_("The pixbuf to use to draw the border"),
+                                                        GDK_TYPE_PIXBUF,
+                                                        G_PARAM_WRITABLE));
+}
+
+
+/* This initializes the common grid data. */
+static void
+goo_canvas_grid_init_data (GooCanvasGridData *grid_data)
+{
+  grid_data->x = 0.0;
+  grid_data->y = 0.0;
+  grid_data->width = 0.0;
+  grid_data->height = 0.0;
+  grid_data->x_step = 10.0;
+  grid_data->y_step = 10.0;
+  grid_data->x_offset = 0.0;
+  grid_data->y_offset = 0.0;
+  grid_data->horz_grid_line_width = -1.0;
+  grid_data->vert_grid_line_width = -1.0;
+  grid_data->horz_grid_line_pattern = NULL;
+  grid_data->vert_grid_line_pattern = NULL;
+  grid_data->border_width = -1.0;
+  grid_data->border_pattern = NULL;
+  grid_data->vert_grid_lines_on_top = FALSE;
+}
+
+
+/* This frees the contents of the grid data, but not the struct itself. */
+static void
+goo_canvas_grid_free_data (GooCanvasGridData *grid_data)
+{
+
+}
+
+
+static void
+goo_canvas_grid_init (GooCanvasGrid *grid)
+{
+  grid->grid_data = g_slice_new0 (GooCanvasGridData);
+  goo_canvas_grid_init_data (grid->grid_data);
+}
+
+
+/**
+ * goo_canvas_grid_new:
+ * @parent: the parent item, or %NULL. If a parent is specified, it will assume
+ *  ownership of the item, and the item will automatically be freed when it is
+ *  removed from the parent. Otherwise call g_object_unref() to free it.
+ * @x: the x coordinate of the left of the grid.
+ * @y: the y coordinate of the top of the grid.
+ * @width: the width of the grid.
+ * @height: the height of the grid.
+ * @x_step: the distance between the vertical grid lines.
+ * @y_step: the distance between the horizontal grid lines.
+ * @x_offset: the distance before the first vertical grid line.
+ * @y_offset: the distance before the first horizontal grid line.
+ * @...: optional pairs of property names and values, and a terminating %NULL.
+ * 
+ * Creates a new grid item.
+ *
+ * <!--PARAMETERS-->
+ *
+ * Here's an example showing how to create a grid:
+ *
+ * <informalexample><programlisting>
+ *  GooCanvasItem *grid = goo_canvas_grid_new (mygroup, 100.0, 100.0, 400.0, 200.0,
+ *                                             20.0, 20.0, 10.0, 10.0,
+ *                                             "horz-grid-line-width", 4.0,
+ *                                             "horz-grid-line-color", "yellow",
+ *                                             "vert-grid-line-width", 2.0,
+ *                                             "vert-grid-line-color", "red",
+ *                                             "border-width", 3.0,
+ *                                             "border-color", "white",
+ *                                             "fill-color", "blue",
+ *                                             NULL);
+ * </programlisting></informalexample>
+ * 
+ * Returns: a new grid item.
+ **/
+GooCanvasItem*
+goo_canvas_grid_new (GooCanvasItem      *parent,
+		     gdouble             x,
+		     gdouble             y,
+		     gdouble             width,
+		     gdouble             height,
+		     gdouble             x_step,
+		     gdouble             y_step,
+		     gdouble             x_offset,
+		     gdouble             y_offset,
+		     ...)
+{
+  GooCanvasItem *item;
+  GooCanvasGrid *grid;
+  GooCanvasGridData *grid_data;
+  va_list var_args;
+  const char *first_property;
+
+  item = g_object_new (GOO_TYPE_CANVAS_GRID, NULL);
+  grid = (GooCanvasGrid*) item;
+
+  grid_data = grid->grid_data;
+  grid_data->x = x;
+  grid_data->y = y;
+  grid_data->width = width;
+  grid_data->height = height;
+  grid_data->x_step = x_step;
+  grid_data->y_step = y_step;
+  grid_data->x_offset = x_offset;
+  grid_data->y_offset = y_offset;
+
+  va_start (var_args, y_offset);
+  first_property = va_arg (var_args, char*);
+  if (first_property)
+    g_object_set_valist (G_OBJECT (item), first_property, var_args);
+  va_end (var_args);
+
+  if (parent)
+    {
+      goo_canvas_item_add_child (parent, item, -1);
+      g_object_unref (item);
+    }
+
+  return item;
+}
+
+
+static void
+goo_canvas_grid_finalize (GObject *object)
+{
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
+  GooCanvasGrid *grid = (GooCanvasGrid*) object;
+
+  /* Free our data if we didn't have a model. (If we had a model it would
+     have been reset in dispose() and simple_data will be NULL.) */
+  if (simple->simple_data)
+    {
+      goo_canvas_grid_free_data (grid->grid_data);
+      g_slice_free (GooCanvasGridData, grid->grid_data);
+    }
+  grid->grid_data = NULL;
+
+  G_OBJECT_CLASS (goo_canvas_grid_parent_class)->finalize (object);
+}
+
+
+static void
+goo_canvas_grid_get_common_property (GObject              *object,
+				     GooCanvasGridData    *grid_data,
+				     guint                 prop_id,
+				     GValue               *value,
+				     GParamSpec           *pspec)
+{
+  switch (prop_id)
+    {
+    case PROP_X:
+      g_value_set_double (value, grid_data->x);
+      break;
+    case PROP_Y:
+      g_value_set_double (value, grid_data->y);
+      break;
+    case PROP_WIDTH:
+      g_value_set_double (value, grid_data->width);
+      break;
+    case PROP_HEIGHT:
+      g_value_set_double (value, grid_data->height);
+      break;
+    case PROP_X_STEP:
+      g_value_set_double (value, grid_data->x_step);
+      break;
+    case PROP_Y_STEP:
+      g_value_set_double (value, grid_data->y_step);
+      break;
+    case PROP_X_OFFSET:
+      g_value_set_double (value, grid_data->x_offset);
+      break;
+    case PROP_Y_OFFSET:
+      g_value_set_double (value, grid_data->y_offset);
+      break;
+    case PROP_HORZ_GRID_LINE_WIDTH:
+      g_value_set_double (value, grid_data->horz_grid_line_width);
+      break;
+    case PROP_VERT_GRID_LINE_WIDTH:
+      g_value_set_double (value, grid_data->vert_grid_line_width);
+      break;
+    case PROP_HORZ_GRID_LINE_PATTERN:
+      g_value_set_boxed (value, grid_data->horz_grid_line_pattern);
+      break;
+    case PROP_VERT_GRID_LINE_PATTERN:
+      g_value_set_boxed (value, grid_data->vert_grid_line_pattern);
+      break;
+    case PROP_BORDER_WIDTH:
+      g_value_set_double (value, grid_data->border_width);
+      break;
+    case PROP_BORDER_PATTERN:
+      g_value_set_boxed (value, grid_data->border_pattern);
+      break;
+    case PROP_VERT_GRID_LINES_ON_TOP:
+      g_value_set_boolean (value, grid_data->vert_grid_lines_on_top);
+      break;
+
+  /* Convenience properties. */
+    case PROP_HORZ_GRID_LINE_COLOR_RGBA:
+      goo_canvas_get_rgba_value_from_pattern (grid_data->horz_grid_line_pattern, value);
+      break;
+    case PROP_VERT_GRID_LINE_COLOR_RGBA:
+      goo_canvas_get_rgba_value_from_pattern (grid_data->vert_grid_line_pattern, value);
+      break;
+    case PROP_BORDER_COLOR_RGBA:
+      goo_canvas_get_rgba_value_from_pattern (grid_data->border_pattern, value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+goo_canvas_grid_get_property (GObject              *object,
+			      guint                 prop_id,
+			      GValue               *value,
+			      GParamSpec           *pspec)
+{
+  GooCanvasGrid *grid = (GooCanvasGrid*) object;
+
+  goo_canvas_grid_get_common_property (object, grid->grid_data,
+					  prop_id, value, pspec);
+}
+
+
+static void
+goo_canvas_grid_set_common_property (GObject              *object,
+				     GooCanvasGridData    *grid_data,
+				     guint                 prop_id,
+				     const GValue         *value,
+				     GParamSpec           *pspec)
+{
+  switch (prop_id)
+    {
+    case PROP_X:
+      grid_data->x = g_value_get_double (value);
+      break;
+    case PROP_Y:
+      grid_data->y = g_value_get_double (value);
+      break;
+    case PROP_WIDTH:
+      grid_data->width = g_value_get_double (value);
+      break;
+    case PROP_HEIGHT:
+      grid_data->height = g_value_get_double (value);
+      break;
+    case PROP_X_STEP:
+      grid_data->x_step = g_value_get_double (value);
+      break;
+    case PROP_Y_STEP:
+      grid_data->y_step = g_value_get_double (value);
+      break;
+    case PROP_X_OFFSET:
+      grid_data->x_offset = g_value_get_double (value);
+      break;
+    case PROP_Y_OFFSET:
+      grid_data->y_offset = g_value_get_double (value);
+      break;
+    case PROP_HORZ_GRID_LINE_WIDTH:
+      grid_data->horz_grid_line_width = g_value_get_double (value);
+      break;
+    case PROP_VERT_GRID_LINE_WIDTH:
+      grid_data->vert_grid_line_width = g_value_get_double (value);
+      break;
+    case PROP_HORZ_GRID_LINE_PATTERN:
+      cairo_pattern_destroy (grid_data->horz_grid_line_pattern);
+      grid_data->horz_grid_line_pattern = g_value_get_boxed (value);
+      cairo_pattern_reference (grid_data->horz_grid_line_pattern);
+      break;
+    case PROP_VERT_GRID_LINE_PATTERN:
+      cairo_pattern_destroy (grid_data->vert_grid_line_pattern);
+      grid_data->vert_grid_line_pattern = g_value_get_boxed (value);
+      cairo_pattern_reference (grid_data->vert_grid_line_pattern);
+      break;
+    case PROP_BORDER_WIDTH:
+      grid_data->border_width = g_value_get_double (value);
+      break;
+    case PROP_BORDER_PATTERN:
+      cairo_pattern_destroy (grid_data->border_pattern);
+      grid_data->border_pattern = g_value_get_boxed (value);
+      cairo_pattern_reference (grid_data->border_pattern);
+      break;
+    case PROP_VERT_GRID_LINES_ON_TOP:
+      grid_data->vert_grid_lines_on_top = g_value_get_boolean (value);
+      break;
+
+  /* Convenience properties. */
+    case PROP_HORZ_GRID_LINE_COLOR:
+      cairo_pattern_destroy (grid_data->horz_grid_line_pattern);
+      grid_data->horz_grid_line_pattern = goo_canvas_create_pattern_from_color_value (value);
+      break;
+    case PROP_HORZ_GRID_LINE_COLOR_RGBA:
+      cairo_pattern_destroy (grid_data->horz_grid_line_pattern);
+      grid_data->horz_grid_line_pattern = goo_canvas_create_pattern_from_rgba_value (value);
+      break;
+    case PROP_HORZ_GRID_LINE_PIXBUF:
+      cairo_pattern_destroy (grid_data->horz_grid_line_pattern);
+      grid_data->horz_grid_line_pattern = goo_canvas_create_pattern_from_pixbuf_value (value);
+      break;
+
+    case PROP_VERT_GRID_LINE_COLOR:
+      cairo_pattern_destroy (grid_data->vert_grid_line_pattern);
+      grid_data->vert_grid_line_pattern = goo_canvas_create_pattern_from_color_value (value);
+      break;
+    case PROP_VERT_GRID_LINE_COLOR_RGBA:
+      cairo_pattern_destroy (grid_data->vert_grid_line_pattern);
+      grid_data->vert_grid_line_pattern = goo_canvas_create_pattern_from_rgba_value (value);
+      break;
+    case PROP_VERT_GRID_LINE_PIXBUF:
+      cairo_pattern_destroy (grid_data->vert_grid_line_pattern);
+      grid_data->vert_grid_line_pattern = goo_canvas_create_pattern_from_pixbuf_value (value);
+      break;
+
+    case PROP_BORDER_COLOR:
+      cairo_pattern_destroy (grid_data->border_pattern);
+      grid_data->border_pattern = goo_canvas_create_pattern_from_color_value (value);
+      break;
+    case PROP_BORDER_COLOR_RGBA:
+      cairo_pattern_destroy (grid_data->border_pattern);
+      grid_data->border_pattern = goo_canvas_create_pattern_from_rgba_value (value);
+      break;
+    case PROP_BORDER_PIXBUF:
+      cairo_pattern_destroy (grid_data->border_pattern);
+      grid_data->border_pattern = goo_canvas_create_pattern_from_pixbuf_value (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+goo_canvas_grid_set_property (GObject              *object,
+			      guint                 prop_id,
+			      const GValue         *value,
+			      GParamSpec           *pspec)
+{
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
+  GooCanvasGrid *grid = (GooCanvasGrid*) object;
+
+  if (simple->model)
+    {
+      g_warning ("Can't set property of a canvas item with a model - set the model property instead");
+      return;
+    }
+
+  goo_canvas_grid_set_common_property (object, grid->grid_data,
+					  prop_id, value, pspec);
+  goo_canvas_item_simple_changed (simple, TRUE);
+}
+
+
+static void
+goo_canvas_grid_update  (GooCanvasItemSimple *simple,
+			 cairo_t             *cr)
+{
+  GooCanvasGrid *grid = (GooCanvasGrid*) simple;
+  GooCanvasGridData *grid_data = grid->grid_data;
+  gdouble border_width = 0.0;
+
+  /* We can quickly compute the bounds as being just the grid's size
+     plus the border width around each edge. */
+  if (grid_data->border_width > 0.0)
+    border_width = grid_data->border_width;
+
+  simple->bounds.x1 = grid_data->x - border_width;
+  simple->bounds.y1 = grid_data->y - border_width;
+  simple->bounds.x2 = grid_data->x + grid_data->width + border_width;
+  simple->bounds.y2 = grid_data->y + grid_data->height + border_width;
+}
+
+
+static gdouble
+calculate_start_position (gdouble start_pos,
+			  gdouble step,
+			  gdouble redraw_start_pos,
+			  gdouble line_width)
+{
+  gdouble n, result;
+
+  /* We want the first position where pos + line_width/2 >= redraw_start_pos.
+     i.e. start_pos + (n * step) + (line_width / 2) >= redraw_start_pos,
+     or   (n * step) >= redraw_start_pos - start_pos - (line_width / 2),
+     or   n >= (redraw_start_pos - start_pos - (line_width / 2) / step). */
+  n = ceil (((redraw_start_pos - start_pos - (line_width / 2.0))) / step);
+
+  if (n <= 0)
+    result = start_pos;
+  else
+    result = start_pos + (n * step);
+
+  return result;
+}
+
+
+static void
+paint_vertical_lines (GooCanvasItemSimple   *simple,
+		      cairo_t               *cr,
+		      const GooCanvasBounds *bounds)
+{
+  GooCanvasItemSimpleData *simple_data = simple->simple_data;
+  GooCanvasGrid *grid = (GooCanvasGrid*) simple;
+  GooCanvasGridData *grid_data = grid->grid_data;
+  double x, max_x, max_y, max_bounds_x, line_width;
+  gboolean has_stroke;
+
+  max_x = grid_data->x + grid_data->width;
+  max_y = grid_data->y + grid_data->height;
+
+  has_stroke = goo_canvas_style_set_stroke_options (simple_data->style, cr);
+  line_width = goo_canvas_item_simple_get_line_width (simple);
+
+  /* If the grid's vertical grid line pattern/color has been set, use that.
+     If not, and we don't have a stroke color just return. */
+  if (grid_data->vert_grid_line_pattern)
+    cairo_set_source (cr, grid_data->vert_grid_line_pattern);
+  else if (!has_stroke)
+    return;
+
+  /* If the grid's vertical grid line width has been set, use that. */
+  if (grid_data->vert_grid_line_width > 0.0)
+    {
+      line_width = grid_data->vert_grid_line_width;
+      cairo_set_line_width (cr, line_width);
+    }
+
+  cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+
+  /* Calculate the first grid line that intersects the bounds to redraw. */
+  x = calculate_start_position (grid_data->x + grid_data->x_offset,
+				grid_data->x_step, bounds->x1, line_width);
+
+  /* Calculate the last possible line position. */
+  max_bounds_x = bounds->x2 + (line_width / 2.0);
+  max_x = MIN (max_x, max_bounds_x);
+
+  /* Add on a tiny fraction of step to avoid any double comparison issues. */
+  max_x += grid_data->x_step * 0.00001;
+
+  while (x <= max_x)
+    {
+      cairo_move_to (cr, x, grid_data->y);
+      cairo_line_to (cr, x, max_y);
+      cairo_stroke (cr);
+
+      x += grid_data->x_step;
+    }
+}
+
+
+static void
+paint_horizontal_lines (GooCanvasItemSimple   *simple,
+			cairo_t               *cr,
+			const GooCanvasBounds *bounds)
+{
+  GooCanvasItemSimpleData *simple_data = simple->simple_data;
+  GooCanvasGrid *grid = (GooCanvasGrid*) simple;
+  GooCanvasGridData *grid_data = grid->grid_data;
+  double y, max_x, max_y, max_bounds_y, line_width;
+  gboolean has_stroke;
+
+  max_x = grid_data->x + grid_data->width;
+  max_y = grid_data->y + grid_data->height;
+
+  has_stroke = goo_canvas_style_set_stroke_options (simple_data->style, cr);
+  line_width = goo_canvas_item_simple_get_line_width (simple);
+
+  /* If the grid's horizontal grid line pattern/color has been set, use that.
+     If not, and we don't have a stroke color just return. */
+  if (grid_data->horz_grid_line_pattern)
+    cairo_set_source (cr, grid_data->horz_grid_line_pattern);
+  else if (!has_stroke)
+    return;
+
+  /* If the grid's horizontal grid line width has been set, use that. */
+  if (grid_data->horz_grid_line_width > 0.0)
+    {
+      line_width = grid_data->horz_grid_line_width;
+      cairo_set_line_width (cr, grid_data->horz_grid_line_width);
+    }
+
+  cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+
+  /* Calculate the first grid line that intersects the bounds to redraw. */
+  y = calculate_start_position (grid_data->y + grid_data->y_offset,
+				grid_data->y_step, bounds->y1, line_width);
+
+  /* Calculate the last possible line position. */
+  max_bounds_y = bounds->y2 + (line_width / 2.0);
+  max_y = MIN (max_y, max_bounds_y);
+
+  /* Add on a tiny fraction of step to avoid any double comparison issues. */
+  max_y += grid_data->y_step * 0.00001;
+
+  while (y <= max_y)
+    {
+      cairo_move_to (cr, grid_data->x, y);
+      cairo_line_to (cr, max_x, y);
+      cairo_stroke (cr);
+
+      y += grid_data->y_step;
+    }
+}
+
+
+static void
+goo_canvas_grid_paint (GooCanvasItemSimple   *simple,
+		       cairo_t               *cr,
+		       const GooCanvasBounds *bounds)
+{
+  GooCanvasItemSimpleData *simple_data = simple->simple_data;
+  GooCanvasGrid *grid = (GooCanvasGrid*) simple;
+  GooCanvasGridData *grid_data = grid->grid_data;
+  GooCanvasBounds redraw_bounds = *bounds;
+  gdouble half_border_width;
+
+  /* Paint the background in the fill pattern/color, if one is set. */
+  if (goo_canvas_style_set_fill_options (simple_data->style, cr))
+    {
+      cairo_rectangle (cr, grid_data->x, grid_data->y,
+		       grid_data->width, grid_data->height);
+      cairo_fill (cr);
+    }
+
+  /* Clip to the grid's area while painting the grid lines. */
+  cairo_save (cr);
+  cairo_rectangle (cr, grid_data->x, grid_data->y,
+		   grid_data->width, grid_data->height);
+  cairo_clip (cr);
+
+  /* Convert the bounds to be redrawn from device space to item space. */
+  goo_canvas_convert_bounds_to_item_space (simple->canvas,
+					   (GooCanvasItem*) simple,
+					   &redraw_bounds);
+
+  /* Paint the grid lines, in the required order. */
+  if (grid_data->vert_grid_lines_on_top)
+    {
+      paint_horizontal_lines (simple, cr, &redraw_bounds);
+      paint_vertical_lines (simple, cr, &redraw_bounds);
+    }
+  else
+    {
+      paint_vertical_lines (simple, cr, &redraw_bounds);
+      paint_horizontal_lines (simple, cr, &redraw_bounds);
+    }
+
+  cairo_restore (cr);
+
+  /* Paint the border. */
+  if (grid_data->border_width > 0)
+    {
+      if (grid_data->border_pattern)
+	cairo_set_source (cr, grid_data->border_pattern);
+      else
+	goo_canvas_style_set_stroke_options (simple_data->style, cr);
+
+      cairo_set_line_width (cr, grid_data->border_width);
+      half_border_width = grid_data->border_width / 2.0;
+      cairo_rectangle (cr, grid_data->x - half_border_width,
+		       grid_data->y - half_border_width,
+		       grid_data->width + grid_data->border_width,
+		       grid_data->height + grid_data->border_width);
+      cairo_stroke (cr);
+    }
+}
+
+
+static void
+goo_canvas_grid_set_model    (GooCanvasItem      *item,
+			      GooCanvasItemModel *model)
+{
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
+  GooCanvasGrid *grid = (GooCanvasGrid*) item;
+  GooCanvasGridModel *gmodel = (GooCanvasGridModel*) model;
+
+  /* If our grid_data was allocated, free it. */
+  if (!simple->model)
+    {
+      goo_canvas_grid_free_data (grid->grid_data);
+      g_slice_free (GooCanvasGridData, grid->grid_data);
+    }
+
+  /* Now use the new model's grid_data instead. */
+  grid->grid_data = &gmodel->grid_data;
+
+  /* Let the parent class do the rest. */
+  goo_canvas_grid_parent_iface->set_model (item, model);
+}
+
+
+static void
+canvas_item_interface_init (GooCanvasItemIface *iface)
+{
+  iface->set_model      = goo_canvas_grid_set_model;
+}
+
+
+static void
+goo_canvas_grid_class_init (GooCanvasGridClass *klass)
+{
+  GObjectClass *gobject_class = (GObjectClass*) klass;
+  GooCanvasItemSimpleClass *simple_class = (GooCanvasItemSimpleClass*) klass;
+
+  goo_canvas_grid_parent_iface = g_type_interface_peek (goo_canvas_grid_parent_class, GOO_TYPE_CANVAS_ITEM);
+
+  gobject_class->finalize    = goo_canvas_grid_finalize;
+
+  gobject_class->get_property = goo_canvas_grid_get_property;
+  gobject_class->set_property = goo_canvas_grid_set_property;
+
+  simple_class->simple_update      = goo_canvas_grid_update;
+  simple_class->simple_paint       = goo_canvas_grid_paint;
+
+  goo_canvas_grid_install_common_properties (gobject_class);
+}
+
+
+
+/**
+ * SECTION:goocanvasgridmodel
+ * @Title: GooCanvasGridModel
+ * @Short_Description: a model for grid items.
+ *
+ * GooCanvasGridModel represents a model for grid items.
+ *
+ * It is a subclass of #GooCanvasItemModelSimple and so inherits all of the
+ * style properties such as "stroke-color", "fill-color" and "line-width".
+ *
+ * It also implements the #GooCanvasItemModel interface, so you can use the
+ * #GooCanvasItemModel functions such as goo_canvas_item_model_raise() and
+ * goo_canvas_item_model_rotate().
+ *
+ * To create a #GooCanvasGridModel use goo_canvas_grid_model_new().
+ *
+ * To get or set the properties of an existing #GooCanvasGridModel, use
+ * g_object_get() and g_object_set().
+ *
+ * To respond to events such as mouse clicks on the grid you must connect
+ * to the signal handlers of the corresponding #GooCanvasGrid objects.
+ * (See goo_canvas_get_item() and #GooCanvas::item-created.)
+ */
+
+GooCanvasItemModelIface *goo_canvas_grid_model_parent_iface;
+
+static void item_model_interface_init (GooCanvasItemModelIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GooCanvasGridModel, goo_canvas_grid_model,
+                         GOO_TYPE_CANVAS_ITEM_MODEL_SIMPLE,
+			 G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM_MODEL,
+						item_model_interface_init))
+
+
+static void
+goo_canvas_grid_model_init (GooCanvasGridModel *gmodel)
+{
+  goo_canvas_grid_init_data (&gmodel->grid_data);
+}
+
+
+/**
+ * goo_canvas_grid_model_new:
+ * @parent: the parent model, or %NULL. If a parent is specified, it will assume
+ *  ownership of the item, and the item will automatically be freed when it is
+ *  removed from the parent. Otherwise call g_object_unref() to free it.
+ * @x: the x coordinate of the left of the grid.
+ * @y: the y coordinate of the top of the grid.
+ * @width: the width of the grid.
+ * @height: the height of the grid.
+ * @x_step: the distance between the vertical grid lines.
+ * @y_step: the distance between the horizontal grid lines.
+ * @x_offset: the distance before the first vertical grid line.
+ * @y_offset: the distance before the first horizontal grid line.
+ * @...: optional pairs of property names and values, and a terminating %NULL.
+ * 
+ * Creates a new grid model.
+ *
+ * <!--PARAMETERS-->
+ *
+ * Here's an example showing how to create a grid:
+ *
+ * <informalexample><programlisting>
+ *  GooCanvasItemModel *grid = goo_canvas_grid_model_new (mygroup, 100.0, 100.0, 400.0, 200.0,
+ *                                                        20.0, 20.0, 10.0, 10.0,
+ *                                                        "horz-grid-line-width", 4.0,
+ *                                                        "horz-grid-line-color", "yellow",
+ *                                                        "vert-grid-line-width", 2.0,
+ *                                                        "vert-grid-line-color", "red",
+ *                                                        "border-width", 3.0,
+ *                                                        "border-color", "white",
+ *                                                        "fill-color", "blue",
+ *                                                        NULL);
+ * </programlisting></informalexample>
+ * 
+ * Returns: a new grid model.
+ **/
+GooCanvasItemModel*
+goo_canvas_grid_model_new (GooCanvasItemModel *parent,
+			   gdouble             x,
+			   gdouble             y,
+			   gdouble             width,
+			   gdouble             height,
+			   gdouble             x_step,
+			   gdouble             y_step,
+			   gdouble             x_offset,
+			   gdouble             y_offset,
+			   ...)
+{
+  GooCanvasItemModel *model;
+  GooCanvasGridModel *gmodel;
+  GooCanvasGridData *grid_data;
+  const char *first_property;
+  va_list var_args;
+
+  model = g_object_new (GOO_TYPE_CANVAS_GRID_MODEL, NULL);
+  gmodel = (GooCanvasGridModel*) model;
+
+  grid_data = &gmodel->grid_data;
+  grid_data->x = x;
+  grid_data->y = y;
+  grid_data->width = width;
+  grid_data->height = height;
+  grid_data->x_step = x_step;
+  grid_data->y_step = y_step;
+  grid_data->x_offset = x_offset;
+  grid_data->y_offset = y_offset;
+
+  va_start (var_args, y_offset);
+  first_property = va_arg (var_args, char*);
+  if (first_property)
+    g_object_set_valist ((GObject*) model, first_property, var_args);
+  va_end (var_args);
+
+  if (parent)
+    {
+      goo_canvas_item_model_add_child (parent, model, -1);
+      g_object_unref (model);
+    }
+
+  return model;
+}
+
+
+static void
+goo_canvas_grid_model_finalize (GObject *object)
+{
+  GooCanvasGridModel *gmodel = (GooCanvasGridModel*) object;
+
+  goo_canvas_grid_free_data (&gmodel->grid_data);
+
+  G_OBJECT_CLASS (goo_canvas_grid_model_parent_class)->finalize (object);
+}
+
+
+static void
+goo_canvas_grid_model_get_property (GObject              *object,
+				    guint                 prop_id,
+				    GValue               *value,
+				    GParamSpec           *pspec)
+{
+  GooCanvasGridModel *gmodel = (GooCanvasGridModel*) object;
+
+  goo_canvas_grid_get_common_property (object, &gmodel->grid_data,
+					  prop_id, value, pspec);
+}
+
+
+static void
+goo_canvas_grid_model_set_property (GObject              *object,
+				    guint                 prop_id,
+				    const GValue         *value,
+				    GParamSpec           *pspec)
+{
+  GooCanvasGridModel *gmodel = (GooCanvasGridModel*) object;
+
+  goo_canvas_grid_set_common_property (object, &gmodel->grid_data,
+					  prop_id, value, pspec);
+  g_signal_emit_by_name (gmodel, "changed", TRUE);
+}
+
+
+static GooCanvasItem*
+goo_canvas_grid_model_create_item (GooCanvasItemModel *model,
+				   GooCanvas          *canvas)
+{
+  GooCanvasItem *item;
+
+  item = g_object_new (GOO_TYPE_CANVAS_GRID, NULL);
+  goo_canvas_item_set_model (item, model);
+
+  return item;
+}
+
+
+static void
+item_model_interface_init (GooCanvasItemModelIface *iface)
+{
+  iface->create_item    = goo_canvas_grid_model_create_item;
+}
+
+
+static void
+goo_canvas_grid_model_class_init (GooCanvasGridModelClass *klass)
+{
+  GObjectClass *gobject_class = (GObjectClass*) klass;
+
+  goo_canvas_grid_model_parent_iface = g_type_interface_peek (goo_canvas_grid_model_parent_class, GOO_TYPE_CANVAS_ITEM_MODEL);
+
+  gobject_class->finalize     = goo_canvas_grid_model_finalize;
+
+  gobject_class->get_property = goo_canvas_grid_model_get_property;
+  gobject_class->set_property = goo_canvas_grid_model_set_property;
+
+  goo_canvas_grid_install_common_properties (gobject_class);
+}
+
+

Added: trunk/src/goocanvasgrid.h
==============================================================================
--- (empty file)
+++ trunk/src/goocanvasgrid.h	Mon Nov  3 11:31:46 2008
@@ -0,0 +1,149 @@
+/*
+ * GooCanvas. Copyright (C) 2005-8 Damon Chaplin.
+ * Released under the GNU LGPL license. See COPYING for details.
+ *
+ * goocanvasgrid.h - a grid item.
+ */
+#ifndef __GOO_CANVAS_GRID_H__
+#define __GOO_CANVAS_GRID_H__
+
+#include <gtk/gtk.h>
+#include "goocanvasitemsimple.h"
+
+G_BEGIN_DECLS
+
+
+/* This is the data used by both model and view classes. */
+typedef struct _GooCanvasGridData   GooCanvasGridData;
+struct _GooCanvasGridData
+{
+  /* The area that the grid covers. */
+  gdouble x, y, width, height;
+
+  /* The distance between grid lines. */
+  gdouble x_step, y_step;
+
+  /* The offset before the first grid line. */
+  gdouble x_offset, y_offset;
+
+  /* The widths of the grid lines, or -ve to use item's stroke width. */
+  gdouble horz_grid_line_width, vert_grid_line_width;
+
+  /* The color/pattern for the grid lines, or NULL to use the stroke color. */
+  cairo_pattern_t *horz_grid_line_pattern, *vert_grid_line_pattern;
+
+  /* The width of the border around the grid, or -1 for no border. */
+  gdouble border_width;
+
+  /* The color/pattern for the border, or NULL to use the stroke color. */
+  cairo_pattern_t *border_pattern;
+
+  /* If vertical grid lines are drawn on top. */
+  guint vert_grid_lines_on_top : 1;
+};
+
+
+#define GOO_TYPE_CANVAS_GRID            (goo_canvas_grid_get_type ())
+#define GOO_CANVAS_GRID(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOO_TYPE_CANVAS_GRID, GooCanvasGrid))
+#define GOO_CANVAS_GRID_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GOO_TYPE_CANVAS_GRID, GooCanvasGridClass))
+#define GOO_IS_CANVAS_GRID(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOO_TYPE_CANVAS_GRID))
+#define GOO_IS_CANVAS_GRID_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GOO_TYPE_CANVAS_GRID))
+#define GOO_CANVAS_GRID_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GOO_TYPE_CANVAS_GRID, GooCanvasGridClass))
+
+
+typedef struct _GooCanvasGrid       GooCanvasGrid;
+typedef struct _GooCanvasGridClass  GooCanvasGridClass;
+
+/**
+ * GooCanvasGrid
+ *
+ * The #GooCanvasGrid-struct struct contains private data only.
+ */
+struct _GooCanvasGrid
+{
+  GooCanvasItemSimple parent_object;
+
+  GooCanvasGridData *grid_data;
+};
+
+struct _GooCanvasGridClass
+{
+  GooCanvasItemSimpleClass parent_class;
+
+  /*< private >*/
+
+  /* Padding for future expansion */
+  void (*_goo_canvas_reserved1) (void);
+  void (*_goo_canvas_reserved2) (void);
+  void (*_goo_canvas_reserved3) (void);
+  void (*_goo_canvas_reserved4) (void);
+};
+
+
+GType          goo_canvas_grid_get_type      (void) G_GNUC_CONST;
+GooCanvasItem* goo_canvas_grid_new           (GooCanvasItem      *parent,
+					      gdouble             x,
+					      gdouble             y,
+					      gdouble             width,
+					      gdouble             height,
+					      gdouble             x_step,
+					      gdouble             y_step,
+					      gdouble             x_offset,
+					      gdouble             y_offset,
+					      ...);
+
+
+
+#define GOO_TYPE_CANVAS_GRID_MODEL            (goo_canvas_grid_model_get_type ())
+#define GOO_CANVAS_GRID_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOO_TYPE_CANVAS_GRID_MODEL, GooCanvasGridModel))
+#define GOO_CANVAS_GRID_MODEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GOO_TYPE_CANVAS_GRID_MODEL, GooCanvasGridModelClass))
+#define GOO_IS_CANVAS_GRID_MODEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOO_TYPE_CANVAS_GRID_MODEL))
+#define GOO_IS_CANVAS_GRID_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GOO_TYPE_CANVAS_GRID_MODEL))
+#define GOO_CANVAS_GRID_MODEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GOO_TYPE_CANVAS_GRID_MODEL, GooCanvasGridModelClass))
+
+
+typedef struct _GooCanvasGridModel       GooCanvasGridModel;
+typedef struct _GooCanvasGridModelClass  GooCanvasGridModelClass;
+
+/**
+ * GooCanvasGridModel
+ *
+ * The #GooCanvasGridModel-struct struct contains private data only.
+ */
+struct _GooCanvasGridModel
+{
+  GooCanvasItemModelSimple parent_object;
+
+  GooCanvasGridData grid_data;
+};
+
+struct _GooCanvasGridModelClass
+{
+  GooCanvasItemModelSimpleClass parent_class;
+
+  /*< private >*/
+
+  /* Padding for future expansion */
+  void (*_goo_canvas_reserved1) (void);
+  void (*_goo_canvas_reserved2) (void);
+  void (*_goo_canvas_reserved3) (void);
+  void (*_goo_canvas_reserved4) (void);
+};
+
+
+GType               goo_canvas_grid_model_get_type (void) G_GNUC_CONST;
+GooCanvasItemModel* goo_canvas_grid_model_new      (GooCanvasItemModel *parent,
+						    gdouble             x,
+						    gdouble             y,
+						    gdouble             width,
+						    gdouble             height,
+						    gdouble             x_step,
+						    gdouble             y_step,
+						    gdouble             x_offset,
+						    gdouble             y_offset,
+						    ...);
+
+
+G_END_DECLS
+
+#endif /* __GOO_CANVAS_GRID_H__ */

Modified: trunk/src/goocanvasitemsimple.c
==============================================================================
--- trunk/src/goocanvasitemsimple.c	(original)
+++ trunk/src/goocanvasitemsimple.c	Mon Nov  3 11:31:46 2008
@@ -432,27 +432,6 @@
 }
 
 
-static guint
-convert_color (double red, double green, double blue, double alpha)
-{
-  guint red_byte, green_byte, blue_byte, alpha_byte;
-
-  red_byte = red * 256;
-  red_byte -= red_byte >> 8;
-
-  green_byte = green * 256;
-  green_byte -= green_byte >> 8;
-
-  blue_byte = blue * 256;
-  blue_byte -= blue_byte >> 8;
-
-  alpha_byte = alpha * 256;
-  alpha_byte -= alpha_byte >> 8;
-
-  return (red_byte << 24) + (green_byte << 16) + (blue_byte << 8) + alpha_byte;
-}
-
-
 static void
 goo_canvas_item_simple_get_common_property (GObject                 *object,
 					    GooCanvasItemSimpleData *simple_data,
@@ -465,9 +444,6 @@
   GValue *svalue;
   gdouble line_width = 2.0;
   gchar *font = NULL;
-  cairo_pattern_t *pattern;
-  double red, green, blue, alpha;
-  guint rgba = 0;
 
   switch (prop_id)
     {
@@ -539,29 +515,15 @@
       /* Convenience properties. */
     case PROP_STROKE_COLOR_RGBA:
       svalue = goo_canvas_style_get_property (style, goo_canvas_style_stroke_pattern_id);
-      if (svalue && svalue->data[0].v_pointer)
-	{
-	  pattern = svalue->data[0].v_pointer;
-	  if (cairo_pattern_get_type (pattern) == CAIRO_PATTERN_TYPE_SOLID)
-	    {
-	      cairo_pattern_get_rgba (pattern, &red, &green, &blue, &alpha);
-	      rgba = convert_color (red, green, blue, alpha);
-	    }
-	}
-      g_value_set_uint (value, rgba);
+      if (svalue)
+	goo_canvas_get_rgba_value_from_pattern (svalue->data[0].v_pointer,
+						value);
       break;
     case PROP_FILL_COLOR_RGBA:
       svalue = goo_canvas_style_get_property (style, goo_canvas_style_fill_pattern_id);
-      if (svalue && svalue->data[0].v_pointer)
-	{
-	  pattern = svalue->data[0].v_pointer;
-	  if (cairo_pattern_get_type (pattern) == CAIRO_PATTERN_TYPE_SOLID)
-	    {
-	      cairo_pattern_get_rgba (pattern, &red, &green, &blue, &alpha);
-	      rgba = convert_color (red, green, blue, alpha);
-	    }
-	}
-      g_value_set_uint (value, rgba);
+      if (svalue)
+	goo_canvas_get_rgba_value_from_pattern (svalue->data[0].v_pointer,
+						value);
       break;
 
       /* Other properties. */
@@ -630,10 +592,6 @@
 					    GParamSpec              *pspec)
 {
   GooCanvasStyle *style;
-  GdkColor color = { 0, 0, 0, 0, };
-  guint rgba, red, green, blue, alpha;
-  GdkPixbuf *pixbuf;
-  cairo_surface_t *surface;
   cairo_pattern_t *pattern;
   gboolean recompute_bounds = FALSE;
   cairo_matrix_t *transform;
@@ -722,74 +680,29 @@
 
       /* Convenience properties. */
     case PROP_STROKE_COLOR:
-      if (g_value_get_string (value))
-	gdk_color_parse (g_value_get_string (value), &color);
-      pattern = cairo_pattern_create_rgb (color.red / 65535.0,
-					  color.green / 65535.0,
-					  color.blue / 65535.0);
-      g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
-      g_value_take_boxed (&tmpval, pattern);
-      goo_canvas_style_set_property (style, goo_canvas_style_stroke_pattern_id, &tmpval);
-      g_value_unset (&tmpval);
+      pattern = goo_canvas_create_pattern_from_color_value (value);
+      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_stroke_pattern_id, pattern);
       break;
     case PROP_STROKE_COLOR_RGBA:
-      rgba = g_value_get_uint (value);
-      red   = (rgba >> 24) & 0xFF;
-      green = (rgba >> 16) & 0xFF;
-      blue  = (rgba >> 8)  & 0xFF;
-      alpha = (rgba)       & 0xFF;
-      pattern = cairo_pattern_create_rgba (red / 255.0, green / 255.0,
-					   blue / 255.0, alpha / 255.0);
-      g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
-      g_value_take_boxed (&tmpval, pattern);
-      goo_canvas_style_set_property (style, goo_canvas_style_stroke_pattern_id, &tmpval);
-      g_value_unset (&tmpval);
+      pattern = goo_canvas_create_pattern_from_rgba_value (value);
+      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_stroke_pattern_id, pattern);
       break;
     case PROP_STROKE_PIXBUF:
-      pixbuf = g_value_get_object (value);
-      surface = goo_canvas_cairo_surface_from_pixbuf (pixbuf);
-      pattern = cairo_pattern_create_for_surface (surface);
-      cairo_surface_destroy (surface);
-      cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
-      g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
-      g_value_take_boxed (&tmpval, pattern);
-      goo_canvas_style_set_property (style, goo_canvas_style_stroke_pattern_id, &tmpval);
-      g_value_unset (&tmpval);
+      pattern = goo_canvas_create_pattern_from_pixbuf_value (value);
+      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_stroke_pattern_id, pattern);
       break;
+
     case PROP_FILL_COLOR:
-      if (g_value_get_string (value))
-	gdk_color_parse (g_value_get_string (value), &color);
-      pattern = cairo_pattern_create_rgb (color.red / 65535.0,
-					  color.green / 65535.0,
-					  color.blue / 65535.0);
-      g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
-      g_value_take_boxed (&tmpval, pattern);
-      goo_canvas_style_set_property (style, goo_canvas_style_fill_pattern_id, &tmpval);
-      g_value_unset (&tmpval);
+      pattern = goo_canvas_create_pattern_from_color_value (value);
+      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_fill_pattern_id, pattern);
       break;
     case PROP_FILL_COLOR_RGBA:
-      rgba = g_value_get_uint (value);
-      red   = (rgba >> 24) & 0xFF;
-      green = (rgba >> 16) & 0xFF;
-      blue  = (rgba >> 8)  & 0xFF;
-      alpha = (rgba)       & 0xFF;
-      pattern = cairo_pattern_create_rgba (red / 255.0, green / 255.0,
-					   blue / 255.0, alpha / 255.0);
-      g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
-      g_value_take_boxed (&tmpval, pattern);
-      goo_canvas_style_set_property (style, goo_canvas_style_fill_pattern_id, &tmpval);
-      g_value_unset (&tmpval);
+      pattern = goo_canvas_create_pattern_from_rgba_value (value);
+      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_fill_pattern_id, pattern);
       break;
     case PROP_FILL_PIXBUF:
-      pixbuf = g_value_get_object (value);
-      surface = goo_canvas_cairo_surface_from_pixbuf (pixbuf);
-      pattern = cairo_pattern_create_for_surface (surface);
-      cairo_surface_destroy (surface);
-      cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
-      g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
-      g_value_take_boxed (&tmpval, pattern);
-      goo_canvas_style_set_property (style, goo_canvas_style_fill_pattern_id, &tmpval);
-      g_value_unset (&tmpval);
+      pattern = goo_canvas_create_pattern_from_pixbuf_value (value);
+      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_fill_pattern_id, pattern);
       break;
 
       /* Other properties. */

Modified: trunk/src/goocanvasprivate.h
==============================================================================
--- trunk/src/goocanvasprivate.h	(original)
+++ trunk/src/goocanvasprivate.h	Mon Nov  3 11:31:46 2008
@@ -8,6 +8,7 @@
 #define __GOO_CANVAS_PRIVATE_H__
 
 #include <gtk/gtk.h>
+#include "goocanvasstyle.h"
 
 G_BEGIN_DECLS
 
@@ -30,6 +31,22 @@
 cairo_pattern_t* goo_canvas_cairo_pattern_from_pixbuf (GdkPixbuf *pixbuf);
 cairo_surface_t* goo_canvas_cairo_surface_from_pixbuf (GdkPixbuf *pixbuf);
 
+guint goo_canvas_convert_colors_to_rgba (double red,
+					 double green,
+					 double blue,
+					 double alpha);
+
+void goo_canvas_get_rgba_value_from_pattern (cairo_pattern_t *pattern,
+					     GValue          *value);
+
+void goo_canvas_set_style_property_from_pattern (GooCanvasStyle  *style,
+						 GQuark           property_id,
+						 cairo_pattern_t *pattern);
+
+cairo_pattern_t* goo_canvas_create_pattern_from_color_value  (const GValue *value);
+cairo_pattern_t* goo_canvas_create_pattern_from_rgba_value   (const GValue *value);
+cairo_pattern_t* goo_canvas_create_pattern_from_pixbuf_value (const GValue *value);
+
 
 gboolean goo_canvas_boolean_handled_accumulator (GSignalInvocationHint *ihint,
 						 GValue                *return_accu,

Modified: trunk/src/goocanvasutils.c
==============================================================================
--- trunk/src/goocanvasutils.c	(original)
+++ trunk/src/goocanvasutils.c	Mon Nov  3 11:31:46 2008
@@ -1192,3 +1192,103 @@
 }
 
 
+/* Converts red, green, blue and alpha doubles to an RGBA guint. */
+guint
+goo_canvas_convert_colors_to_rgba (double red,
+				   double green,
+				   double blue,
+				   double alpha)
+{
+  guint red_byte, green_byte, blue_byte, alpha_byte;
+
+  red_byte = red * 256;
+  red_byte -= red_byte >> 8;
+
+  green_byte = green * 256;
+  green_byte -= green_byte >> 8;
+
+  blue_byte = blue * 256;
+  blue_byte -= blue_byte >> 8;
+
+  alpha_byte = alpha * 256;
+  alpha_byte -= alpha_byte >> 8;
+
+  return (red_byte << 24) + (green_byte << 16) + (blue_byte << 8) + alpha_byte;
+}
+
+
+void
+goo_canvas_get_rgba_value_from_pattern (cairo_pattern_t *pattern,
+					GValue          *value)
+{
+  double red, green, blue, alpha;
+  guint rgba = 0;
+
+  if (pattern && cairo_pattern_get_type (pattern) == CAIRO_PATTERN_TYPE_SOLID)
+    {
+      cairo_pattern_get_rgba (pattern, &red, &green, &blue, &alpha);
+      rgba = goo_canvas_convert_colors_to_rgba (red, green, blue, alpha);
+    }
+  g_value_set_uint (value, rgba);
+}
+
+
+/* Sets a style property to the given pattern, taking ownership of it. */
+void
+goo_canvas_set_style_property_from_pattern (GooCanvasStyle  *style,
+					    GQuark           property_id,
+					    cairo_pattern_t *pattern)
+{
+  GValue tmpval = { 0 };
+
+  g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
+  g_value_take_boxed (&tmpval, pattern);
+  goo_canvas_style_set_property (style, property_id, &tmpval);
+  g_value_unset (&tmpval);
+}
+
+
+cairo_pattern_t*
+goo_canvas_create_pattern_from_color_value (const GValue *value)
+{
+  GdkColor color = { 0, 0, 0, 0, };
+
+  if (g_value_get_string (value))
+    gdk_color_parse (g_value_get_string (value), &color);
+
+  return cairo_pattern_create_rgb (color.red / 65535.0,
+				   color.green / 65535.0,
+				   color.blue / 65535.0);
+}
+  
+
+cairo_pattern_t*
+goo_canvas_create_pattern_from_rgba_value (const GValue *value)
+{
+  guint rgba, red, green, blue, alpha;
+
+  rgba = g_value_get_uint (value);
+  red   = (rgba >> 24) & 0xFF;
+  green = (rgba >> 16) & 0xFF;
+  blue  = (rgba >> 8)  & 0xFF;
+  alpha = (rgba)       & 0xFF;
+
+  return cairo_pattern_create_rgba (red / 255.0, green / 255.0,
+				    blue / 255.0, alpha / 255.0);
+}
+
+
+cairo_pattern_t*
+goo_canvas_create_pattern_from_pixbuf_value (const GValue *value)
+{
+  GdkPixbuf *pixbuf;
+  cairo_surface_t *surface;
+  cairo_pattern_t *pattern;
+
+  pixbuf = g_value_get_object (value);
+  surface = goo_canvas_cairo_surface_from_pixbuf (pixbuf);
+  pattern = cairo_pattern_create_for_surface (surface);
+  cairo_surface_destroy (surface);
+  cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+  return pattern;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]