[docs] Updated TODO.xml
[adg.git] / adg / adg-dim.c
blob80f74be5fd623cefe99cb0dc21aeebc2b2d5115c
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-intl.h"
40 #include <string.h>
42 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_dim_parent_class)
45 enum {
46 PROP_0,
47 PROP_REF1,
48 PROP_REF2,
49 PROP_POS1,
50 PROP_POS2,
51 PROP_ANGLE,
52 PROP_LEVEL,
53 PROP_VALUE,
54 PROP_VALUE_MIN,
55 PROP_VALUE_MAX,
56 PROP_NOTE
60 static void dispose (GObject *object);
61 static void finalize (GObject *object);
62 static void get_property (GObject *object,
63 guint param_id,
64 GValue *value,
65 GParamSpec *pspec);
66 static void set_property (GObject *object,
67 guint param_id,
68 const GValue *value,
69 GParamSpec *pspec);
70 static gboolean invalidate (AdgEntity *entity);
71 static gchar * default_value (AdgDim *dim);
72 static void quote_layout (AdgDim *dim,
73 cairo_t *cr);
74 static gboolean set_value (AdgDim *dim,
75 const gchar *value);
76 static gboolean set_value_min (AdgDim *dim,
77 const gchar *value_min);
78 static gboolean set_value_max (AdgDim *dim,
79 const gchar *value_max);
80 static gboolean set_note (AdgDim *dim,
81 const gchar *note);
82 static void detach_entity (AdgEntity **p_entity);
85 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY);
88 static void
89 adg_dim_class_init(AdgDimClass *klass)
91 GObjectClass *gobject_class;
92 AdgEntityClass *entity_class;
93 GParamSpec *param;
95 gobject_class = (GObjectClass *) klass;
96 entity_class = (AdgEntityClass *) klass;
98 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
100 gobject_class->dispose = dispose;
101 gobject_class->finalize = finalize;
102 gobject_class->get_property = get_property;
103 gobject_class->set_property = set_property;
105 entity_class->invalidate = invalidate;
107 klass->default_value = default_value;
108 klass->quote_layout = quote_layout;
110 param = g_param_spec_boxed("ref1",
111 P_("Reference 1"),
112 P_("First reference point of the dimension"),
113 ADG_TYPE_PAIR,
114 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
115 g_object_class_install_property(gobject_class, PROP_REF1, param);
117 param = g_param_spec_boxed("ref2",
118 P_("Reference 2"),
119 P_("Second reference point of the dimension"),
120 ADG_TYPE_PAIR,
121 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
122 g_object_class_install_property(gobject_class, PROP_REF2, param);
124 param = g_param_spec_boxed("pos1",
125 P_("Position 1"),
126 P_("First position point: it will be computed with the level property to get the real dimension position"),
127 ADG_TYPE_PAIR, G_PARAM_READWRITE);
128 g_object_class_install_property(gobject_class, PROP_POS1, param);
130 param = g_param_spec_boxed("pos2",
131 P_("Position 2"),
132 P_("Second position point: it will be computed with the level property to get the real dimension position"),
133 ADG_TYPE_PAIR, G_PARAM_READWRITE);
134 g_object_class_install_property(gobject_class, PROP_POS2, param);
136 param = g_param_spec_double("angle",
137 P_("Angle"),
138 P_("The dimension direction, if relevant"),
139 -G_MAXDOUBLE, G_MAXDOUBLE, 0,
140 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
141 g_object_class_install_property(gobject_class, PROP_ANGLE, param);
143 param = g_param_spec_double("level",
144 P_("Level"),
145 P_("The dimension level, that is the factor to multiply dim_style->baseline_spacing to get the offset (in device units) from pos1..pos2 where render the dimension baseline"),
146 -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
147 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
148 g_object_class_install_property(gobject_class, PROP_LEVEL, param);
150 param = g_param_spec_string("value",
151 P_("Basic Value"),
152 P_("The theoretically exact value for this quote: set to NULL to automatically get the default value"),
153 NULL, G_PARAM_READWRITE);
154 g_object_class_install_property(gobject_class, PROP_VALUE, param);
156 param = g_param_spec_string("value-min",
157 P_("Minimum Value or Low Tolerance"),
158 P_("The minimum value allowed or the lowest tolerance from value (depending of the dimension style): set to NULL to suppress"),
159 NULL, G_PARAM_READWRITE);
160 g_object_class_install_property(gobject_class, PROP_VALUE_MIN, param);
162 param = g_param_spec_string("value-max",
163 P_("Maximum Value or High Tolerance"),
164 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
165 NULL, G_PARAM_READWRITE);
166 g_object_class_install_property(gobject_class, PROP_VALUE_MAX, param);
168 param = g_param_spec_string("note",
169 P_("Note"),
170 P_("A custom note appended to the end of the quote"),
171 NULL, G_PARAM_READWRITE);
172 g_object_class_install_property(gobject_class, PROP_NOTE, param);
175 static void
176 adg_dim_init(AdgDim *dim)
178 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
179 AdgDimPrivate);
181 data->ref1.x = data->ref1.y = 0;
182 data->ref2.x = data->ref2.y = 0;
183 data->pos1.x = data->pos1.y = 0;
184 data->pos2.x = data->pos2.y = 0;
185 data->angle = 0;
186 data->level = 1;
187 data->value = NULL;
188 data->value_min = NULL;
189 data->value_max = NULL;
190 data->note = NULL;
192 data->value_entity = g_object_new(ADG_TYPE_TOY_TEXT,
193 "parent", dim,
194 "font-style", ADG_FONT_STYLE_VALUE,
195 NULL);
196 data->value_min_entity = g_object_new(ADG_TYPE_TOY_TEXT,
197 "parent", dim,
198 "font-style", ADG_FONT_STYLE_TOLERANCE,
199 NULL);
200 data->value_max_entity = g_object_new(ADG_TYPE_TOY_TEXT,
201 "parent", dim,
202 "font-style", ADG_FONT_STYLE_TOLERANCE,
203 NULL);
204 data->note_entity = g_object_new(ADG_TYPE_TOY_TEXT,
205 "parent", dim,
206 "font-style", ADG_FONT_STYLE_NOTE,
207 NULL);
209 dim->data = data;
212 static void
213 dispose(GObject *object)
215 AdgDimPrivate *data = ((AdgDim *) object)->data;
217 detach_entity(&data->value_entity);
218 detach_entity(&data->value_min_entity);
219 detach_entity(&data->value_max_entity);
220 detach_entity(&data->note_entity);
222 if (PARENT_OBJECT_CLASS->dispose != NULL)
223 PARENT_OBJECT_CLASS->dispose(object);
226 static void
227 finalize(GObject *object)
229 AdgDimPrivate *data = ((AdgDim *) object)->data;
231 g_free(data->value);
232 g_free(data->value_min);
233 g_free(data->value_max);
234 g_free(data->note);
236 if (PARENT_OBJECT_CLASS->finalize != NULL)
237 PARENT_OBJECT_CLASS->finalize(object);
240 static void
241 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
243 AdgDimPrivate *data = ((AdgDim *) object)->data;
245 switch (prop_id) {
246 case PROP_REF1:
247 g_value_set_boxed(value, &data->ref1);
248 break;
249 case PROP_REF2:
250 g_value_set_boxed(value, &data->ref2);
251 break;
252 case PROP_POS1:
253 g_value_set_boxed(value, &data->pos1);
254 break;
255 case PROP_POS2:
256 g_value_set_boxed(value, &data->pos1);
257 break;
258 case PROP_ANGLE:
259 g_value_set_double(value, data->angle);
260 break;
261 case PROP_LEVEL:
262 g_value_set_double(value, data->level);
263 break;
264 case PROP_VALUE:
265 g_value_set_string(value, data->value);
266 break;
267 case PROP_VALUE_MIN:
268 g_value_set_string(value, data->value_min);
269 break;
270 case PROP_VALUE_MAX:
271 g_value_set_string(value, data->value_max);
272 break;
273 case PROP_NOTE:
274 g_value_set_string(value, data->note);
275 break;
276 default:
277 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
278 break;
282 static void
283 set_property(GObject *object, guint prop_id,
284 const GValue *value, GParamSpec *pspec)
286 AdgDim *dim;
287 AdgDimPrivate *data;
289 dim = (AdgDim *) object;
290 data = dim->data;
292 switch (prop_id) {
293 case PROP_REF1:
294 cpml_pair_copy(&data->ref1, (AdgPair *) g_value_get_boxed(value));
295 break;
296 case PROP_REF2:
297 cpml_pair_copy(&data->ref2, (AdgPair *) g_value_get_boxed(value));
298 break;
299 case PROP_POS1:
300 cpml_pair_copy(&data->pos1, (AdgPair *) g_value_get_boxed(value));
301 break;
302 case PROP_POS2:
303 cpml_pair_copy(&data->pos2, (AdgPair *) g_value_get_boxed(value));
304 break;
305 case PROP_ANGLE:
306 data->angle = g_value_get_double(value);
307 break;
308 case PROP_LEVEL:
309 data->level = g_value_get_double(value);
310 break;
311 case PROP_VALUE:
312 set_value(dim, g_value_get_string(value));
313 break;
314 case PROP_VALUE_MIN:
315 set_value_min(dim, g_value_get_string(value));
316 break;
317 case PROP_VALUE_MAX:
318 set_value_max(dim, g_value_get_string(value));
319 break;
320 case PROP_NOTE:
321 set_note(dim, g_value_get_string(value));
322 break;
323 default:
324 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
325 break;
331 * adg_dim_get_org:
332 * @dim: an #AdgDim
334 * Gets the origin (org) coordinates. The returned pair is internally
335 * owned and must not be freed or modified. This function is only
336 * useful in new dimension implementations.
338 * Returns: the org coordinates
340 const AdgPair *
341 adg_dim_get_org(AdgDim *dim)
343 AdgDimPrivate *data;
345 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
347 data = dim->data;
349 return &data->org;
353 * adg_dim_set_org:
354 * @dim: an #AdgDim
355 * @org: the org coordinates
357 * Sets new org coordinates. This function is only useful
358 * in new dimension implementations.
360 void
361 adg_dim_set_org(AdgDim *dim, const AdgPair *org)
363 AdgDimPrivate *data;
365 g_return_if_fail(ADG_IS_DIM(dim));
366 g_return_if_fail(org != NULL);
368 data = dim->data;
369 data->org = *org;
373 * adg_dim_set_org_explicit:
374 * @dim: an #AdgDim
375 * @org_x: x component of org
376 * @org_y: y component of org
378 * Explicitely sets new org coordinates. This function is only useful
379 * in new dimension implementations.
381 void
382 adg_dim_set_org_explicit(AdgDim *dim, gdouble org_x, gdouble org_y)
384 AdgDimPrivate *data;
386 g_return_if_fail(ADG_IS_DIM(dim));
388 data = dim->data;
389 data->org.x = org_x;
390 data->org.y = org_y;
394 * adg_dim_get_ref1:
395 * @dim: an #AdgDim
397 * Gets the ref1 coordinates. The returned pair is internally owned
398 * and must not be freed or modified.
400 * Returns: the ref1 coordinates
402 const AdgPair *
403 adg_dim_get_ref1(AdgDim *dim)
405 AdgDimPrivate *data;
407 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
409 data = dim->data;
411 return &data->ref1;
415 * adg_dim_get_ref2:
416 * @dim: an #AdgDim
418 * Gets the ref2 coordinates. The returned pair is internally owned
419 * and must not be freed or modified.
421 * Returns: the ref2 coordinates
423 const AdgPair *
424 adg_dim_get_ref2(AdgDim *dim)
426 AdgDimPrivate *data;
428 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
430 data = dim->data;
432 return &data->ref2;
436 * adg_dim_set_ref:
437 * @dim: an #AdgDim
438 * @ref1: the ref1 coordinates
439 * @ref2: the ref2 coordinates
441 * Shortcut to set ref1 and ref2 points at once.
443 void
444 adg_dim_set_ref(AdgDim *dim, const AdgPair *ref1, const AdgPair *ref2)
446 g_return_if_fail(ADG_IS_DIM(dim));
448 if (ref1 != NULL || ref2 != NULL) {
449 GObject *object;
450 AdgDimPrivate *data;
452 data = dim->data;
453 object = (GObject *) dim;
455 g_object_freeze_notify(object);
457 if (ref1 != NULL) {
458 data->ref1 = *ref1;
459 g_object_notify(object, "ref1");
462 if (ref2 != NULL) {
463 data->ref2 = *ref2;
464 g_object_notify(object, "ref2");
467 g_object_thaw_notify(object);
472 * adg_dim_set_ref_explicit:
473 * @dim: an #AdgDim
474 * @ref1_x: x component of pos1
475 * @ref1_y: y component of pos1
476 * @ref2_x: x component of pos2
477 * @ref2_y: y component of pos2
479 * Shortcut to set ref1 and ref2 points at once,
480 * using explicit coordinates.
482 void
483 adg_dim_set_ref_explicit(AdgDim *dim, gdouble ref1_x, gdouble ref1_y,
484 gdouble ref2_x, gdouble ref2_y)
486 AdgPair ref1;
487 AdgPair ref2;
489 ref1.x = ref1_x;
490 ref1.y = ref1_y;
491 ref2.x = ref2_x;
492 ref2.y = ref2_y;
494 adg_dim_set_ref(dim, &ref1, &ref2);
498 * adg_dim_get_pos1:
499 * @dim: an #AdgDim
501 * Gets the pos1 coordinates. The returned pair is internally owned
502 * and must not be freed or modified.
504 * Returns: the pos1 coordinates
506 const AdgPair *
507 adg_dim_get_pos1(AdgDim *dim)
509 AdgDimPrivate *data;
511 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
513 data = dim->data;
515 return &data->pos1;
519 * adg_dim_get_pos2:
520 * @dim: an #AdgDim
522 * Gets the pos2 coordinates. The returned pair is internally owned
523 * and must not be freed or modified.
525 * Returns: the pos2 coordinates
527 const AdgPair *
528 adg_dim_get_pos2(AdgDim *dim)
530 AdgDimPrivate *data;
532 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
534 data = dim->data;
536 return &data->pos2;
540 * adg_dim_set_pos:
541 * @dim: an #AdgDim
542 * @pos1: the pos1 coordinates
543 * @pos2: the pos2 coordinates
545 * Shortcut to set pos1 and pos2 points at once.
547 void
548 adg_dim_set_pos(AdgDim *dim, AdgPair *pos1, AdgPair *pos2)
550 g_return_if_fail(ADG_IS_DIM(dim));
552 if (pos1 != NULL || pos2 != NULL) {
553 AdgDimPrivate *data;
554 GObject *object;
556 data = dim->data;
557 object = (GObject *) dim;
559 g_object_freeze_notify(object);
561 if (pos1 != NULL) {
562 data->pos1 = *pos1;
563 g_object_notify(object, "pos1");
565 if (pos2 != NULL) {
566 data->pos2 = *pos2;
567 g_object_notify(object, "pos2");
570 g_object_thaw_notify(object);
575 * adg_dim_set_pos_explicit:
576 * @dim: an #AdgDim
577 * @pos1_x: x component of pos1
578 * @pos1_y: y component of pos1
579 * @pos2_x: x component of pos2
580 * @pos2_y: y component of pos2
582 * Shortcut to set pos1 and pos2 points at once,
583 * using explicit coordinates.
585 void
586 adg_dim_set_pos_explicit(AdgDim *dim, gdouble pos1_x, gdouble pos1_y,
587 gdouble pos2_x, gdouble pos2_y)
589 AdgPair pos1;
590 AdgPair pos2;
592 pos1.x = pos1_x;
593 pos1.y = pos1_y;
594 pos2.x = pos2_x;
595 pos2.y = pos2_y;
597 adg_dim_set_pos(dim, &pos1, &pos2);
601 * adg_dim_get_angle:
602 * @dim: an #AdgDim
604 * Gets the dimension angle. This function is only useful
605 * in new dimension implementations.
607 * Returns: the angle (in radians)
609 gdouble
610 adg_dim_get_angle(AdgDim *dim)
612 AdgDimPrivate *data;
614 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
616 data = dim->data;
618 return data->angle;
622 * adg_dim_set_angle:
623 * @dim: an #AdgDim
624 * @angle: the new angle (in radians)
626 * Sets a new dimension angle. This function is only useful
627 * in new dimension implementations.
629 void
630 adg_dim_set_angle(AdgDim *dim, gdouble angle)
632 AdgDimPrivate *data;
634 g_return_if_fail(ADG_IS_DIM(dim));
636 data = dim->data;
637 data->angle = angle;
639 g_object_notify((GObject *) dim, "angle");
643 * adg_dim_get_level:
644 * @dim: an #AdgDim
646 * Gets the level of this dimension.
648 * Returns: the level value
650 gdouble
651 adg_dim_get_level(AdgDim *dim)
653 AdgDimPrivate *data;
655 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
657 data = dim->data;
659 return data->level;
663 * adg_dim_set_level:
664 * @dim: an #AdgDim
665 * @level: the new level
667 * Sets a new level for this dimension. The level is used to
668 * stack the quotes using a spacing value from dim_style
669 * (specified in global space).
671 void
672 adg_dim_set_level(AdgDim *dim, gdouble level)
674 AdgDimPrivate *data;
676 g_return_if_fail(ADG_IS_DIM(dim));
678 data = dim->data;
679 data->level = level;
681 g_object_notify((GObject *) dim, "level");
685 * adg_dim_get_value:
686 * @dim: an #AdgDim
688 * Gets the value text. The string is internally owned and
689 * must not be freed or modified.
691 * Returns: the value text
693 const gchar *
694 adg_dim_get_value(AdgDim *dim)
696 AdgDimPrivate *data;
698 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
700 data = dim->data;
702 return data->value;
706 * adg_dim_set_value:
707 * @dim: an #AdgDim
708 * @value: the value text
710 * Explicitely sets the text to use as value. If @value is %NULL or
711 * was never set, an automatic text is calculated using the format
712 * specified in the current #AdgDimStyle and getting its value by
713 * calling the default_value() virtual method.
715 void
716 adg_dim_set_value(AdgDim *dim, const gchar *value)
718 g_return_if_fail(ADG_IS_DIM(dim));
720 if (set_value(dim, value))
721 g_object_notify((GObject *) dim, "value");
725 * adg_dim_get_value_min:
726 * @dim: an #AdgDim
728 * Gets the minimum value text or %NULL on minimum value disabled.
729 * The string is internally owned and must not be freed or modified.
731 * Returns: the mimimum value text
733 const gchar *
734 adg_dim_get_value_min(AdgDim *dim)
736 AdgDimPrivate *data;
738 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
740 data = dim->data;
742 return data->value_min;
746 * adg_dim_set_value_min:
747 * @dim: an #AdgDim
748 * @value_min: the new minimum value
750 * Sets the minimum value. Use %NULL as @value_min to disable it.
752 void
753 adg_dim_set_value_min(AdgDim *dim, const gchar *value_min)
755 g_return_if_fail(ADG_IS_DIM(dim));
757 if (set_value_min(dim, value_min))
758 g_object_notify((GObject *) dim, "value-min");
762 * adg_dim_get_value_max:
763 * @dim: an #AdgDim
765 * Gets the maximum value text or %NULL on maximum value disabled.
766 * The string is internally owned and must not be freed or modified.
768 * Returns: the maximum value text
770 const gchar *
771 adg_dim_get_value_max(AdgDim *dim)
773 AdgDimPrivate *data;
775 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
777 data = dim->data;
779 return data->value_max;
783 * adg_dim_set_value_max:
784 * @dim: an #AdgDim
785 * @value_max: the new maximum value
787 * Sets the maximum value. Use %NULL as @value_max to disable it.
789 void
790 adg_dim_set_value_max(AdgDim *dim, const gchar *value_max)
792 g_return_if_fail(ADG_IS_DIM(dim));
794 if (set_value_max(dim, value_max))
795 g_object_notify((GObject *) dim, "value-max");
799 * adg_dim_set_tolerances:
800 * @dim: an #AdgDim
801 * @value_min: the new minumum value
802 * @value_max: the new maximum value
804 * Shortcut to set both the tolerances at once.
806 void
807 adg_dim_set_tolerances(AdgDim *dim,
808 const gchar *value_min, const gchar *value_max)
810 g_return_if_fail(ADG_IS_DIM(dim));
812 g_object_freeze_notify((GObject *) dim);
813 adg_dim_set_value_min(dim, value_min);
814 adg_dim_set_value_max(dim, value_max);
815 g_object_thaw_notify((GObject *) dim);
819 * adg_dim_get_note:
820 * @dim: and #AdgDim
822 * Gets the note text or %NULL if the note is not used. The string is
823 * internally owned and must not be freed or modified.
825 * Returns: the note text
827 const gchar *
828 adg_dim_get_note(AdgDim *dim)
830 AdgDimPrivate *data;
832 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
834 data = dim->data;
836 return data->note;
840 * adg_dim_set_note:
841 * @dim: an #AdgDim
842 * @note: the new note
844 * Sets a new note text, usually appended at the end of the dimension text.
846 void
847 adg_dim_set_note(AdgDim *dim, const gchar *note)
849 g_return_if_fail(ADG_IS_DIM(dim));
851 if (set_note(dim, note))
852 g_object_notify((GObject *) dim, "note");
856 * adg_dim_render_quote:
857 * @dim: an #AdgDim object
858 * @cr: a #cairo_t drawing context
860 * Renders the quote of @dim at the @org position. This function
861 * is only useful in new dimension implementations.
863 void
864 adg_dim_render_quote(AdgDim *dim, cairo_t *cr)
866 AdgDimPrivate *data;
868 g_return_if_fail(ADG_IS_DIM(dim));
870 data = dim->data;
872 /* Check if the basic value text needs to be automatically generated */
873 if (data->value == NULL) {
874 gchar *text = ADG_DIM_GET_CLASS(dim)->default_value(dim);
875 adg_toy_text_set_label((AdgToyText *) data->value_entity, text);
876 g_free(text);
879 ADG_DIM_GET_CLASS(dim)->quote_layout(dim, cr);
881 adg_entity_render(data->value_entity, cr);
882 adg_entity_render(data->value_min_entity, cr);
883 adg_entity_render(data->value_max_entity, cr);
884 adg_entity_render(data->note_entity, cr);
887 static gboolean
888 invalidate(AdgEntity *entity)
890 AdgDimPrivate *data = ((AdgDim *) entity)->data;
892 adg_entity_invalidate(data->value_entity);
893 adg_entity_invalidate(data->value_min_entity);
894 adg_entity_invalidate(data->value_max_entity);
895 adg_entity_invalidate(data->note_entity);
897 return TRUE;
900 static gchar *
901 default_value(AdgDim *dim)
903 g_warning("AdgDim::default_value not implemented for `%s'",
904 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
905 return g_strdup("undef");
908 static void
909 quote_layout(AdgDim *dim, cairo_t *cr)
911 AdgDimPrivate *data;
912 AdgDimStyle *dim_style;
913 cairo_text_extents_t extents;
914 AdgMatrix map;
915 const AdgPair *shift;
917 data = dim->data;
918 dim_style = (AdgDimStyle *) adg_entity_get_style((AdgEntity *) dim,
919 ADG_SLOT_DIM_STYLE);
921 /* Initialize local maps to the origin */
922 cairo_matrix_init_translate(&map, data->org.x, data->org.y);
924 adg_entity_set_local_map(data->value_entity, &map);
925 adg_entity_set_local_map(data->value_min_entity, &map);
926 adg_entity_set_local_map(data->value_max_entity, &map);
927 adg_entity_set_local_map(data->note_entity, &map);
929 /* Initialize global maps to the quote rotation angle:
930 * XXX: check why I had to invert the angle */
931 cairo_matrix_init_rotate(&map, -data->angle);
933 adg_entity_set_global_map(data->value_entity, &map);
934 adg_entity_set_global_map(data->value_min_entity, &map);
935 adg_entity_set_global_map(data->value_max_entity, &map);
936 adg_entity_set_global_map(data->note_entity, &map);
938 /* Basic value */
939 adg_toy_text_get_extents((AdgToyText *) data->value_entity, cr, &extents);
941 /* Limit values (value_min and value_max) */
942 if (data->value_min != NULL || data->value_max != NULL) {
943 cairo_text_extents_t min_extents = { 0 };
944 cairo_text_extents_t max_extents = { 0 };
945 gdouble spacing = 0;
947 /* Low tolerance */
948 if (data->value_min != NULL)
949 adg_toy_text_get_extents((AdgToyText *) data->value_min_entity,
950 cr, &min_extents);
952 /* High tolerance */
953 if (data->value_max != NULL)
954 adg_toy_text_get_extents((AdgToyText *) data->value_max_entity,
955 cr, &max_extents);
957 shift = adg_dim_style_get_tolerance_shift(dim_style);
958 if (data->value_min != NULL && data->value_max != NULL)
959 spacing = adg_dim_style_get_tolerance_spacing(dim_style);
961 cairo_matrix_init_translate(&map, extents.width + shift->x,
962 (spacing + min_extents.height +
963 max_extents.height) / 2 +
964 shift->y - extents.height / 2);
965 adg_entity_transform_global_map(data->value_min_entity, &map);
966 cairo_matrix_translate(&map, 0, -min_extents.height - spacing);
967 adg_entity_transform_global_map(data->value_max_entity, &map);
969 extents.width += shift->x + MAX(min_extents.width, max_extents.width);
972 /* Note */
973 if (data->note != NULL) {
974 cairo_text_extents_t note_extents;
976 adg_toy_text_get_extents((AdgToyText *) data->note_entity,
977 cr, &note_extents);
978 shift = adg_dim_style_get_note_shift(dim_style);
980 cairo_matrix_init_translate(&map, extents.width + shift->x, shift->y);
981 adg_entity_transform_global_map(data->note_entity, &map);
983 extents.width += shift->x + note_extents.width;
986 /* Center and apply the style displacements */
987 shift = adg_dim_style_get_quote_shift(dim_style);
988 cairo_matrix_init_translate(&map, shift->x - extents.width / 2, shift->y);
990 adg_entity_transform_global_map(data->value_entity, &map);
991 adg_entity_transform_global_map(data->value_min_entity, &map);
992 adg_entity_transform_global_map(data->value_max_entity, &map);
993 adg_entity_transform_global_map(data->note_entity, &map);
996 static gboolean
997 set_value(AdgDim *dim, const gchar *value)
999 AdgDimPrivate *data;
1001 data = dim->data;
1003 if (adg_strcmp(value, data->value) == 0)
1004 return FALSE;
1006 g_free(data->value);
1007 data->value = g_strdup(value);
1008 adg_toy_text_set_label((AdgToyText *) data->value_entity, value);
1010 return TRUE;
1013 static gboolean
1014 set_value_min(AdgDim *dim, const gchar *value_min)
1016 AdgDimPrivate *data = dim->data;
1018 if (adg_strcmp(value_min, data->value_min) == 0)
1019 return FALSE;
1021 g_free(data->value_min);
1022 data->value_min = g_strdup(value_min);
1023 adg_toy_text_set_label((AdgToyText *) data->value_min_entity, value_min);
1025 return TRUE;
1028 static gboolean
1029 set_value_max(AdgDim *dim, const gchar *value_max)
1031 AdgDimPrivate *data = dim->data;
1033 if (adg_strcmp(value_max, data->value_max) == 0)
1034 return FALSE;
1036 g_free(data->value_max);
1037 data->value_max = g_strdup(value_max);
1038 adg_toy_text_set_label((AdgToyText *) data->value_max_entity, value_max);
1040 return TRUE;
1043 static gboolean
1044 set_note(AdgDim *dim, const gchar *note)
1046 AdgDimPrivate *data;
1048 data = dim->data;
1050 if (adg_strcmp(note, data->note) == 0)
1051 return FALSE;
1053 g_free(data->note);
1054 data->note = g_strdup(note);
1055 adg_toy_text_set_label((AdgToyText *) data->note_entity, note);
1057 return TRUE;
1060 static void
1061 detach_entity(AdgEntity **p_entity)
1063 if (*p_entity != NULL) {
1064 adg_entity_set_parent(*p_entity, NULL);
1065 g_object_unref(*p_entity);
1066 *p_entity = NULL;