[AdgDim] "pos" and "ref1", "ref2" should be handled as AdgPoint
[adg.git] / adg / adg-dim.c
blob5740d164f508cabb6e86aa689c15cd5cff6160c5
1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009,2010 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-internal.h"
37 #include "adg-dim.h"
38 #include "adg-dim-private.h"
39 #include "adg-dim-style.h"
40 #include "adg-dress-builtins.h"
41 #include "adg-toy-text.h"
42 #include "adg-type-builtins.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_DETACHED,
57 PROP_VALUE,
58 PROP_MIN,
59 PROP_MAX
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 void global_changed (AdgEntity *entity);
74 static void local_changed (AdgEntity *entity);
75 static void invalidate (AdgEntity *entity);
76 static void arrange (AdgEntity *entity);
77 static gchar * default_value (AdgDim *dim);
78 static gdouble quote_angle (gdouble angle);
79 static gboolean set_dim_dress (AdgDim *dim,
80 AdgDress dress);
81 static gboolean set_ref1 (AdgDim *dim,
82 const AdgPoint *ref1);
83 static gboolean set_ref2 (AdgDim *dim,
84 const AdgPoint *ref2);
85 static gboolean set_pos (AdgDim *dim,
86 const AdgPoint *pos);
87 static gboolean set_outside (AdgDim *dim,
88 AdgThreeState outside);
89 static gboolean set_detached (AdgDim *dim,
90 AdgThreeState detached);
91 static gboolean set_value (AdgDim *dim,
92 const gchar *value);
93 static gboolean set_min (AdgDim *dim,
94 const gchar *min);
95 static gboolean set_max (AdgDim *dim,
96 const gchar *max);
97 static gboolean set_point (AdgPoint **point,
98 const AdgPoint *new_point);
101 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY);
104 static void
105 adg_dim_class_init(AdgDimClass *klass)
107 GObjectClass *gobject_class;
108 AdgEntityClass *entity_class;
109 GParamSpec *param;
111 gobject_class = (GObjectClass *) klass;
112 entity_class = (AdgEntityClass *) klass;
114 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
116 gobject_class->dispose = dispose;
117 gobject_class->finalize = finalize;
118 gobject_class->get_property = get_property;
119 gobject_class->set_property = set_property;
121 entity_class->global_changed = global_changed;
122 entity_class->local_changed = local_changed;
123 entity_class->invalidate = invalidate;
124 entity_class->arrange = arrange;
126 klass->quote_angle = quote_angle;
127 klass->default_value = default_value;
129 param = adg_param_spec_dress("dim-dress",
130 P_("Dimension Dress"),
131 P_("The dress to use for rendering this dimension"),
132 ADG_DRESS_DIMENSION,
133 G_PARAM_READWRITE);
134 g_object_class_install_property(gobject_class, PROP_DIM_DRESS, param);
136 param = g_param_spec_boxed("ref1",
137 P_("Reference 1"),
138 P_("First reference point of the dimension"),
139 ADG_TYPE_POINT,
140 G_PARAM_READWRITE);
141 g_object_class_install_property(gobject_class, PROP_REF1, param);
143 param = g_param_spec_boxed("ref2",
144 P_("Reference 2"),
145 P_("Second reference point of the dimension"),
146 ADG_TYPE_POINT,
147 G_PARAM_READWRITE);
148 g_object_class_install_property(gobject_class, PROP_REF2, param);
150 param = g_param_spec_boxed("pos",
151 P_("Position"),
152 P_("The reference position of the quote: it will be combined with \"level\" to get the real quote position"),
153 ADG_TYPE_POINT,
154 G_PARAM_READWRITE);
155 g_object_class_install_property(gobject_class, PROP_POS, param);
157 param = g_param_spec_double("level",
158 P_("Level"),
159 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"),
160 -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
161 G_PARAM_READWRITE);
162 g_object_class_install_property(gobject_class, PROP_LEVEL, param);
164 param = g_param_spec_enum("outside",
165 P_("Outside"),
166 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"),
167 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
168 G_PARAM_READWRITE);
169 g_object_class_install_property(gobject_class, PROP_OUTSIDE, param);
171 param = g_param_spec_enum("detached",
172 P_("Detached Quote"),
173 P_("Where the quote must be positioned: in the middle of the base line (ADG_THREE_STATE_OFF), near the pos point (ADG_THREE_STATE_ON) or should be automatically deducted depending on the available space"),
174 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
175 G_PARAM_READWRITE);
176 g_object_class_install_property(gobject_class, PROP_DETACHED, param);
178 param = g_param_spec_string("value",
179 P_("Basic Value"),
180 P_("The theoretically exact value for this quote: set to NULL to automatically get the default value"),
181 NULL,
182 G_PARAM_READWRITE);
183 g_object_class_install_property(gobject_class, PROP_VALUE, param);
185 param = g_param_spec_string("min",
186 P_("Minimum Value or Low Tolerance"),
187 P_("The minimum value allowed or the lowest tolerance from value (depending of the dimension style): set to NULL to suppress"),
188 NULL,
189 G_PARAM_READWRITE);
190 g_object_class_install_property(gobject_class, PROP_MIN, param);
192 param = g_param_spec_string("max",
193 P_("Maximum Value or High Tolerance"),
194 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
195 NULL,
196 G_PARAM_READWRITE);
197 g_object_class_install_property(gobject_class, PROP_MAX, param);
200 static void
201 adg_dim_init(AdgDim *dim)
203 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
204 AdgDimPrivate);
206 data->dim_dress = ADG_DRESS_DIMENSION;
207 data->ref1 = NULL;
208 data->ref2 = NULL;
209 data->pos = NULL;
210 data->level = 1;
211 data->outside = ADG_THREE_STATE_UNKNOWN;
212 data->detached = ADG_THREE_STATE_UNKNOWN;
213 data->value = NULL;
214 data->min = NULL;
215 data->max = NULL;
217 dim->data = data;
220 static void
221 dispose(GObject *object)
223 AdgDimPrivate *data = ((AdgDim *) object)->data;
225 if (data->quote.entity != NULL) {
226 g_object_unref(data->quote.entity);
227 data->quote.entity = NULL;
229 if (data->ref1 != NULL) {
230 adg_point_destroy(data->ref1);
231 data->ref1 = NULL;
233 if (data->ref2 != NULL) {
234 adg_point_destroy(data->ref2);
235 data->ref2 = NULL;
237 if (data->pos != NULL) {
238 adg_point_destroy(data->pos);
239 data->pos = NULL;
242 if (PARENT_OBJECT_CLASS->dispose)
243 PARENT_OBJECT_CLASS->dispose(object);
246 static void
247 finalize(GObject *object)
249 AdgDimPrivate *data = ((AdgDim *) object)->data;
251 g_free(data->value);
252 g_free(data->min);
253 g_free(data->max);
255 if (PARENT_OBJECT_CLASS->finalize)
256 PARENT_OBJECT_CLASS->finalize(object);
259 static void
260 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
262 AdgDimPrivate *data = ((AdgDim *) object)->data;
264 switch (prop_id) {
265 case PROP_DIM_DRESS:
266 g_value_set_int(value, data->dim_dress);
267 break;
268 case PROP_REF1:
269 g_value_set_boxed(value, data->ref1);
270 break;
271 case PROP_REF2:
272 g_value_set_boxed(value, data->ref2);
273 break;
274 case PROP_POS:
275 g_value_set_boxed(value, data->pos);
276 break;
277 case PROP_LEVEL:
278 g_value_set_double(value, data->level);
279 break;
280 case PROP_OUTSIDE:
281 g_value_set_enum(value, data->outside);
282 break;
283 case PROP_DETACHED:
284 g_value_set_enum(value, data->detached);
285 break;
286 case PROP_VALUE:
287 g_value_set_string(value, data->value);
288 break;
289 case PROP_MIN:
290 g_value_set_string(value, data->min);
291 break;
292 case PROP_MAX:
293 g_value_set_string(value, data->max);
294 break;
295 default:
296 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
297 break;
301 static void
302 set_property(GObject *object, guint prop_id,
303 const GValue *value, GParamSpec *pspec)
305 AdgDim *dim;
306 AdgDimPrivate *data;
308 dim = (AdgDim *) object;
309 data = dim->data;
311 switch (prop_id) {
312 case PROP_DIM_DRESS:
313 set_dim_dress(dim, g_value_get_int(value));
314 break;
315 case PROP_REF1:
316 set_ref1(dim, g_value_get_boxed(value));
317 break;
318 case PROP_REF2:
319 set_ref2(dim, g_value_get_boxed(value));
320 break;
321 case PROP_POS:
322 set_pos(dim, g_value_get_boxed(value));
323 break;
324 case PROP_LEVEL:
325 data->level = g_value_get_double(value);
326 break;
327 case PROP_OUTSIDE:
328 set_outside(dim, g_value_get_enum(value));
329 break;
330 case PROP_DETACHED:
331 set_detached(dim, g_value_get_enum(value));
332 break;
333 case PROP_VALUE:
334 set_value(dim, g_value_get_string(value));
335 break;
336 case PROP_MIN:
337 set_min(dim, g_value_get_string(value));
338 break;
339 case PROP_MAX:
340 set_max(dim, g_value_get_string(value));
341 break;
342 default:
343 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
344 break;
350 * adg_dim_set_dim_dress:
351 * @dim: an #AdgDim
352 * @dress: the new #AdgDress to use
354 * Sets a new dimension dress to @dim. The new dress must be
355 * related to the original dress for this property: you cannot
356 * set a dress used for line styles to a dress managing fonts.
358 * The check is done by calling adg_dress_are_related() with
359 * @dress and the previous dress as arguments. Check out its
360 * documentation for details on what is a related dress.
362 void
363 adg_dim_set_dim_dress(AdgDim *dim, AdgDress dress)
365 g_return_if_fail(ADG_IS_DIM(dim));
367 if (set_dim_dress(dim, dress))
368 g_object_notify((GObject *) dim, "dim-dress");
372 * adg_dim_get_dim_dress:
373 * @dim: an #AdgDim
375 * Gets the dimension dress to be used in rendering @dim.
377 * Returns: the current dimension dress
379 AdgDress
380 adg_dim_get_dim_dress(AdgDim *dim)
382 AdgDimPrivate *data;
384 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_DRESS_UNDEFINED);
386 data = dim->data;
388 return data->dim_dress;
392 * adg_dim_set_ref1:
393 * @dim: an #AdgDim
394 * @ref1: the new point to use as first reference
396 * Sets the #AdgDim:ref1 property to @ref1. The old point
397 * is silently discarded, unreferencing its model if that
398 * point was bound to a named pair (hence, possibly destroying
399 * the model if this was the last reference).
401 * @ref1 can be %NULL, in which case the point is unset.
403 void
404 adg_dim_set_ref1(AdgDim *dim, const AdgPoint *ref1)
406 g_return_if_fail(ADG_IS_DIM(dim));
408 if (set_ref1(dim, ref1))
409 g_object_notify((GObject *) dim, "ref1");
413 * adg_dim_set_ref1_explicit:
414 * @dim: an #AdgDim
415 * @x: x coordinate of the first reference point
416 * @y: y coordinate of the first reference point
418 * Sets the #AdgDim:ref1 property to the (@x, @y) explicit
419 * coordinates. The old point is silently discarded,
420 * unreferencing its model if that point was bound to a named
421 * pair (hence, possibly destroying the model if this was the
422 * last reference).
424 void
425 adg_dim_set_ref1_explicit(AdgDim *dim, gdouble x, gdouble y)
427 AdgPoint *point = adg_point_new();
429 adg_point_set_pair_explicit(point, x, y);
430 adg_dim_set_ref1(dim, point);
432 adg_point_destroy(point);
436 * adg_dim_set_ref1_from_pair:
437 * @dim: an #AdgDim
438 * @ref1: the coordinates pair of the first reference point
440 * Convenient function to set the #AdgDim:ref1 property using a
441 * pair instead of explicit coordinates.
443 void
444 adg_dim_set_ref1_from_pair(AdgDim *dim, const AdgPair *ref1)
446 g_return_if_fail(ref1 != NULL);
448 adg_dim_set_ref1_explicit(dim, ref1->x, ref1->y);
452 * adg_dim_set_ref1_from_model:
453 * @dim: an #AdgDim
454 * @model: the source #AdgModel
455 * @ref1: a named pair in @model
457 * Binds #AdgDim:ref1 to the @ref1 named pair of @model. If @model
458 * is %NULL, the point will be unset. In any case, the old point
459 * is silently discarded, unreferencing its model if that point
460 * was bound to a named pair (hence, possibly destroying the model
461 * if this was the last reference).
463 * The assignment is lazy so @ref1 could be not be present in @model.
464 * Anyway, at the first access to this point an error will be raised
465 * if the named pair is still missing.
467 void
468 adg_dim_set_ref1_from_model(AdgDim *dim, AdgModel *model, const gchar *ref1)
470 AdgPoint *point = adg_point_new();
472 adg_point_set_pair_from_model(point, model, ref1);
473 adg_dim_set_ref1(dim, point);
475 adg_point_destroy(point);
479 * adg_dim_get_ref1:
480 * @dim: an #AdgDim
482 * Gets the #AdgDim:ref1 point. The returned point is internally owned
483 * and must not be freed or modified. Anyway, it is not const because
484 * adg_point_get_pair() must be able to modify the internal cache of
485 * the returned point.
487 * Returns: the first reference point
489 AdgPoint *
490 adg_dim_get_ref1(AdgDim *dim)
492 AdgDimPrivate *data;
494 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
496 data = dim->data;
498 return data->ref1;
502 * adg_dim_set_ref2:
503 * @dim: an #AdgDim
504 * @ref2: the new point to use as second reference
506 * Sets the #AdgDim:ref2 property to @ref2. The old point
507 * is silently discarded, unreferencing its model if that
508 * point was bound to a named pair (hence, possibly destroying
509 * the model if it was the last reference).
511 * @ref2 can be %NULL, in which case the point is unset.
513 void
514 adg_dim_set_ref2(AdgDim *dim, const AdgPoint *ref2)
516 g_return_if_fail(ADG_IS_DIM(dim));
518 if (set_ref2(dim, ref2))
519 g_object_notify((GObject *) dim, "ref2");
523 * adg_dim_set_ref2_explicit:
524 * @dim: an #AdgDim
525 * @x: x coordinate of the second reference point
526 * @y: y coordinate of the second reference point
528 * Sets the #AdgDim:ref2 property to the (@x, @y) explicit
529 * coordinates. The old point is silently discarded,
530 * unreferencing its model if that point was bound to a named
531 * pair (hence, possibly destroying the model if this was the
532 * last reference).
534 void
535 adg_dim_set_ref2_explicit(AdgDim *dim, gdouble x, gdouble y)
537 AdgPoint *point = adg_point_new();
539 adg_point_set_pair_explicit(point, x, y);
540 adg_dim_set_ref2(dim, point);
542 adg_point_destroy(point);
546 * adg_dim_set_ref2_from_pair:
547 * @dim: an #AdgDim
548 * @ref2: the coordinates pair of the second reference point
550 * Convenient function to set the #AdgDim:ref2 property using a
551 * pair instead of explicit coordinates.
553 void
554 adg_dim_set_ref2_from_pair(AdgDim *dim, const AdgPair *ref2)
556 g_return_if_fail(ref2 != NULL);
558 adg_dim_set_ref2_explicit(dim, ref2->x, ref2->y);
562 * adg_dim_set_ref2_from_model:
563 * @dim: an #AdgDim
564 * @model: the source #AdgModel
565 * @ref2: a named pair in @model
567 * Binds #AdgDim:ref2 to the @ref2 named pair of @model. If @model
568 * is %NULL, the point will be unset. In any case, the old point
569 * is silently discarded, unreferencing its model if that point
570 * was bound to a named pair (hence, possibly destroying the model
571 * if this was the last reference).
573 * The assignment is lazy so @ref2 could be not be present in @model.
574 * Anyway, at the first access to this point an error will be raised
575 * if the named pair is still missing.
577 void
578 adg_dim_set_ref2_from_model(AdgDim *dim, AdgModel *model, const gchar *ref2)
580 AdgPoint *point = adg_point_new();
582 adg_point_set_pair_from_model(point, model, ref2);
583 adg_dim_set_ref2(dim, point);
585 adg_point_destroy(point);
589 * adg_dim_get_ref2:
590 * @dim: an #AdgDim
592 * Gets the #AdgDim:ref2 point. The returned point is internally owned
593 * and must not be freed or modified. Anyway, it is not const because
594 * adg_point_get_pair() must be able to modify the internal cache of
595 * the returned point.
597 * Returns: the second reference point
599 AdgPoint *
600 adg_dim_get_ref2(AdgDim *dim)
602 AdgDimPrivate *data;
604 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
606 data = dim->data;
608 return data->ref2;
612 * adg_dim_set_pos:
613 * @dim: an #AdgDim
614 * @pos: the new point to use as position
616 * Sets the #AdgDim:pos property to @pos. The old point
617 * is silently discarded, unreferencing its model if that
618 * point was bound to a named pair (hence, possibly destroying
619 * the model if it was the last reference).
621 * @pos can be %NULL, in which case the point is unset.
623 void
624 adg_dim_set_pos(AdgDim *dim, const AdgPoint *pos)
626 g_return_if_fail(ADG_IS_DIM(dim));
628 if (set_pos(dim, pos))
629 g_object_notify((GObject *) dim, "pos");
633 * adg_dim_set_pos_explicit:
634 * @dim: an #AdgDim
635 * @x: x coordinate of the position
636 * @y: y coordinate of the position
638 * Sets the #AdgDim:pos property to the (@x, @y) explicit
639 * coordinates. The old point is silently discarded,
640 * unreferencing its model if that point was bound to a named
641 * pair (hence, possibly destroying the model if this was the
642 * last reference).
644 void
645 adg_dim_set_pos_explicit(AdgDim *dim, gdouble x, gdouble y)
647 AdgPoint *point = adg_point_new();
649 adg_point_set_pair_explicit(point, x, y);
650 adg_dim_set_pos(dim, point);
652 adg_point_destroy(point);
656 * adg_dim_set_pos_from_pair:
657 * @dim: an #AdgDim
658 * @pos: the coordinates pair of the position point
660 * Convenient function to set the #AdgDim:pos property using a
661 * pair instead of explicit coordinates.
663 void
664 adg_dim_set_pos_from_pair(AdgDim *dim, const AdgPair *pos)
666 g_return_if_fail(pos != NULL);
668 adg_dim_set_pos_explicit(dim, pos->x, pos->y);
672 * adg_dim_set_pos_from_model:
673 * @dim: an #AdgDim
674 * @model: the source #AdgModel
675 * @pos: a named pair in @model
677 * Binds #AdgDim:pos to the @pos named pair of @model. If @model
678 * is %NULL, the point will be unset. In any case, the old point
679 * is silently discarded, unreferencing its model if that point
680 * was bound to a named pair (hence, possibly destroying the model
681 * if this was the last reference).
683 * The assignment is lazy so @pos could be not be present in @model.
684 * Anyway, at the first access to this point an error will be raised
685 * if the named pair is still missing.
687 void
688 adg_dim_set_pos_from_model(AdgDim *dim, AdgModel *model, const gchar *pos)
690 AdgPoint *point = adg_point_new();
692 adg_point_set_pair_from_model(point, model, pos);
693 adg_dim_set_pos(dim, point);
695 adg_point_destroy(point);
699 * adg_dim_get_pos:
700 * @dim: an #AdgDim
702 * Gets the #AdgDim:pos point. The returned point is internally owned
703 * and must not be freed or modified. Anyway, it is not const because
704 * adg_point_get_pair() must be able to modify the internal cache of
705 * the returned point.
707 * Returns: the position point
709 AdgPoint *
710 adg_dim_get_pos(AdgDim *dim)
712 AdgDimPrivate *data;
714 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
716 data = dim->data;
718 return data->pos;
722 * adg_dim_set_level:
723 * @dim: an #AdgDim
724 * @level: the new level
726 * Sets a new level for this dimension. The level is used to
727 * stack the quotes using a spacing value from dim_style
728 * (specified in global space).
730 void
731 adg_dim_set_level(AdgDim *dim, gdouble level)
733 AdgDimPrivate *data;
735 g_return_if_fail(ADG_IS_DIM(dim));
737 data = dim->data;
738 data->level = level;
740 g_object_notify((GObject *) dim, "level");
744 * adg_dim_get_level:
745 * @dim: an #AdgDim
747 * Gets the level of this dimension.
749 * Returns: the level value
751 gdouble
752 adg_dim_get_level(AdgDim *dim)
754 AdgDimPrivate *data;
756 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
758 data = dim->data;
760 return data->level;
764 * adg_dim_set_outside:
765 * @dim: an #AdgDim
766 * @outside: the new outside state
768 * Sets a new state for the #AdgDim:outside flag: check the property
769 * documentation for further details.
771 void
772 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
774 g_return_if_fail(ADG_IS_DIM(dim));
776 if (set_outside(dim, outside))
777 g_object_notify((GObject *) dim, "outside");
781 * adg_dim_get_outside:
782 * @dim: an #AdgDim
784 * Gets the state of the #AdgDim:outside property: check the property
785 * documentation for further details.
787 * Returns: the current flag state
789 AdgThreeState
790 adg_dim_get_outside(AdgDim *dim)
792 AdgDimPrivate *data;
794 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
796 data = dim->data;
798 return data->outside;
802 * adg_dim_set_detached:
803 * @dim: an #AdgDim
804 * @detached: the new detached state
806 * Sets a new state for the #AdgDim:detached flag: check the property
807 * documentation for further details.
809 * This is used only by dimensions where detaching has meaning.
810 * In some cases, such as with #AdgRDim dimensions, this property is
811 * not used.
813 void
814 adg_dim_set_detached(AdgDim *dim, AdgThreeState detached)
816 g_return_if_fail(ADG_IS_DIM(dim));
818 if (set_detached(dim, detached))
819 g_object_notify((GObject *) dim, "detached");
823 * adg_dim_get_detached:
824 * @dim: an #AdgDim
826 * Gets the state of the #AdgDim:detached property: check the property
827 * documentation for further details.
829 * Returns: the current flag state
831 AdgThreeState
832 adg_dim_get_detached(AdgDim *dim)
834 AdgDimPrivate *data;
836 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
838 data = dim->data;
840 return data->detached;
844 * adg_dim_set_value:
845 * @dim: an #AdgDim
846 * @value: the value text
848 * Explicitely sets the text to use as value. If @value is %NULL or
849 * was never set, an automatic text is calculated using the format
850 * specified in the current #AdgDimStyle and getting its value by
851 * calling the default_value() virtual method.
853 void
854 adg_dim_set_value(AdgDim *dim, const gchar *value)
856 g_return_if_fail(ADG_IS_DIM(dim));
858 if (set_value(dim, value))
859 g_object_notify((GObject *) dim, "value");
863 * adg_dim_get_value:
864 * @dim: an #AdgDim
866 * Gets the value text. The string is internally owned and
867 * must not be freed or modified.
869 * Returns: the value text
871 const gchar *
872 adg_dim_get_value(AdgDim *dim)
874 AdgDimPrivate *data;
876 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
878 data = dim->data;
880 return data->value;
884 * adg_dim_set_limits:
885 * @dim: an #AdgDim
886 * @min: the new minumum value
887 * @max: the new maximum value
889 * Shortcut to set both the limits at once.
891 void
892 adg_dim_set_limits(AdgDim *dim, const gchar *min, const gchar *max)
894 g_return_if_fail(ADG_IS_DIM(dim));
896 g_object_freeze_notify((GObject *) dim);
897 adg_dim_set_min(dim, min);
898 adg_dim_set_max(dim, max);
899 g_object_thaw_notify((GObject *) dim);
903 * adg_dim_set_min:
904 * @dim: an #AdgDim
905 * @min: the new minimum limit
907 * Sets the minimum value. Use %NULL as @min to disable it.
909 void
910 adg_dim_set_min(AdgDim *dim, const gchar *min)
912 g_return_if_fail(ADG_IS_DIM(dim));
914 if (set_min(dim, min))
915 g_object_notify((GObject *) dim, "min");
919 * adg_dim_get_min:
920 * @dim: an #AdgDim
922 * Gets the minimum value text or %NULL on minimum value disabled.
923 * The string is internally owned and must not be freed or modified.
925 * Returns: the mimimum value text
927 const gchar *
928 adg_dim_get_min(AdgDim *dim)
930 AdgDimPrivate *data;
932 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
934 data = dim->data;
936 return data->min;
940 * adg_dim_set_max:
941 * @dim: an #AdgDim
942 * @max: the new maximum value
944 * Sets the maximum value. Use %NULL as @max to disable it.
946 void
947 adg_dim_set_max(AdgDim *dim, const gchar *max)
949 g_return_if_fail(ADG_IS_DIM(dim));
951 if (set_max(dim, max))
952 g_object_notify((GObject *) dim, "max");
956 * adg_dim_get_max:
957 * @dim: an #AdgDim
959 * Gets the maximum value text or %NULL on maximum value disabled.
960 * The string is internally owned and must not be freed or modified.
962 * Returns: the maximum value text
964 const gchar *
965 adg_dim_get_max(AdgDim *dim)
967 AdgDimPrivate *data;
969 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
971 data = dim->data;
973 return data->max;
977 * adg_dim_get_quote:
978 * @dim: an #AdgDim
980 * <note><para>
981 * This function is only useful in new dimension implementations.
982 * </para></note>
984 * Gets the quote entity, if any. This function is valid only after
985 * the #AdgDim implementation of the arrange() virtual method has
986 * been called.
988 * Returns: the quote entity
990 AdgAlignment *
991 adg_dim_get_quote(AdgDim *dim)
993 AdgDimPrivate *data;
995 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
997 data = dim->data;
999 return data->quote.entity;
1003 * adg_dim_quote_angle:
1004 * @dim: an #AdgDim
1005 * @angle: an angle (in radians)
1007 * <note><para>
1008 * This function is only useful in new dimension implementations.
1009 * </para></note>
1011 * Converts @angle accordling to the style of @dim. Any quote angle
1012 * should be validated by this method because every dimensioning
1013 * style has its own convention regardling the text rotation.
1015 * Returns: the angle to use (always in radians)
1017 gdouble
1018 adg_dim_quote_angle(AdgDim *dim, gdouble angle)
1020 AdgDimClass *klass;
1022 g_return_val_if_fail(ADG_IS_DIM(dim), angle);
1024 klass = ADG_DIM_GET_CLASS(dim);
1026 if (klass->quote_angle == NULL)
1027 return angle;
1029 return klass->quote_angle(angle);
1033 static void
1034 global_changed(AdgEntity *entity)
1036 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1038 if (PARENT_ENTITY_CLASS->global_changed)
1039 PARENT_ENTITY_CLASS->global_changed(entity);
1041 if (data->quote.entity != NULL)
1042 adg_entity_global_changed((AdgEntity *) data->quote.entity);
1045 static void
1046 local_changed(AdgEntity *entity)
1048 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1050 if (PARENT_ENTITY_CLASS->local_changed)
1051 PARENT_ENTITY_CLASS->local_changed(entity);
1053 if (data->quote.entity != NULL)
1054 adg_entity_local_changed((AdgEntity *) data->quote.entity);
1057 static void
1058 invalidate(AdgEntity *entity)
1060 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1062 if (PARENT_ENTITY_CLASS->invalidate)
1063 PARENT_ENTITY_CLASS->invalidate(entity);
1065 if (data->quote.entity != NULL)
1066 adg_entity_invalidate((AdgEntity *) data->quote.entity);
1068 adg_point_invalidate(data->ref1);
1069 adg_point_invalidate(data->ref2);
1070 adg_point_invalidate(data->pos);
1073 static void
1074 arrange(AdgEntity *entity)
1076 AdgDim *dim;
1077 AdgDimPrivate *data;
1078 AdgEntity *quote_entity;
1079 AdgContainer *quote_container;
1080 AdgEntity *value_entity;
1081 AdgEntity *min_entity;
1082 AdgEntity *max_entity;
1083 const AdgPair *shift;
1084 AdgMatrix map;
1086 dim = (AdgDim *) entity;
1087 data = dim->data;
1089 /* Resolve the dim style */
1090 if (data->dim_style == NULL)
1091 data->dim_style = (AdgDimStyle *)
1092 adg_entity_style(entity, data->dim_dress);
1094 if (data->quote.entity == NULL)
1095 data->quote.entity = g_object_new(ADG_TYPE_ALIGNMENT,
1096 "local-method", ADG_MIX_NONE,
1097 "parent", dim, NULL);
1099 quote_entity = (AdgEntity *) data->quote.entity;
1100 quote_container = (AdgContainer *) data->quote.entity;
1102 if (data->quote.value == NULL) {
1103 AdgDress dress = adg_dim_style_get_value_dress(data->dim_style);
1105 data->quote.value = g_object_new(ADG_TYPE_TOY_TEXT,
1106 "local-method", ADG_MIX_PARENT,
1107 "font-dress", dress, NULL);
1109 adg_container_add(quote_container, (AdgEntity *) data->quote.value);
1111 if (data->value) {
1112 adg_toy_text_set_label(data->quote.value, data->value);
1113 } else {
1114 AdgDimClass *klass = ADG_DIM_GET_CLASS(dim);
1116 if (klass->default_value) {
1117 /* Automatically generate the value text */
1118 gchar *text = klass->default_value(dim);
1119 adg_toy_text_set_label(data->quote.value, text);
1120 g_free(text);
1125 if (data->quote.min == NULL && data->min != NULL) {
1126 AdgDress dress = adg_dim_style_get_min_dress(data->dim_style);
1128 data->quote.min = g_object_new(ADG_TYPE_TOY_TEXT,
1129 "local-method", ADG_MIX_PARENT,
1130 "font-dress", dress, NULL);
1132 adg_container_add(quote_container, (AdgEntity *) data->quote.min);
1133 adg_toy_text_set_label(data->quote.min, data->min);
1136 if (data->quote.max == NULL && data->max != NULL) {
1137 AdgDress dress = adg_dim_style_get_max_dress(data->dim_style);
1139 data->quote.max = g_object_new(ADG_TYPE_TOY_TEXT,
1140 "local-method", ADG_MIX_PARENT,
1141 "font-dress", dress, NULL);
1143 adg_container_add(quote_container, (AdgEntity *) data->quote.max);
1144 adg_toy_text_set_label(data->quote.max, data->max);
1147 value_entity = (AdgEntity *) data->quote.value;
1148 min_entity = (AdgEntity *) data->quote.min;
1149 max_entity = (AdgEntity *) data->quote.max;
1150 shift = adg_dim_style_get_quote_shift(data->dim_style);
1152 adg_entity_set_global_map(quote_entity, adg_matrix_identity());
1153 adg_entity_global_changed(quote_entity);
1155 cairo_matrix_init_translate(&map, shift->x, shift->y);
1156 adg_entity_set_global_map(value_entity, &map);
1157 adg_entity_arrange(value_entity);
1159 /* Limit values (min and max) */
1160 if (min_entity != NULL || max_entity != NULL) {
1161 const CpmlExtents *extents = adg_entity_get_extents(value_entity);
1162 //CpmlExtents min_extents = { 0 };
1163 //CpmlExtents max_extents = { 0 };
1164 const AdgPair *limits_shift = adg_dim_style_get_limits_shift(data->dim_style);
1166 #if 0
1167 if (min_entity != NULL)
1168 cpml_extents_copy(&min_extents, adg_entity_get_extents(min_entity));
1170 if (max_entity != NULL)
1171 cpml_extents_copy(&max_extents, adg_entity_get_extents(max_entity));
1173 if (min_entity != NULL && max_entity != NULL)
1174 spacing = adg_dim_style_get_limits_spacing(data->dim_style);
1176 cairo_matrix_init_translate(&map,
1177 extents->size.x +
1178 shift->x + limit_shift->x,
1179 (spacing + min_extents.size.y +
1180 max_extents.size.y - extents->size.y) / 2 +
1181 shift->y + limit_shift->y);
1182 #endif
1183 cairo_matrix_init_translate(&map, extents->size.x + limits_shift->x,
1184 -extents->size.y / 2 + limits_shift->y);
1186 if (min_entity != NULL) {
1187 adg_entity_set_global_map(min_entity, &map);
1188 adg_entity_arrange(min_entity);
1189 extents = adg_entity_get_extents(min_entity);
1190 map.y0 -= extents->size.y +
1191 adg_dim_style_get_limits_spacing(data->dim_style);
1194 if (max_entity != NULL) {
1195 adg_entity_set_global_map(max_entity, &map);
1196 adg_entity_arrange(max_entity);
1200 adg_entity_arrange(quote_entity);
1203 static gchar *
1204 default_value(AdgDim *dim)
1206 g_warning("AdgDim::default_value not implemented for `%s'",
1207 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
1208 return g_strdup("undef");
1211 static gdouble
1212 quote_angle(gdouble angle)
1214 angle = cpml_angle(angle);
1216 if (angle > G_PI_4 * 4 / 3 || angle <= -G_PI_4 * 3)
1217 angle = cpml_angle(angle + G_PI);
1219 return angle;
1222 static gboolean
1223 set_dim_dress(AdgDim *dim, AdgDress dress)
1225 AdgDimPrivate *data = dim->data;
1227 if (adg_dress_set(&data->dim_dress, dress)) {
1228 data->dim_style = NULL;
1229 return TRUE;
1232 return FALSE;
1235 static gboolean
1236 set_ref1(AdgDim *dim, const AdgPoint *ref1)
1238 AdgDimPrivate *data = dim->data;
1240 return set_point(&data->ref1, ref1);
1243 static gboolean
1244 set_ref2(AdgDim *dim, const AdgPoint *ref2)
1246 AdgDimPrivate *data = dim->data;
1248 return set_point(&data->ref2, ref2);
1251 static gboolean
1252 set_pos(AdgDim *dim, const AdgPoint *pos)
1254 AdgDimPrivate *data = dim->data;
1256 return set_point(&data->pos, pos);
1259 static gboolean
1260 set_outside(AdgDim *dim, AdgThreeState outside)
1262 AdgDimPrivate *data;
1264 g_return_val_if_fail(adg_is_enum_value(outside, ADG_TYPE_THREE_STATE),
1265 FALSE);
1267 data = dim->data;
1269 if (data->outside == outside)
1270 return FALSE;
1272 data->outside = outside;
1274 return TRUE;
1277 static gboolean
1278 set_detached(AdgDim *dim, AdgThreeState detached)
1280 AdgDimPrivate *data;
1282 g_return_val_if_fail(adg_is_enum_value(detached, ADG_TYPE_THREE_STATE),
1283 FALSE);
1285 data = dim->data;
1287 if (data->detached == detached)
1288 return FALSE;
1290 data->detached = detached;
1292 return TRUE;
1295 static gboolean
1296 set_value(AdgDim *dim, const gchar *value)
1298 AdgDimPrivate *data;
1300 data = dim->data;
1302 if (adg_strcmp(value, data->value) == 0)
1303 return FALSE;
1305 g_free(data->value);
1306 data->value = g_strdup(value);
1308 if (data->quote.value != NULL) {
1309 g_object_unref(data->quote.value);
1310 data->quote.value = NULL;
1313 return TRUE;
1316 static gboolean
1317 set_min(AdgDim *dim, const gchar *min)
1319 AdgDimPrivate *data = dim->data;
1321 if (adg_strcmp(min, data->min) == 0)
1322 return FALSE;
1324 g_free(data->min);
1325 data->min = g_strdup(min);
1327 if (data->quote.min != NULL) {
1328 g_object_unref(data->quote.min);
1329 data->quote.min = NULL;
1332 return TRUE;
1335 static gboolean
1336 set_max(AdgDim *dim, const gchar *max)
1338 AdgDimPrivate *data = dim->data;
1340 if (adg_strcmp(max, data->max) == 0)
1341 return FALSE;
1343 g_free(data->max);
1344 data->max = g_strdup(max);
1346 if (data->quote.max != NULL) {
1347 g_object_unref(data->quote.max);
1348 data->quote.max = NULL;
1351 return TRUE;
1354 static gboolean
1355 set_point(AdgPoint **point, const AdgPoint *new_point)
1357 if ((*point == new_point) ||
1358 (*point && new_point && adg_point_equal(*point, new_point)))
1359 return FALSE;
1361 if (*point == NULL)
1362 *point = adg_point_new();
1364 if (new_point) {
1365 adg_point_copy(*point, new_point);
1366 } else {
1367 adg_point_destroy(*point);
1368 *point = NULL;
1371 return TRUE;