[AdgModel] Enhanced docs
[adg.git] / adg / adg-marker.c
blob3f30a2485fcb51bc320f179c27b5ae1bd3be4431
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 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-marker
23 * @short_description: Base entity for markers
25 * A marker is an entity to be applied at the start or end of a segment.
26 * Typical examples include arrows, ticks, dots and so on.
28 * The #AdgMarker:path and #AdgMarker:n-segment properties specify the
29 * segment where the marker should be applied. Similarly to the
30 * #AdgStroke type, if the associated path is destroyed the above
31 * properties are unset.
33 * Use adg_marker_set_pos() to select the position where the marker
34 * should be put: %0 means the start point of the segment while %1
35 * means the end point.
37 * The #AdgMarker:model property and APIs are intended only for marker
38 * implementation purposes.
39 **/
41 /**
42 * AdgMarker:
44 * All fields are privates and should not be used directly.
45 * Use its public methods instead.
46 **/
49 #include "adg-marker.h"
50 #include "adg-marker-private.h"
51 #include "adg-intl.h"
53 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_marker_parent_class)
56 enum {
57 PROP_0,
58 PROP_PATH,
59 PROP_N_SEGMENT,
60 PROP_POS,
61 PROP_SIZE,
62 PROP_MODEL
66 static void dispose (GObject *object);
67 static void get_property (GObject *object,
68 guint prop_id,
69 GValue *value,
70 GParamSpec *pspec);
71 static void set_property (GObject *object,
72 guint prop_id,
73 const GValue *value,
74 GParamSpec *pspec);
75 static gboolean invalidate (AdgEntity *entity);
76 static gboolean set_path (AdgMarker *marker,
77 AdgPath *path);
78 static void unset_path (AdgMarker *marker);
79 static gboolean set_n_segment (AdgMarker *marker,
80 gint n_segment);
81 static gboolean set_pos (AdgMarker *marker,
82 gdouble pos);
83 static gboolean set_size (AdgMarker *marker,
84 gdouble size);
85 static gboolean set_model (AdgMarker *marker,
86 AdgModel *model);
87 static AdgModel * create_model (AdgMarker *marker);
90 G_DEFINE_ABSTRACT_TYPE(AdgMarker, adg_marker, ADG_TYPE_ENTITY);
93 static void
94 adg_marker_class_init(AdgMarkerClass *klass)
96 GObjectClass *gobject_class;
97 AdgEntityClass *entity_class;
98 GParamSpec *param;
100 gobject_class = (GObjectClass *) klass;
101 entity_class = (AdgEntityClass *) klass;
103 g_type_class_add_private(klass, sizeof(AdgMarkerPrivate));
105 gobject_class->dispose = dispose;
106 gobject_class->set_property = set_property;
107 gobject_class->get_property = get_property;
109 entity_class->invalidate = invalidate;
111 klass->create_model = create_model;
113 param = g_param_spec_object("path",
114 P_("Path"),
115 P_("The subject path for this marker"),
116 ADG_TYPE_PATH,
117 G_PARAM_CONSTRUCT|G_PARAM_READWRITE);
118 g_object_class_install_property(gobject_class, PROP_PATH, param);
120 param = g_param_spec_uint("n-segment",
121 P_("Segment Index"),
122 P_("The segment of path where this marker should be applied (where 0 means undefined segment, 1 the first segment and so on)"),
123 0, G_MAXUINT, 0,
124 G_PARAM_CONSTRUCT|G_PARAM_READWRITE);
125 g_object_class_install_property(gobject_class, PROP_N_SEGMENT, param);
127 param = g_param_spec_double("pos",
128 P_("Position"),
129 P_("The position ratio inside the segment where to put the marker (0 means the start point while 1 means the end point)"),
130 0, 1, 0,
131 G_PARAM_CONSTRUCT|G_PARAM_READWRITE);
132 g_object_class_install_property(gobject_class, PROP_POS, param);
134 param = g_param_spec_double("size",
135 P_("Marker Size"),
136 P_("The size (in global space) of the marker"),
137 0, G_MAXDOUBLE, 12,
138 G_PARAM_READWRITE);
139 g_object_class_install_property(gobject_class, PROP_SIZE, param);
141 param = g_param_spec_object("model",
142 P_("Model"),
143 P_("A general purpose model usable by the marker implementations"),
144 ADG_TYPE_MODEL,
145 G_PARAM_READWRITE);
146 g_object_class_install_property(gobject_class, PROP_MODEL, param);
149 static void
150 adg_marker_init(AdgMarker *marker)
152 AdgMarkerPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(marker,
153 ADG_TYPE_MARKER,
154 AdgMarkerPrivate);
155 data->path = NULL;
156 data->n_segment = 0;
157 data->backup_segment = NULL;
158 memset(&data->segment, 0, sizeof(data->segment));
159 data->pos = 0;
160 data->size = 10;
161 data->model = NULL;
163 marker->data = data;
166 static void
167 dispose(GObject *object)
169 AdgMarker *marker = (AdgMarker *) object;
171 adg_marker_set_model(marker, NULL);
172 adg_marker_set_path(marker, NULL);
174 if (PARENT_OBJECT_CLASS->dispose != NULL)
175 PARENT_OBJECT_CLASS->dispose(object);
179 static void
180 get_property(GObject *object,
181 guint prop_id, GValue *value, GParamSpec *pspec)
183 AdgMarkerPrivate *data = ((AdgMarker *) object)->data;
185 switch (prop_id) {
186 case PROP_PATH:
187 g_value_set_object(value, data->path);
188 break;
189 case PROP_N_SEGMENT:
190 g_value_set_uint(value, data->n_segment);
191 break;
192 case PROP_POS:
193 g_value_set_double(value, data->pos);
194 break;
195 case PROP_SIZE:
196 g_value_set_double(value, data->size);
197 break;
198 case PROP_MODEL:
199 g_value_set_object(value, data->model);
200 break;
201 default:
202 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
203 break;
207 static void
208 set_property(GObject *object,
209 guint prop_id, const GValue *value, GParamSpec *pspec)
211 AdgMarker *marker = (AdgMarker *) object;
213 switch (prop_id) {
214 case PROP_PATH:
215 set_path(marker, g_value_get_object(value));
216 break;
217 case PROP_N_SEGMENT:
218 set_n_segment(marker, g_value_get_uint(value));
219 break;
220 case PROP_POS:
221 set_pos(marker, g_value_get_double(value));
222 break;
223 case PROP_SIZE:
224 set_size(marker, g_value_get_double(value));
225 break;
226 case PROP_MODEL:
227 set_model(marker, g_value_get_object(value));
228 break;
229 default:
230 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
231 break;
237 * adg_marker_get_path:
238 * @marker: an #AdgMarker
240 * Gets the path where this marker should be applied.
242 * Returns: the path owned by @marker or %NULL on errors
244 AdgPath *
245 adg_marker_get_path(AdgMarker *marker)
247 AdgMarkerPrivate *data;
249 g_return_val_if_fail(ADG_IS_MARKER(marker), NULL);
251 data = marker->data;
253 return data->path;
257 * adg_marker_set_path:
258 * @marker: an #AdgMarker
259 * @path: a new #AdgPath
261 * Sets a new path where the marker should be applied. The weak reference
262 * to the old path (if an old path was present) is dropped while a new
263 * weak reference is added to @path. If @path is destroyed, the weak
264 * reference callback will automatically unset #AdgMarker:path and will
265 * set #AdgMarker:n-segment to %0.
267 * After setting a new path, the #AdgMarker:n-segment property is
268 * reset to %1. This means the first segment of the path is always
269 * selected by default.
271 void
272 adg_marker_set_path(AdgMarker *marker, AdgPath *path)
274 g_return_if_fail(ADG_IS_MARKER(marker));
276 if (set_path(marker, path))
277 g_object_notify((GObject *) marker, "path");
281 * adg_marker_get_n_segment:
282 * @marker: an #AdgMarker
284 * Returns the segment of the associated path where this marker
285 * should be applied, where %1 is the first segment.
287 * Returns: an index greather than %0 on success or %0 on errors
289 gint
290 adg_marker_get_n_segment(AdgMarker *marker)
292 AdgMarkerPrivate *data;
294 g_return_val_if_fail(ADG_IS_MARKER(marker), 0);
296 data = marker->data;
298 return data->n_segment;
302 * adg_marker_set_n_segment:
303 * @marker: an #AdgMarker
304 * @n_segment: a new segment index
306 * Sets a new segment to use. @n_segment is expected to be greather than
307 * %0 and to not exceed the number of segments in the underlying path.
308 * By convention, %1 is the first segment.
310 void
311 adg_marker_set_n_segment(AdgMarker *marker, gint n_segment)
313 g_return_if_fail(ADG_IS_MARKER(marker));
315 if (set_n_segment(marker, n_segment))
316 g_object_notify((GObject *) marker, "n-segment");
320 * adg_marker_get_backup_segment:
321 * @marker: an #AdgMarker
323 * <note><para>
324 * This function is only useful in marker implementations.
325 * </para></note>
327 * Gets the original segment where the marker has been applied.
328 * Applying a marker could modify the underlying path, usually
329 * by trimming the original segment of a #AdgMarker:size dependent
330 * length from the end. The marker instance holds a copy of the
331 * original segment, got using adg_segment_deep_dup(), to be used
332 * in recomputation (when the marker changes size, for instance).
334 * When the subject segment is changed (either by changing
335 * #AdgMarker:path or #AdgMarker:n-segment) the original segment
336 * is restored.
338 * Returns: the original segment or %NULL on errors
340 const AdgSegment *
341 adg_marker_get_backup_segment(AdgMarker *marker)
343 AdgMarkerPrivate *data;
345 g_return_val_if_fail(ADG_IS_MARKER(marker), NULL);
347 data = marker->data;
349 return data->backup_segment;
353 * adg_marker_get_segment:
354 * @marker: an #AdgMarker
356 * <note><para>
357 * This function is only useful in marker implementations.
358 * </para></note>
360 * Gets the segment where the marker will be applied. This segment
361 * is eventually a modified version of the backup segment, after
362 * having applied the marker.
364 * Returns: the segment or %NULL on errors
366 AdgSegment *
367 adg_marker_get_segment(AdgMarker *marker)
369 AdgMarkerPrivate *data;
371 g_return_val_if_fail(ADG_IS_MARKER(marker), NULL);
373 data = marker->data;
375 return &data->segment;
379 * adg_marker_get_pos:
380 * @marker: an #AdgMarker
382 * Gets the current position of @marker. The returned value is a ratio
383 * position referred to the segment associated to @marker: %0 means the
384 * start point and %1 means the end point of the segment.
386 * Returns: the marker position
388 gdouble
389 adg_marker_get_pos(AdgMarker *marker)
391 AdgMarkerPrivate *data;
393 g_return_val_if_fail(ADG_IS_MARKER(marker), 0);
395 data = marker->data;
397 return data->pos;
401 * adg_marker_set_pos:
402 * @marker: an #AdgMarker
403 * @pos: the new pos
405 * Sets a new position on @marker. Check out adg_marker_get_pos() for
406 * details on what @pos represents.
408 void
409 adg_marker_set_pos(AdgMarker *marker, gdouble pos)
411 g_return_if_fail(ADG_IS_MARKER(marker));
413 if (set_pos(marker, pos))
414 g_object_notify((GObject *) marker, "pos");
418 * adg_marker_get_size:
419 * @marker: an #AdgMarker
421 * Gets the current size of @marker.
423 * Returns: the marker size, in global space
425 gdouble
426 adg_marker_get_size(AdgMarker *marker)
428 AdgMarkerPrivate *data;
430 g_return_val_if_fail(ADG_IS_MARKER(marker), 0);
432 data = marker->data;
434 return data->size;
438 * adg_marker_set_size:
439 * @marker: an #AdgMarker
440 * @size: the new size
442 * Sets a new size on @marker. The @size is an implementation-dependent
443 * property: it has meaning only when used by an #AdgMarker derived type.
445 void
446 adg_marker_set_size(AdgMarker *marker, gdouble size)
448 g_return_if_fail(ADG_IS_MARKER(marker));
450 if (set_size(marker, size))
451 g_object_notify((GObject *) marker, "size");
455 * adg_marker_model:
456 * @marker: an #AdgMarker
458 * <note><para>
459 * This function is only useful in marker implementations.
460 * </para></note>
462 * Gets the model of @marker. If the model is not found, it is
463 * automatically created by calling the create_model() virtual method.
465 * Returns: the current model owned by @marker or %NULL on errors
467 AdgModel *
468 adg_marker_model(AdgMarker *marker)
470 AdgMarkerPrivate *data;
472 g_return_val_if_fail(ADG_IS_MARKER(marker), NULL);
474 data = marker->data;
476 if (data->model == NULL) {
477 /* Model not found: regenerate it */
478 AdgMarkerClass *marker_class = ADG_MARKER_GET_CLASS(marker);
480 adg_marker_set_model(marker, marker_class->create_model(marker));
483 return data->model;
487 * adg_marker_get_model:
488 * @marker: an #AdgMarker
490 * <note><para>
491 * This function is only useful in marker implementations.
492 * </para></note>
494 * Gets the current model of @marker. This is an accessor method:
495 * if you need to get the model for rendering, use adg_marker_model()
496 * instead.
498 * Returns: the cached model owned by @marker or %NULL on errors
500 AdgModel *
501 adg_marker_get_model(AdgMarker *marker)
503 AdgMarkerPrivate *data;
505 g_return_val_if_fail(ADG_IS_MARKER(marker), NULL);
507 data = marker->data;
509 return data->model;
513 * adg_marker_set_model:
514 * @marker: an #AdgMarker
515 * @model: a new #AdgModel
517 * <note><para>
518 * This function is only useful in marker implementations.
519 * </para></note>
521 * Sets a new model for @marker. The reference to the old model (if an
522 * old model was present) is dropped while a new reference is added to
523 * @model.
525 void
526 adg_marker_set_model(AdgMarker *marker, AdgModel *model)
528 g_return_if_fail(ADG_IS_MARKER(marker));
530 if (set_model(marker, model))
531 g_object_notify((GObject *) marker, "model");
535 static gboolean
536 invalidate(AdgEntity *entity)
538 AdgMarker *marker = (AdgMarker *) entity;
540 adg_marker_set_model(marker, NULL);
542 return TRUE;
546 static gboolean
547 set_path(AdgMarker *marker, AdgPath *path)
549 AdgMarkerPrivate *data;
550 AdgEntity *entity;
552 data = marker->data;
554 if (path == data->path)
555 return FALSE;
557 entity = (AdgEntity *) marker;
559 if (data->path != NULL) {
560 /* Restore the original segment in the old path */
561 set_n_segment(marker, 0);
563 g_object_weak_unref((GObject *) data->path,
564 (GWeakNotify) unset_path, marker);
565 adg_model_remove_dependency((AdgModel *) data->path, entity);
568 data->path = path;
570 if (data->path != NULL) {
571 g_object_weak_ref((GObject *) data->path,
572 (GWeakNotify) unset_path, marker);
573 adg_model_add_dependency((AdgModel *) data->path, entity);
575 /* Set the first segment by default */
576 set_n_segment(marker, 1);
579 return TRUE;
582 static void
583 unset_path(AdgMarker *marker)
585 AdgMarkerPrivate *data = marker->data;
587 if (data->path != NULL) {
588 data->path = NULL;
589 set_n_segment(marker, 0);
593 static gboolean
594 set_n_segment(AdgMarker *marker, gint n_segment)
596 AdgMarkerPrivate *data = marker->data;
598 if (n_segment == data->n_segment)
599 return FALSE;
601 if (data->n_segment > 0) {
602 g_assert(data->backup_segment != NULL);
604 /* Restore the original segment */
605 adg_segment_deep_copy(&data->segment, data->backup_segment);
608 if (data->backup_segment != NULL) {
609 g_free(data->backup_segment);
610 data->backup_segment = NULL;
613 if (n_segment > 0) {
614 data->n_segment = 0;
615 g_return_val_if_fail(data->path != NULL, FALSE);
617 if (!adg_path_get_segment(data->path,
618 &data->segment, data->n_segment))
619 return FALSE;
621 /* Backup the segment */
622 data->backup_segment = adg_segment_deep_dup(&data->segment);
625 data->n_segment = n_segment;
627 return TRUE;
630 static gboolean
631 set_pos(AdgMarker *marker, gdouble pos)
633 AdgMarkerPrivate *data = marker->data;
635 if (pos == data->pos)
636 return FALSE;
638 data->pos = pos;
640 return TRUE;
643 static gboolean
644 set_size(AdgMarker *marker, gdouble size)
646 AdgMarkerPrivate *data = marker->data;
648 if (size == data->size)
649 return FALSE;
651 data->size = size;
653 return TRUE;
656 static gboolean
657 set_model(AdgMarker *marker, AdgModel *model)
659 AdgMarkerPrivate *data = marker->data;
661 if (model == data->model)
662 return FALSE;
664 if (data->model != NULL)
665 g_object_unref((GObject *) data->model);
667 data->model = model;
669 if (data->model != NULL)
670 g_object_ref((GObject *) data->model);
672 return TRUE;
675 static AdgModel *
676 create_model(AdgMarker *marker)
678 g_warning("%s: `create_model' method not implemented for type `%s'",
679 G_STRLOC, g_type_name(G_OBJECT_TYPE(marker)));
680 return NULL;