Implemented patterns in AdgStyle
[adg.git] / adg / adg-dim.c
blobc17e873b573d2cb6af1363cc15127e005593de0e
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.
21 /**
22 * SECTION:dim
23 * @title: AdgDim
24 * @short_description: Root abstract class for all dimension entities
26 * The #AdgDim class is the base stub of all the dimension entities.
29 #include "adg-dim.h"
30 #include "adg-dim-private.h"
31 #include "adg-dim-style.h"
32 #include "adg-dim-style-private.h"
33 #include "adg-util.h"
34 #include "adg-intl.h"
36 #define PARENT_CLASS ((AdgEntityClass *) adg_dim_parent_class)
39 enum
41 PROP_0,
42 PROP_DIM_STYLE,
43 PROP_REF1,
44 PROP_REF2,
45 PROP_POS1,
46 PROP_POS2,
47 PROP_LEVEL,
48 PROP_QUOTE,
49 PROP_TOLERANCE_UP,
50 PROP_TOLERANCE_DOWN,
51 PROP_NOTE
55 static void finalize (GObject *object);
56 static void get_property (GObject *object,
57 guint param_id,
58 GValue *value,
59 GParamSpec *pspec);
60 static void set_property (GObject *object,
61 guint param_id,
62 const GValue *value,
63 GParamSpec *pspec);
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,
72 cairo_t *cr);
75 G_DEFINE_ABSTRACT_TYPE (AdgDim, adg_dim, ADG_TYPE_ENTITY);
78 static void
79 adg_dim_class_init (AdgDimClass *klass)
81 GObjectClass *gobject_class;
82 AdgEntityClass *entity_class;
83 GParamSpec *param;
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"),
103 ADG_TYPE_DIM_STYLE,
104 G_PARAM_READWRITE);
105 g_object_class_install_property (gobject_class, PROP_DIM_STYLE, param);
107 param = g_param_spec_boxed ("ref1",
108 P_("Reference 1"),
109 P_("First reference point of the dimension"),
110 ADG_TYPE_PAIR,
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",
115 P_("Reference 2"),
116 P_("Second reference point of the dimension"),
117 ADG_TYPE_PAIR,
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",
122 P_("Position 1"),
123 P_("First position point: it will be computed with the level property to get the real dimension position"),
124 ADG_TYPE_PAIR,
125 G_PARAM_READWRITE);
126 g_object_class_install_property (gobject_class, PROP_POS1, param);
128 param = g_param_spec_boxed ("pos2",
129 P_("Position 2"),
130 P_("Second position point: it will be computed with the level property to get the real dimension position"),
131 ADG_TYPE_PAIR,
132 G_PARAM_READWRITE);
133 g_object_class_install_property (gobject_class, PROP_POS2, param);
135 param = g_param_spec_double ("level",
136 P_("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",
143 P_("Quote"),
144 P_("The quote to display: set to NULL to get the default quote"),
145 NULL,
146 G_PARAM_READWRITE);
147 g_object_class_install_property (gobject_class, PROP_QUOTE, param);
149 param = g_param_spec_string ("tolerance-up",
150 P_("Up Tolerance"),
151 P_("The up tolerance of the quote: set to NULL to suppress"),
152 NULL,
153 G_PARAM_READWRITE);
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"),
159 NULL,
160 G_PARAM_READWRITE);
161 g_object_class_install_property (gobject_class, PROP_TOLERANCE_DOWN, param);
163 param = g_param_spec_string ("note",
164 P_("Note"),
165 P_("A custom note appended to the dimension quote"),
166 NULL,
167 G_PARAM_READWRITE);
168 g_object_class_install_property (gobject_class, PROP_NOTE, param);
171 static void
172 adg_dim_init (AdgDim *dim)
174 AdgDimPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (dim, ADG_TYPE_DIM,
175 AdgDimPrivate);
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.;
183 priv->level = 1.;
184 priv->quote = NULL;
185 priv->tolerance_up = NULL;
186 priv->tolerance_down = NULL;
187 priv->note = NULL;
189 dim->priv = priv;
190 invalidate (dim);
193 static void
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);
205 static void
206 get_property (GObject *object,
207 guint prop_id,
208 GValue *value,
209 GParamSpec *pspec)
211 AdgDim *dim = (AdgDim *) object;
213 switch (prop_id)
215 case PROP_DIM_STYLE:
216 g_value_set_boxed (value, dim->priv->dim_style);
217 break;
218 case PROP_REF1:
219 g_value_set_boxed (value, &dim->priv->ref1);
220 break;
221 case PROP_REF2:
222 g_value_set_boxed (value, &dim->priv->ref2);
223 break;
224 case PROP_POS1:
225 g_value_set_boxed (value, &dim->priv->pos1);
226 break;
227 case PROP_POS2:
228 g_value_set_boxed (value, &dim->priv->pos1);
229 break;
230 case PROP_LEVEL:
231 g_value_set_double (value, dim->priv->level);
232 break;
233 case PROP_QUOTE:
234 g_value_set_string (value, dim->priv->quote);
235 break;
236 case PROP_TOLERANCE_UP:
237 g_value_set_string (value, dim->priv->tolerance_up);
238 break;
239 case PROP_TOLERANCE_DOWN:
240 g_value_set_string (value, dim->priv->tolerance_down);
241 break;
242 case PROP_NOTE:
243 g_value_set_string (value, dim->priv->note);
244 break;
245 default:
246 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
247 break;
251 static void
252 set_property (GObject *object,
253 guint prop_id,
254 const GValue *value,
255 GParamSpec *pspec)
257 AdgDim *dim = (AdgDim *) object;
259 switch (prop_id)
261 case PROP_DIM_STYLE:
262 dim->priv->dim_style = g_value_get_boxed (value);
263 invalidate (dim);
264 break;
265 case PROP_REF1:
266 cpml_pair_copy (&dim->priv->ref1, (AdgPair *) g_value_get_boxed (value));
267 invalidate (dim);
268 break;
269 case PROP_REF2:
270 cpml_pair_copy (&dim->priv->ref2, (AdgPair *) g_value_get_boxed (value));
271 invalidate (dim);
272 break;
273 case PROP_POS1:
274 cpml_pair_copy (&dim->priv->pos1, (AdgPair *) g_value_get_boxed (value));
275 invalidate (dim);
276 break;
277 case PROP_POS2:
278 cpml_pair_copy (&dim->priv->pos2, (AdgPair *) g_value_get_boxed (value));
279 invalidate (dim);
280 break;
281 case PROP_LEVEL:
282 dim->priv->level = g_value_get_double (value);
283 invalidate (dim);
284 break;
285 case PROP_QUOTE:
286 g_free (dim->priv->quote);
287 dim->priv->quote = g_value_dup_string (value);
288 invalidate_quote (dim);
289 break;
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);
294 break;
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);
299 break;
300 case PROP_NOTE:
301 g_free (dim->priv->note);
302 dim->priv->note = g_value_dup_string (value);
303 invalidate_quote (dim);
304 break;
305 default:
306 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
307 break;
312 static void
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);
320 static void
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;
336 static void
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");
344 static gchar *
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");
351 static void
352 quote_layout (AdgDim *dim,
353 cairo_t *cr)
355 AdgDimStylePrivate *style_data;
356 AdgPair offset;
357 AdgPair cp;
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)
373 double width;
374 double midspacing;
376 adg_font_style_apply (ADG_FONT_STYLE (style_data->tolerance_style), cr);
378 width = 0.0;
379 midspacing = style_data->tolerance_spacing / 2.0;
380 cpml_pair_copy (&offset, &style_data->tolerance_shift);
381 cp.x += offset.x;
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;
403 cp.x += 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);
412 cp.x += offset.x;
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;
439 const AdgPair *
440 adg_dim_get_ref1 (AdgDim *dim)
442 g_return_val_if_fail (ADG_IS_DIM (dim), NULL);
444 return &dim->priv->ref1;
447 const AdgPair *
448 adg_dim_get_ref2 (AdgDim *dim)
450 g_return_val_if_fail (ADG_IS_DIM (dim), NULL);
452 return &dim->priv->ref2;
455 void
456 adg_dim_set_ref (AdgDim *dim,
457 const AdgPair *ref1,
458 const AdgPair *ref2)
460 GObject *object;
462 g_return_if_fail (ADG_IS_DIM (dim));
464 object = G_OBJECT (dim);
466 if (ref1 != NULL)
468 dim->priv->ref1 = *ref1;
469 g_object_notify (object, "ref1");
472 if (ref2 != NULL)
474 dim->priv->ref2 = *ref2;
475 g_object_notify (object, "ref2");
479 void
480 adg_dim_set_ref_explicit (AdgDim *dim,
481 double ref1_x,
482 double ref1_y,
483 double ref2_x,
484 double ref2_y)
486 AdgPair ref1;
487 AdgPair ref2;
489 ref1.x = ref1_x;
490 ref1.y = ref1_y;
491 ref2.x = ref2_x;
492 ref2.y = ref2_y;
494 adg_dim_set_ref (dim, &ref1, &ref2);
497 const AdgPair *
498 adg_dim_get_pos1 (AdgDim *dim)
500 g_return_val_if_fail (ADG_IS_DIM (dim), NULL);
502 return &dim->priv->pos1;
505 const AdgPair *
506 adg_dim_get_pos2 (AdgDim *dim)
508 g_return_val_if_fail (ADG_IS_DIM (dim), NULL);
510 return &dim->priv->pos2;
513 void
514 adg_dim_set_pos (AdgDim *dim,
515 AdgPair *pos1,
516 AdgPair *pos2)
518 GObject *object;
520 g_return_if_fail (ADG_IS_DIM (dim));
522 object = G_OBJECT (dim);
524 g_object_freeze_notify (object);
526 if (pos1 != NULL)
528 dim->priv->pos1 = *pos1;
529 g_object_notify (object, "pos1");
532 if (pos2 != NULL)
534 dim->priv->pos2 = *pos2;
535 g_object_notify (object, "pos2");
538 g_object_thaw_notify (object);
541 void
542 adg_dim_set_pos_explicit (AdgDim *dim,
543 double pos1_x,
544 double pos1_y,
545 double pos2_x,
546 double pos2_y)
548 AdgPair pos1;
549 AdgPair pos2;
551 pos1.x = pos1_x;
552 pos1.y = pos1_y;
553 pos2.x = pos2_x;
554 pos2.y = pos2_y;
556 adg_dim_set_pos (dim, &pos1, &pos2);
559 double
560 adg_dim_get_level (AdgDim *dim)
562 g_return_val_if_fail (ADG_IS_DIM (dim), 0.0);
564 return dim->priv->level;
567 void
568 adg_dim_set_level (AdgDim *dim,
569 double level)
571 g_return_if_fail (ADG_IS_DIM (dim));
573 dim->priv->level = level;
574 g_object_notify ((GObject *) dim, "level");
577 const gchar *
578 adg_dim_get_quote (AdgDim *dim)
580 g_return_val_if_fail (ADG_IS_DIM (dim), NULL);
582 return dim->priv->quote;
585 void
586 adg_dim_set_quote (AdgDim *dim,
587 const gchar *quote)
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");
598 const gchar *
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;
606 void
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");
619 const gchar *
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;
627 void
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");
640 void
641 adg_dim_set_tolerances (AdgDim *dim,
642 const gchar *tolerance_up,
643 const gchar *tolerance_down)
645 GObject *object;
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);
666 const gchar *
667 adg_dim_get_note (AdgDim *dim)
669 g_return_val_if_fail (ADG_IS_DIM (dim), NULL);
671 return dim->priv->note;
674 void
675 adg_dim_set_note (AdgDim *dim,
676 const gchar *note)
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.
697 void
698 _adg_dim_render_quote (AdgDim *dim,
699 cairo_t *cr)
701 AdgDimStylePrivate *style_data;
702 AdgPair quote_shift;
703 AdgPair tolerance_up_shift;
704 AdgPair tolerance_down_shift;
705 AdgPair note_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 (&quote_shift, &dim->priv->quote_shift);
722 cairo_device_to_user_distance (cr, &quote_shift.x, &quote_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);
728 cairo_save (cr);
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);
754 /* Rendering note */
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);
761 cairo_restore (cr);