Included 2009 in the copyright
[adg.git] / adg / adg-path.c
blobaac7e6c56de9a0f33d05b9f175814d41f74341f6
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 /**
21 * SECTION:path
22 * @title: AdgPath
23 * @short_description: A stroked path entity
25 * The #AdgPath object is peraphs the simplest entity.
27 * It contains a pointer to the desired #cairo_path_t structure.
30 #include "adg-path.h"
31 #include "adg-path-private.h"
32 #include "adg-line-style.h"
33 #include "adg-util.h"
34 #include "adg-canvas.h"
35 #include "adg-intl.h"
36 #include <math.h>
38 #define PARENT_CLASS ((AdgEntityClass *) adg_path_parent_class)
41 static void finalize (GObject *object);
42 static void invalidate (AdgEntity *entity);
43 static void render (AdgEntity *entity,
44 cairo_t *cr);
45 static void clear_path_cache (AdgPath *path);
48 G_DEFINE_TYPE(AdgPath, adg_path, ADG_TYPE_ENTITY)
51 static void
52 adg_path_class_init(AdgPathClass *klass)
54 GObjectClass *gobject_class;
55 AdgEntityClass *entity_class;
57 gobject_class = (GObjectClass *) klass;
58 entity_class = (AdgEntityClass *) klass;
60 g_type_class_add_private(klass, sizeof(AdgPathPrivate));
62 gobject_class->finalize = finalize;
64 entity_class->invalidate = invalidate;
65 entity_class->render = render;
68 static void
69 adg_path_init(AdgPath *path)
71 AdgPathPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE(path, ADG_TYPE_PATH,
72 AdgPathPrivate);
74 priv->cp.x = 0.;
75 priv->cp.y = 0.;
76 priv->cairo_path = NULL;
77 priv->callback = NULL;
79 path->priv = priv;
82 static void
83 finalize(GObject *object)
85 clear_path_cache((AdgPath *) object);
87 ((GObjectClass *) PARENT_CLASS)->finalize(object);
90 /**
91 * adg_path_new:
92 * @callback: an #AdgCallback callback
94 * Creates a new path entity. The path must be constructed in the @callback
95 * function: AdgPath will cache and reuse the cairo_copy_path() returned by
96 * the cairo context after the @callback call.
98 * Return value: the new entity
99 **/
100 AdgEntity *
101 adg_path_new(AdgCallback callback)
103 AdgEntity *entity;
105 entity = (AdgEntity *) g_object_new(ADG_TYPE_PATH, NULL);
106 ((AdgPath *) entity)->priv->callback = callback;
108 return entity;
111 const cairo_path_t *
112 adg_path_get_cairo_path(AdgPath *path)
114 g_return_val_if_fail(ADG_IS_PATH(path), NULL);
116 return path->priv->cairo_path;
119 void
120 adg_path_dump(AdgPath *path)
122 cairo_path_data_t *data;
123 gint n_data, n_point;
125 g_return_if_fail(ADG_IS_PATH(path));
127 if (path->priv->cairo_path->data == NULL)
128 return;
130 for (n_data = 0; n_data < path->priv->cairo_path->num_data; ++n_data) {
131 data = path->priv->cairo_path->data + n_data;
133 switch (data->header.type) {
134 case CAIRO_PATH_MOVE_TO:
135 g_print("Move to ");
136 break;
137 case CAIRO_PATH_LINE_TO:
138 g_print("Line to ");
139 break;
140 case CAIRO_PATH_CURVE_TO:
141 g_print("Curve to ");
142 break;
143 case CAIRO_PATH_CLOSE_PATH:
144 g_print("Path close");
145 break;
146 default:
147 g_print("Unknown entity (%d)", data->header.type);
148 break;
151 for (n_point = 1; n_point < data->header.length; ++n_point)
152 g_print("(%lf, %lf) ", data[n_point].point.x,
153 data[n_point].point.y);
155 n_data += n_point - 1;
156 g_print("\n");
161 static void
162 invalidate(AdgEntity *entity)
164 clear_path_cache((AdgPath *) entity);
166 PARENT_CLASS->invalidate(entity);
169 static void
170 render(AdgEntity *entity, cairo_t *cr)
172 AdgPath *path = (AdgPath *) entity;
174 if (path->priv->cairo_path) {
175 /* Use cached data */
176 cairo_move_to(cr, path->priv->cp.x, path->priv->cp.y);
177 cairo_append_path(cr, path->priv->cairo_path);
178 } else {
179 /* Construct and store the cache */
180 cairo_get_current_point(cr, &path->priv->cp.x, &path->priv->cp.y);
182 if (path->priv->callback)
183 path->priv->callback(entity, cr);
185 path->priv->cairo_path = cairo_copy_path(cr);
188 adg_entity_apply(entity, ADG_SLOT_LINE_STYLE, cr);
189 cairo_stroke(cr);
191 PARENT_CLASS->render(entity, cr);
194 static void
195 clear_path_cache(AdgPath *path)
197 AdgPathPrivate *priv = path->priv;
199 if (priv->cairo_path != NULL) {
200 cairo_path_destroy(priv->cairo_path);
201 priv->cairo_path = NULL;
204 priv->cp.x = priv->cp.y = 0.;