doc: improve t_i methods section in BAIOCA
[adg.git] / src / adg / adg-dim.c
blob4efd8c89bbbb45f7be83b414ded18164b44b5318
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010,2011,2012,2013 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.
27 * Since: 1.0
28 **/
30 /**
31 * AdgDim:
33 * All fields are private and should not be used directly.
34 * Use its public methods instead.
36 * Since: 1.0
37 **/
39 /**
40 * AdgDimClass:
41 * @quote_angle: virtual method that must return the rotation angle of the
42 * quote (in radians) of the current dimension.
43 * @default_value: abstract virtual method that must return the default value
44 * (as a newly allocated string to be freed with g_free()) of
45 * the current dimension.
47 * The default implementation of @quote_angle flips the quote if it should be
48 * rotated in the bottom right half of the circle, that is:
50 * <informalexample><programlisting>
51 * if 1/3 PI <= angle <= -3/4 PI; then angle += PI.
52 * </programlisting></informalexample>
54 * The virtual method @default_value instead *must* be implemented by any
55 * derived class. The default implementation will trigger an error if called.
57 * Since: 1.0
58 **/
61 #include "adg-internal.h"
62 #include "adg-text-internal.h"
64 #include "adg-container.h"
65 #include "adg-alignment.h"
66 #include "adg-model.h"
67 #include "adg-trail.h"
68 #include "adg-point.h"
69 #include "adg-marker.h"
70 #include "adg-dim-style.h"
71 #include "adg-dress.h"
72 #include "adg-param-dress.h"
74 #include "adg-dim.h"
75 #include "adg-dim-private.h"
79 #define _ADG_OLD_OBJECT_CLASS ((GObjectClass *) adg_dim_parent_class)
80 #define _ADG_OLD_ENTITY_CLASS ((AdgEntityClass *) adg_dim_parent_class)
83 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY)
85 enum {
86 PROP_0,
87 PROP_DIM_DRESS,
88 PROP_REF1,
89 PROP_REF2,
90 PROP_POS,
91 PROP_LEVEL,
92 PROP_OUTSIDE,
93 PROP_DETACHED,
94 PROP_VALUE,
95 PROP_MIN,
96 PROP_MAX
100 static void _adg_dispose (GObject *object);
101 static void _adg_finalize (GObject *object);
102 static void _adg_get_property (GObject *object,
103 guint param_id,
104 GValue *value,
105 GParamSpec *pspec);
106 static void _adg_set_property (GObject *object,
107 guint param_id,
108 const GValue *value,
109 GParamSpec *pspec);
110 static void _adg_global_changed (AdgEntity *entity);
111 static void _adg_local_changed (AdgEntity *entity);
112 static void _adg_invalidate (AdgEntity *entity);
113 static void _adg_arrange (AdgEntity *entity);
114 static gchar * _adg_default_value (AdgDim *dim);
115 static gdouble _adg_quote_angle (gdouble angle);
116 static gboolean _adg_set_outside (AdgDim *dim,
117 AdgThreeState outside);
118 static gboolean _adg_set_detached (AdgDim *dim,
119 AdgThreeState detached);
120 static gboolean _adg_set_value (AdgDim *dim,
121 const gchar *value);
122 static gboolean _adg_set_min (AdgDim *dim,
123 const gchar *min);
124 static gboolean _adg_set_max (AdgDim *dim,
125 const gchar *max);
128 static void
129 adg_dim_class_init(AdgDimClass *klass)
131 GObjectClass *gobject_class;
132 AdgEntityClass *entity_class;
133 GParamSpec *param;
135 gobject_class = (GObjectClass *) klass;
136 entity_class = (AdgEntityClass *) klass;
138 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
140 gobject_class->dispose = _adg_dispose;
141 gobject_class->finalize = _adg_finalize;
142 gobject_class->get_property = _adg_get_property;
143 gobject_class->set_property = _adg_set_property;
145 entity_class->global_changed = _adg_global_changed;
146 entity_class->local_changed = _adg_local_changed;
147 entity_class->invalidate = _adg_invalidate;
148 entity_class->arrange = _adg_arrange;
150 klass->quote_angle = _adg_quote_angle;
151 klass->default_value = _adg_default_value;
153 param = adg_param_spec_dress("dim-dress",
154 P_("Dimension Dress"),
155 P_("The dress to use for rendering this dimension"),
156 ADG_DRESS_DIMENSION,
157 G_PARAM_READWRITE);
158 g_object_class_install_property(gobject_class, PROP_DIM_DRESS, param);
160 param = g_param_spec_boxed("ref1",
161 P_("First Reference"),
162 P_("First reference point of the dimension"),
163 ADG_TYPE_POINT,
164 G_PARAM_READWRITE);
165 g_object_class_install_property(gobject_class, PROP_REF1, param);
167 param = g_param_spec_boxed("ref2",
168 P_("Second Reference"),
169 P_("Second reference point of the dimension"),
170 ADG_TYPE_POINT,
171 G_PARAM_READWRITE);
172 g_object_class_install_property(gobject_class, PROP_REF2, param);
174 param = g_param_spec_boxed("pos",
175 P_("Position"),
176 P_("The reference position of the quote: it will be combined with \"level\" to get the real quote position"),
177 ADG_TYPE_POINT,
178 G_PARAM_READWRITE);
179 g_object_class_install_property(gobject_class, PROP_POS, param);
181 param = g_param_spec_double("level",
182 P_("Level"),
183 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"),
184 -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
185 G_PARAM_READWRITE);
186 g_object_class_install_property(gobject_class, PROP_LEVEL, param);
188 param = g_param_spec_enum("outside",
189 P_("Outside"),
190 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"),
191 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
192 G_PARAM_READWRITE);
193 g_object_class_install_property(gobject_class, PROP_OUTSIDE, param);
195 param = g_param_spec_enum("detached",
196 P_("Detached Quote"),
197 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"),
198 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
199 G_PARAM_READWRITE);
200 g_object_class_install_property(gobject_class, PROP_DETACHED, param);
202 param = g_param_spec_string("value",
203 P_("Value Template"),
204 P_("The template string to be used for generating the set value of the quote"),
205 NULL,
206 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
207 g_object_class_install_property(gobject_class, PROP_VALUE, param);
209 param = g_param_spec_string("min",
210 P_("Minimum Value or Low Tolerance"),
211 P_("The minimum value allowed or the lowest tolerance from value (depending of the dimension style): set to NULL to suppress"),
212 NULL,
213 G_PARAM_READWRITE);
214 g_object_class_install_property(gobject_class, PROP_MIN, param);
216 param = g_param_spec_string("max",
217 P_("Maximum Value or High Tolerance"),
218 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
219 NULL,
220 G_PARAM_READWRITE);
221 g_object_class_install_property(gobject_class, PROP_MAX, param);
224 static void
225 adg_dim_init(AdgDim *dim)
227 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
228 AdgDimPrivate);
230 data->dim_dress = ADG_DRESS_DIMENSION;
231 data->ref1 = NULL;
232 data->ref2 = NULL;
233 data->pos = NULL;
234 data->level = 1;
235 data->outside = ADG_THREE_STATE_UNKNOWN;
236 data->detached = ADG_THREE_STATE_UNKNOWN;
237 data->min = NULL;
238 data->max = NULL;
240 #if 0
241 /* This one is G_PARAM_CONSTRUCT, so set by property inizialization */
242 data->value = NULL
243 #endif
245 dim->data = data;
248 static void
249 _adg_dispose(GObject *object)
251 AdgEntity *entity;
252 AdgDimPrivate *data;
254 entity = (AdgEntity *) object;
255 data = ((AdgDim *) object)->data;
257 if (data->quote.entity) {
258 g_object_unref(data->quote.entity);
259 data->quote.entity = NULL;
262 if (data->ref1)
263 data->ref1 = adg_entity_point(entity, data->ref1, NULL);
265 if (data->ref2)
266 data->ref2 = adg_entity_point(entity, data->ref2, NULL);
268 if (data->pos)
269 data->pos = adg_entity_point(entity, data->pos, NULL);
271 if (_ADG_OLD_OBJECT_CLASS->dispose)
272 _ADG_OLD_OBJECT_CLASS->dispose(object);
275 static void
276 _adg_finalize(GObject *object)
278 AdgDimPrivate *data = ((AdgDim *) object)->data;
280 g_free(data->value);
281 g_free(data->min);
282 g_free(data->max);
284 if (_ADG_OLD_OBJECT_CLASS->finalize)
285 _ADG_OLD_OBJECT_CLASS->finalize(object);
288 static void
289 _adg_get_property(GObject *object, guint prop_id,
290 GValue *value, GParamSpec *pspec)
292 AdgDimPrivate *data = ((AdgDim *) object)->data;
294 switch (prop_id) {
295 case PROP_DIM_DRESS:
296 g_value_set_enum(value, data->dim_dress);
297 break;
298 case PROP_REF1:
299 g_value_set_boxed(value, data->ref1);
300 break;
301 case PROP_REF2:
302 g_value_set_boxed(value, data->ref2);
303 break;
304 case PROP_POS:
305 g_value_set_boxed(value, data->pos);
306 break;
307 case PROP_LEVEL:
308 g_value_set_double(value, data->level);
309 break;
310 case PROP_OUTSIDE:
311 g_value_set_enum(value, data->outside);
312 break;
313 case PROP_DETACHED:
314 g_value_set_enum(value, data->detached);
315 break;
316 case PROP_VALUE:
317 g_value_set_string(value, data->value);
318 break;
319 case PROP_MIN:
320 g_value_set_string(value, data->min);
321 break;
322 case PROP_MAX:
323 g_value_set_string(value, data->max);
324 break;
325 default:
326 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
327 break;
331 static void
332 _adg_set_property(GObject *object, guint prop_id,
333 const GValue *value, GParamSpec *pspec)
335 AdgEntity *entity;
336 AdgDim *dim;
337 AdgDimPrivate *data;
339 entity = (AdgEntity *) object;
340 dim = (AdgDim *) object;
341 data = dim->data;
343 switch (prop_id) {
344 case PROP_DIM_DRESS:
345 data->dim_dress = g_value_get_enum(value);
346 break;
347 case PROP_REF1:
348 data->ref1 = adg_entity_point(entity, data->ref1,
349 g_value_get_boxed(value));
350 break;
351 case PROP_REF2:
352 data->ref2 = adg_entity_point(entity, data->ref2,
353 g_value_get_boxed(value));
354 break;
355 case PROP_POS:
356 data->pos = adg_entity_point(entity, data->pos,
357 g_value_get_boxed(value));
358 break;
359 case PROP_LEVEL:
360 data->level = g_value_get_double(value);
361 break;
362 case PROP_OUTSIDE:
363 _adg_set_outside(dim, g_value_get_enum(value));
364 break;
365 case PROP_DETACHED:
366 _adg_set_detached(dim, g_value_get_enum(value));
367 break;
368 case PROP_VALUE:
369 _adg_set_value(dim, g_value_get_string(value));
370 break;
371 case PROP_MIN:
372 _adg_set_min(dim, g_value_get_string(value));
373 break;
374 case PROP_MAX:
375 _adg_set_max(dim, g_value_get_string(value));
376 break;
377 default:
378 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
379 break;
385 * adg_dim_set_dim_dress:
386 * @dim: an #AdgDim
387 * @dress: the new #AdgDress to use
389 * Sets a new dimension dress to @dim. The new dress must be
390 * related to the original dress for this property: you cannot
391 * set a dress used for line styles to a dress managing fonts.
393 * The check is done by calling adg_dress_are_related() with
394 * @dress and the previous dress as arguments. Check out its
395 * documentation for details on what is a related dress.
397 * Since: 1.0
399 void
400 adg_dim_set_dim_dress(AdgDim *dim, AdgDress dress)
402 g_return_if_fail(ADG_IS_DIM(dim));
403 g_object_set(dim, "dim-dress", dress, NULL);
407 * adg_dim_get_dim_dress:
408 * @dim: an #AdgDim
410 * Gets the dimension dress to be used in rendering @dim.
412 * Returns: (transfer none): the current dimension dress.
414 * Since: 1.0
416 AdgDress
417 adg_dim_get_dim_dress(AdgDim *dim)
419 AdgDimPrivate *data;
421 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_DRESS_UNDEFINED);
423 data = dim->data;
425 return data->dim_dress;
429 * adg_dim_set_ref1:
430 * @dim: an #AdgDim
431 * @ref1: the new point to use as first reference
433 * Sets the #AdgDim:ref1 property to @ref1. The old point
434 * is silently discarded, unreferencing its model if that
435 * point was bound to a named pair (hence, possibly destroying
436 * the model if this was the last reference).
438 * @ref1 can be <constant>NULL</constant>, in which case the
439 * point is destroyed.
441 * Since: 1.0
443 void
444 adg_dim_set_ref1(AdgDim *dim, const AdgPoint *ref1)
446 g_return_if_fail(ADG_IS_DIM(dim));
447 g_object_set(dim, "ref1", ref1, NULL);
451 * adg_dim_set_ref1_explicit:
452 * @dim: an #AdgDim
453 * @x: x coordinate of the first reference point
454 * @y: y coordinate of the first reference point
456 * Sets the #AdgDim:ref1 property to the (@x, @y) explicit
457 * coordinates. The old point is silently discarded,
458 * unreferencing its model if that point was bound to a named
459 * pair (hence, possibly destroying the model if this was the
460 * last reference).
462 * Since: 1.0
464 void
465 adg_dim_set_ref1_explicit(AdgDim *dim, gdouble x, gdouble y)
467 AdgPoint *point = adg_point_new();
469 adg_point_set_pair_explicit(point, x, y);
470 adg_dim_set_ref1(dim, point);
472 adg_point_destroy(point);
476 * adg_dim_set_ref1_from_pair:
477 * @dim: an #AdgDim
478 * @ref1: the coordinates pair of the first reference point
480 * Convenient function to set the #AdgDim:ref1 property using a
481 * pair instead of explicit coordinates.
483 * Since: 1.0
485 void
486 adg_dim_set_ref1_from_pair(AdgDim *dim, const CpmlPair *ref1)
488 g_return_if_fail(ref1 != NULL);
490 adg_dim_set_ref1_explicit(dim, ref1->x, ref1->y);
494 * adg_dim_set_ref1_from_model:
495 * @dim: an #AdgDim
496 * @model: the source #AdgModel
497 * @ref1: a named pair in @model
499 * Binds #AdgDim:ref1 to the @ref1 named pair of @model. If @model
500 * is <constant>NULL</constant>, the point will be unset. In any case,
501 * the old point is silently discarded, unreferencing its model
502 * if that point was bound to a named pair (hence, possibly destroying
503 * the model if this was the last reference).
505 * The assignment is lazy so @ref1 could be not be present in @model.
506 * Anyway, at the first access to this point an error will be raised
507 * if the named pair is still missing.
509 * Since: 1.0
511 void
512 adg_dim_set_ref1_from_model(AdgDim *dim, AdgModel *model, const gchar *ref1)
514 AdgPoint *point = adg_point_new();
516 adg_point_set_pair_from_model(point, model, ref1);
517 adg_dim_set_ref1(dim, point);
519 adg_point_destroy(point);
523 * adg_dim_get_ref1:
524 * @dim: an #AdgDim
526 * Gets the #AdgDim:ref1 point of @dim.
528 * The returned point is internally owned and must not be freed
529 * or modified. Anyway it is not const because a call to
530 * adg_point_update() with the returned value must be able to
531 * modify the internal cache.
533 * Returns: (transfer none): the first reference point.
535 * Since: 1.0
537 AdgPoint *
538 adg_dim_get_ref1(AdgDim *dim)
540 AdgDimPrivate *data;
542 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
544 data = dim->data;
546 return data->ref1;
550 * adg_dim_set_ref2:
551 * @dim: an #AdgDim
552 * @ref2: the new point to use as second reference
554 * Sets the #AdgDim:ref2 property to @ref2. The old point
555 * is silently discarded, unreferencing its model if that
556 * point was bound to a named pair (hence, possibly destroying
557 * the model if it was the last reference).
559 * @ref2 can be <constant>NULL</constant>, in which case
560 * the point is destroyed.
562 * Since: 1.0
564 void
565 adg_dim_set_ref2(AdgDim *dim, const AdgPoint *ref2)
567 g_return_if_fail(ADG_IS_DIM(dim));
568 g_object_set(dim, "ref2", ref2, NULL);
572 * adg_dim_set_ref2_explicit:
573 * @dim: an #AdgDim
574 * @x: x coordinate of the second reference point
575 * @y: y coordinate of the second reference point
577 * Sets the #AdgDim:ref2 property to the (@x, @y) explicit
578 * coordinates. The old point is silently discarded,
579 * unreferencing its model if that point was bound to a named
580 * pair (hence, possibly destroying the model if this was the
581 * last reference).
583 * Since: 1.0
585 void
586 adg_dim_set_ref2_explicit(AdgDim *dim, gdouble x, gdouble y)
588 AdgPoint *point = adg_point_new();
590 adg_point_set_pair_explicit(point, x, y);
591 adg_dim_set_ref2(dim, point);
593 adg_point_destroy(point);
597 * adg_dim_set_ref2_from_pair:
598 * @dim: an #AdgDim
599 * @ref2: the coordinates pair of the second reference point
601 * Convenient function to set the #AdgDim:ref2 property using a
602 * pair instead of explicit coordinates.
604 * Since: 1.0
606 void
607 adg_dim_set_ref2_from_pair(AdgDim *dim, const CpmlPair *ref2)
609 g_return_if_fail(ref2 != NULL);
611 adg_dim_set_ref2_explicit(dim, ref2->x, ref2->y);
615 * adg_dim_set_ref2_from_model:
616 * @dim: an #AdgDim
617 * @model: the source #AdgModel
618 * @ref2: a named pair in @model
620 * Binds #AdgDim:ref2 to the @ref2 named pair of @model. If @model
621 * is <constant>NULL</constant>, the point will be unset. In any
622 * case, the old point is silently discarded, unreferencing its
623 * model if that point was bound to a named pair (hence, possibly
624 * destroying the model if this was the last reference).
626 * The assignment is lazy so @ref2 could be not be present in @model.
627 * Anyway, at the first access to this point an error will be raised
628 * if the named pair is still missing.
630 * Since: 1.0
632 void
633 adg_dim_set_ref2_from_model(AdgDim *dim, AdgModel *model, const gchar *ref2)
635 AdgPoint *point = adg_point_new();
637 adg_point_set_pair_from_model(point, model, ref2);
638 adg_dim_set_ref2(dim, point);
640 adg_point_destroy(point);
644 * adg_dim_get_ref2:
645 * @dim: an #AdgDim
647 * Gets the #AdgDim:ref2 point of @dim.
649 * The returned point is internally owned and must not be freed
650 * or modified. Anyway it is not const because a call to
651 * adg_point_update() with the returned value must be able to
652 * modify the internal cache.
654 * Returns: (transfer none): the second reference point.
656 * Since: 1.0
658 AdgPoint *
659 adg_dim_get_ref2(AdgDim *dim)
661 AdgDimPrivate *data;
663 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
665 data = dim->data;
667 return data->ref2;
671 * adg_dim_set_pos:
672 * @dim: an #AdgDim
673 * @pos: the new point to use as position
675 * Sets the #AdgDim:pos property of @dim to @pos. The old point
676 * is silently discarded, unreferencing its model if that
677 * point was bound to a named pair (hence, possibly destroying
678 * the model if it was the last reference).
680 * @pos can be <constant>NULL</constant>, in which case the
681 * point is destroyed.
683 * Since: 1.0
685 void
686 adg_dim_set_pos(AdgDim *dim, const AdgPoint *pos)
688 g_return_if_fail(ADG_IS_DIM(dim));
689 g_object_set(dim, "pos", pos, NULL);
693 * adg_dim_set_pos_explicit:
694 * @dim: an #AdgDim
695 * @x: x coordinate of the position
696 * @y: y coordinate of the position
698 * Sets the #AdgDim:pos property to the (@x, @y) explicit
699 * coordinates. The old point is silently discarded,
700 * unreferencing its model if that point was bound to a named
701 * pair (hence, possibly destroying the model if this was the
702 * last reference).
704 * Since: 1.0
706 void
707 adg_dim_set_pos_explicit(AdgDim *dim, gdouble x, gdouble y)
709 AdgPoint *point = adg_point_new();
711 adg_point_set_pair_explicit(point, x, y);
712 adg_dim_set_pos(dim, point);
714 adg_point_destroy(point);
718 * adg_dim_set_pos_from_pair:
719 * @dim: an #AdgDim
720 * @pos: the coordinates pair of the position point
722 * Convenient function to set the #AdgDim:pos property using a
723 * pair instead of explicit coordinates.
725 * Since: 1.0
727 void
728 adg_dim_set_pos_from_pair(AdgDim *dim, const CpmlPair *pos)
730 g_return_if_fail(pos != NULL);
732 adg_dim_set_pos_explicit(dim, pos->x, pos->y);
736 * adg_dim_set_pos_from_model:
737 * @dim: an #AdgDim
738 * @model: the source #AdgModel
739 * @pos: a named pair in @model
741 * Binds #AdgDim:pos to the @pos named pair of @model. If @model
742 * is <constant>NULL</constant>, the point will be unset. In any
743 * case, the old point is silently discarded, unreferencing its
744 * model if that point was bound to a named pair (hence,
745 * possibly destroying the model if this was the last reference).
747 * The assignment is lazy so @pos could be not be present in @model.
748 * Anyway, at the first access to this point an error will be raised
749 * if the named pair is still missing.
751 * Since: 1.0
753 void
754 adg_dim_set_pos_from_model(AdgDim *dim, AdgModel *model, const gchar *pos)
756 AdgPoint *point = adg_point_new();
758 adg_point_set_pair_from_model(point, model, pos);
759 adg_dim_set_pos(dim, point);
761 adg_point_destroy(point);
765 * adg_dim_get_pos:
766 * @dim: an #AdgDim
768 * Gets the #AdgDim:pos point of @dim.
770 * The returned point is internally owned and must not be freed
771 * or modified. Anyway it is not const because a call to
772 * adg_point_update() with the returned value must be able to
773 * modify the internal cache.
775 * Returns: (transfer none): the position point.
777 * Since: 1.0
779 AdgPoint *
780 adg_dim_get_pos(AdgDim *dim)
782 AdgDimPrivate *data;
784 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
786 data = dim->data;
788 return data->pos;
792 * adg_dim_set_level:
793 * @dim: an #AdgDim
794 * @level: the new level
796 * Sets a new level for this dimension. The level is used to
797 * stack the quotes using a spacing value from dim_style
798 * (specified in global space).
800 * Since: 1.0
802 void
803 adg_dim_set_level(AdgDim *dim, gdouble level)
805 AdgDimPrivate *data;
807 g_return_if_fail(ADG_IS_DIM(dim));
809 data = dim->data;
810 data->level = level;
812 g_object_notify((GObject *) dim, "level");
816 * adg_dim_get_level:
817 * @dim: an #AdgDim
819 * Gets the level of this dimension.
821 * Returns: the level value.
823 * Since: 1.0
825 gdouble
826 adg_dim_get_level(AdgDim *dim)
828 AdgDimPrivate *data;
830 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
832 data = dim->data;
834 return data->level;
838 * adg_dim_set_outside:
839 * @dim: an #AdgDim
840 * @outside: the new outside state
842 * Sets a new state for the #AdgDim:outside flag: check the property
843 * documentation for further details.
845 * Since: 1.0
847 void
848 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
850 g_return_if_fail(ADG_IS_DIM(dim));
852 if (_adg_set_outside(dim, outside))
853 g_object_notify((GObject *) dim, "outside");
857 * adg_dim_get_outside:
858 * @dim: an #AdgDim
860 * Gets the state of the #AdgDim:outside property: check the property
861 * documentation for further details.
863 * Returns: the current flag state.
865 * Since: 1.0
867 AdgThreeState
868 adg_dim_get_outside(AdgDim *dim)
870 AdgDimPrivate *data;
872 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
874 data = dim->data;
876 return data->outside;
880 * adg_dim_set_detached:
881 * @dim: an #AdgDim
882 * @detached: the new detached state
884 * Sets a new state for the #AdgDim:detached flag: check the property
885 * documentation for further details.
887 * This is used only by dimensions where detaching has meaning.
888 * In some cases, such as with #AdgRDim dimensions, this property is
889 * not used.
891 * Since: 1.0
893 void
894 adg_dim_set_detached(AdgDim *dim, AdgThreeState detached)
896 g_return_if_fail(ADG_IS_DIM(dim));
898 if (_adg_set_detached(dim, detached))
899 g_object_notify((GObject *) dim, "detached");
903 * adg_dim_get_detached:
904 * @dim: an #AdgDim
906 * Gets the state of the #AdgDim:detached property: check the property
907 * documentation for further details.
909 * Returns: the current flag state.
911 * Since: 1.0
913 AdgThreeState
914 adg_dim_get_detached(AdgDim *dim)
916 AdgDimPrivate *data;
918 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
920 data = dim->data;
922 return data->detached;
926 * adg_dim_set_value:
927 * @dim: an #AdgDim
928 * @value: (allow-none): the value text
930 * Explicitely sets the text to use as value. If @value
931 * is <constant>NULL</constant> or was never set, an automatic
932 * text is calculated using the format specified in the current
933 * #AdgDimStyle and getting its value by calling
934 * the <function>default_value</function> virtual method.
936 * Inside the template string, the "<>" tag (or whatever specified
937 * by the #AdgDimStyle:number-tag property) is substituted with the
938 * string returned by <function>default_value</function>.
940 * Since: 1.0
942 void
943 adg_dim_set_value(AdgDim *dim, const gchar *value)
945 g_return_if_fail(ADG_IS_DIM(dim));
947 if (_adg_set_value(dim, value))
948 g_object_notify((GObject *) dim, "value");
952 * adg_dim_get_value:
953 * @dim: an #AdgDim
955 * Gets the value text. The string is internally owned and
956 * must not be freed or modified.
958 * Returns: (transfer none): the value text.
960 * Since: 1.0
962 const gchar *
963 adg_dim_get_value(AdgDim *dim)
965 AdgDimPrivate *data;
967 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
969 data = dim->data;
971 return data->value;
975 * adg_dim_set_limits:
976 * @dim: an #AdgDim
977 * @min: (allow-none): the new minumum value
978 * @max: (allow-none): the new maximum value
980 * Shortcut to set both the limits at once.
982 * Since: 1.0
984 void
985 adg_dim_set_limits(AdgDim *dim, const gchar *min, const gchar *max)
987 g_return_if_fail(ADG_IS_DIM(dim));
989 g_object_freeze_notify((GObject *) dim);
990 adg_dim_set_min(dim, min);
991 adg_dim_set_max(dim, max);
992 g_object_thaw_notify((GObject *) dim);
996 * adg_dim_set_min:
997 * @dim: an #AdgDim
998 * @min: (allow-none): the new minimum limit
1000 * Sets the minimum value. Use <constant>NULL</constant>
1001 * as @min to disable it.
1003 * Since: 1.0
1005 void
1006 adg_dim_set_min(AdgDim *dim, const gchar *min)
1008 g_return_if_fail(ADG_IS_DIM(dim));
1010 if (_adg_set_min(dim, min))
1011 g_object_notify((GObject *) dim, "min");
1015 * adg_dim_get_min:
1016 * @dim: an #AdgDim
1018 * Gets the minimum value text or <constant>NULL</constant>
1019 * on minimum value disabled.
1021 * The string is internally owned and must not be freed or modified.
1023 * Returns: (transfer none): the mimimum value text.
1025 * Since: 1.0
1027 const gchar *
1028 adg_dim_get_min(AdgDim *dim)
1030 AdgDimPrivate *data;
1032 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
1034 data = dim->data;
1036 return data->min;
1040 * adg_dim_set_max:
1041 * @dim: an #AdgDim
1042 * @max: (allow-none): the new maximum value
1044 * Sets the maximum value. Use <constant>NULL</constant>
1045 * as @max to disable it.
1047 * Since: 1.0
1049 void
1050 adg_dim_set_max(AdgDim *dim, const gchar *max)
1052 g_return_if_fail(ADG_IS_DIM(dim));
1054 if (_adg_set_max(dim, max))
1055 g_object_notify((GObject *) dim, "max");
1059 * adg_dim_get_max:
1060 * @dim: an #AdgDim
1062 * Gets the maximum value text or <constant>NULL</constant>
1063 * on maximum value disabled.
1065 * The string is internally owned and must not be freed or modified.
1067 * Returns: (transfer none): the maximum value text.
1069 * Since: 1.0
1071 const gchar *
1072 adg_dim_get_max(AdgDim *dim)
1074 AdgDimPrivate *data;
1076 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
1078 data = dim->data;
1080 return data->max;
1084 * adg_dim_get_quote:
1085 * @dim: an #AdgDim
1087 * Gets the quote entity, if any. This function is valid only after
1088 * the #AdgDim implementation of the arrange() virtual method has
1089 * been called.
1091 * The returned entity is owned by @dim and should not be
1092 * modified or freed.
1094 * <note><para>
1095 * This function is only useful in new dimension implementations.
1096 * </para></note>
1098 * Returns: (transfer none): the quote entity.
1100 * Since: 1.0
1102 AdgAlignment *
1103 adg_dim_get_quote(AdgDim *dim)
1105 AdgDimPrivate *data;
1107 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
1109 data = dim->data;
1111 return data->quote.entity;
1115 * adg_dim_quote_angle:
1116 * @dim: an #AdgDim
1117 * @angle: an angle (in radians)
1119 * <note><para>
1120 * This function is only useful in new dimension implementations.
1121 * </para></note>
1123 * Converts @angle accordling to the style of @dim. Any quote angle
1124 * should be validated by this method because every dimensioning
1125 * style has its own convention regardling the text rotation.
1127 * Returns: the angle to use (always in radians).
1129 * Since: 1.0
1131 gdouble
1132 adg_dim_quote_angle(AdgDim *dim, gdouble angle)
1134 AdgDimClass *klass;
1136 g_return_val_if_fail(ADG_IS_DIM(dim), angle);
1138 klass = ADG_DIM_GET_CLASS(dim);
1140 if (klass->quote_angle == NULL)
1141 return angle;
1143 return klass->quote_angle(angle);
1147 static void
1148 _adg_global_changed(AdgEntity *entity)
1150 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1152 if (_ADG_OLD_ENTITY_CLASS->global_changed)
1153 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
1155 if (data->quote.entity)
1156 adg_entity_global_changed((AdgEntity *) data->quote.entity);
1159 static void
1160 _adg_local_changed(AdgEntity *entity)
1162 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1164 if (_ADG_OLD_ENTITY_CLASS->local_changed)
1165 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
1167 if (data->quote.entity)
1168 adg_entity_local_changed((AdgEntity *) data->quote.entity);
1171 static void
1172 _adg_invalidate(AdgEntity *entity)
1174 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1176 if (data->quote.value) {
1177 g_object_unref(data->quote.value);
1178 data->quote.value = NULL;
1180 if (data->quote.entity)
1181 adg_entity_invalidate((AdgEntity *) data->quote.entity);
1182 if (data->ref1)
1183 adg_point_invalidate(data->ref1);
1184 if (data->ref2)
1185 adg_point_invalidate(data->ref2);
1186 if (data->pos)
1187 adg_point_invalidate(data->pos);
1189 if (_ADG_OLD_ENTITY_CLASS->invalidate)
1190 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
1193 static void
1194 _adg_arrange(AdgEntity *entity)
1196 AdgDim *dim;
1197 AdgDimPrivate *data;
1198 AdgEntity *quote_entity;
1199 AdgContainer *quote_container;
1200 AdgEntity *value_entity;
1201 AdgEntity *min_entity;
1202 AdgEntity *max_entity;
1203 const CpmlPair *shift;
1204 cairo_matrix_t map;
1206 dim = (AdgDim *) entity;
1207 data = dim->data;
1209 /* Resolve the dim style */
1210 if (data->dim_style == NULL)
1211 data->dim_style = (AdgDimStyle *)
1212 adg_entity_style(entity, data->dim_dress);
1214 if (data->quote.entity == NULL)
1215 data->quote.entity = g_object_new(ADG_TYPE_ALIGNMENT,
1216 "local-mix", ADG_MIX_NONE,
1217 "parent", dim, NULL);
1219 quote_entity = (AdgEntity *) data->quote.entity;
1220 quote_container = (AdgContainer *) data->quote.entity;
1222 if (data->quote.value == NULL) {
1223 AdgDimClass *klass;
1224 AdgDress dress;
1225 const gchar *tag;
1226 gchar *value;
1227 gchar *text;
1229 klass = ADG_DIM_GET_CLASS(dim);
1230 dress = adg_dim_style_get_value_dress(data->dim_style);
1231 tag = adg_dim_style_get_number_tag(data->dim_style);
1232 value = klass->default_value ? klass->default_value(dim) : NULL;
1234 data->quote.value = g_object_new(ADG_TYPE_BEST_TEXT,
1235 "local-mix", ADG_MIX_PARENT,
1236 "font-dress", dress, NULL);
1237 adg_container_add(quote_container, (AdgEntity *) data->quote.value);
1239 if (data->value)
1240 text = adg_string_replace(data->value, tag, value);
1241 else
1242 text = g_strdup(value);
1244 g_free(value);
1246 adg_textual_set_text(data->quote.value, text);
1247 g_free(text);
1250 if (data->quote.min == NULL && data->min != NULL) {
1251 AdgDress dress = adg_dim_style_get_min_dress(data->dim_style);
1253 data->quote.min = g_object_new(ADG_TYPE_BEST_TEXT,
1254 "local-mix", ADG_MIX_PARENT,
1255 "font-dress", dress, NULL);
1257 adg_container_add(quote_container, (AdgEntity *) data->quote.min);
1258 adg_textual_set_text(data->quote.min, data->min);
1261 if (data->quote.max == NULL && data->max != NULL) {
1262 AdgDress dress = adg_dim_style_get_max_dress(data->dim_style);
1264 data->quote.max = g_object_new(ADG_TYPE_BEST_TEXT,
1265 "local-mix", ADG_MIX_PARENT,
1266 "font-dress", dress, NULL);
1268 adg_container_add(quote_container, (AdgEntity *) data->quote.max);
1269 adg_textual_set_text(data->quote.max, data->max);
1272 value_entity = (AdgEntity *) data->quote.value;
1273 min_entity = (AdgEntity *) data->quote.min;
1274 max_entity = (AdgEntity *) data->quote.max;
1275 shift = adg_dim_style_get_quote_shift(data->dim_style);
1277 adg_entity_set_global_map(quote_entity, adg_matrix_identity());
1278 adg_entity_global_changed(quote_entity);
1280 cairo_matrix_init_translate(&map, 0, shift->y);
1281 adg_entity_set_global_map(value_entity, &map);
1282 adg_entity_arrange(value_entity);
1284 /* Limit values (min and max) */
1285 if (min_entity != NULL || max_entity != NULL) {
1286 const CpmlPair *limits_shift;
1287 gdouble spacing;
1288 CpmlPair size;
1289 CpmlPair org_min, org_max;
1291 limits_shift = adg_dim_style_get_limits_shift(data->dim_style);
1292 spacing = adg_dim_style_get_limits_spacing(data->dim_style);
1293 size = adg_entity_get_extents(value_entity)->size;
1294 org_min.x = size.x + limits_shift->x;
1295 org_min.y = -size.y / 2 + limits_shift->y;
1296 org_max = org_min;
1298 if (min_entity && max_entity) {
1299 /* Prearrange the min entity to get its extents */
1300 adg_entity_arrange(min_entity);
1301 size = adg_entity_get_extents(min_entity)->size;
1303 org_min.y += spacing / 2;
1304 org_max.y = org_min.y - size.y - spacing / 2;
1307 if (min_entity != NULL) {
1308 cairo_matrix_init_translate(&map, org_min.x, org_min.y);
1309 adg_entity_set_global_map(min_entity, &map);
1310 adg_entity_arrange(min_entity);
1313 if (max_entity != NULL) {
1314 cairo_matrix_init_translate(&map, org_max.x, org_max.y);
1315 adg_entity_set_global_map(max_entity, &map);
1316 adg_entity_arrange(max_entity);
1321 static gchar *
1322 _adg_default_value(AdgDim *dim)
1324 g_warning(_("AdgDim::default_value not implemented for `%s'"),
1325 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
1326 return g_strdup("undef");
1329 static gdouble
1330 _adg_quote_angle(gdouble angle)
1332 angle = cpml_angle(angle);
1334 if (angle > G_PI_4 * 4 / 3 || angle <= -G_PI_4 * 3)
1335 angle = cpml_angle(angle + G_PI);
1337 return angle;
1340 static gboolean
1341 _adg_set_outside(AdgDim *dim, AdgThreeState outside)
1343 AdgDimPrivate *data;
1345 g_return_val_if_fail(adg_is_enum_value(outside, ADG_TYPE_THREE_STATE),
1346 FALSE);
1348 data = dim->data;
1350 if (data->outside == outside)
1351 return FALSE;
1353 data->outside = outside;
1355 return TRUE;
1358 static gboolean
1359 _adg_set_detached(AdgDim *dim, AdgThreeState detached)
1361 AdgDimPrivate *data;
1363 g_return_val_if_fail(adg_is_enum_value(detached, ADG_TYPE_THREE_STATE),
1364 FALSE);
1366 data = dim->data;
1368 if (data->detached == detached)
1369 return FALSE;
1371 data->detached = detached;
1373 return TRUE;
1376 static gboolean
1377 _adg_set_value(AdgDim *dim, const gchar *value)
1379 AdgDimPrivate *data;
1381 data = dim->data;
1383 if (g_strcmp0(value, data->value) == 0)
1384 return FALSE;
1386 g_free(data->value);
1387 data->value = g_strdup(value);
1389 if (data->quote.value) {
1390 g_object_unref(data->quote.value);
1391 data->quote.value = NULL;
1394 return TRUE;
1397 static gboolean
1398 _adg_set_min(AdgDim *dim, const gchar *min)
1400 AdgDimPrivate *data = dim->data;
1402 if (g_strcmp0(min, data->min) == 0)
1403 return FALSE;
1405 g_free(data->min);
1406 data->min = g_strdup(min);
1408 if (data->quote.min) {
1409 g_object_unref(data->quote.min);
1410 data->quote.min = NULL;
1413 return TRUE;
1416 static gboolean
1417 _adg_set_max(AdgDim *dim, const gchar *max)
1419 AdgDimPrivate *data = dim->data;
1421 if (g_strcmp0(max, data->max) == 0)
1422 return FALSE;
1424 g_free(data->max);
1425 data->max = g_strdup(max);
1427 if (data->quote.max) {
1428 g_object_unref(data->quote.max);
1429 data->quote.max = NULL;
1432 return TRUE;