[AdgStroke] Using adg_entity_apply_local_matrix()
[adg.git] / adg / adg-dim.c
blob4a57f831c3dd0560279afc20bb7cf34d39296b45
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-toy-text.h"
40 #include "adg-type-builtins.h"
41 #include "adg-intl.h"
43 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_dim_parent_class)
46 enum {
47 PROP_0,
48 PROP_REF1,
49 PROP_REF2,
50 PROP_POS1,
51 PROP_POS2,
52 PROP_ANGLE,
53 PROP_LEVEL,
54 PROP_OUTSIDE,
55 PROP_VALUE,
56 PROP_VALUE_MIN,
57 PROP_VALUE_MAX,
58 PROP_NOTE
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 gboolean invalidate (AdgEntity *entity);
73 static gchar * default_value (AdgDim *dim);
74 static void quote_layout (AdgDim *dim,
75 cairo_t *cr);
76 static gboolean set_value (AdgDim *dim,
77 const gchar *value);
78 static gboolean set_value_min (AdgDim *dim,
79 const gchar *value_min);
80 static gboolean set_value_max (AdgDim *dim,
81 const gchar *value_max);
82 static gboolean set_note (AdgDim *dim,
83 const gchar *note);
84 static void detach_entity (AdgEntity **p_entity);
87 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY);
90 static void
91 adg_dim_class_init(AdgDimClass *klass)
93 GObjectClass *gobject_class;
94 AdgEntityClass *entity_class;
95 GParamSpec *param;
97 gobject_class = (GObjectClass *) klass;
98 entity_class = (AdgEntityClass *) klass;
100 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
102 gobject_class->dispose = dispose;
103 gobject_class->finalize = finalize;
104 gobject_class->get_property = get_property;
105 gobject_class->set_property = set_property;
107 entity_class->invalidate = invalidate;
109 klass->default_value = default_value;
110 klass->quote_layout = quote_layout;
112 param = g_param_spec_boxed("ref1",
113 P_("Reference 1"),
114 P_("First reference point of the dimension"),
115 ADG_TYPE_PAIR,
116 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
117 g_object_class_install_property(gobject_class, PROP_REF1, param);
119 param = g_param_spec_boxed("ref2",
120 P_("Reference 2"),
121 P_("Second reference point of the dimension"),
122 ADG_TYPE_PAIR,
123 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
124 g_object_class_install_property(gobject_class, PROP_REF2, param);
126 param = g_param_spec_boxed("pos1",
127 P_("Position 1"),
128 P_("First position point: it will be computed with the level property to get the real dimension position"),
129 ADG_TYPE_PAIR, G_PARAM_READWRITE);
130 g_object_class_install_property(gobject_class, PROP_POS1, param);
132 param = g_param_spec_boxed("pos2",
133 P_("Position 2"),
134 P_("Second position point: it will be computed with the level property to get the real dimension position"),
135 ADG_TYPE_PAIR, G_PARAM_READWRITE);
136 g_object_class_install_property(gobject_class, PROP_POS2, param);
138 param = g_param_spec_double("angle",
139 P_("Angle"),
140 P_("The dimension direction, if relevant"),
141 -G_MAXDOUBLE, G_MAXDOUBLE, 0,
142 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
143 g_object_class_install_property(gobject_class, PROP_ANGLE, param);
145 param = g_param_spec_double("level",
146 P_("Level"),
147 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"),
148 -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
149 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
150 g_object_class_install_property(gobject_class, PROP_LEVEL, param);
152 param = g_param_spec_enum("outside",
153 P_("Outside"),
154 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"),
155 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
156 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
157 g_object_class_install_property(gobject_class, PROP_OUTSIDE, param);
159 param = g_param_spec_string("value",
160 P_("Basic Value"),
161 P_("The theoretically exact value for this quote: set to NULL to automatically get the default value"),
162 NULL, G_PARAM_READWRITE);
163 g_object_class_install_property(gobject_class, PROP_VALUE, param);
165 param = g_param_spec_string("value-min",
166 P_("Minimum Value or Low Tolerance"),
167 P_("The minimum value allowed or the lowest tolerance from value (depending of the dimension style): set to NULL to suppress"),
168 NULL, G_PARAM_READWRITE);
169 g_object_class_install_property(gobject_class, PROP_VALUE_MIN, param);
171 param = g_param_spec_string("value-max",
172 P_("Maximum Value or High Tolerance"),
173 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
174 NULL, G_PARAM_READWRITE);
175 g_object_class_install_property(gobject_class, PROP_VALUE_MAX, param);
177 param = g_param_spec_string("note",
178 P_("Note"),
179 P_("A custom note appended to the end of the quote"),
180 NULL, G_PARAM_READWRITE);
181 g_object_class_install_property(gobject_class, PROP_NOTE, param);
184 static void
185 adg_dim_init(AdgDim *dim)
187 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
188 AdgDimPrivate);
190 data->ref1.x = data->ref1.y = 0;
191 data->ref2.x = data->ref2.y = 0;
192 data->pos1.x = data->pos1.y = 0;
193 data->pos2.x = data->pos2.y = 0;
194 data->angle = 0;
195 data->level = 1;
196 data->value = NULL;
197 data->value_min = NULL;
198 data->value_max = NULL;
199 data->note = NULL;
201 data->value_entity = g_object_new(ADG_TYPE_TOY_TEXT,
202 "parent", dim,
203 "font-style", ADG_FONT_STYLE_VALUE,
204 NULL);
205 data->value_min_entity = g_object_new(ADG_TYPE_TOY_TEXT,
206 "parent", dim,
207 "font-style", ADG_FONT_STYLE_TOLERANCE,
208 NULL);
209 data->value_max_entity = g_object_new(ADG_TYPE_TOY_TEXT,
210 "parent", dim,
211 "font-style", ADG_FONT_STYLE_TOLERANCE,
212 NULL);
213 data->note_entity = g_object_new(ADG_TYPE_TOY_TEXT,
214 "parent", dim,
215 "font-style", ADG_FONT_STYLE_NOTE,
216 NULL);
218 dim->data = data;
221 static void
222 dispose(GObject *object)
224 AdgDimPrivate *data = ((AdgDim *) object)->data;
226 detach_entity(&data->value_entity);
227 detach_entity(&data->value_min_entity);
228 detach_entity(&data->value_max_entity);
229 detach_entity(&data->note_entity);
231 if (PARENT_OBJECT_CLASS->dispose != NULL)
232 PARENT_OBJECT_CLASS->dispose(object);
235 static void
236 finalize(GObject *object)
238 AdgDimPrivate *data = ((AdgDim *) object)->data;
240 g_free(data->value);
241 g_free(data->value_min);
242 g_free(data->value_max);
243 g_free(data->note);
245 if (PARENT_OBJECT_CLASS->finalize != NULL)
246 PARENT_OBJECT_CLASS->finalize(object);
249 static void
250 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
252 AdgDimPrivate *data = ((AdgDim *) object)->data;
254 switch (prop_id) {
255 case PROP_REF1:
256 g_value_set_boxed(value, &data->ref1);
257 break;
258 case PROP_REF2:
259 g_value_set_boxed(value, &data->ref2);
260 break;
261 case PROP_POS1:
262 g_value_set_boxed(value, &data->pos1);
263 break;
264 case PROP_POS2:
265 g_value_set_boxed(value, &data->pos1);
266 break;
267 case PROP_ANGLE:
268 g_value_set_double(value, data->angle);
269 break;
270 case PROP_LEVEL:
271 g_value_set_double(value, data->level);
272 break;
273 case PROP_OUTSIDE:
274 g_value_set_enum(value, data->outside);
275 break;
276 case PROP_VALUE:
277 g_value_set_string(value, data->value);
278 break;
279 case PROP_VALUE_MIN:
280 g_value_set_string(value, data->value_min);
281 break;
282 case PROP_VALUE_MAX:
283 g_value_set_string(value, data->value_max);
284 break;
285 case PROP_NOTE:
286 g_value_set_string(value, data->note);
287 break;
288 default:
289 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
290 break;
294 static void
295 set_property(GObject *object, guint prop_id,
296 const GValue *value, GParamSpec *pspec)
298 AdgDim *dim;
299 AdgDimPrivate *data;
301 dim = (AdgDim *) object;
302 data = dim->data;
304 switch (prop_id) {
305 case PROP_REF1:
306 cpml_pair_copy(&data->ref1, (AdgPair *) g_value_get_boxed(value));
307 break;
308 case PROP_REF2:
309 cpml_pair_copy(&data->ref2, (AdgPair *) g_value_get_boxed(value));
310 break;
311 case PROP_POS1:
312 cpml_pair_copy(&data->pos1, (AdgPair *) g_value_get_boxed(value));
313 break;
314 case PROP_POS2:
315 cpml_pair_copy(&data->pos2, (AdgPair *) g_value_get_boxed(value));
316 break;
317 case PROP_ANGLE:
318 data->angle = g_value_get_double(value);
319 break;
320 case PROP_LEVEL:
321 data->level = g_value_get_double(value);
322 break;
323 case PROP_OUTSIDE:
324 data->outside = g_value_get_enum(value);
325 break;
326 case PROP_VALUE:
327 set_value(dim, g_value_get_string(value));
328 break;
329 case PROP_VALUE_MIN:
330 set_value_min(dim, g_value_get_string(value));
331 break;
332 case PROP_VALUE_MAX:
333 set_value_max(dim, g_value_get_string(value));
334 break;
335 case PROP_NOTE:
336 set_note(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_get_org:
347 * @dim: an #AdgDim
349 * Gets the origin (org) coordinates. The returned pair is internally
350 * owned and must not be freed or modified. This function is only
351 * useful in new dimension implementations.
353 * Returns: the org coordinates
355 const AdgPair *
356 adg_dim_get_org(AdgDim *dim)
358 AdgDimPrivate *data;
360 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
362 data = dim->data;
364 return &data->org;
368 * adg_dim_set_org:
369 * @dim: an #AdgDim
370 * @org: the org coordinates
372 * <note><para>
373 * This function is only useful in new dimension implementations.
374 * </para></note>
376 * Sets new org coordinates.
378 void
379 adg_dim_set_org(AdgDim *dim, const AdgPair *org)
381 AdgDimPrivate *data;
383 g_return_if_fail(ADG_IS_DIM(dim));
384 g_return_if_fail(org != NULL);
386 data = dim->data;
387 data->org = *org;
391 * adg_dim_set_org_explicit:
392 * @dim: an #AdgDim
393 * @org_x: x component of org
394 * @org_y: y component of org
396 * <note><para>
397 * This function is only useful in new dimension implementations.
398 * </para></note>
400 * Explicitely sets new org coordinates.
402 void
403 adg_dim_set_org_explicit(AdgDim *dim, gdouble org_x, gdouble org_y)
405 AdgDimPrivate *data;
407 g_return_if_fail(ADG_IS_DIM(dim));
409 data = dim->data;
410 data->org.x = org_x;
411 data->org.y = org_y;
415 * adg_dim_get_ref1:
416 * @dim: an #AdgDim
418 * Gets the ref1 coordinates. The returned pair is internally owned
419 * and must not be freed or modified.
421 * Returns: the ref1 coordinates
423 const AdgPair *
424 adg_dim_get_ref1(AdgDim *dim)
426 AdgDimPrivate *data;
428 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
430 data = dim->data;
432 return &data->ref1;
436 * adg_dim_get_ref2:
437 * @dim: an #AdgDim
439 * Gets the ref2 coordinates. The returned pair is internally owned
440 * and must not be freed or modified.
442 * Returns: the ref2 coordinates
444 const AdgPair *
445 adg_dim_get_ref2(AdgDim *dim)
447 AdgDimPrivate *data;
449 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
451 data = dim->data;
453 return &data->ref2;
457 * adg_dim_set_ref:
458 * @dim: an #AdgDim
459 * @ref1: the ref1 coordinates
460 * @ref2: the ref2 coordinates
462 * Shortcut to set ref1 and ref2 points at once.
464 void
465 adg_dim_set_ref(AdgDim *dim, const AdgPair *ref1, const AdgPair *ref2)
467 g_return_if_fail(ADG_IS_DIM(dim));
469 if (ref1 != NULL || ref2 != NULL) {
470 GObject *object;
471 AdgDimPrivate *data;
473 data = dim->data;
474 object = (GObject *) dim;
476 g_object_freeze_notify(object);
478 if (ref1 != NULL) {
479 data->ref1 = *ref1;
480 g_object_notify(object, "ref1");
483 if (ref2 != NULL) {
484 data->ref2 = *ref2;
485 g_object_notify(object, "ref2");
488 g_object_thaw_notify(object);
493 * adg_dim_set_ref_explicit:
494 * @dim: an #AdgDim
495 * @ref1_x: x component of pos1
496 * @ref1_y: y component of pos1
497 * @ref2_x: x component of pos2
498 * @ref2_y: y component of pos2
500 * Shortcut to set ref1 and ref2 points at once,
501 * using explicit coordinates.
503 void
504 adg_dim_set_ref_explicit(AdgDim *dim, gdouble ref1_x, gdouble ref1_y,
505 gdouble ref2_x, gdouble ref2_y)
507 AdgPair ref1;
508 AdgPair ref2;
510 ref1.x = ref1_x;
511 ref1.y = ref1_y;
512 ref2.x = ref2_x;
513 ref2.y = ref2_y;
515 adg_dim_set_ref(dim, &ref1, &ref2);
519 * adg_dim_get_pos1:
520 * @dim: an #AdgDim
522 * Gets the pos1 coordinates. The returned pair is internally owned
523 * and must not be freed or modified.
525 * Returns: the pos1 coordinates
527 const AdgPair *
528 adg_dim_get_pos1(AdgDim *dim)
530 AdgDimPrivate *data;
532 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
534 data = dim->data;
536 return &data->pos1;
540 * adg_dim_get_pos2:
541 * @dim: an #AdgDim
543 * Gets the pos2 coordinates. The returned pair is internally owned
544 * and must not be freed or modified.
546 * Returns: the pos2 coordinates
548 const AdgPair *
549 adg_dim_get_pos2(AdgDim *dim)
551 AdgDimPrivate *data;
553 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
555 data = dim->data;
557 return &data->pos2;
561 * adg_dim_set_pos:
562 * @dim: an #AdgDim
563 * @pos1: the pos1 coordinates
564 * @pos2: the pos2 coordinates
566 * Shortcut to set pos1 and pos2 points at once.
568 void
569 adg_dim_set_pos(AdgDim *dim, AdgPair *pos1, AdgPair *pos2)
571 g_return_if_fail(ADG_IS_DIM(dim));
573 if (pos1 != NULL || pos2 != NULL) {
574 AdgDimPrivate *data;
575 GObject *object;
577 data = dim->data;
578 object = (GObject *) dim;
580 g_object_freeze_notify(object);
582 if (pos1 != NULL) {
583 data->pos1 = *pos1;
584 g_object_notify(object, "pos1");
586 if (pos2 != NULL) {
587 data->pos2 = *pos2;
588 g_object_notify(object, "pos2");
591 g_object_thaw_notify(object);
596 * adg_dim_set_pos_explicit:
597 * @dim: an #AdgDim
598 * @pos1_x: x component of pos1
599 * @pos1_y: y component of pos1
600 * @pos2_x: x component of pos2
601 * @pos2_y: y component of pos2
603 * Shortcut to set pos1 and pos2 points at once,
604 * using explicit coordinates.
606 void
607 adg_dim_set_pos_explicit(AdgDim *dim, gdouble pos1_x, gdouble pos1_y,
608 gdouble pos2_x, gdouble pos2_y)
610 AdgPair pos1;
611 AdgPair pos2;
613 pos1.x = pos1_x;
614 pos1.y = pos1_y;
615 pos2.x = pos2_x;
616 pos2.y = pos2_y;
618 adg_dim_set_pos(dim, &pos1, &pos2);
622 * adg_dim_get_angle:
623 * @dim: an #AdgDim
625 * <note><para>
626 * This function is only useful in new dimension implementations.
627 * </para></note>
629 * Gets the dimension angle.
631 * Returns: the angle (in radians)
633 gdouble
634 adg_dim_get_angle(AdgDim *dim)
636 AdgDimPrivate *data;
638 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
640 data = dim->data;
642 return data->angle;
646 * adg_dim_set_angle:
647 * @dim: an #AdgDim
648 * @angle: the new angle (in radians)
650 * <note><para>
651 * This function is only useful in new dimension implementations.
652 * </para></note>
654 * Sets a new dimension angle.
656 void
657 adg_dim_set_angle(AdgDim *dim, gdouble angle)
659 AdgDimPrivate *data;
661 g_return_if_fail(ADG_IS_DIM(dim));
663 data = dim->data;
664 data->angle = angle;
666 g_object_notify((GObject *) dim, "angle");
670 * adg_dim_get_level:
671 * @dim: an #AdgDim
673 * Gets the level of this dimension.
675 * Returns: the level value
677 gdouble
678 adg_dim_get_level(AdgDim *dim)
680 AdgDimPrivate *data;
682 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
684 data = dim->data;
686 return data->level;
690 * adg_dim_set_level:
691 * @dim: an #AdgDim
692 * @level: the new level
694 * Sets a new level for this dimension. The level is used to
695 * stack the quotes using a spacing value from dim_style
696 * (specified in global space).
698 void
699 adg_dim_set_level(AdgDim *dim, gdouble level)
701 AdgDimPrivate *data;
703 g_return_if_fail(ADG_IS_DIM(dim));
705 data = dim->data;
706 data->level = level;
708 g_object_notify((GObject *) dim, "level");
712 * adg_dim_get_outside:
713 * @dim: an #AdgDim
715 * Gets the state of the #AdgDim:outside property: check the property
716 * documentation for further details.
718 * Returns: the current flag state
720 AdgThreeState
721 adg_dim_get_outside(AdgDim *dim)
723 AdgDimPrivate *data;
725 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
727 data = dim->data;
729 return data->outside;
733 * adg_dim_set_outside:
734 * @dim: an #AdgDim
735 * @outside: the new outside state
737 * Sets a new state for the #AdgDim:outside flag: check the property
738 * documentation for further details.
740 void
741 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
743 AdgDimPrivate *data;
745 g_return_if_fail(ADG_IS_DIM(dim));
747 data = dim->data;
748 data->outside = outside;
750 g_object_notify((GObject *) dim, "outside");
754 * adg_dim_get_value:
755 * @dim: an #AdgDim
757 * Gets the value text. The string is internally owned and
758 * must not be freed or modified.
760 * Returns: the value text
762 const gchar *
763 adg_dim_get_value(AdgDim *dim)
765 AdgDimPrivate *data;
767 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
769 data = dim->data;
771 return data->value;
775 * adg_dim_set_value:
776 * @dim: an #AdgDim
777 * @value: the value text
779 * Explicitely sets the text to use as value. If @value is %NULL or
780 * was never set, an automatic text is calculated using the format
781 * specified in the current #AdgDimStyle and getting its value by
782 * calling the default_value() virtual method.
784 void
785 adg_dim_set_value(AdgDim *dim, const gchar *value)
787 g_return_if_fail(ADG_IS_DIM(dim));
789 if (set_value(dim, value))
790 g_object_notify((GObject *) dim, "value");
794 * adg_dim_get_value_min:
795 * @dim: an #AdgDim
797 * Gets the minimum value text or %NULL on minimum value disabled.
798 * The string is internally owned and must not be freed or modified.
800 * Returns: the mimimum value text
802 const gchar *
803 adg_dim_get_value_min(AdgDim *dim)
805 AdgDimPrivate *data;
807 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
809 data = dim->data;
811 return data->value_min;
815 * adg_dim_set_value_min:
816 * @dim: an #AdgDim
817 * @value_min: the new minimum value
819 * Sets the minimum value. Use %NULL as @value_min to disable it.
821 void
822 adg_dim_set_value_min(AdgDim *dim, const gchar *value_min)
824 g_return_if_fail(ADG_IS_DIM(dim));
826 if (set_value_min(dim, value_min))
827 g_object_notify((GObject *) dim, "value-min");
831 * adg_dim_get_value_max:
832 * @dim: an #AdgDim
834 * Gets the maximum value text or %NULL on maximum value disabled.
835 * The string is internally owned and must not be freed or modified.
837 * Returns: the maximum value text
839 const gchar *
840 adg_dim_get_value_max(AdgDim *dim)
842 AdgDimPrivate *data;
844 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
846 data = dim->data;
848 return data->value_max;
852 * adg_dim_set_value_max:
853 * @dim: an #AdgDim
854 * @value_max: the new maximum value
856 * Sets the maximum value. Use %NULL as @value_max to disable it.
858 void
859 adg_dim_set_value_max(AdgDim *dim, const gchar *value_max)
861 g_return_if_fail(ADG_IS_DIM(dim));
863 if (set_value_max(dim, value_max))
864 g_object_notify((GObject *) dim, "value-max");
868 * adg_dim_set_tolerances:
869 * @dim: an #AdgDim
870 * @value_min: the new minumum value
871 * @value_max: the new maximum value
873 * Shortcut to set both the tolerances at once.
875 void
876 adg_dim_set_tolerances(AdgDim *dim,
877 const gchar *value_min, const gchar *value_max)
879 g_return_if_fail(ADG_IS_DIM(dim));
881 g_object_freeze_notify((GObject *) dim);
882 adg_dim_set_value_min(dim, value_min);
883 adg_dim_set_value_max(dim, value_max);
884 g_object_thaw_notify((GObject *) dim);
888 * adg_dim_get_note:
889 * @dim: and #AdgDim
891 * Gets the note text or %NULL if the note is not used. The string is
892 * internally owned and must not be freed or modified.
894 * Returns: the note text
896 const gchar *
897 adg_dim_get_note(AdgDim *dim)
899 AdgDimPrivate *data;
901 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
903 data = dim->data;
905 return data->note;
909 * adg_dim_set_note:
910 * @dim: an #AdgDim
911 * @note: the new note
913 * Sets a new note text, usually appended at the end of the dimension text.
915 void
916 adg_dim_set_note(AdgDim *dim, const gchar *note)
918 g_return_if_fail(ADG_IS_DIM(dim));
920 if (set_note(dim, note))
921 g_object_notify((GObject *) dim, "note");
925 * adg_dim_render_quote:
926 * @dim: an #AdgDim object
927 * @cr: a #cairo_t drawing context
929 * <note><para>
930 * This function is only useful in new dimension implementations.
931 * </para></note>
933 * Renders the quote of @dim at the @org position.
935 void
936 adg_dim_render_quote(AdgDim *dim, cairo_t *cr)
938 AdgDimPrivate *data;
940 g_return_if_fail(ADG_IS_DIM(dim));
942 data = dim->data;
944 /* Check if the basic value text needs to be automatically generated */
945 if (data->value == NULL) {
946 gchar *text = ADG_DIM_GET_CLASS(dim)->default_value(dim);
947 adg_toy_text_set_label((AdgToyText *) data->value_entity, text);
948 g_free(text);
951 ADG_DIM_GET_CLASS(dim)->quote_layout(dim, cr);
953 adg_entity_render(data->value_entity, cr);
954 adg_entity_render(data->value_min_entity, cr);
955 adg_entity_render(data->value_max_entity, cr);
956 adg_entity_render(data->note_entity, cr);
959 static gboolean
960 invalidate(AdgEntity *entity)
962 AdgDimPrivate *data = ((AdgDim *) entity)->data;
964 adg_entity_invalidate(data->value_entity);
965 adg_entity_invalidate(data->value_min_entity);
966 adg_entity_invalidate(data->value_max_entity);
967 adg_entity_invalidate(data->note_entity);
969 return TRUE;
972 static gchar *
973 default_value(AdgDim *dim)
975 g_warning("AdgDim::default_value not implemented for `%s'",
976 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
977 return g_strdup("undef");
980 static void
981 quote_layout(AdgDim *dim, cairo_t *cr)
983 AdgDimPrivate *data;
984 AdgDimStyle *dim_style;
985 cairo_text_extents_t extents;
986 AdgMatrix map;
987 const AdgPair *shift;
989 data = dim->data;
990 dim_style = (AdgDimStyle *) adg_entity_get_style((AdgEntity *) dim,
991 ADG_SLOT_DIM_STYLE);
993 /* Initialize local maps to the origin */
994 cairo_matrix_init_translate(&map, data->org.x, data->org.y);
996 adg_entity_set_local_map(data->value_entity, &map);
997 adg_entity_set_local_map(data->value_min_entity, &map);
998 adg_entity_set_local_map(data->value_max_entity, &map);
999 adg_entity_set_local_map(data->note_entity, &map);
1001 /* Initialize global maps to the quote rotation angle:
1002 * XXX: check why I had to invert the angle */
1003 cairo_matrix_init_rotate(&map, -data->angle);
1005 adg_entity_set_global_map(data->value_entity, &map);
1006 adg_entity_set_global_map(data->value_min_entity, &map);
1007 adg_entity_set_global_map(data->value_max_entity, &map);
1008 adg_entity_set_global_map(data->note_entity, &map);
1010 /* Basic value */
1011 adg_toy_text_get_extents((AdgToyText *) data->value_entity, cr, &extents);
1013 /* Limit values (value_min and value_max) */
1014 if (data->value_min != NULL || data->value_max != NULL) {
1015 cairo_text_extents_t min_extents = { 0 };
1016 cairo_text_extents_t max_extents = { 0 };
1017 gdouble spacing = 0;
1019 /* Low tolerance */
1020 if (data->value_min != NULL)
1021 adg_toy_text_get_extents((AdgToyText *) data->value_min_entity,
1022 cr, &min_extents);
1024 /* High tolerance */
1025 if (data->value_max != NULL)
1026 adg_toy_text_get_extents((AdgToyText *) data->value_max_entity,
1027 cr, &max_extents);
1029 shift = adg_dim_style_get_tolerance_shift(dim_style);
1030 if (data->value_min != NULL && data->value_max != NULL)
1031 spacing = adg_dim_style_get_tolerance_spacing(dim_style);
1033 cairo_matrix_init_translate(&map, extents.width + shift->x,
1034 (spacing + min_extents.height +
1035 max_extents.height) / 2 +
1036 shift->y - extents.height / 2);
1037 adg_entity_transform_global_map(data->value_min_entity, &map);
1038 cairo_matrix_translate(&map, 0, -min_extents.height - spacing);
1039 adg_entity_transform_global_map(data->value_max_entity, &map);
1041 extents.width += shift->x + MAX(min_extents.width, max_extents.width);
1044 /* Note */
1045 if (data->note != NULL) {
1046 cairo_text_extents_t note_extents;
1048 adg_toy_text_get_extents((AdgToyText *) data->note_entity,
1049 cr, &note_extents);
1050 shift = adg_dim_style_get_note_shift(dim_style);
1052 cairo_matrix_init_translate(&map, extents.width + shift->x, shift->y);
1053 adg_entity_transform_global_map(data->note_entity, &map);
1055 extents.width += shift->x + note_extents.width;
1058 /* Center and apply the style displacements */
1059 shift = adg_dim_style_get_quote_shift(dim_style);
1060 cairo_matrix_init_translate(&map, shift->x - extents.width / 2, shift->y);
1062 adg_entity_transform_global_map(data->value_entity, &map);
1063 adg_entity_transform_global_map(data->value_min_entity, &map);
1064 adg_entity_transform_global_map(data->value_max_entity, &map);
1065 adg_entity_transform_global_map(data->note_entity, &map);
1068 static gboolean
1069 set_value(AdgDim *dim, const gchar *value)
1071 AdgDimPrivate *data;
1073 data = dim->data;
1075 if (adg_strcmp(value, data->value) == 0)
1076 return FALSE;
1078 g_free(data->value);
1079 data->value = g_strdup(value);
1080 adg_toy_text_set_label((AdgToyText *) data->value_entity, value);
1082 return TRUE;
1085 static gboolean
1086 set_value_min(AdgDim *dim, const gchar *value_min)
1088 AdgDimPrivate *data = dim->data;
1090 if (adg_strcmp(value_min, data->value_min) == 0)
1091 return FALSE;
1093 g_free(data->value_min);
1094 data->value_min = g_strdup(value_min);
1095 adg_toy_text_set_label((AdgToyText *) data->value_min_entity, value_min);
1097 return TRUE;
1100 static gboolean
1101 set_value_max(AdgDim *dim, const gchar *value_max)
1103 AdgDimPrivate *data = dim->data;
1105 if (adg_strcmp(value_max, data->value_max) == 0)
1106 return FALSE;
1108 g_free(data->value_max);
1109 data->value_max = g_strdup(value_max);
1110 adg_toy_text_set_label((AdgToyText *) data->value_max_entity, value_max);
1112 return TRUE;
1115 static gboolean
1116 set_note(AdgDim *dim, const gchar *note)
1118 AdgDimPrivate *data;
1120 data = dim->data;
1122 if (adg_strcmp(note, data->note) == 0)
1123 return FALSE;
1125 g_free(data->note);
1126 data->note = g_strdup(note);
1127 adg_toy_text_set_label((AdgToyText *) data->note_entity, note);
1129 return TRUE;
1132 static void
1133 detach_entity(AdgEntity **p_entity)
1135 if (*p_entity != NULL) {
1136 adg_entity_set_parent(*p_entity, NULL);
1137 g_object_unref(*p_entity);
1138 *p_entity = NULL;