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.
32 * All fields are privates and should not be used directly.
33 * Use its public methods instead.
37 #include "adg-marker.h"
38 #include "adg-marker-private.h"
41 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_marker_parent_class)
54 static void dispose (GObject
*object
);
55 static void get_property (GObject
*object
,
59 static void set_property (GObject
*object
,
63 static gboolean
invalidate (AdgEntity
*entity
);
64 static gboolean
set_path (AdgMarker
*marker
,
66 static void unset_path (AdgMarker
*marker
);
67 static gboolean
set_n_segment (AdgMarker
*marker
,
69 static gboolean
set_pos (AdgMarker
*marker
,
71 static gboolean
set_size (AdgMarker
*marker
,
73 static gboolean
set_model (AdgMarker
*marker
,
75 static AdgModel
* create_model (AdgMarker
*marker
);
78 G_DEFINE_ABSTRACT_TYPE(AdgMarker
, adg_marker
, ADG_TYPE_ENTITY
);
82 adg_marker_class_init(AdgMarkerClass
*klass
)
84 GObjectClass
*gobject_class
;
85 AdgEntityClass
*entity_class
;
88 gobject_class
= (GObjectClass
*) klass
;
89 entity_class
= (AdgEntityClass
*) klass
;
91 g_type_class_add_private(klass
, sizeof(AdgMarkerPrivate
));
93 gobject_class
->dispose
= dispose
;
94 gobject_class
->set_property
= set_property
;
95 gobject_class
->get_property
= get_property
;
97 entity_class
->invalidate
= invalidate
;
99 klass
->create_model
= create_model
;
101 param
= g_param_spec_object("path",
103 P_("The subject path for this marker"),
105 G_PARAM_CONSTRUCT
|G_PARAM_READWRITE
);
106 g_object_class_install_property(gobject_class
, PROP_PATH
, param
);
108 param
= g_param_spec_uint("n-segment",
110 P_("The segment of path where this marker should be applied (where 0 means undefined segment, 1 the first segment and so on)"),
112 G_PARAM_CONSTRUCT
|G_PARAM_READWRITE
);
113 g_object_class_install_property(gobject_class
, PROP_N_SEGMENT
, param
);
115 param
= g_param_spec_double("pos",
117 P_("The position ratio inside the segment where to put the marker (0 means the start point while 1 means the end point)"),
119 G_PARAM_CONSTRUCT
|G_PARAM_READWRITE
);
120 g_object_class_install_property(gobject_class
, PROP_POS
, param
);
122 param
= g_param_spec_double("size",
124 P_("The size (in global space) of the marker"),
127 g_object_class_install_property(gobject_class
, PROP_SIZE
, param
);
129 param
= g_param_spec_object("model",
131 P_("A general purpose model usable by the marker implementations"),
134 g_object_class_install_property(gobject_class
, PROP_MODEL
, param
);
138 adg_marker_init(AdgMarker
*marker
)
140 AdgMarkerPrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(marker
,
145 data
->backup_segment
= NULL
;
146 memset(&data
->segment
, 0, sizeof(data
->segment
));
155 dispose(GObject
*object
)
157 AdgMarker
*marker
= (AdgMarker
*) object
;
159 adg_marker_set_model(marker
, NULL
);
160 adg_marker_set_path(marker
, NULL
);
162 if (PARENT_OBJECT_CLASS
->dispose
!= NULL
)
163 PARENT_OBJECT_CLASS
->dispose(object
);
168 get_property(GObject
*object
,
169 guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
171 AdgMarkerPrivate
*data
= ((AdgMarker
*) object
)->data
;
175 g_value_set_object(value
, data
->path
);
178 g_value_set_uint(value
, data
->n_segment
);
181 g_value_set_double(value
, data
->pos
);
184 g_value_set_double(value
, data
->size
);
187 g_value_set_object(value
, data
->model
);
190 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
196 set_property(GObject
*object
,
197 guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
199 AdgMarker
*marker
= (AdgMarker
*) object
;
203 set_path(marker
, g_value_get_object(value
));
206 set_n_segment(marker
, g_value_get_uint(value
));
209 set_pos(marker
, g_value_get_double(value
));
212 set_size(marker
, g_value_get_double(value
));
215 set_model(marker
, g_value_get_object(value
));
218 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
225 * adg_marker_get_path:
226 * @marker: an #AdgMarker
228 * Gets the path where this marker should be applied.
230 * Returns: the path owned by @marker or %NULL on errors
233 adg_marker_get_path(AdgMarker
*marker
)
235 AdgMarkerPrivate
*data
;
237 g_return_val_if_fail(ADG_IS_MARKER(marker
), NULL
);
245 * adg_marker_set_path:
246 * @marker: an #AdgMarker
247 * @path: a new #AdgPath
249 * Sets a new path where the marker should be applied. The weak reference
250 * to the old path (if an old path was present) is dropped while a new
251 * weak reference is added to @path. If @path is destroyed, the weak
252 * reference callback will automatically unset #AdgMarker:path and will
253 * set #AdgMarker:n-segment to %0.
255 * After setting a new path, the #AdgMarker:n-segment property is
256 * reset to %1. This means the first segment of the path is always
257 * selected by default.
260 adg_marker_set_path(AdgMarker
*marker
, AdgPath
*path
)
262 g_return_if_fail(ADG_IS_MARKER(marker
));
264 if (set_path(marker
, path
))
265 g_object_notify((GObject
*) marker
, "path");
269 * adg_marker_get_n_segment:
270 * @marker: an #AdgMarker
272 * Returns the segment of the associated path where this marker
273 * should be applied, where %1 is the first segment.
275 * Returns: an index greather than %0 on success or %0 on errors
278 adg_marker_get_n_segment(AdgMarker
*marker
)
280 AdgMarkerPrivate
*data
;
282 g_return_val_if_fail(ADG_IS_MARKER(marker
), 0);
286 return data
->n_segment
;
290 * adg_marker_set_n_segment:
291 * @marker: an #AdgMarker
292 * @n_segment: a new segment index
294 * Sets a new segment to use. @n_segment is expected to be greather than
295 * %0 and to not exceed the number of segments in the underlying path.
296 * By convention, %1 is the first segment.
299 adg_marker_set_n_segment(AdgMarker
*marker
, gint n_segment
)
301 g_return_if_fail(ADG_IS_MARKER(marker
));
303 if (set_n_segment(marker
, n_segment
))
304 g_object_notify((GObject
*) marker
, "n-segment");
308 * adg_marker_get_backup_segment:
309 * @marker: an #AdgMarker
312 * This function is only useful in marker implementations.
315 * Gets the original segment where the marker has been applied.
316 * Applying a marker could modify the underlying path, usually
317 * by trimming the original segment of a #AdgMarker:size dependent
318 * length from the end. The marker instance holds a copy of the
319 * original segment, got using adg_segment_deep_dup(), to be used
320 * in recomputation (when the marker changes size, for instance).
322 * When the subject segment is changed (either by changing
323 * #AdgMarker:path or #AdgMarker:n-segment) the original segment
326 * Returns: the original segment or %NULL on errors
329 adg_marker_get_backup_segment(AdgMarker
*marker
)
331 AdgMarkerPrivate
*data
;
333 g_return_val_if_fail(ADG_IS_MARKER(marker
), NULL
);
337 return data
->backup_segment
;
341 * adg_marker_get_segment:
342 * @marker: an #AdgMarker
345 * This function is only useful in marker implementations.
348 * Gets the segment where the marker will be applied. This segment
349 * is eventually a modified version of the backup segment, after
350 * having applied the marker.
352 * Returns: the segment or %NULL on errors
355 adg_marker_get_segment(AdgMarker
*marker
)
357 AdgMarkerPrivate
*data
;
359 g_return_val_if_fail(ADG_IS_MARKER(marker
), NULL
);
363 return &data
->segment
;
367 * adg_marker_get_pos:
368 * @marker: an #AdgMarker
370 * Gets the current position of @marker. The returned value is a ratio
371 * position referred to the segment associated to @marker: %0 means the
372 * start point and %1 means the end point of the segment.
374 * Returns: the marker position
377 adg_marker_get_pos(AdgMarker
*marker
)
379 AdgMarkerPrivate
*data
;
381 g_return_val_if_fail(ADG_IS_MARKER(marker
), 0);
389 * adg_marker_set_pos:
390 * @marker: an #AdgMarker
393 * Sets a new position on @marker. Check out adg_marker_get_pos() for
394 * details on what @pos represents.
397 adg_marker_set_pos(AdgMarker
*marker
, gdouble pos
)
399 g_return_if_fail(ADG_IS_MARKER(marker
));
401 if (set_pos(marker
, pos
))
402 g_object_notify((GObject
*) marker
, "pos");
406 * adg_marker_get_size:
407 * @marker: an #AdgMarker
409 * Gets the current size of @marker.
411 * Returns: the marker size, in global space
414 adg_marker_get_size(AdgMarker
*marker
)
416 AdgMarkerPrivate
*data
;
418 g_return_val_if_fail(ADG_IS_MARKER(marker
), 0);
426 * adg_marker_set_size:
427 * @marker: an #AdgMarker
428 * @size: the new size
430 * Sets a new size on @marker. The @size is an implementation-dependent
431 * property: it has meaning only when used by an #AdgMarker derived type.
434 adg_marker_set_size(AdgMarker
*marker
, gdouble size
)
436 g_return_if_fail(ADG_IS_MARKER(marker
));
438 if (set_size(marker
, size
))
439 g_object_notify((GObject
*) marker
, "size");
444 * @marker: an #AdgMarker
447 * This function is only useful in marker implementations.
450 * Gets the model of @marker. If the model is not found, it is
451 * automatically created by calling the create_model() virtual method.
453 * Returns: the current model owned by @marker or %NULL on errors
456 adg_marker_model(AdgMarker
*marker
)
458 AdgMarkerPrivate
*data
;
460 g_return_val_if_fail(ADG_IS_MARKER(marker
), NULL
);
464 if (data
->model
== NULL
) {
465 /* Model not found: regenerate it */
466 AdgMarkerClass
*marker_class
= ADG_MARKER_GET_CLASS(marker
);
468 adg_marker_set_model(marker
, marker_class
->create_model(marker
));
475 * adg_marker_get_model:
476 * @marker: an #AdgMarker
479 * This function is only useful in marker implementations.
482 * Gets the current model of @marker. This is an accessor method:
483 * if you need to get the model for rendering, use adg_marker_model()
486 * Returns: the cached model owned by @marker or %NULL on errors
489 adg_marker_get_model(AdgMarker
*marker
)
491 AdgMarkerPrivate
*data
;
493 g_return_val_if_fail(ADG_IS_MARKER(marker
), NULL
);
501 * adg_marker_set_model:
502 * @marker: an #AdgMarker
503 * @model: a new #AdgModel
506 * This function is only useful in marker implementations.
509 * Sets a new model for @marker. The reference to the old model (if an
510 * old model was present) is dropped while a new reference is added to
514 adg_marker_set_model(AdgMarker
*marker
, AdgModel
*model
)
516 g_return_if_fail(ADG_IS_MARKER(marker
));
518 if (set_model(marker
, model
))
519 g_object_notify((GObject
*) marker
, "model");
524 invalidate(AdgEntity
*entity
)
526 AdgMarker
*marker
= (AdgMarker
*) entity
;
528 adg_marker_set_model(marker
, NULL
);
535 set_path(AdgMarker
*marker
, AdgPath
*path
)
537 AdgMarkerPrivate
*data
;
542 if (path
== data
->path
)
545 entity
= (AdgEntity
*) marker
;
547 if (data
->path
!= NULL
) {
548 /* Restore the original segment in the old path */
549 set_n_segment(marker
, 0);
551 g_object_weak_unref((GObject
*) data
->path
,
552 (GWeakNotify
) unset_path
, marker
);
553 adg_model_remove_dependency((AdgModel
*) data
->path
, entity
);
558 if (data
->path
!= NULL
) {
559 g_object_weak_ref((GObject
*) data
->path
,
560 (GWeakNotify
) unset_path
, marker
);
561 adg_model_add_dependency((AdgModel
*) data
->path
, entity
);
563 /* Set the first segment by default */
564 set_n_segment(marker
, 1);
571 unset_path(AdgMarker
*marker
)
573 AdgMarkerPrivate
*data
= marker
->data
;
575 if (data
->path
!= NULL
) {
577 set_n_segment(marker
, 0);
582 set_n_segment(AdgMarker
*marker
, gint n_segment
)
584 AdgMarkerPrivate
*data
= marker
->data
;
586 if (n_segment
== data
->n_segment
)
589 if (data
->n_segment
> 0) {
590 g_assert(data
->backup_segment
!= NULL
);
592 /* Restore the original segment */
593 adg_segment_deep_copy(&data
->segment
, data
->backup_segment
);
596 if (data
->backup_segment
!= NULL
) {
597 g_free(data
->backup_segment
);
598 data
->backup_segment
= NULL
;
603 g_return_val_if_fail(data
->path
!= NULL
, FALSE
);
605 if (!adg_path_get_segment(data
->path
,
606 &data
->segment
, data
->n_segment
))
609 /* Backup the segment */
610 data
->backup_segment
= adg_segment_deep_dup(&data
->segment
);
613 data
->n_segment
= n_segment
;
619 set_pos(AdgMarker
*marker
, gdouble pos
)
621 AdgMarkerPrivate
*data
= marker
->data
;
623 if (pos
== data
->pos
)
632 set_size(AdgMarker
*marker
, gdouble size
)
634 AdgMarkerPrivate
*data
= marker
->data
;
636 if (size
== data
->size
)
645 set_model(AdgMarker
*marker
, AdgModel
*model
)
647 AdgMarkerPrivate
*data
= marker
->data
;
649 if (model
== data
->model
)
652 if (data
->model
!= NULL
)
653 g_object_unref((GObject
*) data
->model
);
657 if (data
->model
!= NULL
)
658 g_object_ref((GObject
*) data
->model
);
664 create_model(AdgMarker
*marker
)
666 g_warning("%s: `create_model' method not implemented for type `%s'",
667 G_STRLOC
, g_type_name(G_OBJECT_TYPE(marker
)));