[AdgMarker] Added missing APIs
[adg.git] / adg / adg-dim.c
blob72d631af800f5c8e51d350f8dce1ce6dbf34bbcc
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_outside (AdgDim *dim,
82 AdgThreeState outside);
83 static gboolean set_detached (AdgDim *dim,
84 AdgThreeState detached);
85 static gboolean set_value (AdgDim *dim,
86 const gchar *value);
87 static gboolean set_min (AdgDim *dim,
88 const gchar *min);
89 static gboolean set_max (AdgDim *dim,
90 const gchar *max);
93 G_DEFINE_ABSTRACT_TYPE(AdgDim, adg_dim, ADG_TYPE_ENTITY);
96 static void
97 adg_dim_class_init(AdgDimClass *klass)
99 GObjectClass *gobject_class;
100 AdgEntityClass *entity_class;
101 GParamSpec *param;
103 gobject_class = (GObjectClass *) klass;
104 entity_class = (AdgEntityClass *) klass;
106 g_type_class_add_private(klass, sizeof(AdgDimPrivate));
108 gobject_class->dispose = dispose;
109 gobject_class->finalize = finalize;
110 gobject_class->get_property = get_property;
111 gobject_class->set_property = set_property;
113 entity_class->global_changed = global_changed;
114 entity_class->local_changed = local_changed;
115 entity_class->invalidate = invalidate;
116 entity_class->arrange = arrange;
118 klass->quote_angle = quote_angle;
119 klass->default_value = default_value;
121 param = adg_param_spec_dress("dim-dress",
122 P_("Dimension Dress"),
123 P_("The dress to use for rendering this dimension"),
124 ADG_DRESS_DIMENSION,
125 G_PARAM_READWRITE);
126 g_object_class_install_property(gobject_class, PROP_DIM_DRESS, param);
128 param = g_param_spec_boxed("ref1",
129 P_("First Reference"),
130 P_("First reference point of the dimension"),
131 ADG_TYPE_POINT,
132 G_PARAM_READWRITE);
133 g_object_class_install_property(gobject_class, PROP_REF1, param);
135 param = g_param_spec_boxed("ref2",
136 P_("Second Reference"),
137 P_("Second reference point of the dimension"),
138 ADG_TYPE_POINT,
139 G_PARAM_READWRITE);
140 g_object_class_install_property(gobject_class, PROP_REF2, param);
142 param = g_param_spec_boxed("pos",
143 P_("Position"),
144 P_("The reference position of the quote: it will be combined with \"level\" to get the real quote position"),
145 ADG_TYPE_POINT,
146 G_PARAM_READWRITE);
147 g_object_class_install_property(gobject_class, PROP_POS, param);
149 param = g_param_spec_double("level",
150 P_("Level"),
151 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"),
152 -G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
153 G_PARAM_READWRITE);
154 g_object_class_install_property(gobject_class, PROP_LEVEL, param);
156 param = g_param_spec_enum("outside",
157 P_("Outside"),
158 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"),
159 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
160 G_PARAM_READWRITE);
161 g_object_class_install_property(gobject_class, PROP_OUTSIDE, param);
163 param = g_param_spec_enum("detached",
164 P_("Detached Quote"),
165 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"),
166 ADG_TYPE_THREE_STATE, ADG_THREE_STATE_UNKNOWN,
167 G_PARAM_READWRITE);
168 g_object_class_install_property(gobject_class, PROP_DETACHED, param);
170 param = g_param_spec_string("value",
171 P_("Basic Value"),
172 P_("The theoretically exact value for this quote: set to NULL to automatically get the default value"),
173 NULL,
174 G_PARAM_READWRITE);
175 g_object_class_install_property(gobject_class, PROP_VALUE, param);
177 param = g_param_spec_string("min",
178 P_("Minimum Value or Low Tolerance"),
179 P_("The minimum value allowed or the lowest tolerance from value (depending of the dimension style): set to NULL to suppress"),
180 NULL,
181 G_PARAM_READWRITE);
182 g_object_class_install_property(gobject_class, PROP_MIN, param);
184 param = g_param_spec_string("max",
185 P_("Maximum Value or High Tolerance"),
186 P_("The maximum value allowed or the highest tolerance from value (depending of the dimension style): set to NULL to suppress"),
187 NULL,
188 G_PARAM_READWRITE);
189 g_object_class_install_property(gobject_class, PROP_MAX, param);
192 static void
193 adg_dim_init(AdgDim *dim)
195 AdgDimPrivate *data = G_TYPE_INSTANCE_GET_PRIVATE(dim, ADG_TYPE_DIM,
196 AdgDimPrivate);
198 data->dim_dress = ADG_DRESS_DIMENSION;
199 data->ref1 = NULL;
200 data->ref2 = NULL;
201 data->pos = NULL;
202 data->level = 1;
203 data->outside = ADG_THREE_STATE_UNKNOWN;
204 data->detached = ADG_THREE_STATE_UNKNOWN;
205 data->value = NULL;
206 data->min = NULL;
207 data->max = NULL;
209 dim->data = data;
212 static void
213 dispose(GObject *object)
215 AdgDimPrivate *data = ((AdgDim *) object)->data;
217 if (data->quote.entity != NULL) {
218 g_object_unref(data->quote.entity);
219 data->quote.entity = NULL;
221 if (data->ref1 != NULL) {
222 adg_point_destroy(data->ref1);
223 data->ref1 = NULL;
225 if (data->ref2 != NULL) {
226 adg_point_destroy(data->ref2);
227 data->ref2 = NULL;
229 if (data->pos != NULL) {
230 adg_point_destroy(data->pos);
231 data->pos = NULL;
234 if (PARENT_OBJECT_CLASS->dispose)
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->min);
245 g_free(data->max);
247 if (PARENT_OBJECT_CLASS->finalize)
248 PARENT_OBJECT_CLASS->finalize(object);
251 static void
252 get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
254 AdgDimPrivate *data = ((AdgDim *) object)->data;
256 switch (prop_id) {
257 case PROP_DIM_DRESS:
258 g_value_set_int(value, data->dim_dress);
259 break;
260 case PROP_REF1:
261 g_value_set_boxed(value, data->ref1);
262 break;
263 case PROP_REF2:
264 g_value_set_boxed(value, data->ref2);
265 break;
266 case PROP_POS:
267 g_value_set_boxed(value, data->pos);
268 break;
269 case PROP_LEVEL:
270 g_value_set_double(value, data->level);
271 break;
272 case PROP_OUTSIDE:
273 g_value_set_enum(value, data->outside);
274 break;
275 case PROP_DETACHED:
276 g_value_set_enum(value, data->detached);
277 break;
278 case PROP_VALUE:
279 g_value_set_string(value, data->value);
280 break;
281 case PROP_MIN:
282 g_value_set_string(value, data->min);
283 break;
284 case PROP_MAX:
285 g_value_set_string(value, data->max);
286 break;
287 default:
288 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
289 break;
293 static void
294 set_property(GObject *object, guint prop_id,
295 const GValue *value, GParamSpec *pspec)
297 AdgDim *dim;
298 AdgDimPrivate *data;
300 dim = (AdgDim *) object;
301 data = dim->data;
303 switch (prop_id) {
304 case PROP_DIM_DRESS:
305 set_dim_dress(dim, g_value_get_int(value));
306 break;
307 case PROP_REF1:
308 adg_point_set(&data->ref1, g_value_get_boxed(value));
309 break;
310 case PROP_REF2:
311 adg_point_set(&data->ref2, g_value_get_boxed(value));
312 break;
313 case PROP_POS:
314 adg_point_set(&data->pos, g_value_get_boxed(value));
315 break;
316 case PROP_LEVEL:
317 data->level = g_value_get_double(value);
318 break;
319 case PROP_OUTSIDE:
320 set_outside(dim, g_value_get_enum(value));
321 break;
322 case PROP_DETACHED:
323 set_detached(dim, g_value_get_enum(value));
324 break;
325 case PROP_VALUE:
326 set_value(dim, g_value_get_string(value));
327 break;
328 case PROP_MIN:
329 set_min(dim, g_value_get_string(value));
330 break;
331 case PROP_MAX:
332 set_max(dim, g_value_get_string(value));
333 break;
334 default:
335 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
336 break;
342 * adg_dim_set_dim_dress:
343 * @dim: an #AdgDim
344 * @dress: the new #AdgDress to use
346 * Sets a new dimension dress to @dim. The new dress must be
347 * related to the original dress for this property: you cannot
348 * set a dress used for line styles to a dress managing fonts.
350 * The check is done by calling adg_dress_are_related() with
351 * @dress and the previous dress as arguments. Check out its
352 * documentation for details on what is a related dress.
354 void
355 adg_dim_set_dim_dress(AdgDim *dim, AdgDress dress)
357 g_return_if_fail(ADG_IS_DIM(dim));
359 if (set_dim_dress(dim, dress))
360 g_object_notify((GObject *) dim, "dim-dress");
364 * adg_dim_get_dim_dress:
365 * @dim: an #AdgDim
367 * Gets the dimension dress to be used in rendering @dim.
369 * Returns: the current dimension dress
371 AdgDress
372 adg_dim_get_dim_dress(AdgDim *dim)
374 AdgDimPrivate *data;
376 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_DRESS_UNDEFINED);
378 data = dim->data;
380 return data->dim_dress;
384 * adg_dim_set_ref1:
385 * @dim: an #AdgDim
386 * @ref1: the new point to use as first reference
388 * Sets the #AdgDim:ref1 property to @ref1. The old point
389 * is silently discarded, unreferencing its model if that
390 * point was bound to a named pair (hence, possibly destroying
391 * the model if this was the last reference).
393 * @ref1 can be %NULL, in which case the point is unset.
395 void
396 adg_dim_set_ref1(AdgDim *dim, const AdgPoint *ref1)
398 AdgDimPrivate *data;
400 g_return_if_fail(ADG_IS_DIM(dim));
402 data = dim->data;
404 if (adg_point_set(&data->ref1, ref1))
405 g_object_notify((GObject *) dim, "ref1");
409 * adg_dim_set_ref1_explicit:
410 * @dim: an #AdgDim
411 * @x: x coordinate of the first reference point
412 * @y: y coordinate of the first reference point
414 * Sets the #AdgDim:ref1 property to the (@x, @y) explicit
415 * coordinates. The old point is silently discarded,
416 * unreferencing its model if that point was bound to a named
417 * pair (hence, possibly destroying the model if this was the
418 * last reference).
420 void
421 adg_dim_set_ref1_explicit(AdgDim *dim, gdouble x, gdouble y)
423 AdgPoint *point = adg_point_new();
425 adg_point_set_pair_explicit(point, x, y);
426 adg_dim_set_ref1(dim, point);
428 adg_point_destroy(point);
432 * adg_dim_set_ref1_from_pair:
433 * @dim: an #AdgDim
434 * @ref1: the coordinates pair of the first reference point
436 * Convenient function to set the #AdgDim:ref1 property using a
437 * pair instead of explicit coordinates.
439 void
440 adg_dim_set_ref1_from_pair(AdgDim *dim, const AdgPair *ref1)
442 g_return_if_fail(ref1 != NULL);
444 adg_dim_set_ref1_explicit(dim, ref1->x, ref1->y);
448 * adg_dim_set_ref1_from_model:
449 * @dim: an #AdgDim
450 * @model: the source #AdgModel
451 * @ref1: a named pair in @model
453 * Binds #AdgDim:ref1 to the @ref1 named pair of @model. If @model
454 * is %NULL, the point will be unset. In any case, the old point
455 * is silently discarded, unreferencing its model if that point
456 * was bound to a named pair (hence, possibly destroying the model
457 * if this was the last reference).
459 * The assignment is lazy so @ref1 could be not be present in @model.
460 * Anyway, at the first access to this point an error will be raised
461 * if the named pair is still missing.
463 void
464 adg_dim_set_ref1_from_model(AdgDim *dim, AdgModel *model, const gchar *ref1)
466 AdgPoint *point = adg_point_new();
468 adg_point_set_pair_from_model(point, model, ref1);
469 adg_dim_set_ref1(dim, point);
471 adg_point_destroy(point);
475 * adg_dim_get_ref1:
476 * @dim: an #AdgDim
478 * Gets the #AdgDim:ref1 point. The returned point is internally owned
479 * and must not be freed or modified. Anyway, it is not const because
480 * adg_point_get_pair() must be able to modify the internal cache of
481 * the returned point.
483 * Returns: the first reference point
485 AdgPoint *
486 adg_dim_get_ref1(AdgDim *dim)
488 AdgDimPrivate *data;
490 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
492 data = dim->data;
494 return data->ref1;
498 * adg_dim_set_ref2:
499 * @dim: an #AdgDim
500 * @ref2: the new point to use as second reference
502 * Sets the #AdgDim:ref2 property to @ref2. The old point
503 * is silently discarded, unreferencing its model if that
504 * point was bound to a named pair (hence, possibly destroying
505 * the model if it was the last reference).
507 * @ref2 can be %NULL, in which case the point is unset.
509 void
510 adg_dim_set_ref2(AdgDim *dim, const AdgPoint *ref2)
512 AdgDimPrivate *data;
514 g_return_if_fail(ADG_IS_DIM(dim));
516 data = dim->data;
518 if (adg_point_set(&data->ref2, 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 AdgDimPrivate *data;
628 g_return_if_fail(ADG_IS_DIM(dim));
630 data = dim->data;
632 if (adg_point_set(&data->pos, pos))
633 g_object_notify((GObject *) dim, "pos");
637 * adg_dim_set_pos_explicit:
638 * @dim: an #AdgDim
639 * @x: x coordinate of the position
640 * @y: y coordinate of the position
642 * Sets the #AdgDim:pos property to the (@x, @y) explicit
643 * coordinates. The old point is silently discarded,
644 * unreferencing its model if that point was bound to a named
645 * pair (hence, possibly destroying the model if this was the
646 * last reference).
648 void
649 adg_dim_set_pos_explicit(AdgDim *dim, gdouble x, gdouble y)
651 AdgPoint *point = adg_point_new();
653 adg_point_set_pair_explicit(point, x, y);
654 adg_dim_set_pos(dim, point);
656 adg_point_destroy(point);
660 * adg_dim_set_pos_from_pair:
661 * @dim: an #AdgDim
662 * @pos: the coordinates pair of the position point
664 * Convenient function to set the #AdgDim:pos property using a
665 * pair instead of explicit coordinates.
667 void
668 adg_dim_set_pos_from_pair(AdgDim *dim, const AdgPair *pos)
670 g_return_if_fail(pos != NULL);
672 adg_dim_set_pos_explicit(dim, pos->x, pos->y);
676 * adg_dim_set_pos_from_model:
677 * @dim: an #AdgDim
678 * @model: the source #AdgModel
679 * @pos: a named pair in @model
681 * Binds #AdgDim:pos to the @pos named pair of @model. If @model
682 * is %NULL, the point will be unset. In any case, the old point
683 * is silently discarded, unreferencing its model if that point
684 * was bound to a named pair (hence, possibly destroying the model
685 * if this was the last reference).
687 * The assignment is lazy so @pos could be not be present in @model.
688 * Anyway, at the first access to this point an error will be raised
689 * if the named pair is still missing.
691 void
692 adg_dim_set_pos_from_model(AdgDim *dim, AdgModel *model, const gchar *pos)
694 AdgPoint *point = adg_point_new();
696 adg_point_set_pair_from_model(point, model, pos);
697 adg_dim_set_pos(dim, point);
699 adg_point_destroy(point);
703 * adg_dim_get_pos:
704 * @dim: an #AdgDim
706 * Gets the #AdgDim:pos point. The returned point is internally owned
707 * and must not be freed or modified. Anyway, it is not const because
708 * adg_point_get_pair() must be able to modify the internal cache of
709 * the returned point.
711 * Returns: the position point
713 AdgPoint *
714 adg_dim_get_pos(AdgDim *dim)
716 AdgDimPrivate *data;
718 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
720 data = dim->data;
722 return data->pos;
726 * adg_dim_set_level:
727 * @dim: an #AdgDim
728 * @level: the new level
730 * Sets a new level for this dimension. The level is used to
731 * stack the quotes using a spacing value from dim_style
732 * (specified in global space).
734 void
735 adg_dim_set_level(AdgDim *dim, gdouble level)
737 AdgDimPrivate *data;
739 g_return_if_fail(ADG_IS_DIM(dim));
741 data = dim->data;
742 data->level = level;
744 g_object_notify((GObject *) dim, "level");
748 * adg_dim_get_level:
749 * @dim: an #AdgDim
751 * Gets the level of this dimension.
753 * Returns: the level value
755 gdouble
756 adg_dim_get_level(AdgDim *dim)
758 AdgDimPrivate *data;
760 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
762 data = dim->data;
764 return data->level;
768 * adg_dim_set_outside:
769 * @dim: an #AdgDim
770 * @outside: the new outside state
772 * Sets a new state for the #AdgDim:outside flag: check the property
773 * documentation for further details.
775 void
776 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
778 g_return_if_fail(ADG_IS_DIM(dim));
780 if (set_outside(dim, outside))
781 g_object_notify((GObject *) dim, "outside");
785 * adg_dim_get_outside:
786 * @dim: an #AdgDim
788 * Gets the state of the #AdgDim:outside property: check the property
789 * documentation for further details.
791 * Returns: the current flag state
793 AdgThreeState
794 adg_dim_get_outside(AdgDim *dim)
796 AdgDimPrivate *data;
798 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
800 data = dim->data;
802 return data->outside;
806 * adg_dim_set_detached:
807 * @dim: an #AdgDim
808 * @detached: the new detached state
810 * Sets a new state for the #AdgDim:detached flag: check the property
811 * documentation for further details.
813 * This is used only by dimensions where detaching has meaning.
814 * In some cases, such as with #AdgRDim dimensions, this property is
815 * not used.
817 void
818 adg_dim_set_detached(AdgDim *dim, AdgThreeState detached)
820 g_return_if_fail(ADG_IS_DIM(dim));
822 if (set_detached(dim, detached))
823 g_object_notify((GObject *) dim, "detached");
827 * adg_dim_get_detached:
828 * @dim: an #AdgDim
830 * Gets the state of the #AdgDim:detached property: check the property
831 * documentation for further details.
833 * Returns: the current flag state
835 AdgThreeState
836 adg_dim_get_detached(AdgDim *dim)
838 AdgDimPrivate *data;
840 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
842 data = dim->data;
844 return data->detached;
848 * adg_dim_set_value:
849 * @dim: an #AdgDim
850 * @value: the value text
852 * Explicitely sets the text to use as value. If @value is %NULL or
853 * was never set, an automatic text is calculated using the format
854 * specified in the current #AdgDimStyle and getting its value by
855 * calling the default_value() virtual method.
857 void
858 adg_dim_set_value(AdgDim *dim, const gchar *value)
860 g_return_if_fail(ADG_IS_DIM(dim));
862 if (set_value(dim, value))
863 g_object_notify((GObject *) dim, "value");
867 * adg_dim_get_value:
868 * @dim: an #AdgDim
870 * Gets the value text. The string is internally owned and
871 * must not be freed or modified.
873 * Returns: the value text
875 const gchar *
876 adg_dim_get_value(AdgDim *dim)
878 AdgDimPrivate *data;
880 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
882 data = dim->data;
884 return data->value;
888 * adg_dim_set_limits:
889 * @dim: an #AdgDim
890 * @min: the new minumum value
891 * @max: the new maximum value
893 * Shortcut to set both the limits at once.
895 void
896 adg_dim_set_limits(AdgDim *dim, const gchar *min, const gchar *max)
898 g_return_if_fail(ADG_IS_DIM(dim));
900 g_object_freeze_notify((GObject *) dim);
901 adg_dim_set_min(dim, min);
902 adg_dim_set_max(dim, max);
903 g_object_thaw_notify((GObject *) dim);
907 * adg_dim_set_min:
908 * @dim: an #AdgDim
909 * @min: the new minimum limit
911 * Sets the minimum value. Use %NULL as @min to disable it.
913 void
914 adg_dim_set_min(AdgDim *dim, const gchar *min)
916 g_return_if_fail(ADG_IS_DIM(dim));
918 if (set_min(dim, min))
919 g_object_notify((GObject *) dim, "min");
923 * adg_dim_get_min:
924 * @dim: an #AdgDim
926 * Gets the minimum value text or %NULL on minimum value disabled.
927 * The string is internally owned and must not be freed or modified.
929 * Returns: the mimimum value text
931 const gchar *
932 adg_dim_get_min(AdgDim *dim)
934 AdgDimPrivate *data;
936 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
938 data = dim->data;
940 return data->min;
944 * adg_dim_set_max:
945 * @dim: an #AdgDim
946 * @max: the new maximum value
948 * Sets the maximum value. Use %NULL as @max to disable it.
950 void
951 adg_dim_set_max(AdgDim *dim, const gchar *max)
953 g_return_if_fail(ADG_IS_DIM(dim));
955 if (set_max(dim, max))
956 g_object_notify((GObject *) dim, "max");
960 * adg_dim_get_max:
961 * @dim: an #AdgDim
963 * Gets the maximum value text or %NULL on maximum value disabled.
964 * The string is internally owned and must not be freed or modified.
966 * Returns: the maximum value text
968 const gchar *
969 adg_dim_get_max(AdgDim *dim)
971 AdgDimPrivate *data;
973 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
975 data = dim->data;
977 return data->max;
981 * adg_dim_get_quote:
982 * @dim: an #AdgDim
984 * <note><para>
985 * This function is only useful in new dimension implementations.
986 * </para></note>
988 * Gets the quote entity, if any. This function is valid only after
989 * the #AdgDim implementation of the arrange() virtual method has
990 * been called.
992 * Returns: the quote entity
994 AdgAlignment *
995 adg_dim_get_quote(AdgDim *dim)
997 AdgDimPrivate *data;
999 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
1001 data = dim->data;
1003 return data->quote.entity;
1007 * adg_dim_quote_angle:
1008 * @dim: an #AdgDim
1009 * @angle: an angle (in radians)
1011 * <note><para>
1012 * This function is only useful in new dimension implementations.
1013 * </para></note>
1015 * Converts @angle accordling to the style of @dim. Any quote angle
1016 * should be validated by this method because every dimensioning
1017 * style has its own convention regardling the text rotation.
1019 * Returns: the angle to use (always in radians)
1021 gdouble
1022 adg_dim_quote_angle(AdgDim *dim, gdouble angle)
1024 AdgDimClass *klass;
1026 g_return_val_if_fail(ADG_IS_DIM(dim), angle);
1028 klass = ADG_DIM_GET_CLASS(dim);
1030 if (klass->quote_angle == NULL)
1031 return angle;
1033 return klass->quote_angle(angle);
1037 static void
1038 global_changed(AdgEntity *entity)
1040 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1042 if (PARENT_ENTITY_CLASS->global_changed)
1043 PARENT_ENTITY_CLASS->global_changed(entity);
1045 if (data->quote.entity != NULL)
1046 adg_entity_global_changed((AdgEntity *) data->quote.entity);
1049 static void
1050 local_changed(AdgEntity *entity)
1052 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1054 if (PARENT_ENTITY_CLASS->local_changed)
1055 PARENT_ENTITY_CLASS->local_changed(entity);
1057 if (data->quote.entity != NULL)
1058 adg_entity_local_changed((AdgEntity *) data->quote.entity);
1061 static void
1062 invalidate(AdgEntity *entity)
1064 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1066 if (PARENT_ENTITY_CLASS->invalidate)
1067 PARENT_ENTITY_CLASS->invalidate(entity);
1069 if (data->quote.entity != NULL)
1070 adg_entity_invalidate((AdgEntity *) data->quote.entity);
1072 adg_point_invalidate(data->ref1);
1073 adg_point_invalidate(data->ref2);
1074 adg_point_invalidate(data->pos);
1077 static void
1078 arrange(AdgEntity *entity)
1080 AdgDim *dim;
1081 AdgDimPrivate *data;
1082 AdgEntity *quote_entity;
1083 AdgContainer *quote_container;
1084 AdgEntity *value_entity;
1085 AdgEntity *min_entity;
1086 AdgEntity *max_entity;
1087 const AdgPair *shift;
1088 AdgMatrix map;
1090 dim = (AdgDim *) entity;
1091 data = dim->data;
1093 /* Resolve the dim style */
1094 if (data->dim_style == NULL)
1095 data->dim_style = (AdgDimStyle *)
1096 adg_entity_style(entity, data->dim_dress);
1098 if (data->quote.entity == NULL)
1099 data->quote.entity = g_object_new(ADG_TYPE_ALIGNMENT,
1100 "local-method", ADG_MIX_NONE,
1101 "parent", dim, NULL);
1103 quote_entity = (AdgEntity *) data->quote.entity;
1104 quote_container = (AdgContainer *) data->quote.entity;
1106 if (data->quote.value == NULL) {
1107 AdgDress dress = adg_dim_style_get_value_dress(data->dim_style);
1109 data->quote.value = g_object_new(ADG_TYPE_TOY_TEXT,
1110 "local-method", ADG_MIX_PARENT,
1111 "font-dress", dress, NULL);
1113 adg_container_add(quote_container, (AdgEntity *) data->quote.value);
1115 if (data->value) {
1116 adg_toy_text_set_label(data->quote.value, data->value);
1117 } else {
1118 AdgDimClass *klass = ADG_DIM_GET_CLASS(dim);
1120 if (klass->default_value) {
1121 /* Automatically generate the value text */
1122 gchar *text = klass->default_value(dim);
1123 adg_toy_text_set_label(data->quote.value, text);
1124 g_free(text);
1129 if (data->quote.min == NULL && data->min != NULL) {
1130 AdgDress dress = adg_dim_style_get_min_dress(data->dim_style);
1132 data->quote.min = g_object_new(ADG_TYPE_TOY_TEXT,
1133 "local-method", ADG_MIX_PARENT,
1134 "font-dress", dress, NULL);
1136 adg_container_add(quote_container, (AdgEntity *) data->quote.min);
1137 adg_toy_text_set_label(data->quote.min, data->min);
1140 if (data->quote.max == NULL && data->max != NULL) {
1141 AdgDress dress = adg_dim_style_get_max_dress(data->dim_style);
1143 data->quote.max = g_object_new(ADG_TYPE_TOY_TEXT,
1144 "local-method", ADG_MIX_PARENT,
1145 "font-dress", dress, NULL);
1147 adg_container_add(quote_container, (AdgEntity *) data->quote.max);
1148 adg_toy_text_set_label(data->quote.max, data->max);
1151 value_entity = (AdgEntity *) data->quote.value;
1152 min_entity = (AdgEntity *) data->quote.min;
1153 max_entity = (AdgEntity *) data->quote.max;
1154 shift = adg_dim_style_get_quote_shift(data->dim_style);
1156 adg_entity_set_global_map(quote_entity, adg_matrix_identity());
1157 adg_entity_global_changed(quote_entity);
1159 cairo_matrix_init_translate(&map, shift->x, shift->y);
1160 adg_entity_set_global_map(value_entity, &map);
1161 adg_entity_arrange(value_entity);
1163 /* Limit values (min and max) */
1164 if (min_entity != NULL || max_entity != NULL) {
1165 const CpmlExtents *extents = adg_entity_get_extents(value_entity);
1166 //CpmlExtents min_extents = { 0 };
1167 //CpmlExtents max_extents = { 0 };
1168 const AdgPair *limits_shift = adg_dim_style_get_limits_shift(data->dim_style);
1170 #if 0
1171 if (min_entity != NULL)
1172 cpml_extents_copy(&min_extents, adg_entity_get_extents(min_entity));
1174 if (max_entity != NULL)
1175 cpml_extents_copy(&max_extents, adg_entity_get_extents(max_entity));
1177 if (min_entity != NULL && max_entity != NULL)
1178 spacing = adg_dim_style_get_limits_spacing(data->dim_style);
1180 cairo_matrix_init_translate(&map,
1181 extents->size.x +
1182 shift->x + limit_shift->x,
1183 (spacing + min_extents.size.y +
1184 max_extents.size.y - extents->size.y) / 2 +
1185 shift->y + limit_shift->y);
1186 #endif
1187 cairo_matrix_init_translate(&map, extents->size.x + limits_shift->x,
1188 -extents->size.y / 2 + limits_shift->y);
1190 if (min_entity != NULL) {
1191 adg_entity_set_global_map(min_entity, &map);
1192 adg_entity_arrange(min_entity);
1193 extents = adg_entity_get_extents(min_entity);
1194 map.y0 -= extents->size.y +
1195 adg_dim_style_get_limits_spacing(data->dim_style);
1198 if (max_entity != NULL) {
1199 adg_entity_set_global_map(max_entity, &map);
1200 adg_entity_arrange(max_entity);
1204 adg_entity_arrange(quote_entity);
1207 static gchar *
1208 default_value(AdgDim *dim)
1210 g_warning("AdgDim::default_value not implemented for `%s'",
1211 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
1212 return g_strdup("undef");
1215 static gdouble
1216 quote_angle(gdouble angle)
1218 angle = cpml_angle(angle);
1220 if (angle > G_PI_4 * 4 / 3 || angle <= -G_PI_4 * 3)
1221 angle = cpml_angle(angle + G_PI);
1223 return angle;
1226 static gboolean
1227 set_dim_dress(AdgDim *dim, AdgDress dress)
1229 AdgDimPrivate *data = dim->data;
1231 if (adg_dress_set(&data->dim_dress, dress)) {
1232 data->dim_style = NULL;
1233 return TRUE;
1236 return FALSE;
1239 static gboolean
1240 set_outside(AdgDim *dim, AdgThreeState outside)
1242 AdgDimPrivate *data;
1244 g_return_val_if_fail(adg_is_enum_value(outside, ADG_TYPE_THREE_STATE),
1245 FALSE);
1247 data = dim->data;
1249 if (data->outside == outside)
1250 return FALSE;
1252 data->outside = outside;
1254 return TRUE;
1257 static gboolean
1258 set_detached(AdgDim *dim, AdgThreeState detached)
1260 AdgDimPrivate *data;
1262 g_return_val_if_fail(adg_is_enum_value(detached, ADG_TYPE_THREE_STATE),
1263 FALSE);
1265 data = dim->data;
1267 if (data->detached == detached)
1268 return FALSE;
1270 data->detached = detached;
1272 return TRUE;
1275 static gboolean
1276 set_value(AdgDim *dim, const gchar *value)
1278 AdgDimPrivate *data;
1280 data = dim->data;
1282 if (adg_strcmp(value, data->value) == 0)
1283 return FALSE;
1285 g_free(data->value);
1286 data->value = g_strdup(value);
1288 if (data->quote.value != NULL) {
1289 g_object_unref(data->quote.value);
1290 data->quote.value = NULL;
1293 return TRUE;
1296 static gboolean
1297 set_min(AdgDim *dim, const gchar *min)
1299 AdgDimPrivate *data = dim->data;
1301 if (adg_strcmp(min, data->min) == 0)
1302 return FALSE;
1304 g_free(data->min);
1305 data->min = g_strdup(min);
1307 if (data->quote.min != NULL) {
1308 g_object_unref(data->quote.min);
1309 data->quote.min = NULL;
1312 return TRUE;
1315 static gboolean
1316 set_max(AdgDim *dim, const gchar *max)
1318 AdgDimPrivate *data = dim->data;
1320 if (adg_strcmp(max, data->max) == 0)
1321 return FALSE;
1323 g_free(data->max);
1324 data->max = g_strdup(max);
1326 if (data->quote.max != NULL) {
1327 g_object_unref(data->quote.max);
1328 data->quote.max = NULL;
1331 return TRUE;