1 /* ADG - Automatic Drawing Generation
2 * Copyright (C) 2007,2008,2009 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.
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"
49 static void finalize (GObject
*object
);
50 static void get_property (GObject
*object
,
54 static void set_property (GObject
*object
,
58 static void paper_matrix_changed (AdgEntity
*entity
,
59 AdgMatrix
*parent_matrix
);
60 static void invalidate (AdgEntity
*entity
);
61 static void clear (AdgDim
*entity
);
62 static gchar
* default_quote (AdgDim
*dim
);
63 static void quote_layout (AdgDim
*dim
,
65 static void text_cache_init (AdgTextCache
*text_cache
);
66 static gboolean
text_cache_update (AdgTextCache
*text_cache
,
70 static void text_cache_clear (AdgTextCache
*text_cache
);
71 static void text_cache_move_to (AdgTextCache
*text_cache
,
73 static void text_cache_render (AdgTextCache
*text_cache
,
77 G_DEFINE_ABSTRACT_TYPE(AdgDim
, adg_dim
, ADG_TYPE_ENTITY
);
81 adg_dim_class_init(AdgDimClass
*klass
)
83 GObjectClass
*gobject_class
;
84 AdgEntityClass
*entity_class
;
87 gobject_class
= (GObjectClass
*) klass
;
88 entity_class
= (AdgEntityClass
*) klass
;
90 g_type_class_add_private(klass
, sizeof(AdgDimPrivate
));
92 gobject_class
->finalize
= finalize
;
93 gobject_class
->get_property
= get_property
;
94 gobject_class
->set_property
= set_property
;
96 entity_class
->paper_matrix_changed
= paper_matrix_changed
;
97 entity_class
->invalidate
= invalidate
;
99 klass
->default_quote
= default_quote
;
100 klass
->quote_layout
= quote_layout
;
102 param
= g_param_spec_boxed("ref1",
104 P_("First reference point of the dimension"),
106 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
);
107 g_object_class_install_property(gobject_class
, PROP_REF1
, param
);
109 param
= g_param_spec_boxed("ref2",
111 P_("Second reference point of the dimension"),
113 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
);
114 g_object_class_install_property(gobject_class
, PROP_REF2
, param
);
116 param
= g_param_spec_boxed("pos1",
118 P_("First position point: it will be computed with the level property to get the real dimension position"),
119 ADG_TYPE_PAIR
, G_PARAM_READWRITE
);
120 g_object_class_install_property(gobject_class
, PROP_POS1
, param
);
122 param
= g_param_spec_boxed("pos2",
124 P_("Second position point: it will be computed with the level property to get the real dimension position"),
125 ADG_TYPE_PAIR
, G_PARAM_READWRITE
);
126 g_object_class_install_property(gobject_class
, PROP_POS2
, param
);
128 param
= g_param_spec_double("level",
130 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"),
131 -G_MAXDOUBLE
, G_MAXDOUBLE
, 1.0,
132 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
);
133 g_object_class_install_property(gobject_class
, PROP_LEVEL
, param
);
135 param
= g_param_spec_string("quote",
137 P_("The quote to display: set to NULL to get the default quote"),
138 NULL
, G_PARAM_READWRITE
);
139 g_object_class_install_property(gobject_class
, PROP_QUOTE
, param
);
141 param
= g_param_spec_string("tolerance-up",
143 P_("The up tolerance of the quote: set to NULL to suppress"),
144 NULL
, G_PARAM_READWRITE
);
145 g_object_class_install_property(gobject_class
, PROP_TOLERANCE_UP
, param
);
147 param
= g_param_spec_string("tolerance-down",
148 P_("Down Tolerance"),
149 P_("The down tolerance of the quote: set to NULL to suppress"),
150 NULL
, G_PARAM_READWRITE
);
151 g_object_class_install_property(gobject_class
, PROP_TOLERANCE_DOWN
, param
);
153 param
= g_param_spec_string("note",
155 P_("A custom note appended to the dimension quote"),
156 NULL
, G_PARAM_READWRITE
);
157 g_object_class_install_property(gobject_class
, PROP_NOTE
, param
);
161 adg_dim_init(AdgDim
*dim
)
163 AdgDimPrivate
*priv
= G_TYPE_INSTANCE_GET_PRIVATE(dim
, ADG_TYPE_DIM
,
166 priv
->ref1
.x
= priv
->ref1
.y
= 0;
167 priv
->ref2
.x
= priv
->ref2
.y
= 0;
168 priv
->pos1
.x
= priv
->pos1
.y
= 0;
169 priv
->pos2
.x
= priv
->pos2
.y
= 0;
172 priv
->tolerance_up
= NULL
;
173 priv
->tolerance_down
= NULL
;
176 priv
->org
.x
= priv
->org
.y
= 0;
178 text_cache_init(&priv
->quote_cache
);
179 text_cache_init(&priv
->tolerance_up_cache
);
180 text_cache_init(&priv
->tolerance_down_cache
);
181 text_cache_init(&priv
->note_cache
);
187 finalize(GObject
*object
)
190 GObjectClass
*object_class
;
192 dim
= (AdgDim
*) object
;
193 object_class
= (GObjectClass
*) adg_dim_parent_class
;
195 g_free(dim
->priv
->quote
);
196 g_free(dim
->priv
->tolerance_up
);
197 g_free(dim
->priv
->tolerance_down
);
201 if (object_class
->finalize
!= NULL
)
202 object_class
->finalize(object
);
206 get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
208 AdgDim
*dim
= (AdgDim
*) object
;
212 g_value_set_boxed(value
, &dim
->priv
->ref1
);
215 g_value_set_boxed(value
, &dim
->priv
->ref2
);
218 g_value_set_boxed(value
, &dim
->priv
->pos1
);
221 g_value_set_boxed(value
, &dim
->priv
->pos1
);
224 g_value_set_double(value
, dim
->priv
->level
);
227 g_value_set_string(value
, dim
->priv
->quote
);
229 case PROP_TOLERANCE_UP
:
230 g_value_set_string(value
, dim
->priv
->tolerance_up
);
232 case PROP_TOLERANCE_DOWN
:
233 g_value_set_string(value
, dim
->priv
->tolerance_down
);
236 g_value_set_string(value
, dim
->priv
->note
);
239 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
245 set_property(GObject
*object
, guint prop_id
,
246 const GValue
*value
, GParamSpec
*pspec
)
251 entity
= (AdgEntity
*) object
;
252 dim
= (AdgDim
*) object
;
256 cpml_pair_copy(&dim
->priv
->ref1
, (AdgPair
*) g_value_get_boxed(value
));
260 cpml_pair_copy(&dim
->priv
->ref2
, (AdgPair
*) g_value_get_boxed(value
));
264 cpml_pair_copy(&dim
->priv
->pos1
, (AdgPair
*) g_value_get_boxed(value
));
268 cpml_pair_copy(&dim
->priv
->pos2
, (AdgPair
*) g_value_get_boxed(value
));
272 dim
->priv
->level
= g_value_get_double(value
);
276 g_free(dim
->priv
->quote
);
277 dim
->priv
->quote
= g_value_dup_string(value
);
278 text_cache_clear(&dim
->priv
->quote_cache
);
280 case PROP_TOLERANCE_UP
:
281 g_free(dim
->priv
->tolerance_up
);
282 dim
->priv
->tolerance_up
= g_value_dup_string(value
);
283 text_cache_clear(&dim
->priv
->tolerance_up_cache
);
285 case PROP_TOLERANCE_DOWN
:
286 g_free(dim
->priv
->tolerance_down
);
287 dim
->priv
->tolerance_down
= g_value_dup_string(value
);
288 text_cache_clear(&dim
->priv
->tolerance_down_cache
);
291 g_free(dim
->priv
->note
);
292 dim
->priv
->note
= g_value_dup_string(value
);
293 text_cache_clear(&dim
->priv
->note_cache
);
296 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
306 * Gets the origin (org) coordinates. The returned pair is internally
307 * owned and must not be freed or modified. This function is only
308 * useful in new dimension implementations.
310 * Return value: the org coordinates
313 adg_dim_get_org(AdgDim
*dim
)
315 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
317 return &dim
->priv
->org
;
323 * @org: the org coordinates
325 * Sets new org coordinates. This function is only useful
326 * in new dimension implementations.
329 adg_dim_set_org(AdgDim
*dim
, const AdgPair
*org
)
331 g_return_if_fail(ADG_IS_DIM(dim
));
332 g_return_if_fail(org
!= NULL
);
334 dim
->priv
->org
= *org
;
338 * adg_dim_set_org_explicit:
340 * @org_x: x component of org
341 * @org_y: y component of org
343 * Explicitely sets new org coordinates. This function is only useful
344 * in new dimension implementations.
347 adg_dim_set_org_explicit(AdgDim
*dim
, gdouble org_x
, gdouble org_y
)
349 g_return_if_fail(ADG_IS_DIM(dim
));
351 dim
->priv
->org
.x
= org_x
;
352 dim
->priv
->org
.y
= org_y
;
359 * Gets the dimension angle. This function is only useful
360 * in new dimension implementations.
362 * Return value: the angle (in radians)
365 adg_dim_get_angle(AdgDim
*dim
)
367 g_return_val_if_fail(ADG_IS_DIM(dim
), 0);
369 return dim
->priv
->angle
;
375 * @angle: the new angle (in radians)
377 * Sets a new dimension angle. This function is only useful
378 * in new dimension implementations.
381 adg_dim_set_angle(AdgDim
*dim
, gdouble angle
)
383 g_return_if_fail(ADG_IS_DIM(dim
));
385 dim
->priv
->angle
= angle
;
392 * Gets the ref1 coordinates. The returned pair is internally owned
393 * and must not be freed or modified.
395 * Return value: the ref1 coordinates
398 adg_dim_get_ref1(AdgDim
*dim
)
400 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
402 return &dim
->priv
->ref1
;
409 * Gets the ref2 coordinates. The returned pair is internally owned
410 * and must not be freed or modified.
412 * Return value: the ref2 coordinates
415 adg_dim_get_ref2(AdgDim
*dim
)
417 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
419 return &dim
->priv
->ref2
;
425 * @ref1: the ref1 coordinates
426 * @ref2: the ref2 coordinates
428 * Shortcut to set ref1 and ref2 points at once.
431 adg_dim_set_ref(AdgDim
*dim
, const AdgPair
*ref1
, const AdgPair
*ref2
)
433 g_return_if_fail(ADG_IS_DIM(dim
));
435 if (ref1
!= NULL
|| ref2
!= NULL
) {
436 GObject
*object
= (GObject
*) dim
;
438 g_object_freeze_notify(object
);
441 dim
->priv
->ref1
= *ref1
;
442 g_object_notify(object
, "ref1");
446 dim
->priv
->ref2
= *ref2
;
447 g_object_notify(object
, "ref2");
450 g_object_thaw_notify(object
);
456 * adg_dim_set_ref_explicit:
458 * @ref1_x: x component of pos1
459 * @ref1_y: y component of pos1
460 * @ref2_x: x component of pos2
461 * @ref2_y: y component of pos2
463 * Shortcut to set ref1 and ref2 points at once,
464 * using explicit coordinates.
467 adg_dim_set_ref_explicit(AdgDim
*dim
, gdouble ref1_x
, gdouble ref1_y
,
468 gdouble ref2_x
, gdouble ref2_y
)
478 adg_dim_set_ref(dim
, &ref1
, &ref2
);
485 * Gets the pos1 coordinates. The returned pair is internally owned
486 * and must not be freed or modified.
488 * Return value: the pos1 coordinates
491 adg_dim_get_pos1(AdgDim
*dim
)
493 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
495 return &dim
->priv
->pos1
;
502 * Gets the pos2 coordinates. The returned pair is internally owned
503 * and must not be freed or modified.
505 * Return value: the pos2 coordinates
508 adg_dim_get_pos2(AdgDim
*dim
)
510 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
512 return &dim
->priv
->pos2
;
518 * @pos1: the pos1 coordinates
519 * @pos2: the pos2 coordinates
521 * Shortcut to set pos1 and pos2 points at once.
524 adg_dim_set_pos(AdgDim
*dim
, AdgPair
*pos1
, AdgPair
*pos2
)
526 g_return_if_fail(ADG_IS_DIM(dim
));
528 if (pos1
!= NULL
|| pos2
!= NULL
) {
529 GObject
*object
= (GObject
*) dim
;
531 g_object_freeze_notify(object
);
534 dim
->priv
->pos1
= *pos1
;
535 g_object_notify(object
, "pos1");
538 dim
->priv
->pos2
= *pos2
;
539 g_object_notify(object
, "pos2");
542 g_object_thaw_notify(object
);
548 * adg_dim_set_pos_explicit:
550 * @pos1_x: x component of pos1
551 * @pos1_y: y component of pos1
552 * @pos2_x: x component of pos2
553 * @pos2_y: y component of pos2
555 * Shortcut to set pos1 and pos2 points at once,
556 * using explicit coordinates.
559 adg_dim_set_pos_explicit(AdgDim
*dim
, gdouble pos1_x
, gdouble pos1_y
,
560 gdouble pos2_x
, gdouble pos2_y
)
570 adg_dim_set_pos(dim
, &pos1
, &pos2
);
577 * Gets the level of this dimension.
579 * Return value: the level value
582 adg_dim_get_level(AdgDim
*dim
)
584 g_return_val_if_fail(ADG_IS_DIM(dim
), 0);
586 return dim
->priv
->level
;
592 * @level: the new level
594 * Sets a new level for this dimension. The level is used to
595 * stack the quotes using a spacing value from dim_style
596 * (specified in paper space).
599 adg_dim_set_level(AdgDim
*dim
, gdouble level
)
601 g_return_if_fail(ADG_IS_DIM(dim
));
603 dim
->priv
->level
= level
;
604 g_object_notify((GObject
*) dim
, "level");
612 * Gets the quote text. The string is internally owned and
613 * must not be freed or modified.
615 * Return value: the quote text
618 adg_dim_get_quote(AdgDim
*dim
)
620 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
622 return dim
->priv
->quote
;
628 * @quote: the quote text
630 * Explicitely sets the text to use as quote. If @quote is %NULL or
631 * was never set, an automatic text is calculated using the format as
632 * specified by the dim_style associated to this entity and getting
633 * the number from the construction points (ref1, ref2, pos1 and pos2).
636 adg_dim_set_quote(AdgDim
*dim
, const gchar
*quote
)
638 g_return_if_fail(ADG_IS_DIM(dim
));
640 g_free(dim
->priv
->quote
);
641 dim
->priv
->quote
= g_strdup(quote
);
642 g_object_notify((GObject
*) dim
, "quote");
644 text_cache_clear(&dim
->priv
->quote_cache
);
648 * adg_dim_get_tolerance_up:
651 * Gets the upper tolerance text or %NULL on upper tolerance disabled.
652 * The string is internally owned and must not be freed or modified.
654 * Return value: the tolerance text
657 adg_dim_get_tolerance_up(AdgDim
*dim
)
659 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
661 return dim
->priv
->tolerance_up
;
665 * adg_dim_set_tolerance_up:
667 * @tolerance_up: the upper tolerance
669 * Sets the upper tolerance. Use %NULL as @tolerance_up to disable it.
672 adg_dim_set_tolerance_up(AdgDim
*dim
, const gchar
*tolerance_up
)
674 g_return_if_fail(ADG_IS_DIM(dim
));
676 g_free(dim
->priv
->tolerance_up
);
677 dim
->priv
->tolerance_up
= g_strdup(tolerance_up
);
678 g_object_notify((GObject
*) dim
, "tolerance-up");
680 text_cache_clear(&dim
->priv
->tolerance_up_cache
);
684 * adg_dim_get_tolerance_down:
687 * Gets the lower tolerance text or %NULL on lower tolerance disabled.
688 * The string is internally owned and must not be freed or modified.
690 * Return value: the tolerance text
693 adg_dim_get_tolerance_down(AdgDim
*dim
)
695 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
697 return dim
->priv
->tolerance_down
;
701 * adg_dim_set_tolerance_down:
703 * @tolerance_down: the lower tolerance
705 * Sets the lower tolerance. Use %NULL as @tolerance_down to disable it.
708 adg_dim_set_tolerance_down(AdgDim
*dim
, const gchar
*tolerance_down
)
710 g_return_if_fail(ADG_IS_DIM(dim
));
712 g_free(dim
->priv
->tolerance_down
);
713 dim
->priv
->tolerance_down
= g_strdup(tolerance_down
);
714 g_object_notify((GObject
*) dim
, "tolerance-down");
716 text_cache_clear(&dim
->priv
->tolerance_down_cache
);
720 * adg_dim_set_tolerances:
722 * @tolerance_up: the upper tolerance text
723 * @tolerance_down: the lower tolerance text
725 * Shortcut to set both the tolerance at once.
728 adg_dim_set_tolerances(AdgDim
*dim
, const gchar
*tolerance_up
,
729 const gchar
*tolerance_down
)
731 g_return_if_fail(ADG_IS_DIM(dim
));
733 g_object_freeze_notify((GObject
*) dim
);
734 adg_dim_set_tolerance_up(dim
, tolerance_up
);
735 adg_dim_set_tolerance_down(dim
, tolerance_down
);
736 g_object_thaw_notify((GObject
*) dim
);
743 * Gets the note text or %NULL if the note is not used. The string is
744 * internally owned and must not be freed or modified.
746 * Return value: the note text
749 adg_dim_get_note(AdgDim
*dim
)
751 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
753 return dim
->priv
->note
;
759 * @note: the new note
761 * Sets a new note text, usually appended at the end of the dimension text.
764 adg_dim_set_note(AdgDim
*dim
, const gchar
*note
)
766 g_return_if_fail(ADG_IS_DIM(dim
));
768 g_free(dim
->priv
->note
);
769 dim
->priv
->note
= g_strdup(note
);
770 g_object_notify((GObject
*) dim
, "note");
772 text_cache_clear(&dim
->priv
->note_cache
);
776 * adg_dim_render_quote:
777 * @dim: an #AdgDim object
778 * @cr: a #cairo_t drawing context
780 * Renders the quote of @dim at the @org position. This function
781 * is only useful in new dimension implementations.
784 adg_dim_render_quote(AdgDim
*dim
, cairo_t
*cr
)
787 AdgDimStyle
*dim_style
;
789 g_return_if_fail(ADG_IS_DIM(dim
));
792 dim_style
= (AdgDimStyle
*) adg_entity_get_style((AdgEntity
*) dim
,
795 if (priv
->quote
== NULL
)
796 adg_dim_set_quote(dim
, ADG_DIM_GET_CLASS(dim
)->default_quote(dim
));
800 cairo_set_matrix(cr
, adg_entity_get_paper_matrix((AdgEntity
*) dim
));
801 ADG_DIM_GET_CLASS(dim
)->quote_layout(dim
, cr
);
802 cairo_set_matrix(cr
, adg_entity_get_model_matrix((AdgEntity
*) dim
));
804 cairo_translate(cr
, priv
->org
.x
, priv
->org
.y
);
805 adg_entity_scale_to_paper((AdgEntity
*) dim
, cr
);
806 cairo_rotate(cr
, -priv
->angle
);
808 /* Rendering quote */
809 adg_style_apply(adg_dim_style_get_quote_style(dim_style
), cr
);
810 text_cache_render(&priv
->quote_cache
, cr
);
812 /* Rendering tolerances */
813 if (priv
->tolerance_up
!= NULL
|| priv
->tolerance_down
!= NULL
) {
814 adg_style_apply(adg_dim_style_get_tolerance_style(dim_style
), cr
);
816 if (priv
->tolerance_up
!= NULL
)
817 text_cache_render(&priv
->tolerance_up_cache
, cr
);
819 if (priv
->tolerance_down
!= NULL
)
820 text_cache_render(&priv
->tolerance_down_cache
, cr
);
823 /* Rendering the note */
824 if (priv
->note
!= NULL
) {
825 adg_style_apply(adg_dim_style_get_note_style(dim_style
), cr
);
826 text_cache_render(&priv
->note_cache
, cr
);
834 paper_matrix_changed(AdgEntity
*entity
, AdgMatrix
*parent_matrix
)
836 AdgEntityClass
*entity_class
= (AdgEntityClass
*) adg_dim_parent_class
;
838 clear((AdgDim
*) entity
);
840 if (entity_class
->paper_matrix_changed
!= NULL
)
841 entity_class
->paper_matrix_changed(entity
, parent_matrix
);
845 invalidate(AdgEntity
*entity
)
847 AdgEntityClass
*entity_class
= (AdgEntityClass
*) adg_dim_parent_class
;
849 clear((AdgDim
*) entity
);
851 if (entity_class
->invalidate
!= NULL
)
852 entity_class
->invalidate(entity
);
858 text_cache_clear(&dim
->priv
->quote_cache
);
859 text_cache_clear(&dim
->priv
->tolerance_up_cache
);
860 text_cache_clear(&dim
->priv
->tolerance_down_cache
);
861 text_cache_clear(&dim
->priv
->note_cache
);
865 default_quote(AdgDim
*dim
)
867 g_warning("AdgDim::default_quote not implemented for `%s'",
868 g_type_name(G_TYPE_FROM_INSTANCE(dim
)));
869 return g_strdup("undef");
873 quote_layout(AdgDim
*dim
, cairo_t
*cr
)
876 AdgDimStyle
*dim_style
;
879 CpmlPair tolerance_up_org
, tolerance_down_org
, note_org
;
882 dim_style
= (AdgDimStyle
*) adg_entity_get_style((AdgEntity
*) dim
,
885 /* Compute the quote */
886 if (text_cache_update(&priv
->quote_cache
, priv
->quote
, cr
,
887 adg_dim_style_get_quote_style(dim_style
))) {
888 cp
.x
= priv
->quote_cache
.extents
.width
;
889 cp
.y
= priv
->quote_cache
.extents
.height
/ -2.;
895 /* Compute the tolerances */
896 if (priv
->tolerance_up
!= NULL
|| priv
->tolerance_down
!= NULL
) {
900 adg_style_apply(adg_dim_style_get_tolerance_style(dim_style
), cr
);
903 midspacing
= adg_dim_style_get_tolerance_spacing(dim_style
) / 2.;
904 cpml_pair_copy(&shift
, adg_dim_style_get_tolerance_shift(dim_style
));
907 if (text_cache_update(&priv
->tolerance_up_cache
,
908 priv
->tolerance_up
, cr
, NULL
)) {
909 tolerance_up_org
.x
= cp
.x
;
910 tolerance_up_org
.y
= cp
.y
+ shift
.y
- midspacing
;
912 width
= priv
->tolerance_up_cache
.extents
.width
;
915 if (text_cache_update(&priv
->tolerance_down_cache
,
916 priv
->tolerance_down
, cr
, NULL
)) {
917 tolerance_down_org
.x
= cp
.x
;
918 tolerance_down_org
.y
= cp
.y
+ shift
.y
+ midspacing
+
919 priv
->tolerance_down_cache
.extents
.height
;
921 if (priv
->tolerance_down_cache
.extents
.width
> width
)
922 width
= priv
->tolerance_down_cache
.extents
.width
;
928 /* Compute the note */
929 if (text_cache_update(&priv
->note_cache
, priv
->note
, cr
,
930 adg_dim_style_get_note_style(dim_style
))) {
931 cpml_pair_copy(&shift
, adg_dim_style_get_note_shift(dim_style
));
935 note_org
.y
= cp
.y
+ shift
.y
+ priv
->note_cache
.extents
.height
/ 2.;
937 cp
.x
+= priv
->note_cache
.extents
.width
;
940 /* Centering and shifting the whole group */
941 cpml_pair_copy(&shift
, adg_dim_style_get_quote_shift(dim_style
));
942 shift
.x
-= cp
.x
/ 2.;
944 if (priv
->quote_cache
.glyphs
) {
945 text_cache_move_to(&priv
->quote_cache
, &shift
);
948 if (priv
->tolerance_up_cache
.glyphs
) {
949 tolerance_up_org
.x
+= shift
.x
;
950 tolerance_up_org
.y
+= shift
.y
;
951 text_cache_move_to(&priv
->tolerance_up_cache
, &tolerance_up_org
);
954 if (priv
->tolerance_down_cache
.glyphs
) {
955 tolerance_down_org
.x
+= shift
.x
;
956 tolerance_down_org
.y
+= shift
.y
;
957 text_cache_move_to(&priv
->tolerance_down_cache
, &tolerance_down_org
);
960 if (priv
->note_cache
.glyphs
) {
961 note_org
.x
+= shift
.x
;
962 note_org
.y
+= shift
.y
;
963 text_cache_move_to(&priv
->note_cache
, ¬e_org
);
968 text_cache_init(AdgTextCache
*text_cache
)
970 text_cache
->utf8
= NULL
;
971 text_cache
->utf8_len
= -1;
972 text_cache
->glyphs
= NULL
;
973 text_cache
->num_glyphs
= 0;
974 text_cache
->clusters
= NULL
;
975 text_cache
->num_clusters
= 0;
976 text_cache
->cluster_flags
= 0;
977 memset(&text_cache
->extents
, 0, sizeof(text_cache
->extents
));
981 text_cache_update(AdgTextCache
*text_cache
, const gchar
*text
,
982 cairo_t
*cr
, AdgStyle
*style
)
987 text_cache
->utf8
= text
;
988 text_cache
->utf8_len
= g_utf8_strlen(text
, -1);
991 adg_style_apply(style
, cr
);
993 if (!text_cache
->glyphs
) {
994 cairo_status_t status
;
996 status
= cairo_scaled_font_text_to_glyphs(cairo_get_scaled_font(cr
),
999 text_cache
->utf8_len
,
1000 &text_cache
->glyphs
,
1001 &text_cache
->num_glyphs
,
1002 &text_cache
->clusters
,
1003 &text_cache
->num_clusters
,
1004 &text_cache
->cluster_flags
);
1006 if (status
!= CAIRO_STATUS_SUCCESS
) {
1007 g_error("Unable to build glyphs (cairo message: %s)",
1008 cairo_status_to_string(status
));
1012 cairo_glyph_extents(cr
, text_cache
->glyphs
, text_cache
->num_glyphs
,
1013 &text_cache
->extents
);
1020 text_cache_clear(AdgTextCache
*text_cache
)
1022 text_cache
->utf8
= NULL
;
1023 text_cache
->utf8_len
= -1;
1025 if (text_cache
->glyphs
) {
1026 cairo_glyph_free(text_cache
->glyphs
);
1027 text_cache
->glyphs
= NULL
;
1028 text_cache
->num_glyphs
= 0;
1030 if (text_cache
->clusters
) {
1031 cairo_text_cluster_free(text_cache
->clusters
);
1032 text_cache
->clusters
= NULL
;
1033 text_cache
->num_clusters
= 0;
1034 text_cache
->cluster_flags
= 0;
1036 memset(&text_cache
->extents
, 0, sizeof(text_cache
->extents
));
1040 text_cache_move_to(AdgTextCache
*text_cache
, const CpmlPair
*to
)
1042 cairo_glyph_t
*glyph
;
1046 glyph
= text_cache
->glyphs
;
1047 cnt
= text_cache
->num_glyphs
;
1048 x
= to
->x
- glyph
->x
;
1049 y
= to
->y
- glyph
->y
;
1059 text_cache_render(AdgTextCache
*text_cache
, cairo_t
*cr
)
1061 cairo_show_text_glyphs(cr
, text_cache
->utf8
, text_cache
->utf8_len
,
1062 text_cache
->glyphs
, text_cache
->num_glyphs
,
1063 text_cache
->clusters
, text_cache
->num_clusters
,
1064 text_cache
->cluster_flags
);