build: depends on cairo-gobject if introspection is enabled
[adg.git] / src / adg / adg-dim.c
blobb28c2e1acfacdaef48ca02d95a3f0bb3a5258d72
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 * |[
51 * if 1/3 PI <= angle <= -3/4 PI; then angle += PI.
52 * ]|
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 %NULL, in which case the point is destroyed.
440 * Since: 1.0
442 void
443 adg_dim_set_ref1(AdgDim *dim, const AdgPoint *ref1)
445 g_return_if_fail(ADG_IS_DIM(dim));
446 g_object_set(dim, "ref1", ref1, NULL);
450 * adg_dim_set_ref1_explicit:
451 * @dim: an #AdgDim
452 * @x: x coordinate of the first reference point
453 * @y: y coordinate of the first reference point
455 * Sets the #AdgDim:ref1 property to the (@x, @y) explicit
456 * coordinates. The old point is silently discarded,
457 * unreferencing its model if that point was bound to a named
458 * pair (hence, possibly destroying the model if this was the
459 * last reference).
461 * Since: 1.0
463 void
464 adg_dim_set_ref1_explicit(AdgDim *dim, gdouble x, gdouble y)
466 AdgPoint *point = adg_point_new();
468 adg_point_set_pair_explicit(point, x, y);
469 adg_dim_set_ref1(dim, point);
471 adg_point_destroy(point);
475 * adg_dim_set_ref1_from_pair:
476 * @dim: an #AdgDim
477 * @ref1: the coordinates pair of the first reference point
479 * Convenient function to set the #AdgDim:ref1 property using a
480 * pair instead of explicit coordinates.
482 * Since: 1.0
484 void
485 adg_dim_set_ref1_from_pair(AdgDim *dim, const CpmlPair *ref1)
487 g_return_if_fail(ref1 != NULL);
489 adg_dim_set_ref1_explicit(dim, ref1->x, ref1->y);
493 * adg_dim_set_ref1_from_model:
494 * @dim: an #AdgDim
495 * @model: the source #AdgModel
496 * @ref1: a named pair in @model
498 * Binds #AdgDim:ref1 to the @ref1 named pair of @model. If @model
499 * is %NULL, the point will be unset. In any case, the old point
500 * is silently discarded, unreferencing its model if that point
501 * was bound to a named pair (hence, possibly destroying the model
502 * if this was the last reference).
504 * The assignment is lazy so @ref1 could be not be present in @model.
505 * Anyway, at the first access to this point an error will be raised
506 * if the named pair is still missing.
508 * Since: 1.0
510 void
511 adg_dim_set_ref1_from_model(AdgDim *dim, AdgModel *model, const gchar *ref1)
513 AdgPoint *point = adg_point_new();
515 adg_point_set_pair_from_model(point, model, ref1);
516 adg_dim_set_ref1(dim, point);
518 adg_point_destroy(point);
522 * adg_dim_get_ref1:
523 * @dim: an #AdgDim
525 * Gets the #AdgDim:ref1 point of @dim.
527 * The returned point is internally owned and must not be freed
528 * or modified. Anyway it is not const because a call to
529 * adg_point_update() with the returned value must be able to
530 * modify the internal cache.
532 * Returns: (transfer none): the first reference point.
534 * Since: 1.0
536 AdgPoint *
537 adg_dim_get_ref1(AdgDim *dim)
539 AdgDimPrivate *data;
541 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
543 data = dim->data;
545 return data->ref1;
549 * adg_dim_set_ref2:
550 * @dim: an #AdgDim
551 * @ref2: the new point to use as second reference
553 * Sets the #AdgDim:ref2 property to @ref2. The old point
554 * is silently discarded, unreferencing its model if that
555 * point was bound to a named pair (hence, possibly destroying
556 * the model if it was the last reference).
558 * @ref2 can be %NULL, in which case the point is destroyed.
560 * Since: 1.0
562 void
563 adg_dim_set_ref2(AdgDim *dim, const AdgPoint *ref2)
565 g_return_if_fail(ADG_IS_DIM(dim));
566 g_object_set(dim, "ref2", ref2, NULL);
570 * adg_dim_set_ref2_explicit:
571 * @dim: an #AdgDim
572 * @x: x coordinate of the second reference point
573 * @y: y coordinate of the second reference point
575 * Sets the #AdgDim:ref2 property to the (@x, @y) explicit
576 * coordinates. The old point is silently discarded,
577 * unreferencing its model if that point was bound to a named
578 * pair (hence, possibly destroying the model if this was the
579 * last reference).
581 * Since: 1.0
583 void
584 adg_dim_set_ref2_explicit(AdgDim *dim, gdouble x, gdouble y)
586 AdgPoint *point = adg_point_new();
588 adg_point_set_pair_explicit(point, x, y);
589 adg_dim_set_ref2(dim, point);
591 adg_point_destroy(point);
595 * adg_dim_set_ref2_from_pair:
596 * @dim: an #AdgDim
597 * @ref2: the coordinates pair of the second reference point
599 * Convenient function to set the #AdgDim:ref2 property using a
600 * pair instead of explicit coordinates.
602 * Since: 1.0
604 void
605 adg_dim_set_ref2_from_pair(AdgDim *dim, const CpmlPair *ref2)
607 g_return_if_fail(ref2 != NULL);
609 adg_dim_set_ref2_explicit(dim, ref2->x, ref2->y);
613 * adg_dim_set_ref2_from_model:
614 * @dim: an #AdgDim
615 * @model: the source #AdgModel
616 * @ref2: a named pair in @model
618 * Binds #AdgDim:ref2 to the @ref2 named pair of @model. If @model
619 * is %NULL, the point will be unset. In any case, the old point
620 * is silently discarded, unreferencing its model if that point
621 * was bound to a named pair (hence, possibly destroying the model
622 * if this was the last reference).
624 * The assignment is lazy so @ref2 could be not be present in @model.
625 * Anyway, at the first access to this point an error will be raised
626 * if the named pair is still missing.
628 * Since: 1.0
630 void
631 adg_dim_set_ref2_from_model(AdgDim *dim, AdgModel *model, const gchar *ref2)
633 AdgPoint *point = adg_point_new();
635 adg_point_set_pair_from_model(point, model, ref2);
636 adg_dim_set_ref2(dim, point);
638 adg_point_destroy(point);
642 * adg_dim_get_ref2:
643 * @dim: an #AdgDim
645 * Gets the #AdgDim:ref2 point of @dim.
647 * The returned point is internally owned and must not be freed
648 * or modified. Anyway it is not const because a call to
649 * adg_point_update() with the returned value must be able to
650 * modify the internal cache.
652 * Returns: (transfer none): the second reference point.
654 * Since: 1.0
656 AdgPoint *
657 adg_dim_get_ref2(AdgDim *dim)
659 AdgDimPrivate *data;
661 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
663 data = dim->data;
665 return data->ref2;
669 * adg_dim_set_pos:
670 * @dim: an #AdgDim
671 * @pos: the new point to use as position
673 * Sets the #AdgDim:pos property of @dim to @pos. The old point
674 * is silently discarded, unreferencing its model if that
675 * point was bound to a named pair (hence, possibly destroying
676 * the model if it was the last reference).
678 * @pos can be %NULL, in which case the point is destroyed.
680 * Since: 1.0
682 void
683 adg_dim_set_pos(AdgDim *dim, const AdgPoint *pos)
685 g_return_if_fail(ADG_IS_DIM(dim));
686 g_object_set(dim, "pos", pos, NULL);
690 * adg_dim_set_pos_explicit:
691 * @dim: an #AdgDim
692 * @x: x coordinate of the position
693 * @y: y coordinate of the position
695 * Sets the #AdgDim:pos property to the (@x, @y) explicit
696 * coordinates. The old point is silently discarded,
697 * unreferencing its model if that point was bound to a named
698 * pair (hence, possibly destroying the model if this was the
699 * last reference).
701 * Since: 1.0
703 void
704 adg_dim_set_pos_explicit(AdgDim *dim, gdouble x, gdouble y)
706 AdgPoint *point = adg_point_new();
708 adg_point_set_pair_explicit(point, x, y);
709 adg_dim_set_pos(dim, point);
711 adg_point_destroy(point);
715 * adg_dim_set_pos_from_pair:
716 * @dim: an #AdgDim
717 * @pos: the coordinates pair of the position point
719 * Convenient function to set the #AdgDim:pos property using a
720 * pair instead of explicit coordinates.
722 * Since: 1.0
724 void
725 adg_dim_set_pos_from_pair(AdgDim *dim, const CpmlPair *pos)
727 g_return_if_fail(pos != NULL);
729 adg_dim_set_pos_explicit(dim, pos->x, pos->y);
733 * adg_dim_set_pos_from_model:
734 * @dim: an #AdgDim
735 * @model: the source #AdgModel
736 * @pos: a named pair in @model
738 * Binds #AdgDim:pos to the @pos named pair of @model. If @model
739 * is %NULL, the point will be unset. In any case, the old point
740 * is silently discarded, unreferencing its model if that point
741 * was bound to a named pair (hence, possibly destroying the model
742 * if this was the last reference).
744 * The assignment is lazy so @pos could be not be present in @model.
745 * Anyway, at the first access to this point an error will be raised
746 * if the named pair is still missing.
748 * Since: 1.0
750 void
751 adg_dim_set_pos_from_model(AdgDim *dim, AdgModel *model, const gchar *pos)
753 AdgPoint *point = adg_point_new();
755 adg_point_set_pair_from_model(point, model, pos);
756 adg_dim_set_pos(dim, point);
758 adg_point_destroy(point);
762 * adg_dim_get_pos:
763 * @dim: an #AdgDim
765 * Gets the #AdgDim:pos point of @dim.
767 * The returned point is internally owned and must not be freed
768 * or modified. Anyway it is not const because a call to
769 * adg_point_update() with the returned value must be able to
770 * modify the internal cache.
772 * Returns: (transfer none): the position point.
774 * Since: 1.0
776 AdgPoint *
777 adg_dim_get_pos(AdgDim *dim)
779 AdgDimPrivate *data;
781 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
783 data = dim->data;
785 return data->pos;
789 * adg_dim_set_level:
790 * @dim: an #AdgDim
791 * @level: the new level
793 * Sets a new level for this dimension. The level is used to
794 * stack the quotes using a spacing value from dim_style
795 * (specified in global space).
797 * Since: 1.0
799 void
800 adg_dim_set_level(AdgDim *dim, gdouble level)
802 AdgDimPrivate *data;
804 g_return_if_fail(ADG_IS_DIM(dim));
806 data = dim->data;
807 data->level = level;
809 g_object_notify((GObject *) dim, "level");
813 * adg_dim_get_level:
814 * @dim: an #AdgDim
816 * Gets the level of this dimension.
818 * Returns: the level value.
820 * Since: 1.0
822 gdouble
823 adg_dim_get_level(AdgDim *dim)
825 AdgDimPrivate *data;
827 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
829 data = dim->data;
831 return data->level;
835 * adg_dim_set_outside:
836 * @dim: an #AdgDim
837 * @outside: the new outside state
839 * Sets a new state for the #AdgDim:outside flag: check the property
840 * documentation for further details.
842 * Since: 1.0
844 void
845 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
847 g_return_if_fail(ADG_IS_DIM(dim));
849 if (_adg_set_outside(dim, outside))
850 g_object_notify((GObject *) dim, "outside");
854 * adg_dim_get_outside:
855 * @dim: an #AdgDim
857 * Gets the state of the #AdgDim:outside property: check the property
858 * documentation for further details.
860 * Returns: the current flag state.
862 * Since: 1.0
864 AdgThreeState
865 adg_dim_get_outside(AdgDim *dim)
867 AdgDimPrivate *data;
869 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
871 data = dim->data;
873 return data->outside;
877 * adg_dim_set_detached:
878 * @dim: an #AdgDim
879 * @detached: the new detached state
881 * Sets a new state for the #AdgDim:detached flag: check the property
882 * documentation for further details.
884 * This is used only by dimensions where detaching has meaning.
885 * In some cases, such as with #AdgRDim dimensions, this property is
886 * not used.
888 * Since: 1.0
890 void
891 adg_dim_set_detached(AdgDim *dim, AdgThreeState detached)
893 g_return_if_fail(ADG_IS_DIM(dim));
895 if (_adg_set_detached(dim, detached))
896 g_object_notify((GObject *) dim, "detached");
900 * adg_dim_get_detached:
901 * @dim: an #AdgDim
903 * Gets the state of the #AdgDim:detached property: check the property
904 * documentation for further details.
906 * Returns: the current flag state.
908 * Since: 1.0
910 AdgThreeState
911 adg_dim_get_detached(AdgDim *dim)
913 AdgDimPrivate *data;
915 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
917 data = dim->data;
919 return data->detached;
923 * adg_dim_set_value:
924 * @dim: an #AdgDim
925 * @value: (allow-none): the value text
927 * Explicitely sets the text to use as value. If @value is %NULL or
928 * was never set, an automatic text is calculated using the format
929 * specified in the current #AdgDimStyle and getting its value by
930 * calling the default_value() virtual method.
932 * Inside the template string, the "<>" tag (or whatever specified
933 * by the #AdgDimStyle:number-tag property) is substituted with the
934 * string returned by the default_value() virtual method.
936 * Since: 1.0
938 void
939 adg_dim_set_value(AdgDim *dim, const gchar *value)
941 g_return_if_fail(ADG_IS_DIM(dim));
943 if (_adg_set_value(dim, value))
944 g_object_notify((GObject *) dim, "value");
948 * adg_dim_get_value:
949 * @dim: an #AdgDim
951 * Gets the value text. The string is internally owned and
952 * must not be freed or modified.
954 * Returns: (transfer none): the value text.
956 * Since: 1.0
958 const gchar *
959 adg_dim_get_value(AdgDim *dim)
961 AdgDimPrivate *data;
963 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
965 data = dim->data;
967 return data->value;
971 * adg_dim_set_limits:
972 * @dim: an #AdgDim
973 * @min: (allow-none): the new minumum value
974 * @max: (allow-none): the new maximum value
976 * Shortcut to set both the limits at once.
978 * Since: 1.0
980 void
981 adg_dim_set_limits(AdgDim *dim, const gchar *min, const gchar *max)
983 g_return_if_fail(ADG_IS_DIM(dim));
985 g_object_freeze_notify((GObject *) dim);
986 adg_dim_set_min(dim, min);
987 adg_dim_set_max(dim, max);
988 g_object_thaw_notify((GObject *) dim);
992 * adg_dim_set_min:
993 * @dim: an #AdgDim
994 * @min: (allow-none): the new minimum limit
996 * Sets the minimum value. Use %NULL as @min to disable it.
998 * Since: 1.0
1000 void
1001 adg_dim_set_min(AdgDim *dim, const gchar *min)
1003 g_return_if_fail(ADG_IS_DIM(dim));
1005 if (_adg_set_min(dim, min))
1006 g_object_notify((GObject *) dim, "min");
1010 * adg_dim_get_min:
1011 * @dim: an #AdgDim
1013 * Gets the minimum value text or %NULL on minimum value disabled.
1015 * The string is internally owned and must not be freed or modified.
1017 * Returns: (transfer none): the mimimum value text.
1019 * Since: 1.0
1021 const gchar *
1022 adg_dim_get_min(AdgDim *dim)
1024 AdgDimPrivate *data;
1026 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
1028 data = dim->data;
1030 return data->min;
1034 * adg_dim_set_max:
1035 * @dim: an #AdgDim
1036 * @max: (allow-none): the new maximum value
1038 * Sets the maximum value. Use %NULL as @max to disable it.
1040 * Since: 1.0
1042 void
1043 adg_dim_set_max(AdgDim *dim, const gchar *max)
1045 g_return_if_fail(ADG_IS_DIM(dim));
1047 if (_adg_set_max(dim, max))
1048 g_object_notify((GObject *) dim, "max");
1052 * adg_dim_get_max:
1053 * @dim: an #AdgDim
1055 * Gets the maximum value text or %NULL on maximum value disabled.
1057 * The string is internally owned and must not be freed or modified.
1059 * Returns: (transfer none): the maximum value text.
1061 * Since: 1.0
1063 const gchar *
1064 adg_dim_get_max(AdgDim *dim)
1066 AdgDimPrivate *data;
1068 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
1070 data = dim->data;
1072 return data->max;
1076 * adg_dim_get_quote:
1077 * @dim: an #AdgDim
1079 * Gets the quote entity, if any. This function is valid only after
1080 * the #AdgDim implementation of the arrange() virtual method has
1081 * been called.
1083 * The returned entity is owned by @dim and should not be
1084 * modified or freed.
1086 * <note><para>
1087 * This function is only useful in new dimension implementations.
1088 * </para></note>
1090 * Returns: (transfer none): the quote entity.
1092 * Since: 1.0
1094 AdgAlignment *
1095 adg_dim_get_quote(AdgDim *dim)
1097 AdgDimPrivate *data;
1099 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
1101 data = dim->data;
1103 return data->quote.entity;
1107 * adg_dim_quote_angle:
1108 * @dim: an #AdgDim
1109 * @angle: an angle (in radians)
1111 * <note><para>
1112 * This function is only useful in new dimension implementations.
1113 * </para></note>
1115 * Converts @angle accordling to the style of @dim. Any quote angle
1116 * should be validated by this method because every dimensioning
1117 * style has its own convention regardling the text rotation.
1119 * Returns: the angle to use (always in radians).
1121 * Since: 1.0
1123 gdouble
1124 adg_dim_quote_angle(AdgDim *dim, gdouble angle)
1126 AdgDimClass *klass;
1128 g_return_val_if_fail(ADG_IS_DIM(dim), angle);
1130 klass = ADG_DIM_GET_CLASS(dim);
1132 if (klass->quote_angle == NULL)
1133 return angle;
1135 return klass->quote_angle(angle);
1139 static void
1140 _adg_global_changed(AdgEntity *entity)
1142 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1144 if (_ADG_OLD_ENTITY_CLASS->global_changed)
1145 _ADG_OLD_ENTITY_CLASS->global_changed(entity);
1147 if (data->quote.entity)
1148 adg_entity_global_changed((AdgEntity *) data->quote.entity);
1151 static void
1152 _adg_local_changed(AdgEntity *entity)
1154 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1156 if (_ADG_OLD_ENTITY_CLASS->local_changed)
1157 _ADG_OLD_ENTITY_CLASS->local_changed(entity);
1159 if (data->quote.entity)
1160 adg_entity_local_changed((AdgEntity *) data->quote.entity);
1163 static void
1164 _adg_invalidate(AdgEntity *entity)
1166 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1168 if (data->quote.value) {
1169 g_object_unref(data->quote.value);
1170 data->quote.value = NULL;
1172 if (data->quote.entity)
1173 adg_entity_invalidate((AdgEntity *) data->quote.entity);
1174 if (data->ref1)
1175 adg_point_invalidate(data->ref1);
1176 if (data->ref2)
1177 adg_point_invalidate(data->ref2);
1178 if (data->pos)
1179 adg_point_invalidate(data->pos);
1181 if (_ADG_OLD_ENTITY_CLASS->invalidate)
1182 _ADG_OLD_ENTITY_CLASS->invalidate(entity);
1185 static void
1186 _adg_arrange(AdgEntity *entity)
1188 AdgDim *dim;
1189 AdgDimPrivate *data;
1190 AdgEntity *quote_entity;
1191 AdgContainer *quote_container;
1192 AdgEntity *value_entity;
1193 AdgEntity *min_entity;
1194 AdgEntity *max_entity;
1195 const CpmlPair *shift;
1196 cairo_matrix_t map;
1198 dim = (AdgDim *) entity;
1199 data = dim->data;
1201 /* Resolve the dim style */
1202 if (data->dim_style == NULL)
1203 data->dim_style = (AdgDimStyle *)
1204 adg_entity_style(entity, data->dim_dress);
1206 if (data->quote.entity == NULL)
1207 data->quote.entity = g_object_new(ADG_TYPE_ALIGNMENT,
1208 "local-mix", ADG_MIX_NONE,
1209 "parent", dim, NULL);
1211 quote_entity = (AdgEntity *) data->quote.entity;
1212 quote_container = (AdgContainer *) data->quote.entity;
1214 if (data->quote.value == NULL) {
1215 AdgDimClass *klass;
1216 AdgDress dress;
1217 const gchar *tag;
1218 gchar *value;
1219 gchar *text;
1221 klass = ADG_DIM_GET_CLASS(dim);
1222 dress = adg_dim_style_get_value_dress(data->dim_style);
1223 tag = adg_dim_style_get_number_tag(data->dim_style);
1224 value = klass->default_value ? klass->default_value(dim) : NULL;
1226 data->quote.value = g_object_new(ADG_TYPE_BEST_TEXT,
1227 "local-mix", ADG_MIX_PARENT,
1228 "font-dress", dress, NULL);
1229 adg_container_add(quote_container, (AdgEntity *) data->quote.value);
1231 if (data->value)
1232 text = adg_string_replace(data->value, tag, value);
1233 else
1234 text = g_strdup(value);
1236 g_free(value);
1238 adg_textual_set_text(data->quote.value, text);
1239 g_free(text);
1242 if (data->quote.min == NULL && data->min != NULL) {
1243 AdgDress dress = adg_dim_style_get_min_dress(data->dim_style);
1245 data->quote.min = g_object_new(ADG_TYPE_BEST_TEXT,
1246 "local-mix", ADG_MIX_PARENT,
1247 "font-dress", dress, NULL);
1249 adg_container_add(quote_container, (AdgEntity *) data->quote.min);
1250 adg_textual_set_text(data->quote.min, data->min);
1253 if (data->quote.max == NULL && data->max != NULL) {
1254 AdgDress dress = adg_dim_style_get_max_dress(data->dim_style);
1256 data->quote.max = g_object_new(ADG_TYPE_BEST_TEXT,
1257 "local-mix", ADG_MIX_PARENT,
1258 "font-dress", dress, NULL);
1260 adg_container_add(quote_container, (AdgEntity *) data->quote.max);
1261 adg_textual_set_text(data->quote.max, data->max);
1264 value_entity = (AdgEntity *) data->quote.value;
1265 min_entity = (AdgEntity *) data->quote.min;
1266 max_entity = (AdgEntity *) data->quote.max;
1267 shift = adg_dim_style_get_quote_shift(data->dim_style);
1269 adg_entity_set_global_map(quote_entity, adg_matrix_identity());
1270 adg_entity_global_changed(quote_entity);
1272 cairo_matrix_init_translate(&map, 0, shift->y);
1273 adg_entity_set_global_map(value_entity, &map);
1274 adg_entity_arrange(value_entity);
1276 /* Limit values (min and max) */
1277 if (min_entity != NULL || max_entity != NULL) {
1278 const CpmlPair *limits_shift;
1279 gdouble spacing;
1280 CpmlPair size;
1281 CpmlPair org_min, org_max;
1283 limits_shift = adg_dim_style_get_limits_shift(data->dim_style);
1284 spacing = adg_dim_style_get_limits_spacing(data->dim_style);
1285 size = adg_entity_get_extents(value_entity)->size;
1286 org_min.x = size.x + limits_shift->x;
1287 org_min.y = -size.y / 2 + limits_shift->y;
1288 org_max = org_min;
1290 if (min_entity && max_entity) {
1291 /* Prearrange the min entity to get its extents */
1292 adg_entity_arrange(min_entity);
1293 size = adg_entity_get_extents(min_entity)->size;
1295 org_min.y += spacing / 2;
1296 org_max.y = org_min.y - size.y - spacing / 2;
1299 if (min_entity != NULL) {
1300 cairo_matrix_init_translate(&map, org_min.x, org_min.y);
1301 adg_entity_set_global_map(min_entity, &map);
1302 adg_entity_arrange(min_entity);
1305 if (max_entity != NULL) {
1306 cairo_matrix_init_translate(&map, org_max.x, org_max.y);
1307 adg_entity_set_global_map(max_entity, &map);
1308 adg_entity_arrange(max_entity);
1313 static gchar *
1314 _adg_default_value(AdgDim *dim)
1316 g_warning(_("AdgDim::default_value not implemented for `%s'"),
1317 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
1318 return g_strdup("undef");
1321 static gdouble
1322 _adg_quote_angle(gdouble angle)
1324 angle = cpml_angle(angle);
1326 if (angle > G_PI_4 * 4 / 3 || angle <= -G_PI_4 * 3)
1327 angle = cpml_angle(angle + G_PI);
1329 return angle;
1332 static gboolean
1333 _adg_set_outside(AdgDim *dim, AdgThreeState outside)
1335 AdgDimPrivate *data;
1337 g_return_val_if_fail(adg_is_enum_value(outside, ADG_TYPE_THREE_STATE),
1338 FALSE);
1340 data = dim->data;
1342 if (data->outside == outside)
1343 return FALSE;
1345 data->outside = outside;
1347 return TRUE;
1350 static gboolean
1351 _adg_set_detached(AdgDim *dim, AdgThreeState detached)
1353 AdgDimPrivate *data;
1355 g_return_val_if_fail(adg_is_enum_value(detached, ADG_TYPE_THREE_STATE),
1356 FALSE);
1358 data = dim->data;
1360 if (data->detached == detached)
1361 return FALSE;
1363 data->detached = detached;
1365 return TRUE;
1368 static gboolean
1369 _adg_set_value(AdgDim *dim, const gchar *value)
1371 AdgDimPrivate *data;
1373 data = dim->data;
1375 if (g_strcmp0(value, data->value) == 0)
1376 return FALSE;
1378 g_free(data->value);
1379 data->value = g_strdup(value);
1381 if (data->quote.value) {
1382 g_object_unref(data->quote.value);
1383 data->quote.value = NULL;
1386 return TRUE;
1389 static gboolean
1390 _adg_set_min(AdgDim *dim, const gchar *min)
1392 AdgDimPrivate *data = dim->data;
1394 if (g_strcmp0(min, data->min) == 0)
1395 return FALSE;
1397 g_free(data->min);
1398 data->min = g_strdup(min);
1400 if (data->quote.min) {
1401 g_object_unref(data->quote.min);
1402 data->quote.min = NULL;
1405 return TRUE;
1408 static gboolean
1409 _adg_set_max(AdgDim *dim, const gchar *max)
1411 AdgDimPrivate *data = dim->data;
1413 if (g_strcmp0(max, data->max) == 0)
1414 return FALSE;
1416 g_free(data->max);
1417 data->max = g_strdup(max);
1419 if (data->quote.max) {
1420 g_object_unref(data->quote.max);
1421 data->quote.max = NULL;
1424 return TRUE;