[ADG] The extents are now expressed on identity matrix
[adg.git] / adg / adg-dim.c
blobd80fc1ecfa2a83465e1384b130c58109566db9c2
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 /**
22 * SECTION:adg-dim
23 * @short_description: Root abstract class for all dimension entities
25 * The #AdgDim class is the base stub of all the dimension entities.
26 **/
28 /**
29 * AdgDim:
31 * All fields are private and should not be used directly.
32 * Use its public methods instead.
33 **/
36 #include "adg-dim.h"
37 #include "adg-dim-private.h"
38 #include "adg-dim-style.h"
39 #include "adg-dress-builtins.h"
40 #include "adg-toy-text.h"
41 #include "adg-type-builtins.h"
42 #include "adg-intl.h"
44 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_dim_parent_class)
45 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_dim_parent_class)
48 enum {
49 PROP_0,
50 PROP_DIM_DRESS,
51 PROP_REF1,
52 PROP_REF2,
53 PROP_POS,
54 PROP_LEVEL,
55 PROP_OUTSIDE,
56 PROP_VALUE,
57 PROP_MIN,
58 PROP_MAX
62 static void dispose (GObject *object);
63 static void finalize (GObject *object);
64 static void get_property (GObject *object,
65 guint param_id,
66 GValue *value,
67 GParamSpec *pspec);
68 static void set_property (GObject *object,
69 guint param_id,
70 const GValue *value,
71 GParamSpec *pspec);
72 static void global_changed (AdgEntity *entity);
73 static void local_changed (AdgEntity *entity);
74 static void invalidate (AdgEntity *entity);
75 static void arrange (AdgEntity *entity);
76 static gchar * default_value (AdgDim *dim);
77 static gdouble quote_angle (gdouble angle);
78 static gboolean set_dim_dress (AdgDim *dim,
79 AdgDress dress);
80 static gboolean set_value (AdgDim *dim,
81 const gchar *value);
82 static gboolean set_min (AdgDim *dim,
83 const gchar *min);
84 static gboolean set_max (AdgDim *dim,
85 const gchar *max);
88 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY);
91 static void
92 adg_dim_class_init(AdgDimClass *klass)
94 GObjectClass *gobject_class;
95 AdgEntityClass *entity_class;
96 GParamSpec *param;
98 gobject_class = (GObjectClass *) klass;
99 entity_class = (AdgEntityClass *) klass;
101 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
103 gobject_class->dispose = dispose;
104 gobject_class->finalize = finalize;
105 gobject_class->get_property = get_property;
106 gobject_class->set_property = set_property;
108 entity_class->global_changed = global_changed;
109 entity_class->local_changed = local_changed;
110 entity_class->invalidate = invalidate;
111 entity_class->arrange = arrange;
113 klass->quote_angle = quote_angle;
114 klass->default_value = default_value;
116 param = adg_param_spec_dress("dim-dress",
117 P_("Dimension Dress"),
118 P_("The dress to use for rendering this dimension"),
119 ADG_DRESS_DIMENSION,
120 G_PARAM_READWRITE);
121 g_object_class_install_property(gobject_class, PROP_DIM_DRESS, param);
123 param = g_param_spec_boxed("ref1",
124 P_("Reference 1"),
125 P_("First reference point of the dimension"),
126 ADG_TYPE_POINT,
127 G_PARAM_READWRITE);
128 g_object_class_install_property(gobject_class, PROP_REF1, param);
130 param = g_param_spec_boxed("ref2",
131 P_("Reference 2"),
132 P_("Second reference point of the dimension"),
133 ADG_TYPE_POINT,
134 G_PARAM_READWRITE);
135 g_object_class_install_property(gobject_class, PROP_REF2, param);
137 param = g_param_spec_boxed("pos",
138 P_("Position"),
139 P_("The reference position in local space of the quote: it will be combined with \"level\" to get the real quote position"),
140 ADG_TYPE_POINT,
141 G_PARAM_READWRITE);
142 g_object_class_install_property(gobject_class, PROP_POS, param);
144 param = g_param_spec_double("level",
145 P_("Level"),
146 P_("The dimension level, that is the factor to multiply the baseline spacing (defined in the dimension style) to get the offset from pos where the quote should be rendered"),
147 -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
148 G_PARAM_READWRITE);
149 g_object_class_install_property(gobject_class, PROP_LEVEL, param);
151 param = g_param_spec_enum("outside",
152 P_("Outside"),
153 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"),
154 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
155 G_PARAM_READWRITE);
156 g_object_class_install_property(gobject_class, PROP_OUTSIDE, param);
158 param = g_param_spec_string("value",
159 P_("Basic Value"),
160 P_("The theoretically exact value for this quote: set to NULL to automatically get the default value"),
161 NULL,
162 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,
169 G_PARAM_READWRITE);
170 g_object_class_install_property(gobject_class, PROP_MIN, param);
172 param = g_param_spec_string("value-max",
173 P_("Maximum Value or High Tolerance"),
174 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
175 NULL,
176 G_PARAM_READWRITE);
177 g_object_class_install_property(gobject_class, PROP_MAX, param);
180 static void
181 adg_dim_init(AdgDim *dim)
183 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
184 AdgDimPrivate);
186 data->dim_dress = ADG_DRESS_DIMENSION;
187 data->ref1 = NULL;
188 data->ref2 = NULL;
189 data->pos = NULL;
190 data->level = 1;
191 data->outside = ADG_THREE_STATE_UNKNOWN;
192 data->value = NULL;
193 data->min = NULL;
194 data->max = NULL;
196 dim->data = data;
199 static void
200 dispose(GObject *object)
202 AdgDimPrivate *data = ((AdgDim *) object)->data;
204 if (data->quote.entity != NULL) {
205 g_object_unref(data->quote.entity);
206 data->quote.entity = NULL;
208 if (data->ref1 != NULL) {
209 adg_point_destroy(data->ref1);
210 data->ref1 = NULL;
212 if (data->ref2 != NULL) {
213 adg_point_destroy(data->ref2);
214 data->ref2 = NULL;
216 if (data->pos != NULL) {
217 adg_point_destroy(data->pos);
218 data->pos = NULL;
221 if (PARENT_OBJECT_CLASS->dispose)
222 PARENT_OBJECT_CLASS->dispose(object);
225 static void
226 finalize(GObject *object)
228 AdgDimPrivate *data = ((AdgDim *) object)->data;
230 g_free(data->value);
231 g_free(data->min);
232 g_free(data->max);
234 if (PARENT_OBJECT_CLASS->finalize)
235 PARENT_OBJECT_CLASS->finalize(object);
238 static void
239 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
241 AdgDimPrivate *data = ((AdgDim *) object)->data;
243 switch (prop_id) {
244 case PROP_DIM_DRESS:
245 g_value_set_int(value, data->dim_dress);
246 break;
247 case PROP_REF1:
248 g_value_set_boxed(value, data->ref1);
249 break;
250 case PROP_REF2:
251 g_value_set_boxed(value, data->ref2);
252 break;
253 case PROP_POS:
254 g_value_set_boxed(value, data->pos);
255 break;
256 case PROP_LEVEL:
257 g_value_set_double(value, data->level);
258 break;
259 case PROP_OUTSIDE:
260 g_value_set_enum(value, data->outside);
261 break;
262 case PROP_VALUE:
263 g_value_set_string(value, data->value);
264 break;
265 case PROP_MIN:
266 g_value_set_string(value, data->min);
267 break;
268 case PROP_MAX:
269 g_value_set_string(value, data->max);
270 break;
271 default:
272 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
273 break;
277 static void
278 set_property(GObject *object, guint prop_id,
279 const GValue *value, GParamSpec *pspec)
281 AdgDim *dim;
282 AdgDimPrivate *data;
284 dim = (AdgDim *) object;
285 data = dim->data;
287 switch (prop_id) {
288 case PROP_DIM_DRESS:
289 set_dim_dress(dim, g_value_get_int(value));
290 break;
291 case PROP_REF1:
292 if (data->ref1 != NULL)
293 adg_point_destroy(data->ref1);
294 data->ref1 = g_value_dup_boxed(value);
295 break;
296 case PROP_REF2:
297 if (data->ref2 != NULL)
298 adg_point_destroy(data->ref2);
299 data->ref2 = g_value_dup_boxed(value);
300 break;
301 case PROP_POS:
302 if (data->pos != NULL)
303 adg_point_destroy(data->pos);
304 data->pos = g_value_dup_boxed(value);
305 break;
306 case PROP_LEVEL:
307 data->level = g_value_get_double(value);
308 break;
309 case PROP_OUTSIDE:
310 data->outside = g_value_get_enum(value);
311 break;
312 case PROP_VALUE:
313 set_value(dim, g_value_get_string(value));
314 break;
315 case PROP_MIN:
316 set_min(dim, g_value_get_string(value));
317 break;
318 case PROP_MAX:
319 set_max(dim, g_value_get_string(value));
320 break;
321 default:
322 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
323 break;
329 * adg_dim_set_dim_dress:
330 * @dim: an #AdgDim
331 * @dress: the new #AdgDress to use
333 * Sets a new dimension dress to @dim. The new dress must be
334 * related to the original dress for this property: you cannot
335 * set a dress used for line styles to a dress managing fonts.
337 * The check is done by calling adg_dress_are_related() with
338 * @dress and the previous dress as arguments. Check out its
339 * documentation for details on what is a related dress.
341 void
342 adg_dim_set_dim_dress(AdgDim *dim, AdgDress dress)
344 g_return_if_fail(ADG_IS_DIM(dim));
346 if (set_dim_dress(dim, dress))
347 g_object_notify((GObject *) dim, "dim-dress");
351 * adg_dim_get_dim_dress:
352 * @dim: an #AdgDim
354 * Gets the dimension dress to be used in rendering @dim.
356 * Returns: the current dimension dress
358 AdgDress
359 adg_dim_get_dim_dress(AdgDim *dim)
361 AdgDimPrivate *data;
363 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_DRESS_UNDEFINED);
365 data = dim->data;
367 return data->dim_dress;
371 * adg_dim_set_ref:
372 * @dim: an #AdgDim
373 * @ref1: the ref1 coordinates
374 * @ref2: the ref2 coordinates
376 * Sets the #AdgDim:ref1 and #AdgDim:ref2 reference points
377 * using @ref1 and @ref2 pairs. @ref1 or @ref2 could be
378 * %NULL (but not both), in which case only the non-null
379 * reference point is changed.
381 void
382 adg_dim_set_ref(AdgDim *dim, const AdgPair *ref1, const AdgPair *ref2)
384 GObject *object;
385 AdgDimPrivate *data;
387 g_return_if_fail(ADG_IS_DIM(dim));
388 g_return_if_fail(ref1 != NULL || ref2 != NULL);
390 data = dim->data;
391 object = (GObject *) dim;
393 g_object_freeze_notify(object);
395 if (ref1 != NULL) {
396 if (data->ref1 == NULL)
397 data->ref1 = adg_point_new();
399 adg_point_set(data->ref1, ref1);
401 g_object_notify(object, "ref1");
404 if (ref2 != NULL) {
405 if (data->ref2 == NULL)
406 data->ref2 = adg_point_new();
408 adg_point_set(data->ref2, ref2);
410 g_object_notify(object, "ref2");
413 g_object_thaw_notify(object);
417 * adg_dim_set_ref_explicit:
418 * @dim: an #AdgDim
419 * @ref1_x: x coordinate of ref1
420 * @ref1_y: y coordinate of ref1
421 * @ref2_x: x coordinate of ref2
422 * @ref2_y: y coordinate of ref2
424 * Works in the same way as adg_dim_set_ref() but using
425 * explicit coordinates instead of #AdgPair args. The
426 * notable difference is that, by using gdouble values,
427 * you can't set only a single reference point.
429 void
430 adg_dim_set_ref_explicit(AdgDim *dim,
431 gdouble ref1_x, gdouble ref1_y,
432 gdouble ref2_x, gdouble ref2_y)
434 AdgPair ref1, ref2;
436 ref1.x = ref1_x;
437 ref1.y = ref1_y;
438 ref2.x = ref2_x;
439 ref2.y = ref2_y;
441 adg_dim_set_ref(dim, &ref1, &ref2);
445 * adg_dim_set_ref_from_model:
446 * @dim: an #AdgDim
447 * @model: the source #AdgModel
448 * @ref1: name of the pair in @model to use as ref1
449 * @ref2: name of the pair in @model to use as ref2
451 * Sets #AdgDim:ref1 and #AdgDim:ref2 properties by linking
452 * them to the @ref1 and @ref2 named pairs in @model. @ref1
453 * or @ref2 could be %NULL (but not both), in which case
454 * only the non-null reference point is changed.
456 * Using this function twice you can also link the reference
457 * points to named pairs taken from different models:
459 * |[
460 * adg_dim_set_ref_from_model(dim, model1, ref1, NULL);
461 * adg_dim_set_ref_from_model(dim, model2, NULL, ref2);
462 * ]|
464 void
465 adg_dim_set_ref_from_model(AdgDim *dim, AdgModel *model,
466 const gchar *ref1, const gchar *ref2)
468 GObject *object;
469 AdgDimPrivate *data;
471 g_return_if_fail(ADG_IS_DIM(dim));
472 g_return_if_fail(ADG_IS_MODEL(model));
473 g_return_if_fail(ref1 != NULL || ref2 != NULL);
475 object = (GObject *) dim;
476 data = dim->data;
478 g_object_freeze_notify(object);
480 if (ref1 != NULL) {
481 if (data->ref1 == NULL)
482 data->ref1 = adg_point_new();
484 adg_point_set_from_model(data->ref1, model, ref1);
486 g_object_notify(object, "ref1");
489 if (ref2 != NULL) {
490 if (data->ref2 == NULL)
491 data->ref2 = adg_point_new();
493 adg_point_set_from_model(data->ref2, model, ref2);
495 g_object_notify(object, "ref2");
498 g_object_thaw_notify(object);
502 * adg_dim_get_ref1:
503 * @dim: an #AdgDim
505 * Gets the ref1 coordinates. The returned pair is internally owned
506 * and must not be freed or modified.
508 * Returns: the ref1 coordinates
510 const AdgPair *
511 adg_dim_get_ref1(AdgDim *dim)
513 AdgDimPrivate *data;
515 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
517 data = dim->data;
519 return adg_point_pair(data->ref1);
523 * adg_dim_get_ref2:
524 * @dim: an #AdgDim
526 * Gets the ref2 coordinates. The returned pair is internally owned
527 * and must not be freed or modified.
529 * Returns: the ref2 coordinates
531 const AdgPair *
532 adg_dim_get_ref2(AdgDim *dim)
534 AdgDimPrivate *data;
536 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
538 data = dim->data;
540 return adg_point_pair(data->ref2);
544 * adg_dim_set_pos:
545 * @dim: an #AdgDim
546 * @pos: the pos coordinates
548 * Sets a new #AdgDim:pos position.
550 void
551 adg_dim_set_pos(AdgDim *dim, const AdgPair *pos)
553 AdgDimPrivate *data;
555 g_return_if_fail(ADG_IS_DIM(dim));
556 g_return_if_fail(pos != NULL);
558 data = dim->data;
560 if (data->pos == NULL)
561 data->pos = adg_point_new();
563 adg_point_set(data->pos, pos);
565 g_object_notify((GObject *) dim, "pos");
569 * adg_dim_set_pos_explicit:
570 * @dim: an #AdgDim
571 * @pos_x: x coordinate of pos
572 * @pos_y: y coordinate of pos
574 * Shortcut to set #AdgDim:pos using explicit coordinates.
576 void
577 adg_dim_set_pos_explicit(AdgDim *dim, gdouble x, gdouble y)
579 AdgPair pos;
581 pos.x = x;
582 pos.y = y;
584 adg_dim_set_pos(dim, &pos);
588 * adg_dim_set_pos_from_model:
589 * @dim: an #AdgDim
590 * @model: the source #AdgModel
591 * @ref1: name of the pair in @model to use as pos
593 * Sets #AdgDim:pos by linking it to the @pos named pair
594 * in @model.
596 void
597 adg_dim_set_pos_from_model(AdgDim *dim, AdgModel *model, const gchar *pos)
599 AdgDimPrivate *data;
601 g_return_if_fail(ADG_IS_DIM(dim));
602 g_return_if_fail(ADG_IS_MODEL(model));
603 g_return_if_fail(pos != NULL);
605 data = dim->data;
607 if (data->pos == NULL)
608 data->pos = adg_point_new();
610 adg_point_set_from_model(data->pos, model, pos);
612 g_object_notify((GObject *) dim, "pos");
616 * adg_dim_get_pos:
617 * @dim: an #AdgDim
619 * Gets the position coordinates. The returned pair is internally owned
620 * and must not be freed or modified.
622 * Returns: the pos coordinates
624 const AdgPair *
625 adg_dim_get_pos(AdgDim *dim)
627 AdgDimPrivate *data;
629 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
631 data = dim->data;
633 return adg_point_pair(data->pos);
637 * adg_dim_set_level:
638 * @dim: an #AdgDim
639 * @level: the new level
641 * Sets a new level for this dimension. The level is used to
642 * stack the quotes using a spacing value from dim_style
643 * (specified in global space).
645 void
646 adg_dim_set_level(AdgDim *dim, gdouble level)
648 AdgDimPrivate *data;
650 g_return_if_fail(ADG_IS_DIM(dim));
652 data = dim->data;
653 data->level = level;
655 g_object_notify((GObject *) dim, "level");
659 * adg_dim_get_level:
660 * @dim: an #AdgDim
662 * Gets the level of this dimension.
664 * Returns: the level value
666 gdouble
667 adg_dim_get_level(AdgDim *dim)
669 AdgDimPrivate *data;
671 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
673 data = dim->data;
675 return data->level;
679 * adg_dim_set_outside:
680 * @dim: an #AdgDim
681 * @outside: the new outside state
683 * Sets a new state for the #AdgDim:outside flag: check the property
684 * documentation for further details.
686 void
687 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
689 AdgDimPrivate *data;
691 g_return_if_fail(ADG_IS_DIM(dim));
693 data = dim->data;
694 data->outside = outside;
696 g_object_notify((GObject *) dim, "outside");
700 * adg_dim_get_outside:
701 * @dim: an #AdgDim
703 * Gets the state of the #AdgDim:outside property: check the property
704 * documentation for further details.
706 * Returns: the current flag state
708 AdgThreeState
709 adg_dim_get_outside(AdgDim *dim)
711 AdgDimPrivate *data;
713 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
715 data = dim->data;
717 return data->outside;
721 * adg_dim_set_value:
722 * @dim: an #AdgDim
723 * @value: the value text
725 * Explicitely sets the text to use as value. If @value is %NULL or
726 * was never set, an automatic text is calculated using the format
727 * specified in the current #AdgDimStyle and getting its value by
728 * calling the default_value() virtual method.
730 void
731 adg_dim_set_value(AdgDim *dim, const gchar *value)
733 g_return_if_fail(ADG_IS_DIM(dim));
735 if (set_value(dim, value))
736 g_object_notify((GObject *) dim, "value");
740 * adg_dim_get_value:
741 * @dim: an #AdgDim
743 * Gets the value text. The string is internally owned and
744 * must not be freed or modified.
746 * Returns: the value text
748 const gchar *
749 adg_dim_get_value(AdgDim *dim)
751 AdgDimPrivate *data;
753 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
755 data = dim->data;
757 return data->value;
761 * adg_dim_set_limits:
762 * @dim: an #AdgDim
763 * @min: the new minumum value
764 * @max: the new maximum value
766 * Shortcut to set both the limits at once.
768 void
769 adg_dim_set_limits(AdgDim *dim, const gchar *min, const gchar *max)
771 g_return_if_fail(ADG_IS_DIM(dim));
773 g_object_freeze_notify((GObject *) dim);
774 adg_dim_set_min(dim, min);
775 adg_dim_set_max(dim, max);
776 g_object_thaw_notify((GObject *) dim);
780 * adg_dim_set_min:
781 * @dim: an #AdgDim
782 * @min: the new minimum limit
784 * Sets the minimum value. Use %NULL as @min to disable it.
786 void
787 adg_dim_set_min(AdgDim *dim, const gchar *min)
789 g_return_if_fail(ADG_IS_DIM(dim));
791 if (set_min(dim, min))
792 g_object_notify((GObject *) dim, "value-min");
796 * adg_dim_get_min:
797 * @dim: an #AdgDim
799 * Gets the minimum value text or %NULL on minimum value disabled.
800 * The string is internally owned and must not be freed or modified.
802 * Returns: the mimimum value text
804 const gchar *
805 adg_dim_get_min(AdgDim *dim)
807 AdgDimPrivate *data;
809 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
811 data = dim->data;
813 return data->min;
817 * adg_dim_set_max:
818 * @dim: an #AdgDim
819 * @max: the new maximum value
821 * Sets the maximum value. Use %NULL as @max to disable it.
823 void
824 adg_dim_set_max(AdgDim *dim, const gchar *max)
826 g_return_if_fail(ADG_IS_DIM(dim));
828 if (set_max(dim, max))
829 g_object_notify((GObject *) dim, "value-max");
833 * adg_dim_get_max:
834 * @dim: an #AdgDim
836 * Gets the maximum value text or %NULL on maximum value disabled.
837 * The string is internally owned and must not be freed or modified.
839 * Returns: the maximum value text
841 const gchar *
842 adg_dim_get_max(AdgDim *dim)
844 AdgDimPrivate *data;
846 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
848 data = dim->data;
850 return data->max;
854 * adg_dim_get_quote:
855 * @dim: an #AdgDim
857 * <note><para>
858 * This function is only useful in new dimension implementations.
859 * </para></note>
861 * Gets the quote entity, if any. This function is valid only after
862 * the #AdgDim implementation of the arrange() virtual method has
863 * been called.
865 * Returns: the quote entity
867 AdgAlignment *
868 adg_dim_get_quote(AdgDim *dim)
870 AdgDimPrivate *data;
872 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
874 data = dim->data;
876 return data->quote.entity;
880 * adg_dim_quote_angle:
881 * @dim: an #AdgDim
882 * @angle: an angle (in radians)
884 * <note><para>
885 * This function is only useful in new dimension implementations.
886 * </para></note>
888 * Converts @angle accordling to the style of @dim. Any quote angle
889 * should be validated by this method because every dimensioning
890 * style has its own convention regardling the text rotation.
892 * Returns: the angle to use (always in radians)
894 gdouble
895 adg_dim_quote_angle(AdgDim *dim, gdouble angle)
897 AdgDimClass *klass;
899 g_return_val_if_fail(ADG_IS_DIM(dim), angle);
901 klass = ADG_DIM_GET_CLASS(dim);
903 if (klass->quote_angle == NULL)
904 return angle;
906 return klass->quote_angle(angle);
910 static void
911 global_changed(AdgEntity *entity)
913 AdgDimPrivate *data = ((AdgDim *) entity)->data;
915 if (PARENT_ENTITY_CLASS->global_changed)
916 PARENT_ENTITY_CLASS->global_changed(entity);
918 if (data->quote.entity != NULL)
919 adg_entity_global_changed((AdgEntity *) data->quote.entity);
922 static void
923 local_changed(AdgEntity *entity)
925 AdgDimPrivate *data = ((AdgDim *) entity)->data;
927 if (PARENT_ENTITY_CLASS->local_changed)
928 PARENT_ENTITY_CLASS->local_changed(entity);
930 if (data->quote.entity != NULL)
931 adg_entity_local_changed((AdgEntity *) data->quote.entity);
934 static void
935 invalidate(AdgEntity *entity)
937 AdgDimPrivate *data = ((AdgDim *) entity)->data;
939 if (PARENT_ENTITY_CLASS->invalidate)
940 PARENT_ENTITY_CLASS->invalidate(entity);
942 if (data->quote.entity != NULL)
943 adg_entity_invalidate((AdgEntity *) data->quote.entity);
945 adg_point_invalidate(data->ref1);
946 adg_point_invalidate(data->ref2);
947 adg_point_invalidate(data->pos);
950 static void
951 arrange(AdgEntity *entity)
953 AdgDim *dim;
954 AdgDimPrivate *data;
955 AdgEntity *quote_entity;
956 AdgContainer *quote_container;
957 AdgEntity *value_entity;
958 AdgEntity *min_entity;
959 AdgEntity *max_entity;
960 const AdgPair *shift;
961 AdgMatrix map;
963 dim = (AdgDim *) entity;
964 data = dim->data;
966 /* Resolve the dim style */
967 if (data->dim_style == NULL)
968 data->dim_style = (AdgDimStyle *)
969 adg_entity_style(entity, data->dim_dress);
971 if (data->quote.entity == NULL) {
972 AdgPair factor = { 0.5, 0 };
973 data->quote.entity = g_object_new(ADG_TYPE_ALIGNMENT,
974 "local-method", ADG_MIX_NONE,
975 "factor", &factor,
976 "parent", dim, NULL);
979 quote_entity = (AdgEntity *) data->quote.entity;
980 quote_container = (AdgContainer *) data->quote.entity;
982 if (data->quote.value == NULL) {
983 AdgDress dress = adg_dim_style_get_value_dress(data->dim_style);
985 data->quote.value = g_object_new(ADG_TYPE_TOY_TEXT,
986 "local-method", ADG_MIX_PARENT,
987 "font-dress", dress, NULL);
989 adg_container_add(quote_container, (AdgEntity *) data->quote.value);
991 if (data->value) {
992 adg_toy_text_set_label(data->quote.value, data->value);
993 } else {
994 AdgDimClass *klass = ADG_DIM_GET_CLASS(dim);
996 if (klass->default_value) {
997 /* Automatically generate the value text */
998 gchar *text = klass->default_value(dim);
999 adg_toy_text_set_label(data->quote.value, text);
1000 g_free(text);
1005 if (data->quote.min == NULL && data->min != NULL) {
1006 AdgDress dress = adg_dim_style_get_min_dress(data->dim_style);
1008 data->quote.min = g_object_new(ADG_TYPE_TOY_TEXT,
1009 "local-method", ADG_MIX_PARENT,
1010 "font-dress", dress, NULL);
1012 adg_container_add(quote_container, (AdgEntity *) data->quote.min);
1013 adg_toy_text_set_label(data->quote.min, data->min);
1016 if (data->quote.max == NULL && data->max != NULL) {
1017 AdgDress dress = adg_dim_style_get_max_dress(data->dim_style);
1019 data->quote.max = g_object_new(ADG_TYPE_TOY_TEXT,
1020 "local-method", ADG_MIX_PARENT,
1021 "font-dress", dress, NULL);
1023 adg_container_add(quote_container, (AdgEntity *) data->quote.max);
1024 adg_toy_text_set_label(data->quote.max, data->max);
1027 value_entity = (AdgEntity *) data->quote.value;
1028 min_entity = (AdgEntity *) data->quote.min;
1029 max_entity = (AdgEntity *) data->quote.max;
1030 shift = adg_dim_style_get_quote_shift(data->dim_style);
1032 adg_entity_set_global_map(quote_entity, adg_matrix_identity());
1033 adg_entity_global_changed(quote_entity);
1035 cairo_matrix_init_translate(&map, shift->x, shift->y);
1036 adg_entity_set_global_map(value_entity, &map);
1037 adg_entity_arrange(value_entity);
1039 /* Limit values (min and max) */
1040 if (min_entity != NULL || max_entity != NULL) {
1041 const CpmlExtents *extents = adg_entity_get_extents(value_entity);
1042 //CpmlExtents min_extents = { 0 };
1043 //CpmlExtents max_extents = { 0 };
1044 const AdgPair *limits_shift = adg_dim_style_get_limits_shift(data->dim_style);
1046 #if 0
1047 if (min_entity != NULL)
1048 cpml_extents_copy(&min_extents, adg_entity_get_extents(min_entity));
1050 if (max_entity != NULL)
1051 cpml_extents_copy(&max_extents, adg_entity_get_extents(max_entity));
1053 if (min_entity != NULL && max_entity != NULL)
1054 spacing = adg_dim_style_get_limits_spacing(data->dim_style);
1056 cairo_matrix_init_translate(&map,
1057 extents->size.x +
1058 shift->x + limit_shift->x,
1059 (spacing + min_extents.size.y +
1060 max_extents.size.y - extents->size.y) / 2 +
1061 shift->y + limit_shift->y);
1062 #endif
1063 cairo_matrix_init_translate(&map, extents->size.x + limits_shift->x,
1064 -extents->size.y / 2 + limits_shift->y);
1066 if (min_entity != NULL) {
1067 adg_entity_set_global_map(min_entity, &map);
1068 adg_entity_arrange(min_entity);
1069 extents = adg_entity_get_extents(min_entity);
1070 map.y0 -= extents->size.y +
1071 adg_dim_style_get_limits_spacing(data->dim_style);
1074 if (max_entity != NULL) {
1075 adg_entity_set_global_map(max_entity, &map);
1076 adg_entity_arrange(max_entity);
1080 adg_entity_arrange(quote_entity);
1083 static gchar *
1084 default_value(AdgDim *dim)
1086 g_warning("AdgDim::default_value not implemented for `%s'",
1087 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
1088 return g_strdup("undef");
1091 static gdouble
1092 quote_angle(gdouble angle)
1094 angle = cpml_angle(angle);
1096 if (angle > G_PI_4 * 4 / 3 || angle <= -G_PI_4 * 3)
1097 angle = cpml_angle(angle + G_PI);
1099 return angle;
1102 static gboolean
1103 set_dim_dress(AdgDim *dim, AdgDress dress)
1105 AdgDimPrivate *data = dim->data;
1107 if (adg_dress_set(&data->dim_dress, dress)) {
1108 data->dim_style = NULL;
1109 return TRUE;
1112 return FALSE;
1115 static gboolean
1116 set_value(AdgDim *dim, const gchar *value)
1118 AdgDimPrivate *data;
1120 data = dim->data;
1122 if (adg_strcmp(value, data->value) == 0)
1123 return FALSE;
1125 g_free(data->value);
1126 data->value = g_strdup(value);
1128 if (data->quote.value != NULL) {
1129 g_object_unref(data->quote.value);
1130 data->quote.value = NULL;
1133 return TRUE;
1136 static gboolean
1137 set_min(AdgDim *dim, const gchar *min)
1139 AdgDimPrivate *data = dim->data;
1141 if (adg_strcmp(min, data->min) == 0)
1142 return FALSE;
1144 g_free(data->min);
1145 data->min = g_strdup(min);
1147 if (data->quote.min != NULL) {
1148 g_object_unref(data->quote.min);
1149 data->quote.min = NULL;
1152 return TRUE;
1155 static gboolean
1156 set_max(AdgDim *dim, const gchar *max)
1158 AdgDimPrivate *data = dim->data;
1160 if (adg_strcmp(max, data->max) == 0)
1161 return FALSE;
1163 g_free(data->max);
1164 data->max = g_strdup(max);
1166 if (data->quote.max != NULL) {
1167 g_object_unref(data->quote.max);
1168 data->quote.max = NULL;
1171 return TRUE;