[AdgDim] Dress name mangling and code cleanup
[adg.git] / adg / adg-dim.c
blob381b3e07750f1e4eee1f24c18a5839fa12255396
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 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-dim.h"
37 #include "adg-dim-private.h"
38 #include "adg-dim-style.h"
39 #include "adg-dress-builtins.h"
40 #include "adg-toy-text.h"
41 #include "adg-type-builtins.h"
42 #include "adg-intl.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_VALUE,
57 PROP_MIN,
58 PROP_MAX
62 static void dispose (GObject *object);
63 static void finalize (GObject *object);
64 static void get_property (GObject *object,
65 guint param_id,
66 GValue *value,
67 GParamSpec *pspec);
68 static void set_property (GObject *object,
69 guint param_id,
70 const GValue *value,
71 GParamSpec *pspec);
72 static void global_changed (AdgEntity *entity);
73 static void local_changed (AdgEntity *entity);
74 static void invalidate (AdgEntity *entity);
75 static void arrange (AdgEntity *entity);
76 static gchar * default_value (AdgDim *dim);
77 static gdouble quote_angle (gdouble angle);
78 static gboolean set_dim_dress (AdgDim *dim,
79 AdgDress dress);
80 static gboolean set_value (AdgDim *dim,
81 const gchar *value);
82 static gboolean set_min (AdgDim *dim,
83 const gchar *min);
84 static gboolean set_max (AdgDim *dim,
85 const gchar *max);
88 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY);
91 static void
92 adg_dim_class_init(AdgDimClass *klass)
94 GObjectClass *gobject_class;
95 AdgEntityClass *entity_class;
96 GParamSpec *param;
98 gobject_class = (GObjectClass *) klass;
99 entity_class = (AdgEntityClass *) klass;
101 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
103 gobject_class->dispose = dispose;
104 gobject_class->finalize = finalize;
105 gobject_class->get_property = get_property;
106 gobject_class->set_property = set_property;
108 entity_class->global_changed = global_changed;
109 entity_class->local_changed = local_changed;
110 entity_class->invalidate = invalidate;
111 entity_class->arrange = arrange;
113 klass->quote_angle = quote_angle;
114 klass->default_value = default_value;
116 param = adg_param_spec_dress("dim-dress",
117 P_("Dress Style"),
118 P_("The dress to use for rendering this dimension"),
119 ADG_DRESS_DIMENSION,
120 G_PARAM_READWRITE);
121 g_object_class_install_property(gobject_class, PROP_DIM_DRESS, param);
123 param = g_param_spec_boxed("ref1",
124 P_("Reference 1"),
125 P_("First reference point of the dimension"),
126 ADG_TYPE_PAIR,
127 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
128 g_object_class_install_property(gobject_class, PROP_REF1, param);
130 param = g_param_spec_boxed("ref2",
131 P_("Reference 2"),
132 P_("Second reference point of the dimension"),
133 ADG_TYPE_PAIR,
134 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
135 g_object_class_install_property(gobject_class, PROP_REF2, param);
137 param = g_param_spec_boxed("pos",
138 P_("Position"),
139 P_("The reference position in local space of the quote: it will be combined with \"level\" to get the real quote position"),
140 ADG_TYPE_PAIR, G_PARAM_READWRITE);
141 g_object_class_install_property(gobject_class, PROP_POS, param);
143 param = g_param_spec_double("level",
144 P_("Level"),
145 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"),
146 -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
147 G_PARAM_READWRITE);
148 g_object_class_install_property(gobject_class, PROP_LEVEL, param);
150 param = g_param_spec_enum("outside",
151 P_("Outside"),
152 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"),
153 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
154 G_PARAM_READWRITE);
155 g_object_class_install_property(gobject_class, PROP_OUTSIDE, param);
157 param = g_param_spec_string("value",
158 P_("Basic Value"),
159 P_("The theoretically exact value for this quote: set to NULL to automatically get the default value"),
160 NULL, G_PARAM_READWRITE);
161 g_object_class_install_property(gobject_class, PROP_VALUE, param);
163 param = g_param_spec_string("value-min",
164 P_("Minimum Value or Low Tolerance"),
165 P_("The minimum value allowed or the lowest tolerance from value (depending of the dimension style): set to NULL to suppress"),
166 NULL, G_PARAM_READWRITE);
167 g_object_class_install_property(gobject_class, PROP_MIN, param);
169 param = g_param_spec_string("value-max",
170 P_("Maximum Value or High Tolerance"),
171 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
172 NULL, G_PARAM_READWRITE);
173 g_object_class_install_property(gobject_class, PROP_MAX, param);
176 static void
177 adg_dim_init(AdgDim *dim)
179 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
180 AdgDimPrivate);
182 data->dim_dress = ADG_DRESS_DIMENSION;
183 data->ref1.x = data->ref1.y = 0;
184 data->ref2.x = data->ref2.y = 0;
185 data->pos.x = data->pos.y = 0;
186 data->level = 1;
187 data->outside = ADG_THREE_STATE_UNKNOWN;
188 data->value = NULL;
189 data->min = NULL;
190 data->max = NULL;
192 dim->data = data;
195 static void
196 dispose(GObject *object)
198 AdgDimPrivate *data = ((AdgDim *) object)->data;
200 if (data->quote.container != NULL) {
201 g_object_unref(data->quote.container);
202 data->quote.container = NULL;
205 if (PARENT_OBJECT_CLASS->dispose != NULL)
206 PARENT_OBJECT_CLASS->dispose(object);
209 static void
210 finalize(GObject *object)
212 AdgDimPrivate *data = ((AdgDim *) object)->data;
214 g_free(data->value);
215 g_free(data->min);
216 g_free(data->max);
218 if (PARENT_OBJECT_CLASS->finalize != NULL)
219 PARENT_OBJECT_CLASS->finalize(object);
222 static void
223 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
225 AdgDimPrivate *data = ((AdgDim *) object)->data;
227 switch (prop_id) {
228 case PROP_DIM_DRESS:
229 g_value_set_int(value, data->dim_dress);
230 break;
231 case PROP_REF1:
232 g_value_set_boxed(value, &data->ref1);
233 break;
234 case PROP_REF2:
235 g_value_set_boxed(value, &data->ref2);
236 break;
237 case PROP_POS:
238 g_value_set_boxed(value, &data->pos);
239 break;
240 case PROP_LEVEL:
241 g_value_set_double(value, data->level);
242 break;
243 case PROP_OUTSIDE:
244 g_value_set_enum(value, data->outside);
245 break;
246 case PROP_VALUE:
247 g_value_set_string(value, data->value);
248 break;
249 case PROP_MIN:
250 g_value_set_string(value, data->min);
251 break;
252 case PROP_MAX:
253 g_value_set_string(value, data->max);
254 break;
255 default:
256 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
257 break;
261 static void
262 set_property(GObject *object, guint prop_id,
263 const GValue *value, GParamSpec *pspec)
265 AdgDim *dim;
266 AdgDimPrivate *data;
268 dim = (AdgDim *) object;
269 data = dim->data;
271 switch (prop_id) {
272 case PROP_DIM_DRESS:
273 set_dim_dress(dim, g_value_get_int(value));
274 break;
275 case PROP_REF1:
276 cpml_pair_copy(&data->ref1, (AdgPair *) g_value_get_boxed(value));
277 break;
278 case PROP_REF2:
279 cpml_pair_copy(&data->ref2, (AdgPair *) g_value_get_boxed(value));
280 break;
281 case PROP_POS:
282 cpml_pair_copy(&data->pos, (AdgPair *) g_value_get_boxed(value));
283 break;
284 case PROP_LEVEL:
285 data->level = g_value_get_double(value);
286 break;
287 case PROP_OUTSIDE:
288 data->outside = g_value_get_enum(value);
289 break;
290 case PROP_VALUE:
291 set_value(dim, g_value_get_string(value));
292 break;
293 case PROP_MIN:
294 set_min(dim, g_value_get_string(value));
295 break;
296 case PROP_MAX:
297 set_max(dim, g_value_get_string(value));
298 break;
299 default:
300 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
301 break;
307 * adg_dim_get_dim_dress:
308 * @dim: an #AdgDim
310 * Gets the dimension dress to be used in rendering @dim.
312 * Returns: the current dimension dress
314 AdgDress
315 adg_dim_get_dim_dress(AdgDim *dim)
317 AdgDimPrivate *data;
319 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_DRESS_UNDEFINED);
321 data = dim->data;
323 return data->dim_dress;
327 * adg_dim_set_dim_dress:
328 * @dim: an #AdgDim
329 * @dress: the new #AdgDress to use
331 * Sets a new dimension dress to @dim. The new dress must be
332 * related to the original dress for this property: you cannot
333 * set a dress used for line styles to a dress managing fonts.
335 * The check is done by calling adg_dress_are_related() with
336 * @dress and the previous dress as arguments. Check out its
337 * documentation for details on what is a related dress.
339 void
340 adg_dim_set_dim_dress(AdgDim *dim, AdgDress dress)
342 g_return_if_fail(ADG_IS_DIM(dim));
344 if (set_dim_dress(dim, dress))
345 g_object_notify((GObject *) dim, "dim-dress");
349 * adg_dim_get_ref1:
350 * @dim: an #AdgDim
352 * Gets the ref1 coordinates. The returned pair is internally owned
353 * and must not be freed or modified.
355 * Returns: the ref1 coordinates
357 const AdgPair *
358 adg_dim_get_ref1(AdgDim *dim)
360 AdgDimPrivate *data;
362 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
364 data = dim->data;
366 return &data->ref1;
370 * adg_dim_get_ref2:
371 * @dim: an #AdgDim
373 * Gets the ref2 coordinates. The returned pair is internally owned
374 * and must not be freed or modified.
376 * Returns: the ref2 coordinates
378 const AdgPair *
379 adg_dim_get_ref2(AdgDim *dim)
381 AdgDimPrivate *data;
383 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
385 data = dim->data;
387 return &data->ref2;
391 * adg_dim_set_ref:
392 * @dim: an #AdgDim
393 * @ref1: the ref1 coordinates
394 * @ref2: the ref2 coordinates
396 * Shortcut to set ref1 and ref2 points at once.
398 void
399 adg_dim_set_ref(AdgDim *dim, const AdgPair *ref1, const AdgPair *ref2)
401 g_return_if_fail(ADG_IS_DIM(dim));
403 if (ref1 != NULL || ref2 != NULL) {
404 GObject *object;
405 AdgDimPrivate *data;
407 data = dim->data;
408 object = (GObject *) dim;
410 g_object_freeze_notify(object);
412 if (ref1 != NULL) {
413 data->ref1 = *ref1;
414 g_object_notify(object, "ref1");
417 if (ref2 != NULL) {
418 data->ref2 = *ref2;
419 g_object_notify(object, "ref2");
422 g_object_thaw_notify(object);
427 * adg_dim_set_ref_explicit:
428 * @dim: an #AdgDim
429 * @ref1_x: x coordinate of ref1
430 * @ref1_y: y coordinate of ref1
431 * @ref2_x: x coordinate of ref2
432 * @ref2_y: y coordinate of ref2
434 * Shortcut to set ref1 and ref2 points at once,
435 * using explicit coordinates.
437 void
438 adg_dim_set_ref_explicit(AdgDim *dim, gdouble ref1_x, gdouble ref1_y,
439 gdouble ref2_x, gdouble ref2_y)
441 AdgPair ref1;
442 AdgPair ref2;
444 ref1.x = ref1_x;
445 ref1.y = ref1_y;
446 ref2.x = ref2_x;
447 ref2.y = ref2_y;
449 adg_dim_set_ref(dim, &ref1, &ref2);
453 * adg_dim_get_pos:
454 * @dim: an #AdgDim
456 * Gets the position coordinates. The returned pair is internally owned
457 * and must not be freed or modified.
459 * Returns: the pos coordinates
461 const AdgPair *
462 adg_dim_get_pos(AdgDim *dim)
464 AdgDimPrivate *data;
466 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
468 data = dim->data;
470 return &data->pos;
474 * adg_dim_set_pos:
475 * @dim: an #AdgDim
476 * @pos: the pos coordinates
478 * Sets a new #AdgDim:pos position.
480 void
481 adg_dim_set_pos(AdgDim *dim, const AdgPair *pos)
483 AdgDimPrivate *data;
485 g_return_if_fail(ADG_IS_DIM(dim));
486 g_return_if_fail(pos != NULL);
488 data = dim->data;
490 data->pos = *pos;
492 g_object_notify((GObject *) dim, "pos");
496 * adg_dim_set_pos_explicit:
497 * @dim: an #AdgDim
498 * @pos_x: x coordinate of pos
499 * @pos_y: y coordinate of pos
501 * Shortcut to set #AdgDim:pos using explicit coordinates.
503 void
504 adg_dim_set_pos_explicit(AdgDim *dim, gdouble x, gdouble y)
506 AdgPair pos;
508 pos.x = x;
509 pos.y = y;
511 adg_dim_set_pos(dim, &pos);
515 * adg_dim_get_level:
516 * @dim: an #AdgDim
518 * Gets the level of this dimension.
520 * Returns: the level value
522 gdouble
523 adg_dim_get_level(AdgDim *dim)
525 AdgDimPrivate *data;
527 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
529 data = dim->data;
531 return data->level;
535 * adg_dim_set_level:
536 * @dim: an #AdgDim
537 * @level: the new level
539 * Sets a new level for this dimension. The level is used to
540 * stack the quotes using a spacing value from dim_style
541 * (specified in global space).
543 void
544 adg_dim_set_level(AdgDim *dim, gdouble level)
546 AdgDimPrivate *data;
548 g_return_if_fail(ADG_IS_DIM(dim));
550 data = dim->data;
551 data->level = level;
553 g_object_notify((GObject *) dim, "level");
557 * adg_dim_get_outside:
558 * @dim: an #AdgDim
560 * Gets the state of the #AdgDim:outside property: check the property
561 * documentation for further details.
563 * Returns: the current flag state
565 AdgThreeState
566 adg_dim_get_outside(AdgDim *dim)
568 AdgDimPrivate *data;
570 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
572 data = dim->data;
574 return data->outside;
578 * adg_dim_set_outside:
579 * @dim: an #AdgDim
580 * @outside: the new outside state
582 * Sets a new state for the #AdgDim:outside flag: check the property
583 * documentation for further details.
585 void
586 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
588 AdgDimPrivate *data;
590 g_return_if_fail(ADG_IS_DIM(dim));
592 data = dim->data;
593 data->outside = outside;
595 g_object_notify((GObject *) dim, "outside");
599 * adg_dim_get_value:
600 * @dim: an #AdgDim
602 * Gets the value text. The string is internally owned and
603 * must not be freed or modified.
605 * Returns: the value text
607 const gchar *
608 adg_dim_get_value(AdgDim *dim)
610 AdgDimPrivate *data;
612 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
614 data = dim->data;
616 return data->value;
620 * adg_dim_set_value:
621 * @dim: an #AdgDim
622 * @value: the value text
624 * Explicitely sets the text to use as value. If @value is %NULL or
625 * was never set, an automatic text is calculated using the format
626 * specified in the current #AdgDimStyle and getting its value by
627 * calling the default_value() virtual method.
629 void
630 adg_dim_set_value(AdgDim *dim, const gchar *value)
632 g_return_if_fail(ADG_IS_DIM(dim));
634 if (set_value(dim, value))
635 g_object_notify((GObject *) dim, "value");
639 * adg_dim_get_min:
640 * @dim: an #AdgDim
642 * Gets the minimum value text or %NULL on minimum value disabled.
643 * The string is internally owned and must not be freed or modified.
645 * Returns: the mimimum value text
647 const gchar *
648 adg_dim_get_min(AdgDim *dim)
650 AdgDimPrivate *data;
652 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
654 data = dim->data;
656 return data->min;
660 * adg_dim_set_min:
661 * @dim: an #AdgDim
662 * @min: the new minimum limit
664 * Sets the minimum value. Use %NULL as @min to disable it.
666 void
667 adg_dim_set_min(AdgDim *dim, const gchar *min)
669 g_return_if_fail(ADG_IS_DIM(dim));
671 if (set_min(dim, min))
672 g_object_notify((GObject *) dim, "value-min");
676 * adg_dim_get_max:
677 * @dim: an #AdgDim
679 * Gets the maximum value text or %NULL on maximum value disabled.
680 * The string is internally owned and must not be freed or modified.
682 * Returns: the maximum value text
684 const gchar *
685 adg_dim_get_max(AdgDim *dim)
687 AdgDimPrivate *data;
689 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
691 data = dim->data;
693 return data->max;
697 * adg_dim_set_max:
698 * @dim: an #AdgDim
699 * @max: the new maximum value
701 * Sets the maximum value. Use %NULL as @max to disable it.
703 void
704 adg_dim_set_max(AdgDim *dim, const gchar *max)
706 g_return_if_fail(ADG_IS_DIM(dim));
708 if (set_max(dim, max))
709 g_object_notify((GObject *) dim, "value-max");
713 * adg_dim_set_limits:
714 * @dim: an #AdgDim
715 * @min: the new minumum value
716 * @max: the new maximum value
718 * Shortcut to set both the limits at once.
720 void
721 adg_dim_set_limits(AdgDim *dim, const gchar *min, const gchar *max)
723 g_return_if_fail(ADG_IS_DIM(dim));
725 g_object_freeze_notify((GObject *) dim);
726 adg_dim_set_min(dim, min);
727 adg_dim_set_max(dim, max);
728 g_object_thaw_notify((GObject *) dim);
732 * adg_dim_get_quote:
733 * @dim: an #AdgDim
735 * <note><para>
736 * This function is only useful in new dimension implementations.
737 * </para></note>
739 * Gets the quote container, if any. This function is valid only
740 * after the #AdgDim implementation of the arrange() virtual method
741 * has been called.
743 * Returns: the quote container
745 AdgContainer *
746 adg_dim_get_quote(AdgDim *dim)
748 AdgDimPrivate *data;
750 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
752 data = dim->data;
754 return data->quote.container;
758 * adg_dim_quote_angle:
759 * @dim: an #AdgDim
760 * @angle: an angle (in radians)
762 * <note><para>
763 * This function is only useful in new dimension implementations.
764 * </para></note>
766 * Converts @angle accordling to the style of @dim. Any quote angle
767 * should be validated by this method because every dimensioning
768 * style has its own convention regardling the text rotation.
770 * Returns: the angle to use (always in radians)
772 gdouble
773 adg_dim_quote_angle(AdgDim *dim, gdouble angle)
775 AdgDimClass *klass;
777 g_return_val_if_fail(ADG_IS_DIM(dim), angle);
779 klass = ADG_DIM_GET_CLASS(dim);
781 if (klass->quote_angle == NULL)
782 return angle;
784 return klass->quote_angle(angle);
788 * _adg_dim_get_dim_style:
789 * @dim: an #AdgDim entity
791 * Gets the #AdgDimStyle associated to @dim. The dress to style
792 * resolution is done in the arrange() method so this value is
793 * typically available in render() or in a derived arrange()
794 * method, after the #AdgDim arrange() function has been chained up.
796 * Returns: the dim style of @entity
798 AdgDimStyle *
799 _adg_dim_get_dim_style(AdgDim *dim)
801 AdgDimPrivate *data;
803 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
805 data = dim->data;
807 return data->dim_style;
811 static void
812 arrange(AdgEntity *entity)
814 AdgDim *dim;
815 AdgDimPrivate *data;
816 AdgEntity *container_entity;
817 AdgEntity *value_entity;
818 AdgEntity *min_entity;
819 AdgEntity *max_entity;
820 CpmlExtents extents;
821 AdgMatrix map;
822 const AdgPair *shift;
824 dim = (AdgDim *) entity;
825 data = dim->data;
827 /* Resolve the dim style */
828 if (data->dim_style == NULL)
829 data->dim_style = (AdgDimStyle *) adg_entity_style(entity,
830 data->dim_dress);
832 if (data->quote.container == NULL)
833 data->quote.container = g_object_new(ADG_TYPE_CONTAINER,
834 "parent", dim, NULL);
836 if (data->quote.value == NULL) {
837 AdgDress dress = adg_dim_style_get_value_dress(data->dim_style);
839 data->quote.value = g_object_new(ADG_TYPE_TOY_TEXT,
840 "dress", dress, NULL);
842 adg_container_add(data->quote.container,
843 (AdgEntity *) data->quote.value);
845 if (data->value == NULL) {
846 /* Automatically generate the value text */
847 gchar *text = ADG_DIM_GET_CLASS(dim)->default_value(dim);
848 adg_toy_text_set_label(data->quote.value, text);
849 g_free(text);
850 } else {
851 adg_toy_text_set_label(data->quote.value, data->value);
855 if (data->quote.min == NULL && data->min != NULL) {
856 AdgDress dress = adg_dim_style_get_min_dress(data->dim_style);
858 data->quote.min = g_object_new(ADG_TYPE_TOY_TEXT, "dress", dress, NULL);
860 adg_container_add(data->quote.container, (AdgEntity *) data->quote.min);
861 adg_toy_text_set_label(data->quote.min, data->min);
864 if (data->quote.max == NULL && data->max != NULL) {
865 AdgDress dress = adg_dim_style_get_max_dress(data->dim_style);
867 data->quote.max = g_object_new(ADG_TYPE_TOY_TEXT, "dress", dress, NULL);
869 adg_container_add(data->quote.container, (AdgEntity *) data->quote.max);
870 adg_toy_text_set_label(data->quote.max, data->max);
873 container_entity = (AdgEntity *) data->quote.container;
874 value_entity = (AdgEntity *) data->quote.value;
875 min_entity = (AdgEntity *) data->quote.min;
876 max_entity = (AdgEntity *) data->quote.max;
878 /* Propagate the arrange signal to the quote container */
879 adg_entity_arrange(container_entity);
881 /* Basic value */
882 adg_entity_get_extents(value_entity, &extents);
884 /* Limit values (min and max) */
885 if (min_entity != NULL || max_entity != NULL) {
886 CpmlExtents min_extents = { 0 };
887 CpmlExtents max_extents = { 0 };
888 gdouble spacing = 0;
890 /* Minimum limit */
891 if (min_entity != NULL)
892 adg_entity_get_extents(min_entity, &min_extents);
894 /* Maximum limit */
895 if (max_entity != NULL)
896 adg_entity_get_extents(max_entity, &max_extents);
898 shift = adg_dim_style_get_limits_shift(data->dim_style);
899 if (min_entity != NULL && max_entity != NULL)
900 spacing = adg_dim_style_get_limits_spacing(data->dim_style);
902 cairo_matrix_init_translate(&map, extents.size.x + shift->x,
903 (spacing + min_extents.size.y +
904 max_extents.size.y) / 2 +
905 shift->y - extents.size.y / 2);
907 if (min_entity != NULL)
908 adg_entity_set_global_map(min_entity, &map);
910 if (max_entity != NULL) {
911 cairo_matrix_translate(&map, 0, -min_extents.size.y - spacing);
912 adg_entity_set_global_map(max_entity, &map);
915 extents.size.x += shift->x + MAX(min_extents.size.x, max_extents.size.x);
918 /* Center and apply the style displacements */
919 shift = adg_dim_style_get_quote_shift(data->dim_style);
920 cairo_matrix_init_translate(&map, shift->x - extents.size.x / 2, shift->y);
921 adg_entity_set_global_map(container_entity, &map);
923 adg_entity_arrange(container_entity);
926 static void
927 global_changed(AdgEntity *entity)
929 AdgDimPrivate *data = ((AdgDim *) entity)->data;
931 PARENT_ENTITY_CLASS->global_changed(entity);
933 if (data->quote.container != NULL)
934 adg_entity_global_changed((AdgEntity *) data->quote.container);
937 static void
938 local_changed(AdgEntity *entity)
940 AdgDimPrivate *data = ((AdgDim *) entity)->data;
942 PARENT_ENTITY_CLASS->local_changed(entity);
944 if (data->quote.container != NULL)
945 adg_entity_local_changed((AdgEntity *) data->quote.container);
948 static void
949 invalidate(AdgEntity *entity)
951 AdgDimPrivate *data = ((AdgDim *) entity)->data;
953 if (data->quote.container != NULL)
954 adg_entity_invalidate((AdgEntity *) data->quote.container);
957 static gchar *
958 default_value(AdgDim *dim)
960 g_warning("AdgDim::default_value not implemented for `%s'",
961 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
962 return g_strdup("undef");
965 static gdouble
966 quote_angle(gdouble angle)
968 angle = cpml_angle(angle);
970 if (angle > G_PI_4 * 4 / 3 || angle <= -G_PI_4 * 3)
971 angle = cpml_angle(angle + G_PI);
973 return angle;
976 static gboolean
977 set_dim_dress(AdgDim *dim, AdgDress dress)
979 AdgDimPrivate *data = dim->data;
981 if (adg_dress_set(&data->dim_dress, dress)) {
982 data->dim_style = NULL;
983 return TRUE;
986 return FALSE;
989 static gboolean
990 set_value(AdgDim *dim, const gchar *value)
992 AdgDimPrivate *data;
994 data = dim->data;
996 if (adg_strcmp(value, data->value) == 0)
997 return FALSE;
999 g_free(data->value);
1000 data->value = g_strdup(value);
1002 if (data->quote.value != NULL) {
1003 g_object_unref(data->quote.value);
1004 data->quote.value = NULL;
1007 return TRUE;
1010 static gboolean
1011 set_min(AdgDim *dim, const gchar *min)
1013 AdgDimPrivate *data = dim->data;
1015 if (adg_strcmp(min, data->min) == 0)
1016 return FALSE;
1018 g_free(data->min);
1019 data->min = g_strdup(min);
1021 if (data->quote.min != NULL) {
1022 g_object_unref(data->quote.min);
1023 data->quote.min = NULL;
1026 return TRUE;
1029 static gboolean
1030 set_max(AdgDim *dim, const gchar *max)
1032 AdgDimPrivate *data = dim->data;
1034 if (adg_strcmp(max, data->max) == 0)
1035 return FALSE;
1037 g_free(data->max);
1038 data->max = g_strdup(max);
1040 if (data->quote.max != NULL) {
1041 g_object_unref(data->quote.max);
1042 data->quote.max = NULL;
1045 return TRUE;