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.
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.
44 * All fields are privates and should not be used directly.
45 * Use its public methods instead.
49 #include "adg-marker.h"
50 #include "adg-marker-private.h"
53 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_marker_parent_class)
66 static void dispose (GObject
*object
);
67 static void get_property (GObject
*object
,
71 static void set_property (GObject
*object
,
75 static gboolean
invalidate (AdgEntity
*entity
);
76 static gboolean
set_path (AdgMarker
*marker
,
78 static void unset_path (AdgMarker
*marker
);
79 static gboolean
set_n_segment (AdgMarker
*marker
,
81 static gboolean
set_pos (AdgMarker
*marker
,
83 static gboolean
set_size (AdgMarker
*marker
,
85 static gboolean
set_model (AdgMarker
*marker
,
87 static AdgModel
* create_model (AdgMarker
*marker
);
90 G_DEFINE_ABSTRACT_TYPE(AdgMarker
, adg_marker
, ADG_TYPE_ENTITY
);
94 adg_marker_class_init(AdgMarkerClass
*klass
)
96 GObjectClass
*gobject_class
;
97 AdgEntityClass
*entity_class
;
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",
115 P_("The subject path for this marker"),
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",
122 P_("The segment of path where this marker should be applied (where 0 means undefined segment, 1 the first segment and so on)"),
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",
129 P_("The position ratio inside the segment where to put the marker (0 means the start point while 1 means the end point)"),
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",
136 P_("The size (in global space) of the marker"),
139 g_object_class_install_property(gobject_class
, PROP_SIZE
, param
);
141 param
= g_param_spec_object("model",
143 P_("A general purpose model usable by the marker implementations"),
146 g_object_class_install_property(gobject_class
, PROP_MODEL
, param
);
150 adg_marker_init(AdgMarker
*marker
)
152 AdgMarkerPrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(marker
,
157 data
->backup_segment
= NULL
;
158 memset(&data
->segment
, 0, sizeof(data
->segment
));
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
);
180 get_property(GObject
*object
,
181 guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
183 AdgMarkerPrivate
*data
= ((AdgMarker
*) object
)->data
;
187 g_value_set_object(value
, data
->path
);
190 g_value_set_uint(value
, data
->n_segment
);
193 g_value_set_double(value
, data
->pos
);
196 g_value_set_double(value
, data
->size
);
199 g_value_set_object(value
, data
->model
);
202 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
208 set_property(GObject
*object
,
209 guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
211 AdgMarker
*marker
= (AdgMarker
*) object
;
215 set_path(marker
, g_value_get_object(value
));
218 set_n_segment(marker
, g_value_get_uint(value
));
221 set_pos(marker
, g_value_get_double(value
));
224 set_size(marker
, g_value_get_double(value
));
227 set_model(marker
, g_value_get_object(value
));
230 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
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
245 adg_marker_get_path(AdgMarker
*marker
)
247 AdgMarkerPrivate
*data
;
249 g_return_val_if_fail(ADG_IS_MARKER(marker
), NULL
);
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.
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
290 adg_marker_get_n_segment(AdgMarker
*marker
)
292 AdgMarkerPrivate
*data
;
294 g_return_val_if_fail(ADG_IS_MARKER(marker
), 0);
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.
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
324 * This function is only useful in marker implementations.
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
338 * Returns: the original segment or %NULL on errors
341 adg_marker_get_backup_segment(AdgMarker
*marker
)
343 AdgMarkerPrivate
*data
;
345 g_return_val_if_fail(ADG_IS_MARKER(marker
), NULL
);
349 return data
->backup_segment
;
353 * adg_marker_get_segment:
354 * @marker: an #AdgMarker
357 * This function is only useful in marker implementations.
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
367 adg_marker_get_segment(AdgMarker
*marker
)
369 AdgMarkerPrivate
*data
;
371 g_return_val_if_fail(ADG_IS_MARKER(marker
), NULL
);
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
389 adg_marker_get_pos(AdgMarker
*marker
)
391 AdgMarkerPrivate
*data
;
393 g_return_val_if_fail(ADG_IS_MARKER(marker
), 0);
401 * adg_marker_set_pos:
402 * @marker: an #AdgMarker
405 * Sets a new position on @marker. Check out adg_marker_get_pos() for
406 * details on what @pos represents.
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
426 adg_marker_get_size(AdgMarker
*marker
)
428 AdgMarkerPrivate
*data
;
430 g_return_val_if_fail(ADG_IS_MARKER(marker
), 0);
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.
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");
456 * @marker: an #AdgMarker
459 * This function is only useful in marker implementations.
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
468 adg_marker_model(AdgMarker
*marker
)
470 AdgMarkerPrivate
*data
;
472 g_return_val_if_fail(ADG_IS_MARKER(marker
), NULL
);
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
));
487 * adg_marker_get_model:
488 * @marker: an #AdgMarker
491 * This function is only useful in marker implementations.
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()
498 * Returns: the cached model owned by @marker or %NULL on errors
501 adg_marker_get_model(AdgMarker
*marker
)
503 AdgMarkerPrivate
*data
;
505 g_return_val_if_fail(ADG_IS_MARKER(marker
), NULL
);
513 * adg_marker_set_model:
514 * @marker: an #AdgMarker
515 * @model: a new #AdgModel
518 * This function is only useful in marker implementations.
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
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");
536 invalidate(AdgEntity
*entity
)
538 AdgMarker
*marker
= (AdgMarker
*) entity
;
540 adg_marker_set_model(marker
, NULL
);
547 set_path(AdgMarker
*marker
, AdgPath
*path
)
549 AdgMarkerPrivate
*data
;
554 if (path
== data
->path
)
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
);
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);
583 unset_path(AdgMarker
*marker
)
585 AdgMarkerPrivate
*data
= marker
->data
;
587 if (data
->path
!= NULL
) {
589 set_n_segment(marker
, 0);
594 set_n_segment(AdgMarker
*marker
, gint n_segment
)
596 AdgMarkerPrivate
*data
= marker
->data
;
598 if (n_segment
== data
->n_segment
)
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
;
615 g_return_val_if_fail(data
->path
!= NULL
, FALSE
);
617 if (!adg_path_get_segment(data
->path
,
618 &data
->segment
, data
->n_segment
))
621 /* Backup the segment */
622 data
->backup_segment
= adg_segment_deep_dup(&data
->segment
);
625 data
->n_segment
= n_segment
;
631 set_pos(AdgMarker
*marker
, gdouble pos
)
633 AdgMarkerPrivate
*data
= marker
->data
;
635 if (pos
== data
->pos
)
644 set_size(AdgMarker
*marker
, gdouble size
)
646 AdgMarkerPrivate
*data
= marker
->data
;
648 if (size
== data
->size
)
657 set_model(AdgMarker
*marker
, AdgModel
*model
)
659 AdgMarkerPrivate
*data
= marker
->data
;
661 if (model
== data
->model
)
664 if (data
->model
!= NULL
)
665 g_object_unref((GObject
*) data
->model
);
669 if (data
->model
!= NULL
)
670 g_object_ref((GObject
*) data
->model
);
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
)));