Tested build process under ss-dev of OpenIndiana
[adg.git] / src / adg / adg-dim.c
blob50618b8f6ab9b2c2c503bdab8d9cdeceb15ebdc6
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011 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-dim
23 * @short_description: Root abstract class for all dimension entities
25 * The #AdgDim class is the base stub of all the dimension entities.
26 **/
28 /**
29 * AdgDim:
31 * All fields are private and should not be used directly.
32 * Use its public methods instead.
33 **/
36 #include "adg-internal.h"
37 #include "adg-container.h"
38 #include "adg-alignment.h"
39 #include "adg-textual.h"
40 #include "adg-toy-text.h"
41 #include "adg-text.h"
42 #include "adg-model.h"
43 #include "adg-trail.h"
44 #include "adg-point.h"
45 #include "adg-marker.h"
46 #include "adg-style.h"
47 #include "adg-dim-style.h"
48 #include "adg-dress.h"
49 #include "adg-dress-builtins.h"
51 #include "adg-dim.h"
52 #include "adg-dim-private.h"
56 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_dim_parent_class)
57 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_dim_parent_class)
60 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY)
62 enum {
63 PROP_0,
64 PROP_DIM_DRESS,
65 PROP_REF1,
66 PROP_REF2,
67 PROP_POS,
68 PROP_LEVEL,
69 PROP_OUTSIDE,
70 PROP_DETACHED,
71 PROP_VALUE,
72 PROP_MIN,
73 PROP_MAX
77 static void _adg_dispose (GObject *object);
78 static void _adg_finalize (GObject *object);
79 static void _adg_get_property (GObject *object,
80 guint param_id,
81 GValue *value,
82 GParamSpec *pspec);
83 static void _adg_set_property (GObject *object,
84 guint param_id,
85 const GValue *value,
86 GParamSpec *pspec);
87 static void _adg_global_changed (AdgEntity *entity);
88 static void _adg_local_changed (AdgEntity *entity);
89 static void _adg_invalidate (AdgEntity *entity);
90 static void _adg_arrange (AdgEntity *entity);
91 static gchar * _adg_default_value (AdgDim *dim);
92 static gdouble _adg_quote_angle (gdouble angle);
93 static gboolean _adg_set_outside (AdgDim *dim,
94 AdgThreeState outside);
95 static gboolean _adg_set_detached (AdgDim *dim,
96 AdgThreeState detached);
97 static gboolean _adg_set_value (AdgDim *dim,
98 const gchar *value);
99 static gboolean _adg_set_min (AdgDim *dim,
100 const gchar *min);
101 static gboolean _adg_set_max (AdgDim *dim,
102 const gchar *max);
105 static void
106 adg_dim_class_init(AdgDimClass *klass)
108 GObjectClass *gobject_class;
109 AdgEntityClass *entity_class;
110 GParamSpec *param;
112 gobject_class = (GObjectClass *) klass;
113 entity_class = (AdgEntityClass *) klass;
115 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
117 gobject_class->dispose = _adg_dispose;
118 gobject_class->finalize = _adg_finalize;
119 gobject_class->get_property = _adg_get_property;
120 gobject_class->set_property = _adg_set_property;
122 entity_class->global_changed = _adg_global_changed;
123 entity_class->local_changed = _adg_local_changed;
124 entity_class->invalidate = _adg_invalidate;
125 entity_class->arrange = _adg_arrange;
127 klass->quote_angle = _adg_quote_angle;
128 klass->default_value = _adg_default_value;
130 param = adg_param_spec_dress("dim-dress",
131 P_("Dimension Dress"),
132 P_("The dress to use for rendering this dimension"),
133 ADG_DRESS_DIMENSION,
134 G_PARAM_READWRITE);
135 g_object_class_install_property(gobject_class, PROP_DIM_DRESS, param);
137 param = g_param_spec_boxed("ref1",
138 P_("First Reference"),
139 P_("First reference point of the dimension"),
140 ADG_TYPE_POINT,
141 G_PARAM_READWRITE);
142 g_object_class_install_property(gobject_class, PROP_REF1, param);
144 param = g_param_spec_boxed("ref2",
145 P_("Second Reference"),
146 P_("Second reference point of the dimension"),
147 ADG_TYPE_POINT,
148 G_PARAM_READWRITE);
149 g_object_class_install_property(gobject_class, PROP_REF2, param);
151 param = g_param_spec_boxed("pos",
152 P_("Position"),
153 P_("The reference position of the quote: it will be combined with \"level\" to get the real quote position"),
154 ADG_TYPE_POINT,
155 G_PARAM_READWRITE);
156 g_object_class_install_property(gobject_class, PROP_POS, param);
158 param = g_param_spec_double("level",
159 P_("Level"),
160 P_("The dimension level, that is the factor to multiply the baseline spacing (defined in the dimension style) to get the offset from pos where the quote should be rendered"),
161 -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
162 G_PARAM_READWRITE);
163 g_object_class_install_property(gobject_class, PROP_LEVEL, param);
165 param = g_param_spec_enum("outside",
166 P_("Outside"),
167 P_("Whether the arrows must be inside the extension lines (ADG_THREE_STATE_OFF), must be extended outside the extension lines (ADG_THREE_STATE_ON) or should be automatically handled depending on the available space"),
168 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
169 G_PARAM_READWRITE);
170 g_object_class_install_property(gobject_class, PROP_OUTSIDE, param);
172 param = g_param_spec_enum("detached",
173 P_("Detached Quote"),
174 P_("Where the quote must be positioned: in the middle of the base line (ADG_THREE_STATE_OFF), near the pos point (ADG_THREE_STATE_ON) or should be automatically deducted depending on the available space"),
175 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
176 G_PARAM_READWRITE);
177 g_object_class_install_property(gobject_class, PROP_DETACHED, param);
179 param = g_param_spec_string("value",
180 P_("Value Template"),
181 P_("The template string to be used for generating the set value of the quote"),
182 NULL,
183 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
184 g_object_class_install_property(gobject_class, PROP_VALUE, param);
186 param = g_param_spec_string("min",
187 P_("Minimum Value or Low Tolerance"),
188 P_("The minimum value allowed or the lowest tolerance from value (depending of the dimension style): set to NULL to suppress"),
189 NULL,
190 G_PARAM_READWRITE);
191 g_object_class_install_property(gobject_class, PROP_MIN, param);
193 param = g_param_spec_string("max",
194 P_("Maximum Value or High Tolerance"),
195 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
196 NULL,
197 G_PARAM_READWRITE);
198 g_object_class_install_property(gobject_class, PROP_MAX, param);
201 static void
202 adg_dim_init(AdgDim *dim)
204 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
205 AdgDimPrivate);
207 data->dim_dress = ADG_DRESS_DIMENSION;
208 data->ref1 = NULL;
209 data->ref2 = NULL;
210 data->pos = NULL;
211 data->level = 1;
212 data->outside = ADG_THREE_STATE_UNKNOWN;
213 data->detached = ADG_THREE_STATE_UNKNOWN;
214 data->min = NULL;
215 data->max = NULL;
217 #if 0
218 /* These ones are G_PARAM_CONSTRUCT, so initialized by GObject */
219 data->value = NULL
220 #endif
222 dim->data = data;
225 static void
226 _adg_dispose(GObject *object)
228 AdgEntity *entity;
229 AdgDimPrivate *data;
231 entity = (AdgEntity *) object;
232 data = ((AdgDim *) object)->data;
234 if (data->quote.entity) {
235 g_object_unref(data->quote.entity);
236 data->quote.entity = NULL;
239 if (data->ref1)
240 data->ref1 = adg_entity_point(entity, data->ref1, NULL);
242 if (data->ref2)
243 data->ref2 = adg_entity_point(entity, data->ref2, NULL);
245 if (data->pos)
246 data->pos = adg_entity_point(entity, data->pos, NULL);
248 if (_ADG_OLD_OBJECT_CLASS->dispose)
249 _ADG_OLD_OBJECT_CLASS->dispose(object);
252 static void
253 _adg_finalize(GObject *object)
255 AdgDimPrivate *data = ((AdgDim *) object)->data;
257 g_free(data->value);
258 g_free(data->min);
259 g_free(data->max);
261 if (_ADG_OLD_OBJECT_CLASS->finalize)
262 _ADG_OLD_OBJECT_CLASS->finalize(object);
265 static void
266 _adg_get_property(GObject *object, guint prop_id,
267 GValue *value, GParamSpec *pspec)
269 AdgDimPrivate *data = ((AdgDim *) object)->data;
271 switch (prop_id) {
272 case PROP_DIM_DRESS:
273 g_value_set_int(value, data->dim_dress);
274 break;
275 case PROP_REF1:
276 g_value_set_boxed(value, data->ref1);
277 break;
278 case PROP_REF2:
279 g_value_set_boxed(value, data->ref2);
280 break;
281 case PROP_POS:
282 g_value_set_boxed(value, data->pos);
283 break;
284 case PROP_LEVEL:
285 g_value_set_double(value, data->level);
286 break;
287 case PROP_OUTSIDE:
288 g_value_set_enum(value, data->outside);
289 break;
290 case PROP_DETACHED:
291 g_value_set_enum(value, data->detached);
292 break;
293 case PROP_VALUE:
294 g_value_set_string(value, data->value);
295 break;
296 case PROP_MIN:
297 g_value_set_string(value, data->min);
298 break;
299 case PROP_MAX:
300 g_value_set_string(value, data->max);
301 break;
302 default:
303 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
304 break;
308 static void
309 _adg_set_property(GObject *object, guint prop_id,
310 const GValue *value, GParamSpec *pspec)
312 AdgEntity *entity;
313 AdgDim *dim;
314 AdgDimPrivate *data;
316 entity = (AdgEntity *) object;
317 dim = (AdgDim *) object;
318 data = dim->data;
320 switch (prop_id) {
321 case PROP_DIM_DRESS:
322 data->dim_dress = g_value_get_int(value);
323 break;
324 case PROP_REF1:
325 data->ref1 = adg_entity_point(entity, data->ref1,
326 g_value_get_boxed(value));
327 break;
328 case PROP_REF2:
329 data->ref2 = adg_entity_point(entity, data->ref2,
330 g_value_get_boxed(value));
331 break;
332 case PROP_POS:
333 data->pos = adg_entity_point(entity, data->pos,
334 g_value_get_boxed(value));
335 break;
336 case PROP_LEVEL:
337 data->level = g_value_get_double(value);
338 break;
339 case PROP_OUTSIDE:
340 _adg_set_outside(dim, g_value_get_enum(value));
341 break;
342 case PROP_DETACHED:
343 _adg_set_detached(dim, g_value_get_enum(value));
344 break;
345 case PROP_VALUE:
346 _adg_set_value(dim, g_value_get_string(value));
347 break;
348 case PROP_MIN:
349 _adg_set_min(dim, g_value_get_string(value));
350 break;
351 case PROP_MAX:
352 _adg_set_max(dim, g_value_get_string(value));
353 break;
354 default:
355 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
356 break;
362 * adg_dim_set_dim_dress:
363 * @dim: an #AdgDim
364 * @dress: the new #AdgDress to use
366 * Sets a new dimension dress to @dim. The new dress must be
367 * related to the original dress for this property: you cannot
368 * set a dress used for line styles to a dress managing fonts.
370 * The check is done by calling adg_dress_are_related() with
371 * @dress and the previous dress as arguments. Check out its
372 * documentation for details on what is a related dress.
374 void
375 adg_dim_set_dim_dress(AdgDim *dim, AdgDress dress)
377 g_return_if_fail(ADG_IS_DIM(dim));
378 g_object_set(dim, "dim-dress", dress, NULL);
382 * adg_dim_get_dim_dress:
383 * @dim: an #AdgDim
385 * Gets the dimension dress to be used in rendering @dim.
387 * Returns: the current dimension dress
389 AdgDress
390 adg_dim_get_dim_dress(AdgDim *dim)
392 AdgDimPrivate *data;
394 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_DRESS_UNDEFINED);
396 data = dim->data;
398 return data->dim_dress;
402 * adg_dim_set_ref1:
403 * @dim: an #AdgDim
404 * @ref1: the new point to use as first reference
406 * Sets the #AdgDim:ref1 property to @ref1. The old point
407 * is silently discarded, unreferencing its model if that
408 * point was bound to a named pair (hence, possibly destroying
409 * the model if this was the last reference).
411 * @ref1 can be %NULL, in which case the point is destroyed.
413 void
414 adg_dim_set_ref1(AdgDim *dim, const AdgPoint *ref1)
416 g_return_if_fail(ADG_IS_DIM(dim));
417 g_object_set(dim, "ref1", ref1, NULL);
421 * adg_dim_set_ref1_explicit:
422 * @dim: an #AdgDim
423 * @x: x coordinate of the first reference point
424 * @y: y coordinate of the first reference point
426 * Sets the #AdgDim:ref1 property to the (@x, @y) explicit
427 * coordinates. The old point is silently discarded,
428 * unreferencing its model if that point was bound to a named
429 * pair (hence, possibly destroying the model if this was the
430 * last reference).
432 void
433 adg_dim_set_ref1_explicit(AdgDim *dim, gdouble x, gdouble y)
435 AdgPoint *point = adg_point_new();
437 adg_point_set_pair_explicit(point, x, y);
438 adg_dim_set_ref1(dim, point);
440 adg_point_destroy(point);
444 * adg_dim_set_ref1_from_pair:
445 * @dim: an #AdgDim
446 * @ref1: the coordinates pair of the first reference point
448 * Convenient function to set the #AdgDim:ref1 property using a
449 * pair instead of explicit coordinates.
451 void
452 adg_dim_set_ref1_from_pair(AdgDim *dim, const AdgPair *ref1)
454 g_return_if_fail(ref1 != NULL);
456 adg_dim_set_ref1_explicit(dim, ref1->x, ref1->y);
460 * adg_dim_set_ref1_from_model:
461 * @dim: an #AdgDim
462 * @model: the source #AdgModel
463 * @ref1: a named pair in @model
465 * Binds #AdgDim:ref1 to the @ref1 named pair of @model. If @model
466 * is %NULL, the point will be unset. In any case, the old point
467 * is silently discarded, unreferencing its model if that point
468 * was bound to a named pair (hence, possibly destroying the model
469 * if this was the last reference).
471 * The assignment is lazy so @ref1 could be not be present in @model.
472 * Anyway, at the first access to this point an error will be raised
473 * if the named pair is still missing.
475 void
476 adg_dim_set_ref1_from_model(AdgDim *dim, AdgModel *model, const gchar *ref1)
478 AdgPoint *point = adg_point_new();
480 adg_point_set_pair_from_model(point, model, ref1);
481 adg_dim_set_ref1(dim, point);
483 adg_point_destroy(point);
487 * adg_dim_get_ref1:
488 * @dim: an #AdgDim
490 * Gets the #AdgDim:ref1 point. The returned point is internally owned
491 * and must not be freed or modified. Anyway, it is not const because
492 * adg_point_get_pair() must be able to modify the internal cache of
493 * the returned point.
495 * Returns: the first reference point
497 AdgPoint *
498 adg_dim_get_ref1(AdgDim *dim)
500 AdgDimPrivate *data;
502 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
504 data = dim->data;
506 return data->ref1;
510 * adg_dim_set_ref2:
511 * @dim: an #AdgDim
512 * @ref2: the new point to use as second reference
514 * Sets the #AdgDim:ref2 property to @ref2. The old point
515 * is silently discarded, unreferencing its model if that
516 * point was bound to a named pair (hence, possibly destroying
517 * the model if it was the last reference).
519 * @ref2 can be %NULL, in which case the point is destroyed.
521 void
522 adg_dim_set_ref2(AdgDim *dim, const AdgPoint *ref2)
524 g_return_if_fail(ADG_IS_DIM(dim));
525 g_object_set(dim, "ref2", ref2, NULL);
529 * adg_dim_set_ref2_explicit:
530 * @dim: an #AdgDim
531 * @x: x coordinate of the second reference point
532 * @y: y coordinate of the second reference point
534 * Sets the #AdgDim:ref2 property to the (@x, @y) explicit
535 * coordinates. The old point is silently discarded,
536 * unreferencing its model if that point was bound to a named
537 * pair (hence, possibly destroying the model if this was the
538 * last reference).
540 void
541 adg_dim_set_ref2_explicit(AdgDim *dim, gdouble x, gdouble y)
543 AdgPoint *point = adg_point_new();
545 adg_point_set_pair_explicit(point, x, y);
546 adg_dim_set_ref2(dim, point);
548 adg_point_destroy(point);
552 * adg_dim_set_ref2_from_pair:
553 * @dim: an #AdgDim
554 * @ref2: the coordinates pair of the second reference point
556 * Convenient function to set the #AdgDim:ref2 property using a
557 * pair instead of explicit coordinates.
559 void
560 adg_dim_set_ref2_from_pair(AdgDim *dim, const AdgPair *ref2)
562 g_return_if_fail(ref2 != NULL);
564 adg_dim_set_ref2_explicit(dim, ref2->x, ref2->y);
568 * adg_dim_set_ref2_from_model:
569 * @dim: an #AdgDim
570 * @model: the source #AdgModel
571 * @ref2: a named pair in @model
573 * Binds #AdgDim:ref2 to the @ref2 named pair of @model. If @model
574 * is %NULL, the point will be unset. In any case, the old point
575 * is silently discarded, unreferencing its model if that point
576 * was bound to a named pair (hence, possibly destroying the model
577 * if this was the last reference).
579 * The assignment is lazy so @ref2 could be not be present in @model.
580 * Anyway, at the first access to this point an error will be raised
581 * if the named pair is still missing.
583 void
584 adg_dim_set_ref2_from_model(AdgDim *dim, AdgModel *model, const gchar *ref2)
586 AdgPoint *point = adg_point_new();
588 adg_point_set_pair_from_model(point, model, ref2);
589 adg_dim_set_ref2(dim, point);
591 adg_point_destroy(point);
595 * adg_dim_get_ref2:
596 * @dim: an #AdgDim
598 * Gets the #AdgDim:ref2 point. The returned point is internally owned
599 * and must not be freed or modified. Anyway, it is not const because
600 * adg_point_get_pair() must be able to modify the internal cache of
601 * the returned point.
603 * Returns: the second reference point
605 AdgPoint *
606 adg_dim_get_ref2(AdgDim *dim)
608 AdgDimPrivate *data;
610 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
612 data = dim->data;
614 return data->ref2;
618 * adg_dim_set_pos:
619 * @dim: an #AdgDim
620 * @pos: the new point to use as position
622 * Sets the #AdgDim:pos property to @pos. The old point
623 * is silently discarded, unreferencing its model if that
624 * point was bound to a named pair (hence, possibly destroying
625 * the model if it was the last reference).
627 * @pos can be %NULL, in which case the point is destroyed.
629 void
630 adg_dim_set_pos(AdgDim *dim, const AdgPoint *pos)
632 g_return_if_fail(ADG_IS_DIM(dim));
633 g_object_set(dim, "pos", pos, NULL);
637 * adg_dim_set_pos_explicit:
638 * @dim: an #AdgDim
639 * @x: x coordinate of the position
640 * @y: y coordinate of the position
642 * Sets the #AdgDim:pos property to the (@x, @y) explicit
643 * coordinates. The old point is silently discarded,
644 * unreferencing its model if that point was bound to a named
645 * pair (hence, possibly destroying the model if this was the
646 * last reference).
648 void
649 adg_dim_set_pos_explicit(AdgDim *dim, gdouble x, gdouble y)
651 AdgPoint *point = adg_point_new();
653 adg_point_set_pair_explicit(point, x, y);
654 adg_dim_set_pos(dim, point);
656 adg_point_destroy(point);
660 * adg_dim_set_pos_from_pair:
661 * @dim: an #AdgDim
662 * @pos: the coordinates pair of the position point
664 * Convenient function to set the #AdgDim:pos property using a
665 * pair instead of explicit coordinates.
667 void
668 adg_dim_set_pos_from_pair(AdgDim *dim, const AdgPair *pos)
670 g_return_if_fail(pos != NULL);
672 adg_dim_set_pos_explicit(dim, pos->x, pos->y);
676 * adg_dim_set_pos_from_model:
677 * @dim: an #AdgDim
678 * @model: the source #AdgModel
679 * @pos: a named pair in @model
681 * Binds #AdgDim:pos to the @pos named pair of @model. If @model
682 * is %NULL, the point will be unset. In any case, the old point
683 * is silently discarded, unreferencing its model if that point
684 * was bound to a named pair (hence, possibly destroying the model
685 * if this was the last reference).
687 * The assignment is lazy so @pos could be not be present in @model.
688 * Anyway, at the first access to this point an error will be raised
689 * if the named pair is still missing.
691 void
692 adg_dim_set_pos_from_model(AdgDim *dim, AdgModel *model, const gchar *pos)
694 AdgPoint *point = adg_point_new();
696 adg_point_set_pair_from_model(point, model, pos);
697 adg_dim_set_pos(dim, point);
699 adg_point_destroy(point);
703 * adg_dim_get_pos:
704 * @dim: an #AdgDim
706 * Gets the #AdgDim:pos point. The returned point is internally owned
707 * and must not be freed or modified. Anyway, it is not const because
708 * adg_point_get_pair() must be able to modify the internal cache of
709 * the returned point.
711 * Returns: the position point
713 AdgPoint *
714 adg_dim_get_pos(AdgDim *dim)
716 AdgDimPrivate *data;
718 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
720 data = dim->data;
722 return data->pos;
726 * adg_dim_set_level:
727 * @dim: an #AdgDim
728 * @level: the new level
730 * Sets a new level for this dimension. The level is used to
731 * stack the quotes using a spacing value from dim_style
732 * (specified in global space).
734 void
735 adg_dim_set_level(AdgDim *dim, gdouble level)
737 AdgDimPrivate *data;
739 g_return_if_fail(ADG_IS_DIM(dim));
741 data = dim->data;
742 data->level = level;
744 g_object_notify((GObject *) dim, "level");
748 * adg_dim_get_level:
749 * @dim: an #AdgDim
751 * Gets the level of this dimension.
753 * Returns: the level value
755 gdouble
756 adg_dim_get_level(AdgDim *dim)
758 AdgDimPrivate *data;
760 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
762 data = dim->data;
764 return data->level;
768 * adg_dim_set_outside:
769 * @dim: an #AdgDim
770 * @outside: the new outside state
772 * Sets a new state for the #AdgDim:outside flag: check the property
773 * documentation for further details.
775 void
776 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
778 g_return_if_fail(ADG_IS_DIM(dim));
780 if (_adg_set_outside(dim, outside))
781 g_object_notify((GObject *) dim, "outside");
785 * adg_dim_get_outside:
786 * @dim: an #AdgDim
788 * Gets the state of the #AdgDim:outside property: check the property
789 * documentation for further details.
791 * Returns: the current flag state
793 AdgThreeState
794 adg_dim_get_outside(AdgDim *dim)
796 AdgDimPrivate *data;
798 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
800 data = dim->data;
802 return data->outside;
806 * adg_dim_set_detached:
807 * @dim: an #AdgDim
808 * @detached: the new detached state
810 * Sets a new state for the #AdgDim:detached flag: check the property
811 * documentation for further details.
813 * This is used only by dimensions where detaching has meaning.
814 * In some cases, such as with #AdgRDim dimensions, this property is
815 * not used.
817 void
818 adg_dim_set_detached(AdgDim *dim, AdgThreeState detached)
820 g_return_if_fail(ADG_IS_DIM(dim));
822 if (_adg_set_detached(dim, detached))
823 g_object_notify((GObject *) dim, "detached");
827 * adg_dim_get_detached:
828 * @dim: an #AdgDim
830 * Gets the state of the #AdgDim:detached property: check the property
831 * documentation for further details.
833 * Returns: the current flag state
835 AdgThreeState
836 adg_dim_get_detached(AdgDim *dim)
838 AdgDimPrivate *data;
840 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
842 data = dim->data;
844 return data->detached;
848 * adg_dim_set_value:
849 * @dim: an #AdgDim
850 * @value: the value text
852 * Explicitely sets the text to use as value. If @value is %NULL or
853 * was never set, an automatic text is calculated using the format
854 * specified in the current #AdgDimStyle and getting its value by
855 * calling the default_value() virtual method.
857 * Inside the template string, the "<>" tag (or whatever specified
858 * by the #AdgDimStyle:number-tag property) is substituted with the
859 * string returned by the default_value() virtual method.
861 void
862 adg_dim_set_value(AdgDim *dim, const gchar *value)
864 g_return_if_fail(ADG_IS_DIM(dim));
866 if (_adg_set_value(dim, value))
867 g_object_notify((GObject *) dim, "value");
871 * adg_dim_get_value:
872 * @dim: an #AdgDim
874 * Gets the value text. The string is internally owned and
875 * must not be freed or modified.
877 * Returns: the value text
879 const gchar *
880 adg_dim_get_value(AdgDim *dim)
882 AdgDimPrivate *data;
884 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
886 data = dim->data;
888 return data->value;
892 * adg_dim_set_limits:
893 * @dim: an #AdgDim
894 * @min: the new minumum value
895 * @max: the new maximum value
897 * Shortcut to set both the limits at once.
899 void
900 adg_dim_set_limits(AdgDim *dim, const gchar *min, const gchar *max)
902 g_return_if_fail(ADG_IS_DIM(dim));
904 g_object_freeze_notify((GObject *) dim);
905 adg_dim_set_min(dim, min);
906 adg_dim_set_max(dim, max);
907 g_object_thaw_notify((GObject *) dim);
911 * adg_dim_set_min:
912 * @dim: an #AdgDim
913 * @min: the new minimum limit
915 * Sets the minimum value. Use %NULL as @min to disable it.
917 void
918 adg_dim_set_min(AdgDim *dim, const gchar *min)
920 g_return_if_fail(ADG_IS_DIM(dim));
922 if (_adg_set_min(dim, min))
923 g_object_notify((GObject *) dim, "min");
927 * adg_dim_get_min:
928 * @dim: an #AdgDim
930 * Gets the minimum value text or %NULL on minimum value disabled.
931 * The string is internally owned and must not be freed or modified.
933 * Returns: the mimimum value text
935 const gchar *
936 adg_dim_get_min(AdgDim *dim)
938 AdgDimPrivate *data;
940 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
942 data = dim->data;
944 return data->min;
948 * adg_dim_set_max:
949 * @dim: an #AdgDim
950 * @max: the new maximum value
952 * Sets the maximum value. Use %NULL as @max to disable it.
954 void
955 adg_dim_set_max(AdgDim *dim, const gchar *max)
957 g_return_if_fail(ADG_IS_DIM(dim));
959 if (_adg_set_max(dim, max))
960 g_object_notify((GObject *) dim, "max");
964 * adg_dim_get_max:
965 * @dim: an #AdgDim
967 * Gets the maximum value text or %NULL on maximum value disabled.
968 * The string is internally owned and must not be freed or modified.
970 * Returns: the maximum value text
972 const gchar *
973 adg_dim_get_max(AdgDim *dim)
975 AdgDimPrivate *data;
977 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
979 data = dim->data;
981 return data->max;
985 * adg_dim_get_quote:
986 * @dim: an #AdgDim
988 * <note><para>
989 * This function is only useful in new dimension implementations.
990 * </para></note>
992 * Gets the quote entity, if any. This function is valid only after
993 * the #AdgDim implementation of the arrange() virtual method has
994 * been called.
996 * Returns: the quote entity
998 AdgAlignment *
999 adg_dim_get_quote(AdgDim *dim)
1001 AdgDimPrivate *data;
1003 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
1005 data = dim->data;
1007 return data->quote.entity;
1011 * adg_dim_quote_angle:
1012 * @dim: an #AdgDim
1013 * @angle: an angle (in radians)
1015 * <note><para>
1016 * This function is only useful in new dimension implementations.
1017 * </para></note>
1019 * Converts @angle accordling to the style of @dim. Any quote angle
1020 * should be validated by this method because every dimensioning
1021 * style has its own convention regardling the text rotation.
1023 * Returns: the angle to use (always in radians)
1025 gdouble
1026 adg_dim_quote_angle(AdgDim *dim, gdouble angle)
1028 AdgDimClass *klass;
1030 g_return_val_if_fail(ADG_IS_DIM(dim), angle);
1032 klass = ADG_DIM_GET_CLASS(dim);
1034 if (klass->quote_angle == NULL)
1035 return angle;
1037 return klass->quote_angle(angle);
1041 static void
1042 _adg_global_changed(AdgEntity *entity)
1044 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1046 if (_ADG_OLD_ENTITY_CLASS->global_changed)
1047 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
1049 if (data->quote.entity)
1050 adg_entity_global_changed((AdgEntity *) data->quote.entity);
1053 static void
1054 _adg_local_changed(AdgEntity *entity)
1056 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1058 if (_ADG_OLD_ENTITY_CLASS->local_changed)
1059 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
1061 if (data->quote.entity)
1062 adg_entity_local_changed((AdgEntity *) data->quote.entity);
1065 static void
1066 _adg_invalidate(AdgEntity *entity)
1068 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1070 if (data->quote.value) {
1071 g_object_unref(data->quote.value);
1072 data->quote.value = NULL;
1074 if (data->quote.entity)
1075 adg_entity_invalidate((AdgEntity *) data->quote.entity);
1076 if (data->ref1)
1077 adg_point_invalidate(data->ref1);
1078 if (data->ref2)
1079 adg_point_invalidate(data->ref2);
1080 if (data->pos)
1081 adg_point_invalidate(data->pos);
1083 if (_ADG_OLD_ENTITY_CLASS->invalidate)
1084 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
1087 static void
1088 _adg_arrange(AdgEntity *entity)
1090 AdgDim *dim;
1091 AdgDimPrivate *data;
1092 AdgEntity *quote_entity;
1093 AdgContainer *quote_container;
1094 AdgEntity *value_entity;
1095 AdgEntity *min_entity;
1096 AdgEntity *max_entity;
1097 const AdgPair *shift;
1098 AdgMatrix map;
1100 dim = (AdgDim *) entity;
1101 data = dim->data;
1103 /* Resolve the dim style */
1104 if (data->dim_style == NULL)
1105 data->dim_style = (AdgDimStyle *)
1106 adg_entity_style(entity, data->dim_dress);
1108 if (data->quote.entity == NULL)
1109 data->quote.entity = g_object_new(ADG_TYPE_ALIGNMENT,
1110 "local-method", ADG_MIX_NONE,
1111 "parent", dim, NULL);
1113 quote_entity = (AdgEntity *) data->quote.entity;
1114 quote_container = (AdgContainer *) data->quote.entity;
1116 if (data->quote.value == NULL) {
1117 AdgDimClass *klass;
1118 AdgDress dress;
1119 const gchar *tag;
1120 gchar *value;
1121 gchar *text;
1123 klass = ADG_DIM_GET_CLASS(dim);
1124 dress = adg_dim_style_get_value_dress(data->dim_style);
1125 tag = adg_dim_style_get_number_tag(data->dim_style);
1126 value = klass->default_value ? klass->default_value(dim) : NULL;
1128 data->quote.value = g_object_new(ADG_TYPE_BEST_TEXT,
1129 "local-method", ADG_MIX_PARENT,
1130 "font-dress", dress, NULL);
1131 adg_container_add(quote_container, (AdgEntity *) data->quote.value);
1133 if (data->value)
1134 text = adg_string_replace(data->value, tag, value);
1135 else
1136 text = g_strdup(value);
1138 g_free(value);
1140 adg_textual_set_text(data->quote.value, text);
1141 g_free(text);
1144 if (data->quote.min == NULL && data->min) {
1145 AdgDress dress = adg_dim_style_get_min_dress(data->dim_style);
1147 data->quote.min = g_object_new(ADG_TYPE_BEST_TEXT,
1148 "local-method", ADG_MIX_PARENT,
1149 "font-dress", dress, NULL);
1151 adg_container_add(quote_container, (AdgEntity *) data->quote.min);
1152 adg_textual_set_text(data->quote.min, data->min);
1155 if (data->quote.max == NULL && data->max) {
1156 AdgDress dress = adg_dim_style_get_max_dress(data->dim_style);
1158 data->quote.max = g_object_new(ADG_TYPE_BEST_TEXT,
1159 "local-method", ADG_MIX_PARENT,
1160 "font-dress", dress, NULL);
1162 adg_container_add(quote_container, (AdgEntity *) data->quote.max);
1163 adg_textual_set_text(data->quote.max, data->max);
1166 value_entity = (AdgEntity *) data->quote.value;
1167 min_entity = (AdgEntity *) data->quote.min;
1168 max_entity = (AdgEntity *) data->quote.max;
1169 shift = adg_dim_style_get_quote_shift(data->dim_style);
1171 adg_entity_set_global_map(quote_entity, adg_matrix_identity());
1172 adg_entity_global_changed(quote_entity);
1174 cairo_matrix_init_translate(&map, 0, shift->y);
1175 adg_entity_set_global_map(value_entity, &map);
1176 adg_entity_arrange(value_entity);
1178 /* Limit values (min and max) */
1179 if (min_entity || max_entity) {
1180 const AdgPair *limits_shift;
1181 gdouble spacing;
1182 AdgPair size;
1183 AdgMatrix unglobal;
1184 AdgPair org_min, org_max;
1186 limits_shift = adg_dim_style_get_limits_shift(data->dim_style);
1187 spacing = adg_dim_style_get_limits_spacing(data->dim_style);
1188 size = adg_entity_get_extents(value_entity)->size;
1189 adg_matrix_copy(&unglobal, adg_entity_get_global_matrix(entity));
1190 cairo_matrix_invert(&unglobal);
1191 cpml_vector_transform(&size, &unglobal);
1192 org_min.x = size.x + limits_shift->x;
1193 org_min.y = -size.y / 2 + limits_shift->y;
1194 org_max = org_min;
1196 if (min_entity && max_entity) {
1197 /* Prearrange the min entity to get its extents */
1198 adg_entity_arrange(min_entity);
1199 size = adg_entity_get_extents(min_entity)->size;
1200 cpml_vector_transform(&size, &unglobal);
1202 org_min.y += spacing / 2;
1203 org_max.y = org_min.y - size.y - spacing / 2;
1206 if (min_entity) {
1207 cairo_matrix_init_translate(&map, org_min.x, org_min.y);
1208 adg_entity_set_global_map(min_entity, &map);
1209 adg_entity_arrange(min_entity);
1212 if (max_entity) {
1213 cairo_matrix_init_translate(&map, org_max.x, org_max.y);
1214 adg_entity_set_global_map(max_entity, &map);
1215 adg_entity_arrange(max_entity);
1219 adg_entity_arrange(quote_entity);
1222 static gchar *
1223 _adg_default_value(AdgDim *dim)
1225 g_warning(_("AdgDim::default_value not implemented for `%s'"),
1226 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
1227 return g_strdup("undef");
1230 static gdouble
1231 _adg_quote_angle(gdouble angle)
1233 angle = cpml_angle(angle);
1235 if (angle > G_PI_4 * 4 / 3 || angle <= -G_PI_4 * 3)
1236 angle = cpml_angle(angle + G_PI);
1238 return angle;
1241 static gboolean
1242 _adg_set_outside(AdgDim *dim, AdgThreeState outside)
1244 AdgDimPrivate *data;
1246 g_return_val_if_fail(adg_is_enum_value(outside, ADG_TYPE_THREE_STATE),
1247 FALSE);
1249 data = dim->data;
1251 if (data->outside == outside)
1252 return FALSE;
1254 data->outside = outside;
1256 return TRUE;
1259 static gboolean
1260 _adg_set_detached(AdgDim *dim, AdgThreeState detached)
1262 AdgDimPrivate *data;
1264 g_return_val_if_fail(adg_is_enum_value(detached, ADG_TYPE_THREE_STATE),
1265 FALSE);
1267 data = dim->data;
1269 if (data->detached == detached)
1270 return FALSE;
1272 data->detached = detached;
1274 return TRUE;
1277 static gboolean
1278 _adg_set_value(AdgDim *dim, const gchar *value)
1280 AdgDimPrivate *data;
1282 data = dim->data;
1284 if (g_strcmp0(value, data->value) == 0)
1285 return FALSE;
1287 g_free(data->value);
1288 data->value = g_strdup(value);
1290 if (data->quote.value) {
1291 g_object_unref(data->quote.value);
1292 data->quote.value = NULL;
1295 return TRUE;
1298 static gboolean
1299 _adg_set_min(AdgDim *dim, const gchar *min)
1301 AdgDimPrivate *data = dim->data;
1303 if (g_strcmp0(min, data->min) == 0)
1304 return FALSE;
1306 g_free(data->min);
1307 data->min = g_strdup(min);
1309 if (data->quote.min) {
1310 g_object_unref(data->quote.min);
1311 data->quote.min = NULL;
1314 return TRUE;
1317 static gboolean
1318 _adg_set_max(AdgDim *dim, const gchar *max)
1320 AdgDimPrivate *data = dim->data;
1322 if (g_strcmp0(max, data->max) == 0)
1323 return FALSE;
1325 g_free(data->max);
1326 data->max = g_strdup(max);
1328 if (data->quote.max) {
1329 g_object_unref(data->quote.max);
1330 data->quote.max = NULL;
1333 return TRUE;