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: 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.
29 #include "adg-toy-text.h"
30 #include "adg-toy-text-private.h"
31 #include "adg-translatable.h"
32 #include "adg-rotable.h"
33 #include "adg-font-style.h"
44 static void translatable_init (AdgTranslatableIface
*iface
);
45 static void get_origin (AdgTranslatable
*translatable
,
47 static void set_origin (AdgTranslatable
*translatable
,
48 const AdgPoint
*origin
);
50 static void rotable_init (AdgRotableIface
*iface
);
51 static gdouble
get_angle (AdgRotable
*rotable
);
52 static void set_angle (AdgRotable
*rotable
,
55 static void finalize (GObject
*object
);
56 static void get_property (GObject
*object
,
60 static void set_property (GObject
*object
,
64 static void model_matrix_changed (AdgEntity
*entity
,
65 AdgMatrix
*parent_matrix
);
66 static void invalidate (AdgEntity
*entity
);
67 static void render (AdgEntity
*entity
,
69 static gboolean
update_origin_cache (AdgToyText
*toy_text
,
71 static gboolean
update_label_cache (AdgToyText
*toy_text
,
73 static void clear_label_cache (AdgToyText
*toy_text
);
74 static void clear_origin_cache (AdgToyText
*toy_text
);
77 G_DEFINE_TYPE_WITH_CODE(AdgToyText
, adg_toy_text
, ADG_TYPE_ENTITY
,
78 G_IMPLEMENT_INTERFACE(ADG_TYPE_TRANSLATABLE
,
80 G_IMPLEMENT_INTERFACE(ADG_TYPE_ROTABLE
, rotable_init
))
84 translatable_init(AdgTranslatableIface
*iface
)
86 iface
->get_origin
= get_origin
;
87 iface
->set_origin
= set_origin
;
91 get_origin(AdgTranslatable
*translatable
, AdgPoint
*dest
)
93 AdgToyText
*toy_text
= (AdgToyText
*) translatable
;
94 adg_point_copy(dest
, &toy_text
->priv
->origin
);
98 set_origin(AdgTranslatable
*translatable
, const AdgPoint
*origin
)
100 AdgToyText
*toy_text
= (AdgToyText
*) translatable
;
101 adg_point_copy(&toy_text
->priv
->origin
, origin
);
106 rotable_init(AdgRotableIface
*iface
)
108 iface
->get_angle
= get_angle
;
109 iface
->set_angle
= set_angle
;
113 get_angle(AdgRotable
*rotable
)
115 AdgToyText
*toy_text
= (AdgToyText
*) rotable
;
116 return toy_text
->priv
->angle
;
120 set_angle(AdgRotable
*rotable
, gdouble angle
)
122 AdgToyText
*toy_text
= (AdgToyText
*) rotable
;
123 toy_text
->priv
->angle
= angle
;
128 adg_toy_text_class_init(AdgToyTextClass
*klass
)
130 GObjectClass
*gobject_class
;
131 AdgEntityClass
*entity_class
;
134 gobject_class
= (GObjectClass
*) klass
;
135 entity_class
= (AdgEntityClass
*) klass
;
137 g_type_class_add_private(klass
, sizeof(AdgToyTextPrivate
));
139 gobject_class
->finalize
= finalize
;
140 gobject_class
->get_property
= get_property
;
141 gobject_class
->set_property
= set_property
;
143 entity_class
->model_matrix_changed
= model_matrix_changed
;
144 entity_class
->invalidate
= invalidate
;
145 entity_class
->render
= render
;
147 g_object_class_override_property(gobject_class
, PROP_ORIGIN
, "origin");
148 g_object_class_override_property(gobject_class
, PROP_ANGLE
, "angle");
150 param
= g_param_spec_string("label",
152 P_("The label to display"),
153 NULL
, G_PARAM_READWRITE
);
154 g_object_class_install_property(gobject_class
, PROP_LABEL
, param
);
158 adg_toy_text_init(AdgToyText
*toy_text
)
160 AdgToyTextPrivate
*priv
= G_TYPE_INSTANCE_GET_PRIVATE(toy_text
,
165 adg_point_unset(&priv
->origin
);
167 priv
->origin_cached
= FALSE
;
170 toy_text
->priv
= priv
;
174 finalize(GObject
*object
)
176 AdgToyText
*toy_text
;
177 GObjectClass
*object_class
;
179 toy_text
= (AdgToyText
*) object
;
180 object_class
= (GObjectClass
*) adg_toy_text_parent_class
;
182 g_free(toy_text
->priv
->label
);
183 clear_label_cache(toy_text
);
184 clear_origin_cache(toy_text
);
186 if (object_class
->finalize
!= NULL
)
187 object_class
->finalize(object
);
191 get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
193 AdgToyText
*toy_text
= (AdgToyText
*) object
;
197 g_value_set_boxed(value
, &toy_text
->priv
->origin
);
200 g_value_set_double(value
, toy_text
->priv
->angle
);
203 g_value_set_string(value
, toy_text
->priv
->label
);
206 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
212 set_property(GObject
*object
, guint prop_id
,
213 const GValue
*value
, GParamSpec
*pspec
)
215 AdgToyText
*toy_text
= (AdgToyText
*) object
;
219 adg_point_copy(&toy_text
->priv
->origin
,
220 (AdgPoint
*) g_value_get_boxed(value
));
221 clear_origin_cache(toy_text
);
224 toy_text
->priv
->angle
= g_value_get_double(value
);
225 clear_origin_cache(toy_text
);
228 g_free(toy_text
->priv
->label
);
229 toy_text
->priv
->label
= g_value_dup_string(value
);
230 clear_label_cache(toy_text
);
233 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
241 * @label: the label text
243 * Creates a new toy text entity using @label as its text
245 * Return value: the new entity
248 adg_toy_text_new(const gchar
*label
)
250 return (AdgEntity
*) g_object_new(ADG_TYPE_TOY_TEXT
, "label", label
, NULL
);
254 * adg_toy_text_get_label:
255 * @toy_text: an #AdgToyText
257 * Gets the label text. The string is internally owned and
258 * must not be freed or modified.
260 * Return value: the label text
263 adg_toy_text_get_label(AdgToyText
*toy_text
)
265 g_return_val_if_fail(ADG_IS_TOY_TEXT(toy_text
), NULL
);
267 return toy_text
->priv
->label
;
271 * adg_toy_text_set_label:
272 * @toy_text: an #AdgToyText
273 * @label: the label text
275 * Explicitely sets the text to use as label.
278 adg_toy_text_set_label(AdgToyText
*toy_text
, const gchar
*label
)
280 g_return_if_fail(ADG_IS_TOY_TEXT(label
));
282 g_free(toy_text
->priv
->label
);
283 toy_text
->priv
->label
= g_strdup(label
);
284 g_object_notify((GObject
*) toy_text
, "label");
286 clear_label_cache(toy_text
);
291 render(AdgEntity
*entity
, cairo_t
*cr
)
293 AdgToyText
*toy_text
;
294 AdgToyTextPrivate
*priv
;
295 AdgEntityClass
*entity_class
;
297 toy_text
= (AdgToyText
*) entity
;
298 priv
= toy_text
->priv
;
299 entity_class
= (AdgEntityClass
*) adg_toy_text_parent_class
;
302 AdgStyle
*font_style
;
304 font_style
= adg_entity_get_style(entity
, ADG_SLOT_FONT_STYLE
);
307 cairo_set_matrix(cr
, adg_entity_get_paper_matrix(entity
));
308 adg_style_apply(font_style
, cr
);
309 cairo_rotate(cr
, priv
->angle
);
312 update_label_cache(toy_text
, cr
);
313 if (!priv
->origin_cached
)
314 update_origin_cache(toy_text
, cr
);
316 cairo_show_glyphs(cr
, priv
->glyphs
, priv
->num_glyphs
);
320 if (entity_class
->render
!= NULL
)
321 entity_class
->render(entity
, cr
);
325 model_matrix_changed(AdgEntity
*entity
, AdgMatrix
*parent_matrix
)
327 AdgEntityClass
*entity_class
= (AdgEntityClass
*) adg_toy_text_parent_class
;
329 clear_origin_cache((AdgToyText
*) entity
);
331 if (entity_class
->model_matrix_changed
!= NULL
)
332 entity_class
->model_matrix_changed(entity
, parent_matrix
);
336 invalidate(AdgEntity
*entity
)
338 AdgToyText
*toy_text
;
339 AdgEntityClass
*entity_class
;
341 toy_text
= (AdgToyText
*) entity
;
342 entity_class
= (AdgEntityClass
*) adg_toy_text_parent_class
;
344 clear_label_cache(toy_text
);
345 clear_origin_cache(toy_text
);
347 if (entity_class
->invalidate
!= NULL
)
348 entity_class
->invalidate(entity
);
352 update_origin_cache(AdgToyText
*toy_text
, cairo_t
*cr
)
354 AdgToyTextPrivate
*priv
;
357 cairo_glyph_t
*glyph
;
361 priv
= toy_text
->priv
;
362 adg_point_copy(&point
, &priv
->origin
);
363 pair
= &priv
->origin_pair
;
364 glyph
= priv
->glyphs
;
365 cnt
= priv
->num_glyphs
;
367 /* On undefined label return error */
368 if (glyph
== NULL
|| cnt
<= 0)
371 if (priv
->angle
!= 0.) {
372 /* Following the less surprise rule, also the paper component
373 * of the origin point should rotate with the provided angle */
374 cairo_matrix_t rotation
;
375 cairo_matrix_init_rotate(&rotation
, priv
->angle
);
376 cpml_pair_transform(&point
.paper
, &rotation
);
379 adg_entity_point_to_pair((AdgEntity
*) toy_text
, &point
, pair
, cr
);
380 priv
->origin_cached
= TRUE
;
382 /* Check if the origin is still the same */
383 if (pair
->x
== glyph
->x
&& pair
->y
== glyph
->y
)
386 x
= pair
->x
- glyph
->x
;
387 y
= pair
->y
- glyph
->y
;
399 update_label_cache(AdgToyText
*toy_text
, cairo_t
*cr
)
401 AdgToyTextPrivate
*priv
= toy_text
->priv
;
402 cairo_status_t status
;
404 status
= cairo_scaled_font_text_to_glyphs(cairo_get_scaled_font(cr
),
405 0., 0., priv
->label
, -1,
410 if (status
!= CAIRO_STATUS_SUCCESS
) {
411 g_error("Unable to build glyphs (cairo message: %s)",
412 cairo_status_to_string(status
));
416 cairo_glyph_extents(cr
, priv
->glyphs
, priv
->num_glyphs
, &priv
->extents
);
418 clear_origin_cache(toy_text
);
423 clear_origin_cache(AdgToyText
*toy_text
)
425 toy_text
->priv
->origin_cached
= FALSE
;
429 clear_label_cache(AdgToyText
*toy_text
)
431 AdgToyTextPrivate
*priv
= toy_text
->priv
;
434 cairo_glyph_free(priv
->glyphs
);
438 priv
->num_glyphs
= 0;
439 memset(&priv
->extents
, 0, sizeof(priv
->extents
));