[AdgDim] Invalidate also the quote value text
[adg.git] / src / adg / adg-dim.c
blob041b27f74e8b1e35bc65f1b7ccd9bbce1bf70616
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010 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-dim.h"
38 #include "adg-dim-private.h"
39 #include "adg-dim-style.h"
40 #include "adg-dress-builtins.h"
41 #include "adg-toy-text.h"
42 #include "adg-type-builtins.h"
44 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_dim_parent_class)
45 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_dim_parent_class)
48 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY);
50 enum {
51 PROP_0,
52 PROP_DIM_DRESS,
53 PROP_REF1,
54 PROP_REF2,
55 PROP_POS,
56 PROP_LEVEL,
57 PROP_OUTSIDE,
58 PROP_DETACHED,
59 PROP_VALUE,
60 PROP_MIN,
61 PROP_MAX
65 static void _adg_dispose (GObject *object);
66 static void _adg_finalize (GObject *object);
67 static void _adg_get_property (GObject *object,
68 guint param_id,
69 GValue *value,
70 GParamSpec *pspec);
71 static void _adg_set_property (GObject *object,
72 guint param_id,
73 const GValue *value,
74 GParamSpec *pspec);
75 static void _adg_global_changed (AdgEntity *entity);
76 static void _adg_local_changed (AdgEntity *entity);
77 static void _adg_invalidate (AdgEntity *entity);
78 static void _adg_arrange (AdgEntity *entity);
79 static gchar * _adg_default_value (AdgDim *dim);
80 static gdouble _adg_quote_angle (gdouble angle);
81 static gboolean _adg_set_outside (AdgDim *dim,
82 AdgThreeState outside);
83 static gboolean _adg_set_detached (AdgDim *dim,
84 AdgThreeState detached);
85 static gboolean _adg_set_value (AdgDim *dim,
86 const gchar *value);
87 static gboolean _adg_set_min (AdgDim *dim,
88 const gchar *min);
89 static gboolean _adg_set_max (AdgDim *dim,
90 const gchar *max);
93 static void
94 adg_dim_class_init(AdgDimClass *klass)
96 GObjectClass *gobject_class;
97 AdgEntityClass *entity_class;
98 GParamSpec *param;
100 gobject_class = (GObjectClass *) klass;
101 entity_class = (AdgEntityClass *) klass;
103 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
105 gobject_class->dispose = _adg_dispose;
106 gobject_class->finalize = _adg_finalize;
107 gobject_class->get_property = _adg_get_property;
108 gobject_class->set_property = _adg_set_property;
110 entity_class->global_changed = _adg_global_changed;
111 entity_class->local_changed = _adg_local_changed;
112 entity_class->invalidate = _adg_invalidate;
113 entity_class->arrange = _adg_arrange;
115 klass->quote_angle = _adg_quote_angle;
116 klass->default_value = _adg_default_value;
118 param = adg_param_spec_dress("dim-dress",
119 P_("Dimension Dress"),
120 P_("The dress to use for rendering this dimension"),
121 ADG_DRESS_DIMENSION,
122 G_PARAM_READWRITE);
123 g_object_class_install_property(gobject_class, PROP_DIM_DRESS, param);
125 param = g_param_spec_boxed("ref1",
126 P_("First Reference"),
127 P_("First reference point of the dimension"),
128 ADG_TYPE_POINT,
129 G_PARAM_READWRITE);
130 g_object_class_install_property(gobject_class, PROP_REF1, param);
132 param = g_param_spec_boxed("ref2",
133 P_("Second Reference"),
134 P_("Second reference point of the dimension"),
135 ADG_TYPE_POINT,
136 G_PARAM_READWRITE);
137 g_object_class_install_property(gobject_class, PROP_REF2, param);
139 param = g_param_spec_boxed("pos",
140 P_("Position"),
141 P_("The reference position of the quote: it will be combined with \"level\" to get the real quote position"),
142 ADG_TYPE_POINT,
143 G_PARAM_READWRITE);
144 g_object_class_install_property(gobject_class, PROP_POS, param);
146 param = g_param_spec_double("level",
147 P_("Level"),
148 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"),
149 -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
150 G_PARAM_READWRITE);
151 g_object_class_install_property(gobject_class, PROP_LEVEL, param);
153 param = g_param_spec_enum("outside",
154 P_("Outside"),
155 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"),
156 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
157 G_PARAM_READWRITE);
158 g_object_class_install_property(gobject_class, PROP_OUTSIDE, param);
160 param = g_param_spec_enum("detached",
161 P_("Detached Quote"),
162 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"),
163 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
164 G_PARAM_READWRITE);
165 g_object_class_install_property(gobject_class, PROP_DETACHED, param);
167 param = g_param_spec_string("value",
168 P_("Basic Value"),
169 P_("The theoretically exact value for this quote: set to NULL to automatically get the default value"),
170 NULL,
171 G_PARAM_READWRITE);
172 g_object_class_install_property(gobject_class, PROP_VALUE, param);
174 param = g_param_spec_string("min",
175 P_("Minimum Value or Low Tolerance"),
176 P_("The minimum value allowed or the lowest tolerance from value (depending of the dimension style): set to NULL to suppress"),
177 NULL,
178 G_PARAM_READWRITE);
179 g_object_class_install_property(gobject_class, PROP_MIN, param);
181 param = g_param_spec_string("max",
182 P_("Maximum Value or High Tolerance"),
183 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
184 NULL,
185 G_PARAM_READWRITE);
186 g_object_class_install_property(gobject_class, PROP_MAX, param);
189 static void
190 adg_dim_init(AdgDim *dim)
192 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
193 AdgDimPrivate);
195 data->dim_dress = ADG_DRESS_DIMENSION;
196 data->ref1 = NULL;
197 data->ref2 = NULL;
198 data->pos = NULL;
199 data->level = 1;
200 data->outside = ADG_THREE_STATE_UNKNOWN;
201 data->detached = ADG_THREE_STATE_UNKNOWN;
202 data->value = NULL;
203 data->min = NULL;
204 data->max = NULL;
206 dim->data = data;
209 static void
210 _adg_dispose(GObject *object)
212 AdgEntity *entity;
213 AdgDimPrivate *data;
215 entity = (AdgEntity *) object;
216 data = ((AdgDim *) object)->data;
218 if (data->quote.entity) {
219 g_object_unref(data->quote.entity);
220 data->quote.entity = NULL;
223 if (data->ref1)
224 data->ref1 = adg_entity_point(entity, data->ref1, NULL);
226 if (data->ref2)
227 data->ref2 = adg_entity_point(entity, data->ref2, NULL);
229 if (data->pos)
230 data->pos = adg_entity_point(entity, data->pos, NULL);
232 if (PARENT_OBJECT_CLASS->dispose)
233 PARENT_OBJECT_CLASS->dispose(object);
236 static void
237 _adg_finalize(GObject *object)
239 AdgDimPrivate *data = ((AdgDim *) object)->data;
241 g_free(data->value);
242 g_free(data->min);
243 g_free(data->max);
245 if (PARENT_OBJECT_CLASS->finalize)
246 PARENT_OBJECT_CLASS->finalize(object);
249 static void
250 _adg_get_property(GObject *object, guint prop_id,
251 GValue *value, GParamSpec *pspec)
253 AdgDimPrivate *data = ((AdgDim *) object)->data;
255 switch (prop_id) {
256 case PROP_DIM_DRESS:
257 g_value_set_int(value, data->dim_dress);
258 break;
259 case PROP_REF1:
260 g_value_set_boxed(value, data->ref1);
261 break;
262 case PROP_REF2:
263 g_value_set_boxed(value, data->ref2);
264 break;
265 case PROP_POS:
266 g_value_set_boxed(value, data->pos);
267 break;
268 case PROP_LEVEL:
269 g_value_set_double(value, data->level);
270 break;
271 case PROP_OUTSIDE:
272 g_value_set_enum(value, data->outside);
273 break;
274 case PROP_DETACHED:
275 g_value_set_enum(value, data->detached);
276 break;
277 case PROP_VALUE:
278 g_value_set_string(value, data->value);
279 break;
280 case PROP_MIN:
281 g_value_set_string(value, data->min);
282 break;
283 case PROP_MAX:
284 g_value_set_string(value, data->max);
285 break;
286 default:
287 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
288 break;
292 static void
293 _adg_set_property(GObject *object, guint prop_id,
294 const GValue *value, GParamSpec *pspec)
296 AdgEntity *entity;
297 AdgDim *dim;
298 AdgDimPrivate *data;
300 entity = (AdgEntity *) object;
301 dim = (AdgDim *) object;
302 data = dim->data;
304 switch (prop_id) {
305 case PROP_DIM_DRESS:
306 data->dim_dress = g_value_get_int(value);
307 break;
308 case PROP_REF1:
309 data->ref1 = adg_entity_point(entity, data->ref1,
310 g_value_get_boxed(value));
311 break;
312 case PROP_REF2:
313 data->ref2 = adg_entity_point(entity, data->ref2,
314 g_value_get_boxed(value));
315 break;
316 case PROP_POS:
317 data->pos = adg_entity_point(entity, data->pos,
318 g_value_get_boxed(value));
319 break;
320 case PROP_LEVEL:
321 data->level = g_value_get_double(value);
322 break;
323 case PROP_OUTSIDE:
324 _adg_set_outside(dim, g_value_get_enum(value));
325 break;
326 case PROP_DETACHED:
327 _adg_set_detached(dim, g_value_get_enum(value));
328 break;
329 case PROP_VALUE:
330 _adg_set_value(dim, g_value_get_string(value));
331 break;
332 case PROP_MIN:
333 _adg_set_min(dim, g_value_get_string(value));
334 break;
335 case PROP_MAX:
336 _adg_set_max(dim, g_value_get_string(value));
337 break;
338 default:
339 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
340 break;
346 * adg_dim_set_dim_dress:
347 * @dim: an #AdgDim
348 * @dress: the new #AdgDress to use
350 * Sets a new dimension dress to @dim. The new dress must be
351 * related to the original dress for this property: you cannot
352 * set a dress used for line styles to a dress managing fonts.
354 * The check is done by calling adg_dress_are_related() with
355 * @dress and the previous dress as arguments. Check out its
356 * documentation for details on what is a related dress.
358 void
359 adg_dim_set_dim_dress(AdgDim *dim, AdgDress dress)
361 g_return_if_fail(ADG_IS_DIM(dim));
362 g_object_set((GObject *) dim, "dim-dress", dress, NULL);
366 * adg_dim_get_dim_dress:
367 * @dim: an #AdgDim
369 * Gets the dimension dress to be used in rendering @dim.
371 * Returns: the current dimension dress
373 AdgDress
374 adg_dim_get_dim_dress(AdgDim *dim)
376 AdgDimPrivate *data;
378 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_DRESS_UNDEFINED);
380 data = dim->data;
382 return data->dim_dress;
386 * adg_dim_set_ref1:
387 * @dim: an #AdgDim
388 * @ref1: the new point to use as first reference
390 * Sets the #AdgDim:ref1 property to @ref1. The old point
391 * is silently discarded, unreferencing its model if that
392 * point was bound to a named pair (hence, possibly destroying
393 * the model if this was the last reference).
395 * @ref1 can be %NULL, in which case the point is destroyed.
397 void
398 adg_dim_set_ref1(AdgDim *dim, const AdgPoint *ref1)
400 g_return_if_fail(ADG_IS_DIM(dim));
401 g_object_set((GObject *) dim, "ref1", ref1, NULL);
405 * adg_dim_set_ref1_explicit:
406 * @dim: an #AdgDim
407 * @x: x coordinate of the first reference point
408 * @y: y coordinate of the first reference point
410 * Sets the #AdgDim:ref1 property to the (@x, @y) explicit
411 * coordinates. The old point is silently discarded,
412 * unreferencing its model if that point was bound to a named
413 * pair (hence, possibly destroying the model if this was the
414 * last reference).
416 void
417 adg_dim_set_ref1_explicit(AdgDim *dim, gdouble x, gdouble y)
419 AdgPoint *point = adg_point_new();
421 adg_point_set_pair_explicit(point, x, y);
422 adg_dim_set_ref1(dim, point);
424 adg_point_destroy(point);
428 * adg_dim_set_ref1_from_pair:
429 * @dim: an #AdgDim
430 * @ref1: the coordinates pair of the first reference point
432 * Convenient function to set the #AdgDim:ref1 property using a
433 * pair instead of explicit coordinates.
435 void
436 adg_dim_set_ref1_from_pair(AdgDim *dim, const AdgPair *ref1)
438 g_return_if_fail(ref1 != NULL);
440 adg_dim_set_ref1_explicit(dim, ref1->x, ref1->y);
444 * adg_dim_set_ref1_from_model:
445 * @dim: an #AdgDim
446 * @model: the source #AdgModel
447 * @ref1: a named pair in @model
449 * Binds #AdgDim:ref1 to the @ref1 named pair of @model. If @model
450 * is %NULL, the point will be unset. In any case, the old point
451 * is silently discarded, unreferencing its model if that point
452 * was bound to a named pair (hence, possibly destroying the model
453 * if this was the last reference).
455 * The assignment is lazy so @ref1 could be not be present in @model.
456 * Anyway, at the first access to this point an error will be raised
457 * if the named pair is still missing.
459 void
460 adg_dim_set_ref1_from_model(AdgDim *dim, AdgModel *model, const gchar *ref1)
462 AdgPoint *point = adg_point_new();
464 adg_point_set_pair_from_model(point, model, ref1);
465 adg_dim_set_ref1(dim, point);
467 adg_point_destroy(point);
471 * adg_dim_get_ref1:
472 * @dim: an #AdgDim
474 * Gets the #AdgDim:ref1 point. The returned point is internally owned
475 * and must not be freed or modified. Anyway, it is not const because
476 * adg_point_get_pair() must be able to modify the internal cache of
477 * the returned point.
479 * Returns: the first reference point
481 AdgPoint *
482 adg_dim_get_ref1(AdgDim *dim)
484 AdgDimPrivate *data;
486 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
488 data = dim->data;
490 return data->ref1;
494 * adg_dim_set_ref2:
495 * @dim: an #AdgDim
496 * @ref2: the new point to use as second reference
498 * Sets the #AdgDim:ref2 property to @ref2. The old point
499 * is silently discarded, unreferencing its model if that
500 * point was bound to a named pair (hence, possibly destroying
501 * the model if it was the last reference).
503 * @ref2 can be %NULL, in which case the point is destroyed.
505 void
506 adg_dim_set_ref2(AdgDim *dim, const AdgPoint *ref2)
508 g_return_if_fail(ADG_IS_DIM(dim));
509 g_object_set((GObject *) dim, "ref2", ref2, NULL);
513 * adg_dim_set_ref2_explicit:
514 * @dim: an #AdgDim
515 * @x: x coordinate of the second reference point
516 * @y: y coordinate of the second reference point
518 * Sets the #AdgDim:ref2 property to the (@x, @y) explicit
519 * coordinates. The old point is silently discarded,
520 * unreferencing its model if that point was bound to a named
521 * pair (hence, possibly destroying the model if this was the
522 * last reference).
524 void
525 adg_dim_set_ref2_explicit(AdgDim *dim, gdouble x, gdouble y)
527 AdgPoint *point = adg_point_new();
529 adg_point_set_pair_explicit(point, x, y);
530 adg_dim_set_ref2(dim, point);
532 adg_point_destroy(point);
536 * adg_dim_set_ref2_from_pair:
537 * @dim: an #AdgDim
538 * @ref2: the coordinates pair of the second reference point
540 * Convenient function to set the #AdgDim:ref2 property using a
541 * pair instead of explicit coordinates.
543 void
544 adg_dim_set_ref2_from_pair(AdgDim *dim, const AdgPair *ref2)
546 g_return_if_fail(ref2 != NULL);
548 adg_dim_set_ref2_explicit(dim, ref2->x, ref2->y);
552 * adg_dim_set_ref2_from_model:
553 * @dim: an #AdgDim
554 * @model: the source #AdgModel
555 * @ref2: a named pair in @model
557 * Binds #AdgDim:ref2 to the @ref2 named pair of @model. If @model
558 * is %NULL, the point will be unset. In any case, the old point
559 * is silently discarded, unreferencing its model if that point
560 * was bound to a named pair (hence, possibly destroying the model
561 * if this was the last reference).
563 * The assignment is lazy so @ref2 could be not be present in @model.
564 * Anyway, at the first access to this point an error will be raised
565 * if the named pair is still missing.
567 void
568 adg_dim_set_ref2_from_model(AdgDim *dim, AdgModel *model, const gchar *ref2)
570 AdgPoint *point = adg_point_new();
572 adg_point_set_pair_from_model(point, model, ref2);
573 adg_dim_set_ref2(dim, point);
575 adg_point_destroy(point);
579 * adg_dim_get_ref2:
580 * @dim: an #AdgDim
582 * Gets the #AdgDim:ref2 point. The returned point is internally owned
583 * and must not be freed or modified. Anyway, it is not const because
584 * adg_point_get_pair() must be able to modify the internal cache of
585 * the returned point.
587 * Returns: the second reference point
589 AdgPoint *
590 adg_dim_get_ref2(AdgDim *dim)
592 AdgDimPrivate *data;
594 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
596 data = dim->data;
598 return data->ref2;
602 * adg_dim_set_pos:
603 * @dim: an #AdgDim
604 * @pos: the new point to use as position
606 * Sets the #AdgDim:pos property to @pos. The old point
607 * is silently discarded, unreferencing its model if that
608 * point was bound to a named pair (hence, possibly destroying
609 * the model if it was the last reference).
611 * @pos can be %NULL, in which case the point is destroyed.
613 void
614 adg_dim_set_pos(AdgDim *dim, const AdgPoint *pos)
616 g_return_if_fail(ADG_IS_DIM(dim));
617 g_object_set((GObject *) dim, "pos", pos, NULL);
621 * adg_dim_set_pos_explicit:
622 * @dim: an #AdgDim
623 * @x: x coordinate of the position
624 * @y: y coordinate of the position
626 * Sets the #AdgDim:pos property to the (@x, @y) explicit
627 * coordinates. The old point is silently discarded,
628 * unreferencing its model if that point was bound to a named
629 * pair (hence, possibly destroying the model if this was the
630 * last reference).
632 void
633 adg_dim_set_pos_explicit(AdgDim *dim, gdouble x, gdouble y)
635 AdgPoint *point = adg_point_new();
637 adg_point_set_pair_explicit(point, x, y);
638 adg_dim_set_pos(dim, point);
640 adg_point_destroy(point);
644 * adg_dim_set_pos_from_pair:
645 * @dim: an #AdgDim
646 * @pos: the coordinates pair of the position point
648 * Convenient function to set the #AdgDim:pos property using a
649 * pair instead of explicit coordinates.
651 void
652 adg_dim_set_pos_from_pair(AdgDim *dim, const AdgPair *pos)
654 g_return_if_fail(pos != NULL);
656 adg_dim_set_pos_explicit(dim, pos->x, pos->y);
660 * adg_dim_set_pos_from_model:
661 * @dim: an #AdgDim
662 * @model: the source #AdgModel
663 * @pos: a named pair in @model
665 * Binds #AdgDim:pos to the @pos named pair of @model. If @model
666 * is %NULL, the point will be unset. In any case, the old point
667 * is silently discarded, unreferencing its model if that point
668 * was bound to a named pair (hence, possibly destroying the model
669 * if this was the last reference).
671 * The assignment is lazy so @pos could be not be present in @model.
672 * Anyway, at the first access to this point an error will be raised
673 * if the named pair is still missing.
675 void
676 adg_dim_set_pos_from_model(AdgDim *dim, AdgModel *model, const gchar *pos)
678 AdgPoint *point = adg_point_new();
680 adg_point_set_pair_from_model(point, model, pos);
681 adg_dim_set_pos(dim, point);
683 adg_point_destroy(point);
687 * adg_dim_get_pos:
688 * @dim: an #AdgDim
690 * Gets the #AdgDim:pos point. The returned point is internally owned
691 * and must not be freed or modified. Anyway, it is not const because
692 * adg_point_get_pair() must be able to modify the internal cache of
693 * the returned point.
695 * Returns: the position point
697 AdgPoint *
698 adg_dim_get_pos(AdgDim *dim)
700 AdgDimPrivate *data;
702 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
704 data = dim->data;
706 return data->pos;
710 * adg_dim_set_level:
711 * @dim: an #AdgDim
712 * @level: the new level
714 * Sets a new level for this dimension. The level is used to
715 * stack the quotes using a spacing value from dim_style
716 * (specified in global space).
718 void
719 adg_dim_set_level(AdgDim *dim, gdouble level)
721 AdgDimPrivate *data;
723 g_return_if_fail(ADG_IS_DIM(dim));
725 data = dim->data;
726 data->level = level;
728 g_object_notify((GObject *) dim, "level");
732 * adg_dim_get_level:
733 * @dim: an #AdgDim
735 * Gets the level of this dimension.
737 * Returns: the level value
739 gdouble
740 adg_dim_get_level(AdgDim *dim)
742 AdgDimPrivate *data;
744 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
746 data = dim->data;
748 return data->level;
752 * adg_dim_set_outside:
753 * @dim: an #AdgDim
754 * @outside: the new outside state
756 * Sets a new state for the #AdgDim:outside flag: check the property
757 * documentation for further details.
759 void
760 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
762 g_return_if_fail(ADG_IS_DIM(dim));
764 if (_adg_set_outside(dim, outside))
765 g_object_notify((GObject *) dim, "outside");
769 * adg_dim_get_outside:
770 * @dim: an #AdgDim
772 * Gets the state of the #AdgDim:outside property: check the property
773 * documentation for further details.
775 * Returns: the current flag state
777 AdgThreeState
778 adg_dim_get_outside(AdgDim *dim)
780 AdgDimPrivate *data;
782 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
784 data = dim->data;
786 return data->outside;
790 * adg_dim_set_detached:
791 * @dim: an #AdgDim
792 * @detached: the new detached state
794 * Sets a new state for the #AdgDim:detached flag: check the property
795 * documentation for further details.
797 * This is used only by dimensions where detaching has meaning.
798 * In some cases, such as with #AdgRDim dimensions, this property is
799 * not used.
801 void
802 adg_dim_set_detached(AdgDim *dim, AdgThreeState detached)
804 g_return_if_fail(ADG_IS_DIM(dim));
806 if (_adg_set_detached(dim, detached))
807 g_object_notify((GObject *) dim, "detached");
811 * adg_dim_get_detached:
812 * @dim: an #AdgDim
814 * Gets the state of the #AdgDim:detached property: check the property
815 * documentation for further details.
817 * Returns: the current flag state
819 AdgThreeState
820 adg_dim_get_detached(AdgDim *dim)
822 AdgDimPrivate *data;
824 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
826 data = dim->data;
828 return data->detached;
832 * adg_dim_set_value:
833 * @dim: an #AdgDim
834 * @value: the value text
836 * Explicitely sets the text to use as value. If @value is %NULL or
837 * was never set, an automatic text is calculated using the format
838 * specified in the current #AdgDimStyle and getting its value by
839 * calling the default_value() virtual method.
841 void
842 adg_dim_set_value(AdgDim *dim, const gchar *value)
844 g_return_if_fail(ADG_IS_DIM(dim));
846 if (_adg_set_value(dim, value))
847 g_object_notify((GObject *) dim, "value");
851 * adg_dim_get_value:
852 * @dim: an #AdgDim
854 * Gets the value text. The string is internally owned and
855 * must not be freed or modified.
857 * Returns: the value text
859 const gchar *
860 adg_dim_get_value(AdgDim *dim)
862 AdgDimPrivate *data;
864 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
866 data = dim->data;
868 return data->value;
872 * adg_dim_set_limits:
873 * @dim: an #AdgDim
874 * @min: the new minumum value
875 * @max: the new maximum value
877 * Shortcut to set both the limits at once.
879 void
880 adg_dim_set_limits(AdgDim *dim, const gchar *min, const gchar *max)
882 g_return_if_fail(ADG_IS_DIM(dim));
884 g_object_freeze_notify((GObject *) dim);
885 adg_dim_set_min(dim, min);
886 adg_dim_set_max(dim, max);
887 g_object_thaw_notify((GObject *) dim);
891 * adg_dim_set_min:
892 * @dim: an #AdgDim
893 * @min: the new minimum limit
895 * Sets the minimum value. Use %NULL as @min to disable it.
897 void
898 adg_dim_set_min(AdgDim *dim, const gchar *min)
900 g_return_if_fail(ADG_IS_DIM(dim));
902 if (_adg_set_min(dim, min))
903 g_object_notify((GObject *) dim, "min");
907 * adg_dim_get_min:
908 * @dim: an #AdgDim
910 * Gets the minimum value text or %NULL on minimum value disabled.
911 * The string is internally owned and must not be freed or modified.
913 * Returns: the mimimum value text
915 const gchar *
916 adg_dim_get_min(AdgDim *dim)
918 AdgDimPrivate *data;
920 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
922 data = dim->data;
924 return data->min;
928 * adg_dim_set_max:
929 * @dim: an #AdgDim
930 * @max: the new maximum value
932 * Sets the maximum value. Use %NULL as @max to disable it.
934 void
935 adg_dim_set_max(AdgDim *dim, const gchar *max)
937 g_return_if_fail(ADG_IS_DIM(dim));
939 if (_adg_set_max(dim, max))
940 g_object_notify((GObject *) dim, "max");
944 * adg_dim_get_max:
945 * @dim: an #AdgDim
947 * Gets the maximum value text or %NULL on maximum value disabled.
948 * The string is internally owned and must not be freed or modified.
950 * Returns: the maximum value text
952 const gchar *
953 adg_dim_get_max(AdgDim *dim)
955 AdgDimPrivate *data;
957 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
959 data = dim->data;
961 return data->max;
965 * adg_dim_get_quote:
966 * @dim: an #AdgDim
968 * <note><para>
969 * This function is only useful in new dimension implementations.
970 * </para></note>
972 * Gets the quote entity, if any. This function is valid only after
973 * the #AdgDim implementation of the arrange() virtual method has
974 * been called.
976 * Returns: the quote entity
978 AdgAlignment *
979 adg_dim_get_quote(AdgDim *dim)
981 AdgDimPrivate *data;
983 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
985 data = dim->data;
987 return data->quote.entity;
991 * adg_dim_quote_angle:
992 * @dim: an #AdgDim
993 * @angle: an angle (in radians)
995 * <note><para>
996 * This function is only useful in new dimension implementations.
997 * </para></note>
999 * Converts @angle accordling to the style of @dim. Any quote angle
1000 * should be validated by this method because every dimensioning
1001 * style has its own convention regardling the text rotation.
1003 * Returns: the angle to use (always in radians)
1005 gdouble
1006 adg_dim_quote_angle(AdgDim *dim, gdouble angle)
1008 AdgDimClass *klass;
1010 g_return_val_if_fail(ADG_IS_DIM(dim), angle);
1012 klass = ADG_DIM_GET_CLASS(dim);
1014 if (klass->quote_angle == NULL)
1015 return angle;
1017 return klass->quote_angle(angle);
1021 static void
1022 _adg_global_changed(AdgEntity *entity)
1024 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1026 if (PARENT_ENTITY_CLASS->global_changed)
1027 PARENT_ENTITY_CLASS->global_changed(entity);
1029 if (data->quote.entity)
1030 adg_entity_global_changed((AdgEntity *) data->quote.entity);
1033 static void
1034 _adg_local_changed(AdgEntity *entity)
1036 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1038 if (PARENT_ENTITY_CLASS->local_changed)
1039 PARENT_ENTITY_CLASS->local_changed(entity);
1041 if (data->quote.entity)
1042 adg_entity_local_changed((AdgEntity *) data->quote.entity);
1045 static void
1046 _adg_invalidate(AdgEntity *entity)
1048 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1050 if (data->quote.value) {
1051 g_object_unref(data->quote.value);
1052 data->quote.value = NULL;
1054 if (data->quote.entity)
1055 adg_entity_invalidate((AdgEntity *) data->quote.entity);
1056 if (data->ref1)
1057 adg_point_invalidate(data->ref1);
1058 if (data->ref2)
1059 adg_point_invalidate(data->ref2);
1060 if (data->pos)
1061 adg_point_invalidate(data->pos);
1063 if (PARENT_ENTITY_CLASS->invalidate)
1064 PARENT_ENTITY_CLASS->invalidate(entity);
1067 static void
1068 _adg_arrange(AdgEntity *entity)
1070 AdgDim *dim;
1071 AdgDimPrivate *data;
1072 AdgEntity *quote_entity;
1073 AdgContainer *quote_container;
1074 AdgEntity *value_entity;
1075 AdgEntity *min_entity;
1076 AdgEntity *max_entity;
1077 const AdgPair *shift;
1078 AdgMatrix map;
1080 dim = (AdgDim *) entity;
1081 data = dim->data;
1083 /* Resolve the dim style */
1084 if (data->dim_style == NULL)
1085 data->dim_style = (AdgDimStyle *)
1086 adg_entity_style(entity, data->dim_dress);
1088 if (data->quote.entity == NULL)
1089 data->quote.entity = g_object_new(ADG_TYPE_ALIGNMENT,
1090 "local-method", ADG_MIX_NONE,
1091 "parent", dim, NULL);
1093 quote_entity = (AdgEntity *) data->quote.entity;
1094 quote_container = (AdgContainer *) data->quote.entity;
1096 if (data->quote.value == NULL) {
1097 AdgDress dress = adg_dim_style_get_value_dress(data->dim_style);
1099 data->quote.value = g_object_new(ADG_TYPE_TOY_TEXT,
1100 "local-method", ADG_MIX_PARENT,
1101 "font-dress", dress, NULL);
1103 adg_container_add(quote_container, (AdgEntity *) data->quote.value);
1105 if (data->value) {
1106 adg_toy_text_set_label(data->quote.value, data->value);
1107 } else {
1108 AdgDimClass *klass = ADG_DIM_GET_CLASS(dim);
1110 if (klass->default_value) {
1111 /* Automatically generate the value text */
1112 gchar *text = klass->default_value(dim);
1113 adg_toy_text_set_label(data->quote.value, text);
1114 g_free(text);
1119 if (data->quote.min == NULL && data->min) {
1120 AdgDress dress = adg_dim_style_get_min_dress(data->dim_style);
1122 data->quote.min = g_object_new(ADG_TYPE_TOY_TEXT,
1123 "local-method", ADG_MIX_PARENT,
1124 "font-dress", dress, NULL);
1126 adg_container_add(quote_container, (AdgEntity *) data->quote.min);
1127 adg_toy_text_set_label(data->quote.min, data->min);
1130 if (data->quote.max == NULL && data->max) {
1131 AdgDress dress = adg_dim_style_get_max_dress(data->dim_style);
1133 data->quote.max = g_object_new(ADG_TYPE_TOY_TEXT,
1134 "local-method", ADG_MIX_PARENT,
1135 "font-dress", dress, NULL);
1137 adg_container_add(quote_container, (AdgEntity *) data->quote.max);
1138 adg_toy_text_set_label(data->quote.max, data->max);
1141 value_entity = (AdgEntity *) data->quote.value;
1142 min_entity = (AdgEntity *) data->quote.min;
1143 max_entity = (AdgEntity *) data->quote.max;
1144 shift = adg_dim_style_get_quote_shift(data->dim_style);
1146 adg_entity_set_global_map(quote_entity, adg_matrix_identity());
1147 adg_entity_global_changed(quote_entity);
1149 cairo_matrix_init_translate(&map, shift->x, shift->y);
1150 adg_entity_set_global_map(value_entity, &map);
1151 adg_entity_arrange(value_entity);
1153 /* Limit values (min and max) */
1154 if (min_entity || max_entity) {
1155 const CpmlExtents *extents;
1156 const AdgPair *limits_shift;
1157 AdgMatrix unglobal;
1159 extents = adg_entity_get_extents(value_entity);
1160 limits_shift = adg_dim_style_get_limits_shift(data->dim_style);
1162 cairo_matrix_init_translate(&map, extents->size.x + limits_shift->x,
1163 -extents->size.y / 2 + limits_shift->y);
1165 adg_matrix_copy(&unglobal, adg_entity_get_global_matrix(entity));
1166 cairo_matrix_invert(&unglobal);
1167 cairo_matrix_transform_distance(&unglobal, &map.x0, &map.y0);
1169 if (min_entity) {
1170 AdgPair offset;
1172 adg_entity_set_global_map(min_entity, &map);
1173 adg_entity_arrange(min_entity);
1174 extents = adg_entity_get_extents(min_entity);
1176 offset.x = 0;
1177 offset.y = -extents->size.y - adg_dim_style_get_limits_spacing(data->dim_style);
1178 cairo_matrix_transform_distance(&unglobal, &offset.x, &offset.y);
1180 map.x0 += offset.x;
1181 map.y0 += offset.y;
1184 if (max_entity) {
1185 adg_entity_set_global_map(max_entity, &map);
1186 adg_entity_arrange(max_entity);
1190 adg_entity_arrange(quote_entity);
1193 static gchar *
1194 _adg_default_value(AdgDim *dim)
1196 g_warning("AdgDim::default_value not implemented for `%s'",
1197 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
1198 return g_strdup("undef");
1201 static gdouble
1202 _adg_quote_angle(gdouble angle)
1204 angle = cpml_angle(angle);
1206 if (angle > G_PI_4 * 4 / 3 || angle <= -G_PI_4 * 3)
1207 angle = cpml_angle(angle + G_PI);
1209 return angle;
1212 static gboolean
1213 _adg_set_outside(AdgDim *dim, AdgThreeState outside)
1215 AdgDimPrivate *data;
1217 g_return_val_if_fail(adg_is_enum_value(outside, ADG_TYPE_THREE_STATE),
1218 FALSE);
1220 data = dim->data;
1222 if (data->outside == outside)
1223 return FALSE;
1225 data->outside = outside;
1227 return TRUE;
1230 static gboolean
1231 _adg_set_detached(AdgDim *dim, AdgThreeState detached)
1233 AdgDimPrivate *data;
1235 g_return_val_if_fail(adg_is_enum_value(detached, ADG_TYPE_THREE_STATE),
1236 FALSE);
1238 data = dim->data;
1240 if (data->detached == detached)
1241 return FALSE;
1243 data->detached = detached;
1245 return TRUE;
1248 static gboolean
1249 _adg_set_value(AdgDim *dim, const gchar *value)
1251 AdgDimPrivate *data;
1253 data = dim->data;
1255 if (g_strcmp0(value, data->value) == 0)
1256 return FALSE;
1258 g_free(data->value);
1259 data->value = g_strdup(value);
1261 if (data->quote.value) {
1262 g_object_unref(data->quote.value);
1263 data->quote.value = NULL;
1266 return TRUE;
1269 static gboolean
1270 _adg_set_min(AdgDim *dim, const gchar *min)
1272 AdgDimPrivate *data = dim->data;
1274 if (g_strcmp0(min, data->min) == 0)
1275 return FALSE;
1277 g_free(data->min);
1278 data->min = g_strdup(min);
1280 if (data->quote.min) {
1281 g_object_unref(data->quote.min);
1282 data->quote.min = NULL;
1285 return TRUE;
1288 static gboolean
1289 _adg_set_max(AdgDim *dim, const gchar *max)
1291 AdgDimPrivate *data = dim->data;
1293 if (g_strcmp0(max, data->max) == 0)
1294 return FALSE;
1296 g_free(data->max);
1297 data->max = g_strdup(max);
1299 if (data->quote.max) {
1300 g_object_unref(data->quote.max);
1301 data->quote.max = NULL;
1304 return TRUE;