1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007-2008, 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 Library 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 * Library 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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
24 * @short_description: Root abstract class for all dimension entities
26 * The #AdgDim class is the base stub of all the dimension entities.
30 #include "adg-dim-private.h"
31 #include "adg-dim-style.h"
32 #include "adg-dim-style-private.h"
36 #define PARENT_CLASS ((AdgEntityClass *) adg_dim_parent_class)
55 static void finalize (GObject
*object
);
56 static void get_property (GObject
*object
,
60 static void set_property (GObject
*object
,
64 static void invalidate (AdgDim
*dim
);
65 static void invalidate_quote (AdgDim
*dim
);
66 static const AdgDimStyle
*
67 get_dim_style (AdgEntity
*entity
);
68 static void set_dim_style (AdgEntity
*entity
,
69 AdgDimStyle
*dim_style
);
70 static gchar
* default_quote (AdgDim
*dim
);
71 static void quote_layout (AdgDim
*dim
,
75 G_DEFINE_ABSTRACT_TYPE (AdgDim
, adg_dim
, ADG_TYPE_ENTITY
);
79 adg_dim_class_init (AdgDimClass
*klass
)
81 GObjectClass
*gobject_class
;
82 AdgEntityClass
*entity_class
;
85 gobject_class
= (GObjectClass
*) klass
;
86 entity_class
= (AdgEntityClass
*) klass
;
88 g_type_class_add_private (klass
, sizeof (AdgDimPrivate
));
90 gobject_class
->finalize
= finalize
;
91 gobject_class
->get_property
= get_property
;
92 gobject_class
->set_property
= set_property
;
94 entity_class
->get_dim_style
= get_dim_style
;
95 entity_class
->set_dim_style
= set_dim_style
;
97 klass
->default_quote
= default_quote
;
98 klass
->quote_layout
= quote_layout
;
100 param
= g_param_spec_boxed ("dim-style",
101 P_("Dimension Style"),
102 P_("Dimension style to use while rendering"),
105 g_object_class_install_property (gobject_class
, PROP_DIM_STYLE
, param
);
107 param
= g_param_spec_boxed ("ref1",
109 P_("First reference point of the dimension"),
111 G_PARAM_READWRITE
|G_PARAM_CONSTRUCT
);
112 g_object_class_install_property (gobject_class
, PROP_REF1
, param
);
114 param
= g_param_spec_boxed ("ref2",
116 P_("Second reference point of the dimension"),
118 G_PARAM_READWRITE
|G_PARAM_CONSTRUCT
);
119 g_object_class_install_property (gobject_class
, PROP_REF2
, param
);
121 param
= g_param_spec_boxed ("pos1",
123 P_("First position point: it will be computed with the level property to get the real dimension position"),
126 g_object_class_install_property (gobject_class
, PROP_POS1
, param
);
128 param
= g_param_spec_boxed ("pos2",
130 P_("Second position point: it will be computed with the level property to get the real dimension position"),
133 g_object_class_install_property (gobject_class
, PROP_POS2
, param
);
135 param
= g_param_spec_double ("level",
137 P_("The dimension level, that is the factor to multiply dim_style->baseline_spacing to get the offset (in device units) from pos1..pos2 where render the dimension baseline"),
138 -G_MAXDOUBLE
, G_MAXDOUBLE
, 1.0,
139 G_PARAM_READWRITE
|G_PARAM_CONSTRUCT
);
140 g_object_class_install_property (gobject_class
, PROP_LEVEL
, param
);
142 param
= g_param_spec_string ("quote",
144 P_("The quote to display: set to NULL to get the default quote"),
147 g_object_class_install_property (gobject_class
, PROP_QUOTE
, param
);
149 param
= g_param_spec_string ("tolerance-up",
151 P_("The up tolerance of the quote: set to NULL to suppress"),
154 g_object_class_install_property (gobject_class
, PROP_TOLERANCE_UP
, param
);
156 param
= g_param_spec_string ("tolerance-down",
157 P_("Down Tolerance"),
158 P_("The down tolerance of the quote: set to NULL to suppress"),
161 g_object_class_install_property (gobject_class
, PROP_TOLERANCE_DOWN
, param
);
163 param
= g_param_spec_string ("note",
165 P_("A custom note appended to the dimension quote"),
168 g_object_class_install_property (gobject_class
, PROP_NOTE
, param
);
172 adg_dim_init (AdgDim
*dim
)
174 AdgDimPrivate
*priv
= G_TYPE_INSTANCE_GET_PRIVATE (dim
, ADG_TYPE_DIM
,
177 priv
->dim_style
= (AdgDimStyle
*) adg_dim_style_from_id (ADG_DIM_STYLE_ISO
);
179 priv
->ref1
.x
= priv
->ref1
.y
= 0.;
180 priv
->ref2
.x
= priv
->ref2
.y
= 0.;
181 priv
->pos1
.x
= priv
->pos1
.y
= 0.;
182 priv
->pos2
.x
= priv
->pos2
.y
= 0.;
185 priv
->tolerance_up
= NULL
;
186 priv
->tolerance_down
= NULL
;
194 finalize (GObject
*object
)
196 AdgDimPrivate
*priv
= ((AdgDim
*) object
)->priv
;
198 g_free (priv
->quote
);
199 g_free (priv
->tolerance_up
);
200 g_free (priv
->tolerance_down
);
202 ((GObjectClass
*) PARENT_CLASS
)->finalize (object
);
206 get_property (GObject
*object
,
211 AdgDim
*dim
= (AdgDim
*) object
;
216 g_value_set_boxed (value
, dim
->priv
->dim_style
);
219 g_value_set_boxed (value
, &dim
->priv
->ref1
);
222 g_value_set_boxed (value
, &dim
->priv
->ref2
);
225 g_value_set_boxed (value
, &dim
->priv
->pos1
);
228 g_value_set_boxed (value
, &dim
->priv
->pos1
);
231 g_value_set_double (value
, dim
->priv
->level
);
234 g_value_set_string (value
, dim
->priv
->quote
);
236 case PROP_TOLERANCE_UP
:
237 g_value_set_string (value
, dim
->priv
->tolerance_up
);
239 case PROP_TOLERANCE_DOWN
:
240 g_value_set_string (value
, dim
->priv
->tolerance_down
);
243 g_value_set_string (value
, dim
->priv
->note
);
246 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
252 set_property (GObject
*object
,
257 AdgDim
*dim
= (AdgDim
*) object
;
262 dim
->priv
->dim_style
= g_value_get_boxed (value
);
266 cpml_pair_copy (&dim
->priv
->ref1
, (AdgPair
*) g_value_get_boxed (value
));
270 cpml_pair_copy (&dim
->priv
->ref2
, (AdgPair
*) g_value_get_boxed (value
));
274 cpml_pair_copy (&dim
->priv
->pos1
, (AdgPair
*) g_value_get_boxed (value
));
278 cpml_pair_copy (&dim
->priv
->pos2
, (AdgPair
*) g_value_get_boxed (value
));
282 dim
->priv
->level
= g_value_get_double (value
);
286 g_free (dim
->priv
->quote
);
287 dim
->priv
->quote
= g_value_dup_string (value
);
288 invalidate_quote (dim
);
290 case PROP_TOLERANCE_UP
:
291 g_free (dim
->priv
->tolerance_up
);
292 dim
->priv
->tolerance_up
= g_value_dup_string (value
);
293 invalidate_quote (dim
);
295 case PROP_TOLERANCE_DOWN
:
296 g_free (dim
->priv
->tolerance_down
);
297 dim
->priv
->tolerance_down
= g_value_dup_string (value
);
298 invalidate_quote (dim
);
301 g_free (dim
->priv
->note
);
302 dim
->priv
->note
= g_value_dup_string (value
);
303 invalidate_quote (dim
);
306 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
313 invalidate (AdgDim
*dim
)
315 dim
->priv
->quote_org
.x
= dim
->priv
->quote_org
.y
= 0.;
316 dim
->priv
->quote_angle
= 0.;
317 invalidate_quote (dim
);
321 invalidate_quote (AdgDim
*dim
)
323 dim
->priv
->quote_shift
.x
= dim
->priv
->quote_shift
.y
= 0.;
324 dim
->priv
->tolerance_up_shift
.x
= dim
->priv
->tolerance_up_shift
.y
= 0.;
325 dim
->priv
->tolerance_down_shift
.x
= dim
->priv
->tolerance_down_shift
.y
= 0.;
326 dim
->priv
->note_shift
.x
= dim
->priv
->note_shift
.y
= 0.;
330 static const AdgDimStyle
*
331 get_dim_style (AdgEntity
*entity
)
333 return ((AdgDim
*) entity
)->priv
->dim_style
;
337 set_dim_style (AdgEntity
*entity
,
338 AdgDimStyle
*dim_style
)
340 ((AdgDim
*) entity
)->priv
->dim_style
= dim_style
;
341 g_object_notify (G_OBJECT (entity
), "dim-style");
345 default_quote (AdgDim
*dim
)
347 g_warning ("AdgDim::default_quote not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (dim
)));
348 return g_strdup ("undef");
352 quote_layout (AdgDim
*dim
,
355 AdgDimStylePrivate
*style_data
;
358 cairo_text_extents_t extents
;
360 style_data
= dim
->priv
->dim_style
->priv
;
362 /* Compute the quote */
363 adg_font_style_apply (ADG_FONT_STYLE (style_data
->quote_style
), cr
);
365 cairo_text_extents (cr
, dim
->priv
->quote
, &extents
);
366 cairo_user_to_device_distance (cr
, &extents
.width
, &extents
.height
);
367 cp
.x
= extents
.width
;
368 cp
.y
= -extents
.height
/ 2.;
370 /* Compute the tolerances */
371 if (dim
->priv
->tolerance_up
!= NULL
|| dim
->priv
->tolerance_down
!= NULL
)
376 adg_font_style_apply (ADG_FONT_STYLE (style_data
->tolerance_style
), cr
);
379 midspacing
= style_data
->tolerance_spacing
/ 2.0;
380 cpml_pair_copy (&offset
, &style_data
->tolerance_shift
);
383 if (dim
->priv
->tolerance_up
!= NULL
)
385 cairo_text_extents (cr
, dim
->priv
->tolerance_up
, &extents
);
386 cairo_user_to_device_distance (cr
, &extents
.width
, &extents
.height
);
387 dim
->priv
->tolerance_up_shift
.x
= cp
.x
;
388 dim
->priv
->tolerance_up_shift
.y
= cp
.y
+ offset
.y
- midspacing
;
389 width
= extents
.width
;
392 if (dim
->priv
->tolerance_down
!= NULL
)
394 cairo_text_extents (cr
, dim
->priv
->tolerance_down
, &extents
);
395 cairo_user_to_device_distance (cr
, &extents
.width
, &extents
.height
);
396 dim
->priv
->tolerance_down_shift
.x
= cp
.x
;
397 dim
->priv
->tolerance_down_shift
.y
= cp
.y
+ offset
.y
+ midspacing
+ extents
.height
;
399 if (extents
.width
> width
)
400 width
= extents
.width
;
406 /* Compute the note */
407 if (dim
->priv
->note
!= NULL
)
409 adg_font_style_apply (ADG_FONT_STYLE (style_data
->note_style
), cr
);
411 cpml_pair_copy (&offset
, &style_data
->note_shift
);
414 cairo_text_extents (cr
, dim
->priv
->note
, &extents
);
415 cairo_user_to_device_distance (cr
, &extents
.width
, &extents
.height
);
416 dim
->priv
->note_shift
.x
= cp
.x
;
417 dim
->priv
->note_shift
.y
= cp
.y
+ offset
.y
+ extents
.height
/ 2.;
419 cp
.x
+= extents
.width
;
422 /* Calculating the offsets */
423 offset
.x
= style_data
->quote_shift
.x
- cp
.x
/ 2.0;
424 offset
.y
= style_data
->quote_shift
.y
;
426 cpml_pair_copy (&dim
->priv
->quote_shift
, &offset
);
428 dim
->priv
->tolerance_up_shift
.x
+= offset
.x
;
429 dim
->priv
->tolerance_up_shift
.y
+= offset
.y
;
431 dim
->priv
->tolerance_down_shift
.x
+= offset
.x
;
432 dim
->priv
->tolerance_down_shift
.y
+= offset
.y
;
434 dim
->priv
->note_shift
.x
+= offset
.x
;
435 dim
->priv
->note_shift
.y
+= offset
.y
;
440 adg_dim_get_ref1 (AdgDim
*dim
)
442 g_return_val_if_fail (ADG_IS_DIM (dim
), NULL
);
444 return &dim
->priv
->ref1
;
448 adg_dim_get_ref2 (AdgDim
*dim
)
450 g_return_val_if_fail (ADG_IS_DIM (dim
), NULL
);
452 return &dim
->priv
->ref2
;
456 adg_dim_set_ref (AdgDim
*dim
,
462 g_return_if_fail (ADG_IS_DIM (dim
));
464 object
= G_OBJECT (dim
);
468 dim
->priv
->ref1
= *ref1
;
469 g_object_notify (object
, "ref1");
474 dim
->priv
->ref2
= *ref2
;
475 g_object_notify (object
, "ref2");
480 adg_dim_set_ref_explicit (AdgDim
*dim
,
494 adg_dim_set_ref (dim
, &ref1
, &ref2
);
498 adg_dim_get_pos1 (AdgDim
*dim
)
500 g_return_val_if_fail (ADG_IS_DIM (dim
), NULL
);
502 return &dim
->priv
->pos1
;
506 adg_dim_get_pos2 (AdgDim
*dim
)
508 g_return_val_if_fail (ADG_IS_DIM (dim
), NULL
);
510 return &dim
->priv
->pos2
;
514 adg_dim_set_pos (AdgDim
*dim
,
520 g_return_if_fail (ADG_IS_DIM (dim
));
522 object
= G_OBJECT (dim
);
524 g_object_freeze_notify (object
);
528 dim
->priv
->pos1
= *pos1
;
529 g_object_notify (object
, "pos1");
534 dim
->priv
->pos2
= *pos2
;
535 g_object_notify (object
, "pos2");
538 g_object_thaw_notify (object
);
542 adg_dim_set_pos_explicit (AdgDim
*dim
,
556 adg_dim_set_pos (dim
, &pos1
, &pos2
);
560 adg_dim_get_level (AdgDim
*dim
)
562 g_return_val_if_fail (ADG_IS_DIM (dim
), 0.0);
564 return dim
->priv
->level
;
568 adg_dim_set_level (AdgDim
*dim
,
571 g_return_if_fail (ADG_IS_DIM (dim
));
573 dim
->priv
->level
= level
;
574 g_object_notify ((GObject
*) dim
, "level");
578 adg_dim_get_quote (AdgDim
*dim
)
580 g_return_val_if_fail (ADG_IS_DIM (dim
), NULL
);
582 return dim
->priv
->quote
;
586 adg_dim_set_quote (AdgDim
*dim
,
589 g_return_if_fail (ADG_IS_DIM (dim
));
591 g_free (dim
->priv
->quote
);
592 dim
->priv
->quote
= g_strdup (quote
);
593 invalidate_quote (dim
);
595 g_object_notify ((GObject
*) dim
, "quote");
599 adg_dim_get_tolerance_up (AdgDim
*dim
)
601 g_return_val_if_fail (ADG_IS_DIM (dim
), NULL
);
603 return dim
->priv
->tolerance_up
;
607 adg_dim_set_tolerance_up (AdgDim
*dim
,
608 const gchar
*tolerance_up
)
610 g_return_if_fail (ADG_IS_DIM (dim
));
612 g_free (dim
->priv
->tolerance_up
);
613 dim
->priv
->tolerance_down
= g_strdup (tolerance_up
);
614 invalidate_quote (dim
);
616 g_object_notify ((GObject
*) dim
, "tolerance-up");
620 adg_dim_get_tolerance_down (AdgDim
*dim
)
622 g_return_val_if_fail (ADG_IS_DIM (dim
), NULL
);
624 return dim
->priv
->tolerance_down
;
628 adg_dim_set_tolerance_down (AdgDim
*dim
,
629 const gchar
*tolerance_down
)
631 g_return_if_fail (ADG_IS_DIM (dim
));
633 g_free (dim
->priv
->tolerance_down
);
634 dim
->priv
->tolerance_down
= g_strdup (tolerance_down
);
635 invalidate_quote (dim
);
637 g_object_notify ((GObject
*) dim
, "tolerance-down");
641 adg_dim_set_tolerances (AdgDim
*dim
,
642 const gchar
*tolerance_up
,
643 const gchar
*tolerance_down
)
647 g_return_if_fail (ADG_IS_DIM (dim
));
649 object
= G_OBJECT (dim
);
651 g_object_freeze_notify (object
);
653 g_free (dim
->priv
->tolerance_up
);
654 dim
->priv
->tolerance_up
= g_strdup (tolerance_up
);
655 g_object_notify (object
, "tolerance-up");
657 g_free (dim
->priv
->tolerance_down
);
658 dim
->priv
->tolerance_down
= g_strdup (tolerance_down
);
659 g_object_notify (object
, "tolerance-down");
661 invalidate_quote (dim
);
663 g_object_thaw_notify (object
);
667 adg_dim_get_note (AdgDim
*dim
)
669 g_return_val_if_fail (ADG_IS_DIM (dim
), NULL
);
671 return dim
->priv
->note
;
675 adg_dim_set_note (AdgDim
*dim
,
678 g_return_if_fail (ADG_IS_DIM (dim
));
680 g_free (dim
->priv
->note
);
681 dim
->priv
->note
= g_strdup (note
);
682 invalidate_quote (dim
);
684 g_object_notify ((GObject
*) dim
, "note");
689 * _adg_dim_render_quote:
690 * @dim: an #AdgDim object
691 * @cr: a #cairo_t drawing context
693 * Renders the quote of @dim at the @org position.
695 * This function is only useful in new dimension implementations.
698 _adg_dim_render_quote (AdgDim
*dim
,
701 AdgDimStylePrivate
*style_data
;
703 AdgPair tolerance_up_shift
;
704 AdgPair tolerance_down_shift
;
707 g_return_if_fail (ADG_IS_DIM (dim
));
708 g_return_if_fail (dim
->priv
->dim_style
!= NULL
);
710 style_data
= dim
->priv
->dim_style
->priv
;
712 if (dim
->priv
->quote
== NULL
)
714 dim
->priv
->quote
= ADG_DIM_GET_CLASS (dim
)->default_quote (dim
);
715 invalidate_quote (dim
);
716 g_object_notify ((GObject
*) dim
, "quote");
719 ADG_DIM_GET_CLASS (dim
)->quote_layout (dim
, cr
);
721 cpml_pair_copy ("e_shift
, &dim
->priv
->quote_shift
);
722 cairo_device_to_user_distance (cr
, "e_shift
.x
, "e_shift
.y
);
723 cpml_pair_copy (&tolerance_up_shift
, &dim
->priv
->tolerance_up_shift
);
724 cairo_device_to_user_distance (cr
, &tolerance_up_shift
.x
, &tolerance_up_shift
.y
);
725 cpml_pair_copy (&tolerance_down_shift
, &dim
->priv
->tolerance_down_shift
);
726 cairo_device_to_user_distance (cr
, &tolerance_down_shift
.x
, &tolerance_down_shift
.y
);
729 cairo_translate (cr
, dim
->priv
->quote_org
.x
, dim
->priv
->quote_org
.y
);
730 cairo_rotate (cr
, dim
->priv
->quote_angle
);
732 /* Rendering quote */
733 adg_font_style_apply (ADG_FONT_STYLE (style_data
->quote_style
), cr
);
734 cairo_move_to (cr
, quote_shift
.x
, quote_shift
.y
);
735 cairo_show_text (cr
, dim
->priv
->quote
);
737 /* Rendering tolerances */
738 if (dim
->priv
->tolerance_up
!= NULL
|| dim
->priv
->tolerance_down
!= NULL
)
740 adg_font_style_apply (ADG_FONT_STYLE (style_data
->tolerance_style
), cr
);
742 if (dim
->priv
->tolerance_up
!= NULL
)
744 cairo_move_to (cr
, tolerance_up_shift
.x
, tolerance_up_shift
.y
);
745 cairo_show_text (cr
, dim
->priv
->tolerance_up
);
747 if (dim
->priv
->tolerance_down
!= NULL
)
749 cairo_move_to (cr
, tolerance_down_shift
.x
, tolerance_down_shift
.y
);
750 cairo_show_text (cr
, dim
->priv
->tolerance_down
);
755 if (dim
->priv
->note
!= NULL
)
757 cairo_move_to (cr
, note_shift
.x
, note_shift
.y
);
758 cairo_show_text (cr
, dim
->priv
->note
);