[AdgPoin] Added adg_point_set()
[adg.git] / adg / adg-point.c
blob6dc4d186bf5f0a49fd51e219079a7cba8782aed7
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010 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 Lesser 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 * Lesser 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., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 /**
22 * SECTION:adg-point
23 * @Section_Id:AdgPoint
24 * @title: AdgPoint
25 * @short_description: A struct holding x, y coordinates
26 * (either named or explicit)
28 * AdgPoint is an opaque structure that manages 2D coordinates,
29 * either set explicitely throught adg_point_set_pair() and
30 * adg_point_set_pair_explicit() or taken from a model with
31 * adg_point_set_pair_from_model(). It can be thought as an
32 * #AdgPair on steroid, because it adds named pair support to
33 * a simple pair, enabling coordinates depending on #AdgModel.
34 **/
36 /**
37 * AdgPoint:
39 * This is an opaque struct: all its fields are privates.
40 **/
43 #include "adg-internal.h"
44 #include "adg-point.h"
45 #include <string.h>
48 struct _AdgPoint {
49 AdgPair pair;
50 AdgModel *model;
51 gchar *name;
52 gboolean is_uptodate;
56 GType
57 adg_point_get_type(void)
59 static int type = 0;
61 if (G_UNLIKELY(type == 0))
62 type = g_boxed_type_register_static("AdgPoint",
63 (GBoxedCopyFunc) adg_point_dup,
64 (GBoxedFreeFunc) adg_point_destroy);
66 return type;
69 /**
70 * adg_point_new:
72 * Creates a new empty #AdgPoint. The returned pointer
73 * should be freed with adg_point_destroy() when no longer needed.
75 * The returned value should be freed with adg_point_destroy()
76 * when no longer needed.
78 * Returns: a newly created #AdgPoint
79 **/
80 AdgPoint *
81 adg_point_new(void)
83 return g_new0(AdgPoint, 1);
86 /**
87 * adg_point_dup:
88 * @src: an #AdgPoint
90 * Duplicates @src. This operation also adds a new reference
91 * to the internal model if @src is linked to a named pair.
93 * The returned value should be freed with adg_point_destroy()
94 * when no longer needed.
96 * Returns: the duplicated #AdgPoint struct or %NULL on errors
97 **/
98 AdgPoint *
99 adg_point_dup(const AdgPoint *src)
101 AdgPoint *point;
103 g_return_val_if_fail(src != NULL, NULL);
105 if (src->model)
106 g_object_ref(src->model);
108 point = g_memdup(src, sizeof(AdgPoint));
109 point->name = g_strdup(src->name);
111 return point;
115 * adg_point_copy:
116 * @point: an #AdgPoint
117 * @src: the source point to copy
119 * Copies @src into @point. If @point was linked to a named pair, the
120 * reference to the old model is dropped. Similary, if @src is linked
121 * to a model, a new reference to this new model is added.
123 void
124 adg_point_copy(AdgPoint *point, const AdgPoint *src)
126 g_return_if_fail(point != NULL);
127 g_return_if_fail(src != NULL);
129 if (src->model != NULL)
130 g_object_ref(src->model);
131 if (point->model != NULL)
132 g_object_unref(point->model);
134 if (point->name != NULL)
135 g_free(point->name);
137 memcpy(point, src, sizeof(AdgPoint));
138 point->name = g_strdup(src->name);
142 * adg_point_set:
143 * @p_point: a pointer to an #AdgPoint
144 * @new_point: the new point to assign
146 * Convenient method to assign @new_point to the #AdgPoint pointed
147 * by @p_point. This is useful while implementing #AdgPoint
148 * property setters.
150 * At the end *@p_point will be set to @new_point, allocating a new
151 * #AdgPoint or destroying the previous one when necessary. It is
152 * allowed to use %NULL as @new_point to unset *@p_point.
154 * Returns: %TRUE if the pointer pointed by @p_point has been changed,
155 * %FALSE otherwise
157 gboolean
158 adg_point_set(AdgPoint **p_point, const AdgPoint *new_point)
160 g_return_val_if_fail(p_point != NULL, FALSE);
162 if ((*p_point == new_point) ||
163 (*p_point && new_point && adg_point_equal(*p_point, new_point)))
164 return FALSE;
166 if (*p_point == NULL)
167 *p_point = adg_point_new();
169 if (new_point) {
170 adg_point_copy(*p_point, new_point);
171 } else {
172 adg_point_destroy(*p_point);
173 *p_point = NULL;
176 return TRUE;
180 * adg_point_destroy:
181 * @point: an #AdgPoint
183 * Destroys the @point instance, unreferencing the internal model if
184 * @point is linked to a named pair.
186 void
187 adg_point_destroy(AdgPoint *point)
189 g_return_if_fail(point != NULL);
191 adg_point_set_pair_from_model(point, NULL, NULL);
193 g_free(point);
197 * adg_point_set_pair:
198 * @point: an #AdgPoint
199 * @pair: the #AdgPair to use
201 * Sets an explicit pair in @point by using the given @pair. If
202 * @point was linked to a named pair in a model, this link is
203 * dropped before setting the pair.
205 void
206 adg_point_set_pair(AdgPoint *point, const AdgPair *pair)
208 g_return_if_fail(point != NULL);
209 g_return_if_fail(pair != NULL);
211 adg_point_set_pair_explicit(point, pair->x, pair->y);
215 * adg_point_set_pair_explicit:
216 * @point: an #AdgPoint
217 * @x: the x coordinate of the point
218 * @y: the y coordinate of the point
220 * Works in the same way of adg_point_set_pair() but accept direct numbers
221 * instead of an #AdgPair structure.
223 void
224 adg_point_set_pair_explicit(AdgPoint *point, gdouble x, gdouble y)
226 g_return_if_fail(point != NULL);
228 /* Unlink the named pair dependency, if any */
229 adg_point_set_pair_from_model(point, NULL, NULL);
231 point->pair.x = x;
232 point->pair.y = y;
233 point->is_uptodate = TRUE;
237 * adg_point_set_pair_from_model:
238 * @point: an #AdgPoint
239 * @model: the #AdgModel
240 * @name: the id of a named pair in @model
242 * Links the @name named pair of @model to @point, so any subsequent
243 * call to adg_point_update() will read the named pair content. A
244 * new reference is added to @model while the previous model (if any)
245 * is unreferenced.
247 * It is allowed to use %NULL as @model, in which case the possible
248 * link between @point and the named pair is dropped.
250 void
251 adg_point_set_pair_from_model(AdgPoint *point,
252 AdgModel *model, const gchar *name)
254 g_return_if_fail(point != NULL);
255 g_return_if_fail(model == NULL || name != NULL);
257 /* Check if unlinking a yet unlinked point */
258 if (model == NULL && point->model == NULL)
259 return;
261 /* Return if the named pair is not changed */
262 if (model == point->model &&
263 (model == NULL || strcmp(point->name, name) == 0)) {
264 return;
267 if (model != NULL)
268 g_object_ref(model);
270 if (point->model != NULL) {
271 /* Remove the old named pair */
272 g_object_unref(point->model);
273 g_free(point->name);
274 point->model = NULL;
275 point->name = NULL;
278 point->is_uptodate = FALSE;
280 if (model != NULL) {
281 /* Set the new named pair */
282 point->model = model;
283 point->name = g_strdup(name);
288 * adg_point_get_pair:
289 * @point: an #AdgPoint
291 * #AdgPoint is an evolution of the pair concept, but internally the
292 * relevant data is still stored in an #AdgPair struct. This function
293 * gets this struct, optionally updating the internal value from the
294 * linked named pair if necessary.
296 * Returns: the pair of @point
298 const AdgPair *
299 adg_point_get_pair(AdgPoint *point)
301 g_return_val_if_fail(point != NULL, NULL);
303 if (!point->is_uptodate) {
304 const AdgPair *pair;
306 if (point->model == NULL) {
307 /* A point with explicit coordinates not up to date
308 * is an unexpected condition */
309 g_warning(_("%s: trying to get a pair from an undefined point"),
310 G_STRLOC);
311 return NULL;
314 pair = adg_model_get_named_pair(point->model, point->name);
316 if (pair == NULL) {
317 g_warning(_("%s: `%s' named pair not found in `%s' model instance"),
318 G_STRLOC, point->name,
319 g_type_name(G_TYPE_FROM_INSTANCE(point->model)));
320 return NULL;
323 cpml_pair_copy(&point->pair, pair);
326 return (AdgPair *) point;
330 * adg_point_invalidate:
331 * @point: an #AdgPoint
333 * Invalidates @point, forcing a refresh of its internal #AdgPair if
334 * the point is linked to a named pair. If @point is explicitely set,
335 * this function has no effect.
337 void
338 adg_point_invalidate(AdgPoint *point)
340 g_return_if_fail(point != NULL);
342 if (point->model != NULL)
343 point->is_uptodate = FALSE;
347 * adg_point_equal:
348 * @point1: the first point to compare
349 * @point2: the second point to compare
351 * Compares @point1 and @point2 and returns %TRUE if the points are
352 * equals. The comparison is made by matching also where the points
353 * are bound. If you want to compare only the coordinates, use
354 * adg_pair_equal() directly on their pairs:
356 * |[
357 * adg_pair_equal(adg_point_get_pair(point1), adg_point_get_pair(point2));
358 * ]|
360 * Returns: %TRUE if @point1 is equal to @point2, %FALSE otherwise
362 gboolean
363 adg_point_equal(const AdgPoint *point1, const AdgPoint *point2)
365 g_return_val_if_fail(point1 != NULL, FALSE);
366 g_return_val_if_fail(point2 != NULL, FALSE);
368 /* Check if the points are not bound to the same model
369 * or if only one of the two points is explicit */
370 if (point1->model != point2->model)
371 return FALSE;
373 /* Handle points bound to named pairs */
374 if (point1->model)
375 return adg_strcmp(point1->name, point2->name) == 0;
377 /* Handle points with explicit coordinates */
378 return adg_pair_equal(&point1->pair, &point2->pair);