/*
* GooCanvas. Copyright (C) 2005-6 Damon Chaplin.
* Released under the GNU LGPL license. See COPYING for details.
*
* goocanvaspath.c - a path item, very similar to the SVG path element.
*/
/**
* SECTION:goocanvaspath
* @Title: GooCanvasPath
* @Short_Description: a path item (a series of lines and curves).
*
* GooCanvasPath represents a path item, which is a series of one or more
* lines, bezier curves, or elliptical arcs.
*
* 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().
*
* #GooCanvasPath uses the same path specification strings as the Scalable
* Vector Graphics (SVG) path element. For details see the
* SVG specification.
*
* To create a #GooCanvasPath use goo_canvas_path_new().
*
* To get or set the properties of an existing #GooCanvasPath, use
* g_object_get() and g_object_set().
*/
#include
#include
#include
#include "goocanvaspath.h"
enum {
PROP_0,
PROP_DATA,
};
static void canvas_item_interface_init (GooCanvasItemIface *iface);
static void goo_canvas_path_finalize (GObject *object);
static void goo_canvas_path_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec);
static void goo_canvas_path_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec);
static void goo_canvas_path_create_path (GooCanvasItemSimple *simple,
cairo_t *cr);
G_DEFINE_TYPE_WITH_CODE (GooCanvasPath, goo_canvas_path,
GOO_TYPE_CANVAS_ITEM_SIMPLE,
G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM,
canvas_item_interface_init))
static void
goo_canvas_path_install_common_properties (GObjectClass *gobject_class)
{
/**
* GooCanvasPath:data
*
* The sequence of path commands, specified as a string using the same syntax
* as in the Scalable Vector
* Graphics (SVG) path element.
*/
g_object_class_install_property (gobject_class, PROP_DATA,
g_param_spec_string ("data",
_("Path Data"),
_("The sequence of path commands"),
NULL,
G_PARAM_WRITABLE));
}
static void
goo_canvas_path_class_init (GooCanvasPathClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*) klass;
GooCanvasItemSimpleClass *simple_class = (GooCanvasItemSimpleClass*) klass;
gobject_class->finalize = goo_canvas_path_finalize;
gobject_class->get_property = goo_canvas_path_get_property;
gobject_class->set_property = goo_canvas_path_set_property;
simple_class->simple_create_path = goo_canvas_path_create_path;
goo_canvas_path_install_common_properties (gobject_class);
}
static void
goo_canvas_path_init (GooCanvasPath *path)
{
path->path_commands = NULL;
}
/**
* goo_canvas_path_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.
* @path_data: the sequence of path commands, specified as a string using the
* same syntax as in the Scalable
* Vector Graphics (SVG) path element.
* @...: optional pairs of property names and values, and a terminating %NULL.
*
* Creates a new path item.
*
*
*
* Here's an example showing how to create a red line from (20,20) to (40,40):
*
*
* GooCanvasItem *path = goo_canvas_path_new (mygroup,
* "M 20 20 L 40 40",
* "stroke-color", "red",
* NULL);
*
*
* This example creates a cubic bezier curve from (20,100) to (100,100) with
* the control points at (20,50) and (100,50):
*
*
* GooCanvasItem *path = goo_canvas_path_new (mygroup,
* "M20,100 C20,50 100,50 100,100",
* "stroke-color", "blue",
* NULL);
*
*
* This example uses an elliptical arc to create a filled circle with one
* quarter missing:
*
*
* GooCanvasItem *path = goo_canvas_path_new (mygroup,
* "M200,500 h-150 a150,150 0 1,0 150,-150 z",
* "fill-color", "red",
* "stroke-color", "blue",
* "line-width", 5.0,
* NULL);
*
*
* Returns: a new path item.
**/
GooCanvasItem*
goo_canvas_path_new (GooCanvasItem *parent,
const gchar *path_data,
...)
{
GooCanvasItem *item;
GooCanvasPath *path;
const char *first_property;
va_list var_args;
item = g_object_new (GOO_TYPE_CANVAS_PATH, NULL);
path = (GooCanvasPath*) item;
path->path_commands = goo_canvas_parse_path_data (path_data);
va_start (var_args, path_data);
first_property = va_arg (var_args, char*);
if (first_property)
g_object_set_valist ((GObject*) 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_path_finalize (GObject *object)
{
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
GooCanvasPath *path = (GooCanvasPath*) 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)
{
if (path->path_commands)
g_array_free (path->path_commands, TRUE);
}
path->path_commands = NULL;
G_OBJECT_CLASS (goo_canvas_path_parent_class)->finalize (object);
}
static void
goo_canvas_path_get_common_property (GObject *object,
GArray *path_commands,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
goo_canvas_path_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GooCanvasPath *path = (GooCanvasPath*) object;
goo_canvas_path_get_common_property (object, path->path_commands, prop_id,
value, pspec);
}
static void
goo_canvas_path_set_common_property (GObject *object,
GArray **path_commands,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
case PROP_DATA:
if (*path_commands)
g_array_free (*path_commands, TRUE);
*path_commands = goo_canvas_parse_path_data (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
goo_canvas_path_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
GooCanvasPath *path = (GooCanvasPath*) 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_path_set_common_property (object, &path->path_commands, prop_id,
value, pspec);
goo_canvas_item_simple_changed (simple, TRUE);
}
static void
goo_canvas_path_create_path (GooCanvasItemSimple *simple,
cairo_t *cr)
{
GooCanvasPath *path = (GooCanvasPath*) simple;
goo_canvas_create_path (path->path_commands, cr);
}
static void
goo_canvas_path_set_model (GooCanvasItem *item,
GooCanvasItemModel *model)
{
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
GooCanvasPath *path = (GooCanvasPath*) item;
GooCanvasPathModel *emodel = (GooCanvasPathModel*) model;
/* If our data was allocated, free it. */
if (!simple->model)
{
if (path->path_commands)
g_array_free (path->path_commands, TRUE);
}
/* Now use the new model's data instead. */
path->path_commands = emodel->path_commands;
/* Let the parent GooCanvasItemSimple code do the rest. */
goo_canvas_item_simple_set_model (simple, model);
}
static void
canvas_item_interface_init (GooCanvasItemIface *iface)
{
iface->set_model = goo_canvas_path_set_model;
}
/**
* SECTION:goocanvaspathmodel
* @Title: GooCanvasPathModel
* @Short_Description: a model for path items (a series of lines and curves).
*
* GooCanvasPathModel represents a model for path items, which are a series of
* one or more lines, bezier curves, or elliptical arcs.
*
* 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().
*
* #GooCanvasPathModel uses the same path specification strings as the Scalable
* Vector Graphics (SVG) path element. For details see the
* SVG specification.
*
* To create a #GooCanvasPathModel use goo_canvas_path_model_new().
*
* To get or set the properties of an existing #GooCanvasPathModel, use
* g_object_get() and g_object_set().
*
* To respond to events such as mouse clicks on the path you must connect
* to the signal handlers of the corresponding #GooCanvasPath objects.
* (See goo_canvas_get_item() and #GooCanvas::item-created.)
*/
static void item_model_interface_init (GooCanvasItemModelIface *iface);
static void goo_canvas_path_model_finalize (GObject *object);
static void goo_canvas_path_model_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec);
static void goo_canvas_path_model_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE_WITH_CODE (GooCanvasPathModel, goo_canvas_path_model,
GOO_TYPE_CANVAS_ITEM_MODEL_SIMPLE,
G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM_MODEL,
item_model_interface_init))
static void
goo_canvas_path_model_class_init (GooCanvasPathModelClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*) klass;
gobject_class->finalize = goo_canvas_path_model_finalize;
gobject_class->get_property = goo_canvas_path_model_get_property;
gobject_class->set_property = goo_canvas_path_model_set_property;
goo_canvas_path_install_common_properties (gobject_class);
}
static void
goo_canvas_path_model_init (GooCanvasPathModel *pmodel)
{
pmodel->path_commands = g_array_new (0, 0, sizeof (GooCanvasPathCommand));
}
/**
* goo_canvas_path_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.
* @path_data: the sequence of path commands, specified as a string using the
* same syntax as in the Scalable
* Vector Graphics (SVG) path element.
* @...: optional pairs of property names and values, and a terminating %NULL.
*
* Creates a new path model.
*
*
*
* Here's an example showing how to create a red line from (20,20) to (40,40):
*
*
* GooCanvasItemModel *path = goo_canvas_path_model_new (mygroup,
* "M 20 20 L 40 40",
* "stroke-color", "red",
* NULL);
*
*
* This example creates a cubic bezier curve from (20,100) to (100,100) with
* the control points at (20,50) and (100,50):
*
*
* GooCanvasItemModel *path = goo_canvas_path_model_new (mygroup,
* "M20,100 C20,50 100,50 100,100",
* "stroke-color", "blue",
* NULL);
*
*
* This example uses an elliptical arc to create a filled circle with one
* quarter missing:
*
*
* GooCanvasItemModel *path = goo_canvas_path_model_new (mygroup,
* "M200,500 h-150 a150,150 0 1,0 150,-150 z",
* "fill-color", "red",
* "stroke-color", "blue",
* "line-width", 5.0,
* NULL);
*
*
* Returns: a new path model.
**/
GooCanvasItemModel*
goo_canvas_path_model_new (GooCanvasItemModel *parent,
const gchar *path_data,
...)
{
GooCanvasItemModel *model;
GooCanvasPathModel *pmodel;
const char *first_property;
va_list var_args;
model = g_object_new (GOO_TYPE_CANVAS_PATH_MODEL, NULL);
pmodel = (GooCanvasPathModel*) model;
pmodel->path_commands = goo_canvas_parse_path_data (path_data);
va_start (var_args, path_data);
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_path_model_finalize (GObject *object)
{
GooCanvasPathModel *pmodel = (GooCanvasPathModel*) object;
if (pmodel->path_commands)
g_array_free (pmodel->path_commands, TRUE);
G_OBJECT_CLASS (goo_canvas_path_model_parent_class)->finalize (object);
}
static void
goo_canvas_path_model_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GooCanvasPathModel *pmodel = (GooCanvasPathModel*) object;
goo_canvas_path_get_common_property (object, pmodel->path_commands, prop_id,
value, pspec);
}
static void
goo_canvas_path_model_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GooCanvasPathModel *pmodel = (GooCanvasPathModel*) object;
goo_canvas_path_set_common_property (object, &pmodel->path_commands, prop_id,
value, pspec);
g_signal_emit_by_name (pmodel, "changed", TRUE);
}
static GooCanvasItem*
goo_canvas_path_model_create_item (GooCanvasItemModel *model,
GooCanvas *canvas)
{
GooCanvasItem *item;
item = g_object_new (GOO_TYPE_CANVAS_PATH, NULL);
goo_canvas_item_set_model (item, model);
return item;
}
static void
item_model_interface_init (GooCanvasItemModelIface *iface)
{
iface->create_item = goo_canvas_path_model_create_item;
}