[AdgDress] Rearranged builtin dresses
[adg.git] / src / adg / adg-dim.c
blob2d274728c185407e1c5ae6f7f00d0b7b62d21a78
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 _adg_dispose (GObject *object);
64 static void _adg_finalize (GObject *object);
65 static void _adg_get_property (GObject *object,
66 guint param_id,
67 GValue *value,
68 GParamSpec *pspec);
69 static void _adg_set_property (GObject *object,
70 guint param_id,
71 const GValue *value,
72 GParamSpec *pspec);
73 static void _adg_global_changed (AdgEntity *entity);
74 static void _adg_local_changed (AdgEntity *entity);
75 static void _adg_invalidate (AdgEntity *entity);
76 static void _adg_arrange (AdgEntity *entity);
77 static gchar * _adg_default_value (AdgDim *dim);
78 static gdouble _adg_quote_angle (gdouble angle);
79 static gboolean _adg_set_dim_dress (AdgDim *dim,
80 AdgDress dress);
81 static gboolean _adg_set_outside (AdgDim *dim,
82 AdgThreeState outside);
83 static gboolean _adg_set_detached (AdgDim *dim,
84 AdgThreeState detached);
85 static gboolean _adg_set_value (AdgDim *dim,
86 const gchar *value);
87 static gboolean _adg_set_min (AdgDim *dim,
88 const gchar *min);
89 static gboolean _adg_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 = _adg_dispose;
109 gobject_class->finalize = _adg_finalize;
110 gobject_class->get_property = _adg_get_property;
111 gobject_class->set_property = _adg_set_property;
113 entity_class->global_changed = _adg_global_changed;
114 entity_class->local_changed = _adg_local_changed;
115 entity_class->invalidate = _adg_invalidate;
116 entity_class->arrange = _adg_arrange;
118 klass->quote_angle = _adg_quote_angle;
119 klass->default_value = _adg_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 _adg_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 _adg_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 _adg_get_property(GObject *object, guint prop_id,
253 GValue *value, GParamSpec *pspec)
255 AdgDimPrivate *data = ((AdgDim *) object)->data;
257 switch (prop_id) {
258 case PROP_DIM_DRESS:
259 g_value_set_int(value, data->dim_dress);
260 break;
261 case PROP_REF1:
262 g_value_set_boxed(value, data->ref1);
263 break;
264 case PROP_REF2:
265 g_value_set_boxed(value, data->ref2);
266 break;
267 case PROP_POS:
268 g_value_set_boxed(value, data->pos);
269 break;
270 case PROP_LEVEL:
271 g_value_set_double(value, data->level);
272 break;
273 case PROP_OUTSIDE:
274 g_value_set_enum(value, data->outside);
275 break;
276 case PROP_DETACHED:
277 g_value_set_enum(value, data->detached);
278 break;
279 case PROP_VALUE:
280 g_value_set_string(value, data->value);
281 break;
282 case PROP_MIN:
283 g_value_set_string(value, data->min);
284 break;
285 case PROP_MAX:
286 g_value_set_string(value, data->max);
287 break;
288 default:
289 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
290 break;
294 static void
295 _adg_set_property(GObject *object, guint prop_id,
296 const GValue *value, GParamSpec *pspec)
298 AdgDim *dim;
299 AdgDimPrivate *data;
301 dim = (AdgDim *) object;
302 data = dim->data;
304 switch (prop_id) {
305 case PROP_DIM_DRESS:
306 _adg_set_dim_dress(dim, g_value_get_int(value));
307 break;
308 case PROP_REF1:
309 adg_point_set(&data->ref1, g_value_get_boxed(value));
310 break;
311 case PROP_REF2:
312 adg_point_set(&data->ref2, g_value_get_boxed(value));
313 break;
314 case PROP_POS:
315 adg_point_set(&data->pos, g_value_get_boxed(value));
316 break;
317 case PROP_LEVEL:
318 data->level = g_value_get_double(value);
319 break;
320 case PROP_OUTSIDE:
321 _adg_set_outside(dim, g_value_get_enum(value));
322 break;
323 case PROP_DETACHED:
324 _adg_set_detached(dim, g_value_get_enum(value));
325 break;
326 case PROP_VALUE:
327 _adg_set_value(dim, g_value_get_string(value));
328 break;
329 case PROP_MIN:
330 _adg_set_min(dim, g_value_get_string(value));
331 break;
332 case PROP_MAX:
333 _adg_set_max(dim, g_value_get_string(value));
334 break;
335 default:
336 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
337 break;
343 * adg_dim_set_dim_dress:
344 * @dim: an #AdgDim
345 * @dress: the new #AdgDress to use
347 * Sets a new dimension dress to @dim. The new dress must be
348 * related to the original dress for this property: you cannot
349 * set a dress used for line styles to a dress managing fonts.
351 * The check is done by calling adg_dress_are_related() with
352 * @dress and the previous dress as arguments. Check out its
353 * documentation for details on what is a related dress.
355 void
356 adg_dim_set_dim_dress(AdgDim *dim, AdgDress dress)
358 g_return_if_fail(ADG_IS_DIM(dim));
360 if (_adg_set_dim_dress(dim, dress))
361 g_object_notify((GObject *) dim, "dim-dress");
365 * adg_dim_get_dim_dress:
366 * @dim: an #AdgDim
368 * Gets the dimension dress to be used in rendering @dim.
370 * Returns: the current dimension dress
372 AdgDress
373 adg_dim_get_dim_dress(AdgDim *dim)
375 AdgDimPrivate *data;
377 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_DRESS_UNDEFINED);
379 data = dim->data;
381 return data->dim_dress;
385 * adg_dim_set_ref1:
386 * @dim: an #AdgDim
387 * @ref1: the new point to use as first reference
389 * Sets the #AdgDim:ref1 property to @ref1. The old point
390 * is silently discarded, unreferencing its model if that
391 * point was bound to a named pair (hence, possibly destroying
392 * the model if this was the last reference).
394 * @ref1 can be %NULL, in which case the point is unset.
396 void
397 adg_dim_set_ref1(AdgDim *dim, const AdgPoint *ref1)
399 AdgDimPrivate *data;
401 g_return_if_fail(ADG_IS_DIM(dim));
403 data = dim->data;
405 if (adg_point_set(&data->ref1, ref1))
406 g_object_notify((GObject *) dim, "ref1");
410 * adg_dim_set_ref1_explicit:
411 * @dim: an #AdgDim
412 * @x: x coordinate of the first reference point
413 * @y: y coordinate of the first reference point
415 * Sets the #AdgDim:ref1 property to the (@x, @y) explicit
416 * coordinates. The old point is silently discarded,
417 * unreferencing its model if that point was bound to a named
418 * pair (hence, possibly destroying the model if this was the
419 * last reference).
421 void
422 adg_dim_set_ref1_explicit(AdgDim *dim, gdouble x, gdouble y)
424 AdgPoint *point = adg_point_new();
426 adg_point_set_pair_explicit(point, x, y);
427 adg_dim_set_ref1(dim, point);
429 adg_point_destroy(point);
433 * adg_dim_set_ref1_from_pair:
434 * @dim: an #AdgDim
435 * @ref1: the coordinates pair of the first reference point
437 * Convenient function to set the #AdgDim:ref1 property using a
438 * pair instead of explicit coordinates.
440 void
441 adg_dim_set_ref1_from_pair(AdgDim *dim, const AdgPair *ref1)
443 g_return_if_fail(ref1 != NULL);
445 adg_dim_set_ref1_explicit(dim, ref1->x, ref1->y);
449 * adg_dim_set_ref1_from_model:
450 * @dim: an #AdgDim
451 * @model: the source #AdgModel
452 * @ref1: a named pair in @model
454 * Binds #AdgDim:ref1 to the @ref1 named pair of @model. If @model
455 * is %NULL, the point will be unset. In any case, the old point
456 * is silently discarded, unreferencing its model if that point
457 * was bound to a named pair (hence, possibly destroying the model
458 * if this was the last reference).
460 * The assignment is lazy so @ref1 could be not be present in @model.
461 * Anyway, at the first access to this point an error will be raised
462 * if the named pair is still missing.
464 void
465 adg_dim_set_ref1_from_model(AdgDim *dim, AdgModel *model, const gchar *ref1)
467 AdgPoint *point = adg_point_new();
469 adg_point_set_pair_from_model(point, model, ref1);
470 adg_dim_set_ref1(dim, point);
472 adg_point_destroy(point);
476 * adg_dim_get_ref1:
477 * @dim: an #AdgDim
479 * Gets the #AdgDim:ref1 point. The returned point is internally owned
480 * and must not be freed or modified. Anyway, it is not const because
481 * adg_point_get_pair() must be able to modify the internal cache of
482 * the returned point.
484 * Returns: the first reference point
486 AdgPoint *
487 adg_dim_get_ref1(AdgDim *dim)
489 AdgDimPrivate *data;
491 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
493 data = dim->data;
495 return data->ref1;
499 * adg_dim_set_ref2:
500 * @dim: an #AdgDim
501 * @ref2: the new point to use as second reference
503 * Sets the #AdgDim:ref2 property to @ref2. The old point
504 * is silently discarded, unreferencing its model if that
505 * point was bound to a named pair (hence, possibly destroying
506 * the model if it was the last reference).
508 * @ref2 can be %NULL, in which case the point is unset.
510 void
511 adg_dim_set_ref2(AdgDim *dim, const AdgPoint *ref2)
513 AdgDimPrivate *data;
515 g_return_if_fail(ADG_IS_DIM(dim));
517 data = dim->data;
519 if (adg_point_set(&data->ref2, ref2))
520 g_object_notify((GObject *) dim, "ref2");
524 * adg_dim_set_ref2_explicit:
525 * @dim: an #AdgDim
526 * @x: x coordinate of the second reference point
527 * @y: y coordinate of the second reference point
529 * Sets the #AdgDim:ref2 property to the (@x, @y) explicit
530 * coordinates. The old point is silently discarded,
531 * unreferencing its model if that point was bound to a named
532 * pair (hence, possibly destroying the model if this was the
533 * last reference).
535 void
536 adg_dim_set_ref2_explicit(AdgDim *dim, gdouble x, gdouble y)
538 AdgPoint *point = adg_point_new();
540 adg_point_set_pair_explicit(point, x, y);
541 adg_dim_set_ref2(dim, point);
543 adg_point_destroy(point);
547 * adg_dim_set_ref2_from_pair:
548 * @dim: an #AdgDim
549 * @ref2: the coordinates pair of the second reference point
551 * Convenient function to set the #AdgDim:ref2 property using a
552 * pair instead of explicit coordinates.
554 void
555 adg_dim_set_ref2_from_pair(AdgDim *dim, const AdgPair *ref2)
557 g_return_if_fail(ref2 != NULL);
559 adg_dim_set_ref2_explicit(dim, ref2->x, ref2->y);
563 * adg_dim_set_ref2_from_model:
564 * @dim: an #AdgDim
565 * @model: the source #AdgModel
566 * @ref2: a named pair in @model
568 * Binds #AdgDim:ref2 to the @ref2 named pair of @model. If @model
569 * is %NULL, the point will be unset. In any case, the old point
570 * is silently discarded, unreferencing its model if that point
571 * was bound to a named pair (hence, possibly destroying the model
572 * if this was the last reference).
574 * The assignment is lazy so @ref2 could be not be present in @model.
575 * Anyway, at the first access to this point an error will be raised
576 * if the named pair is still missing.
578 void
579 adg_dim_set_ref2_from_model(AdgDim *dim, AdgModel *model, const gchar *ref2)
581 AdgPoint *point = adg_point_new();
583 adg_point_set_pair_from_model(point, model, ref2);
584 adg_dim_set_ref2(dim, point);
586 adg_point_destroy(point);
590 * adg_dim_get_ref2:
591 * @dim: an #AdgDim
593 * Gets the #AdgDim:ref2 point. The returned point is internally owned
594 * and must not be freed or modified. Anyway, it is not const because
595 * adg_point_get_pair() must be able to modify the internal cache of
596 * the returned point.
598 * Returns: the second reference point
600 AdgPoint *
601 adg_dim_get_ref2(AdgDim *dim)
603 AdgDimPrivate *data;
605 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
607 data = dim->data;
609 return data->ref2;
613 * adg_dim_set_pos:
614 * @dim: an #AdgDim
615 * @pos: the new point to use as position
617 * Sets the #AdgDim:pos property to @pos. The old point
618 * is silently discarded, unreferencing its model if that
619 * point was bound to a named pair (hence, possibly destroying
620 * the model if it was the last reference).
622 * @pos can be %NULL, in which case the point is unset.
624 void
625 adg_dim_set_pos(AdgDim *dim, const AdgPoint *pos)
627 AdgDimPrivate *data;
629 g_return_if_fail(ADG_IS_DIM(dim));
631 data = dim->data;
633 if (adg_point_set(&data->pos, pos))
634 g_object_notify((GObject *) dim, "pos");
638 * adg_dim_set_pos_explicit:
639 * @dim: an #AdgDim
640 * @x: x coordinate of the position
641 * @y: y coordinate of the position
643 * Sets the #AdgDim:pos property to the (@x, @y) explicit
644 * coordinates. The old point is silently discarded,
645 * unreferencing its model if that point was bound to a named
646 * pair (hence, possibly destroying the model if this was the
647 * last reference).
649 void
650 adg_dim_set_pos_explicit(AdgDim *dim, gdouble x, gdouble y)
652 AdgPoint *point = adg_point_new();
654 adg_point_set_pair_explicit(point, x, y);
655 adg_dim_set_pos(dim, point);
657 adg_point_destroy(point);
661 * adg_dim_set_pos_from_pair:
662 * @dim: an #AdgDim
663 * @pos: the coordinates pair of the position point
665 * Convenient function to set the #AdgDim:pos property using a
666 * pair instead of explicit coordinates.
668 void
669 adg_dim_set_pos_from_pair(AdgDim *dim, const AdgPair *pos)
671 g_return_if_fail(pos != NULL);
673 adg_dim_set_pos_explicit(dim, pos->x, pos->y);
677 * adg_dim_set_pos_from_model:
678 * @dim: an #AdgDim
679 * @model: the source #AdgModel
680 * @pos: a named pair in @model
682 * Binds #AdgDim:pos to the @pos named pair of @model. If @model
683 * is %NULL, the point will be unset. In any case, the old point
684 * is silently discarded, unreferencing its model if that point
685 * was bound to a named pair (hence, possibly destroying the model
686 * if this was the last reference).
688 * The assignment is lazy so @pos could be not be present in @model.
689 * Anyway, at the first access to this point an error will be raised
690 * if the named pair is still missing.
692 void
693 adg_dim_set_pos_from_model(AdgDim *dim, AdgModel *model, const gchar *pos)
695 AdgPoint *point = adg_point_new();
697 adg_point_set_pair_from_model(point, model, pos);
698 adg_dim_set_pos(dim, point);
700 adg_point_destroy(point);
704 * adg_dim_get_pos:
705 * @dim: an #AdgDim
707 * Gets the #AdgDim:pos point. The returned point is internally owned
708 * and must not be freed or modified. Anyway, it is not const because
709 * adg_point_get_pair() must be able to modify the internal cache of
710 * the returned point.
712 * Returns: the position point
714 AdgPoint *
715 adg_dim_get_pos(AdgDim *dim)
717 AdgDimPrivate *data;
719 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
721 data = dim->data;
723 return data->pos;
727 * adg_dim_set_level:
728 * @dim: an #AdgDim
729 * @level: the new level
731 * Sets a new level for this dimension. The level is used to
732 * stack the quotes using a spacing value from dim_style
733 * (specified in global space).
735 void
736 adg_dim_set_level(AdgDim *dim, gdouble level)
738 AdgDimPrivate *data;
740 g_return_if_fail(ADG_IS_DIM(dim));
742 data = dim->data;
743 data->level = level;
745 g_object_notify((GObject *) dim, "level");
749 * adg_dim_get_level:
750 * @dim: an #AdgDim
752 * Gets the level of this dimension.
754 * Returns: the level value
756 gdouble
757 adg_dim_get_level(AdgDim *dim)
759 AdgDimPrivate *data;
761 g_return_val_if_fail(ADG_IS_DIM(dim), 0);
763 data = dim->data;
765 return data->level;
769 * adg_dim_set_outside:
770 * @dim: an #AdgDim
771 * @outside: the new outside state
773 * Sets a new state for the #AdgDim:outside flag: check the property
774 * documentation for further details.
776 void
777 adg_dim_set_outside(AdgDim *dim, AdgThreeState outside)
779 g_return_if_fail(ADG_IS_DIM(dim));
781 if (_adg_set_outside(dim, outside))
782 g_object_notify((GObject *) dim, "outside");
786 * adg_dim_get_outside:
787 * @dim: an #AdgDim
789 * Gets the state of the #AdgDim:outside property: check the property
790 * documentation for further details.
792 * Returns: the current flag state
794 AdgThreeState
795 adg_dim_get_outside(AdgDim *dim)
797 AdgDimPrivate *data;
799 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
801 data = dim->data;
803 return data->outside;
807 * adg_dim_set_detached:
808 * @dim: an #AdgDim
809 * @detached: the new detached state
811 * Sets a new state for the #AdgDim:detached flag: check the property
812 * documentation for further details.
814 * This is used only by dimensions where detaching has meaning.
815 * In some cases, such as with #AdgRDim dimensions, this property is
816 * not used.
818 void
819 adg_dim_set_detached(AdgDim *dim, AdgThreeState detached)
821 g_return_if_fail(ADG_IS_DIM(dim));
823 if (_adg_set_detached(dim, detached))
824 g_object_notify((GObject *) dim, "detached");
828 * adg_dim_get_detached:
829 * @dim: an #AdgDim
831 * Gets the state of the #AdgDim:detached property: check the property
832 * documentation for further details.
834 * Returns: the current flag state
836 AdgThreeState
837 adg_dim_get_detached(AdgDim *dim)
839 AdgDimPrivate *data;
841 g_return_val_if_fail(ADG_IS_DIM(dim), ADG_THREE_STATE_UNKNOWN);
843 data = dim->data;
845 return data->detached;
849 * adg_dim_set_value:
850 * @dim: an #AdgDim
851 * @value: the value text
853 * Explicitely sets the text to use as value. If @value is %NULL or
854 * was never set, an automatic text is calculated using the format
855 * specified in the current #AdgDimStyle and getting its value by
856 * calling the default_value() virtual method.
858 void
859 adg_dim_set_value(AdgDim *dim, const gchar *value)
861 g_return_if_fail(ADG_IS_DIM(dim));
863 if (_adg_set_value(dim, value))
864 g_object_notify((GObject *) dim, "value");
868 * adg_dim_get_value:
869 * @dim: an #AdgDim
871 * Gets the value text. The string is internally owned and
872 * must not be freed or modified.
874 * Returns: the value text
876 const gchar *
877 adg_dim_get_value(AdgDim *dim)
879 AdgDimPrivate *data;
881 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
883 data = dim->data;
885 return data->value;
889 * adg_dim_set_limits:
890 * @dim: an #AdgDim
891 * @min: the new minumum value
892 * @max: the new maximum value
894 * Shortcut to set both the limits at once.
896 void
897 adg_dim_set_limits(AdgDim *dim, const gchar *min, const gchar *max)
899 g_return_if_fail(ADG_IS_DIM(dim));
901 g_object_freeze_notify((GObject *) dim);
902 adg_dim_set_min(dim, min);
903 adg_dim_set_max(dim, max);
904 g_object_thaw_notify((GObject *) dim);
908 * adg_dim_set_min:
909 * @dim: an #AdgDim
910 * @min: the new minimum limit
912 * Sets the minimum value. Use %NULL as @min to disable it.
914 void
915 adg_dim_set_min(AdgDim *dim, const gchar *min)
917 g_return_if_fail(ADG_IS_DIM(dim));
919 if (_adg_set_min(dim, min))
920 g_object_notify((GObject *) dim, "min");
924 * adg_dim_get_min:
925 * @dim: an #AdgDim
927 * Gets the minimum value text or %NULL on minimum value disabled.
928 * The string is internally owned and must not be freed or modified.
930 * Returns: the mimimum value text
932 const gchar *
933 adg_dim_get_min(AdgDim *dim)
935 AdgDimPrivate *data;
937 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
939 data = dim->data;
941 return data->min;
945 * adg_dim_set_max:
946 * @dim: an #AdgDim
947 * @max: the new maximum value
949 * Sets the maximum value. Use %NULL as @max to disable it.
951 void
952 adg_dim_set_max(AdgDim *dim, const gchar *max)
954 g_return_if_fail(ADG_IS_DIM(dim));
956 if (_adg_set_max(dim, max))
957 g_object_notify((GObject *) dim, "max");
961 * adg_dim_get_max:
962 * @dim: an #AdgDim
964 * Gets the maximum value text or %NULL on maximum value disabled.
965 * The string is internally owned and must not be freed or modified.
967 * Returns: the maximum value text
969 const gchar *
970 adg_dim_get_max(AdgDim *dim)
972 AdgDimPrivate *data;
974 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
976 data = dim->data;
978 return data->max;
982 * adg_dim_get_quote:
983 * @dim: an #AdgDim
985 * <note><para>
986 * This function is only useful in new dimension implementations.
987 * </para></note>
989 * Gets the quote entity, if any. This function is valid only after
990 * the #AdgDim implementation of the arrange() virtual method has
991 * been called.
993 * Returns: the quote entity
995 AdgAlignment *
996 adg_dim_get_quote(AdgDim *dim)
998 AdgDimPrivate *data;
1000 g_return_val_if_fail(ADG_IS_DIM(dim), NULL);
1002 data = dim->data;
1004 return data->quote.entity;
1008 * adg_dim_quote_angle:
1009 * @dim: an #AdgDim
1010 * @angle: an angle (in radians)
1012 * <note><para>
1013 * This function is only useful in new dimension implementations.
1014 * </para></note>
1016 * Converts @angle accordling to the style of @dim. Any quote angle
1017 * should be validated by this method because every dimensioning
1018 * style has its own convention regardling the text rotation.
1020 * Returns: the angle to use (always in radians)
1022 gdouble
1023 adg_dim_quote_angle(AdgDim *dim, gdouble angle)
1025 AdgDimClass *klass;
1027 g_return_val_if_fail(ADG_IS_DIM(dim), angle);
1029 klass = ADG_DIM_GET_CLASS(dim);
1031 if (klass->quote_angle == NULL)
1032 return angle;
1034 return klass->quote_angle(angle);
1038 static void
1039 _adg_global_changed(AdgEntity *entity)
1041 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1043 if (PARENT_ENTITY_CLASS->global_changed)
1044 PARENT_ENTITY_CLASS->global_changed(entity);
1046 if (data->quote.entity != NULL)
1047 adg_entity_global_changed((AdgEntity *) data->quote.entity);
1050 static void
1051 _adg_local_changed(AdgEntity *entity)
1053 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1055 if (PARENT_ENTITY_CLASS->local_changed)
1056 PARENT_ENTITY_CLASS->local_changed(entity);
1058 if (data->quote.entity != NULL)
1059 adg_entity_local_changed((AdgEntity *) data->quote.entity);
1062 static void
1063 _adg_invalidate(AdgEntity *entity)
1065 AdgDimPrivate *data = ((AdgDim *) entity)->data;
1067 if (PARENT_ENTITY_CLASS->invalidate)
1068 PARENT_ENTITY_CLASS->invalidate(entity);
1070 if (data->quote.entity != NULL)
1071 adg_entity_invalidate((AdgEntity *) data->quote.entity);
1073 adg_point_invalidate(data->ref1);
1074 adg_point_invalidate(data->ref2);
1075 adg_point_invalidate(data->pos);
1078 static void
1079 _adg_arrange(AdgEntity *entity)
1081 AdgDim *dim;
1082 AdgDimPrivate *data;
1083 AdgEntity *quote_entity;
1084 AdgContainer *quote_container;
1085 AdgEntity *value_entity;
1086 AdgEntity *min_entity;
1087 AdgEntity *max_entity;
1088 const AdgPair *shift;
1089 AdgMatrix map;
1091 dim = (AdgDim *) entity;
1092 data = dim->data;
1094 /* Resolve the dim style */
1095 if (data->dim_style == NULL)
1096 data->dim_style = (AdgDimStyle *)
1097 adg_entity_style(entity, data->dim_dress);
1099 if (data->quote.entity == NULL)
1100 data->quote.entity = g_object_new(ADG_TYPE_ALIGNMENT,
1101 "local-method", ADG_MIX_NONE,
1102 "parent", dim, NULL);
1104 quote_entity = (AdgEntity *) data->quote.entity;
1105 quote_container = (AdgContainer *) data->quote.entity;
1107 if (data->quote.value == NULL) {
1108 AdgDress dress = adg_dim_style_get_value_dress(data->dim_style);
1110 data->quote.value = g_object_new(ADG_TYPE_TOY_TEXT,
1111 "local-method", ADG_MIX_PARENT,
1112 "font-dress", dress, NULL);
1114 adg_container_add(quote_container, (AdgEntity *) data->quote.value);
1116 if (data->value) {
1117 adg_toy_text_set_label(data->quote.value, data->value);
1118 } else {
1119 AdgDimClass *klass = ADG_DIM_GET_CLASS(dim);
1121 if (klass->default_value) {
1122 /* Automatically generate the value text */
1123 gchar *text = klass->default_value(dim);
1124 adg_toy_text_set_label(data->quote.value, text);
1125 g_free(text);
1130 if (data->quote.min == NULL && data->min != NULL) {
1131 AdgDress dress = adg_dim_style_get_min_dress(data->dim_style);
1133 data->quote.min = g_object_new(ADG_TYPE_TOY_TEXT,
1134 "local-method", ADG_MIX_PARENT,
1135 "font-dress", dress, NULL);
1137 adg_container_add(quote_container, (AdgEntity *) data->quote.min);
1138 adg_toy_text_set_label(data->quote.min, data->min);
1141 if (data->quote.max == NULL && data->max != NULL) {
1142 AdgDress dress = adg_dim_style_get_max_dress(data->dim_style);
1144 data->quote.max = g_object_new(ADG_TYPE_TOY_TEXT,
1145 "local-method", ADG_MIX_PARENT,
1146 "font-dress", dress, NULL);
1148 adg_container_add(quote_container, (AdgEntity *) data->quote.max);
1149 adg_toy_text_set_label(data->quote.max, data->max);
1152 value_entity = (AdgEntity *) data->quote.value;
1153 min_entity = (AdgEntity *) data->quote.min;
1154 max_entity = (AdgEntity *) data->quote.max;
1155 shift = adg_dim_style_get_quote_shift(data->dim_style);
1157 adg_entity_set_global_map(quote_entity, adg_matrix_identity());
1158 adg_entity_global_changed(quote_entity);
1160 cairo_matrix_init_translate(&map, shift->x, shift->y);
1161 adg_entity_set_global_map(value_entity, &map);
1162 adg_entity_arrange(value_entity);
1164 /* Limit values (min and max) */
1165 if (min_entity != NULL || max_entity != NULL) {
1166 const CpmlExtents *extents = adg_entity_get_extents(value_entity);
1167 //CpmlExtents min_extents = { 0 };
1168 //CpmlExtents max_extents = { 0 };
1169 const AdgPair *limits_shift = adg_dim_style_get_limits_shift(data->dim_style);
1171 #if 0
1172 if (min_entity != NULL)
1173 cpml_extents_copy(&min_extents, adg_entity_get_extents(min_entity));
1175 if (max_entity != NULL)
1176 cpml_extents_copy(&max_extents, adg_entity_get_extents(max_entity));
1178 if (min_entity != NULL && max_entity != NULL)
1179 spacing = adg_dim_style_get_limits_spacing(data->dim_style);
1181 cairo_matrix_init_translate(&map,
1182 extents->size.x +
1183 shift->x + limit_shift->x,
1184 (spacing + min_extents.size.y +
1185 max_extents.size.y - extents->size.y) / 2 +
1186 shift->y + limit_shift->y);
1187 #endif
1188 cairo_matrix_init_translate(&map, extents->size.x + limits_shift->x,
1189 -extents->size.y / 2 + limits_shift->y);
1191 if (min_entity != NULL) {
1192 adg_entity_set_global_map(min_entity, &map);
1193 adg_entity_arrange(min_entity);
1194 extents = adg_entity_get_extents(min_entity);
1195 map.y0 -= extents->size.y +
1196 adg_dim_style_get_limits_spacing(data->dim_style);
1199 if (max_entity != NULL) {
1200 adg_entity_set_global_map(max_entity, &map);
1201 adg_entity_arrange(max_entity);
1205 adg_entity_arrange(quote_entity);
1208 static gchar *
1209 _adg_default_value(AdgDim *dim)
1211 g_warning("AdgDim::default_value not implemented for `%s'",
1212 g_type_name(G_TYPE_FROM_INSTANCE(dim)));
1213 return g_strdup("undef");
1216 static gdouble
1217 _adg_quote_angle(gdouble angle)
1219 angle = cpml_angle(angle);
1221 if (angle > G_PI_4 * 4 / 3 || angle <= -G_PI_4 * 3)
1222 angle = cpml_angle(angle + G_PI);
1224 return angle;
1227 static gboolean
1228 _adg_set_dim_dress(AdgDim *dim, AdgDress dress)
1230 AdgDimPrivate *data = dim->data;
1232 if (adg_dress_set(&data->dim_dress, dress)) {
1233 data->dim_style = NULL;
1234 return TRUE;
1237 return FALSE;
1240 static gboolean
1241 _adg_set_outside(AdgDim *dim, AdgThreeState outside)
1243 AdgDimPrivate *data;
1245 g_return_val_if_fail(adg_is_enum_value(outside, ADG_TYPE_THREE_STATE),
1246 FALSE);
1248 data = dim->data;
1250 if (data->outside == outside)
1251 return FALSE;
1253 data->outside = outside;
1255 return TRUE;
1258 static gboolean
1259 _adg_set_detached(AdgDim *dim, AdgThreeState detached)
1261 AdgDimPrivate *data;
1263 g_return_val_if_fail(adg_is_enum_value(detached, ADG_TYPE_THREE_STATE),
1264 FALSE);
1266 data = dim->data;
1268 if (data->detached == detached)
1269 return FALSE;
1271 data->detached = detached;
1273 return TRUE;
1276 static gboolean
1277 _adg_set_value(AdgDim *dim, const gchar *value)
1279 AdgDimPrivate *data;
1281 data = dim->data;
1283 if (adg_strcmp(value, data->value) == 0)
1284 return FALSE;
1286 g_free(data->value);
1287 data->value = g_strdup(value);
1289 if (data->quote.value != NULL) {
1290 g_object_unref(data->quote.value);
1291 data->quote.value = NULL;
1294 return TRUE;
1297 static gboolean
1298 _adg_set_min(AdgDim *dim, const gchar *min)
1300 AdgDimPrivate *data = dim->data;
1302 if (adg_strcmp(min, data->min) == 0)
1303 return FALSE;
1305 g_free(data->min);
1306 data->min = g_strdup(min);
1308 if (data->quote.min != NULL) {
1309 g_object_unref(data->quote.min);
1310 data->quote.min = NULL;
1313 return TRUE;
1316 static gboolean
1317 _adg_set_max(AdgDim *dim, const gchar *max)
1319 AdgDimPrivate *data = dim->data;
1321 if (adg_strcmp(max, data->max) == 0)
1322 return FALSE;
1324 g_free(data->max);
1325 data->max = g_strdup(max);
1327 if (data->quote.max != NULL) {
1328 g_object_unref(data->quote.max);
1329 data->quote.max = NULL;
1332 return TRUE;