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.
22 * SECTION:adg-toy-text
23 * @short_description: Simple text entity that use the cairo "toy" text API
25 * The #AdgToyText class is a basic class to show simple text. It internally
26 * uses the so called cairo "toy" API and it shares the same limitations.
28 * The toy text entity is not subject to the local matrix, only its origin is.
34 * All fields are privates and should not be used directly.
35 * Use its public methods instead.
39 #include "adg-toy-text.h"
40 #include "adg-toy-text-private.h"
41 #include "adg-dress-builtins.h"
42 #include "adg-font-style.h"
45 #define PARENT_OBJECT_CLASS ((GObjectClass *) adg_toy_text_parent_class)
46 #define PARENT_ENTITY_CLASS ((AdgEntityClass *) adg_toy_text_parent_class)
56 static void finalize (GObject
*object
);
57 static void get_property (GObject
*object
,
61 static void set_property (GObject
*object
,
65 static void global_changed (AdgEntity
*entity
);
66 static void local_changed (AdgEntity
*entity
);
67 static void invalidate (AdgEntity
*entity
);
68 static void arrange (AdgEntity
*entity
);
69 static void render (AdgEntity
*entity
,
71 static gboolean
set_font_dress (AdgToyText
*toy_text
,
73 static gboolean
set_label (AdgToyText
*toy_text
,
75 static void unset_font (AdgToyText
*toy_text
);
76 static void unset_glyphs (AdgToyText
*toy_text
);
79 G_DEFINE_TYPE(AdgToyText
, adg_toy_text
, ADG_TYPE_ENTITY
);
83 adg_toy_text_class_init(AdgToyTextClass
*klass
)
85 GObjectClass
*gobject_class
;
86 AdgEntityClass
*entity_class
;
89 gobject_class
= (GObjectClass
*) klass
;
90 entity_class
= (AdgEntityClass
*) klass
;
92 g_type_class_add_private(klass
, sizeof(AdgToyTextPrivate
));
94 gobject_class
->finalize
= finalize
;
95 gobject_class
->get_property
= get_property
;
96 gobject_class
->set_property
= set_property
;
98 entity_class
->global_changed
= global_changed
;
99 entity_class
->local_changed
= local_changed
;
100 entity_class
->invalidate
= invalidate
;
101 entity_class
->arrange
= arrange
;
102 entity_class
->render
= render
;
104 param
= adg_param_spec_dress("font-dress",
106 P_("The font dress to use for rendering this text"),
109 g_object_class_install_property(gobject_class
, PROP_FONT_DRESS
, param
);
111 param
= g_param_spec_string("label",
113 P_("The label to display"),
116 g_object_class_install_property(gobject_class
, PROP_LABEL
, param
);
120 adg_toy_text_init(AdgToyText
*toy_text
)
122 AdgToyTextPrivate
*data
= G_TYPE_INSTANCE_GET_PRIVATE(toy_text
,
126 data
->font_dress
= ADG_DRESS_TEXT
;
130 toy_text
->data
= data
;
134 finalize(GObject
*object
)
136 AdgToyText
*toy_text
;
137 AdgToyTextPrivate
*data
;
139 toy_text
= (AdgToyText
*) object
;
140 data
= toy_text
->data
;
143 unset_font(toy_text
);
144 unset_glyphs(toy_text
);
146 if (PARENT_OBJECT_CLASS
->finalize
)
147 PARENT_OBJECT_CLASS
->finalize(object
);
151 get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
153 AdgToyTextPrivate
*data
= ((AdgToyText
*) object
)->data
;
156 case PROP_FONT_DRESS
:
157 g_value_set_int(value
, data
->font_dress
);
160 g_value_set_string(value
, data
->label
);
163 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
169 set_property(GObject
*object
, guint prop_id
,
170 const GValue
*value
, GParamSpec
*pspec
)
172 AdgToyText
*toy_text
= (AdgToyText
*) object
;
175 case PROP_FONT_DRESS
:
176 set_font_dress(toy_text
, g_value_get_int(value
));
179 set_label(toy_text
, g_value_get_string(value
));
182 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
190 * @label: the label text
192 * Creates a new toy text entity using @label as its text. The
193 * #AdgEntity:local-method property is set by default to
194 * #ADG_LOCAL_NORMALIZED.
196 * Returns: the newly created toy text entity
199 adg_toy_text_new(const gchar
*label
)
201 return g_object_new(ADG_TYPE_TOY_TEXT
,
202 "local-method", ADG_MIX_ANCESTORS_NORMALIZED
,
203 "label", label
, NULL
);
207 * adg_toy_text_get_font_dress:
208 * @toy_text: an #AdgToyText
210 * Gets the font dress to be used in rendering @toy_text.
212 * Returns: the current font dress
215 adg_toy_text_get_font_dress(AdgToyText
*toy_text
)
217 AdgToyTextPrivate
*data
;
219 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text
), ADG_DRESS_UNDEFINED
);
221 data
= toy_text
->data
;
223 return data
->font_dress
;
227 * adg_toy_text_set_font_dress:
228 * @toy_text: an #AdgToyText
229 * @dress: the new #AdgDress to use
231 * Sets a new font dress for rendering @toy_text. The new dress
232 * must be related to the original dress for this property:
233 * you cannot set a dress used for line styles to a dress
236 * The check is done by calling adg_dress_are_related() with
237 * @dress and the previous dress as arguments. Check out its
238 * documentation for details on what is a related dress.
241 adg_toy_text_set_font_dress(AdgToyText
*toy_text
, AdgDress dress
)
243 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text
));
245 if (set_font_dress(toy_text
, dress
))
246 g_object_notify((GObject
*) toy_text
, "font-dress");
250 * adg_toy_text_get_label:
251 * @toy_text: an #AdgToyText
253 * Gets the label text. The string is internally owned and
254 * must not be freed or modified.
256 * Returns: the label text
259 adg_toy_text_get_label(AdgToyText
*toy_text
)
261 AdgToyTextPrivate
*data
;
263 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text
), NULL
);
265 data
= toy_text
->data
;
271 * adg_toy_text_set_label:
272 * @toy_text: an #AdgToyText
273 * @label: the label text
275 * Sets a new label for @toy_text. @label can be also %NULL,
276 * in which case will be treated as an empty string.
279 adg_toy_text_set_label(AdgToyText
*toy_text
, const gchar
*label
)
281 g_return_if_fail(ADG_IS_TOY_TEXT(toy_text
));
283 if (set_label(toy_text
, label
))
284 g_object_notify((GObject
*) toy_text
, "label");
289 global_changed(AdgEntity
*entity
)
292 const AdgMatrix
*new;
294 adg_matrix_copy(&old
, adg_entity_get_global_matrix(entity
));
296 if (PARENT_ENTITY_CLASS
->global_changed
)
297 PARENT_ENTITY_CLASS
->global_changed(entity
);
299 new = adg_entity_get_global_matrix(entity
);
301 /* If scaling or rotation has changed, invalidate the font */
302 if (old
.xx
!= new->xx
|| old
.yy
!= new->yy
||
303 old
.xy
!= new->xy
|| old
.yx
!= new->yx
)
304 unset_font((AdgToyText
*) entity
);
308 local_changed(AdgEntity
*entity
)
311 const AdgMatrix
*new;
314 adg_matrix_copy(&old
, adg_entity_get_local_matrix(entity
));
316 if (PARENT_ENTITY_CLASS
->local_changed
)
317 PARENT_ENTITY_CLASS
->local_changed(entity
);
319 new = adg_entity_get_local_matrix(entity
);
321 /* If scaling or rotation has changed, invalidate the font */
322 if (old
.xx
!= new->xx
|| old
.yy
!= new->yy
||
323 old
.xy
!= new->xy
|| old
.yx
!= new->yx
)
324 unset_font((AdgToyText
*) entity
);
326 cpml_extents_copy(&extents
, adg_entity_get_extents(entity
));
328 if (extents
.is_defined
) {
329 /* Update the extents to the new local map */
330 cairo_matrix_invert(&old
);
331 cpml_extents_transform(&extents
, &old
);
332 cpml_extents_transform(&extents
, new);
334 adg_entity_set_extents(entity
, &extents
);
339 invalidate(AdgEntity
*entity
)
341 unset_font((AdgToyText
*) entity
);
342 unset_glyphs((AdgToyText
*) entity
);
344 if (PARENT_ENTITY_CLASS
->invalidate
)
345 PARENT_ENTITY_CLASS
->invalidate(entity
);
349 arrange(AdgEntity
*entity
)
351 AdgToyText
*toy_text
;
352 AdgToyTextPrivate
*data
;
355 toy_text
= (AdgToyText
*) entity
;
356 data
= toy_text
->data
;
358 if (data
->font
== NULL
) {
360 AdgFontStyle
*font_style
;
363 dress
= data
->font_dress
;
364 font_style
= (AdgFontStyle
*) adg_entity_style(entity
, dress
);
366 adg_matrix_copy(&ctm
, adg_entity_get_global_matrix(entity
));
367 adg_matrix_transform(&ctm
, adg_entity_get_local_matrix(entity
),
368 ADG_TRANSFORM_BEFORE
);
370 data
->font
= adg_font_style_font(font_style
, &ctm
);
373 if (adg_is_empty(data
->label
)) {
374 /* Undefined label */
375 extents
.is_defined
= FALSE
;
376 } else if (data
->glyphs
!= NULL
) {
380 cairo_status_t status
;
381 cairo_text_extents_t cairo_extents
;
383 status
= cairo_scaled_font_text_to_glyphs(data
->font
, 0, 0,
389 if (status
!= CAIRO_STATUS_SUCCESS
) {
390 unset_glyphs(toy_text
);
391 g_error("Unable to build glyphs (cairo message: %s)",
392 cairo_status_to_string(status
));
396 cairo_scaled_font_glyph_extents(data
->font
, data
->glyphs
,
397 data
->num_glyphs
, &cairo_extents
);
398 cpml_extents_from_cairo_text(&extents
, &cairo_extents
);
399 cpml_extents_transform(&extents
, adg_entity_get_local_matrix(entity
));
403 adg_entity_set_extents(entity
, &extents
);
407 render(AdgEntity
*entity
, cairo_t
*cr
)
409 AdgToyText
*toy_text
;
410 AdgToyTextPrivate
*data
;
412 toy_text
= (AdgToyText
*) entity
;
413 data
= toy_text
->data
;
415 if (data
->glyphs
!= NULL
) {
416 adg_entity_apply_dress(entity
, data
->font_dress
, cr
);
417 cairo_transform(cr
, adg_entity_get_local_matrix(entity
));
418 cairo_show_glyphs(cr
, data
->glyphs
, data
->num_glyphs
);
423 set_font_dress(AdgToyText
*toy_text
, AdgDress dress
)
425 AdgToyTextPrivate
*data
= toy_text
->data
;
427 if (adg_dress_set(&data
->font_dress
, dress
)) {
428 unset_font(toy_text
);
436 set_label(AdgToyText
*toy_text
, const gchar
*label
)
438 AdgToyTextPrivate
*data
= toy_text
->data
;
440 /* Check if the new label differs from the current label */
441 if (adg_strcmp(label
, data
->label
) == 0)
445 data
->label
= g_strdup(label
);
447 unset_glyphs(toy_text
);
452 unset_font(AdgToyText
*toy_text
)
454 AdgToyTextPrivate
*data
= toy_text
->data
;
460 unset_glyphs(AdgToyText
*toy_text
)
462 AdgToyTextPrivate
*data
= toy_text
->data
;
464 if (data
->glyphs
!= NULL
) {
465 cairo_glyph_free(data
->glyphs
);
469 data
->num_glyphs
= 0;