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.
23 * @short_description: Root abstract class for all dimension entities
25 * The #AdgDim class is the base stub of all the dimension entities.
29 #include "adg-dim-private.h"
33 #define PARENT_CLASS ((AdgEntityClass *) adg_dim_parent_class)
50 static void finalize (GObject
*object
);
51 static void get_property (GObject
*object
,
55 static void set_property (GObject
*object
,
59 static void invalidate (AdgDim
*dim
);
60 static void invalidate_quote (AdgDim
*dim
);
61 static gchar
* default_quote (AdgDim
*dim
);
62 static void quote_layout (AdgDim
*dim
,
66 G_DEFINE_ABSTRACT_TYPE(AdgDim
, adg_dim
, ADG_TYPE_ENTITY
);
70 adg_dim_class_init(AdgDimClass
*klass
)
72 GObjectClass
*gobject_class
;
73 AdgEntityClass
*entity_class
;
76 gobject_class
= (GObjectClass
*) klass
;
77 entity_class
= (AdgEntityClass
*) klass
;
79 g_type_class_add_private(klass
, sizeof(AdgDimPrivate
));
81 gobject_class
->finalize
= finalize
;
82 gobject_class
->get_property
= get_property
;
83 gobject_class
->set_property
= set_property
;
85 klass
->default_quote
= default_quote
;
86 klass
->quote_layout
= quote_layout
;
88 param
= g_param_spec_boxed("ref1",
90 P_("First reference point of the dimension"),
92 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
);
93 g_object_class_install_property(gobject_class
, PROP_REF1
, param
);
95 param
= g_param_spec_boxed("ref2",
97 P_("Second reference point of the dimension"),
99 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
);
100 g_object_class_install_property(gobject_class
, PROP_REF2
, param
);
102 param
= g_param_spec_boxed("pos1",
104 P_("First position point: it will be computed with the level property to get the real dimension position"),
105 ADG_TYPE_PAIR
, G_PARAM_READWRITE
);
106 g_object_class_install_property(gobject_class
, PROP_POS1
, param
);
108 param
= g_param_spec_boxed("pos2",
110 P_("Second position point: it will be computed with the level property to get the real dimension position"),
111 ADG_TYPE_PAIR
, G_PARAM_READWRITE
);
112 g_object_class_install_property(gobject_class
, PROP_POS2
, param
);
114 param
= g_param_spec_double("level",
116 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"),
117 -G_MAXDOUBLE
, G_MAXDOUBLE
, 1.0,
118 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
);
119 g_object_class_install_property(gobject_class
, PROP_LEVEL
, param
);
121 param
= g_param_spec_string("quote",
123 P_("The quote to display: set to NULL to get the default quote"),
124 NULL
, G_PARAM_READWRITE
);
125 g_object_class_install_property(gobject_class
, PROP_QUOTE
, param
);
127 param
= g_param_spec_string("tolerance-up",
129 P_("The up tolerance of the quote: set to NULL to suppress"),
130 NULL
, G_PARAM_READWRITE
);
131 g_object_class_install_property(gobject_class
, PROP_TOLERANCE_UP
,
134 param
= g_param_spec_string("tolerance-down",
135 P_("Down Tolerance"),
136 P_("The down tolerance of the quote: set to NULL to suppress"),
137 NULL
, G_PARAM_READWRITE
);
138 g_object_class_install_property(gobject_class
, PROP_TOLERANCE_DOWN
,
141 param
= g_param_spec_string("note",
143 P_("A custom note appended to the dimension quote"),
144 NULL
, G_PARAM_READWRITE
);
145 g_object_class_install_property(gobject_class
, PROP_NOTE
, param
);
149 adg_dim_init(AdgDim
*dim
)
151 AdgDimPrivate
*priv
= G_TYPE_INSTANCE_GET_PRIVATE(dim
, ADG_TYPE_DIM
,
154 priv
->ref1
.x
= priv
->ref1
.y
= 0.;
155 priv
->ref2
.x
= priv
->ref2
.y
= 0.;
156 priv
->pos1
.x
= priv
->pos1
.y
= 0.;
157 priv
->pos2
.x
= priv
->pos2
.y
= 0.;
160 priv
->tolerance_up
= NULL
;
161 priv
->tolerance_down
= NULL
;
169 finalize(GObject
*object
)
171 AdgDimPrivate
*priv
= ((AdgDim
*) object
)->priv
;
174 g_free(priv
->tolerance_up
);
175 g_free(priv
->tolerance_down
);
177 ((GObjectClass
*) PARENT_CLASS
)->finalize(object
);
181 get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
183 AdgDim
*dim
= (AdgDim
*) object
;
187 g_value_set_boxed(value
, &dim
->priv
->ref1
);
190 g_value_set_boxed(value
, &dim
->priv
->ref2
);
193 g_value_set_boxed(value
, &dim
->priv
->pos1
);
196 g_value_set_boxed(value
, &dim
->priv
->pos1
);
199 g_value_set_double(value
, dim
->priv
->level
);
202 g_value_set_string(value
, dim
->priv
->quote
);
204 case PROP_TOLERANCE_UP
:
205 g_value_set_string(value
, dim
->priv
->tolerance_up
);
207 case PROP_TOLERANCE_DOWN
:
208 g_value_set_string(value
, dim
->priv
->tolerance_down
);
211 g_value_set_string(value
, dim
->priv
->note
);
214 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
220 set_property(GObject
*object
,
221 guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
223 AdgDim
*dim
= (AdgDim
*) object
;
227 cpml_pair_copy(&dim
->priv
->ref1
,
228 (AdgPair
*) g_value_get_boxed(value
));
232 cpml_pair_copy(&dim
->priv
->ref2
,
233 (AdgPair
*) g_value_get_boxed(value
));
237 cpml_pair_copy(&dim
->priv
->pos1
,
238 (AdgPair
*) g_value_get_boxed(value
));
242 cpml_pair_copy(&dim
->priv
->pos2
,
243 (AdgPair
*) g_value_get_boxed(value
));
247 dim
->priv
->level
= g_value_get_double(value
);
251 g_free(dim
->priv
->quote
);
252 dim
->priv
->quote
= g_value_dup_string(value
);
253 invalidate_quote(dim
);
255 case PROP_TOLERANCE_UP
:
256 g_free(dim
->priv
->tolerance_up
);
257 dim
->priv
->tolerance_up
= g_value_dup_string(value
);
258 invalidate_quote(dim
);
260 case PROP_TOLERANCE_DOWN
:
261 g_free(dim
->priv
->tolerance_down
);
262 dim
->priv
->tolerance_down
= g_value_dup_string(value
);
263 invalidate_quote(dim
);
266 g_free(dim
->priv
->note
);
267 dim
->priv
->note
= g_value_dup_string(value
);
268 invalidate_quote(dim
);
271 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
278 invalidate(AdgDim
*dim
)
280 dim
->priv
->quote_org
.x
= dim
->priv
->quote_org
.y
= 0.;
281 dim
->priv
->quote_angle
= 0.;
282 invalidate_quote(dim
);
286 invalidate_quote(AdgDim
*dim
)
288 dim
->priv
->quote_shift
.x
= dim
->priv
->quote_shift
.y
= 0.;
289 dim
->priv
->tolerance_up_shift
.x
= dim
->priv
->tolerance_up_shift
.y
= 0.;
290 dim
->priv
->tolerance_down_shift
.x
= dim
->priv
->tolerance_down_shift
.y
=
292 dim
->priv
->note_shift
.x
= dim
->priv
->note_shift
.y
= 0.;
297 default_quote(AdgDim
*dim
)
299 g_warning("AdgDim::default_quote not implemented for `%s'",
300 g_type_name(G_TYPE_FROM_INSTANCE(dim
)));
301 return g_strdup("undef");
305 quote_layout(AdgDim
*dim
, cairo_t
*cr
)
307 AdgDimStyle
*dim_style
;
310 cairo_text_extents_t extents
;
312 dim_style
= (AdgDimStyle
*) adg_entity_get_style((AdgEntity
*) dim
,
315 /* Compute the quote */
316 adg_style_apply(adg_dim_style_get_quote_style(dim_style
), cr
);
318 cairo_text_extents(cr
, dim
->priv
->quote
, &extents
);
319 cairo_user_to_device_distance(cr
, &extents
.width
, &extents
.height
);
320 cp
.x
= extents
.width
;
321 cp
.y
= -extents
.height
/ 2.;
323 /* Compute the tolerances */
324 if (dim
->priv
->tolerance_up
!= NULL
325 || dim
->priv
->tolerance_down
!= NULL
) {
329 adg_style_apply(adg_dim_style_get_tolerance_style(dim_style
), cr
);
332 midspacing
= adg_dim_style_get_tolerance_spacing(dim_style
) / 2.;
333 cpml_pair_copy(&offset
,
334 adg_dim_style_get_tolerance_shift(dim_style
));
337 if (dim
->priv
->tolerance_up
!= NULL
) {
338 cairo_text_extents(cr
, dim
->priv
->tolerance_up
, &extents
);
339 cairo_user_to_device_distance(cr
, &extents
.width
,
341 dim
->priv
->tolerance_up_shift
.x
= cp
.x
;
342 dim
->priv
->tolerance_up_shift
.y
= cp
.y
+ offset
.y
- midspacing
;
343 width
= extents
.width
;
346 if (dim
->priv
->tolerance_down
!= NULL
) {
347 cairo_text_extents(cr
, dim
->priv
->tolerance_down
, &extents
);
348 cairo_user_to_device_distance(cr
, &extents
.width
,
350 dim
->priv
->tolerance_down_shift
.x
= cp
.x
;
351 dim
->priv
->tolerance_down_shift
.y
=
352 cp
.y
+ offset
.y
+ midspacing
+ extents
.height
;
354 if (extents
.width
> width
)
355 width
= extents
.width
;
361 /* Compute the note */
362 if (dim
->priv
->note
!= NULL
) {
363 adg_style_apply(adg_dim_style_get_note_style(dim_style
), cr
);
365 cpml_pair_copy(&offset
, adg_dim_style_get_note_shift(dim_style
));
368 cairo_text_extents(cr
, dim
->priv
->note
, &extents
);
369 cairo_user_to_device_distance(cr
, &extents
.width
, &extents
.height
);
370 dim
->priv
->note_shift
.x
= cp
.x
;
371 dim
->priv
->note_shift
.y
= cp
.y
+ offset
.y
+ extents
.height
/ 2.;
373 cp
.x
+= extents
.width
;
376 /* Calculating the offsets */
377 cpml_pair_copy(&offset
, adg_dim_style_get_quote_shift(dim_style
));
378 offset
.x
-= cp
.x
/ 2.;
380 cpml_pair_copy(&dim
->priv
->quote_shift
, &offset
);
382 dim
->priv
->tolerance_up_shift
.x
+= offset
.x
;
383 dim
->priv
->tolerance_up_shift
.y
+= offset
.y
;
385 dim
->priv
->tolerance_down_shift
.x
+= offset
.x
;
386 dim
->priv
->tolerance_down_shift
.y
+= offset
.y
;
388 dim
->priv
->note_shift
.x
+= offset
.x
;
389 dim
->priv
->note_shift
.y
+= offset
.y
;
394 adg_dim_get_ref1(AdgDim
*dim
)
396 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
398 return &dim
->priv
->ref1
;
402 adg_dim_get_ref2(AdgDim
*dim
)
404 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
406 return &dim
->priv
->ref2
;
410 adg_dim_set_ref(AdgDim
*dim
, const AdgPair
*ref1
, const AdgPair
*ref2
)
414 g_return_if_fail(ADG_IS_DIM(dim
));
416 object
= G_OBJECT(dim
);
419 dim
->priv
->ref1
= *ref1
;
420 g_object_notify(object
, "ref1");
424 dim
->priv
->ref2
= *ref2
;
425 g_object_notify(object
, "ref2");
430 adg_dim_set_ref_explicit(AdgDim
*dim
, double ref1_x
, double ref1_y
,
431 double ref2_x
, double ref2_y
)
441 adg_dim_set_ref(dim
, &ref1
, &ref2
);
445 adg_dim_get_pos1(AdgDim
*dim
)
447 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
449 return &dim
->priv
->pos1
;
453 adg_dim_get_pos2(AdgDim
*dim
)
455 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
457 return &dim
->priv
->pos2
;
461 adg_dim_set_pos(AdgDim
*dim
, AdgPair
*pos1
, AdgPair
*pos2
)
465 g_return_if_fail(ADG_IS_DIM(dim
));
467 object
= G_OBJECT(dim
);
469 g_object_freeze_notify(object
);
472 dim
->priv
->pos1
= *pos1
;
473 g_object_notify(object
, "pos1");
477 dim
->priv
->pos2
= *pos2
;
478 g_object_notify(object
, "pos2");
481 g_object_thaw_notify(object
);
485 adg_dim_set_pos_explicit(AdgDim
*dim
, double pos1_x
, double pos1_y
,
486 double pos2_x
, double pos2_y
)
496 adg_dim_set_pos(dim
, &pos1
, &pos2
);
500 adg_dim_get_level(AdgDim
*dim
)
502 g_return_val_if_fail(ADG_IS_DIM(dim
), 0.0);
504 return dim
->priv
->level
;
508 adg_dim_set_level(AdgDim
*dim
, double level
)
510 g_return_if_fail(ADG_IS_DIM(dim
));
512 dim
->priv
->level
= level
;
513 g_object_notify((GObject
*) dim
, "level");
517 adg_dim_get_quote(AdgDim
*dim
)
519 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
521 return dim
->priv
->quote
;
525 adg_dim_set_quote(AdgDim
*dim
, const gchar
*quote
)
527 g_return_if_fail(ADG_IS_DIM(dim
));
529 g_free(dim
->priv
->quote
);
530 dim
->priv
->quote
= g_strdup(quote
);
531 invalidate_quote(dim
);
533 g_object_notify((GObject
*) dim
, "quote");
537 adg_dim_get_tolerance_up(AdgDim
*dim
)
539 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
541 return dim
->priv
->tolerance_up
;
545 adg_dim_set_tolerance_up(AdgDim
*dim
, const gchar
*tolerance_up
)
547 g_return_if_fail(ADG_IS_DIM(dim
));
549 g_free(dim
->priv
->tolerance_up
);
550 dim
->priv
->tolerance_down
= g_strdup(tolerance_up
);
551 invalidate_quote(dim
);
553 g_object_notify((GObject
*) dim
, "tolerance-up");
557 adg_dim_get_tolerance_down(AdgDim
*dim
)
559 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
561 return dim
->priv
->tolerance_down
;
565 adg_dim_set_tolerance_down(AdgDim
*dim
, const gchar
*tolerance_down
)
567 g_return_if_fail(ADG_IS_DIM(dim
));
569 g_free(dim
->priv
->tolerance_down
);
570 dim
->priv
->tolerance_down
= g_strdup(tolerance_down
);
571 invalidate_quote(dim
);
573 g_object_notify((GObject
*) dim
, "tolerance-down");
577 adg_dim_set_tolerances(AdgDim
*dim
,
578 const gchar
*tolerance_up
, const gchar
*tolerance_down
)
582 g_return_if_fail(ADG_IS_DIM(dim
));
584 object
= G_OBJECT(dim
);
586 g_object_freeze_notify(object
);
588 g_free(dim
->priv
->tolerance_up
);
589 dim
->priv
->tolerance_up
= g_strdup(tolerance_up
);
590 g_object_notify(object
, "tolerance-up");
592 g_free(dim
->priv
->tolerance_down
);
593 dim
->priv
->tolerance_down
= g_strdup(tolerance_down
);
594 g_object_notify(object
, "tolerance-down");
596 invalidate_quote(dim
);
598 g_object_thaw_notify(object
);
602 adg_dim_get_note(AdgDim
*dim
)
604 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
606 return dim
->priv
->note
;
610 adg_dim_set_note(AdgDim
*dim
, const gchar
*note
)
612 g_return_if_fail(ADG_IS_DIM(dim
));
614 g_free(dim
->priv
->note
);
615 dim
->priv
->note
= g_strdup(note
);
616 invalidate_quote(dim
);
618 g_object_notify((GObject
*) dim
, "note");
623 * adg_dim_render_quote:
624 * @dim: an #AdgDim object
625 * @cr: a #cairo_t drawing context
627 * Renders the quote of @dim at the @org position. This function
628 * is only useful in new dimension implementations.
631 adg_dim_render_quote(AdgDim
*dim
, cairo_t
*cr
)
633 AdgDimStyle
*dim_style
;
635 AdgPair tolerance_up_shift
;
636 AdgPair tolerance_down_shift
;
639 g_return_if_fail(ADG_IS_DIM(dim
));
641 dim_style
= (AdgDimStyle
*) adg_entity_get_style((AdgEntity
*) dim
,
644 if (dim
->priv
->quote
== NULL
) {
645 dim
->priv
->quote
= ADG_DIM_GET_CLASS(dim
)->default_quote(dim
);
646 invalidate_quote(dim
);
647 g_object_notify((GObject
*) dim
, "quote");
650 ADG_DIM_GET_CLASS(dim
)->quote_layout(dim
, cr
);
652 cpml_pair_copy("e_shift
, &dim
->priv
->quote_shift
);
653 cairo_device_to_user_distance(cr
, "e_shift
.x
, "e_shift
.y
);
654 cpml_pair_copy(&tolerance_up_shift
, &dim
->priv
->tolerance_up_shift
);
655 cairo_device_to_user_distance(cr
, &tolerance_up_shift
.x
,
656 &tolerance_up_shift
.y
);
657 cpml_pair_copy(&tolerance_down_shift
,
658 &dim
->priv
->tolerance_down_shift
);
659 cairo_device_to_user_distance(cr
, &tolerance_down_shift
.x
,
660 &tolerance_down_shift
.y
);
663 cairo_translate(cr
, dim
->priv
->quote_org
.x
, dim
->priv
->quote_org
.y
);
664 cairo_rotate(cr
, dim
->priv
->quote_angle
);
666 /* Rendering quote */
667 adg_style_apply(adg_dim_style_get_quote_style(dim_style
), cr
);
668 cairo_move_to(cr
, quote_shift
.x
, quote_shift
.y
);
669 cairo_show_text(cr
, dim
->priv
->quote
);
671 /* Rendering tolerances */
672 if (dim
->priv
->tolerance_up
!= NULL
673 || dim
->priv
->tolerance_down
!= NULL
) {
674 adg_style_apply(adg_dim_style_get_tolerance_style(dim_style
), cr
);
676 if (dim
->priv
->tolerance_up
!= NULL
) {
677 cairo_move_to(cr
, tolerance_up_shift
.x
, tolerance_up_shift
.y
);
678 cairo_show_text(cr
, dim
->priv
->tolerance_up
);
680 if (dim
->priv
->tolerance_down
!= NULL
) {
681 cairo_move_to(cr
, tolerance_down_shift
.x
,
682 tolerance_down_shift
.y
);
683 cairo_show_text(cr
, dim
->priv
->tolerance_down
);
688 if (dim
->priv
->note
!= NULL
) {
689 cairo_move_to(cr
, note_shift
.x
, note_shift
.y
);
690 cairo_show_text(cr
, dim
->priv
->note
);