[build] Bumped version to 0.5.1
[adg.git] / adg / adg-dim.c
blobc175498d1c3597aa663f8136392176a62b8740f3
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_DRESS,
49 PROP_REF1,
50 PROP_REF2,
51 PROP_POS1,
52 PROP_POS2,
53 PROP_ANGLE,
54 PROP_LEVEL,
55 PROP_OUTSIDE,
56 PROP_VALUE,
57 PROP_VALUE_MIN,
58 PROP_VALUE_MAX,
59 PROP_NOTE
63 static void dispose (GObject *object);
64 static void finalize (GObject *object);
65 static void get_property (GObject *object,
66 guint param_id,
67 GValue *value,
68 GParamSpec *pspec);
69 static void set_property (GObject *object,
70 guint param_id,
71 const GValue *value,
72 GParamSpec *pspec);
73 static gboolean invalidate (AdgEntity *entity);
74 static gchar * default_value (AdgDim *dim);
75 static void quote_layout (AdgDim *dim,
76 cairo_t *cr);
77 static gboolean set_angle (AdgDim *dim,
78 gdouble angle);
79 static gboolean set_value (AdgDim *dim,
80 const gchar *value);
81 static gboolean set_value_min (AdgDim *dim,
82 const gchar *value_min);
83 static gboolean set_value_max (AdgDim *dim,
84 const gchar *value_max);
85 static gboolean set_note (AdgDim *dim,
86 const gchar *note);
87 static void detach_entity (AdgEntity **p_entity);
90 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY);
93 static void
94 adg_dim_class_init(AdgDimClass *klass)
96 GObjectClass *gobject_class;
97 AdgEntityClass *entity_class;
98 GParamSpec *param;
100 gobject_class = (GObjectClass *) klass;
101 entity_class = (AdgEntityClass *) klass;
103 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
105 gobject_class->dispose = dispose;
106 gobject_class->finalize = finalize;
107 gobject_class->get_property = get_property;
108 gobject_class->set_property = set_property;
110 entity_class->invalidate = invalidate;
112 klass->default_value = default_value;
113 klass->quote_layout = quote_layout;
115 param = adg_param_spec_dress("dress",
116 P_("Dress Style"),
117 P_("The dress to use for rendering this dimension"),
118 ADG_DRESS_DIMENSION_REGULAR,
119 G_PARAM_READWRITE);
120 g_object_class_install_property(gobject_class, PROP_DRESS, param);
122 param = g_param_spec_boxed("ref1",
123 P_("Reference 1"),
124 P_("First reference point of the dimension"),
125 ADG_TYPE_PAIR,
126 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
127 g_object_class_install_property(gobject_class, PROP_REF1, param);
129 param = g_param_spec_boxed("ref2",
130 P_("Reference 2"),
131 P_("Second reference point of the dimension"),
132 ADG_TYPE_PAIR,
133 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
134 g_object_class_install_property(gobject_class, PROP_REF2, param);
136 param = g_param_spec_boxed("pos1",
137 P_("Position 1"),
138 P_("First position point: it will be computed with the level property to get the real dimension position"),
139 ADG_TYPE_PAIR, G_PARAM_READWRITE);
140 g_object_class_install_property(gobject_class, PROP_POS1, param);
142 param = g_param_spec_boxed("pos2",
143 P_("Position 2"),
144 P_("Second position point: it will be computed with the level property to get the real dimension position"),
145 ADG_TYPE_PAIR, G_PARAM_READWRITE);
146 g_object_class_install_property(gobject_class, PROP_POS2, param);
148 param = g_param_spec_double("angle",
149 P_("Angle"),
150 P_("The dimension direction, if relevant"),
151 -G_MAXDOUBLE, G_MAXDOUBLE, 0,
152 G_PARAM_READWRITE);
153 g_object_class_install_property(gobject_class, PROP_ANGLE, param);
155 param = g_param_spec_double("level",
156 P_("Level"),
157 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"),
158 -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
159 G_PARAM_READWRITE);
160 g_object_class_install_property(gobject_class, PROP_LEVEL, param);
162 param = g_param_spec_enum("outside",
163 P_("Outside"),
164 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"),
165 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
166 G_PARAM_READWRITE);
167 g_object_class_install_property(gobject_class, PROP_OUTSIDE, param);
169 param = g_param_spec_string("value",
170 P_("Basic Value"),
171 P_("The theoretically exact value for this quote: set to NULL to automatically get the default value"),
172 NULL, G_PARAM_READWRITE);
173 g_object_class_install_property(gobject_class, PROP_VALUE, param);
175 param = g_param_spec_string("value-min",
176 P_("Minimum Value or Low Tolerance"),
177 P_("The minimum value allowed or the lowest tolerance from value (depending of the dimension style): set to NULL to suppress"),
178 NULL, G_PARAM_READWRITE);
179 g_object_class_install_property(gobject_class, PROP_VALUE_MIN, param);
181 param = g_param_spec_string("value-max",
182 P_("Maximum Value or High Tolerance"),
183 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
184 NULL, G_PARAM_READWRITE);
185 g_object_class_install_property(gobject_class, PROP_VALUE_MAX, param);
187 param = g_param_spec_string("note",
188 P_("Note"),
189 P_("A custom note appended to the end of the quote"),
190 NULL, G_PARAM_READWRITE);
191 g_object_class_install_property(gobject_class, PROP_NOTE, param);
194 static void
195 adg_dim_init(AdgDim *dim)
197 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
198 AdgDimPrivate);
200 data->dress = ADG_DRESS_DIMENSION_REGULAR;
201 data->ref1.x = data->ref1.y = 0;
202 data->ref2.x = data->ref2.y = 0;
203 data->pos1.x = data->pos1.y = 0;
204 data->pos2.x = data->pos2.y = 0;
205 data->angle = 0;
206 data->level = 1;
207 data->value = NULL;
208 data->value_min = NULL;
209 data->value_max = NULL;
210 data->note = NULL;
212 data->value_entity = g_object_new(ADG_TYPE_TOY_TEXT,
213 "parent", dim, NULL);
214 data->value_min_entity = g_object_new(ADG_TYPE_TOY_TEXT,
215 "parent", dim, NULL);
216 data->value_max_entity = g_object_new(ADG_TYPE_TOY_TEXT,
217 "parent", dim, NULL);
218 data->note_entity = g_object_new(ADG_TYPE_TOY_TEXT,
219 "parent", dim, NULL);
221 dim->data = data;
224 static void
225 dispose(GObject *object)
227 AdgDimPrivate *data = ((AdgDim *) object)->data;
229 detach_entity(&data->value_entity);
230 detach_entity(&data->value_min_entity);
231 detach_entity(&data->value_max_entity);
232 detach_entity(&data->note_entity);
234 if (PARENT_OBJECT_CLASS->dispose != NULL)
235 PARENT_OBJECT_CLASS->dispose(object);
238 static void
239 finalize(GObject *object)
241 AdgDimPrivate *data = ((AdgDim *) object)->data;
243 g_free(data->value);
244 g_free(data->value_min);
245 g_free(data->value_max);
246 g_free(data->note);
248 if (PARENT_OBJECT_CLASS->finalize != NULL)
249 PARENT_OBJECT_CLASS->finalize(object);
252 static void
253 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
255 AdgDimPrivate *data = ((AdgDim *) object)->data;
257 switch (prop_id) {
258 case PROP_DRESS:
259 g_value_set_int(value, data->dress);
260 break;
261 case PROP_REF1:
262 g_value_set_boxed(value, &data->ref1);
263 break;
264 case PROP_REF2:
265 g_value_set_boxed(value, &data->ref2);
266 break;
267 case PROP_POS1:
268 g_value_set_boxed(value, &data->pos1);
269 break;
270 case PROP_POS2:
271 g_value_set_boxed(value, &data->pos1);
272 break;
273 case PROP_ANGLE:
274 g_value_set_double(value, data->angle);
275 break;
276 case PROP_LEVEL:
277 g_value_set_double(value, data->level);
278 break;
279 case PROP_OUTSIDE:
280 g_value_set_enum(value, data->outside);
281 break;
282 case PROP_VALUE:
283 g_value_set_string(value, data->value);
284 break;
285 case PROP_VALUE_MIN:
286 g_value_set_string(value, data->value_min);
287 break;
288 case PROP_VALUE_MAX:
289 g_value_set_string(value, data->value_max);
290 break;
291 case PROP_NOTE:
292 g_value_set_string(value, data->note);
293 break;
294 default:
295 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
296 break;
300 static void
301 set_property(GObject *object, guint prop_id,
302 const GValue *value, GParamSpec *pspec)
304 AdgDim *dim;
305 AdgDimPrivate *data;
307 dim = (AdgDim *) object;
308 data = dim->data;
310 switch (prop_id) {
311 case PROP_DRESS:
312 adg_dress_set(&data->dress, g_value_get_int(value));
313 break;
314 case PROP_REF1:
315 cpml_pair_copy(&data->ref1, (AdgPair *) g_value_get_boxed(value));
316 break;
317 case PROP_REF2:
318 cpml_pair_copy(&data->ref2, (AdgPair *) g_value_get_boxed(value));
319 break;
320 case PROP_POS1:
321 cpml_pair_copy(&data->pos1, (AdgPair *) g_value_get_boxed(value));
322 break;
323 case PROP_POS2:
324 cpml_pair_copy(&data->pos2, (AdgPair *) g_value_get_boxed(value));
325 break;
326 case PROP_ANGLE:
327 set_angle(dim, g_value_get_double(value));
328 break;
329 case PROP_LEVEL:
330 data->level = g_value_get_double(value);
331 break;
332 case PROP_OUTSIDE:
333 data->outside = g_value_get_enum(value);
334 break;
335 case PROP_VALUE:
336 set_value(dim, g_value_get_string(value));
337 break;
338 case PROP_VALUE_MIN:
339 set_value_min(dim, g_value_get_string(value));
340 break;
341 case PROP_VALUE_MAX:
342 set_value_max(dim, g_value_get_string(value));
343 break;
344 case PROP_NOTE:
345 set_note(dim, g_value_get_string(value));
346 break;
347 default:
348 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
349 break;
355 * adg_dim_get_dress:
356 * @dim: an #AdgDim
358 * Gets the dimension dress to be used in rendering @dim.
360 * Returns: the current dimension dress
362 AdgDress
363 adg_dim_get_dress(AdgDim *dim)
365 AdgDimPrivate *data;
367 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_DRESS_UNDEFINED);
369 data = dim->data;
371 return data->dress;
375 * adg_dim_set_dress:
376 * @dim: an #AdgDim
377 * @dress: the new #AdgDress to use
379 * Sets a new dimension dress to @dim. The new dress must be
380 * related to the original dress for this property: you cannot
381 * set a dress used for line styles to a dress managing fonts.
383 * The check is done by calling adg_dress_are_related() with
384 * @dress and the previous dress as arguments. Check out its
385 * documentation for details on what is a related dress.
387 void
388 adg_dim_set_dress(AdgDim *dim, AdgDress dress)
390 AdgDimPrivate *data;
392 g_return_if_fail(ADG_IS_DIM(dim));
394 data = dim->data;
396 if (adg_dress_set(&data->dress, dress))
397 g_object_notify((GObject *) dim, "dress");
401 * adg_dim_get_org:
402 * @dim: an #AdgDim
404 * Gets the origin (org) coordinates. The returned pair is internally
405 * owned and must not be freed or modified. This function is only
406 * useful in new dimension implementations.
408 * Returns: the org coordinates
410 const AdgPair *
411 adg_dim_get_org(AdgDim *dim)
413 AdgDimPrivate *data;
415 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
417 data = dim->data;
419 return &data->org;
423 * adg_dim_set_org:
424 * @dim: an #AdgDim
425 * @org: the org coordinates
427 * <note><para>
428 * This function is only useful in new dimension implementations.
429 * </para></note>
431 * Sets new org coordinates.
433 void
434 adg_dim_set_org(AdgDim *dim, const AdgPair *org)
436 AdgDimPrivate *data;
438 g_return_if_fail(ADG_IS_DIM(dim));
439 g_return_if_fail(org != NULL);
441 data = dim->data;
442 data->org = *org;
446 * adg_dim_set_org_explicit:
447 * @dim: an #AdgDim
448 * @org_x: x component of org
449 * @org_y: y component of org
451 * <note><para>
452 * This function is only useful in new dimension implementations.
453 * </para></note>
455 * Explicitely sets new org coordinates.
457 void
458 adg_dim_set_org_explicit(AdgDim *dim, gdouble org_x, gdouble org_y)
460 AdgDimPrivate *data;
462 g_return_if_fail(ADG_IS_DIM(dim));
464 data = dim->data;
465 data->org.x = org_x;
466 data->org.y = org_y;
470 * adg_dim_get_ref1:
471 * @dim: an #AdgDim
473 * Gets the ref1 coordinates. The returned pair is internally owned
474 * and must not be freed or modified.
476 * Returns: the ref1 coordinates
478 const AdgPair *
479 adg_dim_get_ref1(AdgDim *dim)
481 AdgDimPrivate *data;
483 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
485 data = dim->data;
487 return &data->ref1;
491 * adg_dim_get_ref2:
492 * @dim: an #AdgDim
494 * Gets the ref2 coordinates. The returned pair is internally owned
495 * and must not be freed or modified.
497 * Returns: the ref2 coordinates
499 const AdgPair *
500 adg_dim_get_ref2(AdgDim *dim)
502 AdgDimPrivate *data;
504 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
506 data = dim->data;
508 return &data->ref2;
512 * adg_dim_set_ref:
513 * @dim: an #AdgDim
514 * @ref1: the ref1 coordinates
515 * @ref2: the ref2 coordinates
517 * Shortcut to set ref1 and ref2 points at once.
519 void
520 adg_dim_set_ref(AdgDim *dim, const AdgPair *ref1, const AdgPair *ref2)
522 g_return_if_fail(ADG_IS_DIM(dim));
524 if (ref1 != NULL || ref2 != NULL) {
525 GObject *object;
526 AdgDimPrivate *data;
528 data = dim->data;
529 object = (GObject *) dim;
531 g_object_freeze_notify(object);
533 if (ref1 != NULL) {
534 data->ref1 = *ref1;
535 g_object_notify(object, "ref1");
538 if (ref2 != NULL) {
539 data->ref2 = *ref2;
540 g_object_notify(object, "ref2");
543 g_object_thaw_notify(object);
548 * adg_dim_set_ref_explicit:
549 * @dim: an #AdgDim
550 * @ref1_x: x component of pos1
551 * @ref1_y: y component of pos1
552 * @ref2_x: x component of pos2
553 * @ref2_y: y component of pos2
555 * Shortcut to set ref1 and ref2 points at once,
556 * using explicit coordinates.
558 void
559 adg_dim_set_ref_explicit(AdgDim *dim, gdouble ref1_x, gdouble ref1_y,
560 gdouble ref2_x, gdouble ref2_y)
562 AdgPair ref1;
563 AdgPair ref2;
565 ref1.x = ref1_x;
566 ref1.y = ref1_y;
567 ref2.x = ref2_x;
568 ref2.y = ref2_y;
570 adg_dim_set_ref(dim, &ref1, &ref2);
574 * adg_dim_get_pos1:
575 * @dim: an #AdgDim
577 * Gets the pos1 coordinates. The returned pair is internally owned
578 * and must not be freed or modified.
580 * Returns: the pos1 coordinates
582 const AdgPair *
583 adg_dim_get_pos1(AdgDim *dim)
585 AdgDimPrivate *data;
587 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
589 data = dim->data;
591 return &data->pos1;
595 * adg_dim_get_pos2:
596 * @dim: an #AdgDim
598 * Gets the pos2 coordinates. The returned pair is internally owned
599 * and must not be freed or modified.
601 * Returns: the pos2 coordinates
603 const AdgPair *
604 adg_dim_get_pos2(AdgDim *dim)
606 AdgDimPrivate *data;
608 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
610 data = dim->data;
612 return &data->pos2;
616 * adg_dim_set_pos:
617 * @dim: an #AdgDim
618 * @pos1: the pos1 coordinates
619 * @pos2: the pos2 coordinates
621 * Shortcut to set pos1 and pos2 points at once.
623 void
624 adg_dim_set_pos(AdgDim *dim, AdgPair *pos1, AdgPair *pos2)
626 g_return_if_fail(ADG_IS_DIM(dim));
628 if (pos1 != NULL || pos2 != NULL) {
629 AdgDimPrivate *data;
630 GObject *object;
632 data = dim->data;
633 object = (GObject *) dim;
635 g_object_freeze_notify(object);
637 if (pos1 != NULL) {
638 data->pos1 = *pos1;
639 g_object_notify(object, "pos1");
641 if (pos2 != NULL) {
642 data->pos2 = *pos2;
643 g_object_notify(object, "pos2");
646 g_object_thaw_notify(object);
651 * adg_dim_set_pos_explicit:
652 * @dim: an #AdgDim
653 * @pos1_x: x component of pos1
654 * @pos1_y: y component of pos1
655 * @pos2_x: x component of pos2
656 * @pos2_y: y component of pos2
658 * Shortcut to set pos1 and pos2 points at once,
659 * using explicit coordinates.
661 void
662 adg_dim_set_pos_explicit(AdgDim *dim, gdouble pos1_x, gdouble pos1_y,
663 gdouble pos2_x, gdouble pos2_y)
665 AdgPair pos1;
666 AdgPair pos2;
668 pos1.x = pos1_x;
669 pos1.y = pos1_y;
670 pos2.x = pos2_x;
671 pos2.y = pos2_y;
673 adg_dim_set_pos(dim, &pos1, &pos2);
677 * adg_dim_get_angle:
678 * @dim: an #AdgDim
680 * <note><para>
681 * This function is only useful in new dimension implementations.
682 * </para></note>
684 * Gets the dimension angle.
686 * Returns: the angle (in radians)
688 gdouble
689 adg_dim_get_angle(AdgDim *dim)
691 AdgDimPrivate *data;
693 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
695 data = dim->data;
697 return data->angle;
701 * adg_dim_set_angle:
702 * @dim: an #AdgDim
703 * @angle: the new angle (in radians)
705 * <note><para>
706 * This function is only useful in new dimension implementations.
707 * </para></note>
709 * Sets a new dimension angle. The @angle could be modified by this
710 * function to fit in the current dimension style mode, so do not
711 * expect to get the same value with adg_dim_get_angle().
713 void
714 adg_dim_set_angle(AdgDim *dim, gdouble angle)
716 g_return_if_fail(ADG_IS_DIM(dim));
718 if (set_angle(dim, angle))
719 g_object_notify((GObject *) dim, "angle");
723 * adg_dim_get_level:
724 * @dim: an #AdgDim
726 * Gets the level of this dimension.
728 * Returns: the level value
730 gdouble
731 adg_dim_get_level(AdgDim *dim)
733 AdgDimPrivate *data;
735 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
737 data = dim->data;
739 return data->level;
743 * adg_dim_set_level:
744 * @dim: an #AdgDim
745 * @level: the new level
747 * Sets a new level for this dimension. The level is used to
748 * stack the quotes using a spacing value from dim_style
749 * (specified in global space).
751 void
752 adg_dim_set_level(AdgDim *dim, gdouble level)
754 AdgDimPrivate *data;
756 g_return_if_fail(ADG_IS_DIM(dim));
758 data = dim->data;
759 data->level = level;
761 g_object_notify((GObject *) dim, "level");
765 * adg_dim_get_outside:
766 * @dim: an #AdgDim
768 * Gets the state of the #AdgDim:outside property: check the property
769 * documentation for further details.
771 * Returns: the current flag state
773 AdgThreeState
774 adg_dim_get_outside(AdgDim *dim)
776 AdgDimPrivate *data;
778 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
780 data = dim->data;
782 return data->outside;
786 * adg_dim_set_outside:
787 * @dim: an #AdgDim
788 * @outside: the new outside state
790 * Sets a new state for the #AdgDim:outside flag: check the property
791 * documentation for further details.
793 void
794 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
796 AdgDimPrivate *data;
798 g_return_if_fail(ADG_IS_DIM(dim));
800 data = dim->data;
801 data->outside = outside;
803 g_object_notify((GObject *) dim, "outside");
807 * adg_dim_get_value:
808 * @dim: an #AdgDim
810 * Gets the value text. The string is internally owned and
811 * must not be freed or modified.
813 * Returns: the value text
815 const gchar *
816 adg_dim_get_value(AdgDim *dim)
818 AdgDimPrivate *data;
820 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
822 data = dim->data;
824 return data->value;
828 * adg_dim_set_value:
829 * @dim: an #AdgDim
830 * @value: the value text
832 * Explicitely sets the text to use as value. If @value is %NULL or
833 * was never set, an automatic text is calculated using the format
834 * specified in the current #AdgDimStyle and getting its value by
835 * calling the default_value() virtual method.
837 void
838 adg_dim_set_value(AdgDim *dim, const gchar *value)
840 g_return_if_fail(ADG_IS_DIM(dim));
842 if (set_value(dim, value))
843 g_object_notify((GObject *) dim, "value");
847 * adg_dim_get_value_min:
848 * @dim: an #AdgDim
850 * Gets the minimum value text or %NULL on minimum value disabled.
851 * The string is internally owned and must not be freed or modified.
853 * Returns: the mimimum value text
855 const gchar *
856 adg_dim_get_value_min(AdgDim *dim)
858 AdgDimPrivate *data;
860 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
862 data = dim->data;
864 return data->value_min;
868 * adg_dim_set_value_min:
869 * @dim: an #AdgDim
870 * @value_min: the new minimum value
872 * Sets the minimum value. Use %NULL as @value_min to disable it.
874 void
875 adg_dim_set_value_min(AdgDim *dim, const gchar *value_min)
877 g_return_if_fail(ADG_IS_DIM(dim));
879 if (set_value_min(dim, value_min))
880 g_object_notify((GObject *) dim, "value-min");
884 * adg_dim_get_value_max:
885 * @dim: an #AdgDim
887 * Gets the maximum value text or %NULL on maximum value disabled.
888 * The string is internally owned and must not be freed or modified.
890 * Returns: the maximum value text
892 const gchar *
893 adg_dim_get_value_max(AdgDim *dim)
895 AdgDimPrivate *data;
897 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
899 data = dim->data;
901 return data->value_max;
905 * adg_dim_set_value_max:
906 * @dim: an #AdgDim
907 * @value_max: the new maximum value
909 * Sets the maximum value. Use %NULL as @value_max to disable it.
911 void
912 adg_dim_set_value_max(AdgDim *dim, const gchar *value_max)
914 g_return_if_fail(ADG_IS_DIM(dim));
916 if (set_value_max(dim, value_max))
917 g_object_notify((GObject *) dim, "value-max");
921 * adg_dim_set_tolerances:
922 * @dim: an #AdgDim
923 * @value_min: the new minumum value
924 * @value_max: the new maximum value
926 * Shortcut to set both the tolerances at once.
928 void
929 adg_dim_set_tolerances(AdgDim *dim,
930 const gchar *value_min, const gchar *value_max)
932 g_return_if_fail(ADG_IS_DIM(dim));
934 g_object_freeze_notify((GObject *) dim);
935 adg_dim_set_value_min(dim, value_min);
936 adg_dim_set_value_max(dim, value_max);
937 g_object_thaw_notify((GObject *) dim);
941 * adg_dim_get_note:
942 * @dim: and #AdgDim
944 * Gets the note text or %NULL if the note is not used. The string is
945 * internally owned and must not be freed or modified.
947 * Returns: the note text
949 const gchar *
950 adg_dim_get_note(AdgDim *dim)
952 AdgDimPrivate *data;
954 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
956 data = dim->data;
958 return data->note;
962 * adg_dim_set_note:
963 * @dim: an #AdgDim
964 * @note: the new note
966 * Sets a new note text, usually appended at the end of the dimension text.
968 void
969 adg_dim_set_note(AdgDim *dim, const gchar *note)
971 g_return_if_fail(ADG_IS_DIM(dim));
973 if (set_note(dim, note))
974 g_object_notify((GObject *) dim, "note");
978 * adg_dim_render_quote:
979 * @dim: an #AdgDim object
980 * @cr: a #cairo_t drawing context
982 * <note><para>
983 * This function is only useful in new dimension implementations.
984 * </para></note>
986 * Renders the quote of @dim at the @org position.
988 void
989 adg_dim_render_quote(AdgDim *dim, cairo_t *cr)
991 AdgDimPrivate *data;
992 AdgDimStyle *dim_style;
994 g_return_if_fail(ADG_IS_DIM(dim));
996 data = dim->data;
997 dim_style = (AdgDimStyle *)
998 adg_entity_style((AdgEntity *) dim, data->dress);
1000 /* Check if the basic value text needs to be automatically generated */
1001 if (data->value == NULL) {
1002 gchar *text = ADG_DIM_GET_CLASS(dim)->default_value(dim);
1003 adg_toy_text_set_label((AdgToyText *) data->value_entity, text);
1004 g_free(text);
1007 /* Set the internal toy_text dresses */
1008 adg_toy_text_set_dress((AdgToyText *) data->value_entity,
1009 adg_dim_style_get_value_dress(dim_style));
1010 adg_toy_text_set_dress((AdgToyText *) data->value_min_entity,
1011 adg_dim_style_get_down_dress(dim_style));
1012 adg_toy_text_set_dress((AdgToyText *) data->value_max_entity,
1013 adg_dim_style_get_up_dress(dim_style));
1014 adg_toy_text_set_dress((AdgToyText *) data->note_entity,
1015 adg_dim_style_get_note_dress(dim_style));
1017 ADG_DIM_GET_CLASS(dim)->quote_layout(dim, cr);
1019 adg_entity_render(data->value_entity, cr);
1020 adg_entity_render(data->value_min_entity, cr);
1021 adg_entity_render(data->value_max_entity, cr);
1022 adg_entity_render(data->note_entity, cr);
1025 static gboolean
1026 invalidate(AdgEntity *entity)
1028 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1030 adg_entity_invalidate(data->value_entity);
1031 adg_entity_invalidate(data->value_min_entity);
1032 adg_entity_invalidate(data->value_max_entity);
1033 adg_entity_invalidate(data->note_entity);
1035 return TRUE;
1038 static gchar *
1039 default_value(AdgDim *dim)
1041 g_warning("AdgDim::default_value not implemented for `%s'",
1042 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
1043 return g_strdup("undef");
1046 static void
1047 quote_layout(AdgDim *dim, cairo_t *cr)
1049 AdgEntity *entity;
1050 AdgDimPrivate *data;
1051 AdgDimStyle *dim_style;
1052 cairo_text_extents_t extents;
1053 AdgMatrix map;
1054 const AdgPair *shift;
1056 entity = (AdgEntity *) dim;
1057 data = dim->data;
1058 dim_style = (AdgDimStyle *) adg_entity_style(entity, data->dress);
1060 /* Initialize local maps to the origin */
1061 cairo_matrix_init_translate(&map, data->org.x, data->org.y);
1063 adg_entity_set_local_map(data->value_entity, &map);
1064 adg_entity_set_local_map(data->value_min_entity, &map);
1065 adg_entity_set_local_map(data->value_max_entity, &map);
1066 adg_entity_set_local_map(data->note_entity, &map);
1068 /* Initialize global maps to the quote rotation angle */
1069 cairo_matrix_init_rotate(&map, data->angle);
1071 adg_entity_set_global_map(data->value_entity, &map);
1072 adg_entity_set_global_map(data->value_min_entity, &map);
1073 adg_entity_set_global_map(data->value_max_entity, &map);
1074 adg_entity_set_global_map(data->note_entity, &map);
1076 /* Basic value */
1077 adg_toy_text_get_extents((AdgToyText *) data->value_entity, cr, &extents);
1079 /* Limit values (value_min and value_max) */
1080 if (data->value_min != NULL || data->value_max != NULL) {
1081 cairo_text_extents_t min_extents = { 0 };
1082 cairo_text_extents_t max_extents = { 0 };
1083 gdouble spacing = 0;
1085 /* Low tolerance */
1086 if (data->value_min != NULL)
1087 adg_toy_text_get_extents((AdgToyText *) data->value_min_entity,
1088 cr, &min_extents);
1090 /* High tolerance */
1091 if (data->value_max != NULL)
1092 adg_toy_text_get_extents((AdgToyText *) data->value_max_entity,
1093 cr, &max_extents);
1095 shift = adg_dim_style_get_tolerance_shift(dim_style);
1096 if (data->value_min != NULL && data->value_max != NULL)
1097 spacing = adg_dim_style_get_tolerance_spacing(dim_style);
1099 cairo_matrix_init_translate(&map, extents.width + shift->x,
1100 (spacing + min_extents.height +
1101 max_extents.height) / 2 +
1102 shift->y - extents.height / 2);
1103 adg_entity_transform_global_map(data->value_min_entity, &map);
1104 cairo_matrix_translate(&map, 0, -min_extents.height - spacing);
1105 adg_entity_transform_global_map(data->value_max_entity, &map);
1107 extents.width += shift->x + MAX(min_extents.width, max_extents.width);
1110 /* Note */
1111 if (data->note != NULL) {
1112 cairo_text_extents_t note_extents;
1114 adg_toy_text_get_extents((AdgToyText *) data->note_entity,
1115 cr, &note_extents);
1116 shift = adg_dim_style_get_note_shift(dim_style);
1118 cairo_matrix_init_translate(&map, extents.width + shift->x, shift->y);
1119 adg_entity_transform_global_map(data->note_entity, &map);
1121 extents.width += shift->x + note_extents.width;
1124 /* Center and apply the style displacements */
1125 shift = adg_dim_style_get_quote_shift(dim_style);
1126 cairo_matrix_init_translate(&map, shift->x - extents.width / 2, shift->y);
1128 adg_entity_transform_global_map(data->value_entity, &map);
1129 adg_entity_transform_global_map(data->value_min_entity, &map);
1130 adg_entity_transform_global_map(data->value_max_entity, &map);
1131 adg_entity_transform_global_map(data->note_entity, &map);
1134 static gboolean
1135 set_angle(AdgDim *dim, gdouble angle)
1137 AdgDimPrivate *data = dim->data;
1139 angle = cpml_angle(angle);
1140 if (angle > G_PI_4 || angle <= -G_PI_4 * 3)
1141 angle = cpml_angle(angle + G_PI);
1143 if (angle == data->angle)
1144 return FALSE;
1146 data->angle = angle;
1148 return TRUE;
1151 static gboolean
1152 set_value(AdgDim *dim, const gchar *value)
1154 AdgDimPrivate *data;
1156 data = dim->data;
1158 if (adg_strcmp(value, data->value) == 0)
1159 return FALSE;
1161 g_free(data->value);
1162 data->value = g_strdup(value);
1163 adg_toy_text_set_label((AdgToyText *) data->value_entity, value);
1165 return TRUE;
1168 static gboolean
1169 set_value_min(AdgDim *dim, const gchar *value_min)
1171 AdgDimPrivate *data = dim->data;
1173 if (adg_strcmp(value_min, data->value_min) == 0)
1174 return FALSE;
1176 g_free(data->value_min);
1177 data->value_min = g_strdup(value_min);
1178 adg_toy_text_set_label((AdgToyText *) data->value_min_entity, value_min);
1180 return TRUE;
1183 static gboolean
1184 set_value_max(AdgDim *dim, const gchar *value_max)
1186 AdgDimPrivate *data = dim->data;
1188 if (adg_strcmp(value_max, data->value_max) == 0)
1189 return FALSE;
1191 g_free(data->value_max);
1192 data->value_max = g_strdup(value_max);
1193 adg_toy_text_set_label((AdgToyText *) data->value_max_entity, value_max);
1195 return TRUE;
1198 static gboolean
1199 set_note(AdgDim *dim, const gchar *note)
1201 AdgDimPrivate *data = dim->data;
1203 if (adg_strcmp(note, data->note) == 0)
1204 return FALSE;
1206 g_free(data->note);
1207 data->note = g_strdup(note);
1208 adg_toy_text_set_label((AdgToyText *) data->note_entity, note);
1210 return TRUE;
1213 static void
1214 detach_entity(AdgEntity **p_entity)
1216 if (*p_entity != NULL) {
1217 adg_entity_set_parent(*p_entity, NULL);
1218 g_object_unref(*p_entity);
1219 *p_entity = NULL;