[AdgDim] Rely on automatic dress validation
[adg.git] / src / adg / adg-dim.c
blobde92db5d8b4e8082aeeab0727f86a605b2de963b
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 enum {
49 PROP_0,
50 PROP_DIM_DRESS,
51 PROP_REF1,
52 PROP_REF2,
53 PROP_POS,
54 PROP_LEVEL,
55 PROP_OUTSIDE,
56 PROP_DETACHED,
57 PROP_VALUE,
58 PROP_MIN,
59 PROP_MAX
63 static void _adg_dispose (GObject *object);
64 static void _adg_finalize (GObject *object);
65 static void _adg_get_property (GObject *object,
66 guint param_id,
67 GValue *value,
68 GParamSpec *pspec);
69 static void _adg_set_property (GObject *object,
70 guint param_id,
71 const GValue *value,
72 GParamSpec *pspec);
73 static void _adg_global_changed (AdgEntity *entity);
74 static void _adg_local_changed (AdgEntity *entity);
75 static void _adg_invalidate (AdgEntity *entity);
76 static void _adg_arrange (AdgEntity *entity);
77 static gchar * _adg_default_value (AdgDim *dim);
78 static gdouble _adg_quote_angle (gdouble angle);
79 static gboolean _adg_set_outside (AdgDim *dim,
80 AdgThreeState outside);
81 static gboolean _adg_set_detached (AdgDim *dim,
82 AdgThreeState detached);
83 static gboolean _adg_set_value (AdgDim *dim,
84 const gchar *value);
85 static gboolean _adg_set_min (AdgDim *dim,
86 const gchar *min);
87 static gboolean _adg_set_max (AdgDim *dim,
88 const gchar *max);
91 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY);
94 static void
95 adg_dim_class_init(AdgDimClass *klass)
97 GObjectClass *gobject_class;
98 AdgEntityClass *entity_class;
99 GParamSpec *param;
101 gobject_class = (GObjectClass *) klass;
102 entity_class = (AdgEntityClass *) klass;
104 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
106 gobject_class->dispose = _adg_dispose;
107 gobject_class->finalize = _adg_finalize;
108 gobject_class->get_property = _adg_get_property;
109 gobject_class->set_property = _adg_set_property;
111 entity_class->global_changed = _adg_global_changed;
112 entity_class->local_changed = _adg_local_changed;
113 entity_class->invalidate = _adg_invalidate;
114 entity_class->arrange = _adg_arrange;
116 klass->quote_angle = _adg_quote_angle;
117 klass->default_value = _adg_default_value;
119 param = adg_param_spec_dress("dim-dress",
120 P_("Dimension Dress"),
121 P_("The dress to use for rendering this dimension"),
122 ADG_DRESS_DIMENSION,
123 G_PARAM_READWRITE);
124 g_object_class_install_property(gobject_class, PROP_DIM_DRESS, param);
126 param = g_param_spec_boxed("ref1",
127 P_("First Reference"),
128 P_("First reference point of the dimension"),
129 ADG_TYPE_POINT,
130 G_PARAM_READWRITE);
131 g_object_class_install_property(gobject_class, PROP_REF1, param);
133 param = g_param_spec_boxed("ref2",
134 P_("Second Reference"),
135 P_("Second reference point of the dimension"),
136 ADG_TYPE_POINT,
137 G_PARAM_READWRITE);
138 g_object_class_install_property(gobject_class, PROP_REF2, param);
140 param = g_param_spec_boxed("pos",
141 P_("Position"),
142 P_("The reference position of the quote: it will be combined with \"level\" to get the real quote position"),
143 ADG_TYPE_POINT,
144 G_PARAM_READWRITE);
145 g_object_class_install_property(gobject_class, PROP_POS, param);
147 param = g_param_spec_double("level",
148 P_("Level"),
149 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"),
150 -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
151 G_PARAM_READWRITE);
152 g_object_class_install_property(gobject_class, PROP_LEVEL, param);
154 param = g_param_spec_enum("outside",
155 P_("Outside"),
156 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"),
157 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
158 G_PARAM_READWRITE);
159 g_object_class_install_property(gobject_class, PROP_OUTSIDE, param);
161 param = g_param_spec_enum("detached",
162 P_("Detached Quote"),
163 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"),
164 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
165 G_PARAM_READWRITE);
166 g_object_class_install_property(gobject_class, PROP_DETACHED, param);
168 param = g_param_spec_string("value",
169 P_("Basic Value"),
170 P_("The theoretically exact value for this quote: set to NULL to automatically get the default value"),
171 NULL,
172 G_PARAM_READWRITE);
173 g_object_class_install_property(gobject_class, PROP_VALUE, param);
175 param = g_param_spec_string("min",
176 P_("Minimum Value or Low Tolerance"),
177 P_("The minimum value allowed or the lowest tolerance from value (depending of the dimension style): set to NULL to suppress"),
178 NULL,
179 G_PARAM_READWRITE);
180 g_object_class_install_property(gobject_class, PROP_MIN, param);
182 param = g_param_spec_string("max",
183 P_("Maximum Value or High Tolerance"),
184 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
185 NULL,
186 G_PARAM_READWRITE);
187 g_object_class_install_property(gobject_class, PROP_MAX, param);
190 static void
191 adg_dim_init(AdgDim *dim)
193 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
194 AdgDimPrivate);
196 data->dim_dress = ADG_DRESS_DIMENSION;
197 data->ref1 = NULL;
198 data->ref2 = NULL;
199 data->pos = NULL;
200 data->level = 1;
201 data->outside = ADG_THREE_STATE_UNKNOWN;
202 data->detached = ADG_THREE_STATE_UNKNOWN;
203 data->value = NULL;
204 data->min = NULL;
205 data->max = NULL;
207 dim->data = data;
210 static void
211 _adg_dispose(GObject *object)
213 AdgDimPrivate *data = ((AdgDim *) object)->data;
215 if (data->quote.entity != NULL) {
216 g_object_unref(data->quote.entity);
217 data->quote.entity = NULL;
219 if (data->ref1 != NULL) {
220 adg_point_destroy(data->ref1);
221 data->ref1 = NULL;
223 if (data->ref2 != NULL) {
224 adg_point_destroy(data->ref2);
225 data->ref2 = NULL;
227 if (data->pos != NULL) {
228 adg_point_destroy(data->pos);
229 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 AdgDim *dim;
297 AdgDimPrivate *data;
299 dim = (AdgDim *) object;
300 data = dim->data;
302 switch (prop_id) {
303 case PROP_DIM_DRESS:
304 data->dim_dress = g_value_get_int(value);
305 break;
306 case PROP_REF1:
307 adg_point_set(&data->ref1, g_value_get_boxed(value));
308 break;
309 case PROP_REF2:
310 adg_point_set(&data->ref2, g_value_get_boxed(value));
311 break;
312 case PROP_POS:
313 adg_point_set(&data->pos, g_value_get_boxed(value));
314 break;
315 case PROP_LEVEL:
316 data->level = g_value_get_double(value);
317 break;
318 case PROP_OUTSIDE:
319 _adg_set_outside(dim, g_value_get_enum(value));
320 break;
321 case PROP_DETACHED:
322 _adg_set_detached(dim, g_value_get_enum(value));
323 break;
324 case PROP_VALUE:
325 _adg_set_value(dim, g_value_get_string(value));
326 break;
327 case PROP_MIN:
328 _adg_set_min(dim, g_value_get_string(value));
329 break;
330 case PROP_MAX:
331 _adg_set_max(dim, g_value_get_string(value));
332 break;
333 default:
334 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
335 break;
341 * adg_dim_set_dim_dress:
342 * @dim: an #AdgDim
343 * @dress: the new #AdgDress to use
345 * Sets a new dimension dress to @dim. The new dress must be
346 * related to the original dress for this property: you cannot
347 * set a dress used for line styles to a dress managing fonts.
349 * The check is done by calling adg_dress_are_related() with
350 * @dress and the previous dress as arguments. Check out its
351 * documentation for details on what is a related dress.
353 void
354 adg_dim_set_dim_dress(AdgDim *dim, AdgDress dress)
356 g_return_if_fail(ADG_IS_DIM(dim));
357 g_object_set((GObject *) dim, "dim-dress", dress, NULL);
361 * adg_dim_get_dim_dress:
362 * @dim: an #AdgDim
364 * Gets the dimension dress to be used in rendering @dim.
366 * Returns: the current dimension dress
368 AdgDress
369 adg_dim_get_dim_dress(AdgDim *dim)
371 AdgDimPrivate *data;
373 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_DRESS_UNDEFINED);
375 data = dim->data;
377 return data->dim_dress;
381 * adg_dim_set_ref1:
382 * @dim: an #AdgDim
383 * @ref1: the new point to use as first reference
385 * Sets the #AdgDim:ref1 property to @ref1. The old point
386 * is silently discarded, unreferencing its model if that
387 * point was bound to a named pair (hence, possibly destroying
388 * the model if this was the last reference).
390 * @ref1 can be %NULL, in which case the point is unset.
392 void
393 adg_dim_set_ref1(AdgDim *dim, const AdgPoint *ref1)
395 AdgDimPrivate *data;
397 g_return_if_fail(ADG_IS_DIM(dim));
399 data = dim->data;
401 if (adg_point_set(&data->ref1, ref1))
402 g_object_notify((GObject *) dim, "ref1");
406 * adg_dim_set_ref1_explicit:
407 * @dim: an #AdgDim
408 * @x: x coordinate of the first reference point
409 * @y: y coordinate of the first reference point
411 * Sets the #AdgDim:ref1 property to the (@x, @y) explicit
412 * coordinates. The old point is silently discarded,
413 * unreferencing its model if that point was bound to a named
414 * pair (hence, possibly destroying the model if this was the
415 * last reference).
417 void
418 adg_dim_set_ref1_explicit(AdgDim *dim, gdouble x, gdouble y)
420 AdgPoint *point = adg_point_new();
422 adg_point_set_pair_explicit(point, x, y);
423 adg_dim_set_ref1(dim, point);
425 adg_point_destroy(point);
429 * adg_dim_set_ref1_from_pair:
430 * @dim: an #AdgDim
431 * @ref1: the coordinates pair of the first reference point
433 * Convenient function to set the #AdgDim:ref1 property using a
434 * pair instead of explicit coordinates.
436 void
437 adg_dim_set_ref1_from_pair(AdgDim *dim, const AdgPair *ref1)
439 g_return_if_fail(ref1 != NULL);
441 adg_dim_set_ref1_explicit(dim, ref1->x, ref1->y);
445 * adg_dim_set_ref1_from_model:
446 * @dim: an #AdgDim
447 * @model: the source #AdgModel
448 * @ref1: a named pair in @model
450 * Binds #AdgDim:ref1 to the @ref1 named pair of @model. If @model
451 * is %NULL, the point will be unset. In any case, the old point
452 * is silently discarded, unreferencing its model if that point
453 * was bound to a named pair (hence, possibly destroying the model
454 * if this was the last reference).
456 * The assignment is lazy so @ref1 could be not be present in @model.
457 * Anyway, at the first access to this point an error will be raised
458 * if the named pair is still missing.
460 void
461 adg_dim_set_ref1_from_model(AdgDim *dim, AdgModel *model, const gchar *ref1)
463 AdgPoint *point = adg_point_new();
465 adg_point_set_pair_from_model(point, model, ref1);
466 adg_dim_set_ref1(dim, point);
468 adg_point_destroy(point);
472 * adg_dim_get_ref1:
473 * @dim: an #AdgDim
475 * Gets the #AdgDim:ref1 point. The returned point is internally owned
476 * and must not be freed or modified. Anyway, it is not const because
477 * adg_point_get_pair() must be able to modify the internal cache of
478 * the returned point.
480 * Returns: the first reference point
482 AdgPoint *
483 adg_dim_get_ref1(AdgDim *dim)
485 AdgDimPrivate *data;
487 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
489 data = dim->data;
491 return data->ref1;
495 * adg_dim_set_ref2:
496 * @dim: an #AdgDim
497 * @ref2: the new point to use as second reference
499 * Sets the #AdgDim:ref2 property to @ref2. The old point
500 * is silently discarded, unreferencing its model if that
501 * point was bound to a named pair (hence, possibly destroying
502 * the model if it was the last reference).
504 * @ref2 can be %NULL, in which case the point is unset.
506 void
507 adg_dim_set_ref2(AdgDim *dim, const AdgPoint *ref2)
509 AdgDimPrivate *data;
511 g_return_if_fail(ADG_IS_DIM(dim));
513 data = dim->data;
515 if (adg_point_set(&data->ref2, ref2))
516 g_object_notify((GObject *) dim, "ref2");
520 * adg_dim_set_ref2_explicit:
521 * @dim: an #AdgDim
522 * @x: x coordinate of the second reference point
523 * @y: y coordinate of the second reference point
525 * Sets the #AdgDim:ref2 property to the (@x, @y) explicit
526 * coordinates. The old point is silently discarded,
527 * unreferencing its model if that point was bound to a named
528 * pair (hence, possibly destroying the model if this was the
529 * last reference).
531 void
532 adg_dim_set_ref2_explicit(AdgDim *dim, gdouble x, gdouble y)
534 AdgPoint *point = adg_point_new();
536 adg_point_set_pair_explicit(point, x, y);
537 adg_dim_set_ref2(dim, point);
539 adg_point_destroy(point);
543 * adg_dim_set_ref2_from_pair:
544 * @dim: an #AdgDim
545 * @ref2: the coordinates pair of the second reference point
547 * Convenient function to set the #AdgDim:ref2 property using a
548 * pair instead of explicit coordinates.
550 void
551 adg_dim_set_ref2_from_pair(AdgDim *dim, const AdgPair *ref2)
553 g_return_if_fail(ref2 != NULL);
555 adg_dim_set_ref2_explicit(dim, ref2->x, ref2->y);
559 * adg_dim_set_ref2_from_model:
560 * @dim: an #AdgDim
561 * @model: the source #AdgModel
562 * @ref2: a named pair in @model
564 * Binds #AdgDim:ref2 to the @ref2 named pair of @model. If @model
565 * is %NULL, the point will be unset. In any case, the old point
566 * is silently discarded, unreferencing its model if that point
567 * was bound to a named pair (hence, possibly destroying the model
568 * if this was the last reference).
570 * The assignment is lazy so @ref2 could be not be present in @model.
571 * Anyway, at the first access to this point an error will be raised
572 * if the named pair is still missing.
574 void
575 adg_dim_set_ref2_from_model(AdgDim *dim, AdgModel *model, const gchar *ref2)
577 AdgPoint *point = adg_point_new();
579 adg_point_set_pair_from_model(point, model, ref2);
580 adg_dim_set_ref2(dim, point);
582 adg_point_destroy(point);
586 * adg_dim_get_ref2:
587 * @dim: an #AdgDim
589 * Gets the #AdgDim:ref2 point. The returned point is internally owned
590 * and must not be freed or modified. Anyway, it is not const because
591 * adg_point_get_pair() must be able to modify the internal cache of
592 * the returned point.
594 * Returns: the second reference point
596 AdgPoint *
597 adg_dim_get_ref2(AdgDim *dim)
599 AdgDimPrivate *data;
601 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
603 data = dim->data;
605 return data->ref2;
609 * adg_dim_set_pos:
610 * @dim: an #AdgDim
611 * @pos: the new point to use as position
613 * Sets the #AdgDim:pos property to @pos. The old point
614 * is silently discarded, unreferencing its model if that
615 * point was bound to a named pair (hence, possibly destroying
616 * the model if it was the last reference).
618 * @pos can be %NULL, in which case the point is unset.
620 void
621 adg_dim_set_pos(AdgDim *dim, const AdgPoint *pos)
623 AdgDimPrivate *data;
625 g_return_if_fail(ADG_IS_DIM(dim));
627 data = dim->data;
629 if (adg_point_set(&data->pos, pos))
630 g_object_notify((GObject *) dim, "pos");
634 * adg_dim_set_pos_explicit:
635 * @dim: an #AdgDim
636 * @x: x coordinate of the position
637 * @y: y coordinate of the position
639 * Sets the #AdgDim:pos property to the (@x, @y) explicit
640 * coordinates. The old point is silently discarded,
641 * unreferencing its model if that point was bound to a named
642 * pair (hence, possibly destroying the model if this was the
643 * last reference).
645 void
646 adg_dim_set_pos_explicit(AdgDim *dim, gdouble x, gdouble y)
648 AdgPoint *point = adg_point_new();
650 adg_point_set_pair_explicit(point, x, y);
651 adg_dim_set_pos(dim, point);
653 adg_point_destroy(point);
657 * adg_dim_set_pos_from_pair:
658 * @dim: an #AdgDim
659 * @pos: the coordinates pair of the position point
661 * Convenient function to set the #AdgDim:pos property using a
662 * pair instead of explicit coordinates.
664 void
665 adg_dim_set_pos_from_pair(AdgDim *dim, const AdgPair *pos)
667 g_return_if_fail(pos != NULL);
669 adg_dim_set_pos_explicit(dim, pos->x, pos->y);
673 * adg_dim_set_pos_from_model:
674 * @dim: an #AdgDim
675 * @model: the source #AdgModel
676 * @pos: a named pair in @model
678 * Binds #AdgDim:pos to the @pos named pair of @model. If @model
679 * is %NULL, the point will be unset. In any case, the old point
680 * is silently discarded, unreferencing its model if that point
681 * was bound to a named pair (hence, possibly destroying the model
682 * if this was the last reference).
684 * The assignment is lazy so @pos could be not be present in @model.
685 * Anyway, at the first access to this point an error will be raised
686 * if the named pair is still missing.
688 void
689 adg_dim_set_pos_from_model(AdgDim *dim, AdgModel *model, const gchar *pos)
691 AdgPoint *point = adg_point_new();
693 adg_point_set_pair_from_model(point, model, pos);
694 adg_dim_set_pos(dim, point);
696 adg_point_destroy(point);
700 * adg_dim_get_pos:
701 * @dim: an #AdgDim
703 * Gets the #AdgDim:pos point. The returned point is internally owned
704 * and must not be freed or modified. Anyway, it is not const because
705 * adg_point_get_pair() must be able to modify the internal cache of
706 * the returned point.
708 * Returns: the position point
710 AdgPoint *
711 adg_dim_get_pos(AdgDim *dim)
713 AdgDimPrivate *data;
715 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
717 data = dim->data;
719 return data->pos;
723 * adg_dim_set_level:
724 * @dim: an #AdgDim
725 * @level: the new level
727 * Sets a new level for this dimension. The level is used to
728 * stack the quotes using a spacing value from dim_style
729 * (specified in global space).
731 void
732 adg_dim_set_level(AdgDim *dim, gdouble level)
734 AdgDimPrivate *data;
736 g_return_if_fail(ADG_IS_DIM(dim));
738 data = dim->data;
739 data->level = level;
741 g_object_notify((GObject *) dim, "level");
745 * adg_dim_get_level:
746 * @dim: an #AdgDim
748 * Gets the level of this dimension.
750 * Returns: the level value
752 gdouble
753 adg_dim_get_level(AdgDim *dim)
755 AdgDimPrivate *data;
757 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
759 data = dim->data;
761 return data->level;
765 * adg_dim_set_outside:
766 * @dim: an #AdgDim
767 * @outside: the new outside state
769 * Sets a new state for the #AdgDim:outside flag: check the property
770 * documentation for further details.
772 void
773 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
775 g_return_if_fail(ADG_IS_DIM(dim));
777 if (_adg_set_outside(dim, outside))
778 g_object_notify((GObject *) dim, "outside");
782 * adg_dim_get_outside:
783 * @dim: an #AdgDim
785 * Gets the state of the #AdgDim:outside property: check the property
786 * documentation for further details.
788 * Returns: the current flag state
790 AdgThreeState
791 adg_dim_get_outside(AdgDim *dim)
793 AdgDimPrivate *data;
795 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
797 data = dim->data;
799 return data->outside;
803 * adg_dim_set_detached:
804 * @dim: an #AdgDim
805 * @detached: the new detached state
807 * Sets a new state for the #AdgDim:detached flag: check the property
808 * documentation for further details.
810 * This is used only by dimensions where detaching has meaning.
811 * In some cases, such as with #AdgRDim dimensions, this property is
812 * not used.
814 void
815 adg_dim_set_detached(AdgDim *dim, AdgThreeState detached)
817 g_return_if_fail(ADG_IS_DIM(dim));
819 if (_adg_set_detached(dim, detached))
820 g_object_notify((GObject *) dim, "detached");
824 * adg_dim_get_detached:
825 * @dim: an #AdgDim
827 * Gets the state of the #AdgDim:detached property: check the property
828 * documentation for further details.
830 * Returns: the current flag state
832 AdgThreeState
833 adg_dim_get_detached(AdgDim *dim)
835 AdgDimPrivate *data;
837 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
839 data = dim->data;
841 return data->detached;
845 * adg_dim_set_value:
846 * @dim: an #AdgDim
847 * @value: the value text
849 * Explicitely sets the text to use as value. If @value is %NULL or
850 * was never set, an automatic text is calculated using the format
851 * specified in the current #AdgDimStyle and getting its value by
852 * calling the default_value() virtual method.
854 void
855 adg_dim_set_value(AdgDim *dim, const gchar *value)
857 g_return_if_fail(ADG_IS_DIM(dim));
859 if (_adg_set_value(dim, value))
860 g_object_notify((GObject *) dim, "value");
864 * adg_dim_get_value:
865 * @dim: an #AdgDim
867 * Gets the value text. The string is internally owned and
868 * must not be freed or modified.
870 * Returns: the value text
872 const gchar *
873 adg_dim_get_value(AdgDim *dim)
875 AdgDimPrivate *data;
877 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
879 data = dim->data;
881 return data->value;
885 * adg_dim_set_limits:
886 * @dim: an #AdgDim
887 * @min: the new minumum value
888 * @max: the new maximum value
890 * Shortcut to set both the limits at once.
892 void
893 adg_dim_set_limits(AdgDim *dim, const gchar *min, const gchar *max)
895 g_return_if_fail(ADG_IS_DIM(dim));
897 g_object_freeze_notify((GObject *) dim);
898 adg_dim_set_min(dim, min);
899 adg_dim_set_max(dim, max);
900 g_object_thaw_notify((GObject *) dim);
904 * adg_dim_set_min:
905 * @dim: an #AdgDim
906 * @min: the new minimum limit
908 * Sets the minimum value. Use %NULL as @min to disable it.
910 void
911 adg_dim_set_min(AdgDim *dim, const gchar *min)
913 g_return_if_fail(ADG_IS_DIM(dim));
915 if (_adg_set_min(dim, min))
916 g_object_notify((GObject *) dim, "min");
920 * adg_dim_get_min:
921 * @dim: an #AdgDim
923 * Gets the minimum value text or %NULL on minimum value disabled.
924 * The string is internally owned and must not be freed or modified.
926 * Returns: the mimimum value text
928 const gchar *
929 adg_dim_get_min(AdgDim *dim)
931 AdgDimPrivate *data;
933 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
935 data = dim->data;
937 return data->min;
941 * adg_dim_set_max:
942 * @dim: an #AdgDim
943 * @max: the new maximum value
945 * Sets the maximum value. Use %NULL as @max to disable it.
947 void
948 adg_dim_set_max(AdgDim *dim, const gchar *max)
950 g_return_if_fail(ADG_IS_DIM(dim));
952 if (_adg_set_max(dim, max))
953 g_object_notify((GObject *) dim, "max");
957 * adg_dim_get_max:
958 * @dim: an #AdgDim
960 * Gets the maximum value text or %NULL on maximum value disabled.
961 * The string is internally owned and must not be freed or modified.
963 * Returns: the maximum value text
965 const gchar *
966 adg_dim_get_max(AdgDim *dim)
968 AdgDimPrivate *data;
970 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
972 data = dim->data;
974 return data->max;
978 * adg_dim_get_quote:
979 * @dim: an #AdgDim
981 * <note><para>
982 * This function is only useful in new dimension implementations.
983 * </para></note>
985 * Gets the quote entity, if any. This function is valid only after
986 * the #AdgDim implementation of the arrange() virtual method has
987 * been called.
989 * Returns: the quote entity
991 AdgAlignment *
992 adg_dim_get_quote(AdgDim *dim)
994 AdgDimPrivate *data;
996 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
998 data = dim->data;
1000 return data->quote.entity;
1004 * adg_dim_quote_angle:
1005 * @dim: an #AdgDim
1006 * @angle: an angle (in radians)
1008 * <note><para>
1009 * This function is only useful in new dimension implementations.
1010 * </para></note>
1012 * Converts @angle accordling to the style of @dim. Any quote angle
1013 * should be validated by this method because every dimensioning
1014 * style has its own convention regardling the text rotation.
1016 * Returns: the angle to use (always in radians)
1018 gdouble
1019 adg_dim_quote_angle(AdgDim *dim, gdouble angle)
1021 AdgDimClass *klass;
1023 g_return_val_if_fail(ADG_IS_DIM(dim), angle);
1025 klass = ADG_DIM_GET_CLASS(dim);
1027 if (klass->quote_angle == NULL)
1028 return angle;
1030 return klass->quote_angle(angle);
1034 static void
1035 _adg_global_changed(AdgEntity *entity)
1037 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1039 if (PARENT_ENTITY_CLASS->global_changed)
1040 PARENT_ENTITY_CLASS->global_changed(entity);
1042 if (data->quote.entity != NULL)
1043 adg_entity_global_changed((AdgEntity *) data->quote.entity);
1046 static void
1047 _adg_local_changed(AdgEntity *entity)
1049 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1051 if (PARENT_ENTITY_CLASS->local_changed)
1052 PARENT_ENTITY_CLASS->local_changed(entity);
1054 if (data->quote.entity != NULL)
1055 adg_entity_local_changed((AdgEntity *) data->quote.entity);
1058 static void
1059 _adg_invalidate(AdgEntity *entity)
1061 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1063 if (PARENT_ENTITY_CLASS->invalidate)
1064 PARENT_ENTITY_CLASS->invalidate(entity);
1066 if (data->quote.entity != NULL)
1067 adg_entity_invalidate((AdgEntity *) data->quote.entity);
1069 adg_point_invalidate(data->ref1);
1070 adg_point_invalidate(data->ref2);
1071 adg_point_invalidate(data->pos);
1074 static void
1075 _adg_arrange(AdgEntity *entity)
1077 AdgDim *dim;
1078 AdgDimPrivate *data;
1079 AdgEntity *quote_entity;
1080 AdgContainer *quote_container;
1081 AdgEntity *value_entity;
1082 AdgEntity *min_entity;
1083 AdgEntity *max_entity;
1084 const AdgPair *shift;
1085 AdgMatrix map;
1087 dim = (AdgDim *) entity;
1088 data = dim->data;
1090 /* Resolve the dim style */
1091 if (data->dim_style == NULL)
1092 data->dim_style = (AdgDimStyle *)
1093 adg_entity_style(entity, data->dim_dress);
1095 if (data->quote.entity == NULL)
1096 data->quote.entity = g_object_new(ADG_TYPE_ALIGNMENT,
1097 "local-method", ADG_MIX_NONE,
1098 "parent", dim, NULL);
1100 quote_entity = (AdgEntity *) data->quote.entity;
1101 quote_container = (AdgContainer *) data->quote.entity;
1103 if (data->quote.value == NULL) {
1104 AdgDress dress = adg_dim_style_get_value_dress(data->dim_style);
1106 data->quote.value = g_object_new(ADG_TYPE_TOY_TEXT,
1107 "local-method", ADG_MIX_PARENT,
1108 "font-dress", dress, NULL);
1110 adg_container_add(quote_container, (AdgEntity *) data->quote.value);
1112 if (data->value) {
1113 adg_toy_text_set_label(data->quote.value, data->value);
1114 } else {
1115 AdgDimClass *klass = ADG_DIM_GET_CLASS(dim);
1117 if (klass->default_value) {
1118 /* Automatically generate the value text */
1119 gchar *text = klass->default_value(dim);
1120 adg_toy_text_set_label(data->quote.value, text);
1121 g_free(text);
1126 if (data->quote.min == NULL && data->min != NULL) {
1127 AdgDress dress = adg_dim_style_get_min_dress(data->dim_style);
1129 data->quote.min = g_object_new(ADG_TYPE_TOY_TEXT,
1130 "local-method", ADG_MIX_PARENT,
1131 "font-dress", dress, NULL);
1133 adg_container_add(quote_container, (AdgEntity *) data->quote.min);
1134 adg_toy_text_set_label(data->quote.min, data->min);
1137 if (data->quote.max == NULL && data->max != NULL) {
1138 AdgDress dress = adg_dim_style_get_max_dress(data->dim_style);
1140 data->quote.max = g_object_new(ADG_TYPE_TOY_TEXT,
1141 "local-method", ADG_MIX_PARENT,
1142 "font-dress", dress, NULL);
1144 adg_container_add(quote_container, (AdgEntity *) data->quote.max);
1145 adg_toy_text_set_label(data->quote.max, data->max);
1148 value_entity = (AdgEntity *) data->quote.value;
1149 min_entity = (AdgEntity *) data->quote.min;
1150 max_entity = (AdgEntity *) data->quote.max;
1151 shift = adg_dim_style_get_quote_shift(data->dim_style);
1153 adg_entity_set_global_map(quote_entity, adg_matrix_identity());
1154 adg_entity_global_changed(quote_entity);
1156 cairo_matrix_init_translate(&map, shift->x, shift->y);
1157 adg_entity_set_global_map(value_entity, &map);
1158 adg_entity_arrange(value_entity);
1160 /* Limit values (min and max) */
1161 if (min_entity != NULL || max_entity != NULL) {
1162 const CpmlExtents *extents = adg_entity_get_extents(value_entity);
1163 //CpmlExtents min_extents = { 0 };
1164 //CpmlExtents max_extents = { 0 };
1165 const AdgPair *limits_shift = adg_dim_style_get_limits_shift(data->dim_style);
1167 #if 0
1168 if (min_entity != NULL)
1169 cpml_extents_copy(&min_extents, adg_entity_get_extents(min_entity));
1171 if (max_entity != NULL)
1172 cpml_extents_copy(&max_extents, adg_entity_get_extents(max_entity));
1174 if (min_entity != NULL && max_entity != NULL)
1175 spacing = adg_dim_style_get_limits_spacing(data->dim_style);
1177 cairo_matrix_init_translate(&map,
1178 extents->size.x +
1179 shift->x + limit_shift->x,
1180 (spacing + min_extents.size.y +
1181 max_extents.size.y - extents->size.y) / 2 +
1182 shift->y + limit_shift->y);
1183 #endif
1184 cairo_matrix_init_translate(&map, extents->size.x + limits_shift->x,
1185 -extents->size.y / 2 + limits_shift->y);
1187 if (min_entity != NULL) {
1188 adg_entity_set_global_map(min_entity, &map);
1189 adg_entity_arrange(min_entity);
1190 extents = adg_entity_get_extents(min_entity);
1191 map.y0 -= extents->size.y +
1192 adg_dim_style_get_limits_spacing(data->dim_style);
1195 if (max_entity != NULL) {
1196 adg_entity_set_global_map(max_entity, &map);
1197 adg_entity_arrange(max_entity);
1201 adg_entity_arrange(quote_entity);
1204 static gchar *
1205 _adg_default_value(AdgDim *dim)
1207 g_warning("AdgDim::default_value not implemented for `%s'",
1208 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
1209 return g_strdup("undef");
1212 static gdouble
1213 _adg_quote_angle(gdouble angle)
1215 angle = cpml_angle(angle);
1217 if (angle > G_PI_4 * 4 / 3 || angle <= -G_PI_4 * 3)
1218 angle = cpml_angle(angle + G_PI);
1220 return angle;
1223 static gboolean
1224 _adg_set_outside(AdgDim *dim, AdgThreeState outside)
1226 AdgDimPrivate *data;
1228 g_return_val_if_fail(adg_is_enum_value(outside, ADG_TYPE_THREE_STATE),
1229 FALSE);
1231 data = dim->data;
1233 if (data->outside == outside)
1234 return FALSE;
1236 data->outside = outside;
1238 return TRUE;
1241 static gboolean
1242 _adg_set_detached(AdgDim *dim, AdgThreeState detached)
1244 AdgDimPrivate *data;
1246 g_return_val_if_fail(adg_is_enum_value(detached, ADG_TYPE_THREE_STATE),
1247 FALSE);
1249 data = dim->data;
1251 if (data->detached == detached)
1252 return FALSE;
1254 data->detached = detached;
1256 return TRUE;
1259 static gboolean
1260 _adg_set_value(AdgDim *dim, const gchar *value)
1262 AdgDimPrivate *data;
1264 data = dim->data;
1266 if (g_strcmp0(value, data->value) == 0)
1267 return FALSE;
1269 g_free(data->value);
1270 data->value = g_strdup(value);
1272 if (data->quote.value != NULL) {
1273 g_object_unref(data->quote.value);
1274 data->quote.value = NULL;
1277 return TRUE;
1280 static gboolean
1281 _adg_set_min(AdgDim *dim, const gchar *min)
1283 AdgDimPrivate *data = dim->data;
1285 if (g_strcmp0(min, data->min) == 0)
1286 return FALSE;
1288 g_free(data->min);
1289 data->min = g_strdup(min);
1291 if (data->quote.min != NULL) {
1292 g_object_unref(data->quote.min);
1293 data->quote.min = NULL;
1296 return TRUE;
1299 static gboolean
1300 _adg_set_max(AdgDim *dim, const gchar *max)
1302 AdgDimPrivate *data = dim->data;
1304 if (g_strcmp0(max, data->max) == 0)
1305 return FALSE;
1307 g_free(data->max);
1308 data->max = g_strdup(max);
1310 if (data->quote.max != NULL) {
1311 g_object_unref(data->quote.max);
1312 data->quote.max = NULL;
1315 return TRUE;