[AdgLineStyle] Updated for AdgDress
[adg.git] / adg / adg-dim.c
blobcb202659aab840d818b8b228466e2e1acb5e78ce
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_angle (AdgDim *dim,
77 gdouble angle);
78 static gboolean set_value (AdgDim *dim,
79 const gchar *value);
80 static gboolean set_value_min (AdgDim *dim,
81 const gchar *value_min);
82 static gboolean set_value_max (AdgDim *dim,
83 const gchar *value_max);
84 static gboolean set_note (AdgDim *dim,
85 const gchar *note);
86 static void detach_entity (AdgEntity **p_entity);
89 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY);
92 static void
93 adg_dim_class_init(AdgDimClass *klass)
95 GObjectClass *gobject_class;
96 AdgEntityClass *entity_class;
97 GParamSpec *param;
99 gobject_class = (GObjectClass *) klass;
100 entity_class = (AdgEntityClass *) klass;
102 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
104 gobject_class->dispose = dispose;
105 gobject_class->finalize = finalize;
106 gobject_class->get_property = get_property;
107 gobject_class->set_property = set_property;
109 entity_class->invalidate = invalidate;
111 klass->default_value = default_value;
112 klass->quote_layout = quote_layout;
114 param = g_param_spec_boxed("ref1",
115 P_("Reference 1"),
116 P_("First reference point of the dimension"),
117 ADG_TYPE_PAIR,
118 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
119 g_object_class_install_property(gobject_class, PROP_REF1, param);
121 param = g_param_spec_boxed("ref2",
122 P_("Reference 2"),
123 P_("Second reference point of the dimension"),
124 ADG_TYPE_PAIR,
125 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
126 g_object_class_install_property(gobject_class, PROP_REF2, param);
128 param = g_param_spec_boxed("pos1",
129 P_("Position 1"),
130 P_("First position point: it will be computed with the level property to get the real dimension position"),
131 ADG_TYPE_PAIR, G_PARAM_READWRITE);
132 g_object_class_install_property(gobject_class, PROP_POS1, param);
134 param = g_param_spec_boxed("pos2",
135 P_("Position 2"),
136 P_("Second position point: it will be computed with the level property to get the real dimension position"),
137 ADG_TYPE_PAIR, G_PARAM_READWRITE);
138 g_object_class_install_property(gobject_class, PROP_POS2, param);
140 param = g_param_spec_double("angle",
141 P_("Angle"),
142 P_("The dimension direction, if relevant"),
143 -G_MAXDOUBLE, G_MAXDOUBLE, 0,
144 G_PARAM_READWRITE);
145 g_object_class_install_property(gobject_class, PROP_ANGLE, param);
147 param = g_param_spec_double("level",
148 P_("Level"),
149 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"),
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_string("value",
162 P_("Basic Value"),
163 P_("The theoretically exact value for this quote: set to NULL to automatically get the default value"),
164 NULL, G_PARAM_READWRITE);
165 g_object_class_install_property(gobject_class, PROP_VALUE, param);
167 param = g_param_spec_string("value-min",
168 P_("Minimum Value or Low Tolerance"),
169 P_("The minimum value allowed or the lowest tolerance from value (depending of the dimension style): set to NULL to suppress"),
170 NULL, G_PARAM_READWRITE);
171 g_object_class_install_property(gobject_class, PROP_VALUE_MIN, param);
173 param = g_param_spec_string("value-max",
174 P_("Maximum Value or High Tolerance"),
175 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
176 NULL, G_PARAM_READWRITE);
177 g_object_class_install_property(gobject_class, PROP_VALUE_MAX, param);
179 param = g_param_spec_string("note",
180 P_("Note"),
181 P_("A custom note appended to the end of the quote"),
182 NULL, G_PARAM_READWRITE);
183 g_object_class_install_property(gobject_class, PROP_NOTE, param);
186 static void
187 adg_dim_init(AdgDim *dim)
189 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
190 AdgDimPrivate);
192 data->ref1.x = data->ref1.y = 0;
193 data->ref2.x = data->ref2.y = 0;
194 data->pos1.x = data->pos1.y = 0;
195 data->pos2.x = data->pos2.y = 0;
196 data->angle = 0;
197 data->level = 1;
198 data->value = NULL;
199 data->value_min = NULL;
200 data->value_max = NULL;
201 data->note = NULL;
203 data->value_entity = g_object_new(ADG_TYPE_TOY_TEXT,
204 "parent", dim,
205 "font-style", ADG_FONT_STYLE_VALUE,
206 NULL);
207 data->value_min_entity = g_object_new(ADG_TYPE_TOY_TEXT,
208 "parent", dim,
209 "font-style", ADG_FONT_STYLE_TOLERANCE,
210 NULL);
211 data->value_max_entity = g_object_new(ADG_TYPE_TOY_TEXT,
212 "parent", dim,
213 "font-style", ADG_FONT_STYLE_TOLERANCE,
214 NULL);
215 data->note_entity = g_object_new(ADG_TYPE_TOY_TEXT,
216 "parent", dim,
217 "font-style", ADG_FONT_STYLE_NOTE,
218 NULL);
220 dim->data = data;
223 static void
224 dispose(GObject *object)
226 AdgDimPrivate *data = ((AdgDim *) object)->data;
228 detach_entity(&data->value_entity);
229 detach_entity(&data->value_min_entity);
230 detach_entity(&data->value_max_entity);
231 detach_entity(&data->note_entity);
233 if (PARENT_OBJECT_CLASS->dispose != NULL)
234 PARENT_OBJECT_CLASS->dispose(object);
237 static void
238 finalize(GObject *object)
240 AdgDimPrivate *data = ((AdgDim *) object)->data;
242 g_free(data->value);
243 g_free(data->value_min);
244 g_free(data->value_max);
245 g_free(data->note);
247 if (PARENT_OBJECT_CLASS->finalize != NULL)
248 PARENT_OBJECT_CLASS->finalize(object);
251 static void
252 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
254 AdgDimPrivate *data = ((AdgDim *) object)->data;
256 switch (prop_id) {
257 case PROP_REF1:
258 g_value_set_boxed(value, &data->ref1);
259 break;
260 case PROP_REF2:
261 g_value_set_boxed(value, &data->ref2);
262 break;
263 case PROP_POS1:
264 g_value_set_boxed(value, &data->pos1);
265 break;
266 case PROP_POS2:
267 g_value_set_boxed(value, &data->pos1);
268 break;
269 case PROP_ANGLE:
270 g_value_set_double(value, data->angle);
271 break;
272 case PROP_LEVEL:
273 g_value_set_double(value, data->level);
274 break;
275 case PROP_OUTSIDE:
276 g_value_set_enum(value, data->outside);
277 break;
278 case PROP_VALUE:
279 g_value_set_string(value, data->value);
280 break;
281 case PROP_VALUE_MIN:
282 g_value_set_string(value, data->value_min);
283 break;
284 case PROP_VALUE_MAX:
285 g_value_set_string(value, data->value_max);
286 break;
287 case PROP_NOTE:
288 g_value_set_string(value, data->note);
289 break;
290 default:
291 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
292 break;
296 static void
297 set_property(GObject *object, guint prop_id,
298 const GValue *value, GParamSpec *pspec)
300 AdgDim *dim;
301 AdgDimPrivate *data;
303 dim = (AdgDim *) object;
304 data = dim->data;
306 switch (prop_id) {
307 case PROP_REF1:
308 cpml_pair_copy(&data->ref1, (AdgPair *) g_value_get_boxed(value));
309 break;
310 case PROP_REF2:
311 cpml_pair_copy(&data->ref2, (AdgPair *) g_value_get_boxed(value));
312 break;
313 case PROP_POS1:
314 cpml_pair_copy(&data->pos1, (AdgPair *) g_value_get_boxed(value));
315 break;
316 case PROP_POS2:
317 cpml_pair_copy(&data->pos2, (AdgPair *) g_value_get_boxed(value));
318 break;
319 case PROP_ANGLE:
320 set_angle(dim, g_value_get_double(value));
321 break;
322 case PROP_LEVEL:
323 data->level = g_value_get_double(value);
324 break;
325 case PROP_OUTSIDE:
326 data->outside = g_value_get_enum(value);
327 break;
328 case PROP_VALUE:
329 set_value(dim, g_value_get_string(value));
330 break;
331 case PROP_VALUE_MIN:
332 set_value_min(dim, g_value_get_string(value));
333 break;
334 case PROP_VALUE_MAX:
335 set_value_max(dim, g_value_get_string(value));
336 break;
337 case PROP_NOTE:
338 set_note(dim, g_value_get_string(value));
339 break;
340 default:
341 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
342 break;
348 * adg_dim_get_org:
349 * @dim: an #AdgDim
351 * Gets the origin (org) coordinates. The returned pair is internally
352 * owned and must not be freed or modified. This function is only
353 * useful in new dimension implementations.
355 * Returns: the org coordinates
357 const AdgPair *
358 adg_dim_get_org(AdgDim *dim)
360 AdgDimPrivate *data;
362 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
364 data = dim->data;
366 return &data->org;
370 * adg_dim_set_org:
371 * @dim: an #AdgDim
372 * @org: the org coordinates
374 * <note><para>
375 * This function is only useful in new dimension implementations.
376 * </para></note>
378 * Sets new org coordinates.
380 void
381 adg_dim_set_org(AdgDim *dim, const AdgPair *org)
383 AdgDimPrivate *data;
385 g_return_if_fail(ADG_IS_DIM(dim));
386 g_return_if_fail(org != NULL);
388 data = dim->data;
389 data->org = *org;
393 * adg_dim_set_org_explicit:
394 * @dim: an #AdgDim
395 * @org_x: x component of org
396 * @org_y: y component of org
398 * <note><para>
399 * This function is only useful in new dimension implementations.
400 * </para></note>
402 * Explicitely sets new org coordinates.
404 void
405 adg_dim_set_org_explicit(AdgDim *dim, gdouble org_x, gdouble org_y)
407 AdgDimPrivate *data;
409 g_return_if_fail(ADG_IS_DIM(dim));
411 data = dim->data;
412 data->org.x = org_x;
413 data->org.y = org_y;
417 * adg_dim_get_ref1:
418 * @dim: an #AdgDim
420 * Gets the ref1 coordinates. The returned pair is internally owned
421 * and must not be freed or modified.
423 * Returns: the ref1 coordinates
425 const AdgPair *
426 adg_dim_get_ref1(AdgDim *dim)
428 AdgDimPrivate *data;
430 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
432 data = dim->data;
434 return &data->ref1;
438 * adg_dim_get_ref2:
439 * @dim: an #AdgDim
441 * Gets the ref2 coordinates. The returned pair is internally owned
442 * and must not be freed or modified.
444 * Returns: the ref2 coordinates
446 const AdgPair *
447 adg_dim_get_ref2(AdgDim *dim)
449 AdgDimPrivate *data;
451 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
453 data = dim->data;
455 return &data->ref2;
459 * adg_dim_set_ref:
460 * @dim: an #AdgDim
461 * @ref1: the ref1 coordinates
462 * @ref2: the ref2 coordinates
464 * Shortcut to set ref1 and ref2 points at once.
466 void
467 adg_dim_set_ref(AdgDim *dim, const AdgPair *ref1, const AdgPair *ref2)
469 g_return_if_fail(ADG_IS_DIM(dim));
471 if (ref1 != NULL || ref2 != NULL) {
472 GObject *object;
473 AdgDimPrivate *data;
475 data = dim->data;
476 object = (GObject *) dim;
478 g_object_freeze_notify(object);
480 if (ref1 != NULL) {
481 data->ref1 = *ref1;
482 g_object_notify(object, "ref1");
485 if (ref2 != NULL) {
486 data->ref2 = *ref2;
487 g_object_notify(object, "ref2");
490 g_object_thaw_notify(object);
495 * adg_dim_set_ref_explicit:
496 * @dim: an #AdgDim
497 * @ref1_x: x component of pos1
498 * @ref1_y: y component of pos1
499 * @ref2_x: x component of pos2
500 * @ref2_y: y component of pos2
502 * Shortcut to set ref1 and ref2 points at once,
503 * using explicit coordinates.
505 void
506 adg_dim_set_ref_explicit(AdgDim *dim, gdouble ref1_x, gdouble ref1_y,
507 gdouble ref2_x, gdouble ref2_y)
509 AdgPair ref1;
510 AdgPair ref2;
512 ref1.x = ref1_x;
513 ref1.y = ref1_y;
514 ref2.x = ref2_x;
515 ref2.y = ref2_y;
517 adg_dim_set_ref(dim, &ref1, &ref2);
521 * adg_dim_get_pos1:
522 * @dim: an #AdgDim
524 * Gets the pos1 coordinates. The returned pair is internally owned
525 * and must not be freed or modified.
527 * Returns: the pos1 coordinates
529 const AdgPair *
530 adg_dim_get_pos1(AdgDim *dim)
532 AdgDimPrivate *data;
534 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
536 data = dim->data;
538 return &data->pos1;
542 * adg_dim_get_pos2:
543 * @dim: an #AdgDim
545 * Gets the pos2 coordinates. The returned pair is internally owned
546 * and must not be freed or modified.
548 * Returns: the pos2 coordinates
550 const AdgPair *
551 adg_dim_get_pos2(AdgDim *dim)
553 AdgDimPrivate *data;
555 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
557 data = dim->data;
559 return &data->pos2;
563 * adg_dim_set_pos:
564 * @dim: an #AdgDim
565 * @pos1: the pos1 coordinates
566 * @pos2: the pos2 coordinates
568 * Shortcut to set pos1 and pos2 points at once.
570 void
571 adg_dim_set_pos(AdgDim *dim, AdgPair *pos1, AdgPair *pos2)
573 g_return_if_fail(ADG_IS_DIM(dim));
575 if (pos1 != NULL || pos2 != NULL) {
576 AdgDimPrivate *data;
577 GObject *object;
579 data = dim->data;
580 object = (GObject *) dim;
582 g_object_freeze_notify(object);
584 if (pos1 != NULL) {
585 data->pos1 = *pos1;
586 g_object_notify(object, "pos1");
588 if (pos2 != NULL) {
589 data->pos2 = *pos2;
590 g_object_notify(object, "pos2");
593 g_object_thaw_notify(object);
598 * adg_dim_set_pos_explicit:
599 * @dim: an #AdgDim
600 * @pos1_x: x component of pos1
601 * @pos1_y: y component of pos1
602 * @pos2_x: x component of pos2
603 * @pos2_y: y component of pos2
605 * Shortcut to set pos1 and pos2 points at once,
606 * using explicit coordinates.
608 void
609 adg_dim_set_pos_explicit(AdgDim *dim, gdouble pos1_x, gdouble pos1_y,
610 gdouble pos2_x, gdouble pos2_y)
612 AdgPair pos1;
613 AdgPair pos2;
615 pos1.x = pos1_x;
616 pos1.y = pos1_y;
617 pos2.x = pos2_x;
618 pos2.y = pos2_y;
620 adg_dim_set_pos(dim, &pos1, &pos2);
624 * adg_dim_get_angle:
625 * @dim: an #AdgDim
627 * <note><para>
628 * This function is only useful in new dimension implementations.
629 * </para></note>
631 * Gets the dimension angle.
633 * Returns: the angle (in radians)
635 gdouble
636 adg_dim_get_angle(AdgDim *dim)
638 AdgDimPrivate *data;
640 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
642 data = dim->data;
644 return data->angle;
648 * adg_dim_set_angle:
649 * @dim: an #AdgDim
650 * @angle: the new angle (in radians)
652 * <note><para>
653 * This function is only useful in new dimension implementations.
654 * </para></note>
656 * Sets a new dimension angle. The @angle could be modified by this
657 * function to fit in the current dimension style mode, so do not
658 * expect to get the same value with adg_dim_get_angle().
660 void
661 adg_dim_set_angle(AdgDim *dim, gdouble angle)
663 g_return_if_fail(ADG_IS_DIM(dim));
665 if (set_angle(dim, 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 cairo_matrix_init_rotate(&map, data->angle);
1004 adg_entity_set_global_map(data->value_entity, &map);
1005 adg_entity_set_global_map(data->value_min_entity, &map);
1006 adg_entity_set_global_map(data->value_max_entity, &map);
1007 adg_entity_set_global_map(data->note_entity, &map);
1009 /* Basic value */
1010 adg_toy_text_get_extents((AdgToyText *) data->value_entity, cr, &extents);
1012 /* Limit values (value_min and value_max) */
1013 if (data->value_min != NULL || data->value_max != NULL) {
1014 cairo_text_extents_t min_extents = { 0 };
1015 cairo_text_extents_t max_extents = { 0 };
1016 gdouble spacing = 0;
1018 /* Low tolerance */
1019 if (data->value_min != NULL)
1020 adg_toy_text_get_extents((AdgToyText *) data->value_min_entity,
1021 cr, &min_extents);
1023 /* High tolerance */
1024 if (data->value_max != NULL)
1025 adg_toy_text_get_extents((AdgToyText *) data->value_max_entity,
1026 cr, &max_extents);
1028 shift = adg_dim_style_get_tolerance_shift(dim_style);
1029 if (data->value_min != NULL && data->value_max != NULL)
1030 spacing = adg_dim_style_get_tolerance_spacing(dim_style);
1032 cairo_matrix_init_translate(&map, extents.width + shift->x,
1033 (spacing + min_extents.height +
1034 max_extents.height) / 2 +
1035 shift->y - extents.height / 2);
1036 adg_entity_transform_global_map(data->value_min_entity, &map);
1037 cairo_matrix_translate(&map, 0, -min_extents.height - spacing);
1038 adg_entity_transform_global_map(data->value_max_entity, &map);
1040 extents.width += shift->x + MAX(min_extents.width, max_extents.width);
1043 /* Note */
1044 if (data->note != NULL) {
1045 cairo_text_extents_t note_extents;
1047 adg_toy_text_get_extents((AdgToyText *) data->note_entity,
1048 cr, &note_extents);
1049 shift = adg_dim_style_get_note_shift(dim_style);
1051 cairo_matrix_init_translate(&map, extents.width + shift->x, shift->y);
1052 adg_entity_transform_global_map(data->note_entity, &map);
1054 extents.width += shift->x + note_extents.width;
1057 /* Center and apply the style displacements */
1058 shift = adg_dim_style_get_quote_shift(dim_style);
1059 cairo_matrix_init_translate(&map, shift->x - extents.width / 2, shift->y);
1061 adg_entity_transform_global_map(data->value_entity, &map);
1062 adg_entity_transform_global_map(data->value_min_entity, &map);
1063 adg_entity_transform_global_map(data->value_max_entity, &map);
1064 adg_entity_transform_global_map(data->note_entity, &map);
1067 static gboolean
1068 set_angle(AdgDim *dim, gdouble angle)
1070 AdgDimPrivate *data = dim->data;
1072 angle = cpml_angle(angle);
1073 if (angle > G_PI_4 || angle <= -G_PI_4 * 3)
1074 angle = cpml_angle(angle + G_PI);
1076 if (angle == data->angle)
1077 return FALSE;
1079 data->angle = angle;
1081 return TRUE;
1084 static gboolean
1085 set_value(AdgDim *dim, const gchar *value)
1087 AdgDimPrivate *data;
1089 data = dim->data;
1091 if (adg_strcmp(value, data->value) == 0)
1092 return FALSE;
1094 g_free(data->value);
1095 data->value = g_strdup(value);
1096 adg_toy_text_set_label((AdgToyText *) data->value_entity, value);
1098 return TRUE;
1101 static gboolean
1102 set_value_min(AdgDim *dim, const gchar *value_min)
1104 AdgDimPrivate *data = dim->data;
1106 if (adg_strcmp(value_min, data->value_min) == 0)
1107 return FALSE;
1109 g_free(data->value_min);
1110 data->value_min = g_strdup(value_min);
1111 adg_toy_text_set_label((AdgToyText *) data->value_min_entity, value_min);
1113 return TRUE;
1116 static gboolean
1117 set_value_max(AdgDim *dim, const gchar *value_max)
1119 AdgDimPrivate *data = dim->data;
1121 if (adg_strcmp(value_max, data->value_max) == 0)
1122 return FALSE;
1124 g_free(data->value_max);
1125 data->value_max = g_strdup(value_max);
1126 adg_toy_text_set_label((AdgToyText *) data->value_max_entity, value_max);
1128 return TRUE;
1131 static gboolean
1132 set_note(AdgDim *dim, const gchar *note)
1134 AdgDimPrivate *data = dim->data;
1136 if (adg_strcmp(note, data->note) == 0)
1137 return FALSE;
1139 g_free(data->note);
1140 data->note = g_strdup(note);
1141 adg_toy_text_set_label((AdgToyText *) data->note_entity, note);
1143 return TRUE;
1146 static void
1147 detach_entity(AdgEntity **p_entity)
1149 if (*p_entity != NULL) {
1150 adg_entity_set_parent(*p_entity, NULL);
1151 g_object_unref(*p_entity);
1152 *p_entity = NULL;