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.
24 * @short_description: Root abstract class for all dimension entities
26 * The #AdgDim class is the base stub of all the dimension entities.
32 * All fields are private and should not be used directly.
33 * Use its public methods instead.
38 #include "adg-dim-private.h"
58 static void finalize (GObject
*object
);
59 static void get_property (GObject
*object
,
63 static void set_property (GObject
*object
,
67 static void paper_matrix_changed (AdgEntity
*entity
,
68 AdgMatrix
*parent_matrix
);
69 static void invalidate (AdgEntity
*entity
);
70 static void clear (AdgDim
*entity
);
71 static gchar
* default_quote (AdgDim
*dim
);
72 static void quote_layout (AdgDim
*dim
,
74 static void text_cache_init (AdgTextCache
*text_cache
);
75 static gboolean
text_cache_update (AdgTextCache
*text_cache
,
79 static void text_cache_clear (AdgTextCache
*text_cache
);
80 static void text_cache_move_to (AdgTextCache
*text_cache
,
82 static void text_cache_render (AdgTextCache
*text_cache
,
86 G_DEFINE_ABSTRACT_TYPE(AdgDim
, adg_dim
, ADG_TYPE_ENTITY
);
90 adg_dim_class_init(AdgDimClass
*klass
)
92 GObjectClass
*gobject_class
;
93 AdgEntityClass
*entity_class
;
96 gobject_class
= (GObjectClass
*) klass
;
97 entity_class
= (AdgEntityClass
*) klass
;
99 g_type_class_add_private(klass
, sizeof(AdgDimPrivate
));
101 gobject_class
->finalize
= finalize
;
102 gobject_class
->get_property
= get_property
;
103 gobject_class
->set_property
= set_property
;
105 entity_class
->paper_matrix_changed
= paper_matrix_changed
;
106 entity_class
->invalidate
= invalidate
;
108 klass
->default_quote
= default_quote
;
109 klass
->quote_layout
= quote_layout
;
111 param
= g_param_spec_boxed("ref1",
113 P_("First reference point of the dimension"),
115 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
);
116 g_object_class_install_property(gobject_class
, PROP_REF1
, param
);
118 param
= g_param_spec_boxed("ref2",
120 P_("Second reference point of the dimension"),
122 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
);
123 g_object_class_install_property(gobject_class
, PROP_REF2
, param
);
125 param
= g_param_spec_boxed("pos1",
127 P_("First position point: it will be computed with the level property to get the real dimension position"),
128 ADG_TYPE_PAIR
, G_PARAM_READWRITE
);
129 g_object_class_install_property(gobject_class
, PROP_POS1
, param
);
131 param
= g_param_spec_boxed("pos2",
133 P_("Second position point: it will be computed with the level property to get the real dimension position"),
134 ADG_TYPE_PAIR
, G_PARAM_READWRITE
);
135 g_object_class_install_property(gobject_class
, PROP_POS2
, param
);
137 param
= g_param_spec_double("level",
139 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"),
140 -G_MAXDOUBLE
, G_MAXDOUBLE
, 1.0,
141 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
);
142 g_object_class_install_property(gobject_class
, PROP_LEVEL
, param
);
144 param
= g_param_spec_string("quote",
146 P_("The quote to display: set to NULL to get the default quote"),
147 NULL
, G_PARAM_READWRITE
);
148 g_object_class_install_property(gobject_class
, PROP_QUOTE
, param
);
150 param
= g_param_spec_string("tolerance-up",
152 P_("The up tolerance of the quote: set to NULL to suppress"),
153 NULL
, 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
, G_PARAM_READWRITE
);
160 g_object_class_install_property(gobject_class
, PROP_TOLERANCE_DOWN
, param
);
162 param
= g_param_spec_string("note",
164 P_("A custom note appended to the dimension quote"),
165 NULL
, G_PARAM_READWRITE
);
166 g_object_class_install_property(gobject_class
, PROP_NOTE
, param
);
170 adg_dim_init(AdgDim
*dim
)
172 AdgDimPrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(dim
, ADG_TYPE_DIM
,
175 data
->ref1
.x
= data
->ref1
.y
= 0;
176 data
->ref2
.x
= data
->ref2
.y
= 0;
177 data
->pos1
.x
= data
->pos1
.y
= 0;
178 data
->pos2
.x
= data
->pos2
.y
= 0;
181 data
->tolerance_up
= NULL
;
182 data
->tolerance_down
= NULL
;
185 data
->org
.x
= data
->org
.y
= 0;
187 text_cache_init(&data
->quote_cache
);
188 text_cache_init(&data
->tolerance_up_cache
);
189 text_cache_init(&data
->tolerance_down_cache
);
190 text_cache_init(&data
->note_cache
);
196 finalize(GObject
*object
)
200 GObjectClass
*object_class
;
202 dim
= (AdgDim
*) object
;
204 object_class
= (GObjectClass
*) adg_dim_parent_class
;
207 g_free(data
->tolerance_up
);
208 g_free(data
->tolerance_down
);
212 if (object_class
->finalize
!= NULL
)
213 object_class
->finalize(object
);
217 get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
219 AdgDimPrivate
*data
= ((AdgDim
*) object
)->data
;
223 g_value_set_boxed(value
, &data
->ref1
);
226 g_value_set_boxed(value
, &data
->ref2
);
229 g_value_set_boxed(value
, &data
->pos1
);
232 g_value_set_boxed(value
, &data
->pos1
);
235 g_value_set_double(value
, data
->level
);
238 g_value_set_string(value
, data
->quote
);
240 case PROP_TOLERANCE_UP
:
241 g_value_set_string(value
, data
->tolerance_up
);
243 case PROP_TOLERANCE_DOWN
:
244 g_value_set_string(value
, data
->tolerance_down
);
247 g_value_set_string(value
, data
->note
);
250 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
256 set_property(GObject
*object
, guint prop_id
,
257 const GValue
*value
, GParamSpec
*pspec
)
262 dim
= (AdgDim
*) object
;
267 cpml_pair_copy(&data
->ref1
, (AdgPair
*) g_value_get_boxed(value
));
271 cpml_pair_copy(&data
->ref2
, (AdgPair
*) g_value_get_boxed(value
));
275 cpml_pair_copy(&data
->pos1
, (AdgPair
*) g_value_get_boxed(value
));
279 cpml_pair_copy(&data
->pos2
, (AdgPair
*) g_value_get_boxed(value
));
283 data
->level
= g_value_get_double(value
);
288 data
->quote
= g_value_dup_string(value
);
289 text_cache_clear(&data
->quote_cache
);
291 case PROP_TOLERANCE_UP
:
292 g_free(data
->tolerance_up
);
293 data
->tolerance_up
= g_value_dup_string(value
);
294 text_cache_clear(&data
->tolerance_up_cache
);
296 case PROP_TOLERANCE_DOWN
:
297 g_free(data
->tolerance_down
);
298 data
->tolerance_down
= g_value_dup_string(value
);
299 text_cache_clear(&data
->tolerance_down_cache
);
303 data
->note
= g_value_dup_string(value
);
304 text_cache_clear(&data
->note_cache
);
307 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
317 * Gets the origin (org) coordinates. The returned pair is internally
318 * owned and must not be freed or modified. This function is only
319 * useful in new dimension implementations.
321 * Return value: the org coordinates
324 adg_dim_get_org(AdgDim
*dim
)
328 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
338 * @org: the org coordinates
340 * Sets new org coordinates. This function is only useful
341 * in new dimension implementations.
344 adg_dim_set_org(AdgDim
*dim
, const AdgPair
*org
)
348 g_return_if_fail(ADG_IS_DIM(dim
));
349 g_return_if_fail(org
!= NULL
);
356 * adg_dim_set_org_explicit:
358 * @org_x: x component of org
359 * @org_y: y component of org
361 * Explicitely sets new org coordinates. This function is only useful
362 * in new dimension implementations.
365 adg_dim_set_org_explicit(AdgDim
*dim
, gdouble org_x
, gdouble org_y
)
369 g_return_if_fail(ADG_IS_DIM(dim
));
380 * Gets the dimension angle. This function is only useful
381 * in new dimension implementations.
383 * Return value: the angle (in radians)
386 adg_dim_get_angle(AdgDim
*dim
)
390 g_return_val_if_fail(ADG_IS_DIM(dim
), 0);
400 * @angle: the new angle (in radians)
402 * Sets a new dimension angle. This function is only useful
403 * in new dimension implementations.
406 adg_dim_set_angle(AdgDim
*dim
, gdouble angle
)
410 g_return_if_fail(ADG_IS_DIM(dim
));
420 * Gets the ref1 coordinates. The returned pair is internally owned
421 * and must not be freed or modified.
423 * Return value: the ref1 coordinates
426 adg_dim_get_ref1(AdgDim
*dim
)
430 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
441 * Gets the ref2 coordinates. The returned pair is internally owned
442 * and must not be freed or modified.
444 * Return value: the ref2 coordinates
447 adg_dim_get_ref2(AdgDim
*dim
)
451 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
461 * @ref1: the ref1 coordinates
462 * @ref2: the ref2 coordinates
464 * Shortcut to set ref1 and ref2 points at once.
467 adg_dim_set_ref(AdgDim
*dim
, const AdgPair
*ref1
, const AdgPair
*ref2
)
469 g_return_if_fail(ADG_IS_DIM(dim
));
471 if (ref1
!= NULL
|| ref2
!= NULL
) {
476 object
= (GObject
*) dim
;
478 g_object_freeze_notify(object
);
482 g_object_notify(object
, "ref1");
487 g_object_notify(object
, "ref2");
490 g_object_thaw_notify(object
);
496 * adg_dim_set_ref_explicit:
498 * @ref1_x: x component of pos1
499 * @ref1_y: y component of pos1
500 * @ref2_x: x component of pos2
501 * @ref2_y: y component of pos2
503 * Shortcut to set ref1 and ref2 points at once,
504 * using explicit coordinates.
507 adg_dim_set_ref_explicit(AdgDim
*dim
, gdouble ref1_x
, gdouble ref1_y
,
508 gdouble ref2_x
, gdouble ref2_y
)
518 adg_dim_set_ref(dim
, &ref1
, &ref2
);
525 * Gets the pos1 coordinates. The returned pair is internally owned
526 * and must not be freed or modified.
528 * Return value: the pos1 coordinates
531 adg_dim_get_pos1(AdgDim
*dim
)
535 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
546 * Gets the pos2 coordinates. The returned pair is internally owned
547 * and must not be freed or modified.
549 * Return value: the pos2 coordinates
552 adg_dim_get_pos2(AdgDim
*dim
)
556 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
566 * @pos1: the pos1 coordinates
567 * @pos2: the pos2 coordinates
569 * Shortcut to set pos1 and pos2 points at once.
572 adg_dim_set_pos(AdgDim
*dim
, AdgPair
*pos1
, AdgPair
*pos2
)
574 g_return_if_fail(ADG_IS_DIM(dim
));
576 if (pos1
!= NULL
|| pos2
!= NULL
) {
581 object
= (GObject
*) dim
;
583 g_object_freeze_notify(object
);
587 g_object_notify(object
, "pos1");
591 g_object_notify(object
, "pos2");
594 g_object_thaw_notify(object
);
600 * adg_dim_set_pos_explicit:
602 * @pos1_x: x component of pos1
603 * @pos1_y: y component of pos1
604 * @pos2_x: x component of pos2
605 * @pos2_y: y component of pos2
607 * Shortcut to set pos1 and pos2 points at once,
608 * using explicit coordinates.
611 adg_dim_set_pos_explicit(AdgDim
*dim
, gdouble pos1_x
, gdouble pos1_y
,
612 gdouble pos2_x
, gdouble pos2_y
)
622 adg_dim_set_pos(dim
, &pos1
, &pos2
);
629 * Gets the level of this dimension.
631 * Return value: the level value
634 adg_dim_get_level(AdgDim
*dim
)
638 g_return_val_if_fail(ADG_IS_DIM(dim
), 0);
648 * @level: the new level
650 * Sets a new level for this dimension. The level is used to
651 * stack the quotes using a spacing value from dim_style
652 * (specified in paper space).
655 adg_dim_set_level(AdgDim
*dim
, gdouble level
)
659 g_return_if_fail(ADG_IS_DIM(dim
));
664 g_object_notify((GObject
*) dim
, "level");
672 * Gets the quote text. The string is internally owned and
673 * must not be freed or modified.
675 * Return value: the quote text
678 adg_dim_get_quote(AdgDim
*dim
)
682 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
692 * @quote: the quote text
694 * Explicitely sets the text to use as quote. If @quote is %NULL or
695 * was never set, an automatic text is calculated using the format as
696 * specified by the dim_style associated to this entity and getting
697 * the number from the construction points (ref1, ref2, pos1 and pos2).
700 adg_dim_set_quote(AdgDim
*dim
, const gchar
*quote
)
704 g_return_if_fail(ADG_IS_DIM(dim
));
709 data
->quote
= g_strdup(quote
);
710 g_object_notify((GObject
*) dim
, "quote");
712 text_cache_clear(&data
->quote_cache
);
716 * adg_dim_get_tolerance_up:
719 * Gets the upper tolerance text or %NULL on upper tolerance disabled.
720 * The string is internally owned and must not be freed or modified.
722 * Return value: the tolerance text
725 adg_dim_get_tolerance_up(AdgDim
*dim
)
729 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
733 return data
->tolerance_up
;
737 * adg_dim_set_tolerance_up:
739 * @tolerance_up: the upper tolerance
741 * Sets the upper tolerance. Use %NULL as @tolerance_up to disable it.
744 adg_dim_set_tolerance_up(AdgDim
*dim
, const gchar
*tolerance_up
)
748 g_return_if_fail(ADG_IS_DIM(dim
));
752 g_free(data
->tolerance_up
);
753 data
->tolerance_up
= g_strdup(tolerance_up
);
754 g_object_notify((GObject
*) dim
, "tolerance-up");
756 text_cache_clear(&data
->tolerance_up_cache
);
760 * adg_dim_get_tolerance_down:
763 * Gets the lower tolerance text or %NULL on lower tolerance disabled.
764 * The string is internally owned and must not be freed or modified.
766 * Return value: the tolerance text
769 adg_dim_get_tolerance_down(AdgDim
*dim
)
773 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
777 return data
->tolerance_down
;
781 * adg_dim_set_tolerance_down:
783 * @tolerance_down: the lower tolerance
785 * Sets the lower tolerance. Use %NULL as @tolerance_down to disable it.
788 adg_dim_set_tolerance_down(AdgDim
*dim
, const gchar
*tolerance_down
)
792 g_return_if_fail(ADG_IS_DIM(dim
));
796 g_free(data
->tolerance_down
);
797 data
->tolerance_down
= g_strdup(tolerance_down
);
798 g_object_notify((GObject
*) dim
, "tolerance-down");
800 text_cache_clear(&data
->tolerance_down_cache
);
804 * adg_dim_set_tolerances:
806 * @tolerance_up: the upper tolerance text
807 * @tolerance_down: the lower tolerance text
809 * Shortcut to set both the tolerance at once.
812 adg_dim_set_tolerances(AdgDim
*dim
, const gchar
*tolerance_up
,
813 const gchar
*tolerance_down
)
815 g_return_if_fail(ADG_IS_DIM(dim
));
817 g_object_freeze_notify((GObject
*) dim
);
818 adg_dim_set_tolerance_up(dim
, tolerance_up
);
819 adg_dim_set_tolerance_down(dim
, tolerance_down
);
820 g_object_thaw_notify((GObject
*) dim
);
827 * Gets the note text or %NULL if the note is not used. The string is
828 * internally owned and must not be freed or modified.
830 * Return value: the note text
833 adg_dim_get_note(AdgDim
*dim
)
837 g_return_val_if_fail(ADG_IS_DIM(dim
), NULL
);
847 * @note: the new note
849 * Sets a new note text, usually appended at the end of the dimension text.
852 adg_dim_set_note(AdgDim
*dim
, const gchar
*note
)
856 g_return_if_fail(ADG_IS_DIM(dim
));
861 data
->note
= g_strdup(note
);
862 g_object_notify((GObject
*) dim
, "note");
864 text_cache_clear(&data
->note_cache
);
868 * adg_dim_render_quote:
869 * @dim: an #AdgDim object
870 * @cr: a #cairo_t drawing context
872 * Renders the quote of @dim at the @org position. This function
873 * is only useful in new dimension implementations.
876 adg_dim_render_quote(AdgDim
*dim
, cairo_t
*cr
)
880 AdgDimStyle
*dim_style
;
881 const AdgMatrix
*paper
;
882 cairo_matrix_t matrix
;
884 g_return_if_fail(ADG_IS_DIM(dim
));
887 entity
= (AdgEntity
*) dim
;
888 dim_style
= (AdgDimStyle
*) adg_entity_get_style(entity
, ADG_SLOT_DIM_STYLE
);
889 paper
= adg_entity_get_paper_matrix(entity
);
891 if (data
->quote
== NULL
)
892 adg_dim_set_quote(dim
, ADG_DIM_GET_CLASS(dim
)->default_quote(dim
));
896 cairo_set_matrix(cr
, paper
);
897 ADG_DIM_GET_CLASS(dim
)->quote_layout(dim
, cr
);
898 cairo_set_matrix(cr
, adg_entity_get_model_matrix(entity
));
900 cairo_translate(cr
, data
->org
.x
, data
->org
.y
);
901 cairo_get_matrix(cr
, &matrix
);
902 matrix
.xx
= paper
->xx
;
903 matrix
.yy
= paper
->yy
;
904 cairo_set_matrix(cr
, &matrix
);
905 cairo_rotate(cr
, -data
->angle
);
907 /* Rendering quote */
908 adg_style_apply(adg_dim_style_get_quote_style(dim_style
), cr
);
909 text_cache_render(&data
->quote_cache
, cr
);
911 /* Rendering tolerances */
912 if (data
->tolerance_up
!= NULL
|| data
->tolerance_down
!= NULL
) {
913 adg_style_apply(adg_dim_style_get_tolerance_style(dim_style
), cr
);
915 if (data
->tolerance_up
!= NULL
)
916 text_cache_render(&data
->tolerance_up_cache
, cr
);
918 if (data
->tolerance_down
!= NULL
)
919 text_cache_render(&data
->tolerance_down_cache
, cr
);
922 /* Rendering the note */
923 if (data
->note
!= NULL
) {
924 adg_style_apply(adg_dim_style_get_note_style(dim_style
), cr
);
925 text_cache_render(&data
->note_cache
, cr
);
933 paper_matrix_changed(AdgEntity
*entity
, AdgMatrix
*parent_matrix
)
935 AdgEntityClass
*entity_class
= (AdgEntityClass
*) adg_dim_parent_class
;
937 clear((AdgDim
*) entity
);
939 if (entity_class
->paper_matrix_changed
!= NULL
)
940 entity_class
->paper_matrix_changed(entity
, parent_matrix
);
944 invalidate(AdgEntity
*entity
)
946 AdgEntityClass
*entity_class
= (AdgEntityClass
*) adg_dim_parent_class
;
948 clear((AdgDim
*) entity
);
950 if (entity_class
->invalidate
!= NULL
)
951 entity_class
->invalidate(entity
);
957 AdgDimPrivate
*data
= dim
->data
;
959 text_cache_clear(&data
->quote_cache
);
960 text_cache_clear(&data
->tolerance_up_cache
);
961 text_cache_clear(&data
->tolerance_down_cache
);
962 text_cache_clear(&data
->note_cache
);
966 default_quote(AdgDim
*dim
)
968 g_warning("AdgDim::default_quote not implemented for `%s'",
969 g_type_name(G_TYPE_FROM_INSTANCE(dim
)));
970 return g_strdup("undef");
974 quote_layout(AdgDim
*dim
, cairo_t
*cr
)
977 AdgDimStyle
*dim_style
;
980 CpmlPair tolerance_up_org
, tolerance_down_org
, note_org
;
983 dim_style
= (AdgDimStyle
*) adg_entity_get_style((AdgEntity
*) dim
,
985 tolerance_up_org
.x
= tolerance_up_org
.y
= 0;
986 tolerance_down_org
.x
= tolerance_down_org
.y
= 0;
987 note_org
.x
= note_org
.y
= 0;
989 /* Compute the quote */
990 if (text_cache_update(&data
->quote_cache
, data
->quote
, cr
,
991 adg_dim_style_get_quote_style(dim_style
))) {
992 cp
.x
= data
->quote_cache
.extents
.width
;
993 cp
.y
= data
->quote_cache
.extents
.height
/ -2.;
999 /* Compute the tolerances */
1000 if (data
->tolerance_up
!= NULL
|| data
->tolerance_down
!= NULL
) {
1004 adg_style_apply(adg_dim_style_get_tolerance_style(dim_style
), cr
);
1007 midspacing
= adg_dim_style_get_tolerance_spacing(dim_style
) / 2.;
1008 cpml_pair_copy(&shift
, adg_dim_style_get_tolerance_shift(dim_style
));
1011 if (text_cache_update(&data
->tolerance_up_cache
,
1012 data
->tolerance_up
, cr
, NULL
)) {
1013 tolerance_up_org
.x
= cp
.x
;
1014 tolerance_up_org
.y
= cp
.y
+ shift
.y
- midspacing
;
1016 width
= data
->tolerance_up_cache
.extents
.width
;
1019 if (text_cache_update(&data
->tolerance_down_cache
,
1020 data
->tolerance_down
, cr
, NULL
)) {
1021 tolerance_down_org
.x
= cp
.x
;
1022 tolerance_down_org
.y
= cp
.y
+ shift
.y
+ midspacing
+
1023 data
->tolerance_down_cache
.extents
.height
;
1025 if (data
->tolerance_down_cache
.extents
.width
> width
)
1026 width
= data
->tolerance_down_cache
.extents
.width
;
1032 /* Compute the note */
1033 if (text_cache_update(&data
->note_cache
, data
->note
, cr
,
1034 adg_dim_style_get_note_style(dim_style
))) {
1035 cpml_pair_copy(&shift
, adg_dim_style_get_note_shift(dim_style
));
1039 note_org
.y
= cp
.y
+ shift
.y
+ data
->note_cache
.extents
.height
/ 2.;
1041 cp
.x
+= data
->note_cache
.extents
.width
;
1044 /* Centering and shifting the whole group */
1045 cpml_pair_copy(&shift
, adg_dim_style_get_quote_shift(dim_style
));
1046 shift
.x
-= cp
.x
/ 2.;
1048 if (data
->quote_cache
.glyphs
) {
1049 text_cache_move_to(&data
->quote_cache
, &shift
);
1052 if (data
->tolerance_up_cache
.glyphs
) {
1053 tolerance_up_org
.x
+= shift
.x
;
1054 tolerance_up_org
.y
+= shift
.y
;
1055 text_cache_move_to(&data
->tolerance_up_cache
, &tolerance_up_org
);
1058 if (data
->tolerance_down_cache
.glyphs
) {
1059 tolerance_down_org
.x
+= shift
.x
;
1060 tolerance_down_org
.y
+= shift
.y
;
1061 text_cache_move_to(&data
->tolerance_down_cache
, &tolerance_down_org
);
1064 if (data
->note_cache
.glyphs
) {
1065 note_org
.x
+= shift
.x
;
1066 note_org
.y
+= shift
.y
;
1067 text_cache_move_to(&data
->note_cache
, ¬e_org
);
1072 text_cache_init(AdgTextCache
*text_cache
)
1074 text_cache
->utf8
= NULL
;
1075 text_cache
->utf8_len
= -1;
1076 text_cache
->glyphs
= NULL
;
1077 text_cache
->num_glyphs
= 0;
1078 text_cache
->clusters
= NULL
;
1079 text_cache
->num_clusters
= 0;
1080 text_cache
->cluster_flags
= 0;
1081 memset(&text_cache
->extents
, 0, sizeof(text_cache
->extents
));
1085 text_cache_update(AdgTextCache
*text_cache
, const gchar
*text
,
1086 cairo_t
*cr
, AdgStyle
*style
)
1091 text_cache
->utf8
= text
;
1092 text_cache
->utf8_len
= g_utf8_strlen(text
, -1);
1095 adg_style_apply(style
, cr
);
1097 if (!text_cache
->glyphs
) {
1098 cairo_status_t status
;
1100 status
= cairo_scaled_font_text_to_glyphs(cairo_get_scaled_font(cr
),
1103 text_cache
->utf8_len
,
1104 &text_cache
->glyphs
,
1105 &text_cache
->num_glyphs
,
1106 &text_cache
->clusters
,
1107 &text_cache
->num_clusters
,
1108 &text_cache
->cluster_flags
);
1110 if (status
!= CAIRO_STATUS_SUCCESS
) {
1111 g_error("Unable to build glyphs (cairo message: %s)",
1112 cairo_status_to_string(status
));
1116 cairo_glyph_extents(cr
, text_cache
->glyphs
, text_cache
->num_glyphs
,
1117 &text_cache
->extents
);
1124 text_cache_clear(AdgTextCache
*text_cache
)
1126 text_cache
->utf8
= NULL
;
1127 text_cache
->utf8_len
= -1;
1129 if (text_cache
->glyphs
) {
1130 cairo_glyph_free(text_cache
->glyphs
);
1131 text_cache
->glyphs
= NULL
;
1132 text_cache
->num_glyphs
= 0;
1134 if (text_cache
->clusters
) {
1135 cairo_text_cluster_free(text_cache
->clusters
);
1136 text_cache
->clusters
= NULL
;
1137 text_cache
->num_clusters
= 0;
1138 text_cache
->cluster_flags
= 0;
1140 memset(&text_cache
->extents
, 0, sizeof(text_cache
->extents
));
1144 text_cache_move_to(AdgTextCache
*text_cache
, const CpmlPair
*to
)
1146 cairo_glyph_t
*glyph
;
1150 glyph
= text_cache
->glyphs
;
1151 cnt
= text_cache
->num_glyphs
;
1152 x
= to
->x
- glyph
->x
;
1153 y
= to
->y
- glyph
->y
;
1163 text_cache_render(AdgTextCache
*text_cache
, cairo_t
*cr
)
1165 cairo_show_text_glyphs(cr
, text_cache
->utf8
, text_cache
->utf8_len
,
1166 text_cache
->glyphs
, text_cache
->num_glyphs
,
1167 text_cache
->clusters
, text_cache
->num_clusters
,
1168 text_cache
->cluster_flags
);